Add upstream code as of Chromium r334380.

Copy the unchanged source from
https://chromium.googlesource.com/chromium/src/base/ as of
r334380 (really r334285 a.k.a. 23911a0c in the base/
subtree).

Also add MODULE_LICENSE_BSD and copy Chromium's current
LICENSE file to NOTICE.

Bug: 22317122
Change-Id: I89863bfeca67b3a1ff05e6078f2f9ee4e31c5c99
diff --git a/MODULE_LICENSE_BSD b/MODULE_LICENSE_BSD
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_BSD
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000..972bb2e
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,27 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/base/BUILD.gn b/base/BUILD.gn
new file mode 100644
index 0000000..8a32ed6
--- /dev/null
+++ b/base/BUILD.gn
@@ -0,0 +1,1522 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/ui.gni")
+import("//testing/test.gni")
+
+if (is_android) {
+  import("//build/config/android/rules.gni")
+}
+
+config("base_implementation") {
+  defines = [ "BASE_IMPLEMENTATION" ]
+}
+
+if (is_win) {
+  # This is in a separate config so the flags can be applied to dependents.
+  # ldflags in GN aren't automatically inherited.
+  config("base_win_linker_flags") {
+    ldflags = [
+      "/DELAYLOAD:cfgmgr32.dll",
+      "/DELAYLOAD:powrprof.dll",
+      "/DELAYLOAD:setupapi.dll",
+    ]
+  }
+}
+
+source_set("base_paths") {
+  sources = [
+    "base_paths.cc",
+    "base_paths.h",
+    "base_paths_android.cc",
+    "base_paths_android.h",
+    "base_paths_mac.h",
+    "base_paths_mac.mm",
+    "base_paths_posix.cc",
+    "base_paths_posix.h",
+    "base_paths_win.cc",
+    "base_paths_win.h",
+  ]
+
+  if (is_android || is_mac) {
+    sources -= [ "base_paths_posix.cc" ]
+  }
+
+  if (is_nacl) {
+    sources -= [
+      "base_paths.cc",
+      "base_paths_posix.cc",
+    ]
+  }
+
+  configs += [ ":base_implementation" ]
+
+  deps = [
+    "//base/memory",
+    "//base/process",
+  ]
+
+  visibility = [ ":base" ]
+}
+
+component("base") {
+  sources = [
+    "allocator/allocator_extension.cc",
+    "allocator/allocator_extension.h",
+    "allocator/type_profiler_control.cc",
+    "allocator/type_profiler_control.h",
+    "android/animation_frame_time_histogram.cc",
+    "android/animation_frame_time_histogram.h",
+    "android/apk_assets.cc",
+    "android/apk_assets.h",
+    "android/application_status_listener.cc",
+    "android/application_status_listener.h",
+    "android/base_jni_onload.cc",
+    "android/base_jni_onload.h",
+    "android/base_jni_registrar.cc",
+    "android/base_jni_registrar.h",
+    "android/build_info.cc",
+    "android/build_info.h",
+    "android/command_line_android.cc",
+    "android/command_line_android.h",
+    "android/content_uri_utils.cc",
+    "android/content_uri_utils.h",
+    "android/cpu_features.cc",
+    "android/event_log.cc",
+    "android/event_log.h",
+    "android/field_trial_list.cc",
+    "android/field_trial_list.h",
+    "android/fifo_utils.cc",
+    "android/fifo_utils.h",
+    "android/important_file_writer_android.cc",
+    "android/important_file_writer_android.h",
+    "android/java_handler_thread.cc",
+    "android/java_handler_thread.h",
+    "android/java_runtime.cc",
+    "android/java_runtime.h",
+    "android/jni_android.cc",
+    "android/jni_android.h",
+    "android/jni_array.cc",
+    "android/jni_array.h",
+    "android/jni_registrar.cc",
+    "android/jni_registrar.h",
+    "android/jni_string.cc",
+    "android/jni_string.h",
+    "android/jni_utils.cc",
+    "android/jni_utils.h",
+    "android/jni_weak_ref.cc",
+    "android/jni_weak_ref.h",
+    "android/library_loader/library_load_from_apk_status_codes.h",
+    "android/library_loader/library_loader_hooks.cc",
+    "android/library_loader/library_loader_hooks.h",
+    "android/library_loader/library_prefetcher.cc",
+    "android/library_loader/library_prefetcher.h",
+    "android/locale_utils.cc",
+    "android/locale_utils.h",
+    "android/memory_pressure_listener_android.cc",
+    "android/memory_pressure_listener_android.h",
+    "android/path_service_android.cc",
+    "android/path_service_android.h",
+    "android/path_utils.cc",
+    "android/path_utils.h",
+    "android/record_histogram.cc",
+    "android/record_histogram.h",
+    "android/record_user_action.cc",
+    "android/record_user_action.h",
+    "android/scoped_java_ref.cc",
+    "android/scoped_java_ref.h",
+    "android/sys_utils.cc",
+    "android/sys_utils.h",
+    "android/thread_utils.h",
+    "android/trace_event_binding.cc",
+    "android/trace_event_binding.h",
+    "async_socket_io_handler.h",
+    "async_socket_io_handler_posix.cc",
+    "async_socket_io_handler_win.cc",
+    "at_exit.cc",
+    "at_exit.h",
+    "atomic_ref_count.h",
+    "atomic_sequence_num.h",
+    "atomicops.h",
+    "atomicops_internals_gcc.h",
+    "atomicops_internals_mac.h",
+    "atomicops_internals_portable.h",
+    "atomicops_internals_x86_gcc.cc",
+    "atomicops_internals_x86_gcc.h",
+    "atomicops_internals_x86_msvc.h",
+    "auto_reset.h",
+    "barrier_closure.cc",
+    "barrier_closure.h",
+    "base64.cc",
+    "base64.h",
+    "base_export.h",
+    "base_switches.h",
+    "basictypes.h",
+    "big_endian.cc",
+    "big_endian.h",
+    "bind.h",
+    "bind_helpers.cc",
+    "bind_helpers.h",
+    "bind_internal.h",
+    "bind_internal_win.h",
+    "bits.h",
+    "build_time.cc",
+    "build_time.h",
+    "callback.h",
+    "callback_helpers.cc",
+    "callback_helpers.h",
+    "callback_internal.cc",
+    "callback_internal.h",
+    "cancelable_callback.h",
+    "command_line.cc",
+    "command_line.h",
+    "compiler_specific.h",
+    "containers/adapters.h",
+    "containers/hash_tables.h",
+    "containers/linked_list.h",
+    "containers/mru_cache.h",
+    "containers/scoped_ptr_hash_map.h",
+    "containers/scoped_ptr_map.h",
+    "containers/small_map.h",
+    "containers/stack_container.h",
+    "cpu.cc",
+    "cpu.h",
+    "critical_closure.h",
+    "critical_closure_internal_ios.mm",
+    "deferred_sequenced_task_runner.cc",
+    "deferred_sequenced_task_runner.h",
+    "environment.cc",
+    "environment.h",
+    "file_descriptor_posix.h",
+    "file_version_info.h",
+    "file_version_info_mac.h",
+    "file_version_info_mac.mm",
+    "file_version_info_win.cc",
+    "file_version_info_win.h",
+    "files/dir_reader_fallback.h",
+    "files/dir_reader_linux.h",
+    "files/dir_reader_posix.h",
+    "files/file.cc",
+    "files/file_enumerator.cc",
+    "files/file_enumerator.h",
+    "files/file_enumerator_posix.cc",
+    "files/file_enumerator_win.cc",
+    "files/file_path.cc",
+    "files/file_path.h",
+    "files/file_path_constants.cc",
+    "files/file_path_watcher.cc",
+    "files/file_path_watcher.h",
+    "files/file_path_watcher_fsevents.cc",
+    "files/file_path_watcher_fsevents.h",
+    "files/file_path_watcher_kqueue.cc",
+    "files/file_path_watcher_kqueue.h",
+    "files/file_path_watcher_linux.cc",
+    "files/file_path_watcher_mac.cc",
+    "files/file_path_watcher_win.cc",
+    "files/file_posix.cc",
+    "files/file_proxy.cc",
+    "files/file_proxy.h",
+    "files/file_tracing.cc",
+    "files/file_tracing.h",
+    "files/file_util.cc",
+    "files/file_util.h",
+    "files/file_util_android.cc",
+    "files/file_util_linux.cc",
+    "files/file_util_mac.mm",
+    "files/file_util_posix.cc",
+    "files/file_util_proxy.cc",
+    "files/file_util_proxy.h",
+    "files/file_util_win.cc",
+    "files/file_win.cc",
+    "files/important_file_writer.cc",
+    "files/important_file_writer.h",
+    "files/memory_mapped_file.cc",
+    "files/memory_mapped_file.h",
+    "files/memory_mapped_file_posix.cc",
+    "files/memory_mapped_file_win.cc",
+    "files/scoped_file.cc",
+    "files/scoped_file.h",
+    "files/scoped_temp_dir.cc",
+    "files/scoped_temp_dir.h",
+    "format_macros.h",
+    "gtest_prod_util.h",
+    "guid.cc",
+    "guid.h",
+    "guid_posix.cc",
+    "guid_win.cc",
+    "hash.cc",
+    "hash.h",
+    "id_map.h",
+    "ios/device_util.h",
+    "ios/device_util.mm",
+    "ios/ios_util.h",
+    "ios/ios_util.mm",
+    "ios/scoped_critical_action.h",
+    "ios/scoped_critical_action.mm",
+    "ios/weak_nsobject.h",
+    "ios/weak_nsobject.mm",
+    "lazy_instance.cc",
+    "lazy_instance.h",
+    "linux_util.cc",
+    "linux_util.h",
+    "location.cc",
+    "location.h",
+    "logging.cc",
+    "logging.h",
+    "logging_win.cc",
+    "logging_win.h",
+    "mac/authorization_util.h",
+    "mac/authorization_util.mm",
+    "mac/bind_objc_block.h",
+    "mac/bundle_locations.h",
+    "mac/bundle_locations.mm",
+    "mac/cocoa_protocols.h",
+    "mac/dispatch_source_mach.cc",
+    "mac/dispatch_source_mach.h",
+    "mac/foundation_util.h",
+    "mac/foundation_util.mm",
+    "mac/launch_services_util.cc",
+    "mac/launch_services_util.h",
+    "mac/launchd.cc",
+    "mac/launchd.h",
+    "mac/libdispatch_task_runner.cc",
+    "mac/libdispatch_task_runner.h",
+    "mac/mac_logging.cc",
+    "mac/mac_logging.h",
+    "mac/mac_util.h",
+    "mac/mac_util.mm",
+    "mac/mach_logging.cc",
+    "mac/mach_logging.h",
+    "mac/objc_property_releaser.h",
+    "mac/objc_property_releaser.mm",
+    "mac/os_crash_dumps.cc",
+    "mac/os_crash_dumps.h",
+    "mac/scoped_aedesc.h",
+    "mac/scoped_authorizationref.h",
+    "mac/scoped_block.h",
+    "mac/scoped_cftyperef.h",
+    "mac/scoped_ioobject.h",
+    "mac/scoped_ioplugininterface.h",
+    "mac/scoped_launch_data.h",
+    "mac/scoped_mach_port.cc",
+    "mac/scoped_mach_port.h",
+    "mac/scoped_mach_vm.cc",
+    "mac/scoped_mach_vm.h",
+    "mac/scoped_nsautorelease_pool.h",
+    "mac/scoped_nsautorelease_pool.mm",
+    "mac/scoped_nsexception_enabler.h",
+    "mac/scoped_nsexception_enabler.mm",
+    "mac/scoped_nsobject.h",
+    "mac/scoped_objc_class_swizzler.h",
+    "mac/scoped_objc_class_swizzler.mm",
+    "mac/scoped_sending_event.h",
+    "mac/scoped_sending_event.mm",
+    "mac/sdk_forward_declarations.h",
+    "mac/sdk_forward_declarations.mm",
+    "macros.h",
+    "md5.cc",
+    "md5.h",
+    "message_loop/incoming_task_queue.cc",
+    "message_loop/incoming_task_queue.h",
+    "message_loop/message_loop.cc",
+    "message_loop/message_loop.h",
+    "message_loop/message_loop_proxy.cc",
+    "message_loop/message_loop_proxy.h",
+    "message_loop/message_loop_proxy_impl.cc",
+    "message_loop/message_loop_proxy_impl.h",
+    "message_loop/message_pump.cc",
+    "message_loop/message_pump.h",
+    "message_loop/message_pump_android.cc",
+    "message_loop/message_pump_android.h",
+    "message_loop/message_pump_default.cc",
+    "message_loop/message_pump_default.h",
+    "message_loop/message_pump_glib.cc",
+    "message_loop/message_pump_glib.h",
+    "message_loop/message_pump_io_ios.cc",
+    "message_loop/message_pump_io_ios.h",
+    "message_loop/message_pump_libevent.cc",
+    "message_loop/message_pump_libevent.h",
+    "message_loop/message_pump_mac.h",
+    "message_loop/message_pump_mac.mm",
+    "message_loop/message_pump_win.cc",
+    "message_loop/message_pump_win.h",
+    "move.h",
+    "native_library.h",
+    "native_library_ios.mm",
+    "native_library_mac.mm",
+    "native_library_posix.cc",
+    "native_library_win.cc",
+    "nix/mime_util_xdg.cc",
+    "nix/mime_util_xdg.h",
+    "nix/xdg_util.cc",
+    "nix/xdg_util.h",
+    "numerics/safe_conversions.h",
+    "numerics/safe_conversions_impl.h",
+    "numerics/safe_math.h",
+    "numerics/safe_math_impl.h",
+    "observer_list.h",
+    "observer_list_threadsafe.h",
+    "os_compat_android.cc",
+    "os_compat_android.h",
+    "os_compat_nacl.cc",
+    "os_compat_nacl.h",
+    "path_service.cc",
+    "path_service.h",
+    "pending_task.cc",
+    "pending_task.h",
+    "pickle.cc",
+    "pickle.h",
+    "port.h",
+    "posix/eintr_wrapper.h",
+    "posix/file_descriptor_shuffle.cc",
+    "posix/global_descriptors.cc",
+    "posix/global_descriptors.h",
+    "posix/safe_strerror.cc",
+    "posix/safe_strerror.h",
+    "posix/unix_domain_socket_linux.cc",
+    "posix/unix_domain_socket_linux.h",
+    "power_monitor/power_monitor.cc",
+    "power_monitor/power_monitor.h",
+    "power_monitor/power_monitor_device_source.cc",
+    "power_monitor/power_monitor_device_source.h",
+    "power_monitor/power_monitor_device_source_android.cc",
+    "power_monitor/power_monitor_device_source_android.h",
+    "power_monitor/power_monitor_device_source_chromeos.cc",
+    "power_monitor/power_monitor_device_source_ios.mm",
+    "power_monitor/power_monitor_device_source_mac.mm",
+    "power_monitor/power_monitor_device_source_posix.cc",
+    "power_monitor/power_monitor_device_source_win.cc",
+    "power_monitor/power_monitor_source.cc",
+    "power_monitor/power_monitor_source.h",
+    "power_monitor/power_observer.h",
+    "profiler/alternate_timer.cc",
+    "profiler/alternate_timer.h",
+    "profiler/native_stack_sampler.cc",
+    "profiler/native_stack_sampler.h",
+    "profiler/scoped_profile.cc",
+    "profiler/scoped_profile.h",
+    "profiler/scoped_tracker.cc",
+    "profiler/scoped_tracker.h",
+    "profiler/stack_sampling_profiler.cc",
+    "profiler/stack_sampling_profiler.h",
+    "profiler/stack_sampling_profiler_posix.cc",
+    "profiler/stack_sampling_profiler_win.cc",
+    "profiler/tracked_time.cc",
+    "profiler/tracked_time.h",
+    "rand_util.cc",
+    "rand_util.h",
+    "rand_util_nacl.cc",
+    "rand_util_posix.cc",
+    "rand_util_win.cc",
+    "run_loop.cc",
+    "run_loop.h",
+    "scoped_generic.h",
+    "scoped_native_library.cc",
+    "scoped_native_library.h",
+    "scoped_observer.h",
+    "sequence_checker.h",
+    "sequence_checker_impl.cc",
+    "sequence_checker_impl.h",
+    "sequenced_task_runner.cc",
+    "sequenced_task_runner.h",
+    "sequenced_task_runner_helpers.h",
+    "sha1.h",
+    "sha1_portable.cc",
+    "sha1_win.cc",
+    "single_thread_task_runner.h",
+    "stl_util.h",
+    "strings/latin1_string_conversions.cc",
+    "strings/latin1_string_conversions.h",
+    "strings/nullable_string16.cc",
+    "strings/nullable_string16.h",
+    "strings/safe_sprintf.cc",
+    "strings/safe_sprintf.h",
+    "strings/string16.cc",
+    "strings/string16.h",
+    "strings/string_number_conversions.cc",
+    "strings/string_number_conversions.h",
+    "strings/string_piece.cc",
+    "strings/string_piece.h",
+    "strings/string_split.cc",
+    "strings/string_split.h",
+    "strings/string_tokenizer.h",
+    "strings/string_util.cc",
+    "strings/string_util.h",
+    "strings/string_util_constants.cc",
+    "strings/string_util_posix.h",
+    "strings/string_util_win.h",
+    "strings/stringize_macros.h",
+    "strings/stringprintf.cc",
+    "strings/stringprintf.h",
+    "strings/sys_string_conversions.h",
+    "strings/sys_string_conversions_mac.mm",
+    "strings/sys_string_conversions_posix.cc",
+    "strings/sys_string_conversions_win.cc",
+    "strings/utf_offset_string_conversions.cc",
+    "strings/utf_offset_string_conversions.h",
+    "strings/utf_string_conversion_utils.cc",
+    "strings/utf_string_conversion_utils.h",
+    "strings/utf_string_conversions.cc",
+    "strings/utf_string_conversions.h",
+    "supports_user_data.cc",
+    "supports_user_data.h",
+    "sync_socket.h",
+    "sync_socket_posix.cc",
+    "sync_socket_win.cc",
+    "synchronization/cancellation_flag.cc",
+    "synchronization/cancellation_flag.h",
+    "synchronization/condition_variable.h",
+    "synchronization/condition_variable_posix.cc",
+    "synchronization/condition_variable_win.cc",
+    "synchronization/lock.cc",
+    "synchronization/lock.h",
+    "synchronization/lock_impl.h",
+    "synchronization/lock_impl_posix.cc",
+    "synchronization/lock_impl_win.cc",
+    "synchronization/spin_wait.h",
+    "synchronization/waitable_event.h",
+    "synchronization/waitable_event_posix.cc",
+    "synchronization/waitable_event_watcher.h",
+    "synchronization/waitable_event_watcher_posix.cc",
+    "synchronization/waitable_event_watcher_win.cc",
+    "synchronization/waitable_event_win.cc",
+    "sys_byteorder.h",
+    "sys_info.cc",
+    "sys_info.h",
+    "sys_info_android.cc",
+    "sys_info_chromeos.cc",
+    "sys_info_freebsd.cc",
+    "sys_info_ios.mm",
+    "sys_info_linux.cc",
+    "sys_info_mac.cc",
+    "sys_info_openbsd.cc",
+    "sys_info_posix.cc",
+    "sys_info_win.cc",
+    "system_monitor/system_monitor.cc",
+    "system_monitor/system_monitor.h",
+    "task/cancelable_task_tracker.cc",
+    "task/cancelable_task_tracker.h",
+    "task_runner.cc",
+    "task_runner.h",
+    "task_runner_util.h",
+    "template_util.h",
+    "third_party/dmg_fp/dmg_fp.h",
+    "third_party/dmg_fp/dtoa_wrapper.cc",
+    "third_party/dmg_fp/g_fmt.cc",
+    "third_party/icu/icu_utf.cc",
+    "third_party/icu/icu_utf.h",
+    "third_party/nspr/prtime.cc",
+    "third_party/nspr/prtime.h",
+    "third_party/superfasthash/superfasthash.c",
+    "thread_task_runner_handle.cc",
+    "thread_task_runner_handle.h",
+    "threading/non_thread_safe.h",
+    "threading/non_thread_safe_impl.cc",
+    "threading/non_thread_safe_impl.h",
+    "threading/platform_thread.h",
+    "threading/platform_thread_android.cc",
+    "threading/platform_thread_internal_posix.cc",
+    "threading/platform_thread_internal_posix.h",
+    "threading/platform_thread_linux.cc",
+    "threading/platform_thread_mac.mm",
+    "threading/platform_thread_posix.cc",
+    "threading/platform_thread_win.cc",
+    "threading/post_task_and_reply_impl.cc",
+    "threading/post_task_and_reply_impl.h",
+    "threading/sequenced_worker_pool.cc",
+    "threading/sequenced_worker_pool.h",
+    "threading/simple_thread.cc",
+    "threading/simple_thread.h",
+    "threading/thread.cc",
+    "threading/thread.h",
+    "threading/thread_checker.h",
+    "threading/thread_checker_impl.cc",
+    "threading/thread_checker_impl.h",
+    "threading/thread_collision_warner.cc",
+    "threading/thread_collision_warner.h",
+    "threading/thread_id_name_manager.cc",
+    "threading/thread_id_name_manager.h",
+    "threading/thread_local.h",
+    "threading/thread_local_android.cc",
+    "threading/thread_local_posix.cc",
+    "threading/thread_local_storage.cc",
+    "threading/thread_local_storage.h",
+    "threading/thread_local_storage_posix.cc",
+    "threading/thread_local_storage_win.cc",
+    "threading/thread_local_win.cc",
+    "threading/thread_restrictions.cc",
+    "threading/thread_restrictions.h",
+    "threading/watchdog.cc",
+    "threading/watchdog.h",
+    "threading/worker_pool.cc",
+    "threading/worker_pool.h",
+    "threading/worker_pool_posix.cc",
+    "threading/worker_pool_posix.h",
+    "threading/worker_pool_win.cc",
+    "time/clock.cc",
+    "time/clock.h",
+    "time/default_clock.cc",
+    "time/default_clock.h",
+    "time/default_tick_clock.cc",
+    "time/default_tick_clock.h",
+    "time/tick_clock.cc",
+    "time/tick_clock.h",
+    "time/time.cc",
+    "time/time.h",
+    "time/time_mac.cc",
+    "time/time_posix.cc",
+    "time/time_win.cc",
+    "timer/elapsed_timer.cc",
+    "timer/elapsed_timer.h",
+    "timer/hi_res_timer_manager.h",
+    "timer/hi_res_timer_manager_posix.cc",
+    "timer/hi_res_timer_manager_win.cc",
+    "timer/mock_timer.cc",
+    "timer/mock_timer.h",
+    "timer/timer.cc",
+    "timer/timer.h",
+    "tracked_objects.cc",
+    "tracked_objects.h",
+    "tracking_info.cc",
+    "tracking_info.h",
+    "tuple.h",
+    "value_conversions.cc",
+    "value_conversions.h",
+    "values.cc",
+    "values.h",
+    "version.cc",
+    "version.h",
+    "vlog.cc",
+    "vlog.h",
+    "win/enum_variant.cc",
+    "win/enum_variant.h",
+    "win/event_trace_consumer.h",
+    "win/event_trace_controller.cc",
+    "win/event_trace_controller.h",
+    "win/event_trace_provider.cc",
+    "win/event_trace_provider.h",
+    "win/i18n.cc",
+    "win/i18n.h",
+    "win/iat_patch_function.cc",
+    "win/iat_patch_function.h",
+    "win/iunknown_impl.cc",
+    "win/iunknown_impl.h",
+    "win/message_window.cc",
+    "win/message_window.h",
+    "win/metro.cc",
+    "win/metro.h",
+    "win/object_watcher.cc",
+    "win/object_watcher.h",
+    "win/registry.cc",
+    "win/registry.h",
+    "win/resource_util.cc",
+    "win/resource_util.h",
+    "win/scoped_bstr.cc",
+    "win/scoped_bstr.h",
+    "win/scoped_co_mem.h",
+    "win/scoped_com_initializer.h",
+    "win/scoped_comptr.h",
+    "win/scoped_gdi_object.h",
+    "win/scoped_handle.cc",
+    "win/scoped_handle.h",
+    "win/scoped_hdc.h",
+    "win/scoped_hglobal.h",
+    "win/scoped_process_information.cc",
+    "win/scoped_process_information.h",
+    "win/scoped_propvariant.h",
+    "win/scoped_select_object.h",
+    "win/scoped_variant.cc",
+    "win/scoped_variant.h",
+    "win/shortcut.cc",
+    "win/shortcut.h",
+    "win/startup_information.cc",
+    "win/startup_information.h",
+    "win/win_util.cc",
+    "win/win_util.h",
+    "win/windows_version.cc",
+    "win/windows_version.h",
+    "win/wrapped_window_proc.cc",
+    "win/wrapped_window_proc.h",
+  ]
+
+  sources -= [
+    "sys_info_freebsd.cc",
+    "sys_info_openbsd.cc",
+  ]
+
+  configs += [ ":base_implementation" ]
+
+  deps = [
+    ":base_static",
+    "//base/allocator:allocator_extension_thunks",
+    "//base/third_party/dynamic_annotations",
+    "//third_party/modp_b64",
+  ]
+
+  public_deps = [
+    ":base_paths",
+    "//base/debug",
+    "//base/json",
+    "//base/memory",
+    "//base/metrics",
+    "//base/process",
+    "//base/trace_event",
+  ]
+
+  # Allow more direct string conversions on platforms with native utf8
+  # strings
+  if (is_mac || is_ios || is_chromeos) {
+    defines = [ "SYSTEM_NATIVE_UTF8" ]
+  }
+
+  if (is_android) {
+    sources -= [ "power_monitor/power_monitor_device_source_posix.cc" ]
+
+    # Android uses some Linux sources, put those back.
+    set_sources_assignment_filter([])
+    sources += [
+      "files/file_path_watcher_linux.cc",
+      "posix/unix_domain_socket_linux.cc",
+      "sys_info_linux.cc",
+    ]
+    set_sources_assignment_filter(sources_assignment_filter)
+
+    deps += [
+      ":base_jni_headers",
+      "//third_party/ashmem",
+      "//third_party/android_tools:cpu_features",
+    ]
+
+    # logging.cc uses the Android logging library.
+    libs = [ "log" ]
+  }
+
+  if (is_chromeos) {
+    sources -= [ "power_monitor/power_monitor_device_source_posix.cc" ]
+  }
+
+  if (is_nacl) {
+    # We reset sources_assignment_filter in order to explicitly include
+    # the linux file (which would otherwise be filtered out).
+    set_sources_assignment_filter([])
+    sources += [
+      "files/file_path_watcher_stub.cc",
+      "sync_socket_nacl.cc",
+      "threading/platform_thread_linux.cc",
+    ]
+    set_sources_assignment_filter(sources_assignment_filter)
+
+    sources -= [
+      "allocator/type_profiler_control.cc",
+      "allocator/type_profiler_control.h",
+      "async_socket_io_handler_posix.cc",
+      "cpu.cc",
+      "files/file_enumerator_posix.cc",
+      "files/file_proxy.cc",
+      "files/file_util.cc",
+      "files/file_util_posix.cc",
+      "files/file_util_proxy.cc",
+      "files/important_file_writer.cc",
+      "files/important_file_writer.h",
+      "files/scoped_temp_dir.cc",
+      "message_loop/message_pump_libevent.cc",
+      "native_library_posix.cc",
+      "path_service.cc",
+      "rand_util_posix.cc",
+      "scoped_native_library.cc",
+      "sync_socket_posix.cc",
+      "sys_info.cc",
+      "sys_info_posix.cc",
+    ]
+  } else {
+    # Remove NaCl stuff.
+    sources -= [
+      "os_compat_nacl.cc",
+      "os_compat_nacl.h",
+      "rand_util_nacl.cc",
+    ]
+  }
+
+  # Windows.
+  if (is_win) {
+    sources -= [
+      "message_loop/message_pump_libevent.cc",
+      "strings/string16.cc",
+
+      # Not using sha1_win.cc because it may have caused a
+      # regression to page cycler moz.
+      "sha1_win.cc",
+    ]
+
+    # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+    configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
+
+    libs = [
+      "cfgmgr32.lib",
+      "netapi32.lib",
+      "powrprof.lib",
+      "setupapi.lib",
+    ]
+    all_dependent_configs = [ ":base_win_linker_flags" ]
+  } else if (!is_nacl) {
+    # Non-Windows.
+    deps += [ "//third_party/libevent" ]
+  }
+
+  # Mac.
+  if (is_mac) {
+    sources -= [
+      "native_library_posix.cc",
+      "strings/sys_string_conversions_posix.cc",
+      "threading/platform_thread_internal_posix.cc",
+    ]
+  } else {
+    # Non-Mac.
+    sources -= [
+      "files/file_path_watcher_fsevents.cc",
+      "files/file_path_watcher_fsevents.h",
+      "files/file_path_watcher_kqueue.cc",
+      "files/file_path_watcher_kqueue.h",
+    ]
+  }
+
+  # Linux.
+  if (is_linux) {
+    # TODO(brettw) this will need to be parameterized at some point.
+    linux_configs = []
+    if (use_glib) {
+      linux_configs += [ "//build/config/linux:glib" ]
+    }
+
+    configs += linux_configs
+    all_dependent_configs = linux_configs
+
+    # These dependencies are not required on Android, and in the case
+    # of xdg_mime must be excluded due to licensing restrictions.
+    deps += [
+      "//base/third_party/xdg_mime",
+      "//base/third_party/xdg_user_dirs",
+    ]
+  } else {
+    # Non-Linux.
+    sources -= [
+      "nix/mime_util_xdg.cc",
+      "nix/mime_util_xdg.h",
+      "nix/xdg_util.cc",
+      "nix/xdg_util.h",
+    ]
+
+    if (!is_android) {
+      sources -= [
+        "linux_util.cc",
+        "linux_util.h",
+      ]
+    }
+  }
+
+  if (!use_glib) {
+    sources -= [
+      "message_loop/message_pump_glib.cc",
+      "message_loop/message_pump_glib.h",
+    ]
+  }
+
+  configs += [ "//build/config/compiler:wexit_time_destructors" ]
+  if (is_android && !is_debug) {
+    configs -= [ "//build/config/compiler:optimize" ]
+    configs += [ "//build/config/compiler:optimize_max" ]
+  }
+
+  allow_circular_includes_from = public_deps
+}
+
+# This is the subset of files from base that should not be used with a dynamic
+# library. Note that this library cannot depend on base because base depends on
+# base_static.
+source_set("base_static") {
+  sources = [
+    "base_switches.cc",
+    "base_switches.h",
+    "win/pe_image.cc",
+    "win/pe_image.h",
+  ]
+
+  if (is_android && !is_debug) {
+    configs -= [ "//build/config/compiler:optimize" ]
+    configs += [ "//build/config/compiler:optimize_max" ]
+  }
+}
+
+component("i18n") {
+  output_name = "base_i18n"
+  sources = [
+    "i18n/base_i18n_export.h",
+    "i18n/bidi_line_iterator.cc",
+    "i18n/bidi_line_iterator.h",
+    "i18n/break_iterator.cc",
+    "i18n/break_iterator.h",
+    "i18n/case_conversion.cc",
+    "i18n/case_conversion.h",
+    "i18n/char_iterator.cc",
+    "i18n/char_iterator.h",
+    "i18n/file_util_icu.cc",
+    "i18n/file_util_icu.h",
+    "i18n/i18n_constants.cc",
+    "i18n/i18n_constants.h",
+    "i18n/icu_encoding_detection.cc",
+    "i18n/icu_encoding_detection.h",
+    "i18n/icu_string_conversions.cc",
+    "i18n/icu_string_conversions.h",
+    "i18n/icu_util.cc",
+    "i18n/icu_util.h",
+    "i18n/number_formatting.cc",
+    "i18n/number_formatting.h",
+    "i18n/rtl.cc",
+    "i18n/rtl.h",
+    "i18n/streaming_utf8_validator.cc",
+    "i18n/streaming_utf8_validator.h",
+    "i18n/string_compare.cc",
+    "i18n/string_compare.h",
+    "i18n/string_search.cc",
+    "i18n/string_search.h",
+    "i18n/time_formatting.cc",
+    "i18n/time_formatting.h",
+    "i18n/timezone.cc",
+    "i18n/timezone.h",
+    "i18n/utf8_validator_tables.cc",
+    "i18n/utf8_validator_tables.h",
+  ]
+  defines = [ "BASE_I18N_IMPLEMENTATION" ]
+  configs += [ "//build/config/compiler:wexit_time_destructors" ]
+  deps = [
+    ":base",
+    "//base/third_party/dynamic_annotations",
+    "//third_party/icu",
+  ]
+
+  if (is_android && !is_debug) {
+    configs -= [ "//build/config/compiler:optimize" ]
+    configs += [ "//build/config/compiler:optimize_max" ]
+  }
+
+  # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+  configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
+}
+
+if (is_win || (is_linux && !is_chromeos)) {
+  # TODO(GYP): Figure out which of these work and are needed on other platforms.
+  test("base_perftests") {
+    sources = [
+      "message_loop/message_pump_perftest.cc",
+
+      # "test/run_all_unittests.cc",
+      "threading/thread_perftest.cc",
+    ]
+    deps = [
+      ":base",
+      "//base/test:test_support",
+      "//base/test:test_support_perf",
+      "//testing/perf",
+      "//testing/gtest",
+    ]
+
+    if (is_android) {
+      deps += [ "//testing/android/native_test:native_test_native_code" ]
+    }
+  }
+
+  test("base_i18n_perftests") {
+    sources = [
+      "i18n/streaming_utf8_validator_perftest.cc",
+    ]
+    deps = [
+      ":base",
+      ":i18n",
+      "//base/test:test_support",
+      "//base/test:test_support_perf",
+      "//testing/gtest",
+    ]
+  }
+
+  if (!is_ios) {
+    executable("build_utf8_validator_tables") {
+      sources = [
+        "i18n/build_utf8_validator_tables.cc",
+      ]
+      deps = [
+        ":base",
+        "//third_party/icu:icuuc",
+      ]
+    }
+
+    executable("check_example") {
+      sources = [
+        "check_example.cc",
+      ]
+      deps = [
+        ":base",
+      ]
+    }
+  }
+}
+
+component("prefs") {
+  sources = [
+    "prefs/base_prefs_export.h",
+    "prefs/default_pref_store.cc",
+    "prefs/default_pref_store.h",
+    "prefs/json_pref_store.cc",
+    "prefs/json_pref_store.h",
+    "prefs/overlay_user_pref_store.cc",
+    "prefs/overlay_user_pref_store.h",
+    "prefs/persistent_pref_store.h",
+    "prefs/pref_change_registrar.cc",
+    "prefs/pref_change_registrar.h",
+    "prefs/pref_filter.h",
+    "prefs/pref_member.cc",
+    "prefs/pref_member.h",
+    "prefs/pref_notifier.h",
+    "prefs/pref_notifier_impl.cc",
+    "prefs/pref_notifier_impl.h",
+    "prefs/pref_observer.h",
+    "prefs/pref_registry.cc",
+    "prefs/pref_registry.h",
+    "prefs/pref_registry_simple.cc",
+    "prefs/pref_registry_simple.h",
+    "prefs/pref_service.cc",
+    "prefs/pref_service.h",
+    "prefs/pref_service_factory.cc",
+    "prefs/pref_service_factory.h",
+    "prefs/pref_store.cc",
+    "prefs/pref_store.h",
+    "prefs/pref_value_map.cc",
+    "prefs/pref_value_map.h",
+    "prefs/pref_value_store.cc",
+    "prefs/pref_value_store.h",
+    "prefs/scoped_user_pref_update.cc",
+    "prefs/scoped_user_pref_update.h",
+    "prefs/value_map_pref_store.cc",
+    "prefs/value_map_pref_store.h",
+    "prefs/writeable_pref_store.h",
+  ]
+
+  defines = [ "BASE_PREFS_IMPLEMENTATION" ]
+
+  deps = [
+    ":base",
+  ]
+
+  if (is_android && !is_debug) {
+    configs -= [ "//build/config/compiler:optimize" ]
+    configs += [ "//build/config/compiler:optimize_max" ]
+  }
+}
+
+source_set("prefs_test_support") {
+  testonly = true
+  sources = [
+    "prefs/mock_pref_change_callback.cc",
+    "prefs/mock_pref_change_callback.h",
+    "prefs/pref_store_observer_mock.cc",
+    "prefs/pref_store_observer_mock.h",
+    "prefs/testing_pref_service.cc",
+    "prefs/testing_pref_service.h",
+    "prefs/testing_pref_store.cc",
+    "prefs/testing_pref_store.h",
+  ]
+
+  public_deps = [
+    ":prefs",
+  ]
+  deps = [
+    ":base",
+    "//testing/gmock",
+    "//testing/gtest",
+  ]
+}
+
+source_set("message_loop_tests") {
+  testonly = true
+  sources = [
+    "message_loop/message_loop_test.cc",
+    "message_loop/message_loop_test.h",
+  ]
+
+  deps = [
+    ":base",
+    "//testing/gtest",
+  ]
+}
+
+if (is_win) {
+  # Target to manually rebuild pe_image_test.dll which is checked into
+  # base/test/data/pe_image.
+  shared_library("pe_image_test") {
+    sources = [
+      "win/pe_image_test.cc",
+    ]
+    ldflags = [
+      "/DELAYLOAD:cfgmgr32.dll",
+      "/DELAYLOAD:shell32.dll",
+      "/SUBSYSTEM:WINDOWS",
+    ]
+    libs = [
+      "cfgmgr32.lib",
+      "shell32.lib",
+    ]
+  }
+}
+
+test("base_unittests") {
+  sources = [
+    "android/application_status_listener_unittest.cc",
+    "android/content_uri_utils_unittest.cc",
+    "android/jni_android_unittest.cc",
+    "android/jni_array_unittest.cc",
+    "android/jni_string_unittest.cc",
+    "android/library_loader/library_prefetcher_unittest.cc",
+    "android/path_utils_unittest.cc",
+    "android/scoped_java_ref_unittest.cc",
+    "android/sys_utils_unittest.cc",
+    "async_socket_io_handler_unittest.cc",
+    "at_exit_unittest.cc",
+    "atomicops_unittest.cc",
+    "barrier_closure_unittest.cc",
+    "base64_unittest.cc",
+    "big_endian_unittest.cc",
+    "bind_unittest.cc",
+    "bind_unittest.nc",
+    "bits_unittest.cc",
+    "build_time_unittest.cc",
+    "callback_helpers_unittest.cc",
+    "callback_list_unittest.cc",
+    "callback_list_unittest.nc",
+    "callback_unittest.cc",
+    "callback_unittest.nc",
+    "cancelable_callback_unittest.cc",
+    "command_line_unittest.cc",
+    "containers/adapters_unittest.cc",
+    "containers/hash_tables_unittest.cc",
+    "containers/linked_list_unittest.cc",
+    "containers/mru_cache_unittest.cc",
+    "containers/scoped_ptr_hash_map_unittest.cc",
+    "containers/scoped_ptr_map_unittest.cc",
+    "containers/small_map_unittest.cc",
+    "containers/stack_container_unittest.cc",
+    "cpu_unittest.cc",
+    "debug/crash_logging_unittest.cc",
+    "debug/debugger_unittest.cc",
+    "debug/leak_tracker_unittest.cc",
+    "debug/proc_maps_linux_unittest.cc",
+    "debug/stack_trace_unittest.cc",
+    "debug/task_annotator_unittest.cc",
+    "deferred_sequenced_task_runner_unittest.cc",
+    "environment_unittest.cc",
+    "file_version_info_unittest.cc",
+    "files/dir_reader_posix_unittest.cc",
+    "files/file_path_unittest.cc",
+    "files/file_path_watcher_unittest.cc",
+    "files/file_proxy_unittest.cc",
+    "files/file_unittest.cc",
+    "files/file_util_proxy_unittest.cc",
+    "files/file_util_unittest.cc",
+    "files/important_file_writer_unittest.cc",
+    "files/scoped_temp_dir_unittest.cc",
+    "gmock_unittest.cc",
+    "guid_unittest.cc",
+    "hash_unittest.cc",
+    "i18n/break_iterator_unittest.cc",
+    "i18n/case_conversion_unittest.cc",
+    "i18n/char_iterator_unittest.cc",
+    "i18n/file_util_icu_unittest.cc",
+    "i18n/icu_string_conversions_unittest.cc",
+    "i18n/number_formatting_unittest.cc",
+    "i18n/rtl_unittest.cc",
+    "i18n/streaming_utf8_validator_unittest.cc",
+    "i18n/string_search_unittest.cc",
+    "i18n/time_formatting_unittest.cc",
+    "i18n/timezone_unittest.cc",
+    "id_map_unittest.cc",
+    "ios/device_util_unittest.mm",
+    "ios/weak_nsobject_unittest.mm",
+    "json/json_parser_unittest.cc",
+    "json/json_reader_unittest.cc",
+    "json/json_value_converter_unittest.cc",
+    "json/json_value_serializer_unittest.cc",
+    "json/json_writer_unittest.cc",
+    "json/string_escape_unittest.cc",
+    "lazy_instance_unittest.cc",
+    "logging_unittest.cc",
+    "mac/bind_objc_block_unittest.mm",
+    "mac/dispatch_source_mach_unittest.cc",
+    "mac/foundation_util_unittest.mm",
+    "mac/libdispatch_task_runner_unittest.cc",
+    "mac/mac_util_unittest.mm",
+    "mac/objc_property_releaser_unittest.mm",
+    "mac/scoped_nsobject_unittest.mm",
+    "mac/scoped_objc_class_swizzler_unittest.mm",
+    "mac/scoped_sending_event_unittest.mm",
+    "md5_unittest.cc",
+    "memory/aligned_memory_unittest.cc",
+    "memory/discardable_shared_memory_unittest.cc",
+    "memory/linked_ptr_unittest.cc",
+    "memory/memory_pressure_monitor_chromeos_unittest.cc",
+    "memory/memory_pressure_monitor_win_unittest.cc",
+    "memory/ref_counted_memory_unittest.cc",
+    "memory/ref_counted_unittest.cc",
+    "memory/scoped_ptr_unittest.cc",
+    "memory/scoped_ptr_unittest.nc",
+    "memory/scoped_vector_unittest.cc",
+    "memory/shared_memory_unittest.cc",
+    "memory/singleton_unittest.cc",
+    "memory/weak_ptr_unittest.cc",
+    "memory/weak_ptr_unittest.nc",
+    "message_loop/message_loop_proxy_impl_unittest.cc",
+    "message_loop/message_loop_proxy_unittest.cc",
+    "message_loop/message_loop_unittest.cc",
+    "message_loop/message_pump_glib_unittest.cc",
+    "message_loop/message_pump_io_ios_unittest.cc",
+    "metrics/bucket_ranges_unittest.cc",
+    "metrics/field_trial_unittest.cc",
+    "metrics/histogram_base_unittest.cc",
+    "metrics/histogram_delta_serialization_unittest.cc",
+    "metrics/histogram_snapshot_manager_unittest.cc",
+    "metrics/histogram_unittest.cc",
+    "metrics/sample_map_unittest.cc",
+    "metrics/sample_vector_unittest.cc",
+    "metrics/sparse_histogram_unittest.cc",
+    "metrics/statistics_recorder_unittest.cc",
+    "move_unittest.cc",
+    "numerics/safe_numerics_unittest.cc",
+    "observer_list_unittest.cc",
+    "os_compat_android_unittest.cc",
+    "path_service_unittest.cc",
+    "pickle_unittest.cc",
+    "posix/file_descriptor_shuffle_unittest.cc",
+    "posix/unix_domain_socket_linux_unittest.cc",
+    "power_monitor/power_monitor_unittest.cc",
+    "prefs/default_pref_store_unittest.cc",
+    "prefs/json_pref_store_unittest.cc",
+    "prefs/overlay_user_pref_store_unittest.cc",
+    "prefs/pref_change_registrar_unittest.cc",
+    "prefs/pref_member_unittest.cc",
+    "prefs/pref_notifier_impl_unittest.cc",
+    "prefs/pref_service_unittest.cc",
+    "prefs/pref_value_map_unittest.cc",
+    "prefs/pref_value_store_unittest.cc",
+    "prefs/scoped_user_pref_update_unittest.cc",
+    "process/memory_unittest.cc",
+    "process/memory_unittest_mac.h",
+    "process/memory_unittest_mac.mm",
+    "process/process_metrics_unittest.cc",
+    "process/process_metrics_unittest_ios.cc",
+    "process/process_unittest.cc",
+    "process/process_util_unittest.cc",
+    "process/process_util_unittest_ios.cc",
+    "profiler/stack_sampling_profiler_unittest.cc",
+    "profiler/tracked_time_unittest.cc",
+    "rand_util_unittest.cc",
+    "scoped_clear_errno_unittest.cc",
+    "scoped_generic_unittest.cc",
+    "scoped_native_library_unittest.cc",
+    "security_unittest.cc",
+    "sequence_checker_unittest.cc",
+    "sha1_unittest.cc",
+    "stl_util_unittest.cc",
+    "strings/nullable_string16_unittest.cc",
+    "strings/safe_sprintf_unittest.cc",
+    "strings/string16_unittest.cc",
+    "strings/string_number_conversions_unittest.cc",
+    "strings/string_piece_unittest.cc",
+    "strings/string_split_unittest.cc",
+    "strings/string_tokenizer_unittest.cc",
+    "strings/string_util_unittest.cc",
+    "strings/stringize_macros_unittest.cc",
+    "strings/stringprintf_unittest.cc",
+    "strings/sys_string_conversions_mac_unittest.mm",
+    "strings/sys_string_conversions_unittest.cc",
+    "strings/utf_offset_string_conversions_unittest.cc",
+    "strings/utf_string_conversions_unittest.cc",
+    "supports_user_data_unittest.cc",
+    "sync_socket_unittest.cc",
+    "synchronization/cancellation_flag_unittest.cc",
+    "synchronization/condition_variable_unittest.cc",
+    "synchronization/lock_unittest.cc",
+    "synchronization/waitable_event_unittest.cc",
+    "synchronization/waitable_event_watcher_unittest.cc",
+    "sys_info_unittest.cc",
+    "system_monitor/system_monitor_unittest.cc",
+    "task/cancelable_task_tracker_unittest.cc",
+    "task_runner_util_unittest.cc",
+    "template_util_unittest.cc",
+    "test/expectations/expectation_unittest.cc",
+    "test/expectations/parser_unittest.cc",
+    "test/histogram_tester_unittest.cc",
+    "test/test_reg_util_win_unittest.cc",
+    "test/trace_event_analyzer_unittest.cc",
+    "test/user_action_tester_unittest.cc",
+    "threading/non_thread_safe_unittest.cc",
+    "threading/platform_thread_unittest.cc",
+    "threading/sequenced_worker_pool_unittest.cc",
+    "threading/simple_thread_unittest.cc",
+    "threading/thread_checker_unittest.cc",
+    "threading/thread_collision_warner_unittest.cc",
+    "threading/thread_id_name_manager_unittest.cc",
+    "threading/thread_local_storage_unittest.cc",
+    "threading/thread_local_unittest.cc",
+    "threading/thread_unittest.cc",
+    "threading/watchdog_unittest.cc",
+    "threading/worker_pool_posix_unittest.cc",
+    "threading/worker_pool_unittest.cc",
+    "time/pr_time_unittest.cc",
+    "time/time_unittest.cc",
+    "time/time_win_unittest.cc",
+    "timer/hi_res_timer_manager_unittest.cc",
+    "timer/mock_timer_unittest.cc",
+    "timer/timer_unittest.cc",
+    "tools_sanity_unittest.cc",
+    "tracked_objects_unittest.cc",
+    "tuple_unittest.cc",
+    "values_unittest.cc",
+    "version_unittest.cc",
+    "vlog_unittest.cc",
+    "win/dllmain.cc",
+    "win/enum_variant_unittest.cc",
+    "win/event_trace_consumer_unittest.cc",
+    "win/event_trace_controller_unittest.cc",
+    "win/event_trace_provider_unittest.cc",
+    "win/i18n_unittest.cc",
+    "win/iunknown_impl_unittest.cc",
+    "win/message_window_unittest.cc",
+    "win/object_watcher_unittest.cc",
+    "win/pe_image_unittest.cc",
+    "win/registry_unittest.cc",
+    "win/scoped_bstr_unittest.cc",
+    "win/scoped_comptr_unittest.cc",
+    "win/scoped_process_information_unittest.cc",
+    "win/scoped_variant_unittest.cc",
+    "win/shortcut_unittest.cc",
+    "win/startup_information_unittest.cc",
+    "win/win_util_unittest.cc",
+    "win/wrapped_window_proc_unittest.cc",
+  ]
+
+  deps = [
+    ":base",
+    ":i18n",
+    ":message_loop_tests",
+    ":prefs",
+    ":prefs_test_support",
+    "//base/allocator",
+    "//base/test:run_all_unittests",
+    "//base/test:test_support",
+    "//base/third_party/dynamic_annotations",
+    "//base/trace_event:trace_event_unittests",
+    "//testing/gmock",
+    "//testing/gtest",
+    "//third_party/icu",
+  ]
+
+  data = [
+    "test/data/",
+
+    # TODO(dpranke): Remove when icu declares this directly.
+    "$root_out_dir/icudtl.dat",
+  ]
+
+  # Allow more direct string conversions on platforms with native utf8
+  # strings
+  if (is_mac || is_ios || is_chromeos) {
+    defines = [ "SYSTEM_NATIVE_UTF8" ]
+  }
+
+  if (is_android) {
+    apk_deps = [
+      ":base_java",
+      ":base_java_unittest_support",
+    ]
+    isolate_file = "base_unittests.isolate"
+  }
+
+  if (is_ios) {
+    sources -= [
+      "process/memory_unittest.cc",
+      "process/memory_unittest_mac.h",
+      "process/memory_unittest_mac.mm",
+      "process/process_unittest.cc",
+      "process/process_util_unittest.cc",
+    ]
+
+    # Pull in specific Mac files for iOS (which have been filtered out by file
+    # name rules).
+    set_sources_assignment_filter([])
+    sources += [
+      "mac/bind_objc_block_unittest.mm",
+      "mac/foundation_util_unittest.mm",
+      "mac/objc_property_releaser_unittest.mm",
+      "mac/scoped_nsobject_unittest.mm",
+      "sys_string_conversions_mac_unittest.mm",
+    ]
+    set_sources_assignment_filter(sources_assignment_filter)
+
+    # TODO(GYP): dep on copy_test_data_ios action.
+  }
+
+  if (is_linux) {
+    sources -= [ "file_version_info_unittest.cc" ]
+    sources += [ "nix/xdg_util_unittest.cc" ]
+    deps += [ "//base/test:malloc_wrapper" ]
+
+    if (use_glib) {
+      configs += [ "//build/config/linux:glib" ]
+    }
+  }
+
+  if (!is_linux || use_ozone) {
+    sources -= [ "message_loop/message_pump_glib_unittest.cc" ]
+  }
+
+  if (is_posix || is_ios) {
+    sources += [ "message_loop/message_pump_libevent_unittest.cc" ]
+    deps += [ "//third_party/libevent" ]
+  }
+
+  if (is_android) {
+    deps += [ "//testing/android/native_test:native_test_native_code" ]
+    set_sources_assignment_filter([])
+    sources += [ "debug/proc_maps_linux_unittest.cc" ]
+    set_sources_assignment_filter(sources_assignment_filter)
+  }
+
+  # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+  configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
+}
+
+if (is_android) {
+  # GYP: //base.gyp:base_jni_headers
+  generate_jni("base_jni_headers") {
+    sources = [
+      "android/java/src/org/chromium/base/AnimationFrameTimeHistogram.java",
+      "android/java/src/org/chromium/base/ApkAssets.java",
+      "android/java/src/org/chromium/base/ApplicationStatus.java",
+      "android/java/src/org/chromium/base/BuildInfo.java",
+      "android/java/src/org/chromium/base/CommandLine.java",
+      "android/java/src/org/chromium/base/ContentUriUtils.java",
+      "android/java/src/org/chromium/base/CpuFeatures.java",
+      "android/java/src/org/chromium/base/EventLog.java",
+      "android/java/src/org/chromium/base/FieldTrialList.java",
+      "android/java/src/org/chromium/base/ImportantFileWriterAndroid.java",
+      "android/java/src/org/chromium/base/JNIUtils.java",
+      "android/java/src/org/chromium/base/JavaHandlerThread.java",
+      "android/java/src/org/chromium/base/LocaleUtils.java",
+      "android/java/src/org/chromium/base/MemoryPressureListener.java",
+      "android/java/src/org/chromium/base/PathService.java",
+      "android/java/src/org/chromium/base/PathUtils.java",
+      "android/java/src/org/chromium/base/PowerMonitor.java",
+      "android/java/src/org/chromium/base/SysUtils.java",
+      "android/java/src/org/chromium/base/SystemMessageHandler.java",
+      "android/java/src/org/chromium/base/ThreadUtils.java",
+      "android/java/src/org/chromium/base/TraceEvent.java",
+      "android/java/src/org/chromium/base/library_loader/LibraryLoader.java",
+      "android/java/src/org/chromium/base/metrics/RecordHistogram.java",
+      "android/java/src/org/chromium/base/metrics/RecordUserAction.java",
+    ]
+
+    deps = [
+      ":android_runtime_jni_headers",
+    ]
+
+    jni_package = "base"
+  }
+
+  # GYP: //base.gyp:android_runtime_jni_headers
+  generate_jar_jni("android_runtime_jni_headers") {
+    jni_package = "base"
+    classes = [ "java/lang/Runtime.class" ]
+  }
+
+  # GYP: //base.gyp:base_java
+  android_library("base_java") {
+    srcjar_deps = [
+      ":base_android_java_enums_srcjar",
+      ":base_native_libraries_gen",
+    ]
+
+    deps = [
+      "//third_party/jsr-305:jsr_305_javalib",
+    ]
+
+    DEPRECATED_java_in_dir = "android/java/src"
+
+    # A new version of NativeLibraries.java (with the actual correct values)
+    # will be created when creating an apk.
+    jar_excluded_patterns = [
+      "*/NativeLibraries.class",
+      "*/NativeLibraries##*.class",
+    ]
+  }
+
+  # GYP: //base.gyp:base_javatests
+  android_library("base_javatests") {
+    deps = [
+      ":base_java",
+      ":base_java_test_support",
+    ]
+    DEPRECATED_java_in_dir = "android/javatests/src"
+  }
+
+  # GYP: //base.gyp:base_java_test_support
+  android_library("base_java_test_support") {
+    deps = [
+      ":base_java",
+      "//testing/android/reporter:reporter_java",
+    ]
+    DEPRECATED_java_in_dir = "test/android/javatests/src"
+  }
+
+  # GYP: //base.gyp:base_junit_tests
+  junit_binary("base_junit_tests") {
+    java_files = [ "android/junit/src/org/chromium/base/LogTest.java" ]
+    deps = [
+      ":base_java",
+      ":base_java_test_support",
+    ]
+  }
+
+  # GYP: //base.gyp:base_java_application_state
+  # GYP: //base.gyp:base_java_library_load_from_apk_status_codes
+  # GYP: //base.gyp:base_java_library_process_type
+  # GYP: //base.gyp:base_java_memory_pressure_level
+  java_cpp_enum("base_android_java_enums_srcjar") {
+    sources = [
+      "android/application_status_listener.h",
+      "android/library_loader/library_load_from_apk_status_codes.h",
+      "android/library_loader/library_loader_hooks.h",
+      "memory/memory_pressure_listener.h",
+    ]
+    outputs = [
+      "org/chromium/base/ApplicationState.java",
+      "org/chromium/base/library_loader/LibraryLoadFromApkStatusCodes.java",
+      "org/chromium/base/library_loader/LibraryProcessType.java",
+      "org/chromium/base/MemoryPressureLevel.java",
+    ]
+  }
+
+  # GYP: //base/base.gyp:base_native_libraries_gen
+  java_cpp_template("base_native_libraries_gen") {
+    sources = [
+      "android/java/templates/NativeLibraries.template",
+    ]
+    package_name = "org/chromium/base/library_loader"
+  }
+
+  # GYP: //base.gyp:base_java_unittest_support
+  android_library("base_java_unittest_support") {
+    deps = [
+      ":base_java",
+    ]
+    java_files =
+        [ "test/android/java/src/org/chromium/base/ContentUriTestUtils.java" ]
+  }
+}
diff --git a/base/DEPS b/base/DEPS
new file mode 100644
index 0000000..c632e35
--- /dev/null
+++ b/base/DEPS
@@ -0,0 +1,17 @@
+include_rules = [
+  "+jni",
+  "+third_party/ashmem",
+  "+third_party/apple_apsl",
+  "+third_party/libevent",
+  "+third_party/dmg_fp",
+  "+third_party/mach_override",
+  "+third_party/modp_b64",
+  "+third_party/tcmalloc",
+
+  # These are implicitly brought in from the root, and we don't want them.
+  "-ipc",
+  "-url",
+
+  # ICU dependendencies must be separate from the rest of base.
+  "-i18n",
+]
diff --git a/base/OWNERS b/base/OWNERS
new file mode 100644
index 0000000..9890491
--- /dev/null
+++ b/base/OWNERS
@@ -0,0 +1,31 @@
+mark@chromium.org
+darin@chromium.org
+thakis@chromium.org
+danakj@chromium.org
+rvargas@chromium.org
+thestig@chromium.org
+
+# On extended leave.
+willchan@chromium.org
+
+# Chromium is a very mature project, most things that are generally useful are
+# already here, and that things not here aren't generally useful.
+#
+# Base is pulled into many projects. For example, various ChromeOS daemons. So
+# the bar for adding stuff is that it must have demonstrated wide
+# applicability. Prefer to add things closer to where they're used (i.e. "not
+# base"), and pull into base only when needed.  In a project our size,
+# sometimes even duplication is OK and inevitable.
+#
+# Adding a new logging macro DPVELOG_NE is not more clear than just
+# writing the stuff you want to log in a regular logging statement, even
+# if it makes your calling code longer. Just add it to your own code.
+
+per-file *.isolate=csharp@chromium.org
+per-file *.isolate=maruel@chromium.org
+per-file security_unittest.cc=jln@chromium.org
+
+# For Android-specific changes:
+per-file *android*=nyquist@chromium.org
+per-file *android*=rmcilroy@chromium.org
+per-file *android*=yfriedman@chromium.org
diff --git a/base/PRESUBMIT.py b/base/PRESUBMIT.py
new file mode 100644
index 0000000..7fc8107
--- /dev/null
+++ b/base/PRESUBMIT.py
@@ -0,0 +1,49 @@
+# Copyright (c) 2012 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.
+
+"""Chromium presubmit script for src/base.
+
+See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
+for more details on the presubmit API built into depot_tools.
+"""
+
+def _CheckNoInterfacesInBase(input_api, output_api):
+  """Checks to make sure no files in libbase.a have |@interface|."""
+  pattern = input_api.re.compile(r'^\s*@interface', input_api.re.MULTILINE)
+  files = []
+  for f in input_api.AffectedSourceFiles(input_api.FilterSourceFile):
+    if (f.LocalPath().startswith('base/') and
+        not "/ios/" in f.LocalPath() and
+        not "/test/" in f.LocalPath() and
+        not f.LocalPath().endswith('_unittest.mm') and
+        not f.LocalPath().endswith('mac/sdk_forward_declarations.h')):
+      contents = input_api.ReadFile(f)
+      if pattern.search(contents):
+        files.append(f)
+
+  if len(files):
+    return [ output_api.PresubmitError(
+        'Objective-C interfaces or categories are forbidden in libbase. ' +
+        'See http://groups.google.com/a/chromium.org/group/chromium-dev/' +
+        'browse_thread/thread/efb28c10435987fd',
+        files) ]
+  return []
+
+
+def _CommonChecks(input_api, output_api):
+  """Checks common to both upload and commit."""
+  results = []
+  results.extend(_CheckNoInterfacesInBase(input_api, output_api))
+  return results
+
+def CheckChangeOnUpload(input_api, output_api):
+  results = []
+  results.extend(_CommonChecks(input_api, output_api))
+  return results
+
+
+def CheckChangeOnCommit(input_api, output_api):
+  results = []
+  results.extend(_CommonChecks(input_api, output_api))
+  return results
diff --git a/base/allocator/BUILD.gn b/base/allocator/BUILD.gn
new file mode 100644
index 0000000..a07a356
--- /dev/null
+++ b/base/allocator/BUILD.gn
@@ -0,0 +1,259 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/allocator.gni")
+
+# Only executables and not libraries should depend on the allocator target;
+# only the application (the final executable) knows what allocator makes sense.
+# This "allocator" meta-target will forward to the default allocator according
+# to the build settings.
+group("allocator") {
+  if (use_allocator == "tcmalloc") {
+    deps = [
+      ":tcmalloc",
+    ]
+  }
+}
+
+# This config and libc modification are only used on Windows.
+if (is_win) {
+  import("//build/config/win/visual_studio_version.gni")
+
+  config("nocmt") {
+    ldflags = [
+      "/NODEFAULTLIB:libcmt",
+      "/NODEFAULTLIB:libcmtd",
+    ]
+    libs = [ rebase_path("$target_gen_dir/allocator/libcmt.lib") ]
+  }
+
+  action("prep_libc") {
+    script = "prep_libc.py"
+    outputs = [
+      "$target_gen_dir/allocator/libcmt.lib",
+    ]
+    args = [
+      visual_studio_path + "/vc/lib",
+      rebase_path("$target_gen_dir/allocator"),
+      current_cpu,
+    ]
+  }
+}
+
+if (use_allocator == "tcmalloc") {
+  # tcmalloc currently won't compile on Android.
+  source_set("tcmalloc") {
+    tcmalloc_dir = "//third_party/tcmalloc/chromium"
+
+    # Don't check tcmalloc's includes. These files include various files like
+    # base/foo.h and they actually refer to tcmalloc's forked copy of base
+    # rather than the regular one, which confuses the header checker.
+    check_includes = false
+
+    sources = [
+      # Generated for our configuration from tcmalloc"s build
+      # and checked in.
+      "$tcmalloc_dir/src/config.h",
+      "$tcmalloc_dir/src/config_android.h",
+      "$tcmalloc_dir/src/config_linux.h",
+      "$tcmalloc_dir/src/config_win.h",
+
+      # tcmalloc native and forked files.
+      "$tcmalloc_dir/src/base/abort.cc",
+      "$tcmalloc_dir/src/base/abort.h",
+      "$tcmalloc_dir/src/base/arm_instruction_set_select.h",
+
+      # We don't list dynamic_annotations.c since its copy is already
+      # present in the dynamic_annotations target.
+      "$tcmalloc_dir/src/base/elf_mem_image.cc",
+      "$tcmalloc_dir/src/base/elf_mem_image.h",
+      "$tcmalloc_dir/src/base/linuxthreads.cc",
+      "$tcmalloc_dir/src/base/linuxthreads.h",
+      "$tcmalloc_dir/src/base/logging.cc",
+      "$tcmalloc_dir/src/base/logging.h",
+      "$tcmalloc_dir/src/base/low_level_alloc.cc",
+      "$tcmalloc_dir/src/base/low_level_alloc.h",
+      "$tcmalloc_dir/src/base/spinlock.cc",
+      "$tcmalloc_dir/src/base/spinlock.h",
+      "$tcmalloc_dir/src/base/spinlock_internal.cc",
+      "$tcmalloc_dir/src/base/spinlock_internal.h",
+      "$tcmalloc_dir/src/base/synchronization_profiling.h",
+      "$tcmalloc_dir/src/base/sysinfo.cc",
+      "$tcmalloc_dir/src/base/sysinfo.h",
+      "$tcmalloc_dir/src/base/thread_lister.c",
+      "$tcmalloc_dir/src/base/thread_lister.h",
+      "$tcmalloc_dir/src/base/vdso_support.cc",
+      "$tcmalloc_dir/src/base/vdso_support.h",
+      "$tcmalloc_dir/src/central_freelist.cc",
+      "$tcmalloc_dir/src/central_freelist.h",
+      "$tcmalloc_dir/src/common.cc",
+      "$tcmalloc_dir/src/common.h",
+
+      # #included by debugallocation_shim.cc
+      #"$tcmalloc_dir/src/debugallocation.cc",
+      "$tcmalloc_dir/src/deep-heap-profile.cc",
+      "$tcmalloc_dir/src/deep-heap-profile.h",
+      "$tcmalloc_dir/src/free_list.cc",
+      "$tcmalloc_dir/src/free_list.h",
+      "$tcmalloc_dir/src/heap-profile-table.cc",
+      "$tcmalloc_dir/src/heap-profile-table.h",
+      "$tcmalloc_dir/src/heap-profiler.cc",
+      "$tcmalloc_dir/src/internal_logging.cc",
+      "$tcmalloc_dir/src/internal_logging.h",
+      "$tcmalloc_dir/src/linked_list.h",
+      "$tcmalloc_dir/src/malloc_extension.cc",
+      "$tcmalloc_dir/src/malloc_hook-inl.h",
+      "$tcmalloc_dir/src/malloc_hook.cc",
+      "$tcmalloc_dir/src/maybe_threads.cc",
+      "$tcmalloc_dir/src/maybe_threads.h",
+      "$tcmalloc_dir/src/memory_region_map.cc",
+      "$tcmalloc_dir/src/memory_region_map.h",
+      "$tcmalloc_dir/src/page_heap.cc",
+      "$tcmalloc_dir/src/page_heap.h",
+      "$tcmalloc_dir/src/profile-handler.cc",
+      "$tcmalloc_dir/src/profile-handler.h",
+      "$tcmalloc_dir/src/profiledata.cc",
+      "$tcmalloc_dir/src/profiledata.h",
+      "$tcmalloc_dir/src/profiler.cc",
+      "$tcmalloc_dir/src/raw_printer.cc",
+      "$tcmalloc_dir/src/raw_printer.h",
+      "$tcmalloc_dir/src/sampler.cc",
+      "$tcmalloc_dir/src/sampler.h",
+      "$tcmalloc_dir/src/span.cc",
+      "$tcmalloc_dir/src/span.h",
+      "$tcmalloc_dir/src/stack_trace_table.cc",
+      "$tcmalloc_dir/src/stack_trace_table.h",
+      "$tcmalloc_dir/src/stacktrace.cc",
+      "$tcmalloc_dir/src/static_vars.cc",
+      "$tcmalloc_dir/src/static_vars.h",
+      "$tcmalloc_dir/src/symbolize.cc",
+      "$tcmalloc_dir/src/symbolize.h",
+      "$tcmalloc_dir/src/system-alloc.cc",
+      "$tcmalloc_dir/src/system-alloc.h",
+
+      # #included by debugallocation_shim.cc
+      #"$tcmalloc_dir/src/tcmalloc.cc",
+      "$tcmalloc_dir/src/thread_cache.cc",
+      "$tcmalloc_dir/src/thread_cache.h",
+      "$tcmalloc_dir/src/windows/port.cc",
+      "$tcmalloc_dir/src/windows/port.h",
+      "allocator_shim.cc",
+      "debugallocation_shim.cc",
+
+      # These are both #included by allocator_shim for maximal linking.
+      #"generic_allocators.cc",
+      #"win_allocator.cc",
+    ]
+
+    # Disable the heap checker in tcmalloc.
+    defines = [ "NO_HEAP_CHECK" ]
+
+    include_dirs = [
+      ".",
+      "$tcmalloc_dir/src/base",
+      "$tcmalloc_dir/src",
+    ]
+
+    configs -= [ "//build/config/compiler:chromium_code" ]
+    configs += [ "//build/config/compiler:no_chromium_code" ]
+
+    deps = []
+
+    if (is_win) {
+      sources -= [
+        "$tcmalloc_dir/src/base/elf_mem_image.cc",
+        "$tcmalloc_dir/src/base/elf_mem_image.h",
+        "$tcmalloc_dir/src/base/linuxthreads.cc",
+        "$tcmalloc_dir/src/base/linuxthreads.h",
+        "$tcmalloc_dir/src/base/vdso_support.cc",
+        "$tcmalloc_dir/src/base/vdso_support.h",
+        "$tcmalloc_dir/src/maybe_threads.cc",
+        "$tcmalloc_dir/src/maybe_threads.h",
+        "$tcmalloc_dir/src/symbolize.h",
+        "$tcmalloc_dir/src/system-alloc.cc",
+        "$tcmalloc_dir/src/system-alloc.h",
+
+        # included by allocator_shim.cc
+        "debugallocation_shim.cc",
+
+        # cpuprofiler
+        "$tcmalloc_dir/src/base/thread_lister.c",
+        "$tcmalloc_dir/src/base/thread_lister.h",
+        "$tcmalloc_dir/src/profile-handler.cc",
+        "$tcmalloc_dir/src/profile-handler.h",
+        "$tcmalloc_dir/src/profiledata.cc",
+        "$tcmalloc_dir/src/profiledata.h",
+        "$tcmalloc_dir/src/profiler.cc",
+      ]
+      defines += [ "PERFTOOLS_DLL_DECL=" ]
+
+      configs -= [
+        # Tcmalloc defines this itself, and we don't want duplicate definition
+        # warnings.
+        "//build/config/win:nominmax",
+      ]
+
+      public_configs = [ ":nocmt" ]
+
+      deps += [ ":prep_libc" ]
+    }
+
+    if (is_linux || is_android) {
+      sources -= [
+        "$tcmalloc_dir/src/system-alloc.h",
+        "$tcmalloc_dir/src/windows/port.cc",
+        "$tcmalloc_dir/src/windows/port.h",
+
+        # TODO(willchan): Support allocator shim later on.
+        "allocator_shim.cc",
+      ]
+
+      # We enable all warnings by default, but upstream disables a few.
+      # Keep "-Wno-*" flags in sync with upstream by comparing against:
+      # http://code.google.com/p/google-perftools/source/browse/trunk/Makefile.am
+      cflags = [
+        "-Wno-sign-compare",
+        "-Wno-unused-result",
+      ]
+
+      configs -= [ "//build/config/gcc:symbol_visibility_hidden" ]
+
+      ldflags = [
+        # Don't let linker rip this symbol out, otherwise the heap&cpu
+        # profilers will not initialize properly on startup.
+        "-Wl,-uIsHeapProfilerRunning,-uProfilerStart",
+
+        # Do the same for heap leak checker.
+        "-Wl,-u_Z21InitialMallocHook_NewPKvj,-u_Z22InitialMallocHook_MMapPKvS0_jiiix,-u_Z22InitialMallocHook_SbrkPKvi",
+        "-Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl",
+        "-Wl,-u_ZN15HeapLeakChecker12IgnoreObjectEPKv,-u_ZN15HeapLeakChecker14UnIgnoreObjectEPKv",
+      ]
+    }
+
+    # Make sure the allocation library is optimized as much as possible when
+    # we"re in release mode.
+    if (!is_debug) {
+      configs -= [ "//build/config/compiler:optimize" ]
+      configs += [ "//build/config/compiler:optimize_max" ]
+    }
+
+    deps += [ "//base/third_party/dynamic_annotations" ]
+
+    if (is_win) {
+      ldflags = [ "/ignore:4006:4221" ]
+    }
+  }
+}  # !is_android
+
+source_set("allocator_extension_thunks") {
+  visibility = [ "//base/*" ]
+  sources = [
+    "allocator_extension_thunks.cc",
+    "allocator_extension_thunks.h",
+  ]
+  if (is_android && !is_debug) {
+    configs -= [ "//build/config/compiler:optimize" ]
+    configs += [ "//build/config/compiler:optimize_max" ]
+  }
+}
diff --git a/base/allocator/OWNERS b/base/allocator/OWNERS
new file mode 100644
index 0000000..5d9997b
--- /dev/null
+++ b/base/allocator/OWNERS
@@ -0,0 +1,4 @@
+wfh@chromium.org
+
+# For changes to tcmalloc it is advisable to ask jar@chromium.org
+# before proceeding.
diff --git a/base/allocator/README b/base/allocator/README
new file mode 100644
index 0000000..ec8a707
--- /dev/null
+++ b/base/allocator/README
@@ -0,0 +1,59 @@
+Notes about the Chrome memory allocator.
+
+Background
+----------
+We use this library as a generic way to fork into any of several allocators.
+Currently we can, at runtime, switch between:
+   the default windows allocator
+   the windows low-fragmentation-heap
+   tcmalloc
+   jemalloc (the heap used most notably within Mozilla Firefox)
+
+The mechanism for hooking LIBCMT in windows is rather tricky.  The core
+problem is that by default, the windows library does not declare malloc and
+free as weak symbols.  Because of this, they cannot be overriden.  To work
+around this, we start with the LIBCMT.LIB, and manually remove all allocator
+related functions from it using the visual studio library tool.  Once removed,
+we can now link against the library and provide custom versions of the 
+allocator related functionality.
+
+
+Source code
+-----------
+This directory contains just the allocator (i.e. shim) layer that switches
+between the different underlying memory allocation implementations.
+
+The tcmalloc and jemalloc libraries originate outside of Chromium
+and exist in ../../third_party/tcmalloc and ../../third_party/jemalloc
+(currently, the actual locations are defined in the allocator.gyp file).
+The third party sources use a vendor-branch SCM pattern to track
+Chromium-specific changes independently from upstream changes.
+
+The general intent is to push local changes upstream so that over
+time we no longer need any forked files.
+
+
+Adding a new allocator
+----------------------
+Adding a new allocator requires definition of the following five functions:
+
+  extern "C" {
+    bool init();
+    void* malloc(size_t s);
+    void* realloc(void* p, size_t s);
+    void free(void* s);
+    size_t msize(void* p);
+  }
+
+All other allocation related functions (new/delete/calloc/etc) have been
+implemented generically to work across all allocators.
+
+
+Usage
+-----
+You can use the different allocators by setting the environment variable
+CHROME_ALLOCATOR to:
+   "tcmalloc"  - TC Malloc (default)
+   "jemalloc"  - JE Malloc
+   "winheap"   - Windows default heap
+   "winlfh"    - Windows Low-Fragmentation heap
diff --git a/base/allocator/allocator.gyp b/base/allocator/allocator.gyp
new file mode 100644
index 0000000..d426c9c
--- /dev/null
+++ b/base/allocator/allocator.gyp
@@ -0,0 +1,572 @@
+# Copyright (c) 2012 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.
+
+{
+  'target_defaults': {
+    'variables': {
+      # This code gets run a lot and debugged rarely, so it should be fast
+      # by default. See http://crbug.com/388949.
+      'debug_optimize': '2',
+      'win_debug_Optimization': '0',
+      # Run time checks are incompatible with any level of optimizations.
+      'win_debug_RuntimeChecks': '0',
+    },
+  },
+  'variables': {
+    'tcmalloc_dir': '../../third_party/tcmalloc/chromium',
+    'use_vtable_verify%': 0,
+  },
+  'targets': [
+    # Only executables and not libraries should depend on the
+    # allocator target; only the application (the final executable)
+    # knows what allocator makes sense.
+    {
+      'target_name': 'allocator',
+      'type': 'static_library',
+      'direct_dependent_settings': {
+        'configurations': {
+          'Common_Base': {
+            'msvs_settings': {
+              'VCLinkerTool': {
+                'IgnoreDefaultLibraryNames': ['libcmtd.lib', 'libcmt.lib'],
+                'AdditionalDependencies': [
+                  '<(SHARED_INTERMEDIATE_DIR)/allocator/libcmt.lib'
+                ],
+              },
+            },
+          },
+        },
+        'conditions': [
+          ['OS=="win"', {
+            'defines': [
+              'PERFTOOLS_DLL_DECL=',
+            ],
+          }],
+        ],
+      },
+      'dependencies': [
+        '../third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+      ],
+      'msvs_settings': {
+        # TODO(sgk):  merge this with build/common.gypi settings
+        'VCLibrarianTool': {
+          'AdditionalOptions': ['/ignore:4006,4221'],
+        },
+        'VCLinkerTool': {
+          'AdditionalOptions': ['/ignore:4006'],
+        },
+      },
+      'configurations': {
+        'Debug_Base': {
+          'msvs_settings': {
+            'VCCLCompilerTool': {
+              'RuntimeLibrary': '0',
+            },
+          },
+          'variables': {
+            # Provide a way to force disable debugallocation in Debug builds,
+            # e.g. for profiling (it's more rare to profile Debug builds,
+            # but people sometimes need to do that).
+            'disable_debugallocation%': 0,
+          },
+          'conditions': [
+            ['disable_debugallocation==0', {
+              'defines': [
+                # Use debugallocation for Debug builds to catch problems early
+                # and cleanly, http://crbug.com/30715 .
+                'TCMALLOC_FOR_DEBUGALLOCATION',
+              ],
+            }],
+          ],
+        },
+      },
+      'conditions': [
+        ['use_allocator=="tcmalloc"', {
+          # Disable the heap checker in tcmalloc.
+          'defines': [
+            'NO_HEAP_CHECK',
+          ],
+          'include_dirs': [
+            '.',
+            '<(tcmalloc_dir)/src/base',
+            '<(tcmalloc_dir)/src',
+            '../..',
+          ],
+          'sources': [
+            # Generated for our configuration from tcmalloc's build
+            # and checked in.
+            '<(tcmalloc_dir)/src/config.h',
+            '<(tcmalloc_dir)/src/config_android.h',
+            '<(tcmalloc_dir)/src/config_linux.h',
+            '<(tcmalloc_dir)/src/config_win.h',
+
+            # all tcmalloc native and forked files
+            '<(tcmalloc_dir)/src/addressmap-inl.h',
+            '<(tcmalloc_dir)/src/base/abort.cc',
+            '<(tcmalloc_dir)/src/base/abort.h',
+            '<(tcmalloc_dir)/src/base/arm_instruction_set_select.h',
+            '<(tcmalloc_dir)/src/base/atomicops-internals-arm-generic.h',
+            '<(tcmalloc_dir)/src/base/atomicops-internals-arm-v6plus.h',
+            '<(tcmalloc_dir)/src/base/atomicops-internals-linuxppc.h',
+            '<(tcmalloc_dir)/src/base/atomicops-internals-macosx.h',
+            '<(tcmalloc_dir)/src/base/atomicops-internals-windows.h',
+            '<(tcmalloc_dir)/src/base/atomicops-internals-x86.cc',
+            '<(tcmalloc_dir)/src/base/atomicops-internals-x86.h',
+            '<(tcmalloc_dir)/src/base/atomicops.h',
+            '<(tcmalloc_dir)/src/base/basictypes.h',
+            '<(tcmalloc_dir)/src/base/commandlineflags.h',
+            '<(tcmalloc_dir)/src/base/cycleclock.h',
+            # We don't list dynamic_annotations.c since its copy is already
+            # present in the dynamic_annotations target.
+            '<(tcmalloc_dir)/src/base/dynamic_annotations.h',
+            '<(tcmalloc_dir)/src/base/elf_mem_image.cc',
+            '<(tcmalloc_dir)/src/base/elf_mem_image.h',
+            '<(tcmalloc_dir)/src/base/elfcore.h',
+            '<(tcmalloc_dir)/src/base/googleinit.h',
+            '<(tcmalloc_dir)/src/base/linux_syscall_support.h',
+            '<(tcmalloc_dir)/src/base/linuxthreads.cc',
+            '<(tcmalloc_dir)/src/base/linuxthreads.h',
+            '<(tcmalloc_dir)/src/base/logging.cc',
+            '<(tcmalloc_dir)/src/base/logging.h',
+            '<(tcmalloc_dir)/src/base/low_level_alloc.cc',
+            '<(tcmalloc_dir)/src/base/low_level_alloc.h',
+            '<(tcmalloc_dir)/src/base/simple_mutex.h',
+            '<(tcmalloc_dir)/src/base/spinlock.cc',
+            '<(tcmalloc_dir)/src/base/spinlock.h',
+            '<(tcmalloc_dir)/src/base/spinlock_internal.cc',
+            '<(tcmalloc_dir)/src/base/spinlock_internal.h',
+            '<(tcmalloc_dir)/src/base/spinlock_linux-inl.h',
+            '<(tcmalloc_dir)/src/base/spinlock_posix-inl.h',
+            '<(tcmalloc_dir)/src/base/spinlock_win32-inl.h',
+            '<(tcmalloc_dir)/src/base/stl_allocator.h',
+            '<(tcmalloc_dir)/src/base/synchronization_profiling.h',
+            '<(tcmalloc_dir)/src/base/sysinfo.cc',
+            '<(tcmalloc_dir)/src/base/sysinfo.h',
+            '<(tcmalloc_dir)/src/base/thread_annotations.h',
+            '<(tcmalloc_dir)/src/base/thread_lister.c',
+            '<(tcmalloc_dir)/src/base/thread_lister.h',
+            '<(tcmalloc_dir)/src/base/vdso_support.cc',
+            '<(tcmalloc_dir)/src/base/vdso_support.h',
+            '<(tcmalloc_dir)/src/central_freelist.cc',
+            '<(tcmalloc_dir)/src/central_freelist.h',
+            '<(tcmalloc_dir)/src/common.cc',
+            '<(tcmalloc_dir)/src/common.h',
+            '<(tcmalloc_dir)/src/debugallocation.cc',
+            '<(tcmalloc_dir)/src/deep-heap-profile.cc',
+            '<(tcmalloc_dir)/src/deep-heap-profile.h',
+            '<(tcmalloc_dir)/src/free_list.cc',
+            '<(tcmalloc_dir)/src/free_list.h',
+            '<(tcmalloc_dir)/src/getpc.h',
+            '<(tcmalloc_dir)/src/gperftools/heap-checker.h',
+            '<(tcmalloc_dir)/src/gperftools/heap-profiler.h',
+            '<(tcmalloc_dir)/src/gperftools/malloc_extension.h',
+            '<(tcmalloc_dir)/src/gperftools/malloc_extension_c.h',
+            '<(tcmalloc_dir)/src/gperftools/malloc_hook.h',
+            '<(tcmalloc_dir)/src/gperftools/malloc_hook_c.h',
+            '<(tcmalloc_dir)/src/gperftools/profiler.h',
+            '<(tcmalloc_dir)/src/gperftools/stacktrace.h',
+            '<(tcmalloc_dir)/src/gperftools/tcmalloc.h',
+            '<(tcmalloc_dir)/src/heap-checker-bcad.cc',
+            '<(tcmalloc_dir)/src/heap-checker.cc',
+            '<(tcmalloc_dir)/src/heap-profile-table.cc',
+            '<(tcmalloc_dir)/src/heap-profile-table.h',
+            '<(tcmalloc_dir)/src/heap-profiler.cc',
+            '<(tcmalloc_dir)/src/internal_logging.cc',
+            '<(tcmalloc_dir)/src/internal_logging.h',
+            '<(tcmalloc_dir)/src/libc_override.h',
+            '<(tcmalloc_dir)/src/libc_override_gcc_and_weak.h',
+            '<(tcmalloc_dir)/src/libc_override_glibc.h',
+            '<(tcmalloc_dir)/src/libc_override_osx.h',
+            '<(tcmalloc_dir)/src/libc_override_redefine.h',
+            '<(tcmalloc_dir)/src/linked_list.h',
+            '<(tcmalloc_dir)/src/malloc_extension.cc',
+            '<(tcmalloc_dir)/src/malloc_hook-inl.h',
+            '<(tcmalloc_dir)/src/malloc_hook.cc',
+            '<(tcmalloc_dir)/src/malloc_hook_mmap_freebsd.h',
+            '<(tcmalloc_dir)/src/malloc_hook_mmap_linux.h',
+            '<(tcmalloc_dir)/src/maybe_threads.cc',
+            '<(tcmalloc_dir)/src/maybe_threads.h',
+            '<(tcmalloc_dir)/src/memfs_malloc.cc',
+            '<(tcmalloc_dir)/src/memory_region_map.cc',
+            '<(tcmalloc_dir)/src/memory_region_map.h',
+            '<(tcmalloc_dir)/src/packed-cache-inl.h',
+            '<(tcmalloc_dir)/src/page_heap.cc',
+            '<(tcmalloc_dir)/src/page_heap.h',
+            '<(tcmalloc_dir)/src/page_heap_allocator.h',
+            '<(tcmalloc_dir)/src/pagemap.h',
+            '<(tcmalloc_dir)/src/profile-handler.cc',
+            '<(tcmalloc_dir)/src/profile-handler.h',
+            '<(tcmalloc_dir)/src/profiledata.cc',
+            '<(tcmalloc_dir)/src/profiledata.h',
+            '<(tcmalloc_dir)/src/profiler.cc',
+            '<(tcmalloc_dir)/src/raw_printer.cc',
+            '<(tcmalloc_dir)/src/raw_printer.h',
+            '<(tcmalloc_dir)/src/sampler.cc',
+            '<(tcmalloc_dir)/src/sampler.h',
+            '<(tcmalloc_dir)/src/span.cc',
+            '<(tcmalloc_dir)/src/span.h',
+            '<(tcmalloc_dir)/src/stack_trace_table.cc',
+            '<(tcmalloc_dir)/src/stack_trace_table.h',
+            '<(tcmalloc_dir)/src/stacktrace.cc',
+            '<(tcmalloc_dir)/src/stacktrace_arm-inl.h',
+            '<(tcmalloc_dir)/src/stacktrace_config.h',
+            '<(tcmalloc_dir)/src/stacktrace_generic-inl.h',
+            '<(tcmalloc_dir)/src/stacktrace_libunwind-inl.h',
+            '<(tcmalloc_dir)/src/stacktrace_powerpc-inl.h',
+            '<(tcmalloc_dir)/src/stacktrace_win32-inl.h',
+            '<(tcmalloc_dir)/src/stacktrace_with_context.cc',
+            '<(tcmalloc_dir)/src/stacktrace_x86-inl.h',
+            '<(tcmalloc_dir)/src/static_vars.cc',
+            '<(tcmalloc_dir)/src/static_vars.h',
+            '<(tcmalloc_dir)/src/symbolize.cc',
+            '<(tcmalloc_dir)/src/symbolize.h',
+            '<(tcmalloc_dir)/src/system-alloc.cc',
+            '<(tcmalloc_dir)/src/system-alloc.h',
+            '<(tcmalloc_dir)/src/tcmalloc.cc',
+            '<(tcmalloc_dir)/src/tcmalloc_guard.h',
+            '<(tcmalloc_dir)/src/thread_cache.cc',
+            '<(tcmalloc_dir)/src/thread_cache.h',
+
+            'debugallocation_shim.cc',
+          ],
+          # sources! means that these are not compiled directly.
+          'sources!': [
+            # We simply don't use these, but list them above so that IDE
+            # users can view the full available source for reference, etc.
+            '<(tcmalloc_dir)/src/addressmap-inl.h',
+            '<(tcmalloc_dir)/src/base/atomicops-internals-linuxppc.h',
+            '<(tcmalloc_dir)/src/base/atomicops-internals-macosx.h',
+            '<(tcmalloc_dir)/src/base/atomicops-internals-x86-msvc.h',
+            '<(tcmalloc_dir)/src/base/atomicops-internals-x86.h',
+            '<(tcmalloc_dir)/src/base/atomicops.h',
+            '<(tcmalloc_dir)/src/base/basictypes.h',
+            '<(tcmalloc_dir)/src/base/commandlineflags.h',
+            '<(tcmalloc_dir)/src/base/cycleclock.h',
+            '<(tcmalloc_dir)/src/base/elf_mem_image.h',
+            '<(tcmalloc_dir)/src/base/elfcore.h',
+            '<(tcmalloc_dir)/src/base/googleinit.h',
+            '<(tcmalloc_dir)/src/base/linux_syscall_support.h',
+            '<(tcmalloc_dir)/src/base/simple_mutex.h',
+            '<(tcmalloc_dir)/src/base/spinlock_linux-inl.h',
+            '<(tcmalloc_dir)/src/base/spinlock_posix-inl.h',
+            '<(tcmalloc_dir)/src/base/spinlock_win32-inl.h',
+            '<(tcmalloc_dir)/src/base/stl_allocator.h',
+            '<(tcmalloc_dir)/src/base/thread_annotations.h',
+            '<(tcmalloc_dir)/src/getpc.h',
+            '<(tcmalloc_dir)/src/gperftools/heap-checker.h',
+            '<(tcmalloc_dir)/src/gperftools/heap-profiler.h',
+            '<(tcmalloc_dir)/src/gperftools/malloc_extension.h',
+            '<(tcmalloc_dir)/src/gperftools/malloc_extension_c.h',
+            '<(tcmalloc_dir)/src/gperftools/malloc_hook.h',
+            '<(tcmalloc_dir)/src/gperftools/malloc_hook_c.h',
+            '<(tcmalloc_dir)/src/gperftools/profiler.h',
+            '<(tcmalloc_dir)/src/gperftools/stacktrace.h',
+            '<(tcmalloc_dir)/src/gperftools/tcmalloc.h',
+            '<(tcmalloc_dir)/src/heap-checker-bcad.cc',
+            '<(tcmalloc_dir)/src/heap-checker.cc',
+            '<(tcmalloc_dir)/src/libc_override.h',
+            '<(tcmalloc_dir)/src/libc_override_gcc_and_weak.h',
+            '<(tcmalloc_dir)/src/libc_override_glibc.h',
+            '<(tcmalloc_dir)/src/libc_override_osx.h',
+            '<(tcmalloc_dir)/src/libc_override_redefine.h',
+            '<(tcmalloc_dir)/src/malloc_hook_mmap_freebsd.h',
+            '<(tcmalloc_dir)/src/malloc_hook_mmap_linux.h',
+            '<(tcmalloc_dir)/src/memfs_malloc.cc',
+            '<(tcmalloc_dir)/src/packed-cache-inl.h',
+            '<(tcmalloc_dir)/src/page_heap_allocator.h',
+            '<(tcmalloc_dir)/src/pagemap.h',
+            '<(tcmalloc_dir)/src/stacktrace_arm-inl.h',
+            '<(tcmalloc_dir)/src/stacktrace_config.h',
+            '<(tcmalloc_dir)/src/stacktrace_generic-inl.h',
+            '<(tcmalloc_dir)/src/stacktrace_libunwind-inl.h',
+            '<(tcmalloc_dir)/src/stacktrace_powerpc-inl.h',
+            '<(tcmalloc_dir)/src/stacktrace_win32-inl.h',
+            '<(tcmalloc_dir)/src/stacktrace_with_context.cc',
+            '<(tcmalloc_dir)/src/stacktrace_x86-inl.h',
+            '<(tcmalloc_dir)/src/tcmalloc_guard.h',
+
+            # Included by debugallocation_shim.cc.
+            '<(tcmalloc_dir)/src/debugallocation.cc',
+            '<(tcmalloc_dir)/src/tcmalloc.cc',
+          ]
+        },{
+          'include_dirs': [
+            '.',
+            '../..',
+          ],
+        }],
+        ['OS=="linux" and clang_type_profiler==1', {
+          'dependencies': [
+            'type_profiler_tcmalloc',
+          ],
+          # It is undoing dependencies and cflags_cc for type_profiler which
+          # build/common.gypi injects into all targets.
+          'dependencies!': [
+            'type_profiler',
+          ],
+          'cflags_cc!': [
+            '-fintercept-allocation-functions',
+          ],
+        }],
+        ['OS=="win"', {
+          'dependencies': [
+            'libcmt',
+          ],
+          'sources': [
+            'allocator_shim_win.cc',
+          ],
+        }],
+        ['profiling!=1', {
+          'sources!': [
+            # cpuprofiler
+            '<(tcmalloc_dir)/src/base/thread_lister.c',
+            '<(tcmalloc_dir)/src/base/thread_lister.h',
+            '<(tcmalloc_dir)/src/profile-handler.cc',
+            '<(tcmalloc_dir)/src/profile-handler.h',
+            '<(tcmalloc_dir)/src/profiledata.cc',
+            '<(tcmalloc_dir)/src/profiledata.h',
+            '<(tcmalloc_dir)/src/profiler.cc',
+          ],
+        }],
+        ['OS=="linux" or OS=="freebsd" or OS=="solaris" or OS=="android"', {
+          'sources!': [
+            '<(tcmalloc_dir)/src/system-alloc.h',
+          ],
+          # We enable all warnings by default, but upstream disables a few.
+          # Keep "-Wno-*" flags in sync with upstream by comparing against:
+          # http://code.google.com/p/google-perftools/source/browse/trunk/Makefile.am
+          'cflags': [
+            '-Wno-sign-compare',
+            '-Wno-unused-result',
+          ],
+          'cflags!': [
+            '-fvisibility=hidden',
+          ],
+          'link_settings': {
+            'ldflags': [
+              # Don't let linker rip this symbol out, otherwise the heap&cpu
+              # profilers will not initialize properly on startup.
+              '-Wl,-uIsHeapProfilerRunning,-uProfilerStart',
+              # Do the same for heap leak checker.
+              '-Wl,-u_Z21InitialMallocHook_NewPKvj,-u_Z22InitialMallocHook_MMapPKvS0_jiiix,-u_Z22InitialMallocHook_SbrkPKvi',
+              '-Wl,-u_Z21InitialMallocHook_NewPKvm,-u_Z22InitialMallocHook_MMapPKvS0_miiil,-u_Z22InitialMallocHook_SbrkPKvl',
+              '-Wl,-u_ZN15HeapLeakChecker12IgnoreObjectEPKv,-u_ZN15HeapLeakChecker14UnIgnoreObjectEPKv',
+          ]},
+        }],
+        [ 'use_vtable_verify==1', {
+          'cflags': [
+            '-fvtable-verify=preinit',
+          ],
+        }],
+        ['order_profiling != 0', {
+          'target_conditions' : [
+            ['_toolset=="target"', {
+              'cflags!': [ '-finstrument-functions' ],
+            }],
+          ],
+        }],
+      ],
+    },
+    {
+      # This library is linked in to src/base.gypi:base and allocator_unittests
+      # It can't depend on either and nothing else should depend on it - all
+      # other code should use the interfaced provided by base.
+      'target_name': 'allocator_extension_thunks',
+      'type': 'static_library',
+      'sources': [
+        'allocator_extension_thunks.cc',
+        'allocator_extension_thunks.h',
+      ],
+      'toolsets': ['host', 'target'],
+      'include_dirs': [
+        '../../'
+      ],
+      'conditions': [
+        ['OS=="linux" and clang_type_profiler==1', {
+          # It is undoing dependencies and cflags_cc for type_profiler which
+          # build/common.gypi injects into all targets.
+          'dependencies!': [
+            'type_profiler',
+          ],
+          'cflags_cc!': [
+            '-fintercept-allocation-functions',
+          ],
+        }],
+      ],
+    },
+   ],
+  'conditions': [
+    ['OS=="win"', {
+      'targets': [
+        {
+          'target_name': 'libcmt',
+          'type': 'none',
+          'actions': [
+            {
+              'action_name': 'libcmt',
+              'inputs': [
+                'prep_libc.py',
+              ],
+              'outputs': [
+                '<(SHARED_INTERMEDIATE_DIR)/allocator/libcmt.lib',
+              ],
+              'action': [
+                'python',
+                'prep_libc.py',
+                '$(VCInstallDir)lib',
+                '<(SHARED_INTERMEDIATE_DIR)/allocator',
+                '<(target_arch)',
+              ],
+            },
+          ],
+        },
+        {
+          'target_name': 'allocator_unittests',
+          'type': 'executable',
+          'dependencies': [
+            'allocator',
+            'allocator_extension_thunks',
+            '../../testing/gtest.gyp:gtest',
+          ],
+          'include_dirs': [
+            '.',
+            '../..',
+          ],
+          'sources': [
+            '../profiler/alternate_timer.cc',
+            '../profiler/alternate_timer.h',
+            'allocator_unittest.cc',
+          ],
+        },
+      ],
+    }],
+    ['OS=="win" and target_arch=="ia32"', {
+      'targets': [
+        {
+          'target_name': 'allocator_extension_thunks_win64',
+          'type': 'static_library',
+          'sources': [
+            'allocator_extension_thunks.cc',
+            'allocator_extension_thunks.h',
+          ],
+          'toolsets': ['host', 'target'],
+          'include_dirs': [
+            '../../'
+          ],
+          'configurations': {
+            'Common_Base': {
+              'msvs_target_platform': 'x64',
+            },
+          },
+        },
+      ],
+    }],
+    ['OS=="linux" and clang_type_profiler==1', {
+      # Some targets in this section undo dependencies and cflags_cc for
+      # type_profiler which build/common.gypi injects into all targets.
+      'targets': [
+        {
+          'target_name': 'type_profiler',
+          'type': 'static_library',
+          'dependencies!': [
+            'type_profiler',
+          ],
+          'cflags_cc!': [
+            '-fintercept-allocation-functions',
+          ],
+          'include_dirs': [
+            '../..',
+          ],
+          'sources': [
+            'type_profiler.cc',
+            'type_profiler.h',
+            'type_profiler_control.h',
+          ],
+          'toolsets': ['host', 'target'],
+        },
+        {
+          'target_name': 'type_profiler_tcmalloc',
+          'type': 'static_library',
+          'dependencies!': [
+            'type_profiler',
+          ],
+          'cflags_cc!': [
+            '-fintercept-allocation-functions',
+          ],
+          'include_dirs': [
+            '<(tcmalloc_dir)/src',
+            '../..',
+          ],
+          'sources': [
+            '<(tcmalloc_dir)/src/gperftools/type_profiler_map.h',
+            '<(tcmalloc_dir)/src/type_profiler_map.cc',
+            'type_profiler_tcmalloc.cc',
+            'type_profiler_tcmalloc.h',
+          ],
+        },
+        {
+          'target_name': 'type_profiler_unittests',
+          'type': 'executable',
+          'dependencies': [
+            '../../testing/gtest.gyp:gtest',
+            '../base.gyp:base',
+            'allocator',
+            'type_profiler_tcmalloc',
+          ],
+          'include_dirs': [
+            '../..',
+          ],
+          'sources': [
+            'type_profiler_control.cc',
+            'type_profiler_control.h',
+            'type_profiler_unittest.cc',
+          ],
+        },
+        {
+          'target_name': 'type_profiler_map_unittests',
+          'type': 'executable',
+          'dependencies': [
+            '../../testing/gtest.gyp:gtest',
+            '../base.gyp:base',
+            'allocator',
+          ],
+          'dependencies!': [
+            'type_profiler',
+          ],
+          'cflags_cc!': [
+            '-fintercept-allocation-functions',
+          ],
+          'include_dirs': [
+            '<(tcmalloc_dir)/src',
+            '../..',
+          ],
+          'sources': [
+            '<(tcmalloc_dir)/src/gperftools/type_profiler_map.h',
+            '<(tcmalloc_dir)/src/type_profiler_map.cc',
+            'type_profiler_map_unittest.cc',
+          ],
+        },
+      ],
+    }],
+    ['use_allocator=="tcmalloc"', {
+      'targets': [
+         {
+           'target_name': 'tcmalloc_unittest',
+           'type': 'executable',
+           'sources': [
+             'tcmalloc_unittest.cc',
+           ],
+           'include_dirs': [
+             '<(tcmalloc_dir)/src',
+             '../..',
+           ],
+           'dependencies': [
+             '../../testing/gtest.gyp:gtest',
+             'allocator',
+          ],
+        },
+      ],
+    }],
+  ],
+}
diff --git a/base/allocator/allocator_extension.cc b/base/allocator/allocator_extension.cc
new file mode 100644
index 0000000..83e460a
--- /dev/null
+++ b/base/allocator/allocator_extension.cc
@@ -0,0 +1,56 @@
+// Copyright (c) 2012 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/allocator/allocator_extension.h"
+
+#include "base/logging.h"
+
+namespace base {
+namespace allocator {
+
+bool GetAllocatorWasteSize(size_t* size) {
+  thunks::GetAllocatorWasteSizeFunction get_allocator_waste_size_function =
+      thunks::GetGetAllocatorWasteSizeFunction();
+  return get_allocator_waste_size_function != NULL &&
+         get_allocator_waste_size_function(size);
+}
+
+void GetStats(char* buffer, int buffer_length) {
+  DCHECK_GT(buffer_length, 0);
+  thunks::GetStatsFunction get_stats_function = thunks::GetGetStatsFunction();
+  if (get_stats_function)
+    get_stats_function(buffer, buffer_length);
+  else
+    buffer[0] = '\0';
+}
+
+void ReleaseFreeMemory() {
+  thunks::ReleaseFreeMemoryFunction release_free_memory_function =
+      thunks::GetReleaseFreeMemoryFunction();
+  if (release_free_memory_function)
+    release_free_memory_function();
+}
+
+void SetGetAllocatorWasteSizeFunction(
+    thunks::GetAllocatorWasteSizeFunction get_allocator_waste_size_function) {
+  DCHECK_EQ(thunks::GetGetAllocatorWasteSizeFunction(),
+            reinterpret_cast<thunks::GetAllocatorWasteSizeFunction>(NULL));
+  thunks::SetGetAllocatorWasteSizeFunction(get_allocator_waste_size_function);
+}
+
+void SetGetStatsFunction(thunks::GetStatsFunction get_stats_function) {
+  DCHECK_EQ(thunks::GetGetStatsFunction(),
+            reinterpret_cast<thunks::GetStatsFunction>(NULL));
+  thunks::SetGetStatsFunction(get_stats_function);
+}
+
+void SetReleaseFreeMemoryFunction(
+    thunks::ReleaseFreeMemoryFunction release_free_memory_function) {
+  DCHECK_EQ(thunks::GetReleaseFreeMemoryFunction(),
+            reinterpret_cast<thunks::ReleaseFreeMemoryFunction>(NULL));
+  thunks::SetReleaseFreeMemoryFunction(release_free_memory_function);
+}
+
+}  // namespace allocator
+}  // namespace base
diff --git a/base/allocator/allocator_extension.h b/base/allocator/allocator_extension.h
new file mode 100644
index 0000000..e65822b
--- /dev/null
+++ b/base/allocator/allocator_extension.h
@@ -0,0 +1,59 @@
+// Copyright (c) 2012 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_ALLOCATOR_ALLOCATOR_EXTENSION_H_
+#define BASE_ALLOCATOR_ALLOCATOR_EXTENSION_H_
+
+#include <stddef.h> // for size_t
+
+#include "base/allocator/allocator_extension_thunks.h"
+#include "base/base_export.h"
+#include "build/build_config.h"
+
+namespace base {
+namespace allocator {
+
+// Request the allocator to report value of its waste memory size.
+// Waste size corresponds to memory that has been allocated from the OS but
+// not passed up to the application. It e.g. includes memory retained by free
+// lists, internal data, chunks padding, etc.
+//
+// |size| pointer to the returned value, must be not NULL.
+// Returns true if the value has been returned, false otherwise.
+BASE_EXPORT bool GetAllocatorWasteSize(size_t* size);
+
+// Request that the allocator print a human-readable description of the current
+// state of the allocator into a null-terminated string in the memory segment
+// buffer[0,buffer_length-1].
+//
+// |buffer| must point to a valid piece of memory
+// |buffer_length| must be > 0.
+BASE_EXPORT void GetStats(char* buffer, int buffer_length);
+
+// Request that the allocator release any free memory it knows about to the
+// system.
+BASE_EXPORT void ReleaseFreeMemory();
+
+
+// These settings allow specifying a callback used to implement the allocator
+// extension functions.  These are optional, but if set they must only be set
+// once.  These will typically called in an allocator-specific initialization
+// routine.
+//
+// No threading promises are made.  The caller is responsible for making sure
+// these pointers are set before any other threads attempt to call the above
+// functions.
+BASE_EXPORT void SetGetAllocatorWasteSizeFunction(
+    thunks::GetAllocatorWasteSizeFunction get_allocator_waste_size_function);
+
+BASE_EXPORT void SetGetStatsFunction(
+    thunks::GetStatsFunction get_stats_function);
+
+BASE_EXPORT void SetReleaseFreeMemoryFunction(
+    thunks::ReleaseFreeMemoryFunction release_free_memory_function);
+
+}  // namespace allocator
+}  // namespace base
+
+#endif  // BASE_ALLOCATOR_ALLOCATOR_EXTENSION_H_
diff --git a/base/allocator/allocator_extension_thunks.cc b/base/allocator/allocator_extension_thunks.cc
new file mode 100644
index 0000000..e4024fb
--- /dev/null
+++ b/base/allocator/allocator_extension_thunks.cc
@@ -0,0 +1,52 @@
+// Copyright (c) 2012 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/allocator/allocator_extension_thunks.h"
+
+#include <cstddef> // for NULL
+
+namespace base {
+namespace allocator {
+namespace thunks {
+
+// This slightly odd translation unit exists because of the peculularity of how
+// allocator_unittests work on windows.  That target has to perform
+// tcmalloc-specific initialization on windows, but it cannot depend on base
+// otherwise. This target sits in the middle - base and allocator_unittests
+// can depend on it. This file can't depend on anything else in base, including
+// logging.
+
+static GetAllocatorWasteSizeFunction g_get_allocator_waste_size_function = NULL;
+static GetStatsFunction g_get_stats_function = NULL;
+static ReleaseFreeMemoryFunction g_release_free_memory_function = NULL;
+
+void SetGetAllocatorWasteSizeFunction(
+    GetAllocatorWasteSizeFunction get_allocator_waste_size_function) {
+  g_get_allocator_waste_size_function = get_allocator_waste_size_function;
+}
+
+GetAllocatorWasteSizeFunction GetGetAllocatorWasteSizeFunction() {
+  return g_get_allocator_waste_size_function;
+}
+
+void SetGetStatsFunction(GetStatsFunction get_stats_function) {
+  g_get_stats_function = get_stats_function;
+}
+
+GetStatsFunction GetGetStatsFunction() {
+  return g_get_stats_function;
+}
+
+void SetReleaseFreeMemoryFunction(
+    ReleaseFreeMemoryFunction release_free_memory_function) {
+  g_release_free_memory_function = release_free_memory_function;
+}
+
+ReleaseFreeMemoryFunction GetReleaseFreeMemoryFunction() {
+  return g_release_free_memory_function;
+}
+
+}  // namespace thunks
+}  // namespace allocator
+}  // namespace base
diff --git a/base/allocator/allocator_extension_thunks.h b/base/allocator/allocator_extension_thunks.h
new file mode 100644
index 0000000..4e5027b
--- /dev/null
+++ b/base/allocator/allocator_extension_thunks.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2012 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_ALLOCATOR_ALLOCATOR_EXTENSION_THUNKS_H_
+#define BASE_ALLOCATOR_ALLOCATOR_EXTENSION_THUNKS_H_
+
+#include <stddef.h> // for size_t
+
+namespace base {
+namespace allocator {
+namespace thunks {
+
+// WARNING: You probably don't want to use this file unless you are routing a
+// new allocator extension from a specific allocator implementation to base.
+// See allocator_extension.h to see the interface that base exports.
+
+typedef bool (*GetAllocatorWasteSizeFunction)(size_t* size);
+void SetGetAllocatorWasteSizeFunction(
+    GetAllocatorWasteSizeFunction get_allocator_waste_size_function);
+GetAllocatorWasteSizeFunction GetGetAllocatorWasteSizeFunction();
+
+typedef void (*GetStatsFunction)(char* buffer, int buffer_length);
+void SetGetStatsFunction(GetStatsFunction get_stats_function);
+GetStatsFunction GetGetStatsFunction();
+
+typedef void (*ReleaseFreeMemoryFunction)();
+void SetReleaseFreeMemoryFunction(
+    ReleaseFreeMemoryFunction release_free_memory_function);
+ReleaseFreeMemoryFunction GetReleaseFreeMemoryFunction();
+
+}  // namespace thunks
+}  // namespace allocator
+}  // namespace base
+
+#endif  // BASE_ALLOCATOR_ALLOCATOR_EXTENSION_THUNKS_H_
diff --git a/base/allocator/allocator_shim_win.cc b/base/allocator/allocator_shim_win.cc
new file mode 100644
index 0000000..a1473e5
--- /dev/null
+++ b/base/allocator/allocator_shim_win.cc
@@ -0,0 +1,319 @@
+// Copyright (c) 2012 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 <malloc.h>
+#include <new.h>
+#include <windows.h>
+
+#include "base/basictypes.h"
+
+// This shim make it possible to perform additional checks on allocations
+// before passing them to the Heap functions.
+
+// Heap functions are stripped from libcmt.lib using the prep_libc.py
+// for each object file stripped, we re-implement them here to allow us to
+// perform additional checks:
+// 1. Enforcing the maximum size that can be allocated to 2Gb.
+// 2. Calling new_handler if malloc fails.
+
+extern "C" {
+// We set this to 1 because part of the CRT uses a check of _crtheap != 0
+// to test whether the CRT has been initialized.  Once we've ripped out
+// the allocators from libcmt, we need to provide this definition so that
+// the rest of the CRT is still usable.
+// heapinit.c
+void* _crtheap = reinterpret_cast<void*>(1);
+}
+
+namespace {
+
+const size_t kWindowsPageSize = 4096;
+const size_t kMaxWindowsAllocation = INT_MAX - kWindowsPageSize;
+int new_mode = 0;
+
+// VS2013 crt uses the process heap as its heap, so we do the same here.
+// See heapinit.c in VS CRT sources.
+bool win_heap_init() {
+  // Set the _crtheap global here.  THis allows us to offload most of the
+  // memory management to the CRT, except the functions we need to shim.
+  _crtheap = GetProcessHeap();
+  if (_crtheap == NULL)
+    return false;
+
+  ULONG enable_lfh = 2;
+  // NOTE: Setting LFH may fail.  Vista already has it enabled.
+  //       And under the debugger, it won't use LFH.  So we
+  //       ignore any errors.
+  HeapSetInformation(_crtheap, HeapCompatibilityInformation, &enable_lfh,
+                     sizeof(enable_lfh));
+
+  return true;
+}
+
+void* win_heap_malloc(size_t size) {
+  if (size < kMaxWindowsAllocation)
+    return HeapAlloc(_crtheap, 0, size);
+  return NULL;
+}
+
+void win_heap_free(void* size) {
+  HeapFree(_crtheap, 0, size);
+}
+
+void* win_heap_realloc(void* ptr, size_t size) {
+  if (!ptr)
+    return win_heap_malloc(size);
+  if (!size) {
+    win_heap_free(ptr);
+    return NULL;
+  }
+  if (size < kMaxWindowsAllocation)
+    return HeapReAlloc(_crtheap, 0, ptr, size);
+  return NULL;
+}
+
+void win_heap_term() {
+  _crtheap = NULL;
+}
+
+// Call the new handler, if one has been set.
+// Returns true on successfully calling the handler, false otherwise.
+inline bool call_new_handler(bool nothrow, size_t size) {
+  // Get the current new handler.
+  _PNH nh = _query_new_handler();
+#if defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS
+  if (!nh)
+    return false;
+  // Since exceptions are disabled, we don't really know if new_handler
+  // failed.  Assume it will abort if it fails.
+  return nh(size);
+#else
+#error "Exceptions in allocator shim are not supported!"
+#endif  // defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS
+  return false;
+}
+
+// Implement a C++ style allocation, which always calls the new_handler
+// on failure.
+inline void* generic_cpp_alloc(size_t size, bool nothrow) {
+  void* ptr;
+  for (;;) {
+    ptr = malloc(size);
+    if (ptr)
+      return ptr;
+    if (!call_new_handler(nothrow, size))
+      break;
+  }
+  return ptr;
+}
+
+}  // namespace
+
+// new.cpp
+void* operator new(size_t size) {
+  return generic_cpp_alloc(size, false);
+}
+
+// delete.cpp
+void operator delete(void* p) throw() {
+  free(p);
+}
+
+// new2.cpp
+void* operator new[](size_t size) {
+  return generic_cpp_alloc(size, false);
+}
+
+// delete2.cpp
+void operator delete[](void* p) throw() {
+  free(p);
+}
+
+// newopnt.cpp
+void* operator new(size_t size, const std::nothrow_t& nt) {
+  return generic_cpp_alloc(size, true);
+}
+
+// newaopnt.cpp
+void* operator new[](size_t size, const std::nothrow_t& nt) {
+  return generic_cpp_alloc(size, true);
+}
+
+// This function behaves similarly to MSVC's _set_new_mode.
+// If flag is 0 (default), calls to malloc will behave normally.
+// If flag is 1, calls to malloc will behave like calls to new,
+// and the std_new_handler will be invoked on failure.
+// Returns the previous mode.
+// new_mode.cpp
+int _set_new_mode(int flag) throw() {
+  int old_mode = new_mode;
+  new_mode = flag;
+  return old_mode;
+}
+
+// new_mode.cpp
+int _query_new_mode() {
+  return new_mode;
+}
+
+extern "C" {
+// malloc.c
+void* malloc(size_t size) {
+  void* ptr;
+  for (;;) {
+    ptr = win_heap_malloc(size);
+    if (ptr)
+      return ptr;
+
+    if (!new_mode || !call_new_handler(true, size))
+      break;
+  }
+  return ptr;
+}
+
+// free.c
+void free(void* p) {
+  win_heap_free(p);
+  return;
+}
+
+// realloc.c
+void* realloc(void* ptr, size_t size) {
+  // Webkit is brittle for allocators that return NULL for malloc(0).  The
+  // realloc(0, 0) code path does not guarantee a non-NULL return, so be sure
+  // to call malloc for this case.
+  if (!ptr)
+    return malloc(size);
+
+  void* new_ptr;
+  for (;;) {
+    new_ptr = win_heap_realloc(ptr, size);
+
+    // Subtle warning:  NULL return does not alwas indicate out-of-memory.  If
+    // the requested new size is zero, realloc should free the ptr and return
+    // NULL.
+    if (new_ptr || !size)
+      return new_ptr;
+    if (!new_mode || !call_new_handler(true, size))
+      break;
+  }
+  return new_ptr;
+}
+
+// heapinit.c
+intptr_t _get_heap_handle() {
+  return reinterpret_cast<intptr_t>(_crtheap);
+}
+
+// heapinit.c
+int _heap_init() {
+  return win_heap_init() ? 1 : 0;
+}
+
+// heapinit.c
+void _heap_term() {
+  win_heap_term();
+}
+
+// calloc.c
+void* calloc(size_t n, size_t elem_size) {
+  // Overflow check.
+  const size_t size = n * elem_size;
+  if (elem_size != 0 && size / elem_size != n)
+    return NULL;
+
+  void* result = malloc(size);
+  if (result != NULL) {
+    memset(result, 0, size);
+  }
+  return result;
+}
+
+// recalloc.c
+void* _recalloc(void* p, size_t n, size_t elem_size) {
+  if (!p)
+    return calloc(n, elem_size);
+
+  // This API is a bit odd.
+  // Note: recalloc only guarantees zeroed memory when p is NULL.
+  //   Generally, calls to malloc() have padding.  So a request
+  //   to malloc N bytes actually malloc's N+x bytes.  Later, if
+  //   that buffer is passed to recalloc, we don't know what N
+  //   was anymore.  We only know what N+x is.  As such, there is
+  //   no way to know what to zero out.
+  const size_t size = n * elem_size;
+  if (elem_size != 0 && size / elem_size != n)
+    return NULL;
+  return realloc(p, size);
+}
+
+// calloc_impl.c
+void* _calloc_impl(size_t n, size_t size) {
+  return calloc(n, size);
+}
+
+#ifndef NDEBUG
+#undef malloc
+#undef free
+#undef calloc
+
+static int error_handler(int reportType) {
+  switch (reportType) {
+    case 0:  // _CRT_WARN
+      __debugbreak();
+      return 0;
+
+    case 1:  // _CRT_ERROR
+      __debugbreak();
+      return 0;
+
+    case 2:  // _CRT_ASSERT
+      __debugbreak();
+      return 0;
+  }
+  char* p = NULL;
+  *p = '\0';
+  return 0;
+}
+
+int _CrtDbgReport(int reportType,
+                  const char*,
+                  int,
+                  const char*,
+                  const char*,
+                  ...) {
+  return error_handler(reportType);
+}
+
+int _CrtDbgReportW(int reportType,
+                   const wchar_t*,
+                   int,
+                   const wchar_t*,
+                   const wchar_t*,
+                   ...) {
+  return error_handler(reportType);
+}
+
+int _CrtSetReportMode(int, int) {
+  return 0;
+}
+
+void* _malloc_dbg(size_t size, int, const char*, int) {
+  return malloc(size);
+}
+
+void* _realloc_dbg(void* ptr, size_t size, int, const char*, int) {
+  return realloc(ptr, size);
+}
+
+void _free_dbg(void* ptr, int) {
+  free(ptr);
+}
+
+void* _calloc_dbg(size_t n, size_t size, int, const char*, int) {
+  return calloc(n, size);
+}
+#endif  // NDEBUG
+
+}  // extern C
diff --git a/base/allocator/allocator_unittest.cc b/base/allocator/allocator_unittest.cc
new file mode 100644
index 0000000..a1d1ef0
--- /dev/null
+++ b/base/allocator/allocator_unittest.cc
@@ -0,0 +1,245 @@
+// 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.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <algorithm>   // for min()
+
+#include "base/macros.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Number of bits in a size_t.
+static const int kSizeBits = 8 * sizeof(size_t);
+// The maximum size of a size_t.
+static const size_t kMaxSize = ~static_cast<size_t>(0);
+// Maximum positive size of a size_t if it were signed.
+static const size_t kMaxSignedSize = ((size_t(1) << (kSizeBits-1)) - 1);
+
+namespace {
+
+using std::min;
+
+// Fill a buffer of the specified size with a predetermined pattern
+static void Fill(unsigned char* buffer, int n) {
+  for (int i = 0; i < n; i++) {
+    buffer[i] = (i & 0xff);
+  }
+}
+
+// Check that the specified buffer has the predetermined pattern
+// generated by Fill()
+static bool Valid(unsigned char* buffer, int n) {
+  for (int i = 0; i < n; i++) {
+    if (buffer[i] != (i & 0xff)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+// Check that a buffer is completely zeroed.
+static bool IsZeroed(unsigned char* buffer, int n) {
+  for (int i = 0; i < n; i++) {
+    if (buffer[i] != 0) {
+      return false;
+    }
+  }
+  return true;
+}
+
+// Check alignment
+static void CheckAlignment(void* p, int align) {
+  EXPECT_EQ(0, reinterpret_cast<uintptr_t>(p) & (align-1));
+}
+
+// Return the next interesting size/delta to check.  Returns -1 if no more.
+static int NextSize(int size) {
+  if (size < 100)
+    return size+1;
+
+  if (size < 100000) {
+    // Find next power of two
+    int power = 1;
+    while (power < size)
+      power <<= 1;
+
+    // Yield (power-1, power, power+1)
+    if (size < power-1)
+      return power-1;
+
+    if (size == power-1)
+      return power;
+
+    assert(size == power);
+    return power+1;
+  } else {
+    return -1;
+  }
+}
+
+static void TestCalloc(size_t n, size_t s, bool ok) {
+  char* p = reinterpret_cast<char*>(calloc(n, s));
+  if (!ok) {
+    EXPECT_EQ(NULL, p) << "calloc(n, s) should not succeed";
+  } else {
+    EXPECT_NE(reinterpret_cast<void*>(NULL), p) <<
+        "calloc(n, s) should succeed";
+    for (size_t i = 0; i < n*s; i++) {
+      EXPECT_EQ('\0', p[i]);
+    }
+    free(p);
+  }
+}
+
+}  // namespace
+
+//-----------------------------------------------------------------------------
+
+
+TEST(Allocators, Malloc) {
+  // Try allocating data with a bunch of alignments and sizes
+  for (int size = 1; size < 1048576; size *= 2) {
+    unsigned char* ptr = reinterpret_cast<unsigned char*>(malloc(size));
+    CheckAlignment(ptr, 2);  // Should be 2 byte aligned
+    Fill(ptr, size);
+    EXPECT_TRUE(Valid(ptr, size));
+    free(ptr);
+  }
+}
+
+TEST(Allocators, Calloc) {
+  TestCalloc(0, 0, true);
+  TestCalloc(0, 1, true);
+  TestCalloc(1, 1, true);
+  TestCalloc(1<<10, 0, true);
+  TestCalloc(1<<20, 0, true);
+  TestCalloc(0, 1<<10, true);
+  TestCalloc(0, 1<<20, true);
+  TestCalloc(1<<20, 2, true);
+  TestCalloc(2, 1<<20, true);
+  TestCalloc(1000, 1000, true);
+
+  TestCalloc(kMaxSize, 2, false);
+  TestCalloc(2, kMaxSize, false);
+  TestCalloc(kMaxSize, kMaxSize, false);
+
+  TestCalloc(kMaxSignedSize, 3, false);
+  TestCalloc(3, kMaxSignedSize, false);
+  TestCalloc(kMaxSignedSize, kMaxSignedSize, false);
+}
+
+// This makes sure that reallocing a small number of bytes in either
+// direction doesn't cause us to allocate new memory.
+TEST(Allocators, Realloc1) {
+  int start_sizes[] = { 100, 1000, 10000, 100000 };
+  int deltas[] = { 1, -2, 4, -8, 16, -32, 64, -128 };
+
+  for (int s = 0; s < sizeof(start_sizes)/sizeof(*start_sizes); ++s) {
+    void* p = malloc(start_sizes[s]);
+    ASSERT_TRUE(p);
+    // The larger the start-size, the larger the non-reallocing delta.
+    for (int d = 0; d < s*2; ++d) {
+      void* new_p = realloc(p, start_sizes[s] + deltas[d]);
+      ASSERT_EQ(p, new_p);  // realloc should not allocate new memory
+    }
+    // Test again, but this time reallocing smaller first.
+    for (int d = 0; d < s*2; ++d) {
+      void* new_p = realloc(p, start_sizes[s] - deltas[d]);
+      ASSERT_EQ(p, new_p);  // realloc should not allocate new memory
+    }
+    free(p);
+  }
+}
+
+TEST(Allocators, Realloc2) {
+  for (int src_size = 0; src_size >= 0; src_size = NextSize(src_size)) {
+    for (int dst_size = 0; dst_size >= 0; dst_size = NextSize(dst_size)) {
+      unsigned char* src = reinterpret_cast<unsigned char*>(malloc(src_size));
+      Fill(src, src_size);
+      unsigned char* dst =
+          reinterpret_cast<unsigned char*>(realloc(src, dst_size));
+      EXPECT_TRUE(Valid(dst, min(src_size, dst_size)));
+      Fill(dst, dst_size);
+      EXPECT_TRUE(Valid(dst, dst_size));
+      if (dst != NULL) free(dst);
+    }
+  }
+
+  // Now make sure realloc works correctly even when we overflow the
+  // packed cache, so some entries are evicted from the cache.
+  // The cache has 2^12 entries, keyed by page number.
+  const int kNumEntries = 1 << 14;
+  int** p = reinterpret_cast<int**>(malloc(sizeof(*p) * kNumEntries));
+  int sum = 0;
+  for (int i = 0; i < kNumEntries; i++) {
+    // no page size is likely to be bigger than 8192?
+    p[i] = reinterpret_cast<int*>(malloc(8192));
+    p[i][1000] = i;              // use memory deep in the heart of p
+  }
+  for (int i = 0; i < kNumEntries; i++) {
+    p[i] = reinterpret_cast<int*>(realloc(p[i], 9000));
+  }
+  for (int i = 0; i < kNumEntries; i++) {
+    sum += p[i][1000];
+    free(p[i]);
+  }
+  EXPECT_EQ(kNumEntries/2 * (kNumEntries - 1), sum);  // assume kNE is even
+  free(p);
+}
+
+// Test recalloc
+TEST(Allocators, Recalloc) {
+  for (int src_size = 0; src_size >= 0; src_size = NextSize(src_size)) {
+    for (int dst_size = 0; dst_size >= 0; dst_size = NextSize(dst_size)) {
+      unsigned char* src =
+          reinterpret_cast<unsigned char*>(_recalloc(NULL, 1, src_size));
+      EXPECT_TRUE(IsZeroed(src, src_size));
+      Fill(src, src_size);
+      unsigned char* dst =
+          reinterpret_cast<unsigned char*>(_recalloc(src, 1, dst_size));
+      EXPECT_TRUE(Valid(dst, min(src_size, dst_size)));
+      Fill(dst, dst_size);
+      EXPECT_TRUE(Valid(dst, dst_size));
+      if (dst != NULL)
+        free(dst);
+    }
+  }
+}
+
+// Test windows specific _aligned_malloc() and _aligned_free() methods.
+TEST(Allocators, AlignedMalloc) {
+  // Try allocating data with a bunch of alignments and sizes
+  static const int kTestAlignments[] = {8, 16, 256, 4096, 8192, 16384};
+  for (int size = 1; size > 0; size = NextSize(size)) {
+    for (int i = 0; i < arraysize(kTestAlignments); ++i) {
+      unsigned char* ptr = static_cast<unsigned char*>(
+          _aligned_malloc(size, kTestAlignments[i]));
+      CheckAlignment(ptr, kTestAlignments[i]);
+      Fill(ptr, size);
+      EXPECT_TRUE(Valid(ptr, size));
+
+      // Make a second allocation of the same size and alignment to prevent
+      // allocators from passing this test by accident.  Per jar, tcmalloc
+      // provides allocations for new (never before seen) sizes out of a thread
+      // local heap of a given "size class."  Each time the test requests a new
+      // size, it will usually get the first element of a span, which is a
+      // 4K aligned allocation.
+      unsigned char* ptr2 = static_cast<unsigned char*>(
+          _aligned_malloc(size, kTestAlignments[i]));
+      CheckAlignment(ptr2, kTestAlignments[i]);
+      Fill(ptr2, size);
+      EXPECT_TRUE(Valid(ptr2, size));
+
+      // Should never happen, but sanity check just in case.
+      ASSERT_NE(ptr, ptr2);
+      _aligned_free(ptr);
+      _aligned_free(ptr2);
+    }
+  }
+}
+
+int main(int argc, char** argv) {
+  testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/base/allocator/debugallocation_shim.cc b/base/allocator/debugallocation_shim.cc
new file mode 100644
index 0000000..d1cf52a
--- /dev/null
+++ b/base/allocator/debugallocation_shim.cc
@@ -0,0 +1,9 @@
+// Copyright (c) 2012 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.
+
+#if defined(TCMALLOC_FOR_DEBUGALLOCATION)
+#include "third_party/tcmalloc/chromium/src/debugallocation.cc"
+#else
+#include "third_party/tcmalloc/chromium/src/tcmalloc.cc"
+#endif
diff --git a/base/allocator/prep_libc.py b/base/allocator/prep_libc.py
new file mode 100755
index 0000000..079297b
--- /dev/null
+++ b/base/allocator/prep_libc.py
@@ -0,0 +1,67 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 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 script takes libcmt.lib for VS2013 and removes the allocation related
+# functions from it.
+#
+# Usage: prep_libc.py <VCLibDir> <OutputDir> <arch>
+#
+# VCLibDir is the path where VC is installed, something like:
+#    C:\Program Files\Microsoft Visual Studio 8\VC\lib
+# OutputDir is the directory where the modified libcmt file should be stored.
+# arch is one of: 'ia32', 'x86' or 'x64'. ia32 and x86 are synonyms.
+
+import os
+import shutil
+import subprocess
+import sys
+
+def run(command):
+  """Run |command|.  If any lines that match an error condition then
+      terminate."""
+  error = 'cannot find member object'
+  popen = subprocess.Popen(
+      command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+  out, _ = popen.communicate()
+  for line in out.splitlines():
+    print line
+    if error and line.find(error) != -1:
+      print 'prep_libc.py: Error stripping object from C runtime.'
+      sys.exit(1)
+
+def main():
+  bindir = 'SELF_X86'
+  objdir = 'INTEL'
+  vs_install_dir = sys.argv[1]
+  outdir = sys.argv[2]
+  if "x64" in sys.argv[3]:
+    bindir = 'SELF_64_amd64'
+    objdir = 'amd64'
+    vs_install_dir = os.path.join(vs_install_dir, 'amd64')
+  output_lib = os.path.join(outdir, 'libcmt.lib')
+  shutil.copyfile(os.path.join(vs_install_dir, 'libcmt.lib'), output_lib)
+  shutil.copyfile(os.path.join(vs_install_dir, 'libcmt.pdb'),
+                  os.path.join(outdir, 'libcmt.pdb'))
+  cvspath = 'f:\\binaries\\Intermediate\\vctools\\crt_bld\\' + bindir + \
+      '\\crt\\prebuild\\build\\' + objdir + '\\mt_obj\\nativec\\\\';
+  cppvspath = 'f:\\binaries\\Intermediate\\vctools\\crt_bld\\' + bindir + \
+      '\\crt\\prebuild\\build\\' + objdir + '\\mt_obj\\nativecpp\\\\';
+
+  cobjfiles = ['malloc', 'free', 'realloc', 'heapinit', 'calloc', 'recalloc',
+      'calloc_impl']
+  cppobjfiles = ['new', 'new2', 'delete', 'delete2', 'new_mode', 'newopnt',
+      'newaopnt']
+  for obj in cobjfiles:
+    cmd = ('lib /nologo /ignore:4006,4221 /remove:%s%s.obj %s' %
+           (cvspath, obj, output_lib))
+    run(cmd)
+  for obj in cppobjfiles:
+    cmd = ('lib /nologo /ignore:4006,4221 /remove:%s%s.obj %s' %
+           (cppvspath, obj, output_lib))
+    run(cmd)
+
+if __name__ == "__main__":
+  sys.exit(main())
diff --git a/base/allocator/tcmalloc_unittest.cc b/base/allocator/tcmalloc_unittest.cc
new file mode 100644
index 0000000..0f7082e
--- /dev/null
+++ b/base/allocator/tcmalloc_unittest.cc
@@ -0,0 +1,96 @@
+// Copyright (c) 2012 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 <stddef.h>
+#include <stdio.h>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+// TCMalloc header files.
+#include "common.h"  // For TCMalloc constants like page size, etc.
+
+// TCMalloc implementation.
+#include "debugallocation_shim.cc"
+
+namespace {
+
+void* TCMallocDoMallocForTest(size_t size) {
+  return do_malloc(size);
+}
+
+void TCMallocDoFreeForTest(void* ptr) {
+  do_free(ptr);
+}
+
+size_t ExcludeSpaceForMarkForTest(size_t size) {
+  return ExcludeSpaceForMark(size);
+}
+
+}  // namespace
+
+TEST(TCMallocFreeCheck, BadPointerInFirstPageOfTheLargeObject) {
+  char* p = reinterpret_cast<char*>(
+      TCMallocDoMallocForTest(ExcludeSpaceForMarkForTest(kMaxSize + 1)));
+  for (int offset = 1; offset < kPageSize ; offset <<= 1) {
+    ASSERT_DEATH(TCMallocDoFreeForTest(p + offset),
+                 "Pointer is not pointing to the start of a span");
+  }
+}
+
+TEST(TCMallocFreeCheck, BadPageAlignedPointerInsideLargeObject) {
+  char* p = reinterpret_cast<char*>(
+      TCMallocDoMallocForTest(ExcludeSpaceForMarkForTest(kMaxSize + 1)));
+
+  for (int offset = kPageSize; offset < kMaxSize; offset += kPageSize) {
+    // Only the first and last page of a span are in heap map. So for others
+    // tcmalloc will give a general error of invalid pointer.
+    ASSERT_DEATH(TCMallocDoFreeForTest(p + offset),
+                 "Attempt to free invalid pointer");
+  }
+  ASSERT_DEATH(TCMallocDoFreeForTest(p + kMaxSize),
+               "Pointer is not pointing to the start of a span");
+}
+
+TEST(TCMallocFreeCheck, DoubleFreeLargeObject) {
+  char* p = reinterpret_cast<char*>(
+      TCMallocDoMallocForTest(ExcludeSpaceForMarkForTest(kMaxSize + 1)));
+  ASSERT_DEATH(TCMallocDoFreeForTest(p); TCMallocDoFreeForTest(p),
+               "Object was not in-use");
+}
+
+
+#ifdef NDEBUG
+TEST(TCMallocFreeCheck, DoubleFreeSmallObject) {
+  for (size_t size = 1;
+       size <= ExcludeSpaceForMarkForTest(kMaxSize);
+       size <<= 1) {
+    char* p = reinterpret_cast<char*>(TCMallocDoMallocForTest(size));
+    ASSERT_DEATH(TCMallocDoFreeForTest(p); TCMallocDoFreeForTest(p),
+                 "Circular loop in list detected");
+  }
+}
+#else
+TEST(TCMallocFreeCheck, DoubleFreeSmallObject) {
+  size_t size = 1;
+
+  // When the object is small, tcmalloc validation can not distinguish normal
+  // memory corruption or double free, because there's not enough space in
+  // freed objects to keep the mark.
+  for (; size <= ExcludeSpaceForMarkForTest(kMinClassSize); size <<= 1) {
+    char* p = reinterpret_cast<char*>(TCMallocDoMallocForTest(size));
+    ASSERT_DEATH(TCMallocDoFreeForTest(p); TCMallocDoFreeForTest(p),
+                 "Memory corrupted");
+  }
+
+  for (; size <= ExcludeSpaceForMarkForTest(kMaxSize); size <<= 1) {
+    char* p = reinterpret_cast<char*>(TCMallocDoMallocForTest(size));
+    ASSERT_DEATH(TCMallocDoFreeForTest(p); TCMallocDoFreeForTest(p),
+                 "Attempt to double free");
+  }
+}
+#endif
+
+int main(int argc, char **argv) {
+  testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/base/allocator/type_profiler.cc b/base/allocator/type_profiler.cc
new file mode 100644
index 0000000..635fbcf
--- /dev/null
+++ b/base/allocator/type_profiler.cc
@@ -0,0 +1,63 @@
+// Copyright 2012 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.
+
+#if defined(TYPE_PROFILING)
+
+#include "base/allocator/type_profiler.h"
+
+#include <assert.h>
+
+namespace {
+
+void* NopIntercept(void* ptr, size_t size, const std::type_info& type) {
+  return ptr;
+}
+
+base::type_profiler::InterceptFunction* g_new_intercept = NopIntercept;
+base::type_profiler::InterceptFunction* g_delete_intercept = NopIntercept;
+
+}
+
+void* __op_new_intercept__(void* ptr,
+                           size_t size,
+                           const std::type_info& type) {
+  return g_new_intercept(ptr, size, type);
+}
+
+void* __op_delete_intercept__(void* ptr,
+                              size_t size,
+                              const std::type_info& type) {
+  return g_delete_intercept(ptr, size, type);
+}
+
+namespace base {
+namespace type_profiler {
+
+// static
+void InterceptFunctions::SetFunctions(InterceptFunction* new_intercept,
+                                      InterceptFunction* delete_intercept) {
+  // Don't use DCHECK, as this file is injected into targets
+  // that do not and should not depend on base/base.gyp:base
+  assert(g_new_intercept == NopIntercept);
+  assert(g_delete_intercept == NopIntercept);
+
+  g_new_intercept = new_intercept;
+  g_delete_intercept = delete_intercept;
+}
+
+// static
+void InterceptFunctions::ResetFunctions() {
+  g_new_intercept = NopIntercept;
+  g_delete_intercept = NopIntercept;
+}
+
+// static
+bool InterceptFunctions::IsAvailable() {
+  return g_new_intercept != NopIntercept || g_delete_intercept != NopIntercept;
+}
+
+}  // namespace type_profiler
+}  // namespace base
+
+#endif  // defined(TYPE_PROFILING)
diff --git a/base/allocator/type_profiler.h b/base/allocator/type_profiler.h
new file mode 100644
index 0000000..86b5711
--- /dev/null
+++ b/base/allocator/type_profiler.h
@@ -0,0 +1,40 @@
+// Copyright 2012 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_ALLOCATOR_TYPE_PROFILER_H_
+#define BASE_ALLOCATOR_TYPE_PROFILER_H_
+
+#if defined(TYPE_PROFILING)
+
+#include <stddef.h>  // for size_t
+#include <typeinfo>  // for std::typeinfo
+
+namespace base {
+namespace type_profiler {
+
+typedef void* InterceptFunction(void*, size_t, const std::type_info&);
+
+class InterceptFunctions {
+ public:
+  // It must be called only once in a process while it is in single-thread.
+  // For now, ContentMainRunnerImpl::Initialize is the only supposed caller
+  // of this function except for single-threaded unit tests.
+  static void SetFunctions(InterceptFunction* new_intercept,
+                           InterceptFunction* delete_intercept);
+
+ private:
+  friend class TypeProfilerTest;
+
+  // These functions are not thread safe.
+  // They must be used only from single-threaded unit tests.
+  static void ResetFunctions();
+  static bool IsAvailable();
+};
+
+}  // namespace type_profiler
+}  // namespace base
+
+#endif  // defined(TYPE_PROFILING)
+
+#endif  // BASE_ALLOCATOR_TYPE_PROFILER_H_
diff --git a/base/allocator/type_profiler_control.cc b/base/allocator/type_profiler_control.cc
new file mode 100644
index 0000000..6be7984
--- /dev/null
+++ b/base/allocator/type_profiler_control.cc
@@ -0,0 +1,38 @@
+// Copyright 2012 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/allocator/type_profiler_control.h"
+
+namespace base {
+namespace type_profiler {
+
+namespace {
+
+#if defined(TYPE_PROFILING)
+const bool kTypeProfilingEnabled = true;
+#else
+const bool kTypeProfilingEnabled = false;
+#endif
+
+bool g_enable_intercept = kTypeProfilingEnabled;
+
+}  // namespace
+
+// static
+void Controller::Stop() {
+  g_enable_intercept = false;
+}
+
+// static
+bool Controller::IsProfiling() {
+  return kTypeProfilingEnabled && g_enable_intercept;
+}
+
+// static
+void Controller::Restart() {
+  g_enable_intercept = kTypeProfilingEnabled;
+}
+
+}  // namespace type_profiler
+}  // namespace base
diff --git a/base/allocator/type_profiler_control.h b/base/allocator/type_profiler_control.h
new file mode 100644
index 0000000..17cf5b6
--- /dev/null
+++ b/base/allocator/type_profiler_control.h
@@ -0,0 +1,31 @@
+// Copyright 2012 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_ALLOCATOR_TYPE_PROFILER_CONTROL_H_
+#define BASE_ALLOCATOR_TYPE_PROFILER_CONTROL_H_
+
+#include "base/gtest_prod_util.h"
+
+namespace base {
+namespace type_profiler {
+
+class Controller {
+ public:
+  static void Stop();
+  static bool IsProfiling();
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(TypeProfilerTest,
+                           TestProfileNewWithoutProfiledDelete);
+
+  // It must be used only from allowed unit tests.  The following is only
+  // allowed for use in unit tests. Profiling should never be restarted in
+  // regular use.
+  static void Restart();
+};
+
+}  // namespace type_profiler
+}  // namespace base
+
+#endif  // BASE_ALLOCATOR_TYPE_PROFILER_CONTROL_H_
diff --git a/base/allocator/type_profiler_map_unittest.cc b/base/allocator/type_profiler_map_unittest.cc
new file mode 100644
index 0000000..514ec16
--- /dev/null
+++ b/base/allocator/type_profiler_map_unittest.cc
@@ -0,0 +1,99 @@
+// 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 is a unittest set for type_profiler_map in third_party/tcmalloc.  It is
+// independent from other tests and executed manually like allocator_unittests
+// since type_profiler_map is a singleton (like TCMalloc's heap-profiler), and
+// it requires RTTI and different compiling/linking options from others.
+
+#if defined(TYPE_PROFILING)
+
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/tcmalloc/chromium/src/gperftools/type_profiler_map.h"
+
+namespace base {
+namespace type_profiler {
+
+static const void* const g_const_null = static_cast<const void*>(NULL);
+
+TEST(TypeProfilerMapTest, NormalOperation) {
+  // Allocate an object just to get a valid address.
+  // This 'new' is not profiled by type_profiler.
+  scoped_ptr<int> dummy(new int(48));
+  const std::type_info* type;
+
+  type = LookupType(dummy.get());
+  EXPECT_EQ(g_const_null, type);
+
+  InsertType(dummy.get(), 12, typeid(int));
+  type = LookupType(dummy.get());
+  ASSERT_NE(g_const_null, type);
+  EXPECT_STREQ(typeid(int).name(), type->name());
+
+  EraseType(dummy.get());
+  type = LookupType(dummy.get());
+  EXPECT_EQ(g_const_null, type);
+}
+
+TEST(TypeProfilerMapTest, EraseWithoutInsert) {
+  scoped_ptr<int> dummy(new int(48));
+  const std::type_info* type;
+
+  for (int i = 0; i < 10; ++i) {
+    EraseType(dummy.get());
+    type = LookupType(dummy.get());
+    EXPECT_EQ(g_const_null, type);
+  }
+}
+
+TEST(TypeProfilerMapTest, InsertThenMultipleErase) {
+  scoped_ptr<int> dummy(new int(48));
+  const std::type_info* type;
+
+  InsertType(dummy.get(), 12, typeid(int));
+  type = LookupType(dummy.get());
+  ASSERT_NE(g_const_null, type);
+  EXPECT_STREQ(typeid(int).name(), type->name());
+
+  for (int i = 0; i < 10; ++i) {
+    EraseType(dummy.get());
+    type = LookupType(dummy.get());
+    EXPECT_EQ(g_const_null, type);
+  }
+}
+
+TEST(TypeProfilerMapTest, MultipleInsertWithoutErase) {
+  scoped_ptr<int> dummy(new int(48));
+  const std::type_info* type;
+
+  InsertType(dummy.get(), 12, typeid(int));
+  type = LookupType(dummy.get());
+  ASSERT_NE(g_const_null, type);
+  EXPECT_STREQ(typeid(int).name(), type->name());
+
+  InsertType(dummy.get(), 5, typeid(char));
+  type = LookupType(dummy.get());
+  ASSERT_NE(g_const_null, type);
+  EXPECT_STREQ(typeid(char).name(), type->name());
+
+  InsertType(dummy.get(), 129, typeid(long));
+  type = LookupType(dummy.get());
+  ASSERT_NE(g_const_null, type);
+  EXPECT_STREQ(typeid(long).name(), type->name());
+
+  EraseType(dummy.get());
+  type = LookupType(dummy.get());
+  EXPECT_EQ(g_const_null, type);
+}
+
+}  // namespace type_profiler
+}  // namespace base
+
+#endif  // defined(TYPE_PROFILING)
+
+int main(int argc, char** argv) {
+  testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/base/allocator/type_profiler_tcmalloc.cc b/base/allocator/type_profiler_tcmalloc.cc
new file mode 100644
index 0000000..e5e10e0
--- /dev/null
+++ b/base/allocator/type_profiler_tcmalloc.cc
@@ -0,0 +1,37 @@
+// Copyright 2012 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.
+
+#if defined(TYPE_PROFILING)
+
+#include "base/allocator/type_profiler_tcmalloc.h"
+
+#include "base/allocator/type_profiler_control.h"
+#include "third_party/tcmalloc/chromium/src/gperftools/heap-profiler.h"
+#include "third_party/tcmalloc/chromium/src/gperftools/type_profiler_map.h"
+
+namespace base {
+namespace type_profiler {
+
+void* NewInterceptForTCMalloc(void* ptr,
+                              size_t size,
+                              const std::type_info& type) {
+  if (Controller::IsProfiling())
+    InsertType(ptr, size, type);
+
+  return ptr;
+}
+
+void* DeleteInterceptForTCMalloc(void* ptr,
+                                 size_t size,
+                                 const std::type_info& type) {
+  if (Controller::IsProfiling())
+    EraseType(ptr);
+
+  return ptr;
+}
+
+}  // namespace type_profiler
+}  // namespace base
+
+#endif  // defined(TYPE_PROFILING)
diff --git a/base/allocator/type_profiler_tcmalloc.h b/base/allocator/type_profiler_tcmalloc.h
new file mode 100644
index 0000000..ac55995
--- /dev/null
+++ b/base/allocator/type_profiler_tcmalloc.h
@@ -0,0 +1,29 @@
+// Copyright 2012 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_ALLOCATOR_TYPE_PROFILER_TCMALLOC_H_
+#define BASE_ALLOCATOR_TYPE_PROFILER_TCMALLOC_H_
+
+#if defined(TYPE_PROFILING)
+
+#include <cstddef>  // for size_t
+#include <typeinfo>  // for std::type_info
+
+namespace base {
+namespace type_profiler {
+
+void* NewInterceptForTCMalloc(void* ptr,
+                              size_t size,
+                              const std::type_info& type);
+
+void* DeleteInterceptForTCMalloc(void* ptr,
+                                 size_t size,
+                                 const std::type_info& type);
+
+}  // namespace type_profiler
+}  // namespace base
+
+#endif  // defined(TYPE_PROFILING)
+
+#endif  // BASE_ALLOCATOR_TYPE_PROFILER_TCMALLOC_H_
diff --git a/base/allocator/type_profiler_unittest.cc b/base/allocator/type_profiler_unittest.cc
new file mode 100644
index 0000000..3d7369c38
--- /dev/null
+++ b/base/allocator/type_profiler_unittest.cc
@@ -0,0 +1,189 @@
+// 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 is a unittest set for type_profiler.  It is independent from other
+// tests and executed manually like allocator_unittests since type_profiler_map
+// used in type_profiler is a singleton (like TCMalloc's heap-profiler), and
+// it requires RTTI and different compiling/linking options from others
+//
+// It tests that the profiler doesn't fail in suspicous cases.  For example,
+// 'new' is not profiled, but 'delete' for the created object is profiled.
+
+#if defined(TYPE_PROFILING)
+
+#include "base/allocator/type_profiler.h"
+#include "base/allocator/type_profiler_control.h"
+#include "base/allocator/type_profiler_tcmalloc.h"
+#include "base/basictypes.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/tcmalloc/chromium/src/gperftools/type_profiler_map.h"
+
+namespace base {
+namespace type_profiler {
+
+class TypeProfilerTest : public testing::Test {
+ public:
+  TypeProfilerTest() {}
+
+  void SetInterceptFunctions() {
+    InterceptFunctions::SetFunctions(NewInterceptForTCMalloc,
+                                     DeleteInterceptForTCMalloc);
+  }
+
+  void ResetInterceptFunctions() {
+    InterceptFunctions::ResetFunctions();
+  }
+
+  void SetUp() {
+    SetInterceptFunctions();
+  }
+
+  void TearDown() {
+    ResetInterceptFunctions();
+  }
+
+ protected:
+  static const size_t kDummyArraySize;
+  static const void* const kConstNull;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TypeProfilerTest);
+};
+
+const size_t TypeProfilerTest::kDummyArraySize = 10;
+const void* const TypeProfilerTest::kConstNull = static_cast<const void*>(NULL);
+
+TEST_F(TypeProfilerTest, TestNormalProfiling) {
+  int* dummy = new int(48);
+  const std::type_info* type;
+
+  type = LookupType(dummy);
+  ASSERT_NE(kConstNull, type);
+  EXPECT_STREQ(typeid(int).name(), type->name());
+  delete dummy;
+
+  type = LookupType(dummy);
+  EXPECT_EQ(kConstNull, type);
+}
+
+TEST_F(TypeProfilerTest, TestNormalArrayProfiling) {
+  int* dummy = new int[kDummyArraySize];
+  const std::type_info* type;
+
+  type = LookupType(dummy);
+  ASSERT_NE(kConstNull, type);
+  // For an array, the profiler remembers its base type.
+  EXPECT_STREQ(typeid(int).name(), type->name());
+  delete[] dummy;
+
+  type = LookupType(dummy);
+  EXPECT_EQ(kConstNull, type);
+}
+
+TEST_F(TypeProfilerTest, TestRepeatedNewAndDelete) {
+  int *dummy[kDummyArraySize];
+  const std::type_info* type;
+  for (int i = 0; i < kDummyArraySize; ++i)
+    dummy[i] = new int(i);
+
+  for (int i = 0; i < kDummyArraySize; ++i) {
+    type = LookupType(dummy[i]);
+    ASSERT_NE(kConstNull, type);
+    EXPECT_STREQ(typeid(int).name(), type->name());
+  }
+
+  for (int i = 0; i < kDummyArraySize; ++i) {
+    delete dummy[i];
+    type = LookupType(dummy[i]);
+    ASSERT_EQ(kConstNull, type);
+  }
+}
+
+TEST_F(TypeProfilerTest, TestMultipleNewWithDroppingDelete) {
+  static const size_t large_size = 256 * 1024;
+
+  char* dummy_char = new char[large_size / sizeof(*dummy_char)];
+  const std::type_info* type;
+
+  type = LookupType(dummy_char);
+  ASSERT_NE(kConstNull, type);
+  EXPECT_STREQ(typeid(char).name(), type->name());
+
+  // Call "::operator delete" directly to drop __op_delete_intercept__.
+  ::operator delete[](dummy_char);
+
+  type = LookupType(dummy_char);
+  ASSERT_NE(kConstNull, type);
+  EXPECT_STREQ(typeid(char).name(), type->name());
+
+  // Allocates a little different size.
+  int* dummy_int = new int[large_size / sizeof(*dummy_int) - 1];
+
+  // We expect that tcmalloc returns the same address for these large (over 32k)
+  // allocation calls.  It usually happens, but maybe probablistic.
+  ASSERT_EQ(static_cast<void*>(dummy_char), static_cast<void*>(dummy_int)) <<
+      "two new (malloc) calls didn't return the same address; retry it.";
+
+  type = LookupType(dummy_int);
+  ASSERT_NE(kConstNull, type);
+  EXPECT_STREQ(typeid(int).name(), type->name());
+
+  delete[] dummy_int;
+
+  type = LookupType(dummy_int);
+  EXPECT_EQ(kConstNull, type);
+}
+
+TEST_F(TypeProfilerTest, TestProfileDeleteWithoutProfiledNew) {
+  // 'dummy' should be new'ed in this test before intercept functions are set.
+  ResetInterceptFunctions();
+
+  int* dummy = new int(48);
+  const std::type_info* type;
+
+  // Set intercept functions again after 'dummy' is new'ed.
+  SetInterceptFunctions();
+
+  delete dummy;
+
+  type = LookupType(dummy);
+  EXPECT_EQ(kConstNull, type);
+
+  ResetInterceptFunctions();
+}
+
+TEST_F(TypeProfilerTest, TestProfileNewWithoutProfiledDelete) {
+  int* dummy = new int(48);
+  const std::type_info* type;
+
+  EXPECT_TRUE(Controller::IsProfiling());
+
+  // Stop profiling before deleting 'dummy'.
+  Controller::Stop();
+  EXPECT_FALSE(Controller::IsProfiling());
+
+  delete dummy;
+
+  // NOTE: We accept that a profile entry remains when a profiled object is
+  // deleted after Controller::Stop().
+  type = LookupType(dummy);
+  ASSERT_NE(kConstNull, type);
+  EXPECT_STREQ(typeid(int).name(), type->name());
+
+  Controller::Restart();
+  EXPECT_TRUE(Controller::IsProfiling());
+
+  // Remove manually since 'dummy' is not removed from type_profiler_map.
+  EraseType(dummy);
+}
+
+}  // namespace type_profiler
+}  // namespace base
+
+#endif  // defined(TYPE_PROFILING)
+
+int main(int argc, char** argv) {
+  testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/base/allocator/unittest_utils.cc b/base/allocator/unittest_utils.cc
new file mode 100644
index 0000000..130ba15
--- /dev/null
+++ b/base/allocator/unittest_utils.cc
@@ -0,0 +1,18 @@
+// Copyright (c) 2009 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.
+
+// The unittests need a this in order to link up without pulling in tons
+// of other libraries
+
+#include <config.h>
+
+inline int snprintf(char* buffer, size_t count, const char* format, ...) {
+    int result;
+    va_list args;
+    va_start(args, format);
+    result = _vsnprintf(buffer, count, format, args);
+    va_end(args);
+    return result;
+}
+
diff --git a/base/android/OWNERS b/base/android/OWNERS
new file mode 100644
index 0000000..778fb75
--- /dev/null
+++ b/base/android/OWNERS
@@ -0,0 +1,3 @@
+nyquist@chromium.org
+rmcilroy@chromium.org
+yfriedman@chromium.org
diff --git a/base/android/animation_frame_time_histogram.cc b/base/android/animation_frame_time_histogram.cc
new file mode 100644
index 0000000..0d79619
--- /dev/null
+++ b/base/android/animation_frame_time_histogram.cc
@@ -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.
+
+#include "base/android/animation_frame_time_histogram.h"
+
+#include "base/android/jni_string.h"
+#include "base/metrics/histogram_macros.h"
+#include "jni/AnimationFrameTimeHistogram_jni.h"
+
+// static
+void SaveHistogram(JNIEnv* env,
+                   jobject jcaller,
+                   jstring j_histogram_name,
+                   jlongArray j_frame_times_ms,
+                   jint j_count) {
+  jlong *frame_times_ms = env->GetLongArrayElements(j_frame_times_ms, NULL);
+  std::string histogram_name = base::android::ConvertJavaStringToUTF8(
+      env, j_histogram_name);
+
+  for (int i = 0; i < j_count; ++i) {
+    UMA_HISTOGRAM_TIMES(histogram_name.c_str(),
+                        base::TimeDelta::FromMilliseconds(frame_times_ms[i]));
+  }
+}
+
+namespace base {
+namespace android {
+
+// static
+bool RegisterAnimationFrameTimeHistogram(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/animation_frame_time_histogram.h b/base/android/animation_frame_time_histogram.h
new file mode 100644
index 0000000..63f938b
--- /dev/null
+++ b/base/android/animation_frame_time_histogram.h
@@ -0,0 +1,18 @@
+// 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_ANIMATION_FRAME_TIME_HISTOGRAM_H_
+#define BASE_ANDROID_ANIMATION_FRAME_TIME_HISTOGRAM_H_
+
+#include <jni.h>
+
+namespace base {
+namespace android {
+
+bool RegisterAnimationFrameTimeHistogram(JNIEnv* env);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_ANIMATION_FRAME_TIME_HISTOGRAM_H_
diff --git a/base/android/apk_assets.cc b/base/android/apk_assets.cc
new file mode 100644
index 0000000..bcdac6d
--- /dev/null
+++ b/base/android/apk_assets.cc
@@ -0,0 +1,51 @@
+// 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 <jni.h>
+
+#include "base/android/apk_assets.h"
+
+#include "base/android/jni_array.h"
+#include "base/android/jni_string.h"
+#include "base/android/scoped_java_ref.h"
+#include "jni/ApkAssets_jni.h"
+
+namespace base {
+namespace android {
+
+bool RegisterApkAssets(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+int OpenApkAsset(const std::string& file_path,
+                 base::MemoryMappedFile::Region* region) {
+  // The AAssetManager API of the NDK is does not expose a method for accessing
+  // raw resources :(.
+  JNIEnv* env = base::android::AttachCurrentThread();
+  ScopedJavaLocalRef<jlongArray> jarr = Java_ApkAssets_open(
+      env,
+      base::android::GetApplicationContext(),
+      base::android::ConvertUTF8ToJavaString(env, file_path).Release());
+  std::vector<jlong> results;
+  base::android::JavaLongArrayToLongVector(env, jarr.obj(), &results);
+  CHECK_EQ(3U, results.size());
+  int fd = static_cast<int>(results[0]);
+  region->offset = results[1];
+  region->size = results[2];
+  return fd;
+}
+
+bool RegisterApkAssetWithGlobalDescriptors(base::GlobalDescriptors::Key key,
+                                           const std::string& file_path) {
+  base::MemoryMappedFile::Region region =
+      base::MemoryMappedFile::Region::kWholeFile;
+  int asset_fd = OpenApkAsset(file_path, &region);
+  if (asset_fd != -1) {
+    base::GlobalDescriptors::GetInstance()->Set(key, asset_fd, region);
+  }
+  return asset_fd != -1;
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/apk_assets.h b/base/android/apk_assets.h
new file mode 100644
index 0000000..6eb5da3
--- /dev/null
+++ b/base/android/apk_assets.h
@@ -0,0 +1,40 @@
+// 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_APK_ASSETS_H_
+#define BASE_ANDROID_APK_ASSETS_H_
+
+#include <string>
+
+#include "base/android/jni_android.h"
+#include "base/files/memory_mapped_file.h"
+#include "base/posix/global_descriptors.h"
+
+namespace base {
+namespace android {
+
+bool RegisterApkAssets(JNIEnv* env);
+
+// Opens an asset (e.g. a .pak file) from the apk.
+// Can be used from renderer process.
+// Fails if the asset is not stored uncompressed within the .apk.
+// Returns: The File Descriptor of the asset, or -1 upon failure.
+// Input arguments:
+// - |file_path|: Path to file within .apk. e.g.: assets/foo.pak
+// Output arguments:
+// - |region|: size & offset (in bytes) within the .apk of the asset.
+BASE_EXPORT int OpenApkAsset(
+    const std::string& file_path,
+    base::MemoryMappedFile::Region* region);
+
+// Registers an uncompressed asset from within the apk with GlobalDescriptors.
+// Returns: true in case of success, false otherwise.
+BASE_EXPORT bool RegisterApkAssetWithGlobalDescriptors(
+    base::GlobalDescriptors::Key key,
+    const std::string& file_path);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_APK_ASSETS_H_
diff --git a/base/android/application_status_listener.cc b/base/android/application_status_listener.cc
new file mode 100644
index 0000000..3e6fbf8
--- /dev/null
+++ b/base/android/application_status_listener.cc
@@ -0,0 +1,76 @@
+// 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.
+
+#include "base/android/application_status_listener.h"
+
+#include <jni.h>
+
+#include "base/lazy_instance.h"
+#include "base/observer_list_threadsafe.h"
+#include "jni/ApplicationStatus_jni.h"
+
+namespace base {
+namespace android {
+
+namespace {
+
+struct LeakyLazyObserverListTraits :
+    base::internal::LeakyLazyInstanceTraits<
+        ObserverListThreadSafe<ApplicationStatusListener> > {
+  static ObserverListThreadSafe<ApplicationStatusListener>*
+      New(void* instance) {
+    ObserverListThreadSafe<ApplicationStatusListener>* ret =
+        base::internal::LeakyLazyInstanceTraits<ObserverListThreadSafe<
+            ApplicationStatusListener>>::New(instance);
+    // Leaky.
+    ret->AddRef();
+    return ret;
+  }
+};
+
+LazyInstance<ObserverListThreadSafe<ApplicationStatusListener>,
+             LeakyLazyObserverListTraits> g_observers =
+    LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+ApplicationStatusListener::ApplicationStatusListener(
+    const ApplicationStatusListener::ApplicationStateChangeCallback& callback)
+    : callback_(callback) {
+  DCHECK(!callback_.is_null());
+  g_observers.Get().AddObserver(this);
+
+  Java_ApplicationStatus_registerThreadSafeNativeApplicationStateListener(
+      AttachCurrentThread());
+}
+
+ApplicationStatusListener::~ApplicationStatusListener() {
+  g_observers.Get().RemoveObserver(this);
+}
+
+void ApplicationStatusListener::Notify(ApplicationState state) {
+  callback_.Run(state);
+}
+
+// static
+bool ApplicationStatusListener::RegisterBindings(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+// static
+void ApplicationStatusListener::NotifyApplicationStateChange(
+    ApplicationState state) {
+  g_observers.Get().Notify(FROM_HERE, &ApplicationStatusListener::Notify,
+                           state);
+}
+
+static void OnApplicationStateChange(JNIEnv* env,
+                                     jclass clazz,
+                                     jint new_state) {
+  ApplicationState application_state = static_cast<ApplicationState>(new_state);
+  ApplicationStatusListener::NotifyApplicationStateChange(application_state);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/application_status_listener.h b/base/android/application_status_listener.h
new file mode 100644
index 0000000..30048b2
--- /dev/null
+++ b/base/android/application_status_listener.h
@@ -0,0 +1,87 @@
+// 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.
+
+#ifndef BASE_ANDROID_APPLICATION_STATUS_LISTENER_H_
+#define BASE_ANDROID_APPLICATION_STATUS_LISTENER_H_
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/singleton.h"
+#include "base/observer_list_threadsafe.h"
+
+namespace base {
+namespace android {
+
+// Define application state values like APPLICATION_STATE_VISIBLE in a
+// way that ensures they're always the same than their Java counterpart.
+//
+// Note that these states represent the most visible Activity state.
+// If there are activities with states paused and stopped, only
+// HAS_PAUSED_ACTIVITIES should be returned.
+//
+// A Java counterpart will be generated for this enum.
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.base
+enum ApplicationState {
+  APPLICATION_STATE_HAS_RUNNING_ACTIVITIES = 1,
+  APPLICATION_STATE_HAS_PAUSED_ACTIVITIES = 2,
+  APPLICATION_STATE_HAS_STOPPED_ACTIVITIES = 3,
+  APPLICATION_STATE_HAS_DESTROYED_ACTIVITIES = 4
+};
+
+// A native helper class to listen to state changes of the Android
+// Application. This mirrors org.chromium.base.ApplicationStatus.
+// any thread.
+//
+// To start listening, create a new instance, passing a callback to a
+// function that takes an ApplicationState parameter. To stop listening,
+// simply delete the listener object. The implementation guarantees
+// that the callback will always be called on the thread that created
+// the listener.
+//
+// Example:
+//
+//    void OnApplicationStateChange(ApplicationState state) {
+//       ...
+//    }
+//
+//    // Start listening.
+//    ApplicationStatusListener* my_listener =
+//        new ApplicationStatusListener(
+//            base::Bind(&OnApplicationStateChange));
+//
+//    ...
+//
+//    // Stop listening.
+//    delete my_listener
+//
+class BASE_EXPORT ApplicationStatusListener {
+ public:
+  typedef base::Callback<void(ApplicationState)> ApplicationStateChangeCallback;
+
+  explicit ApplicationStatusListener(
+      const ApplicationStateChangeCallback& callback);
+  ~ApplicationStatusListener();
+
+  // Internal use: must be public to be called from base_jni_registrar.cc
+  static bool RegisterBindings(JNIEnv* env);
+
+  // Internal use only: must be public to be called from JNI and unit tests.
+  static void NotifyApplicationStateChange(ApplicationState state);
+
+ private:
+  void Notify(ApplicationState state);
+
+  ApplicationStateChangeCallback callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(ApplicationStatusListener);
+};
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_APPLICATION_STATUS_LISTENER_H_
diff --git a/base/android/application_status_listener_unittest.cc b/base/android/application_status_listener_unittest.cc
new file mode 100644
index 0000000..ce78bf9
--- /dev/null
+++ b/base/android/application_status_listener_unittest.cc
@@ -0,0 +1,129 @@
+// 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.
+
+#include "base/android/application_status_listener.h"
+#include "base/bind.h"
+#include "base/callback_forward.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace android {
+
+namespace {
+
+using base::android::ScopedJavaLocalRef;
+
+// An invalid ApplicationState value.
+const ApplicationState kInvalidApplicationState =
+    static_cast<ApplicationState>(100);
+
+// Used to generate a callback that stores the new state at a given location.
+void StoreStateTo(ApplicationState* target, ApplicationState state) {
+  *target = state;
+}
+
+void RunTasksUntilIdle() {
+  RunLoop run_loop;
+  run_loop.RunUntilIdle();
+}
+
+// Shared state for the multi-threaded test.
+// This uses a thread to register for events and listen to them, while state
+// changes are forced on the main thread.
+class MultiThreadedTest {
+ public:
+  MultiThreadedTest()
+      : state_(kInvalidApplicationState),
+        event_(false, false),
+        thread_("ApplicationStatusTest thread"),
+        main_() {
+  }
+
+  void Run() {
+    // Start the thread and tell it to register for events.
+    thread_.Start();
+    thread_.task_runner()->PostTask(
+        FROM_HERE, base::Bind(&MultiThreadedTest::RegisterThreadForEvents,
+                              base::Unretained(this)));
+
+    // Wait for its completion.
+    event_.Wait();
+
+    // Change state, then wait for the thread to modify state.
+    ApplicationStatusListener::NotifyApplicationStateChange(
+        APPLICATION_STATE_HAS_RUNNING_ACTIVITIES);
+    event_.Wait();
+    EXPECT_EQ(APPLICATION_STATE_HAS_RUNNING_ACTIVITIES, state_);
+
+    // Again
+    ApplicationStatusListener::NotifyApplicationStateChange(
+        APPLICATION_STATE_HAS_DESTROYED_ACTIVITIES);
+    event_.Wait();
+    EXPECT_EQ(APPLICATION_STATE_HAS_DESTROYED_ACTIVITIES, state_);
+  }
+
+ private:
+  void ExpectOnThread() {
+    EXPECT_EQ(thread_.message_loop(), base::MessageLoop::current());
+  }
+
+  void RegisterThreadForEvents() {
+    ExpectOnThread();
+    listener_.reset(new ApplicationStatusListener(base::Bind(
+        &MultiThreadedTest::StoreStateAndSignal, base::Unretained(this))));
+    EXPECT_TRUE(listener_.get());
+    event_.Signal();
+  }
+
+  void StoreStateAndSignal(ApplicationState state) {
+    ExpectOnThread();
+    state_ = state;
+    event_.Signal();
+  }
+
+  ApplicationState state_;
+  base::WaitableEvent event_;
+  base::Thread thread_;
+  base::MessageLoop main_;
+  scoped_ptr<ApplicationStatusListener> listener_;
+};
+
+}  // namespace
+
+TEST(ApplicationStatusListenerTest, SingleThread) {
+  MessageLoop message_loop;
+
+  ApplicationState result = kInvalidApplicationState;
+
+  // Create a new listener that stores the new state into |result| on every
+  // state change.
+  ApplicationStatusListener listener(
+      base::Bind(&StoreStateTo, base::Unretained(&result)));
+
+  EXPECT_EQ(kInvalidApplicationState, result);
+
+  ApplicationStatusListener::NotifyApplicationStateChange(
+      APPLICATION_STATE_HAS_RUNNING_ACTIVITIES);
+  RunTasksUntilIdle();
+  EXPECT_EQ(APPLICATION_STATE_HAS_RUNNING_ACTIVITIES, result);
+
+  ApplicationStatusListener::NotifyApplicationStateChange(
+      APPLICATION_STATE_HAS_DESTROYED_ACTIVITIES);
+  RunTasksUntilIdle();
+  EXPECT_EQ(APPLICATION_STATE_HAS_DESTROYED_ACTIVITIES, result);
+}
+
+TEST(ApplicationStatusListenerTest, TwoThreads) {
+  MultiThreadedTest test;
+  test.Run();
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/base_jni_onload.cc b/base/android/base_jni_onload.cc
new file mode 100644
index 0000000..7ab4982
--- /dev/null
+++ b/base/android/base_jni_onload.cc
@@ -0,0 +1,57 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/base_jni_onload.h"
+
+#include "base/android/jni_android.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 {
+
+bool RegisterJNI(JNIEnv* env) {
+  return RegisterLibraryLoaderEntryHook(env);
+}
+
+bool Init() {
+  InitAtExitManager();
+  JNIEnv* env = base::android::AttachCurrentThread();
+  base::android::InitReplacementClassLoader(env,
+                                            base::android::GetClassLoader(env));
+  return true;
+}
+
+}  // namespace
+
+
+bool OnJNIOnLoadRegisterJNI(JavaVM* vm,
+                            std::vector<RegisterCallback> callbacks) {
+  base::android::InitVM(vm);
+  JNIEnv* env = base::android::AttachCurrentThread();
+
+  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;
+}
+
+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;
+  }
+  return true;
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/base_jni_onload.h b/base/android/base_jni_onload.h
new file mode 100644
index 0000000..dcc7756
--- /dev/null
+++ b/base/android/base_jni_onload.h
@@ -0,0 +1,32 @@
+// 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_BASE_JNI_ONLOAD_H_
+#define BASE_ANDROID_BASE_JNI_ONLOAD_H_
+
+#include <jni.h>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/callback.h"
+
+namespace base {
+namespace android {
+
+// 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 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
+
+#endif  // BASE_ANDROID_BASE_JNI_ONLOAD_H_
diff --git a/base/android/base_jni_registrar.cc b/base/android/base_jni_registrar.cc
new file mode 100644
index 0000000..752dcff
--- /dev/null
+++ b/base/android/base_jni_registrar.cc
@@ -0,0 +1,78 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/base_jni_registrar.h"
+
+#include "base/android/animation_frame_time_histogram.h"
+#include "base/android/apk_assets.h"
+#include "base/android/application_status_listener.h"
+#include "base/android/build_info.h"
+#include "base/android/command_line_android.h"
+#include "base/android/content_uri_utils.h"
+#include "base/android/cpu_features.h"
+#include "base/android/event_log.h"
+#include "base/android/field_trial_list.h"
+#include "base/android/important_file_writer_android.h"
+#include "base/android/java_handler_thread.h"
+#include "base/android/java_runtime.h"
+#include "base/android/jni_android.h"
+#include "base/android/jni_registrar.h"
+#include "base/android/jni_utils.h"
+#include "base/android/locale_utils.h"
+#include "base/android/memory_pressure_listener_android.h"
+#include "base/android/path_service_android.h"
+#include "base/android/path_utils.h"
+#include "base/android/record_histogram.h"
+#include "base/android/record_user_action.h"
+#include "base/android/sys_utils.h"
+#include "base/android/thread_utils.h"
+#include "base/android/trace_event_binding.h"
+#include "base/basictypes.h"
+#include "base/message_loop/message_pump_android.h"
+#include "base/power_monitor/power_monitor_device_source_android.h"
+#include "base/trace_event/trace_event.h"
+
+namespace base {
+namespace android {
+
+static RegistrationMethod kBaseRegisteredMethods[] = {
+    {"AnimationFrameTimeHistogram",
+     base::android::RegisterAnimationFrameTimeHistogram},
+    {"ApkAssets",
+     base::android::RegisterApkAssets},
+    {"ApplicationStatusListener",
+     base::android::ApplicationStatusListener::RegisterBindings},
+    {"BuildInfo", base::android::BuildInfo::RegisterBindings},
+    {"CommandLine", base::android::RegisterCommandLine},
+    {"ContentUriUtils", base::RegisterContentUriUtils},
+    {"CpuFeatures", base::android::RegisterCpuFeatures},
+    {"EventLog", base::android::RegisterEventLog},
+    {"FieldTrialList", base::android::RegisterFieldTrialList},
+    {"ImportantFileWriterAndroid",
+     base::android::RegisterImportantFileWriterAndroid},
+    {"JNIUtils", base::android::RegisterJNIUtils},
+    {"LocaleUtils", base::android::RegisterLocaleUtils},
+    {"MemoryPressureListenerAndroid",
+     base::android::MemoryPressureListenerAndroid::Register},
+    {"JavaHandlerThread", base::android::JavaHandlerThread::RegisterBindings},
+    {"PathService", base::android::RegisterPathService},
+    {"PathUtils", base::android::RegisterPathUtils},
+    {"PowerMonitor", base::RegisterPowerMonitor},
+    {"RecordHistogram", base::android::RegisterRecordHistogram},
+    {"RecordUserAction", base::android::RegisterRecordUserAction},
+    {"Runtime", base::android::JavaRuntime::Register},
+    {"SystemMessageHandler", base::MessagePumpForUI::RegisterBindings},
+    {"SysUtils", base::android::SysUtils::Register},
+    {"ThreadUtils", base::RegisterThreadUtils},
+    {"TraceEvent", base::android::RegisterTraceEvent},
+};
+
+bool RegisterJni(JNIEnv* env) {
+  TRACE_EVENT0("startup", "base_android::RegisterJni");
+  return RegisterNativeMethods(env, kBaseRegisteredMethods,
+                               arraysize(kBaseRegisteredMethods));
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/base_jni_registrar.h b/base/android/base_jni_registrar.h
new file mode 100644
index 0000000..fdaf5f2
--- /dev/null
+++ b/base/android/base_jni_registrar.h
@@ -0,0 +1,21 @@
+// Copyright (c) 2012 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_BASE_JNI_REGISTRAR_H_
+#define BASE_ANDROID_BASE_JNI_REGISTRAR_H_
+
+#include <jni.h>
+
+#include "base/base_export.h"
+
+namespace base {
+namespace android {
+
+// Register all JNI bindings necessary for base.
+BASE_EXPORT bool RegisterJni(JNIEnv* env);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_BASE_JNI_REGISTRAR_H_
diff --git a/base/android/build_info.cc b/base/android/build_info.cc
new file mode 100644
index 0000000..4d3cd55
--- /dev/null
+++ b/base/android/build_info.cc
@@ -0,0 +1,87 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/build_info.h"
+
+#include <string>
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/logging.h"
+#include "base/memory/singleton.h"
+#include "jni/BuildInfo_jni.h"
+
+namespace {
+
+// The caller takes ownership of the returned const char*.
+const char* StrDupJString(const base::android::JavaRef<jstring>& java_string) {
+  std::string str = ConvertJavaStringToUTF8(java_string);
+  return strdup(str.c_str());
+}
+
+}  // namespace
+
+namespace base {
+namespace android {
+
+struct BuildInfoSingletonTraits {
+  static BuildInfo* New() {
+    return new BuildInfo(AttachCurrentThread());
+  }
+
+  static void Delete(BuildInfo* x) {
+    // We're leaking this type, see kRegisterAtExit.
+    NOTREACHED();
+  }
+
+  static const bool kRegisterAtExit = false;
+#ifndef NDEBUG
+  static const bool kAllowedToAccessOnNonjoinableThread = true;
+#endif
+};
+
+BuildInfo::BuildInfo(JNIEnv* env)
+    : device_(StrDupJString(Java_BuildInfo_getDevice(env))),
+      manufacturer_(StrDupJString(Java_BuildInfo_getDeviceManufacturer(env))),
+      model_(StrDupJString(Java_BuildInfo_getDeviceModel(env))),
+      brand_(StrDupJString(Java_BuildInfo_getBrand(env))),
+      android_build_id_(StrDupJString(Java_BuildInfo_getAndroidBuildId(env))),
+      android_build_fp_(StrDupJString(
+          Java_BuildInfo_getAndroidBuildFingerprint(env))),
+      package_version_code_(StrDupJString(Java_BuildInfo_getPackageVersionCode(
+          env, GetApplicationContext()))),
+      package_version_name_(StrDupJString(Java_BuildInfo_getPackageVersionName(
+          env, GetApplicationContext()))),
+      package_label_(StrDupJString(Java_BuildInfo_getPackageLabel(
+          env, GetApplicationContext()))),
+      package_name_(StrDupJString(Java_BuildInfo_getPackageName(
+          env, GetApplicationContext()))),
+      build_type_(StrDupJString(Java_BuildInfo_getBuildType(env))),
+      sdk_int_(Java_BuildInfo_getSdkInt(env)),
+      java_exception_info_(NULL) {
+}
+
+// static
+BuildInfo* BuildInfo::GetInstance() {
+  return Singleton<BuildInfo, BuildInfoSingletonTraits >::get();
+}
+
+void BuildInfo::SetJavaExceptionInfo(const std::string& info) {
+  DCHECK(!java_exception_info_) << "info should be set only once.";
+  java_exception_info_ = strndup(info.c_str(), 4096);
+}
+
+void BuildInfo::ClearJavaExceptionInfo() {
+  delete java_exception_info_;
+  java_exception_info_ = nullptr;
+}
+
+// static
+bool BuildInfo::RegisterBindings(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/build_info.h b/base/android/build_info.h
new file mode 100644
index 0000000..093b832
--- /dev/null
+++ b/base/android/build_info.h
@@ -0,0 +1,139 @@
+// Copyright (c) 2012 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_BUILD_INFO_H_
+#define BASE_ANDROID_BUILD_INFO_H_
+
+#include <jni.h>
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/memory/singleton.h"
+
+namespace base {
+namespace android {
+
+// This enumeration maps to the values returned by BuildInfo::sdk_int(),
+// indicating the Android release associated with a given SDK version.
+enum SdkVersion {
+  SDK_VERSION_JELLY_BEAN = 16,
+  SDK_VERSION_JELLY_BEAN_MR1 = 17,
+  SDK_VERSION_JELLY_BEAN_MR2 = 18,
+  SDK_VERSION_KITKAT = 19,
+  SDK_VERSION_KITKAT_WEAR = 20,
+  SDK_VERSION_LOLLIPOP = 21,
+  SDK_VERSION_LOLLIPOP_MR1 = 22
+};
+
+// BuildInfo is a singleton class that stores android build and device
+// information. It will be called from Android specific code and gets used
+// primarily in crash reporting.
+
+// It is also used to store the last java exception seen during JNI.
+// TODO(nileshagrawal): Find a better place to store this info.
+class BASE_EXPORT BuildInfo {
+ public:
+
+  ~BuildInfo() {}
+
+  // Static factory method for getting the singleton BuildInfo instance.
+  // Note that ownership is not conferred on the caller and the BuildInfo in
+  // question isn't actually freed until shutdown. This is ok because there
+  // should only be one instance of BuildInfo ever created.
+  static BuildInfo* GetInstance();
+
+  // Const char* is used instead of std::strings because these values must be
+  // available even if the process is in a crash state. Sadly
+  // std::string.c_str() doesn't guarantee that memory won't be allocated when
+  // it is called.
+  const char* device() const {
+    return device_;
+  }
+
+  const char* manufacturer() const {
+    return manufacturer_;
+  }
+
+  const char* model() const {
+    return model_;
+  }
+
+  const char* brand() const {
+    return brand_;
+  }
+
+  const char* android_build_id() const {
+    return android_build_id_;
+  }
+
+  const char* android_build_fp() const {
+    return android_build_fp_;
+  }
+
+  const char* package_version_code() const {
+    return package_version_code_;
+  }
+
+  const char* package_version_name() const {
+    return package_version_name_;
+  }
+
+  const char* package_label() const {
+    return package_label_;
+  }
+
+  const char* package_name() const {
+    return package_name_;
+  }
+
+  const char* build_type() const {
+    return build_type_;
+  }
+
+  int sdk_int() const {
+    return sdk_int_;
+  }
+
+  const char* java_exception_info() const {
+    return java_exception_info_;
+  }
+
+  void SetJavaExceptionInfo(const std::string& info);
+
+  void ClearJavaExceptionInfo();
+
+  static bool RegisterBindings(JNIEnv* env);
+
+ private:
+  friend struct BuildInfoSingletonTraits;
+
+  explicit BuildInfo(JNIEnv* env);
+
+  // Const char* is used instead of std::strings because these values must be
+  // available even if the process is in a crash state. Sadly
+  // std::string.c_str() doesn't guarantee that memory won't be allocated when
+  // it is called.
+  const char* const device_;
+  const char* const manufacturer_;
+  const char* const model_;
+  const char* const brand_;
+  const char* const android_build_id_;
+  const char* const android_build_fp_;
+  const char* const package_version_code_;
+  const char* const package_version_name_;
+  const char* const package_label_;
+  const char* const package_name_;
+  const char* const build_type_;
+  const int sdk_int_;
+  // This is set via set_java_exception_info, not at constructor time.
+  const char* java_exception_info_;
+
+  DISALLOW_COPY_AND_ASSIGN(BuildInfo);
+};
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_BUILD_INFO_H_
diff --git a/base/android/command_line_android.cc b/base/android/command_line_android.cc
new file mode 100644
index 0000000..064450d
--- /dev/null
+++ b/base/android/command_line_android.cc
@@ -0,0 +1,86 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/command_line_android.h"
+
+#include "base/android/jni_array.h"
+#include "base/android/jni_string.h"
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "jni/CommandLine_jni.h"
+
+using base::android::ConvertUTF8ToJavaString;
+using base::android::ConvertJavaStringToUTF8;
+using base::CommandLine;
+
+namespace {
+
+void AppendJavaStringArrayToCommandLine(JNIEnv* env,
+                                        jobjectArray array,
+                                        bool includes_program) {
+  std::vector<std::string> vec;
+  if (array)
+    base::android::AppendJavaStringArrayToStringVector(env, array, &vec);
+  if (!includes_program)
+    vec.insert(vec.begin(), "");
+  CommandLine extra_command_line(vec);
+  CommandLine::ForCurrentProcess()->AppendArguments(extra_command_line,
+                                                    includes_program);
+}
+
+}  // namespace
+
+static void Reset(JNIEnv* env, jclass clazz) {
+  CommandLine::Reset();
+}
+
+static jboolean HasSwitch(JNIEnv* env, jclass clazz, jstring jswitch) {
+  std::string switch_string(ConvertJavaStringToUTF8(env, jswitch));
+  return CommandLine::ForCurrentProcess()->HasSwitch(switch_string);
+}
+
+static jstring GetSwitchValue(JNIEnv* env, jclass clazz, jstring jswitch) {
+  std::string switch_string(ConvertJavaStringToUTF8(env, jswitch));
+  std::string value(CommandLine::ForCurrentProcess()->GetSwitchValueNative(
+      switch_string));
+  if (value.empty())
+    return 0;
+  // OK to release, JNI binding.
+  return ConvertUTF8ToJavaString(env, value).Release();
+}
+
+static void AppendSwitch(JNIEnv* env, jclass clazz, jstring jswitch) {
+  std::string switch_string(ConvertJavaStringToUTF8(env, jswitch));
+  CommandLine::ForCurrentProcess()->AppendSwitch(switch_string);
+}
+
+static void AppendSwitchWithValue(JNIEnv* env, jclass clazz,
+                                  jstring jswitch, jstring jvalue) {
+  std::string switch_string(ConvertJavaStringToUTF8(env, jswitch));
+  std::string value_string (ConvertJavaStringToUTF8(env, jvalue));
+  CommandLine::ForCurrentProcess()->AppendSwitchASCII(switch_string,
+                                                      value_string);
+}
+
+static void AppendSwitchesAndArguments(JNIEnv* env, jclass clazz,
+                                       jobjectArray array) {
+  AppendJavaStringArrayToCommandLine(env, array, false);
+}
+
+namespace base {
+namespace android {
+
+void InitNativeCommandLineFromJavaArray(JNIEnv* env, jobjectArray array) {
+  // TODO(port): Make an overload of Init() that takes StringVector rather than
+  // have to round-trip via AppendArguments.
+  CommandLine::Init(0, NULL);
+  AppendJavaStringArrayToCommandLine(env, array, true);
+}
+
+bool RegisterCommandLine(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/command_line_android.h b/base/android/command_line_android.h
new file mode 100644
index 0000000..cf117e2
--- /dev/null
+++ b/base/android/command_line_android.h
@@ -0,0 +1,26 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_COMMAND_LINE_ANDROID_H_
+#define BASE_ANDROID_COMMAND_LINE_ANDROID_H_
+
+#include <jni.h>
+
+#include "base/base_export.h"
+
+namespace base {
+namespace android {
+
+// Appends all strings in the given array as flags to the Chrome command line.
+void BASE_EXPORT InitNativeCommandLineFromJavaArray(
+    JNIEnv* env,
+    jobjectArray init_command_line);
+
+// JNI registration boilerplate.
+bool RegisterCommandLine(JNIEnv* env);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_COMMAND_LINE_ANDROID_H_
diff --git a/base/android/content_uri_utils.cc b/base/android/content_uri_utils.cc
new file mode 100644
index 0000000..0482fee
--- /dev/null
+++ b/base/android/content_uri_utils.cc
@@ -0,0 +1,48 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/content_uri_utils.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "jni/ContentUriUtils_jni.h"
+
+using base::android::ConvertUTF8ToJavaString;
+
+namespace base {
+
+bool RegisterContentUriUtils(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+bool ContentUriExists(const FilePath& content_uri) {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  ScopedJavaLocalRef<jstring> j_uri =
+      ConvertUTF8ToJavaString(env, content_uri.value());
+  return Java_ContentUriUtils_contentUriExists(
+      env, base::android::GetApplicationContext(), j_uri.obj());
+}
+
+File OpenContentUriForRead(const FilePath& content_uri) {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  ScopedJavaLocalRef<jstring> j_uri =
+      ConvertUTF8ToJavaString(env, content_uri.value());
+  jint fd = Java_ContentUriUtils_openContentUriForRead(
+      env, base::android::GetApplicationContext(), j_uri.obj());
+  if (fd < 0)
+    return File();
+  return File(fd);
+}
+
+std::string GetContentUriMimeType(const FilePath& content_uri) {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  ScopedJavaLocalRef<jstring> j_uri =
+      ConvertUTF8ToJavaString(env, content_uri.value());
+  ScopedJavaLocalRef<jstring> j_mime =
+      Java_ContentUriUtils_getMimeType(
+          env, base::android::GetApplicationContext(), j_uri.obj());
+  return base::android::ConvertJavaStringToUTF8(env, j_mime.obj());
+}
+
+}  // namespace base
diff --git a/base/android/content_uri_utils.h b/base/android/content_uri_utils.h
new file mode 100644
index 0000000..e66b770
--- /dev/null
+++ b/base/android/content_uri_utils.h
@@ -0,0 +1,32 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_CONTENT_URI_UTILS_H_
+#define BASE_ANDROID_CONTENT_URI_UTILS_H_
+
+#include <jni.h>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+
+namespace base {
+
+bool RegisterContentUriUtils(JNIEnv* env);
+
+// Opens a content URI for read and returns the file descriptor to the caller.
+// Returns -1 if the URI is invalid.
+BASE_EXPORT File OpenContentUriForRead(const FilePath& content_uri);
+
+// Check whether a content URI exists.
+BASE_EXPORT bool ContentUriExists(const FilePath& content_uri);
+
+// Gets MIME type from a content URI. Returns an empty string if the URI is
+// invalid.
+BASE_EXPORT std::string GetContentUriMimeType(const FilePath& content_uri);
+
+}  // namespace base
+
+#endif  // BASE_ANDROID_CONTENT_URI_UTILS_H_
diff --git a/base/android/content_uri_utils_unittest.cc b/base/android/content_uri_utils_unittest.cc
new file mode 100644
index 0000000..c762035
--- /dev/null
+++ b/base/android/content_uri_utils_unittest.cc
@@ -0,0 +1,37 @@
+// 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.
+
+#include "base/android/content_uri_utils.h"
+#include "base/files/file_util.h"
+#include "base/path_service.h"
+#include "base/test/test_file_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace android {
+
+TEST(ContentUriUtilsTest, ContentUriMimeTest) {
+  // Get the test image path.
+  FilePath data_dir;
+  ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &data_dir));
+  data_dir = data_dir.AppendASCII("file_util");
+  ASSERT_TRUE(PathExists(data_dir));
+  FilePath image_file = data_dir.Append(FILE_PATH_LITERAL("red.png"));
+
+  // Insert the image into MediaStore. MediaStore will do some conversions, and
+  // return the content URI.
+  FilePath path = base::InsertImageIntoMediaStore(image_file);
+  EXPECT_TRUE(path.IsContentUri());
+  EXPECT_TRUE(PathExists(path));
+
+  std::string mime = GetContentUriMimeType(path);
+  EXPECT_EQ(mime, std::string("image/png"));
+
+  FilePath invalid_path("content://foo.bar");
+  mime = GetContentUriMimeType(invalid_path);
+  EXPECT_TRUE(mime.empty());
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/cpu_features.cc b/base/android/cpu_features.cc
new file mode 100644
index 0000000..6a18695
--- /dev/null
+++ b/base/android/cpu_features.cc
@@ -0,0 +1,26 @@
+// Copyright (c) 2012 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 <cpu-features.h>
+
+#include "base/android/jni_android.h"
+#include "jni/CpuFeatures_jni.h"
+
+namespace base {
+namespace android {
+
+jint GetCoreCount(JNIEnv*, jclass) {
+  return android_getCpuCount();
+}
+
+jlong GetCpuFeatures(JNIEnv*, jclass) {
+  return android_getCpuFeatures();
+}
+
+bool RegisterCpuFeatures(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/cpu_features.h b/base/android/cpu_features.h
new file mode 100644
index 0000000..0a27822
--- /dev/null
+++ b/base/android/cpu_features.h
@@ -0,0 +1,18 @@
+// Copyright (c) 2012 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_CPU_FEATURES_H_
+#define BASE_ANDROID_CPU_FEATURES_H_
+
+#include <jni.h>
+
+namespace base {
+namespace android {
+
+bool RegisterCpuFeatures(JNIEnv* env);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_CPU_FEATURES_H_
diff --git a/base/android/event_log.cc b/base/android/event_log.cc
new file mode 100644
index 0000000..a4b1dd1
--- /dev/null
+++ b/base/android/event_log.cc
@@ -0,0 +1,20 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/event_log.h"
+#include "jni/EventLog_jni.h"
+
+namespace base {
+namespace android {
+
+void EventLogWriteInt(int tag, int value) {
+  Java_EventLog_writeEvent(AttachCurrentThread(), tag, value);
+}
+
+bool RegisterEventLog(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/event_log.h b/base/android/event_log.h
new file mode 100644
index 0000000..dad4e4c
--- /dev/null
+++ b/base/android/event_log.h
@@ -0,0 +1,22 @@
+// 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.
+
+#ifndef BASE_ANDROID_EVENT_LOG_H_
+#define BASE_ANDROID_EVENT_LOG_H_
+
+#include <jni.h>
+
+#include "base/base_export.h"
+
+namespace base {
+namespace android {
+
+void BASE_EXPORT EventLogWriteInt(int tag, int value);
+
+bool RegisterEventLog(JNIEnv* env);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_EVENT_LOG_H_
diff --git a/base/android/field_trial_list.cc b/base/android/field_trial_list.cc
new file mode 100644
index 0000000..9cb38d2
--- /dev/null
+++ b/base/android/field_trial_list.cc
@@ -0,0 +1,38 @@
+// 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.
+
+#include "base/android/field_trial_list.h"
+
+#include <jni.h>
+
+#include "base/android/jni_string.h"
+#include "base/metrics/field_trial.h"
+#include "jni/FieldTrialList_jni.h"
+
+using base::android::ConvertJavaStringToUTF8;
+using base::android::ConvertUTF8ToJavaString;
+
+static jstring FindFullName(JNIEnv* env,
+                            jclass clazz,
+                            jstring jtrial_name) {
+  std::string trial_name(ConvertJavaStringToUTF8(env, jtrial_name));
+  return ConvertUTF8ToJavaString(
+      env,
+      base::FieldTrialList::FindFullName(trial_name)).Release();
+}
+
+static jboolean TrialExists(JNIEnv* env, jclass clazz, jstring jtrial_name) {
+  std::string trial_name(ConvertJavaStringToUTF8(env, jtrial_name));
+  return base::FieldTrialList::TrialExists(trial_name);
+}
+
+namespace base {
+namespace android {
+
+bool RegisterFieldTrialList(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/field_trial_list.h b/base/android/field_trial_list.h
new file mode 100644
index 0000000..b4eaf91
--- /dev/null
+++ b/base/android/field_trial_list.h
@@ -0,0 +1,18 @@
+// 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.
+
+#ifndef BASE_ANDROID_FIELD_TRIAL_LIST_H_
+#define BASE_ANDROID_FIELD_TRIAL_LIST_H_
+
+#include <jni.h>
+
+namespace base {
+namespace android {
+
+bool RegisterFieldTrialList(JNIEnv* env);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_FIELD_TRIAL_LIST_H_
diff --git a/base/android/fifo_utils.cc b/base/android/fifo_utils.cc
new file mode 100644
index 0000000..8f3e95f
--- /dev/null
+++ b/base/android/fifo_utils.cc
@@ -0,0 +1,25 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/fifo_utils.h"
+
+#include <sys/stat.h>
+
+#include "base/files/file_path.h"
+
+namespace base {
+namespace android {
+
+bool CreateFIFO(const FilePath& path, int mode) {
+  // Default permissions for mkfifo() is ignored, chmod() is required.
+  return mkfifo(path.value().c_str(), mode) == 0 &&
+         chmod(path.value().c_str(), mode) == 0;
+}
+
+bool RedirectStream(FILE* stream, const FilePath& path, const char* mode) {
+  return freopen(path.value().c_str(), mode, stream) != NULL;
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/fifo_utils.h b/base/android/fifo_utils.h
new file mode 100644
index 0000000..1936def
--- /dev/null
+++ b/base/android/fifo_utils.h
@@ -0,0 +1,32 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_FIFO_UTILS_H_
+#define BASE_ANDROID_FIFO_UTILS_H_
+
+#include <stdio.h>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+
+class FilePath;
+
+namespace android {
+
+// Creates a fifo at the given |path| with POSIX permissions set to |mode|,
+// returning true if it was successfully created and permissions were set.
+BASE_EXPORT bool CreateFIFO(const FilePath& path, int mode);
+
+// Redirects the |stream| to the file provided by |path| with |mode|
+// permissions, returning true if successful.
+BASE_EXPORT bool RedirectStream(FILE* stream,
+                                const FilePath& path,
+                                const char* mode);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_FIFO_UTILS_H_
diff --git a/base/android/important_file_writer_android.cc b/base/android/important_file_writer_android.cc
new file mode 100644
index 0000000..bcbd785
--- /dev/null
+++ b/base/android/important_file_writer_android.cc
@@ -0,0 +1,42 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/important_file_writer_android.h"
+
+#include <string>
+
+#include "base/android/jni_string.h"
+#include "base/files/important_file_writer.h"
+#include "base/threading/thread_restrictions.h"
+#include "jni/ImportantFileWriterAndroid_jni.h"
+
+namespace base {
+namespace android {
+
+static jboolean WriteFileAtomically(JNIEnv* env,
+                                    jclass /* clazz */,
+                                    jstring file_name,
+                                    jbyteArray data) {
+  // This is called on the UI thread during shutdown to save tab data, so
+  // needs to enable IO.
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
+  std::string native_file_name;
+  base::android::ConvertJavaStringToUTF8(env, file_name, &native_file_name);
+  base::FilePath path(native_file_name);
+  int data_length = env->GetArrayLength(data);
+  jbyte* native_data = env->GetByteArrayElements(data, NULL);
+  std::string native_data_string(reinterpret_cast<char *>(native_data),
+                                 data_length);
+  bool result = base::ImportantFileWriter::WriteFileAtomically(
+      path, native_data_string);
+  env->ReleaseByteArrayElements(data, native_data, JNI_ABORT);
+  return result;
+}
+
+bool RegisterImportantFileWriterAndroid(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/important_file_writer_android.h b/base/android/important_file_writer_android.h
new file mode 100644
index 0000000..88e4441
--- /dev/null
+++ b/base/android/important_file_writer_android.h
@@ -0,0 +1,18 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_IMPORTANT_FILE_WRITER_ANDROID_H_
+#define BASE_ANDROID_IMPORTANT_FILE_WRITER_ANDROID_H_
+
+#include <jni.h>
+
+namespace base {
+namespace android {
+
+bool RegisterImportantFileWriterAndroid(JNIEnv* env);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_IMPORTANT_FILE_WRITER_ANDROID_H_
diff --git a/base/android/java/src/org/chromium/base/ActivityState.java b/base/android/java/src/org/chromium/base/ActivityState.java
new file mode 100644
index 0000000..98aff62
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/ActivityState.java
@@ -0,0 +1,40 @@
+// 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;
+
+/**
+ * A set of states that represent the last state change of an Activity.
+ */
+public interface ActivityState {
+    /**
+     * Represents Activity#onCreate().
+     */
+    public final int CREATED = 1;
+
+    /**
+     * Represents Activity#onStart().
+     */
+    public final int STARTED = 2;
+
+    /**
+     * Represents Activity#onResume().
+     */
+    public final int RESUMED = 3;
+
+    /**
+     * Represents Activity#onPause().
+     */
+    public final int PAUSED = 4;
+
+    /**
+     * Represents Activity#onStop().
+     */
+    public final int STOPPED = 5;
+
+    /**
+     * Represents Activity#onDestroy().  This is also used when the state of an Activity is unknown.
+     */
+    public final int DESTROYED = 6;
+}
diff --git a/base/android/java/src/org/chromium/base/AnimationFrameTimeHistogram.java b/base/android/java/src/org/chromium/base/AnimationFrameTimeHistogram.java
new file mode 100644
index 0000000..ad5cdd8
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/AnimationFrameTimeHistogram.java
@@ -0,0 +1,145 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.TimeAnimator;
+import android.animation.TimeAnimator.TimeListener;
+import android.util.Log;
+
+/**
+ * Record Android animation frame rate and save it to UMA histogram. This is mainly for monitoring
+ * any jankiness of short Chrome Android animations. It is limited to few seconds of recording.
+ */
+public class AnimationFrameTimeHistogram {
+    private static final String TAG = "AnimationFrameTimeHistogram";
+    private static final int MAX_FRAME_TIME_NUM = 600; // 10 sec on 60 fps.
+
+    private final Recorder mRecorder = new Recorder();
+    private final String mHistogramName;
+
+    /**
+     * @param histogramName The histogram name that the recorded frame times will be saved.
+     *                      This must be also defined in histograms.xml
+     * @return An AnimatorListener instance that records frame time histogram on start and end
+     *         automatically.
+     */
+    public static AnimatorListener getAnimatorRecorder(final String histogramName) {
+        return new AnimatorListenerAdapter() {
+            private final AnimationFrameTimeHistogram mAnimationFrameTimeHistogram =
+                    new AnimationFrameTimeHistogram(histogramName);
+
+            @Override
+            public void onAnimationStart(Animator animation) {
+                mAnimationFrameTimeHistogram.startRecording();
+            }
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mAnimationFrameTimeHistogram.endRecording();
+            }
+
+            @Override
+            public void onAnimationCancel(Animator animation) {
+                mAnimationFrameTimeHistogram.endRecording();
+            }
+        };
+    }
+
+    /**
+     * @param histogramName The histogram name that the recorded frame times will be saved.
+     *                      This must be also defined in histograms.xml
+     */
+    public AnimationFrameTimeHistogram(String histogramName) {
+        mHistogramName = histogramName;
+    }
+
+    /**
+     * Start recording frame times. The recording can fail if it exceeds a few seconds.
+     */
+    public void startRecording() {
+        mRecorder.startRecording();
+    }
+
+    /**
+     * End recording and save it to histogram. It won't save histogram if the recording wasn't
+     * successful.
+     */
+    public void endRecording() {
+        if (mRecorder.endRecording()) {
+            nativeSaveHistogram(mHistogramName,
+                    mRecorder.getFrameTimesMs(), mRecorder.getFrameTimesCount());
+        }
+        mRecorder.cleanUp();
+    }
+
+    /**
+     * Record Android animation frame rate and return the result.
+     */
+    private static class Recorder implements TimeListener {
+        // TODO(kkimlabs): If we can use in the future, migrate to Choreographer for minimal
+        //                 workload.
+        private final TimeAnimator mAnimator = new TimeAnimator();
+        private long[] mFrameTimesMs;
+        private int mFrameTimesCount;
+
+        private Recorder() {
+            mAnimator.setTimeListener(this);
+        }
+
+        private void startRecording() {
+            assert !mAnimator.isRunning();
+            mFrameTimesCount = 0;
+            mFrameTimesMs = new long[MAX_FRAME_TIME_NUM];
+            mAnimator.start();
+        }
+
+        /**
+         * @return Whether the recording was successful. If successful, the result is available via
+         *         getFrameTimesNs and getFrameTimesCount.
+         */
+        private boolean endRecording() {
+            boolean succeeded = mAnimator.isStarted();
+            mAnimator.end();
+            return succeeded;
+        }
+
+        private long[] getFrameTimesMs() {
+            return mFrameTimesMs;
+        }
+
+        private int getFrameTimesCount() {
+            return mFrameTimesCount;
+        }
+
+        /**
+         * Deallocates the temporary buffer to record frame times. Must be called after ending
+         * the recording and getting the result.
+         */
+        private void cleanUp() {
+            mFrameTimesMs = null;
+        }
+
+        @Override
+        public void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime) {
+            if (mFrameTimesCount == mFrameTimesMs.length) {
+                mAnimator.end();
+                cleanUp();
+                Log.w(TAG, "Animation frame time recording reached the maximum number. It's either"
+                        + "the animation took too long or recording end is not called.");
+                return;
+            }
+
+            // deltaTime is 0 for the first frame.
+            if (deltaTime > 0) {
+                mFrameTimesMs[mFrameTimesCount++] = deltaTime;
+            }
+        }
+    }
+
+    private native void nativeSaveHistogram(String histogramName, long[] frameTimesMs, int count);
+}
diff --git a/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java b/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java
new file mode 100644
index 0000000..b3eff94
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java
@@ -0,0 +1,418 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.annotation.TargetApi;
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.PendingIntent;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.content.res.Resources.NotFoundException;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.os.PowerManager;
+import android.provider.Settings;
+import android.view.View;
+import android.view.ViewGroup.MarginLayoutParams;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.TextView;
+
+/**
+ * Utility class to use new APIs that were added after ICS (API level 14).
+ */
+@TargetApi(Build.VERSION_CODES.LOLLIPOP)
+public class ApiCompatibilityUtils {
+    private ApiCompatibilityUtils() {
+    }
+
+    /**
+     * Returns true if view's layout direction is right-to-left.
+     *
+     * @param view the View whose layout is being considered
+     */
+    public static boolean isLayoutRtl(View view) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            return view.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
+        } else {
+            // All layouts are LTR before JB MR1.
+            return false;
+        }
+    }
+
+    /**
+     * @see Configuration#getLayoutDirection()
+     */
+    public static int getLayoutDirection(Configuration configuration) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            return configuration.getLayoutDirection();
+        } else {
+            // All layouts are LTR before JB MR1.
+            return View.LAYOUT_DIRECTION_LTR;
+        }
+    }
+
+    /**
+     * @return True if the running version of the Android supports printing.
+     */
+    public static boolean isPrintingSupported() {
+        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
+    }
+
+    /**
+     * @see android.view.View#setLayoutDirection(int)
+     */
+    public static void setLayoutDirection(View view, int layoutDirection) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            view.setLayoutDirection(layoutDirection);
+        } else {
+            // Do nothing. RTL layouts aren't supported before JB MR1.
+        }
+    }
+
+    /**
+     * @see android.view.View#setTextAlignment(int)
+     */
+    public static void setTextAlignment(View view, int textAlignment) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            view.setTextAlignment(textAlignment);
+        } else {
+            // Do nothing. RTL text isn't supported before JB MR1.
+        }
+    }
+
+    /**
+     * @see android.view.View#setTextDirection(int)
+     */
+    public static void setTextDirection(View view, int textDirection) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            view.setTextDirection(textDirection);
+        } else {
+            // Do nothing. RTL text isn't supported before JB MR1.
+        }
+    }
+
+    /**
+     * @see android.view.ViewGroup.MarginLayoutParams#setMarginEnd(int)
+     */
+    public static void setMarginEnd(MarginLayoutParams layoutParams, int end) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            layoutParams.setMarginEnd(end);
+        } else {
+            layoutParams.rightMargin = end;
+        }
+    }
+
+    /**
+     * @see android.view.ViewGroup.MarginLayoutParams#getMarginEnd()
+     */
+    public static int getMarginEnd(MarginLayoutParams layoutParams) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            return layoutParams.getMarginEnd();
+        } else {
+            return layoutParams.rightMargin;
+        }
+    }
+
+    /**
+     * @see android.view.ViewGroup.MarginLayoutParams#setMarginStart(int)
+     */
+    public static void setMarginStart(MarginLayoutParams layoutParams, int start) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            layoutParams.setMarginStart(start);
+        } else {
+            layoutParams.leftMargin = start;
+        }
+    }
+
+    /**
+     * @see android.view.ViewGroup.MarginLayoutParams#getMarginStart()
+     */
+    public static int getMarginStart(MarginLayoutParams layoutParams) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            return layoutParams.getMarginStart();
+        } else {
+            return layoutParams.leftMargin;
+        }
+    }
+
+    /**
+     * @see android.view.View#setPaddingRelative(int, int, int, int)
+     */
+    public static void setPaddingRelative(View view, int start, int top, int end, int bottom) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            view.setPaddingRelative(start, top, end, bottom);
+        } else {
+            // Before JB MR1, all layouts are left-to-right, so start == left, etc.
+            view.setPadding(start, top, end, bottom);
+        }
+    }
+
+    /**
+     * @see android.view.View#getPaddingStart()
+     */
+    public static int getPaddingStart(View view) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            return view.getPaddingStart();
+        } else {
+            // Before JB MR1, all layouts are left-to-right, so start == left.
+            return view.getPaddingLeft();
+        }
+    }
+
+    /**
+     * @see android.view.View#getPaddingEnd()
+     */
+    public static int getPaddingEnd(View view) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            return view.getPaddingEnd();
+        } else {
+            // Before JB MR1, all layouts are left-to-right, so end == right.
+            return view.getPaddingRight();
+        }
+    }
+
+    /**
+     * @see android.widget.TextView#setCompoundDrawablesRelative(Drawable, Drawable, Drawable,
+     *      Drawable)
+     */
+    public static void setCompoundDrawablesRelative(TextView textView, Drawable start, Drawable top,
+            Drawable end, Drawable bottom) {
+        if (Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            // On JB MR1, due to a platform bug, setCompoundDrawablesRelative() is a no-op if the
+            // view has ever been measured. As a workaround, use setCompoundDrawables() directly.
+            // See: http://crbug.com/368196 and http://crbug.com/361709
+            boolean isRtl = isLayoutRtl(textView);
+            textView.setCompoundDrawables(isRtl ? end : start, top, isRtl ? start : end, bottom);
+        } else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            textView.setCompoundDrawablesRelative(start, top, end, bottom);
+        } else {
+            textView.setCompoundDrawables(start, top, end, bottom);
+        }
+    }
+
+    /**
+     * @see android.widget.TextView#setCompoundDrawablesRelativeWithIntrinsicBounds(Drawable,
+     *      Drawable, Drawable, Drawable)
+     */
+    public static void setCompoundDrawablesRelativeWithIntrinsicBounds(TextView textView,
+            Drawable start, Drawable top, Drawable end, Drawable bottom) {
+        if (Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            // Work around the platform bug described in setCompoundDrawablesRelative() above.
+            boolean isRtl = isLayoutRtl(textView);
+            textView.setCompoundDrawablesWithIntrinsicBounds(isRtl ? end : start, top,
+                    isRtl ? start : end, bottom);
+        } else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            textView.setCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom);
+        } else {
+            textView.setCompoundDrawablesWithIntrinsicBounds(start, top, end, bottom);
+        }
+    }
+
+    /**
+     * @see android.widget.TextView#setCompoundDrawablesRelativeWithIntrinsicBounds(int, int, int,
+     *      int)
+     */
+    public static void setCompoundDrawablesRelativeWithIntrinsicBounds(TextView textView,
+            int start, int top, int end, int bottom) {
+        if (Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            // Work around the platform bug described in setCompoundDrawablesRelative() above.
+            boolean isRtl = isLayoutRtl(textView);
+            textView.setCompoundDrawablesWithIntrinsicBounds(isRtl ? end : start, top,
+                    isRtl ? start : end, bottom);
+        } else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            textView.setCompoundDrawablesRelativeWithIntrinsicBounds(start, top, end, bottom);
+        } else {
+            textView.setCompoundDrawablesWithIntrinsicBounds(start, top, end, bottom);
+        }
+    }
+
+    // These methods have a new name, and the old name is deprecated.
+
+    /**
+     * @see android.app.PendingIntent#getCreatorPackage()
+     */
+    @SuppressWarnings("deprecation")
+    public static String getCreatorPackage(PendingIntent intent) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+            return intent.getCreatorPackage();
+        } else {
+            return intent.getTargetPackage();
+        }
+    }
+
+    /**
+     * @see android.provider.Settings.Global#DEVICE_PROVISIONED
+     */
+    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
+    public static boolean isDeviceProvisioned(Context context) {
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) return true;
+        if (context == null) return true;
+        if (context.getContentResolver() == null) return true;
+        return Settings.Global.getInt(
+                context.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0) != 0;
+    }
+
+    /**
+     * @see android.app.Activity#finishAndRemoveTask()
+     */
+    public static void finishAndRemoveTask(Activity activity) {
+        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
+            activity.finishAndRemoveTask();
+        } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP) {
+            // crbug.com/395772 : Fallback for Activity.finishAndRemoveTask() failing.
+            new FinishAndRemoveTaskWithRetry(activity).run();
+        } else {
+            activity.finish();
+        }
+    }
+
+    private static class FinishAndRemoveTaskWithRetry implements Runnable {
+        private static final long RETRY_DELAY_MS = 500;
+        private static final long MAX_TRY_COUNT = 3;
+        private final Activity mActivity;
+        private int mTryCount;
+
+        FinishAndRemoveTaskWithRetry(Activity activity) {
+            mActivity = activity;
+        }
+
+        @Override
+        public void run() {
+            mActivity.finishAndRemoveTask();
+            mTryCount++;
+            if (!mActivity.isFinishing()) {
+                if (mTryCount < MAX_TRY_COUNT) {
+                    ThreadUtils.postOnUiThreadDelayed(this, RETRY_DELAY_MS);
+                } else {
+                    mActivity.finish();
+                }
+            }
+        }
+    }
+
+    /**
+     * @return Whether the screen of the device is interactive.
+     */
+    @SuppressWarnings("deprecation")
+    public static boolean isInteractive(Context context) {
+        PowerManager manager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
+            return manager.isInteractive();
+        } else {
+            return manager.isScreenOn();
+        }
+    }
+
+    @SuppressWarnings("deprecation")
+    public static int getActivityNewDocumentFlag() {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            return Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
+        } else {
+            return Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET;
+        }
+    }
+
+    /**
+     * @see android.provider.Settings.Secure#SKIP_FIRST_USE_HINTS
+     */
+    public static boolean shouldSkipFirstUseHints(ContentResolver contentResolver) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            return Settings.Secure.getInt(
+                    contentResolver, Settings.Secure.SKIP_FIRST_USE_HINTS, 0) != 0;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * @param activity Activity that should get the task description update.
+     * @param title Title of the activity.
+     * @param icon Icon of the activity.
+     * @param color Color of the activity.
+     */
+    public static void setTaskDescription(Activity activity, String title, Bitmap icon, int color) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            ActivityManager.TaskDescription description =
+                    new ActivityManager.TaskDescription(title, icon, color);
+            activity.setTaskDescription(description);
+        }
+    }
+
+    /**
+     * @see android.view.Window#setStatusBarColor(int color).
+     * TODO(ianwen): remove this method after downstream rolling.
+     */
+    public static void setStatusBarColor(Activity activity, int statusBarColor) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            // If both system bars are black, we can remove these from our layout,
+            // removing or shrinking the SurfaceFlinger overlay required for our views.
+            Window window = activity.getWindow();
+            if (statusBarColor == Color.BLACK && window.getNavigationBarColor() == Color.BLACK) {
+                window.clearFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+            } else {
+                window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+            }
+            window.setStatusBarColor(statusBarColor);
+        }
+    }
+
+    /**
+     * @see android.view.Window#setStatusBarColor(int color).
+     */
+    public static void setStatusBarColor(Window window, int statusBarColor) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            // If both system bars are black, we can remove these from our layout,
+            // removing or shrinking the SurfaceFlinger overlay required for our views.
+            if (statusBarColor == Color.BLACK && window.getNavigationBarColor() == Color.BLACK) {
+                window.clearFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+            } else {
+                window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+            }
+            window.setStatusBarColor(statusBarColor);
+        }
+    }
+
+    /**
+     * @see android.content.res.Resources#getDrawable(int id).
+     */
+    @SuppressWarnings("deprecation")
+    public static Drawable getDrawable(Resources res, int id) throws NotFoundException {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            return res.getDrawable(id, null);
+        } else {
+            return res.getDrawable(id);
+        }
+    }
+
+    /**
+     * @see android.content.res.Resources#getDrawableForDensity(int id, int density).
+     */
+    @SuppressWarnings("deprecation")
+    public static Drawable getDrawableForDensity(Resources res, int id, int density) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            return res.getDrawableForDensity(id, density, null);
+        } else {
+            return res.getDrawableForDensity(id, density);
+        }
+    }
+
+    /**
+     * @see android.app.Activity#finishAfterTransition().
+     */
+    public static void finishAfterTransition(Activity activity) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            activity.finishAfterTransition();
+        } else {
+            activity.finish();
+        }
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/ApkAssets.java b/base/android/java/src/org/chromium/base/ApkAssets.java
new file mode 100644
index 0000000..329660f
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/ApkAssets.java
@@ -0,0 +1,45 @@
+// 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;
+
+import android.content.Context;
+import android.content.res.AssetFileDescriptor;
+import android.content.res.AssetManager;
+import android.util.Log;
+
+import java.io.IOException;
+
+/**
+ * A utility class to retrieve references to uncompressed assets insides the apk. A reference is
+ * defined as tuple (file descriptor, offset, size) enabling direct mapping without deflation.
+ * This can be used even within the renderer process, since it just dup's the apk's fd.
+ */
+@JNINamespace("base::android")
+public class ApkAssets {
+    private static final String LOGTAG = "ApkAssets";
+
+    @CalledByNative
+    public static long[] open(Context context, String fileName) {
+        AssetFileDescriptor afd = null;
+        try {
+            AssetManager manager = context.getAssets();
+            afd = manager.openNonAssetFd(fileName);
+            return new long[] { afd.getParcelFileDescriptor().detachFd(),
+                                afd.getStartOffset(),
+                                afd.getLength() };
+        } catch (IOException e) {
+            Log.e(LOGTAG, "Error while loading asset " + fileName + ": " + e);
+            return new long[] {-1, -1, -1};
+        } finally {
+            try {
+                if (afd != null) {
+                    afd.close();
+                }
+            } catch (IOException e2) {
+                Log.e(LOGTAG, "Unable to close AssetFileDescriptor", e2);
+            }
+        }
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/ApplicationStatus.java b/base/android/java/src/org/chromium/base/ApplicationStatus.java
new file mode 100644
index 0000000..8c36b61
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/ApplicationStatus.java
@@ -0,0 +1,448 @@
+// 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;
+
+import android.app.Activity;
+import android.app.Application;
+import android.app.Application.ActivityLifecycleCallbacks;
+import android.content.Context;
+import android.os.Bundle;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Provides information about the current activity's status, and a way
+ * to register / unregister listeners for state changes.
+ */
+@JNINamespace("base::android")
+public class ApplicationStatus {
+    private static class ActivityInfo {
+        private int mStatus = ActivityState.DESTROYED;
+        private ObserverList<ActivityStateListener> mListeners =
+                new ObserverList<ActivityStateListener>();
+
+        /**
+         * @return The current {@link ActivityState} of the activity.
+         */
+        public int getStatus() {
+            return mStatus;
+        }
+
+        /**
+         * @param status The new {@link ActivityState} of the activity.
+         */
+        public void setStatus(int status) {
+            mStatus = status;
+        }
+
+        /**
+         * @return A list of {@link ActivityStateListener}s listening to this activity.
+         */
+        public ObserverList<ActivityStateListener> getListeners() {
+            return mListeners;
+        }
+    }
+
+    private static Application sApplication;
+
+    private static Object sCachedApplicationStateLock = new Object();
+    private static Integer sCachedApplicationState;
+
+    /** Last activity that was shown (or null if none or it was destroyed). */
+    private static Activity sActivity;
+
+    /** A lazily initialized listener that forwards application state changes to native. */
+    private static ApplicationStateListener sNativeApplicationStateListener;
+
+    /**
+     * A map of which observers listen to state changes from which {@link Activity}.
+     */
+    private static final Map<Activity, ActivityInfo> sActivityInfo =
+            new ConcurrentHashMap<Activity, ActivityInfo>();
+
+    /**
+     * A list of observers to be notified when any {@link Activity} has a state change.
+     */
+    private static final ObserverList<ActivityStateListener> sGeneralActivityStateListeners =
+            new ObserverList<ActivityStateListener>();
+
+    /**
+     * A list of observers to be notified when the visibility state of this {@link Application}
+     * changes.  See {@link #getStateForApplication()}.
+     */
+    private static final ObserverList<ApplicationStateListener> sApplicationStateListeners =
+            new ObserverList<ApplicationStateListener>();
+
+    /**
+     * Interface to be implemented by listeners.
+     */
+    public interface ApplicationStateListener {
+        /**
+         * Called when the application's state changes.
+         * @param newState The application state.
+         */
+        public void onApplicationStateChange(int newState);
+    }
+
+    /**
+     * Interface to be implemented by listeners.
+     */
+    public interface ActivityStateListener {
+        /**
+         * Called when the activity's state changes.
+         * @param activity The activity that had a state change.
+         * @param newState New activity state.
+         */
+        public void onActivityStateChange(Activity activity, int newState);
+    }
+
+    private ApplicationStatus() {}
+
+    /**
+     * Initializes the activity status for a specified application.
+     *
+     * @param application The application whose status you wish to monitor.
+     */
+    public static void initialize(BaseChromiumApplication application) {
+        sApplication = application;
+
+        application.registerWindowFocusChangedListener(
+                new BaseChromiumApplication.WindowFocusChangedListener() {
+                    @Override
+                    public void onWindowFocusChanged(Activity activity, boolean hasFocus) {
+                        if (!hasFocus || activity == sActivity) return;
+
+                        int state = getStateForActivity(activity);
+
+                        if (state != ActivityState.DESTROYED && state != ActivityState.STOPPED) {
+                            sActivity = activity;
+                        }
+
+                        // TODO(dtrainor): Notify of active activity change?
+                    }
+                });
+
+        application.registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
+            @Override
+            public void onActivityCreated(final Activity activity, Bundle savedInstanceState) {
+                onStateChange(activity, ActivityState.CREATED);
+            }
+
+            @Override
+            public void onActivityDestroyed(Activity activity) {
+                onStateChange(activity, ActivityState.DESTROYED);
+            }
+
+            @Override
+            public void onActivityPaused(Activity activity) {
+                onStateChange(activity, ActivityState.PAUSED);
+            }
+
+            @Override
+            public void onActivityResumed(Activity activity) {
+                onStateChange(activity, ActivityState.RESUMED);
+            }
+
+            @Override
+            public void onActivitySaveInstanceState(Activity activity, Bundle outState) {}
+
+            @Override
+            public void onActivityStarted(Activity activity) {
+                onStateChange(activity, ActivityState.STARTED);
+            }
+
+            @Override
+            public void onActivityStopped(Activity activity) {
+                onStateChange(activity, ActivityState.STOPPED);
+            }
+        });
+    }
+
+    /**
+     * Must be called by the main activity when it changes state.
+     *
+     * @param activity Current activity.
+     * @param newState New state value.
+     */
+    private static void onStateChange(Activity activity, int newState) {
+        if (activity == null) throw new IllegalArgumentException("null activity is not supported");
+
+        if (sActivity == null
+                || newState == ActivityState.CREATED
+                || newState == ActivityState.RESUMED
+                || newState == ActivityState.STARTED) {
+            sActivity = activity;
+        }
+
+        int oldApplicationState = getStateForApplication();
+
+        if (newState == ActivityState.CREATED) {
+            assert !sActivityInfo.containsKey(activity);
+            sActivityInfo.put(activity, new ActivityInfo());
+        }
+
+        // Invalidate the cached application state.
+        synchronized (sCachedApplicationStateLock) {
+            sCachedApplicationState = null;
+        }
+
+        ActivityInfo info = sActivityInfo.get(activity);
+        info.setStatus(newState);
+
+        // Notify all state observers that are specifically listening to this activity.
+        for (ActivityStateListener listener : info.getListeners()) {
+            listener.onActivityStateChange(activity, newState);
+        }
+
+        // Notify all state observers that are listening globally for all activity state
+        // changes.
+        for (ActivityStateListener listener : sGeneralActivityStateListeners) {
+            listener.onActivityStateChange(activity, newState);
+        }
+
+        int applicationState = getStateForApplication();
+        if (applicationState != oldApplicationState) {
+            for (ApplicationStateListener listener : sApplicationStateListeners) {
+                listener.onApplicationStateChange(applicationState);
+            }
+        }
+
+        if (newState == ActivityState.DESTROYED) {
+            sActivityInfo.remove(activity);
+            if (activity == sActivity) sActivity = null;
+        }
+    }
+
+    /**
+     * Testing method to update the state of the specified activity.
+     */
+    @VisibleForTesting
+    public static void onStateChangeForTesting(Activity activity, int newState) {
+        onStateChange(activity, newState);
+    }
+
+    /**
+     * @return The most recent focused {@link Activity} tracked by this class.  Being focused means
+     *         out of all the activities tracked here, it has most recently gained window focus.
+     */
+    public static Activity getLastTrackedFocusedActivity() {
+        return sActivity;
+    }
+
+    /**
+     * @return A {@link List} of all non-destroyed {@link Activity}s.
+     */
+    public static List<WeakReference<Activity>> getRunningActivities() {
+        List<WeakReference<Activity>> activities = new ArrayList<WeakReference<Activity>>();
+        for (Activity activity : sActivityInfo.keySet()) {
+            activities.add(new WeakReference<Activity>(activity));
+        }
+        return activities;
+    }
+
+    /**
+     * @return The {@link Context} for the {@link Application}.
+     */
+    public static Context getApplicationContext() {
+        return sApplication != null ? sApplication.getApplicationContext() : null;
+    }
+
+    /**
+     * Query the state for a given activity.  If the activity is not being tracked, this will
+     * return {@link ActivityState#DESTROYED}.
+     *
+     * <p>
+     * Please note that Chrome can have multiple activities running simultaneously.  Please also
+     * look at {@link #getStateForApplication()} for more details.
+     *
+     * <p>
+     * When relying on this method, be familiar with the expected life cycle state
+     * transitions:
+     * <a href="http://developer.android.com/guide/components/activities.html#Lifecycle">
+     *   Activity Lifecycle
+     * </a>
+     *
+     * <p>
+     * During activity transitions (activity B launching in front of activity A), A will completely
+     * paused before the creation of activity B begins.
+     *
+     * <p>
+     * A basic flow for activity A starting, followed by activity B being opened and then closed:
+     * <ul>
+     *   <li> -- Starting Activity A --
+     *   <li> Activity A - ActivityState.CREATED
+     *   <li> Activity A - ActivityState.STARTED
+     *   <li> Activity A - ActivityState.RESUMED
+     *   <li> -- Starting Activity B --
+     *   <li> Activity A - ActivityState.PAUSED
+     *   <li> Activity B - ActivityState.CREATED
+     *   <li> Activity B - ActivityState.STARTED
+     *   <li> Activity B - ActivityState.RESUMED
+     *   <li> Activity A - ActivityState.STOPPED
+     *   <li> -- Closing Activity B, Activity A regaining focus --
+     *   <li> Activity B - ActivityState.PAUSED
+     *   <li> Activity A - ActivityState.STARTED
+     *   <li> Activity A - ActivityState.RESUMED
+     *   <li> Activity B - ActivityState.STOPPED
+     *   <li> Activity B - ActivityState.DESTROYED
+     * </ul>
+     *
+     * @param activity The activity whose state is to be returned.
+     * @return The state of the specified activity (see {@link ActivityState}).
+     */
+    public static int getStateForActivity(Activity activity) {
+        ActivityInfo info = sActivityInfo.get(activity);
+        return info != null ? info.getStatus() : ActivityState.DESTROYED;
+    }
+
+    /**
+     * @return The state of the application (see {@link ApplicationState}).
+     */
+    public static int getStateForApplication() {
+        synchronized (sCachedApplicationStateLock) {
+            if (sCachedApplicationState == null) {
+                sCachedApplicationState = determineApplicationState();
+            }
+            return sCachedApplicationState.intValue();
+        }
+    }
+
+    /**
+     * Checks whether or not any Activity in this Application is visible to the user.  Note that
+     * this includes the PAUSED state, which can happen when the Activity is temporarily covered
+     * by another Activity's Fragment (e.g.).
+     * @return Whether any Activity under this Application is visible.
+     */
+    public static boolean hasVisibleActivities() {
+        int state = getStateForApplication();
+        return state == ApplicationState.HAS_RUNNING_ACTIVITIES
+                || state == ApplicationState.HAS_PAUSED_ACTIVITIES;
+    }
+
+    /**
+     * Checks to see if there are any active Activity instances being watched by ApplicationStatus.
+     * @return True if all Activities have been destroyed.
+     */
+    public static boolean isEveryActivityDestroyed() {
+        return sActivityInfo.isEmpty();
+    }
+
+    /**
+     * Registers the given listener to receive state changes for all activities.
+     * @param listener Listener to receive state changes.
+     */
+    public static void registerStateListenerForAllActivities(ActivityStateListener listener) {
+        sGeneralActivityStateListeners.addObserver(listener);
+    }
+
+    /**
+     * Registers the given listener to receive state changes for {@code activity}.  After a call to
+     * {@link ActivityStateListener#onActivityStateChange(Activity, int)} with
+     * {@link ActivityState#DESTROYED} all listeners associated with that particular
+     * {@link Activity} are removed.
+     * @param listener Listener to receive state changes.
+     * @param activity Activity to track or {@code null} to track all activities.
+     */
+    public static void registerStateListenerForActivity(ActivityStateListener listener,
+            Activity activity) {
+        assert activity != null;
+
+        ActivityInfo info = sActivityInfo.get(activity);
+        assert info != null && info.getStatus() != ActivityState.DESTROYED;
+        info.getListeners().addObserver(listener);
+    }
+
+    /**
+     * Unregisters the given listener from receiving activity state changes.
+     * @param listener Listener that doesn't want to receive state changes.
+     */
+    public static void unregisterActivityStateListener(ActivityStateListener listener) {
+        sGeneralActivityStateListeners.removeObserver(listener);
+
+        // Loop through all observer lists for all activities and remove the listener.
+        for (ActivityInfo info : sActivityInfo.values()) {
+            info.getListeners().removeObserver(listener);
+        }
+    }
+
+    /**
+     * Registers the given listener to receive state changes for the application.
+     * @param listener Listener to receive state state changes.
+     */
+    public static void registerApplicationStateListener(ApplicationStateListener listener) {
+        sApplicationStateListeners.addObserver(listener);
+    }
+
+    /**
+     * Unregisters the given listener from receiving state changes.
+     * @param listener Listener that doesn't want to receive state changes.
+     */
+    public static void unregisterApplicationStateListener(ApplicationStateListener listener) {
+        sApplicationStateListeners.removeObserver(listener);
+    }
+
+    /**
+     * Registers the single thread-safe native activity status listener.
+     * This handles the case where the caller is not on the main thread.
+     * Note that this is used by a leaky singleton object from the native
+     * side, hence lifecycle management is greatly simplified.
+     */
+    @CalledByNative
+    private static void registerThreadSafeNativeApplicationStateListener() {
+        ThreadUtils.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                if (sNativeApplicationStateListener != null) return;
+
+                sNativeApplicationStateListener = new ApplicationStateListener() {
+                    @Override
+                    public void onApplicationStateChange(int newState) {
+                        nativeOnApplicationStateChange(newState);
+                    }
+                };
+                registerApplicationStateListener(sNativeApplicationStateListener);
+            }
+        });
+    }
+
+    /**
+     * Determines the current application state as defined by {@link ApplicationState}.  This will
+     * loop over all the activities and check their state to determine what the general application
+     * state should be.
+     * @return HAS_RUNNING_ACTIVITIES if any activity is not paused, stopped, or destroyed.
+     *         HAS_PAUSED_ACTIVITIES if none are running and one is paused.
+     *         HAS_STOPPED_ACTIVITIES if none are running/paused and one is stopped.
+     *         HAS_DESTROYED_ACTIVITIES if none are running/paused/stopped.
+     */
+    private static int determineApplicationState() {
+        boolean hasPausedActivity = false;
+        boolean hasStoppedActivity = false;
+
+        for (ActivityInfo info : sActivityInfo.values()) {
+            int state = info.getStatus();
+            if (state != ActivityState.PAUSED
+                    && state != ActivityState.STOPPED
+                    && state != ActivityState.DESTROYED) {
+                return ApplicationState.HAS_RUNNING_ACTIVITIES;
+            } else if (state == ActivityState.PAUSED) {
+                hasPausedActivity = true;
+            } else if (state == ActivityState.STOPPED) {
+                hasStoppedActivity = true;
+            }
+        }
+
+        if (hasPausedActivity) return ApplicationState.HAS_PAUSED_ACTIVITIES;
+        if (hasStoppedActivity) return ApplicationState.HAS_STOPPED_ACTIVITIES;
+        return ApplicationState.HAS_DESTROYED_ACTIVITIES;
+    }
+
+    // Called to notify the native side of state changes.
+    // IMPORTANT: This is always called on the main thread!
+    private static native void nativeOnApplicationStateChange(int newState);
+}
diff --git a/base/android/java/src/org/chromium/base/BaseChromiumApplication.java b/base/android/java/src/org/chromium/base/BaseChromiumApplication.java
new file mode 100644
index 0000000..d7c7b05
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/BaseChromiumApplication.java
@@ -0,0 +1,170 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.app.Activity;
+import android.app.Application;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.KeyEvent;
+import android.view.Window;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+/**
+ * Basic application functionality that should be shared among all browser applications.
+ */
+public class BaseChromiumApplication extends Application {
+    /**
+     * Interface to be implemented by listeners for window focus events.
+     */
+    public interface WindowFocusChangedListener {
+        /**
+         * Called when the window focus changes for {@code activity}.
+         * @param activity The {@link Activity} that has a window focus changed event.
+         * @param hasFocus Whether or not {@code activity} gained or lost focus.
+         */
+        public void onWindowFocusChanged(Activity activity, boolean hasFocus);
+    }
+
+    private ObserverList<WindowFocusChangedListener> mWindowFocusListeners =
+            new ObserverList<WindowFocusChangedListener>();
+
+    /**
+     * Intercepts calls to an existing Window.Callback. Most invocations are passed on directly
+     * to the composed Window.Callback but enables intercepting/manipulating others.
+     *
+     * This is used to relay window focus changes throughout the app and remedy a bug in the
+     * appcompat library.
+     */
+    private class WindowCallbackProxy implements InvocationHandler {
+        private final Window.Callback mCallback;
+        private final Activity mActivity;
+
+        public WindowCallbackProxy(Activity activity, Window.Callback callback) {
+            mCallback = callback;
+            mActivity = activity;
+        }
+
+        @Override
+        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+            if (method.getName().equals("onWindowFocusChanged") && args.length == 1
+                    && args[0] instanceof Boolean) {
+                onWindowFocusChanged((boolean) args[0]);
+                return null;
+            } else if (method.getName().equals("dispatchKeyEvent") && args.length == 1
+                    && args[0] instanceof KeyEvent) {
+                return dispatchKeyEvent((KeyEvent) args[0]);
+            } else {
+                try {
+                    return method.invoke(mCallback, args);
+                } catch (InvocationTargetException e) {
+                    // Special-case for when a method is not defined on the underlying
+                    // Window.Callback object. Because we're using a Proxy to forward all method
+                    // calls, this breaks the Android framework's handling for apps built against
+                    // an older SDK. The framework expects an AbstractMethodError but due to
+                    // reflection it becomes wrapped inside an InvocationTargetException. Undo the
+                    // wrapping to signal the framework accordingly.
+                    if (e.getCause() instanceof AbstractMethodError) {
+                        throw e.getCause();
+                    }
+                    throw e;
+                }
+            }
+        }
+
+        public void onWindowFocusChanged(boolean hasFocus) {
+            mCallback.onWindowFocusChanged(hasFocus);
+
+            for (WindowFocusChangedListener listener : mWindowFocusListeners) {
+                listener.onWindowFocusChanged(mActivity, hasFocus);
+            }
+        }
+
+        public boolean dispatchKeyEvent(KeyEvent event) {
+            // TODO(aurimas): remove this once AppCompatDelegateImpl no longer steals
+            // KEYCODE_MENU. (see b/20529185)
+            if (event.getKeyCode() == KeyEvent.KEYCODE_MENU && mActivity.dispatchKeyEvent(event)) {
+                return true;
+            }
+            return mCallback.dispatchKeyEvent(event);
+        }
+    }
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        ApplicationStatus.initialize(this);
+        registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
+            @Override
+            public void onActivityCreated(final Activity activity, Bundle savedInstanceState) {
+                Window.Callback callback = activity.getWindow().getCallback();
+                activity.getWindow().setCallback((Window.Callback) Proxy.newProxyInstance(
+                        Window.Callback.class.getClassLoader(), new Class[] {Window.Callback.class},
+                        new WindowCallbackProxy(activity, callback)));
+            }
+
+            @Override
+            public void onActivityDestroyed(Activity activity) {
+                assert Proxy.isProxyClass(activity.getWindow().getCallback().getClass());
+            }
+
+            @Override
+            public void onActivityPaused(Activity activity) {
+                assert Proxy.isProxyClass(activity.getWindow().getCallback().getClass());
+            }
+
+            @Override
+            public void onActivityResumed(Activity activity) {
+                assert Proxy.isProxyClass(activity.getWindow().getCallback().getClass());
+            }
+
+            @Override
+            public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
+                assert Proxy.isProxyClass(activity.getWindow().getCallback().getClass());
+            }
+
+            @Override
+            public void onActivityStarted(Activity activity) {
+                assert Proxy.isProxyClass(activity.getWindow().getCallback().getClass());
+            }
+
+            @Override
+            public void onActivityStopped(Activity activity) {
+                assert Proxy.isProxyClass(activity.getWindow().getCallback().getClass());
+            }
+        });
+    }
+
+    /**
+     * Registers a listener to receive window focus updates on activities in this application.
+     * @param listener Listener to receive window focus events.
+     */
+    public void registerWindowFocusChangedListener(WindowFocusChangedListener listener) {
+        mWindowFocusListeners.addObserver(listener);
+    }
+
+    /**
+     * Unregisters a listener from receiving window focus updates on activities in this application.
+     * @param listener Listener that doesn't want to receive window focus events.
+     */
+    public void unregisterWindowFocusChangedListener(WindowFocusChangedListener listener) {
+        mWindowFocusListeners.removeObserver(listener);
+    }
+
+    /** Initializes the {@link CommandLine}. */
+    public void initCommandLine() {}
+
+    /**
+     * This must only be called for contexts whose application is a subclass of
+     * {@link BaseChromiumApplication}.
+     */
+    @VisibleForTesting
+    public static void initCommandLine(Context context) {
+        ((BaseChromiumApplication) context.getApplicationContext()).initCommandLine();
+    };
+}
diff --git a/base/android/java/src/org/chromium/base/BaseSwitches.java b/base/android/java/src/org/chromium/base/BaseSwitches.java
new file mode 100644
index 0000000..ad73e15
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/BaseSwitches.java
@@ -0,0 +1,32 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+/**
+ * Contains all of the command line switches that are specific to the base/
+ * portion of Chromium on Android.
+ */
+public abstract class BaseSwitches {
+    // Block onCreate() of Chrome until a Java debugger is attached.
+    public static final String WAIT_FOR_JAVA_DEBUGGER = "wait-for-java-debugger";
+
+    // Block ChildProcessMain thread of render process service until a Java debugger is attached.
+    public static final String RENDERER_WAIT_FOR_JAVA_DEBUGGER = "renderer-wait-for-java-debugger";
+
+    // Force low-end device mode when set.
+    public static final String ENABLE_LOW_END_DEVICE_MODE = "enable-low-end-device-mode";
+
+    // Force disabling of low-end device mode when set.
+    public static final String DISABLE_LOW_END_DEVICE_MODE = "disable-low-end-device-mode";
+
+    // Adds additional thread idle time information into the trace event output.
+    public static final String ENABLE_IDLE_TRACING = "enable-idle-tracing";
+
+    // Default country code to be used for search engine localization.
+    public static final String DEFAULT_COUNTRY_CODE_AT_INSTALL = "default-country-code";
+
+    // Prevent instantiation.
+    private BaseSwitches() {}
+}
diff --git a/base/android/java/src/org/chromium/base/BuildInfo.java b/base/android/java/src/org/chromium/base/BuildInfo.java
new file mode 100644
index 0000000..54f611d
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/BuildInfo.java
@@ -0,0 +1,125 @@
+// Copyright 2012 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;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Build;
+import android.util.Log;
+
+/**
+ * BuildInfo is a utility class providing easy access to {@link PackageInfo}
+ * information. This is primarly of use for accessesing package information
+ * from native code.
+ */
+public class BuildInfo {
+    private static final String TAG = "BuildInfo";
+    private static final int MAX_FINGERPRINT_LENGTH = 128;
+
+    /**
+     * BuildInfo is a static utility class and therefore shouldn't be
+     * instantiated.
+     */
+    private BuildInfo() {
+    }
+
+    @CalledByNative
+    public static String getDevice() {
+        return Build.DEVICE;
+    }
+
+    @CalledByNative
+    public static String getBrand() {
+        return Build.BRAND;
+    }
+
+    @CalledByNative
+    public static String getAndroidBuildId() {
+        return Build.ID;
+    }
+
+    /**
+     * @return The build fingerprint for the current Android install.  The value is truncated to a
+     *         128 characters as this is used for crash and UMA reporting, which should avoid huge
+     *         strings.
+     */
+    @CalledByNative
+    public static String getAndroidBuildFingerprint() {
+        return Build.FINGERPRINT.substring(
+                0, Math.min(Build.FINGERPRINT.length(), MAX_FINGERPRINT_LENGTH));
+    }
+
+    @CalledByNative
+    public static String getDeviceManufacturer() {
+        return Build.MANUFACTURER;
+    }
+
+    @CalledByNative
+    public static String getDeviceModel() {
+        return Build.MODEL;
+    }
+
+    @CalledByNative
+    public static String getPackageVersionCode(Context context) {
+        String msg = "versionCode not available.";
+        try {
+            PackageManager pm = context.getPackageManager();
+            PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0);
+            msg = "";
+            if (pi.versionCode > 0) {
+                msg = Integer.toString(pi.versionCode);
+            }
+        } catch (NameNotFoundException e) {
+            Log.d(TAG, msg);
+        }
+        return msg;
+
+    }
+
+    @CalledByNative
+    public static String getPackageVersionName(Context context) {
+        String msg = "versionName not available";
+        try {
+            PackageManager pm = context.getPackageManager();
+            PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0);
+            msg = pi.versionName;
+        } catch (NameNotFoundException e) {
+            Log.d(TAG, msg);
+        }
+        return msg;
+    }
+
+    @CalledByNative
+    public static String getPackageLabel(Context context) {
+        try {
+            PackageManager packageManager = context.getPackageManager();
+            ApplicationInfo appInfo = packageManager.getApplicationInfo(context.getPackageName(),
+                    PackageManager.GET_META_DATA);
+            CharSequence label = packageManager.getApplicationLabel(appInfo);
+            return  label != null ? label.toString() : "";
+        } catch (NameNotFoundException e) {
+            return "";
+        }
+    }
+
+    @CalledByNative
+    public static String getPackageName(Context context) {
+        String packageName = context != null ? context.getPackageName() : null;
+        return packageName != null ? packageName : "";
+    }
+
+    @CalledByNative
+    public static String getBuildType() {
+        return Build.TYPE;
+    }
+
+    @CalledByNative
+    public static int getSdkInt() {
+        return Build.VERSION.SDK_INT;
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/CalledByNative.java b/base/android/java/src/org/chromium/base/CalledByNative.java
new file mode 100644
index 0000000..3e6315e
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/CalledByNative.java
@@ -0,0 +1,23 @@
+// Copyright 2012 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;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @CalledByNative is used by the JNI generator to create the necessary JNI
+ * bindings and expose this method to native code.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.CLASS)
+public @interface CalledByNative {
+    /*
+     *  If present, tells which inner class the method belongs to.
+     */
+    public String value() default "";
+}
diff --git a/base/android/java/src/org/chromium/base/CollectionUtil.java b/base/android/java/src/org/chromium/base/CollectionUtil.java
new file mode 100644
index 0000000..4a4c754
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/CollectionUtil.java
@@ -0,0 +1,41 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+
+/**
+ * Functions used for easier initialization of Java collections. Inspired by
+ * functionality in com.google.common.collect in Guava but cherry-picked to
+ * bare-minimum functionality to avoid bloat. (http://crbug.com/272790 provides
+ * further details)
+ */
+public final class CollectionUtil {
+    private CollectionUtil() {}
+
+    @SafeVarargs
+    public static <E> HashSet<E> newHashSet(E... elements) {
+        HashSet<E> set = new HashSet<E>(elements.length);
+        Collections.addAll(set, elements);
+        return set;
+    }
+
+    @SafeVarargs
+    public static <E> ArrayList<E> newArrayList(E... elements) {
+        ArrayList<E> list = new ArrayList<E>(elements.length);
+        Collections.addAll(list, elements);
+        return list;
+    }
+
+    public static <E> ArrayList<E> newArrayList(Iterable<E> iterable) {
+        ArrayList<E> list = new ArrayList<E>();
+        for (E element : iterable) {
+            list.add(element);
+        }
+        return list;
+    }
+}
\ No newline at end of file
diff --git a/base/android/java/src/org/chromium/base/CommandLine.java b/base/android/java/src/org/chromium/base/CommandLine.java
new file mode 100644
index 0000000..9f54079
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/CommandLine.java
@@ -0,0 +1,383 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Java mirror of base/command_line.h.
+ * Android applications don't have command line arguments. Instead, they're "simulated" by reading a
+ * file at a specific location early during startup. Applications each define their own files, e.g.,
+ * ContentShellApplication.COMMAND_LINE_FILE or ChromeShellApplication.COMMAND_LINE_FILE.
+**/
+public abstract class CommandLine {
+    // Public abstract interface, implemented in derived classes.
+    // All these methods reflect their native-side counterparts.
+    /**
+     *  Returns true if this command line contains the given switch.
+     *  (Switch names ARE case-sensitive).
+     */
+    @VisibleForTesting
+    public abstract boolean hasSwitch(String switchString);
+
+    /**
+     * Return the value associated with the given switch, or null.
+     * @param switchString The switch key to lookup. It should NOT start with '--' !
+     * @return switch value, or null if the switch is not set or set to empty.
+     */
+    public abstract String getSwitchValue(String switchString);
+
+    /**
+     * Return the value associated with the given switch, or {@code defaultValue} if the switch
+     * was not specified.
+     * @param switchString The switch key to lookup. It should NOT start with '--' !
+     * @param defaultValue The default value to return if the switch isn't set.
+     * @return Switch value, or {@code defaultValue} if the switch is not set or set to empty.
+     */
+    public String getSwitchValue(String switchString, String defaultValue) {
+        String value = getSwitchValue(switchString);
+        return TextUtils.isEmpty(value) ? defaultValue : value;
+    }
+
+    /**
+     * Append a switch to the command line.  There is no guarantee
+     * this action happens before the switch is needed.
+     * @param switchString the switch to add.  It should NOT start with '--' !
+     */
+    @VisibleForTesting
+    public abstract void appendSwitch(String switchString);
+
+    /**
+     * Append a switch and value to the command line.  There is no
+     * guarantee this action happens before the switch is needed.
+     * @param switchString the switch to add.  It should NOT start with '--' !
+     * @param value the value for this switch.
+     * For example, --foo=bar becomes 'foo', 'bar'.
+     */
+    public abstract void appendSwitchWithValue(String switchString, String value);
+
+    /**
+     * Append switch/value items in "command line" format (excluding argv[0] program name).
+     * E.g. { '--gofast', '--username=fred' }
+     * @param array an array of switch or switch/value items in command line format.
+     *   Unlike the other append routines, these switches SHOULD start with '--' .
+     *   Unlike init(), this does not include the program name in array[0].
+     */
+    public abstract void appendSwitchesAndArguments(String[] array);
+
+    /**
+     * Determine if the command line is bound to the native (JNI) implementation.
+     * @return true if the underlying implementation is delegating to the native command line.
+     */
+    public boolean isNativeImplementation() {
+        return false;
+    }
+
+    private static final AtomicReference<CommandLine> sCommandLine =
+            new AtomicReference<CommandLine>();
+
+    /**
+     * @returns true if the command line has already been initialized.
+     */
+    public static boolean isInitialized() {
+        return sCommandLine.get() != null;
+    }
+
+    // Equivalent to CommandLine::ForCurrentProcess in C++.
+    @VisibleForTesting
+    public static CommandLine getInstance() {
+        CommandLine commandLine = sCommandLine.get();
+        assert commandLine != null;
+        return commandLine;
+    }
+
+    /**
+     * Initialize the singleton instance, must be called exactly once (either directly or
+     * via one of the convenience wrappers below) before using the static singleton instance.
+     * @param args command line flags in 'argv' format: args[0] is the program name.
+     */
+    public static void init(String[] args) {
+        setInstance(new JavaCommandLine(args));
+    }
+
+    /**
+     * Initialize the command line from the command-line file.
+     *
+     * @param file The fully qualified command line file.
+     */
+    public static void initFromFile(String file) {
+        // Arbitrary clamp of 8k on the amount of file we read in.
+        char[] buffer = readUtf8FileFully(file, 8 * 1024);
+        init(buffer == null ? null : tokenizeQuotedAruments(buffer));
+    }
+
+    /**
+     * Resets both the java proxy and the native command lines. This allows the entire
+     * command line initialization to be re-run including the call to onJniLoaded.
+     */
+    @VisibleForTesting
+    public static void reset() {
+        setInstance(null);
+    }
+
+    /**
+     * Public for testing (TODO: why are the tests in a different package?)
+     * Parse command line flags from a flat buffer, supporting double-quote enclosed strings
+     * containing whitespace. argv elements are derived by splitting the buffer on whitepace;
+     * double quote characters may enclose tokens containing whitespace; a double-quote literal
+     * may be escaped with back-slash. (Otherwise backslash is taken as a literal).
+     * @param buffer A command line in command line file format as described above.
+     * @return the tokenized arguments, suitable for passing to init().
+     */
+    public static String[] tokenizeQuotedAruments(char[] buffer) {
+        ArrayList<String> args = new ArrayList<String>();
+        StringBuilder arg = null;
+        final char noQuote = '\0';
+        final char singleQuote = '\'';
+        final char doubleQuote = '"';
+        char currentQuote = noQuote;
+        for (char c : buffer) {
+            // Detect start or end of quote block.
+            if ((currentQuote == noQuote && (c == singleQuote || c == doubleQuote))
+                    || c == currentQuote) {
+                if (arg != null && arg.length() > 0 && arg.charAt(arg.length() - 1) == '\\') {
+                    // Last char was a backslash; pop it, and treat c as a literal.
+                    arg.setCharAt(arg.length() - 1, c);
+                } else {
+                    currentQuote = currentQuote == noQuote ? c : noQuote;
+                }
+            } else if (currentQuote == noQuote && Character.isWhitespace(c)) {
+                if (arg != null) {
+                    args.add(arg.toString());
+                    arg = null;
+                }
+            } else {
+                if (arg == null) arg = new StringBuilder();
+                arg.append(c);
+            }
+        }
+        if (arg != null) {
+            if (currentQuote != noQuote) {
+                Log.w(TAG, "Unterminated quoted string: " + arg);
+            }
+            args.add(arg.toString());
+        }
+        return args.toArray(new String[args.size()]);
+    }
+
+    private static final String TAG = "CommandLine";
+    private static final String SWITCH_PREFIX = "--";
+    private static final String SWITCH_TERMINATOR = SWITCH_PREFIX;
+    private static final String SWITCH_VALUE_SEPARATOR = "=";
+
+    public static void enableNativeProxy() {
+        // Make a best-effort to ensure we make a clean (atomic) switch over from the old to
+        // the new command line implementation. If another thread is modifying the command line
+        // when this happens, all bets are off. (As per the native CommandLine).
+        sCommandLine.set(new NativeCommandLine());
+    }
+
+    public static String[] getJavaSwitchesOrNull() {
+        CommandLine commandLine = sCommandLine.get();
+        if (commandLine != null) {
+            assert !commandLine.isNativeImplementation();
+            return ((JavaCommandLine) commandLine).getCommandLineArguments();
+        }
+        return null;
+    }
+
+    private static void setInstance(CommandLine commandLine) {
+        CommandLine oldCommandLine = sCommandLine.getAndSet(commandLine);
+        if (oldCommandLine != null && oldCommandLine.isNativeImplementation()) {
+            nativeReset();
+        }
+    }
+
+    /**
+     * @param fileName the file to read in.
+     * @param sizeLimit cap on the file size.
+     * @return Array of chars read from the file, or null if the file cannot be read
+     *         or if its length exceeds |sizeLimit|.
+     */
+    private static char[] readUtf8FileFully(String fileName, int sizeLimit) {
+        Reader reader = null;
+        File f = new File(fileName);
+        long fileLength = f.length();
+
+        if (fileLength == 0) {
+            return null;
+        }
+
+        if (fileLength > sizeLimit) {
+            Log.w(TAG, "File " + fileName + " length " + fileLength + " exceeds limit "
+                    + sizeLimit);
+            return null;
+        }
+
+        try {
+            char[] buffer = new char[(int) fileLength];
+            reader = new InputStreamReader(new FileInputStream(f), "UTF-8");
+            int charsRead = reader.read(buffer);
+            // Debug check that we've exhausted the input stream (will fail e.g. if the
+            // file grew after we inspected its length).
+            assert !reader.ready();
+            return charsRead < buffer.length ? Arrays.copyOfRange(buffer, 0, charsRead) : buffer;
+        } catch (FileNotFoundException e) {
+            return null;
+        } catch (IOException e) {
+            return null;
+        } finally {
+            try {
+                if (reader != null) reader.close();
+            } catch (IOException e) {
+                Log.e(TAG, "Unable to close file reader.", e);
+            }
+        }
+    }
+
+    private CommandLine() {}
+
+    private static class JavaCommandLine extends CommandLine {
+        private HashMap<String, String> mSwitches = new HashMap<String, String>();
+        private ArrayList<String> mArgs = new ArrayList<String>();
+
+        // The arguments begin at index 1, since index 0 contains the executable name.
+        private int mArgsBegin = 1;
+
+        JavaCommandLine(String[] args) {
+            if (args == null || args.length == 0 || args[0] == null) {
+                mArgs.add("");
+            } else {
+                mArgs.add(args[0]);
+                appendSwitchesInternal(args, 1);
+            }
+            // Invariant: we always have the argv[0] program name element.
+            assert mArgs.size() > 0;
+        }
+
+        /**
+         * Returns the switches and arguments passed into the program, with switches and their
+         * values coming before all of the arguments.
+         */
+        private String[] getCommandLineArguments() {
+            return mArgs.toArray(new String[mArgs.size()]);
+        }
+
+        @Override
+        public boolean hasSwitch(String switchString) {
+            return mSwitches.containsKey(switchString);
+        }
+
+        @Override
+        public String getSwitchValue(String switchString) {
+            // This is slightly round about, but needed for consistency with the NativeCommandLine
+            // version which does not distinguish empty values from key not present.
+            String value = mSwitches.get(switchString);
+            return value == null || value.isEmpty() ? null : value;
+        }
+
+        @Override
+        public void appendSwitch(String switchString) {
+            appendSwitchWithValue(switchString, null);
+        }
+
+        /**
+         * Appends a switch to the current list.
+         * @param switchString the switch to add.  It should NOT start with '--' !
+         * @param value the value for this switch.
+         */
+        @Override
+        public void appendSwitchWithValue(String switchString, String value) {
+            mSwitches.put(switchString, value == null ? "" : value);
+
+            // Append the switch and update the switches/arguments divider mArgsBegin.
+            String combinedSwitchString = SWITCH_PREFIX + switchString;
+            if (value != null && !value.isEmpty()) {
+                combinedSwitchString += SWITCH_VALUE_SEPARATOR + value;
+            }
+
+            mArgs.add(mArgsBegin++, combinedSwitchString);
+        }
+
+        @Override
+        public void appendSwitchesAndArguments(String[] array) {
+            appendSwitchesInternal(array, 0);
+        }
+
+        // Add the specified arguments, but skipping the first |skipCount| elements.
+        private void appendSwitchesInternal(String[] array, int skipCount) {
+            boolean parseSwitches = true;
+            for (String arg : array) {
+                if (skipCount > 0) {
+                    --skipCount;
+                    continue;
+                }
+
+                if (arg.equals(SWITCH_TERMINATOR)) {
+                    parseSwitches = false;
+                }
+
+                if (parseSwitches && arg.startsWith(SWITCH_PREFIX)) {
+                    String[] parts = arg.split(SWITCH_VALUE_SEPARATOR, 2);
+                    String value = parts.length > 1 ? parts[1] : null;
+                    appendSwitchWithValue(parts[0].substring(SWITCH_PREFIX.length()), value);
+                } else {
+                    mArgs.add(arg);
+                }
+            }
+        }
+    }
+
+    private static class NativeCommandLine extends CommandLine {
+        @Override
+        public boolean hasSwitch(String switchString) {
+            return nativeHasSwitch(switchString);
+        }
+
+        @Override
+        public String getSwitchValue(String switchString) {
+            return nativeGetSwitchValue(switchString);
+        }
+
+        @Override
+        public void appendSwitch(String switchString) {
+            nativeAppendSwitch(switchString);
+        }
+
+        @Override
+        public void appendSwitchWithValue(String switchString, String value) {
+            nativeAppendSwitchWithValue(switchString, value);
+        }
+
+        @Override
+        public void appendSwitchesAndArguments(String[] array) {
+            nativeAppendSwitchesAndArguments(array);
+        }
+
+        @Override
+        public boolean isNativeImplementation() {
+            return true;
+        }
+    }
+
+    private static native void nativeReset();
+    private static native boolean nativeHasSwitch(String switchString);
+    private static native String nativeGetSwitchValue(String switchString);
+    private static native void nativeAppendSwitch(String switchString);
+    private static native void nativeAppendSwitchWithValue(String switchString, String value);
+    private static native void nativeAppendSwitchesAndArguments(String[] array);
+}
diff --git a/base/android/java/src/org/chromium/base/ContentUriUtils.java b/base/android/java/src/org/chromium/base/ContentUriUtils.java
new file mode 100644
index 0000000..ef527e1
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/ContentUriUtils.java
@@ -0,0 +1,150 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+
+/**
+ * This class provides methods to access content URI schemes.
+ */
+public abstract class ContentUriUtils {
+    private static final String TAG = "ContentUriUtils";
+    private static FileProviderUtil sFileProviderUtil;
+
+    /**
+     * Provides functionality to translate a file into a content URI for use
+     * with a content provider.
+     */
+    public interface FileProviderUtil {
+        /**
+         * Generate a content URI from the given file.
+         * @param context Application context.
+         * @param file The file to be translated.
+         */
+        Uri getContentUriFromFile(Context context, File file);
+    }
+
+    // Prevent instantiation.
+    private ContentUriUtils() {}
+
+    public static void setFileProviderUtil(FileProviderUtil util) {
+        sFileProviderUtil = util;
+    }
+
+    public static Uri getContentUriFromFile(Context context, File file) {
+        ThreadUtils.assertOnUiThread();
+        if (sFileProviderUtil != null) {
+            return sFileProviderUtil.getContentUriFromFile(context, file);
+        }
+        return null;
+    }
+
+    /**
+     * Opens the content URI for reading, and returns the file descriptor to
+     * the caller. The caller is responsible for closing the file desciptor.
+     *
+     * @param context {@link Context} in interest
+     * @param uriString the content URI to open
+     * @return file desciptor upon sucess, or -1 otherwise.
+     */
+    @CalledByNative
+    public static int openContentUriForRead(Context context, String uriString) {
+        ParcelFileDescriptor pfd = getParcelFileDescriptor(context, uriString);
+        if (pfd != null) {
+            return pfd.detachFd();
+        }
+        return -1;
+    }
+
+    /**
+     * Check whether a content URI exists.
+     *
+     * @param context {@link Context} in interest.
+     * @param uriString the content URI to query.
+     * @return true if the URI exists, or false otherwise.
+     */
+    @CalledByNative
+    public static boolean contentUriExists(Context context, String uriString) {
+        return getParcelFileDescriptor(context, uriString) != null;
+    }
+
+    /**
+     * Retrieve the MIME type for the content URI.
+     *
+     * @param context {@link Context} in interest.
+     * @param uriString the content URI to look up.
+     * @return MIME type or null if the input params are empty or invalid.
+     */
+    @CalledByNative
+    public static String getMimeType(Context context, String uriString) {
+        ContentResolver resolver = context.getContentResolver();
+        if (resolver == null) return null;
+        Uri uri = Uri.parse(uriString);
+        return resolver.getType(uri);
+    }
+
+    /**
+     * Helper method to open a content URI and returns the ParcelFileDescriptor.
+     *
+     * @param context {@link Context} in interest.
+     * @param uriString the content URI to open.
+     * @return ParcelFileDescriptor of the content URI, or NULL if the file does not exist.
+     */
+    private static ParcelFileDescriptor getParcelFileDescriptor(Context context, String uriString) {
+        ContentResolver resolver = context.getContentResolver();
+        Uri uri = Uri.parse(uriString);
+
+        ParcelFileDescriptor pfd = null;
+        try {
+            pfd = resolver.openFileDescriptor(uri, "r");
+        } catch (FileNotFoundException e) {
+            Log.w(TAG, "Cannot find content uri: " + uriString, e);
+        } catch (SecurityException e) {
+            Log.w(TAG, "Cannot open content uri: " + uriString, e);
+        } catch (IllegalArgumentException e) {
+            Log.w(TAG, "Unknown content uri: " + uriString, e);
+        }
+        return pfd;
+    }
+
+    /**
+     * Method to resolve the display name of a content URI.
+     *
+     * @param uri the content URI to be resolved.
+     * @param contentResolver the content resolver to query.
+     * @param columnField the column field to query.
+     * @return the display name of the @code uri if present in the database
+     *  or an empty string otherwise.
+     */
+    public static String getDisplayName(
+            Uri uri, ContentResolver contentResolver, String columnField) {
+        if (contentResolver == null || uri == null) return "";
+        Cursor cursor = null;
+        try {
+            cursor = contentResolver.query(uri, null, null, null, null);
+
+            if (cursor != null && cursor.getCount() >= 1) {
+                cursor.moveToFirst();
+                int index = cursor.getColumnIndex(columnField);
+                if (index > -1) return cursor.getString(index);
+            }
+        } catch (NullPointerException e) {
+            // Some android models don't handle the provider call correctly.
+            // see crbug.com/345393
+            return "";
+        } finally {
+            if (cursor != null) cursor.close();
+        }
+        return "";
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/CpuFeatures.java b/base/android/java/src/org/chromium/base/CpuFeatures.java
new file mode 100644
index 0000000..0e8a7ab
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/CpuFeatures.java
@@ -0,0 +1,40 @@
+// Copyright 2012 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;
+
+// The only purpose of this class is to allow sending CPU properties
+// from the browser process to sandboxed renderer processes. This is
+// needed because sandboxed processes cannot, on ARM, query the kernel
+// about the CPU's properties by parsing /proc, so this operation must
+// be performed in the browser process, and the result passed to
+// renderer ones.
+//
+// For more context, see http://crbug.com/164154
+//
+// Technically, this is a wrapper around the native NDK cpufeatures
+// library. The exact CPU features bits are never used in Java so
+// there is no point in duplicating their definitions here.
+//
+@JNINamespace("base::android")
+public abstract class CpuFeatures {
+    /**
+     * Return the number of CPU Cores on the device.
+     */
+    public static int getCount() {
+        return nativeGetCoreCount();
+    }
+
+    /**
+     * Return the CPU feature mask.
+     * This is a 64-bit integer that corresponds to the CPU's features.
+     * The value comes directly from android_getCpuFeatures().
+     */
+    public static long getMask() {
+        return nativeGetCpuFeatures();
+    }
+
+    private static native int nativeGetCoreCount();
+    private static native long nativeGetCpuFeatures();
+}
diff --git a/base/android/java/src/org/chromium/base/EventLog.java b/base/android/java/src/org/chromium/base/EventLog.java
new file mode 100644
index 0000000..894de15
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/EventLog.java
@@ -0,0 +1,17 @@
+// 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;
+
+/**
+ * A simple interface to Android's EventLog to be used by native code.
+ */
+@JNINamespace("base::android")
+public class EventLog {
+
+    @CalledByNative
+    public static void writeEvent(int tag, int value) {
+        android.util.EventLog.writeEvent(tag, value);
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/FieldTrialList.java b/base/android/java/src/org/chromium/base/FieldTrialList.java
new file mode 100644
index 0000000..5fc9a1f
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/FieldTrialList.java
@@ -0,0 +1,33 @@
+// 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;
+
+/**
+ * Helper to get field trial information.
+ */
+public class FieldTrialList {
+
+    private FieldTrialList() {}
+
+    /**
+     * @param trialName The name of the trial to get the group for.
+     * @return The group name chosen for the named trial, or the empty string if the trial does
+     *         not exist.
+     */
+    public static String findFullName(String trialName) {
+        return nativeFindFullName(trialName);
+    }
+
+    /**
+     * @param trialName The name of the trial to get the group for.
+     * @return Whether the trial exists or not.
+     */
+    public static boolean trialExists(String trialName) {
+        return nativeTrialExists(trialName);
+    }
+
+    private static native String nativeFindFullName(String trialName);
+    private static native boolean nativeTrialExists(String trialName);
+}
diff --git a/base/android/java/src/org/chromium/base/ImportantFileWriterAndroid.java b/base/android/java/src/org/chromium/base/ImportantFileWriterAndroid.java
new file mode 100644
index 0000000..3921cea
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/ImportantFileWriterAndroid.java
@@ -0,0 +1,29 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+/**
+ * This class provides an interface to the native class for writing
+ * important data files without risking data loss.
+ */
+@JNINamespace("base::android")
+public class ImportantFileWriterAndroid {
+
+    /**
+     * Write a binary file atomically.
+     *
+     * This either writes all the data or leaves the file unchanged.
+     *
+     * @param fileName The complete path of the file to be written
+     * @param data The data to be written to the file
+     * @return true if the data was written to the file, false if not.
+     */
+    public static boolean writeFileAtomically(String fileName, byte[] data) {
+        return nativeWriteFileAtomically(fileName, data);
+    }
+
+    private static native boolean nativeWriteFileAtomically(
+            String fileName, byte[] data);
+}
diff --git a/base/android/java/src/org/chromium/base/JNIAdditionalImport.java b/base/android/java/src/org/chromium/base/JNIAdditionalImport.java
new file mode 100644
index 0000000..499d158
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/JNIAdditionalImport.java
@@ -0,0 +1,35 @@
+// 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;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * JNIAdditionalImport is used by the JNI generator to qualify inner types used on JNI methods. Must
+ * be used when an inner class is used from a class within the same package. Example:
+ *
+ * <pre>
+ * @JNIAdditionImport(Foo.class)
+ * public class Bar {
+ *     @CalledByNative static void doSomethingWithInner(Foo.Inner inner) {
+ *     ...
+ *     }
+ * }
+ * <pre>
+ * <p>
+ * Notes:
+ * 1) Foo must be in the same package as Bar
+ * 2) For classes in different packages, they should be imported as:
+ *    import other.package.Foo;
+ *    and this annotation should not be used.
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.CLASS)
+public @interface JNIAdditionalImport {
+    Class<?>[] value();
+}
diff --git a/base/android/java/src/org/chromium/base/JNINamespace.java b/base/android/java/src/org/chromium/base/JNINamespace.java
new file mode 100644
index 0000000..5ad7a42
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/JNINamespace.java
@@ -0,0 +1,20 @@
+// Copyright 2012 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;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @JNINamespace is used by the JNI generator to create the necessary JNI
+ * bindings and expose this method to native code using the specified namespace.
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface JNINamespace {
+    public String value();
+}
diff --git a/base/android/java/src/org/chromium/base/JNIUtils.java b/base/android/java/src/org/chromium/base/JNIUtils.java
new file mode 100644
index 0000000..6f6cd54
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/JNIUtils.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;
+
+/**
+ * This class provides JNI-related methods to the native library.
+ */
+public class JNIUtils {
+    /**
+     * This returns a ClassLoader that is capable of loading Chromium Java code. Such a ClassLoader
+     * is needed for the few cases where the JNI mechanism is unable to automatically determine the
+     * appropriate ClassLoader instance.
+     */
+    @CalledByNative
+    public static Object getClassLoader() {
+        return JNIUtils.class.getClassLoader();
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/JavaHandlerThread.java b/base/android/java/src/org/chromium/base/JavaHandlerThread.java
new file mode 100644
index 0000000..3153a9b
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/JavaHandlerThread.java
@@ -0,0 +1,56 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.annotation.TargetApi;
+import android.os.Build;
+import android.os.Handler;
+import android.os.HandlerThread;
+
+/**
+ * This class is an internal detail of the native counterpart.
+ * It is instantiated and owned by the native object.
+ */
+@JNINamespace("base::android")
+class JavaHandlerThread {
+    final HandlerThread mThread;
+
+    private JavaHandlerThread(String name) {
+        mThread = new HandlerThread(name);
+    }
+
+    @CalledByNative
+    private static JavaHandlerThread create(String name) {
+        return new JavaHandlerThread(name);
+    }
+
+    @CalledByNative
+    private void start(final long nativeThread, final long nativeEvent) {
+        mThread.start();
+        new Handler(mThread.getLooper()).post(new Runnable() {
+            @Override
+            public void run() {
+                nativeInitializeThread(nativeThread, nativeEvent);
+            }
+        });
+    }
+
+    @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
+    @CalledByNative
+    private void stop(final long nativeThread, final long nativeEvent) {
+        final boolean quitSafely = Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2;
+        new Handler(mThread.getLooper()).post(new Runnable() {
+            @Override
+            public void run() {
+                nativeStopThread(nativeThread, nativeEvent);
+                if (!quitSafely) mThread.quit();
+            }
+        });
+        if (quitSafely) mThread.quitSafely();
+    }
+
+    private native void nativeInitializeThread(long nativeJavaHandlerThread, long nativeEvent);
+    private native void nativeStopThread(long nativeJavaHandlerThread, long nativeEvent);
+}
diff --git a/base/android/java/src/org/chromium/base/LocaleUtils.java b/base/android/java/src/org/chromium/base/LocaleUtils.java
new file mode 100644
index 0000000..82b2c8f
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/LocaleUtils.java
@@ -0,0 +1,55 @@
+// 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;
+
+import java.util.Locale;
+
+/**
+ * This class provides the locale related methods.
+ */
+public class LocaleUtils {
+    /**
+     * Guards this class from being instantiated.
+     */
+    private LocaleUtils() {
+    }
+
+    /**
+     * @return the default locale, translating Android deprecated
+     * language codes into the modern ones used by Chromium.
+     */
+    @CalledByNative
+    public static String getDefaultLocale() {
+        Locale locale = Locale.getDefault();
+        String language = locale.getLanguage();
+        String country = locale.getCountry();
+
+        // Android uses deprecated lanuages codes for Hebrew and Indonesian but Chromium uses the
+        // updated codes. Also, Android uses "tl" while Chromium uses "fil" for Tagalog/Filipino.
+        // So apply a mapping.
+        // See http://developer.android.com/reference/java/util/Locale.html
+        if ("iw".equals(language)) {
+            language = "he";
+        } else if ("in".equals(language)) {
+            language = "id";
+        } else if ("tl".equals(language)) {
+            language = "fil";
+        }
+        return country.isEmpty() ? language : language + "-" + country;
+    }
+
+    /**
+     * Get the default country code set during install.
+     * @return country code.
+     */
+    @CalledByNative
+    private static String getDefaultCountryCode() {
+        CommandLine commandLine = CommandLine.getInstance();
+        return commandLine.hasSwitch(BaseSwitches.DEFAULT_COUNTRY_CODE_AT_INSTALL)
+                ? commandLine.getSwitchValue(BaseSwitches.DEFAULT_COUNTRY_CODE_AT_INSTALL)
+                : Locale.getDefault().getCountry();
+    }
+
+}
diff --git a/base/android/java/src/org/chromium/base/Log.java b/base/android/java/src/org/chromium/base/Log.java
new file mode 100644
index 0000000..4a1a00d
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/Log.java
@@ -0,0 +1,353 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.text.TextUtils;
+
+import org.chromium.base.annotations.NoSideEffects;
+
+import java.util.Locale;
+
+/**
+ * Utility class for Logging.
+ *
+ * <p>
+ * Defines logging access points for each feature. They format and forward the logs to
+ * {@link android.util.Log}, allowing to standardize the output, to make it easy to identify
+ * the origin of logs, and enable or disable logging in different parts of the code.
+ * </p>
+ * <p>
+ * @see usage documentation: <a href="README_logging.md">README_logging.md</a>.
+ * </p>
+ */
+public class Log {
+    /** Convenience property, same as {@link android.util.Log#ASSERT}. */
+    public static final int ASSERT = android.util.Log.ASSERT;
+
+    /** Convenience property, same as {@link android.util.Log#DEBUG}. */
+    public static final int DEBUG = android.util.Log.DEBUG;
+
+    /** Convenience property, same as {@link android.util.Log#ERROR}. */
+    public static final int ERROR = android.util.Log.ERROR;
+
+    /** Convenience property, same as {@link android.util.Log#INFO}. */
+    public static final int INFO = android.util.Log.INFO;
+
+    /** Convenience property, same as {@link android.util.Log#VERBOSE}. */
+    public static final int VERBOSE = android.util.Log.VERBOSE;
+
+    /** Convenience property, same as {@link android.util.Log#WARN}. */
+    public static final int WARN = android.util.Log.WARN;
+
+    private Log() {
+        // Static only access
+    }
+
+    /** Returns a formatted log message, using the supplied format and arguments.*/
+    private static String formatLog(String messageTemplate, Object... params) {
+        if (params != null && params.length != 0) {
+            messageTemplate = String.format(Locale.US, messageTemplate, params);
+        }
+
+        return messageTemplate;
+    }
+
+    /**
+     * Returns a formatted log message, using the supplied format and arguments.
+     * The message will be prepended with the filename and line number of the call.
+     */
+    private static String formatLogWithStack(String messageTemplate, Object... params) {
+        return "[" + getCallOrigin() + "] " + formatLog(messageTemplate, params);
+    }
+
+    /**
+     * Returns a full tag for the provided group tag. Full tags longer than 23 characters
+     * will cause a runtime exception.
+     *
+     * @param groupTag {@code null} and empty string are allowed.
+     *
+     * @see android.util.Log#isLoggable(String, int)
+     * @throws IllegalArgumentException if the tag is too long.
+     * @deprecated Directly use a string (e.g. "cr.Tag") in your class. See http://crbug.com/485772
+     */
+    @Deprecated
+    public static String makeTag(String groupTag) {
+        if (TextUtils.isEmpty(groupTag)) return "cr";
+        String tag = "cr." + groupTag;
+        if (tag.length() > 23) {
+            throw new IllegalArgumentException(
+                    "The full tag (" + tag + ") is longer than 23 characters.");
+        }
+        return tag;
+    }
+
+    /** Convenience function, forwards to {@link android.util.Log#isLoggable(String, int)}. */
+    public static boolean isLoggable(String tag, int level) {
+        return android.util.Log.isLoggable(tag, level);
+    }
+
+    /**
+     * Sends a {@link android.util.Log#VERBOSE} log message.
+     *
+     * For optimization purposes, only the fixed parameters versions are visible. If you need more
+     * than 7 parameters, consider building your log message using a function annotated with
+     * {@link NoSideEffects}.
+     *
+     * @param tag Used to identify the source of a log message.
+     * @param messageTemplate The message you would like logged. It is to be specified as a format
+     *                        string.
+     * @param args Arguments referenced by the format specifiers in the format string. If the last
+     *             one is a {@link Throwable}, its trace will be printed.
+     */
+    private static void verbose(String tag, String messageTemplate, Object... args) {
+        if (Log.isLoggable(tag, Log.VERBOSE)) {
+            String message = formatLogWithStack(messageTemplate, args);
+            Throwable tr = getThrowableToLog(args);
+            if (tr != null) {
+                android.util.Log.v(tag, message, tr);
+            } else {
+                android.util.Log.v(tag, message);
+            }
+        }
+    }
+
+    /** Sends a {@link android.util.Log#VERBOSE} log message. 0 arg version. */
+    public static void v(String tag, String message) {
+        verbose(tag, message);
+    }
+
+    /** Sends a {@link android.util.Log#VERBOSE} log message. 1 arg version. */
+    public static void v(String tag, String messageTemplate, Object arg1) {
+        verbose(tag, messageTemplate, arg1);
+    }
+
+    /** Sends a {@link android.util.Log#VERBOSE} log message. 2 args version */
+    public static void v(String tag, String messageTemplate, Object arg1, Object arg2) {
+        verbose(tag, messageTemplate, arg1, arg2);
+    }
+
+    /** Sends a {@link android.util.Log#VERBOSE} log message. 3 args version */
+    public static void v(
+            String tag, String messageTemplate, Object arg1, Object arg2, Object arg3) {
+        verbose(tag, messageTemplate, arg1, arg2, arg3);
+    }
+
+    /** Sends a {@link android.util.Log#VERBOSE} log message. 4 args version */
+    public static void v(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
+            Object arg4) {
+        verbose(tag, messageTemplate, arg1, arg2, arg3, arg4);
+    }
+
+    /** Sends a {@link android.util.Log#VERBOSE} log message. 5 args version */
+    public static void v(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
+            Object arg4, Object arg5) {
+        verbose(tag, messageTemplate, arg1, arg2, arg3, arg4, arg5);
+    }
+
+    /** Sends a {@link android.util.Log#VERBOSE} log message. 6 args version */
+    public static void v(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
+            Object arg4, Object arg5, Object arg6) {
+        verbose(tag, messageTemplate, arg1, arg2, arg3, arg4, arg5, arg6);
+    }
+
+    /** Sends a {@link android.util.Log#VERBOSE} log message. 7 args version */
+    public static void v(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
+            Object arg4, Object arg5, Object arg6, Object arg7) {
+        verbose(tag, messageTemplate, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+    }
+
+    /**
+     * Sends a {@link android.util.Log#DEBUG} log message.
+     *
+     * For optimization purposes, only the fixed parameters versions are visible. If you need more
+     * than 7 parameters, consider building your log message using a function annotated with
+     * {@link NoSideEffects}.
+     *
+     * @param tag Used to identify the source of a log message.
+     * @param messageTemplate The message you would like logged. It is to be specified as a format
+     *                        string.
+     * @param args Arguments referenced by the format specifiers in the format string. If the last
+     *             one is a {@link Throwable}, its trace will be printed.
+     */
+    private static void debug(String tag, String messageTemplate, Object... args) {
+        if (isLoggable(tag, Log.DEBUG)) {
+            String message = formatLogWithStack(messageTemplate, args);
+            Throwable tr = getThrowableToLog(args);
+            if (tr != null) {
+                android.util.Log.d(tag, message, tr);
+            } else {
+                android.util.Log.d(tag, message);
+            }
+        }
+    }
+
+    /** Sends a {@link android.util.Log#DEBUG} log message. 0 arg version. */
+    public static void d(String tag, String message) {
+        debug(tag, message);
+    }
+
+    /** Sends a {@link android.util.Log#DEBUG} log message. 1 arg version. */
+    public static void d(String tag, String messageTemplate, Object arg1) {
+        debug(tag, messageTemplate, arg1);
+    }
+    /** Sends a {@link android.util.Log#DEBUG} log message. 2 args version */
+    public static void d(String tag, String messageTemplate, Object arg1, Object arg2) {
+        debug(tag, messageTemplate, arg1, arg2);
+    }
+    /** Sends a {@link android.util.Log#DEBUG} log message. 3 args version */
+    public static void d(
+            String tag, String messageTemplate, Object arg1, Object arg2, Object arg3) {
+        debug(tag, messageTemplate, arg1, arg2, arg3);
+    }
+
+    /** Sends a {@link android.util.Log#DEBUG} log message. 4 args version */
+    public static void d(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
+            Object arg4) {
+        debug(tag, messageTemplate, arg1, arg2, arg3, arg4);
+    }
+
+    /** Sends a {@link android.util.Log#DEBUG} log message. 5 args version */
+    public static void d(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
+            Object arg4, Object arg5) {
+        debug(tag, messageTemplate, arg1, arg2, arg3, arg4, arg5);
+    }
+
+    /** Sends a {@link android.util.Log#DEBUG} log message. 6 args version */
+    public static void d(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
+            Object arg4, Object arg5, Object arg6) {
+        debug(tag, messageTemplate, arg1, arg2, arg3, arg4, arg5, arg6);
+    }
+
+    /** Sends a {@link android.util.Log#DEBUG} log message. 7 args version */
+    public static void d(String tag, String messageTemplate, Object arg1, Object arg2, Object arg3,
+            Object arg4, Object arg5, Object arg6, Object arg7) {
+        debug(tag, messageTemplate, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+    }
+
+    /**
+     * Sends an {@link android.util.Log#INFO} log message.
+     *
+     * @param tag Used to identify the source of a log message.
+     * @param messageTemplate The message you would like logged. It is to be specified as a format
+     *                        string.
+     * @param args Arguments referenced by the format specifiers in the format string. If the last
+     *             one is a {@link Throwable}, its trace will be printed.
+     */
+    @VisibleForTesting
+    public static void i(String tag, String messageTemplate, Object... args) {
+        if (Log.isLoggable(tag, Log.INFO)) {
+            String message = formatLog(messageTemplate, args);
+            Throwable tr = getThrowableToLog(args);
+            if (tr != null) {
+                android.util.Log.i(tag, message, tr);
+            } else {
+                android.util.Log.i(tag, message);
+            }
+        }
+    }
+
+    /**
+     * Sends a {@link android.util.Log#WARN} log message.
+     *
+     * @param tag Used to identify the source of a log message.
+     * @param messageTemplate The message you would like logged. It is to be specified as a format
+     *                        string.
+     * @param args Arguments referenced by the format specifiers in the format string. If the last
+     *             one is a {@link Throwable}, its trace will be printed.
+     */
+    @VisibleForTesting
+    public static void w(String tag, String messageTemplate, Object... args) {
+        if (Log.isLoggable(tag, Log.WARN)) {
+            String message = formatLog(messageTemplate, args);
+            Throwable tr = getThrowableToLog(args);
+            if (tr != null) {
+                android.util.Log.w(tag, message, tr);
+            } else {
+                android.util.Log.w(tag, message);
+            }
+        }
+    }
+
+    /**
+     * Sends an {@link android.util.Log#ERROR} log message.
+     *
+     * @param tag Used to identify the source of a log message.
+     * @param messageTemplate The message you would like logged. It is to be specified as a format
+     *                        string.
+     * @param args Arguments referenced by the format specifiers in the format string. If the last
+     *             one is a {@link Throwable}, its trace will be printed.
+     */
+    @VisibleForTesting
+    public static void e(String tag, String messageTemplate, Object... args) {
+        if (Log.isLoggable(tag, Log.ERROR)) {
+            String message = formatLog(messageTemplate, args);
+            Throwable tr = getThrowableToLog(args);
+            if (tr != null) {
+                android.util.Log.e(tag, message, tr);
+            } else {
+                android.util.Log.e(tag, message);
+            }
+        }
+    }
+
+    /**
+     * What a Terrible Failure: Used for conditions that should never happen, and logged at
+     * the {@link android.util.Log#ASSERT} level. Depending on the configuration, it might
+     * terminate the process.
+     *
+     * @see android.util.Log#wtf(String, String, Throwable)
+     *
+     * @param tag Used to identify the source of a log message.
+     * @param messageTemplate The message you would like logged. It is to be specified as a format
+     *                        string.
+     * @param args Arguments referenced by the format specifiers in the format string. If the last
+     *             one is a {@link Throwable}, its trace will be printed.
+     */
+    @VisibleForTesting
+    public static void wtf(String tag, String messageTemplate, Object... args) {
+        if (Log.isLoggable(tag, Log.ASSERT)) {
+            String message = formatLog(messageTemplate, args);
+            Throwable tr = getThrowableToLog(args);
+            if (tr != null) {
+                android.util.Log.wtf(tag, message, tr);
+            } else {
+                android.util.Log.wtf(tag, message);
+            }
+        }
+    }
+
+    private static Throwable getThrowableToLog(Object[] args) {
+        if (args == null || args.length == 0) return null;
+
+        Object lastArg = args[args.length - 1];
+
+        if (!(lastArg instanceof Throwable)) return null;
+        return (Throwable) lastArg;
+    }
+
+    /** Returns a string form of the origin of the log call, to be used as secondary tag.*/
+    private static String getCallOrigin() {
+        StackTraceElement[] st = Thread.currentThread().getStackTrace();
+
+        // The call stack should look like:
+        //   n [a variable number of calls depending on the vm used]
+        //  +0 getCallOrigin()
+        //  +1 privateLogFunction: verbose or debug
+        //  +2 formatLogWithStack()
+        //  +3 logFunction: v or d
+        //  +4 caller
+
+        int callerStackIndex;
+        String logClassName = Log.class.getName();
+        for (callerStackIndex = 0; callerStackIndex < st.length; callerStackIndex++) {
+            if (st[callerStackIndex].getClassName().equals(logClassName)) {
+                callerStackIndex += 4;
+                break;
+            }
+        }
+
+        return st[callerStackIndex].getFileName() + ":" + st[callerStackIndex].getLineNumber();
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/MemoryPressureListener.java b/base/android/java/src/org/chromium/base/MemoryPressureListener.java
new file mode 100644
index 0000000..7979287
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/MemoryPressureListener.java
@@ -0,0 +1,114 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.app.Activity;
+import android.content.ComponentCallbacks2;
+import android.content.Context;
+import android.content.res.Configuration;
+
+
+/**
+ * This is an internal implementation of the C++ counterpart.
+ * It registers a ComponentCallbacks2 with the system, and dispatches into
+ * native for levels that are considered actionable.
+ */
+public class MemoryPressureListener {
+    /**
+     * Sending an intent with this action to Chrome will cause it to issue a call to onLowMemory
+     * thus simulating a low memory situations.
+     */
+    private static final String ACTION_LOW_MEMORY = "org.chromium.base.ACTION_LOW_MEMORY";
+
+    /**
+     * Sending an intent with this action to Chrome will cause it to issue a call to onTrimMemory
+     * thus simulating a low memory situations.
+     */
+    private static final String ACTION_TRIM_MEMORY = "org.chromium.base.ACTION_TRIM_MEMORY";
+
+    /**
+     * Sending an intent with this action to Chrome will cause it to issue a call to onTrimMemory
+     * with notification level TRIM_MEMORY_RUNNING_CRITICAL thus simulating a low memory situation
+     */
+    private static final String ACTION_TRIM_MEMORY_RUNNING_CRITICAL =
+            "org.chromium.base.ACTION_TRIM_MEMORY_RUNNING_CRITICAL";
+
+    /**
+     * Sending an intent with this action to Chrome will cause it to issue a call to onTrimMemory
+     * with notification level TRIM_MEMORY_MODERATE thus simulating a low memory situation
+     */
+    private static final String ACTION_TRIM_MEMORY_MODERATE =
+            "org.chromium.base.ACTION_TRIM_MEMORY_MODERATE";
+
+    @CalledByNative
+    private static void registerSystemCallback(Context context) {
+        context.registerComponentCallbacks(
+                new ComponentCallbacks2() {
+                    @Override
+                    public void onTrimMemory(int level) {
+                        maybeNotifyMemoryPresure(level);
+                    }
+
+                    @Override
+                    public void onLowMemory() {
+                        nativeOnMemoryPressure(MemoryPressureLevel.CRITICAL);
+                    }
+
+                    @Override
+                    public void onConfigurationChanged(Configuration configuration) {
+                    }
+                });
+    }
+
+    /**
+     * Used by applications to simulate a memory pressure signal. By throwing certain intent
+     * actions.
+     */
+    public static boolean handleDebugIntent(Activity activity, String action) {
+        if (ACTION_LOW_MEMORY.equals(action)) {
+            simulateLowMemoryPressureSignal(activity);
+        } else if (ACTION_TRIM_MEMORY.equals(action)) {
+            simulateTrimMemoryPressureSignal(activity, ComponentCallbacks2.TRIM_MEMORY_COMPLETE);
+        } else if (ACTION_TRIM_MEMORY_RUNNING_CRITICAL.equals(action)) {
+            simulateTrimMemoryPressureSignal(activity,
+                    ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL);
+        } else if (ACTION_TRIM_MEMORY_MODERATE.equals(action)) {
+            simulateTrimMemoryPressureSignal(activity, ComponentCallbacks2.TRIM_MEMORY_MODERATE);
+        } else {
+            return false;
+        }
+
+        return true;
+    }
+
+    public static void maybeNotifyMemoryPresure(int level) {
+        if (level >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE) {
+            nativeOnMemoryPressure(MemoryPressureLevel.CRITICAL);
+        } else if (level >= ComponentCallbacks2.TRIM_MEMORY_BACKGROUND
+                || level == ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL) {
+            // Don't notifiy on TRIM_MEMORY_UI_HIDDEN, since this class only
+            // dispatches actionable memory pressure signals to native.
+            nativeOnMemoryPressure(MemoryPressureLevel.MODERATE);
+        }
+    }
+
+    private static void simulateLowMemoryPressureSignal(Activity activity) {
+        // The Application and the Activity each have a list of callbacks they notify when this
+        // method is called.  Notifying these will simulate the event at the App/Activity level
+        // as well as trigger the listener bound from native in this process.
+        activity.getApplication().onLowMemory();
+        activity.onLowMemory();
+    }
+
+    private static void simulateTrimMemoryPressureSignal(Activity activity, int level) {
+        // The Application and the Activity each have a list of callbacks they notify when this
+        // method is called.  Notifying these will simulate the event at the App/Activity level
+        // as well as trigger the listener bound from native in this process.
+        activity.getApplication().onTrimMemory(level);
+        activity.onTrimMemory(level);
+    }
+
+    private static native void nativeOnMemoryPressure(int memoryPressureType);
+}
diff --git a/base/android/java/src/org/chromium/base/NativeCall.java b/base/android/java/src/org/chromium/base/NativeCall.java
new file mode 100644
index 0000000..352edf7
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/NativeCall.java
@@ -0,0 +1,24 @@
+// 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;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @NativeCall is used by the JNI generator to create the necessary JNI bindings
+ * so a native function can be bound to a Java inner class. The native class for
+ * which the JNI method will be generated is specified by the first parameter.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.CLASS)
+public @interface NativeCall {
+    /*
+     * Value determines which native class the method should map to.
+     */
+    public String value() default "";
+}
diff --git a/base/android/java/src/org/chromium/base/NativeClassQualifiedName.java b/base/android/java/src/org/chromium/base/NativeClassQualifiedName.java
new file mode 100644
index 0000000..e55b18c
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/NativeClassQualifiedName.java
@@ -0,0 +1,25 @@
+// Copyright 2012 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;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @NativeClassQualifiedName is used by the JNI generator to create the necessary JNI
+ * bindings to call into the specified native class name.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface NativeClassQualifiedName {
+    /*
+     * Tells which native class the method is going to be bound to.
+     * The first parameter of the annotated method must be an int nativePtr pointing to
+     * an instance of this class.
+     */
+    public String value();
+}
diff --git a/base/android/java/src/org/chromium/base/OWNERS b/base/android/java/src/org/chromium/base/OWNERS
new file mode 100644
index 0000000..d99aec1
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/OWNERS
@@ -0,0 +1,2 @@
+per-file ApiCompatibilityUtils.java=aurimas@chromium.org
+per-file ApiCompatibilityUtils.java=newt@chromium.org
diff --git a/base/android/java/src/org/chromium/base/ObserverList.java b/base/android/java/src/org/chromium/base/ObserverList.java
new file mode 100644
index 0000000..7a2ab98
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/ObserverList.java
@@ -0,0 +1,249 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+import javax.annotation.concurrent.NotThreadSafe;
+
+/**
+ * A container for a list of observers.
+ * <p/>
+ * This container can be modified during iteration without invalidating the iterator.
+ * So, it safely handles the case of an observer removing itself or other observers from the list
+ * while observers are being notified.
+ * <p/>
+ * The implementation (and the interface) is heavily influenced by the C++ ObserverList.
+ * Notable differences:
+ *   - The iterator implements NOTIFY_EXISTING_ONLY.
+ *   - The FOR_EACH_OBSERVER closure is left to the clients to implement in terms of iterator().
+ * <p/>
+ * This class is not threadsafe. Observers MUST be added, removed and will be notified on the same
+ * thread this is created.
+ *
+ * @param <E> The type of observers that this list should hold.
+ */
+@NotThreadSafe
+public class ObserverList<E> implements Iterable<E> {
+    /**
+     * Extended iterator interface that provides rewind functionality.
+     */
+    public interface RewindableIterator<E> extends Iterator<E> {
+        /**
+         * Rewind the iterator back to the beginning.
+         *
+         * If we need to iterate multiple times, we can avoid iterator object reallocation by using
+         * this method.
+         */
+        public void rewind();
+    }
+
+    public final List<E> mObservers = new ArrayList<E>();
+    private int mIterationDepth = 0;
+    private int mCount = 0;
+    private boolean mNeedsCompact = false;
+
+    public ObserverList() {}
+
+    /**
+     * Add an observer to the list.
+     * <p/>
+     * An observer should not be added to the same list more than once. If an iteration is already
+     * in progress, this observer will be not be visible during that iteration.
+     *
+     * @return true if the observer list changed as a result of the call.
+     */
+    public boolean addObserver(E obs) {
+        // Avoid adding null elements to the list as they may be removed on a compaction.
+        if (obs == null || mObservers.contains(obs)) {
+            return false;
+        }
+
+        // Structurally modifying the underlying list here. This means we
+        // cannot use the underlying list's iterator to iterate over the list.
+        boolean result = mObservers.add(obs);
+        assert result;
+
+        ++mCount;
+        return true;
+    }
+
+    /**
+     * Remove an observer from the list if it is in the list.
+     *
+     * @return true if an element was removed as a result of this call.
+     */
+    public boolean removeObserver(E obs) {
+        if (obs == null) {
+            return false;
+        }
+
+        int index = mObservers.indexOf(obs);
+        if (index == -1) {
+            return false;
+        }
+
+        if (mIterationDepth == 0) {
+            // No one is iterating over the list.
+            mObservers.remove(index);
+        } else {
+            mNeedsCompact = true;
+            mObservers.set(index, null);
+        }
+        --mCount;
+        assert mCount >= 0;
+
+        return true;
+    }
+
+    public boolean hasObserver(E obs) {
+        return mObservers.contains(obs);
+    }
+
+    public void clear() {
+        mCount = 0;
+
+        if (mIterationDepth == 0) {
+            mObservers.clear();
+            return;
+        }
+
+        int size = mObservers.size();
+        mNeedsCompact |= size != 0;
+        for (int i = 0; i < size; i++) {
+            mObservers.set(i, null);
+        }
+    }
+
+    @Override
+    public Iterator<E> iterator() {
+        return new ObserverListIterator();
+    }
+
+    /**
+     * It's the same as {@link ObserverList#iterator()} but the return type is
+     * {@link RewindableIterator}. Use this iterator type if you need to use
+     * {@link RewindableIterator#rewind()}.
+     */
+    public RewindableIterator<E> rewindableIterator() {
+        return new ObserverListIterator();
+    }
+
+    /**
+     * Returns the number of observers currently registered in the ObserverList.
+     * This is equivalent to the number of non-empty spaces in |mObservers|.
+     */
+    public int size() {
+        return mCount;
+    }
+
+    /**
+     * Returns true if the ObserverList contains no observers.
+     */
+    public boolean isEmpty() {
+        return mCount == 0;
+    }
+
+    /**
+     * Compact the underlying list be removing null elements.
+     * <p/>
+     * Should only be called when mIterationDepth is zero.
+     */
+    private void compact() {
+        assert mIterationDepth == 0;
+        for (int i = mObservers.size() - 1; i >= 0; i--) {
+            if (mObservers.get(i) == null) {
+                mObservers.remove(i);
+            }
+        }
+    }
+
+    private void incrementIterationDepth() {
+        mIterationDepth++;
+    }
+
+    private void decrementIterationDepthAndCompactIfNeeded() {
+        mIterationDepth--;
+        assert mIterationDepth >= 0;
+        if (mIterationDepth > 0) return;
+        if (!mNeedsCompact) return;
+        mNeedsCompact = false;
+        compact();
+    }
+
+    /**
+     * Returns the size of the underlying storage of the ObserverList.
+     * It will take into account the empty spaces inside |mObservers|.
+     */
+    private int capacity() {
+        return mObservers.size();
+    }
+
+    private E getObserverAt(int index) {
+        return mObservers.get(index);
+    }
+
+    private class ObserverListIterator implements RewindableIterator<E> {
+        private int mListEndMarker;
+        private int mIndex = 0;
+        private boolean mIsExhausted = false;
+
+        private ObserverListIterator() {
+            ObserverList.this.incrementIterationDepth();
+            mListEndMarker = ObserverList.this.capacity();
+        }
+
+        @Override
+        public void rewind() {
+            compactListIfNeeded();
+            ObserverList.this.incrementIterationDepth();
+            mListEndMarker = ObserverList.this.capacity();
+            mIsExhausted = false;
+            mIndex = 0;
+        }
+
+        @Override
+        public boolean hasNext() {
+            int lookupIndex = mIndex;
+            while (lookupIndex < mListEndMarker
+                    && ObserverList.this.getObserverAt(lookupIndex) == null) {
+                lookupIndex++;
+            }
+            if (lookupIndex < mListEndMarker) return true;
+
+            // We have reached the end of the list, allow for compaction.
+            compactListIfNeeded();
+            return false;
+        }
+
+        @Override
+        public E next() {
+            // Advance if the current element is null.
+            while (mIndex < mListEndMarker && ObserverList.this.getObserverAt(mIndex) == null) {
+                mIndex++;
+            }
+            if (mIndex < mListEndMarker) return ObserverList.this.getObserverAt(mIndex++);
+
+            // We have reached the end of the list, allow for compaction.
+            compactListIfNeeded();
+            throw new NoSuchElementException();
+        }
+
+        @Override
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+
+        private void compactListIfNeeded() {
+            if (!mIsExhausted) {
+                mIsExhausted = true;
+                ObserverList.this.decrementIterationDepthAndCompactIfNeeded();
+            }
+        }
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/PackageUtils.java b/base/android/java/src/org/chromium/base/PackageUtils.java
new file mode 100644
index 0000000..b1cb29e
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/PackageUtils.java
@@ -0,0 +1,55 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+
+/**
+ * This class provides package checking related methods.
+ */
+public class PackageUtils {
+    /**
+     * Retrieves the PackageInfo object for this application.
+     *
+     * @param context Any context.
+     * @return The PackageInfo object for this application.
+     */
+    public static PackageInfo getOwnPackageInfo(Context context) {
+        PackageManager manager = context.getPackageManager();
+        try {
+            String packageName = context.getApplicationContext().getPackageName();
+            return manager.getPackageInfo(packageName, 0);
+        } catch (NameNotFoundException e) {
+            // Should never happen.
+            throw new AssertionError("Failed to retrieve own package info");
+        }
+    }
+
+    /**
+     * Retrieves the version of the given package installed on the device.
+     *
+     * @param context Any context.
+     * @param packageName Name of the package to find.
+     * @return The package's version code if found, -1 otherwise.
+     */
+    public static int getPackageVersion(Context context, String packageName) {
+        int versionCode = -1;
+        PackageManager pm = context.getPackageManager();
+        try {
+            PackageInfo packageInfo = pm.getPackageInfo(packageName, 0);
+            if (packageInfo != null) versionCode = packageInfo.versionCode;
+        } catch (PackageManager.NameNotFoundException e) {
+            // Do nothing, versionCode stays -1
+        }
+        return versionCode;
+    }
+
+    private PackageUtils() {
+        // Hide constructor
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/PathService.java b/base/android/java/src/org/chromium/base/PathService.java
new file mode 100644
index 0000000..b22328c
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/PathService.java
@@ -0,0 +1,24 @@
+// Copyright 2012 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;
+
+/**
+ * This class provides java side access to the native PathService.
+ */
+@JNINamespace("base::android")
+public abstract class PathService {
+
+    // Must match the value of DIR_MODULE in base/base_paths.h!
+    public static final int DIR_MODULE = 3;
+
+    // Prevent instantiation.
+    private PathService() {}
+
+    public static void override(int what, String path) {
+        nativeOverride(what, path);
+    }
+
+    private static native void nativeOverride(int what, String path);
+}
diff --git a/base/android/java/src/org/chromium/base/PathUtils.java b/base/android/java/src/org/chromium/base/PathUtils.java
new file mode 100644
index 0000000..e46fc30
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/PathUtils.java
@@ -0,0 +1,127 @@
+// Copyright 2012 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;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.os.AsyncTask;
+import android.os.Environment;
+
+import java.util.concurrent.ExecutionException;
+
+/**
+ * This class provides the path related methods for the native library.
+ */
+public abstract class PathUtils {
+
+    private static final int DATA_DIRECTORY = 0;
+    private static final int DATABASE_DIRECTORY = 1;
+    private static final int CACHE_DIRECTORY = 2;
+    private static final int NUM_DIRECTORIES = 3;
+    private static AsyncTask<String, Void, String[]> sDirPathFetchTask;
+
+    // Prevent instantiation.
+    private PathUtils() {}
+
+    /**
+     * Starts an asynchronous task to fetch the path of the directory where private data is to be
+     * stored by the application.
+     *
+     * @param suffix The private data directory suffix.
+     * @see Context#getDir(String, int)
+     */
+    public static void setPrivateDataDirectorySuffix(String suffix, Context context) {
+        final Context appContext = context.getApplicationContext();
+        sDirPathFetchTask = new AsyncTask<String, Void, String[]>() {
+            @Override
+            protected String[] doInBackground(String... dataDirectorySuffix) {
+                String[] paths = new String[NUM_DIRECTORIES];
+                paths[DATA_DIRECTORY] =
+                        appContext.getDir(dataDirectorySuffix[0], Context.MODE_PRIVATE).getPath();
+                paths[DATABASE_DIRECTORY] = appContext.getDatabasePath("foo").getParent();
+                // TODO(wnwen): Find a way to avoid calling this function in renderer process.
+                if (appContext.getCacheDir() != null) {
+                    paths[CACHE_DIRECTORY] = appContext.getCacheDir().getPath();
+                }
+                return paths;
+            }
+        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, suffix);
+    }
+
+    /**
+     * @param index The index of the cached directory path.
+     * @return The directory path requested, or null if not available.
+     */
+    private static String getDirectoryPath(int index) {
+        try {
+            return sDirPathFetchTask.get()[index];
+        } catch (InterruptedException e) {
+        } catch (ExecutionException e) {
+        }
+        return null;
+    }
+
+    /**
+     * @return the private directory that is used to store application data.
+     */
+    @CalledByNative
+    public static String getDataDirectory(Context appContext) {
+        assert sDirPathFetchTask != null : "setDataDirectorySuffix must be called first.";
+        return getDirectoryPath(DATA_DIRECTORY);
+    }
+
+    /**
+     * @return the private directory that is used to store application database.
+     */
+    @CalledByNative
+    public static String getDatabaseDirectory(Context appContext) {
+        assert sDirPathFetchTask != null : "setDataDirectorySuffix must be called first.";
+        return getDirectoryPath(DATABASE_DIRECTORY);
+    }
+
+    /**
+     * @return the cache directory.
+     */
+    @SuppressWarnings("unused")
+    @CalledByNative
+    public static String getCacheDirectory(Context appContext) {
+        assert sDirPathFetchTask != null : "setDataDirectorySuffix must be called first.";
+        return getDirectoryPath(CACHE_DIRECTORY);
+    }
+
+    /**
+     * @return the public downloads directory.
+     */
+    @SuppressWarnings("unused")
+    @CalledByNative
+    private static String getDownloadsDirectory(Context appContext) {
+        return Environment.getExternalStoragePublicDirectory(
+                Environment.DIRECTORY_DOWNLOADS).getPath();
+    }
+
+    /**
+     * @return the path to native libraries.
+     */
+    @SuppressWarnings("unused")
+    @CalledByNative
+    private static String getNativeLibraryDirectory(Context appContext) {
+        ApplicationInfo ai = appContext.getApplicationInfo();
+        if ((ai.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0
+                || (ai.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
+            return ai.nativeLibraryDir;
+        }
+
+        return "/system/lib/";
+    }
+
+    /**
+     * @return the external storage directory.
+     */
+    @SuppressWarnings("unused")
+    @CalledByNative
+    public static String getExternalStorageDirectory() {
+        return Environment.getExternalStorageDirectory().getAbsolutePath();
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/PerfTraceEvent.java b/base/android/java/src/org/chromium/base/PerfTraceEvent.java
new file mode 100644
index 0000000..c0e4b21
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/PerfTraceEvent.java
@@ -0,0 +1,379 @@
+// 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;
+
+import android.os.Debug;
+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;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * PerfTraceEvent can be used like TraceEvent, but is intended for
+ * performance measurement.  By limiting the types of tracing we hope
+ * to minimize impact on measurement.
+ *
+ * All PerfTraceEvent events funnel into TraceEvent. When not doing
+ * performance measurements, they act the same.  However,
+ * PerfTraceEvents can be enabled even when TraceEvent is not.
+ *
+ * Unlike TraceEvent, PerfTraceEvent data is sent to the system log,
+ * not to a trace file.
+ *
+ * Performance events need to have very specific names so we find
+ * the right ones.  For example, we specify the name exactly in
+ * 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";
+    private static File sOutputFile = null;
+
+    /** The event types understood by the perf trace scripts. */
+    private enum EventType {
+        START("S"),
+        FINISH("F"),
+        INSTANT("I");
+
+        // The string understood by the trace scripts.
+        private final String mTypeStr;
+
+        EventType(String typeStr) {
+            mTypeStr = typeStr;
+        }
+
+        @Override
+        public String toString() {
+            return mTypeStr;
+        }
+    }
+
+    private static boolean sEnabled = false;
+    private static boolean sTrackTiming = true;
+    private static boolean sTrackMemory = false;
+
+    // A list of performance trace event strings.
+    // Events are stored as a JSON dict much like TraceEvent.
+    // E.g. timestamp is in microseconds.
+    private static JSONArray sPerfTraceStrings;
+
+    // A filter for performance tracing.  Only events that match a
+    // string in the list are saved.  Presence of a filter does not
+    // necessarily mean perf tracing is enabled.
+    private static List<String> sFilter;
+
+    // Nanosecond start time of performance tracing.
+    private static long sBeginNanoTime;
+
+    /**
+     * Specifies what event names will be tracked.
+     *
+     * @param strings Event names we will record.
+     */
+    @VisibleForTesting
+    public static synchronized void setFilter(List<String> strings) {
+        sFilter = new LinkedList<String>(strings);
+    }
+
+    /**
+     * Enable or disable perf tracing.
+     * Disabling of perf tracing will dump trace data to the system log.
+     */
+    @VisibleForTesting
+    public static synchronized void setEnabled(boolean enabled) {
+        if (sEnabled == enabled) {
+            return;
+        }
+        if (enabled) {
+            sBeginNanoTime = System.nanoTime();
+            sPerfTraceStrings = new JSONArray();
+        } else {
+            dumpPerf();
+            sPerfTraceStrings = null;
+            sFilter = null;
+        }
+        sEnabled = enabled;
+    }
+
+    /**
+     * Enables memory tracking for all timing perf events tracked.
+     *
+     * <p>
+     * Only works when called in combination with {@link #setEnabled(boolean)}.
+     *
+     * <p>
+     * By enabling this feature, an additional perf event containing the memory usage will be
+     * logged whenever {@link #instant(String)}, {@link #begin(String)}, or {@link #end(String)}
+     * is called.
+     *
+     * @param enabled Whether to enable memory tracking for all perf events.
+     */
+    @VisibleForTesting
+    public static synchronized void setMemoryTrackingEnabled(boolean enabled) {
+        sTrackMemory = enabled;
+    }
+
+    /**
+     * Enables timing tracking for all perf events tracked.
+     *
+     * <p>
+     * Only works when called in combination with {@link #setEnabled(boolean)}.
+     *
+     * <p>
+     * If this feature is enabled, whenever {@link #instant(String)}, {@link #begin(String)},
+     * or {@link #end(String)} is called the time since start of tracking will be logged.
+     *
+     * @param enabled Whether to enable timing tracking for all perf events.
+     */
+    @VisibleForTesting
+    public static synchronized void setTimingTrackingEnabled(boolean enabled) {
+        sTrackTiming = enabled;
+    }
+
+    /**
+     * @return True if tracing is enabled, false otherwise.
+     * It is safe to call trace methods without checking if PerfTraceEvent
+     * is enabled.
+     */
+    @VisibleForTesting
+    public static synchronized boolean enabled() {
+        return sEnabled;
+    }
+
+    /**
+     * Record an "instant" perf trace event.  E.g. "screen update happened".
+     */
+    public static synchronized void instant(String name) {
+        // Instant doesn't really need/take an event id, but this should be okay.
+        final long eventId = name.hashCode();
+        TraceEvent.instant(name);
+        if (sEnabled && matchesFilter(name)) {
+            savePerfString(name, eventId, EventType.INSTANT, false);
+        }
+    }
+
+
+    /**
+     * Record an "begin" perf trace event.
+     * Begin trace events should have a matching end event.
+     */
+    @VisibleForTesting
+    public static synchronized void begin(String name) {
+        final long eventId = name.hashCode();
+        TraceEvent.startAsync(name, eventId);
+        if (sEnabled && matchesFilter(name)) {
+            // Done before calculating the starting perf data to ensure calculating the memory usage
+            // does not influence the timing data.
+            if (sTrackMemory) {
+                savePerfString(makeMemoryTraceNameFromTimingName(name), eventId, EventType.START,
+                        true);
+            }
+            if (sTrackTiming) {
+                savePerfString(name, eventId, EventType.START, false);
+            }
+        }
+    }
+
+    /**
+     * Record an "end" perf trace event, to match a begin event.  The
+     * time delta between begin and end is usually interesting to
+     * graph code.
+     */
+    @VisibleForTesting
+    public static synchronized void end(String name) {
+        final long eventId = name.hashCode();
+        TraceEvent.finishAsync(name, eventId);
+        if (sEnabled && matchesFilter(name)) {
+            if (sTrackTiming) {
+                savePerfString(name, eventId, EventType.FINISH, false);
+            }
+            // Done after calculating the ending perf data to ensure calculating the memory usage
+            // does not influence the timing data.
+            if (sTrackMemory) {
+                savePerfString(makeMemoryTraceNameFromTimingName(name), eventId, EventType.FINISH,
+                        true);
+            }
+        }
+    }
+
+    /**
+     * Record an "begin" memory trace event.
+     * Begin trace events should have a matching end event.
+     */
+    @VisibleForTesting
+    public static synchronized void begin(String name, MemoryInfo memoryInfo) {
+        final long eventId = name.hashCode();
+        TraceEvent.startAsync(name, eventId);
+        if (sEnabled && matchesFilter(name)) {
+            // Done before calculating the starting perf data to ensure calculating the memory usage
+            // does not influence the timing data.
+            long timestampUs = (System.nanoTime() - sBeginNanoTime) / 1000;
+            savePerfString(makeMemoryTraceNameFromTimingName(name), eventId, EventType.START,
+                    timestampUs, memoryInfo);
+            if (sTrackTiming) {
+                savePerfString(name, eventId, EventType.START, false);
+            }
+        }
+    }
+
+    /**
+     * Record an "end" memory trace event, to match a begin event.  The
+     * memory usage delta between begin and end is usually interesting to
+     * graph code.
+     */
+    @VisibleForTesting
+    public static synchronized void end(String name, MemoryInfo memoryInfo) {
+        final long eventId = name.hashCode();
+        TraceEvent.finishAsync(name, eventId);
+        if (sEnabled && matchesFilter(name)) {
+            if (sTrackTiming) {
+                savePerfString(name, eventId, EventType.FINISH, false);
+            }
+            // Done after calculating the instant perf data to ensure calculating the memory usage
+            // does not influence the timing data.
+            long timestampUs = (System.nanoTime() - sBeginNanoTime) / 1000;
+            savePerfString(makeMemoryTraceNameFromTimingName(name), eventId, EventType.FINISH,
+                    timestampUs, memoryInfo);
+        }
+    }
+
+    /**
+     * Determine if we are interested in this trace event.
+     * @return True if the name matches the allowed filter; else false.
+     */
+    private static boolean matchesFilter(String name) {
+        return sFilter != null ? sFilter.contains(name) : false;
+    }
+
+    /**
+     * Save a perf trace event as a JSON dict.  The format mirrors a TraceEvent dict.
+     *
+     * @param name The trace data
+     * @param id The id of the event
+     * @param type the type of trace event (I, S, F)
+     * @param includeMemory Whether to include current browser process memory usage in the trace.
+     */
+    private static void savePerfString(String name, long id, EventType type,
+            boolean includeMemory) {
+        long timestampUs = (System.nanoTime() - sBeginNanoTime) / 1000;
+        MemoryInfo memInfo = null;
+        if (includeMemory) {
+            memInfo = new MemoryInfo();
+            Debug.getMemoryInfo(memInfo);
+        }
+        savePerfString(name, id, type, timestampUs, memInfo);
+    }
+
+    /**
+     * Save a perf trace event as a JSON dict.  The format mirrors a TraceEvent dict.
+     *
+     * @param name The trace data
+     * @param id The id of the event
+     * @param type the type of trace event (I, S, F)
+     * @param timestampUs The time stamp at which this event was recorded
+     * @param memoryInfo Memory details to be included in this perf string, null if
+     *                   no memory details are to be included.
+     */
+    private static void savePerfString(String name, long id, EventType type, long timestampUs,
+            MemoryInfo memoryInfo) {
+        try {
+            JSONObject traceObj = new JSONObject();
+            traceObj.put("cat", "Java");
+            traceObj.put("ts", timestampUs);
+            traceObj.put("ph", type);
+            traceObj.put("name", name);
+            traceObj.put("id", id);
+            if (memoryInfo != null) {
+                int pss = memoryInfo.nativePss + memoryInfo.dalvikPss + memoryInfo.otherPss;
+                traceObj.put("mem", pss);
+            }
+            sPerfTraceStrings.put(traceObj);
+        } catch (JSONException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Generating a trace name for tracking memory based on the timing name passed in.
+     *
+     * @param name The timing name to use as a base for the memory perf name.
+     * @return The memory perf name to use.
+     */
+    public static String makeMemoryTraceNameFromTimingName(String name) {
+        return makeSafeTraceName(name, MEMORY_TRACE_NAME_SUFFIX);
+    }
+
+    /**
+     * Builds a name to be used in the perf trace framework.  The framework has length requirements
+     * for names, so this ensures the generated name does not exceed the maximum (trimming the
+     * base name if necessary).
+     *
+     * @param baseName The base name to use when generating the name.
+     * @param suffix The required suffix to be appended to the name.
+     * @return A name that is safe for the perf trace framework.
+     */
+    public static String makeSafeTraceName(String baseName, String suffix) {
+        int suffixLength = suffix.length();
+
+        if (baseName.length() + suffixLength > MAX_NAME_LENGTH) {
+            baseName = baseName.substring(0, MAX_NAME_LENGTH - suffixLength);
+        }
+        return baseName + suffix;
+    }
+
+    /**
+     * Sets a file to dump the results to.  If {@code file} is {@code null}, it will be dumped
+     * to STDOUT, otherwise the JSON performance data will be appended to {@code file}.  This should
+     * be called before the performance run starts.  When {@link #setEnabled(boolean)} is called
+     * with {@code false}, the perf data will be dumped.
+     *
+     * @param file Which file to append the performance data to.  If {@code null}, the performance
+     *             data will be sent to STDOUT.
+     */
+    @VisibleForTesting
+    public static synchronized void setOutputFile(File file) {
+        sOutputFile = file;
+    }
+
+    /**
+     * Dump all performance data we have saved up to the log.
+     * Output as JSON for parsing convenience.
+     */
+    private static void dumpPerf() {
+        String json = sPerfTraceStrings.toString();
+
+        if (sOutputFile == null) {
+            System.out.println(json);
+        } else {
+            try {
+                PrintStream stream = new PrintStream(new FileOutputStream(sOutputFile, true));
+                try {
+                    stream.print(json);
+                } finally {
+                    try {
+                        stream.close();
+                    } catch (Exception ex) {
+                        Log.e("PerfTraceEvent", "Unable to close perf trace output file.");
+                    }
+                }
+            } catch (FileNotFoundException ex) {
+                Log.e("PerfTraceEvent", "Unable to dump perf trace data to output file.");
+            }
+        }
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/PowerMonitor.java b/base/android/java/src/org/chromium/base/PowerMonitor.java
new file mode 100644
index 0000000..3d0ed48
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/PowerMonitor.java
@@ -0,0 +1,98 @@
+// Copyright 2012 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;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.BatteryManager;
+import android.os.Handler;
+import android.os.Looper;
+
+
+/**
+ * Integrates native PowerMonitor with the java side.
+ */
+@JNINamespace("base::android")
+public class PowerMonitor implements ApplicationStatus.ApplicationStateListener {
+    private static final long SUSPEND_DELAY_MS = 1 * 60 * 1000;  // 1 minute.
+    private static class LazyHolder {
+        private static final PowerMonitor INSTANCE = new PowerMonitor();
+    }
+    private static PowerMonitor sInstance;
+
+    private boolean mIsBatteryPower;
+    private final Handler mHandler = new Handler(Looper.getMainLooper());
+
+    // Asynchronous task used to fire the "paused" event to the native side 1 minute after the main
+    // activity transitioned to the "paused" state. This event is not sent immediately because it
+    // would be too aggressive. An Android activity can be in the "paused" state quite often. This
+    // can happen when a dialog window shows up for instance.
+    private static final Runnable sSuspendTask = new Runnable() {
+        @Override
+        public void run() {
+            nativeOnMainActivitySuspended();
+        }
+    };
+
+    public static void createForTests(Context context) {
+        // Applications will create this once the JNI side has been fully wired up both sides. For
+        // tests, we just need native -> java, that is, we don't need to notify java -> native on
+        // creation.
+        sInstance = LazyHolder.INSTANCE;
+    }
+
+    /**
+     * Create a PowerMonitor instance if none exists.
+     * @param context The context to register broadcast receivers for.  The application context
+     *                will be used from this parameter.
+     */
+    public static void create(Context context) {
+        context = context.getApplicationContext();
+        if (sInstance == null) {
+            sInstance = LazyHolder.INSTANCE;
+            ApplicationStatus.registerApplicationStateListener(sInstance);
+            IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
+            Intent batteryStatusIntent = context.registerReceiver(null, ifilter);
+            onBatteryChargingChanged(batteryStatusIntent);
+        }
+    }
+
+    private PowerMonitor() {
+    }
+
+    public static void onBatteryChargingChanged(Intent intent) {
+        if (sInstance == null) {
+            // We may be called by the framework intent-filter before being fully initialized. This
+            // is not a problem, since our constructor will check for the state later on.
+            return;
+        }
+        int chargePlug = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
+        // If we're not plugged, assume we're running on battery power.
+        sInstance.mIsBatteryPower = chargePlug != BatteryManager.BATTERY_PLUGGED_USB
+                && chargePlug != BatteryManager.BATTERY_PLUGGED_AC;
+        nativeOnBatteryChargingChanged();
+    }
+
+    @Override
+    public void onApplicationStateChange(int newState) {
+        if (newState == ApplicationState.HAS_RUNNING_ACTIVITIES) {
+            // Remove the callback from the message loop in case it hasn't been executed yet.
+            mHandler.removeCallbacks(sSuspendTask);
+            nativeOnMainActivityResumed();
+        } else if (newState == ApplicationState.HAS_PAUSED_ACTIVITIES) {
+            mHandler.postDelayed(sSuspendTask, SUSPEND_DELAY_MS);
+        }
+    }
+
+    @CalledByNative
+    private static boolean isBatteryPower() {
+        return sInstance.mIsBatteryPower;
+    }
+
+    private static native void nativeOnBatteryChargingChanged();
+    private static native void nativeOnMainActivitySuspended();
+    private static native void nativeOnMainActivityResumed();
+}
diff --git a/base/android/java/src/org/chromium/base/PowerStatusReceiver.java b/base/android/java/src/org/chromium/base/PowerStatusReceiver.java
new file mode 100644
index 0000000..904a740
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/PowerStatusReceiver.java
@@ -0,0 +1,23 @@
+// Copyright 2012 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;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+
+/**
+ * A BroadcastReceiver that listens to changes in power status and notifies
+ * PowerMonitor.
+ * It's instantiated by the framework via the application intent-filter
+ * declared in its manifest.
+ */
+public class PowerStatusReceiver extends BroadcastReceiver {
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        PowerMonitor.onBatteryChargingChanged(intent);
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/README_logging.md b/base/android/java/src/org/chromium/base/README_logging.md
new file mode 100644
index 0000000..a680ce1
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/README_logging.md
@@ -0,0 +1,181 @@
+## Logging ##
+
+Logging used to be done using Android's [android.util.Log]
+(http://developer.android.com/reference/android/util/Log.html).
+
+A wrapper on that is now available: org.chromium.base.Log. It is designed to write logs as
+belonging to logical groups going beyond single classes, and to make it easy to switch logging on
+or off for individual groups.
+
+Usage:
+
+    private static final String TAG = "cr.YourModuleTag";
+    ...
+    Log.i(TAG, "Logged INFO message.");
+    Log.d(TAG, "Some DEBUG info: %s", data);
+
+Output:
+
+    I/cr.YourModuleTag: ( 999): Logged INFO message
+    D/cr.YourModuleTag: ( 999): [MyClass.java:42] Some DEBUG info: data's toString output
+
+Here, **TAG** will be a feature or package name, "MediaRemote" or "NFC" for example. In most
+cases, the class name is not needed.
+
+**Caveat:** Property keys are limited to 23 characters. If the tag is too long, `Log#isLoggable`
+throws a RuntimeException.
+
+### Verbose and Debug logs have special handling ###
+
+*   `Log.v` and `Log.d` Calls made using `org.chromium.base.Log` are stripped
+    out of production binaries using Proguard. There is no way to get those logs
+	in release builds.
+
+*   The file name and line number will be prepended to the log message.
+    For higher priority logs, those are not added for performance concerns.
+
+*   By default, Verbose and Debug logs are not enabled, see guarding:
+
+### Log calls are guarded: Tag groups can be enabled or disabled using ADB ###
+
+    adb shell setprop log.tag.cr.YourModuleTag <LEVEL>
+
+Level here is either `VERBOSE`, `DEBUG`, `INFO`, `WARN`, `ERROR`, `ASSERT`, or `SUPPRESS`
+By default, the level for all tags is `INFO`.
+
+### An exception trace is printed when the exception is the last parameter ###
+
+As with `java.util.Log`, putting a throwable as last parameter will dump the corresponding stack
+trace:
+
+    Log.i(TAG, "An error happened: %s", e)
+
+    I/cr.YourModuleTag: ( 999): An error happened: This is the exception's message
+    I/cr.YourModuleTag: ( 999): java.lang.Exception: This is the exception's message
+    I/cr.YourModuleTag: ( 999):     at foo.bar.MyClass.test(MyClass.java:42)
+    I/cr.YourModuleTag: ( 999):     ...
+
+Having the exception as last parameter doesn't prevent it from being used for string formatting.
+
+### Logging Best Practices
+
+#### Rule #1: Never log PII (Personal Identification Information):
+
+This is a huge concern, because other applications can access the log and extract a lot of data
+from your own by doing so. Even if JellyBean restricted this, people are going to run your
+application on rooted devices and allow some apps to access it. Also anyone with USB access to the
+device can use ADB to get the full logcat and get the same data right now.
+
+If you really need to print something , print a series of Xs instead (e.g. "XXXXXX"), or print a
+truncated hash of the PII instead. Truncation is required to make it harder for an attacker to
+recover the full data through rainbow tables and similar methods.
+
+Similarly, avoid dumping API keys, cookies, etc...
+
+#### Rule #2: Do not write debug logs in production code:
+
+The kernel log buffer is global and of limited size. Any extra debug log you add to your activity
+or service makes it more difficult to diagnose problems on other parts of the system, because they
+tend to push the interesting bit out of the buffer too soon. This is a recurring problem on
+Android, so avoid participating into it.
+
+Logs can be disabled using system properties. Because log messages might not be
+written, the cost of creating them should also be avoided. This can be done using three
+complementary ways:
+
+-   Use string formatting instead of concatenations
+
+        // BAD
+        Log.d(TAG, "I " + preference + " writing logs.");
+
+        // BETTER
+        Log.d(TAG, "I %s writing logs.", preference);
+
+    If logging is disabled, the function's arguments will still have to be computed and provided
+    as input. The first call above will always lead to the creation of a `StringBuilder` and a few
+    concatenations, while the second just passes the arguments and won't need that.
+
+-   Guard expensive calls
+
+    Sometimes the values to log aren't readily available and need to be computed specially. This
+    should be avoided when logging is disabled.
+
+    Using `Log#isLoggable` will return whether logging for a specific tag is allowed or not. It is
+    the call used inside the log functions and using allows to know when running the expensive
+    functions is needed.
+
+        if (Log.isLoggable(TAG, Log.DEBUG) {
+          Log.d(TAG, "Something happened: %s", dumpDom(tab));
+        }
+
+    For more info, See the [android framework documentation]
+    (http://developer.android.com/tools/debugging/debugging-log.html).
+
+    Using a debug constant is a less flexible, but more perfomance oriented alternative.
+
+        static private final boolean DEBUG = false;  // set to 'true' to enable debug
+        ...
+        if (DEBUG) {
+          Log.i(TAG, createThatExpensiveLogMessage(activity))
+        }
+
+    Because the variable is a `static final` that can be evaluated at compile time, the Java
+    compiler will optimize out all guarded calls from the generated `.class` file. Changing it
+    however requires editing each of the files for which debug should be enabled and recompiling,
+    while the previous method can enable or disable debugging for a whole feature without changing
+    any source file.
+
+-   Annotate debug functions with the `@NoSideEffects` annotation.
+
+    That annotation tells Proguard to assume that a given function has no side effects, and is
+    called only for its returned value. If this value is unused, the call will be removed. If the
+    function is not called at all, it will also be removed. Since Proguard is already used to
+    strip debug and verbose calls out of release builds, this annotation allows it to have a
+    deeper action by removing also function calls used to generate the log call's arguments.
+  
+        /* If that function is only used in Log.d calls, proguard should completely remove it from
+         * the release builds. */
+        @NoSideEffects
+        private static String getSomeDebugLogString(Thing[] things) {
+          /* Still needs to be guarded to avoid impacting debug builds, or in case it's used for
+           * some other log levels. But at least it is done only once, inside the function. */
+          if (!Log.isLoggable(TAG, Log.DEBUG)) return null;
+
+          StringBuilder sb = new StringBuilder("Reporting " + thing.length + " things:");
+          for (Thing thing : things) {
+            sb.append('\n').append(thing.id).append(' ').append(report.foo);
+          }
+          return sb.toString();
+        }
+
+        public void bar() {
+          ...
+          Log.d(TAG, getSomeDebugLogString(things)); /* In debug builds, the function does nothing
+                                                      * is debug is disabled, and the entire line 
+                                                      * is removed in release builds. */
+        }
+
+    Again, this is useful only if the input to that function are variables already available in
+    the scope. The idea is to move computations, concatenations, etc. to a place where that can be
+    removed when not needed, without invading the main function's logic.
+
+#### Rule #3: Favor small log messages
+
+This is still related to the global fixed-sized kernel buffer used to keep all logs. Try to make
+your log information as terse as possible. This reduces the risk of pushing interesting log data
+out of the buffer when something really nasty happens. It's really better to have a single-line
+log message, than several ones. I.e. don't use:
+
+    Log.GROUP.d(TAG, "field1 = %s", value1);
+    Log.GROUP.d(TAG, "field2 = %s", value2);
+    Log.GROUP.d(TAG, "field3 = %s", value3);
+
+Instead, write this as:
+
+    Log.d(TAG, "field1 = %s, field2 = %s, field3 = %s", value1, value2, value3);
+
+That doesn't seem to be much different if you count overall character counts, but each independent
+log entry also implies a small, but non-trivial header, in the kernel log buffer.
+And since every byte count, you can also try something even shorter, as in:
+
+    Log.d(TAG, "fields [%s,%s,%s]", value1, value2, value3);
diff --git a/base/android/java/src/org/chromium/base/ResourceExtractor.java b/base/android/java/src/org/chromium/base/ResourceExtractor.java
new file mode 100644
index 0000000..d44f2fc
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/ResourceExtractor.java
@@ -0,0 +1,484 @@
+// Copyright 2012 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;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+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;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import java.util.regex.Pattern;
+
+/**
+ * Handles extracting the necessary resources bundled in an APK and moving them to a location on
+ * the file system accessible from the native code.
+ */
+public class ResourceExtractor {
+
+    private static final String LOGTAG = "ResourceExtractor";
+    private static final String LAST_LANGUAGE = "Last language";
+    private static final String PAK_FILENAMES_LEGACY_NOREUSE = "Pak filenames";
+    private static final String ICU_DATA_FILENAME = "icudtl.dat";
+    private static final String V8_NATIVES_DATA_FILENAME = "natives_blob.bin";
+    private static final String V8_SNAPSHOT_DATA_FILENAME = "snapshot_blob.bin";
+
+    private static String[] sMandatoryPaks = null;
+
+    // By default, we attempt to extract a pak file for the users
+    // current device locale. Use setExtractImplicitLocale() to
+    // change this behavior.
+    private static boolean sExtractImplicitLocalePak = true;
+
+    private static boolean isAppDataFile(String file) {
+        return ICU_DATA_FILENAME.equals(file)
+                || V8_NATIVES_DATA_FILENAME.equals(file)
+                || V8_SNAPSHOT_DATA_FILENAME.equals(file);
+    }
+
+    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() {
+        }
+
+        private void doInBackgroundImpl() {
+            final File outputDir = getOutputDir();
+            final File appDataDir = getAppDataDir();
+            if (!outputDir.exists() && !outputDir.mkdirs()) {
+                Log.e(LOGTAG, "Unable to create pak resources directory!");
+                return;
+            }
+
+            String timestampFile = null;
+            beginTraceSection("checkPakTimeStamp");
+            try {
+                timestampFile = checkPakTimestamp(outputDir);
+            } finally {
+                endTraceSection();
+            }
+            if (timestampFile != null) {
+                deleteFiles();
+            }
+
+            SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
+            String currentLocale = LocaleUtils.getDefaultLocale();
+            String currentLanguage = currentLocale.split("-", 2)[0];
+            // If everything we need is already there (and the locale hasn't
+            // changed), quick exit.
+            if (prefs.getString(LAST_LANGUAGE, "").equals(currentLanguage)) {
+                boolean filesPresent = true;
+                for (String file : sMandatoryPaks) {
+                    File directory = isAppDataFile(file) ? appDataDir : outputDir;
+                    if (!new File(directory, file).exists()) {
+                        filesPresent = false;
+                        break;
+                    }
+                }
+                if (filesPresent) return;
+            } else {
+                prefs.edit().putString(LAST_LANGUAGE, currentLanguage).apply();
+            }
+
+            StringBuilder p = new StringBuilder();
+            for (String mandatoryPak : sMandatoryPaks) {
+                if (p.length() > 0) p.append('|');
+                p.append("\\Q" + mandatoryPak + "\\E");
+            }
+
+            if (sExtractImplicitLocalePak) {
+                if (p.length() > 0) p.append('|');
+                // As well as the minimum required set of .paks above, we'll
+                // also add all .paks that we have for the user's currently
+                // selected language.
+                p.append(currentLanguage);
+                p.append("(-\\w+)?\\.pak");
+            }
+
+            Pattern paksToInstall = Pattern.compile(p.toString());
+
+            AssetManager manager = mContext.getResources().getAssets();
+            beginTraceSection("WalkAssets");
+            try {
+                // Loop through every asset file that we have in the APK, and look for the
+                // ones that we need to extract by trying to match the Patterns that we
+                // created above.
+                byte[] buffer = null;
+                String[] files = manager.list("");
+                for (String file : files) {
+                    if (!paksToInstall.matcher(file).matches()) {
+                        continue;
+                    }
+                    File output = new File(isAppDataFile(file) ? appDataDir : outputDir, file);
+                    if (output.exists()) {
+                        continue;
+                    }
+
+                    InputStream is = null;
+                    OutputStream os = null;
+                    beginTraceSection("ExtractResource");
+                    try {
+                        is = manager.open(file);
+                        os = new FileOutputStream(output);
+                        Log.i(LOGTAG, "Extracting resource " + file);
+                        if (buffer == null) {
+                            buffer = new byte[BUFFER_SIZE];
+                        }
+
+                        int count = 0;
+                        while ((count = is.read(buffer, 0, BUFFER_SIZE)) != -1) {
+                            os.write(buffer, 0, count);
+                        }
+                        os.flush();
+
+                        // Ensure something reasonable was written.
+                        if (output.length() == 0) {
+                            throw new IOException(file + " extracted with 0 length!");
+                        }
+
+                        if (isAppDataFile(file)) {
+                            // icu and V8 data need to be accessed by a renderer
+                            // process.
+                            output.setReadable(true, false);
+                        }
+                    } finally {
+                        try {
+                            if (is != null) {
+                                is.close();
+                            }
+                        } finally {
+                            if (os != null) {
+                                os.close();
+                            }
+                            endTraceSection(); // ExtractResource
+                        }
+                    }
+                }
+            } catch (IOException e) {
+                // TODO(benm): See crbug/152413.
+                // Try to recover here, can we try again after deleting files instead of
+                // returning null? It might be useful to gather UMA here too to track if
+                // this happens with regularity.
+                Log.w(LOGTAG, "Exception unpacking required pak resources: " + e.getMessage());
+                deleteFiles();
+                return;
+            } finally {
+                endTraceSection(); // WalkAssets
+            }
+
+            // Finished, write out a timestamp file if we need to.
+            if (timestampFile != null) {
+                try {
+                    new File(outputDir, timestampFile).createNewFile();
+                } catch (IOException e) {
+                    // Worst case we don't write a timestamp, so we'll re-extract the resource
+                    // paks next start up.
+                    Log.w(LOGTAG, "Failed to write resource pak timestamp!");
+                }
+            }
+        }
+
+        @Override
+        protected Void doInBackground(Void... unused) {
+            // TODO(lizeb): Use chrome tracing here (and above in
+            // doInBackgroundImpl) when it will be possible. This is currently
+            // not doable since the native library is not loaded yet, and the
+            // TraceEvent calls are dropped before this point.
+            beginTraceSection("ResourceExtractor.ExtractTask.doInBackground");
+            try {
+                doInBackgroundImpl();
+            } finally {
+                endTraceSection();
+            }
+            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
+        // a String that represents the filename of a timestamp to create.
+        // Note that we do this to avoid adding a BroadcastReceiver on
+        // android.content.Intent#ACTION_PACKAGE_CHANGED as that causes process churn
+        // on (re)installation of *all* APK files.
+        private String checkPakTimestamp(File outputDir) {
+            final String timestampPrefix = "pak_timestamp-";
+            PackageManager pm = mContext.getPackageManager();
+            PackageInfo pi = null;
+
+            try {
+                pi = pm.getPackageInfo(mContext.getPackageName(), 0);
+            } catch (PackageManager.NameNotFoundException e) {
+                return timestampPrefix;
+            }
+
+            if (pi == null) {
+                return timestampPrefix;
+            }
+
+            String expectedTimestamp = timestampPrefix + pi.versionCode + "-" + pi.lastUpdateTime;
+
+            String[] timestamps = outputDir.list(new FilenameFilter() {
+                @Override
+                public boolean accept(File dir, String name) {
+                    return name.startsWith(timestampPrefix);
+                }
+            });
+
+            if (timestamps.length != 1) {
+                // If there's no timestamp, nuke to be safe as we can't tell the age of the files.
+                // If there's multiple timestamps, something's gone wrong so nuke.
+                return expectedTimestamp;
+            }
+
+            if (!expectedTimestamp.equals(timestamps[0])) {
+                return expectedTimestamp;
+            }
+
+            // timestamp file is already up-to date.
+            return null;
+        }
+
+        @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
+        private void beginTraceSection(String section) {
+            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) return;
+            Trace.beginSection(section);
+        }
+
+        @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
+        private void endTraceSection() {
+            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) return;
+            Trace.endSection();
+        }
+    }
+
+    private final Context mContext;
+    private ExtractTask mExtractTask;
+
+    private static ResourceExtractor sInstance;
+
+    public static ResourceExtractor get(Context context) {
+        if (sInstance == null) {
+            sInstance = new ResourceExtractor(context);
+        }
+        return sInstance;
+    }
+
+    /**
+     * Specifies the .pak files that should be extracted from the APK's asset resources directory
+     * and moved to {@link #getOutputDirFromContext(Context)}.
+     * @param mandatoryPaks The list of pak files to be loaded. If no pak files are
+     *     required, pass a single empty string.
+     */
+    public static void setMandatoryPaksToExtract(String... mandatoryPaks) {
+        assert (sInstance == null || sInstance.mExtractTask == null)
+                : "Must be called before startExtractingResources is called";
+        sMandatoryPaks = mandatoryPaks;
+
+    }
+
+    /**
+     * By default the ResourceExtractor will attempt to extract a pak resource for the users
+     * currently specified locale. This behavior can be changed with this function and is
+     * only needed by tests.
+     * @param extract False if we should not attempt to extract a pak file for
+     *         the users currently selected locale and try to extract only the
+     *         pak files specified in sMandatoryPaks.
+     */
+    @VisibleForTesting
+    public static void setExtractImplicitLocaleForTesting(boolean extract) {
+        assert (sInstance == null || sInstance.mExtractTask == null)
+                : "Must be called before startExtractingResources is called";
+        sExtractImplicitLocalePak = extract;
+    }
+
+    /**
+     * Marks all the 'pak' resources, packaged as assets, for extraction during
+     * running the tests.
+     */
+    @VisibleForTesting
+    public void setExtractAllPaksAndV8SnapshotForTesting() {
+        List<String> pakAndSnapshotFileAssets = new ArrayList<String>();
+        AssetManager manager = mContext.getResources().getAssets();
+        try {
+            String[] files = manager.list("");
+            for (String file : files) {
+                if (file.endsWith(".pak")) pakAndSnapshotFileAssets.add(file);
+            }
+        } catch (IOException e) {
+            Log.w(LOGTAG, "Exception while accessing assets: " + e.getMessage(), e);
+        }
+        pakAndSnapshotFileAssets.add("natives_blob.bin");
+        pakAndSnapshotFileAssets.add("snapshot_blob.bin");
+        setMandatoryPaksToExtract(pakAndSnapshotFileAssets.toArray(
+                new String[pakAndSnapshotFileAssets.size()]));
+    }
+
+    private ResourceExtractor(Context context) {
+        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;
+        }
+
+        assert mExtractTask != null;
+
+        try {
+            mExtractTask.get();
+        } catch (CancellationException e) {
+            // Don't leave the files in an inconsistent state.
+            deleteFiles();
+        } catch (ExecutionException e2) {
+            deleteFiles();
+        } catch (InterruptedException e3) {
+            deleteFiles();
+        }
+    }
+
+    /**
+     * 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.
+     */
+    public void startExtractingResources() {
+        if (mExtractTask != null) {
+            return;
+        }
+
+        if (shouldSkipPakExtraction()) {
+            return;
+        }
+
+        mExtractTask = new ExtractTask();
+        mExtractTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+    }
+
+    private File getAppDataDir() {
+        return new File(PathUtils.getDataDirectory(mContext));
+    }
+
+    private File getOutputDir() {
+        return new File(getAppDataDir(), "paks");
+    }
+
+    /**
+     * Pak files (UI strings and other resources) should be updated along with
+     * Chrome. A version mismatch can lead to a rather broken user experience.
+     * Failing to update the V8 snapshot files will lead to a version mismatch
+     * between V8 and the loaded snapshot which will cause V8 to crash, so this
+     * is treated as an error. The ICU data (icudtl.dat) is less
+     * version-sensitive, but still can lead to malfunction/UX misbehavior. So,
+     * we regard failing to update them as an error.
+     */
+    private void deleteFiles() {
+        File icudata = new File(getAppDataDir(), ICU_DATA_FILENAME);
+        if (icudata.exists() && !icudata.delete()) {
+            Log.e(LOGTAG, "Unable to remove the icudata " + icudata.getName());
+        }
+        File v8_natives = new File(getAppDataDir(), V8_NATIVES_DATA_FILENAME);
+        if (v8_natives.exists() && !v8_natives.delete()) {
+            Log.e(LOGTAG,
+                    "Unable to remove the v8 data " + v8_natives.getName());
+        }
+        File v8_snapshot = new File(getAppDataDir(), V8_SNAPSHOT_DATA_FILENAME);
+        if (v8_snapshot.exists() && !v8_snapshot.delete()) {
+            Log.e(LOGTAG,
+                    "Unable to remove the v8 data " + v8_snapshot.getName());
+        }
+        File dir = getOutputDir();
+        if (dir.exists()) {
+            File[] files = dir.listFiles();
+            for (File file : files) {
+                if (!file.delete()) {
+                    Log.e(LOGTAG, "Unable to remove existing resource " + file.getName());
+                }
+            }
+        }
+    }
+
+    /**
+     * Pak extraction not necessarily required by the embedder; we allow them to skip
+     * this process if they call setMandatoryPaksToExtract with a single empty String.
+     */
+    private static boolean shouldSkipPakExtraction() {
+        // Must call setMandatoryPaksToExtract before beginning resource extraction.
+        assert sMandatoryPaks != null;
+        return sMandatoryPaks.length == 1 && "".equals(sMandatoryPaks[0]);
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/SecureRandomInitializer.java b/base/android/java/src/org/chromium/base/SecureRandomInitializer.java
new file mode 100644
index 0000000..457e2ef
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/SecureRandomInitializer.java
@@ -0,0 +1,42 @@
+// 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;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.security.SecureRandom;
+
+/**
+ * This class contains code to initialize a SecureRandom generator securely on Android platforms
+ * <= 4.3. See
+ * {@link http://android-developers.blogspot.com/2013/08/some-securerandom-thoughts.html}.
+ */
+public class SecureRandomInitializer {
+    private static final int NUM_RANDOM_BYTES = 16;
+
+    private static byte[] sSeedBytes = new byte[NUM_RANDOM_BYTES];
+
+    /**
+     * Safely initializes the random number generator, by seeding it with data from /dev/urandom.
+     */
+    public static void initialize(SecureRandom generator) throws IOException {
+        FileInputStream fis = null;
+        try {
+            fis = new FileInputStream("/dev/urandom");
+            if (fis.read(sSeedBytes) != sSeedBytes.length) {
+                throw new IOException("Failed to get enough random data.");
+            }
+            generator.setSeed(sSeedBytes);
+        } finally {
+            try {
+                if (fis != null) {
+                    fis.close();
+                }
+            } catch (IOException e) {
+                // Ignore exception closing the device.
+            }
+        }
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/SysUtils.java b/base/android/java/src/org/chromium/base/SysUtils.java
new file mode 100644
index 0000000..9dad516
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/SysUtils.java
@@ -0,0 +1,139 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.annotation.TargetApi;
+import android.app.ActivityManager;
+import android.content.Context;
+import android.os.Build;
+import android.os.StrictMode;
+import android.util.Log;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Exposes system related information about the current device.
+ */
+public class SysUtils {
+    // A device reporting strictly more total memory in megabytes cannot be considered 'low-end'.
+    private static final int ANDROID_LOW_MEMORY_DEVICE_THRESHOLD_MB = 512;
+
+    // Number of kilobytes in a megabyte.
+    private static final int KBS_IN_MB = 1024;
+
+    private static final String TAG = "SysUtils";
+
+    private static Boolean sLowEndDevice;
+
+    private SysUtils() { }
+
+    /**
+     * Return the amount of physical memory on this device in kilobytes.
+     * @return Amount of physical memory in kilobytes, or 0 if there was
+     *         an error trying to access the information.
+     */
+    private static int amountOfPhysicalMemoryMB() {
+        // Extract total memory RAM size by parsing /proc/meminfo, note that
+        // this is exactly what the implementation of sysconf(_SC_PHYS_PAGES)
+        // does. However, it can't be called because this method must be
+        // usable before any native code is loaded.
+
+        // An alternative is to use ActivityManager.getMemoryInfo(), but this
+        // requires a valid ActivityManager handle, which can only come from
+        // a valid Context object, which itself cannot be retrieved
+        // during early startup, where this method is called. And making it
+        // an explicit parameter here makes all call paths _much_ more
+        // complicated.
+
+        Pattern pattern = Pattern.compile("^MemTotal:\\s+([0-9]+) kB$");
+        // Synchronously reading files in /proc in the UI thread is safe.
+        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+        try {
+            FileReader fileReader = new FileReader("/proc/meminfo");
+            try {
+                BufferedReader reader = new BufferedReader(fileReader);
+                try {
+                    String line;
+                    for (;;) {
+                        line = reader.readLine();
+                        if (line == null) {
+                            Log.w(TAG, "/proc/meminfo lacks a MemTotal entry?");
+                            break;
+                        }
+                        Matcher m = pattern.matcher(line);
+                        if (!m.find()) continue;
+
+                        int totalMemoryKB = Integer.parseInt(m.group(1));
+                        // Sanity check.
+                        if (totalMemoryKB <= KBS_IN_MB) {
+                            Log.w(TAG, "Invalid /proc/meminfo total size in kB: " + m.group(1));
+                            break;
+                        }
+
+                        return totalMemoryKB / KBS_IN_MB;
+                    }
+
+                } finally {
+                    reader.close();
+                }
+            } finally {
+                fileReader.close();
+            }
+        } catch (Exception e) {
+            Log.w(TAG, "Cannot get total physical size from /proc/meminfo", e);
+        } finally {
+            StrictMode.setThreadPolicy(oldPolicy);
+        }
+
+        return 0;
+    }
+
+    /**
+     * @return Whether or not this device should be considered a low end device.
+     */
+    @CalledByNative
+    public static boolean isLowEndDevice() {
+        if (sLowEndDevice == null) {
+            sLowEndDevice = detectLowEndDevice();
+        }
+        return sLowEndDevice.booleanValue();
+    }
+
+    @TargetApi(Build.VERSION_CODES.KITKAT)
+    private static boolean detectLowEndDevice() {
+        assert CommandLine.isInitialized();
+        if (CommandLine.getInstance().hasSwitch(BaseSwitches.ENABLE_LOW_END_DEVICE_MODE)) {
+            return true;
+        }
+        if (CommandLine.getInstance().hasSwitch(BaseSwitches.DISABLE_LOW_END_DEVICE_MODE)) {
+            return false;
+        }
+        // Any pre-KitKat device cannot be considered 'low-end'.
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
+            return false;
+        }
+
+        Context context = ApplicationStatus.getApplicationContext();
+        if (context != null) {
+            ActivityManager activityManager = (ActivityManager)
+                    context.getSystemService(Context.ACTIVITY_SERVICE);
+            if (activityManager.isLowRamDevice()) {
+                return true;
+            }
+        } else {
+            Log.e(TAG, "ApplicationContext is null in ApplicationStatus");
+        }
+
+        int ramSizeMB = amountOfPhysicalMemoryMB();
+        if (ramSizeMB <= 0) {
+            return false;
+        }
+
+        return ramSizeMB < ANDROID_LOW_MEMORY_DEVICE_THRESHOLD_MB;
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/SystemMessageHandler.java b/base/android/java/src/org/chromium/base/SystemMessageHandler.java
new file mode 100644
index 0000000..fd3dc5a
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/SystemMessageHandler.java
@@ -0,0 +1,111 @@
+// Copyright 2012 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;
+
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+class SystemMessageHandler extends Handler {
+
+    private static final String TAG = "SystemMessageHandler";
+
+    private static final int SCHEDULED_WORK = 1;
+    private static final int DELAYED_SCHEDULED_WORK = 2;
+
+    // Native class pointer set by the constructor of the SharedClient native class.
+    private long mMessagePumpDelegateNative = 0;
+    private long mDelayedScheduledTimeTicks = 0;
+
+    // Reflected API for marking a message as asynchronous. This is a workaround
+    // to provide fair Chromium task dispatch when served by the Android UI
+    // thread's Looper, avoiding stalls when the Looper has a sync barrier.
+    // Note: Use of this API is experimental and likely to evolve in the future.
+    private Method mMessageMethodSetAsynchronous;
+
+    private SystemMessageHandler(long messagePumpDelegateNative) {
+        mMessagePumpDelegateNative = messagePumpDelegateNative;
+
+        try {
+            Class<?> messageClass = Class.forName("android.os.Message");
+            mMessageMethodSetAsynchronous = messageClass.getMethod(
+                    "setAsynchronous", new Class[]{boolean.class});
+        } catch (ClassNotFoundException e) {
+            Log.e(TAG, "Failed to find android.os.Message class:" + e);
+        } catch (NoSuchMethodException e) {
+            Log.e(TAG, "Failed to load Message.setAsynchronous method:" + e);
+        } catch (RuntimeException e) {
+            Log.e(TAG, "Exception while loading Message.setAsynchronous method: " + e);
+        }
+
+    }
+
+    @Override
+    public void handleMessage(Message msg) {
+        if (msg.what == DELAYED_SCHEDULED_WORK) {
+            mDelayedScheduledTimeTicks = 0;
+        }
+        nativeDoRunLoopOnce(mMessagePumpDelegateNative, mDelayedScheduledTimeTicks);
+    }
+
+    @SuppressWarnings("unused")
+    @CalledByNative
+    private void scheduleWork() {
+        sendMessage(obtainAsyncMessage(SCHEDULED_WORK));
+    }
+
+    @SuppressWarnings("unused")
+    @CalledByNative
+    private void scheduleDelayedWork(long delayedTimeTicks, long millis) {
+        if (mDelayedScheduledTimeTicks != 0) {
+            removeMessages(DELAYED_SCHEDULED_WORK);
+        }
+        mDelayedScheduledTimeTicks = delayedTimeTicks;
+        sendMessageDelayed(obtainAsyncMessage(DELAYED_SCHEDULED_WORK), millis);
+    }
+
+    @SuppressWarnings("unused")
+    @CalledByNative
+    private void removeAllPendingMessages() {
+        removeMessages(SCHEDULED_WORK);
+        removeMessages(DELAYED_SCHEDULED_WORK);
+    }
+
+    private Message obtainAsyncMessage(int what) {
+        Message msg = Message.obtain();
+        msg.what = what;
+        if (mMessageMethodSetAsynchronous != null) {
+            // If invocation fails, assume this is indicative of future
+            // failures, and avoid log spam by nulling the reflected method.
+            try {
+                mMessageMethodSetAsynchronous.invoke(msg, true);
+            } catch (IllegalAccessException e) {
+                Log.e(TAG, "Illegal access to asynchronous message creation, disabling.");
+                mMessageMethodSetAsynchronous = null;
+            } catch (IllegalArgumentException e) {
+                Log.e(TAG, "Illegal argument for asynchronous message creation, disabling.");
+                mMessageMethodSetAsynchronous = null;
+            } catch (InvocationTargetException e) {
+                Log.e(TAG, "Invocation exception during asynchronous message creation, disabling.");
+                mMessageMethodSetAsynchronous = null;
+            } catch (RuntimeException e) {
+                Log.e(TAG, "Runtime exception during asynchronous message creation, disabling.");
+                mMessageMethodSetAsynchronous = null;
+            }
+        }
+        return msg;
+    }
+
+    @CalledByNative
+    private static SystemMessageHandler create(long messagePumpDelegateNative) {
+        return new SystemMessageHandler(messagePumpDelegateNative);
+    }
+
+    private native void nativeDoRunLoopOnce(
+            long messagePumpDelegateNative, long delayedScheduledTimeTicks);
+}
diff --git a/base/android/java/src/org/chromium/base/ThreadUtils.java b/base/android/java/src/org/chromium/base/ThreadUtils.java
new file mode 100644
index 0000000..c0b9172
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/ThreadUtils.java
@@ -0,0 +1,209 @@
+// Copyright 2012 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;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Process;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.FutureTask;
+
+/**
+ * Helper methods to deal with threading related tasks.
+ */
+public class ThreadUtils {
+
+    private static final Object sLock = new Object();
+
+    private static boolean sWillOverride = false;
+
+    private static Handler sUiThreadHandler = null;
+
+    public static void setWillOverrideUiThread() {
+        synchronized (sLock) {
+            sWillOverride = true;
+        }
+    }
+
+    public static void setUiThread(Looper looper) {
+        synchronized (sLock) {
+            if (sUiThreadHandler != null && sUiThreadHandler.getLooper() != looper) {
+                throw new RuntimeException("UI thread looper is already set to "
+                        + sUiThreadHandler.getLooper() + " (Main thread looper is "
+                        + Looper.getMainLooper() + "), cannot set to new looper " + looper);
+            } else {
+                sUiThreadHandler = new Handler(looper);
+            }
+        }
+    }
+
+    private static Handler getUiThreadHandler() {
+        synchronized (sLock) {
+            if (sUiThreadHandler == null) {
+                if (sWillOverride) {
+                    throw new RuntimeException("Did not yet override the UI thread");
+                }
+                sUiThreadHandler = new Handler(Looper.getMainLooper());
+            }
+            return sUiThreadHandler;
+        }
+    }
+
+    /**
+     * Run the supplied Runnable on the main thread. The method will block until the Runnable
+     * completes.
+     *
+     * @param r The Runnable to run.
+     */
+    public static void runOnUiThreadBlocking(final Runnable r) {
+        if (runningOnUiThread()) {
+            r.run();
+        } else {
+            FutureTask<Void> task = new FutureTask<Void>(r, null);
+            postOnUiThread(task);
+            try {
+                task.get();
+            } catch (Exception e) {
+                throw new RuntimeException("Exception occured while waiting for runnable", e);
+            }
+        }
+    }
+
+    /**
+     * Run the supplied Callable on the main thread, wrapping any exceptions in a RuntimeException.
+     * The method will block until the Callable completes.
+     *
+     * @param c The Callable to run
+     * @return The result of the callable
+     */
+    public static <T> T runOnUiThreadBlockingNoException(Callable<T> c) {
+        try {
+            return runOnUiThreadBlocking(c);
+        } catch (ExecutionException e) {
+            throw new RuntimeException("Error occured waiting for callable", e);
+        }
+    }
+
+    /**
+     * Run the supplied Callable on the main thread, The method will block until the Callable
+     * completes.
+     *
+     * @param c The Callable to run
+     * @return The result of the callable
+     * @throws ExecutionException c's exception
+     */
+    public static <T> T runOnUiThreadBlocking(Callable<T> c) throws ExecutionException {
+        FutureTask<T> task = new FutureTask<T>(c);
+        runOnUiThread(task);
+        try {
+            return task.get();
+        } catch (InterruptedException e) {
+            throw new RuntimeException("Interrupted waiting for callable", e);
+        }
+    }
+
+    /**
+     * Run the supplied FutureTask on the main thread. The method will block only if the current
+     * thread is the main thread.
+     *
+     * @param task The FutureTask to run
+     * @return The queried task (to aid inline construction)
+     */
+    public static <T> FutureTask<T> runOnUiThread(FutureTask<T> task) {
+        if (runningOnUiThread()) {
+            task.run();
+        } else {
+            postOnUiThread(task);
+        }
+        return task;
+    }
+
+    /**
+     * Run the supplied Callable on the main thread. The method will block only if the current
+     * thread is the main thread.
+     *
+     * @param c The Callable to run
+     * @return A FutureTask wrapping the callable to retrieve results
+     */
+    public static <T> FutureTask<T> runOnUiThread(Callable<T> c) {
+        return runOnUiThread(new FutureTask<T>(c));
+    }
+
+    /**
+     * Run the supplied Runnable on the main thread. The method will block only if the current
+     * thread is the main thread.
+     *
+     * @param r The Runnable to run
+     */
+    public static void runOnUiThread(Runnable r) {
+        if (runningOnUiThread()) {
+            r.run();
+        } else {
+            getUiThreadHandler().post(r);
+        }
+    }
+
+    /**
+     * Post the supplied FutureTask to run on the main thread. The method will not block, even if
+     * called on the UI thread.
+     *
+     * @param task The FutureTask to run
+     * @return The queried task (to aid inline construction)
+     */
+    public static <T> FutureTask<T> postOnUiThread(FutureTask<T> task) {
+        getUiThreadHandler().post(task);
+        return task;
+    }
+
+    /**
+     * Post the supplied Runnable to run on the main thread. The method will not block, even if
+     * called on the UI thread.
+     *
+     * @param task The Runnable to run
+     */
+    public static void postOnUiThread(Runnable task) {
+        getUiThreadHandler().post(task);
+    }
+
+    /**
+     * Post the supplied Runnable to run on the main thread after the given amount of time. The
+     * method will not block, even if called on the UI thread.
+     *
+     * @param task The Runnable to run
+     * @param delayMillis The delay in milliseconds until the Runnable will be run
+     */
+    @VisibleForTesting
+    public static void postOnUiThreadDelayed(Runnable task, long delayMillis) {
+        getUiThreadHandler().postDelayed(task, delayMillis);
+    }
+
+    /**
+     * Asserts that the current thread is running on the main thread.
+     */
+    public static void assertOnUiThread() {
+        assert runningOnUiThread();
+    }
+
+    /**
+     * @return true iff the current thread is the main (UI) thread.
+     */
+    public static boolean runningOnUiThread() {
+        return getUiThreadHandler().getLooper() == Looper.myLooper();
+    }
+
+    public static Looper getUiThreadLooper() {
+        return getUiThreadHandler().getLooper();
+    }
+
+    /**
+     * Set thread priority to audio.
+     */
+    @CalledByNative
+    public static void setThreadPriorityAudio(int tid) {
+        Process.setThreadPriority(tid, Process.THREAD_PRIORITY_AUDIO);
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/TraceEvent.java b/base/android/java/src/org/chromium/base/TraceEvent.java
new file mode 100644
index 0000000..3d3b11a
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/TraceEvent.java
@@ -0,0 +1,285 @@
+// 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;
+
+import android.os.Looper;
+import android.os.MessageQueue;
+import android.os.SystemClock;
+import android.util.Log;
+import android.util.Printer;
+/**
+ * Java mirror of Chrome trace event API. See base/trace_event/trace_event.h. Unlike the native
+ * version, Java does not have stack objects, so a TRACE_EVENT() which does both TRACE_EVENT_BEGIN()
+ * and TRACE_EVENT_END() in ctor/dtor is not possible.
+ * It is OK to use tracing before the native library has loaded, but such traces will
+ * be ignored. (Perhaps we could devise to buffer them up in future?).
+ */
+@JNINamespace("base::android")
+public class TraceEvent {
+
+    private static volatile boolean sEnabled = false;
+
+    private static class BasicLooperMonitor implements Printer {
+        @Override
+        public void println(final String line) {
+            if (line.startsWith(">")) {
+                beginHandling(line);
+            } else {
+                assert line.startsWith("<");
+                endHandling(line);
+            }
+        }
+
+        void beginHandling(final String line) {
+            if (sEnabled) nativeBeginToplevel();
+        }
+
+        void endHandling(final String line) {
+            if (sEnabled) nativeEndToplevel();
+        }
+    }
+
+    /**
+     * A class that records, traces and logs statistics about the UI thead's Looper.
+     * The output of this class can be used in a number of interesting ways:
+     * <p>
+     * <ol><li>
+     * When using chrometrace, there will be a near-continuous line of
+     * measurements showing both event dispatches as well as idles;
+     * </li><li>
+     * Logging messages are output for events that run too long on the
+     * event dispatcher, making it easy to identify problematic areas;
+     * </li><li>
+     * Statistics are output whenever there is an idle after a non-trivial
+     * amount of activity, allowing information to be gathered about task
+     * density and execution cadence on the Looper;
+     * </li></ol>
+     * <p>
+     * The class attaches itself as an idle handler to the main Looper, and
+     * monitors the execution of events and idle notifications. Task counters
+     * accumulate between idle notifications and get reset when a new idle
+     * notification is received.
+     */
+    private static final class IdleTracingLooperMonitor extends BasicLooperMonitor
+            implements MessageQueue.IdleHandler {
+        // Tags for dumping to logcat or TraceEvent
+        private static final String TAG = "TraceEvent.LooperMonitor";
+        private static final String IDLE_EVENT_NAME = "Looper.queueIdle";
+
+        // Calculation constants
+        private static final long FRAME_DURATION_MILLIS = 1000L / 60L; // 60 FPS
+        // A reasonable threshold for defining a Looper event as "long running"
+        private static final long MIN_INTERESTING_DURATION_MILLIS =
+                FRAME_DURATION_MILLIS;
+        // A reasonable threshold for a "burst" of tasks on the Looper
+        private static final long MIN_INTERESTING_BURST_DURATION_MILLIS =
+                MIN_INTERESTING_DURATION_MILLIS * 3;
+
+        // Stats tracking
+        private long mLastIdleStartedAt = 0L;
+        private long mLastWorkStartedAt = 0L;
+        private int mNumTasksSeen = 0;
+        private int mNumIdlesSeen = 0;
+        private int mNumTasksSinceLastIdle = 0;
+
+        // State
+        private boolean mIdleMonitorAttached = false;
+
+        // Called from within the begin/end methods only.
+        // This method can only execute on the looper thread, because that is
+        // the only thread that is permitted to call Looper.myqueue().
+        private final void syncIdleMonitoring() {
+            if (sEnabled && !mIdleMonitorAttached) {
+                // approximate start time for computational purposes
+                mLastIdleStartedAt = SystemClock.elapsedRealtime();
+                Looper.myQueue().addIdleHandler(this);
+                mIdleMonitorAttached = true;
+                Log.v(TAG, "attached idle handler");
+            } else if (mIdleMonitorAttached && !sEnabled) {
+                Looper.myQueue().removeIdleHandler(this);
+                mIdleMonitorAttached = false;
+                Log.v(TAG, "detached idle handler");
+            }
+        }
+
+        @Override
+        final void beginHandling(final String line) {
+            // Close-out any prior 'idle' period before starting new task.
+            if (mNumTasksSinceLastIdle == 0) {
+                TraceEvent.end(IDLE_EVENT_NAME);
+            }
+            mLastWorkStartedAt = SystemClock.elapsedRealtime();
+            syncIdleMonitoring();
+            super.beginHandling(line);
+        }
+
+        @Override
+        final void endHandling(final String line) {
+            final long elapsed = SystemClock.elapsedRealtime()
+                    - mLastWorkStartedAt;
+            if (elapsed > MIN_INTERESTING_DURATION_MILLIS) {
+                traceAndLog(Log.WARN, "observed a task that took "
+                        + elapsed + "ms: " + line);
+            }
+            super.endHandling(line);
+            syncIdleMonitoring();
+            mNumTasksSeen++;
+            mNumTasksSinceLastIdle++;
+        }
+
+        private static void traceAndLog(int level, String message) {
+            TraceEvent.instant("TraceEvent.LooperMonitor:IdleStats", message);
+            Log.println(level, TAG, message);
+        }
+
+        @Override
+        public final boolean queueIdle() {
+            final long now =  SystemClock.elapsedRealtime();
+            if (mLastIdleStartedAt == 0) mLastIdleStartedAt = now;
+            final long elapsed = now - mLastIdleStartedAt;
+            mNumIdlesSeen++;
+            TraceEvent.begin(IDLE_EVENT_NAME, mNumTasksSinceLastIdle + " tasks since last idle.");
+            if (elapsed > MIN_INTERESTING_BURST_DURATION_MILLIS) {
+                // Dump stats
+                String statsString = mNumTasksSeen + " tasks and "
+                        + mNumIdlesSeen + " idles processed so far, "
+                        + mNumTasksSinceLastIdle + " tasks bursted and "
+                        + elapsed + "ms elapsed since last idle";
+                traceAndLog(Log.DEBUG, statsString);
+            }
+            mLastIdleStartedAt = now;
+            mNumTasksSinceLastIdle = 0;
+            return true; // stay installed
+        }
+    }
+
+    // Holder for monitor avoids unnecessary construction on non-debug runs
+    private static final class LooperMonitorHolder {
+        private static final BasicLooperMonitor sInstance =
+                CommandLine.getInstance().hasSwitch(BaseSwitches.ENABLE_IDLE_TRACING)
+                ? new IdleTracingLooperMonitor() : new BasicLooperMonitor();
+    }
+
+
+    /**
+     * Register an enabled observer, such that java traces are always enabled with native.
+     */
+    public static void registerNativeEnabledObserver() {
+        nativeRegisterEnabledObserver();
+    }
+
+    /**
+     * Notification from native that tracing is enabled/disabled.
+     */
+    @CalledByNative
+    public static void setEnabled(boolean enabled) {
+        sEnabled = enabled;
+        ThreadUtils.getUiThreadLooper().setMessageLogging(
+                enabled ? LooperMonitorHolder.sInstance : null);
+    }
+
+    /**
+     * Enables or disabled Android systrace path of Chrome tracing. If enabled, all Chrome
+     * traces will be also output to Android systrace. Because of the overhead of Android
+     * systrace, this is for WebView only.
+     */
+    public static void setATraceEnabled(boolean enabled) {
+        if (sEnabled == enabled) return;
+        if (enabled) {
+            nativeStartATrace();
+        } else {
+            nativeStopATrace();
+        }
+    }
+
+    /**
+     * @return True if tracing is enabled, false otherwise.
+     * It is safe to call trace methods without checking if TraceEvent
+     * is enabled.
+     */
+    public static boolean enabled() {
+        return sEnabled;
+    }
+
+    /**
+     * Triggers the 'instant' native trace event with no arguments.
+     * @param name The name of the event.
+     */
+    public static void instant(String name) {
+        if (sEnabled) nativeInstant(name, null);
+    }
+
+    /**
+     * Triggers the 'instant' native trace event.
+     * @param name The name of the event.
+     * @param arg  The arguments of the event.
+     */
+    public static void instant(String name, String arg) {
+        if (sEnabled) nativeInstant(name, arg);
+    }
+
+    /**
+     * Triggers the 'start' native trace event with no arguments.
+     * @param name The name of the event.
+     * @param id   The id of the asynchronous event.
+     */
+    public static void startAsync(String name, long id) {
+        if (sEnabled) nativeStartAsync(name, id);
+    }
+
+    /**
+     * Triggers the 'finish' native trace event with no arguments.
+     * @param name The name of the event.
+     * @param id   The id of the asynchronous event.
+     */
+    public static void finishAsync(String name, long id) {
+        if (sEnabled) nativeFinishAsync(name, id);
+    }
+
+    /**
+     * Triggers the 'begin' native trace event with no arguments.
+     * @param name The name of the event.
+     */
+    public static void begin(String name) {
+        if (sEnabled) nativeBegin(name, null);
+    }
+
+    /**
+     * Triggers the 'begin' native trace event.
+     * @param name The name of the event.
+     * @param arg  The arguments of the event.
+     */
+    public static void begin(String name, String arg) {
+        if (sEnabled) nativeBegin(name, arg);
+    }
+
+    /**
+     * Triggers the 'end' native trace event with no arguments.
+     * @param name The name of the event.
+     */
+    public static void end(String name) {
+        if (sEnabled) nativeEnd(name, null);
+    }
+
+    /**
+     * Triggers the 'end' native trace event.
+     * @param name The name of the event.
+     * @param arg  The arguments of the event.
+     */
+    public static void end(String name, String arg) {
+        if (sEnabled) nativeEnd(name, arg);
+    }
+
+    private static native void nativeRegisterEnabledObserver();
+    private static native void nativeStartATrace();
+    private static native void nativeStopATrace();
+    private static native void nativeInstant(String name, String arg);
+    private static native void nativeBegin(String name, String arg);
+    private static native void nativeEnd(String name, String arg);
+    private static native void nativeBeginToplevel();
+    private static native void nativeEndToplevel();
+    private static native void nativeStartAsync(String name, long id);
+    private static native void nativeFinishAsync(String name, long id);
+}
diff --git a/base/android/java/src/org/chromium/base/VisibleForTesting.java b/base/android/java/src/org/chromium/base/VisibleForTesting.java
new file mode 100644
index 0000000..24cbfad
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/VisibleForTesting.java
@@ -0,0 +1,12 @@
+// 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;
+
+/**
+ * Annotation used to mark code that has wider visibility or present for testing code.
+ */
+public @interface VisibleForTesting {
+
+}
diff --git a/base/android/java/src/org/chromium/base/annotations/AccessedByNative.java b/base/android/java/src/org/chromium/base/annotations/AccessedByNative.java
new file mode 100644
index 0000000..6df7c11
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/annotations/AccessedByNative.java
@@ -0,0 +1,20 @@
+// Copyright 2012 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.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ *  @AccessedByNative is used to ensure proguard will keep this field, since it's
+ *  only accessed by native.
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.CLASS)
+public @interface AccessedByNative {
+    public String value() default "";
+}
diff --git a/base/android/java/src/org/chromium/base/annotations/CalledByNativeUnchecked.java b/base/android/java/src/org/chromium/base/annotations/CalledByNativeUnchecked.java
new file mode 100644
index 0000000..c0abcbe
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/annotations/CalledByNativeUnchecked.java
@@ -0,0 +1,27 @@
+// Copyright 2012 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.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ *  @CalledByNativeUnchecked is used to generate JNI bindings that do not check for exceptions.
+ *  It only makes sense to use this annotation on methods that declare a throws... spec.
+ *  However, note that the exception received native side maybe an 'unchecked' (RuntimeExpception)
+ *  such as NullPointerException, so the native code should differentiate these cases.
+ *  Usage of this should be very rare; where possible handle exceptions in the Java side and use a
+ *  return value to indicate success / failure.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.CLASS)
+public @interface CalledByNativeUnchecked {
+    /*
+     *  If present, tells which inner class the method belongs to.
+     */
+    public String value() default "";
+}
diff --git a/base/android/java/src/org/chromium/base/annotations/NoSideEffects.java b/base/android/java/src/org/chromium/base/annotations/NoSideEffects.java
new file mode 100644
index 0000000..803c3f9
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/annotations/NoSideEffects.java
@@ -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.
+
+package org.chromium.base.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation used to indicate to proguard methods that have no side effects and can be
+ * safely removed if their return value is not used. This is to be used with
+ * {@link org.chromium.base.Log}'s method, that can also be removed by proguard. That way
+ * expensive calls can be left in debug builds but removed in release.
+ */
+@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
+public @interface NoSideEffects {}
diff --git a/base/android/java/src/org/chromium/base/annotations/SuppressFBWarnings.java b/base/android/java/src/org/chromium/base/annotations/SuppressFBWarnings.java
new file mode 100644
index 0000000..89068ac
--- /dev/null
+++ b/base/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/base/android/java/src/org/chromium/base/annotations/UsedByReflection.java b/base/android/java/src/org/chromium/base/annotations/UsedByReflection.java
new file mode 100644
index 0000000..a2af704
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/annotations/UsedByReflection.java
@@ -0,0 +1,24 @@
+// 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.ElementType;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation used for marking methods and fields that are called by reflection.
+ * Useful for keeping components that would otherwise be removed by Proguard.
+ * Use the value parameter to mention a file that calls this method.
+ *
+ * Note that adding this annotation to a method is not enough to guarantee that
+ * it is kept - either its class must be referenced elsewhere in the program, or
+ * the class must be annotated with this as well.
+ */
+@Target({
+        ElementType.METHOD, ElementType.FIELD, ElementType.TYPE,
+        ElementType.CONSTRUCTOR })
+public @interface UsedByReflection {
+    String value();
+}
diff --git a/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java b/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java
new file mode 100644
index 0000000..a789eff
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/library_loader/LibraryLoader.java
@@ -0,0 +1,509 @@
+// 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.library_loader;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.os.AsyncTask;
+import android.os.Build;
+import android.os.SystemClock;
+import android.util.Log;
+
+import org.chromium.base.CalledByNative;
+import org.chromium.base.CommandLine;
+import org.chromium.base.JNINamespace;
+import org.chromium.base.PackageUtils;
+import org.chromium.base.TraceEvent;
+import org.chromium.base.VisibleForTesting;
+import org.chromium.base.metrics.RecordHistogram;
+
+import javax.annotation.Nullable;
+
+/**
+ * This class provides functionality to load and register the native libraries.
+ * Callers are allowed to separate loading the libraries from initializing them.
+ * This may be an advantage for Android Webview, where the libraries can be loaded
+ * by the zygote process, but then needs per process initialization after the
+ * application processes are forked from the zygote process.
+ *
+ * The libraries may be loaded and initialized from any thread. Synchronization
+ * primitives are used to ensure that overlapping requests from different
+ * threads are handled sequentially.
+ *
+ * See also base/android/library_loader/library_loader_hooks.cc, which contains
+ * the native counterpart to this class.
+ */
+@JNINamespace("base::android")
+public class LibraryLoader {
+    private static final String TAG = "LibraryLoader";
+
+    // Set to true to enable debug logs.
+    private static final boolean DEBUG = false;
+
+    // Guards all access to the libraries
+    private static final Object sLock = new Object();
+
+    // The singleton instance of LibraryLoader.
+    private static volatile LibraryLoader sInstance;
+
+    // One-way switch becomes true when the libraries are loaded.
+    private boolean mLoaded;
+
+    // One-way switch becomes true when the Java command line is switched to
+    // native.
+    private boolean mCommandLineSwitched;
+
+    // One-way switch becomes true when the libraries are initialized (
+    // by calling nativeLibraryLoaded, which forwards to LibraryLoaded(...) in
+    // library_loader_hooks.cc).
+    // Note that this member should remain a one-way switch, since it accessed from multiple
+    // threads without a lock.
+    private volatile boolean mInitialized;
+
+    // One-way switches recording attempts to use Relro sharing in the browser.
+    // The flags are used to report UMA stats later.
+    private boolean mIsUsingBrowserSharedRelros;
+    private boolean mLoadAtFixedAddressFailed;
+
+    // One-way switch becomes true if the Chromium library was loaded from the
+    // APK file directly.
+    private boolean mLibraryWasLoadedFromApk;
+
+    // One-way switch becomes false if the Chromium library should be loaded
+    // directly from the APK file but it was compressed or not aligned.
+    private boolean mLibraryIsMappableInApk = true;
+
+    // The type of process the shared library is loaded in.
+    // This member can be accessed from multiple threads simultaneously, so it have to be
+    // final (like now) or be protected in some way (volatile of synchronized).
+    private final int mLibraryProcessType;
+
+    /**
+     * @param libraryProcessType the process the shared library is loaded in. refer to
+     *                           LibraryProcessType for possible values.
+     * @return LibraryLoader if existing, otherwise create a new one.
+     */
+    public static LibraryLoader get(int libraryProcessType) throws ProcessInitException {
+        synchronized (sLock) {
+            if (sInstance != null) {
+                if (sInstance.mLibraryProcessType == libraryProcessType) return sInstance;
+                throw new ProcessInitException(
+                        LoaderErrors.LOADER_ERROR_NATIVE_LIBRARY_LOAD_FAILED);
+            }
+            sInstance = new LibraryLoader(libraryProcessType);
+            return sInstance;
+        }
+    }
+
+    private LibraryLoader(int libraryProcessType) {
+        mLibraryProcessType = libraryProcessType;
+    }
+
+    /**
+     * The same as ensureInitialized(null, false), should only be called
+     * by non-browser processes.
+     *
+     * @throws ProcessInitException
+     */
+    @VisibleForTesting
+    public void ensureInitialized() throws ProcessInitException {
+        ensureInitialized(null, false);
+    }
+
+    /**
+     *  This method blocks until the library is fully loaded and initialized.
+     *
+     *  @param context The context in which the method is called, the caller
+     *    may pass in a null context if it doesn't know in which context it
+     *    is running.
+     *
+     *  @param shouldDeleteFallbackLibraries The flag tells whether the method
+     *    should delete the fallback libraries or not.
+     */
+    public void ensureInitialized(
+            Context context, boolean shouldDeleteFallbackLibraries)
+            throws ProcessInitException {
+        synchronized (sLock) {
+            if (mInitialized) {
+                // Already initialized, nothing to do.
+                return;
+            }
+            loadAlreadyLocked(context, shouldDeleteFallbackLibraries);
+            initializeAlreadyLocked();
+        }
+    }
+
+    /**
+     * Checks if library is fully loaded and initialized.
+     */
+    public static boolean isInitialized() {
+        return sInstance != null && sInstance.mInitialized;
+    }
+
+    /**
+     * The same as loadNow(null, false), should only be called by
+     * non-browser process.
+     *
+     * @throws ProcessInitException
+     */
+    public void loadNow() throws ProcessInitException {
+        loadNow(null, false);
+    }
+
+    /**
+     * Loads the library and blocks until the load completes. The caller is responsible
+     * for subsequently calling ensureInitialized().
+     * May be called on any thread, but should only be called once. Note the thread
+     * this is called on will be the thread that runs the native code's static initializers.
+     * See the comment in doInBackground() for more considerations on this.
+     *
+     * @param context The context the code is running, or null if it doesn't have one.
+     * @param shouldDeleteFallbackLibraries The flag tells whether the method
+     *   should delete the old fallback libraries or not.
+     *
+     * @throws ProcessInitException if the native library failed to load.
+     */
+    public void loadNow(Context context, boolean shouldDeleteFallbackLibraries)
+            throws ProcessInitException {
+        synchronized (sLock) {
+            loadAlreadyLocked(context, shouldDeleteFallbackLibraries);
+        }
+    }
+
+    /**
+     * initializes the library here and now: must be called on the thread that the
+     * native will call its "main" thread. The library must have previously been
+     * loaded with loadNow.
+     */
+    public void initialize() throws ProcessInitException {
+        synchronized (sLock) {
+            initializeAlreadyLocked();
+        }
+    }
+
+    /** Prefetches the native libraries in a background thread.
+     *
+     * Launches an AsyncTask that, through a short-lived forked process, reads a
+     * part of each page of the native library.  This is done to warm up the
+     * page cache, turning hard page faults into soft ones.
+     *
+     * This is done this way, as testing shows that fadvise(FADV_WILLNEED) is
+     * detrimental to the startup time.
+     *
+     * @param context the application context.
+     */
+    public void asyncPrefetchLibrariesToMemory(final Context context) {
+        new AsyncTask<Void, Void, Void>() {
+            @Override
+            protected Void doInBackground(Void... params) {
+                TraceEvent.begin("LibraryLoader.asyncPrefetchLibrariesToMemory");
+                boolean success = nativeForkAndPrefetchNativeLibrary();
+                if (!success) {
+                    Log.w(TAG, "Forking a process to prefetch the native library failed.");
+                }
+                RecordHistogram.recordBooleanHistogram("LibraryLoader.PrefetchStatus", success);
+                TraceEvent.end("LibraryLoader.asyncPrefetchLibrariesToMemory");
+                return null;
+            }
+        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+    }
+
+    // Invoke System.loadLibrary(...), triggering JNI_OnLoad in native code
+    private void loadAlreadyLocked(
+            Context context, boolean shouldDeleteFallbackLibraries)
+            throws ProcessInitException {
+        try {
+            if (!mLoaded) {
+                assert !mInitialized;
+
+                long startTime = SystemClock.uptimeMillis();
+                boolean useChromiumLinker = Linker.isUsed();
+                boolean fallbackWasUsed = false;
+
+                if (useChromiumLinker) {
+                    // Determine the APK file path.
+                    String apkFilePath = null;
+                    if (context != null) {
+                        apkFilePath = getLibraryApkPath(context);
+                    } else {
+                        Log.w(TAG, "could not check load from APK support due to null context");
+                    }
+
+                    // Load libraries using the Chromium linker.
+                    Linker.prepareLibraryLoad();
+
+                    for (String library : NativeLibraries.LIBRARIES) {
+                        // Don't self-load the linker. This is because the build system is
+                        // not clever enough to understand that all the libraries packaged
+                        // in the final .apk don't need to be explicitly loaded.
+                        if (Linker.isChromiumLinkerLibrary(library)) {
+                            if (DEBUG) Log.i(TAG, "ignoring self-linker load");
+                            continue;
+                        }
+
+                        // Determine where the library should be loaded from.
+                        String zipFilePath = null;
+                        String libFilePath = System.mapLibraryName(library);
+                        if (apkFilePath != null && Linker.isInZipFile()) {
+                            // The library is in the APK file.
+                            if (!Linker.checkLibraryIsMappableInApk(apkFilePath, libFilePath)) {
+                                mLibraryIsMappableInApk = false;
+                            }
+                            if (mLibraryIsMappableInApk) {
+                                // Load directly from the APK.
+                                zipFilePath = apkFilePath;
+                                Log.i(TAG, "Loading " + library + " directly from within "
+                                        + apkFilePath);
+                            } else {
+                                // Unpack library fallback.
+                                Log.i(TAG, "Loading " + library
+                                        + " using unpack library fallback from within "
+                                        + apkFilePath);
+                                libFilePath = LibraryLoaderHelper.buildFallbackLibrary(
+                                        context, library);
+                                fallbackWasUsed = true;
+                                Log.i(TAG, "Built fallback library " + libFilePath);
+                            }
+                        } else {
+                            // The library is in its own file.
+                            Log.i(TAG, "Loading " + library);
+                        }
+
+                        // Load the library.
+                        boolean isLoaded = false;
+                        if (Linker.isUsingBrowserSharedRelros()) {
+                            mIsUsingBrowserSharedRelros = true;
+                            try {
+                                loadLibrary(zipFilePath, libFilePath);
+                                isLoaded = true;
+                            } catch (UnsatisfiedLinkError e) {
+                                Log.w(TAG, "Failed to load native library with shared RELRO, "
+                                        + "retrying without");
+                                Linker.disableSharedRelros();
+                                mLoadAtFixedAddressFailed = true;
+                            }
+                        }
+                        if (!isLoaded) {
+                            loadLibrary(zipFilePath, libFilePath);
+                        }
+                    }
+
+                    Linker.finishLibraryLoad();
+                } else {
+                    // Load libraries using the system linker.
+                    for (String library : NativeLibraries.LIBRARIES) {
+                        System.loadLibrary(library);
+                    }
+                }
+
+                if (!fallbackWasUsed && context != null
+                        && shouldDeleteFallbackLibraries) {
+                    LibraryLoaderHelper.deleteLibrariesAsynchronously(
+                            context, LibraryLoaderHelper.LOAD_FROM_APK_FALLBACK_DIR);
+                }
+
+                long stopTime = SystemClock.uptimeMillis();
+                Log.i(TAG, String.format("Time to load native libraries: %d ms (timestamps %d-%d)",
+                        stopTime - startTime,
+                        startTime % 10000,
+                        stopTime % 10000));
+
+                mLoaded = true;
+            }
+        } catch (UnsatisfiedLinkError e) {
+            throw new ProcessInitException(LoaderErrors.LOADER_ERROR_NATIVE_LIBRARY_LOAD_FAILED, e);
+        }
+        // Check that the version of the library we have loaded matches the version we expect
+        Log.i(TAG, String.format(
+                "Expected native library version number \"%s\","
+                        + "actual native library version number \"%s\"",
+                NativeLibraries.sVersionNumber,
+                nativeGetVersionNumber()));
+        if (!NativeLibraries.sVersionNumber.equals(nativeGetVersionNumber())) {
+            throw new ProcessInitException(LoaderErrors.LOADER_ERROR_NATIVE_LIBRARY_WRONG_VERSION);
+        }
+    }
+
+    // Returns whether the given split name is that of the ABI split.
+    private static boolean isAbiSplit(String splitName) {
+        // The split name for the ABI split is manually set in the build rules.
+        return splitName.startsWith("abi_");
+    }
+
+    // Returns the path to the .apk that holds the native libraries.
+    // This is either the main .apk, or the abi split apk.
+    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+    private static String getLibraryApkPath(Context context) {
+        ApplicationInfo appInfo = context.getApplicationInfo();
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
+            return appInfo.sourceDir;
+        }
+        PackageInfo packageInfo = PackageUtils.getOwnPackageInfo(context);
+        if (packageInfo.splitNames != null) {
+            for (int i = 0; i < packageInfo.splitNames.length; ++i) {
+                if (isAbiSplit(packageInfo.splitNames[i])) {
+                    return appInfo.splitSourceDirs[i];
+                }
+            }
+        }
+        return appInfo.sourceDir;
+    }
+
+    // Load a native shared library with the Chromium linker. If the zip file
+    // path is not null, the library is loaded directly from the zip file.
+    private void loadLibrary(@Nullable String zipFilePath, String libFilePath) {
+        Linker.loadLibrary(zipFilePath, libFilePath);
+        if (zipFilePath != null) {
+            mLibraryWasLoadedFromApk = true;
+        }
+    }
+
+    // The WebView requires the Command Line to be switched over before
+    // initialization is done. This is okay in the WebView's case since the
+    // JNI is already loaded by this point.
+    public void switchCommandLineForWebView() {
+        synchronized (sLock) {
+            ensureCommandLineSwitchedAlreadyLocked();
+        }
+    }
+
+    // Switch the CommandLine over from Java to native if it hasn't already been done.
+    // This must happen after the code is loaded and after JNI is ready (since after the
+    // switch the Java CommandLine will delegate all calls the native CommandLine).
+    private void ensureCommandLineSwitchedAlreadyLocked() {
+        assert mLoaded;
+        if (mCommandLineSwitched) {
+            return;
+        }
+        nativeInitCommandLine(CommandLine.getJavaSwitchesOrNull());
+        CommandLine.enableNativeProxy();
+        mCommandLineSwitched = true;
+    }
+
+    // Invoke base::android::LibraryLoaded in library_loader_hooks.cc
+    private void initializeAlreadyLocked() throws ProcessInitException {
+        if (mInitialized) {
+            return;
+        }
+
+        // Setup the native command line if necessary.
+        if (!mCommandLineSwitched) {
+            nativeInitCommandLine(CommandLine.getJavaSwitchesOrNull());
+        }
+
+        if (!nativeLibraryLoaded()) {
+            Log.e(TAG, "error calling nativeLibraryLoaded");
+            throw new ProcessInitException(LoaderErrors.LOADER_ERROR_FAILED_TO_REGISTER_JNI);
+        }
+
+        // The Chrome JNI is registered by now so we can switch the Java
+        // command line over to delegating to native if it's necessary.
+        if (!mCommandLineSwitched) {
+            CommandLine.enableNativeProxy();
+            mCommandLineSwitched = true;
+        }
+
+        // From now on, keep tracing in sync with native.
+        TraceEvent.registerNativeEnabledObserver();
+
+        // From this point on, native code is ready to use and checkIsReady()
+        // shouldn't complain from now on (and in fact, it's used by the
+        // following calls).
+        // Note that this flag can be accessed asynchronously, so any initialization
+        // must be performed before.
+        mInitialized = true;
+    }
+
+    // Called after all native initializations are complete.
+    public void onNativeInitializationComplete(Context context) {
+        recordBrowserProcessHistogram(context);
+    }
+
+    // Record Chromium linker histogram state for the main browser process. Called from
+    // onNativeInitializationComplete().
+    private void recordBrowserProcessHistogram(Context context) {
+        if (Linker.isUsed()) {
+            nativeRecordChromiumAndroidLinkerBrowserHistogram(mIsUsingBrowserSharedRelros,
+                                                              mLoadAtFixedAddressFailed,
+                                                              getLibraryLoadFromApkStatus(context));
+        }
+    }
+
+    // Returns the device's status for loading a library directly from the APK file.
+    // This method can only be called when the Chromium linker is used.
+    private int getLibraryLoadFromApkStatus(Context context) {
+        assert Linker.isUsed();
+
+        if (mLibraryWasLoadedFromApk) {
+            return LibraryLoadFromApkStatusCodes.SUCCESSFUL;
+        }
+
+        if (!mLibraryIsMappableInApk) {
+            return LibraryLoadFromApkStatusCodes.USED_UNPACK_LIBRARY_FALLBACK;
+        }
+
+        // There were no libraries to be loaded directly from the APK file.
+        return LibraryLoadFromApkStatusCodes.UNKNOWN;
+    }
+
+    // Register pending Chromium linker histogram state for renderer processes. This cannot be
+    // recorded as a histogram immediately because histograms and IPC are not ready at the
+    // time it are captured. This function stores a pending value, so that a later call to
+    // RecordChromiumAndroidLinkerRendererHistogram() will record it correctly.
+    public void registerRendererProcessHistogram(boolean requestedSharedRelro,
+                                                 boolean loadAtFixedAddressFailed) {
+        if (Linker.isUsed()) {
+            nativeRegisterChromiumAndroidLinkerRendererHistogram(requestedSharedRelro,
+                                                                 loadAtFixedAddressFailed);
+        }
+    }
+
+    /**
+     * @return the process the shared library is loaded in, see the LibraryProcessType
+     *         for possible values.
+     */
+    @CalledByNative
+    public static int getLibraryProcessType() {
+        if (sInstance == null) return LibraryProcessType.PROCESS_UNINITIALIZED;
+        return sInstance.mLibraryProcessType;
+    }
+
+    private native void nativeInitCommandLine(String[] initCommandLine);
+
+    // Only methods needed before or during normal JNI registration are during System.OnLoad.
+    // nativeLibraryLoaded is then called to register everything else.  This process is called
+    // "initialization".  This method will be mapped (by generated code) to the LibraryLoaded
+    // definition in base/android/library_loader/library_loader_hooks.cc.
+    //
+    // Return true on success and false on failure.
+    private native boolean nativeLibraryLoaded();
+
+    // Method called to record statistics about the Chromium linker operation for the main
+    // browser process. Indicates whether the linker attempted relro sharing for the browser,
+    // and if it did, whether the library failed to load at a fixed address. Also records
+    // support for loading a library directly from the APK file.
+    private native void nativeRecordChromiumAndroidLinkerBrowserHistogram(
+            boolean isUsingBrowserSharedRelros,
+            boolean loadAtFixedAddressFailed,
+            int libraryLoadFromApkStatus);
+
+    // Method called to register (for later recording) statistics about the Chromium linker
+    // operation for a renderer process. Indicates whether the linker attempted relro sharing,
+    // and if it did, whether the library failed to load at a fixed address.
+    private native void nativeRegisterChromiumAndroidLinkerRendererHistogram(
+            boolean requestedSharedRelro,
+            boolean loadAtFixedAddressFailed);
+
+    // Get the version of the native library. This is needed so that we can check we
+    // have the right version before initializing the (rest of the) JNI.
+    private native String nativeGetVersionNumber();
+
+    // Finds the ranges corresponding to the native library pages, forks a new
+    // process to prefetch these pages and waits for it. The new process then
+    // terminates. This is blocking.
+    private static native boolean nativeForkAndPrefetchNativeLibrary();
+}
diff --git a/base/android/java/src/org/chromium/base/library_loader/LibraryLoaderHelper.java b/base/android/java/src/org/chromium/base/library_loader/LibraryLoaderHelper.java
new file mode 100644
index 0000000..7dd1a29
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/library_loader/LibraryLoaderHelper.java
@@ -0,0 +1,338 @@
+// 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.library_loader;
+
+import android.content.Context;
+import android.util.Log;
+
+import java.io.BufferedOutputStream;
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
+import java.util.zip.ZipFile;
+
+/**
+ * Class representing an exception which occured during the unpacking process.
+ */
+class UnpackingException extends Exception {
+    public UnpackingException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public UnpackingException(String message) {
+        super(message);
+    }
+}
+
+/**
+ * The class provides helper functions to extract native libraries from APK,
+ * and load libraries from there.
+ */
+class LibraryLoaderHelper {
+    private static final String TAG = "LibraryLoaderHelper";
+
+    // Fallback directories.
+    static final String LOAD_FROM_APK_FALLBACK_DIR = "fallback";
+
+    private static final int BUFFER_SIZE = 16384;
+
+    /**
+     * Returns the directory for holding extracted native libraries.
+     * It may create the directory if it doesn't exist.
+     *
+     * @param context The context the code is running.
+     * @param dirName The name of the directory containing the libraries.
+     * @return The directory file object.
+     */
+    static File getLibDir(Context context, String dirName) {
+        return context.getDir(dirName, Context.MODE_PRIVATE);
+    }
+
+    /**
+     * Delete libraries and their directory synchronously.
+     */
+    private static void deleteLibrariesSynchronously(Context context, String dirName) {
+        File libDir = getLibDir(context, dirName);
+        deleteObsoleteLibraries(libDir, Collections.<File>emptyList());
+    }
+
+    /**
+     * Delete libraries and their directory asynchronously.
+     * The actual deletion is done in a background thread.
+     */
+    static void deleteLibrariesAsynchronously(
+            final Context context, final String dirName) {
+        // Child process should not reach here.
+        new Thread() {
+            @Override
+            public void run() {
+                deleteLibrariesSynchronously(context, dirName);
+            }
+        }.start();
+    }
+
+    /**
+     * Copy a library from a zip file to the application's private directory.
+     * This is used as a fallback when we are unable to load the library
+     * directly from the APK file (crbug.com/390618).
+     *
+     * @param context The context the code is running in.
+     * @param library Library name.
+     * @return name of the fallback copy of the library.
+     */
+    static String buildFallbackLibrary(Context context, String library) {
+        try {
+            String libName = System.mapLibraryName(library);
+            File fallbackLibDir = getLibDir(context, LOAD_FROM_APK_FALLBACK_DIR);
+            File fallbackLibFile = new File(fallbackLibDir, libName);
+            String pathInZipFile = Linker.getLibraryFilePathInZipFile(libName);
+            Map<String, File> dstFiles = Collections.singletonMap(pathInZipFile, fallbackLibFile);
+
+            deleteObsoleteLibraries(fallbackLibDir, dstFiles.values());
+            unpackLibraries(context, dstFiles);
+
+            return fallbackLibFile.getAbsolutePath();
+        } catch (Exception e) {
+            String errorMessage = "Unable to load fallback for library " + library
+                    + " (" + (e.getMessage() == null ? e.toString() : e.getMessage()) + ")";
+            Log.e(TAG, errorMessage, e);
+            throw new UnsatisfiedLinkError(errorMessage);
+        }
+    }
+
+    // Delete obsolete libraries from a library folder.
+    private static void deleteObsoleteLibraries(File libDir, Collection<File> keptFiles) {
+        try {
+            // Build a list of libraries that should NOT be deleted.
+            Set<String> keptFileNames = new HashSet<String>();
+            for (File k : keptFiles) {
+                keptFileNames.add(k.getName());
+            }
+
+            // Delete the obsolete libraries.
+            Log.i(TAG, "Deleting obsolete libraries in " + libDir.getPath());
+            File[] files = libDir.listFiles();
+            if (files != null) {
+                for (File f : files) {
+                    if (!keptFileNames.contains(f.getName())) {
+                        delete(f);
+                    }
+                }
+            } else {
+                Log.e(TAG, "Failed to list files in " + libDir.getPath());
+            }
+
+            // Delete the folder if no libraries were kept.
+            if (keptFileNames.isEmpty()) {
+                delete(libDir);
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "Failed to remove obsolete libraries from " + libDir.getPath());
+        }
+    }
+
+    // Unpack libraries from a zip file to the file system.
+    private static void unpackLibraries(Context context,
+            Map<String, File> dstFiles) throws UnpackingException {
+        String zipFilePath = context.getApplicationInfo().sourceDir;
+        Log.i(TAG, "Opening zip file " + zipFilePath);
+        File zipFile = new File(zipFilePath);
+        ZipFile zipArchive = openZipFile(zipFile);
+
+        try {
+            for (Entry<String, File> d : dstFiles.entrySet()) {
+                String pathInZipFile = d.getKey();
+                File dstFile = d.getValue();
+                Log.i(TAG, "Unpacking " + pathInZipFile
+                        + " to " + dstFile.getAbsolutePath());
+                ZipEntry packedLib = zipArchive.getEntry(pathInZipFile);
+
+                if (needToUnpackLibrary(zipFile, packedLib, dstFile)) {
+                    unpackLibraryFromZipFile(zipArchive, packedLib, dstFile);
+                    setLibraryFilePermissions(dstFile);
+                }
+            }
+        } finally {
+            closeZipFile(zipArchive);
+        }
+    }
+
+    // Open a zip file.
+    private static ZipFile openZipFile(File zipFile) throws UnpackingException {
+        try {
+            return new ZipFile(zipFile);
+        } catch (ZipException e) {
+            throw new UnpackingException("Failed to open zip file " + zipFile.getPath());
+        } catch (IOException e) {
+            throw new UnpackingException("Failed to open zip file " + zipFile.getPath());
+        }
+    }
+
+    // Determine whether it is necessary to unpack a library from a zip file.
+    private static boolean needToUnpackLibrary(
+            File zipFile, ZipEntry packedLib, File dstFile) {
+        // Check if the fallback library already exists.
+        if (!dstFile.exists()) {
+            Log.i(TAG, "File " + dstFile.getPath() + " does not exist yet");
+            return true;
+        }
+
+        // Check last modification dates.
+        long zipTime = zipFile.lastModified();
+        long fallbackLibTime = dstFile.lastModified();
+        if (zipTime > fallbackLibTime) {
+            Log.i(TAG, "Not using existing fallback file because "
+                    + "the APK file " + zipFile.getPath()
+                    + " (timestamp=" + zipTime + ") is newer than "
+                    + "the fallback library " + dstFile.getPath()
+                    + "(timestamp=" + fallbackLibTime + ")");
+            return true;
+        }
+
+        // Check file sizes.
+        long packedLibSize = packedLib.getSize();
+        long fallbackLibSize = dstFile.length();
+        if (fallbackLibSize != packedLibSize) {
+            Log.i(TAG, "Not using existing fallback file because "
+                    + "the library in the APK " + zipFile.getPath()
+                    + " (" + packedLibSize + "B) has a different size than "
+                    + "the fallback library " + dstFile.getPath()
+                    + "(" + fallbackLibSize + "B)");
+            return true;
+        }
+
+        Log.i(TAG, "Reusing existing file " + dstFile.getPath());
+        return false;
+    }
+
+    // Unpack a library from a zip file to the filesystem.
+    private static void unpackLibraryFromZipFile(ZipFile zipArchive, ZipEntry packedLib,
+            File dstFile) throws UnpackingException {
+        // Open input stream for the library file inside the zip file.
+        InputStream in;
+        try {
+            in = zipArchive.getInputStream(packedLib);
+        } catch (IOException e) {
+            throw new UnpackingException(
+                    "IO exception when locating library in the zip file", e);
+        }
+
+        // Ensure that the input stream is closed at the end.
+        try {
+            // Delete existing file if it exists.
+            if (dstFile.exists()) {
+                Log.i(TAG, "Deleting existing unpacked library file " + dstFile.getPath());
+                if (!dstFile.delete()) {
+                    throw new UnpackingException(
+                            "Failed to delete existing unpacked library file " + dstFile.getPath());
+                }
+            }
+
+            // Ensure that the library folder exists. Since this is added
+            // for increased robustness, we log errors and carry on.
+            try {
+                dstFile.getParentFile().mkdirs();
+            } catch (Exception e) {
+                Log.e(TAG, "Failed to make library folder", e);
+            }
+
+            // Create the destination file.
+            try {
+                if (!dstFile.createNewFile()) {
+                    throw new UnpackingException("existing unpacked library file was not deleted");
+                }
+            } catch (IOException e) {
+                throw new UnpackingException("failed to create unpacked library file", e);
+            }
+
+            // Open the output stream for the destination file.
+            OutputStream out;
+            try {
+                out = new BufferedOutputStream(new FileOutputStream(dstFile));
+            } catch (FileNotFoundException e) {
+                throw new UnpackingException(
+                        "failed to open output stream for unpacked library file", e);
+            }
+
+            // Ensure that the output stream is closed at the end.
+            try {
+                // Copy the library from the zip file to the destination file.
+                Log.i(TAG, "Copying " + packedLib.getName() + " from " + zipArchive.getName()
+                        + " to " + dstFile.getPath());
+                byte[] buffer = new byte[BUFFER_SIZE];
+                int len;
+                while ((len = in.read(buffer)) != -1) {
+                    out.write(buffer, 0, len);
+                }
+            } catch (IOException e) {
+                throw new UnpackingException(
+                        "failed to copy the library from the zip file", e);
+            } finally {
+                close(out, "output stream");
+            }
+        } finally {
+            close(in, "input stream");
+        }
+    }
+
+    // Set up library file permissions.
+    private static void setLibraryFilePermissions(File libFile) {
+        // Change permission to rwxr-xr-x
+        Log.i(TAG, "Setting file permissions for " + libFile.getPath());
+        if (!libFile.setReadable(/* readable */ true, /* ownerOnly */ false)) {
+            Log.e(TAG, "failed to chmod a+r the temporary file");
+        }
+        if (!libFile.setExecutable(/* executable */ true, /* ownerOnly */ false)) {
+            Log.e(TAG, "failed to chmod a+x the temporary file");
+        }
+        if (!libFile.setWritable(/* writable */ true)) {
+            Log.e(TAG, "failed to chmod +w the temporary file");
+        }
+    }
+
+    // Close a closable and log a warning if it fails.
+    private static void close(Closeable closeable, String name) {
+        try {
+            closeable.close();
+        } catch (IOException e) {
+            // Warn and ignore.
+            Log.w(TAG, "IO exception when closing " + name, e);
+        }
+    }
+
+    // Close a zip file and log a warning if it fails.
+    // This needs to be a separate method because ZipFile is not Closeable in
+    // Java 6 (used on some older devices).
+    private static void closeZipFile(ZipFile file) {
+        try {
+            file.close();
+        } catch (IOException e) {
+            // Warn and ignore.
+            Log.w(TAG, "IO exception when closing zip file", e);
+        }
+    }
+
+    // Delete a file and log it.
+    private static void delete(File file) {
+        if (file.delete()) {
+            Log.i(TAG, "Deleted " + file.getPath());
+        } else {
+            Log.w(TAG, "Failed to delete " + file.getPath());
+        }
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/library_loader/Linker.java b/base/android/java/src/org/chromium/base/library_loader/Linker.java
new file mode 100644
index 0000000..9a64a3f
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/library_loader/Linker.java
@@ -0,0 +1,1095 @@
+// 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.library_loader;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
+import android.os.Parcelable;
+import android.util.Log;
+
+import org.chromium.base.CalledByNative;
+import org.chromium.base.SysUtils;
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.annotations.AccessedByNative;
+
+import java.io.FileNotFoundException;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+/*
+ * Technical note:
+ *
+ * The point of this class is to provide an alternative to System.loadLibrary()
+ * to load native shared libraries. One specific feature that it supports is the
+ * ability to save RAM by sharing the ELF RELRO sections between renderer
+ * processes.
+ *
+ * When two processes load the same native library at the _same_ memory address,
+ * the content of their RELRO section (which includes C++ vtables or any
+ * constants that contain pointers) will be largely identical [1].
+ *
+ * By default, the RELRO section is backed by private RAM in each process,
+ * which is still significant on mobile (e.g. 1.28 MB / process on Chrome 30 for
+ * Android).
+ *
+ * However, it is possible to save RAM by creating a shared memory region,
+ * copy the RELRO content into it, then have each process swap its private,
+ * regular RELRO, with a shared, read-only, mapping of the shared one.
+ *
+ * This trick saves 98% of the RELRO section size per extra process, after the
+ * first one. On the other hand, this requires careful communication between
+ * the process where the shared RELRO is created and the one(s) where it is used.
+ *
+ * Note that swapping the regular RELRO with the shared one is not an atomic
+ * operation. Care must be taken that no other thread tries to run native code
+ * that accesses it during it. In practice, this means the swap must happen
+ * before library native code is executed.
+ *
+ * [1] The exceptions are pointers to external, randomized, symbols, like
+ * those from some system libraries, but these are very few in practice.
+ */
+
+/*
+ * Security considerations:
+ *
+ * - Whether the browser process loads its native libraries at the same
+ *   addresses as the service ones (to save RAM by sharing the RELRO too)
+ *   depends on the configuration variable BROWSER_SHARED_RELRO_CONFIG below.
+ *
+ *   Not using fixed library addresses in the browser process is preferred
+ *   for regular devices since it maintains the efficacy of ASLR as an
+ *   exploit mitigation across the render <-> browser privilege boundary.
+ *
+ * - The shared RELRO memory region is always forced read-only after creation,
+ *   which means it is impossible for a compromised service process to map
+ *   it read-write (e.g. by calling mmap() or mprotect()) and modify its
+ *   content, altering values seen in other service processes.
+ *
+ * - Unfortunately, certain Android systems use an old, buggy kernel, that
+ *   doesn't check Ashmem region permissions correctly. See CVE-2011-1149
+ *   for details. This linker probes the system on startup and will completely
+ *   disable shared RELROs if it detects the problem. For the record, this is
+ *   common for Android emulator system images (which are still based on 2.6.29)
+ *
+ * - Once the RELRO ashmem region is mapped into a service process' address
+ *   space, the corresponding file descriptor is immediately closed. The
+ *   file descriptor is kept opened in the browser process, because a copy needs
+ *   to be sent to each new potential service process.
+ *
+ * - The common library load addresses are randomized for each instance of
+ *   the program on the device. See computeRandomBaseLoadAddress() for more
+ *   details on how this is computed.
+ *
+ * - When loading several libraries in service processes, a simple incremental
+ *   approach from the original random base load address is used. This is
+ *   sufficient to deal correctly with component builds (which can use dozens
+ *   of shared libraries), while regular builds always embed a single shared
+ *   library per APK.
+ */
+
+/**
+ * Here's an explanation of how this class is supposed to be used:
+ *
+ *  - Native shared libraries should be loaded with Linker.loadLibrary(),
+ *    instead of System.loadLibrary(). The two functions take the same parameter
+ *    and should behave the same (at a high level).
+ *
+ *  - Before loading any library, prepareLibraryLoad() should be called.
+ *
+ *  - After loading all libraries, finishLibraryLoad() should be called, before
+ *    running any native code from any of the libraries (except their static
+ *    constructors, which can't be avoided).
+ *
+ *  - A service process shall call either initServiceProcess() or
+ *    disableSharedRelros() early (i.e. before any loadLibrary() call).
+ *    Otherwise, the linker considers that it is running inside the browser
+ *    process. This is because various Chromium projects have vastly
+ *    different initialization paths.
+ *
+ *    disableSharedRelros() completely disables shared RELROs, and loadLibrary()
+ *    will behave exactly like System.loadLibrary().
+ *
+ *    initServiceProcess(baseLoadAddress) indicates that shared RELROs are to be
+ *    used in this process.
+ *
+ *  - The browser is in charge of deciding where in memory each library should
+ *    be loaded. This address must be passed to each service process (see
+ *    ChromiumLinkerParams.java in content for a helper class to do so).
+ *
+ *  - The browser will also generate shared RELROs for each library it loads.
+ *    More specifically, by default when in the browser process, the linker
+ *    will:
+ *
+ *       - Load libraries randomly (just like System.loadLibrary()).
+ *       - Compute the fixed address to be used to load the same library
+ *         in service processes.
+ *       - Create a shared memory region populated with the RELRO region
+ *         content pre-relocated for the specific fixed address above.
+ *
+ *    Note that these shared RELRO regions cannot be used inside the browser
+ *    process. They are also never mapped into it.
+ *
+ *    This behaviour is altered by the BROWSER_SHARED_RELRO_CONFIG configuration
+ *    variable below, which may force the browser to load the libraries at
+ *    fixed addresses too.
+ *
+ *  - Once all libraries are loaded in the browser process, one can call
+ *    getSharedRelros() which returns a Bundle instance containing a map that
+ *    links each loaded library to its shared RELRO region.
+ *
+ *    This Bundle must be passed to each service process, for example through
+ *    a Binder call (note that the Bundle includes file descriptors and cannot
+ *    be added as an Intent extra).
+ *
+ *  - In a service process, finishLibraryLoad() will block until the RELRO
+ *    section Bundle is received. This is typically done by calling
+ *    useSharedRelros() from another thread.
+ *
+ *    This method also ensures the process uses the shared RELROs.
+ */
+public class Linker {
+
+    // Log tag for this class. This must match the name of the linker's native library.
+    private static final String TAG = "chromium_android_linker";
+
+    // Set to true to enable debug logs.
+    private static final boolean DEBUG = false;
+
+    // Constants used to control the behaviour of the browser process with
+    // regards to the shared RELRO section.
+    //   NEVER        -> The browser never uses it itself.
+    //   LOW_RAM_ONLY -> It is only used on devices with low RAM.
+    //   ALWAYS       -> It is always used.
+    // NOTE: These names are known and expected by the Linker test scripts.
+    public static final int BROWSER_SHARED_RELRO_CONFIG_NEVER = 0;
+    public static final int BROWSER_SHARED_RELRO_CONFIG_LOW_RAM_ONLY = 1;
+    public static final int BROWSER_SHARED_RELRO_CONFIG_ALWAYS = 2;
+
+    // Configuration variable used to control how the browser process uses the
+    // shared RELRO. Only change this while debugging linker-related issues.
+    // NOTE: This variable's name is known and expected by the Linker test scripts.
+    public static final int BROWSER_SHARED_RELRO_CONFIG =
+            BROWSER_SHARED_RELRO_CONFIG_LOW_RAM_ONLY;
+
+    // Constants used to control the value of sMemoryDeviceConfig.
+    //   INIT         -> Value is undetermined (will check at runtime).
+    //   LOW          -> This is a low-memory device.
+    //   NORMAL       -> This is not a low-memory device.
+    public static final int MEMORY_DEVICE_CONFIG_INIT = 0;
+    public static final int MEMORY_DEVICE_CONFIG_LOW = 1;
+    public static final int MEMORY_DEVICE_CONFIG_NORMAL = 2;
+
+    // Indicates if this is a low-memory device or not. The default is to
+    // determine this by probing the system at runtime, but this can be forced
+    // for testing by calling setMemoryDeviceConfig().
+    private static int sMemoryDeviceConfig = MEMORY_DEVICE_CONFIG_INIT;
+
+    // Becomes true after linker initialization.
+    private static boolean sInitialized = false;
+
+    // Set to true to indicate that the system supports safe sharing of RELRO sections.
+    private static boolean sRelroSharingSupported = false;
+
+    // Set to true if this runs in the browser process. Disabled by initServiceProcess().
+    // TODO(petrcermak): This flag can be incorrectly set to false (even though this might run in
+    // the browser process) on low-memory devices.
+    private static boolean sInBrowserProcess = true;
+
+    // Becomes true to indicate this process needs to wait for a shared RELRO in
+    // finishLibraryLoad().
+    private static boolean sWaitForSharedRelros = false;
+
+    // Becomes true when initialization determines that the browser process can use the
+    // shared RELRO.
+    private static boolean sBrowserUsesSharedRelro = false;
+
+    // The map of all RELRO sections either created or used in this process.
+    private static Bundle sSharedRelros = null;
+
+    // Current common random base load address.
+    private static long sBaseLoadAddress = 0;
+
+    // Current fixed-location load address for the next library called by loadLibrary().
+    private static long sCurrentLoadAddress = 0;
+
+    // Becomes true once prepareLibraryLoad() has been called.
+    private static boolean sPrepareLibraryLoadCalled = false;
+
+    // Used internally to initialize the linker's static data. Assume lock is held.
+    private static void ensureInitializedLocked() {
+        assert Thread.holdsLock(Linker.class);
+
+        if (!sInitialized) {
+            sRelroSharingSupported = false;
+            if (NativeLibraries.sUseLinker) {
+                if (DEBUG) Log.i(TAG, "Loading lib" + TAG + ".so");
+                try {
+                    System.loadLibrary(TAG);
+                } catch (UnsatisfiedLinkError  e) {
+                    // In a component build, the ".cr" suffix is added to each library name.
+                    Log.w(TAG, "Couldn't load lib" + TAG + ".so, trying lib" + TAG + ".cr.so");
+                    System.loadLibrary(TAG + ".cr");
+                }
+                sRelroSharingSupported = nativeCanUseSharedRelro();
+                if (!sRelroSharingSupported) {
+                    Log.w(TAG, "This system cannot safely share RELRO sections");
+                } else {
+                    if (DEBUG) Log.i(TAG, "This system supports safe shared RELRO sections");
+                }
+
+                if (sMemoryDeviceConfig == MEMORY_DEVICE_CONFIG_INIT) {
+                    sMemoryDeviceConfig = SysUtils.isLowEndDevice()
+                            ? MEMORY_DEVICE_CONFIG_LOW : MEMORY_DEVICE_CONFIG_NORMAL;
+                }
+
+                switch (BROWSER_SHARED_RELRO_CONFIG) {
+                    case BROWSER_SHARED_RELRO_CONFIG_NEVER:
+                        sBrowserUsesSharedRelro = false;
+                        break;
+                    case BROWSER_SHARED_RELRO_CONFIG_LOW_RAM_ONLY:
+                        sBrowserUsesSharedRelro =
+                                (sMemoryDeviceConfig == MEMORY_DEVICE_CONFIG_LOW);
+                        if (sBrowserUsesSharedRelro) {
+                            Log.w(TAG, "Low-memory device: shared RELROs used in all processes");
+                        }
+                        break;
+                    case BROWSER_SHARED_RELRO_CONFIG_ALWAYS:
+                        Log.w(TAG, "Beware: shared RELROs used in all processes!");
+                        sBrowserUsesSharedRelro = true;
+                        break;
+                    default:
+                        assert false : "Unreached";
+                        break;
+                }
+            } else {
+                if (DEBUG) Log.i(TAG, "Linker disabled");
+            }
+
+            if (!sRelroSharingSupported) {
+                // Sanity.
+                sBrowserUsesSharedRelro = false;
+                sWaitForSharedRelros = false;
+            }
+
+            sInitialized = true;
+        }
+    }
+
+    /**
+     * A public interface used to run runtime linker tests after loading
+     * libraries. Should only be used to implement the linker unit tests,
+     * which is controlled by the value of NativeLibraries.sEnableLinkerTests
+     * configured at build time.
+     */
+    public interface TestRunner {
+        /**
+         * Run runtime checks and return true if they all pass.
+         * @param memoryDeviceConfig The current memory device configuration.
+         * @param inBrowserProcess true iff this is the browser process.
+         */
+        public boolean runChecks(int memoryDeviceConfig, boolean inBrowserProcess);
+    }
+
+    // The name of a class that implements TestRunner.
+    static String sTestRunnerClassName = null;
+
+    /**
+     * Set the TestRunner by its class name. It will be instantiated at
+     * runtime after all libraries are loaded.
+     * @param testRunnerClassName null or a String for the class name of the
+     * TestRunner to use.
+     */
+    public static void setTestRunnerClassName(String testRunnerClassName) {
+        if (DEBUG) Log.i(TAG, "setTestRunnerByClassName(" + testRunnerClassName + ") called");
+
+        if (!NativeLibraries.sEnableLinkerTests) {
+            // Ignore this in production code to prevent malvolent runtime injection.
+            return;
+        }
+
+        synchronized (Linker.class) {
+            assert sTestRunnerClassName == null;
+            sTestRunnerClassName = testRunnerClassName;
+        }
+    }
+
+    /**
+     * Call this to retrieve the name of the current TestRunner class name
+     * if any. This can be useful to pass it from the browser process to
+     * child ones.
+     * @return null or a String holding the name of the class implementing
+     * the TestRunner set by calling setTestRunnerClassName() previously.
+     */
+    public static String getTestRunnerClassName() {
+        synchronized (Linker.class) {
+            return sTestRunnerClassName;
+        }
+    }
+
+    /**
+     * Call this method before any other Linker method to force a specific
+     * memory device configuration. Should only be used for testing.
+     * @param memoryDeviceConfig either MEMORY_DEVICE_CONFIG_LOW or MEMORY_DEVICE_CONFIG_NORMAL.
+     */
+    public static void setMemoryDeviceConfig(int memoryDeviceConfig) {
+        if (DEBUG) Log.i(TAG, "setMemoryDeviceConfig(" + memoryDeviceConfig + ") called");
+        // Sanity check. This method should only be called during tests.
+        assert NativeLibraries.sEnableLinkerTests;
+        synchronized (Linker.class) {
+            assert sMemoryDeviceConfig == MEMORY_DEVICE_CONFIG_INIT;
+            assert memoryDeviceConfig == MEMORY_DEVICE_CONFIG_LOW
+                   || memoryDeviceConfig == MEMORY_DEVICE_CONFIG_NORMAL;
+            if (DEBUG) {
+                if (memoryDeviceConfig == MEMORY_DEVICE_CONFIG_LOW) {
+                    Log.i(TAG, "Simulating a low-memory device");
+                } else {
+                    Log.i(TAG, "Simulating a regular-memory device");
+                }
+            }
+            sMemoryDeviceConfig = memoryDeviceConfig;
+        }
+    }
+
+    /**
+     * Call this method to determine if this chromium project must
+     * use this linker. If not, System.loadLibrary() should be used to load
+     * libraries instead.
+     */
+    public static boolean isUsed() {
+        // Only GYP targets that are APKs and have the 'use_chromium_linker' variable
+        // defined as 1 will use this linker. For all others (the default), the
+        // auto-generated NativeLibraries.sUseLinker variable will be false.
+        if (!NativeLibraries.sUseLinker) return false;
+
+        synchronized (Linker.class) {
+            ensureInitializedLocked();
+            // At the moment, there is also no point in using this linker if the
+            // system does not support RELRO sharing safely.
+            return sRelroSharingSupported;
+        }
+    }
+
+    /**
+     * Call this method to determine if the linker will try to use shared RELROs
+     * for the browser process.
+     */
+    public static boolean isUsingBrowserSharedRelros() {
+        synchronized (Linker.class) {
+            ensureInitializedLocked();
+            return sBrowserUsesSharedRelro;
+        }
+    }
+
+    /**
+     * Call this method to determine if the chromium project must load
+     * the library directly from the zip file.
+     */
+    public static boolean isInZipFile() {
+        return NativeLibraries.sUseLibraryInZipFile;
+    }
+
+    /**
+     * Call this method just before loading any native shared libraries in this process.
+     */
+    public static void prepareLibraryLoad() {
+        if (DEBUG) Log.i(TAG, "prepareLibraryLoad() called");
+        synchronized (Linker.class) {
+            sPrepareLibraryLoadCalled = true;
+
+            if (sInBrowserProcess) {
+                // Force generation of random base load address, as well
+                // as creation of shared RELRO sections in this process.
+                setupBaseLoadAddressLocked();
+            }
+        }
+    }
+
+    /**
+     * Call this method just after loading all native shared libraries in this process.
+     * Note that when in a service process, this will block until the RELRO bundle is
+     * received, i.e. when another thread calls useSharedRelros().
+     */
+    public static void finishLibraryLoad() {
+        if (DEBUG) Log.i(TAG, "finishLibraryLoad() called");
+        synchronized (Linker.class) {
+            if (DEBUG) Log.i(TAG, String.format(
+                    Locale.US,
+                    "sInBrowserProcess=%s sBrowserUsesSharedRelro=%s sWaitForSharedRelros=%s",
+                    sInBrowserProcess ? "true" : "false",
+                    sBrowserUsesSharedRelro ? "true" : "false",
+                    sWaitForSharedRelros ? "true" : "false"));
+
+            if (sLoadedLibraries == null) {
+                if (DEBUG) Log.i(TAG, "No libraries loaded");
+            } else {
+                if (sInBrowserProcess) {
+                    // Create new Bundle containing RELRO section information
+                    // for all loaded libraries. Make it available to getSharedRelros().
+                    sSharedRelros = createBundleFromLibInfoMap(sLoadedLibraries);
+                    if (DEBUG) {
+                        Log.i(TAG, "Shared RELRO created");
+                        dumpBundle(sSharedRelros);
+                    }
+
+                    if (sBrowserUsesSharedRelro) {
+                        useSharedRelrosLocked(sSharedRelros);
+                    }
+                }
+
+                if (sWaitForSharedRelros) {
+                    assert !sInBrowserProcess;
+
+                    // Wait until the shared relro bundle is received from useSharedRelros().
+                    while (sSharedRelros == null) {
+                        try {
+                            Linker.class.wait();
+                        } catch (InterruptedException ie) {
+                            // no-op
+                        }
+                    }
+                    useSharedRelrosLocked(sSharedRelros);
+                    // Clear the Bundle to ensure its file descriptor references can't be reused.
+                    sSharedRelros.clear();
+                    sSharedRelros = null;
+                }
+            }
+
+            if (NativeLibraries.sEnableLinkerTests && sTestRunnerClassName != null) {
+                // The TestRunner implementation must be instantiated _after_
+                // all libraries are loaded to ensure that its native methods
+                // are properly registered.
+                if (DEBUG) Log.i(TAG, "Instantiating " + sTestRunnerClassName);
+                TestRunner testRunner = null;
+                try {
+                    testRunner = (TestRunner)
+                            Class.forName(sTestRunnerClassName).newInstance();
+                } catch (Exception e) {
+                    Log.e(TAG, "Could not extract test runner class name", e);
+                    testRunner = null;
+                }
+                if (testRunner != null) {
+                    if (!testRunner.runChecks(sMemoryDeviceConfig, sInBrowserProcess)) {
+                        Log.wtf(TAG, "Linker runtime tests failed in this process!!");
+                        assert false;
+                    } else {
+                        Log.i(TAG, "All linker tests passed!");
+                    }
+                }
+            }
+        }
+        if (DEBUG) Log.i(TAG, "finishLibraryLoad() exiting");
+    }
+
+    /**
+     * Call this to send a Bundle containing the shared RELRO sections to be
+     * used in this process. If initServiceProcess() was previously called,
+     * finishLibraryLoad() will not exit until this method is called in another
+     * thread with a non-null value.
+     * @param bundle The Bundle instance containing a map of shared RELRO sections
+     * to use in this process.
+     */
+    public static void useSharedRelros(Bundle bundle) {
+        // Ensure the bundle uses the application's class loader, not the framework
+        // one which doesn't know anything about LibInfo.
+        // Also, hold a fresh copy of it so the caller can't recycle it.
+        Bundle clonedBundle = null;
+        if (bundle != null) {
+            bundle.setClassLoader(LibInfo.class.getClassLoader());
+            clonedBundle = new Bundle(LibInfo.class.getClassLoader());
+            Parcel parcel = Parcel.obtain();
+            bundle.writeToParcel(parcel, 0);
+            parcel.setDataPosition(0);
+            clonedBundle.readFromParcel(parcel);
+            parcel.recycle();
+        }
+        if (DEBUG) {
+            Log.i(TAG, "useSharedRelros() called with " + bundle
+                    + ", cloned " + clonedBundle);
+        }
+        synchronized (Linker.class) {
+            // Note that in certain cases, this can be called before
+            // initServiceProcess() in service processes.
+            sSharedRelros = clonedBundle;
+            // Tell any listener blocked in finishLibraryLoad() about it.
+            Linker.class.notifyAll();
+        }
+    }
+
+    /**
+     * Call this to retrieve the shared RELRO sections created in this process,
+     * after loading all libraries.
+     * @return a new Bundle instance, or null if RELRO sharing is disabled on
+     * this system, or if initServiceProcess() was called previously.
+     */
+    public static Bundle getSharedRelros() {
+        if (DEBUG) Log.i(TAG, "getSharedRelros() called");
+        synchronized (Linker.class) {
+            if (!sInBrowserProcess) {
+                if (DEBUG) Log.i(TAG, "... returning null Bundle");
+                return null;
+            }
+
+            // Return the Bundle created in finishLibraryLoad().
+            if (DEBUG) Log.i(TAG, "... returning " + sSharedRelros);
+            return sSharedRelros;
+        }
+    }
+
+
+    /**
+     * Call this method before loading any libraries to indicate that this
+     * process shall neither create or reuse shared RELRO sections.
+     */
+    public static void disableSharedRelros() {
+        if (DEBUG) Log.i(TAG, "disableSharedRelros() called");
+        synchronized (Linker.class) {
+            sInBrowserProcess = false;
+            sWaitForSharedRelros = false;
+            sBrowserUsesSharedRelro = false;
+        }
+    }
+
+    /**
+     * Call this method before loading any libraries to indicate that this
+     * process is ready to reuse shared RELRO sections from another one.
+     * Typically used when starting service processes.
+     * @param baseLoadAddress the base library load address to use.
+     */
+    public static void initServiceProcess(long baseLoadAddress) {
+        if (DEBUG) {
+            Log.i(TAG, String.format(
+                    Locale.US, "initServiceProcess(0x%x) called", baseLoadAddress));
+        }
+        synchronized (Linker.class) {
+            ensureInitializedLocked();
+            sInBrowserProcess = false;
+            sBrowserUsesSharedRelro = false;
+            if (sRelroSharingSupported) {
+                sWaitForSharedRelros = true;
+                sBaseLoadAddress = baseLoadAddress;
+                sCurrentLoadAddress = baseLoadAddress;
+            }
+        }
+    }
+
+    /**
+     * Retrieve the base load address of all shared RELRO sections.
+     * This also enforces the creation of shared RELRO sections in
+     * prepareLibraryLoad(), which can later be retrieved with getSharedRelros().
+     * @return a common, random base load address, or 0 if RELRO sharing is
+     * disabled.
+     */
+    public static long getBaseLoadAddress() {
+        synchronized (Linker.class) {
+            ensureInitializedLocked();
+            if (!sInBrowserProcess) {
+                Log.w(TAG, "Shared RELRO sections are disabled in this process!");
+                return 0;
+            }
+
+            setupBaseLoadAddressLocked();
+            if (DEBUG) Log.i(TAG, String.format(Locale.US, "getBaseLoadAddress() returns 0x%x",
+                                                sBaseLoadAddress));
+            return sBaseLoadAddress;
+        }
+    }
+
+    // Used internally to lazily setup the common random base load address.
+    private static void setupBaseLoadAddressLocked() {
+        assert Thread.holdsLock(Linker.class);
+        if (sBaseLoadAddress == 0) {
+            long address = computeRandomBaseLoadAddress();
+            sBaseLoadAddress = address;
+            sCurrentLoadAddress = address;
+            if (address == 0) {
+                // If the computed address is 0, there are issues with finding enough
+                // free address space, so disable RELRO shared / fixed load addresses.
+                Log.w(TAG, "Disabling shared RELROs due address space pressure");
+                sBrowserUsesSharedRelro = false;
+                sWaitForSharedRelros = false;
+            }
+        }
+    }
+
+
+    /**
+     * Compute a random base load address at which to place loaded libraries.
+     * @return new base load address, or 0 if the system does not support
+     * RELRO sharing.
+     */
+    private static long computeRandomBaseLoadAddress() {
+        // nativeGetRandomBaseLoadAddress() returns an address at which it has previously
+        // successfully mapped an area of the given size, on the basis that we will be
+        // able, with high probability, to map our library into it.
+        //
+        // One issue with this is that we do not yet know the size of the library that
+        // we will load is. So here we pass a value that we expect will always be larger
+        // than that needed. If it is smaller the library mapping may still succeed. The
+        // other issue is that although highly unlikely, there is no guarantee that
+        // something else does not map into the area we are going to use between here and
+        // when we try to map into it.
+        //
+        // The above notes mean that all of this is probablistic. It is however okay to do
+        // because if, worst case and unlikely, we get unlucky in our choice of address,
+        // the back-out and retry without the shared RELRO in the ChildProcessService will
+        // keep things running.
+        final long maxExpectedBytes = 192 * 1024 * 1024;
+        final long address = nativeGetRandomBaseLoadAddress(maxExpectedBytes);
+        if (DEBUG) {
+            Log.i(TAG, String.format(Locale.US, "Random native base load address: 0x%x", address));
+        }
+        return address;
+    }
+
+    // Used for debugging only.
+    private static void dumpBundle(Bundle bundle) {
+        if (DEBUG) Log.i(TAG, "Bundle has " + bundle.size() + " items: " + bundle);
+    }
+
+    /**
+     * Use the shared RELRO section from a Bundle received form another process.
+     * Call this after calling setBaseLoadAddress() then loading all libraries
+     * with loadLibrary().
+     * @param bundle Bundle instance generated with createSharedRelroBundle() in
+     * another process.
+     */
+    private static void useSharedRelrosLocked(Bundle bundle) {
+        assert Thread.holdsLock(Linker.class);
+
+        if (DEBUG) Log.i(TAG, "Linker.useSharedRelrosLocked() called");
+
+        if (bundle == null) {
+            if (DEBUG) Log.i(TAG, "null bundle!");
+            return;
+        }
+
+        if (!sRelroSharingSupported) {
+            if (DEBUG) Log.i(TAG, "System does not support RELRO sharing");
+            return;
+        }
+
+        if (sLoadedLibraries == null) {
+            if (DEBUG) Log.i(TAG, "No libraries loaded!");
+            return;
+        }
+
+        if (DEBUG) dumpBundle(bundle);
+        HashMap<String, LibInfo> relroMap = createLibInfoMapFromBundle(bundle);
+
+        // Apply the RELRO section to all libraries that were already loaded.
+        for (Map.Entry<String, LibInfo> entry : relroMap.entrySet()) {
+            String libName = entry.getKey();
+            LibInfo libInfo = entry.getValue();
+            if (!nativeUseSharedRelro(libName, libInfo)) {
+                Log.w(TAG, "Could not use shared RELRO section for " + libName);
+            } else {
+                if (DEBUG) Log.i(TAG, "Using shared RELRO section for " + libName);
+            }
+        }
+
+        // In service processes, close all file descriptors from the map now.
+        if (!sInBrowserProcess) closeLibInfoMap(relroMap);
+
+        if (DEBUG) Log.i(TAG, "Linker.useSharedRelrosLocked() exiting");
+    }
+
+    /**
+     * Load a native shared library with the Chromium linker. If the zip file
+     * is not null, the shared library must be uncompressed and page aligned
+     * inside the zipfile. Note the crazy linker treats libraries and files as
+     * equivalent, so you can only open one library in a given zip file. The
+     * library must not be the Chromium linker library.
+     *
+     * @param zipFilePath The path of the zip file containing the library (or null).
+     * @param libFilePath The path of the library (possibly in the zip file).
+     */
+    public static void loadLibrary(@Nullable String zipFilePath, String libFilePath) {
+        if (DEBUG) Log.i(TAG, "loadLibrary: " + zipFilePath + ", " + libFilePath);
+
+        synchronized (Linker.class) {
+            ensureInitializedLocked();
+
+            // Security: Ensure prepareLibraryLoad() was called before.
+            // In theory, this can be done lazily here, but it's more consistent
+            // to use a pair of functions (i.e. prepareLibraryLoad() + finishLibraryLoad())
+            // that wrap all calls to loadLibrary() in the library loader.
+            assert sPrepareLibraryLoadCalled;
+
+            if (sLoadedLibraries == null) sLoadedLibraries = new HashMap<String, LibInfo>();
+
+            if (sLoadedLibraries.containsKey(libFilePath)) {
+                if (DEBUG) Log.i(TAG, "Not loading " + libFilePath + " twice");
+                return;
+            }
+
+            LibInfo libInfo = new LibInfo();
+            long loadAddress = 0;
+            if ((sInBrowserProcess && sBrowserUsesSharedRelro) || sWaitForSharedRelros) {
+                // Load the library at a fixed address.
+                loadAddress = sCurrentLoadAddress;
+            }
+
+            String sharedRelRoName = libFilePath;
+            if (zipFilePath != null) {
+                if (!nativeLoadLibraryInZipFile(zipFilePath, libFilePath, loadAddress, libInfo)) {
+                    String errorMessage = "Unable to load library: " + libFilePath
+                                          + ", in: " + zipFilePath;
+                    Log.e(TAG, errorMessage);
+                    throw new UnsatisfiedLinkError(errorMessage);
+                }
+                sharedRelRoName = zipFilePath;
+            } else {
+                if (!nativeLoadLibrary(libFilePath, loadAddress, libInfo)) {
+                    String errorMessage = "Unable to load library: " + libFilePath;
+                    Log.e(TAG, errorMessage);
+                    throw new UnsatisfiedLinkError(errorMessage);
+                }
+            }
+
+            // Print the load address to the logcat when testing the linker. The format
+            // of the string is expected by the Python test_runner script as one of:
+            //    BROWSER_LIBRARY_ADDRESS: <library-name> <address>
+            //    RENDERER_LIBRARY_ADDRESS: <library-name> <address>
+            // Where <library-name> is the library name, and <address> is the hexadecimal load
+            // address.
+            if (NativeLibraries.sEnableLinkerTests) {
+                Log.i(TAG, String.format(
+                        Locale.US,
+                        "%s_LIBRARY_ADDRESS: %s %x",
+                        sInBrowserProcess ? "BROWSER" : "RENDERER",
+                        libFilePath,
+                        libInfo.mLoadAddress));
+            }
+
+            if (sInBrowserProcess) {
+                // Create a new shared RELRO section at the 'current' fixed load address.
+                if (!nativeCreateSharedRelro(sharedRelRoName, sCurrentLoadAddress, libInfo)) {
+                    Log.w(TAG, String.format(Locale.US,
+                            "Could not create shared RELRO for %s at %x", libFilePath,
+                            sCurrentLoadAddress));
+                } else {
+                    if (DEBUG) Log.i(TAG,
+                        String.format(
+                            Locale.US,
+                            "Created shared RELRO for %s at %x: %s",
+                            sharedRelRoName,
+                            sCurrentLoadAddress,
+                            libInfo.toString()));
+                }
+            }
+
+            if (sCurrentLoadAddress != 0) {
+                // Compute the next current load address. If sBaseLoadAddress
+                // is not 0, this is an explicit library load address. Otherwise,
+                // this is an explicit load address for relocated RELRO sections
+                // only.
+                sCurrentLoadAddress = libInfo.mLoadAddress + libInfo.mLoadSize;
+            }
+
+            sLoadedLibraries.put(sharedRelRoName, libInfo);
+            if (DEBUG) Log.i(TAG, "Library details " + libInfo.toString());
+        }
+    }
+
+    /**
+     * Determine whether a library is the linker library. Also deal with the
+     * component build that adds a .cr suffix to the name.
+     */
+    public static boolean isChromiumLinkerLibrary(String library) {
+        return library.equals(TAG) || library.equals(TAG + ".cr");
+    }
+
+    /**
+     * Get the full library path in zip file (lib/<abi>/crazy.<lib_name>).
+     *
+     * @param library The library's base name.
+     * @return the library path.
+     */
+    public static String getLibraryFilePathInZipFile(String library) throws FileNotFoundException {
+        synchronized (Linker.class) {
+            ensureInitializedLocked();
+
+            String path = nativeGetLibraryFilePathInZipFile(library);
+            if (path.equals("")) {
+                throw new FileNotFoundException(
+                        "Failed to retrieve path in zip file for library " + library);
+            }
+            return path;
+        }
+    }
+
+    /**
+     * Check whether a library is page aligned and uncompressed in the APK file.
+     *
+     * @param apkFile Filename of the APK.
+     * @param library The library's base name.
+     * @return true if page aligned and uncompressed.
+     */
+    public static boolean checkLibraryIsMappableInApk(String apkFile, String library) {
+        synchronized (Linker.class) {
+            ensureInitializedLocked();
+
+            if (DEBUG) Log.i(TAG, "checkLibraryIsMappableInApk: " + apkFile + ", " + library);
+            boolean aligned = nativeCheckLibraryIsMappableInApk(apkFile, library);
+            if (DEBUG) Log.i(TAG, library + " is " + (aligned ? "" : "NOT ")
+                    + "page aligned in " + apkFile);
+            return aligned;
+        }
+    }
+
+    /**
+     * Move activity from the native thread to the main UI thread.
+     * Called from native code on its own thread.  Posts a callback from
+     * the UI thread back to native code.
+     *
+     * @param opaque Opaque argument.
+     */
+    @CalledByNative
+    public static void postCallbackOnMainThread(final long opaque) {
+        ThreadUtils.postOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                nativeRunCallbackOnUiThread(opaque);
+            }
+        });
+    }
+
+    /**
+     * Native method to run callbacks on the main UI thread.
+     * Supplied by the crazy linker and called by postCallbackOnMainThread.
+     * @param opaque Opaque crazy linker arguments.
+     */
+    private static native void nativeRunCallbackOnUiThread(long opaque);
+
+    /**
+     * Native method used to load a library.
+     * @param library Platform specific library name (e.g. libfoo.so)
+     * @param loadAddress Explicit load address, or 0 for randomized one.
+     * @param libInfo If not null, the mLoadAddress and mLoadSize fields
+     * of this LibInfo instance will set on success.
+     * @return true for success, false otherwise.
+     */
+    private static native boolean nativeLoadLibrary(String library,
+                                                    long loadAddress,
+                                                    LibInfo libInfo);
+
+    /**
+     * Native method used to load a library which is inside a zipfile.
+     * @param zipfileName Filename of the zip file containing the library.
+     * @param library Platform specific library name (e.g. libfoo.so)
+     * @param loadAddress Explicit load address, or 0 for randomized one.
+     * @param libInfo If not null, the mLoadAddress and mLoadSize fields
+     * of this LibInfo instance will set on success.
+     * @return true for success, false otherwise.
+     */
+    private static native boolean nativeLoadLibraryInZipFile(String zipfileName,
+                                                             String libraryName,
+                                                             long loadAddress,
+                                                             LibInfo libInfo);
+
+    /**
+     * Native method used to create a shared RELRO section.
+     * If the library was already loaded at the same address using
+     * nativeLoadLibrary(), this creates the RELRO for it. Otherwise,
+     * this loads a new temporary library at the specified address,
+     * creates and extracts the RELRO section from it, then unloads it.
+     * @param library Library name.
+     * @param loadAddress load address, which can be different from the one
+     * used to load the library in the current process!
+     * @param libInfo libInfo instance. On success, the mRelroStart, mRelroSize
+     * and mRelroFd will be set.
+     * @return true on success, false otherwise.
+     */
+    private static native boolean nativeCreateSharedRelro(String library,
+                                                          long loadAddress,
+                                                          LibInfo libInfo);
+
+    /**
+     * Native method used to use a shared RELRO section.
+     * @param library Library name.
+     * @param libInfo A LibInfo instance containing valid RELRO information
+     * @return true on success.
+     */
+    private static native boolean nativeUseSharedRelro(String library,
+                                                       LibInfo libInfo);
+
+    /**
+     * Checks that the system supports shared RELROs. Old Android kernels
+     * have a bug in the way they check Ashmem region protection flags, which
+     * makes using shared RELROs unsafe. This method performs a simple runtime
+     * check for this misfeature, even though nativeEnableSharedRelro() will
+     * always fail if this returns false.
+     */
+    private static native boolean nativeCanUseSharedRelro();
+
+    /**
+     * Return a random address that should be free to be mapped with the given size.
+     * Maps an area of size bytes, and if successful then unmaps it and returns
+     * the address of the area allocated by the system (with ASLR). The idea is
+     * that this area should remain free of other mappings until we map our library
+     * into it.
+     * @param sizeBytes Size of area in bytes to search for.
+     * @return address to pass to future mmap, or 0 on error.
+     */
+    private static native long nativeGetRandomBaseLoadAddress(long sizeBytes);
+
+    /**
+      * Native method used to get the full library path in zip file
+      * (lib/<abi>/crazy.<lib_name>).
+      *
+      * @param library The library's base name.
+      * @return the library path (or empty string on failure).
+      */
+    private static native String nativeGetLibraryFilePathInZipFile(String library);
+
+    /**
+     * Native method which checks whether a library is page aligned and
+     * uncompressed in the APK file.
+     *
+     * @param apkFile Filename of the APK.
+     * @param library The library's base name.
+     * @return true if page aligned and uncompressed.
+     */
+    private static native boolean nativeCheckLibraryIsMappableInApk(String apkFile, String library);
+
+    /**
+     * Record information for a given library.
+     * IMPORTANT: Native code knows about this class's fields, so
+     * don't change them without modifying the corresponding C++ sources.
+     * Also, the LibInfo instance owns the ashmem file descriptor.
+     */
+    public static class LibInfo implements Parcelable {
+
+        public LibInfo() {
+            mLoadAddress = 0;
+            mLoadSize = 0;
+            mRelroStart = 0;
+            mRelroSize = 0;
+            mRelroFd = -1;
+        }
+
+        public void close() {
+            if (mRelroFd >= 0) {
+                try {
+                    ParcelFileDescriptor.adoptFd(mRelroFd).close();
+                } catch (java.io.IOException e) {
+                    if (DEBUG) Log.e(TAG, "Failed to close fd: " + mRelroFd);
+                }
+                mRelroFd = -1;
+            }
+        }
+
+        // from Parcelable
+        public LibInfo(Parcel in) {
+            mLoadAddress = in.readLong();
+            mLoadSize = in.readLong();
+            mRelroStart = in.readLong();
+            mRelroSize = in.readLong();
+            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();
+        }
+
+        // from Parcelable
+        @Override
+        public void writeToParcel(Parcel out, int flags) {
+            if (mRelroFd >= 0) {
+                out.writeLong(mLoadAddress);
+                out.writeLong(mLoadSize);
+                out.writeLong(mRelroStart);
+                out.writeLong(mRelroSize);
+                try {
+                    ParcelFileDescriptor fd = ParcelFileDescriptor.fromFd(mRelroFd);
+                    fd.writeToParcel(out, 0);
+                    fd.close();
+                } catch (java.io.IOException e) {
+                    Log.e(TAG, "Cant' write LibInfo file descriptor to parcel", e);
+                }
+            }
+        }
+
+        // from Parcelable
+        @Override
+        public int describeContents() {
+            return Parcelable.CONTENTS_FILE_DESCRIPTOR;
+        }
+
+        // from Parcelable
+        public static final Parcelable.Creator<LibInfo> CREATOR =
+                new Parcelable.Creator<LibInfo>() {
+                    @Override
+                    public LibInfo createFromParcel(Parcel in) {
+                        return new LibInfo(in);
+                    }
+
+                    @Override
+                    public LibInfo[] newArray(int size) {
+                        return new LibInfo[size];
+                    }
+                };
+
+        @Override
+        public String toString() {
+            return String.format(Locale.US,
+                                 "[load=0x%x-0x%x relro=0x%x-0x%x fd=%d]",
+                                 mLoadAddress,
+                                 mLoadAddress + mLoadSize,
+                                 mRelroStart,
+                                 mRelroStart + mRelroSize,
+                                 mRelroFd);
+        }
+
+        // IMPORTANT: Don't change these fields without modifying the
+        // native code that accesses them directly!
+        @AccessedByNative
+        public long mLoadAddress; // page-aligned library load address.
+        @AccessedByNative
+        public long mLoadSize;    // page-aligned library load size.
+        @AccessedByNative
+        public long mRelroStart;  // page-aligned address in memory, or 0 if none.
+        @AccessedByNative
+        public long mRelroSize;   // page-aligned size in memory, or 0.
+        @AccessedByNative
+        public int  mRelroFd;     // ashmem file descriptor, or -1
+    }
+
+    // Create a Bundle from a map of LibInfo objects.
+    private static Bundle createBundleFromLibInfoMap(HashMap<String, LibInfo> map) {
+        Bundle bundle = new Bundle(map.size());
+        for (Map.Entry<String, LibInfo> entry : map.entrySet()) {
+            bundle.putParcelable(entry.getKey(), entry.getValue());
+        }
+
+        return bundle;
+    }
+
+    // Create a new LibInfo map from a Bundle.
+    private static HashMap<String, LibInfo> createLibInfoMapFromBundle(Bundle bundle) {
+        HashMap<String, LibInfo> map = new HashMap<String, LibInfo>();
+        for (String library : bundle.keySet()) {
+            LibInfo libInfo = bundle.getParcelable(library);
+            map.put(library, libInfo);
+        }
+        return map;
+    }
+
+    // Call the close() method on all values of a LibInfo map.
+    private static void closeLibInfoMap(HashMap<String, LibInfo> map) {
+        for (Map.Entry<String, LibInfo> entry : map.entrySet()) {
+            entry.getValue().close();
+        }
+    }
+
+    // The map of libraries that are currently loaded in this process.
+    private static HashMap<String, LibInfo> sLoadedLibraries = null;
+
+    // Used to pass the shared RELRO Bundle through Binder.
+    public static final String EXTRA_LINKER_SHARED_RELROS =
+            "org.chromium.base.android.linker.shared_relros";
+}
diff --git a/base/android/java/src/org/chromium/base/library_loader/LoaderErrors.java b/base/android/java/src/org/chromium/base/library_loader/LoaderErrors.java
new file mode 100644
index 0000000..2b94370
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/library_loader/LoaderErrors.java
@@ -0,0 +1,16 @@
+// 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.library_loader;
+
+/**
+ * These are the possible failures from the LibraryLoader
+ */
+public class LoaderErrors {
+    public static final int LOADER_ERROR_NORMAL_COMPLETION = 0;
+    public static final int LOADER_ERROR_FAILED_TO_REGISTER_JNI = 1;
+    public static final int LOADER_ERROR_NATIVE_LIBRARY_LOAD_FAILED = 2;
+    public static final int LOADER_ERROR_NATIVE_LIBRARY_WRONG_VERSION = 3;
+    public static final int LOADER_ERROR_NATIVE_STARTUP_FAILED = 4;
+}
diff --git a/base/android/java/src/org/chromium/base/library_loader/ProcessInitException.java b/base/android/java/src/org/chromium/base/library_loader/ProcessInitException.java
new file mode 100644
index 0000000..1066675
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/library_loader/ProcessInitException.java
@@ -0,0 +1,35 @@
+// 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.library_loader;
+
+/**
+ * The exception that is thrown when the intialization of a process was failed.
+ */
+public class ProcessInitException extends Exception {
+    private int mErrorCode = LoaderErrors.LOADER_ERROR_NORMAL_COMPLETION;
+
+    /**
+     * @param errorCode This will be one of the LoaderErrors error codes.
+     */
+    public ProcessInitException(int errorCode) {
+        mErrorCode = errorCode;
+    }
+
+    /**
+     * @param errorCode This will be one of the LoaderErrors error codes.
+     * @param throwable The wrapped throwable obj.
+     */
+    public ProcessInitException(int errorCode, Throwable throwable) {
+        super(null, throwable);
+        mErrorCode = errorCode;
+    }
+
+    /**
+     * Return the error code.
+     */
+    public int getErrorCode() {
+        return mErrorCode;
+    }
+}
diff --git a/base/android/java/src/org/chromium/base/metrics/RecordHistogram.java b/base/android/java/src/org/chromium/base/metrics/RecordHistogram.java
new file mode 100644
index 0000000..2f4356b
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/metrics/RecordHistogram.java
@@ -0,0 +1,177 @@
+// 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.metrics;
+
+import org.chromium.base.JNINamespace;
+import org.chromium.base.VisibleForTesting;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Java API for recording UMA histograms. Internally, the histogram will be cached by
+ * System.identityHashCode(name).
+ *
+ * Note: the JNI calls are relatively costly - avoid calling these methods in performance-critical
+ * code.
+ */
+@JNINamespace("base::android")
+public class RecordHistogram {
+    /**
+     * Records a sample in a boolean UMA histogram of the given name. Boolean histogram has two
+     * buckets, corresponding to success (true) and failure (false). This is the Java equivalent of
+     * the UMA_HISTOGRAM_BOOLEAN C++ macro.
+     * @param name name of the histogram
+     * @param sample sample to be recorded, either true or false
+     */
+    public static void recordBooleanHistogram(String name, boolean sample) {
+        nativeRecordBooleanHistogram(name, System.identityHashCode(name), sample);
+    }
+
+    /**
+     * Records a sample in an enumerated histogram of the given name and boundary. Note that
+     * |boundary| identifies the histogram - it should be the same at every invocation. This is the
+     * Java equivalent of the UMA_HISTOGRAM_ENUMERATION C++ macro.
+     * @param name name of the histogram
+     * @param sample sample to be recorded, at least 0 and at most |boundary| - 1
+     * @param boundary upper bound for legal sample values - all sample values have to be strictly
+     *        lower than |boundary|
+     */
+    public static void recordEnumeratedHistogram(String name, int sample, int boundary) {
+        nativeRecordEnumeratedHistogram(name, System.identityHashCode(name), sample, boundary);
+    }
+
+    /**
+     * Records a sample in a count histogram. This is the Java equivalent of the
+     * UMA_HISTOGRAM_COUNTS C++ macro.
+     * @param name name of the histogram
+     * @param sample sample to be recorded, at least 1 and at most 999999
+     */
+    public static void recordCountHistogram(String name, int sample) {
+        recordCustomCountHistogram(name, sample, 1, 1000000, 50);
+    }
+
+    /**
+     * Records a sample in a count histogram. This is the Java equivalent of the
+     * UMA_HISTOGRAM_COUNTS_100 C++ macro.
+     * @param name name of the histogram
+     * @param sample sample to be recorded, at least 1 and at most 99
+     */
+    public static void recordCount100Histogram(String name, int sample) {
+        recordCustomCountHistogram(name, sample, 1, 100, 50);
+    }
+
+    /**
+     * Records a sample in a count histogram. This is the Java equivalent of the
+     * UMA_HISTOGRAM_CUSTOM_COUNTS C++ macro.
+     * @param name name of the histogram
+     * @param sample sample to be recorded, at least |min| and at most |max| - 1
+     * @param min lower bound for expected sample values
+     * @param max upper bounds for expected sample values
+     * @param numBuckets the number of buckets
+     */
+    public static void recordCustomCountHistogram(
+            String name, int sample, int min, int max, int numBuckets) {
+        nativeRecordCustomCountHistogram(
+                name, System.identityHashCode(name), sample, min, max, numBuckets);
+    }
+
+    /**
+    * Records a sparse histogram. This is the Java equivalent of UMA_HISTOGRAM_SPARSE_SLOWLY.
+    * @param name name of the histogram
+    * @param sample sample to be recorded. All values of |sample| are valid, including negative
+    *        values.
+    */
+    public static void recordSparseSlowlyHistogram(String name, int sample) {
+        nativeRecordSparseHistogram(name, System.identityHashCode(name), sample);
+    }
+
+    /**
+     * Records a sample in a histogram of times. Useful for recording short durations. This is the
+     * Java equivalent of the UMA_HISTOGRAM_TIMES C++ macro.
+     * @param name name of the histogram
+     * @param duration duration to be recorded
+     * @param timeUnit the unit of the duration argument
+     */
+    public static void recordTimesHistogram(String name, long duration, TimeUnit timeUnit) {
+        recordCustomTimesHistogramMilliseconds(
+                name, timeUnit.toMillis(duration), 1, TimeUnit.SECONDS.toMillis(10), 50);
+    }
+
+    /**
+     * Records a sample in a histogram of times. Useful for recording medium durations. This is the
+     * Java equivalent of the UMA_HISTOGRAM_MEDIUM_TIMES C++ macro.
+     * @param name name of the histogram
+     * @param duration duration to be recorded
+     * @param timeUnit the unit of the duration argument
+     */
+    public static void recordMediumTimesHistogram(String name, long duration, TimeUnit timeUnit) {
+        recordCustomTimesHistogramMilliseconds(
+                name, timeUnit.toMillis(duration), 10, TimeUnit.MINUTES.toMillis(3), 50);
+    }
+
+    /**
+     * Records a sample in a histogram of times. Useful for recording long durations. This is the
+     * Java equivalent of the UMA_HISTOGRAM_LONG_TIMES C++ macro.
+     * @param name name of the histogram
+     * @param duration duration to be recorded
+     * @param timeUnit the unit of the duration argument
+     */
+    public static void recordLongTimesHistogram(String name, long duration, TimeUnit timeUnit) {
+        recordCustomTimesHistogramMilliseconds(
+                name, timeUnit.toMillis(duration), 1, TimeUnit.HOURS.toMillis(1), 50);
+    }
+
+    /**
+     * Records a sample in a histogram of times with custom buckets. This is the Java equivalent of
+     * the UMA_HISTOGRAM_CUSTOM_TIMES C++ macro.
+     * @param name name of the histogram
+     * @param duration duration to be recorded
+     * @param min the minimum bucket value
+     * @param max the maximum bucket value
+     * @param timeUnit the unit of the duration, min, and max arguments
+     * @param numBuckets the number of buckets
+     */
+    public static void recordCustomTimesHistogram(
+            String name, long duration, long min, long max, TimeUnit timeUnit, int numBuckets) {
+        recordCustomTimesHistogramMilliseconds(name, timeUnit.toMillis(duration),
+                timeUnit.toMillis(min), timeUnit.toMillis(max), numBuckets);
+    }
+
+    private static void recordCustomTimesHistogramMilliseconds(
+            String name, long duration, long min, long max, int numBuckets) {
+        nativeRecordCustomTimesHistogramMilliseconds(
+                name, System.identityHashCode(name), duration, min, max, numBuckets);
+    }
+
+    /**
+     * Returns the number of samples recorded in the given bucket of the given histogram.
+     * @param name name of the histogram to look up
+     * @param sample the bucket containing this sample value will be looked up
+     */
+    @VisibleForTesting
+    public static int getHistogramValueCountForTesting(String name, int sample) {
+        return nativeGetHistogramValueCountForTesting(name, sample);
+    }
+
+    /**
+     * Initializes the metrics system.
+     */
+    public static void initialize() {
+        nativeInitialize();
+    }
+
+    private static native void nativeRecordCustomTimesHistogramMilliseconds(
+            String name, int key, long duration, long min, long max, int numBuckets);
+
+    private static native void nativeRecordBooleanHistogram(String name, int key, boolean sample);
+    private static native void nativeRecordEnumeratedHistogram(
+            String name, int key, int sample, int boundary);
+    private static native void nativeRecordCustomCountHistogram(
+            String name, int key, int sample, int min, int max, int numBuckets);
+    private static native void nativeRecordSparseHistogram(String name, int key, int sample);
+
+    private static native int nativeGetHistogramValueCountForTesting(String name, int sample);
+    private static native void nativeInitialize();
+}
diff --git a/base/android/java/src/org/chromium/base/metrics/RecordUserAction.java b/base/android/java/src/org/chromium/base/metrics/RecordUserAction.java
new file mode 100644
index 0000000..d7cc32c
--- /dev/null
+++ b/base/android/java/src/org/chromium/base/metrics/RecordUserAction.java
@@ -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.
+
+package org.chromium.base.metrics;
+
+import org.chromium.base.JNINamespace;
+import org.chromium.base.ThreadUtils;
+
+/**
+ * Java API for recording UMA actions.
+ *
+ * WARNINGS:
+ * JNI calls are relatively costly - avoid using in performance-critical code.
+ *
+ * We use a script (extract_actions.py) to scan the source code and extract actions. A string
+ * literal (not a variable) must be passed to record().
+ */
+@JNINamespace("base::android")
+public class RecordUserAction {
+    public static void record(final String action) {
+        if (ThreadUtils.runningOnUiThread()) {
+            nativeRecordUserAction(action);
+            return;
+        }
+
+        ThreadUtils.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                nativeRecordUserAction(action);
+            }
+        });
+    }
+
+    private static native void nativeRecordUserAction(String action);
+}
diff --git a/base/android/java/templates/NativeLibraries.template b/base/android/java/templates/NativeLibraries.template
new file mode 100644
index 0000000..8b812a6
--- /dev/null
+++ b/base/android/java/templates/NativeLibraries.template
@@ -0,0 +1,95 @@
+// 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.library_loader;
+
+import org.chromium.base.annotations.SuppressFBWarnings;
+
+@SuppressFBWarnings
+public class NativeLibraries {
+    /**
+     * IMPORTANT NOTE: The variables defined here must _not_ be 'final'.
+     *
+     * The reason for this is very subtle:
+     *
+     * - This template is used to generate several distinct, but similar
+     *   files used in different contexts:
+     *
+     *   o .../gen/templates/org/chromium/base/library_loader/NativeLibraries.java
+     *
+     *     This file is used to build base.jar, which is the library
+     *     jar used by chromium projects. However, the
+     *     corresponding NativeLibraries.class file will _not_ be part
+     *     of the final base.jar.
+     *
+     *   o .../$PROJECT/native_libraries_java/NativeLibraries.java
+     *
+     *     This file is used to build an APK (e.g. $PROJECT
+     *     could be 'content_shell_apk'). Its content will depend on
+     *     this target's specific build configuration, and differ from
+     *     the source file above.
+     *
+     * - During the final link, all .jar files are linked together into
+     *   a single .dex file, and the second version of NativeLibraries.class
+     *   will be put into the final output file, and used at runtime.
+     *
+     * - If the variables were defined as 'final', their value would be
+     *   optimized out inside of 'base.jar', and could not be specialized
+     *   for every chromium program. This, however, doesn't apply to arrays of
+     *   strings, which can be defined as final.
+     *
+     * This exotic scheme is used to avoid injecting project-specific, or
+     * even build-specific, values into the base layer. E.g. this is
+     * how the component build is supported on Android without modifying
+     * the sources of each and every Chromium-based target.
+     */
+
+#if defined(ENABLE_CHROMIUM_LINKER_LIBRARY_IN_ZIP_FILE) && \
+    !defined(ENABLE_CHROMIUM_LINKER)
+#error "Must have ENABLE_CHROMIUM_LINKER to enable library in zip file"
+#endif
+
+    // Set to true to enable the use of the Chromium Linker.
+#if defined(ENABLE_CHROMIUM_LINKER)
+    public static boolean sUseLinker = true;
+#else
+    public static boolean sUseLinker = false;
+#endif
+
+#if defined(ENABLE_CHROMIUM_LINKER_LIBRARY_IN_ZIP_FILE)
+    public static boolean sUseLibraryInZipFile = true;
+#else
+    public static boolean sUseLibraryInZipFile = false;
+#endif
+
+#if defined(ENABLE_CHROMIUM_LINKER_TESTS)
+    public static boolean sEnableLinkerTests = true;
+#else
+    public static boolean sEnableLinkerTests = false;
+#endif
+
+    // This is the list of native libraries to be loaded (in the correct order)
+    // by LibraryLoader.java.  The base java library is compiled with no
+    // array defined, and then the build system creates a version of the file
+    // with the real list of libraries required (which changes based upon which
+    // .apk is being built).
+    // TODO(cjhopman): This is public since it is referenced by NativeTestActivity.java
+    // directly. The two ways of library loading should be refactored into one.
+    public static final String[] LIBRARIES =
+#if defined(NATIVE_LIBRARIES_LIST)
+      NATIVE_LIBRARIES_LIST;
+#else
+      {};
+#endif
+
+    // This is the expected version of the 'main' native library, which is the one that
+    // implements the initial set of base JNI functions including
+    // base::android::nativeGetVersionName()
+    static String sVersionNumber =
+#if defined(NATIVE_LIBRARIES_VERSION_NUMBER)
+      NATIVE_LIBRARIES_VERSION_NUMBER;
+#else
+      "";
+#endif
+}
diff --git a/base/android/java_handler_thread.cc b/base/android/java_handler_thread.cc
new file mode 100644
index 0000000..117971e
--- /dev/null
+++ b/base/android/java_handler_thread.cc
@@ -0,0 +1,77 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/java_handler_thread.h"
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/message_loop/message_loop.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread_restrictions.h"
+#include "jni/JavaHandlerThread_jni.h"
+
+namespace base {
+
+namespace android {
+
+JavaHandlerThread::JavaHandlerThread(const char* name) {
+  JNIEnv* env = base::android::AttachCurrentThread();
+
+  java_thread_.Reset(Java_JavaHandlerThread_create(
+      env, ConvertUTF8ToJavaString(env, name).Release()));
+}
+
+JavaHandlerThread::~JavaHandlerThread() {
+}
+
+void JavaHandlerThread::Start() {
+  // Check the thread has not already been started.
+  DCHECK(!message_loop_);
+
+  JNIEnv* env = base::android::AttachCurrentThread();
+  base::WaitableEvent initialize_event(false, false);
+  Java_JavaHandlerThread_start(env,
+                               java_thread_.obj(),
+                               reinterpret_cast<intptr_t>(this),
+                               reinterpret_cast<intptr_t>(&initialize_event));
+  // Wait for thread to be initialized so it is ready to be used when Start
+  // returns.
+  base::ThreadRestrictions::ScopedAllowWait wait_allowed;
+  initialize_event.Wait();
+}
+
+void JavaHandlerThread::Stop() {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  base::WaitableEvent shutdown_event(false, false);
+  Java_JavaHandlerThread_stop(env,
+                              java_thread_.obj(),
+                              reinterpret_cast<intptr_t>(this),
+                              reinterpret_cast<intptr_t>(&shutdown_event));
+  // Wait for thread to shut down before returning.
+  base::ThreadRestrictions::ScopedAllowWait wait_allowed;
+  shutdown_event.Wait();
+}
+
+void JavaHandlerThread::InitializeThread(JNIEnv* env, jobject obj,
+                                         jlong event) {
+  // TYPE_JAVA to get the Android java style message loop.
+  message_loop_.reset(new base::MessageLoop(base::MessageLoop::TYPE_JAVA));
+  static_cast<MessageLoopForUI*>(message_loop_.get())->Start();
+  reinterpret_cast<base::WaitableEvent*>(event)->Signal();
+}
+
+void JavaHandlerThread::StopThread(JNIEnv* env, jobject obj, jlong event) {
+  static_cast<MessageLoopForUI*>(message_loop_.get())->Quit();
+  reinterpret_cast<base::WaitableEvent*>(event)->Signal();
+}
+
+// static
+bool JavaHandlerThread::RegisterBindings(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+} // namespace android
+} // namespace base
diff --git a/base/android/java_handler_thread.h b/base/android/java_handler_thread.h
new file mode 100644
index 0000000..c9a2c02
--- /dev/null
+++ b/base/android/java_handler_thread.h
@@ -0,0 +1,49 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_JAVA_HANDLER_THREAD_H_
+#define BASE_ANDROID_JAVA_HANDLER_THREAD_H_
+
+#include <jni.h>
+
+#include "base/android/scoped_java_ref.h"
+#include "base/memory/scoped_ptr.h"
+
+namespace base {
+
+class MessageLoop;
+class WaitableEvent;
+
+namespace android {
+
+// A Java Thread with a native message loop. To run tasks, post them
+// to the message loop and they will be scheduled along with Java tasks
+// on the thread.
+// This is useful for callbacks where the receiver expects a thread
+// with a prepared Looper.
+class BASE_EXPORT JavaHandlerThread {
+ public:
+  JavaHandlerThread(const char* name);
+  virtual ~JavaHandlerThread();
+
+  base::MessageLoop* message_loop() const { return message_loop_.get(); }
+  void Start();
+  void Stop();
+
+  // Called from java on the newly created thread.
+  // Start() will not return before this methods has finished.
+  void InitializeThread(JNIEnv* env, jobject obj, jlong event);
+  void StopThread(JNIEnv* env, jobject obj, jlong event);
+
+  static bool RegisterBindings(JNIEnv* env);
+
+ private:
+  scoped_ptr<base::MessageLoop> message_loop_;
+  ScopedJavaGlobalRef<jobject> java_thread_;
+};
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_JAVA_HANDLER_THREAD_H_
diff --git a/base/android/java_runtime.cc b/base/android/java_runtime.cc
new file mode 100644
index 0000000..5be9adf
--- /dev/null
+++ b/base/android/java_runtime.cc
@@ -0,0 +1,25 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/java_runtime.h"
+
+#include "jni/Runtime_jni.h"
+
+namespace base {
+namespace android {
+
+bool JavaRuntime::Register(JNIEnv* env) {
+  return JNI_Runtime::RegisterNativesImpl(env);
+}
+
+void JavaRuntime::GetMemoryUsage(long* total_memory, long* free_memory) {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  base::android::ScopedJavaLocalRef<jobject> runtime =
+      JNI_Runtime::Java_Runtime_getRuntime(env);
+  *total_memory = JNI_Runtime::Java_Runtime_totalMemory(env, runtime.obj());
+  *free_memory = JNI_Runtime::Java_Runtime_freeMemory(env, runtime.obj());
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/java_runtime.h b/base/android/java_runtime.h
new file mode 100644
index 0000000..4ca889e
--- /dev/null
+++ b/base/android/java_runtime.h
@@ -0,0 +1,28 @@
+// 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_JAVA_RUNTIME_H_
+#define BASE_ANDROID_JAVA_RUNTIME_H_
+
+#include "base/android/scoped_java_ref.h"
+#include "base/base_export.h"
+
+namespace base {
+namespace android {
+
+// Wrapper class for using the java.lang.Runtime object from jni.
+class BASE_EXPORT JavaRuntime {
+ public:
+  // Registers the jni class (once per process).
+  static bool Register(JNIEnv* env);
+
+  // Fills the total memory used and memory allocated for objects by the java
+  // heap in the current process. Returns true on success.
+  static void GetMemoryUsage(long* total_memory, long* free_memory);
+};
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_JAVA_RUNTIME_H_
diff --git a/base/android/javatests/src/org/chromium/base/AdvancedMockContextTest.java b/base/android/javatests/src/org/chromium/base/AdvancedMockContextTest.java
new file mode 100644
index 0000000..d7c103b
--- /dev/null
+++ b/base/android/javatests/src/org/chromium/base/AdvancedMockContextTest.java
@@ -0,0 +1,68 @@
+// 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;
+
+import android.app.Application;
+import android.content.ComponentCallbacks;
+import android.content.ComponentCallbacks2;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.test.InstrumentationTestCase;
+
+import org.chromium.base.test.util.AdvancedMockContext;
+
+/**
+ * Tests for {@link org.chromium.base.test.util.AdvancedMockContext}.
+ */
+public class AdvancedMockContextTest extends InstrumentationTestCase {
+    private static class Callback1 implements ComponentCallbacks {
+        protected Configuration mConfiguration;
+        protected boolean mOnLowMemoryCalled;
+
+        @Override
+        public void onConfigurationChanged(Configuration configuration) {
+            mConfiguration = configuration;
+        }
+
+        @Override
+        public void onLowMemory() {
+            mOnLowMemoryCalled = true;
+        }
+    }
+
+    private static class Callback2 extends Callback1 implements ComponentCallbacks2 {
+        private int mLevel;
+
+        @Override
+        public void onTrimMemory(int level) {
+            mLevel = level;
+        }
+    }
+
+    public void testComponentCallbacksForTargetContext() {
+        Context targetContext = getInstrumentation().getTargetContext();
+        Application targetApplication = (Application) targetContext.getApplicationContext();
+        AdvancedMockContext context = new AdvancedMockContext(targetContext);
+        Callback1 callback1 = new Callback1();
+        Callback2 callback2 = new Callback2();
+        context.registerComponentCallbacks(callback1);
+        context.registerComponentCallbacks(callback2);
+
+        targetApplication.onLowMemory();
+        assertTrue("onLowMemory should have been called.", callback1.mOnLowMemoryCalled);
+        assertTrue("onLowMemory should have been called.", callback2.mOnLowMemoryCalled);
+
+        Configuration configuration = new Configuration();
+        targetApplication.onConfigurationChanged(configuration);
+        assertEquals("onConfigurationChanged should have been called.", configuration,
+                callback1.mConfiguration);
+        assertEquals("onConfigurationChanged should have been called.", configuration,
+                callback2.mConfiguration);
+
+        targetApplication.onTrimMemory(ComponentCallbacks2.TRIM_MEMORY_MODERATE);
+        assertEquals("onTrimMemory should have been called.", ComponentCallbacks2
+                .TRIM_MEMORY_MODERATE, callback2.mLevel);
+    }
+}
diff --git a/base/android/javatests/src/org/chromium/base/ApiCompatibilityUtilsTest.java b/base/android/javatests/src/org/chromium/base/ApiCompatibilityUtilsTest.java
new file mode 100644
index 0000000..45b3e21
--- /dev/null
+++ b/base/android/javatests/src/org/chromium/base/ApiCompatibilityUtilsTest.java
@@ -0,0 +1,71 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.annotation.TargetApi;
+import android.app.Activity;
+import android.os.Build;
+import android.os.SystemClock;
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Test of ApiCompatibilityUtils
+ */
+public class ApiCompatibilityUtilsTest extends InstrumentationTestCase {
+    private static final long WAIT_TIMEOUT_IN_MS = 5000;
+    private static final long SLEEP_INTERVAL_IN_MS = 50;
+
+    static class MockActivity extends Activity {
+        int mFinishAndRemoveTaskCallbackCount;
+        int mFinishCallbackCount;
+        boolean mIsFinishing;
+
+        @TargetApi(Build.VERSION_CODES.LOLLIPOP)
+        @Override
+        public void finishAndRemoveTask() {
+            mFinishAndRemoveTaskCallbackCount++;
+            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) mIsFinishing = true;
+        }
+
+        @Override
+        public void finish() {
+            mFinishCallbackCount++;
+            mIsFinishing = true;
+        }
+
+        @Override
+        public boolean isFinishing() {
+            return mIsFinishing;
+        }
+    }
+
+    @SmallTest
+    public void testFinishAndRemoveTask() throws InterruptedException {
+        MockActivity activity = new MockActivity();
+        ApiCompatibilityUtils.finishAndRemoveTask(activity);
+
+        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
+            assertEquals(1, activity.mFinishAndRemoveTaskCallbackCount);
+            assertEquals(0, activity.mFinishCallbackCount);
+        } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP) {
+            long startTime = SystemClock.uptimeMillis();
+            while (activity.mFinishCallbackCount == 0
+                    && SystemClock.uptimeMillis() - startTime < WAIT_TIMEOUT_IN_MS) {
+                Thread.sleep(SLEEP_INTERVAL_IN_MS);
+            }
+
+            // MockActivity#finishAndRemoveTask() never sets isFinishing() to true for LOLLIPOP to
+            // simulate an exceptional case. In that case, MockActivity#finish() should be called
+            // after 3 tries.
+            assertEquals(3, activity.mFinishAndRemoveTaskCallbackCount);
+            assertEquals(1, activity.mFinishCallbackCount);
+        } else {
+            assertEquals(0, activity.mFinishAndRemoveTaskCallbackCount);
+            assertEquals(1, activity.mFinishCallbackCount);
+        }
+        assertTrue(activity.mIsFinishing);
+    }
+}
diff --git a/base/android/javatests/src/org/chromium/base/CommandLineTest.java b/base/android/javatests/src/org/chromium/base/CommandLineTest.java
new file mode 100644
index 0000000..2b1a967
--- /dev/null
+++ b/base/android/javatests/src/org/chromium/base/CommandLineTest.java
@@ -0,0 +1,128 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.chromium.base.test.util.Feature;
+
+public class CommandLineTest extends InstrumentationTestCase {
+    // A reference command line. Note that switch2 is [brea\d], switch3 is [and "butter"],
+    // and switch4 is [a "quoted" 'food'!]
+    static final String INIT_SWITCHES[] = { "init_command", "--SWITCH", "Arg",
+        "--switch2=brea\\d", "--switch3=and \"butter\"",
+        "--switch4=a \"quoted\" 'food'!",
+        "--", "--actually_an_arg" };
+
+    // The same command line, but in quoted string format.
+    static final char INIT_SWITCHES_BUFFER[] =
+        ("init_command --SWITCH Arg --switch2=brea\\d --switch3=\"and \\\"butt\"er\\\"   "
+        + "--switch4='a \"quoted\" \\'food\\'!' "
+        + "-- --actually_an_arg").toCharArray();
+
+    static final String CL_ADDED_SWITCH = "zappo-dappo-doggy-trainer";
+    static final String CL_ADDED_SWITCH_2 = "username";
+    static final String CL_ADDED_VALUE_2 = "bozo";
+
+    @Override
+    public void setUp() throws Exception {
+        CommandLine.reset();
+    }
+
+    void checkInitSwitches() {
+        CommandLine cl = CommandLine.getInstance();
+        assertFalse(cl.hasSwitch("init_command"));
+        assertFalse(cl.hasSwitch("switch"));
+        assertTrue(cl.hasSwitch("SWITCH"));
+        assertFalse(cl.hasSwitch("--SWITCH"));
+        assertFalse(cl.hasSwitch("Arg"));
+        assertFalse(cl.hasSwitch("actually_an_arg"));
+        assertEquals("brea\\d", cl.getSwitchValue("switch2"));
+        assertEquals("and \"butter\"", cl.getSwitchValue("switch3"));
+        assertEquals("a \"quoted\" 'food'!", cl.getSwitchValue("switch4"));
+        assertNull(cl.getSwitchValue("SWITCH"));
+        assertNull(cl.getSwitchValue("non-existant"));
+    }
+
+    void checkSettingThenGetting() {
+        CommandLine cl = CommandLine.getInstance();
+
+        // Add a plain switch.
+        assertFalse(cl.hasSwitch(CL_ADDED_SWITCH));
+        cl.appendSwitch(CL_ADDED_SWITCH);
+        assertTrue(cl.hasSwitch(CL_ADDED_SWITCH));
+
+        // Add a switch paired with a value.
+        assertFalse(cl.hasSwitch(CL_ADDED_SWITCH_2));
+        assertNull(cl.getSwitchValue(CL_ADDED_SWITCH_2));
+        cl.appendSwitchWithValue(CL_ADDED_SWITCH_2, CL_ADDED_VALUE_2);
+        assertTrue(CL_ADDED_VALUE_2.equals(cl.getSwitchValue(CL_ADDED_SWITCH_2)));
+
+        // Append a few new things.
+        final String switchesAndArgs[] = { "dummy", "--superfast", "--speed=turbo" };
+        assertFalse(cl.hasSwitch("dummy"));
+        assertFalse(cl.hasSwitch("superfast"));
+        assertNull(cl.getSwitchValue("speed"));
+        cl.appendSwitchesAndArguments(switchesAndArgs);
+        assertFalse(cl.hasSwitch("dummy"));
+        assertFalse(cl.hasSwitch("command"));
+        assertTrue(cl.hasSwitch("superfast"));
+        assertTrue("turbo".equals(cl.getSwitchValue("speed")));
+    }
+
+    void checkTokenizer(String[] expected, String toParse) {
+        String[] actual = CommandLine.tokenizeQuotedAruments(toParse.toCharArray());
+        assertEquals(expected.length, actual.length);
+        for (int i = 0; i < expected.length; ++i) {
+            assertEquals("comparing element " + i, expected[i], actual[i]);
+        }
+    }
+
+    @SmallTest
+    @Feature({"Android-AppBase"})
+    public void testJavaInitialization() {
+        CommandLine.init(INIT_SWITCHES);
+        checkInitSwitches();
+        checkSettingThenGetting();
+    }
+
+    @SmallTest
+    @Feature({"Android-AppBase"})
+    public void testBufferInitialization() {
+        CommandLine.init(CommandLine.tokenizeQuotedAruments(INIT_SWITCHES_BUFFER));
+        checkInitSwitches();
+        checkSettingThenGetting();
+    }
+
+    @SmallTest
+    @Feature({"Android-AppBase"})
+    public void testArgumentTokenizer() {
+        String toParse = " a\"\\bc de\\\"f g\"\\h ij    k\" \"lm";
+        String[] expected = { "a\\bc de\"f g\\h",
+                              "ij",
+                              "k lm" };
+        checkTokenizer(expected, toParse);
+
+        toParse = "";
+        expected = new String[0];
+        checkTokenizer(expected, toParse);
+
+        toParse = " \t\n";
+        checkTokenizer(expected, toParse);
+
+        toParse = " \"a'b\" 'c\"d' \"e\\\"f\" 'g\\'h' \"i\\'j\" 'k\\\"l'"
+                + " m\"n\\'o\"p q'r\\\"s't";
+        expected = new String[] { "a'b",
+                                  "c\"d",
+                                  "e\"f",
+                                  "g'h",
+                                  "i\\'j",
+                                  "k\\\"l",
+                                  "mn\\'op",
+                                  "qr\\\"st"};
+        checkTokenizer(expected, toParse);
+    }
+}
diff --git a/base/android/javatests/src/org/chromium/base/ObserverListTest.java b/base/android/javatests/src/org/chromium/base/ObserverListTest.java
new file mode 100644
index 0000000..973682b
--- /dev/null
+++ b/base/android/javatests/src/org/chromium/base/ObserverListTest.java
@@ -0,0 +1,326 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.chromium.base.test.util.Feature;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ * Tests for (@link ObserverList}.
+ */
+public class ObserverListTest extends InstrumentationTestCase {
+    interface Observer {
+        void observe(int x);
+    }
+
+    private static class Foo implements Observer {
+        private final int mScalar;
+        private int mTotal = 0;
+
+        Foo(int scalar) {
+            mScalar = scalar;
+        }
+
+        @Override
+        public void observe(int x) {
+            mTotal += x * mScalar;
+        }
+    }
+
+    /**
+     * An observer which add a given Observer object to the list when observe is called.
+     */
+    private static class FooAdder implements Observer {
+        private final ObserverList<Observer> mList;
+        private final Observer mLucky;
+
+        FooAdder(ObserverList<Observer> list, Observer oblivious) {
+            mList = list;
+            mLucky = oblivious;
+        }
+
+        @Override
+        public void observe(int x) {
+            mList.addObserver(mLucky);
+        }
+    }
+
+    /**
+     * An observer which removes a given Observer object from the list when observe is called.
+     */
+    private static class FooRemover implements Observer {
+        private final ObserverList<Observer> mList;
+        private final Observer mDoomed;
+
+        FooRemover(ObserverList<Observer> list, Observer innocent) {
+            mList = list;
+            mDoomed = innocent;
+        }
+
+        @Override
+        public void observe(int x) {
+            mList.removeObserver(mDoomed);
+        }
+    }
+
+    private static <T> int getSizeOfIterable(Iterable<T> iterable) {
+        int num = 0;
+        for (T el : iterable) num++;
+        return num;
+    }
+
+    @SmallTest
+    @Feature({"Android-AppBase"})
+    public void testRemoveWhileIteration() {
+        ObserverList<Observer> observerList = new ObserverList<Observer>();
+        Foo a = new Foo(1);
+        Foo b = new Foo(-1);
+        Foo c = new Foo(1);
+        Foo d = new Foo(-1);
+        Foo e = new Foo(-1);
+        FooRemover evil = new FooRemover(observerList, c);
+
+        observerList.addObserver(a);
+        observerList.addObserver(b);
+
+        for (Observer obs : observerList) obs.observe(10);
+
+        // Removing an observer not in the list should do nothing.
+        observerList.removeObserver(e);
+
+        observerList.addObserver(evil);
+        observerList.addObserver(c);
+        observerList.addObserver(d);
+
+        for (Observer obs : observerList) obs.observe(10);
+
+        // observe should be called twice on a.
+        assertEquals(20, a.mTotal);
+        // observe should be called twice on b.
+        assertEquals(-20, b.mTotal);
+        // evil removed c from the observerList before it got any callbacks.
+        assertEquals(0, c.mTotal);
+        // observe should be called once on d.
+        assertEquals(-10, d.mTotal);
+        // e was never added to the list, observe should not be called.
+        assertEquals(0, e.mTotal);
+    }
+
+    @SmallTest
+    @Feature({"Android-AppBase"})
+    public void testAddWhileIteration() {
+        ObserverList<Observer> observerList = new ObserverList<Observer>();
+        Foo a = new Foo(1);
+        Foo b = new Foo(-1);
+        Foo c = new Foo(1);
+        FooAdder evil = new FooAdder(observerList, c);
+
+        observerList.addObserver(evil);
+        observerList.addObserver(a);
+        observerList.addObserver(b);
+
+        for (Observer obs : observerList) obs.observe(10);
+
+        assertTrue(observerList.hasObserver(c));
+        assertEquals(10, a.mTotal);
+        assertEquals(-10, b.mTotal);
+        assertEquals(0, c.mTotal);
+    }
+
+    @SmallTest
+    @Feature({"Android-AppBase"})
+    public void testIterator() {
+        ObserverList<Integer> observerList = new ObserverList<Integer>();
+        observerList.addObserver(5);
+        observerList.addObserver(10);
+        observerList.addObserver(15);
+        assertEquals(3, getSizeOfIterable(observerList));
+
+        observerList.removeObserver(10);
+        assertEquals(2, getSizeOfIterable(observerList));
+
+        Iterator<Integer> it = observerList.iterator();
+        assertTrue(it.hasNext());
+        assertTrue(5 == it.next());
+        assertTrue(it.hasNext());
+        assertTrue(15 == it.next());
+        assertFalse(it.hasNext());
+
+        boolean removeExceptionThrown = false;
+        try {
+            it.remove();
+            fail("Expecting UnsupportedOperationException to be thrown here.");
+        } catch (UnsupportedOperationException e) {
+            removeExceptionThrown = true;
+        }
+        assertTrue(removeExceptionThrown);
+        assertEquals(2, getSizeOfIterable(observerList));
+
+        boolean noElementExceptionThrown = false;
+        try {
+            it.next();
+            fail("Expecting NoSuchElementException to be thrown here.");
+        } catch (NoSuchElementException e) {
+            noElementExceptionThrown = true;
+        }
+        assertTrue(noElementExceptionThrown);
+    }
+
+    @SmallTest
+    @Feature({"Android-AppBase"})
+    public void testRewindableIterator() {
+        ObserverList<Integer> observerList = new ObserverList<Integer>();
+        observerList.addObserver(5);
+        observerList.addObserver(10);
+        observerList.addObserver(15);
+        assertEquals(3, getSizeOfIterable(observerList));
+
+        ObserverList.RewindableIterator<Integer> it = observerList.rewindableIterator();
+        assertTrue(it.hasNext());
+        assertTrue(5 == it.next());
+        assertTrue(it.hasNext());
+        assertTrue(10 == it.next());
+        assertTrue(it.hasNext());
+        assertTrue(15 == it.next());
+        assertFalse(it.hasNext());
+
+        it.rewind();
+
+        assertTrue(it.hasNext());
+        assertTrue(5 == it.next());
+        assertTrue(it.hasNext());
+        assertTrue(10 == it.next());
+        assertTrue(it.hasNext());
+        assertTrue(15 == it.next());
+        assertEquals(5, (int) observerList.mObservers.get(0));
+        observerList.removeObserver(5);
+        assertEquals(null, observerList.mObservers.get(0));
+
+        it.rewind();
+
+        assertEquals(10, (int) observerList.mObservers.get(0));
+        assertTrue(it.hasNext());
+        assertTrue(10 == it.next());
+        assertTrue(it.hasNext());
+        assertTrue(15 == it.next());
+    }
+
+    @SmallTest
+    @Feature({"Android-AppBase"})
+    public void testAddObserverReturnValue() {
+        ObserverList<Object> observerList = new ObserverList<Object>();
+
+        Object a = new Object();
+        assertTrue(observerList.addObserver(a));
+        assertFalse(observerList.addObserver(a));
+
+        Object b = new Object();
+        assertTrue(observerList.addObserver(b));
+        assertFalse(observerList.addObserver(null));
+    }
+
+    @SmallTest
+    @Feature({"Android-AppBase"})
+    public void testRemoveObserverReturnValue() {
+        ObserverList<Object> observerList = new ObserverList<Object>();
+
+        Object a = new Object();
+        Object b = new Object();
+        observerList.addObserver(a);
+        observerList.addObserver(b);
+
+        assertTrue(observerList.removeObserver(a));
+        assertFalse(observerList.removeObserver(a));
+        assertFalse(observerList.removeObserver(new Object()));
+        assertTrue(observerList.removeObserver(b));
+        assertFalse(observerList.removeObserver(null));
+
+        // If we remove an object while iterating, it will be replaced by 'null'.
+        observerList.addObserver(a);
+        assertTrue(observerList.removeObserver(a));
+        assertFalse(observerList.removeObserver(null));
+    }
+
+    @SmallTest
+    @Feature({"Android-AppBase"})
+    public void testSize() {
+        ObserverList<Object> observerList = new ObserverList<Object>();
+
+        assertEquals(0, observerList.size());
+        assertTrue(observerList.isEmpty());
+
+        observerList.addObserver(null);
+        assertEquals(0, observerList.size());
+        assertTrue(observerList.isEmpty());
+
+        Object a = new Object();
+        observerList.addObserver(a);
+        assertEquals(1, observerList.size());
+        assertFalse(observerList.isEmpty());
+
+        observerList.addObserver(a);
+        assertEquals(1, observerList.size());
+        assertFalse(observerList.isEmpty());
+
+        observerList.addObserver(null);
+        assertEquals(1, observerList.size());
+        assertFalse(observerList.isEmpty());
+
+        Object b = new Object();
+        observerList.addObserver(b);
+        assertEquals(2, observerList.size());
+        assertFalse(observerList.isEmpty());
+
+        observerList.removeObserver(null);
+        assertEquals(2, observerList.size());
+        assertFalse(observerList.isEmpty());
+
+        observerList.removeObserver(new Object());
+        assertEquals(2, observerList.size());
+        assertFalse(observerList.isEmpty());
+
+        observerList.removeObserver(b);
+        assertEquals(1, observerList.size());
+        assertFalse(observerList.isEmpty());
+
+        observerList.removeObserver(b);
+        assertEquals(1, observerList.size());
+        assertFalse(observerList.isEmpty());
+
+        observerList.removeObserver(a);
+        assertEquals(0, observerList.size());
+        assertTrue(observerList.isEmpty());
+
+        observerList.removeObserver(a);
+        observerList.removeObserver(b);
+        observerList.removeObserver(null);
+        observerList.removeObserver(new Object());
+        assertEquals(0, observerList.size());
+        assertTrue(observerList.isEmpty());
+
+        observerList.addObserver(new Object());
+        observerList.addObserver(new Object());
+        observerList.addObserver(new Object());
+        observerList.addObserver(a);
+        assertEquals(4, observerList.size());
+        assertFalse(observerList.isEmpty());
+
+        observerList.clear();
+        assertEquals(0, observerList.size());
+        assertTrue(observerList.isEmpty());
+
+        observerList.removeObserver(a);
+        observerList.removeObserver(b);
+        observerList.removeObserver(null);
+        observerList.removeObserver(new Object());
+        assertEquals(0, observerList.size());
+        assertTrue(observerList.isEmpty());
+    }
+}
diff --git a/base/android/javatests/src/org/chromium/base/metrics/RecordHistogramTest.java b/base/android/javatests/src/org/chromium/base/metrics/RecordHistogramTest.java
new file mode 100644
index 0000000..24af056
--- /dev/null
+++ b/base/android/javatests/src/org/chromium/base/metrics/RecordHistogramTest.java
@@ -0,0 +1,159 @@
+// 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.metrics;
+
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.chromium.base.library_loader.LibraryLoader;
+import org.chromium.base.library_loader.LibraryProcessType;
+import org.chromium.base.test.util.MetricsUtils.HistogramDelta;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Tests for the Java API for recording UMA histograms.
+ */
+public class RecordHistogramTest extends InstrumentationTestCase {
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        LibraryLoader.get(LibraryProcessType.PROCESS_BROWSER).ensureInitialized();
+        RecordHistogram.initialize();
+    }
+
+    /**
+     * Tests recording of boolean histograms.
+     */
+    @SmallTest
+    public void testRecordBooleanHistogram() {
+        String histogram = "HelloWorld.BooleanMetric";
+        HistogramDelta falseCount = new HistogramDelta(histogram, 0);
+        HistogramDelta trueCount = new HistogramDelta(histogram, 1);
+        assertEquals(0, trueCount.getDelta());
+        assertEquals(0, falseCount.getDelta());
+
+        RecordHistogram.recordBooleanHistogram(histogram, true);
+        assertEquals(1, trueCount.getDelta());
+        assertEquals(0, falseCount.getDelta());
+
+        RecordHistogram.recordBooleanHistogram(histogram, true);
+        assertEquals(2, trueCount.getDelta());
+        assertEquals(0, falseCount.getDelta());
+
+        RecordHistogram.recordBooleanHistogram(histogram, false);
+        assertEquals(2, trueCount.getDelta());
+        assertEquals(1, falseCount.getDelta());
+    }
+
+    /**
+     * Tests recording of enumerated histograms.
+     */
+    @SmallTest
+    public void testRecordEnumeratedHistogram() {
+        String histogram = "HelloWorld.EnumeratedMetric";
+        HistogramDelta zeroCount = new HistogramDelta(histogram, 0);
+        HistogramDelta oneCount = new HistogramDelta(histogram, 1);
+        HistogramDelta twoCount = new HistogramDelta(histogram, 2);
+        final int boundary = 3;
+
+        assertEquals(0, zeroCount.getDelta());
+        assertEquals(0, oneCount.getDelta());
+        assertEquals(0, twoCount.getDelta());
+
+        RecordHistogram.recordEnumeratedHistogram(histogram, 0, boundary);
+        assertEquals(1, zeroCount.getDelta());
+        assertEquals(0, oneCount.getDelta());
+        assertEquals(0, twoCount.getDelta());
+
+        RecordHistogram.recordEnumeratedHistogram(histogram, 0, boundary);
+        assertEquals(2, zeroCount.getDelta());
+        assertEquals(0, oneCount.getDelta());
+        assertEquals(0, twoCount.getDelta());
+
+        RecordHistogram.recordEnumeratedHistogram(histogram, 2, boundary);
+        assertEquals(2, zeroCount.getDelta());
+        assertEquals(0, oneCount.getDelta());
+        assertEquals(1, twoCount.getDelta());
+    }
+
+    /**
+     * Tests recording of count histograms.
+     */
+    @SmallTest
+    public void testRecordCountHistogram() {
+        String histogram = "HelloWorld.CountMetric";
+        HistogramDelta zeroCount = new HistogramDelta(histogram, 0);
+        HistogramDelta oneCount = new HistogramDelta(histogram, 1);
+        HistogramDelta twoCount = new HistogramDelta(histogram, 2);
+        HistogramDelta eightThousandCount = new HistogramDelta(histogram, 8000);
+
+        assertEquals(0, zeroCount.getDelta());
+        assertEquals(0, oneCount.getDelta());
+        assertEquals(0, twoCount.getDelta());
+        assertEquals(0, eightThousandCount.getDelta());
+
+        RecordHistogram.recordCountHistogram(histogram, 0);
+        assertEquals(1, zeroCount.getDelta());
+        assertEquals(0, oneCount.getDelta());
+        assertEquals(0, twoCount.getDelta());
+        assertEquals(0, eightThousandCount.getDelta());
+
+        RecordHistogram.recordCountHistogram(histogram, 0);
+        assertEquals(2, zeroCount.getDelta());
+        assertEquals(0, oneCount.getDelta());
+        assertEquals(0, twoCount.getDelta());
+        assertEquals(0, eightThousandCount.getDelta());
+
+        RecordHistogram.recordCountHistogram(histogram, 2);
+        assertEquals(2, zeroCount.getDelta());
+        assertEquals(0, oneCount.getDelta());
+        assertEquals(1, twoCount.getDelta());
+        assertEquals(0, eightThousandCount.getDelta());
+
+        RecordHistogram.recordCountHistogram(histogram, 8000);
+        assertEquals(2, zeroCount.getDelta());
+        assertEquals(0, oneCount.getDelta());
+        assertEquals(1, twoCount.getDelta());
+        assertEquals(1, eightThousandCount.getDelta());
+    }
+
+    /**
+     * Tests recording of custom times histograms.
+     */
+    @SmallTest
+    public void testRecordCustomTimesHistogram() {
+        String histogram = "HelloWorld.CustomTimesMetric";
+        HistogramDelta zeroCount = new HistogramDelta(histogram, 0);
+        HistogramDelta oneCount = new HistogramDelta(histogram, 1);
+        HistogramDelta twoCount = new HistogramDelta(histogram, 100);
+
+        assertEquals(0, zeroCount.getDelta());
+        assertEquals(0, oneCount.getDelta());
+        assertEquals(0, twoCount.getDelta());
+
+        TimeUnit milli = TimeUnit.MILLISECONDS;
+
+        RecordHistogram.recordCustomTimesHistogram(histogram, 0, 1, 100, milli, 3);
+        assertEquals(1, zeroCount.getDelta());
+        assertEquals(0, oneCount.getDelta());
+        assertEquals(0, twoCount.getDelta());
+
+        RecordHistogram.recordCustomTimesHistogram(histogram, 0, 1, 100, milli, 3);
+        assertEquals(2, zeroCount.getDelta());
+        assertEquals(0, oneCount.getDelta());
+        assertEquals(0, twoCount.getDelta());
+
+        RecordHistogram.recordCustomTimesHistogram(histogram, 95, 1, 100, milli, 3);
+        assertEquals(2, zeroCount.getDelta());
+        assertEquals(1, oneCount.getDelta());
+        assertEquals(0, twoCount.getDelta());
+
+        RecordHistogram.recordCustomTimesHistogram(histogram, 200, 1, 100, milli, 3);
+        assertEquals(2, zeroCount.getDelta());
+        assertEquals(1, oneCount.getDelta());
+        assertEquals(1, twoCount.getDelta());
+    }
+}
diff --git a/base/android/jni_android.cc b/base/android/jni_android.cc
new file mode 100644
index 0000000..5416be3
--- /dev/null
+++ b/base/android/jni_android.cc
@@ -0,0 +1,300 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/jni_android.h"
+
+#include <map>
+
+#include "base/android/build_info.h"
+#include "base/android/jni_string.h"
+#include "base/android/jni_utils.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+
+namespace {
+using base::android::GetClass;
+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.
+base::LazyInstance<base::android::ScopedJavaGlobalRef<jobject> >::Leaky
+    g_application_context = LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<base::android::ScopedJavaGlobalRef<jobject> >::Leaky
+    g_class_loader = LAZY_INSTANCE_INITIALIZER;
+jmethodID g_class_loader_load_class_method_id = 0;
+
+}  // namespace
+
+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;
+  jint ret = g_jvm->AttachCurrentThread(&env, NULL);
+  DCHECK_EQ(JNI_OK, ret);
+  return env;
+}
+
+JNIEnv* AttachCurrentThreadWithName(const std::string& thread_name) {
+  DCHECK(g_jvm);
+  JavaVMAttachArgs args;
+  args.version = JNI_VERSION_1_2;
+  args.name = thread_name.c_str();
+  args.group = NULL;
+  JNIEnv* env = NULL;
+  jint ret = g_jvm->AttachCurrentThread(&env, &args);
+  DCHECK_EQ(JNI_OK, ret);
+  return env;
+}
+
+void DetachFromVM() {
+  // Ignore the return value, if the thread is not attached, DetachCurrentThread
+  // will fail. But it is ok as the native thread may never be attached.
+  if (g_jvm)
+    g_jvm->DetachCurrentThread();
+}
+
+void InitVM(JavaVM* vm) {
+  DCHECK(!g_jvm);
+  g_jvm = vm;
+}
+
+bool IsVMInitialized() {
+  return g_jvm != NULL;
+}
+
+void InitApplicationContext(JNIEnv* env, const JavaRef<jobject>& context) {
+  if (env->IsSameObject(g_application_context.Get().obj(), context.obj())) {
+    // It's safe to set the context more than once if it's the same context.
+    return;
+  }
+  DCHECK(g_application_context.Get().is_null());
+  g_application_context.Get().Reset(context);
+}
+
+void InitReplacementClassLoader(JNIEnv* env,
+                                const JavaRef<jobject>& class_loader) {
+  DCHECK(g_class_loader.Get().is_null());
+  DCHECK(!class_loader.is_null());
+
+  ScopedJavaLocalRef<jclass> class_loader_clazz =
+      GetClass(env, "java/lang/ClassLoader");
+  CHECK(!ClearException(env));
+  g_class_loader_load_class_method_id =
+      env->GetMethodID(class_loader_clazz.obj(),
+                       "loadClass",
+                       "(Ljava/lang/String;)Ljava/lang/Class;");
+  CHECK(!ClearException(env));
+
+  DCHECK(env->IsInstanceOf(class_loader.obj(), class_loader_clazz.obj()));
+  g_class_loader.Get().Reset(class_loader);
+}
+
+const jobject GetApplicationContext() {
+  DCHECK(!g_application_context.Get().is_null());
+  return g_application_context.Get().obj();
+}
+
+ScopedJavaLocalRef<jclass> GetClass(JNIEnv* env, const char* class_name) {
+  jclass clazz;
+  if (!g_class_loader.Get().is_null()) {
+    // ClassLoader.loadClass expects a classname with components separated by
+    // dots instead of the slashes that JNIEnv::FindClass expects. The JNI
+    // generator generates names with slashes, so we have to replace them here.
+    // TODO(torne): move to an approach where we always use ClassLoader except
+    // for the special case of base::android::GetClassLoader(), and change the
+    // JNI generator to generate dot-separated names. http://crbug.com/461773
+    size_t bufsize = strlen(class_name) + 1;
+    char dotted_name[bufsize];
+    memmove(dotted_name, class_name, bufsize);
+    for (size_t i = 0; i < bufsize; ++i) {
+      if (dotted_name[i] == '/') {
+        dotted_name[i] = '.';
+      }
+    }
+
+    clazz = static_cast<jclass>(
+        env->CallObjectMethod(g_class_loader.Get().obj(),
+                              g_class_loader_load_class_method_id,
+                              ConvertUTF8ToJavaString(env, dotted_name).obj()));
+  } else {
+    clazz = env->FindClass(class_name);
+  }
+  CHECK(!ClearException(env) && clazz) << "Failed to find class " << class_name;
+  return ScopedJavaLocalRef<jclass>(env, clazz);
+}
+
+jclass LazyGetClass(
+    JNIEnv* env,
+    const char* class_name,
+    base::subtle::AtomicWord* atomic_class_id) {
+  COMPILE_ASSERT(sizeof(subtle::AtomicWord) >= sizeof(jclass),
+                 AtomicWord_SmallerThan_jMethodID);
+  subtle::AtomicWord value = base::subtle::Acquire_Load(atomic_class_id);
+  if (value)
+    return reinterpret_cast<jclass>(value);
+  ScopedJavaGlobalRef<jclass> clazz;
+  clazz.Reset(GetClass(env, class_name));
+  subtle::AtomicWord null_aw = reinterpret_cast<subtle::AtomicWord>(NULL);
+  subtle::AtomicWord cas_result = base::subtle::Release_CompareAndSwap(
+      atomic_class_id,
+      null_aw,
+      reinterpret_cast<subtle::AtomicWord>(clazz.obj()));
+  if (cas_result == null_aw) {
+    // We intentionally leak the global ref since we now storing it as a raw
+    // pointer in |atomic_class_id|.
+    return clazz.Release();
+  } else {
+    return reinterpret_cast<jclass>(cas_result);
+  }
+}
+
+template<MethodID::Type type>
+jmethodID MethodID::Get(JNIEnv* env,
+                        jclass clazz,
+                        const char* method_name,
+                        const char* jni_signature) {
+  jmethodID id = type == TYPE_STATIC ?
+      env->GetStaticMethodID(clazz, method_name, jni_signature) :
+      env->GetMethodID(clazz, method_name, jni_signature);
+  CHECK(base::android::ClearException(env) || id) <<
+      "Failed to find " <<
+      (type == TYPE_STATIC ? "static " : "") <<
+      "method " << method_name << " " << jni_signature;
+  return id;
+}
+
+// If |atomic_method_id| set, it'll return immediately. Otherwise, it'll call
+// into ::Get() above. If there's a race, it's ok since the values are the same
+// (and the duplicated effort will happen only once).
+template<MethodID::Type type>
+jmethodID MethodID::LazyGet(JNIEnv* env,
+                            jclass clazz,
+                            const char* method_name,
+                            const char* jni_signature,
+                            base::subtle::AtomicWord* atomic_method_id) {
+  COMPILE_ASSERT(sizeof(subtle::AtomicWord) >= sizeof(jmethodID),
+                 AtomicWord_SmallerThan_jMethodID);
+  subtle::AtomicWord value = base::subtle::Acquire_Load(atomic_method_id);
+  if (value)
+    return reinterpret_cast<jmethodID>(value);
+  jmethodID id = MethodID::Get<type>(env, clazz, method_name, jni_signature);
+  base::subtle::Release_Store(
+      atomic_method_id, reinterpret_cast<subtle::AtomicWord>(id));
+  return id;
+}
+
+// Various template instantiations.
+template jmethodID MethodID::Get<MethodID::TYPE_STATIC>(
+    JNIEnv* env, jclass clazz, const char* method_name,
+    const char* jni_signature);
+
+template jmethodID MethodID::Get<MethodID::TYPE_INSTANCE>(
+    JNIEnv* env, jclass clazz, const char* method_name,
+    const char* jni_signature);
+
+template jmethodID MethodID::LazyGet<MethodID::TYPE_STATIC>(
+    JNIEnv* env, jclass clazz, const char* method_name,
+    const char* jni_signature, base::subtle::AtomicWord* atomic_method_id);
+
+template jmethodID MethodID::LazyGet<MethodID::TYPE_INSTANCE>(
+    JNIEnv* env, jclass clazz, const char* method_name,
+    const char* jni_signature, base::subtle::AtomicWord* atomic_method_id);
+
+bool HasException(JNIEnv* env) {
+  return env->ExceptionCheck() != JNI_FALSE;
+}
+
+bool ClearException(JNIEnv* env) {
+  if (!HasException(env))
+    return false;
+  env->ExceptionDescribe();
+  env->ExceptionClear();
+  return true;
+}
+
+void CheckException(JNIEnv* env) {
+  if (!HasException(env))
+    return;
+
+  // Exception has been found, might as well tell breakpad about it.
+  jthrowable java_throwable = env->ExceptionOccurred();
+  if (java_throwable) {
+    // Clear the pending exception, since a local reference is now held.
+    env->ExceptionDescribe();
+    env->ExceptionClear();
+
+    // Set the exception_string in BuildInfo so that breakpad can read it.
+    // RVO should avoid any extra copies of the exception string.
+    base::android::BuildInfo::GetInstance()->SetJavaExceptionInfo(
+        GetJavaExceptionInfo(env, java_throwable));
+  }
+
+  // Now, feel good about it and die.
+  CHECK(false) << "Please include Java exception stack in crash report";
+}
+
+std::string GetJavaExceptionInfo(JNIEnv* env, jthrowable java_throwable) {
+  ScopedJavaLocalRef<jclass> throwable_clazz =
+      GetClass(env, "java/lang/Throwable");
+  jmethodID throwable_printstacktrace =
+      MethodID::Get<MethodID::TYPE_INSTANCE>(
+          env, throwable_clazz.obj(), "printStackTrace",
+          "(Ljava/io/PrintStream;)V");
+
+  // Create an instance of ByteArrayOutputStream.
+  ScopedJavaLocalRef<jclass> bytearray_output_stream_clazz =
+      GetClass(env, "java/io/ByteArrayOutputStream");
+  jmethodID bytearray_output_stream_constructor =
+      MethodID::Get<MethodID::TYPE_INSTANCE>(
+          env, bytearray_output_stream_clazz.obj(), "<init>", "()V");
+  jmethodID bytearray_output_stream_tostring =
+      MethodID::Get<MethodID::TYPE_INSTANCE>(
+          env, bytearray_output_stream_clazz.obj(), "toString",
+          "()Ljava/lang/String;");
+  ScopedJavaLocalRef<jobject> bytearray_output_stream(env,
+      env->NewObject(bytearray_output_stream_clazz.obj(),
+                     bytearray_output_stream_constructor));
+
+  // Create an instance of PrintStream.
+  ScopedJavaLocalRef<jclass> printstream_clazz =
+      GetClass(env, "java/io/PrintStream");
+  jmethodID printstream_constructor =
+      MethodID::Get<MethodID::TYPE_INSTANCE>(
+          env, printstream_clazz.obj(), "<init>",
+          "(Ljava/io/OutputStream;)V");
+  ScopedJavaLocalRef<jobject> printstream(env,
+      env->NewObject(printstream_clazz.obj(), printstream_constructor,
+                     bytearray_output_stream.obj()));
+
+  // Call Throwable.printStackTrace(PrintStream)
+  env->CallVoidMethod(java_throwable, throwable_printstacktrace,
+      printstream.obj());
+
+  // Call ByteArrayOutputStream.toString()
+  ScopedJavaLocalRef<jstring> exception_string(
+      env, static_cast<jstring>(
+          env->CallObjectMethod(bytearray_output_stream.obj(),
+                                bytearray_output_stream_tostring)));
+
+  return ConvertJavaStringToUTF8(exception_string);
+}
+
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/jni_android.h b/base/android/jni_android.h
new file mode 100644
index 0000000..9df9041
--- /dev/null
+++ b/base/android/jni_android.h
@@ -0,0 +1,140 @@
+// Copyright (c) 2012 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_ANDROID_H_
+#define BASE_ANDROID_JNI_ANDROID_H_
+
+#include <jni.h>
+#include <sys/types.h>
+
+#include <string>
+
+#include "base/android/scoped_java_ref.h"
+#include "base/atomicops.h"
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+
+namespace base {
+namespace android {
+
+// 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;
+  bool (*func)(JNIEnv* env);
+};
+
+// Attaches the current thread to the VM (if necessary) and return the JNIEnv*.
+BASE_EXPORT JNIEnv* AttachCurrentThread();
+
+// Same to AttachCurrentThread except that thread name will be set to
+// |thread_name| if it is the first call. Otherwise, thread_name won't be
+// changed. AttachCurrentThread() doesn't regard underlying platform thread
+// name, but just resets it to "Thread-???". This function should be called
+// right after new thread is created if it is important to keep thread name.
+BASE_EXPORT JNIEnv* AttachCurrentThreadWithName(const std::string& thread_name);
+
+// Detaches the current thread from VM if it is attached.
+BASE_EXPORT void DetachFromVM();
+
+// Initializes the global JVM. It is not necessarily called before
+// InitApplicationContext().
+BASE_EXPORT void InitVM(JavaVM* vm);
+
+// Returns true if the global JVM has been initialized.
+BASE_EXPORT bool IsVMInitialized();
+
+// Initializes the global application context object. The |context| can be any
+// valid reference to the application context. Internally holds a global ref to
+// the context. InitVM and InitApplicationContext maybe called in either order.
+BASE_EXPORT void InitApplicationContext(JNIEnv* env,
+                                        const JavaRef<jobject>& context);
+
+// Initializes the global ClassLoader used by the GetClass and LazyGetClass
+// methods. This is needed because JNI will use the base ClassLoader when there
+// is no Java code on the stack. The base ClassLoader doesn't know about any of
+// the application classes and will fail to lookup anything other than system
+// classes.
+BASE_EXPORT void InitReplacementClassLoader(
+    JNIEnv* env,
+    const JavaRef<jobject>& class_loader);
+
+// Gets a global ref to the application context set with
+// InitApplicationContext(). Ownership is retained by the function - the caller
+// must NOT release it.
+const BASE_EXPORT jobject GetApplicationContext();
+
+// Finds the class named |class_name| and returns it.
+// Use this method instead of invoking directly the JNI FindClass method (to
+// prevent leaking local references).
+// This method triggers a fatal assertion if the class could not be found.
+// Use HasClass if you need to check whether the class exists.
+BASE_EXPORT ScopedJavaLocalRef<jclass> GetClass(JNIEnv* env,
+                                                const char* class_name);
+
+// The method will initialize |atomic_class_id| to contain a global ref to the
+// class. And will return that ref on subsequent calls.  It's the caller's
+// responsibility to release the ref when it is no longer needed.
+// The caller is responsible to zero-initialize |atomic_method_id|.
+// It's fine to simultaneously call this on multiple threads referencing the
+// same |atomic_method_id|.
+BASE_EXPORT jclass LazyGetClass(
+    JNIEnv* env,
+    const char* class_name,
+    base::subtle::AtomicWord* atomic_class_id);
+
+// This class is a wrapper for JNIEnv Get(Static)MethodID.
+class BASE_EXPORT MethodID {
+ public:
+  enum Type {
+    TYPE_STATIC,
+    TYPE_INSTANCE,
+  };
+
+  // Returns the method ID for the method with the specified name and signature.
+  // This method triggers a fatal assertion if the method could not be found.
+  template<Type type>
+  static jmethodID Get(JNIEnv* env,
+                       jclass clazz,
+                       const char* method_name,
+                       const char* jni_signature);
+
+  // The caller is responsible to zero-initialize |atomic_method_id|.
+  // It's fine to simultaneously call this on multiple threads referencing the
+  // same |atomic_method_id|.
+  template<Type type>
+  static jmethodID LazyGet(JNIEnv* env,
+                           jclass clazz,
+                           const char* method_name,
+                           const char* jni_signature,
+                           base::subtle::AtomicWord* atomic_method_id);
+};
+
+// Returns true if an exception is pending in the provided JNIEnv*.
+BASE_EXPORT bool HasException(JNIEnv* env);
+
+// If an exception is pending in the provided JNIEnv*, this function clears it
+// and returns true.
+BASE_EXPORT bool ClearException(JNIEnv* env);
+
+// This function will call CHECK() macro if there's any pending exception.
+BASE_EXPORT void CheckException(JNIEnv* env);
+
+// This returns a string representation of the java stack trace.
+BASE_EXPORT std::string GetJavaExceptionInfo(JNIEnv* env,
+                                             jthrowable java_throwable);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_JNI_ANDROID_H_
diff --git a/base/android/jni_android_unittest.cc b/base/android/jni_android_unittest.cc
new file mode 100644
index 0000000..dabd480
--- /dev/null
+++ b/base/android/jni_android_unittest.cc
@@ -0,0 +1,61 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/jni_android.h"
+
+#include "base/at_exit.h"
+#include "base/logging.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace android {
+
+namespace {
+
+base::subtle::AtomicWord g_atomic_id = 0;
+int LazyMethodIDCall(JNIEnv* env, jclass clazz, int p) {
+  jmethodID id = base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, clazz,
+      "abs",
+      "(I)I",
+      &g_atomic_id);
+
+  return env->CallStaticIntMethod(clazz, id, p);
+}
+
+int MethodIDCall(JNIEnv* env, jclass clazz, jmethodID id, int p) {
+  return env->CallStaticIntMethod(clazz, id, p);
+}
+
+}  // namespace
+
+TEST(JNIAndroidMicrobenchmark, MethodId) {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jclass> clazz(GetClass(env, "java/lang/Math"));
+  base::Time start_lazy = base::Time::Now();
+  int o = 0;
+  for (int i = 0; i < 1024; ++i)
+    o += LazyMethodIDCall(env, clazz.obj(), i);
+  base::Time end_lazy = base::Time::Now();
+
+  jmethodID id = reinterpret_cast<jmethodID>(g_atomic_id);
+  base::Time start = base::Time::Now();
+  for (int i = 0; i < 1024; ++i)
+    o += MethodIDCall(env, clazz.obj(), id, i);
+  base::Time end = base::Time::Now();
+
+  // On a Galaxy Nexus, results were in the range of:
+  // JNI LazyMethodIDCall (us) 1984
+  // JNI MethodIDCall (us) 1861
+  LOG(ERROR) << "JNI LazyMethodIDCall (us) " <<
+      base::TimeDelta(end_lazy - start_lazy).InMicroseconds();
+  LOG(ERROR) << "JNI MethodIDCall (us) " <<
+      base::TimeDelta(end - start).InMicroseconds();
+  LOG(ERROR) << "JNI " << o;
+}
+
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/jni_array.cc b/base/android/jni_array.cc
new file mode 100644
index 0000000..1bbc669
--- /dev/null
+++ b/base/android/jni_array.cc
@@ -0,0 +1,229 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/jni_array.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/logging.h"
+
+namespace base {
+namespace android {
+namespace {
+
+// As |GetArrayLength| makes no guarantees about the returned value (e.g., it
+// may be -1 if |array| is not a valid Java array), provide a safe wrapper
+// that always returns a valid, non-negative size.
+template <typename JavaArrayType>
+size_t SafeGetArrayLength(JNIEnv* env, JavaArrayType jarray) {
+  DCHECK(jarray);
+  jsize length = env->GetArrayLength(jarray);
+  DCHECK_GE(length, 0) << "Invalid array length: " << length;
+  return static_cast<size_t>(std::max(0, length));
+}
+
+}  // namespace
+
+ScopedJavaLocalRef<jbyteArray> ToJavaByteArray(
+    JNIEnv* env, const uint8* bytes, size_t len) {
+  jbyteArray byte_array = env->NewByteArray(len);
+  CheckException(env);
+  DCHECK(byte_array);
+
+  env->SetByteArrayRegion(
+      byte_array, 0, len, reinterpret_cast<const jbyte*>(bytes));
+  CheckException(env);
+
+  return ScopedJavaLocalRef<jbyteArray>(env, byte_array);
+}
+
+ScopedJavaLocalRef<jintArray> ToJavaIntArray(
+    JNIEnv* env, const int* ints, size_t len) {
+  jintArray int_array = env->NewIntArray(len);
+  CheckException(env);
+  DCHECK(int_array);
+
+  env->SetIntArrayRegion(
+      int_array, 0, len, reinterpret_cast<const jint*>(ints));
+  CheckException(env);
+
+  return ScopedJavaLocalRef<jintArray>(env, int_array);
+}
+
+ScopedJavaLocalRef<jintArray> ToJavaIntArray(
+    JNIEnv* env, const std::vector<int>& ints) {
+  return ToJavaIntArray(env, ints.data(), ints.size());
+}
+
+ScopedJavaLocalRef<jlongArray> ToJavaLongArray(
+    JNIEnv* env, const int64* longs, size_t len) {
+  jlongArray long_array = env->NewLongArray(len);
+  CheckException(env);
+  DCHECK(long_array);
+
+  env->SetLongArrayRegion(
+      long_array, 0, len, reinterpret_cast<const jlong*>(longs));
+  CheckException(env);
+
+  return ScopedJavaLocalRef<jlongArray>(env, long_array);
+}
+
+// Returns a new Java long array converted from the given int64 array.
+BASE_EXPORT ScopedJavaLocalRef<jlongArray> ToJavaLongArray(
+    JNIEnv* env, const std::vector<int64>& longs) {
+  return ToJavaLongArray(env, longs.data(), longs.size());
+}
+
+ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfByteArray(
+    JNIEnv* env, const std::vector<std::string>& v) {
+  ScopedJavaLocalRef<jclass> byte_array_clazz = GetClass(env, "[B");
+  jobjectArray joa = env->NewObjectArray(v.size(),
+                                         byte_array_clazz.obj(), NULL);
+  CheckException(env);
+
+  for (size_t i = 0; i < v.size(); ++i) {
+    ScopedJavaLocalRef<jbyteArray> byte_array = ToJavaByteArray(env,
+        reinterpret_cast<const uint8*>(v[i].data()), v[i].length());
+    env->SetObjectArrayElement(joa, i, byte_array.obj());
+  }
+  return ScopedJavaLocalRef<jobjectArray>(env, joa);
+}
+
+ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfStrings(
+    JNIEnv* env, const std::vector<std::string>& v) {
+  ScopedJavaLocalRef<jclass> string_clazz = GetClass(env, "java/lang/String");
+  jobjectArray joa = env->NewObjectArray(v.size(), string_clazz.obj(), NULL);
+  CheckException(env);
+
+  for (size_t i = 0; i < v.size(); ++i) {
+    ScopedJavaLocalRef<jstring> item = ConvertUTF8ToJavaString(env, v[i]);
+    env->SetObjectArrayElement(joa, i, item.obj());
+  }
+  return ScopedJavaLocalRef<jobjectArray>(env, joa);
+}
+
+ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfStrings(
+    JNIEnv* env, const std::vector<string16>& v) {
+  ScopedJavaLocalRef<jclass> string_clazz = GetClass(env, "java/lang/String");
+  jobjectArray joa = env->NewObjectArray(v.size(), string_clazz.obj(), NULL);
+  CheckException(env);
+
+  for (size_t i = 0; i < v.size(); ++i) {
+    ScopedJavaLocalRef<jstring> item = ConvertUTF16ToJavaString(env, v[i]);
+    env->SetObjectArrayElement(joa, i, item.obj());
+  }
+  return ScopedJavaLocalRef<jobjectArray>(env, joa);
+}
+
+void AppendJavaStringArrayToStringVector(JNIEnv* env,
+                                         jobjectArray array,
+                                         std::vector<string16>* out) {
+  DCHECK(out);
+  if (!array)
+    return;
+  size_t len = SafeGetArrayLength(env, array);
+  size_t back = out->size();
+  out->resize(back + len);
+  for (size_t i = 0; i < len; ++i) {
+    ScopedJavaLocalRef<jstring> str(env,
+        static_cast<jstring>(env->GetObjectArrayElement(array, i)));
+    ConvertJavaStringToUTF16(env, str.obj(), &((*out)[back + i]));
+  }
+}
+
+void AppendJavaStringArrayToStringVector(JNIEnv* env,
+                                         jobjectArray array,
+                                         std::vector<std::string>* out) {
+  DCHECK(out);
+  if (!array)
+    return;
+  size_t len = SafeGetArrayLength(env, array);
+  size_t back = out->size();
+  out->resize(back + len);
+  for (size_t i = 0; i < len; ++i) {
+    ScopedJavaLocalRef<jstring> str(env,
+        static_cast<jstring>(env->GetObjectArrayElement(array, i)));
+    ConvertJavaStringToUTF8(env, str.obj(), &((*out)[back + i]));
+  }
+}
+
+void AppendJavaByteArrayToByteVector(JNIEnv* env,
+                                     jbyteArray byte_array,
+                                     std::vector<uint8>* out) {
+  DCHECK(out);
+  if (!byte_array)
+    return;
+  size_t len = SafeGetArrayLength(env, byte_array);
+  if (!len)
+    return;
+  size_t back = out->size();
+  out->resize(back + len);
+  env->GetByteArrayRegion(byte_array, 0, len,
+                          reinterpret_cast<int8*>(&(*out)[back]));
+}
+
+void JavaByteArrayToByteVector(JNIEnv* env,
+                               jbyteArray byte_array,
+                               std::vector<uint8>* out) {
+  DCHECK(out);
+  DCHECK(byte_array);
+  out->clear();
+  AppendJavaByteArrayToByteVector(env, byte_array, out);
+}
+
+void JavaIntArrayToIntVector(JNIEnv* env,
+                             jintArray int_array,
+                             std::vector<int>* out) {
+  DCHECK(out);
+  size_t len = SafeGetArrayLength(env, int_array);
+  out->resize(len);
+  if (!len)
+    return;
+  // TODO(jdduke): Use |out->data()| for pointer access after switch to libc++,
+  // both here and in the other conversion routines. See crbug.com/427718.
+  env->GetIntArrayRegion(int_array, 0, len, &(*out)[0]);
+}
+
+void JavaLongArrayToLongVector(JNIEnv* env,
+                               jlongArray long_array,
+                               std::vector<jlong>* out) {
+  DCHECK(out);
+  size_t len = SafeGetArrayLength(env, long_array);
+  out->resize(len);
+  if (!len)
+    return;
+  env->GetLongArrayRegion(long_array, 0, len, &(*out)[0]);
+}
+
+void JavaFloatArrayToFloatVector(JNIEnv* env,
+                                 jfloatArray float_array,
+                                 std::vector<float>* out) {
+  DCHECK(out);
+  size_t len = SafeGetArrayLength(env, float_array);
+  out->resize(len);
+  if (!len)
+    return;
+  env->GetFloatArrayRegion(float_array, 0, len, &(*out)[0]);
+}
+
+void JavaArrayOfByteArrayToStringVector(
+    JNIEnv* env,
+    jobjectArray array,
+    std::vector<std::string>* out) {
+  DCHECK(out);
+  size_t len = SafeGetArrayLength(env, array);
+  out->resize(len);
+  for (size_t i = 0; i < len; ++i) {
+    ScopedJavaLocalRef<jbyteArray> bytes_array(
+        env, static_cast<jbyteArray>(
+            env->GetObjectArrayElement(array, i)));
+    jsize bytes_len = env->GetArrayLength(bytes_array.obj());
+    jbyte* bytes = env->GetByteArrayElements(bytes_array.obj(), NULL);
+    (*out)[i].assign(reinterpret_cast<const char*>(bytes), bytes_len);
+    env->ReleaseByteArrayElements(bytes_array.obj(), bytes, JNI_ABORT);
+  }
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/jni_array.h b/base/android/jni_array.h
new file mode 100644
index 0000000..0d7ec2e
--- /dev/null
+++ b/base/android/jni_array.h
@@ -0,0 +1,99 @@
+// Copyright (c) 2012 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_ARRAY_H_
+#define BASE_ANDROID_JNI_ARRAY_H_
+
+#include <jni.h>
+#include <string>
+#include <vector>
+
+#include "base/android/scoped_java_ref.h"
+#include "base/basictypes.h"
+#include "base/strings/string16.h"
+
+namespace base {
+namespace android {
+
+// Returns a new Java byte array converted from the given bytes array.
+BASE_EXPORT ScopedJavaLocalRef<jbyteArray> ToJavaByteArray(
+    JNIEnv* env, const uint8* bytes, size_t len);
+
+// Returns a new Java int array converted from the given int array.
+BASE_EXPORT ScopedJavaLocalRef<jintArray> ToJavaIntArray(
+    JNIEnv* env, const int* ints, size_t len);
+
+BASE_EXPORT ScopedJavaLocalRef<jintArray> ToJavaIntArray(
+    JNIEnv* env, const std::vector<int>& ints);
+
+// Returns a new Java long array converted from the given int64 array.
+BASE_EXPORT ScopedJavaLocalRef<jlongArray> ToJavaLongArray(
+    JNIEnv* env, const int64* longs, size_t len);
+
+BASE_EXPORT ScopedJavaLocalRef<jlongArray> ToJavaLongArray(
+    JNIEnv* env, const std::vector<int64>& longs);
+
+// Returns a array of Java byte array converted from |v|.
+BASE_EXPORT ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfByteArray(
+    JNIEnv* env, const std::vector<std::string>& v);
+
+BASE_EXPORT ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfStrings(
+    JNIEnv* env,  const std::vector<std::string>& v);
+
+BASE_EXPORT ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfStrings(
+    JNIEnv* env,  const std::vector<string16>& v);
+
+// Converts a Java string array to a native array.
+BASE_EXPORT void AppendJavaStringArrayToStringVector(
+    JNIEnv* env,
+    jobjectArray array,
+    std::vector<string16>* out);
+
+BASE_EXPORT void AppendJavaStringArrayToStringVector(
+    JNIEnv* env,
+    jobjectArray array,
+    std::vector<std::string>* out);
+
+// Appends the Java bytes in |bytes_array| onto the end of |out|.
+BASE_EXPORT void AppendJavaByteArrayToByteVector(
+    JNIEnv* env,
+    jbyteArray byte_array,
+    std::vector<uint8>* out);
+
+// Replaces the content of |out| with the Java bytes in |bytes_array|.
+BASE_EXPORT void JavaByteArrayToByteVector(
+    JNIEnv* env,
+    jbyteArray byte_array,
+    std::vector<uint8>* out);
+
+// Replaces the content of |out| with the Java ints in |int_array|.
+BASE_EXPORT void JavaIntArrayToIntVector(
+    JNIEnv* env,
+    jintArray int_array,
+    std::vector<int>* out);
+
+// Replaces the content of |out| with the Java longs in |long_array|.
+BASE_EXPORT void JavaLongArrayToLongVector(
+    JNIEnv* env,
+    jlongArray long_array,
+    std::vector<jlong>* out);
+
+// Replaces the content of |out| with the Java floats in |float_array|.
+BASE_EXPORT void JavaFloatArrayToFloatVector(
+    JNIEnv* env,
+    jfloatArray float_array,
+    std::vector<float>* out);
+
+// Assuming |array| is an byte[][] (array of byte arrays), replaces the
+// content of |out| with the corresponding vector of strings. No UTF-8
+// conversion is performed.
+BASE_EXPORT void JavaArrayOfByteArrayToStringVector(
+    JNIEnv* env,
+    jobjectArray array,
+    std::vector<std::string>* out);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_JNI_ARRAY_H_
diff --git a/base/android/jni_array_unittest.cc b/base/android/jni_array_unittest.cc
new file mode 100644
index 0000000..7cb896c
--- /dev/null
+++ b/base/android/jni_array_unittest.cc
@@ -0,0 +1,179 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/jni_array.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace android {
+
+TEST(JniArray, BasicConversions) {
+  const uint8 kBytes[] = { 0, 1, 2, 3 };
+  const size_t kLen = arraysize(kBytes);
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jbyteArray> bytes = ToJavaByteArray(env, kBytes, kLen);
+  ASSERT_TRUE(bytes.obj());
+
+  std::vector<uint8> vec(5);
+  JavaByteArrayToByteVector(env, bytes.obj(), &vec);
+  EXPECT_EQ(4U, vec.size());
+  std::vector<uint8> expected_vec(kBytes, kBytes + kLen);
+  EXPECT_EQ(expected_vec, vec);
+
+  AppendJavaByteArrayToByteVector(env, bytes.obj(), &vec);
+  EXPECT_EQ(8U, vec.size());
+  expected_vec.insert(expected_vec.end(), kBytes, kBytes + kLen);
+  EXPECT_EQ(expected_vec, vec);
+}
+
+void CheckIntConversion(
+    JNIEnv* env,
+    const int* int_array,
+    const size_t len,
+    const ScopedJavaLocalRef<jintArray>& ints) {
+  ASSERT_TRUE(ints.obj());
+
+  jsize java_array_len = env->GetArrayLength(ints.obj());
+  ASSERT_EQ(static_cast<jsize>(len), java_array_len);
+
+  jint value;
+  for (size_t i = 0; i < len; ++i) {
+    env->GetIntArrayRegion(ints.obj(), i, 1, &value);
+    ASSERT_EQ(int_array[i], value);
+  }
+}
+
+TEST(JniArray, IntConversions) {
+  const int kInts[] = { 0, 1, -1, kint32min, kint32max};
+  const size_t kLen = arraysize(kInts);
+
+  JNIEnv* env = AttachCurrentThread();
+  CheckIntConversion(env, kInts, kLen, ToJavaIntArray(env, kInts, kLen));
+
+  const std::vector<int> vec(kInts, kInts + kLen);
+  CheckIntConversion(env, kInts, kLen, ToJavaIntArray(env, vec));
+}
+
+void CheckLongConversion(
+    JNIEnv* env,
+    const int64* long_array,
+    const size_t len,
+    const ScopedJavaLocalRef<jlongArray>& longs) {
+  ASSERT_TRUE(longs.obj());
+
+  jsize java_array_len = env->GetArrayLength(longs.obj());
+  ASSERT_EQ(static_cast<jsize>(len), java_array_len);
+
+  jlong value;
+  for (size_t i = 0; i < len; ++i) {
+    env->GetLongArrayRegion(longs.obj(), i, 1, &value);
+    ASSERT_EQ(long_array[i], value);
+  }
+}
+
+TEST(JniArray, LongConversions) {
+  const int64 kLongs[] = { 0, 1, -1, kint64min, kint64max};
+  const size_t kLen = arraysize(kLongs);
+
+  JNIEnv* env = AttachCurrentThread();
+  CheckLongConversion(env, kLongs, kLen, ToJavaLongArray(env, kLongs, kLen));
+
+  const std::vector<int64> vec(kLongs, kLongs + kLen);
+  CheckLongConversion(env, kLongs, kLen, ToJavaLongArray(env, vec));
+}
+
+TEST(JniArray, JavaIntArrayToIntVector) {
+  const int kInts[] = {0, 1, -1};
+  const size_t kLen = arraysize(kInts);
+
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jintArray> jints(env, env->NewIntArray(kLen));
+  ASSERT_TRUE(jints.obj());
+
+  for (size_t i = 0; i < kLen; ++i) {
+    jint j = static_cast<jint>(kInts[i]);
+    env->SetIntArrayRegion(jints.obj(), i, 1, &j);
+    ASSERT_FALSE(HasException(env));
+  }
+
+  std::vector<int> ints;
+  JavaIntArrayToIntVector(env, jints.obj(), &ints);
+
+  ASSERT_EQ(static_cast<jsize>(ints.size()), env->GetArrayLength(jints.obj()));
+
+  jint value;
+  for (size_t i = 0; i < kLen; ++i) {
+    env->GetIntArrayRegion(jints.obj(), i, 1, &value);
+    ASSERT_EQ(ints[i], value);
+  }
+}
+
+TEST(JniArray, JavaFloatArrayToFloatVector) {
+  const float kFloats[] = {0.0, 0.5, -0.5};
+  const size_t kLen = arraysize(kFloats);
+
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jfloatArray> jfloats(env, env->NewFloatArray(kLen));
+  ASSERT_TRUE(jfloats.obj());
+
+  for (size_t i = 0; i < kLen; ++i) {
+    jfloat j = static_cast<jfloat>(kFloats[i]);
+    env->SetFloatArrayRegion(jfloats.obj(), i, 1, &j);
+    ASSERT_FALSE(HasException(env));
+  }
+
+  std::vector<float> floats;
+  JavaFloatArrayToFloatVector(env, jfloats.obj(), &floats);
+
+  ASSERT_EQ(static_cast<jsize>(floats.size()),
+      env->GetArrayLength(jfloats.obj()));
+
+  jfloat value;
+  for (size_t i = 0; i < kLen; ++i) {
+    env->GetFloatArrayRegion(jfloats.obj(), i, 1, &value);
+    ASSERT_EQ(floats[i], value);
+  }
+}
+
+TEST(JniArray, JavaArrayOfByteArrayToStringVector) {
+  const int kMaxItems = 50;
+  JNIEnv* env = AttachCurrentThread();
+
+  // Create a byte[][] object.
+  ScopedJavaLocalRef<jclass> byte_array_clazz(env, env->FindClass("[B"));
+  ASSERT_TRUE(byte_array_clazz.obj());
+
+  ScopedJavaLocalRef<jobjectArray> array(
+      env, env->NewObjectArray(kMaxItems, byte_array_clazz.obj(), NULL));
+  ASSERT_TRUE(array.obj());
+
+  // Create kMaxItems byte buffers.
+  char text[16];
+  for (int i = 0; i < kMaxItems; ++i) {
+    snprintf(text, sizeof text, "%d", i);
+    ScopedJavaLocalRef<jbyteArray> byte_array = ToJavaByteArray(
+        env, reinterpret_cast<uint8*>(text),
+        static_cast<size_t>(strlen(text)));
+    ASSERT_TRUE(byte_array.obj());
+
+    env->SetObjectArrayElement(array.obj(), i, byte_array.obj());
+    ASSERT_FALSE(HasException(env));
+  }
+
+  // Convert to std::vector<std::string>, check the content.
+  std::vector<std::string> vec;
+  JavaArrayOfByteArrayToStringVector(env, array.obj(), &vec);
+
+  EXPECT_EQ(static_cast<size_t>(kMaxItems), vec.size());
+  for (int i = 0; i < kMaxItems; ++i) {
+    snprintf(text, sizeof text, "%d", i);
+    EXPECT_STREQ(text, vec[i].c_str());
+  }
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/jni_generator/android_jar.classes b/base/android/jni_generator/android_jar.classes
new file mode 100644
index 0000000..7d412ce
--- /dev/null
+++ b/base/android/jni_generator/android_jar.classes
@@ -0,0 +1,98 @@
+java/lang/AbstractMethodError.class
+java/lang/AbstractStringBuilder.class
+java/lang/Appendable.class
+java/lang/ArithmeticException.class
+java/lang/ArrayIndexOutOfBoundsException.class
+java/lang/ArrayStoreException.class
+java/lang/AssertionError.class
+java/lang/AutoCloseable.class
+java/lang/Boolean.class
+java/lang/Byte.class
+java/lang/Character.class
+java/lang/Character$Subset.class
+java/lang/Character$UnicodeBlock.class
+java/lang/CharSequence.class
+java/lang/ClassCastException.class
+java/lang/ClassCircularityError.class
+java/lang/Class.class
+java/lang/ClassFormatError.class
+java/lang/ClassLoader.class
+java/lang/ClassNotFoundException.class
+java/lang/Cloneable.class
+java/lang/CloneNotSupportedException.class
+java/lang/Comparable.class
+java/lang/Compiler.class
+java/lang/Deprecated.class
+java/lang/Double.class
+java/lang/Enum.class
+java/lang/EnumConstantNotPresentException.class
+java/lang/Error.class
+java/lang/Exception.class
+java/lang/ExceptionInInitializerError.class
+java/lang/Float.class
+java/lang/IllegalAccessError.class
+java/lang/IllegalAccessException.class
+java/lang/IllegalArgumentException.class
+java/lang/IllegalMonitorStateException.class
+java/lang/IllegalStateException.class
+java/lang/IncompatibleClassChangeError.class
+java/lang/IndexOutOfBoundsException.class
+java/lang/InheritableThreadLocal.class
+java/lang/InstantiationError.class
+java/lang/InstantiationException.class
+java/lang/Integer.class
+java/lang/InternalError.class
+java/lang/InterruptedException.class
+java/lang/Iterable.class
+java/lang/LinkageError.class
+java/lang/Long.class
+java/lang/Math.class
+java/lang/NegativeArraySizeException.class
+java/lang/NoClassDefFoundError.class
+java/lang/NoSuchFieldError.class
+java/lang/NoSuchFieldException.class
+java/lang/NoSuchMethodError.class
+java/lang/NoSuchMethodException.class
+java/lang/NullPointerException.class
+java/lang/Number.class
+java/lang/NumberFormatException.class
+java/lang/Object.class
+java/lang/OutOfMemoryError.class
+java/lang/Override.class
+java/lang/Package.class
+java/lang/ProcessBuilder.class
+java/lang/Process.class
+java/lang/Readable.class
+java/lang/ReflectiveOperationException.class
+java/lang/Runnable.class
+java/lang/Runtime.class
+java/lang/RuntimeException.class
+java/lang/RuntimePermission.class
+java/lang/SafeVarargs.class
+java/lang/SecurityException.class
+java/lang/SecurityManager.class
+java/lang/Short.class
+java/lang/StackOverflowError.class
+java/lang/StackTraceElement.class
+java/lang/StrictMath.class
+java/lang/StringBuffer.class
+java/lang/StringBuilder.class
+java/lang/String.class
+java/lang/StringIndexOutOfBoundsException.class
+java/lang/SuppressWarnings.class
+java/lang/System.class
+java/lang/Thread.class
+java/lang/ThreadDeath.class
+java/lang/ThreadGroup.class
+java/lang/ThreadLocal.class
+java/lang/Thread$State.class
+java/lang/Thread$UncaughtExceptionHandler.class
+java/lang/Throwable.class
+java/lang/TypeNotPresentException.class
+java/lang/UnknownError.class
+java/lang/UnsatisfiedLinkError.class
+java/lang/UnsupportedClassVersionError.class
+java/lang/UnsupportedOperationException.class
+java/lang/VerifyError.class
+java/lang/VirtualMachineError.class
+java/lang/Void.class
diff --git a/base/android/jni_generator/golden_sample_for_tests_jni.h b/base/android/jni_generator/golden_sample_for_tests_jni.h
new file mode 100644
index 0000000..ba7494e
--- /dev/null
+++ b/base/android/jni_generator/golden_sample_for_tests_jni.h
@@ -0,0 +1,400 @@
+// 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 kInnerStructAClassPath[] =
+    "org/chromium/example/jni_generator/SampleForTests$InnerStructA";
+const char kSampleForTestsClassPath[] =
+    "org/chromium/example/jni_generator/SampleForTests";
+const char kInnerStructBClassPath[] =
+    "org/chromium/example/jni_generator/SampleForTests$InnerStructB";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_InnerStructA_clazz = NULL;
+#define InnerStructA_clazz(env) g_InnerStructA_clazz
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_SampleForTests_clazz = NULL;
+#define SampleForTests_clazz(env) g_SampleForTests_clazz
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_InnerStructB_clazz = NULL;
+#define InnerStructB_clazz(env) g_InnerStructB_clazz
+
+}  // namespace
+
+namespace base {
+namespace android {
+
+static jlong Init(JNIEnv* env, jobject jcaller,
+    jstring param);
+
+static jdouble GetDoubleFunction(JNIEnv* env, jobject jcaller);
+
+static jfloat GetFloatFunction(JNIEnv* env, jclass jcaller);
+
+static void SetNonPODDatatype(JNIEnv* env, jobject jcaller,
+    jobject rect);
+
+static jobject GetNonPODDatatype(JNIEnv* env, jobject jcaller);
+
+// Step 2: method stubs.
+static void Destroy(JNIEnv* env, jobject jcaller,
+    jlong nativeCPPClass) {
+  CPPClass* native = reinterpret_cast<CPPClass*>(nativeCPPClass);
+  CHECK_NATIVE_PTR(env, jcaller, native, "Destroy");
+  return native->Destroy(env, jcaller);
+}
+
+static jint Method(JNIEnv* env, jobject jcaller,
+    jlong nativeCPPClass) {
+  CPPClass* native = reinterpret_cast<CPPClass*>(nativeCPPClass);
+  CHECK_NATIVE_PTR(env, jcaller, native, "Method", 0);
+  return native->Method(env, jcaller);
+}
+
+static jdouble MethodOtherP0(JNIEnv* env, jobject jcaller,
+    jlong nativePtr) {
+  CPPClass::InnerClass* native =
+      reinterpret_cast<CPPClass::InnerClass*>(nativePtr);
+  CHECK_NATIVE_PTR(env, jcaller, native, "MethodOtherP0", 0);
+  return native->MethodOtherP0(env, jcaller);
+}
+
+static void AddStructB(JNIEnv* env, jobject jcaller,
+    jlong nativeCPPClass,
+    jobject b) {
+  CPPClass* native = reinterpret_cast<CPPClass*>(nativeCPPClass);
+  CHECK_NATIVE_PTR(env, jcaller, native, "AddStructB");
+  return native->AddStructB(env, jcaller, b);
+}
+
+static void IterateAndDoSomethingWithStructB(JNIEnv* env, jobject jcaller,
+    jlong nativeCPPClass) {
+  CPPClass* native = reinterpret_cast<CPPClass*>(nativeCPPClass);
+  CHECK_NATIVE_PTR(env, jcaller, native, "IterateAndDoSomethingWithStructB");
+  return native->IterateAndDoSomethingWithStructB(env, jcaller);
+}
+
+static jstring ReturnAString(JNIEnv* env, jobject jcaller,
+    jlong nativeCPPClass) {
+  CPPClass* native = reinterpret_cast<CPPClass*>(nativeCPPClass);
+  CHECK_NATIVE_PTR(env, jcaller, native, "ReturnAString", NULL);
+  return native->ReturnAString(env, jcaller).Release();
+}
+
+static base::subtle::AtomicWord g_SampleForTests_javaMethod = 0;
+static jint Java_SampleForTests_javaMethod(JNIEnv* env, jobject obj,
+    JniIntWrapper foo,
+    JniIntWrapper bar) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      SampleForTests_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, SampleForTests_clazz(env),
+      "javaMethod",
+
+"("
+"I"
+"I"
+")"
+"I",
+      &g_SampleForTests_javaMethod);
+
+  jint ret =
+      env->CallIntMethod(obj,
+          method_id, as_jint(foo), as_jint(bar));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_SampleForTests_staticJavaMethod = 0;
+static jboolean Java_SampleForTests_staticJavaMethod(JNIEnv* env) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, SampleForTests_clazz(env),
+      SampleForTests_clazz(env), false);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, SampleForTests_clazz(env),
+      "staticJavaMethod",
+
+"("
+")"
+"Z",
+      &g_SampleForTests_staticJavaMethod);
+
+  jboolean ret =
+      env->CallStaticBooleanMethod(SampleForTests_clazz(env),
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_SampleForTests_packagePrivateJavaMethod = 0;
+static void Java_SampleForTests_packagePrivateJavaMethod(JNIEnv* env, jobject
+    obj) {
+  /* 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),
+      "packagePrivateJavaMethod",
+
+"("
+")"
+"V",
+      &g_SampleForTests_packagePrivateJavaMethod);
+
+     env->CallVoidMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_SampleForTests_methodThatThrowsException = 0;
+static void Java_SampleForTests_methodThatThrowsException(JNIEnv* env, jobject
+    obj) {
+  /* 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),
+      "methodThatThrowsException",
+
+"("
+")"
+"V",
+      &g_SampleForTests_methodThatThrowsException);
+
+     env->CallVoidMethod(obj,
+          method_id);
+
+}
+
+static base::subtle::AtomicWord g_InnerStructA_create = 0;
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_InnerStructA_create(JNIEnv* env, jlong l,
+    JniIntWrapper i,
+    jstring s) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, InnerStructA_clazz(env),
+      InnerStructA_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, InnerStructA_clazz(env),
+      "create",
+
+"("
+"J"
+"I"
+"Ljava/lang/String;"
+")"
+"Lorg/chromium/example/jni_generator/SampleForTests$InnerStructA;",
+      &g_InnerStructA_create);
+
+  jobject ret =
+      env->CallStaticObjectMethod(InnerStructA_clazz(env),
+          method_id, l, as_jint(i), s);
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
+}
+
+static base::subtle::AtomicWord g_SampleForTests_addStructA = 0;
+static void Java_SampleForTests_addStructA(JNIEnv* env, jobject obj, jobject a)
+    {
+  /* 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),
+      "addStructA",
+
+"("
+"Lorg/chromium/example/jni_generator/SampleForTests$InnerStructA;"
+")"
+"V",
+      &g_SampleForTests_addStructA);
+
+     env->CallVoidMethod(obj,
+          method_id, a);
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_SampleForTests_iterateAndDoSomething = 0;
+static void Java_SampleForTests_iterateAndDoSomething(JNIEnv* env, jobject obj)
+    {
+  /* 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),
+      "iterateAndDoSomething",
+
+"("
+")"
+"V",
+      &g_SampleForTests_iterateAndDoSomething);
+
+     env->CallVoidMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_InnerStructB_getKey = 0;
+static jlong Java_InnerStructB_getKey(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      InnerStructB_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, InnerStructB_clazz(env),
+      "getKey",
+
+"("
+")"
+"J",
+      &g_InnerStructB_getKey);
+
+  jlong ret =
+      env->CallLongMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_InnerStructB_getValue = 0;
+static base::android::ScopedJavaLocalRef<jstring>
+    Java_InnerStructB_getValue(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      InnerStructB_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, InnerStructB_clazz(env),
+      "getValue",
+
+"("
+")"
+"Ljava/lang/String;",
+      &g_InnerStructB_getValue);
+
+  jstring ret =
+      static_cast<jstring>(env->CallObjectMethod(obj,
+          method_id));
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jstring>(env, ret);
+}
+
+// Step 3: RegisterNatives.
+
+static const JNINativeMethod kMethodsSampleForTests[] = {
+    { "nativeInit",
+"("
+"Ljava/lang/String;"
+")"
+"J", reinterpret_cast<void*>(Init) },
+    { "nativeDestroy",
+"("
+"J"
+")"
+"V", reinterpret_cast<void*>(Destroy) },
+    { "nativeGetDoubleFunction",
+"("
+")"
+"D", reinterpret_cast<void*>(GetDoubleFunction) },
+    { "nativeGetFloatFunction",
+"("
+")"
+"F", reinterpret_cast<void*>(GetFloatFunction) },
+    { "nativeSetNonPODDatatype",
+"("
+"Landroid/graphics/Rect;"
+")"
+"V", reinterpret_cast<void*>(SetNonPODDatatype) },
+    { "nativeGetNonPODDatatype",
+"("
+")"
+"Ljava/lang/Object;", reinterpret_cast<void*>(GetNonPODDatatype) },
+    { "nativeMethod",
+"("
+"J"
+")"
+"I", reinterpret_cast<void*>(Method) },
+    { "nativeMethodOtherP0",
+"("
+"J"
+")"
+"D", reinterpret_cast<void*>(MethodOtherP0) },
+    { "nativeAddStructB",
+"("
+"J"
+"Lorg/chromium/example/jni_generator/SampleForTests$InnerStructB;"
+")"
+"V", reinterpret_cast<void*>(AddStructB) },
+    { "nativeIterateAndDoSomethingWithStructB",
+"("
+"J"
+")"
+"V", reinterpret_cast<void*>(IterateAndDoSomethingWithStructB) },
+    { "nativeReturnAString",
+"("
+"J"
+")"
+"Ljava/lang/String;", reinterpret_cast<void*>(ReturnAString) },
+};
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+  g_InnerStructA_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetClass(env, kInnerStructAClassPath).obj()));
+  g_SampleForTests_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetClass(env, kSampleForTestsClassPath).obj()));
+  g_InnerStructB_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetClass(env, kInnerStructBClassPath).obj()));
+
+  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;
+}
+
+}  // namespace android
+}  // namespace base
+
+#endif  // org_chromium_example_jni_generator_SampleForTests_JNI
diff --git a/base/android/jni_generator/java/src/org/chromium/example/jni_generator/SampleForTests.java b/base/android/jni_generator/java/src/org/chromium/example/jni_generator/SampleForTests.java
new file mode 100644
index 0000000..f54944b
--- /dev/null
+++ b/base/android/jni_generator/java/src/org/chromium/example/jni_generator/SampleForTests.java
@@ -0,0 +1,304 @@
+// Copyright 2012 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.example.jni_generator;
+
+import android.graphics.Rect;
+
+import org.chromium.base.CalledByNative;
+import org.chromium.base.JNINamespace;
+import org.chromium.base.NativeClassQualifiedName;
+import org.chromium.base.annotations.AccessedByNative;
+import org.chromium.base.annotations.CalledByNativeUnchecked;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+// This class serves as a reference test for the bindings generator, and as example documentation
+// for how to use the jni generator.
+// The C++ counter-part is sample_for_tests.cc.
+// jni_generator.gyp has a jni_generator_tests target that will:
+//   * Generate a header file for the JNI bindings based on this file.
+//   * Compile sample_for_tests.cc using the generated header file.
+//   * link a native executable to prove the generated header + cc file are self-contained.
+// All comments are informational only, and are ignored by the jni generator.
+//
+// Binding C/C++ with Java is not trivial, specially when ownership and object lifetime
+// semantics needs to be managed across boundaries.
+// Following a few guidelines will make the code simpler and less buggy:
+//
+// - Never write any JNI "by hand". Rely on the bindings generator to have a thin
+// layer of type-safety.
+//
+// - Treat the types from the other side as "opaque" as possible. Do not inspect any
+// object directly, but rather, rely on well-defined getters / setters.
+//
+// - Minimize the surface API between the two sides, and rather than calling multiple
+// functions across boundaries, call only one (and then, internally in the other side,
+// call as many little functions as required).
+//
+// - If a Java object "owns" a native object, stash the pointer in a "long mNativeClassName".
+// Note that it needs to have a "destruction path", i.e., it must eventually call a method
+// to delete the native object (for example, the java object has a "close()" method that
+// in turn deletes the native object). Avoid relying on finalizers: those run in a different
+// thread and makes the native lifetime management more difficult.
+//
+// - For native object "owning" java objects:
+//   - If there's a strong 1:1 to relationship between native and java, the best way is to
+//   stash the java object into a base::android::ScopedJavaGlobalRef. This will ensure the
+//   java object can be GC'd once the native object is destroyed but note that this global strong
+//   ref implies a new GC root, so be sure it will not leak and it must never rely on being
+//   triggered (transitively) from a java side GC.
+//   - In all other cases, the native side should keep a JavaObjectWeakGlobalRef, and check whether
+//   that reference is still valid before de-referencing it. Note that you will need another
+//   java-side object to be holding a strong reference to this java object while it is in use, to
+//   avoid unpredictable GC of the object before native side has finished with it.
+//
+// - The best way to pass "compound" datatypes across in either direction is to create an inner
+// class with PODs and a factory function. If possible, make it immutable (i.e., mark all the
+// fields as "final"). See examples with "InnerStructB" below.
+//
+// - It's simpler to create thin wrappers with a well defined JNI interface than to
+// expose a lot of internal details. This is specially significant for system classes where it's
+// simpler to wrap factory methods and a few getters / setters than expose the entire class.
+//
+// - Use static factory functions annotated with @CalledByNative rather than calling the
+// constructors directly.
+//
+// - Iterate over containers where they are originally owned, then create inner structs or
+// directly call methods on the other side. It's much simpler than trying to amalgamate
+// java and stl containers.
+//
+// An important note about qualified class name resolution:
+// The generator doesn't compile the class and have little context about the
+// classes being passed through the JNI layers. It adds a few simple rules:
+//
+// - all classes are either explicitly imported, or they are assumed to be in
+// the same package.
+//
+// - Inner class needs to be done through an import and usage of the
+// outer class, so that the generator knows how to qualify it:
+// import foo.bar.Zoo;
+// void call(Zoo.Inner);
+//
+// - implicitly imported classes aren't supported, so in order to pass
+// things like Runnable, please import java.lang.Runnable;
+//
+// This JNINamespace annotation indicates that all native methods should be
+// generated inside this namespace, including the native class that this
+// object binds to.
+@JNINamespace("base::android")
+class SampleForTests {
+    // Classes can store their C++ pointer counter part as an int that is normally initialized by
+    // calling out a nativeInit() function. Replace "CPPClass" with your particular class name!
+    long mNativeCPPObject;
+
+    // You can define methods and attributes on the java class just like any other.
+    // Methods without the @CalledByNative annotation won't be exposed to JNI.
+    public SampleForTests() {
+    }
+
+    public void startExample() {
+        // Calls C++ Init(...) method and holds a pointer to the C++ class.
+        mNativeCPPObject = nativeInit("myParam");
+    }
+
+    public void doStuff() {
+        // This will call CPPClass::Method() using nativePtr as a pointer to the object. This must
+        // be done to:
+        // * avoid leaks.
+        // * using finalizers are not allowed to destroy the cpp class.
+        nativeMethod(mNativeCPPObject);
+    }
+
+    public void finishExample() {
+        // We're done, so let's destroy nativePtr object.
+        nativeDestroy(mNativeCPPObject);
+    }
+
+    // ---------------------------------------------------------------------------------------------
+    // The following methods demonstrate exporting Java methods for invocation from C++ code.
+    // Java functions are mapping into C global functions by prefixing the method name with
+    // "Java_<Class>_"
+    // This is triggered by the @CalledByNative annotation; the methods may be named as you wish.
+
+    // Exported to C++ as:
+    // Java_Example_javaMethod(JNIEnv* env, jobject obj, jint foo, jint bar)
+    // Typically the C++ code would have obtained the jobject via the Init() call described above.
+    @CalledByNative
+    public int javaMethod(int foo, int bar) {
+        return 0;
+    }
+
+    // Exported to C++ as Java_Example_staticJavaMethod(JNIEnv* env)
+    // Note no jobject argument, as it is static.
+    @CalledByNative
+    public static boolean staticJavaMethod() {
+        return true;
+    }
+
+    // No prefix, so this method is package private. It will still be exported.
+    @CalledByNative
+    void packagePrivateJavaMethod() {
+    }
+
+    // Note the "Unchecked" suffix. By default, @CalledByNative will always generate bindings that
+    // call CheckException(). With "@CalledByNativeUnchecked", the client C++ code is responsible to
+    // call ClearException() and act as appropriate.
+    // See more details at the "@CalledByNativeUnchecked" annotation.
+    @CalledByNativeUnchecked
+    void methodThatThrowsException() throws Exception {}
+
+    // The generator is not confused by inline comments:
+    // @CalledByNative void thisShouldNotAppearInTheOutput();
+    // @CalledByNativeUnchecked public static void neitherShouldThis(int foo);
+
+    /**
+     * The generator is not confused by block comments:
+     * @CalledByNative void thisShouldNotAppearInTheOutputEither();
+     * @CalledByNativeUnchecked public static void andDefinitelyNotThis(int foo);
+     */
+
+    // String constants that look like comments don't confuse the generator:
+    private String mArrgh = "*/*";
+
+    // ---------------------------------------------------------------------------------------------
+    // Java fields which are accessed from C++ code only must be annotated with @AccessedByNative to
+    // prevent them being eliminated when unreferenced code is stripped.
+    @AccessedByNative
+    private int mJavaField;
+
+    // ---------------------------------------------------------------------------------------------
+    // The following methods demonstrate declaring methods to call into C++ from Java.
+    // The generator detects the "native" and "static" keywords, the type and name of the first
+    // parameter, and the "native" prefix to the function name to determine the C++ function
+    // signatures. Besides these constraints the methods can be freely named.
+
+    // This declares a C++ function which the application code must implement:
+    // static jint Init(JNIEnv* env, jobject obj);
+    // The jobject parameter refers back to this java side object instance.
+    // The implementation must return the pointer to the C++ object cast to jint.
+    // The caller of this method should store it, and supply it as a the nativeCPPClass param to
+    // subsequent native method calls (see the methods below that take an "int native..." as first
+    // param).
+    private native long nativeInit(String param);
+
+    // This defines a function binding to the associated C++ class member function. The name is
+    // derived from |nativeDestroy| and |nativeCPPClass| to arrive at CPPClass::Destroy() (i.e.
+    // native prefixes stripped).
+    //
+    // The |nativeCPPClass| is automatically cast to type CPPClass*, in order to obtain the object
+    // on
+    // which to invoke the member function. Replace "CPPClass" with your particular class name!
+    private native void nativeDestroy(long nativeCPPClass);
+
+    // This declares a C++ function which the application code must implement:
+    // static jdouble GetDoubleFunction(JNIEnv* env, jobject obj);
+    // The jobject parameter refers back to this java side object instance.
+    private native double nativeGetDoubleFunction();
+
+    // Similar to nativeGetDoubleFunction(), but here the C++ side will receive a jclass rather than
+    // jobject param, as the function is declared static.
+    private static native float nativeGetFloatFunction();
+
+    // This function takes a non-POD datatype. We have a list mapping them to their full classpath
+    // in jni_generator.py JavaParamToJni. If you require a new datatype, make sure you add to that
+    // function.
+    private native void nativeSetNonPODDatatype(Rect rect);
+
+    // This declares a C++ function which the application code must implement:
+    // static ScopedJavaLocalRef<jobject> GetNonPODDatatype(JNIEnv* env, jobject obj);
+    // The jobject parameter refers back to this java side object instance.
+    // Note that it returns a ScopedJavaLocalRef<jobject> so that you don' have to worry about
+    // deleting the JNI local reference. This is similar with Strings and arrays.
+    private native Object nativeGetNonPODDatatype();
+
+    // Similar to nativeDestroy above, this will cast nativeCPPClass into pointer of CPPClass type
+    // and call its Method member function. Replace "CPPClass" with your particular class name!
+    private native int nativeMethod(long nativeCPPClass);
+
+    // Similar to nativeMethod above, but here the C++ fully qualified class name is taken from the
+    // annotation rather than parameter name, which can thus be chosen freely.
+    @NativeClassQualifiedName("CPPClass::InnerClass")
+    private native double nativeMethodOtherP0(long nativePtr);
+
+    // This "struct" will be created by the native side using |createInnerStructA|,
+    // and used by the java-side somehow.
+    // Note that |@CalledByNative| has to contain the inner class name.
+    static class InnerStructA {
+        private final long mLong;
+        private final int mInt;
+        private final String mString;
+
+        private InnerStructA(long l, int i, String s) {
+            mLong = l;
+            mInt = i;
+            mString = s;
+        }
+
+        @CalledByNative("InnerStructA")
+        private static InnerStructA create(long l, int i, String s) {
+            return new InnerStructA(l, i, s);
+        }
+    }
+
+    private List<InnerStructA> mListInnerStructA = new ArrayList<InnerStructA>();
+
+    @CalledByNative
+    private void addStructA(InnerStructA a) {
+        // Called by the native side to append another element.
+        mListInnerStructA.add(a);
+    }
+
+    @CalledByNative
+    private void iterateAndDoSomething() {
+        Iterator<InnerStructA> it = mListInnerStructA.iterator();
+        while (it.hasNext()) {
+            InnerStructA element = it.next();
+            // Now, do something with element.
+        }
+        // Done, clear the list.
+        mListInnerStructA.clear();
+    }
+
+    // This "struct" will be created by the java side passed to native, which
+    // will use its getters.
+    // Note that |@CalledByNative| has to contain the inner class name.
+    static class InnerStructB {
+        private final long mKey;
+        private final String mValue;
+
+        private InnerStructB(long k, String v) {
+            mKey = k;
+            mValue = v;
+        }
+
+        @CalledByNative("InnerStructB")
+        private long getKey() {
+            return mKey;
+        }
+
+        @CalledByNative("InnerStructB")
+        private String getValue() {
+            return mValue;
+        }
+    }
+
+    List<InnerStructB> mListInnerStructB = new ArrayList<InnerStructB>();
+
+    void iterateAndDoSomethingWithMap() {
+        Iterator<InnerStructB> it = mListInnerStructB.iterator();
+        while (it.hasNext()) {
+            InnerStructB element = it.next();
+            // Now, do something with element.
+            nativeAddStructB(mNativeCPPObject, element);
+        }
+        nativeIterateAndDoSomethingWithStructB(mNativeCPPObject);
+    }
+
+    native void nativeAddStructB(long nativeCPPClass, InnerStructB b);
+    native void nativeIterateAndDoSomethingWithStructB(long nativeCPPClass);
+    native String nativeReturnAString(long nativeCPPClass);
+}
diff --git a/base/android/jni_generator/jni_generator.gyp b/base/android/jni_generator/jni_generator.gyp
new file mode 100644
index 0000000..4a17f3e
--- /dev/null
+++ b/base/android/jni_generator/jni_generator.gyp
@@ -0,0 +1,68 @@
+# Copyright (c) 2012 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.
+
+{
+  'targets': [
+    {
+      'target_name': 'jni_generator_py_tests',
+      'type': 'none',
+      'variables': {
+        'stamp': '<(INTERMEDIATE_DIR)/jni_generator_py_tests.stamp',
+      },
+      'actions': [
+        {
+          'action_name': 'run_jni_generator_py_tests',
+          'inputs': [
+            'jni_generator.py',
+            'jni_generator_tests.py',
+            'java/src/org/chromium/example/jni_generator/SampleForTests.java',
+            'golden_sample_for_tests_jni.h',
+          ],
+          'outputs': [
+            '<(stamp)',
+          ],
+          'action': [
+            'python', 'jni_generator_tests.py',
+            '--stamp=<(stamp)',
+          ],
+        },
+      ],
+    },
+    {
+      'target_name': 'jni_sample_header',
+      'type': 'none',
+      'sources': [
+        'java/src/org/chromium/example/jni_generator/SampleForTests.java',
+      ],
+      'variables': {
+        'jni_gen_package': 'example',
+      },
+      'includes': [ '../../../build/jni_generator.gypi' ],
+    },
+    {
+      'target_name': 'jni_sample_java',
+      'type': 'none',
+      'variables': {
+        'java_in_dir': '../../../base/android/jni_generator/java',
+      },
+      'dependencies': [
+        '<(DEPTH)/base/base.gyp:base_java',
+      ],
+      'includes': [ '../../../build/java.gypi' ],
+    },
+    {
+      'target_name': 'jni_generator_tests',
+      'type': 'executable',
+      'dependencies': [
+        '../../base.gyp:test_support_base',
+        'jni_generator_py_tests',
+        'jni_sample_header',
+        'jni_sample_java',
+      ],
+      'sources': [
+        'sample_for_tests.cc',
+      ],
+    },
+  ],
+}
diff --git a/base/android/jni_generator/jni_generator.py b/base/android/jni_generator/jni_generator.py
new file mode 100755
index 0000000..d1f14ba
--- /dev/null
+++ b/base/android/jni_generator/jni_generator.py
@@ -0,0 +1,1557 @@
+#!/usr/bin/env python
+# Copyright (c) 2012 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.
+
+"""Extracts native methods from a Java file and generates the JNI bindings.
+If you change this, please run and update the tests."""
+
+import collections
+import errno
+import optparse
+import os
+import re
+import string
+from string import Template
+import subprocess
+import sys
+import textwrap
+import zipfile
+
+CHROMIUM_SRC = os.path.join(
+    os.path.dirname(__file__), os.pardir, os.pardir, os.pardir)
+BUILD_ANDROID_GYP = os.path.join(
+    CHROMIUM_SRC, 'build', 'android', 'gyp')
+
+sys.path.append(BUILD_ANDROID_GYP)
+
+from util import build_utils
+
+
+class ParseError(Exception):
+  """Exception thrown when we can't parse the input file."""
+
+  def __init__(self, description, *context_lines):
+    Exception.__init__(self)
+    self.description = description
+    self.context_lines = context_lines
+
+  def __str__(self):
+    context = '\n'.join(self.context_lines)
+    return '***\nERROR: %s\n\n%s\n***' % (self.description, context)
+
+
+class Param(object):
+  """Describes a param for a method, either java or native."""
+
+  def __init__(self, **kwargs):
+    self.datatype = kwargs['datatype']
+    self.name = kwargs['name']
+
+
+class NativeMethod(object):
+  """Describes a C/C++ method that is called by Java code"""
+
+  def __init__(self, **kwargs):
+    self.static = kwargs['static']
+    self.java_class_name = kwargs['java_class_name']
+    self.return_type = kwargs['return_type']
+    self.name = kwargs['name']
+    self.params = kwargs['params']
+    if self.params:
+      assert type(self.params) is list
+      assert type(self.params[0]) is Param
+    if (self.params and
+        self.params[0].datatype == kwargs.get('ptr_type', 'int') and
+        self.params[0].name.startswith('native')):
+      self.type = 'method'
+      self.p0_type = self.params[0].name[len('native'):]
+      if kwargs.get('native_class_name'):
+        self.p0_type = kwargs['native_class_name']
+    else:
+      self.type = 'function'
+    self.method_id_var_name = kwargs.get('method_id_var_name', None)
+
+
+class CalledByNative(object):
+  """Describes a java method exported to c/c++"""
+
+  def __init__(self, **kwargs):
+    self.system_class = kwargs['system_class']
+    self.unchecked = kwargs['unchecked']
+    self.static = kwargs['static']
+    self.java_class_name = kwargs['java_class_name']
+    self.return_type = kwargs['return_type']
+    self.name = kwargs['name']
+    self.params = kwargs['params']
+    self.method_id_var_name = kwargs.get('method_id_var_name', None)
+    self.signature = kwargs.get('signature')
+    self.is_constructor = kwargs.get('is_constructor', False)
+    self.env_call = GetEnvCall(self.is_constructor, self.static,
+                               self.return_type)
+    self.static_cast = GetStaticCastForReturnType(self.return_type)
+
+
+class ConstantField(object):
+  def __init__(self, **kwargs):
+    self.name = kwargs['name']
+    self.value = kwargs['value']
+
+
+def JavaDataTypeToC(java_type):
+  """Returns a C datatype for the given java type."""
+  java_pod_type_map = {
+      'int': 'jint',
+      'byte': 'jbyte',
+      'char': 'jchar',
+      'short': 'jshort',
+      'boolean': 'jboolean',
+      'long': 'jlong',
+      'double': 'jdouble',
+      'float': 'jfloat',
+  }
+  java_type_map = {
+      'void': 'void',
+      'String': 'jstring',
+      'java/lang/String': 'jstring',
+      'java/lang/Class': 'jclass',
+  }
+
+  if java_type in java_pod_type_map:
+    return java_pod_type_map[java_type]
+  elif java_type in java_type_map:
+    return java_type_map[java_type]
+  elif java_type.endswith('[]'):
+    if java_type[:-2] in java_pod_type_map:
+      return java_pod_type_map[java_type[:-2]] + 'Array'
+    return 'jobjectArray'
+  elif java_type.startswith('Class'):
+    # Checking just the start of the name, rather than a direct comparison,
+    # in order to handle generics.
+    return 'jclass'
+  else:
+    return 'jobject'
+
+
+def JavaDataTypeToCForCalledByNativeParam(java_type):
+  """Returns a C datatype to be when calling from native."""
+  if java_type == 'int':
+    return 'JniIntWrapper'
+  else:
+    return JavaDataTypeToC(java_type)
+
+
+def JavaReturnValueToC(java_type):
+  """Returns a valid C return value for the given java type."""
+  java_pod_type_map = {
+      'int': '0',
+      'byte': '0',
+      'char': '0',
+      'short': '0',
+      'boolean': 'false',
+      'long': '0',
+      'double': '0',
+      'float': '0',
+      'void': ''
+  }
+  return java_pod_type_map.get(java_type, 'NULL')
+
+
+class JniParams(object):
+  _imports = []
+  _fully_qualified_class = ''
+  _package = ''
+  _inner_classes = []
+  _remappings = []
+  _implicit_imports = []
+
+  @staticmethod
+  def SetFullyQualifiedClass(fully_qualified_class):
+    JniParams._fully_qualified_class = 'L' + fully_qualified_class
+    JniParams._package = '/'.join(fully_qualified_class.split('/')[:-1])
+
+  @staticmethod
+  def AddAdditionalImport(class_name):
+    assert class_name.endswith('.class')
+    raw_class_name = class_name[:-len('.class')]
+    if '.' in raw_class_name:
+      raise SyntaxError('%s cannot be used in @JNIAdditionalImport. '
+                        'Only import unqualified outer classes.' % class_name)
+    new_import = 'L%s/%s' % (JniParams._package, raw_class_name)
+    if new_import in JniParams._imports:
+      raise SyntaxError('Do not use JNIAdditionalImport on an already '
+                        'imported class: %s' % (new_import.replace('/', '.')))
+    JniParams._imports += [new_import]
+
+  @staticmethod
+  def ExtractImportsAndInnerClasses(contents):
+    if not JniParams._package:
+      raise RuntimeError('SetFullyQualifiedClass must be called before '
+                         'ExtractImportsAndInnerClasses')
+    contents = contents.replace('\n', '')
+    re_import = re.compile(r'import.*?(?P<class>\S*?);')
+    for match in re.finditer(re_import, contents):
+      JniParams._imports += ['L' + match.group('class').replace('.', '/')]
+
+    re_inner = re.compile(r'(class|interface)\s+?(?P<name>\w+?)\W')
+    for match in re.finditer(re_inner, contents):
+      inner = match.group('name')
+      if not JniParams._fully_qualified_class.endswith(inner):
+        JniParams._inner_classes += [JniParams._fully_qualified_class + '$' +
+                                     inner]
+
+    re_additional_imports = re.compile(
+        r'@JNIAdditionalImport\(\s*{?(?P<class_names>.*?)}?\s*\)')
+    for match in re.finditer(re_additional_imports, contents):
+      for class_name in match.group('class_names').split(','):
+        JniParams.AddAdditionalImport(class_name.strip())
+
+  @staticmethod
+  def ParseJavaPSignature(signature_line):
+    prefix = 'Signature: '
+    index = signature_line.find(prefix)
+    if index == -1:
+      prefix = 'descriptor: '
+      index = signature_line.index(prefix)
+    return '"%s"' % signature_line[index + len(prefix):]
+
+  @staticmethod
+  def JavaToJni(param):
+    """Converts a java param into a JNI signature type."""
+    pod_param_map = {
+        'int': 'I',
+        'boolean': 'Z',
+        'char': 'C',
+        'short': 'S',
+        'long': 'J',
+        'double': 'D',
+        'float': 'F',
+        'byte': 'B',
+        'void': 'V',
+    }
+    object_param_list = [
+        'Ljava/lang/Boolean',
+        'Ljava/lang/Integer',
+        'Ljava/lang/Long',
+        'Ljava/lang/Object',
+        'Ljava/lang/String',
+        'Ljava/lang/Class',
+    ]
+
+    prefix = ''
+    # Array?
+    while param[-2:] == '[]':
+      prefix += '['
+      param = param[:-2]
+    # Generic?
+    if '<' in param:
+      param = param[:param.index('<')]
+    if param in pod_param_map:
+      return prefix + pod_param_map[param]
+    if '/' in param:
+      # Coming from javap, use the fully qualified param directly.
+      return prefix + 'L' + JniParams.RemapClassName(param) + ';'
+
+    for qualified_name in (object_param_list +
+                           [JniParams._fully_qualified_class] +
+                           JniParams._inner_classes):
+      if (qualified_name.endswith('/' + param) or
+          qualified_name.endswith('$' + param.replace('.', '$')) or
+          qualified_name == 'L' + param):
+        return prefix + JniParams.RemapClassName(qualified_name) + ';'
+
+    # Is it from an import? (e.g. referecing Class from import pkg.Class;
+    # note that referencing an inner class Inner from import pkg.Class.Inner
+    # is not supported).
+    for qualified_name in JniParams._imports:
+      if qualified_name.endswith('/' + param):
+        # Ensure it's not an inner class.
+        components = qualified_name.split('/')
+        if len(components) > 2 and components[-2][0].isupper():
+          raise SyntaxError('Inner class (%s) can not be imported '
+                            'and used by JNI (%s). Please import the outer '
+                            'class and use Outer.Inner instead.' %
+                            (qualified_name, param))
+        return prefix + JniParams.RemapClassName(qualified_name) + ';'
+
+    # Is it an inner class from an outer class import? (e.g. referencing
+    # Class.Inner from import pkg.Class).
+    if '.' in param:
+      components = param.split('.')
+      outer = '/'.join(components[:-1])
+      inner = components[-1]
+      for qualified_name in JniParams._imports:
+        if qualified_name.endswith('/' + outer):
+          return (prefix + JniParams.RemapClassName(qualified_name) +
+                  '$' + inner + ';')
+      raise SyntaxError('Inner class (%s) can not be '
+                        'used directly by JNI. Please import the outer '
+                        'class, probably:\n'
+                        'import %s.%s;' %
+                        (param, JniParams._package.replace('/', '.'),
+                         outer.replace('/', '.')))
+
+    JniParams._CheckImplicitImports(param)
+
+    # Type not found, falling back to same package as this class.
+    return (prefix + 'L' +
+            JniParams.RemapClassName(JniParams._package + '/' + param) + ';')
+
+  @staticmethod
+  def _CheckImplicitImports(param):
+    # Ensure implicit imports, such as java.lang.*, are not being treated
+    # as being in the same package.
+    if not JniParams._implicit_imports:
+      # This file was generated from android.jar and lists
+      # all classes that are implicitly imported.
+      with file(os.path.join(os.path.dirname(sys.argv[0]),
+                             'android_jar.classes'), 'r') as f:
+        JniParams._implicit_imports = f.readlines()
+    for implicit_import in JniParams._implicit_imports:
+      implicit_import = implicit_import.strip().replace('.class', '')
+      implicit_import = implicit_import.replace('/', '.')
+      if implicit_import.endswith('.' + param):
+        raise SyntaxError('Ambiguous class (%s) can not be used directly '
+                          'by JNI.\nPlease import it, probably:\n\n'
+                          'import %s;' %
+                          (param, implicit_import))
+
+
+  @staticmethod
+  def Signature(params, returns, wrap):
+    """Returns the JNI signature for the given datatypes."""
+    items = ['(']
+    items += [JniParams.JavaToJni(param.datatype) for param in params]
+    items += [')']
+    items += [JniParams.JavaToJni(returns)]
+    if wrap:
+      return '\n' + '\n'.join(['"' + item + '"' for item in items])
+    else:
+      return '"' + ''.join(items) + '"'
+
+  @staticmethod
+  def Parse(params):
+    """Parses the params into a list of Param objects."""
+    if not params:
+      return []
+    ret = []
+    for p in [p.strip() for p in params.split(',')]:
+      items = p.split(' ')
+      if 'final' in items:
+        items.remove('final')
+      param = Param(
+          datatype=items[0],
+          name=(items[1] if len(items) > 1 else 'p%s' % len(ret)),
+      )
+      ret += [param]
+    return ret
+
+  @staticmethod
+  def RemapClassName(class_name):
+    """Remaps class names using the jarjar mapping table."""
+    for old, new in JniParams._remappings:
+      if old.endswith('**') and old[:-2] in class_name:
+        return class_name.replace(old[:-2], new, 1)
+      if '*' not in old and class_name.endswith(old):
+        return class_name.replace(old, new, 1)
+
+    return class_name
+
+  @staticmethod
+  def SetJarJarMappings(mappings):
+    """Parse jarjar mappings from a string."""
+    JniParams._remappings = []
+    for line in mappings.splitlines():
+      rule = line.split()
+      if rule[0] != 'rule':
+        continue
+      _, src, dest = rule
+      src = src.replace('.', '/')
+      dest = dest.replace('.', '/')
+      if src.endswith('**'):
+        src_real_name = src[:-2]
+      else:
+        assert not '*' in src
+        src_real_name = src
+
+      if dest.endswith('@0'):
+        JniParams._remappings.append((src, dest[:-2] + src_real_name))
+      elif dest.endswith('@1'):
+        assert '**' in src
+        JniParams._remappings.append((src, dest[:-2]))
+      else:
+        assert not '@' in dest
+        JniParams._remappings.append((src, dest))
+
+
+def ExtractJNINamespace(contents):
+  re_jni_namespace = re.compile('.*?@JNINamespace\("(.*?)"\)')
+  m = re.findall(re_jni_namespace, contents)
+  if not m:
+    return ''
+  return m[0]
+
+
+def ExtractFullyQualifiedJavaClassName(java_file_name, contents):
+  re_package = re.compile('.*?package (.*?);')
+  matches = re.findall(re_package, contents)
+  if not matches:
+    raise SyntaxError('Unable to find "package" line in %s' % java_file_name)
+  return (matches[0].replace('.', '/') + '/' +
+          os.path.splitext(os.path.basename(java_file_name))[0])
+
+
+def ExtractNatives(contents, ptr_type):
+  """Returns a list of dict containing information about a native method."""
+  contents = contents.replace('\n', '')
+  natives = []
+  re_native = re.compile(r'(@NativeClassQualifiedName'
+                         '\(\"(?P<native_class_name>.*?)\"\)\s+)?'
+                         '(@NativeCall(\(\"(?P<java_class_name>.*?)\"\))\s+)?'
+                         '(?P<qualifiers>\w+\s\w+|\w+|\s+)\s*native '
+                         '(?P<return_type>\S*) '
+                         '(?P<name>native\w+)\((?P<params>.*?)\);')
+  for match in re.finditer(re_native, contents):
+    native = NativeMethod(
+        static='static' in match.group('qualifiers'),
+        java_class_name=match.group('java_class_name'),
+        native_class_name=match.group('native_class_name'),
+        return_type=match.group('return_type'),
+        name=match.group('name').replace('native', ''),
+        params=JniParams.Parse(match.group('params')),
+        ptr_type=ptr_type)
+    natives += [native]
+  return natives
+
+
+def GetStaticCastForReturnType(return_type):
+  type_map = { 'String' : 'jstring',
+               'java/lang/String' : 'jstring',
+               'boolean[]': 'jbooleanArray',
+               'byte[]': 'jbyteArray',
+               'char[]': 'jcharArray',
+               'short[]': 'jshortArray',
+               'int[]': 'jintArray',
+               'long[]': 'jlongArray',
+               'float[]': 'jfloatArray',
+               'double[]': 'jdoubleArray' }
+  ret = type_map.get(return_type, None)
+  if ret:
+    return ret
+  if return_type.endswith('[]'):
+    return 'jobjectArray'
+  return None
+
+
+def GetEnvCall(is_constructor, is_static, return_type):
+  """Maps the types availabe via env->Call__Method."""
+  if is_constructor:
+    return 'NewObject'
+  env_call_map = {'boolean': 'Boolean',
+                  'byte': 'Byte',
+                  'char': 'Char',
+                  'short': 'Short',
+                  'int': 'Int',
+                  'long': 'Long',
+                  'float': 'Float',
+                  'void': 'Void',
+                  'double': 'Double',
+                  'Object': 'Object',
+                 }
+  call = env_call_map.get(return_type, 'Object')
+  if is_static:
+    call = 'Static' + call
+  return 'Call' + call + 'Method'
+
+
+def GetMangledParam(datatype):
+  """Returns a mangled identifier for the datatype."""
+  if len(datatype) <= 2:
+    return datatype.replace('[', 'A')
+  ret = ''
+  for i in range(1, len(datatype)):
+    c = datatype[i]
+    if c == '[':
+      ret += 'A'
+    elif c.isupper() or datatype[i - 1] in ['/', 'L']:
+      ret += c.upper()
+  return ret
+
+
+def GetMangledMethodName(name, params, return_type):
+  """Returns a mangled method name for the given signature.
+
+     The returned name can be used as a C identifier and will be unique for all
+     valid overloads of the same method.
+
+  Args:
+     name: string.
+     params: list of Param.
+     return_type: string.
+
+  Returns:
+      A mangled name.
+  """
+  mangled_items = []
+  for datatype in [return_type] + [x.datatype for x in params]:
+    mangled_items += [GetMangledParam(JniParams.JavaToJni(datatype))]
+  mangled_name = name + '_'.join(mangled_items)
+  assert re.match(r'[0-9a-zA-Z_]+', mangled_name)
+  return mangled_name
+
+
+def MangleCalledByNatives(called_by_natives):
+  """Mangles all the overloads from the call_by_natives list."""
+  method_counts = collections.defaultdict(
+      lambda: collections.defaultdict(lambda: 0))
+  for called_by_native in called_by_natives:
+    java_class_name = called_by_native.java_class_name
+    name = called_by_native.name
+    method_counts[java_class_name][name] += 1
+  for called_by_native in called_by_natives:
+    java_class_name = called_by_native.java_class_name
+    method_name = called_by_native.name
+    method_id_var_name = method_name
+    if method_counts[java_class_name][method_name] > 1:
+      method_id_var_name = GetMangledMethodName(method_name,
+                                                called_by_native.params,
+                                                called_by_native.return_type)
+    called_by_native.method_id_var_name = method_id_var_name
+  return called_by_natives
+
+
+# Regex to match the JNI return types that should be included in a
+# ScopedJavaLocalRef.
+RE_SCOPED_JNI_RETURN_TYPES = re.compile('jobject|jclass|jstring|.*Array')
+
+# Regex to match a string like "@CalledByNative public void foo(int bar)".
+RE_CALLED_BY_NATIVE = re.compile(
+    '@CalledByNative(?P<Unchecked>(Unchecked)*?)(?:\("(?P<annotation>.*)"\))?'
+    '\s+(?P<prefix>[\w ]*?)'
+    '\s*(?P<return_type>\S+?)'
+    '\s+(?P<name>\w+)'
+    '\s*\((?P<params>[^\)]*)\)')
+
+
+def ExtractCalledByNatives(contents):
+  """Parses all methods annotated with @CalledByNative.
+
+  Args:
+    contents: the contents of the java file.
+
+  Returns:
+    A list of dict with information about the annotated methods.
+    TODO(bulach): return a CalledByNative object.
+
+  Raises:
+    ParseError: if unable to parse.
+  """
+  called_by_natives = []
+  for match in re.finditer(RE_CALLED_BY_NATIVE, contents):
+    called_by_natives += [CalledByNative(
+        system_class=False,
+        unchecked='Unchecked' in match.group('Unchecked'),
+        static='static' in match.group('prefix'),
+        java_class_name=match.group('annotation') or '',
+        return_type=match.group('return_type'),
+        name=match.group('name'),
+        params=JniParams.Parse(match.group('params')))]
+  # Check for any @CalledByNative occurrences that weren't matched.
+  unmatched_lines = re.sub(RE_CALLED_BY_NATIVE, '', contents).split('\n')
+  for line1, line2 in zip(unmatched_lines, unmatched_lines[1:]):
+    if '@CalledByNative' in line1:
+      raise ParseError('could not parse @CalledByNative method signature',
+                       line1, line2)
+  return MangleCalledByNatives(called_by_natives)
+
+
+class JNIFromJavaP(object):
+  """Uses 'javap' to parse a .class file and generate the JNI header file."""
+
+  def __init__(self, contents, options):
+    self.contents = contents
+    self.namespace = options.namespace
+    for line in contents:
+      class_name = re.match(
+          '.*?(public).*?(class|interface) (?P<class_name>\S+?)( |\Z)',
+          line)
+      if class_name:
+        self.fully_qualified_class = class_name.group('class_name')
+        break
+    self.fully_qualified_class = self.fully_qualified_class.replace('.', '/')
+    # Java 7's javap includes type parameters in output, like HashSet<T>. Strip
+    # away the <...> and use the raw class name that Java 6 would've given us.
+    self.fully_qualified_class = self.fully_qualified_class.split('<', 1)[0]
+    JniParams.SetFullyQualifiedClass(self.fully_qualified_class)
+    self.java_class_name = self.fully_qualified_class.split('/')[-1]
+    if not self.namespace:
+      self.namespace = 'JNI_' + self.java_class_name
+    re_method = re.compile('(?P<prefix>.*?)(?P<return_type>\S+?) (?P<name>\w+?)'
+                           '\((?P<params>.*?)\)')
+    self.called_by_natives = []
+    for lineno, content in enumerate(contents[2:], 2):
+      match = re.match(re_method, content)
+      if not match:
+        continue
+      self.called_by_natives += [CalledByNative(
+          system_class=True,
+          unchecked=False,
+          static='static' in match.group('prefix'),
+          java_class_name='',
+          return_type=match.group('return_type').replace('.', '/'),
+          name=match.group('name'),
+          params=JniParams.Parse(match.group('params').replace('.', '/')),
+          signature=JniParams.ParseJavaPSignature(contents[lineno + 1]))]
+    re_constructor = re.compile('(.*?)public ' +
+                                self.fully_qualified_class.replace('/', '.') +
+                                '\((?P<params>.*?)\)')
+    for lineno, content in enumerate(contents[2:], 2):
+      match = re.match(re_constructor, content)
+      if not match:
+        continue
+      self.called_by_natives += [CalledByNative(
+          system_class=True,
+          unchecked=False,
+          static=False,
+          java_class_name='',
+          return_type=self.fully_qualified_class,
+          name='Constructor',
+          params=JniParams.Parse(match.group('params').replace('.', '/')),
+          signature=JniParams.ParseJavaPSignature(contents[lineno + 1]),
+          is_constructor=True)]
+    self.called_by_natives = MangleCalledByNatives(self.called_by_natives)
+
+    self.constant_fields = []
+    re_constant_field = re.compile('.*?public static final int (?P<name>.*?);')
+    re_constant_field_value = re.compile(
+        '.*?Constant(Value| value): int (?P<value>(-*[0-9]+)?)')
+    for lineno, content in enumerate(contents[2:], 2):
+      match = re.match(re_constant_field, content)
+      if not match:
+        continue
+      value = re.match(re_constant_field_value, contents[lineno + 2])
+      if not value:
+        value = re.match(re_constant_field_value, contents[lineno + 3])
+      if value:
+        self.constant_fields.append(
+            ConstantField(name=match.group('name'),
+                          value=value.group('value')))
+
+    self.inl_header_file_generator = InlHeaderFileGenerator(
+        self.namespace, self.fully_qualified_class, [],
+        self.called_by_natives, self.constant_fields, options)
+
+  def GetContent(self):
+    return self.inl_header_file_generator.GetContent()
+
+  @staticmethod
+  def CreateFromClass(class_file, options):
+    class_name = os.path.splitext(os.path.basename(class_file))[0]
+    p = subprocess.Popen(args=[options.javap, '-c', '-verbose',
+                               '-s', class_name],
+                         cwd=os.path.dirname(class_file),
+                         stdout=subprocess.PIPE,
+                         stderr=subprocess.PIPE)
+    stdout, _ = p.communicate()
+    jni_from_javap = JNIFromJavaP(stdout.split('\n'), options)
+    return jni_from_javap
+
+
+class JNIFromJavaSource(object):
+  """Uses the given java source file to generate the JNI header file."""
+
+  # Match single line comments, multiline comments, character literals, and
+  # double-quoted strings.
+  _comment_remover_regex = re.compile(
+      r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"',
+      re.DOTALL | re.MULTILINE)
+
+  def __init__(self, contents, fully_qualified_class, options):
+    contents = self._RemoveComments(contents)
+    JniParams.SetFullyQualifiedClass(fully_qualified_class)
+    JniParams.ExtractImportsAndInnerClasses(contents)
+    jni_namespace = ExtractJNINamespace(contents) or options.namespace
+    natives = ExtractNatives(contents, options.ptr_type)
+    called_by_natives = ExtractCalledByNatives(contents)
+    if len(natives) == 0 and len(called_by_natives) == 0:
+      raise SyntaxError('Unable to find any JNI methods for %s.' %
+                        fully_qualified_class)
+    inl_header_file_generator = InlHeaderFileGenerator(
+        jni_namespace, fully_qualified_class, natives, called_by_natives,
+        [], options)
+    self.content = inl_header_file_generator.GetContent()
+
+  @classmethod
+  def _RemoveComments(cls, contents):
+    # We need to support both inline and block comments, and we need to handle
+    # strings that contain '//' or '/*'.
+    # TODO(bulach): This is a bit hacky. It would be cleaner to use a real Java
+    # parser. Maybe we could ditch JNIFromJavaSource and just always use
+    # JNIFromJavaP; or maybe we could rewrite this script in Java and use APT.
+    # http://code.google.com/p/chromium/issues/detail?id=138941
+    def replacer(match):
+      # Replace matches that are comments with nothing; return literals/strings
+      # unchanged.
+      s = match.group(0)
+      if s.startswith('/'):
+        return ''
+      else:
+        return s
+    return cls._comment_remover_regex.sub(replacer, contents)
+
+  def GetContent(self):
+    return self.content
+
+  @staticmethod
+  def CreateFromFile(java_file_name, options):
+    contents = file(java_file_name).read()
+    fully_qualified_class = ExtractFullyQualifiedJavaClassName(java_file_name,
+                                                               contents)
+    return JNIFromJavaSource(contents, fully_qualified_class, options)
+
+
+class InlHeaderFileGenerator(object):
+  """Generates an inline header file for JNI integration."""
+
+  def __init__(self, namespace, fully_qualified_class, natives,
+               called_by_natives, constant_fields, options):
+    self.namespace = namespace
+    self.fully_qualified_class = fully_qualified_class
+    self.class_name = self.fully_qualified_class.split('/')[-1]
+    self.natives = natives
+    self.called_by_natives = called_by_natives
+    self.header_guard = fully_qualified_class.replace('/', '_') + '_JNI'
+    self.constant_fields = constant_fields
+    self.options = options
+    self.init_native = self.ExtractInitNative(options)
+
+  def ExtractInitNative(self, options):
+    for native in self.natives:
+      if options.jni_init_native_name == 'native' + native.name:
+        self.natives.remove(native)
+        return native
+    return None
+
+  def GetContent(self):
+    """Returns the content of the JNI binding file."""
+    template = Template("""\
+// 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
+//     ${SCRIPT_NAME}
+// For
+//     ${FULLY_QUALIFIED_CLASS}
+
+#ifndef ${HEADER_GUARD}
+#define ${HEADER_GUARD}
+
+#include <jni.h>
+
+${INCLUDES}
+
+#include "base/android/jni_int_wrapper.h"
+
+// Step 1: forward declarations.
+namespace {
+$CLASS_PATH_DEFINITIONS
+$METHOD_ID_DEFINITIONS
+}  // namespace
+
+$OPEN_NAMESPACE
+$FORWARD_DECLARATIONS
+
+$CONSTANT_FIELDS
+
+// Step 2: method stubs.
+$METHOD_STUBS
+
+// Step 3: RegisterNatives.
+$JNI_NATIVE_METHODS
+$REGISTER_NATIVES
+$CLOSE_NAMESPACE
+$JNI_REGISTER_NATIVES
+#endif  // ${HEADER_GUARD}
+""")
+    values = {
+        'SCRIPT_NAME': self.options.script_name,
+        'FULLY_QUALIFIED_CLASS': self.fully_qualified_class,
+        'CLASS_PATH_DEFINITIONS': self.GetClassPathDefinitionsString(),
+        'METHOD_ID_DEFINITIONS': self.GetMethodIDDefinitionsString(),
+        'FORWARD_DECLARATIONS': self.GetForwardDeclarationsString(),
+        'CONSTANT_FIELDS': self.GetConstantFieldsString(),
+        'METHOD_STUBS': self.GetMethodStubsString(),
+        'OPEN_NAMESPACE': self.GetOpenNamespaceString(),
+        'JNI_NATIVE_METHODS': self.GetJNINativeMethodsString(),
+        'REGISTER_NATIVES': self.GetRegisterNativesString(),
+        'CLOSE_NAMESPACE': self.GetCloseNamespaceString(),
+        'HEADER_GUARD': self.header_guard,
+        'INCLUDES': self.GetIncludesString(),
+        'JNI_REGISTER_NATIVES': self.GetJNIRegisterNativesString()
+    }
+    return WrapOutput(template.substitute(values))
+
+  def GetClassPathDefinitionsString(self):
+    ret = []
+    ret += [self.GetClassPathDefinitions()]
+    return '\n'.join(ret)
+
+  def GetMethodIDDefinitionsString(self):
+    """Returns the definition of method ids for the called by native methods."""
+    if not self.options.eager_called_by_natives:
+      return ''
+    template = Template("""\
+jmethodID g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME} = NULL;""")
+    ret = []
+    for called_by_native in self.called_by_natives:
+      values = {
+          'JAVA_CLASS': called_by_native.java_class_name or self.class_name,
+          'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name,
+      }
+      ret += [template.substitute(values)]
+    return '\n'.join(ret)
+
+  def GetForwardDeclarationsString(self):
+    ret = []
+    for native in self.natives:
+      if native.type != 'method':
+        ret += [self.GetForwardDeclaration(native)]
+    if self.options.native_exports and ret:
+      return '\nextern "C" {\n' + "\n".join(ret) + '\n};  // extern "C"'
+    return '\n'.join(ret)
+
+  def GetConstantFieldsString(self):
+    if not self.constant_fields:
+      return ''
+    ret = ['enum Java_%s_constant_fields {' % self.class_name]
+    for c in self.constant_fields:
+      ret += ['  %s = %s,' % (c.name, c.value)]
+    ret += ['};']
+    return '\n'.join(ret)
+
+  def GetMethodStubsString(self):
+    """Returns the code corresponding to method stubs."""
+    ret = []
+    for native in self.natives:
+      if native.type == 'method':
+        ret += [self.GetNativeMethodStubString(native)]
+    if self.options.eager_called_by_natives:
+      ret += self.GetEagerCalledByNativeMethodStubs()
+    else:
+      ret += self.GetLazyCalledByNativeMethodStubs()
+
+    if self.options.native_exports and ret:
+      return '\nextern "C" {\n' + "\n".join(ret) + '\n};  // extern "C"'
+    return '\n'.join(ret)
+
+  def GetLazyCalledByNativeMethodStubs(self):
+    return [self.GetLazyCalledByNativeMethodStub(called_by_native)
+            for called_by_native in self.called_by_natives]
+
+  def GetEagerCalledByNativeMethodStubs(self):
+    ret = []
+    if self.called_by_natives:
+      ret += ['namespace {']
+      for called_by_native in self.called_by_natives:
+        ret += [self.GetEagerCalledByNativeMethodStub(called_by_native)]
+      ret += ['}  // namespace']
+    return ret
+
+  def GetIncludesString(self):
+    if not self.options.includes:
+      return ''
+    includes = self.options.includes.split(',')
+    return '\n'.join('#include "%s"' % x for x in includes)
+
+  def GetKMethodsString(self, clazz):
+    ret = []
+    for native in self.natives:
+      if (native.java_class_name == clazz or
+          (not native.java_class_name and clazz == self.class_name)):
+        ret += [self.GetKMethodArrayEntry(native)]
+    return '\n'.join(ret)
+
+  def SubstituteNativeMethods(self, template):
+    """Substitutes JAVA_CLASS and KMETHODS in the provided template."""
+    ret = []
+    all_classes = self.GetUniqueClasses(self.natives)
+    all_classes[self.class_name] = self.fully_qualified_class
+    for clazz in all_classes:
+      kmethods = self.GetKMethodsString(clazz)
+      if kmethods:
+        values = {'JAVA_CLASS': clazz,
+                  'KMETHODS': kmethods}
+        ret += [template.substitute(values)]
+    if not ret: return ''
+    return '\n' + '\n'.join(ret)
+
+  def GetJNINativeMethodsString(self):
+    """Returns the implementation of the array of native methods."""
+    if self.options.native_exports and not self.options.native_exports_optional:
+      return ''
+    template = Template("""\
+static const JNINativeMethod kMethods${JAVA_CLASS}[] = {
+${KMETHODS}
+};
+""")
+    return self.SubstituteNativeMethods(template)
+
+  def GetRegisterCalledByNativesImplString(self):
+    """Returns the code for registering the called by native methods."""
+    if not self.options.eager_called_by_natives:
+      return ''
+    template = Template("""\
+  g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME} = ${GET_METHOD_ID_IMPL}
+  if (g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME} == NULL) {
+    return false;
+  }
+    """)
+    ret = []
+    for called_by_native in self.called_by_natives:
+      values = {
+          'JAVA_CLASS': called_by_native.java_class_name or self.class_name,
+          'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name,
+          'GET_METHOD_ID_IMPL': self.GetMethodIDImpl(called_by_native),
+      }
+      ret += [template.substitute(values)]
+    return '\n'.join(ret)
+
+  def GetRegisterNativesString(self):
+    """Returns the code for RegisterNatives."""
+    template = Template("""\
+${REGISTER_NATIVES_SIGNATURE} {
+${EARLY_EXIT}
+${CLASSES}
+${NATIVES}
+${CALLED_BY_NATIVES}
+  return true;
+}
+""")
+    signature = 'static bool RegisterNativesImpl(JNIEnv* env'
+    if self.init_native:
+      signature += ', jclass clazz)'
+    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,
+             }
+    return template.substitute(values)
+
+  def GetRegisterNativesImplString(self):
+    """Returns the shared implementation for RegisterNatives."""
+    if self.options.native_exports and not self.options.native_exports_optional:
+      return ''
+
+    template = Template("""\
+  const int kMethods${JAVA_CLASS}Size = arraysize(kMethods${JAVA_CLASS});
+
+  if (env->RegisterNatives(${JAVA_CLASS}_clazz(env),
+                           kMethods${JAVA_CLASS},
+                           kMethods${JAVA_CLASS}Size) < 0) {
+    jni_generator::HandleRegistrationError(
+        env, ${JAVA_CLASS}_clazz(env), __FILE__);
+    return false;
+  }
+""")
+    return self.SubstituteNativeMethods(template)
+
+  def GetJNIRegisterNativesString(self):
+    """Returns the implementation for the JNI registration of native methods."""
+    if not self.init_native:
+      return ''
+
+    template = Template("""\
+extern "C" JNIEXPORT bool JNICALL
+Java_${FULLY_QUALIFIED_CLASS}_${INIT_NATIVE_NAME}(JNIEnv* env, jclass clazz) {
+  return ${NAMESPACE}RegisterNativesImpl(env, clazz);
+}
+""")
+
+    if self.options.native_exports:
+      java_name = JniParams.RemapClassName(self.fully_qualified_class)
+      java_name = java_name.replace('_', '_1').replace('/', '_')
+    else:
+      java_name = self.fully_qualified_class.replace('/', '_')
+
+    namespace = ''
+    if self.namespace:
+      namespace = self.namespace + '::'
+    values = {'FULLY_QUALIFIED_CLASS': java_name,
+              'INIT_NATIVE_NAME': 'native' + self.init_native.name,
+              'NAMESPACE': namespace,
+              'REGISTER_NATIVES_IMPL': self.GetRegisterNativesImplString()
+             }
+    return template.substitute(values)
+
+  def GetOpenNamespaceString(self):
+    if self.namespace:
+      all_namespaces = ['namespace %s {' % ns
+                        for ns in self.namespace.split('::')]
+      return '\n'.join(all_namespaces)
+    return ''
+
+  def GetCloseNamespaceString(self):
+    if self.namespace:
+      all_namespaces = ['}  // namespace %s' % ns
+                        for ns in self.namespace.split('::')]
+      all_namespaces.reverse()
+      return '\n'.join(all_namespaces) + '\n'
+    return ''
+
+  def GetJNIFirstParam(self, native):
+    ret = []
+    if native.type == 'method':
+      ret = ['jobject jcaller']
+    elif native.type == 'function':
+      if native.static:
+        ret = ['jclass jcaller']
+      else:
+        ret = ['jobject jcaller']
+    return ret
+
+  def GetParamsInDeclaration(self, native):
+    """Returns the params for the stub declaration.
+
+    Args:
+      native: the native dictionary describing the method.
+
+    Returns:
+      A string containing the params.
+    """
+    return ',\n    '.join(self.GetJNIFirstParam(native) +
+                          [JavaDataTypeToC(param.datatype) + ' ' +
+                           param.name
+                           for param in native.params])
+
+  def GetCalledByNativeParamsInDeclaration(self, called_by_native):
+    return ',\n    '.join([
+        JavaDataTypeToCForCalledByNativeParam(param.datatype) + ' ' +
+        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});
+"""
+    if self.options.native_exports:
+      template_str += """
+__attribute__((visibility("default")))
+${RETURN} ${STUB_NAME}(JNIEnv* env, ${PARAMS}) {
+  return ${NAME}(${PARAMS_IN_CALL});
+}
+"""
+    template = Template(template_str)
+    params_in_call = []
+    if not self.options.pure_native_methods:
+      params_in_call = ['env', 'jcaller']
+    params_in_call = ', '.join(params_in_call + [p.name for p in native.params])
+
+    values = {'RETURN': JavaDataTypeToC(native.return_type),
+              'NAME': native.name,
+              'PARAMS': self.GetParamsInDeclaration(native),
+              'PARAMS_IN_CALL': params_in_call,
+              'STUB_NAME': self.GetStubName(native)}
+    return template.substitute(values)
+
+  def GetNativeMethodStubString(self, native):
+    """Returns stubs for native methods."""
+    if self.options.native_exports:
+      template_str = """\
+__attribute__((visibility("default")))
+${RETURN} ${STUB_NAME}(JNIEnv* env,
+    ${PARAMS_IN_DECLARATION}) {"""
+    else:
+      template_str = """\
+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});
+  return native->${NAME}(${PARAMS_IN_CALL})${POST_CALL};
+}
+"""
+
+    template = Template(template_str)
+    params = []
+    if not self.options.pure_native_methods:
+      params = ['env', 'jcaller']
+    params_in_call = ', '.join(params + [p.name for p in native.params[1:]])
+
+    return_type = JavaDataTypeToC(native.return_type)
+    optional_error_return = JavaReturnValueToC(native.return_type)
+    if optional_error_return:
+      optional_error_return = ', ' + optional_error_return
+    post_call = ''
+    if re.match(RE_SCOPED_JNI_RETURN_TYPES, return_type):
+      post_call = '.Release()'
+
+    values = {
+        'RETURN': return_type,
+        'OPTIONAL_ERROR_RETURN': optional_error_return,
+        '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,
+        'STUB_NAME': self.GetStubName(native),
+    }
+    return template.substitute(values)
+
+  def GetArgument(self, param):
+    return ('as_jint(' + param.name + ')'
+            if param.datatype == 'int' else param.name)
+
+  def GetArgumentsInCall(self, params):
+    """Return a string of arguments to call from native into Java"""
+    return [self.GetArgument(p) for p in params]
+
+  def GetCalledByNativeValues(self, called_by_native):
+    """Fills in necessary values for the CalledByNative methods."""
+    java_class = called_by_native.java_class_name or self.class_name
+    if called_by_native.static or called_by_native.is_constructor:
+      first_param_in_declaration = ''
+      first_param_in_call = ('%s_clazz(env)' % java_class)
+    else:
+      first_param_in_declaration = ', jobject obj'
+      first_param_in_call = 'obj'
+    params_in_declaration = self.GetCalledByNativeParamsInDeclaration(
+        called_by_native)
+    if params_in_declaration:
+      params_in_declaration = ', ' + params_in_declaration
+    params_in_call = ', '.join(self.GetArgumentsInCall(called_by_native.params))
+    if params_in_call:
+      params_in_call = ', ' + params_in_call
+    pre_call = ''
+    post_call = ''
+    if called_by_native.static_cast:
+      pre_call = 'static_cast<%s>(' % called_by_native.static_cast
+      post_call = ')'
+    check_exception = ''
+    if not called_by_native.unchecked:
+      check_exception = 'jni_generator::CheckException(env);'
+    return_type = JavaDataTypeToC(called_by_native.return_type)
+    optional_error_return = JavaReturnValueToC(called_by_native.return_type)
+    if optional_error_return:
+      optional_error_return = ', ' + optional_error_return
+    return_declaration = ''
+    return_clause = ''
+    if return_type != 'void':
+      pre_call = ' ' + pre_call
+      return_declaration = return_type + ' ret ='
+      if re.match(RE_SCOPED_JNI_RETURN_TYPES, return_type):
+        return_type = 'base::android::ScopedJavaLocalRef<' + return_type + '>'
+        return_clause = 'return ' + return_type + '(env, ret);'
+      else:
+        return_clause = 'return ret;'
+    return {
+        'JAVA_CLASS': java_class,
+        'RETURN_TYPE': return_type,
+        'OPTIONAL_ERROR_RETURN': optional_error_return,
+        'RETURN_DECLARATION': return_declaration,
+        'RETURN_CLAUSE': return_clause,
+        'FIRST_PARAM_IN_DECLARATION': first_param_in_declaration,
+        'PARAMS_IN_DECLARATION': params_in_declaration,
+        'PRE_CALL': pre_call,
+        'POST_CALL': post_call,
+        'ENV_CALL': called_by_native.env_call,
+        'FIRST_PARAM_IN_CALL': first_param_in_call,
+        'PARAMS_IN_CALL': params_in_call,
+        'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name,
+        'CHECK_EXCEPTION': check_exception,
+        'GET_METHOD_ID_IMPL': self.GetMethodIDImpl(called_by_native)
+    }
+
+  def GetEagerCalledByNativeMethodStub(self, called_by_native):
+    """Returns the implementation of the called by native method."""
+    template = Template("""
+static ${RETURN_TYPE} ${METHOD_ID_VAR_NAME}(\
+JNIEnv* env${FIRST_PARAM_IN_DECLARATION}${PARAMS_IN_DECLARATION}) {
+  ${RETURN_DECLARATION}${PRE_CALL}env->${ENV_CALL}(${FIRST_PARAM_IN_CALL},
+      g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME}${PARAMS_IN_CALL})${POST_CALL};
+  ${RETURN_CLAUSE}
+}""")
+    values = self.GetCalledByNativeValues(called_by_native)
+    return template.substitute(values)
+
+  def GetLazyCalledByNativeMethodStub(self, called_by_native):
+    """Returns a string."""
+    function_signature_template = Template("""\
+static ${RETURN_TYPE} Java_${JAVA_CLASS}_${METHOD_ID_VAR_NAME}(\
+JNIEnv* env${FIRST_PARAM_IN_DECLARATION}${PARAMS_IN_DECLARATION})""")
+    function_header_template = Template("""\
+${FUNCTION_SIGNATURE} {""")
+    function_header_with_unused_template = Template("""\
+${FUNCTION_SIGNATURE} __attribute__ ((unused));
+${FUNCTION_SIGNATURE} {""")
+    template = Template("""
+static base::subtle::AtomicWord g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME} = 0;
+${FUNCTION_HEADER}
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, ${FIRST_PARAM_IN_CALL},
+      ${JAVA_CLASS}_clazz(env)${OPTIONAL_ERROR_RETURN});
+  jmethodID method_id =
+    ${GET_METHOD_ID_IMPL}
+  ${RETURN_DECLARATION}
+     ${PRE_CALL}env->${ENV_CALL}(${FIRST_PARAM_IN_CALL},
+          method_id${PARAMS_IN_CALL})${POST_CALL};
+  ${CHECK_EXCEPTION}
+  ${RETURN_CLAUSE}
+}""")
+    values = self.GetCalledByNativeValues(called_by_native)
+    values['FUNCTION_SIGNATURE'] = (
+        function_signature_template.substitute(values))
+    if called_by_native.system_class:
+      values['FUNCTION_HEADER'] = (
+          function_header_with_unused_template.substitute(values))
+    else:
+      values['FUNCTION_HEADER'] = function_header_template.substitute(values)
+    return template.substitute(values)
+
+  def GetKMethodArrayEntry(self, native):
+    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),
+              'STUB_NAME': self.GetStubName(native)}
+    return template.substitute(values)
+
+  def GetUniqueClasses(self, origin):
+    ret = {self.class_name: self.fully_qualified_class}
+    for entry in origin:
+      class_name = self.class_name
+      jni_class_path = self.fully_qualified_class
+      if entry.java_class_name:
+        class_name = entry.java_class_name
+        jni_class_path = self.fully_qualified_class + '$' + class_name
+      ret[class_name] = jni_class_path
+    return ret
+
+  def GetClassPathDefinitions(self):
+    """Returns the ClassPath constants."""
+    ret = []
+    template = Template("""\
+const char k${JAVA_CLASS}ClassPath[] = "${JNI_CLASS_PATH}";""")
+    native_classes = self.GetUniqueClasses(self.natives)
+    called_by_native_classes = self.GetUniqueClasses(self.called_by_natives)
+    if self.options.native_exports:
+      all_classes = called_by_native_classes
+    else:
+      all_classes = native_classes
+      all_classes.update(called_by_native_classes)
+
+    for clazz in all_classes:
+      values = {
+          'JAVA_CLASS': clazz,
+          'JNI_CLASS_PATH': JniParams.RemapClassName(all_classes[clazz]),
+      }
+      ret += [template.substitute(values)]
+    ret += ''
+
+    class_getter_methods = []
+    if self.options.native_exports:
+      template = Template("""\
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+base::subtle::AtomicWord g_${JAVA_CLASS}_clazz __attribute__((unused)) = 0;
+#define ${JAVA_CLASS}_clazz(env) \
+base::android::LazyGetClass(env, k${JAVA_CLASS}ClassPath, \
+&g_${JAVA_CLASS}_clazz)""")
+    else:
+      template = Template("""\
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_${JAVA_CLASS}_clazz = NULL;
+#define ${JAVA_CLASS}_clazz(env) g_${JAVA_CLASS}_clazz""")
+
+    for clazz in called_by_native_classes:
+      values = {
+          'JAVA_CLASS': clazz,
+      }
+      ret += [template.substitute(values)]
+
+    return '\n'.join(ret)
+
+  def GetFindClasses(self):
+    """Returns the imlementation of FindClass for all known classes."""
+    if self.init_native:
+      if self.options.native_exports:
+        template = Template("""\
+  base::subtle::Release_Store(&g_${JAVA_CLASS}_clazz,
+      static_cast<base::subtle::AtomicWord>(env->NewWeakGlobalRef(clazz));""")
+      else:
+        template = Template("""\
+  g_${JAVA_CLASS}_clazz = static_cast<jclass>(env->NewWeakGlobalRef(clazz));""")
+    else:
+      if self.options.native_exports:
+        return '\n'
+      template = Template("""\
+  g_${JAVA_CLASS}_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetClass(env, k${JAVA_CLASS}ClassPath).obj()));""")
+    ret = []
+    for clazz in self.GetUniqueClasses(self.called_by_natives):
+      values = {'JAVA_CLASS': clazz}
+      ret += [template.substitute(values)]
+    return '\n'.join(ret)
+
+  def GetMethodIDImpl(self, called_by_native):
+    """Returns the implementation of GetMethodID."""
+    if self.options.eager_called_by_natives:
+      template = Template("""\
+env->Get${STATIC_METHOD_PART}MethodID(
+      ${JAVA_CLASS}_clazz(env),
+      "${JNI_NAME}", ${JNI_SIGNATURE});""")
+    else:
+      template = Template("""\
+  base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_${STATIC}>(
+      env, ${JAVA_CLASS}_clazz(env),
+      "${JNI_NAME}",
+      ${JNI_SIGNATURE},
+      &g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME});
+""")
+    jni_name = called_by_native.name
+    jni_return_type = called_by_native.return_type
+    if called_by_native.is_constructor:
+      jni_name = '<init>'
+      jni_return_type = 'void'
+    if called_by_native.signature:
+      signature = called_by_native.signature
+    else:
+      signature = JniParams.Signature(called_by_native.params,
+                                      jni_return_type,
+                                      True)
+    values = {
+        'JAVA_CLASS': called_by_native.java_class_name or self.class_name,
+        'JNI_NAME': jni_name,
+        'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name,
+        'STATIC': 'STATIC' if called_by_native.static else 'INSTANCE',
+        'STATIC_METHOD_PART': 'Static' if called_by_native.static else '',
+        'JNI_SIGNATURE': signature,
+    }
+    return template.substitute(values)
+
+
+def WrapOutput(output):
+  ret = []
+  for line in output.splitlines():
+    # Do not wrap lines under 80 characters or preprocessor directives.
+    if len(line) < 80 or line.lstrip()[:1] == '#':
+      stripped = line.rstrip()
+      if len(ret) == 0 or len(ret[-1]) or len(stripped):
+        ret.append(stripped)
+    else:
+      first_line_indent = ' ' * (len(line) - len(line.lstrip()))
+      subsequent_indent =  first_line_indent + ' ' * 4
+      if line.startswith('//'):
+        subsequent_indent = '//' + subsequent_indent
+      wrapper = textwrap.TextWrapper(width=80,
+                                     subsequent_indent=subsequent_indent,
+                                     break_long_words=False)
+      ret += [wrapped.rstrip() for wrapped in wrapper.wrap(line)]
+  ret += ['']
+  return '\n'.join(ret)
+
+
+def ExtractJarInputFile(jar_file, input_file, out_dir):
+  """Extracts input file from jar and returns the filename.
+
+  The input file is extracted to the same directory that the generated jni
+  headers will be placed in.  This is passed as an argument to script.
+
+  Args:
+    jar_file: the jar file containing the input files to extract.
+    input_files: the list of files to extract from the jar file.
+    out_dir: the name of the directories to extract to.
+
+  Returns:
+    the name of extracted input file.
+  """
+  jar_file = zipfile.ZipFile(jar_file)
+
+  out_dir = os.path.join(out_dir, os.path.dirname(input_file))
+  try:
+    os.makedirs(out_dir)
+  except OSError as e:
+    if e.errno != errno.EEXIST:
+      raise
+  extracted_file_name = os.path.join(out_dir, os.path.basename(input_file))
+  with open(extracted_file_name, 'w') as outfile:
+    outfile.write(jar_file.read(input_file))
+
+  return extracted_file_name
+
+
+def GenerateJNIHeader(input_file, output_file, options):
+  try:
+    if os.path.splitext(input_file)[1] == '.class':
+      jni_from_javap = JNIFromJavaP.CreateFromClass(input_file, options)
+      content = jni_from_javap.GetContent()
+    else:
+      jni_from_java_source = JNIFromJavaSource.CreateFromFile(
+          input_file, options)
+      content = jni_from_java_source.GetContent()
+  except ParseError, e:
+    print e
+    sys.exit(1)
+  if output_file:
+    if not os.path.exists(os.path.dirname(os.path.abspath(output_file))):
+      os.makedirs(os.path.dirname(os.path.abspath(output_file)))
+    if options.optimize_generation and os.path.exists(output_file):
+      with file(output_file, 'r') as f:
+        existing_content = f.read()
+        if existing_content == content:
+          return
+    with file(output_file, 'w') as f:
+      f.write(content)
+  else:
+    print content
+
+
+def GetScriptName():
+  script_components = os.path.abspath(sys.argv[0]).split(os.path.sep)
+  base_index = 0
+  for idx, value in enumerate(script_components):
+    if value == 'base' or value == 'third_party':
+      base_index = idx
+      break
+  return os.sep.join(script_components[base_index:])
+
+
+def main(argv):
+  usage = """usage: %prog [OPTIONS]
+This script will parse the given java source code extracting the native
+declarations and print the header file to stdout (or a file).
+See SampleForTests.java for more details.
+  """
+  option_parser = optparse.OptionParser(usage=usage)
+  build_utils.AddDepfileOption(option_parser)
+
+  option_parser.add_option('-j', '--jar_file', dest='jar_file',
+                           help='Extract the list of input files from'
+                           ' a specified jar file.'
+                           ' Uses javap to extract the methods from a'
+                           ' pre-compiled class. --input should point'
+                           ' to pre-compiled Java .class files.')
+  option_parser.add_option('-n', dest='namespace',
+                           help='Uses as a namespace in the generated header '
+                           'instead of the javap class name, or when there is '
+                           'no JNINamespace annotation in the java source.')
+  option_parser.add_option('--input_file',
+                           help='Single input file name. The output file name '
+                           'will be derived from it. Must be used with '
+                           '--output_dir.')
+  option_parser.add_option('--output_dir',
+                           help='The output directory. Must be used with '
+                           '--input')
+  option_parser.add_option('--optimize_generation', type="int",
+                           default=0, help='Whether we should optimize JNI '
+                           'generation by not regenerating files if they have '
+                           'not changed.')
+  option_parser.add_option('--jarjar',
+                           help='Path to optional jarjar rules file.')
+  option_parser.add_option('--script_name', default=GetScriptName(),
+                           help='The name of this script in the generated '
+                           'header.')
+  option_parser.add_option('--includes',
+                           help='The comma-separated list of header files to '
+                           'include in the generated header.')
+  option_parser.add_option('--pure_native_methods',
+                           action='store_true', dest='pure_native_methods',
+                           help='When true, the native methods will be called '
+                           'without any JNI-specific arguments.')
+  option_parser.add_option('--ptr_type', default='int',
+                           type='choice', choices=['int', 'long'],
+                           help='The type used to represent native pointers in '
+                           'Java code. For 32-bit, use int; '
+                           'for 64-bit, use long.')
+  option_parser.add_option('--jni_init_native_name', default='',
+                           help='The name of the JNI registration method that '
+                           'is used to initialize all native methods. If a '
+                           'method with this name is not present in the Java '
+                           'source file, setting this option is a no-op. When '
+                           'a method with this name is found however, the '
+                           'naming convention Java_<packageName>_<className> '
+                           'will limit the initialization to only the '
+                           'top-level class.')
+  option_parser.add_option('--eager_called_by_natives',
+                           action='store_true', dest='eager_called_by_natives',
+                           help='When true, the called-by-native methods will '
+                           'be initialized in a non-atomic way.')
+  option_parser.add_option('--cpp', default='cpp',
+                           help='The path to cpp command.')
+  option_parser.add_option('--javap', default='javap',
+                           help='The path to javap command.')
+  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)
+  elif options.input_file:
+    input_file = options.input_file
+  else:
+    option_parser.print_help()
+    print '\nError: Must specify --jar_file or --input_file.'
+    return 1
+  output_file = None
+  if options.output_dir:
+    root_name = os.path.splitext(os.path.basename(input_file))[0]
+    output_file = os.path.join(options.output_dir, root_name) + '_jni.h'
+  if options.jarjar:
+    with open(options.jarjar) as f:
+      JniParams.SetJarJarMappings(f.read())
+  GenerateJNIHeader(input_file, output_file, options)
+
+  if options.depfile:
+    build_utils.WriteDepfile(
+        options.depfile,
+        build_utils.GetPythonDependencies())
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv))
diff --git a/base/android/jni_generator/jni_generator_helper.h b/base/android/jni_generator/jni_generator_helper.h
new file mode 100644
index 0000000..b9736e1
--- /dev/null
+++ b/base/android/jni_generator/jni_generator_helper.h
@@ -0,0 +1,40 @@
+// 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.
+
+
+#ifndef BASE_ANDROID_JNI_GENERATOR_JNI_GENERATOR_HELPER_H_
+#define BASE_ANDROID_JNI_GENERATOR_JNI_GENERATOR_HELPER_H_
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+// Project-specific macros used by the header files generated by
+// jni_generator.py. Different projects can then specify their own
+// implementation for this file.
+#define CHECK_NATIVE_PTR(env, jcaller, native_ptr, method_name, ...) \
+    DCHECK(native_ptr) << method_name;
+
+#define CHECK_CLAZZ(env, jcaller, clazz, ...) \
+    DCHECK(clazz);
+
+namespace jni_generator {
+
+  inline void HandleRegistrationError(JNIEnv* env, jclass clazz,
+                                      const char* filename) {
+    LOG(ERROR) << "RegisterNatives failed in " << filename;
+  }
+
+  inline void CheckException(JNIEnv* env) {
+    base::android::CheckException(env);
+  }
+
+}  // namespace jni_generator
+
+using base::android::ScopedJavaLocalRef;
+
+#endif  // BASE_ANDROID_JNI_GENERATOR_JNI_GENERATOR_HELPER_H_
diff --git a/base/android/jni_generator/jni_generator_tests.py b/base/android/jni_generator/jni_generator_tests.py
new file mode 100755
index 0000000..6014847
--- /dev/null
+++ b/base/android/jni_generator/jni_generator_tests.py
@@ -0,0 +1,1175 @@
+#!/usr/bin/env python
+# Copyright (c) 2012 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.
+
+"""Tests for jni_generator.py.
+
+This test suite contains various tests for the JNI generator.
+It exercises the low-level parser all the way up to the
+code generator and ensures the output matches a golden
+file.
+"""
+
+import difflib
+import inspect
+import optparse
+import os
+import sys
+import unittest
+import jni_generator
+from jni_generator import CalledByNative, JniParams, NativeMethod, Param
+
+
+SCRIPT_NAME = 'base/android/jni_generator/jni_generator.py'
+INCLUDES = (
+    'base/android/jni_generator/jni_generator_helper.h'
+)
+
+# Set this environment variable in order to regenerate the golden text
+# files.
+REBASELINE_ENV = 'REBASELINE'
+
+class TestOptions(object):
+  """The mock options object which is passed to the jni_generator.py script."""
+
+  def __init__(self):
+    self.namespace = None
+    self.script_name = SCRIPT_NAME
+    self.includes = INCLUDES
+    self.pure_native_methods = False
+    self.ptr_type = 'long'
+    self.jni_init_native_name = None
+    self.eager_called_by_natives = False
+    self.cpp = 'cpp'
+    self.javap = 'javap'
+    self.native_exports = False
+    self.native_exports_optional = False
+
+class TestGenerator(unittest.TestCase):
+  def assertObjEquals(self, first, second):
+    dict_first = first.__dict__
+    dict_second = second.__dict__
+    self.assertEquals(dict_first.keys(), dict_second.keys())
+    for key, value in dict_first.iteritems():
+      if (type(value) is list and len(value) and
+          isinstance(type(value[0]), object)):
+        self.assertListEquals(value, second.__getattribute__(key))
+      else:
+        actual = second.__getattribute__(key)
+        self.assertEquals(value, actual,
+                          'Key ' + key + ': ' + str(value) + '!=' + str(actual))
+
+  def assertListEquals(self, first, second):
+    self.assertEquals(len(first), len(second))
+    for i in xrange(len(first)):
+      if isinstance(first[i], object):
+        self.assertObjEquals(first[i], second[i])
+      else:
+        self.assertEquals(first[i], second[i])
+
+  def assertTextEquals(self, golden_text, generated_text):
+    if not self.compareText(golden_text, generated_text):
+      self.fail('Golden text mismatch.')
+
+  def compareText(self, golden_text, generated_text):
+    def FilterText(text):
+      return [
+          l.strip() for l in text.split('\n')
+          if not l.startswith('// Copyright')
+      ]
+    stripped_golden = FilterText(golden_text)
+    stripped_generated = FilterText(generated_text)
+    if stripped_golden == stripped_generated:
+      return True
+    print self.id()
+    for line in difflib.context_diff(stripped_golden, stripped_generated):
+      print line
+    print '\n\nGenerated'
+    print '=' * 80
+    print generated_text
+    print '=' * 80
+    print 'Run with:'
+    print 'REBASELINE=1', sys.argv[0]
+    print 'to regenerate the data files.'
+
+  def _ReadGoldenFile(self, golden_file):
+    if not os.path.exists(golden_file):
+      return None
+    with file(golden_file, 'r') as f:
+      return f.read()
+
+  def assertGoldenTextEquals(self, generated_text):
+    script_dir = os.path.dirname(sys.argv[0])
+    # This is the caller test method.
+    caller = inspect.stack()[1][3]
+    self.assertTrue(caller.startswith('test'),
+                    'assertGoldenTextEquals can only be called from a '
+                    'test* method, not %s' % caller)
+    golden_file = os.path.join(script_dir, caller + '.golden')
+    golden_text = self._ReadGoldenFile(golden_file)
+    if os.environ.get(REBASELINE_ENV):
+      if golden_text != generated_text:
+        with file(golden_file, 'w') as f:
+          f.write(generated_text)
+      return
+    self.assertTextEquals(golden_text, generated_text)
+
+  def testInspectCaller(self):
+    def willRaise():
+      # This function can only be called from a test* method.
+      self.assertGoldenTextEquals('')
+    self.assertRaises(AssertionError, willRaise)
+
+  def testNatives(self):
+    test_data = """"
+    interface OnFrameAvailableListener {}
+    private native int nativeInit();
+    private native void nativeDestroy(int nativeChromeBrowserProvider);
+    private native long nativeAddBookmark(
+            int nativeChromeBrowserProvider,
+            String url, String title, boolean isFolder, long parentId);
+    private static native String nativeGetDomainAndRegistry(String url);
+    private static native void nativeCreateHistoricalTabFromState(
+            byte[] state, int tab_index);
+    private native byte[] nativeGetStateAsByteArray(View view);
+    private static native String[] nativeGetAutofillProfileGUIDs();
+    private native void nativeSetRecognitionResults(
+            int sessionId, String[] results);
+    private native long nativeAddBookmarkFromAPI(
+            int nativeChromeBrowserProvider,
+            String url, Long created, Boolean isBookmark,
+            Long date, byte[] favicon, String title, Integer visits);
+    native int nativeFindAll(String find);
+    private static native OnFrameAvailableListener nativeGetInnerClass();
+    private native Bitmap nativeQueryBitmap(
+            int nativeChromeBrowserProvider,
+            String[] projection, String selection,
+            String[] selectionArgs, String sortOrder);
+    private native void nativeGotOrientation(
+            int nativeDataFetcherImplAndroid,
+            double alpha, double beta, double gamma);
+    """
+    jni_generator.JniParams.SetFullyQualifiedClass(
+        'org/chromium/example/jni_generator/SampleForTests')
+    jni_generator.JniParams.ExtractImportsAndInnerClasses(test_data)
+    natives = jni_generator.ExtractNatives(test_data, 'int')
+    golden_natives = [
+        NativeMethod(return_type='int', static=False,
+                     name='Init',
+                     params=[],
+                     java_class_name=None,
+                     type='function'),
+        NativeMethod(return_type='void', static=False, name='Destroy',
+                     params=[Param(datatype='int',
+                                   name='nativeChromeBrowserProvider')],
+                     java_class_name=None,
+                     type='method',
+                     p0_type='ChromeBrowserProvider'),
+        NativeMethod(return_type='long', static=False, name='AddBookmark',
+                     params=[Param(datatype='int',
+                                   name='nativeChromeBrowserProvider'),
+                             Param(datatype='String',
+                                   name='url'),
+                             Param(datatype='String',
+                                   name='title'),
+                             Param(datatype='boolean',
+                                   name='isFolder'),
+                             Param(datatype='long',
+                                   name='parentId')],
+                     java_class_name=None,
+                     type='method',
+                     p0_type='ChromeBrowserProvider'),
+        NativeMethod(return_type='String', static=True,
+                     name='GetDomainAndRegistry',
+                     params=[Param(datatype='String',
+                                   name='url')],
+                     java_class_name=None,
+                     type='function'),
+        NativeMethod(return_type='void', static=True,
+                     name='CreateHistoricalTabFromState',
+                     params=[Param(datatype='byte[]',
+                                   name='state'),
+                             Param(datatype='int',
+                                   name='tab_index')],
+                     java_class_name=None,
+                     type='function'),
+        NativeMethod(return_type='byte[]', static=False,
+                     name='GetStateAsByteArray',
+                     params=[Param(datatype='View', name='view')],
+                     java_class_name=None,
+                     type='function'),
+        NativeMethod(return_type='String[]', static=True,
+                     name='GetAutofillProfileGUIDs', params=[],
+                     java_class_name=None,
+                     type='function'),
+        NativeMethod(return_type='void', static=False,
+                     name='SetRecognitionResults',
+                     params=[Param(datatype='int', name='sessionId'),
+                             Param(datatype='String[]', name='results')],
+                     java_class_name=None,
+                     type='function'),
+        NativeMethod(return_type='long', static=False,
+                     name='AddBookmarkFromAPI',
+                     params=[Param(datatype='int',
+                                   name='nativeChromeBrowserProvider'),
+                             Param(datatype='String',
+                                   name='url'),
+                             Param(datatype='Long',
+                                   name='created'),
+                             Param(datatype='Boolean',
+                                   name='isBookmark'),
+                             Param(datatype='Long',
+                                   name='date'),
+                             Param(datatype='byte[]',
+                                   name='favicon'),
+                             Param(datatype='String',
+                                   name='title'),
+                             Param(datatype='Integer',
+                                   name='visits')],
+                     java_class_name=None,
+                     type='method',
+                     p0_type='ChromeBrowserProvider'),
+        NativeMethod(return_type='int', static=False,
+                     name='FindAll',
+                     params=[Param(datatype='String',
+                                   name='find')],
+                     java_class_name=None,
+                     type='function'),
+        NativeMethod(return_type='OnFrameAvailableListener', static=True,
+                     name='GetInnerClass',
+                     params=[],
+                     java_class_name=None,
+                     type='function'),
+        NativeMethod(return_type='Bitmap',
+                     static=False,
+                     name='QueryBitmap',
+                     params=[Param(datatype='int',
+                                   name='nativeChromeBrowserProvider'),
+                             Param(datatype='String[]',
+                                   name='projection'),
+                             Param(datatype='String',
+                                   name='selection'),
+                             Param(datatype='String[]',
+                                   name='selectionArgs'),
+                             Param(datatype='String',
+                                   name='sortOrder'),
+                            ],
+                     java_class_name=None,
+                     type='method',
+                     p0_type='ChromeBrowserProvider'),
+        NativeMethod(return_type='void', static=False,
+                     name='GotOrientation',
+                     params=[Param(datatype='int',
+                                   name='nativeDataFetcherImplAndroid'),
+                             Param(datatype='double',
+                                   name='alpha'),
+                             Param(datatype='double',
+                                   name='beta'),
+                             Param(datatype='double',
+                                   name='gamma'),
+                            ],
+                     java_class_name=None,
+                     type='method',
+                     p0_type='content::DataFetcherImplAndroid'),
+    ]
+    self.assertListEquals(golden_natives, natives)
+    h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni',
+                                             natives, [], [], TestOptions())
+    self.assertGoldenTextEquals(h.GetContent())
+
+  def testInnerClassNatives(self):
+    test_data = """
+    class MyInnerClass {
+      @NativeCall("MyInnerClass")
+      private native int nativeInit();
+    }
+    """
+    natives = jni_generator.ExtractNatives(test_data, 'int')
+    golden_natives = [
+        NativeMethod(return_type='int', static=False,
+                     name='Init', params=[],
+                     java_class_name='MyInnerClass',
+                     type='function')
+    ]
+    self.assertListEquals(golden_natives, natives)
+    h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni',
+                                             natives, [], [], TestOptions())
+    self.assertGoldenTextEquals(h.GetContent())
+
+  def testInnerClassNativesMultiple(self):
+    test_data = """
+    class MyInnerClass {
+      @NativeCall("MyInnerClass")
+      private native int nativeInit();
+    }
+    class MyOtherInnerClass {
+      @NativeCall("MyOtherInnerClass")
+      private native int nativeInit();
+    }
+    """
+    natives = jni_generator.ExtractNatives(test_data, 'int')
+    golden_natives = [
+        NativeMethod(return_type='int', static=False,
+                     name='Init', params=[],
+                     java_class_name='MyInnerClass',
+                     type='function'),
+        NativeMethod(return_type='int', static=False,
+                     name='Init', params=[],
+                     java_class_name='MyOtherInnerClass',
+                     type='function')
+    ]
+    self.assertListEquals(golden_natives, natives)
+    h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni',
+                                             natives, [], [], TestOptions())
+    self.assertGoldenTextEquals(h.GetContent())
+
+  def testInnerClassNativesBothInnerAndOuter(self):
+    test_data = """
+    class MyOuterClass {
+      private native int nativeInit();
+      class MyOtherInnerClass {
+        @NativeCall("MyOtherInnerClass")
+        private native int nativeInit();
+      }
+    }
+    """
+    natives = jni_generator.ExtractNatives(test_data, 'int')
+    golden_natives = [
+        NativeMethod(return_type='int', static=False,
+                     name='Init', params=[],
+                     java_class_name=None,
+                     type='function'),
+        NativeMethod(return_type='int', static=False,
+                     name='Init', params=[],
+                     java_class_name='MyOtherInnerClass',
+                     type='function')
+    ]
+    self.assertListEquals(golden_natives, natives)
+    h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni',
+                                             natives, [], [], TestOptions())
+    self.assertGoldenTextEquals(h.GetContent())
+
+  def testCalledByNatives(self):
+    test_data = """"
+    import android.graphics.Bitmap;
+    import android.view.View;
+    import java.io.InputStream;
+    import java.util.List;
+
+    class InnerClass {}
+
+    @CalledByNative
+    InnerClass showConfirmInfoBar(int nativeInfoBar,
+            String buttonOk, String buttonCancel, String title, Bitmap icon) {
+        InfoBar infobar = new ConfirmInfoBar(nativeInfoBar, mContext,
+                                             buttonOk, buttonCancel,
+                                             title, icon);
+        return infobar;
+    }
+    @CalledByNative
+    InnerClass showAutoLoginInfoBar(int nativeInfoBar,
+            String realm, String account, String args) {
+        AutoLoginInfoBar infobar = new AutoLoginInfoBar(nativeInfoBar, mContext,
+                realm, account, args);
+        if (infobar.displayedAccountCount() == 0)
+            infobar = null;
+        return infobar;
+    }
+    @CalledByNative("InfoBar")
+    void dismiss();
+    @SuppressWarnings("unused")
+    @CalledByNative
+    private static boolean shouldShowAutoLogin(View view,
+            String realm, String account, String args) {
+        AccountManagerContainer accountManagerContainer =
+            new AccountManagerContainer((Activity)contentView.getContext(),
+            realm, account, args);
+        String[] logins = accountManagerContainer.getAccountLogins(null);
+        return logins.length != 0;
+    }
+    @CalledByNative
+    static InputStream openUrl(String url) {
+        return null;
+    }
+    @CalledByNative
+    private void activateHardwareAcceleration(final boolean activated,
+            final int iPid, final int iType,
+            final int iPrimaryID, final int iSecondaryID) {
+      if (!activated) {
+          return
+      }
+    }
+    @CalledByNativeUnchecked
+    private void uncheckedCall(int iParam);
+
+    @CalledByNative
+    public byte[] returnByteArray();
+
+    @CalledByNative
+    public boolean[] returnBooleanArray();
+
+    @CalledByNative
+    public char[] returnCharArray();
+
+    @CalledByNative
+    public short[] returnShortArray();
+
+    @CalledByNative
+    public int[] returnIntArray();
+
+    @CalledByNative
+    public long[] returnLongArray();
+
+    @CalledByNative
+    public double[] returnDoubleArray();
+
+    @CalledByNative
+    public Object[] returnObjectArray();
+
+    @CalledByNative
+    public byte[][] returnArrayOfByteArray();
+
+    @CalledByNative
+    public Bitmap.CompressFormat getCompressFormat();
+
+    @CalledByNative
+    public List<Bitmap.CompressFormat> getCompressFormatList();
+    """
+    jni_generator.JniParams.SetFullyQualifiedClass('org/chromium/Foo')
+    jni_generator.JniParams.ExtractImportsAndInnerClasses(test_data)
+    called_by_natives = jni_generator.ExtractCalledByNatives(test_data)
+    golden_called_by_natives = [
+        CalledByNative(
+            return_type='InnerClass',
+            system_class=False,
+            static=False,
+            name='showConfirmInfoBar',
+            method_id_var_name='showConfirmInfoBar',
+            java_class_name='',
+            params=[Param(datatype='int', name='nativeInfoBar'),
+                    Param(datatype='String', name='buttonOk'),
+                    Param(datatype='String', name='buttonCancel'),
+                    Param(datatype='String', name='title'),
+                    Param(datatype='Bitmap', name='icon')],
+            env_call=('Object', ''),
+            unchecked=False,
+        ),
+        CalledByNative(
+            return_type='InnerClass',
+            system_class=False,
+            static=False,
+            name='showAutoLoginInfoBar',
+            method_id_var_name='showAutoLoginInfoBar',
+            java_class_name='',
+            params=[Param(datatype='int', name='nativeInfoBar'),
+                    Param(datatype='String', name='realm'),
+                    Param(datatype='String', name='account'),
+                    Param(datatype='String', name='args')],
+            env_call=('Object', ''),
+            unchecked=False,
+        ),
+        CalledByNative(
+            return_type='void',
+            system_class=False,
+            static=False,
+            name='dismiss',
+            method_id_var_name='dismiss',
+            java_class_name='InfoBar',
+            params=[],
+            env_call=('Void', ''),
+            unchecked=False,
+        ),
+        CalledByNative(
+            return_type='boolean',
+            system_class=False,
+            static=True,
+            name='shouldShowAutoLogin',
+            method_id_var_name='shouldShowAutoLogin',
+            java_class_name='',
+            params=[Param(datatype='View', name='view'),
+                    Param(datatype='String', name='realm'),
+                    Param(datatype='String', name='account'),
+                    Param(datatype='String', name='args')],
+            env_call=('Boolean', ''),
+            unchecked=False,
+        ),
+        CalledByNative(
+            return_type='InputStream',
+            system_class=False,
+            static=True,
+            name='openUrl',
+            method_id_var_name='openUrl',
+            java_class_name='',
+            params=[Param(datatype='String', name='url')],
+            env_call=('Object', ''),
+            unchecked=False,
+        ),
+        CalledByNative(
+            return_type='void',
+            system_class=False,
+            static=False,
+            name='activateHardwareAcceleration',
+            method_id_var_name='activateHardwareAcceleration',
+            java_class_name='',
+            params=[Param(datatype='boolean', name='activated'),
+                    Param(datatype='int', name='iPid'),
+                    Param(datatype='int', name='iType'),
+                    Param(datatype='int', name='iPrimaryID'),
+                    Param(datatype='int', name='iSecondaryID'),
+                   ],
+            env_call=('Void', ''),
+            unchecked=False,
+        ),
+        CalledByNative(
+            return_type='void',
+            system_class=False,
+            static=False,
+            name='uncheckedCall',
+            method_id_var_name='uncheckedCall',
+            java_class_name='',
+            params=[Param(datatype='int', name='iParam')],
+            env_call=('Void', ''),
+            unchecked=True,
+        ),
+        CalledByNative(
+            return_type='byte[]',
+            system_class=False,
+            static=False,
+            name='returnByteArray',
+            method_id_var_name='returnByteArray',
+            java_class_name='',
+            params=[],
+            env_call=('Void', ''),
+            unchecked=False,
+        ),
+        CalledByNative(
+            return_type='boolean[]',
+            system_class=False,
+            static=False,
+            name='returnBooleanArray',
+            method_id_var_name='returnBooleanArray',
+            java_class_name='',
+            params=[],
+            env_call=('Void', ''),
+            unchecked=False,
+        ),
+        CalledByNative(
+            return_type='char[]',
+            system_class=False,
+            static=False,
+            name='returnCharArray',
+            method_id_var_name='returnCharArray',
+            java_class_name='',
+            params=[],
+            env_call=('Void', ''),
+            unchecked=False,
+        ),
+        CalledByNative(
+            return_type='short[]',
+            system_class=False,
+            static=False,
+            name='returnShortArray',
+            method_id_var_name='returnShortArray',
+            java_class_name='',
+            params=[],
+            env_call=('Void', ''),
+            unchecked=False,
+        ),
+        CalledByNative(
+            return_type='int[]',
+            system_class=False,
+            static=False,
+            name='returnIntArray',
+            method_id_var_name='returnIntArray',
+            java_class_name='',
+            params=[],
+            env_call=('Void', ''),
+            unchecked=False,
+        ),
+        CalledByNative(
+            return_type='long[]',
+            system_class=False,
+            static=False,
+            name='returnLongArray',
+            method_id_var_name='returnLongArray',
+            java_class_name='',
+            params=[],
+            env_call=('Void', ''),
+            unchecked=False,
+        ),
+        CalledByNative(
+            return_type='double[]',
+            system_class=False,
+            static=False,
+            name='returnDoubleArray',
+            method_id_var_name='returnDoubleArray',
+            java_class_name='',
+            params=[],
+            env_call=('Void', ''),
+            unchecked=False,
+        ),
+        CalledByNative(
+            return_type='Object[]',
+            system_class=False,
+            static=False,
+            name='returnObjectArray',
+            method_id_var_name='returnObjectArray',
+            java_class_name='',
+            params=[],
+            env_call=('Void', ''),
+            unchecked=False,
+        ),
+        CalledByNative(
+            return_type='byte[][]',
+            system_class=False,
+            static=False,
+            name='returnArrayOfByteArray',
+            method_id_var_name='returnArrayOfByteArray',
+            java_class_name='',
+            params=[],
+            env_call=('Void', ''),
+            unchecked=False,
+        ),
+        CalledByNative(
+            return_type='Bitmap.CompressFormat',
+            system_class=False,
+            static=False,
+            name='getCompressFormat',
+            method_id_var_name='getCompressFormat',
+            java_class_name='',
+            params=[],
+            env_call=('Void', ''),
+            unchecked=False,
+        ),
+        CalledByNative(
+            return_type='List<Bitmap.CompressFormat>',
+            system_class=False,
+            static=False,
+            name='getCompressFormatList',
+            method_id_var_name='getCompressFormatList',
+            java_class_name='',
+            params=[],
+            env_call=('Void', ''),
+            unchecked=False,
+        ),
+    ]
+    self.assertListEquals(golden_called_by_natives, called_by_natives)
+    h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni',
+                                             [], called_by_natives, [],
+                                             TestOptions())
+    self.assertGoldenTextEquals(h.GetContent())
+
+  def testCalledByNativeParseError(self):
+    try:
+      jni_generator.ExtractCalledByNatives("""
+@CalledByNative
+public static int foo(); // This one is fine
+
+@CalledByNative
+scooby doo
+""")
+      self.fail('Expected a ParseError')
+    except jni_generator.ParseError, e:
+      self.assertEquals(('@CalledByNative', 'scooby doo'), e.context_lines)
+
+  def testFullyQualifiedClassName(self):
+    contents = """
+// Copyright (c) 2010 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.content.browser;
+
+import org.chromium.base.BuildInfo;
+"""
+    self.assertEquals('org/chromium/content/browser/Foo',
+                      jni_generator.ExtractFullyQualifiedJavaClassName(
+                          'org/chromium/content/browser/Foo.java', contents))
+    self.assertEquals('org/chromium/content/browser/Foo',
+                      jni_generator.ExtractFullyQualifiedJavaClassName(
+                          'frameworks/Foo.java', contents))
+    self.assertRaises(SyntaxError,
+                      jni_generator.ExtractFullyQualifiedJavaClassName,
+                      'com/foo/Bar', 'no PACKAGE line')
+
+  def testMethodNameMangling(self):
+    self.assertEquals('closeV',
+        jni_generator.GetMangledMethodName('close', [], 'void'))
+    self.assertEquals('readI_AB_I_I',
+        jni_generator.GetMangledMethodName('read',
+            [Param(name='p1',
+                   datatype='byte[]'),
+             Param(name='p2',
+                   datatype='int'),
+             Param(name='p3',
+                   datatype='int'),],
+             'int'))
+    self.assertEquals('openJIIS_JLS',
+        jni_generator.GetMangledMethodName('open',
+            [Param(name='p1',
+                   datatype='java/lang/String'),],
+             'java/io/InputStream'))
+
+  def testFromJavaPGenerics(self):
+    contents = """
+public abstract class java.util.HashSet<T> extends java.util.AbstractSet<E>
+      implements java.util.Set<E>, java.lang.Cloneable, java.io.Serializable {
+    public void dummy();
+  Signature: ()V
+}
+"""
+    jni_from_javap = jni_generator.JNIFromJavaP(contents.split('\n'),
+                                                TestOptions())
+    self.assertEquals(1, len(jni_from_javap.called_by_natives))
+    self.assertGoldenTextEquals(jni_from_javap.GetContent())
+
+  def testSnippnetJavap6_7_8(self):
+    content_javap6 = """
+public class java.util.HashSet {
+public boolean add(java.lang.Object);
+ Signature: (Ljava/lang/Object;)Z
+}
+"""
+
+    content_javap7 = """
+public class java.util.HashSet {
+public boolean add(E);
+  Signature: (Ljava/lang/Object;)Z
+}
+"""
+
+    content_javap8 = """
+public class java.util.HashSet {
+  public boolean add(E);
+    descriptor: (Ljava/lang/Object;)Z
+}
+"""
+
+    jni_from_javap6 = jni_generator.JNIFromJavaP(content_javap6.split('\n'),
+                                                 TestOptions())
+    jni_from_javap7 = jni_generator.JNIFromJavaP(content_javap7.split('\n'),
+                                                 TestOptions())
+    jni_from_javap8 = jni_generator.JNIFromJavaP(content_javap8.split('\n'),
+                                                 TestOptions())
+    self.assertTrue(jni_from_javap6.GetContent())
+    self.assertTrue(jni_from_javap7.GetContent())
+    self.assertTrue(jni_from_javap8.GetContent())
+    # Ensure the javap7 is correctly parsed and uses the Signature field rather
+    # than the "E" parameter.
+    self.assertTextEquals(jni_from_javap6.GetContent(),
+                          jni_from_javap7.GetContent())
+    # Ensure the javap8 is correctly parsed and uses the descriptor field.
+    self.assertTextEquals(jni_from_javap7.GetContent(),
+                          jni_from_javap8.GetContent())
+
+  def testFromJavaP(self):
+    contents = self._ReadGoldenFile(os.path.join(os.path.dirname(sys.argv[0]),
+        'testInputStream.javap'))
+    jni_from_javap = jni_generator.JNIFromJavaP(contents.split('\n'),
+                                                TestOptions())
+    self.assertEquals(10, len(jni_from_javap.called_by_natives))
+    self.assertGoldenTextEquals(jni_from_javap.GetContent())
+
+  def testConstantsFromJavaP(self):
+    for f in ['testMotionEvent.javap', 'testMotionEvent.javap7']:
+      contents = self._ReadGoldenFile(os.path.join(os.path.dirname(sys.argv[0]),
+          f))
+      jni_from_javap = jni_generator.JNIFromJavaP(contents.split('\n'),
+                                                  TestOptions())
+      self.assertEquals(86, len(jni_from_javap.called_by_natives))
+      self.assertGoldenTextEquals(jni_from_javap.GetContent())
+
+  def testREForNatives(self):
+    # We should not match "native SyncSetupFlow" inside the comment.
+    test_data = """
+    /**
+     * Invoked when the setup process is complete so we can disconnect from the
+     * native-side SyncSetupFlowHandler.
+     */
+    public void destroy() {
+        Log.v(TAG, "Destroying native SyncSetupFlow");
+        if (mNativeSyncSetupFlow != 0) {
+            nativeSyncSetupEnded(mNativeSyncSetupFlow);
+            mNativeSyncSetupFlow = 0;
+        }
+    }
+    private native void nativeSyncSetupEnded(
+        int nativeAndroidSyncSetupFlowHandler);
+    """
+    jni_from_java = jni_generator.JNIFromJavaSource(
+        test_data, 'foo/bar', TestOptions())
+
+  def testRaisesOnNonJNIMethod(self):
+    test_data = """
+    class MyInnerClass {
+      private int Foo(int p0) {
+      }
+    }
+    """
+    self.assertRaises(SyntaxError,
+                      jni_generator.JNIFromJavaSource,
+                      test_data, 'foo/bar', TestOptions())
+
+  def testJniSelfDocumentingExample(self):
+    script_dir = os.path.dirname(sys.argv[0])
+    content = file(os.path.join(script_dir,
+        'java/src/org/chromium/example/jni_generator/SampleForTests.java')
+        ).read()
+    golden_file = os.path.join(script_dir, 'golden_sample_for_tests_jni.h')
+    golden_content = file(golden_file).read()
+    jni_from_java = jni_generator.JNIFromJavaSource(
+        content, 'org/chromium/example/jni_generator/SampleForTests',
+        TestOptions())
+    generated_text = jni_from_java.GetContent()
+    if not self.compareText(golden_content, generated_text):
+      if os.environ.get(REBASELINE_ENV):
+        with file(golden_file, 'w') as f:
+          f.write(generated_text)
+        return
+      self.fail('testJniSelfDocumentingExample')
+
+  def testNoWrappingPreprocessorLines(self):
+    test_data = """
+    package com.google.lookhowextremelylongiam.snarf.icankeepthisupallday;
+
+    class ReallyLongClassNamesAreAllTheRage {
+        private static native int nativeTest();
+    }
+    """
+    jni_from_java = jni_generator.JNIFromJavaSource(
+        test_data, ('com/google/lookhowextremelylongiam/snarf/'
+                    'icankeepthisupallday/ReallyLongClassNamesAreAllTheRage'),
+        TestOptions())
+    jni_lines = jni_from_java.GetContent().split('\n')
+    line = filter(lambda line: line.lstrip().startswith('#ifndef'),
+                  jni_lines)[0]
+    self.assertTrue(len(line) > 80,
+                    ('Expected #ifndef line to be > 80 chars: ', line))
+
+  def testJarJarRemapping(self):
+    test_data = """
+    package org.chromium.example.jni_generator;
+
+    import org.chromium.example2.Test;
+
+    import org.chromium.example3.PrefixFoo;
+    import org.chromium.example3.Prefix;
+    import org.chromium.example3.Bar$Inner;
+
+    class Example {
+      private static native void nativeTest(Test t);
+      private static native void nativeTest2(PrefixFoo t);
+      private static native void nativeTest3(Prefix t);
+      private static native void nativeTest4(Bar$Inner t);
+    }
+    """
+    jni_generator.JniParams.SetJarJarMappings(
+        """rule org.chromium.example.** com.test.@1
+        rule org.chromium.example2.** org.test2.@1
+        rule org.chromium.example3.Prefix org.test3.Test
+        rule org.chromium.example3.Bar$** org.test3.TestBar$@1""")
+    jni_from_java = jni_generator.JNIFromJavaSource(
+        test_data, 'org/chromium/example/jni_generator/Example', TestOptions())
+    jni_generator.JniParams.SetJarJarMappings('')
+    self.assertGoldenTextEquals(jni_from_java.GetContent())
+
+  def testImports(self):
+    import_header = """
+// Copyright (c) 2012 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.content.app;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.SurfaceTexture;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.os.Process;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.Surface;
+
+import java.util.ArrayList;
+
+import org.chromium.base.CalledByNative;
+import org.chromium.base.JNINamespace;
+import org.chromium.content.app.ContentMain;
+import org.chromium.content.browser.SandboxedProcessConnection;
+import org.chromium.content.common.ISandboxedProcessCallback;
+import org.chromium.content.common.ISandboxedProcessService;
+import org.chromium.content.common.WillNotRaise.AnException;
+import org.chromium.content.common.WillRaise.AnException;
+
+import static org.chromium.Bar.Zoo;
+
+class Foo {
+  public static class BookmarkNode implements Parcelable {
+  }
+  public interface PasswordListObserver {
+  }
+}
+    """
+    jni_generator.JniParams.SetFullyQualifiedClass(
+        'org/chromium/content/app/Foo')
+    jni_generator.JniParams.ExtractImportsAndInnerClasses(import_header)
+    self.assertTrue('Lorg/chromium/content/common/ISandboxedProcessService' in
+                    jni_generator.JniParams._imports)
+    self.assertTrue('Lorg/chromium/Bar/Zoo' in
+                    jni_generator.JniParams._imports)
+    self.assertTrue('Lorg/chromium/content/app/Foo$BookmarkNode' in
+                    jni_generator.JniParams._inner_classes)
+    self.assertTrue('Lorg/chromium/content/app/Foo$PasswordListObserver' in
+                    jni_generator.JniParams._inner_classes)
+    self.assertEquals('Lorg/chromium/content/app/ContentMain$Inner;',
+                      jni_generator.JniParams.JavaToJni('ContentMain.Inner'))
+    self.assertRaises(SyntaxError,
+                      jni_generator.JniParams.JavaToJni,
+                      'AnException')
+
+  def testJniParamsJavaToJni(self):
+    self.assertTextEquals('I', JniParams.JavaToJni('int'))
+    self.assertTextEquals('[B', JniParams.JavaToJni('byte[]'))
+    self.assertTextEquals(
+        '[Ljava/nio/ByteBuffer;', JniParams.JavaToJni('java/nio/ByteBuffer[]'))
+
+  def testNativesLong(self):
+    test_options = TestOptions()
+    test_options.ptr_type = 'long'
+    test_data = """"
+    private native void nativeDestroy(long nativeChromeBrowserProvider);
+    """
+    jni_generator.JniParams.ExtractImportsAndInnerClasses(test_data)
+    natives = jni_generator.ExtractNatives(test_data, test_options.ptr_type)
+    golden_natives = [
+        NativeMethod(return_type='void', static=False, name='Destroy',
+                     params=[Param(datatype='long',
+                                   name='nativeChromeBrowserProvider')],
+                     java_class_name=None,
+                     type='method',
+                     p0_type='ChromeBrowserProvider',
+                     ptr_type=test_options.ptr_type),
+    ]
+    self.assertListEquals(golden_natives, natives)
+    h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni',
+                                             natives, [], [], test_options)
+    self.assertGoldenTextEquals(h.GetContent())
+
+  def testPureNativeMethodsOption(self):
+    test_data = """
+    package org.chromium.example.jni_generator;
+
+    /** The pointer to the native Test. */
+    long nativeTest;
+
+    class Test {
+        private static native long nativeMethod(long nativeTest, int arg1);
+    }
+    """
+    options = TestOptions()
+    options.pure_native_methods = True
+    jni_from_java = jni_generator.JNIFromJavaSource(
+        test_data, 'org/chromium/example/jni_generator/Test', options)
+    self.assertGoldenTextEquals(jni_from_java.GetContent())
+
+  def testJNIInitNativeNameOption(self):
+    test_data = """
+    package org.chromium.example.jni_generator;
+
+    /** The pointer to the native Test. */
+    long nativeTest;
+
+    class Test {
+        private static native boolean nativeInitNativeClass();
+        private static native int nativeMethod(long nativeTest, int arg1);
+    }
+    """
+    options = TestOptions()
+    options.jni_init_native_name = 'nativeInitNativeClass'
+    jni_from_java = jni_generator.JNIFromJavaSource(
+        test_data, 'org/chromium/example/jni_generator/Test', options)
+    self.assertGoldenTextEquals(jni_from_java.GetContent())
+
+  def testEagerCalledByNativesOption(self):
+    test_data = """
+    package org.chromium.example.jni_generator;
+
+    /** The pointer to the native Test. */
+    long nativeTest;
+
+    class Test {
+        private static native boolean nativeInitNativeClass();
+        private static native int nativeMethod(long nativeTest, int arg1);
+        @CalledByNative
+        private void testMethodWithParam(int iParam);
+        @CalledByNative
+        private static int testStaticMethodWithParam(int iParam);
+        @CalledByNative
+        private static double testMethodWithNoParam();
+        @CalledByNative
+        private static String testStaticMethodWithNoParam();
+    }
+    """
+    options = TestOptions()
+    options.jni_init_native_name = 'nativeInitNativeClass'
+    options.eager_called_by_natives = True
+    jni_from_java = jni_generator.JNIFromJavaSource(
+        test_data, 'org/chromium/example/jni_generator/Test', options)
+    self.assertGoldenTextEquals(jni_from_java.GetContent())
+
+  def runNativeExportsOption(self, optional):
+    test_data = """
+    package org.chromium.example.jni_generator;
+
+    /** The pointer to the native Test. */
+    long nativeTest;
+
+    class Test {
+        private static native boolean nativeInitNativeClass();
+        private static native int nativeStaticMethod(long nativeTest, int arg1);
+        private native int nativeMethod(long nativeTest, int arg1);
+        @CalledByNative
+        private void testMethodWithParam(int iParam);
+        @CalledByNative
+        private String testMethodWithParamAndReturn(int iParam);
+        @CalledByNative
+        private static int testStaticMethodWithParam(int iParam);
+        @CalledByNative
+        private static double testMethodWithNoParam();
+        @CalledByNative
+        private static String testStaticMethodWithNoParam();
+
+        class MyInnerClass {
+          @NativeCall("MyInnerClass")
+          private native int nativeInit();
+        }
+        class MyOtherInnerClass {
+          @NativeCall("MyOtherInnerClass")
+          private native int nativeInit();
+        }
+    }
+    """
+    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)
+    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 = """
+    package org.chromium.media;
+
+    @CalledByNative
+    static int getCaptureFormatWidth(VideoCapture.CaptureFormat format) {
+        return format.getWidth();
+    }
+    """
+    def willRaise():
+      jni_generator.JNIFromJavaSource(
+          test_data,
+          'org/chromium/media/VideoCaptureFactory',
+          TestOptions())
+    self.assertRaises(SyntaxError, willRaise)
+
+  def testImplicitImport(self):
+    test_data = """
+    package org.chromium.android_webview;
+
+    %(IMPORT)s
+
+    @CalledByNative
+    private static void clientCertificatesCleared(Runnable callback) {
+        if (callbaback == null) return;
+        callback.run();
+    }
+    """
+    def generate(import_clause):
+      jni_generator.JNIFromJavaSource(
+          test_data % {'IMPORT': import_clause},
+          'org/chromium/android_webview/AwContentStatics',
+          TestOptions())
+    # Ensure it raises without the import.
+    self.assertRaises(SyntaxError, lambda: generate(''))
+
+    # Ensure it's fine with the import.
+    generate('import java.lang.Runnable;')
+
+  def testSingleJNIAdditionalImport(self):
+    test_data = """
+    package org.chromium.foo;
+
+    @JNIAdditionalImport(Bar.class)
+    class Foo {
+
+    @CalledByNative
+    private static void calledByNative(Bar.Callback callback) {
+    }
+
+    private static native void nativeDoSomething(Bar.Callback callback);
+    }
+    """
+    jni_from_java = jni_generator.JNIFromJavaSource(test_data,
+                                                    'org/chromium/foo/Foo',
+                                                    TestOptions())
+    self.assertGoldenTextEquals(jni_from_java.GetContent())
+
+  def testMultipleJNIAdditionalImport(self):
+    test_data = """
+    package org.chromium.foo;
+
+    @JNIAdditionalImport({Bar1.class, Bar2.class})
+    class Foo {
+
+    @CalledByNative
+    private static void calledByNative(Bar1.Callback callback1,
+                                       Bar2.Callback callback2) {
+    }
+
+    private static native void nativeDoSomething(Bar1.Callback callback1,
+                                                 Bar2.Callback callback2);
+    }
+    """
+    jni_from_java = jni_generator.JNIFromJavaSource(test_data,
+                                                    'org/chromium/foo/Foo',
+                                                    TestOptions())
+    self.assertGoldenTextEquals(jni_from_java.GetContent())
+
+
+def TouchStamp(stamp_path):
+  dir_name = os.path.dirname(stamp_path)
+  if not os.path.isdir(dir_name):
+    os.makedirs()
+
+  with open(stamp_path, 'a'):
+    os.utime(stamp_path, None)
+
+
+def main(argv):
+  parser = optparse.OptionParser()
+  parser.add_option('--stamp', help='Path to touch on success.')
+  options, _ = parser.parse_args(argv[1:])
+
+  test_result = unittest.main(argv=argv[0:1], exit=False)
+
+  if test_result.result.wasSuccessful() and options.stamp:
+    TouchStamp(options.stamp)
+
+  return not test_result.result.wasSuccessful()
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv))
diff --git a/base/android/jni_generator/sample_for_tests.cc b/base/android/jni_generator/sample_for_tests.cc
new file mode 100644
index 0000000..3c5ca02
--- /dev/null
+++ b/base/android/jni_generator/sample_for_tests.cc
@@ -0,0 +1,120 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/jni_generator/sample_for_tests.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/android/scoped_java_ref.h"
+// Generated file for JNI bindings from C++ to Java @CalledByNative methods.
+// Only to be included in one .cc file.
+// Name is based on the java file name: *.java -> jni/*_jni.h
+#include "jni/SampleForTests_jni.h"  // Generated by JNI.
+
+using base::android::AttachCurrentThread;
+using base::android::ScopedJavaLocalRef;
+
+namespace base {
+namespace android {
+
+jdouble CPPClass::InnerClass::MethodOtherP0(JNIEnv* env, jobject obj) {
+  return 0.0;
+}
+
+CPPClass::CPPClass() {
+}
+
+CPPClass::~CPPClass() {
+}
+
+// static
+bool CPPClass::RegisterJNI(JNIEnv* env) {
+  return RegisterNativesImpl(env);  // Generated in SampleForTests_jni.h
+}
+
+void CPPClass::Destroy(JNIEnv* env, jobject obj) {
+  delete this;
+}
+
+jint CPPClass::Method(JNIEnv* env, jobject obj) {
+  return 0;
+}
+
+void CPPClass::AddStructB(JNIEnv* env, jobject obj, jobject structb) {
+  long key = Java_InnerStructB_getKey(env, structb);
+  std::string value = ConvertJavaStringToUTF8(
+      env, Java_InnerStructB_getValue(env, structb).obj());
+  map_[key] = value;
+}
+
+void CPPClass::IterateAndDoSomethingWithStructB(JNIEnv* env, jobject obj) {
+  // Iterate over the elements and do something with them.
+  for (std::map<long, std::string>::const_iterator it = map_.begin();
+       it != map_.end(); ++it) {
+    long key = it->first;
+    std::string value = it->second;
+  }
+  map_.clear();
+}
+
+base::android::ScopedJavaLocalRef<jstring> CPPClass::ReturnAString(
+    JNIEnv* env, jobject obj) {
+  base::android::ScopedJavaLocalRef<jstring> ret = ConvertUTF8ToJavaString(
+      env, "test");
+  return ret;
+}
+
+// Static free functions declared and called directly from java.
+static jlong Init(JNIEnv* env, jobject obj, jstring param) {
+  return 0;
+}
+
+static jdouble GetDoubleFunction(JNIEnv*, jobject) {
+  return 0;
+}
+
+static jfloat GetFloatFunction(JNIEnv*, jclass) {
+  return 0;
+}
+
+static void SetNonPODDatatype(JNIEnv*, jobject, jobject) {
+}
+
+static jobject GetNonPODDatatype(JNIEnv*, jobject) {
+  return NULL;
+}
+
+static jint InnerFunction(JNIEnv*, jclass) {
+  return 0;
+}
+
+} // namespace android
+} // namespace base
+
+int main() {
+  // On a regular application, you'd call AttachCurrentThread(). This sample is
+  // not yet linking with all the libraries.
+  JNIEnv* env = /* AttachCurrentThread() */ NULL;
+
+  // This is how you call a java static method from C++.
+  bool foo = base::android::Java_SampleForTests_staticJavaMethod(env);
+
+  // This is how you call a java method from C++. Note that you must have
+  // obtained the jobject somehow.
+  jobject my_java_object = NULL;
+  int bar = base::android::Java_SampleForTests_javaMethod(
+      env, my_java_object, 1, 2);
+
+  for (int i = 0; i < 10; ++i) {
+    // Creates a "struct" that will then be used by the java side.
+    ScopedJavaLocalRef<jobject> struct_a =
+        base::android::Java_InnerStructA_create(
+            env, 0, 1,
+            base::android::ConvertUTF8ToJavaString(env, "test").obj());
+    base::android::Java_SampleForTests_addStructA(
+        env, my_java_object, struct_a.obj());
+  }
+  base::android::Java_SampleForTests_iterateAndDoSomething(env, my_java_object);
+  return 0;
+}
diff --git a/base/android/jni_generator/sample_for_tests.h b/base/android/jni_generator/sample_for_tests.h
new file mode 100644
index 0000000..e878e56
--- /dev/null
+++ b/base/android/jni_generator/sample_for_tests.h
@@ -0,0 +1,174 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_JNI_GENERATOR_SAMPLE_FOR_TESTS_H_
+#define BASE_ANDROID_JNI_GENERATOR_SAMPLE_FOR_TESTS_H_
+
+#include <jni.h>
+#include <map>
+#include <string>
+
+#include "base/android/jni_android.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace android {
+
+// This file is used to:
+// - document the best practices and guidelines on JNI usage.
+// - ensure sample_for_tests_jni.h compiles and the functions declared in it
+// as expected.
+//
+// Methods are called directly from Java (except RegisterJNI). More
+// documentation in SampleForTests.java
+//
+// For C++ to access Java methods:
+// - GYP Build must be configured to generate bindings:
+//  # ...
+//  'targets': [
+//    {
+//      # An example target that will rely on JNI:
+//      'target_name': 'foo',
+//      'type': '<(component)',
+//      # ... normal sources, defines, deps.
+//      #     For each jni generated .java -> .h header file in foo_jni_headers
+//      #     target there will be a single .cc file here that includes it.
+//      #
+//      # Add deps for JNI:
+//      'conditions': [
+//        ['OS == "android"', {
+//          'dependencies': [
+//            'foo_java',
+//            'foo_jni_headers',
+//          ],
+//        }],
+//      ],
+//    },
+//  ],
+//  # ...
+//  # Create targets for JNI:
+//  'conditions': [
+//    ['OS == "android"', {
+//      'targets': [
+//        {
+//          'target_name': 'foo_jni_headers',
+//          'type': 'none',
+//          'sources': [
+//            'java/src/org/chromium/example/jni_generator/SampleForTests.java',
+//          ],
+//          'variables': {
+//            'jni_gen_package': 'foo',
+//          },
+//          'includes': [ '../../../build/jni_generator.gypi' ],
+//        },
+//        {
+//          'target_name': 'foo_java',
+//          'type': 'none',
+//          'dependencies': [
+//            '../../../base/base.gyp:base',
+//          ],
+//          'variables': {
+//            'java_in_dir': 'java',
+//          },
+//          'includes': [ '../../../build/java.gypi' ],
+//        },
+//      ],
+//    }],
+//  ],
+//
+// - GN Build must be configured to generate bindings:
+//  # Add import at top of file:
+//  if (is_android) {
+//    import("//build/config/android/rules.gni")  # For generate_jni().
+//  }
+//  # ...
+//  # An example target that will rely on JNI:
+//  component("foo") {
+//    # ... normal sources, defines, deps.
+//    #     For each jni generated .java -> .h header file in jni_headers
+//    #     target there will be a single .cc file here that includes it.
+//    #
+//    # Add a dep for JNI:
+//    if (is_android) {
+//      deps += [ ":foo_jni" ]
+//    }
+//  }
+//  # ...
+//  # Create target for JNI:
+//  if (is_android) {
+//    generate_jni("jni_headers") {
+//      sources = [
+//        "java/src/org/chromium/example/jni_generator/SampleForTests.java",
+//      ]
+//      jni_package = "foo"
+//    }
+//    android_library("java") {
+//      java_files = [
+//        "java/src/org/chromium/example/jni_generator/SampleForTests.java",
+//        "java/src/org/chromium/example/jni_generator/NonJniFile.java",
+//      ]
+//    }
+//  }
+//
+// For C++ methods to be exposed to Java:
+// - The generated RegisterNativesImpl method must be called, this is typically
+//   done by having a static RegisterJNI method in the C++ class.
+// - The RegisterJNI method is added to a module's collection of register
+//   methods, such as: example_jni_registrar.h/cc files which call
+//   base::android::RegisterNativeMethods.
+//   An example_jni_registstrar.cc:
+//
+//     namespace {
+//     const base::android::RegistrationMethod kRegisteredMethods[] = {
+//         // Initial string is for debugging only.
+//         { "ExampleName", base::ExampleNameAndroid::RegisterJNI },
+//         { "ExampleName2", base::ExampleName2Android::RegisterJNI },
+//     };
+//     }  // namespace
+//
+//     bool RegisterModuleNameJni(JNIEnv* env) {
+//       return RegisterNativeMethods(env, kRegisteredMethods,
+//                                    arraysize(kRegisteredMethods));
+//     }
+//
+//  - Each module's RegisterModuleNameJni must be called by a larger module,
+//    or application during startup.
+//
+class CPPClass {
+ public:
+  CPPClass();
+  ~CPPClass();
+
+  // Register C++ methods exposed to Java using JNI.
+  static bool RegisterJNI(JNIEnv* env);
+
+  // Java @CalledByNative methods implicitly available to C++ via the _jni.h
+  // file included in the .cc file.
+
+  class InnerClass {
+   public:
+    jdouble MethodOtherP0(JNIEnv* env, jobject obj);
+  };
+
+  void Destroy(JNIEnv* env, jobject obj);
+
+  jint Method(JNIEnv* env, jobject obj);
+
+  void AddStructB(JNIEnv* env, jobject obj, jobject structb);
+
+  void IterateAndDoSomethingWithStructB(JNIEnv* env, jobject obj);
+
+  base::android::ScopedJavaLocalRef<jstring> ReturnAString(
+      JNIEnv* env, jobject obj);
+
+ private:
+  std::map<long, std::string> map_;
+
+  DISALLOW_COPY_AND_ASSIGN(CPPClass);
+};
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_JNI_GENERATOR_SAMPLE_FOR_TESTS_H_
diff --git a/base/android/jni_generator/testCalledByNatives.golden b/base/android/jni_generator/testCalledByNatives.golden
new file mode 100644
index 0000000..e33356a
--- /dev/null
+++ b/base/android/jni_generator/testCalledByNatives.golden
@@ -0,0 +1,510 @@
+// 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/TestJni
+
+#ifndef org_chromium_TestJni_JNI
+#define org_chromium_TestJni_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 kTestJniClassPath[] = "org/chromium/TestJni";
+const char kInfoBarClassPath[] = "org/chromium/TestJni$InfoBar";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_TestJni_clazz = NULL;
+#define TestJni_clazz(env) g_TestJni_clazz
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_InfoBar_clazz = NULL;
+#define InfoBar_clazz(env) g_InfoBar_clazz
+
+}  // namespace
+
+// Step 2: method stubs.
+
+static base::subtle::AtomicWord g_TestJni_showConfirmInfoBar = 0;
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_TestJni_showConfirmInfoBar(JNIEnv* env, jobject obj, JniIntWrapper
+    nativeInfoBar,
+    jstring buttonOk,
+    jstring buttonCancel,
+    jstring title,
+    jobject icon) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      TestJni_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, TestJni_clazz(env),
+      "showConfirmInfoBar",
+
+"("
+"I"
+"Ljava/lang/String;"
+"Ljava/lang/String;"
+"Ljava/lang/String;"
+"Landroid/graphics/Bitmap;"
+")"
+"Lorg/chromium/Foo$InnerClass;",
+      &g_TestJni_showConfirmInfoBar);
+
+  jobject ret =
+      env->CallObjectMethod(obj,
+          method_id, as_jint(nativeInfoBar), buttonOk, buttonCancel, title,
+              icon);
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
+}
+
+static base::subtle::AtomicWord g_TestJni_showAutoLoginInfoBar = 0;
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_TestJni_showAutoLoginInfoBar(JNIEnv* env, jobject obj, JniIntWrapper
+    nativeInfoBar,
+    jstring realm,
+    jstring account,
+    jstring args) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      TestJni_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, TestJni_clazz(env),
+      "showAutoLoginInfoBar",
+
+"("
+"I"
+"Ljava/lang/String;"
+"Ljava/lang/String;"
+"Ljava/lang/String;"
+")"
+"Lorg/chromium/Foo$InnerClass;",
+      &g_TestJni_showAutoLoginInfoBar);
+
+  jobject ret =
+      env->CallObjectMethod(obj,
+          method_id, as_jint(nativeInfoBar), realm, account, args);
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
+}
+
+static base::subtle::AtomicWord g_InfoBar_dismiss = 0;
+static void Java_InfoBar_dismiss(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      InfoBar_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, InfoBar_clazz(env),
+      "dismiss",
+
+"("
+")"
+"V",
+      &g_InfoBar_dismiss);
+
+     env->CallVoidMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_TestJni_shouldShowAutoLogin = 0;
+static jboolean Java_TestJni_shouldShowAutoLogin(JNIEnv* env, jobject view,
+    jstring realm,
+    jstring account,
+    jstring args) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, TestJni_clazz(env),
+      TestJni_clazz(env), false);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, TestJni_clazz(env),
+      "shouldShowAutoLogin",
+
+"("
+"Landroid/view/View;"
+"Ljava/lang/String;"
+"Ljava/lang/String;"
+"Ljava/lang/String;"
+")"
+"Z",
+      &g_TestJni_shouldShowAutoLogin);
+
+  jboolean ret =
+      env->CallStaticBooleanMethod(TestJni_clazz(env),
+          method_id, view, realm, account, args);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_TestJni_openUrl = 0;
+static base::android::ScopedJavaLocalRef<jobject> Java_TestJni_openUrl(JNIEnv*
+    env, jstring url) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, TestJni_clazz(env),
+      TestJni_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, TestJni_clazz(env),
+      "openUrl",
+
+"("
+"Ljava/lang/String;"
+")"
+"Ljava/io/InputStream;",
+      &g_TestJni_openUrl);
+
+  jobject ret =
+      env->CallStaticObjectMethod(TestJni_clazz(env),
+          method_id, url);
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
+}
+
+static base::subtle::AtomicWord g_TestJni_activateHardwareAcceleration = 0;
+static void Java_TestJni_activateHardwareAcceleration(JNIEnv* env, jobject obj,
+    jboolean activated,
+    JniIntWrapper iPid,
+    JniIntWrapper iType,
+    JniIntWrapper iPrimaryID,
+    JniIntWrapper iSecondaryID) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      TestJni_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, TestJni_clazz(env),
+      "activateHardwareAcceleration",
+
+"("
+"Z"
+"I"
+"I"
+"I"
+"I"
+")"
+"V",
+      &g_TestJni_activateHardwareAcceleration);
+
+     env->CallVoidMethod(obj,
+          method_id, activated, as_jint(iPid), as_jint(iType),
+              as_jint(iPrimaryID), as_jint(iSecondaryID));
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_TestJni_uncheckedCall = 0;
+static void Java_TestJni_uncheckedCall(JNIEnv* env, jobject obj, JniIntWrapper
+    iParam) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      TestJni_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, TestJni_clazz(env),
+      "uncheckedCall",
+
+"("
+"I"
+")"
+"V",
+      &g_TestJni_uncheckedCall);
+
+     env->CallVoidMethod(obj,
+          method_id, as_jint(iParam));
+
+}
+
+static base::subtle::AtomicWord g_TestJni_returnByteArray = 0;
+static base::android::ScopedJavaLocalRef<jbyteArray>
+    Java_TestJni_returnByteArray(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      TestJni_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, TestJni_clazz(env),
+      "returnByteArray",
+
+"("
+")"
+"[B",
+      &g_TestJni_returnByteArray);
+
+  jbyteArray ret =
+      static_cast<jbyteArray>(env->CallObjectMethod(obj,
+          method_id));
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jbyteArray>(env, ret);
+}
+
+static base::subtle::AtomicWord g_TestJni_returnBooleanArray = 0;
+static base::android::ScopedJavaLocalRef<jbooleanArray>
+    Java_TestJni_returnBooleanArray(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      TestJni_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, TestJni_clazz(env),
+      "returnBooleanArray",
+
+"("
+")"
+"[Z",
+      &g_TestJni_returnBooleanArray);
+
+  jbooleanArray ret =
+      static_cast<jbooleanArray>(env->CallObjectMethod(obj,
+          method_id));
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jbooleanArray>(env, ret);
+}
+
+static base::subtle::AtomicWord g_TestJni_returnCharArray = 0;
+static base::android::ScopedJavaLocalRef<jcharArray>
+    Java_TestJni_returnCharArray(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      TestJni_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, TestJni_clazz(env),
+      "returnCharArray",
+
+"("
+")"
+"[C",
+      &g_TestJni_returnCharArray);
+
+  jcharArray ret =
+      static_cast<jcharArray>(env->CallObjectMethod(obj,
+          method_id));
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jcharArray>(env, ret);
+}
+
+static base::subtle::AtomicWord g_TestJni_returnShortArray = 0;
+static base::android::ScopedJavaLocalRef<jshortArray>
+    Java_TestJni_returnShortArray(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      TestJni_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, TestJni_clazz(env),
+      "returnShortArray",
+
+"("
+")"
+"[S",
+      &g_TestJni_returnShortArray);
+
+  jshortArray ret =
+      static_cast<jshortArray>(env->CallObjectMethod(obj,
+          method_id));
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jshortArray>(env, ret);
+}
+
+static base::subtle::AtomicWord g_TestJni_returnIntArray = 0;
+static base::android::ScopedJavaLocalRef<jintArray>
+    Java_TestJni_returnIntArray(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      TestJni_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, TestJni_clazz(env),
+      "returnIntArray",
+
+"("
+")"
+"[I",
+      &g_TestJni_returnIntArray);
+
+  jintArray ret =
+      static_cast<jintArray>(env->CallObjectMethod(obj,
+          method_id));
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jintArray>(env, ret);
+}
+
+static base::subtle::AtomicWord g_TestJni_returnLongArray = 0;
+static base::android::ScopedJavaLocalRef<jlongArray>
+    Java_TestJni_returnLongArray(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      TestJni_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, TestJni_clazz(env),
+      "returnLongArray",
+
+"("
+")"
+"[J",
+      &g_TestJni_returnLongArray);
+
+  jlongArray ret =
+      static_cast<jlongArray>(env->CallObjectMethod(obj,
+          method_id));
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jlongArray>(env, ret);
+}
+
+static base::subtle::AtomicWord g_TestJni_returnDoubleArray = 0;
+static base::android::ScopedJavaLocalRef<jdoubleArray>
+    Java_TestJni_returnDoubleArray(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      TestJni_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, TestJni_clazz(env),
+      "returnDoubleArray",
+
+"("
+")"
+"[D",
+      &g_TestJni_returnDoubleArray);
+
+  jdoubleArray ret =
+      static_cast<jdoubleArray>(env->CallObjectMethod(obj,
+          method_id));
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jdoubleArray>(env, ret);
+}
+
+static base::subtle::AtomicWord g_TestJni_returnObjectArray = 0;
+static base::android::ScopedJavaLocalRef<jobjectArray>
+    Java_TestJni_returnObjectArray(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      TestJni_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, TestJni_clazz(env),
+      "returnObjectArray",
+
+"("
+")"
+"[Ljava/lang/Object;",
+      &g_TestJni_returnObjectArray);
+
+  jobjectArray ret =
+      static_cast<jobjectArray>(env->CallObjectMethod(obj,
+          method_id));
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jobjectArray>(env, ret);
+}
+
+static base::subtle::AtomicWord g_TestJni_returnArrayOfByteArray = 0;
+static base::android::ScopedJavaLocalRef<jobjectArray>
+    Java_TestJni_returnArrayOfByteArray(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      TestJni_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, TestJni_clazz(env),
+      "returnArrayOfByteArray",
+
+"("
+")"
+"[[B",
+      &g_TestJni_returnArrayOfByteArray);
+
+  jobjectArray ret =
+      static_cast<jobjectArray>(env->CallObjectMethod(obj,
+          method_id));
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jobjectArray>(env, ret);
+}
+
+static base::subtle::AtomicWord g_TestJni_getCompressFormat = 0;
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_TestJni_getCompressFormat(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      TestJni_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, TestJni_clazz(env),
+      "getCompressFormat",
+
+"("
+")"
+"Landroid/graphics/Bitmap$CompressFormat;",
+      &g_TestJni_getCompressFormat);
+
+  jobject ret =
+      env->CallObjectMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
+}
+
+static base::subtle::AtomicWord g_TestJni_getCompressFormatList = 0;
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_TestJni_getCompressFormatList(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      TestJni_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, TestJni_clazz(env),
+      "getCompressFormatList",
+
+"("
+")"
+"Ljava/util/List;",
+      &g_TestJni_getCompressFormatList);
+
+  jobject ret =
+      env->CallObjectMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
+}
+
+// Step 3: RegisterNatives.
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+  g_TestJni_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetClass(env, kTestJniClassPath).obj()));
+  g_InfoBar_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetClass(env, kInfoBarClassPath).obj()));
+
+  return true;
+}
+
+#endif  // org_chromium_TestJni_JNI
diff --git a/base/android/jni_generator/testConstantsFromJavaP.golden b/base/android/jni_generator/testConstantsFromJavaP.golden
new file mode 100644
index 0000000..1c816bc
--- /dev/null
+++ b/base/android/jni_generator/testConstantsFromJavaP.golden
@@ -0,0 +1,2233 @@
+// 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
+//     android/view/MotionEvent
+
+#ifndef android_view_MotionEvent_JNI
+#define android_view_MotionEvent_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 kMotionEventClassPath[] = "android/view/MotionEvent";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_MotionEvent_clazz = NULL;
+#define MotionEvent_clazz(env) g_MotionEvent_clazz
+
+}  // namespace
+
+namespace JNI_MotionEvent {
+
+enum Java_MotionEvent_constant_fields {
+  INVALID_POINTER_ID = -1,
+  ACTION_MASK = 255,
+  ACTION_DOWN = 0,
+  ACTION_UP = 1,
+  ACTION_MOVE = 2,
+  ACTION_CANCEL = 3,
+  ACTION_OUTSIDE = 4,
+  ACTION_POINTER_DOWN = 5,
+  ACTION_POINTER_UP = 6,
+  ACTION_HOVER_MOVE = 7,
+  ACTION_SCROLL = 8,
+  ACTION_HOVER_ENTER = 9,
+  ACTION_HOVER_EXIT = 10,
+  ACTION_POINTER_INDEX_MASK = 65280,
+  ACTION_POINTER_INDEX_SHIFT = 8,
+  ACTION_POINTER_1_DOWN = 5,
+  ACTION_POINTER_2_DOWN = 261,
+  ACTION_POINTER_3_DOWN = 517,
+  ACTION_POINTER_1_UP = 6,
+  ACTION_POINTER_2_UP = 262,
+  ACTION_POINTER_3_UP = 518,
+  ACTION_POINTER_ID_MASK = 65280,
+  ACTION_POINTER_ID_SHIFT = 8,
+  FLAG_WINDOW_IS_OBSCURED = 1,
+  EDGE_TOP = 1,
+  EDGE_BOTTOM = 2,
+  EDGE_LEFT = 4,
+  EDGE_RIGHT = 8,
+  AXIS_X = 0,
+  AXIS_Y = 1,
+  AXIS_PRESSURE = 2,
+  AXIS_SIZE = 3,
+  AXIS_TOUCH_MAJOR = 4,
+  AXIS_TOUCH_MINOR = 5,
+  AXIS_TOOL_MAJOR = 6,
+  AXIS_TOOL_MINOR = 7,
+  AXIS_ORIENTATION = 8,
+  AXIS_VSCROLL = 9,
+  AXIS_HSCROLL = 10,
+  AXIS_Z = 11,
+  AXIS_RX = 12,
+  AXIS_RY = 13,
+  AXIS_RZ = 14,
+  AXIS_HAT_X = 15,
+  AXIS_HAT_Y = 16,
+  AXIS_LTRIGGER = 17,
+  AXIS_RTRIGGER = 18,
+  AXIS_THROTTLE = 19,
+  AXIS_RUDDER = 20,
+  AXIS_WHEEL = 21,
+  AXIS_GAS = 22,
+  AXIS_BRAKE = 23,
+  AXIS_DISTANCE = 24,
+  AXIS_TILT = 25,
+  AXIS_GENERIC_1 = 32,
+  AXIS_GENERIC_2 = 33,
+  AXIS_GENERIC_3 = 34,
+  AXIS_GENERIC_4 = 35,
+  AXIS_GENERIC_5 = 36,
+  AXIS_GENERIC_6 = 37,
+  AXIS_GENERIC_7 = 38,
+  AXIS_GENERIC_8 = 39,
+  AXIS_GENERIC_9 = 40,
+  AXIS_GENERIC_10 = 41,
+  AXIS_GENERIC_11 = 42,
+  AXIS_GENERIC_12 = 43,
+  AXIS_GENERIC_13 = 44,
+  AXIS_GENERIC_14 = 45,
+  AXIS_GENERIC_15 = 46,
+  AXIS_GENERIC_16 = 47,
+  BUTTON_PRIMARY = 1,
+  BUTTON_SECONDARY = 2,
+  BUTTON_TERTIARY = 4,
+  BUTTON_BACK = 8,
+  BUTTON_FORWARD = 16,
+  TOOL_TYPE_UNKNOWN = 0,
+  TOOL_TYPE_FINGER = 1,
+  TOOL_TYPE_STYLUS = 2,
+  TOOL_TYPE_MOUSE = 3,
+  TOOL_TYPE_ERASER = 4,
+};
+
+// Step 2: method stubs.
+
+static base::subtle::AtomicWord g_MotionEvent_finalize = 0;
+static void Java_MotionEvent_finalize(JNIEnv* env, jobject obj) __attribute__
+    ((unused));
+static void Java_MotionEvent_finalize(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "finalize",
+      "()V",
+      &g_MotionEvent_finalize);
+
+     env->CallVoidMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord
+    g_MotionEvent_obtainAVME_J_J_I_I_LAVMEPP_LAVMEPC_I_I_F_F_I_I_I_I = 0;
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_MotionEvent_obtainAVME_J_J_I_I_LAVMEPP_LAVMEPC_I_I_F_F_I_I_I_I(JNIEnv*
+    env, jlong p0,
+    jlong p1,
+    JniIntWrapper p2,
+    JniIntWrapper p3,
+    jobjectArray p4,
+    jobjectArray p5,
+    JniIntWrapper p6,
+    JniIntWrapper p7,
+    jfloat p8,
+    jfloat p9,
+    JniIntWrapper p10,
+    JniIntWrapper p11,
+    JniIntWrapper p12,
+    JniIntWrapper p13) __attribute__ ((unused));
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_MotionEvent_obtainAVME_J_J_I_I_LAVMEPP_LAVMEPC_I_I_F_F_I_I_I_I(JNIEnv*
+    env, jlong p0,
+    jlong p1,
+    JniIntWrapper p2,
+    JniIntWrapper p3,
+    jobjectArray p4,
+    jobjectArray p5,
+    JniIntWrapper p6,
+    JniIntWrapper p7,
+    jfloat p8,
+    jfloat p9,
+    JniIntWrapper p10,
+    JniIntWrapper p11,
+    JniIntWrapper p12,
+    JniIntWrapper p13) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, MotionEvent_clazz(env),
+      MotionEvent_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, MotionEvent_clazz(env),
+      "obtain",
+"(JJII[Landroid/view/MotionEvent$PointerProperties;[Landroid/view/MotionEvent$PointerCoords;IIFFIIII)Landroid/view/MotionEvent;",
+      &g_MotionEvent_obtainAVME_J_J_I_I_LAVMEPP_LAVMEPC_I_I_F_F_I_I_I_I);
+
+  jobject ret =
+      env->CallStaticObjectMethod(MotionEvent_clazz(env),
+          method_id, p0, p1, as_jint(p2), as_jint(p3), p4, p5, as_jint(p6),
+              as_jint(p7), p8, p9, as_jint(p10), as_jint(p11), as_jint(p12),
+              as_jint(p13));
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
+}
+
+static base::subtle::AtomicWord
+    g_MotionEvent_obtainAVME_J_J_I_I_AI_LAVMEPC_I_F_F_I_I_I_I = 0;
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_MotionEvent_obtainAVME_J_J_I_I_AI_LAVMEPC_I_F_F_I_I_I_I(JNIEnv* env,
+    jlong p0,
+    jlong p1,
+    JniIntWrapper p2,
+    JniIntWrapper p3,
+    jintArray p4,
+    jobjectArray p5,
+    JniIntWrapper p6,
+    jfloat p7,
+    jfloat p8,
+    JniIntWrapper p9,
+    JniIntWrapper p10,
+    JniIntWrapper p11,
+    JniIntWrapper p12) __attribute__ ((unused));
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_MotionEvent_obtainAVME_J_J_I_I_AI_LAVMEPC_I_F_F_I_I_I_I(JNIEnv* env,
+    jlong p0,
+    jlong p1,
+    JniIntWrapper p2,
+    JniIntWrapper p3,
+    jintArray p4,
+    jobjectArray p5,
+    JniIntWrapper p6,
+    jfloat p7,
+    jfloat p8,
+    JniIntWrapper p9,
+    JniIntWrapper p10,
+    JniIntWrapper p11,
+    JniIntWrapper p12) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, MotionEvent_clazz(env),
+      MotionEvent_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, MotionEvent_clazz(env),
+      "obtain",
+"(JJII[I[Landroid/view/MotionEvent$PointerCoords;IFFIIII)Landroid/view/MotionEvent;",
+      &g_MotionEvent_obtainAVME_J_J_I_I_AI_LAVMEPC_I_F_F_I_I_I_I);
+
+  jobject ret =
+      env->CallStaticObjectMethod(MotionEvent_clazz(env),
+          method_id, p0, p1, as_jint(p2), as_jint(p3), p4, p5, as_jint(p6), p7,
+              p8, as_jint(p9), as_jint(p10), as_jint(p11), as_jint(p12));
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
+}
+
+static base::subtle::AtomicWord g_MotionEvent_obtainAVME_J_J_I_F_F_F_F_I_F_F_I_I
+    = 0;
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_MotionEvent_obtainAVME_J_J_I_F_F_F_F_I_F_F_I_I(JNIEnv* env, jlong p0,
+    jlong p1,
+    JniIntWrapper p2,
+    jfloat p3,
+    jfloat p4,
+    jfloat p5,
+    jfloat p6,
+    JniIntWrapper p7,
+    jfloat p8,
+    jfloat p9,
+    JniIntWrapper p10,
+    JniIntWrapper p11) __attribute__ ((unused));
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_MotionEvent_obtainAVME_J_J_I_F_F_F_F_I_F_F_I_I(JNIEnv* env, jlong p0,
+    jlong p1,
+    JniIntWrapper p2,
+    jfloat p3,
+    jfloat p4,
+    jfloat p5,
+    jfloat p6,
+    JniIntWrapper p7,
+    jfloat p8,
+    jfloat p9,
+    JniIntWrapper p10,
+    JniIntWrapper p11) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, MotionEvent_clazz(env),
+      MotionEvent_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, MotionEvent_clazz(env),
+      "obtain",
+      "(JJIFFFFIFFII)Landroid/view/MotionEvent;",
+      &g_MotionEvent_obtainAVME_J_J_I_F_F_F_F_I_F_F_I_I);
+
+  jobject ret =
+      env->CallStaticObjectMethod(MotionEvent_clazz(env),
+          method_id, p0, p1, as_jint(p2), p3, p4, p5, p6, as_jint(p7), p8, p9,
+              as_jint(p10), as_jint(p11));
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
+}
+
+static base::subtle::AtomicWord
+    g_MotionEvent_obtainAVME_J_J_I_I_F_F_F_F_I_F_F_I_I = 0;
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_MotionEvent_obtainAVME_J_J_I_I_F_F_F_F_I_F_F_I_I(JNIEnv* env, jlong p0,
+    jlong p1,
+    JniIntWrapper p2,
+    JniIntWrapper p3,
+    jfloat p4,
+    jfloat p5,
+    jfloat p6,
+    jfloat p7,
+    JniIntWrapper p8,
+    jfloat p9,
+    jfloat p10,
+    JniIntWrapper p11,
+    JniIntWrapper p12) __attribute__ ((unused));
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_MotionEvent_obtainAVME_J_J_I_I_F_F_F_F_I_F_F_I_I(JNIEnv* env, jlong p0,
+    jlong p1,
+    JniIntWrapper p2,
+    JniIntWrapper p3,
+    jfloat p4,
+    jfloat p5,
+    jfloat p6,
+    jfloat p7,
+    JniIntWrapper p8,
+    jfloat p9,
+    jfloat p10,
+    JniIntWrapper p11,
+    JniIntWrapper p12) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, MotionEvent_clazz(env),
+      MotionEvent_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, MotionEvent_clazz(env),
+      "obtain",
+      "(JJIIFFFFIFFII)Landroid/view/MotionEvent;",
+      &g_MotionEvent_obtainAVME_J_J_I_I_F_F_F_F_I_F_F_I_I);
+
+  jobject ret =
+      env->CallStaticObjectMethod(MotionEvent_clazz(env),
+          method_id, p0, p1, as_jint(p2), as_jint(p3), p4, p5, p6, p7,
+              as_jint(p8), p9, p10, as_jint(p11), as_jint(p12));
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
+}
+
+static base::subtle::AtomicWord g_MotionEvent_obtainAVME_J_J_I_F_F_I = 0;
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_MotionEvent_obtainAVME_J_J_I_F_F_I(JNIEnv* env, jlong p0,
+    jlong p1,
+    JniIntWrapper p2,
+    jfloat p3,
+    jfloat p4,
+    JniIntWrapper p5) __attribute__ ((unused));
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_MotionEvent_obtainAVME_J_J_I_F_F_I(JNIEnv* env, jlong p0,
+    jlong p1,
+    JniIntWrapper p2,
+    jfloat p3,
+    jfloat p4,
+    JniIntWrapper p5) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, MotionEvent_clazz(env),
+      MotionEvent_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, MotionEvent_clazz(env),
+      "obtain",
+      "(JJIFFI)Landroid/view/MotionEvent;",
+      &g_MotionEvent_obtainAVME_J_J_I_F_F_I);
+
+  jobject ret =
+      env->CallStaticObjectMethod(MotionEvent_clazz(env),
+          method_id, p0, p1, as_jint(p2), p3, p4, as_jint(p5));
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
+}
+
+static base::subtle::AtomicWord g_MotionEvent_obtainAVME_AVME = 0;
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_MotionEvent_obtainAVME_AVME(JNIEnv* env, jobject p0) __attribute__
+    ((unused));
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_MotionEvent_obtainAVME_AVME(JNIEnv* env, jobject p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, MotionEvent_clazz(env),
+      MotionEvent_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, MotionEvent_clazz(env),
+      "obtain",
+      "(Landroid/view/MotionEvent;)Landroid/view/MotionEvent;",
+      &g_MotionEvent_obtainAVME_AVME);
+
+  jobject ret =
+      env->CallStaticObjectMethod(MotionEvent_clazz(env),
+          method_id, p0);
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
+}
+
+static base::subtle::AtomicWord g_MotionEvent_obtainNoHistory = 0;
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_MotionEvent_obtainNoHistory(JNIEnv* env, jobject p0) __attribute__
+    ((unused));
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_MotionEvent_obtainNoHistory(JNIEnv* env, jobject p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, MotionEvent_clazz(env),
+      MotionEvent_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, MotionEvent_clazz(env),
+      "obtainNoHistory",
+      "(Landroid/view/MotionEvent;)Landroid/view/MotionEvent;",
+      &g_MotionEvent_obtainNoHistory);
+
+  jobject ret =
+      env->CallStaticObjectMethod(MotionEvent_clazz(env),
+          method_id, p0);
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
+}
+
+static base::subtle::AtomicWord g_MotionEvent_recycle = 0;
+static void Java_MotionEvent_recycle(JNIEnv* env, jobject obj) __attribute__
+    ((unused));
+static void Java_MotionEvent_recycle(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "recycle",
+      "()V",
+      &g_MotionEvent_recycle);
+
+     env->CallVoidMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getDeviceId = 0;
+static jint Java_MotionEvent_getDeviceId(JNIEnv* env, jobject obj) __attribute__
+    ((unused));
+static jint Java_MotionEvent_getDeviceId(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getDeviceId",
+      "()I",
+      &g_MotionEvent_getDeviceId);
+
+  jint ret =
+      env->CallIntMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getSource = 0;
+static jint Java_MotionEvent_getSource(JNIEnv* env, jobject obj) __attribute__
+    ((unused));
+static jint Java_MotionEvent_getSource(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getSource",
+      "()I",
+      &g_MotionEvent_getSource);
+
+  jint ret =
+      env->CallIntMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_setSource = 0;
+static void Java_MotionEvent_setSource(JNIEnv* env, jobject obj, JniIntWrapper
+    p0) __attribute__ ((unused));
+static void Java_MotionEvent_setSource(JNIEnv* env, jobject obj, JniIntWrapper
+    p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "setSource",
+      "(I)V",
+      &g_MotionEvent_setSource);
+
+     env->CallVoidMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getAction = 0;
+static jint Java_MotionEvent_getAction(JNIEnv* env, jobject obj) __attribute__
+    ((unused));
+static jint Java_MotionEvent_getAction(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getAction",
+      "()I",
+      &g_MotionEvent_getAction);
+
+  jint ret =
+      env->CallIntMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getActionMasked = 0;
+static jint Java_MotionEvent_getActionMasked(JNIEnv* env, jobject obj)
+    __attribute__ ((unused));
+static jint Java_MotionEvent_getActionMasked(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getActionMasked",
+      "()I",
+      &g_MotionEvent_getActionMasked);
+
+  jint ret =
+      env->CallIntMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getActionIndex = 0;
+static jint Java_MotionEvent_getActionIndex(JNIEnv* env, jobject obj)
+    __attribute__ ((unused));
+static jint Java_MotionEvent_getActionIndex(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getActionIndex",
+      "()I",
+      &g_MotionEvent_getActionIndex);
+
+  jint ret =
+      env->CallIntMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getFlags = 0;
+static jint Java_MotionEvent_getFlags(JNIEnv* env, jobject obj) __attribute__
+    ((unused));
+static jint Java_MotionEvent_getFlags(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getFlags",
+      "()I",
+      &g_MotionEvent_getFlags);
+
+  jint ret =
+      env->CallIntMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getDownTime = 0;
+static jlong Java_MotionEvent_getDownTime(JNIEnv* env, jobject obj)
+    __attribute__ ((unused));
+static jlong Java_MotionEvent_getDownTime(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getDownTime",
+      "()J",
+      &g_MotionEvent_getDownTime);
+
+  jlong ret =
+      env->CallLongMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getEventTime = 0;
+static jlong Java_MotionEvent_getEventTime(JNIEnv* env, jobject obj)
+    __attribute__ ((unused));
+static jlong Java_MotionEvent_getEventTime(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getEventTime",
+      "()J",
+      &g_MotionEvent_getEventTime);
+
+  jlong ret =
+      env->CallLongMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getXF = 0;
+static jfloat Java_MotionEvent_getXF(JNIEnv* env, jobject obj) __attribute__
+    ((unused));
+static jfloat Java_MotionEvent_getXF(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getX",
+      "()F",
+      &g_MotionEvent_getXF);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getYF = 0;
+static jfloat Java_MotionEvent_getYF(JNIEnv* env, jobject obj) __attribute__
+    ((unused));
+static jfloat Java_MotionEvent_getYF(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getY",
+      "()F",
+      &g_MotionEvent_getYF);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getPressureF = 0;
+static jfloat Java_MotionEvent_getPressureF(JNIEnv* env, jobject obj)
+    __attribute__ ((unused));
+static jfloat Java_MotionEvent_getPressureF(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getPressure",
+      "()F",
+      &g_MotionEvent_getPressureF);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getSizeF = 0;
+static jfloat Java_MotionEvent_getSizeF(JNIEnv* env, jobject obj) __attribute__
+    ((unused));
+static jfloat Java_MotionEvent_getSizeF(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getSize",
+      "()F",
+      &g_MotionEvent_getSizeF);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getTouchMajorF = 0;
+static jfloat Java_MotionEvent_getTouchMajorF(JNIEnv* env, jobject obj)
+    __attribute__ ((unused));
+static jfloat Java_MotionEvent_getTouchMajorF(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getTouchMajor",
+      "()F",
+      &g_MotionEvent_getTouchMajorF);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getTouchMinorF = 0;
+static jfloat Java_MotionEvent_getTouchMinorF(JNIEnv* env, jobject obj)
+    __attribute__ ((unused));
+static jfloat Java_MotionEvent_getTouchMinorF(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getTouchMinor",
+      "()F",
+      &g_MotionEvent_getTouchMinorF);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getToolMajorF = 0;
+static jfloat Java_MotionEvent_getToolMajorF(JNIEnv* env, jobject obj)
+    __attribute__ ((unused));
+static jfloat Java_MotionEvent_getToolMajorF(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getToolMajor",
+      "()F",
+      &g_MotionEvent_getToolMajorF);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getToolMinorF = 0;
+static jfloat Java_MotionEvent_getToolMinorF(JNIEnv* env, jobject obj)
+    __attribute__ ((unused));
+static jfloat Java_MotionEvent_getToolMinorF(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getToolMinor",
+      "()F",
+      &g_MotionEvent_getToolMinorF);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getOrientationF = 0;
+static jfloat Java_MotionEvent_getOrientationF(JNIEnv* env, jobject obj)
+    __attribute__ ((unused));
+static jfloat Java_MotionEvent_getOrientationF(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getOrientation",
+      "()F",
+      &g_MotionEvent_getOrientationF);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getAxisValueF_I = 0;
+static jfloat Java_MotionEvent_getAxisValueF_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getAxisValueF_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getAxisValue",
+      "(I)F",
+      &g_MotionEvent_getAxisValueF_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getPointerCount = 0;
+static jint Java_MotionEvent_getPointerCount(JNIEnv* env, jobject obj)
+    __attribute__ ((unused));
+static jint Java_MotionEvent_getPointerCount(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getPointerCount",
+      "()I",
+      &g_MotionEvent_getPointerCount);
+
+  jint ret =
+      env->CallIntMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getPointerId = 0;
+static jint Java_MotionEvent_getPointerId(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) __attribute__ ((unused));
+static jint Java_MotionEvent_getPointerId(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getPointerId",
+      "(I)I",
+      &g_MotionEvent_getPointerId);
+
+  jint ret =
+      env->CallIntMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getToolType = 0;
+static jint Java_MotionEvent_getToolType(JNIEnv* env, jobject obj, JniIntWrapper
+    p0) __attribute__ ((unused));
+static jint Java_MotionEvent_getToolType(JNIEnv* env, jobject obj, JniIntWrapper
+    p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getToolType",
+      "(I)I",
+      &g_MotionEvent_getToolType);
+
+  jint ret =
+      env->CallIntMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_findPointerIndex = 0;
+static jint Java_MotionEvent_findPointerIndex(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) __attribute__ ((unused));
+static jint Java_MotionEvent_findPointerIndex(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "findPointerIndex",
+      "(I)I",
+      &g_MotionEvent_findPointerIndex);
+
+  jint ret =
+      env->CallIntMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getXF_I = 0;
+static jfloat Java_MotionEvent_getXF_I(JNIEnv* env, jobject obj, JniIntWrapper
+    p0) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getXF_I(JNIEnv* env, jobject obj, JniIntWrapper
+    p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getX",
+      "(I)F",
+      &g_MotionEvent_getXF_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getYF_I = 0;
+static jfloat Java_MotionEvent_getYF_I(JNIEnv* env, jobject obj, JniIntWrapper
+    p0) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getYF_I(JNIEnv* env, jobject obj, JniIntWrapper
+    p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getY",
+      "(I)F",
+      &g_MotionEvent_getYF_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getPressureF_I = 0;
+static jfloat Java_MotionEvent_getPressureF_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getPressureF_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getPressure",
+      "(I)F",
+      &g_MotionEvent_getPressureF_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getSizeF_I = 0;
+static jfloat Java_MotionEvent_getSizeF_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getSizeF_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getSize",
+      "(I)F",
+      &g_MotionEvent_getSizeF_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getTouchMajorF_I = 0;
+static jfloat Java_MotionEvent_getTouchMajorF_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getTouchMajorF_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getTouchMajor",
+      "(I)F",
+      &g_MotionEvent_getTouchMajorF_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getTouchMinorF_I = 0;
+static jfloat Java_MotionEvent_getTouchMinorF_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getTouchMinorF_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getTouchMinor",
+      "(I)F",
+      &g_MotionEvent_getTouchMinorF_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getToolMajorF_I = 0;
+static jfloat Java_MotionEvent_getToolMajorF_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getToolMajorF_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getToolMajor",
+      "(I)F",
+      &g_MotionEvent_getToolMajorF_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getToolMinorF_I = 0;
+static jfloat Java_MotionEvent_getToolMinorF_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getToolMinorF_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getToolMinor",
+      "(I)F",
+      &g_MotionEvent_getToolMinorF_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getOrientationF_I = 0;
+static jfloat Java_MotionEvent_getOrientationF_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getOrientationF_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getOrientation",
+      "(I)F",
+      &g_MotionEvent_getOrientationF_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getAxisValueF_I_I = 0;
+static jfloat Java_MotionEvent_getAxisValueF_I_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0,
+    JniIntWrapper p1) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getAxisValueF_I_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0,
+    JniIntWrapper p1) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getAxisValue",
+      "(II)F",
+      &g_MotionEvent_getAxisValueF_I_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0), as_jint(p1));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getPointerCoords = 0;
+static void Java_MotionEvent_getPointerCoords(JNIEnv* env, jobject obj,
+    JniIntWrapper p0,
+    jobject p1) __attribute__ ((unused));
+static void Java_MotionEvent_getPointerCoords(JNIEnv* env, jobject obj,
+    JniIntWrapper p0,
+    jobject p1) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getPointerCoords",
+      "(ILandroid/view/MotionEvent$PointerCoords;)V",
+      &g_MotionEvent_getPointerCoords);
+
+     env->CallVoidMethod(obj,
+          method_id, as_jint(p0), p1);
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getPointerProperties = 0;
+static void Java_MotionEvent_getPointerProperties(JNIEnv* env, jobject obj,
+    JniIntWrapper p0,
+    jobject p1) __attribute__ ((unused));
+static void Java_MotionEvent_getPointerProperties(JNIEnv* env, jobject obj,
+    JniIntWrapper p0,
+    jobject p1) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getPointerProperties",
+      "(ILandroid/view/MotionEvent$PointerProperties;)V",
+      &g_MotionEvent_getPointerProperties);
+
+     env->CallVoidMethod(obj,
+          method_id, as_jint(p0), p1);
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getMetaState = 0;
+static jint Java_MotionEvent_getMetaState(JNIEnv* env, jobject obj)
+    __attribute__ ((unused));
+static jint Java_MotionEvent_getMetaState(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getMetaState",
+      "()I",
+      &g_MotionEvent_getMetaState);
+
+  jint ret =
+      env->CallIntMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getButtonState = 0;
+static jint Java_MotionEvent_getButtonState(JNIEnv* env, jobject obj)
+    __attribute__ ((unused));
+static jint Java_MotionEvent_getButtonState(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getButtonState",
+      "()I",
+      &g_MotionEvent_getButtonState);
+
+  jint ret =
+      env->CallIntMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getRawX = 0;
+static jfloat Java_MotionEvent_getRawX(JNIEnv* env, jobject obj) __attribute__
+    ((unused));
+static jfloat Java_MotionEvent_getRawX(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getRawX",
+      "()F",
+      &g_MotionEvent_getRawX);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getRawY = 0;
+static jfloat Java_MotionEvent_getRawY(JNIEnv* env, jobject obj) __attribute__
+    ((unused));
+static jfloat Java_MotionEvent_getRawY(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getRawY",
+      "()F",
+      &g_MotionEvent_getRawY);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getXPrecision = 0;
+static jfloat Java_MotionEvent_getXPrecision(JNIEnv* env, jobject obj)
+    __attribute__ ((unused));
+static jfloat Java_MotionEvent_getXPrecision(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getXPrecision",
+      "()F",
+      &g_MotionEvent_getXPrecision);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getYPrecision = 0;
+static jfloat Java_MotionEvent_getYPrecision(JNIEnv* env, jobject obj)
+    __attribute__ ((unused));
+static jfloat Java_MotionEvent_getYPrecision(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getYPrecision",
+      "()F",
+      &g_MotionEvent_getYPrecision);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistorySize = 0;
+static jint Java_MotionEvent_getHistorySize(JNIEnv* env, jobject obj)
+    __attribute__ ((unused));
+static jint Java_MotionEvent_getHistorySize(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistorySize",
+      "()I",
+      &g_MotionEvent_getHistorySize);
+
+  jint ret =
+      env->CallIntMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistoricalEventTime = 0;
+static jlong Java_MotionEvent_getHistoricalEventTime(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) __attribute__ ((unused));
+static jlong Java_MotionEvent_getHistoricalEventTime(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistoricalEventTime",
+      "(I)J",
+      &g_MotionEvent_getHistoricalEventTime);
+
+  jlong ret =
+      env->CallLongMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistoricalXF_I = 0;
+static jfloat Java_MotionEvent_getHistoricalXF_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getHistoricalXF_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistoricalX",
+      "(I)F",
+      &g_MotionEvent_getHistoricalXF_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistoricalYF_I = 0;
+static jfloat Java_MotionEvent_getHistoricalYF_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getHistoricalYF_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistoricalY",
+      "(I)F",
+      &g_MotionEvent_getHistoricalYF_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistoricalPressureF_I = 0;
+static jfloat Java_MotionEvent_getHistoricalPressureF_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getHistoricalPressureF_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistoricalPressure",
+      "(I)F",
+      &g_MotionEvent_getHistoricalPressureF_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistoricalSizeF_I = 0;
+static jfloat Java_MotionEvent_getHistoricalSizeF_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getHistoricalSizeF_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistoricalSize",
+      "(I)F",
+      &g_MotionEvent_getHistoricalSizeF_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistoricalTouchMajorF_I = 0;
+static jfloat Java_MotionEvent_getHistoricalTouchMajorF_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getHistoricalTouchMajorF_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistoricalTouchMajor",
+      "(I)F",
+      &g_MotionEvent_getHistoricalTouchMajorF_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistoricalTouchMinorF_I = 0;
+static jfloat Java_MotionEvent_getHistoricalTouchMinorF_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getHistoricalTouchMinorF_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistoricalTouchMinor",
+      "(I)F",
+      &g_MotionEvent_getHistoricalTouchMinorF_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistoricalToolMajorF_I = 0;
+static jfloat Java_MotionEvent_getHistoricalToolMajorF_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getHistoricalToolMajorF_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistoricalToolMajor",
+      "(I)F",
+      &g_MotionEvent_getHistoricalToolMajorF_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistoricalToolMinorF_I = 0;
+static jfloat Java_MotionEvent_getHistoricalToolMinorF_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getHistoricalToolMinorF_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistoricalToolMinor",
+      "(I)F",
+      &g_MotionEvent_getHistoricalToolMinorF_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistoricalOrientationF_I = 0;
+static jfloat Java_MotionEvent_getHistoricalOrientationF_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getHistoricalOrientationF_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistoricalOrientation",
+      "(I)F",
+      &g_MotionEvent_getHistoricalOrientationF_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistoricalAxisValueF_I_I = 0;
+static jfloat Java_MotionEvent_getHistoricalAxisValueF_I_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0,
+    JniIntWrapper p1) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getHistoricalAxisValueF_I_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0,
+    JniIntWrapper p1) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistoricalAxisValue",
+      "(II)F",
+      &g_MotionEvent_getHistoricalAxisValueF_I_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0), as_jint(p1));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistoricalXF_I_I = 0;
+static jfloat Java_MotionEvent_getHistoricalXF_I_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0,
+    JniIntWrapper p1) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getHistoricalXF_I_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0,
+    JniIntWrapper p1) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistoricalX",
+      "(II)F",
+      &g_MotionEvent_getHistoricalXF_I_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0), as_jint(p1));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistoricalYF_I_I = 0;
+static jfloat Java_MotionEvent_getHistoricalYF_I_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0,
+    JniIntWrapper p1) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getHistoricalYF_I_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0,
+    JniIntWrapper p1) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistoricalY",
+      "(II)F",
+      &g_MotionEvent_getHistoricalYF_I_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0), as_jint(p1));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistoricalPressureF_I_I = 0;
+static jfloat Java_MotionEvent_getHistoricalPressureF_I_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0,
+    JniIntWrapper p1) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getHistoricalPressureF_I_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0,
+    JniIntWrapper p1) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistoricalPressure",
+      "(II)F",
+      &g_MotionEvent_getHistoricalPressureF_I_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0), as_jint(p1));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistoricalSizeF_I_I = 0;
+static jfloat Java_MotionEvent_getHistoricalSizeF_I_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0,
+    JniIntWrapper p1) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getHistoricalSizeF_I_I(JNIEnv* env, jobject obj,
+    JniIntWrapper p0,
+    JniIntWrapper p1) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistoricalSize",
+      "(II)F",
+      &g_MotionEvent_getHistoricalSizeF_I_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0), as_jint(p1));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistoricalTouchMajorF_I_I = 0;
+static jfloat Java_MotionEvent_getHistoricalTouchMajorF_I_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0,
+    JniIntWrapper p1) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getHistoricalTouchMajorF_I_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0,
+    JniIntWrapper p1) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistoricalTouchMajor",
+      "(II)F",
+      &g_MotionEvent_getHistoricalTouchMajorF_I_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0), as_jint(p1));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistoricalTouchMinorF_I_I = 0;
+static jfloat Java_MotionEvent_getHistoricalTouchMinorF_I_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0,
+    JniIntWrapper p1) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getHistoricalTouchMinorF_I_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0,
+    JniIntWrapper p1) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistoricalTouchMinor",
+      "(II)F",
+      &g_MotionEvent_getHistoricalTouchMinorF_I_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0), as_jint(p1));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistoricalToolMajorF_I_I = 0;
+static jfloat Java_MotionEvent_getHistoricalToolMajorF_I_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0,
+    JniIntWrapper p1) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getHistoricalToolMajorF_I_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0,
+    JniIntWrapper p1) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistoricalToolMajor",
+      "(II)F",
+      &g_MotionEvent_getHistoricalToolMajorF_I_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0), as_jint(p1));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistoricalToolMinorF_I_I = 0;
+static jfloat Java_MotionEvent_getHistoricalToolMinorF_I_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0,
+    JniIntWrapper p1) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getHistoricalToolMinorF_I_I(JNIEnv* env, jobject
+    obj, JniIntWrapper p0,
+    JniIntWrapper p1) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistoricalToolMinor",
+      "(II)F",
+      &g_MotionEvent_getHistoricalToolMinorF_I_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0), as_jint(p1));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistoricalOrientationF_I_I = 0;
+static jfloat Java_MotionEvent_getHistoricalOrientationF_I_I(JNIEnv* env,
+    jobject obj, JniIntWrapper p0,
+    JniIntWrapper p1) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getHistoricalOrientationF_I_I(JNIEnv* env,
+    jobject obj, JniIntWrapper p0,
+    JniIntWrapper p1) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistoricalOrientation",
+      "(II)F",
+      &g_MotionEvent_getHistoricalOrientationF_I_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0), as_jint(p1));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistoricalAxisValueF_I_I_I = 0;
+static jfloat Java_MotionEvent_getHistoricalAxisValueF_I_I_I(JNIEnv* env,
+    jobject obj, JniIntWrapper p0,
+    JniIntWrapper p1,
+    JniIntWrapper p2) __attribute__ ((unused));
+static jfloat Java_MotionEvent_getHistoricalAxisValueF_I_I_I(JNIEnv* env,
+    jobject obj, JniIntWrapper p0,
+    JniIntWrapper p1,
+    JniIntWrapper p2) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistoricalAxisValue",
+      "(III)F",
+      &g_MotionEvent_getHistoricalAxisValueF_I_I_I);
+
+  jfloat ret =
+      env->CallFloatMethod(obj,
+          method_id, as_jint(p0), as_jint(p1), as_jint(p2));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getHistoricalPointerCoords = 0;
+static void Java_MotionEvent_getHistoricalPointerCoords(JNIEnv* env, jobject
+    obj, JniIntWrapper p0,
+    JniIntWrapper p1,
+    jobject p2) __attribute__ ((unused));
+static void Java_MotionEvent_getHistoricalPointerCoords(JNIEnv* env, jobject
+    obj, JniIntWrapper p0,
+    JniIntWrapper p1,
+    jobject p2) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getHistoricalPointerCoords",
+      "(IILandroid/view/MotionEvent$PointerCoords;)V",
+      &g_MotionEvent_getHistoricalPointerCoords);
+
+     env->CallVoidMethod(obj,
+          method_id, as_jint(p0), as_jint(p1), p2);
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_MotionEvent_getEdgeFlags = 0;
+static jint Java_MotionEvent_getEdgeFlags(JNIEnv* env, jobject obj)
+    __attribute__ ((unused));
+static jint Java_MotionEvent_getEdgeFlags(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "getEdgeFlags",
+      "()I",
+      &g_MotionEvent_getEdgeFlags);
+
+  jint ret =
+      env->CallIntMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_setEdgeFlags = 0;
+static void Java_MotionEvent_setEdgeFlags(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) __attribute__ ((unused));
+static void Java_MotionEvent_setEdgeFlags(JNIEnv* env, jobject obj,
+    JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "setEdgeFlags",
+      "(I)V",
+      &g_MotionEvent_setEdgeFlags);
+
+     env->CallVoidMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_MotionEvent_setAction = 0;
+static void Java_MotionEvent_setAction(JNIEnv* env, jobject obj, JniIntWrapper
+    p0) __attribute__ ((unused));
+static void Java_MotionEvent_setAction(JNIEnv* env, jobject obj, JniIntWrapper
+    p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "setAction",
+      "(I)V",
+      &g_MotionEvent_setAction);
+
+     env->CallVoidMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_MotionEvent_offsetLocation = 0;
+static void Java_MotionEvent_offsetLocation(JNIEnv* env, jobject obj, jfloat p0,
+    jfloat p1) __attribute__ ((unused));
+static void Java_MotionEvent_offsetLocation(JNIEnv* env, jobject obj, jfloat p0,
+    jfloat p1) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "offsetLocation",
+      "(FF)V",
+      &g_MotionEvent_offsetLocation);
+
+     env->CallVoidMethod(obj,
+          method_id, p0, p1);
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_MotionEvent_setLocation = 0;
+static void Java_MotionEvent_setLocation(JNIEnv* env, jobject obj, jfloat p0,
+    jfloat p1) __attribute__ ((unused));
+static void Java_MotionEvent_setLocation(JNIEnv* env, jobject obj, jfloat p0,
+    jfloat p1) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "setLocation",
+      "(FF)V",
+      &g_MotionEvent_setLocation);
+
+     env->CallVoidMethod(obj,
+          method_id, p0, p1);
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_MotionEvent_transform = 0;
+static void Java_MotionEvent_transform(JNIEnv* env, jobject obj, jobject p0)
+    __attribute__ ((unused));
+static void Java_MotionEvent_transform(JNIEnv* env, jobject obj, jobject p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "transform",
+      "(Landroid/graphics/Matrix;)V",
+      &g_MotionEvent_transform);
+
+     env->CallVoidMethod(obj,
+          method_id, p0);
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_MotionEvent_addBatchV_J_F_F_F_F_I = 0;
+static void Java_MotionEvent_addBatchV_J_F_F_F_F_I(JNIEnv* env, jobject obj,
+    jlong p0,
+    jfloat p1,
+    jfloat p2,
+    jfloat p3,
+    jfloat p4,
+    JniIntWrapper p5) __attribute__ ((unused));
+static void Java_MotionEvent_addBatchV_J_F_F_F_F_I(JNIEnv* env, jobject obj,
+    jlong p0,
+    jfloat p1,
+    jfloat p2,
+    jfloat p3,
+    jfloat p4,
+    JniIntWrapper p5) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "addBatch",
+      "(JFFFFI)V",
+      &g_MotionEvent_addBatchV_J_F_F_F_F_I);
+
+     env->CallVoidMethod(obj,
+          method_id, p0, p1, p2, p3, p4, as_jint(p5));
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_MotionEvent_addBatchV_J_LAVMEPC_I = 0;
+static void Java_MotionEvent_addBatchV_J_LAVMEPC_I(JNIEnv* env, jobject obj,
+    jlong p0,
+    jobjectArray p1,
+    JniIntWrapper p2) __attribute__ ((unused));
+static void Java_MotionEvent_addBatchV_J_LAVMEPC_I(JNIEnv* env, jobject obj,
+    jlong p0,
+    jobjectArray p1,
+    JniIntWrapper p2) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "addBatch",
+      "(J[Landroid/view/MotionEvent$PointerCoords;I)V",
+      &g_MotionEvent_addBatchV_J_LAVMEPC_I);
+
+     env->CallVoidMethod(obj,
+          method_id, p0, p1, as_jint(p2));
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_MotionEvent_toString = 0;
+static base::android::ScopedJavaLocalRef<jstring>
+    Java_MotionEvent_toString(JNIEnv* env, jobject obj) __attribute__
+    ((unused));
+static base::android::ScopedJavaLocalRef<jstring>
+    Java_MotionEvent_toString(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "toString",
+      "()Ljava/lang/String;",
+      &g_MotionEvent_toString);
+
+  jstring ret =
+      static_cast<jstring>(env->CallObjectMethod(obj,
+          method_id));
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jstring>(env, ret);
+}
+
+static base::subtle::AtomicWord g_MotionEvent_actionToString = 0;
+static base::android::ScopedJavaLocalRef<jstring>
+    Java_MotionEvent_actionToString(JNIEnv* env, JniIntWrapper p0) __attribute__
+    ((unused));
+static base::android::ScopedJavaLocalRef<jstring>
+    Java_MotionEvent_actionToString(JNIEnv* env, JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, MotionEvent_clazz(env),
+      MotionEvent_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, MotionEvent_clazz(env),
+      "actionToString",
+      "(I)Ljava/lang/String;",
+      &g_MotionEvent_actionToString);
+
+  jstring ret =
+      static_cast<jstring>(env->CallStaticObjectMethod(MotionEvent_clazz(env),
+          method_id, as_jint(p0)));
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jstring>(env, ret);
+}
+
+static base::subtle::AtomicWord g_MotionEvent_axisToString = 0;
+static base::android::ScopedJavaLocalRef<jstring>
+    Java_MotionEvent_axisToString(JNIEnv* env, JniIntWrapper p0) __attribute__
+    ((unused));
+static base::android::ScopedJavaLocalRef<jstring>
+    Java_MotionEvent_axisToString(JNIEnv* env, JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, MotionEvent_clazz(env),
+      MotionEvent_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, MotionEvent_clazz(env),
+      "axisToString",
+      "(I)Ljava/lang/String;",
+      &g_MotionEvent_axisToString);
+
+  jstring ret =
+      static_cast<jstring>(env->CallStaticObjectMethod(MotionEvent_clazz(env),
+          method_id, as_jint(p0)));
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jstring>(env, ret);
+}
+
+static base::subtle::AtomicWord g_MotionEvent_axisFromString = 0;
+static jint Java_MotionEvent_axisFromString(JNIEnv* env, jstring p0)
+    __attribute__ ((unused));
+static jint Java_MotionEvent_axisFromString(JNIEnv* env, jstring p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, MotionEvent_clazz(env),
+      MotionEvent_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, MotionEvent_clazz(env),
+      "axisFromString",
+      "(Ljava/lang/String;)I",
+      &g_MotionEvent_axisFromString);
+
+  jint ret =
+      env->CallStaticIntMethod(MotionEvent_clazz(env),
+          method_id, p0);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_MotionEvent_writeToParcel = 0;
+static void Java_MotionEvent_writeToParcel(JNIEnv* env, jobject obj, jobject p0,
+    JniIntWrapper p1) __attribute__ ((unused));
+static void Java_MotionEvent_writeToParcel(JNIEnv* env, jobject obj, jobject p0,
+    JniIntWrapper p1) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      MotionEvent_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, MotionEvent_clazz(env),
+      "writeToParcel",
+      "(Landroid/os/Parcel;I)V",
+      &g_MotionEvent_writeToParcel);
+
+     env->CallVoidMethod(obj,
+          method_id, p0, as_jint(p1));
+  jni_generator::CheckException(env);
+
+}
+
+// Step 3: RegisterNatives.
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+  g_MotionEvent_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetClass(env, kMotionEventClassPath).obj()));
+
+  return true;
+}
+
+}  // namespace JNI_MotionEvent
+
+#endif  // android_view_MotionEvent_JNI
diff --git a/base/android/jni_generator/testEagerCalledByNativesOption.golden b/base/android/jni_generator/testEagerCalledByNativesOption.golden
new file mode 100644
index 0000000..19108bf
--- /dev/null
+++ b/base/android/jni_generator/testEagerCalledByNativesOption.golden
@@ -0,0 +1,146 @@
+// 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/Test
+
+#ifndef org_chromium_example_jni_generator_Test_JNI
+#define org_chromium_example_jni_generator_Test_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 kTestClassPath[] = "org/chromium/example/jni_generator/Test";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_Test_clazz = NULL;
+#define Test_clazz(env) g_Test_clazz
+jmethodID g_Test_testMethodWithParam = NULL;
+jmethodID g_Test_testStaticMethodWithParam = NULL;
+jmethodID g_Test_testMethodWithNoParam = NULL;
+jmethodID g_Test_testStaticMethodWithNoParam = NULL;
+}  // namespace
+
+// Step 2: method stubs.
+static jint Method(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);
+}
+
+namespace {
+
+static void testMethodWithParam(JNIEnv* env, jobject obj, JniIntWrapper iParam)
+    {
+  env->CallVoidMethod(obj,
+      g_Test_testMethodWithParam, as_jint(iParam));
+
+}
+
+static jint testStaticMethodWithParam(JNIEnv* env, JniIntWrapper iParam) {
+  jint ret = env->CallStaticIntMethod(Test_clazz(env),
+      g_Test_testStaticMethodWithParam, as_jint(iParam));
+  return ret;
+}
+
+static jdouble testMethodWithNoParam(JNIEnv* env) {
+  jdouble ret = env->CallStaticDoubleMethod(Test_clazz(env),
+      g_Test_testMethodWithNoParam);
+  return ret;
+}
+
+static base::android::ScopedJavaLocalRef<jstring>
+    testStaticMethodWithNoParam(JNIEnv* env) {
+  jstring ret =
+      static_cast<jstring>(env->CallStaticObjectMethod(Test_clazz(env),
+      g_Test_testStaticMethodWithNoParam));
+  return base::android::ScopedJavaLocalRef<jstring>(env, ret);
+}
+}  // namespace
+
+// Step 3: RegisterNatives.
+
+static const JNINativeMethod kMethodsTest[] = {
+    { "nativeMethod",
+"("
+"J"
+"I"
+")"
+"I", reinterpret_cast<void*>(Method) },
+};
+
+static bool RegisterNativesImpl(JNIEnv* env, jclass clazz) {
+
+  g_Test_clazz = static_cast<jclass>(env->NewWeakGlobalRef(clazz));
+
+  const int kMethodsTestSize = arraysize(kMethodsTest);
+
+  if (env->RegisterNatives(Test_clazz(env),
+                           kMethodsTest,
+                           kMethodsTestSize) < 0) {
+    jni_generator::HandleRegistrationError(
+        env, Test_clazz(env), __FILE__);
+    return false;
+  }
+
+  g_Test_testMethodWithParam = env->GetMethodID(
+      Test_clazz(env),
+      "testMethodWithParam",
+"("
+"I"
+")"
+"V");
+  if (g_Test_testMethodWithParam == NULL) {
+    return false;
+  }
+
+  g_Test_testStaticMethodWithParam = env->GetStaticMethodID(
+      Test_clazz(env),
+      "testStaticMethodWithParam",
+"("
+"I"
+")"
+"I");
+  if (g_Test_testStaticMethodWithParam == NULL) {
+    return false;
+  }
+
+  g_Test_testMethodWithNoParam = env->GetStaticMethodID(
+      Test_clazz(env),
+      "testMethodWithNoParam",
+"("
+")"
+"D");
+  if (g_Test_testMethodWithNoParam == NULL) {
+    return false;
+  }
+
+  g_Test_testStaticMethodWithNoParam = env->GetStaticMethodID(
+      Test_clazz(env),
+      "testStaticMethodWithNoParam",
+"("
+")"
+"Ljava/lang/String;");
+  if (g_Test_testStaticMethodWithNoParam == NULL) {
+    return false;
+  }
+
+  return true;
+}
+
+extern "C" JNIEXPORT bool JNICALL
+Java_org_chromium_example_jni_generator_Test_nativeInitNativeClass(JNIEnv* env,
+    jclass clazz) {
+  return RegisterNativesImpl(env, clazz);
+}
+
+#endif  // org_chromium_example_jni_generator_Test_JNI
diff --git a/base/android/jni_generator/testFromJavaP.golden b/base/android/jni_generator/testFromJavaP.golden
new file mode 100644
index 0000000..b7276bc
--- /dev/null
+++ b/base/android/jni_generator/testFromJavaP.golden
@@ -0,0 +1,267 @@
+// 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
+//     java/io/InputStream
+
+#ifndef java_io_InputStream_JNI
+#define java_io_InputStream_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 kInputStreamClassPath[] = "java/io/InputStream";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_InputStream_clazz = NULL;
+#define InputStream_clazz(env) g_InputStream_clazz
+
+}  // namespace
+
+namespace JNI_InputStream {
+
+// Step 2: method stubs.
+
+static base::subtle::AtomicWord g_InputStream_available = 0;
+static jint Java_InputStream_available(JNIEnv* env, jobject obj) __attribute__
+    ((unused));
+static jint Java_InputStream_available(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      InputStream_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, InputStream_clazz(env),
+      "available",
+      "()I",
+      &g_InputStream_available);
+
+  jint ret =
+      env->CallIntMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_InputStream_close = 0;
+static void Java_InputStream_close(JNIEnv* env, jobject obj) __attribute__
+    ((unused));
+static void Java_InputStream_close(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      InputStream_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, InputStream_clazz(env),
+      "close",
+      "()V",
+      &g_InputStream_close);
+
+     env->CallVoidMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_InputStream_mark = 0;
+static void Java_InputStream_mark(JNIEnv* env, jobject obj, JniIntWrapper p0)
+    __attribute__ ((unused));
+static void Java_InputStream_mark(JNIEnv* env, jobject obj, JniIntWrapper p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      InputStream_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, InputStream_clazz(env),
+      "mark",
+      "(I)V",
+      &g_InputStream_mark);
+
+     env->CallVoidMethod(obj,
+          method_id, as_jint(p0));
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_InputStream_markSupported = 0;
+static jboolean Java_InputStream_markSupported(JNIEnv* env, jobject obj)
+    __attribute__ ((unused));
+static jboolean Java_InputStream_markSupported(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      InputStream_clazz(env), false);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, InputStream_clazz(env),
+      "markSupported",
+      "()Z",
+      &g_InputStream_markSupported);
+
+  jboolean ret =
+      env->CallBooleanMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_InputStream_readI = 0;
+static jint Java_InputStream_readI(JNIEnv* env, jobject obj) __attribute__
+    ((unused));
+static jint Java_InputStream_readI(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      InputStream_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, InputStream_clazz(env),
+      "read",
+      "()I",
+      &g_InputStream_readI);
+
+  jint ret =
+      env->CallIntMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_InputStream_readI_AB = 0;
+static jint Java_InputStream_readI_AB(JNIEnv* env, jobject obj, jbyteArray p0)
+    __attribute__ ((unused));
+static jint Java_InputStream_readI_AB(JNIEnv* env, jobject obj, jbyteArray p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      InputStream_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, InputStream_clazz(env),
+      "read",
+      "([B)I",
+      &g_InputStream_readI_AB);
+
+  jint ret =
+      env->CallIntMethod(obj,
+          method_id, p0);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_InputStream_readI_AB_I_I = 0;
+static jint Java_InputStream_readI_AB_I_I(JNIEnv* env, jobject obj, jbyteArray
+    p0,
+    JniIntWrapper p1,
+    JniIntWrapper p2) __attribute__ ((unused));
+static jint Java_InputStream_readI_AB_I_I(JNIEnv* env, jobject obj, jbyteArray
+    p0,
+    JniIntWrapper p1,
+    JniIntWrapper p2) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      InputStream_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, InputStream_clazz(env),
+      "read",
+      "([BII)I",
+      &g_InputStream_readI_AB_I_I);
+
+  jint ret =
+      env->CallIntMethod(obj,
+          method_id, p0, as_jint(p1), as_jint(p2));
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_InputStream_reset = 0;
+static void Java_InputStream_reset(JNIEnv* env, jobject obj) __attribute__
+    ((unused));
+static void Java_InputStream_reset(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      InputStream_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, InputStream_clazz(env),
+      "reset",
+      "()V",
+      &g_InputStream_reset);
+
+     env->CallVoidMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_InputStream_skip = 0;
+static jlong Java_InputStream_skip(JNIEnv* env, jobject obj, jlong p0)
+    __attribute__ ((unused));
+static jlong Java_InputStream_skip(JNIEnv* env, jobject obj, jlong p0) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      InputStream_clazz(env), 0);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, InputStream_clazz(env),
+      "skip",
+      "(J)J",
+      &g_InputStream_skip);
+
+  jlong ret =
+      env->CallLongMethod(obj,
+          method_id, p0);
+  jni_generator::CheckException(env);
+  return ret;
+}
+
+static base::subtle::AtomicWord g_InputStream_Constructor = 0;
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_InputStream_Constructor(JNIEnv* env) __attribute__ ((unused));
+static base::android::ScopedJavaLocalRef<jobject>
+    Java_InputStream_Constructor(JNIEnv* env) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, InputStream_clazz(env),
+      InputStream_clazz(env), NULL);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, InputStream_clazz(env),
+      "<init>",
+      "()V",
+      &g_InputStream_Constructor);
+
+  jobject ret =
+      env->NewObject(InputStream_clazz(env),
+          method_id);
+  jni_generator::CheckException(env);
+  return base::android::ScopedJavaLocalRef<jobject>(env, ret);
+}
+
+// Step 3: RegisterNatives.
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+  g_InputStream_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetClass(env, kInputStreamClassPath).obj()));
+
+  return true;
+}
+
+}  // namespace JNI_InputStream
+
+#endif  // java_io_InputStream_JNI
diff --git a/base/android/jni_generator/testFromJavaPGenerics.golden b/base/android/jni_generator/testFromJavaPGenerics.golden
new file mode 100644
index 0000000..489872c
--- /dev/null
+++ b/base/android/jni_generator/testFromJavaPGenerics.golden
@@ -0,0 +1,65 @@
+// 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
+//     java/util/HashSet
+
+#ifndef java_util_HashSet_JNI
+#define java_util_HashSet_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 kHashSetClassPath[] = "java/util/HashSet";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_HashSet_clazz = NULL;
+#define HashSet_clazz(env) g_HashSet_clazz
+
+}  // namespace
+
+namespace JNI_HashSet {
+
+// Step 2: method stubs.
+
+static base::subtle::AtomicWord g_HashSet_dummy = 0;
+static void Java_HashSet_dummy(JNIEnv* env, jobject obj) __attribute__
+    ((unused));
+static void Java_HashSet_dummy(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, obj,
+      HashSet_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, HashSet_clazz(env),
+      "dummy",
+      "()V",
+      &g_HashSet_dummy);
+
+     env->CallVoidMethod(obj,
+          method_id);
+  jni_generator::CheckException(env);
+
+}
+
+// Step 3: RegisterNatives.
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+  g_HashSet_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetClass(env, kHashSetClassPath).obj()));
+
+  return true;
+}
+
+}  // namespace JNI_HashSet
+
+#endif  // java_util_HashSet_JNI
diff --git a/base/android/jni_generator/testInnerClassNatives.golden b/base/android/jni_generator/testInnerClassNatives.golden
new file mode 100644
index 0000000..5a525ef
--- /dev/null
+++ b/base/android/jni_generator/testInnerClassNatives.golden
@@ -0,0 +1,60 @@
+// 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/TestJni
+
+#ifndef org_chromium_TestJni_JNI
+#define org_chromium_TestJni_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 kTestJniClassPath[] = "org/chromium/TestJni";
+const char kMyInnerClassClassPath[] = "org/chromium/TestJni$MyInnerClass";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_TestJni_clazz = NULL;
+#define TestJni_clazz(env) g_TestJni_clazz
+
+}  // namespace
+
+static jint Init(JNIEnv* env, jobject jcaller);
+
+// Step 2: method stubs.
+
+// Step 3: RegisterNatives.
+
+static const JNINativeMethod kMethodsMyInnerClass[] = {
+    { "nativeInit",
+"("
+")"
+"I", reinterpret_cast<void*>(Init) },
+};
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+  g_TestJni_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetClass(env, kTestJniClassPath).obj()));
+
+  const int kMethodsMyInnerClassSize = arraysize(kMethodsMyInnerClass);
+
+  if (env->RegisterNatives(MyInnerClass_clazz(env),
+                           kMethodsMyInnerClass,
+                           kMethodsMyInnerClassSize) < 0) {
+    jni_generator::HandleRegistrationError(
+        env, MyInnerClass_clazz(env), __FILE__);
+    return false;
+  }
+
+  return true;
+}
+
+#endif  // org_chromium_TestJni_JNI
diff --git a/base/android/jni_generator/testInnerClassNativesBothInnerAndOuter.golden b/base/android/jni_generator/testInnerClassNativesBothInnerAndOuter.golden
new file mode 100644
index 0000000..c8d4b3c
--- /dev/null
+++ b/base/android/jni_generator/testInnerClassNativesBothInnerAndOuter.golden
@@ -0,0 +1,81 @@
+// 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/TestJni
+
+#ifndef org_chromium_TestJni_JNI
+#define org_chromium_TestJni_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 kMyOtherInnerClassClassPath[] =
+    "org/chromium/TestJni$MyOtherInnerClass";
+const char kTestJniClassPath[] = "org/chromium/TestJni";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_TestJni_clazz = NULL;
+#define TestJni_clazz(env) g_TestJni_clazz
+
+}  // namespace
+
+static jint Init(JNIEnv* env, jobject jcaller);
+
+static jint Init(JNIEnv* env, jobject jcaller);
+
+// Step 2: method stubs.
+
+// Step 3: RegisterNatives.
+
+static const JNINativeMethod kMethodsMyOtherInnerClass[] = {
+    { "nativeInit",
+"("
+")"
+"I", reinterpret_cast<void*>(Init) },
+};
+
+static const JNINativeMethod kMethodsTestJni[] = {
+    { "nativeInit",
+"("
+")"
+"I", reinterpret_cast<void*>(Init) },
+};
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+  g_TestJni_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetClass(env, kTestJniClassPath).obj()));
+
+  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 kMethodsTestJniSize = arraysize(kMethodsTestJni);
+
+  if (env->RegisterNatives(TestJni_clazz(env),
+                           kMethodsTestJni,
+                           kMethodsTestJniSize) < 0) {
+    jni_generator::HandleRegistrationError(
+        env, TestJni_clazz(env), __FILE__);
+    return false;
+  }
+
+  return true;
+}
+
+#endif  // org_chromium_TestJni_JNI
diff --git a/base/android/jni_generator/testInnerClassNativesMultiple.golden b/base/android/jni_generator/testInnerClassNativesMultiple.golden
new file mode 100644
index 0000000..42643ae
--- /dev/null
+++ b/base/android/jni_generator/testInnerClassNativesMultiple.golden
@@ -0,0 +1,82 @@
+// 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/TestJni
+
+#ifndef org_chromium_TestJni_JNI
+#define org_chromium_TestJni_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 kMyOtherInnerClassClassPath[] =
+    "org/chromium/TestJni$MyOtherInnerClass";
+const char kTestJniClassPath[] = "org/chromium/TestJni";
+const char kMyInnerClassClassPath[] = "org/chromium/TestJni$MyInnerClass";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_TestJni_clazz = NULL;
+#define TestJni_clazz(env) g_TestJni_clazz
+
+}  // namespace
+
+static jint Init(JNIEnv* env, jobject jcaller);
+
+static jint Init(JNIEnv* env, jobject jcaller);
+
+// Step 2: method stubs.
+
+// Step 3: RegisterNatives.
+
+static const JNINativeMethod kMethodsMyOtherInnerClass[] = {
+    { "nativeInit",
+"("
+")"
+"I", reinterpret_cast<void*>(Init) },
+};
+
+static const JNINativeMethod kMethodsMyInnerClass[] = {
+    { "nativeInit",
+"("
+")"
+"I", reinterpret_cast<void*>(Init) },
+};
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+  g_TestJni_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetClass(env, kTestJniClassPath).obj()));
+
+  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;
+  }
+
+  return true;
+}
+
+#endif  // org_chromium_TestJni_JNI
diff --git a/base/android/jni_generator/testInputStream.javap b/base/android/jni_generator/testInputStream.javap
new file mode 100644
index 0000000..50ab617
--- /dev/null
+++ b/base/android/jni_generator/testInputStream.javap
@@ -0,0 +1,228 @@
+Compiled from "InputStream.java"
+public abstract class java.io.InputStream extends java.lang.Object implements java.io.Closeable
+  SourceFile: "InputStream.java"
+  minor version: 0
+  major version: 49
+  Constant pool:
+const #1 = Method #6.#39; //  java/lang/Object."<init>":()V
+const #2 = class  #40;  //  java/lang/RuntimeException
+const #3 = String #41;  //  Stub!
+const #4 = Method #2.#42; //  java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+const #5 = class  #43;  //  java/io/InputStream
+const #6 = class  #44;  //  java/lang/Object
+const #7 = class  #45;  //  java/io/Closeable
+const #8 = Asciz  <init>;
+const #9 = Asciz  ()V;
+const #10 = Asciz Code;
+const #11 = Asciz LineNumberTable;
+const #12 = Asciz LocalVariableTable;
+const #13 = Asciz this;
+const #14 = Asciz Ljava/io/InputStream;;
+const #15 = Asciz available;
+const #16 = Asciz ()I;
+const #17 = Asciz Exceptions;
+const #18 = class #46;  //  java/io/IOException
+const #19 = Asciz close;
+const #20 = Asciz mark;
+const #21 = Asciz (I)V;
+const #22 = Asciz readlimit;
+const #23 = Asciz I;
+const #24 = Asciz markSupported;
+const #25 = Asciz ()Z;
+const #26 = Asciz read;
+const #27 = Asciz ([B)I;
+const #28 = Asciz buffer;
+const #29 = Asciz [B;
+const #30 = Asciz ([BII)I;
+const #31 = Asciz byteOffset;
+const #32 = Asciz byteCount;
+const #33 = Asciz reset;
+const #34 = Asciz skip;
+const #35 = Asciz (J)J;
+const #36 = Asciz J;
+const #37 = Asciz SourceFile;
+const #38 = Asciz InputStream.java;
+const #39 = NameAndType #8:#9;//  "<init>":()V
+const #40 = Asciz java/lang/RuntimeException;
+const #41 = Asciz Stub!;
+const #42 = NameAndType #8:#47;//  "<init>":(Ljava/lang/String;)V
+const #43 = Asciz java/io/InputStream;
+const #44 = Asciz java/lang/Object;
+const #45 = Asciz java/io/Closeable;
+const #46 = Asciz java/io/IOException;
+const #47 = Asciz (Ljava/lang/String;)V;
+
+{
+public java.io.InputStream();
+  Signature: ()V
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: aload_0
+   1: invokespecial #1; //Method java/lang/Object."<init>":()V
+   4: new #2; //class java/lang/RuntimeException
+   7: dup
+   8: ldc #3; //String Stub!
+   10:  invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   13:  athrow
+  LineNumberTable:
+   line 5: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      14      0    this       Ljava/io/InputStream;
+
+
+public int available()   throws java.io.IOException;
+  Signature: ()I
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 6: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Ljava/io/InputStream;
+
+  Exceptions:
+   throws java.io.IOException
+public void close()   throws java.io.IOException;
+  Signature: ()V
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 7: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Ljava/io/InputStream;
+
+  Exceptions:
+   throws java.io.IOException
+public void mark(int);
+  Signature: (I)V
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 8: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Ljava/io/InputStream;
+   0      10      1    readlimit       I
+
+
+public boolean markSupported();
+  Signature: ()Z
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 9: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Ljava/io/InputStream;
+
+
+public abstract int read()   throws java.io.IOException;
+  Signature: ()I
+  Exceptions:
+   throws java.io.IOException
+public int read(byte[])   throws java.io.IOException;
+  Signature: ([B)I
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 11: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Ljava/io/InputStream;
+   0      10      1    buffer       [B
+
+  Exceptions:
+   throws java.io.IOException
+public int read(byte[], int, int)   throws java.io.IOException;
+  Signature: ([BII)I
+  Code:
+   Stack=3, Locals=4, Args_size=4
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 12: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Ljava/io/InputStream;
+   0      10      1    buffer       [B
+   0      10      2    byteOffset       I
+   0      10      3    byteCount       I
+
+  Exceptions:
+   throws java.io.IOException
+public synchronized void reset()   throws java.io.IOException;
+  Signature: ()V
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 13: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Ljava/io/InputStream;
+
+  Exceptions:
+   throws java.io.IOException
+public long skip(long)   throws java.io.IOException;
+  Signature: (J)J
+  Code:
+   Stack=3, Locals=3, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 14: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Ljava/io/InputStream;
+   0      10      1    byteCount       J
+
+  Exceptions:
+   throws java.io.IOException
+}
+
diff --git a/base/android/jni_generator/testJNIInitNativeNameOption.golden b/base/android/jni_generator/testJNIInitNativeNameOption.golden
new file mode 100644
index 0000000..a0998da
--- /dev/null
+++ b/base/android/jni_generator/testJNIInitNativeNameOption.golden
@@ -0,0 +1,71 @@
+// 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/Test
+
+#ifndef org_chromium_example_jni_generator_Test_JNI
+#define org_chromium_example_jni_generator_Test_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 kTestClassPath[] = "org/chromium/example/jni_generator/Test";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_Test_clazz = NULL;
+#define Test_clazz(env) g_Test_clazz
+
+}  // namespace
+
+// Step 2: method stubs.
+static jint Method(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);
+}
+
+// Step 3: RegisterNatives.
+
+static const JNINativeMethod kMethodsTest[] = {
+    { "nativeMethod",
+"("
+"J"
+"I"
+")"
+"I", reinterpret_cast<void*>(Method) },
+};
+
+static bool RegisterNativesImpl(JNIEnv* env, jclass clazz) {
+
+  g_Test_clazz = static_cast<jclass>(env->NewWeakGlobalRef(clazz));
+
+  const int kMethodsTestSize = arraysize(kMethodsTest);
+
+  if (env->RegisterNatives(Test_clazz(env),
+                           kMethodsTest,
+                           kMethodsTestSize) < 0) {
+    jni_generator::HandleRegistrationError(
+        env, Test_clazz(env), __FILE__);
+    return false;
+  }
+
+  return true;
+}
+
+extern "C" JNIEXPORT bool JNICALL
+Java_org_chromium_example_jni_generator_Test_nativeInitNativeClass(JNIEnv* env,
+    jclass clazz) {
+  return RegisterNativesImpl(env, clazz);
+}
+
+#endif  // org_chromium_example_jni_generator_Test_JNI
diff --git a/base/android/jni_generator/testJarJarRemapping.golden b/base/android/jni_generator/testJarJarRemapping.golden
new file mode 100644
index 0000000..2f85122
--- /dev/null
+++ b/base/android/jni_generator/testJarJarRemapping.golden
@@ -0,0 +1,85 @@
+// 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/Example
+
+#ifndef org_chromium_example_jni_generator_Example_JNI
+#define org_chromium_example_jni_generator_Example_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 kExampleClassPath[] = "com/test/jni_generator/Example";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_Example_clazz = NULL;
+#define Example_clazz(env) g_Example_clazz
+
+}  // namespace
+
+static void Test(JNIEnv* env, jclass jcaller,
+    jobject t);
+
+static void Test2(JNIEnv* env, jclass jcaller,
+    jobject t);
+
+static void Test3(JNIEnv* env, jclass jcaller,
+    jobject t);
+
+static void Test4(JNIEnv* env, jclass jcaller,
+    jobject t);
+
+// Step 2: method stubs.
+
+// Step 3: RegisterNatives.
+
+static const JNINativeMethod kMethodsExample[] = {
+    { "nativeTest",
+"("
+"Lorg/test2/Test;"
+")"
+"V", reinterpret_cast<void*>(Test) },
+    { "nativeTest2",
+"("
+"Lorg/chromium/example3/PrefixFoo;"
+")"
+"V", reinterpret_cast<void*>(Test2) },
+    { "nativeTest3",
+"("
+"Lorg/test3/Test;"
+")"
+"V", reinterpret_cast<void*>(Test3) },
+    { "nativeTest4",
+"("
+"Lorg/test3/TestBar$Inner;"
+")"
+"V", reinterpret_cast<void*>(Test4) },
+};
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+  g_Example_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetClass(env, kExampleClassPath).obj()));
+
+  const int kMethodsExampleSize = arraysize(kMethodsExample);
+
+  if (env->RegisterNatives(Example_clazz(env),
+                           kMethodsExample,
+                           kMethodsExampleSize) < 0) {
+    jni_generator::HandleRegistrationError(
+        env, Example_clazz(env), __FILE__);
+    return false;
+  }
+
+  return true;
+}
+
+#endif  // org_chromium_example_jni_generator_Example_JNI
diff --git a/base/android/jni_generator/testMotionEvent.javap b/base/android/jni_generator/testMotionEvent.javap
new file mode 100644
index 0000000..0746943
--- /dev/null
+++ b/base/android/jni_generator/testMotionEvent.javap
@@ -0,0 +1,2295 @@
+Compiled from "MotionEvent.java"
+public final class android.view.MotionEvent extends android.view.InputEvent implements android.os.Parcelable
+  SourceFile: "MotionEvent.java"
+  InnerClass:
+   public final #10= #9 of #6; //PointerProperties=class android/view/MotionEvent$PointerProperties of class android/view/MotionEvent
+   public final #13= #12 of #6; //PointerCoords=class android/view/MotionEvent$PointerCoords of class android/view/MotionEvent
+   public abstract #150= #149 of #8; //Creator=class android/os/Parcelable$Creator of class android/os/Parcelable
+  minor version: 0
+  major version: 49
+  Constant pool:
+const #1 = Method #7.#293;  //  android/view/InputEvent."<init>":()V
+const #2 = class  #294; //  java/lang/RuntimeException
+const #3 = String #295; //  Stub!
+const #4 = Method #2.#296;  //  java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+const #5 = Field  #6.#297;  //  android/view/MotionEvent.CREATOR:Landroid/os/Parcelable$Creator;
+const #6 = class  #298; //  android/view/MotionEvent
+const #7 = class  #299; //  android/view/InputEvent
+const #8 = class  #300; //  android/os/Parcelable
+const #9 = class  #301; //  android/view/MotionEvent$PointerProperties
+const #10 = Asciz PointerProperties;
+const #11 = Asciz InnerClasses;
+const #12 = class #302; //  android/view/MotionEvent$PointerCoords
+const #13 = Asciz PointerCoords;
+const #14 = Asciz INVALID_POINTER_ID;
+const #15 = Asciz I;
+const #16 = Asciz ConstantValue;
+const #17 = int -1;
+const #18 = Asciz ACTION_MASK;
+const #19 = int 255;
+const #20 = Asciz ACTION_DOWN;
+const #21 = int 0;
+const #22 = Asciz ACTION_UP;
+const #23 = int 1;
+const #24 = Asciz ACTION_MOVE;
+const #25 = int 2;
+const #26 = Asciz ACTION_CANCEL;
+const #27 = int 3;
+const #28 = Asciz ACTION_OUTSIDE;
+const #29 = int 4;
+const #30 = Asciz ACTION_POINTER_DOWN;
+const #31 = int 5;
+const #32 = Asciz ACTION_POINTER_UP;
+const #33 = int 6;
+const #34 = Asciz ACTION_HOVER_MOVE;
+const #35 = int 7;
+const #36 = Asciz ACTION_SCROLL;
+const #37 = int 8;
+const #38 = Asciz ACTION_HOVER_ENTER;
+const #39 = int 9;
+const #40 = Asciz ACTION_HOVER_EXIT;
+const #41 = int 10;
+const #42 = Asciz ACTION_POINTER_INDEX_MASK;
+const #43 = int 65280;
+const #44 = Asciz ACTION_POINTER_INDEX_SHIFT;
+const #45 = Asciz ACTION_POINTER_1_DOWN;
+const #46 = Asciz Deprecated;
+const #47 = Asciz RuntimeVisibleAnnotations;
+const #48 = Asciz Ljava/lang/Deprecated;;
+const #49 = Asciz ACTION_POINTER_2_DOWN;
+const #50 = int 261;
+const #51 = Asciz ACTION_POINTER_3_DOWN;
+const #52 = int 517;
+const #53 = Asciz ACTION_POINTER_1_UP;
+const #54 = Asciz ACTION_POINTER_2_UP;
+const #55 = int 262;
+const #56 = Asciz ACTION_POINTER_3_UP;
+const #57 = int 518;
+const #58 = Asciz ACTION_POINTER_ID_MASK;
+const #59 = Asciz ACTION_POINTER_ID_SHIFT;
+const #60 = Asciz FLAG_WINDOW_IS_OBSCURED;
+const #61 = Asciz EDGE_TOP;
+const #62 = Asciz EDGE_BOTTOM;
+const #63 = Asciz EDGE_LEFT;
+const #64 = Asciz EDGE_RIGHT;
+const #65 = Asciz AXIS_X;
+const #66 = Asciz AXIS_Y;
+const #67 = Asciz AXIS_PRESSURE;
+const #68 = Asciz AXIS_SIZE;
+const #69 = Asciz AXIS_TOUCH_MAJOR;
+const #70 = Asciz AXIS_TOUCH_MINOR;
+const #71 = Asciz AXIS_TOOL_MAJOR;
+const #72 = Asciz AXIS_TOOL_MINOR;
+const #73 = Asciz AXIS_ORIENTATION;
+const #74 = Asciz AXIS_VSCROLL;
+const #75 = Asciz AXIS_HSCROLL;
+const #76 = Asciz AXIS_Z;
+const #77 = int 11;
+const #78 = Asciz AXIS_RX;
+const #79 = int 12;
+const #80 = Asciz AXIS_RY;
+const #81 = int 13;
+const #82 = Asciz AXIS_RZ;
+const #83 = int 14;
+const #84 = Asciz AXIS_HAT_X;
+const #85 = int 15;
+const #86 = Asciz AXIS_HAT_Y;
+const #87 = int 16;
+const #88 = Asciz AXIS_LTRIGGER;
+const #89 = int 17;
+const #90 = Asciz AXIS_RTRIGGER;
+const #91 = int 18;
+const #92 = Asciz AXIS_THROTTLE;
+const #93 = int 19;
+const #94 = Asciz AXIS_RUDDER;
+const #95 = int 20;
+const #96 = Asciz AXIS_WHEEL;
+const #97 = int 21;
+const #98 = Asciz AXIS_GAS;
+const #99 = int 22;
+const #100 = Asciz  AXIS_BRAKE;
+const #101 = int  23;
+const #102 = Asciz  AXIS_DISTANCE;
+const #103 = int  24;
+const #104 = Asciz  AXIS_TILT;
+const #105 = int  25;
+const #106 = Asciz  AXIS_GENERIC_1;
+const #107 = int  32;
+const #108 = Asciz  AXIS_GENERIC_2;
+const #109 = int  33;
+const #110 = Asciz  AXIS_GENERIC_3;
+const #111 = int  34;
+const #112 = Asciz  AXIS_GENERIC_4;
+const #113 = int  35;
+const #114 = Asciz  AXIS_GENERIC_5;
+const #115 = int  36;
+const #116 = Asciz  AXIS_GENERIC_6;
+const #117 = int  37;
+const #118 = Asciz  AXIS_GENERIC_7;
+const #119 = int  38;
+const #120 = Asciz  AXIS_GENERIC_8;
+const #121 = int  39;
+const #122 = Asciz  AXIS_GENERIC_9;
+const #123 = int  40;
+const #124 = Asciz  AXIS_GENERIC_10;
+const #125 = int  41;
+const #126 = Asciz  AXIS_GENERIC_11;
+const #127 = int  42;
+const #128 = Asciz  AXIS_GENERIC_12;
+const #129 = int  43;
+const #130 = Asciz  AXIS_GENERIC_13;
+const #131 = int  44;
+const #132 = Asciz  AXIS_GENERIC_14;
+const #133 = int  45;
+const #134 = Asciz  AXIS_GENERIC_15;
+const #135 = int  46;
+const #136 = Asciz  AXIS_GENERIC_16;
+const #137 = int  47;
+const #138 = Asciz  BUTTON_PRIMARY;
+const #139 = Asciz  BUTTON_SECONDARY;
+const #140 = Asciz  BUTTON_TERTIARY;
+const #141 = Asciz  BUTTON_BACK;
+const #142 = Asciz  BUTTON_FORWARD;
+const #143 = Asciz  TOOL_TYPE_UNKNOWN;
+const #144 = Asciz  TOOL_TYPE_FINGER;
+const #145 = Asciz  TOOL_TYPE_STYLUS;
+const #146 = Asciz  TOOL_TYPE_MOUSE;
+const #147 = Asciz  TOOL_TYPE_ERASER;
+const #148 = Asciz  CREATOR;
+const #149 = class  #303; //  android/os/Parcelable$Creator
+const #150 = Asciz  Creator;
+const #151 = Asciz  Landroid/os/Parcelable$Creator;;
+const #152 = Asciz  Signature;
+const #153 = Asciz  Landroid/os/Parcelable$Creator<Landroid/view/MotionEvent;>;;
+const #154 = Asciz  <init>;
+const #155 = Asciz  ()V;
+const #156 = Asciz  Code;
+const #157 = Asciz  LineNumberTable;
+const #158 = Asciz  LocalVariableTable;
+const #159 = Asciz  this;
+const #160 = Asciz  Landroid/view/MotionEvent;;
+const #161 = Asciz  finalize;
+const #162 = Asciz  Exceptions;
+const #163 = class  #304; //  java/lang/Throwable
+const #164 = Asciz  obtain;
+const #165 = Asciz  (JJII[Landroid/view/MotionEvent$PointerProperties;[Landroid/view/MotionEvent$PointerCoords;IIFFIIII)Landroid/view/MotionEvent;;
+const #166 = Asciz  downTime;
+const #167 = Asciz  J;
+const #168 = Asciz  eventTime;
+const #169 = Asciz  action;
+const #170 = Asciz  pointerCount;
+const #171 = Asciz  pointerProperties;
+const #172 = Asciz  [Landroid/view/MotionEvent$PointerProperties;;
+const #173 = Asciz  pointerCoords;
+const #174 = Asciz  [Landroid/view/MotionEvent$PointerCoords;;
+const #175 = Asciz  metaState;
+const #176 = Asciz  buttonState;
+const #177 = Asciz  xPrecision;
+const #178 = Asciz  F;
+const #179 = Asciz  yPrecision;
+const #180 = Asciz  deviceId;
+const #181 = Asciz  edgeFlags;
+const #182 = Asciz  source;
+const #183 = Asciz  flags;
+const #184 = Asciz  (JJII[I[Landroid/view/MotionEvent$PointerCoords;IFFIIII)Landroid/view/MotionEvent;;
+const #185 = Asciz  pointerIds;
+const #186 = Asciz  [I;
+const #187 = Asciz  (JJIFFFFIFFII)Landroid/view/MotionEvent;;
+const #188 = Asciz  x;
+const #189 = Asciz  y;
+const #190 = Asciz  pressure;
+const #191 = Asciz  size;
+const #192 = Asciz  (JJIIFFFFIFFII)Landroid/view/MotionEvent;;
+const #193 = Asciz  (JJIFFI)Landroid/view/MotionEvent;;
+const #194 = Asciz  (Landroid/view/MotionEvent;)Landroid/view/MotionEvent;;
+const #195 = Asciz  other;
+const #196 = Asciz  obtainNoHistory;
+const #197 = Asciz  recycle;
+const #198 = Asciz  getDeviceId;
+const #199 = Asciz  ()I;
+const #200 = Asciz  getSource;
+const #201 = Asciz  setSource;
+const #202 = Asciz  (I)V;
+const #203 = Asciz  getAction;
+const #204 = Asciz  getActionMasked;
+const #205 = Asciz  getActionIndex;
+const #206 = Asciz  getFlags;
+const #207 = Asciz  getDownTime;
+const #208 = Asciz  ()J;
+const #209 = Asciz  getEventTime;
+const #210 = Asciz  getX;
+const #211 = Asciz  ()F;
+const #212 = Asciz  getY;
+const #213 = Asciz  getPressure;
+const #214 = Asciz  getSize;
+const #215 = Asciz  getTouchMajor;
+const #216 = Asciz  getTouchMinor;
+const #217 = Asciz  getToolMajor;
+const #218 = Asciz  getToolMinor;
+const #219 = Asciz  getOrientation;
+const #220 = Asciz  getAxisValue;
+const #221 = Asciz  (I)F;
+const #222 = Asciz  axis;
+const #223 = Asciz  getPointerCount;
+const #224 = Asciz  getPointerId;
+const #225 = Asciz  (I)I;
+const #226 = Asciz  pointerIndex;
+const #227 = Asciz  getToolType;
+const #228 = Asciz  findPointerIndex;
+const #229 = Asciz  pointerId;
+const #230 = Asciz  (II)F;
+const #231 = Asciz  getPointerCoords;
+const #232 = Asciz  (ILandroid/view/MotionEvent$PointerCoords;)V;
+const #233 = Asciz  outPointerCoords;
+const #234 = Asciz  Landroid/view/MotionEvent$PointerCoords;;
+const #235 = Asciz  getPointerProperties;
+const #236 = Asciz  (ILandroid/view/MotionEvent$PointerProperties;)V;
+const #237 = Asciz  outPointerProperties;
+const #238 = Asciz  Landroid/view/MotionEvent$PointerProperties;;
+const #239 = Asciz  getMetaState;
+const #240 = Asciz  getButtonState;
+const #241 = Asciz  getRawX;
+const #242 = Asciz  getRawY;
+const #243 = Asciz  getXPrecision;
+const #244 = Asciz  getYPrecision;
+const #245 = Asciz  getHistorySize;
+const #246 = Asciz  getHistoricalEventTime;
+const #247 = Asciz  (I)J;
+const #248 = Asciz  pos;
+const #249 = Asciz  getHistoricalX;
+const #250 = Asciz  getHistoricalY;
+const #251 = Asciz  getHistoricalPressure;
+const #252 = Asciz  getHistoricalSize;
+const #253 = Asciz  getHistoricalTouchMajor;
+const #254 = Asciz  getHistoricalTouchMinor;
+const #255 = Asciz  getHistoricalToolMajor;
+const #256 = Asciz  getHistoricalToolMinor;
+const #257 = Asciz  getHistoricalOrientation;
+const #258 = Asciz  getHistoricalAxisValue;
+const #259 = Asciz  (III)F;
+const #260 = Asciz  getHistoricalPointerCoords;
+const #261 = Asciz  (IILandroid/view/MotionEvent$PointerCoords;)V;
+const #262 = Asciz  getEdgeFlags;
+const #263 = Asciz  setEdgeFlags;
+const #264 = Asciz  setAction;
+const #265 = Asciz  offsetLocation;
+const #266 = Asciz  (FF)V;
+const #267 = Asciz  deltaX;
+const #268 = Asciz  deltaY;
+const #269 = Asciz  setLocation;
+const #270 = Asciz  transform;
+const #271 = Asciz  (Landroid/graphics/Matrix;)V;
+const #272 = Asciz  matrix;
+const #273 = Asciz  Landroid/graphics/Matrix;;
+const #274 = Asciz  addBatch;
+const #275 = Asciz  (JFFFFI)V;
+const #276 = Asciz  (J[Landroid/view/MotionEvent$PointerCoords;I)V;
+const #277 = Asciz  toString;
+const #278 = Asciz  ()Ljava/lang/String;;
+const #279 = Asciz  actionToString;
+const #280 = Asciz  (I)Ljava/lang/String;;
+const #281 = Asciz  axisToString;
+const #282 = Asciz  axisFromString;
+const #283 = Asciz  (Ljava/lang/String;)I;
+const #284 = Asciz  symbolicName;
+const #285 = Asciz  Ljava/lang/String;;
+const #286 = Asciz  writeToParcel;
+const #287 = Asciz  (Landroid/os/Parcel;I)V;
+const #288 = Asciz  out;
+const #289 = Asciz  Landroid/os/Parcel;;
+const #290 = Asciz  <clinit>;
+const #291 = Asciz  SourceFile;
+const #292 = Asciz  MotionEvent.java;
+const #293 = NameAndType  #154:#155;//  "<init>":()V
+const #294 = Asciz  java/lang/RuntimeException;
+const #295 = Asciz  Stub!;
+const #296 = NameAndType  #154:#305;//  "<init>":(Ljava/lang/String;)V
+const #297 = NameAndType  #148:#151;//  CREATOR:Landroid/os/Parcelable$Creator;
+const #298 = Asciz  android/view/MotionEvent;
+const #299 = Asciz  android/view/InputEvent;
+const #300 = Asciz  android/os/Parcelable;
+const #301 = Asciz  android/view/MotionEvent$PointerProperties;
+const #302 = Asciz  android/view/MotionEvent$PointerCoords;
+const #303 = Asciz  android/os/Parcelable$Creator;
+const #304 = Asciz  java/lang/Throwable;
+const #305 = Asciz  (Ljava/lang/String;)V;
+
+{
+public static final int INVALID_POINTER_ID;
+  Signature: I
+  Constant value: int -1
+
+public static final int ACTION_MASK;
+  Signature: I
+  Constant value: int 255
+
+public static final int ACTION_DOWN;
+  Signature: I
+  Constant value: int 0
+
+public static final int ACTION_UP;
+  Signature: I
+  Constant value: int 1
+
+public static final int ACTION_MOVE;
+  Signature: I
+  Constant value: int 2
+
+public static final int ACTION_CANCEL;
+  Signature: I
+  Constant value: int 3
+
+public static final int ACTION_OUTSIDE;
+  Signature: I
+  Constant value: int 4
+
+public static final int ACTION_POINTER_DOWN;
+  Signature: I
+  Constant value: int 5
+
+public static final int ACTION_POINTER_UP;
+  Signature: I
+  Constant value: int 6
+
+public static final int ACTION_HOVER_MOVE;
+  Signature: I
+  Constant value: int 7
+
+public static final int ACTION_SCROLL;
+  Signature: I
+  Constant value: int 8
+
+public static final int ACTION_HOVER_ENTER;
+  Signature: I
+  Constant value: int 9
+
+public static final int ACTION_HOVER_EXIT;
+  Signature: I
+  Constant value: int 10
+
+public static final int ACTION_POINTER_INDEX_MASK;
+  Signature: I
+  Constant value: int 65280
+
+public static final int ACTION_POINTER_INDEX_SHIFT;
+  Signature: I
+  Constant value: int 8
+
+public static final int ACTION_POINTER_1_DOWN;
+  Signature: I
+  Constant value: int 5Deprecated: true
+  RuntimeVisibleAnnotations: length = 0x6
+   00 01 00 30 00 00
+
+
+public static final int ACTION_POINTER_2_DOWN;
+  Signature: I
+  Constant value: int 261Deprecated: true
+  RuntimeVisibleAnnotations: length = 0x6
+   00 01 00 30 00 00
+
+
+public static final int ACTION_POINTER_3_DOWN;
+  Signature: I
+  Constant value: int 517Deprecated: true
+  RuntimeVisibleAnnotations: length = 0x6
+   00 01 00 30 00 00
+
+
+public static final int ACTION_POINTER_1_UP;
+  Signature: I
+  Constant value: int 6Deprecated: true
+  RuntimeVisibleAnnotations: length = 0x6
+   00 01 00 30 00 00
+
+
+public static final int ACTION_POINTER_2_UP;
+  Signature: I
+  Constant value: int 262Deprecated: true
+  RuntimeVisibleAnnotations: length = 0x6
+   00 01 00 30 00 00
+
+
+public static final int ACTION_POINTER_3_UP;
+  Signature: I
+  Constant value: int 518Deprecated: true
+  RuntimeVisibleAnnotations: length = 0x6
+   00 01 00 30 00 00
+
+
+public static final int ACTION_POINTER_ID_MASK;
+  Signature: I
+  Constant value: int 65280Deprecated: true
+  RuntimeVisibleAnnotations: length = 0x6
+   00 01 00 30 00 00
+
+
+public static final int ACTION_POINTER_ID_SHIFT;
+  Signature: I
+  Constant value: int 8Deprecated: true
+  RuntimeVisibleAnnotations: length = 0x6
+   00 01 00 30 00 00
+
+
+public static final int FLAG_WINDOW_IS_OBSCURED;
+  Signature: I
+  Constant value: int 1
+
+public static final int EDGE_TOP;
+  Signature: I
+  Constant value: int 1
+
+public static final int EDGE_BOTTOM;
+  Signature: I
+  Constant value: int 2
+
+public static final int EDGE_LEFT;
+  Signature: I
+  Constant value: int 4
+
+public static final int EDGE_RIGHT;
+  Signature: I
+  Constant value: int 8
+
+public static final int AXIS_X;
+  Signature: I
+  Constant value: int 0
+
+public static final int AXIS_Y;
+  Signature: I
+  Constant value: int 1
+
+public static final int AXIS_PRESSURE;
+  Signature: I
+  Constant value: int 2
+
+public static final int AXIS_SIZE;
+  Signature: I
+  Constant value: int 3
+
+public static final int AXIS_TOUCH_MAJOR;
+  Signature: I
+  Constant value: int 4
+
+public static final int AXIS_TOUCH_MINOR;
+  Signature: I
+  Constant value: int 5
+
+public static final int AXIS_TOOL_MAJOR;
+  Signature: I
+  Constant value: int 6
+
+public static final int AXIS_TOOL_MINOR;
+  Signature: I
+  Constant value: int 7
+
+public static final int AXIS_ORIENTATION;
+  Signature: I
+  Constant value: int 8
+
+public static final int AXIS_VSCROLL;
+  Signature: I
+  Constant value: int 9
+
+public static final int AXIS_HSCROLL;
+  Signature: I
+  Constant value: int 10
+
+public static final int AXIS_Z;
+  Signature: I
+  Constant value: int 11
+
+public static final int AXIS_RX;
+  Signature: I
+  Constant value: int 12
+
+public static final int AXIS_RY;
+  Signature: I
+  Constant value: int 13
+
+public static final int AXIS_RZ;
+  Signature: I
+  Constant value: int 14
+
+public static final int AXIS_HAT_X;
+  Signature: I
+  Constant value: int 15
+
+public static final int AXIS_HAT_Y;
+  Signature: I
+  Constant value: int 16
+
+public static final int AXIS_LTRIGGER;
+  Signature: I
+  Constant value: int 17
+
+public static final int AXIS_RTRIGGER;
+  Signature: I
+  Constant value: int 18
+
+public static final int AXIS_THROTTLE;
+  Signature: I
+  Constant value: int 19
+
+public static final int AXIS_RUDDER;
+  Signature: I
+  Constant value: int 20
+
+public static final int AXIS_WHEEL;
+  Signature: I
+  Constant value: int 21
+
+public static final int AXIS_GAS;
+  Signature: I
+  Constant value: int 22
+
+public static final int AXIS_BRAKE;
+  Signature: I
+  Constant value: int 23
+
+public static final int AXIS_DISTANCE;
+  Signature: I
+  Constant value: int 24
+
+public static final int AXIS_TILT;
+  Signature: I
+  Constant value: int 25
+
+public static final int AXIS_GENERIC_1;
+  Signature: I
+  Constant value: int 32
+
+public static final int AXIS_GENERIC_2;
+  Signature: I
+  Constant value: int 33
+
+public static final int AXIS_GENERIC_3;
+  Signature: I
+  Constant value: int 34
+
+public static final int AXIS_GENERIC_4;
+  Signature: I
+  Constant value: int 35
+
+public static final int AXIS_GENERIC_5;
+  Signature: I
+  Constant value: int 36
+
+public static final int AXIS_GENERIC_6;
+  Signature: I
+  Constant value: int 37
+
+public static final int AXIS_GENERIC_7;
+  Signature: I
+  Constant value: int 38
+
+public static final int AXIS_GENERIC_8;
+  Signature: I
+  Constant value: int 39
+
+public static final int AXIS_GENERIC_9;
+  Signature: I
+  Constant value: int 40
+
+public static final int AXIS_GENERIC_10;
+  Signature: I
+  Constant value: int 41
+
+public static final int AXIS_GENERIC_11;
+  Signature: I
+  Constant value: int 42
+
+public static final int AXIS_GENERIC_12;
+  Signature: I
+  Constant value: int 43
+
+public static final int AXIS_GENERIC_13;
+  Signature: I
+  Constant value: int 44
+
+public static final int AXIS_GENERIC_14;
+  Signature: I
+  Constant value: int 45
+
+public static final int AXIS_GENERIC_15;
+  Signature: I
+  Constant value: int 46
+
+public static final int AXIS_GENERIC_16;
+  Signature: I
+  Constant value: int 47
+
+public static final int BUTTON_PRIMARY;
+  Signature: I
+  Constant value: int 1
+
+public static final int BUTTON_SECONDARY;
+  Signature: I
+  Constant value: int 2
+
+public static final int BUTTON_TERTIARY;
+  Signature: I
+  Constant value: int 4
+
+public static final int BUTTON_BACK;
+  Signature: I
+  Constant value: int 8
+
+public static final int BUTTON_FORWARD;
+  Signature: I
+  Constant value: int 16
+
+public static final int TOOL_TYPE_UNKNOWN;
+  Signature: I
+  Constant value: int 0
+
+public static final int TOOL_TYPE_FINGER;
+  Signature: I
+  Constant value: int 1
+
+public static final int TOOL_TYPE_STYLUS;
+  Signature: I
+  Constant value: int 2
+
+public static final int TOOL_TYPE_MOUSE;
+  Signature: I
+  Constant value: int 3
+
+public static final int TOOL_TYPE_ERASER;
+  Signature: I
+  Constant value: int 4
+
+public static final android.os.Parcelable$Creator CREATOR;
+  Signature: Landroid/os/Parcelable$Creator;
+  Signature: length = 0x2
+   00 FFFFFF99
+
+
+android.view.MotionEvent();
+  Signature: ()V
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: aload_0
+   1: invokespecial #1; //Method android/view/InputEvent."<init>":()V
+   4: new #2; //class java/lang/RuntimeException
+   7: dup
+   8: ldc #3; //String Stub!
+   10:  invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   13:  athrow
+  LineNumberTable:
+   line 35: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      14      0    this       Landroid/view/MotionEvent;
+
+
+protected void finalize()   throws java.lang.Throwable;
+  Signature: ()V
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 36: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+  Exceptions:
+   throws java.lang.Throwable
+public static android.view.MotionEvent obtain(long, long, int, int, android.view.MotionEvent$PointerProperties[], android.view.MotionEvent$PointerCoords[], int, int, float, float, int, int, int, int);
+  Signature: (JJII[Landroid/view/MotionEvent$PointerProperties;[Landroid/view/MotionEvent$PointerCoords;IIFFIIII)Landroid/view/MotionEvent;
+  Code:
+   Stack=3, Locals=16, Args_size=14
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 37: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    downTime       J
+   0      10      2    eventTime       J
+   0      10      4    action       I
+   0      10      5    pointerCount       I
+   0      10      6    pointerProperties       [Landroid/view/MotionEvent$PointerProperties;
+   0      10      7    pointerCoords       [Landroid/view/MotionEvent$PointerCoords;
+   0      10      8    metaState       I
+   0      10      9    buttonState       I
+   0      10      10    xPrecision       F
+   0      10      11    yPrecision       F
+   0      10      12    deviceId       I
+   0      10      13    edgeFlags       I
+   0      10      14    source       I
+   0      10      15    flags       I
+
+
+public static android.view.MotionEvent obtain(long, long, int, int, int[], android.view.MotionEvent$PointerCoords[], int, float, float, int, int, int, int);
+  Signature: (JJII[I[Landroid/view/MotionEvent$PointerCoords;IFFIIII)Landroid/view/MotionEvent;
+  Code:
+   Stack=3, Locals=15, Args_size=13
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 39: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    downTime       J
+   0      10      2    eventTime       J
+   0      10      4    action       I
+   0      10      5    pointerCount       I
+   0      10      6    pointerIds       [I
+   0      10      7    pointerCoords       [Landroid/view/MotionEvent$PointerCoords;
+   0      10      8    metaState       I
+   0      10      9    xPrecision       F
+   0      10      10    yPrecision       F
+   0      10      11    deviceId       I
+   0      10      12    edgeFlags       I
+   0      10      13    source       I
+   0      10      14    flags       I
+
+  Deprecated: true
+  RuntimeVisibleAnnotations: length = 0x6
+   00 01 00 30 00 00
+
+public static android.view.MotionEvent obtain(long, long, int, float, float, float, float, int, float, float, int, int);
+  Signature: (JJIFFFFIFFII)Landroid/view/MotionEvent;
+  Code:
+   Stack=3, Locals=14, Args_size=12
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 40: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    downTime       J
+   0      10      2    eventTime       J
+   0      10      4    action       I
+   0      10      5    x       F
+   0      10      6    y       F
+   0      10      7    pressure       F
+   0      10      8    size       F
+   0      10      9    metaState       I
+   0      10      10    xPrecision       F
+   0      10      11    yPrecision       F
+   0      10      12    deviceId       I
+   0      10      13    edgeFlags       I
+
+
+public static android.view.MotionEvent obtain(long, long, int, int, float, float, float, float, int, float, float, int, int);
+  Signature: (JJIIFFFFIFFII)Landroid/view/MotionEvent;
+  Code:
+   Stack=3, Locals=15, Args_size=13
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 42: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    downTime       J
+   0      10      2    eventTime       J
+   0      10      4    action       I
+   0      10      5    pointerCount       I
+   0      10      6    x       F
+   0      10      7    y       F
+   0      10      8    pressure       F
+   0      10      9    size       F
+   0      10      10    metaState       I
+   0      10      11    xPrecision       F
+   0      10      12    yPrecision       F
+   0      10      13    deviceId       I
+   0      10      14    edgeFlags       I
+
+  Deprecated: true
+  RuntimeVisibleAnnotations: length = 0x6
+   00 01 00 30 00 00
+
+public static android.view.MotionEvent obtain(long, long, int, float, float, int);
+  Signature: (JJIFFI)Landroid/view/MotionEvent;
+  Code:
+   Stack=3, Locals=8, Args_size=6
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 43: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    downTime       J
+   0      10      2    eventTime       J
+   0      10      4    action       I
+   0      10      5    x       F
+   0      10      6    y       F
+   0      10      7    metaState       I
+
+
+public static android.view.MotionEvent obtain(android.view.MotionEvent);
+  Signature: (Landroid/view/MotionEvent;)Landroid/view/MotionEvent;
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 44: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    other       Landroid/view/MotionEvent;
+
+
+public static android.view.MotionEvent obtainNoHistory(android.view.MotionEvent);
+  Signature: (Landroid/view/MotionEvent;)Landroid/view/MotionEvent;
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 45: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    other       Landroid/view/MotionEvent;
+
+
+public final void recycle();
+  Signature: ()V
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 46: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final int getDeviceId();
+  Signature: ()I
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 47: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final int getSource();
+  Signature: ()I
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 48: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final void setSource(int);
+  Signature: (I)V
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 49: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    source       I
+
+
+public final int getAction();
+  Signature: ()I
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 50: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final int getActionMasked();
+  Signature: ()I
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 51: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final int getActionIndex();
+  Signature: ()I
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 52: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final int getFlags();
+  Signature: ()I
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 53: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final long getDownTime();
+  Signature: ()J
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 54: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final long getEventTime();
+  Signature: ()J
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 55: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final float getX();
+  Signature: ()F
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 56: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final float getY();
+  Signature: ()F
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 57: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final float getPressure();
+  Signature: ()F
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 58: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final float getSize();
+  Signature: ()F
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 59: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final float getTouchMajor();
+  Signature: ()F
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 60: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final float getTouchMinor();
+  Signature: ()F
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 61: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final float getToolMajor();
+  Signature: ()F
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 62: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final float getToolMinor();
+  Signature: ()F
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 63: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final float getOrientation();
+  Signature: ()F
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 64: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final float getAxisValue(int);
+  Signature: (I)F
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 65: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    axis       I
+
+
+public final int getPointerCount();
+  Signature: ()I
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 66: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final int getPointerId(int);
+  Signature: (I)I
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 67: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+
+
+public final int getToolType(int);
+  Signature: (I)I
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 68: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+
+
+public final int findPointerIndex(int);
+  Signature: (I)I
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 69: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerId       I
+
+
+public final float getX(int);
+  Signature: (I)F
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 70: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+
+
+public final float getY(int);
+  Signature: (I)F
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 71: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+
+
+public final float getPressure(int);
+  Signature: (I)F
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 72: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+
+
+public final float getSize(int);
+  Signature: (I)F
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 73: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+
+
+public final float getTouchMajor(int);
+  Signature: (I)F
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 74: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+
+
+public final float getTouchMinor(int);
+  Signature: (I)F
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 75: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+
+
+public final float getToolMajor(int);
+  Signature: (I)F
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 76: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+
+
+public final float getToolMinor(int);
+  Signature: (I)F
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 77: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+
+
+public final float getOrientation(int);
+  Signature: (I)F
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 78: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+
+
+public final float getAxisValue(int, int);
+  Signature: (II)F
+  Code:
+   Stack=3, Locals=3, Args_size=3
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 79: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    axis       I
+   0      10      2    pointerIndex       I
+
+
+public final void getPointerCoords(int, android.view.MotionEvent$PointerCoords);
+  Signature: (ILandroid/view/MotionEvent$PointerCoords;)V
+  Code:
+   Stack=3, Locals=3, Args_size=3
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 80: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+   0      10      2    outPointerCoords       Landroid/view/MotionEvent$PointerCoords;
+
+
+public final void getPointerProperties(int, android.view.MotionEvent$PointerProperties);
+  Signature: (ILandroid/view/MotionEvent$PointerProperties;)V
+  Code:
+   Stack=3, Locals=3, Args_size=3
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 81: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+   0      10      2    outPointerProperties       Landroid/view/MotionEvent$PointerProperties;
+
+
+public final int getMetaState();
+  Signature: ()I
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 82: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final int getButtonState();
+  Signature: ()I
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 83: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final float getRawX();
+  Signature: ()F
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 84: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final float getRawY();
+  Signature: ()F
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 85: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final float getXPrecision();
+  Signature: ()F
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 86: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final float getYPrecision();
+  Signature: ()F
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 87: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final int getHistorySize();
+  Signature: ()I
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 88: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final long getHistoricalEventTime(int);
+  Signature: (I)J
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 89: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pos       I
+
+
+public final float getHistoricalX(int);
+  Signature: (I)F
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 90: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pos       I
+
+
+public final float getHistoricalY(int);
+  Signature: (I)F
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 91: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pos       I
+
+
+public final float getHistoricalPressure(int);
+  Signature: (I)F
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 92: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pos       I
+
+
+public final float getHistoricalSize(int);
+  Signature: (I)F
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 93: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pos       I
+
+
+public final float getHistoricalTouchMajor(int);
+  Signature: (I)F
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 94: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pos       I
+
+
+public final float getHistoricalTouchMinor(int);
+  Signature: (I)F
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 95: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pos       I
+
+
+public final float getHistoricalToolMajor(int);
+  Signature: (I)F
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 96: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pos       I
+
+
+public final float getHistoricalToolMinor(int);
+  Signature: (I)F
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 97: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pos       I
+
+
+public final float getHistoricalOrientation(int);
+  Signature: (I)F
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 98: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pos       I
+
+
+public final float getHistoricalAxisValue(int, int);
+  Signature: (II)F
+  Code:
+   Stack=3, Locals=3, Args_size=3
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 99: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    axis       I
+   0      10      2    pos       I
+
+
+public final float getHistoricalX(int, int);
+  Signature: (II)F
+  Code:
+   Stack=3, Locals=3, Args_size=3
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 100: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+   0      10      2    pos       I
+
+
+public final float getHistoricalY(int, int);
+  Signature: (II)F
+  Code:
+   Stack=3, Locals=3, Args_size=3
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 101: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+   0      10      2    pos       I
+
+
+public final float getHistoricalPressure(int, int);
+  Signature: (II)F
+  Code:
+   Stack=3, Locals=3, Args_size=3
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 102: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+   0      10      2    pos       I
+
+
+public final float getHistoricalSize(int, int);
+  Signature: (II)F
+  Code:
+   Stack=3, Locals=3, Args_size=3
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 103: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+   0      10      2    pos       I
+
+
+public final float getHistoricalTouchMajor(int, int);
+  Signature: (II)F
+  Code:
+   Stack=3, Locals=3, Args_size=3
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 104: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+   0      10      2    pos       I
+
+
+public final float getHistoricalTouchMinor(int, int);
+  Signature: (II)F
+  Code:
+   Stack=3, Locals=3, Args_size=3
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 105: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+   0      10      2    pos       I
+
+
+public final float getHistoricalToolMajor(int, int);
+  Signature: (II)F
+  Code:
+   Stack=3, Locals=3, Args_size=3
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 106: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+   0      10      2    pos       I
+
+
+public final float getHistoricalToolMinor(int, int);
+  Signature: (II)F
+  Code:
+   Stack=3, Locals=3, Args_size=3
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 107: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+   0      10      2    pos       I
+
+
+public final float getHistoricalOrientation(int, int);
+  Signature: (II)F
+  Code:
+   Stack=3, Locals=3, Args_size=3
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 108: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+   0      10      2    pos       I
+
+
+public final float getHistoricalAxisValue(int, int, int);
+  Signature: (III)F
+  Code:
+   Stack=3, Locals=4, Args_size=4
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 109: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    axis       I
+   0      10      2    pointerIndex       I
+   0      10      3    pos       I
+
+
+public final void getHistoricalPointerCoords(int, int, android.view.MotionEvent$PointerCoords);
+  Signature: (IILandroid/view/MotionEvent$PointerCoords;)V
+  Code:
+   Stack=3, Locals=4, Args_size=4
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 110: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    pointerIndex       I
+   0      10      2    pos       I
+   0      10      3    outPointerCoords       Landroid/view/MotionEvent$PointerCoords;
+
+
+public final int getEdgeFlags();
+  Signature: ()I
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 111: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public final void setEdgeFlags(int);
+  Signature: (I)V
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 112: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    flags       I
+
+
+public final void setAction(int);
+  Signature: (I)V
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 113: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    action       I
+
+
+public final void offsetLocation(float, float);
+  Signature: (FF)V
+  Code:
+   Stack=3, Locals=3, Args_size=3
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 114: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    deltaX       F
+   0      10      2    deltaY       F
+
+
+public final void setLocation(float, float);
+  Signature: (FF)V
+  Code:
+   Stack=3, Locals=3, Args_size=3
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 115: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    x       F
+   0      10      2    y       F
+
+
+public final void transform(android.graphics.Matrix);
+  Signature: (Landroid/graphics/Matrix;)V
+  Code:
+   Stack=3, Locals=2, Args_size=2
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 116: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    matrix       Landroid/graphics/Matrix;
+
+
+public final void addBatch(long, float, float, float, float, int);
+  Signature: (JFFFFI)V
+  Code:
+   Stack=3, Locals=8, Args_size=7
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 117: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    eventTime       J
+   0      10      3    x       F
+   0      10      4    y       F
+   0      10      5    pressure       F
+   0      10      6    size       F
+   0      10      7    metaState       I
+
+
+public final void addBatch(long, android.view.MotionEvent$PointerCoords[], int);
+  Signature: (J[Landroid/view/MotionEvent$PointerCoords;I)V
+  Code:
+   Stack=3, Locals=5, Args_size=4
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 118: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    eventTime       J
+   0      10      3    pointerCoords       [Landroid/view/MotionEvent$PointerCoords;
+   0      10      4    metaState       I
+
+
+public java.lang.String toString();
+  Signature: ()Ljava/lang/String;
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 119: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+
+
+public static java.lang.String actionToString(int);
+  Signature: (I)Ljava/lang/String;
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 120: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    action       I
+
+
+public static java.lang.String axisToString(int);
+  Signature: (I)Ljava/lang/String;
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 121: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    axis       I
+
+
+public static int axisFromString(java.lang.String);
+  Signature: (Ljava/lang/String;)I
+  Code:
+   Stack=3, Locals=1, Args_size=1
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 122: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    symbolicName       Ljava/lang/String;
+
+
+public void writeToParcel(android.os.Parcel, int);
+  Signature: (Landroid/os/Parcel;I)V
+  Code:
+   Stack=3, Locals=3, Args_size=3
+   0: new #2; //class java/lang/RuntimeException
+   3: dup
+   4: ldc #3; //String Stub!
+   6: invokespecial #4; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+   9: athrow
+  LineNumberTable:
+   line 123: 0
+
+  LocalVariableTable:
+   Start  Length  Slot  Name   Signature
+   0      10      0    this       Landroid/view/MotionEvent;
+   0      10      1    out       Landroid/os/Parcel;
+   0      10      2    flags       I
+
+
+static {};
+  Signature: ()V
+  Code:
+   Stack=1, Locals=0, Args_size=0
+   0: aconst_null
+   1: putstatic #5; //Field CREATOR:Landroid/os/Parcelable$Creator;
+   4: return
+  LineNumberTable:
+   line 213: 0
+
+
+}
+
diff --git a/base/android/jni_generator/testMotionEvent.javap7 b/base/android/jni_generator/testMotionEvent.javap7
new file mode 100644
index 0000000..f4f5444
--- /dev/null
+++ b/base/android/jni_generator/testMotionEvent.javap7
@@ -0,0 +1,2370 @@
+Classfile out_android/Debug/gen/content/jni/android/view/MotionEvent.class
+  Last modified Feb 27, 2014; size 13369 bytes
+  MD5 checksum 3718d77a994cb8aceb7b35c5df3c4dd1
+  Compiled from "MotionEvent.java"
+public final class android.view.MotionEvent extends android.view.InputEvent implements android.os.Parcelable
+  SourceFile: "MotionEvent.java"
+  InnerClasses:
+       public static final #10= #9 of #6; //PointerProperties=class android/view/MotionEvent$PointerProperties of class android/view/MotionEvent
+       public static final #13= #12 of #6; //PointerCoords=class android/view/MotionEvent$PointerCoords of class android/view/MotionEvent
+       public static #150= #149 of #8; //Creator=class android/os/Parcelable$Creator of class android/os/Parcelable
+  minor version: 0
+  major version: 49
+  flags: ACC_PUBLIC, ACC_FINAL, ACC_SUPER
+Constant pool:
+    #1 = Methodref          #7.#293       //  android/view/InputEvent."<init>":()V
+    #2 = Class              #294          //  java/lang/RuntimeException
+    #3 = String             #295          //  Stub!
+    #4 = Methodref          #2.#296       //  java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+    #5 = Fieldref           #6.#297       //  android/view/MotionEvent.CREATOR:Landroid/os/Parcelable$Creator;
+    #6 = Class              #298          //  android/view/MotionEvent
+    #7 = Class              #299          //  android/view/InputEvent
+    #8 = Class              #300          //  android/os/Parcelable
+    #9 = Class              #301          //  android/view/MotionEvent$PointerProperties
+   #10 = Utf8               PointerProperties
+   #11 = Utf8               InnerClasses
+   #12 = Class              #302          //  android/view/MotionEvent$PointerCoords
+   #13 = Utf8               PointerCoords
+   #14 = Utf8               INVALID_POINTER_ID
+   #15 = Utf8               I
+   #16 = Utf8               ConstantValue
+   #17 = Integer            -1
+   #18 = Utf8               ACTION_MASK
+   #19 = Integer            255
+   #20 = Utf8               ACTION_DOWN
+   #21 = Integer            0
+   #22 = Utf8               ACTION_UP
+   #23 = Integer            1
+   #24 = Utf8               ACTION_MOVE
+   #25 = Integer            2
+   #26 = Utf8               ACTION_CANCEL
+   #27 = Integer            3
+   #28 = Utf8               ACTION_OUTSIDE
+   #29 = Integer            4
+   #30 = Utf8               ACTION_POINTER_DOWN
+   #31 = Integer            5
+   #32 = Utf8               ACTION_POINTER_UP
+   #33 = Integer            6
+   #34 = Utf8               ACTION_HOVER_MOVE
+   #35 = Integer            7
+   #36 = Utf8               ACTION_SCROLL
+   #37 = Integer            8
+   #38 = Utf8               ACTION_HOVER_ENTER
+   #39 = Integer            9
+   #40 = Utf8               ACTION_HOVER_EXIT
+   #41 = Integer            10
+   #42 = Utf8               ACTION_POINTER_INDEX_MASK
+   #43 = Integer            65280
+   #44 = Utf8               ACTION_POINTER_INDEX_SHIFT
+   #45 = Utf8               ACTION_POINTER_1_DOWN
+   #46 = Utf8               Deprecated
+   #47 = Utf8               RuntimeVisibleAnnotations
+   #48 = Utf8               Ljava/lang/Deprecated;
+   #49 = Utf8               ACTION_POINTER_2_DOWN
+   #50 = Integer            261
+   #51 = Utf8               ACTION_POINTER_3_DOWN
+   #52 = Integer            517
+   #53 = Utf8               ACTION_POINTER_1_UP
+   #54 = Utf8               ACTION_POINTER_2_UP
+   #55 = Integer            262
+   #56 = Utf8               ACTION_POINTER_3_UP
+   #57 = Integer            518
+   #58 = Utf8               ACTION_POINTER_ID_MASK
+   #59 = Utf8               ACTION_POINTER_ID_SHIFT
+   #60 = Utf8               FLAG_WINDOW_IS_OBSCURED
+   #61 = Utf8               EDGE_TOP
+   #62 = Utf8               EDGE_BOTTOM
+   #63 = Utf8               EDGE_LEFT
+   #64 = Utf8               EDGE_RIGHT
+   #65 = Utf8               AXIS_X
+   #66 = Utf8               AXIS_Y
+   #67 = Utf8               AXIS_PRESSURE
+   #68 = Utf8               AXIS_SIZE
+   #69 = Utf8               AXIS_TOUCH_MAJOR
+   #70 = Utf8               AXIS_TOUCH_MINOR
+   #71 = Utf8               AXIS_TOOL_MAJOR
+   #72 = Utf8               AXIS_TOOL_MINOR
+   #73 = Utf8               AXIS_ORIENTATION
+   #74 = Utf8               AXIS_VSCROLL
+   #75 = Utf8               AXIS_HSCROLL
+   #76 = Utf8               AXIS_Z
+   #77 = Integer            11
+   #78 = Utf8               AXIS_RX
+   #79 = Integer            12
+   #80 = Utf8               AXIS_RY
+   #81 = Integer            13
+   #82 = Utf8               AXIS_RZ
+   #83 = Integer            14
+   #84 = Utf8               AXIS_HAT_X
+   #85 = Integer            15
+   #86 = Utf8               AXIS_HAT_Y
+   #87 = Integer            16
+   #88 = Utf8               AXIS_LTRIGGER
+   #89 = Integer            17
+   #90 = Utf8               AXIS_RTRIGGER
+   #91 = Integer            18
+   #92 = Utf8               AXIS_THROTTLE
+   #93 = Integer            19
+   #94 = Utf8               AXIS_RUDDER
+   #95 = Integer            20
+   #96 = Utf8               AXIS_WHEEL
+   #97 = Integer            21
+   #98 = Utf8               AXIS_GAS
+   #99 = Integer            22
+  #100 = Utf8               AXIS_BRAKE
+  #101 = Integer            23
+  #102 = Utf8               AXIS_DISTANCE
+  #103 = Integer            24
+  #104 = Utf8               AXIS_TILT
+  #105 = Integer            25
+  #106 = Utf8               AXIS_GENERIC_1
+  #107 = Integer            32
+  #108 = Utf8               AXIS_GENERIC_2
+  #109 = Integer            33
+  #110 = Utf8               AXIS_GENERIC_3
+  #111 = Integer            34
+  #112 = Utf8               AXIS_GENERIC_4
+  #113 = Integer            35
+  #114 = Utf8               AXIS_GENERIC_5
+  #115 = Integer            36
+  #116 = Utf8               AXIS_GENERIC_6
+  #117 = Integer            37
+  #118 = Utf8               AXIS_GENERIC_7
+  #119 = Integer            38
+  #120 = Utf8               AXIS_GENERIC_8
+  #121 = Integer            39
+  #122 = Utf8               AXIS_GENERIC_9
+  #123 = Integer            40
+  #124 = Utf8               AXIS_GENERIC_10
+  #125 = Integer            41
+  #126 = Utf8               AXIS_GENERIC_11
+  #127 = Integer            42
+  #128 = Utf8               AXIS_GENERIC_12
+  #129 = Integer            43
+  #130 = Utf8               AXIS_GENERIC_13
+  #131 = Integer            44
+  #132 = Utf8               AXIS_GENERIC_14
+  #133 = Integer            45
+  #134 = Utf8               AXIS_GENERIC_15
+  #135 = Integer            46
+  #136 = Utf8               AXIS_GENERIC_16
+  #137 = Integer            47
+  #138 = Utf8               BUTTON_PRIMARY
+  #139 = Utf8               BUTTON_SECONDARY
+  #140 = Utf8               BUTTON_TERTIARY
+  #141 = Utf8               BUTTON_BACK
+  #142 = Utf8               BUTTON_FORWARD
+  #143 = Utf8               TOOL_TYPE_UNKNOWN
+  #144 = Utf8               TOOL_TYPE_FINGER
+  #145 = Utf8               TOOL_TYPE_STYLUS
+  #146 = Utf8               TOOL_TYPE_MOUSE
+  #147 = Utf8               TOOL_TYPE_ERASER
+  #148 = Utf8               CREATOR
+  #149 = Class              #303          //  android/os/Parcelable$Creator
+  #150 = Utf8               Creator
+  #151 = Utf8               Landroid/os/Parcelable$Creator;
+  #152 = Utf8               Signature
+  #153 = Utf8               Landroid/os/Parcelable$Creator<Landroid/view/MotionEvent;>;
+  #154 = Utf8               <init>
+  #155 = Utf8               ()V
+  #156 = Utf8               Code
+  #157 = Utf8               LineNumberTable
+  #158 = Utf8               LocalVariableTable
+  #159 = Utf8               this
+  #160 = Utf8               Landroid/view/MotionEvent;
+  #161 = Utf8               finalize
+  #162 = Utf8               Exceptions
+  #163 = Class              #304          //  java/lang/Throwable
+  #164 = Utf8               obtain
+  #165 = Utf8               (JJII[Landroid/view/MotionEvent$PointerProperties;[Landroid/view/MotionEvent$PointerCoords;IIFFIIII)Landroid/view/MotionEvent;
+  #166 = Utf8               downTime
+  #167 = Utf8               J
+  #168 = Utf8               eventTime
+  #169 = Utf8               action
+  #170 = Utf8               pointerCount
+  #171 = Utf8               pointerProperties
+  #172 = Utf8               [Landroid/view/MotionEvent$PointerProperties;
+  #173 = Utf8               pointerCoords
+  #174 = Utf8               [Landroid/view/MotionEvent$PointerCoords;
+  #175 = Utf8               metaState
+  #176 = Utf8               buttonState
+  #177 = Utf8               xPrecision
+  #178 = Utf8               F
+  #179 = Utf8               yPrecision
+  #180 = Utf8               deviceId
+  #181 = Utf8               edgeFlags
+  #182 = Utf8               source
+  #183 = Utf8               flags
+  #184 = Utf8               (JJII[I[Landroid/view/MotionEvent$PointerCoords;IFFIIII)Landroid/view/MotionEvent;
+  #185 = Utf8               pointerIds
+  #186 = Utf8               [I
+  #187 = Utf8               (JJIFFFFIFFII)Landroid/view/MotionEvent;
+  #188 = Utf8               x
+  #189 = Utf8               y
+  #190 = Utf8               pressure
+  #191 = Utf8               size
+  #192 = Utf8               (JJIIFFFFIFFII)Landroid/view/MotionEvent;
+  #193 = Utf8               (JJIFFI)Landroid/view/MotionEvent;
+  #194 = Utf8               (Landroid/view/MotionEvent;)Landroid/view/MotionEvent;
+  #195 = Utf8               other
+  #196 = Utf8               obtainNoHistory
+  #197 = Utf8               recycle
+  #198 = Utf8               getDeviceId
+  #199 = Utf8               ()I
+  #200 = Utf8               getSource
+  #201 = Utf8               setSource
+  #202 = Utf8               (I)V
+  #203 = Utf8               getAction
+  #204 = Utf8               getActionMasked
+  #205 = Utf8               getActionIndex
+  #206 = Utf8               getFlags
+  #207 = Utf8               getDownTime
+  #208 = Utf8               ()J
+  #209 = Utf8               getEventTime
+  #210 = Utf8               getX
+  #211 = Utf8               ()F
+  #212 = Utf8               getY
+  #213 = Utf8               getPressure
+  #214 = Utf8               getSize
+  #215 = Utf8               getTouchMajor
+  #216 = Utf8               getTouchMinor
+  #217 = Utf8               getToolMajor
+  #218 = Utf8               getToolMinor
+  #219 = Utf8               getOrientation
+  #220 = Utf8               getAxisValue
+  #221 = Utf8               (I)F
+  #222 = Utf8               axis
+  #223 = Utf8               getPointerCount
+  #224 = Utf8               getPointerId
+  #225 = Utf8               (I)I
+  #226 = Utf8               pointerIndex
+  #227 = Utf8               getToolType
+  #228 = Utf8               findPointerIndex
+  #229 = Utf8               pointerId
+  #230 = Utf8               (II)F
+  #231 = Utf8               getPointerCoords
+  #232 = Utf8               (ILandroid/view/MotionEvent$PointerCoords;)V
+  #233 = Utf8               outPointerCoords
+  #234 = Utf8               Landroid/view/MotionEvent$PointerCoords;
+  #235 = Utf8               getPointerProperties
+  #236 = Utf8               (ILandroid/view/MotionEvent$PointerProperties;)V
+  #237 = Utf8               outPointerProperties
+  #238 = Utf8               Landroid/view/MotionEvent$PointerProperties;
+  #239 = Utf8               getMetaState
+  #240 = Utf8               getButtonState
+  #241 = Utf8               getRawX
+  #242 = Utf8               getRawY
+  #243 = Utf8               getXPrecision
+  #244 = Utf8               getYPrecision
+  #245 = Utf8               getHistorySize
+  #246 = Utf8               getHistoricalEventTime
+  #247 = Utf8               (I)J
+  #248 = Utf8               pos
+  #249 = Utf8               getHistoricalX
+  #250 = Utf8               getHistoricalY
+  #251 = Utf8               getHistoricalPressure
+  #252 = Utf8               getHistoricalSize
+  #253 = Utf8               getHistoricalTouchMajor
+  #254 = Utf8               getHistoricalTouchMinor
+  #255 = Utf8               getHistoricalToolMajor
+  #256 = Utf8               getHistoricalToolMinor
+  #257 = Utf8               getHistoricalOrientation
+  #258 = Utf8               getHistoricalAxisValue
+  #259 = Utf8               (III)F
+  #260 = Utf8               getHistoricalPointerCoords
+  #261 = Utf8               (IILandroid/view/MotionEvent$PointerCoords;)V
+  #262 = Utf8               getEdgeFlags
+  #263 = Utf8               setEdgeFlags
+  #264 = Utf8               setAction
+  #265 = Utf8               offsetLocation
+  #266 = Utf8               (FF)V
+  #267 = Utf8               deltaX
+  #268 = Utf8               deltaY
+  #269 = Utf8               setLocation
+  #270 = Utf8               transform
+  #271 = Utf8               (Landroid/graphics/Matrix;)V
+  #272 = Utf8               matrix
+  #273 = Utf8               Landroid/graphics/Matrix;
+  #274 = Utf8               addBatch
+  #275 = Utf8               (JFFFFI)V
+  #276 = Utf8               (J[Landroid/view/MotionEvent$PointerCoords;I)V
+  #277 = Utf8               toString
+  #278 = Utf8               ()Ljava/lang/String;
+  #279 = Utf8               actionToString
+  #280 = Utf8               (I)Ljava/lang/String;
+  #281 = Utf8               axisToString
+  #282 = Utf8               axisFromString
+  #283 = Utf8               (Ljava/lang/String;)I
+  #284 = Utf8               symbolicName
+  #285 = Utf8               Ljava/lang/String;
+  #286 = Utf8               writeToParcel
+  #287 = Utf8               (Landroid/os/Parcel;I)V
+  #288 = Utf8               out
+  #289 = Utf8               Landroid/os/Parcel;
+  #290 = Utf8               <clinit>
+  #291 = Utf8               SourceFile
+  #292 = Utf8               MotionEvent.java
+  #293 = NameAndType        #154:#155     //  "<init>":()V
+  #294 = Utf8               java/lang/RuntimeException
+  #295 = Utf8               Stub!
+  #296 = NameAndType        #154:#305     //  "<init>":(Ljava/lang/String;)V
+  #297 = NameAndType        #148:#151     //  CREATOR:Landroid/os/Parcelable$Creator;
+  #298 = Utf8               android/view/MotionEvent
+  #299 = Utf8               android/view/InputEvent
+  #300 = Utf8               android/os/Parcelable
+  #301 = Utf8               android/view/MotionEvent$PointerProperties
+  #302 = Utf8               android/view/MotionEvent$PointerCoords
+  #303 = Utf8               android/os/Parcelable$Creator
+  #304 = Utf8               java/lang/Throwable
+  #305 = Utf8               (Ljava/lang/String;)V
+{
+  public static final int INVALID_POINTER_ID;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int -1
+
+
+  public static final int ACTION_MASK;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 255
+
+
+  public static final int ACTION_DOWN;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 0
+
+
+  public static final int ACTION_UP;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 1
+
+
+  public static final int ACTION_MOVE;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 2
+
+
+  public static final int ACTION_CANCEL;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 3
+
+
+  public static final int ACTION_OUTSIDE;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 4
+
+
+  public static final int ACTION_POINTER_DOWN;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 5
+
+
+  public static final int ACTION_POINTER_UP;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 6
+
+
+  public static final int ACTION_HOVER_MOVE;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 7
+
+
+  public static final int ACTION_SCROLL;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 8
+
+
+  public static final int ACTION_HOVER_ENTER;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 9
+
+
+  public static final int ACTION_HOVER_EXIT;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 10
+
+
+  public static final int ACTION_POINTER_INDEX_MASK;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 65280
+
+
+  public static final int ACTION_POINTER_INDEX_SHIFT;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 8
+
+
+  public static final int ACTION_POINTER_1_DOWN;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 5
+    Deprecated: true
+    RuntimeVisibleAnnotations:
+      0: #48()
+
+
+  public static final int ACTION_POINTER_2_DOWN;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 261
+    Deprecated: true
+    RuntimeVisibleAnnotations:
+      0: #48()
+
+
+  public static final int ACTION_POINTER_3_DOWN;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 517
+    Deprecated: true
+    RuntimeVisibleAnnotations:
+      0: #48()
+
+
+  public static final int ACTION_POINTER_1_UP;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 6
+    Deprecated: true
+    RuntimeVisibleAnnotations:
+      0: #48()
+
+
+  public static final int ACTION_POINTER_2_UP;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 262
+    Deprecated: true
+    RuntimeVisibleAnnotations:
+      0: #48()
+
+
+  public static final int ACTION_POINTER_3_UP;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 518
+    Deprecated: true
+    RuntimeVisibleAnnotations:
+      0: #48()
+
+
+  public static final int ACTION_POINTER_ID_MASK;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 65280
+    Deprecated: true
+    RuntimeVisibleAnnotations:
+      0: #48()
+
+
+  public static final int ACTION_POINTER_ID_SHIFT;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 8
+    Deprecated: true
+    RuntimeVisibleAnnotations:
+      0: #48()
+
+
+  public static final int FLAG_WINDOW_IS_OBSCURED;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 1
+
+
+  public static final int EDGE_TOP;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 1
+
+
+  public static final int EDGE_BOTTOM;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 2
+
+
+  public static final int EDGE_LEFT;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 4
+
+
+  public static final int EDGE_RIGHT;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 8
+
+
+  public static final int AXIS_X;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 0
+
+
+  public static final int AXIS_Y;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 1
+
+
+  public static final int AXIS_PRESSURE;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 2
+
+
+  public static final int AXIS_SIZE;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 3
+
+
+  public static final int AXIS_TOUCH_MAJOR;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 4
+
+
+  public static final int AXIS_TOUCH_MINOR;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 5
+
+
+  public static final int AXIS_TOOL_MAJOR;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 6
+
+
+  public static final int AXIS_TOOL_MINOR;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 7
+
+
+  public static final int AXIS_ORIENTATION;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 8
+
+
+  public static final int AXIS_VSCROLL;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 9
+
+
+  public static final int AXIS_HSCROLL;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 10
+
+
+  public static final int AXIS_Z;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 11
+
+
+  public static final int AXIS_RX;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 12
+
+
+  public static final int AXIS_RY;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 13
+
+
+  public static final int AXIS_RZ;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 14
+
+
+  public static final int AXIS_HAT_X;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 15
+
+
+  public static final int AXIS_HAT_Y;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 16
+
+
+  public static final int AXIS_LTRIGGER;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 17
+
+
+  public static final int AXIS_RTRIGGER;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 18
+
+
+  public static final int AXIS_THROTTLE;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 19
+
+
+  public static final int AXIS_RUDDER;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 20
+
+
+  public static final int AXIS_WHEEL;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 21
+
+
+  public static final int AXIS_GAS;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 22
+
+
+  public static final int AXIS_BRAKE;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 23
+
+
+  public static final int AXIS_DISTANCE;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 24
+
+
+  public static final int AXIS_TILT;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 25
+
+
+  public static final int AXIS_GENERIC_1;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 32
+
+
+  public static final int AXIS_GENERIC_2;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 33
+
+
+  public static final int AXIS_GENERIC_3;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 34
+
+
+  public static final int AXIS_GENERIC_4;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 35
+
+
+  public static final int AXIS_GENERIC_5;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 36
+
+
+  public static final int AXIS_GENERIC_6;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 37
+
+
+  public static final int AXIS_GENERIC_7;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 38
+
+
+  public static final int AXIS_GENERIC_8;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 39
+
+
+  public static final int AXIS_GENERIC_9;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 40
+
+
+  public static final int AXIS_GENERIC_10;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 41
+
+
+  public static final int AXIS_GENERIC_11;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 42
+
+
+  public static final int AXIS_GENERIC_12;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 43
+
+
+  public static final int AXIS_GENERIC_13;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 44
+
+
+  public static final int AXIS_GENERIC_14;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 45
+
+
+  public static final int AXIS_GENERIC_15;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 46
+
+
+  public static final int AXIS_GENERIC_16;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 47
+
+
+  public static final int BUTTON_PRIMARY;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 1
+
+
+  public static final int BUTTON_SECONDARY;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 2
+
+
+  public static final int BUTTON_TERTIARY;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 4
+
+
+  public static final int BUTTON_BACK;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 8
+
+
+  public static final int BUTTON_FORWARD;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 16
+
+
+  public static final int TOOL_TYPE_UNKNOWN;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 0
+
+
+  public static final int TOOL_TYPE_FINGER;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 1
+
+
+  public static final int TOOL_TYPE_STYLUS;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 2
+
+
+  public static final int TOOL_TYPE_MOUSE;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 3
+
+
+  public static final int TOOL_TYPE_ERASER;
+    Signature: I
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    ConstantValue: int 4
+
+
+  public static final android.os.Parcelable$Creator<android.view.MotionEvent> CREATOR;
+    Signature: Landroid/os/Parcelable$Creator;
+    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
+    Signature: #153                         // Landroid/os/Parcelable$Creator<Landroid/view/MotionEvent;>;
+
+
+  android.view.MotionEvent();
+    Signature: ()V
+    flags:
+    Code:
+      stack=3, locals=1, args_size=1
+         0: aload_0
+         1: invokespecial #1                  // Method android/view/InputEvent."<init>":()V
+         4: new           #2                  // class java/lang/RuntimeException
+         7: dup
+         8: ldc           #3                  // String Stub!
+        10: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+        13: athrow
+      LineNumberTable:
+        line 35: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      14     0  this   Landroid/view/MotionEvent;
+
+  protected void finalize() throws java.lang.Throwable;
+    Signature: ()V
+    flags: ACC_PROTECTED
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 36: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+    Exceptions:
+      throws java.lang.Throwable
+
+  public static android.view.MotionEvent obtain(long, long, int, int, android.view.MotionEvent$PointerProperties[], android.view.MotionEvent$PointerCoords[], int, int, float, float, int, int, int, int);
+    Signature: (JJII[Landroid/view/MotionEvent$PointerProperties;[Landroid/view/MotionEvent$PointerCoords;IIFFIIII)Landroid/view/MotionEvent;
+    flags: ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=16, args_size=14
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 37: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0 downTime   J
+               0      10     2 eventTime   J
+               0      10     4 action   I
+               0      10     5 pointerCount   I
+               0      10     6 pointerProperties   [Landroid/view/MotionEvent$PointerProperties;
+               0      10     7 pointerCoords   [Landroid/view/MotionEvent$PointerCoords;
+               0      10     8 metaState   I
+               0      10     9 buttonState   I
+               0      10    10 xPrecision   F
+               0      10    11 yPrecision   F
+               0      10    12 deviceId   I
+               0      10    13 edgeFlags   I
+               0      10    14 source   I
+               0      10    15 flags   I
+
+  public static android.view.MotionEvent obtain(long, long, int, int, int[], android.view.MotionEvent$PointerCoords[], int, float, float, int, int, int, int);
+    Signature: (JJII[I[Landroid/view/MotionEvent$PointerCoords;IFFIIII)Landroid/view/MotionEvent;
+    flags: ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=15, args_size=13
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 39: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0 downTime   J
+               0      10     2 eventTime   J
+               0      10     4 action   I
+               0      10     5 pointerCount   I
+               0      10     6 pointerIds   [I
+               0      10     7 pointerCoords   [Landroid/view/MotionEvent$PointerCoords;
+               0      10     8 metaState   I
+               0      10     9 xPrecision   F
+               0      10    10 yPrecision   F
+               0      10    11 deviceId   I
+               0      10    12 edgeFlags   I
+               0      10    13 source   I
+               0      10    14 flags   I
+    Deprecated: true
+    RuntimeVisibleAnnotations:
+      0: #48()
+
+  public static android.view.MotionEvent obtain(long, long, int, float, float, float, float, int, float, float, int, int);
+    Signature: (JJIFFFFIFFII)Landroid/view/MotionEvent;
+    flags: ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=14, args_size=12
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 40: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0 downTime   J
+               0      10     2 eventTime   J
+               0      10     4 action   I
+               0      10     5     x   F
+               0      10     6     y   F
+               0      10     7 pressure   F
+               0      10     8  size   F
+               0      10     9 metaState   I
+               0      10    10 xPrecision   F
+               0      10    11 yPrecision   F
+               0      10    12 deviceId   I
+               0      10    13 edgeFlags   I
+
+  public static android.view.MotionEvent obtain(long, long, int, int, float, float, float, float, int, float, float, int, int);
+    Signature: (JJIIFFFFIFFII)Landroid/view/MotionEvent;
+    flags: ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=15, args_size=13
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 42: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0 downTime   J
+               0      10     2 eventTime   J
+               0      10     4 action   I
+               0      10     5 pointerCount   I
+               0      10     6     x   F
+               0      10     7     y   F
+               0      10     8 pressure   F
+               0      10     9  size   F
+               0      10    10 metaState   I
+               0      10    11 xPrecision   F
+               0      10    12 yPrecision   F
+               0      10    13 deviceId   I
+               0      10    14 edgeFlags   I
+    Deprecated: true
+    RuntimeVisibleAnnotations:
+      0: #48()
+
+  public static android.view.MotionEvent obtain(long, long, int, float, float, int);
+    Signature: (JJIFFI)Landroid/view/MotionEvent;
+    flags: ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=8, args_size=6
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 43: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0 downTime   J
+               0      10     2 eventTime   J
+               0      10     4 action   I
+               0      10     5     x   F
+               0      10     6     y   F
+               0      10     7 metaState   I
+
+  public static android.view.MotionEvent obtain(android.view.MotionEvent);
+    Signature: (Landroid/view/MotionEvent;)Landroid/view/MotionEvent;
+    flags: ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 44: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0 other   Landroid/view/MotionEvent;
+
+  public static android.view.MotionEvent obtainNoHistory(android.view.MotionEvent);
+    Signature: (Landroid/view/MotionEvent;)Landroid/view/MotionEvent;
+    flags: ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 45: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0 other   Landroid/view/MotionEvent;
+
+  public final void recycle();
+    Signature: ()V
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 46: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final int getDeviceId();
+    Signature: ()I
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 47: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final int getSource();
+    Signature: ()I
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 48: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final void setSource(int);
+    Signature: (I)V
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 49: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 source   I
+
+  public final int getAction();
+    Signature: ()I
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 50: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final int getActionMasked();
+    Signature: ()I
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 51: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final int getActionIndex();
+    Signature: ()I
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 52: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final int getFlags();
+    Signature: ()I
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 53: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final long getDownTime();
+    Signature: ()J
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 54: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final long getEventTime();
+    Signature: ()J
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 55: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final float getX();
+    Signature: ()F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 56: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final float getY();
+    Signature: ()F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 57: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final float getPressure();
+    Signature: ()F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 58: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final float getSize();
+    Signature: ()F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 59: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final float getTouchMajor();
+    Signature: ()F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 60: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final float getTouchMinor();
+    Signature: ()F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 61: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final float getToolMajor();
+    Signature: ()F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 62: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final float getToolMinor();
+    Signature: ()F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 63: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final float getOrientation();
+    Signature: ()F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 64: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final float getAxisValue(int);
+    Signature: (I)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 65: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1  axis   I
+
+  public final int getPointerCount();
+    Signature: ()I
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 66: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final int getPointerId(int);
+    Signature: (I)I
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 67: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+
+  public final int getToolType(int);
+    Signature: (I)I
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 68: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+
+  public final int findPointerIndex(int);
+    Signature: (I)I
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 69: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerId   I
+
+  public final float getX(int);
+    Signature: (I)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 70: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+
+  public final float getY(int);
+    Signature: (I)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 71: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+
+  public final float getPressure(int);
+    Signature: (I)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 72: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+
+  public final float getSize(int);
+    Signature: (I)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 73: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+
+  public final float getTouchMajor(int);
+    Signature: (I)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 74: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+
+  public final float getTouchMinor(int);
+    Signature: (I)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 75: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+
+  public final float getToolMajor(int);
+    Signature: (I)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 76: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+
+  public final float getToolMinor(int);
+    Signature: (I)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 77: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+
+  public final float getOrientation(int);
+    Signature: (I)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 78: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+
+  public final float getAxisValue(int, int);
+    Signature: (II)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=3, args_size=3
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 79: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1  axis   I
+               0      10     2 pointerIndex   I
+
+  public final void getPointerCoords(int, android.view.MotionEvent$PointerCoords);
+    Signature: (ILandroid/view/MotionEvent$PointerCoords;)V
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=3, args_size=3
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 80: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+               0      10     2 outPointerCoords   Landroid/view/MotionEvent$PointerCoords;
+
+  public final void getPointerProperties(int, android.view.MotionEvent$PointerProperties);
+    Signature: (ILandroid/view/MotionEvent$PointerProperties;)V
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=3, args_size=3
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 81: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+               0      10     2 outPointerProperties   Landroid/view/MotionEvent$PointerProperties;
+
+  public final int getMetaState();
+    Signature: ()I
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 82: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final int getButtonState();
+    Signature: ()I
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 83: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final float getRawX();
+    Signature: ()F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 84: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final float getRawY();
+    Signature: ()F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 85: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final float getXPrecision();
+    Signature: ()F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 86: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final float getYPrecision();
+    Signature: ()F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 87: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final int getHistorySize();
+    Signature: ()I
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 88: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final long getHistoricalEventTime(int);
+    Signature: (I)J
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 89: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1   pos   I
+
+  public final float getHistoricalX(int);
+    Signature: (I)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 90: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1   pos   I
+
+  public final float getHistoricalY(int);
+    Signature: (I)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 91: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1   pos   I
+
+  public final float getHistoricalPressure(int);
+    Signature: (I)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 92: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1   pos   I
+
+  public final float getHistoricalSize(int);
+    Signature: (I)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 93: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1   pos   I
+
+  public final float getHistoricalTouchMajor(int);
+    Signature: (I)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 94: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1   pos   I
+
+  public final float getHistoricalTouchMinor(int);
+    Signature: (I)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 95: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1   pos   I
+
+  public final float getHistoricalToolMajor(int);
+    Signature: (I)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 96: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1   pos   I
+
+  public final float getHistoricalToolMinor(int);
+    Signature: (I)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 97: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1   pos   I
+
+  public final float getHistoricalOrientation(int);
+    Signature: (I)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 98: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1   pos   I
+
+  public final float getHistoricalAxisValue(int, int);
+    Signature: (II)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=3, args_size=3
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 99: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1  axis   I
+               0      10     2   pos   I
+
+  public final float getHistoricalX(int, int);
+    Signature: (II)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=3, args_size=3
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 100: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+               0      10     2   pos   I
+
+  public final float getHistoricalY(int, int);
+    Signature: (II)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=3, args_size=3
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 101: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+               0      10     2   pos   I
+
+  public final float getHistoricalPressure(int, int);
+    Signature: (II)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=3, args_size=3
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 102: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+               0      10     2   pos   I
+
+  public final float getHistoricalSize(int, int);
+    Signature: (II)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=3, args_size=3
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 103: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+               0      10     2   pos   I
+
+  public final float getHistoricalTouchMajor(int, int);
+    Signature: (II)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=3, args_size=3
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 104: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+               0      10     2   pos   I
+
+  public final float getHistoricalTouchMinor(int, int);
+    Signature: (II)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=3, args_size=3
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 105: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+               0      10     2   pos   I
+
+  public final float getHistoricalToolMajor(int, int);
+    Signature: (II)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=3, args_size=3
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 106: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+               0      10     2   pos   I
+
+  public final float getHistoricalToolMinor(int, int);
+    Signature: (II)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=3, args_size=3
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 107: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+               0      10     2   pos   I
+
+  public final float getHistoricalOrientation(int, int);
+    Signature: (II)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=3, args_size=3
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 108: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+               0      10     2   pos   I
+
+  public final float getHistoricalAxisValue(int, int, int);
+    Signature: (III)F
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=4, args_size=4
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 109: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1  axis   I
+               0      10     2 pointerIndex   I
+               0      10     3   pos   I
+
+  public final void getHistoricalPointerCoords(int, int, android.view.MotionEvent$PointerCoords);
+    Signature: (IILandroid/view/MotionEvent$PointerCoords;)V
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=4, args_size=4
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 110: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 pointerIndex   I
+               0      10     2   pos   I
+               0      10     3 outPointerCoords   Landroid/view/MotionEvent$PointerCoords;
+
+  public final int getEdgeFlags();
+    Signature: ()I
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 111: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public final void setEdgeFlags(int);
+    Signature: (I)V
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 112: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 flags   I
+
+  public final void setAction(int);
+    Signature: (I)V
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 113: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 action   I
+
+  public final void offsetLocation(float, float);
+    Signature: (FF)V
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=3, args_size=3
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 114: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 deltaX   F
+               0      10     2 deltaY   F
+
+  public final void setLocation(float, float);
+    Signature: (FF)V
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=3, args_size=3
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 115: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1     x   F
+               0      10     2     y   F
+
+  public final void transform(android.graphics.Matrix);
+    Signature: (Landroid/graphics/Matrix;)V
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=2, args_size=2
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 116: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 matrix   Landroid/graphics/Matrix;
+
+  public final void addBatch(long, float, float, float, float, int);
+    Signature: (JFFFFI)V
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=8, args_size=7
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 117: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 eventTime   J
+               0      10     3     x   F
+               0      10     4     y   F
+               0      10     5 pressure   F
+               0      10     6  size   F
+               0      10     7 metaState   I
+
+  public final void addBatch(long, android.view.MotionEvent$PointerCoords[], int);
+    Signature: (J[Landroid/view/MotionEvent$PointerCoords;I)V
+    flags: ACC_PUBLIC, ACC_FINAL
+    Code:
+      stack=3, locals=5, args_size=4
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 118: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1 eventTime   J
+               0      10     3 pointerCoords   [Landroid/view/MotionEvent$PointerCoords;
+               0      10     4 metaState   I
+
+  public java.lang.String toString();
+    Signature: ()Ljava/lang/String;
+    flags: ACC_PUBLIC
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 119: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+
+  public static java.lang.String actionToString(int);
+    Signature: (I)Ljava/lang/String;
+    flags: ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 120: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0 action   I
+
+  public static java.lang.String axisToString(int);
+    Signature: (I)Ljava/lang/String;
+    flags: ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 121: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  axis   I
+
+  public static int axisFromString(java.lang.String);
+    Signature: (Ljava/lang/String;)I
+    flags: ACC_PUBLIC, ACC_STATIC
+    Code:
+      stack=3, locals=1, args_size=1
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 122: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0 symbolicName   Ljava/lang/String;
+
+  public void writeToParcel(android.os.Parcel, int);
+    Signature: (Landroid/os/Parcel;I)V
+    flags: ACC_PUBLIC
+    Code:
+      stack=3, locals=3, args_size=3
+         0: new           #2                  // class java/lang/RuntimeException
+         3: dup
+         4: ldc           #3                  // String Stub!
+         6: invokespecial #4                  // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
+         9: athrow
+      LineNumberTable:
+        line 123: 0
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+               0      10     0  this   Landroid/view/MotionEvent;
+               0      10     1   out   Landroid/os/Parcel;
+               0      10     2 flags   I
+
+  static {};
+    Signature: ()V
+    flags: ACC_STATIC
+    Code:
+      stack=1, locals=0, args_size=0
+         0: aconst_null
+         1: putstatic     #5                  // Field CREATOR:Landroid/os/Parcelable$Creator;
+         4: return
+      LineNumberTable:
+        line 213: 0
+}
diff --git a/base/android/jni_generator/testMultipleJNIAdditionalImport.golden b/base/android/jni_generator/testMultipleJNIAdditionalImport.golden
new file mode 100644
index 0000000..b0db9dd
--- /dev/null
+++ b/base/android/jni_generator/testMultipleJNIAdditionalImport.golden
@@ -0,0 +1,88 @@
+// 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/foo/Foo
+
+#ifndef org_chromium_foo_Foo_JNI
+#define org_chromium_foo_Foo_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 kFooClassPath[] = "org/chromium/foo/Foo";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_Foo_clazz = NULL;
+#define Foo_clazz(env) g_Foo_clazz
+
+}  // namespace
+
+static void DoSomething(JNIEnv* env, jclass jcaller,
+    jobject callback1,
+    jobject callback2);
+
+// Step 2: method stubs.
+
+static base::subtle::AtomicWord g_Foo_calledByNative = 0;
+static void Java_Foo_calledByNative(JNIEnv* env, jobject callback1,
+    jobject callback2) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, Foo_clazz(env),
+      Foo_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, Foo_clazz(env),
+      "calledByNative",
+
+"("
+"Lorg/chromium/foo/Bar1$Callback;"
+"Lorg/chromium/foo/Bar2$Callback;"
+")"
+"V",
+      &g_Foo_calledByNative);
+
+     env->CallStaticVoidMethod(Foo_clazz(env),
+          method_id, callback1, callback2);
+  jni_generator::CheckException(env);
+
+}
+
+// Step 3: RegisterNatives.
+
+static const JNINativeMethod kMethodsFoo[] = {
+    { "nativeDoSomething",
+"("
+"Lorg/chromium/foo/Bar1$Callback;"
+"Lorg/chromium/foo/Bar2$Callback;"
+")"
+"V", reinterpret_cast<void*>(DoSomething) },
+};
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+  g_Foo_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetClass(env, kFooClassPath).obj()));
+
+  const int kMethodsFooSize = arraysize(kMethodsFoo);
+
+  if (env->RegisterNatives(Foo_clazz(env),
+                           kMethodsFoo,
+                           kMethodsFooSize) < 0) {
+    jni_generator::HandleRegistrationError(
+        env, Foo_clazz(env), __FILE__);
+    return false;
+  }
+
+  return true;
+}
+
+#endif  // org_chromium_foo_Foo_JNI
diff --git a/base/android/jni_generator/testNativeExportsOption.golden b/base/android/jni_generator/testNativeExportsOption.golden
new file mode 100644
index 0000000..395fc39
--- /dev/null
+++ b/base/android/jni_generator/testNativeExportsOption.golden
@@ -0,0 +1,219 @@
+// 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")))
+jint
+    Java_org_chromium_example_jni_1generator_SampleForTests_00024MyInnerClass_nativeInit(JNIEnv*
+    env, jobject jcaller) {
+  return Init(env, jcaller);
+}
+
+static jint Init(JNIEnv* env, jobject jcaller);
+
+__attribute__((visibility("default")))
+jint
+    Java_org_chromium_example_jni_1generator_SampleForTests_00024MyOtherInnerClass_nativeInit(JNIEnv*
+    env, jobject jcaller) {
+  return Init(env, 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 bool RegisterNativesImpl(JNIEnv* env, jclass clazz) {
+
+  base::subtle::Release_Store(&g_SampleForTests_clazz,
+      static_cast<base::subtle::AtomicWord>(env->NewWeakGlobalRef(clazz));
+
+  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/base/android/jni_generator/testNativeExportsOptionalOption.golden b/base/android/jni_generator/testNativeExportsOptionalOption.golden
new file mode 100644
index 0000000..f47cb98
--- /dev/null
+++ b/base/android/jni_generator/testNativeExportsOptionalOption.golden
@@ -0,0 +1,288 @@
+// 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")))
+jint
+    Java_org_chromium_example_jni_1generator_SampleForTests_00024MyInnerClass_nativeInit(JNIEnv*
+    env, jobject jcaller) {
+  return Init(env, jcaller);
+}
+
+static jint Init(JNIEnv* env, jobject jcaller);
+
+__attribute__((visibility("default")))
+jint
+    Java_org_chromium_example_jni_1generator_SampleForTests_00024MyOtherInnerClass_nativeInit(JNIEnv*
+    env, jobject jcaller) {
+  return Init(env, 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/base/android/jni_generator/testNatives.golden b/base/android/jni_generator/testNatives.golden
new file mode 100644
index 0000000..e5a4fab
--- /dev/null
+++ b/base/android/jni_generator/testNatives.golden
@@ -0,0 +1,218 @@
+// 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/TestJni
+
+#ifndef org_chromium_TestJni_JNI
+#define org_chromium_TestJni_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 kTestJniClassPath[] = "org/chromium/TestJni";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_TestJni_clazz = NULL;
+#define TestJni_clazz(env) g_TestJni_clazz
+
+}  // namespace
+
+static jint Init(JNIEnv* env, jobject jcaller);
+
+static jstring GetDomainAndRegistry(JNIEnv* env, jclass jcaller,
+    jstring url);
+
+static void CreateHistoricalTabFromState(JNIEnv* env, jclass jcaller,
+    jbyteArray state,
+    jint tab_index);
+
+static jbyteArray GetStateAsByteArray(JNIEnv* env, jobject jcaller,
+    jobject view);
+
+static jobjectArray GetAutofillProfileGUIDs(JNIEnv* env, jclass jcaller);
+
+static void SetRecognitionResults(JNIEnv* env, jobject jcaller,
+    jint sessionId,
+    jobjectArray results);
+
+static jint FindAll(JNIEnv* env, jobject jcaller,
+    jstring find);
+
+static jobject GetInnerClass(JNIEnv* env, jclass jcaller);
+
+// Step 2: method stubs.
+static void Destroy(JNIEnv* env, jobject jcaller,
+    jint nativeChromeBrowserProvider) {
+  ChromeBrowserProvider* native =
+      reinterpret_cast<ChromeBrowserProvider*>(nativeChromeBrowserProvider);
+  CHECK_NATIVE_PTR(env, jcaller, native, "Destroy");
+  return native->Destroy(env, jcaller);
+}
+
+static jlong AddBookmark(JNIEnv* env, jobject jcaller,
+    jint nativeChromeBrowserProvider,
+    jstring url,
+    jstring title,
+    jboolean isFolder,
+    jlong parentId) {
+  ChromeBrowserProvider* native =
+      reinterpret_cast<ChromeBrowserProvider*>(nativeChromeBrowserProvider);
+  CHECK_NATIVE_PTR(env, jcaller, native, "AddBookmark", 0);
+  return native->AddBookmark(env, jcaller, url, title, isFolder, parentId);
+}
+
+static jlong AddBookmarkFromAPI(JNIEnv* env, jobject jcaller,
+    jint nativeChromeBrowserProvider,
+    jstring url,
+    jobject created,
+    jobject isBookmark,
+    jobject date,
+    jbyteArray favicon,
+    jstring title,
+    jobject visits) {
+  ChromeBrowserProvider* native =
+      reinterpret_cast<ChromeBrowserProvider*>(nativeChromeBrowserProvider);
+  CHECK_NATIVE_PTR(env, jcaller, native, "AddBookmarkFromAPI", 0);
+  return native->AddBookmarkFromAPI(env, jcaller, url, created, isBookmark,
+      date, favicon, title, visits);
+}
+
+static jobject QueryBitmap(JNIEnv* env, jobject jcaller,
+    jint nativeChromeBrowserProvider,
+    jobjectArray projection,
+    jstring selection,
+    jobjectArray selectionArgs,
+    jstring sortOrder) {
+  ChromeBrowserProvider* native =
+      reinterpret_cast<ChromeBrowserProvider*>(nativeChromeBrowserProvider);
+  CHECK_NATIVE_PTR(env, jcaller, native, "QueryBitmap", NULL);
+  return native->QueryBitmap(env, jcaller, projection, selection, selectionArgs,
+      sortOrder).Release();
+}
+
+static void GotOrientation(JNIEnv* env, jobject jcaller,
+    jint nativeDataFetcherImplAndroid,
+    jdouble alpha,
+    jdouble beta,
+    jdouble gamma) {
+  DataFetcherImplAndroid* native =
+      reinterpret_cast<DataFetcherImplAndroid*>(nativeDataFetcherImplAndroid);
+  CHECK_NATIVE_PTR(env, jcaller, native, "GotOrientation");
+  return native->GotOrientation(env, jcaller, alpha, beta, gamma);
+}
+
+// Step 3: RegisterNatives.
+
+static const JNINativeMethod kMethodsTestJni[] = {
+    { "nativeInit",
+"("
+")"
+"I", reinterpret_cast<void*>(Init) },
+    { "nativeDestroy",
+"("
+"I"
+")"
+"V", reinterpret_cast<void*>(Destroy) },
+    { "nativeAddBookmark",
+"("
+"I"
+"Ljava/lang/String;"
+"Ljava/lang/String;"
+"Z"
+"J"
+")"
+"J", reinterpret_cast<void*>(AddBookmark) },
+    { "nativeGetDomainAndRegistry",
+"("
+"Ljava/lang/String;"
+")"
+"Ljava/lang/String;", reinterpret_cast<void*>(GetDomainAndRegistry) },
+    { "nativeCreateHistoricalTabFromState",
+"("
+"[B"
+"I"
+")"
+"V", reinterpret_cast<void*>(CreateHistoricalTabFromState) },
+    { "nativeGetStateAsByteArray",
+"("
+"Landroid/view/View;"
+")"
+"[B", reinterpret_cast<void*>(GetStateAsByteArray) },
+    { "nativeGetAutofillProfileGUIDs",
+"("
+")"
+"[Ljava/lang/String;", reinterpret_cast<void*>(GetAutofillProfileGUIDs) },
+    { "nativeSetRecognitionResults",
+"("
+"I"
+"[Ljava/lang/String;"
+")"
+"V", reinterpret_cast<void*>(SetRecognitionResults) },
+    { "nativeAddBookmarkFromAPI",
+"("
+"I"
+"Ljava/lang/String;"
+"Ljava/lang/Long;"
+"Ljava/lang/Boolean;"
+"Ljava/lang/Long;"
+"[B"
+"Ljava/lang/String;"
+"Ljava/lang/Integer;"
+")"
+"J", reinterpret_cast<void*>(AddBookmarkFromAPI) },
+    { "nativeFindAll",
+"("
+"Ljava/lang/String;"
+")"
+"I", reinterpret_cast<void*>(FindAll) },
+    { "nativeGetInnerClass",
+"("
+")"
+"Lorg/chromium/example/jni_generator/SampleForTests$OnFrameAvailableListener;",
+    reinterpret_cast<void*>(GetInnerClass) },
+    { "nativeQueryBitmap",
+"("
+"I"
+"[Ljava/lang/String;"
+"Ljava/lang/String;"
+"[Ljava/lang/String;"
+"Ljava/lang/String;"
+")"
+"Landroid/graphics/Bitmap;", reinterpret_cast<void*>(QueryBitmap) },
+    { "nativeGotOrientation",
+"("
+"I"
+"D"
+"D"
+"D"
+")"
+"V", reinterpret_cast<void*>(GotOrientation) },
+};
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+  g_TestJni_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetClass(env, kTestJniClassPath).obj()));
+
+  const int kMethodsTestJniSize = arraysize(kMethodsTestJni);
+
+  if (env->RegisterNatives(TestJni_clazz(env),
+                           kMethodsTestJni,
+                           kMethodsTestJniSize) < 0) {
+    jni_generator::HandleRegistrationError(
+        env, TestJni_clazz(env), __FILE__);
+    return false;
+  }
+
+  return true;
+}
+
+#endif  // org_chromium_TestJni_JNI
diff --git a/base/android/jni_generator/testNativesLong.golden b/base/android/jni_generator/testNativesLong.golden
new file mode 100644
index 0000000..5fa901c
--- /dev/null
+++ b/base/android/jni_generator/testNativesLong.golden
@@ -0,0 +1,65 @@
+// 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/TestJni
+
+#ifndef org_chromium_TestJni_JNI
+#define org_chromium_TestJni_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 kTestJniClassPath[] = "org/chromium/TestJni";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_TestJni_clazz = NULL;
+#define TestJni_clazz(env) g_TestJni_clazz
+
+}  // namespace
+
+// Step 2: method stubs.
+static void Destroy(JNIEnv* env, jobject jcaller,
+    jlong nativeChromeBrowserProvider) {
+  ChromeBrowserProvider* native =
+      reinterpret_cast<ChromeBrowserProvider*>(nativeChromeBrowserProvider);
+  CHECK_NATIVE_PTR(env, jcaller, native, "Destroy");
+  return native->Destroy(env, jcaller);
+}
+
+// Step 3: RegisterNatives.
+
+static const JNINativeMethod kMethodsTestJni[] = {
+    { "nativeDestroy",
+"("
+"J"
+")"
+"V", reinterpret_cast<void*>(Destroy) },
+};
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+  g_TestJni_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetClass(env, kTestJniClassPath).obj()));
+
+  const int kMethodsTestJniSize = arraysize(kMethodsTestJni);
+
+  if (env->RegisterNatives(TestJni_clazz(env),
+                           kMethodsTestJni,
+                           kMethodsTestJniSize) < 0) {
+    jni_generator::HandleRegistrationError(
+        env, TestJni_clazz(env), __FILE__);
+    return false;
+  }
+
+  return true;
+}
+
+#endif  // org_chromium_TestJni_JNI
diff --git a/base/android/jni_generator/testPureNativeMethodsOption.golden b/base/android/jni_generator/testPureNativeMethodsOption.golden
new file mode 100644
index 0000000..ad63cca
--- /dev/null
+++ b/base/android/jni_generator/testPureNativeMethodsOption.golden
@@ -0,0 +1,66 @@
+// 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/Test
+
+#ifndef org_chromium_example_jni_generator_Test_JNI
+#define org_chromium_example_jni_generator_Test_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 kTestClassPath[] = "org/chromium/example/jni_generator/Test";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_Test_clazz = NULL;
+#define Test_clazz(env) g_Test_clazz
+
+}  // namespace
+
+// Step 2: method stubs.
+static jlong Method(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(arg1);
+}
+
+// Step 3: RegisterNatives.
+
+static const JNINativeMethod kMethodsTest[] = {
+    { "nativeMethod",
+"("
+"J"
+"I"
+")"
+"J", reinterpret_cast<void*>(Method) },
+};
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+  g_Test_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetClass(env, kTestClassPath).obj()));
+
+  const int kMethodsTestSize = arraysize(kMethodsTest);
+
+  if (env->RegisterNatives(Test_clazz(env),
+                           kMethodsTest,
+                           kMethodsTestSize) < 0) {
+    jni_generator::HandleRegistrationError(
+        env, Test_clazz(env), __FILE__);
+    return false;
+  }
+
+  return true;
+}
+
+#endif  // org_chromium_example_jni_generator_Test_JNI
diff --git a/base/android/jni_generator/testSingleJNIAdditionalImport.golden b/base/android/jni_generator/testSingleJNIAdditionalImport.golden
new file mode 100644
index 0000000..1cf6554
--- /dev/null
+++ b/base/android/jni_generator/testSingleJNIAdditionalImport.golden
@@ -0,0 +1,84 @@
+// 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/foo/Foo
+
+#ifndef org_chromium_foo_Foo_JNI
+#define org_chromium_foo_Foo_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 kFooClassPath[] = "org/chromium/foo/Foo";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_Foo_clazz = NULL;
+#define Foo_clazz(env) g_Foo_clazz
+
+}  // namespace
+
+static void DoSomething(JNIEnv* env, jclass jcaller,
+    jobject callback);
+
+// Step 2: method stubs.
+
+static base::subtle::AtomicWord g_Foo_calledByNative = 0;
+static void Java_Foo_calledByNative(JNIEnv* env, jobject callback) {
+  /* Must call RegisterNativesImpl()  */
+  CHECK_CLAZZ(env, Foo_clazz(env),
+      Foo_clazz(env));
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_STATIC>(
+      env, Foo_clazz(env),
+      "calledByNative",
+
+"("
+"Lorg/chromium/foo/Bar$Callback;"
+")"
+"V",
+      &g_Foo_calledByNative);
+
+     env->CallStaticVoidMethod(Foo_clazz(env),
+          method_id, callback);
+  jni_generator::CheckException(env);
+
+}
+
+// Step 3: RegisterNatives.
+
+static const JNINativeMethod kMethodsFoo[] = {
+    { "nativeDoSomething",
+"("
+"Lorg/chromium/foo/Bar$Callback;"
+")"
+"V", reinterpret_cast<void*>(DoSomething) },
+};
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+  g_Foo_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetClass(env, kFooClassPath).obj()));
+
+  const int kMethodsFooSize = arraysize(kMethodsFoo);
+
+  if (env->RegisterNatives(Foo_clazz(env),
+                           kMethodsFoo,
+                           kMethodsFooSize) < 0) {
+    jni_generator::HandleRegistrationError(
+        env, Foo_clazz(env), __FILE__);
+    return false;
+  }
+
+  return true;
+}
+
+#endif  // org_chromium_foo_Foo_JNI
diff --git a/base/android/jni_int_wrapper.h b/base/android/jni_int_wrapper.h
new file mode 100644
index 0000000..fa0f3d5
--- /dev/null
+++ b/base/android/jni_int_wrapper.h
@@ -0,0 +1,56 @@
+// 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.
+
+#ifndef BASE_ANDROID_JNI_INT_WRAPPER_H_
+#define BASE_ANDROID_JNI_INT_WRAPPER_H_
+
+// Wrapper used to receive int when calling Java from native.
+// The wrapper disallows automatic conversion of long to int.
+// This is to avoid a common anti-pattern where a Java int is used
+// to receive a native pointer. Please use a Java long to receive
+// native pointers, so that the code works on both 32-bit and 64-bit
+// platforms. Note the wrapper allows other lossy conversions into
+// jint that could be consider anti-patterns, such as from size_t.
+
+// Checking is only done in debugging builds.
+
+#ifdef NDEBUG
+
+typedef jint JniIntWrapper;
+
+// This inline is sufficiently trivial that it does not change the
+// final code generated by g++.
+inline jint as_jint(JniIntWrapper wrapper) {
+  return wrapper;
+}
+
+#else
+
+class JniIntWrapper {
+ public:
+  JniIntWrapper() : i_(0) {}
+  JniIntWrapper(int i) : i_(i) {}
+  JniIntWrapper(const JniIntWrapper& ji) : i_(ji.i_) {}
+  template <class T> JniIntWrapper(const T& t) : i_(t) {}
+  jint as_jint() const { return i_; }
+ private:
+  // If you get an "is private" error at the line below it is because you used
+  // an implicit conversion to convert a long to an int when calling Java.
+  // We disallow this, as a common anti-pattern allows converting a native
+  // pointer (intptr_t) to a Java int. Please use a Java long to represent
+  // a native pointer. If you want a lossy conversion, please use an
+  // explicit conversion in your C++ code. Note an error is only seen when
+  // compiling on a 64-bit platform, as intptr_t is indistinguishable from
+  // int on 32-bit platforms.
+  JniIntWrapper(long);
+  jint i_;
+};
+
+inline jint as_jint(const JniIntWrapper& wrapper) {
+  return wrapper.as_jint();
+}
+
+#endif  // NDEBUG
+
+#endif  // BASE_ANDROID_JNI_INT_WRAPPER_H_
diff --git a/base/android/jni_registrar.cc b/base/android/jni_registrar.cc
new file mode 100644
index 0000000..8e13e60
--- /dev/null
+++ b/base/android/jni_registrar.cc
@@ -0,0 +1,30 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/jni_registrar.h"
+
+#include "base/logging.h"
+#include "base/android/jni_android.h"
+#include "base/trace_event/trace_event.h"
+
+namespace base {
+namespace android {
+
+bool RegisterNativeMethods(JNIEnv* env,
+                           const RegistrationMethod* method,
+                           size_t count) {
+  TRACE_EVENT0("startup", "base_android::RegisterNativeMethods")
+  const RegistrationMethod* end = method + count;
+  while (method != end) {
+    if (!method->func(env)) {
+      DLOG(ERROR) << method->name << " failed registration!";
+      return false;
+    }
+    method++;
+  }
+  return true;
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/jni_registrar.h b/base/android/jni_registrar.h
new file mode 100644
index 0000000..849d07f
--- /dev/null
+++ b/base/android/jni_registrar.h
@@ -0,0 +1,27 @@
+// Copyright (c) 2012 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_REGISTRAR_H_
+#define BASE_ANDROID_JNI_REGISTRAR_H_
+
+#include <jni.h>
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace android {
+
+struct RegistrationMethod;
+
+// Registers the JNI bindings for the specified |method| definition containing
+// |count| elements.  Returns whether the registration of the given methods
+// succeeded.
+BASE_EXPORT bool RegisterNativeMethods(JNIEnv* env,
+                                       const RegistrationMethod* method,
+                                       size_t count);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_JNI_REGISTRAR_H_
diff --git a/base/android/jni_string.cc b/base/android/jni_string.cc
new file mode 100644
index 0000000..57c2805
--- /dev/null
+++ b/base/android/jni_string.cc
@@ -0,0 +1,99 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/jni_string.h"
+
+#include "base/android/jni_android.h"
+#include "base/logging.h"
+#include "base/strings/utf_string_conversions.h"
+
+namespace {
+
+// Internal version that does not use a scoped local pointer.
+jstring ConvertUTF16ToJavaStringImpl(JNIEnv* env,
+                                     const base::StringPiece16& str) {
+  jstring result = env->NewString(str.data(), str.length());
+  base::android::CheckException(env);
+  return result;
+}
+
+}  // namespace
+
+namespace base {
+namespace android {
+
+void ConvertJavaStringToUTF8(JNIEnv* env, jstring str, std::string* result) {
+  if (!str) {
+    LOG(WARNING) << "ConvertJavaStringToUTF8 called with null string.";
+    result->clear();
+    return;
+  }
+  // JNI's GetStringUTFChars() returns strings in Java "modified" UTF8, so
+  // instead get the String in UTF16 and convert using chromium's conversion
+  // function that yields plain (non Java-modified) UTF8.
+  const jchar* chars = env->GetStringChars(str, NULL);
+  DCHECK(chars);
+  UTF16ToUTF8(chars, env->GetStringLength(str), result);
+  env->ReleaseStringChars(str, chars);
+  CheckException(env);
+}
+
+std::string ConvertJavaStringToUTF8(JNIEnv* env, jstring str) {
+  std::string result;
+  ConvertJavaStringToUTF8(env, str, &result);
+  return result;
+}
+
+std::string ConvertJavaStringToUTF8(const JavaRef<jstring>& str) {
+  return ConvertJavaStringToUTF8(AttachCurrentThread(), str.obj());
+}
+
+ScopedJavaLocalRef<jstring> ConvertUTF8ToJavaString(
+    JNIEnv* env,
+    const base::StringPiece& str) {
+  // JNI's NewStringUTF expects "modified" UTF8 so instead create the string
+  // via our own UTF16 conversion utility.
+  // Further, Dalvik requires the string passed into NewStringUTF() to come from
+  // a trusted source. We can't guarantee that all UTF8 will be sanitized before
+  // it gets here, so constructing via UTF16 side-steps this issue.
+  // (Dalvik stores strings internally as UTF16 anyway, so there shouldn't be
+  // a significant performance hit by doing it this way).
+  return ScopedJavaLocalRef<jstring>(env, ConvertUTF16ToJavaStringImpl(
+      env, UTF8ToUTF16(str)));
+}
+
+void ConvertJavaStringToUTF16(JNIEnv* env, jstring str, string16* result) {
+  if (!str) {
+    LOG(WARNING) << "ConvertJavaStringToUTF16 called with null string.";
+    result->clear();
+    return;
+  }
+  const jchar* chars = env->GetStringChars(str, NULL);
+  DCHECK(chars);
+  // GetStringChars isn't required to NULL-terminate the strings
+  // it returns, so the length must be explicitly checked.
+  result->assign(chars, env->GetStringLength(str));
+  env->ReleaseStringChars(str, chars);
+  CheckException(env);
+}
+
+string16 ConvertJavaStringToUTF16(JNIEnv* env, jstring str) {
+  string16 result;
+  ConvertJavaStringToUTF16(env, str, &result);
+  return result;
+}
+
+string16 ConvertJavaStringToUTF16(const JavaRef<jstring>& str) {
+  return ConvertJavaStringToUTF16(AttachCurrentThread(), str.obj());
+}
+
+ScopedJavaLocalRef<jstring> ConvertUTF16ToJavaString(
+    JNIEnv* env,
+    const base::StringPiece16& str) {
+  return ScopedJavaLocalRef<jstring>(env,
+                                     ConvertUTF16ToJavaStringImpl(env, str));
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/jni_string.h b/base/android/jni_string.h
new file mode 100644
index 0000000..89af5b0
--- /dev/null
+++ b/base/android/jni_string.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2012 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_STRING_H_
+#define BASE_ANDROID_JNI_STRING_H_
+
+#include <jni.h>
+#include <string>
+
+#include "base/android/scoped_java_ref.h"
+#include "base/base_export.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+namespace android {
+
+// Convert a Java string to UTF8. Returns a std string.
+BASE_EXPORT void ConvertJavaStringToUTF8(JNIEnv* env,
+                                         jstring str,
+                                         std::string* result);
+BASE_EXPORT std::string ConvertJavaStringToUTF8(JNIEnv* env, jstring str);
+BASE_EXPORT std::string ConvertJavaStringToUTF8(const JavaRef<jstring>& str);
+
+// Convert a std string to Java string.
+BASE_EXPORT ScopedJavaLocalRef<jstring> ConvertUTF8ToJavaString(
+    JNIEnv* env,
+    const base::StringPiece& str);
+
+// Convert a Java string to UTF16. Returns a string16.
+BASE_EXPORT void ConvertJavaStringToUTF16(JNIEnv* env,
+                                          jstring str,
+                                          string16* result);
+BASE_EXPORT string16 ConvertJavaStringToUTF16(JNIEnv* env, jstring str);
+BASE_EXPORT string16 ConvertJavaStringToUTF16(const JavaRef<jstring>& str);
+
+// Convert a string16 to a Java string.
+BASE_EXPORT ScopedJavaLocalRef<jstring> ConvertUTF16ToJavaString(
+    JNIEnv* env,
+    const base::StringPiece16& str);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_JNI_STRING_H_
diff --git a/base/android/jni_string_unittest.cc b/base/android/jni_string_unittest.cc
new file mode 100644
index 0000000..abd0683
--- /dev/null
+++ b/base/android/jni_string_unittest.cc
@@ -0,0 +1,32 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/jni_string.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace android {
+
+TEST(JniString, BasicConversionsUTF8) {
+  const std::string kSimpleString = "SimpleTest8";
+  JNIEnv* env = AttachCurrentThread();
+  std::string result =
+      ConvertJavaStringToUTF8(ConvertUTF8ToJavaString(env, kSimpleString));
+  EXPECT_EQ(kSimpleString, result);
+}
+
+TEST(JniString, BasicConversionsUTF16) {
+  const string16 kSimpleString = UTF8ToUTF16("SimpleTest16");
+  JNIEnv* env = AttachCurrentThread();
+  string16 result =
+      ConvertJavaStringToUTF16(ConvertUTF16ToJavaString(env, kSimpleString));
+  EXPECT_EQ(kSimpleString, result);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/jni_utils.cc b/base/android/jni_utils.cc
new file mode 100644
index 0000000..b4d682b
--- /dev/null
+++ b/base/android/jni_utils.cc
@@ -0,0 +1,25 @@
+// 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.
+
+#include "base/android/jni_utils.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+
+#include "jni/JNIUtils_jni.h"
+
+namespace base {
+namespace android {
+
+ScopedJavaLocalRef<jobject> GetClassLoader(JNIEnv* env) {
+  return Java_JNIUtils_getClassLoader(env);
+}
+
+bool RegisterJNIUtils(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace android
+}  // namespace base
+
diff --git a/base/android/jni_utils.h b/base/android/jni_utils.h
new file mode 100644
index 0000000..b793aed
--- /dev/null
+++ b/base/android/jni_utils.h
@@ -0,0 +1,27 @@
+// 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.
+
+#ifndef BASE_ANDROID_JNI_UTILS_H_
+#define BASE_ANDROID_JNI_UTILS_H_
+
+#include <jni.h>
+
+#include "base/android/scoped_java_ref.h"
+
+namespace base {
+
+namespace android {
+
+// Gets a ClassLoader instance capable of loading Chromium java classes.
+// This should be called either from JNI_OnLoad or from within a method called
+// via JNI from Java.
+BASE_EXPORT ScopedJavaLocalRef<jobject> GetClassLoader(JNIEnv* env);
+
+bool RegisterJNIUtils(JNIEnv* env);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_JNI_UTILS_H_
+
diff --git a/base/android/jni_weak_ref.cc b/base/android/jni_weak_ref.cc
new file mode 100644
index 0000000..35a76da
--- /dev/null
+++ b/base/android/jni_weak_ref.cc
@@ -0,0 +1,67 @@
+// 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.
+
+#include "base/android/jni_weak_ref.h"
+
+#include "base/android/jni_android.h"
+#include "base/logging.h"
+
+using base::android::AttachCurrentThread;
+
+JavaObjectWeakGlobalRef::JavaObjectWeakGlobalRef()
+  : obj_(NULL) {
+}
+
+JavaObjectWeakGlobalRef::JavaObjectWeakGlobalRef(
+    const JavaObjectWeakGlobalRef& orig)
+    : obj_(NULL) {
+  Assign(orig);
+}
+
+JavaObjectWeakGlobalRef::JavaObjectWeakGlobalRef(JNIEnv* env, jobject obj)
+    : obj_(env->NewWeakGlobalRef(obj)) {
+  DCHECK(obj_);
+}
+
+JavaObjectWeakGlobalRef::~JavaObjectWeakGlobalRef() {
+  reset();
+}
+
+void JavaObjectWeakGlobalRef::operator=(const JavaObjectWeakGlobalRef& rhs) {
+  Assign(rhs);
+}
+
+void JavaObjectWeakGlobalRef::reset() {
+  if (obj_) {
+    AttachCurrentThread()->DeleteWeakGlobalRef(obj_);
+    obj_ = NULL;
+  }
+}
+
+base::android::ScopedJavaLocalRef<jobject>
+    JavaObjectWeakGlobalRef::get(JNIEnv* env) const {
+  return GetRealObject(env, obj_);
+}
+
+base::android::ScopedJavaLocalRef<jobject> GetRealObject(
+    JNIEnv* env, jweak obj) {
+  jobject real = NULL;
+  if (obj) {
+    real = env->NewLocalRef(obj);
+    if (!real)
+      DLOG(ERROR) << "The real object has been deleted!";
+  }
+  return base::android::ScopedJavaLocalRef<jobject>(env, real);
+}
+
+void JavaObjectWeakGlobalRef::Assign(const JavaObjectWeakGlobalRef& other) {
+  if (&other == this)
+    return;
+
+  JNIEnv* env = AttachCurrentThread();
+  if (obj_)
+    env->DeleteWeakGlobalRef(obj_);
+
+  obj_ = other.obj_ ? env->NewWeakGlobalRef(other.obj_) : NULL;
+}
diff --git a/base/android/jni_weak_ref.h b/base/android/jni_weak_ref.h
new file mode 100644
index 0000000..c851046
--- /dev/null
+++ b/base/android/jni_weak_ref.h
@@ -0,0 +1,43 @@
+// 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.
+
+#ifndef BASE_ANDROID_JNI_WEAK_REF_H_
+#define BASE_ANDROID_JNI_WEAK_REF_H_
+
+#include <jni.h>
+
+#include "base/android/scoped_java_ref.h"
+#include "base/base_export.h"
+
+// Manages WeakGlobalRef lifecycle.
+// This class is not thread-safe w.r.t. get() and reset(). Multiple threads may
+// safely use get() concurrently, but if the user calls reset() (or of course,
+// calls the destructor) they'll need to provide their own synchronization.
+class BASE_EXPORT JavaObjectWeakGlobalRef {
+ public:
+  JavaObjectWeakGlobalRef();
+  JavaObjectWeakGlobalRef(const JavaObjectWeakGlobalRef& orig);
+  JavaObjectWeakGlobalRef(JNIEnv* env, jobject obj);
+  virtual ~JavaObjectWeakGlobalRef();
+
+  void operator=(const JavaObjectWeakGlobalRef& rhs);
+
+  base::android::ScopedJavaLocalRef<jobject> get(JNIEnv* env) const;
+
+  bool is_empty() const { return obj_ == NULL; }
+
+  void reset();
+
+ private:
+  void Assign(const JavaObjectWeakGlobalRef& rhs);
+
+  jweak obj_;
+};
+
+// Get the real object stored in the weak reference returned as a
+// ScopedJavaLocalRef.
+BASE_EXPORT base::android::ScopedJavaLocalRef<jobject> GetRealObject(
+    JNIEnv* env, jweak obj);
+
+#endif  // BASE_ANDROID_JNI_WEAK_REF_H_
diff --git a/base/android/junit/src/org/chromium/base/BaseChromiumApplicationTest.java b/base/android/junit/src/org/chromium/base/BaseChromiumApplicationTest.java
new file mode 100644
index 0000000..d3441f7
--- /dev/null
+++ b/base/android/junit/src/org/chromium/base/BaseChromiumApplicationTest.java
@@ -0,0 +1,94 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import android.app.Activity;
+import android.view.KeyEvent;
+
+import junit.framework.Assert;
+
+import org.chromium.base.BaseChromiumApplication.WindowFocusChangedListener;
+import org.chromium.testing.local.LocalRobolectricTestRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.annotation.Config;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.shadows.ShadowActivity;
+import org.robolectric.util.ActivityController;
+
+/** Unit tests for {@link BaseChromiumApplication}. */
+@RunWith(LocalRobolectricTestRunner.class)
+@Config(manifest = Config.NONE, application = BaseChromiumApplication.class,
+        shadows = {BaseChromiumApplicationTest.TrackingShadowActivity.class})
+public class BaseChromiumApplicationTest {
+
+    @Implements(Activity.class)
+    public static class TrackingShadowActivity extends ShadowActivity {
+        private int mWindowFocusCalls;
+        private int mDispatchKeyEventCalls;
+        private boolean mReturnValueForKeyDispatch;
+
+        @Implementation
+        public void onWindowFocusChanged(@SuppressWarnings("unused") boolean hasFocus) {
+            mWindowFocusCalls++;
+        }
+
+        @Implementation
+        public boolean dispatchKeyEvent(@SuppressWarnings("unused") KeyEvent event) {
+            mDispatchKeyEventCalls++;
+            return mReturnValueForKeyDispatch;
+        }
+    }
+
+    @Test
+    public void testWindowsFocusChanged() throws Exception {
+        BaseChromiumApplication app = (BaseChromiumApplication) Robolectric.application;
+
+        WindowFocusChangedListener mock = mock(WindowFocusChangedListener.class);
+        app.registerWindowFocusChangedListener(mock);
+
+        ActivityController<Activity> controller =
+                Robolectric.buildActivity(Activity.class).create().start().visible();
+        TrackingShadowActivity shadow =
+                (TrackingShadowActivity) Robolectric.shadowOf(controller.get());
+
+        controller.get().getWindow().getCallback().onWindowFocusChanged(true);
+        // Assert that listeners were notified.
+        verify(mock).onWindowFocusChanged(controller.get(), true);
+        // Also ensure that the original activity is forwarded the notification.
+        Assert.assertEquals(1, shadow.mWindowFocusCalls);
+    }
+
+    @Test
+    public void testDispatchKeyEvent() throws Exception {
+        ActivityController<Activity> controller =
+                Robolectric.buildActivity(Activity.class).create().start().visible();
+        TrackingShadowActivity shadow =
+                (TrackingShadowActivity) Robolectric.shadowOf(controller.get());
+
+        final KeyEvent menuKey = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU);
+
+        // Ensure that key events are forwarded.
+        Assert.assertFalse(controller.get().getWindow().getCallback().dispatchKeyEvent(menuKey));
+        // This gets called twice - once to see if the activity is swallowing it, and again to
+        // dispatch it.
+        Assert.assertEquals(2, shadow.mDispatchKeyEventCalls);
+
+        // Ensure that our activity can swallow the event.
+        shadow.mReturnValueForKeyDispatch = true;
+        Assert.assertTrue(controller.get().getWindow().getCallback().dispatchKeyEvent(menuKey));
+        Assert.assertEquals(3, shadow.mDispatchKeyEventCalls);
+
+        // A non-enter key only dispatches once.
+        Assert.assertTrue(controller.get().getWindow().getCallback().dispatchKeyEvent(
+                new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_SPACE)));
+        Assert.assertEquals(4, shadow.mDispatchKeyEventCalls);
+    }
+}
diff --git a/base/android/junit/src/org/chromium/base/LogTest.java b/base/android/junit/src/org/chromium/base/LogTest.java
new file mode 100644
index 0000000..ac98001
--- /dev/null
+++ b/base/android/junit/src/org/chromium/base/LogTest.java
@@ -0,0 +1,226 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import org.chromium.testing.local.LocalRobolectricTestRunner;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.annotation.Config;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.shadows.ShadowLog;
+
+import java.util.List;
+
+/** Unit tests for {@link Log}. */
+@RunWith(LocalRobolectricTestRunner.class)
+@Config(manifest = Config.NONE, shadows = {LogTest.PermissiveShadowLog.class})
+public class LogTest {
+    /** Test method for {@link Log#makeTag(String)} */
+    @Test
+    public void testMakeTag() {
+        assertEquals("cr.Foo", Log.makeTag("Foo"));
+        assertEquals("cr", Log.makeTag(null));
+        assertEquals("cr", Log.makeTag(""));
+    }
+
+    /** Test method for {@link Log#makeTag(String)} */
+    @Test(expected = IllegalArgumentException.class)
+    public void testMakeTagFailure() {
+        Log.makeTag("ThisIs21Char.....Long");
+    }
+
+    /** Tests that the computed call origin is the correct one. */
+    @Test
+    public void callOriginTest() {
+        Log.d("Foo", "Bar");
+
+        List<ShadowLog.LogItem> logs = ShadowLog.getLogs();
+        assertEquals("Only one log should be written", 1, logs.size());
+
+        assertTrue("The origin of the log message (" + logs.get(0).msg + ") looks wrong.",
+                logs.get(0).msg.matches("\\[LogTest.java:\\d+\\].*"));
+    }
+
+    /** Tests that exceptions provided to the log functions are properly recognized and printed. */
+    @Test
+    public void exceptionLoggingTest() {
+        Throwable t = new Throwable() {
+            @Override
+            public String toString() {
+                return "MyThrowable";
+            }
+        };
+
+        Throwable t2 = new Throwable() {
+            @Override
+            public String toString() {
+                return "MyOtherThrowable";
+            }
+        };
+
+        List<ShadowLog.LogItem> logs = ShadowLog.getLogs();
+
+        // The throwable gets printed out
+        Log.i("Foo", "Bar", t);
+        assertEquals(t, logs.get(logs.size() - 1).throwable);
+        assertEquals("Bar", logs.get(logs.size() - 1).msg);
+
+        // The throwable can be both added to the message itself and printed out
+        Log.i("Foo", "Bar %s", t);
+        assertEquals(t, logs.get(logs.size() - 1).throwable);
+        assertEquals("Bar MyThrowable", logs.get(logs.size() - 1).msg);
+
+        // Non throwable are properly identified
+        Log.i("Foo", "Bar %s", t, "Baz");
+        assertNull(logs.get(logs.size() - 1).throwable);
+        assertEquals("Bar MyThrowable", logs.get(logs.size() - 1).msg);
+
+        // The last throwable is the one used that is going to be printed out
+        Log.i("Foo", "Bar %s %s", t, t2);
+        assertEquals(t2, logs.get(logs.size() - 1).throwable);
+        assertEquals("Bar MyThrowable MyOtherThrowable", logs.get(logs.size() - 1).msg);
+    }
+
+    public void verboseLoggingTest() {
+        PermissiveShadowLog.setLevel(Log.VERBOSE);
+        List<ShadowLog.LogItem> logs = ShadowLog.getLogs();
+
+        Log.wtf("Foo", "Bar");
+        Log.e("Foo", "Bar");
+        Log.w("Foo", "Bar");
+        Log.i("Foo", "Bar");
+        Log.d("Foo", "Bar");
+        Log.v("Foo", "Bar");
+
+        assertEquals(Log.ASSERT, logs.get(0).type);
+        assertEquals(Log.ERROR, logs.get(1).type);
+        assertEquals(Log.WARN, logs.get(2).type);
+        assertEquals(Log.INFO, logs.get(3).type);
+        assertEquals(Log.DEBUG, logs.get(4).type);
+        assertEquals(Log.VERBOSE, logs.get(5).type);
+        assertEquals(6, logs.size());
+    }
+
+    @Test
+    public void debugLoggingTest() {
+        PermissiveShadowLog.setLevel(Log.DEBUG);
+        List<ShadowLog.LogItem> logs = ShadowLog.getLogs();
+
+        Log.wtf("Foo", "Bar");
+        Log.e("Foo", "Bar");
+        Log.w("Foo", "Bar");
+        Log.i("Foo", "Bar");
+        Log.d("Foo", "Bar");
+        Log.v("Foo", "Bar");
+
+        assertEquals(Log.ASSERT, logs.get(0).type);
+        assertEquals(Log.ERROR, logs.get(1).type);
+        assertEquals(Log.WARN, logs.get(2).type);
+        assertEquals(Log.INFO, logs.get(3).type);
+        assertEquals(Log.DEBUG, logs.get(4).type);
+        assertEquals(5, logs.size());
+    }
+
+    @Test
+    public void infoLoggingTest() {
+        PermissiveShadowLog.setLevel(Log.INFO);
+        List<ShadowLog.LogItem> logs = ShadowLog.getLogs();
+
+        Log.wtf("Foo", "Bar");
+        Log.e("Foo", "Bar");
+        Log.w("Foo", "Bar");
+        Log.i("Foo", "Bar");
+        Log.d("Foo", "Bar");
+        Log.v("Foo", "Bar");
+
+        assertEquals(Log.ASSERT, logs.get(0).type);
+        assertEquals(Log.ERROR, logs.get(1).type);
+        assertEquals(Log.WARN, logs.get(2).type);
+        assertEquals(Log.INFO, logs.get(3).type);
+        assertEquals(4, logs.size());
+    }
+
+    @Test
+    public void warnLoggingTest() {
+        PermissiveShadowLog.setLevel(Log.WARN);
+        List<ShadowLog.LogItem> logs = ShadowLog.getLogs();
+
+        Log.wtf("Foo", "Bar");
+        Log.e("Foo", "Bar");
+        Log.w("Foo", "Bar");
+        Log.i("Foo", "Bar");
+        Log.d("Foo", "Bar");
+        Log.v("Foo", "Bar");
+
+        assertEquals(Log.ASSERT, logs.get(0).type);
+        assertEquals(Log.ERROR, logs.get(1).type);
+        assertEquals(Log.WARN, logs.get(2).type);
+        assertEquals(3, logs.size());
+    }
+
+    @Test
+    public void errorLoggingTest() {
+        PermissiveShadowLog.setLevel(Log.ERROR);
+        List<ShadowLog.LogItem> logs = ShadowLog.getLogs();
+
+        Log.wtf("Foo", "Bar");
+        Log.e("Foo", "Bar");
+        Log.w("Foo", "Bar");
+        Log.i("Foo", "Bar");
+        Log.d("Foo", "Bar");
+        Log.v("Foo", "Bar");
+
+        assertEquals(Log.ASSERT, logs.get(0).type);
+        assertEquals(Log.ERROR, logs.get(1).type);
+        assertEquals(2, logs.size());
+    }
+
+    @Test
+    public void assertLoggingTest() {
+        PermissiveShadowLog.setLevel(Log.ASSERT);
+        List<ShadowLog.LogItem> logs = ShadowLog.getLogs();
+
+        Log.wtf("Foo", "Bar");
+        Log.e("Foo", "Bar");
+        Log.w("Foo", "Bar");
+        Log.i("Foo", "Bar");
+        Log.d("Foo", "Bar");
+        Log.v("Foo", "Bar");
+
+        assertEquals(Log.ASSERT, logs.get(0).type);
+        assertEquals(1, logs.size());
+    }
+
+    @Before
+    public void beforeTest() {
+        PermissiveShadowLog.reset();
+    }
+
+    /** Needed to allow debug/verbose logging that is disabled by default. */
+    @Implements(android.util.Log.class)
+    public static class PermissiveShadowLog extends ShadowLog {
+        private static int sLevel = Log.VERBOSE;
+
+        /** Sets the log level for all tags. */
+        public static void setLevel(int level) {
+            sLevel = level;
+        }
+
+        @Implementation
+        public static boolean isLoggable(String tag, int level) {
+            return level >= sLevel;
+        }
+
+        public static void reset() {
+            sLevel = Log.VERBOSE;
+        }
+    }
+}
diff --git a/base/android/library_loader/library_load_from_apk_status_codes.h b/base/android/library_loader/library_load_from_apk_status_codes.h
new file mode 100644
index 0000000..8910d48
--- /dev/null
+++ b/base/android/library_loader/library_load_from_apk_status_codes.h
@@ -0,0 +1,49 @@
+// 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.
+
+#ifndef BASE_ANDROID_LIBRARY_LOADER_LIBRARY_LOAD_FROM_APK_STATUS_CODES_H_
+#define BASE_ANDROID_LIBRARY_LOADER_LIBRARY_LOAD_FROM_APK_STATUS_CODES_H_
+
+namespace base {
+namespace android {
+
+namespace {
+
+// This enum must be kept in sync with the LibraryLoadFromApkStatus enum in
+// tools/metrics/histograms/histograms.xml.
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.base.library_loader
+enum LibraryLoadFromApkStatusCodes {
+  // The loader was unable to determine whether the functionality is supported.
+  LIBRARY_LOAD_FROM_APK_STATUS_CODES_UNKNOWN = 0,
+
+  // The device does not support loading a library directly from the APK file
+  // (obsolete).
+  LIBRARY_LOAD_FROM_APK_STATUS_CODES_NOT_SUPPORTED_OBSOLETE = 1,
+
+  // The device supports loading a library directly from the APK file.
+  // (obsolete).
+  LIBRARY_LOAD_FROM_APK_STATUS_CODES_SUPPORTED_OBSOLETE = 2,
+
+  // The Chromium library was successfully loaded directly from the APK file.
+  LIBRARY_LOAD_FROM_APK_STATUS_CODES_SUCCESSFUL = 3,
+
+  // The Chromium library was successfully loaded using the unpack library
+  // fallback because it was compressed or not page aligned in the APK file.
+  LIBRARY_LOAD_FROM_APK_STATUS_CODES_USED_UNPACK_LIBRARY_FALLBACK = 4,
+
+  // The Chromium library was successfully loaded using the no map executable
+  // support fallback (obsolete).
+  LIBRARY_LOAD_FROM_APK_STATUS_CODES_USED_NO_MAP_EXEC_SUPPORT_FALLBACK_OBSOLETE
+      = 5,
+
+  // End sentinel.
+  LIBRARY_LOAD_FROM_APK_STATUS_CODES_MAX = 6,
+};
+
+}  // namespace
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_LIBRARY_LOADER_LIBRARY_LOAD_FROM_APK_STATUS_CODES_H_
diff --git a/base/android/library_loader/library_loader_hooks.cc b/base/android/library_loader/library_loader_hooks.cc
new file mode 100644
index 0000000..0b59a30
--- /dev/null
+++ b/base/android/library_loader/library_loader_hooks.cc
@@ -0,0 +1,152 @@
+// 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.
+
+#include "base/android/library_loader/library_loader_hooks.h"
+
+#include "base/android/command_line_android.h"
+#include "base/android/jni_string.h"
+#include "base/android/library_loader/library_load_from_apk_status_codes.h"
+#include "base/android/library_loader/library_prefetcher.h"
+#include "base/at_exit.h"
+#include "base/metrics/histogram.h"
+#include "jni/LibraryLoader_jni.h"
+
+namespace base {
+namespace android {
+
+namespace {
+
+base::AtExitManager* g_at_exit_manager = NULL;
+const char* g_library_version_number = "";
+LibraryLoadedHook* g_registration_callback = NULL;
+
+enum RendererHistogramCode {
+  // Renderer load at fixed address success, fail, or not attempted.
+  // Renderers do not attempt to load at at fixed address if on a
+  // low-memory device on which browser load at fixed address has already
+  // failed.
+  LFA_SUCCESS = 0,
+  LFA_BACKOFF_USED = 1,
+  LFA_NOT_ATTEMPTED = 2,
+
+  // End sentinel, also used as nothing-pending indicator.
+  MAX_RENDERER_HISTOGRAM_CODE = 3,
+  NO_PENDING_HISTOGRAM_CODE = MAX_RENDERER_HISTOGRAM_CODE
+};
+
+enum BrowserHistogramCode {
+  // Non-low-memory random address browser loads.
+  NORMAL_LRA_SUCCESS = 0,
+
+  // Low-memory browser loads at fixed address, success or fail.
+  LOW_MEMORY_LFA_SUCCESS = 1,
+  LOW_MEMORY_LFA_BACKOFF_USED = 2,
+
+  MAX_BROWSER_HISTOGRAM_CODE = 3,
+};
+
+RendererHistogramCode g_renderer_histogram_code = NO_PENDING_HISTOGRAM_CODE;
+
+} // namespace
+
+static void RegisterChromiumAndroidLinkerRendererHistogram(
+    JNIEnv* env,
+    jobject jcaller,
+    jboolean requested_shared_relro,
+    jboolean load_at_fixed_address_failed) {
+  // Note a pending histogram value for later recording.
+  if (requested_shared_relro) {
+    g_renderer_histogram_code = load_at_fixed_address_failed
+                                ? LFA_BACKOFF_USED : LFA_SUCCESS;
+  } else {
+    g_renderer_histogram_code = LFA_NOT_ATTEMPTED;
+  }
+}
+
+void RecordChromiumAndroidLinkerRendererHistogram() {
+  if (g_renderer_histogram_code == NO_PENDING_HISTOGRAM_CODE)
+    return;
+  // Record and release the pending histogram value.
+  UMA_HISTOGRAM_ENUMERATION("ChromiumAndroidLinker.RendererStates",
+                            g_renderer_histogram_code,
+                            MAX_RENDERER_HISTOGRAM_CODE);
+  g_renderer_histogram_code = NO_PENDING_HISTOGRAM_CODE;
+}
+
+static void RecordChromiumAndroidLinkerBrowserHistogram(
+    JNIEnv* env,
+    jobject jcaller,
+    jboolean is_using_browser_shared_relros,
+    jboolean load_at_fixed_address_failed,
+    jint library_load_from_apk_status) {
+  // For low-memory devices, record whether or not we successfully loaded the
+  // browser at a fixed address. Otherwise just record a normal invocation.
+  BrowserHistogramCode histogram_code;
+  if (is_using_browser_shared_relros) {
+    histogram_code = load_at_fixed_address_failed
+                     ? LOW_MEMORY_LFA_BACKOFF_USED : LOW_MEMORY_LFA_SUCCESS;
+  } else {
+    histogram_code = NORMAL_LRA_SUCCESS;
+  }
+  UMA_HISTOGRAM_ENUMERATION("ChromiumAndroidLinker.BrowserStates",
+                            histogram_code,
+                            MAX_BROWSER_HISTOGRAM_CODE);
+
+  // Record the device support for loading a library directly from the APK file.
+  UMA_HISTOGRAM_ENUMERATION("ChromiumAndroidLinker.LibraryLoadFromApkStatus",
+                            library_load_from_apk_status,
+                            LIBRARY_LOAD_FROM_APK_STATUS_CODES_MAX);
+}
+
+void SetLibraryLoadedHook(LibraryLoadedHook* func) {
+  g_registration_callback = func;
+}
+
+static void InitCommandLine(JNIEnv* env,
+                            jobject jcaller,
+                            jobjectArray init_command_line) {
+  InitNativeCommandLineFromJavaArray(env, init_command_line);
+}
+
+static jboolean LibraryLoaded(JNIEnv* env, jobject jcaller) {
+  if (g_registration_callback == NULL) {
+    return true;
+  }
+  return g_registration_callback(env, NULL);
+}
+
+void LibraryLoaderExitHook() {
+  if (g_at_exit_manager) {
+    delete g_at_exit_manager;
+    g_at_exit_manager = NULL;
+  }
+}
+
+static jboolean ForkAndPrefetchNativeLibrary(JNIEnv* env, jclass clazz) {
+  return NativeLibraryPrefetcher::ForkAndPrefetchNativeLibrary();
+}
+
+bool RegisterLibraryLoaderEntryHook(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+void SetVersionNumber(const char* version_number) {
+  g_library_version_number = strdup(version_number);
+}
+
+jstring GetVersionNumber(JNIEnv* env, jobject jcaller) {
+  return ConvertUTF8ToJavaString(env, g_library_version_number).Release();
+}
+
+LibraryProcessType GetLibraryProcessType(JNIEnv* env) {
+  return static_cast<LibraryProcessType>(
+      Java_LibraryLoader_getLibraryProcessType(env));
+}
+
+void InitAtExitManager() {
+  g_at_exit_manager = new base::AtExitManager();
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/library_loader/library_loader_hooks.h b/base/android/library_loader/library_loader_hooks.h
new file mode 100644
index 0000000..ca3c5a2
--- /dev/null
+++ b/base/android/library_loader/library_loader_hooks.h
@@ -0,0 +1,74 @@
+// 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.
+
+#ifndef BASE_ANDROID_LIBRARY_LOADER_LIBRARY_LOADER_HOOKS_H_
+#define BASE_ANDROID_LIBRARY_LOADER_LIBRARY_LOADER_HOOKS_H_
+
+#include <jni.h>
+
+#include "base/base_export.h"
+
+namespace base {
+namespace android {
+
+// The process the shared library is loaded in.
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.base.library_loader
+enum LibraryProcessType {
+  // The LibraryLoad has not been initialized.
+  PROCESS_UNINITIALIZED = 0,
+  // Shared library is running in browser process.
+  PROCESS_BROWSER = 1,
+  // Shared library is running in child process.
+  PROCESS_CHILD = 2,
+  // Shared library is running in webview process.
+  PROCESS_WEBVIEW = 3,
+};
+
+// Record any pending renderer histogram value as a histogram.  Pending values
+// are set by RegisterChromiumAndroidLinkerRendererHistogram.
+BASE_EXPORT void RecordChromiumAndroidLinkerRendererHistogram();
+
+// Registers the callbacks that allows the entry point of the library to be
+// exposed to the calling java code.  This handles only registering the
+// the callbacks needed by the loader. Any application specific JNI bindings
+// should happen once the native library has fully loaded, either in the library
+// loaded hook function or later.
+BASE_EXPORT bool RegisterLibraryLoaderEntryHook(JNIEnv* env);
+
+// Typedef for hook function to be called (indirectly from Java) once the
+// libraries are loaded. The hook function should register the JNI bindings
+// required to start the application. It should return true for success and
+// false for failure.
+// Note: this can't use base::Callback because there is no way of initializing
+// the default callback without using static objects, which we forbid.
+typedef bool LibraryLoadedHook(JNIEnv* env,
+                               jclass clazz);
+
+// Set the hook function to be called (from Java) once the libraries are loaded.
+// SetLibraryLoadedHook may only be called from JNI_OnLoad. The hook function
+// should register the JNI bindings required to start the application.
+
+BASE_EXPORT void SetLibraryLoadedHook(LibraryLoadedHook* func);
+
+// Pass the version name to the loader. This used to check that the library
+// version matches the version expected by Java before completing JNI
+// registration.
+// Note: argument must remain valid at least until library loading is complete.
+BASE_EXPORT void SetVersionNumber(const char* version_number);
+
+// Call on exit to delete the AtExitManager which OnLibraryLoadedOnUIThread
+// created.
+BASE_EXPORT void LibraryLoaderExitHook();
+
+// Return the process type the shared library is loaded in.
+BASE_EXPORT LibraryProcessType GetLibraryProcessType(JNIEnv* env);
+
+// Initialize AtExitManager, this must be done at the begining of loading
+// shared library.
+void InitAtExitManager();
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_LIBRARY_LOADER_LIBRARY_LOADER_HOOKS_H_
diff --git a/base/android/library_loader/library_prefetcher.cc b/base/android/library_loader/library_prefetcher.cc
new file mode 100644
index 0000000..798a283
--- /dev/null
+++ b/base/android/library_loader/library_prefetcher.cc
@@ -0,0 +1,150 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/library_loader/library_prefetcher.h"
+
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <utility>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/strings/string_util.h"
+
+namespace base {
+namespace android {
+
+namespace {
+
+// Android defines the background priority to this value since at least 2009
+// (see Process.java).
+const int kBackgroundPriority = 10;
+// Valid for all the Android architectures.
+const size_t kPageSize = 4096;
+const char* kLibchromeSuffix = "libchrome.so";
+// "base.apk" is a suffix because the library may be loaded directly from the
+// APK.
+const char* kSuffixesToMatch[] = {kLibchromeSuffix, "base.apk"};
+
+bool IsReadableAndPrivate(const base::debug::MappedMemoryRegion& region) {
+  return region.permissions & base::debug::MappedMemoryRegion::READ &&
+         region.permissions & base::debug::MappedMemoryRegion::PRIVATE;
+}
+
+bool PathMatchesSuffix(const std::string& path) {
+  for (size_t i = 0; i < arraysize(kSuffixesToMatch); i++) {
+    if (EndsWith(path, kSuffixesToMatch[i], true)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+// For each range, reads a byte per page to force it into the page cache.
+// Heap allocations, syscalls and library functions are not allowed in this
+// function.
+// Returns true for success.
+bool Prefetch(const std::vector<std::pair<uintptr_t, uintptr_t>>& ranges) {
+  for (const auto& range : ranges) {
+    const uintptr_t page_mask = kPageSize - 1;
+    // If start or end is not page-aligned, parsing went wrong. It is better to
+    // exit with an error.
+    if ((range.first & page_mask) || (range.second & page_mask)) {
+      return false;  // CHECK() is not allowed here.
+    }
+    unsigned char* start_ptr = reinterpret_cast<unsigned char*>(range.first);
+    unsigned char* end_ptr = reinterpret_cast<unsigned char*>(range.second);
+    unsigned char dummy = 0;
+    for (unsigned char* ptr = start_ptr; ptr < end_ptr; ptr += kPageSize) {
+      // Volatile is required to prevent the compiler from eliminating this
+      // loop.
+      dummy ^= *static_cast<volatile unsigned char*>(ptr);
+    }
+  }
+  return true;
+}
+
+}  // namespace
+
+// static
+bool NativeLibraryPrefetcher::IsGoodToPrefetch(
+    const base::debug::MappedMemoryRegion& region) {
+  return PathMatchesSuffix(region.path) &&
+         IsReadableAndPrivate(region);  // .text and .data mappings are private.
+}
+
+// static
+void NativeLibraryPrefetcher::FilterLibchromeRangesOnlyIfPossible(
+    const std::vector<base::debug::MappedMemoryRegion>& regions,
+    std::vector<AddressRange>* ranges) {
+  bool has_libchrome_region = false;
+  for (const base::debug::MappedMemoryRegion& region : regions) {
+    if (EndsWith(region.path, kLibchromeSuffix, true)) {
+      has_libchrome_region = true;
+      break;
+    }
+  }
+  for (const base::debug::MappedMemoryRegion& region : regions) {
+    if (has_libchrome_region &&
+        !EndsWith(region.path, kLibchromeSuffix, true)) {
+      continue;
+    }
+    ranges->push_back(std::make_pair(region.start, region.end));
+  }
+}
+
+// static
+bool NativeLibraryPrefetcher::FindRanges(std::vector<AddressRange>* ranges) {
+  std::string proc_maps;
+  if (!base::debug::ReadProcMaps(&proc_maps))
+    return false;
+  std::vector<base::debug::MappedMemoryRegion> regions;
+  if (!base::debug::ParseProcMaps(proc_maps, &regions))
+    return false;
+
+  std::vector<base::debug::MappedMemoryRegion> regions_to_prefetch;
+  for (const auto& region : regions) {
+    if (IsGoodToPrefetch(region)) {
+      regions_to_prefetch.push_back(region);
+    }
+  }
+
+  FilterLibchromeRangesOnlyIfPossible(regions_to_prefetch, ranges);
+  return true;
+}
+
+// static
+bool NativeLibraryPrefetcher::ForkAndPrefetchNativeLibrary() {
+  // Looking for ranges is done before the fork, to avoid syscalls and/or memory
+  // allocations in the forked process. The child process inherits the lock
+  // state of its parent thread. It cannot rely on being able to acquire any
+  // lock (unless special care is taken in a pre-fork handler), including being
+  // able to call malloc().
+  std::vector<AddressRange> ranges;
+  if (!FindRanges(&ranges))
+    return false;
+  pid_t pid = fork();
+  if (pid == 0) {
+    setpriority(PRIO_PROCESS, 0, kBackgroundPriority);
+    // _exit() doesn't call the atexit() handlers.
+    _exit(Prefetch(ranges) ? 0 : 1);
+  } else {
+    if (pid < 0) {
+      return false;
+    }
+    int status;
+    const pid_t result = HANDLE_EINTR(waitpid(pid, &status, 0));
+    if (result == pid) {
+      if (WIFEXITED(status)) {
+        return WEXITSTATUS(status) == 0;
+      }
+    }
+    return false;
+  }
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/library_loader/library_prefetcher.h b/base/android/library_loader/library_prefetcher.h
new file mode 100644
index 0000000..64e5e1e
--- /dev/null
+++ b/base/android/library_loader/library_prefetcher.h
@@ -0,0 +1,67 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_LIBRARY_LOADER_LIBRARY_PREFETCHER_H_
+#define BASE_ANDROID_LIBRARY_LOADER_LIBRARY_PREFETCHER_H_
+
+#include <jni.h>
+
+#include <stdint.h>
+#include <string>
+
+#include "base/debug/proc_maps_linux.h"
+#include "base/gtest_prod_util.h"
+
+namespace base {
+namespace android {
+
+// Forks and waits for a process prefetching the native library. This is done in
+// a forked process for the following reasons:
+// - Isolating the main process from mistakes in the parsing. If the parsing
+//   returns an incorrect address, only the forked process will crash.
+// - Not inflating the memory used by the main process uselessly, which could
+//   increase its likelihood to be killed.
+// The forked process has background priority and, since it is not declared to
+// the Android runtime, can be killed at any time, which is not an issue here.
+class BASE_EXPORT NativeLibraryPrefetcher {
+ public:
+  // Finds the ranges matching the native library, forks a low priority
+  // process pre-fetching these ranges and wait()s for it.
+  // Returns true for success.
+  static bool ForkAndPrefetchNativeLibrary();
+
+ private:
+  using AddressRange = std::pair<uintptr_t, uintptr_t>;
+  // Returns true if the region matches native code or data.
+  static bool IsGoodToPrefetch(const base::debug::MappedMemoryRegion& region);
+  // Filters the regions to keep only libchrome ranges if possible.
+  static void FilterLibchromeRangesOnlyIfPossible(
+      const std::vector<base::debug::MappedMemoryRegion>& regions,
+      std::vector<AddressRange>* ranges);
+  // Finds the ranges matching the native library in /proc/self/maps.
+  // Returns true for success.
+  static bool FindRanges(std::vector<AddressRange>* ranges);
+
+  FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
+                           TestIsGoodToPrefetchNoRange);
+  FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
+                           TestIsGoodToPrefetchUnreadableRange);
+  FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
+                           TestIsGoodToPrefetchSkipSharedRange);
+  FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
+                           TestIsGoodToPrefetchLibchromeRange);
+  FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
+                           TestIsGoodToPrefetchBaseApkRange);
+  FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
+                           TestFilterLibchromeRangesOnlyIfPossibleNoLibchrome);
+  FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
+                           TestFilterLibchromeRangesOnlyIfPossibleHasLibchrome);
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(NativeLibraryPrefetcher);
+};
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_LIBRARY_LOADER_LIBRARY_PREFETCHER_H_
diff --git a/base/android/library_loader/library_prefetcher_unittest.cc b/base/android/library_loader/library_prefetcher_unittest.cc
new file mode 100644
index 0000000..7b7296f
--- /dev/null
+++ b/base/android/library_loader/library_prefetcher_unittest.cc
@@ -0,0 +1,95 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/library_loader/library_prefetcher.h"
+
+#include <string>
+#include <vector>
+#include "base/debug/proc_maps_linux.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace android {
+
+namespace {
+const uint8 kRead = base::debug::MappedMemoryRegion::READ;
+const uint8 kReadPrivate = base::debug::MappedMemoryRegion::READ |
+                           base::debug::MappedMemoryRegion::PRIVATE;
+const uint8 kExecutePrivate = base::debug::MappedMemoryRegion::EXECUTE |
+                              base::debug::MappedMemoryRegion::PRIVATE;
+}  // namespace
+
+TEST(NativeLibraryPrefetcherTest, TestIsGoodToPrefetchNoRange) {
+  const base::debug::MappedMemoryRegion regions[4] = {
+      base::debug::MappedMemoryRegion{0x4000, 0x5000, 10, kReadPrivate, ""},
+      base::debug::MappedMemoryRegion{0x4000, 0x5000, 10, kReadPrivate, "foo"},
+      base::debug::MappedMemoryRegion{
+          0x4000, 0x5000, 10, kReadPrivate, "foobar.apk"},
+      base::debug::MappedMemoryRegion{
+          0x4000, 0x5000, 10, kReadPrivate, "libchromium.so"}};
+  for (int i = 0; i < 4; ++i) {
+    ASSERT_FALSE(NativeLibraryPrefetcher::IsGoodToPrefetch(regions[i]));
+  }
+}
+
+TEST(NativeLibraryPrefetcherTest, TestIsGoodToPrefetchUnreadableRange) {
+  const base::debug::MappedMemoryRegion region = {
+      0x4000, 0x5000, 10, kExecutePrivate, "base.apk"};
+  ASSERT_FALSE(NativeLibraryPrefetcher::IsGoodToPrefetch(region));
+}
+
+TEST(NativeLibraryPrefetcherTest, TestIsGoodToPrefetchSkipSharedRange) {
+  const base::debug::MappedMemoryRegion region = {
+      0x4000, 0x5000, 10, kRead, "base.apk"};
+  ASSERT_FALSE(NativeLibraryPrefetcher::IsGoodToPrefetch(region));
+}
+
+TEST(NativeLibraryPrefetcherTest, TestIsGoodToPrefetchLibchromeRange) {
+  const base::debug::MappedMemoryRegion region = {
+      0x4000, 0x5000, 10, kReadPrivate, "libchrome.so"};
+  ASSERT_TRUE(NativeLibraryPrefetcher::IsGoodToPrefetch(region));
+}
+
+TEST(NativeLibraryPrefetcherTest, TestIsGoodToPrefetchBaseApkRange) {
+  const base::debug::MappedMemoryRegion region = {
+      0x4000, 0x5000, 10, kReadPrivate, "base.apk"};
+  ASSERT_TRUE(NativeLibraryPrefetcher::IsGoodToPrefetch(region));
+}
+
+TEST(NativeLibraryPrefetcherTest,
+     TestFilterLibchromeRangesOnlyIfPossibleNoLibchrome) {
+  std::vector<base::debug::MappedMemoryRegion> regions;
+  regions.push_back(
+      base::debug::MappedMemoryRegion{0x1, 0x2, 0, kReadPrivate, "base.apk"});
+  regions.push_back(
+      base::debug::MappedMemoryRegion{0x3, 0x4, 0, kReadPrivate, "base.apk"});
+  std::vector<NativeLibraryPrefetcher::AddressRange> ranges;
+  NativeLibraryPrefetcher::FilterLibchromeRangesOnlyIfPossible(regions,
+                                                               &ranges);
+  EXPECT_EQ(ranges.size(), 2U);
+  EXPECT_EQ(ranges[0].first, 0x1U);
+  EXPECT_EQ(ranges[0].second, 0x2U);
+  EXPECT_EQ(ranges[1].first, 0x3U);
+  EXPECT_EQ(ranges[1].second, 0x4U);
+}
+
+TEST(NativeLibraryPrefetcherTest,
+     TestFilterLibchromeRangesOnlyIfPossibleHasLibchrome) {
+  std::vector<base::debug::MappedMemoryRegion> regions;
+  regions.push_back(
+      base::debug::MappedMemoryRegion{0x1, 0x2, 0, kReadPrivate, "base.apk"});
+  regions.push_back(base::debug::MappedMemoryRegion{
+      0x6, 0x7, 0, kReadPrivate, "libchrome.so"});
+  regions.push_back(
+      base::debug::MappedMemoryRegion{0x3, 0x4, 0, kReadPrivate, "base.apk"});
+  std::vector<NativeLibraryPrefetcher::AddressRange> ranges;
+  NativeLibraryPrefetcher::FilterLibchromeRangesOnlyIfPossible(regions,
+                                                               &ranges);
+  EXPECT_EQ(ranges.size(), 1U);
+  EXPECT_EQ(ranges[0].first, 0x6U);
+  EXPECT_EQ(ranges[0].second, 0x7U);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/linker/BUILD.gn b/base/android/linker/BUILD.gn
new file mode 100644
index 0000000..190ea47
--- /dev/null
+++ b/base/android/linker/BUILD.gn
@@ -0,0 +1,27 @@
+# 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.
+
+import("//build/config/android/config.gni")
+
+assert(is_android)
+
+# GYP: //base/base.gyp:chromium_android_linker
+shared_library("chromium_android_linker") {
+  sources = [
+    "linker_jni.cc",
+  ]
+
+  # The NDK contains the crazy_linker here:
+  #   '<(android_ndk_root)/crazy_linker.gyp:crazy_linker'
+  # However, we use our own fork.  See bug 384700.
+  deps = [
+    "//third_party/android_crazy_linker",
+  ]
+
+  # TODO(GYP):
+  # The crazy linker is never instrumented.
+  #'cflags!': [
+  #'-finstrument-functions',
+  #],
+}
diff --git a/base/android/linker/DEPS b/base/android/linker/DEPS
new file mode 100644
index 0000000..15c3afb
--- /dev/null
+++ b/base/android/linker/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+  # This code cannot depend on anything from base/
+  "-base",
+]
diff --git a/base/android/linker/config.gni b/base/android/linker/config.gni
new file mode 100644
index 0000000..99cbcf0
--- /dev/null
+++ b/base/android/linker/config.gni
@@ -0,0 +1,8 @@
+# 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.
+
+# TODO(GYP) add "|| profiling_full_stack_frames
+# Only enable the chromium linker on regular builds, since the
+# component build crashes on Android 4.4. See b/11379966
+chromium_linker_supported = !is_component_build
diff --git a/base/android/linker/linker_jni.cc b/base/android/linker/linker_jni.cc
new file mode 100644
index 0000000..2bc480c
--- /dev/null
+++ b/base/android/linker/linker_jni.cc
@@ -0,0 +1,803 @@
+// 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 is the Android-specific Chromium linker, a tiny shared library
+// implementing a custom dynamic linker that can be used to load the
+// real Chromium libraries (e.g. libcontentshell.so).
+
+// The main point of this linker is to be able to share the RELRO
+// section of libcontentshell.so (or equivalent) between the browser and
+// renderer process.
+
+// This source code *cannot* depend on anything from base/ or the C++
+// STL, to keep the final library small, and avoid ugly dependency issues.
+
+#include <android/log.h>
+#include <crazy_linker.h>
+#include <fcntl.h>
+#include <jni.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+// Set this to 1 to enable debug traces to the Android log.
+// Note that LOG() from "base/logging.h" cannot be used, since it is
+// in base/ which hasn't been loaded yet.
+#define DEBUG 0
+
+#define TAG "chromium_android_linker"
+
+#if DEBUG
+#define LOG_INFO(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
+#else
+#define LOG_INFO(...) ((void)0)
+#endif
+#define LOG_ERROR(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
+
+#define UNUSED __attribute__((unused))
+
+namespace {
+
+// A simply scoped UTF String class that can be initialized from
+// a Java jstring handle. Modeled like std::string, which cannot
+// be used here.
+class String {
+ public:
+  String(JNIEnv* env, jstring str);
+
+  ~String() {
+    if (ptr_)
+      ::free(ptr_);
+  }
+
+  const char* c_str() const { return ptr_ ? ptr_ : ""; }
+  size_t size() const { return size_; }
+
+ private:
+  char* ptr_;
+  size_t size_;
+};
+
+String::String(JNIEnv* env, jstring str) {
+  size_ = env->GetStringUTFLength(str);
+  ptr_ = static_cast<char*>(::malloc(size_ + 1));
+
+  // Note: the result contains Java "modified UTF-8" bytes.
+  // Good enough for the linker though.
+  const char* bytes = env->GetStringUTFChars(str, NULL);
+  ::memcpy(ptr_, bytes, size_);
+  ptr_[size_] = '\0';
+
+  env->ReleaseStringUTFChars(str, bytes);
+}
+
+// Return true iff |address| is a valid address for the target CPU.
+bool IsValidAddress(jlong address) {
+  return static_cast<jlong>(static_cast<size_t>(address)) == address;
+}
+
+// Find the jclass JNI reference corresponding to a given |class_name|.
+// |env| is the current JNI environment handle.
+// On success, return true and set |*clazz|.
+bool InitClassReference(JNIEnv* env, const char* class_name, jclass* clazz) {
+  *clazz = env->FindClass(class_name);
+  if (!*clazz) {
+    LOG_ERROR("Could not find class for %s", class_name);
+    return false;
+  }
+  return true;
+}
+
+// Initialize a jfieldID corresponding to the field of a given |clazz|,
+// with name |field_name| and signature |field_sig|.
+// |env| is the current JNI environment handle.
+// On success, return true and set |*field_id|.
+bool InitFieldId(JNIEnv* env,
+                 jclass clazz,
+                 const char* field_name,
+                 const char* field_sig,
+                 jfieldID* field_id) {
+  *field_id = env->GetFieldID(clazz, field_name, field_sig);
+  if (!*field_id) {
+    LOG_ERROR("Could not find ID for field '%s'", field_name);
+    return false;
+  }
+  LOG_INFO(
+      "%s: Found ID %p for field '%s'", __FUNCTION__, *field_id, field_name);
+  return true;
+}
+
+// Initialize a jmethodID corresponding to the static method of a given
+// |clazz|, with name |method_name| and signature |method_sig|.
+// |env| is the current JNI environment handle.
+// On success, return true and set |*method_id|.
+bool InitStaticMethodId(JNIEnv* env,
+                        jclass clazz,
+                        const char* method_name,
+                        const char* method_sig,
+                        jmethodID* method_id) {
+  *method_id = env->GetStaticMethodID(clazz, method_name, method_sig);
+  if (!*method_id) {
+    LOG_ERROR("Could not find ID for static method '%s'", method_name);
+    return false;
+  }
+  LOG_INFO("%s: Found ID %p for static method '%s'",
+           __FUNCTION__, *method_id, method_name);
+  return true;
+}
+
+// Initialize a jfieldID corresponding to the static field of a given |clazz|,
+// with name |field_name| and signature |field_sig|.
+// |env| is the current JNI environment handle.
+// On success, return true and set |*field_id|.
+bool InitStaticFieldId(JNIEnv* env,
+                       jclass clazz,
+                       const char* field_name,
+                       const char* field_sig,
+                       jfieldID* field_id) {
+  *field_id = env->GetStaticFieldID(clazz, field_name, field_sig);
+  if (!*field_id) {
+    LOG_ERROR("Could not find ID for static field '%s'", field_name);
+    return false;
+  }
+  LOG_INFO(
+      "%s: Found ID %p for static field '%s'",
+      __FUNCTION__, *field_id, field_name);
+  return true;
+}
+
+// Initialize a jint corresponding to the static integer field of a class
+// with class name |class_name| and field name |field_name|.
+// |env| is the current JNI environment handle.
+// On success, return true and set |*value|.
+bool InitStaticInt(JNIEnv* env,
+                   const char* class_name,
+                   const char* field_name,
+                   jint* value) {
+  jclass clazz;
+  if (!InitClassReference(env, class_name, &clazz))
+    return false;
+
+  jfieldID field_id;
+  if (!InitStaticFieldId(env, clazz, field_name, "I", &field_id))
+    return false;
+
+  *value = env->GetStaticIntField(clazz, field_id);
+  LOG_INFO(
+      "%s: Found value %d for class '%s', static field '%s'",
+      __FUNCTION__, *value, class_name, field_name);
+
+  return true;
+}
+
+// A class used to model the field IDs of the org.chromium.base.Linker
+// LibInfo inner class, used to communicate data with the Java side
+// of the linker.
+struct LibInfo_class {
+  jfieldID load_address_id;
+  jfieldID load_size_id;
+  jfieldID relro_start_id;
+  jfieldID relro_size_id;
+  jfieldID relro_fd_id;
+
+  // Initialize an instance.
+  bool Init(JNIEnv* env) {
+    jclass clazz;
+    if (!InitClassReference(
+             env, "org/chromium/base/library_loader/Linker$LibInfo", &clazz)) {
+      return false;
+    }
+
+    return InitFieldId(env, clazz, "mLoadAddress", "J", &load_address_id) &&
+           InitFieldId(env, clazz, "mLoadSize", "J", &load_size_id) &&
+           InitFieldId(env, clazz, "mRelroStart", "J", &relro_start_id) &&
+           InitFieldId(env, clazz, "mRelroSize", "J", &relro_size_id) &&
+           InitFieldId(env, clazz, "mRelroFd", "I", &relro_fd_id);
+  }
+
+  void SetLoadInfo(JNIEnv* env,
+                   jobject library_info_obj,
+                   size_t load_address,
+                   size_t load_size) {
+    env->SetLongField(library_info_obj, load_address_id, load_address);
+    env->SetLongField(library_info_obj, load_size_id, load_size);
+  }
+
+  // Use this instance to convert a RelroInfo reference into
+  // a crazy_library_info_t.
+  void GetRelroInfo(JNIEnv* env,
+                    jobject library_info_obj,
+                    size_t* relro_start,
+                    size_t* relro_size,
+                    int* relro_fd) {
+    *relro_start = static_cast<size_t>(
+        env->GetLongField(library_info_obj, relro_start_id));
+
+    *relro_size =
+        static_cast<size_t>(env->GetLongField(library_info_obj, relro_size_id));
+
+    *relro_fd = env->GetIntField(library_info_obj, relro_fd_id);
+  }
+
+  void SetRelroInfo(JNIEnv* env,
+                    jobject library_info_obj,
+                    size_t relro_start,
+                    size_t relro_size,
+                    int relro_fd) {
+    env->SetLongField(library_info_obj, relro_start_id, relro_start);
+    env->SetLongField(library_info_obj, relro_size_id, relro_size);
+    env->SetIntField(library_info_obj, relro_fd_id, relro_fd);
+  }
+};
+
+static LibInfo_class s_lib_info_fields;
+
+// Retrieve the SDK build version and pass it into the crazy linker. This
+// needs to be done early in initialization, before any other crazy linker
+// code is run.
+// |env| is the current JNI environment handle.
+// On success, return true.
+bool InitSDKVersionInfo(JNIEnv* env) {
+  jint value = 0;
+  if (!InitStaticInt(env, "android/os/Build$VERSION", "SDK_INT", &value))
+    return false;
+
+  crazy_set_sdk_build_version(static_cast<int>(value));
+  LOG_INFO("%s: Set SDK build version to %d",
+           __FUNCTION__, static_cast<int>(value));
+
+  return true;
+}
+
+// The linker uses a single crazy_context_t object created on demand.
+// There is no need to protect this against concurrent access, locking
+// is already handled on the Java side.
+static crazy_context_t* s_crazy_context;
+
+crazy_context_t* GetCrazyContext() {
+  if (!s_crazy_context) {
+    // Create new context.
+    s_crazy_context = crazy_context_create();
+
+    // Ensure libraries located in the same directory as the linker
+    // can be loaded before system ones.
+    crazy_context_add_search_path_for_address(
+        s_crazy_context, reinterpret_cast<void*>(&s_crazy_context));
+  }
+
+  return s_crazy_context;
+}
+
+// A scoped crazy_library_t that automatically closes the handle
+// on scope exit, unless Release() has been called.
+class ScopedLibrary {
+ public:
+  ScopedLibrary() : lib_(NULL) {}
+
+  ~ScopedLibrary() {
+    if (lib_)
+      crazy_library_close_with_context(lib_, GetCrazyContext());
+  }
+
+  crazy_library_t* Get() { return lib_; }
+
+  crazy_library_t** GetPtr() { return &lib_; }
+
+  crazy_library_t* Release() {
+    crazy_library_t* ret = lib_;
+    lib_ = NULL;
+    return ret;
+  }
+
+ private:
+  crazy_library_t* lib_;
+};
+
+namespace {
+
+template <class LibraryOpener>
+bool GenericLoadLibrary(
+    JNIEnv* env,
+    const char* library_name, jlong load_address, jobject lib_info_obj,
+    const LibraryOpener& opener) {
+  crazy_context_t* context = GetCrazyContext();
+
+  if (!IsValidAddress(load_address)) {
+    LOG_ERROR("%s: Invalid address 0x%llx", __FUNCTION__, load_address);
+    return false;
+  }
+
+  // Set the desired load address (0 means randomize it).
+  crazy_context_set_load_address(context, static_cast<size_t>(load_address));
+
+  ScopedLibrary library;
+  if (!opener.Open(library.GetPtr(), library_name, context)) {
+    return false;
+  }
+
+  crazy_library_info_t info;
+  if (!crazy_library_get_info(library.Get(), context, &info)) {
+    LOG_ERROR("%s: Could not get library information for %s: %s",
+              __FUNCTION__,
+              library_name,
+              crazy_context_get_error(context));
+    return false;
+  }
+
+  // Release library object to keep it alive after the function returns.
+  library.Release();
+
+  s_lib_info_fields.SetLoadInfo(
+      env, lib_info_obj, info.load_address, info.load_size);
+  LOG_INFO("%s: Success loading library %s", __FUNCTION__, library_name);
+  return true;
+}
+
+// Used for opening the library in a regular file.
+class FileLibraryOpener {
+ public:
+  bool Open(
+      crazy_library_t** library,
+      const char* library_name,
+      crazy_context_t* context) const;
+};
+
+bool FileLibraryOpener::Open(
+    crazy_library_t** library,
+    const char* library_name,
+    crazy_context_t* context) const {
+  if (!crazy_library_open(library, library_name, context)) {
+    LOG_ERROR("%s: Could not open %s: %s",
+              __FUNCTION__,
+              library_name,
+              crazy_context_get_error(context));
+    return false;
+  }
+  return true;
+}
+
+// Used for opening the library in a zip file.
+class ZipLibraryOpener {
+ public:
+  explicit ZipLibraryOpener(const char* zip_file) : zip_file_(zip_file) {}
+  bool Open(
+      crazy_library_t** library,
+      const char* library_name,
+      crazy_context_t* context) const;
+ private:
+  const char* zip_file_;
+};
+
+bool ZipLibraryOpener::Open(
+    crazy_library_t** library,
+    const char* library_name,
+    crazy_context_t* context) const {
+  if (!crazy_library_open_in_zip_file(
+          library, zip_file_, library_name, context)) {
+     LOG_ERROR("%s: Could not open %s in zip file %s: %s",
+               __FUNCTION__, library_name, zip_file_,
+               crazy_context_get_error(context));
+     return false;
+  }
+  return true;
+}
+
+}  // unnamed namespace
+
+// Load a library with the chromium linker. This will also call its
+// JNI_OnLoad() method, which shall register its methods. Note that
+// lazy native method resolution will _not_ work after this, because
+// Dalvik uses the system's dlsym() which won't see the new library,
+// so explicit registration is mandatory.
+// |env| is the current JNI environment handle.
+// |clazz| is the static class handle for org.chromium.base.Linker,
+// and is ignored here.
+// |library_name| is the library name (e.g. libfoo.so).
+// |load_address| is an explicit load address.
+// |library_info| is a LibInfo handle used to communicate information
+// with the Java side.
+// Return true on success.
+jboolean LoadLibrary(JNIEnv* env,
+                     jclass clazz,
+                     jstring library_name,
+                     jlong load_address,
+                     jobject lib_info_obj) {
+  String lib_name(env, library_name);
+  FileLibraryOpener opener;
+  return GenericLoadLibrary(
+      env, lib_name.c_str(),
+      static_cast<size_t>(load_address), lib_info_obj, opener);
+}
+
+// Load a library from a zipfile with the chromium linker. The
+// library in the zipfile must be uncompressed and page aligned.
+// The basename of the library is given. The library is expected
+// to be lib/<abi_tag>/crazy.<basename>. The <abi_tag> used will be the
+// same as the abi for this linker. The "crazy." prefix is included
+// so that the Android Package Manager doesn't extract the library into
+// /data/app-lib.
+//
+// Loading the library will also call its JNI_OnLoad() method, which
+// shall register its methods. Note that lazy native method resolution
+// will _not_ work after this, because Dalvik uses the system's dlsym()
+// which won't see the new library, so explicit registration is mandatory.
+//
+// |env| is the current JNI environment handle.
+// |clazz| is the static class handle for org.chromium.base.Linker,
+// and is ignored here.
+// |zipfile_name| is the filename of the zipfile containing the library.
+// |library_name| is the library base name (e.g. libfoo.so).
+// |load_address| is an explicit load address.
+// |library_info| is a LibInfo handle used to communicate information
+// with the Java side.
+// Returns true on success.
+jboolean LoadLibraryInZipFile(JNIEnv* env,
+                              jclass clazz,
+                              jstring zipfile_name,
+                              jstring library_name,
+                              jlong load_address,
+                              jobject lib_info_obj) {
+  String zipfile_name_str(env, zipfile_name);
+  String lib_name(env, library_name);
+  ZipLibraryOpener opener(zipfile_name_str.c_str());
+  return GenericLoadLibrary(
+      env, lib_name.c_str(),
+      static_cast<size_t>(load_address), lib_info_obj, opener);
+}
+
+// Class holding the Java class and method ID for the Java side Linker
+// postCallbackOnMainThread method.
+struct JavaCallbackBindings_class {
+  jclass clazz;
+  jmethodID method_id;
+
+  // Initialize an instance.
+  bool Init(JNIEnv* env, jclass linker_class) {
+    clazz = reinterpret_cast<jclass>(env->NewGlobalRef(linker_class));
+    return InitStaticMethodId(env,
+                              linker_class,
+                              "postCallbackOnMainThread",
+                              "(J)V",
+                              &method_id);
+  }
+};
+
+static JavaCallbackBindings_class s_java_callback_bindings;
+
+// Designated receiver function for callbacks from Java. Its name is known
+// to the Java side.
+// |env| is the current JNI environment handle and is ignored here.
+// |clazz| is the static class handle for org.chromium.base.Linker,
+// and is ignored here.
+// |arg| is a pointer to an allocated crazy_callback_t, deleted after use.
+void RunCallbackOnUiThread(JNIEnv* env, jclass clazz, jlong arg) {
+  crazy_callback_t* callback = reinterpret_cast<crazy_callback_t*>(arg);
+
+  LOG_INFO("%s: Called back from java with handler %p, opaque %p",
+           __FUNCTION__, callback->handler, callback->opaque);
+
+  crazy_callback_run(callback);
+  delete callback;
+}
+
+// Request a callback from Java. The supplied crazy_callback_t is valid only
+// for the duration of this call, so we copy it to a newly allocated
+// crazy_callback_t and then call the Java side's postCallbackOnMainThread.
+// This will call back to to our RunCallbackOnUiThread some time
+// later on the UI thread.
+// |callback_request| is a crazy_callback_t.
+// |poster_opaque| is unused.
+// Returns true if the callback request succeeds.
+static bool PostForLaterExecution(crazy_callback_t* callback_request,
+                                  void* poster_opaque UNUSED) {
+  crazy_context_t* context = GetCrazyContext();
+
+  JavaVM* vm;
+  int minimum_jni_version;
+  crazy_context_get_java_vm(context,
+                            reinterpret_cast<void**>(&vm),
+                            &minimum_jni_version);
+
+  // Do not reuse JNIEnv from JNI_OnLoad, but retrieve our own.
+  JNIEnv* env;
+  if (JNI_OK != vm->GetEnv(
+      reinterpret_cast<void**>(&env), minimum_jni_version)) {
+    LOG_ERROR("Could not create JNIEnv");
+    return false;
+  }
+
+  // Copy the callback; the one passed as an argument may be temporary.
+  crazy_callback_t* callback = new crazy_callback_t();
+  *callback = *callback_request;
+
+  LOG_INFO("%s: Calling back to java with handler %p, opaque %p",
+           __FUNCTION__, callback->handler, callback->opaque);
+
+  jlong arg = static_cast<jlong>(reinterpret_cast<uintptr_t>(callback));
+
+  env->CallStaticVoidMethod(
+      s_java_callback_bindings.clazz, s_java_callback_bindings.method_id, arg);
+
+  // Back out and return false if we encounter a JNI exception.
+  if (env->ExceptionCheck() == JNI_TRUE) {
+    env->ExceptionDescribe();
+    env->ExceptionClear();
+    delete callback;
+    return false;
+  }
+
+  return true;
+}
+
+jboolean CreateSharedRelro(JNIEnv* env,
+                           jclass clazz,
+                           jstring library_name,
+                           jlong load_address,
+                           jobject lib_info_obj) {
+  String lib_name(env, library_name);
+
+  LOG_INFO("%s: Called for %s", __FUNCTION__, lib_name.c_str());
+
+  if (!IsValidAddress(load_address)) {
+    LOG_ERROR("%s: Invalid address 0x%llx", __FUNCTION__, load_address);
+    return false;
+  }
+
+  ScopedLibrary library;
+  if (!crazy_library_find_by_name(lib_name.c_str(), library.GetPtr())) {
+    LOG_ERROR("%s: Could not find %s", __FUNCTION__, lib_name.c_str());
+    return false;
+  }
+
+  crazy_context_t* context = GetCrazyContext();
+  size_t relro_start = 0;
+  size_t relro_size = 0;
+  int relro_fd = -1;
+
+  if (!crazy_library_create_shared_relro(library.Get(),
+                                         context,
+                                         static_cast<size_t>(load_address),
+                                         &relro_start,
+                                         &relro_size,
+                                         &relro_fd)) {
+    LOG_ERROR("%s: Could not create shared RELRO sharing for %s: %s\n",
+              __FUNCTION__,
+              lib_name.c_str(),
+              crazy_context_get_error(context));
+    return false;
+  }
+
+  s_lib_info_fields.SetRelroInfo(
+      env, lib_info_obj, relro_start, relro_size, relro_fd);
+  return true;
+}
+
+jboolean UseSharedRelro(JNIEnv* env,
+                        jclass clazz,
+                        jstring library_name,
+                        jobject lib_info_obj) {
+  String lib_name(env, library_name);
+
+  LOG_INFO("%s: called for %s, lib_info_ref=%p",
+           __FUNCTION__,
+           lib_name.c_str(),
+           lib_info_obj);
+
+  ScopedLibrary library;
+  if (!crazy_library_find_by_name(lib_name.c_str(), library.GetPtr())) {
+    LOG_ERROR("%s: Could not find %s", __FUNCTION__, lib_name.c_str());
+    return false;
+  }
+
+  crazy_context_t* context = GetCrazyContext();
+  size_t relro_start = 0;
+  size_t relro_size = 0;
+  int relro_fd = -1;
+  s_lib_info_fields.GetRelroInfo(
+      env, lib_info_obj, &relro_start, &relro_size, &relro_fd);
+
+  LOG_INFO("%s: library=%s relro start=%p size=%p fd=%d",
+           __FUNCTION__,
+           lib_name.c_str(),
+           (void*)relro_start,
+           (void*)relro_size,
+           relro_fd);
+
+  if (!crazy_library_use_shared_relro(
+           library.Get(), context, relro_start, relro_size, relro_fd)) {
+    LOG_ERROR("%s: Could not use shared RELRO for %s: %s",
+              __FUNCTION__,
+              lib_name.c_str(),
+              crazy_context_get_error(context));
+    return false;
+  }
+
+  LOG_INFO("%s: Library %s using shared RELRO section!",
+           __FUNCTION__,
+           lib_name.c_str());
+
+  return true;
+}
+
+jboolean CanUseSharedRelro(JNIEnv* env, jclass clazz) {
+  return crazy_system_can_share_relro();
+}
+
+jlong GetRandomBaseLoadAddress(JNIEnv* env, jclass clazz, jlong bytes) {
+  void* address =
+      mmap(NULL, bytes, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  if (address == MAP_FAILED) {
+    LOG_INFO("%s: Random base load address not determinable\n", __FUNCTION__);
+    return 0;
+  }
+  munmap(address, bytes);
+  LOG_INFO("%s: Random base load address is %p\n", __FUNCTION__, address);
+  return static_cast<jlong>(reinterpret_cast<uintptr_t>(address));
+}
+
+// Get the full path of a library in the zip file
+// (lib/<abi>/crazy.<lib_name>).
+//
+// |env| is the current JNI environment handle.
+// |clazz| is the static class handle which is not used here.
+// |lib_name| is the library base name.
+// Returns the full path (or empty string on failure).
+jstring GetLibraryFilePathInZipFile(JNIEnv* env,
+                                    jclass clazz,
+                                    jstring lib_name) {
+  String lib_name_str(env, lib_name);
+  const char* lib_name_c_str = lib_name_str.c_str();
+  char buffer[kMaxFilePathLengthInZip + 1];
+  if (crazy_library_file_path_in_zip_file(
+          lib_name_c_str, buffer, sizeof(buffer)) == CRAZY_STATUS_FAILURE) {
+    LOG_ERROR("%s: Failed to get full filename for library '%s'",
+              __FUNCTION__, lib_name_c_str);
+    buffer[0] = '\0';
+  }
+  return env->NewStringUTF(buffer);
+}
+
+// Check whether a library is page aligned and uncompressed in the APK file.
+//
+// |env| is the current JNI environment handle.
+// |clazz| is the static class handle which is not used here.
+// |apkfile_name| is the filename of the APK.
+// |library_name| is the library base name.
+// Returns true if page aligned and uncompressed.
+jboolean CheckLibraryIsMappableInApk(JNIEnv* env, jclass clazz,
+                                     jstring apkfile_name,
+                                     jstring library_name) {
+  String apkfile_name_str(env, apkfile_name);
+  const char* apkfile_name_c_str = apkfile_name_str.c_str();
+  String library_name_str(env, library_name);
+  const char* library_name_c_str = library_name_str.c_str();
+
+  LOG_INFO("%s: Checking if %s is page-aligned and uncompressed in %s\n",
+           __FUNCTION__, library_name_c_str, apkfile_name_c_str);
+  jboolean mappable = crazy_linker_check_library_is_mappable_in_zip_file(
+      apkfile_name_c_str, library_name_c_str) == CRAZY_STATUS_SUCCESS;
+  LOG_INFO("%s: %s\n", __FUNCTION__, mappable ? "Mappable" : "NOT mappable");
+
+  return mappable;
+}
+
+const JNINativeMethod kNativeMethods[] = {
+    {"nativeLoadLibrary",
+     "("
+     "Ljava/lang/String;"
+     "J"
+     "Lorg/chromium/base/library_loader/Linker$LibInfo;"
+     ")"
+     "Z",
+     reinterpret_cast<void*>(&LoadLibrary)},
+    {"nativeLoadLibraryInZipFile",
+     "("
+     "Ljava/lang/String;"
+     "Ljava/lang/String;"
+     "J"
+     "Lorg/chromium/base/library_loader/Linker$LibInfo;"
+     ")"
+     "Z",
+     reinterpret_cast<void*>(&LoadLibraryInZipFile)},
+    {"nativeRunCallbackOnUiThread",
+     "("
+     "J"
+     ")"
+     "V",
+     reinterpret_cast<void*>(&RunCallbackOnUiThread)},
+    {"nativeCreateSharedRelro",
+     "("
+     "Ljava/lang/String;"
+     "J"
+     "Lorg/chromium/base/library_loader/Linker$LibInfo;"
+     ")"
+     "Z",
+     reinterpret_cast<void*>(&CreateSharedRelro)},
+    {"nativeUseSharedRelro",
+     "("
+     "Ljava/lang/String;"
+     "Lorg/chromium/base/library_loader/Linker$LibInfo;"
+     ")"
+     "Z",
+     reinterpret_cast<void*>(&UseSharedRelro)},
+    {"nativeCanUseSharedRelro",
+     "("
+     ")"
+     "Z",
+     reinterpret_cast<void*>(&CanUseSharedRelro)},
+    {"nativeGetRandomBaseLoadAddress",
+     "("
+     "J"
+     ")"
+     "J",
+     reinterpret_cast<void*>(&GetRandomBaseLoadAddress)},
+    {"nativeGetLibraryFilePathInZipFile",
+     "("
+     "Ljava/lang/String;"
+     ")"
+     "Ljava/lang/String;",
+     reinterpret_cast<void*>(&GetLibraryFilePathInZipFile)},
+    {"nativeCheckLibraryIsMappableInApk",
+     "("
+     "Ljava/lang/String;"
+     "Ljava/lang/String;"
+     ")"
+     "Z",
+     reinterpret_cast<void*>(&CheckLibraryIsMappableInApk)}, };
+
+}  // namespace
+
+// JNI_OnLoad() hook called when the linker library is loaded through
+// the regular System.LoadLibrary) API. This shall save the Java VM
+// handle and initialize LibInfo fields.
+jint JNI_OnLoad(JavaVM* vm, void* reserved) {
+  LOG_INFO("%s: Entering", __FUNCTION__);
+  // Get new JNIEnv
+  JNIEnv* env;
+  if (JNI_OK != vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_4)) {
+    LOG_ERROR("Could not create JNIEnv");
+    return -1;
+  }
+
+  // Initialize SDK version info.
+  LOG_INFO("%s: Retrieving SDK version info", __FUNCTION__);
+  if (!InitSDKVersionInfo(env))
+    return -1;
+
+  // Register native methods.
+  jclass linker_class;
+  if (!InitClassReference(env,
+                          "org/chromium/base/library_loader/Linker",
+                          &linker_class))
+    return -1;
+
+  LOG_INFO("%s: Registering native methods", __FUNCTION__);
+  env->RegisterNatives(linker_class,
+                       kNativeMethods,
+                       sizeof(kNativeMethods) / sizeof(kNativeMethods[0]));
+
+  // Find LibInfo field ids.
+  LOG_INFO("%s: Caching field IDs", __FUNCTION__);
+  if (!s_lib_info_fields.Init(env)) {
+    return -1;
+  }
+
+  // Resolve and save the Java side Linker callback class and method.
+  LOG_INFO("%s: Resolving callback bindings", __FUNCTION__);
+  if (!s_java_callback_bindings.Init(env, linker_class)) {
+    return -1;
+  }
+
+  // Save JavaVM* handle into context.
+  crazy_context_t* context = GetCrazyContext();
+  crazy_context_set_java_vm(context, vm, JNI_VERSION_1_4);
+
+  // Register the function that the crazy linker can call to post code
+  // for later execution.
+  crazy_context_set_callback_poster(context, &PostForLaterExecution, NULL);
+
+  LOG_INFO("%s: Done", __FUNCTION__);
+  return JNI_VERSION_1_4;
+}
diff --git a/base/android/locale_utils.cc b/base/android/locale_utils.cc
new file mode 100644
index 0000000..af46f89
--- /dev/null
+++ b/base/android/locale_utils.cc
@@ -0,0 +1,31 @@
+// 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.
+
+#include "base/android/locale_utils.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "jni/LocaleUtils_jni.h"
+
+namespace base {
+namespace android {
+
+std::string GetDefaultCountryCode() {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  return ConvertJavaStringToUTF8(Java_LocaleUtils_getDefaultCountryCode(env));
+}
+
+std::string GetDefaultLocale() {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  ScopedJavaLocalRef<jstring> locale = Java_LocaleUtils_getDefaultLocale(
+      env);
+  return ConvertJavaStringToUTF8(locale);
+}
+
+bool RegisterLocaleUtils(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/locale_utils.h b/base/android/locale_utils.h
new file mode 100644
index 0000000..9e03b83
--- /dev/null
+++ b/base/android/locale_utils.h
@@ -0,0 +1,27 @@
+// 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.
+
+#ifndef BASE_ANDROID_LOCALE_UTILS_H_
+#define BASE_ANDROID_LOCALE_UTILS_H_
+
+#include <jni.h>
+
+#include <string>
+
+#include "base/base_export.h"
+
+namespace base {
+namespace android {
+
+BASE_EXPORT std::string GetDefaultCountryCode();
+
+// Return the current default locale of the device.
+BASE_EXPORT std::string GetDefaultLocale();
+
+BASE_EXPORT bool RegisterLocaleUtils(JNIEnv* env);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_LOCALE_UTILS_H_
diff --git a/base/android/memory_pressure_listener_android.cc b/base/android/memory_pressure_listener_android.cc
new file mode 100644
index 0000000..80c07bc
--- /dev/null
+++ b/base/android/memory_pressure_listener_android.cc
@@ -0,0 +1,31 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/memory_pressure_listener_android.h"
+
+#include "base/memory/memory_pressure_listener.h"
+#include "jni/MemoryPressureListener_jni.h"
+
+// Defined and called by JNI.
+static void OnMemoryPressure(
+    JNIEnv* env, jclass clazz, jint memory_pressure_level) {
+  base::MemoryPressureListener::NotifyMemoryPressure(
+      static_cast<base::MemoryPressureListener::MemoryPressureLevel>(
+          memory_pressure_level));
+}
+
+namespace base {
+namespace android {
+
+bool MemoryPressureListenerAndroid::Register(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+void MemoryPressureListenerAndroid::RegisterSystemCallback(JNIEnv* env) {
+  Java_MemoryPressureListener_registerSystemCallback(
+      env, GetApplicationContext());
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/memory_pressure_listener_android.h b/base/android/memory_pressure_listener_android.h
new file mode 100644
index 0000000..eed8dbb
--- /dev/null
+++ b/base/android/memory_pressure_listener_android.h
@@ -0,0 +1,30 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_MEMORY_PRESSURE_LISTENER_ANDROID_H_
+#define BASE_ANDROID_MEMORY_PRESSURE_LISTENER_ANDROID_H_
+
+#include "base/android/jni_android.h"
+
+namespace base {
+namespace android {
+
+// Implements the C++ counter part of MemoryPressureListener.java
+class BASE_EXPORT MemoryPressureListenerAndroid {
+ public:
+  static bool Register(JNIEnv* env);
+
+  static void RegisterSystemCallback(JNIEnv* env);
+
+  // Called by JNI.
+  static void OnMemoryPressure(int memory_pressure_type);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MemoryPressureListenerAndroid);
+};
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_MEMORY_PRESSURE_LISTENER_ANDROID_H_
diff --git a/base/android/path_service_android.cc b/base/android/path_service_android.cc
new file mode 100644
index 0000000..18ca70c
--- /dev/null
+++ b/base/android/path_service_android.cc
@@ -0,0 +1,26 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/path_service_android.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "jni/PathService_jni.h"
+
+namespace base {
+namespace android {
+
+void Override(JNIEnv* env, jclass clazz, jint what, jstring path) {
+  FilePath file_path(ConvertJavaStringToUTF8(env, path));
+  PathService::Override(what, file_path);
+}
+
+bool RegisterPathService(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/path_service_android.h b/base/android/path_service_android.h
new file mode 100644
index 0000000..26040f9
--- /dev/null
+++ b/base/android/path_service_android.h
@@ -0,0 +1,18 @@
+// Copyright (c) 2012 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_PATH_SERVICE_ANDROID_H_
+#define BASE_ANDROID_PATH_SERVICE_ANDROID_H_
+
+#include <jni.h>
+
+namespace base {
+namespace android {
+
+bool RegisterPathService(JNIEnv* env);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_PATH_SERVICE_ANDROID_H_
diff --git a/base/android/path_utils.cc b/base/android/path_utils.cc
new file mode 100644
index 0000000..c98007c
--- /dev/null
+++ b/base/android/path_utils.cc
@@ -0,0 +1,76 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/path_utils.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/files/file_path.h"
+
+#include "jni/PathUtils_jni.h"
+
+namespace base {
+namespace android {
+
+bool GetDataDirectory(FilePath* result) {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jstring> path =
+      Java_PathUtils_getDataDirectory(env, GetApplicationContext());
+  FilePath data_path(ConvertJavaStringToUTF8(path));
+  *result = data_path;
+  return true;
+}
+
+bool GetDatabaseDirectory(FilePath* result) {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jstring> path =
+      Java_PathUtils_getDatabaseDirectory(env, GetApplicationContext());
+  FilePath data_path(ConvertJavaStringToUTF8(path));
+  *result = data_path;
+  return true;
+}
+
+bool GetCacheDirectory(FilePath* result) {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jstring> path =
+      Java_PathUtils_getCacheDirectory(env, GetApplicationContext());
+  FilePath cache_path(ConvertJavaStringToUTF8(path));
+  *result = cache_path;
+  return true;
+}
+
+bool GetDownloadsDirectory(FilePath* result) {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jstring> path =
+      Java_PathUtils_getDownloadsDirectory(env, GetApplicationContext());
+  FilePath downloads_path(ConvertJavaStringToUTF8(path));
+  *result = downloads_path;
+  return true;
+}
+
+bool GetNativeLibraryDirectory(FilePath* result) {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jstring> path =
+      Java_PathUtils_getNativeLibraryDirectory(env, GetApplicationContext());
+  FilePath library_path(ConvertJavaStringToUTF8(path));
+  *result = library_path;
+  return true;
+}
+
+bool GetExternalStorageDirectory(FilePath* result) {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jstring> path =
+      Java_PathUtils_getExternalStorageDirectory(env);
+  FilePath storage_path(ConvertJavaStringToUTF8(path));
+  *result = storage_path;
+  return true;
+}
+
+bool RegisterPathUtils(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/path_utils.h b/base/android/path_utils.h
new file mode 100644
index 0000000..d3421b3
--- /dev/null
+++ b/base/android/path_utils.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2012 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_PATH_UTILS_H_
+#define BASE_ANDROID_PATH_UTILS_H_
+
+#include <jni.h>
+
+#include "base/base_export.h"
+
+namespace base {
+
+class FilePath;
+
+namespace android {
+
+// Retrieves the absolute path to the data directory of the current
+// application. The result is placed in the FilePath pointed to by 'result'.
+// This method is dedicated for base_paths_android.c, Using
+// PathService::Get(base::DIR_ANDROID_APP_DATA, ...) gets the data dir.
+BASE_EXPORT bool GetDataDirectory(FilePath* result);
+
+// Retrieves the absolute path to the database directory that Android
+// framework's SQLiteDatabase class uses when creating database files.
+BASE_EXPORT bool GetDatabaseDirectory(FilePath* result);
+
+// Retrieves the absolute path to the cache directory. The result is placed in
+// the FilePath pointed to by 'result'. This method is dedicated for
+// base_paths_android.c, Using PathService::Get(base::DIR_CACHE, ...) gets the
+// cache dir.
+BASE_EXPORT bool GetCacheDirectory(FilePath* result);
+
+// Retrieves the path to the public downloads directory. The result is placed
+// in the FilePath pointed to by 'result'.
+BASE_EXPORT bool GetDownloadsDirectory(FilePath* result);
+
+// Retrieves the path to the native JNI libraries via
+// ApplicationInfo.nativeLibraryDir on the Java side. The result is placed in
+// the FilePath pointed to by 'result'.
+BASE_EXPORT bool GetNativeLibraryDirectory(FilePath* result);
+
+// Retrieves the absolute path to the external storage directory. The result
+// is placed in the FilePath pointed to by 'result'.
+BASE_EXPORT bool GetExternalStorageDirectory(FilePath* result);
+
+bool RegisterPathUtils(JNIEnv* env);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_PATH_UTILS_H_
diff --git a/base/android/path_utils_unittest.cc b/base/android/path_utils_unittest.cc
new file mode 100644
index 0000000..c678ce2
--- /dev/null
+++ b/base/android/path_utils_unittest.cc
@@ -0,0 +1,47 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/path_utils.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace android {
+
+typedef testing::Test PathUtilsTest;
+
+TEST_F(PathUtilsTest, TestGetDataDirectory) {
+  // The string comes from the Java side and depends on the APK
+  // we are running in. Assumes that we are packaged in
+  // org.chromium.native_test
+  FilePath path;
+  GetDataDirectory(&path);
+  EXPECT_STREQ("/data/data/org.chromium.native_test/app_chrome",
+               path.value().c_str());
+}
+
+TEST_F(PathUtilsTest, TestGetCacheDirectory) {
+  // The string comes from the Java side and depends on the APK
+  // we are running in. Assumes that we are packaged in
+  // org.chromium.native_test
+  FilePath path;
+  GetCacheDirectory(&path);
+  EXPECT_STREQ("/data/data/org.chromium.native_test/cache",
+               path.value().c_str());
+}
+
+TEST_F(PathUtilsTest, TestGetNativeLibraryDirectory) {
+  // The string comes from the Java side and depends on the APK
+  // we are running in. Assumes that the directory contains
+  // the base tests shared object.
+  FilePath path;
+  GetNativeLibraryDirectory(&path);
+  EXPECT_TRUE(base::PathExists(path.Append(("libbase_unittests.so"))) ||
+              base::PathExists(path.Append(("libbase_unittests.cr.so"))));
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/record_histogram.cc b/base/android/record_histogram.cc
new file mode 100644
index 0000000..9a68dec
--- /dev/null
+++ b/base/android/record_histogram.cc
@@ -0,0 +1,245 @@
+// 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.
+
+#include "base/android/record_histogram.h"
+
+#include <map>
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/lazy_instance.h"
+#include "base/metrics/histogram.h"
+#include "base/metrics/sparse_histogram.h"
+#include "base/metrics/statistics_recorder.h"
+#include "base/synchronization/lock.h"
+#include "base/time/time.h"
+#include "jni/RecordHistogram_jni.h"
+
+namespace base {
+namespace android {
+namespace {
+
+// Simple thread-safe wrapper for caching histograms. This avoids
+// relatively expensive JNI string translation for each recording.
+class HistogramCache {
+ public:
+  HistogramCache() {}
+
+  HistogramBase* BooleanHistogram(JNIEnv* env,
+                                  jstring j_histogram_name,
+                                  jint j_histogram_key) {
+    DCHECK(j_histogram_name);
+    DCHECK(j_histogram_key);
+    HistogramBase* histogram = FindLocked(j_histogram_key);
+    if (histogram)
+      return histogram;
+
+    std::string histogram_name = ConvertJavaStringToUTF8(env, j_histogram_name);
+    histogram = BooleanHistogram::FactoryGet(
+        histogram_name, HistogramBase::kUmaTargetedHistogramFlag);
+    return InsertLocked(j_histogram_key, histogram);
+  }
+
+  HistogramBase* EnumeratedHistogram(JNIEnv* env,
+                                     jstring j_histogram_name,
+                                     jint j_histogram_key,
+                                     jint j_boundary) {
+    DCHECK(j_histogram_name);
+    DCHECK(j_histogram_key);
+    HistogramBase* histogram = FindLocked(j_histogram_key);
+    int boundary = static_cast<int>(j_boundary);
+    if (histogram) {
+      DCHECK(histogram->HasConstructionArguments(1, boundary, boundary + 1));
+      return histogram;
+    }
+
+    std::string histogram_name = ConvertJavaStringToUTF8(env, j_histogram_name);
+    histogram =
+        LinearHistogram::FactoryGet(histogram_name, 1, boundary, boundary + 1,
+                                    HistogramBase::kUmaTargetedHistogramFlag);
+    return InsertLocked(j_histogram_key, histogram);
+  }
+
+  HistogramBase* CustomCountHistogram(JNIEnv* env,
+                                      jstring j_histogram_name,
+                                      jint j_histogram_key,
+                                      jint j_min,
+                                      jint j_max,
+                                      jint j_num_buckets) {
+    DCHECK(j_histogram_name);
+    DCHECK(j_histogram_key);
+    int64 min = static_cast<int64>(j_min);
+    int64 max = static_cast<int64>(j_max);
+    int num_buckets = static_cast<int>(j_num_buckets);
+    HistogramBase* histogram = FindLocked(j_histogram_key);
+    if (histogram) {
+      DCHECK(histogram->HasConstructionArguments(min, max, num_buckets));
+      return histogram;
+    }
+
+    std::string histogram_name = ConvertJavaStringToUTF8(env, j_histogram_name);
+    histogram =
+        Histogram::FactoryGet(histogram_name, min, max, num_buckets,
+                              HistogramBase::kUmaTargetedHistogramFlag);
+    return InsertLocked(j_histogram_key, histogram);
+  }
+
+  HistogramBase* SparseHistogram(JNIEnv* env,
+                                 jstring j_histogram_name,
+                                 jint j_histogram_key) {
+    DCHECK(j_histogram_name);
+    DCHECK(j_histogram_key);
+    HistogramBase* histogram = FindLocked(j_histogram_key);
+    if (histogram)
+      return histogram;
+
+    std::string histogram_name = ConvertJavaStringToUTF8(env, j_histogram_name);
+    histogram = SparseHistogram::FactoryGet(
+        histogram_name, HistogramBase::kUmaTargetedHistogramFlag);
+    return InsertLocked(j_histogram_key, histogram);
+  }
+
+  HistogramBase* CustomTimesHistogram(JNIEnv* env,
+                                      jstring j_histogram_name,
+                                      jint j_histogram_key,
+                                      jlong j_min,
+                                      jlong j_max,
+                                      jint j_bucket_count) {
+    DCHECK(j_histogram_name);
+    DCHECK(j_histogram_key);
+    HistogramBase* histogram = FindLocked(j_histogram_key);
+    int64 min = static_cast<int64>(j_min);
+    int64 max = static_cast<int64>(j_max);
+    int bucket_count = static_cast<int>(j_bucket_count);
+    if (histogram) {
+      DCHECK(histogram->HasConstructionArguments(min, max, bucket_count));
+      return histogram;
+    }
+
+    std::string histogram_name = ConvertJavaStringToUTF8(env, j_histogram_name);
+    // This intentionally uses FactoryGet and not FactoryTimeGet. FactoryTimeGet
+    // is just a convenience for constructing the underlying Histogram with
+    // TimeDelta arguments.
+    histogram = Histogram::FactoryGet(histogram_name, min, max, bucket_count,
+                                      HistogramBase::kUmaTargetedHistogramFlag);
+    return InsertLocked(j_histogram_key, histogram);
+  }
+
+ private:
+  HistogramBase* FindLocked(jint j_histogram_key) {
+    base::AutoLock locked(lock_);
+    auto histogram_it = histograms_.find(j_histogram_key);
+    return histogram_it != histograms_.end() ? histogram_it->second : nullptr;
+  }
+
+  HistogramBase* InsertLocked(jint j_histogram_key, HistogramBase* histogram) {
+    base::AutoLock locked(lock_);
+    histograms_.insert(std::make_pair(j_histogram_key, histogram));
+    return histogram;
+  }
+
+  base::Lock lock_;
+  std::map<jint, HistogramBase*> histograms_;
+
+  DISALLOW_COPY_AND_ASSIGN(HistogramCache);
+};
+
+base::LazyInstance<HistogramCache>::Leaky g_histograms;
+
+}  // namespace
+
+void RecordBooleanHistogram(JNIEnv* env,
+                            jclass clazz,
+                            jstring j_histogram_name,
+                            jint j_histogram_key,
+                            jboolean j_sample) {
+  bool sample = static_cast<bool>(j_sample);
+  g_histograms.Get()
+      .BooleanHistogram(env, j_histogram_name, j_histogram_key)
+      ->AddBoolean(sample);
+}
+
+void RecordEnumeratedHistogram(JNIEnv* env,
+                               jclass clazz,
+                               jstring j_histogram_name,
+                               jint j_histogram_key,
+                               jint j_sample,
+                               jint j_boundary) {
+  int sample = static_cast<int>(j_sample);
+
+  g_histograms.Get()
+      .EnumeratedHistogram(env, j_histogram_name, j_histogram_key, j_boundary)
+      ->Add(sample);
+}
+
+void RecordCustomCountHistogram(JNIEnv* env,
+                                jclass clazz,
+                                jstring j_histogram_name,
+                                jint j_histogram_key,
+                                jint j_sample,
+                                jint j_min,
+                                jint j_max,
+                                jint j_num_buckets) {
+  int sample = static_cast<int>(j_sample);
+
+  g_histograms.Get()
+      .CustomCountHistogram(env, j_histogram_name, j_histogram_key, j_min,
+                            j_max, j_num_buckets)
+      ->Add(sample);
+}
+
+void RecordSparseHistogram(JNIEnv* env,
+                                 jclass clazz,
+                                 jstring j_histogram_name,
+                                 jint j_histogram_key,
+                                 jint j_sample) {
+    int sample = static_cast<int>(j_sample);
+    g_histograms.Get()
+        .SparseHistogram(env, j_histogram_name, j_histogram_key)
+        ->Add(sample);
+}
+
+void RecordCustomTimesHistogramMilliseconds(JNIEnv* env,
+                                            jclass clazz,
+                                            jstring j_histogram_name,
+                                            jint j_histogram_key,
+                                            jlong j_duration,
+                                            jlong j_min,
+                                            jlong j_max,
+                                            jint j_num_buckets) {
+  g_histograms.Get()
+      .CustomTimesHistogram(env, j_histogram_name, j_histogram_key, j_min,
+                            j_max, j_num_buckets)
+      ->AddTime(TimeDelta::FromMilliseconds(static_cast<int64>(j_duration)));
+}
+
+void Initialize(JNIEnv* env, jclass) {
+  StatisticsRecorder::Initialize();
+}
+
+// This backs a Java test util for testing histograms -
+// MetricsUtils.HistogramDelta. It should live in a test-specific file, but we
+// currently can't have test-specific native code packaged in test-specific Java
+// targets - see http://crbug.com/415945.
+jint GetHistogramValueCountForTesting(JNIEnv* env,
+                                      jclass clazz,
+                                      jstring histogram_name,
+                                      jint sample) {
+  HistogramBase* histogram = StatisticsRecorder::FindHistogram(
+      android::ConvertJavaStringToUTF8(env, histogram_name));
+  if (histogram == nullptr) {
+    // No samples have been recorded for this histogram (yet?).
+    return 0;
+  }
+
+  scoped_ptr<HistogramSamples> samples = histogram->SnapshotSamples();
+  return samples->GetCount(static_cast<int>(sample));
+}
+
+bool RegisterRecordHistogram(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/record_histogram.h b/base/android/record_histogram.h
new file mode 100644
index 0000000..caa10f0
--- /dev/null
+++ b/base/android/record_histogram.h
@@ -0,0 +1,18 @@
+// 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.
+
+#ifndef BASE_ANDROID_RECORD_HISTOGRAM_H_
+#define BASE_ANDROID_RECORD_HISTOGRAM_H_
+
+#include <jni.h>
+
+namespace base {
+namespace android {
+
+bool RegisterRecordHistogram(JNIEnv* env);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_RECORD_HISTOGRAM_H_
diff --git a/base/android/record_user_action.cc b/base/android/record_user_action.cc
new file mode 100644
index 0000000..6172f2e
--- /dev/null
+++ b/base/android/record_user_action.cc
@@ -0,0 +1,24 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/record_user_action.h"
+
+#include "base/android/jni_string.h"
+#include "base/metrics/user_metrics.h"
+#include "jni/RecordUserAction_jni.h"
+
+namespace base {
+namespace android {
+
+static void RecordUserAction(JNIEnv* env, jclass clazz, jstring j_action) {
+  RecordComputedAction(ConvertJavaStringToUTF8(env, j_action));
+}
+
+// Register native methods
+bool RegisterRecordUserAction(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/record_user_action.h b/base/android/record_user_action.h
new file mode 100644
index 0000000..2c2b854
--- /dev/null
+++ b/base/android/record_user_action.h
@@ -0,0 +1,19 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_RECORD_USER_ACTION_H_
+#define BASE_ANDROID_RECORD_USER_ACTION_H_
+
+#include <jni.h>
+
+namespace base {
+namespace android {
+
+// Registers the native methods through jni
+bool RegisterRecordUserAction(JNIEnv* env);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_RECORD_USER_ACTION_H_
diff --git a/base/android/scoped_java_ref.cc b/base/android/scoped_java_ref.cc
new file mode 100644
index 0000000..bb6f503
--- /dev/null
+++ b/base/android/scoped_java_ref.cc
@@ -0,0 +1,91 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/scoped_java_ref.h"
+
+#include "base/android/jni_android.h"
+#include "base/logging.h"
+
+namespace base {
+namespace android {
+namespace {
+
+const int kDefaultLocalFrameCapacity = 16;
+
+}  // namespace
+
+ScopedJavaLocalFrame::ScopedJavaLocalFrame(JNIEnv* env) : env_(env) {
+  int failed = env_->PushLocalFrame(kDefaultLocalFrameCapacity);
+  DCHECK(!failed);
+}
+
+ScopedJavaLocalFrame::ScopedJavaLocalFrame(JNIEnv* env, int capacity)
+    : env_(env) {
+  int failed = env_->PushLocalFrame(capacity);
+  DCHECK(!failed);
+}
+
+ScopedJavaLocalFrame::~ScopedJavaLocalFrame() { env_->PopLocalFrame(NULL); }
+
+JavaRef<jobject>::JavaRef() : obj_(NULL) {}
+
+JavaRef<jobject>::JavaRef(JNIEnv* env, jobject obj) : obj_(obj) {
+  if (obj) {
+    DCHECK(env && env->GetObjectRefType(obj) == JNILocalRefType);
+  }
+}
+
+JavaRef<jobject>::~JavaRef() {
+}
+
+JNIEnv* JavaRef<jobject>::SetNewLocalRef(JNIEnv* env, jobject obj) {
+  if (!env) {
+    env = AttachCurrentThread();
+  } else {
+    DCHECK_EQ(env, AttachCurrentThread());  // Is |env| on correct thread.
+  }
+  if (obj)
+    obj = env->NewLocalRef(obj);
+  if (obj_)
+    env->DeleteLocalRef(obj_);
+  obj_ = obj;
+  return env;
+}
+
+void JavaRef<jobject>::SetNewGlobalRef(JNIEnv* env, jobject obj) {
+  if (!env) {
+    env = AttachCurrentThread();
+  } else {
+    DCHECK_EQ(env, AttachCurrentThread());  // Is |env| on correct thread.
+  }
+  if (obj)
+    obj = env->NewGlobalRef(obj);
+  if (obj_)
+    env->DeleteGlobalRef(obj_);
+  obj_ = obj;
+}
+
+void JavaRef<jobject>::ResetLocalRef(JNIEnv* env) {
+  if (obj_) {
+    DCHECK_EQ(env, AttachCurrentThread());  // Is |env| on correct thread.
+    env->DeleteLocalRef(obj_);
+    obj_ = NULL;
+  }
+}
+
+void JavaRef<jobject>::ResetGlobalRef() {
+  if (obj_) {
+    AttachCurrentThread()->DeleteGlobalRef(obj_);
+    obj_ = NULL;
+  }
+}
+
+jobject JavaRef<jobject>::ReleaseInternal() {
+  jobject obj = obj_;
+  obj_ = NULL;
+  return obj;
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/scoped_java_ref.h b/base/android/scoped_java_ref.h
new file mode 100644
index 0000000..8047ee8
--- /dev/null
+++ b/base/android/scoped_java_ref.h
@@ -0,0 +1,217 @@
+// Copyright (c) 2012 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_SCOPED_JAVA_REF_H_
+#define BASE_ANDROID_SCOPED_JAVA_REF_H_
+
+#include <jni.h>
+#include <stddef.h>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace android {
+
+// Creates a new local reference frame, in which at least a given number of
+// local references can be created. Note that local references already created
+// in previous local frames are still valid in the current local frame.
+class BASE_EXPORT ScopedJavaLocalFrame {
+ public:
+  explicit ScopedJavaLocalFrame(JNIEnv* env);
+  ScopedJavaLocalFrame(JNIEnv* env, int capacity);
+  ~ScopedJavaLocalFrame();
+
+ private:
+  // This class is only good for use on the thread it was created on so
+  // it's safe to cache the non-threadsafe JNIEnv* inside this object.
+  JNIEnv* env_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedJavaLocalFrame);
+};
+
+// Forward declare the generic java reference template class.
+template<typename T> class JavaRef;
+
+// Template specialization of JavaRef, which acts as the base class for all
+// other JavaRef<> template types. This allows you to e.g. pass
+// ScopedJavaLocalRef<jstring> into a function taking const JavaRef<jobject>&
+template<>
+class BASE_EXPORT JavaRef<jobject> {
+ public:
+  jobject obj() const { return obj_; }
+
+  bool is_null() const { return obj_ == NULL; }
+
+ protected:
+  // Initializes a NULL reference.
+  JavaRef();
+
+  // Takes ownership of the |obj| reference passed; requires it to be a local
+  // reference type.
+  JavaRef(JNIEnv* env, jobject obj);
+
+  ~JavaRef();
+
+  // The following are implementation detail convenience methods, for
+  // use by the sub-classes.
+  JNIEnv* SetNewLocalRef(JNIEnv* env, jobject obj);
+  void SetNewGlobalRef(JNIEnv* env, jobject obj);
+  void ResetLocalRef(JNIEnv* env);
+  void ResetGlobalRef();
+  jobject ReleaseInternal();
+
+ private:
+  jobject obj_;
+
+  DISALLOW_COPY_AND_ASSIGN(JavaRef);
+};
+
+// Generic base class for ScopedJavaLocalRef and ScopedJavaGlobalRef. Useful
+// for allowing functions to accept a reference without having to mandate
+// whether it is a local or global type.
+template<typename T>
+class JavaRef : public JavaRef<jobject> {
+ public:
+  T obj() const { return static_cast<T>(JavaRef<jobject>::obj()); }
+
+ protected:
+  JavaRef() {}
+  ~JavaRef() {}
+
+  JavaRef(JNIEnv* env, T obj) : JavaRef<jobject>(env, obj) {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(JavaRef);
+};
+
+// Holds a local reference to a Java object. The local reference is scoped
+// to the lifetime of this object.
+// Instances of this class may hold onto any JNIEnv passed into it until
+// destroyed. Therefore, since a JNIEnv is only suitable for use on a single
+// thread, objects of this class must be created, used, and destroyed, on a
+// single thread.
+// Therefore, this class should only be used as a stack-based object and from a
+// single thread. If you wish to have the reference outlive the current
+// callstack (e.g. as a class member) or you wish to pass it across threads,
+// use a ScopedJavaGlobalRef instead.
+template<typename T>
+class ScopedJavaLocalRef : public JavaRef<T> {
+ public:
+  ScopedJavaLocalRef() : env_(NULL) {}
+
+  // Non-explicit copy constructor, to allow ScopedJavaLocalRef to be returned
+  // by value as this is the normal usage pattern.
+  ScopedJavaLocalRef(const ScopedJavaLocalRef<T>& other)
+      : env_(other.env_) {
+    this->SetNewLocalRef(env_, other.obj());
+  }
+
+  template<typename U>
+  explicit ScopedJavaLocalRef(const U& other)
+      : env_(NULL) {
+    this->Reset(other);
+  }
+
+  // Assumes that |obj| is a local reference to a Java object and takes
+  // ownership  of this local reference.
+  ScopedJavaLocalRef(JNIEnv* env, T obj) : JavaRef<T>(env, obj), env_(env) {}
+
+  ~ScopedJavaLocalRef() {
+    this->Reset();
+  }
+
+  // Overloaded assignment operator defined for consistency with the implicit
+  // copy constructor.
+  void operator=(const ScopedJavaLocalRef<T>& other) {
+    this->Reset(other);
+  }
+
+  void Reset() {
+    this->ResetLocalRef(env_);
+  }
+
+  template<typename U>
+  void Reset(const ScopedJavaLocalRef<U>& other) {
+    // We can copy over env_ here as |other| instance must be from the same
+    // thread as |this| local ref. (See class comment for multi-threading
+    // limitations, and alternatives).
+    this->Reset(other.env_, other.obj());
+  }
+
+  template<typename U>
+  void Reset(const U& other) {
+    // If |env_| was not yet set (is still NULL) it will be attached to the
+    // current thread in SetNewLocalRef().
+    this->Reset(env_, other.obj());
+  }
+
+  template<typename U>
+  void Reset(JNIEnv* env, U obj) {
+    implicit_cast<T>(obj);  // Ensure U is assignable to T
+    env_ = this->SetNewLocalRef(env, obj);
+  }
+
+  // Releases the local reference to the caller. The caller *must* delete the
+  // local reference when it is done with it.
+  T Release() {
+    return static_cast<T>(this->ReleaseInternal());
+  }
+
+ private:
+  // This class is only good for use on the thread it was created on so
+  // it's safe to cache the non-threadsafe JNIEnv* inside this object.
+  JNIEnv* env_;
+};
+
+// Holds a global reference to a Java object. The global reference is scoped
+// to the lifetime of this object. This class does not hold onto any JNIEnv*
+// passed to it, hence it is safe to use across threads (within the constraints
+// imposed by the underlying Java object that it references).
+template<typename T>
+class ScopedJavaGlobalRef : public JavaRef<T> {
+ public:
+  ScopedJavaGlobalRef() {}
+
+  explicit ScopedJavaGlobalRef(const ScopedJavaGlobalRef<T>& other) {
+    this->Reset(other);
+  }
+
+  ScopedJavaGlobalRef(JNIEnv* env, T obj) { this->Reset(env, obj); }
+
+  template<typename U>
+  explicit ScopedJavaGlobalRef(const U& other) {
+    this->Reset(other);
+  }
+
+  ~ScopedJavaGlobalRef() {
+    this->Reset();
+  }
+
+  void Reset() {
+    this->ResetGlobalRef();
+  }
+
+  template<typename U>
+  void Reset(const U& other) {
+    this->Reset(NULL, other.obj());
+  }
+
+  template<typename U>
+  void Reset(JNIEnv* env, U obj) {
+    implicit_cast<T>(obj);  // Ensure U is assignable to T
+    this->SetNewGlobalRef(env, obj);
+  }
+
+  // Releases the global reference to the caller. The caller *must* delete the
+  // global reference when it is done with it.
+  T Release() {
+    return static_cast<T>(this->ReleaseInternal());
+  }
+};
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_SCOPED_JAVA_REF_H_
diff --git a/base/android/scoped_java_ref_unittest.cc b/base/android/scoped_java_ref_unittest.cc
new file mode 100644
index 0000000..3f4419a
--- /dev/null
+++ b/base/android/scoped_java_ref_unittest.cc
@@ -0,0 +1,122 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/scoped_java_ref.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace android {
+
+namespace {
+int g_local_refs = 0;
+int g_global_refs = 0;
+
+const JNINativeInterface* g_previous_functions;
+
+jobject NewGlobalRef(JNIEnv* env, jobject obj) {
+  ++g_global_refs;
+  return g_previous_functions->NewGlobalRef(env, obj);
+}
+
+void DeleteGlobalRef(JNIEnv* env, jobject obj) {
+  --g_global_refs;
+  return g_previous_functions->DeleteGlobalRef(env, obj);
+}
+
+jobject NewLocalRef(JNIEnv* env, jobject obj) {
+  ++g_local_refs;
+  return g_previous_functions->NewLocalRef(env, obj);
+}
+
+void DeleteLocalRef(JNIEnv* env, jobject obj) {
+  --g_local_refs;
+  return g_previous_functions->DeleteLocalRef(env, obj);
+}
+}  // namespace
+
+class ScopedJavaRefTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    g_local_refs = 0;
+    g_global_refs = 0;
+    JNIEnv* env = AttachCurrentThread();
+    g_previous_functions = env->functions;
+    hooked_functions = *g_previous_functions;
+    env->functions = &hooked_functions;
+    // We inject our own functions in JNINativeInterface so we can keep track
+    // of the reference counting ourselves.
+    hooked_functions.NewGlobalRef = &NewGlobalRef;
+    hooked_functions.DeleteGlobalRef = &DeleteGlobalRef;
+    hooked_functions.NewLocalRef = &NewLocalRef;
+    hooked_functions.DeleteLocalRef = &DeleteLocalRef;
+  }
+
+  void TearDown() override {
+    JNIEnv* env = AttachCurrentThread();
+    env->functions = g_previous_functions;
+  }
+  // From JellyBean release, the instance of this struct provided in JNIEnv is
+  // read-only, so we deep copy it to allow individual functions to be hooked.
+  JNINativeInterface hooked_functions;
+};
+
+// The main purpose of this is testing the various conversions compile.
+TEST_F(ScopedJavaRefTest, Conversions) {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jstring> str = ConvertUTF8ToJavaString(env, "string");
+  ScopedJavaGlobalRef<jstring> global(str);
+  {
+    ScopedJavaGlobalRef<jobject> global_obj(str);
+    ScopedJavaLocalRef<jobject> local_obj(global);
+    const JavaRef<jobject>& obj_ref1(str);
+    const JavaRef<jobject>& obj_ref2(global);
+    EXPECT_TRUE(env->IsSameObject(obj_ref1.obj(), obj_ref2.obj()));
+    EXPECT_TRUE(env->IsSameObject(global_obj.obj(), obj_ref2.obj()));
+  }
+  global.Reset(str);
+  const JavaRef<jstring>& str_ref = str;
+  EXPECT_EQ("string", ConvertJavaStringToUTF8(str_ref));
+  str.Reset();
+}
+
+TEST_F(ScopedJavaRefTest, RefCounts) {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jstring> str;
+  // The ConvertJavaStringToUTF8 below creates a new string that would normally
+  // return a local ref. We simulate that by starting the g_local_refs count at
+  // 1.
+  g_local_refs = 1;
+  str.Reset(ConvertUTF8ToJavaString(env, "string"));
+  EXPECT_EQ(1, g_local_refs);
+  EXPECT_EQ(0, g_global_refs);
+  {
+    ScopedJavaGlobalRef<jstring> global_str(str);
+    ScopedJavaGlobalRef<jobject> global_obj(global_str);
+    EXPECT_EQ(1, g_local_refs);
+    EXPECT_EQ(2, g_global_refs);
+
+    ScopedJavaLocalRef<jstring> str2(env, str.Release());
+    EXPECT_EQ(1, g_local_refs);
+    {
+      ScopedJavaLocalRef<jstring> str3(str2);
+      EXPECT_EQ(2, g_local_refs);
+    }
+    EXPECT_EQ(1, g_local_refs);
+    str2.Reset();
+    EXPECT_EQ(0, g_local_refs);
+    global_str.Reset();
+    EXPECT_EQ(1, g_global_refs);
+    ScopedJavaGlobalRef<jobject> global_obj2(global_obj);
+    EXPECT_EQ(2, g_global_refs);
+  }
+
+  EXPECT_EQ(0, g_local_refs);
+  EXPECT_EQ(0, g_global_refs);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/sys_utils.cc b/base/android/sys_utils.cc
new file mode 100644
index 0000000..e89c1b3
--- /dev/null
+++ b/base/android/sys_utils.cc
@@ -0,0 +1,25 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/sys_utils.h"
+
+#include "base/android/build_info.h"
+#include "base/sys_info.h"
+#include "jni/SysUtils_jni.h"
+
+namespace base {
+namespace android {
+
+bool SysUtils::Register(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+bool SysUtils::IsLowEndDeviceFromJni() {
+  JNIEnv* env = AttachCurrentThread();
+  return Java_SysUtils_isLowEndDevice(env);
+}
+
+}  // namespace android
+
+}  // namespace base
\ No newline at end of file
diff --git a/base/android/sys_utils.h b/base/android/sys_utils.h
new file mode 100644
index 0000000..85dc035
--- /dev/null
+++ b/base/android/sys_utils.h
@@ -0,0 +1,24 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ANDROID_SYS_UTILS_H_
+#define BASE_ANDROID_SYS_UTILS_H_
+
+#include "base/android/jni_android.h"
+
+namespace base {
+namespace android {
+
+class BASE_EXPORT SysUtils {
+ public:
+  static bool Register(JNIEnv* env);
+
+  // Returns true iff this is a low-end device.
+  static bool IsLowEndDeviceFromJni();
+};
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_SYS_UTILS_H_
diff --git a/base/android/sys_utils_unittest.cc b/base/android/sys_utils_unittest.cc
new file mode 100644
index 0000000..d1421ec
--- /dev/null
+++ b/base/android/sys_utils_unittest.cc
@@ -0,0 +1,23 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <unistd.h>
+
+#include "base/sys_info.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace android {
+
+TEST(SysUtils, AmountOfPhysicalMemory) {
+  // Check that the RAM size reported by sysconf() matches the one
+  // computed by base::SysInfo::AmountOfPhysicalMemory().
+  size_t sys_ram_size =
+      static_cast<size_t>(sysconf(_SC_PHYS_PAGES) * PAGE_SIZE);
+  EXPECT_EQ(sys_ram_size,
+            static_cast<size_t>(SysInfo::AmountOfPhysicalMemory()));
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/thread_utils.h b/base/android/thread_utils.h
new file mode 100644
index 0000000..cbe65f0
--- /dev/null
+++ b/base/android/thread_utils.h
@@ -0,0 +1,16 @@
+// Copyright (c) 2012 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_THREAD_UTILS_H_
+#define BASE_ANDROID_THREAD_UTILS_H_
+
+#include "base/android/jni_android.h"
+
+namespace base {
+
+bool RegisterThreadUtils(JNIEnv* env);
+
+}  // namespace base
+
+#endif  // BASE_ANDROID_THREAD_UTILS_H_
diff --git a/base/android/trace_event_binding.cc b/base/android/trace_event_binding.cc
new file mode 100644
index 0000000..791b67f
--- /dev/null
+++ b/base/android/trace_event_binding.cc
@@ -0,0 +1,148 @@
+// 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.
+
+#include "base/android/trace_event_binding.h"
+
+#include <jni.h>
+
+#include <set>
+
+#include "base/lazy_instance.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_impl.h"
+#include "jni/TraceEvent_jni.h"
+
+namespace base {
+namespace android {
+
+namespace {
+
+const char kJavaCategory[] = "Java";
+const char kToplevelCategory[] = "toplevel";
+const char kLooperDispatchMessage[] = "Looper.dispatchMessage";
+
+// Boilerplate for safely converting Java data to TRACE_EVENT data.
+class TraceEventDataConverter {
+ public:
+  TraceEventDataConverter(JNIEnv* env,
+                          jstring jname,
+                          jstring jarg)
+      : env_(env),
+        jname_(jname),
+        jarg_(jarg),
+        name_(env->GetStringUTFChars(jname, NULL)),
+        arg_(jarg ? env->GetStringUTFChars(jarg, NULL) : NULL) {
+  }
+  ~TraceEventDataConverter() {
+    env_->ReleaseStringUTFChars(jname_, name_);
+    if (jarg_)
+      env_->ReleaseStringUTFChars(jarg_, arg_);
+  }
+
+  // Return saves values to pass to TRACE_EVENT macros.
+  const char* name() { return name_; }
+  const char* arg_name() { return arg_ ? "arg" : NULL; }
+  const char* arg() { return arg_; }
+
+ private:
+  JNIEnv* env_;
+  jstring jname_;
+  jstring jarg_;
+  const char* name_;
+  const char* arg_;
+
+  DISALLOW_COPY_AND_ASSIGN(TraceEventDataConverter);
+};
+
+class TraceEnabledObserver
+    : public trace_event::TraceLog::EnabledStateObserver {
+  public:
+   void OnTraceLogEnabled() override {
+      JNIEnv* env = base::android::AttachCurrentThread();
+      base::android::Java_TraceEvent_setEnabled(env, true);
+    }
+    void OnTraceLogDisabled() override {
+      JNIEnv* env = base::android::AttachCurrentThread();
+      base::android::Java_TraceEvent_setEnabled(env, false);
+    }
+};
+
+base::LazyInstance<TraceEnabledObserver>::Leaky g_trace_enabled_state_observer_;
+
+}  // namespace
+
+static void RegisterEnabledObserver(JNIEnv* env, jclass clazz) {
+  bool enabled = trace_event::TraceLog::GetInstance()->IsEnabled();
+  base::android::Java_TraceEvent_setEnabled(env, enabled);
+  trace_event::TraceLog::GetInstance()->AddEnabledStateObserver(
+      g_trace_enabled_state_observer_.Pointer());
+}
+
+static void StartATrace(JNIEnv* env, jclass clazz) {
+  base::trace_event::TraceLog::GetInstance()->StartATrace();
+}
+
+static void StopATrace(JNIEnv* env, jclass clazz) {
+  base::trace_event::TraceLog::GetInstance()->StopATrace();
+}
+
+static void Instant(JNIEnv* env, jclass clazz,
+                    jstring jname, jstring jarg) {
+  TraceEventDataConverter converter(env, jname, jarg);
+  if (converter.arg()) {
+    TRACE_EVENT_COPY_INSTANT1(kJavaCategory, converter.name(),
+                              TRACE_EVENT_SCOPE_THREAD,
+                              converter.arg_name(), converter.arg());
+  } else {
+    TRACE_EVENT_COPY_INSTANT0(kJavaCategory, converter.name(),
+                              TRACE_EVENT_SCOPE_THREAD);
+  }
+}
+
+static void Begin(JNIEnv* env, jclass clazz,
+                  jstring jname, jstring jarg) {
+  TraceEventDataConverter converter(env, jname, jarg);
+  if (converter.arg()) {
+    TRACE_EVENT_COPY_BEGIN1(kJavaCategory, converter.name(),
+                       converter.arg_name(), converter.arg());
+  } else {
+    TRACE_EVENT_COPY_BEGIN0(kJavaCategory, converter.name());
+  }
+}
+
+static void End(JNIEnv* env, jclass clazz,
+                jstring jname, jstring jarg) {
+  TraceEventDataConverter converter(env, jname, jarg);
+  if (converter.arg()) {
+    TRACE_EVENT_COPY_END1(kJavaCategory, converter.name(),
+                     converter.arg_name(), converter.arg());
+  } else {
+    TRACE_EVENT_COPY_END0(kJavaCategory, converter.name());
+  }
+}
+
+static void BeginToplevel(JNIEnv* env, jclass clazz) {
+  TRACE_EVENT_BEGIN0(kToplevelCategory, kLooperDispatchMessage);
+}
+
+static void EndToplevel(JNIEnv* env, jclass clazz) {
+  TRACE_EVENT_END0(kToplevelCategory, kLooperDispatchMessage);
+}
+
+static void StartAsync(JNIEnv* env, jclass clazz, jstring jname, jlong jid) {
+  TraceEventDataConverter converter(env, jname, nullptr);
+  TRACE_EVENT_COPY_ASYNC_BEGIN0(kJavaCategory, converter.name(), jid);
+}
+
+static void FinishAsync(JNIEnv* env, jclass clazz, jstring jname, jlong jid) {
+  TraceEventDataConverter converter(env, jname, nullptr);
+  TRACE_EVENT_COPY_ASYNC_END0(kJavaCategory, converter.name(), jid);
+}
+
+bool RegisterTraceEvent(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace android
+}  // namespace base
diff --git a/base/android/trace_event_binding.h b/base/android/trace_event_binding.h
new file mode 100644
index 0000000..1c1a60b
--- /dev/null
+++ b/base/android/trace_event_binding.h
@@ -0,0 +1,18 @@
+// 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.
+
+#ifndef BASE_ANDROID_TRACE_EVENT_BINDING_H_
+#define BASE_ANDROID_TRACE_EVENT_BINDING_H_
+
+#include <jni.h>
+
+namespace base {
+namespace android {
+
+extern bool RegisterTraceEvent(JNIEnv* env);
+
+}  // namespace android
+}  // namespace base
+
+#endif  // BASE_ANDROID_TRACE_EVENT_BINDING_H_
diff --git a/base/async_socket_io_handler.h b/base/async_socket_io_handler.h
new file mode 100644
index 0000000..a22c29d
--- /dev/null
+++ b/base/async_socket_io_handler.h
@@ -0,0 +1,110 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ASYNC_SOCKET_IO_HANDLER_H_
+#define BASE_ASYNC_SOCKET_IO_HANDLER_H_
+
+#include "base/message_loop/message_loop.h"
+#include "base/sync_socket.h"
+#include "base/threading/non_thread_safe.h"
+
+namespace base {
+
+// Extends the CancelableSyncSocket class to allow reading from a socket
+// asynchronously on a TYPE_IO message loop thread.  This makes it easy to share
+// a thread that uses a message loop (e.g. for IPC and other things) and not
+// require a separate thread to read from the socket.
+//
+// Example usage (also see the unit tests):
+//
+// class SocketReader {
+//  public:
+//   SocketReader(base::CancelableSyncSocket* socket)
+//       : socket_(socket), buffer_() {
+//     io_handler.Initialize(socket_->handle(),
+//                           base::Bind(&SocketReader::OnDataAvailable,
+//                                      base::Unretained(this));
+//   }
+//
+//   void AsyncRead() {
+//     CHECK(io_handler.Read(&buffer_[0], sizeof(buffer_)));
+//   }
+//
+//  private:
+//   void OnDataAvailable(int bytes_read) {
+//     if (ProcessData(&buffer_[0], bytes_read)) {
+//       // Issue another read.
+//       CHECK(io_handler.Read(&buffer_[0], sizeof(buffer_)));
+//     }
+//   }
+//
+//   base::AsyncSocketIoHandler io_handler;
+//   base::CancelableSyncSocket* socket_;
+//   char buffer_[kBufferSize];
+// };
+//
+class BASE_EXPORT AsyncSocketIoHandler
+    : public NON_EXPORTED_BASE(base::NonThreadSafe),
+// The message loop callback interface is different based on platforms.
+#if defined(OS_WIN)
+      public NON_EXPORTED_BASE(base::MessageLoopForIO::IOHandler) {
+#else
+      public NON_EXPORTED_BASE(base::MessageLoopForIO::Watcher) {
+#endif
+ public:
+  AsyncSocketIoHandler();
+  ~AsyncSocketIoHandler() override;
+
+  // Type definition for the callback. The parameter tells how many
+  // bytes were read and is 0 if an error occurred.
+  typedef base::Callback<void(int)> ReadCompleteCallback;
+
+  // Initializes the AsyncSocketIoHandler by hooking it up to the current
+  // thread's message loop (must be TYPE_IO), to do async reads from the socket
+  // on the current thread.  The |callback| will be invoked whenever a Read()
+  // has completed.
+  bool Initialize(base::SyncSocket::Handle socket,
+                  const ReadCompleteCallback& callback);
+
+  // Attempts to read from the socket.  The return value will be |false|
+  // if an error occurred and |true| if data was read or a pending read
+  // was issued.  Regardless of async or sync operation, the
+  // ReadCompleteCallback (see above) will be called when data is available.
+  bool Read(char* buffer, int buffer_len);
+
+ private:
+#if defined(OS_WIN)
+  // Implementation of IOHandler on Windows.
+  void OnIOCompleted(base::MessageLoopForIO::IOContext* context,
+                     DWORD bytes_transfered,
+                     DWORD error) override;
+#elif defined(OS_POSIX)
+  // Implementation of base::MessageLoopForIO::Watcher.
+  void OnFileCanWriteWithoutBlocking(int socket) override {}
+  void OnFileCanReadWithoutBlocking(int socket) override;
+
+  void EnsureWatchingSocket();
+#endif
+
+  base::SyncSocket::Handle socket_;
+#if defined(OS_WIN)
+  base::MessageLoopForIO::IOContext* context_;
+  bool is_pending_;
+#elif defined(OS_POSIX)
+  base::MessageLoopForIO::FileDescriptorWatcher socket_watcher_;
+  // |pending_buffer_| and |pending_buffer_len_| are valid only between
+  // Read() and OnFileCanReadWithoutBlocking().
+  char* pending_buffer_;
+  int pending_buffer_len_;
+  // |true| iff the message loop is watching the socket for IO events.
+  bool is_watching_;
+#endif
+  ReadCompleteCallback read_complete_;
+
+  DISALLOW_COPY_AND_ASSIGN(AsyncSocketIoHandler);
+};
+
+}  // namespace base.
+
+#endif  // BASE_ASYNC_SOCKET_IO_HANDLER_H_
diff --git a/base/async_socket_io_handler_posix.cc b/base/async_socket_io_handler_posix.cc
new file mode 100644
index 0000000..2fffb84
--- /dev/null
+++ b/base/async_socket_io_handler_posix.cc
@@ -0,0 +1,98 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/async_socket_io_handler.h"
+
+#include <fcntl.h>
+
+#include "base/posix/eintr_wrapper.h"
+
+namespace base {
+
+AsyncSocketIoHandler::AsyncSocketIoHandler()
+    : socket_(base::SyncSocket::kInvalidHandle),
+      pending_buffer_(NULL),
+      pending_buffer_len_(0),
+      is_watching_(false) {
+}
+
+AsyncSocketIoHandler::~AsyncSocketIoHandler() {
+  DCHECK(CalledOnValidThread());
+}
+
+void AsyncSocketIoHandler::OnFileCanReadWithoutBlocking(int socket) {
+  DCHECK(CalledOnValidThread());
+  DCHECK_EQ(socket, socket_);
+  DCHECK(!read_complete_.is_null());
+
+  if (pending_buffer_) {
+    int bytes_read = HANDLE_EINTR(read(socket_, pending_buffer_,
+                                       pending_buffer_len_));
+    DCHECK_GE(bytes_read, 0);
+    pending_buffer_ = NULL;
+    pending_buffer_len_ = 0;
+    read_complete_.Run(bytes_read > 0 ? bytes_read : 0);
+  } else {
+    // We're getting notifications that we can read from the socket while
+    // we're not waiting for data.  In order to not starve the message loop,
+    // let's stop watching the fd and restart the watch when Read() is called.
+    is_watching_ = false;
+    socket_watcher_.StopWatchingFileDescriptor();
+  }
+}
+
+bool AsyncSocketIoHandler::Read(char* buffer, int buffer_len) {
+  DCHECK(CalledOnValidThread());
+  DCHECK(!read_complete_.is_null());
+  DCHECK(!pending_buffer_);
+
+  EnsureWatchingSocket();
+
+  int bytes_read = HANDLE_EINTR(read(socket_, buffer, buffer_len));
+  if (bytes_read < 0) {
+    if (errno == EAGAIN) {
+      pending_buffer_ = buffer;
+      pending_buffer_len_ = buffer_len;
+    } else {
+      NOTREACHED() << "read(): " << errno;
+      return false;
+    }
+  } else {
+    read_complete_.Run(bytes_read);
+  }
+  return true;
+}
+
+bool AsyncSocketIoHandler::Initialize(base::SyncSocket::Handle socket,
+                                      const ReadCompleteCallback& callback) {
+  DCHECK_EQ(socket_, base::SyncSocket::kInvalidHandle);
+
+  DetachFromThread();
+
+  socket_ = socket;
+  read_complete_ = callback;
+
+  // SyncSocket is blocking by default, so let's convert it to non-blocking.
+  int value = fcntl(socket, F_GETFL);
+  if (!(value & O_NONBLOCK)) {
+    // Set the socket to be non-blocking so we can do async reads.
+    if (fcntl(socket, F_SETFL, O_NONBLOCK) == -1) {
+      NOTREACHED();
+      return false;
+    }
+  }
+
+  return true;
+}
+
+void AsyncSocketIoHandler::EnsureWatchingSocket() {
+  DCHECK(CalledOnValidThread());
+  if (!is_watching_ && socket_ != base::SyncSocket::kInvalidHandle) {
+    is_watching_ = base::MessageLoopForIO::current()->WatchFileDescriptor(
+        socket_, true, base::MessageLoopForIO::WATCH_READ,
+        &socket_watcher_, this);
+  }
+}
+
+}  // namespace base.
diff --git a/base/async_socket_io_handler_unittest.cc b/base/async_socket_io_handler_unittest.cc
new file mode 100644
index 0000000..721de9c
--- /dev/null
+++ b/base/async_socket_io_handler_unittest.cc
@@ -0,0 +1,171 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/async_socket_io_handler.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+const char kAsyncSocketIoTestString[] = "Hello, AsyncSocketIoHandler";
+const size_t kAsyncSocketIoTestStringLength =
+    arraysize(kAsyncSocketIoTestString);
+
+class TestSocketReader {
+ public:
+  // Set |number_of_reads_before_quit| to >0 when you expect a specific number
+  // of Read operations to complete.  Once that number is reached, the current
+  // message loop will be Quit().  Set |number_of_reads_before_quit| to -1 if
+  // callbacks should not be counted.
+  TestSocketReader(base::CancelableSyncSocket* socket,
+                   int number_of_reads_before_quit,
+                   bool issue_reads_from_callback,
+                   bool expect_eof)
+      : socket_(socket), buffer_(),
+        number_of_reads_before_quit_(number_of_reads_before_quit),
+        callbacks_received_(0),
+        issue_reads_from_callback_(issue_reads_from_callback),
+        expect_eof_(expect_eof) {
+    io_handler.Initialize(socket_->handle(),
+                          base::Bind(&TestSocketReader::OnRead,
+                                     base::Unretained(this)));
+  }
+  ~TestSocketReader() {}
+
+  bool IssueRead() {
+    return io_handler.Read(&buffer_[0], sizeof(buffer_));
+  }
+
+  const char* buffer() const { return &buffer_[0]; }
+
+  int callbacks_received() const { return callbacks_received_; }
+
+ private:
+  void OnRead(int bytes_read) {
+    if (!expect_eof_) {
+      EXPECT_GT(bytes_read, 0);
+    } else {
+      EXPECT_GE(bytes_read, 0);
+    }
+    ++callbacks_received_;
+    if (number_of_reads_before_quit_ == callbacks_received_) {
+      base::MessageLoop::current()->Quit();
+    } else if (issue_reads_from_callback_) {
+      IssueRead();
+    }
+  }
+
+  base::AsyncSocketIoHandler io_handler;
+  base::CancelableSyncSocket* socket_;  // Ownership lies outside the class.
+  char buffer_[kAsyncSocketIoTestStringLength];
+  int number_of_reads_before_quit_;
+  int callbacks_received_;
+  bool issue_reads_from_callback_;
+  bool expect_eof_;
+};
+
+// Workaround to be able to use a base::Closure for sending data.
+// Send() returns int but a closure must return void.
+void SendData(base::CancelableSyncSocket* socket,
+              const void* buffer,
+              size_t length) {
+  socket->Send(buffer, length);
+}
+
+}  // end namespace.
+
+// Tests doing a pending read from a socket and use an IO handler to get
+// notified of data.
+TEST(AsyncSocketIoHandlerTest, AsynchronousReadWithMessageLoop) {
+  base::MessageLoopForIO loop;
+
+  base::CancelableSyncSocket pair[2];
+  ASSERT_TRUE(base::CancelableSyncSocket::CreatePair(&pair[0], &pair[1]));
+
+  TestSocketReader reader(&pair[0], 1, false, false);
+  EXPECT_TRUE(reader.IssueRead());
+
+  pair[1].Send(kAsyncSocketIoTestString, kAsyncSocketIoTestStringLength);
+  base::MessageLoop::current()->Run();
+  EXPECT_EQ(strcmp(reader.buffer(), kAsyncSocketIoTestString), 0);
+  EXPECT_EQ(1, reader.callbacks_received());
+}
+
+// Tests doing a read from a socket when we know that there is data in the
+// socket.  Here we want to make sure that any async 'can read' notifications
+// won't trip us off and that the synchronous case works as well.
+TEST(AsyncSocketIoHandlerTest, SynchronousReadWithMessageLoop) {
+  base::MessageLoopForIO loop;
+
+  base::CancelableSyncSocket pair[2];
+  ASSERT_TRUE(base::CancelableSyncSocket::CreatePair(&pair[0], &pair[1]));
+
+  TestSocketReader reader(&pair[0], -1, false, false);
+
+  pair[1].Send(kAsyncSocketIoTestString, kAsyncSocketIoTestStringLength);
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, base::MessageLoop::QuitClosure(),
+      base::TimeDelta::FromMilliseconds(100));
+  base::MessageLoop::current()->Run();
+
+  EXPECT_TRUE(reader.IssueRead());
+  EXPECT_EQ(strcmp(reader.buffer(), kAsyncSocketIoTestString), 0);
+  // We've now verified that the read happened synchronously, but it's not
+  // guaranteed that the callback has been issued since the callback will be
+  // called asynchronously even though the read may have been done.
+  // So we call RunUntilIdle() to allow any event notifications or APC's on
+  // Windows, to execute before checking the count of how many callbacks we've
+  // received.
+  base::MessageLoop::current()->RunUntilIdle();
+  EXPECT_EQ(1, reader.callbacks_received());
+}
+
+// Calls Read() from within a callback to test that simple read "loops" work.
+TEST(AsyncSocketIoHandlerTest, ReadFromCallback) {
+  base::MessageLoopForIO loop;
+
+  base::CancelableSyncSocket pair[2];
+  ASSERT_TRUE(base::CancelableSyncSocket::CreatePair(&pair[0], &pair[1]));
+
+  const int kReadOperationCount = 10;
+  TestSocketReader reader(&pair[0], kReadOperationCount, true, false);
+  EXPECT_TRUE(reader.IssueRead());
+
+  // Issue sends on an interval to satisfy the Read() requirements.
+  int64 milliseconds = 0;
+  for (int i = 0; i < kReadOperationCount; ++i) {
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+        FROM_HERE, base::Bind(&SendData, &pair[1], kAsyncSocketIoTestString,
+                              kAsyncSocketIoTestStringLength),
+        base::TimeDelta::FromMilliseconds(milliseconds));
+    milliseconds += 10;
+  }
+
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, base::MessageLoop::QuitClosure(),
+      base::TimeDelta::FromMilliseconds(100 + milliseconds));
+
+  base::MessageLoop::current()->Run();
+  EXPECT_EQ(kReadOperationCount, reader.callbacks_received());
+}
+
+// Calls Read() then close other end, check that a correct callback is received.
+TEST(AsyncSocketIoHandlerTest, ReadThenClose) {
+  base::MessageLoopForIO loop;
+
+  base::CancelableSyncSocket pair[2];
+  ASSERT_TRUE(base::CancelableSyncSocket::CreatePair(&pair[0], &pair[1]));
+
+  const int kReadOperationCount = 1;
+  TestSocketReader reader(&pair[0], kReadOperationCount, false, true);
+  EXPECT_TRUE(reader.IssueRead());
+
+  pair[1].Close();
+
+  base::MessageLoop::current()->Run();
+  EXPECT_EQ(kReadOperationCount, reader.callbacks_received());
+}
diff --git a/base/async_socket_io_handler_win.cc b/base/async_socket_io_handler_win.cc
new file mode 100644
index 0000000..e1d215c
--- /dev/null
+++ b/base/async_socket_io_handler_win.cc
@@ -0,0 +1,77 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/async_socket_io_handler.h"
+
+namespace base {
+
+AsyncSocketIoHandler::AsyncSocketIoHandler()
+    : socket_(base::SyncSocket::kInvalidHandle),
+      context_(NULL),
+      is_pending_(false) {}
+
+AsyncSocketIoHandler::~AsyncSocketIoHandler() {
+  // We need to be deleted on the correct thread to avoid racing with the
+  // message loop thread.
+  DCHECK(CalledOnValidThread());
+
+  if (context_) {
+    if (is_pending_) {
+      // Make the context be deleted by the message pump when done.
+      context_->handler = NULL;
+    } else {
+      delete context_;
+    }
+  }
+}
+
+// Implementation of IOHandler on Windows.
+void AsyncSocketIoHandler::OnIOCompleted(
+    base::MessageLoopForIO::IOContext* context,
+    DWORD bytes_transfered,
+    DWORD error) {
+  DCHECK(CalledOnValidThread());
+  DCHECK_EQ(context_, context);
+  DCHECK(!read_complete_.is_null());
+  is_pending_ = false;
+  read_complete_.Run(error == ERROR_SUCCESS ? bytes_transfered : 0);
+}
+
+bool AsyncSocketIoHandler::Read(char* buffer, int buffer_len) {
+  DCHECK(CalledOnValidThread());
+  DCHECK(!read_complete_.is_null());
+  DCHECK(!is_pending_);
+  DCHECK_NE(socket_, base::SyncSocket::kInvalidHandle);
+
+  DWORD bytes_read = 0;
+  BOOL ok = ::ReadFile(socket_, buffer, buffer_len, &bytes_read,
+                       &context_->overlapped);
+  // The completion port will be signaled regardless of completing the read
+  // straight away or asynchronously (ERROR_IO_PENDING). OnIOCompleted() will
+  // be called regardless and we don't need to explicitly run the callback
+  // in the case where ok is FALSE and GLE==ERROR_IO_PENDING.
+  is_pending_ = !ok && (GetLastError() == ERROR_IO_PENDING);
+  return ok || is_pending_;
+}
+
+bool AsyncSocketIoHandler::Initialize(base::SyncSocket::Handle socket,
+                                      const ReadCompleteCallback& callback) {
+  DCHECK(!context_);
+  DCHECK_EQ(socket_, base::SyncSocket::kInvalidHandle);
+
+  DetachFromThread();
+
+  socket_ = socket;
+  read_complete_ = callback;
+
+  base::MessageLoopForIO::current()->RegisterIOHandler(socket, this);
+
+  context_ = new base::MessageLoopForIO::IOContext();
+  context_->handler = this;
+  memset(&context_->overlapped, 0, sizeof(context_->overlapped));
+
+  return true;
+}
+
+}  // namespace base.
diff --git a/base/at_exit.cc b/base/at_exit.cc
new file mode 100644
index 0000000..0fba355
--- /dev/null
+++ b/base/at_exit.cc
@@ -0,0 +1,82 @@
+// Copyright (c) 2011 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/at_exit.h"
+
+#include <stddef.h>
+#include <ostream>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/logging.h"
+
+namespace base {
+
+// Keep a stack of registered AtExitManagers.  We always operate on the most
+// recent, and we should never have more than one outside of testing (for a
+// statically linked version of this library).  Testing may use the shadow
+// version of the constructor, and if we are building a dynamic library we may
+// end up with multiple AtExitManagers on the same process.  We don't protect
+// this for thread-safe access, since it will only be modified in testing.
+static AtExitManager* g_top_manager = NULL;
+
+AtExitManager::AtExitManager() : next_manager_(g_top_manager) {
+// If multiple modules instantiate AtExitManagers they'll end up living in this
+// module... they have to coexist.
+#if !defined(COMPONENT_BUILD)
+  DCHECK(!g_top_manager);
+#endif
+  g_top_manager = this;
+}
+
+AtExitManager::~AtExitManager() {
+  if (!g_top_manager) {
+    NOTREACHED() << "Tried to ~AtExitManager without an AtExitManager";
+    return;
+  }
+  DCHECK_EQ(this, g_top_manager);
+
+  ProcessCallbacksNow();
+  g_top_manager = next_manager_;
+}
+
+// static
+void AtExitManager::RegisterCallback(AtExitCallbackType func, void* param) {
+  DCHECK(func);
+  RegisterTask(base::Bind(func, param));
+}
+
+// static
+void AtExitManager::RegisterTask(base::Closure task) {
+  if (!g_top_manager) {
+    NOTREACHED() << "Tried to RegisterCallback without an AtExitManager";
+    return;
+  }
+
+  AutoLock lock(g_top_manager->lock_);
+  g_top_manager->stack_.push(task);
+}
+
+// static
+void AtExitManager::ProcessCallbacksNow() {
+  if (!g_top_manager) {
+    NOTREACHED() << "Tried to ProcessCallbacksNow without an AtExitManager";
+    return;
+  }
+
+  AutoLock lock(g_top_manager->lock_);
+
+  while (!g_top_manager->stack_.empty()) {
+    base::Closure task = g_top_manager->stack_.top();
+    task.Run();
+    g_top_manager->stack_.pop();
+  }
+}
+
+AtExitManager::AtExitManager(bool shadow) : next_manager_(g_top_manager) {
+  DCHECK(shadow || !g_top_manager);
+  g_top_manager = this;
+}
+
+}  // namespace base
diff --git a/base/at_exit.h b/base/at_exit.h
new file mode 100644
index 0000000..6fe7361
--- /dev/null
+++ b/base/at_exit.h
@@ -0,0 +1,76 @@
+// Copyright (c) 2011 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_AT_EXIT_H_
+#define BASE_AT_EXIT_H_
+
+#include <stack>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/synchronization/lock.h"
+
+namespace base {
+
+// This class provides a facility similar to the CRT atexit(), except that
+// we control when the callbacks are executed. Under Windows for a DLL they
+// happen at a really bad time and under the loader lock. This facility is
+// mostly used by base::Singleton.
+//
+// The usage is simple. Early in the main() or WinMain() scope create an
+// AtExitManager object on the stack:
+// int main(...) {
+//    base::AtExitManager exit_manager;
+//
+// }
+// When the exit_manager object goes out of scope, all the registered
+// callbacks and singleton destructors will be called.
+
+class BASE_EXPORT AtExitManager {
+ public:
+  typedef void (*AtExitCallbackType)(void*);
+
+  AtExitManager();
+
+  // The dtor calls all the registered callbacks. Do not try to register more
+  // callbacks after this point.
+  ~AtExitManager();
+
+  // Registers the specified function to be called at exit. The prototype of
+  // the callback function is void func(void*).
+  static void RegisterCallback(AtExitCallbackType func, void* param);
+
+  // Registers the specified task to be called at exit.
+  static void RegisterTask(base::Closure task);
+
+  // Calls the functions registered with RegisterCallback in LIFO order. It
+  // is possible to register new callbacks after calling this function.
+  static void ProcessCallbacksNow();
+
+ protected:
+  // This constructor will allow this instance of AtExitManager to be created
+  // even if one already exists.  This should only be used for testing!
+  // AtExitManagers are kept on a global stack, and it will be removed during
+  // destruction.  This allows you to shadow another AtExitManager.
+  explicit AtExitManager(bool shadow);
+
+ private:
+  base::Lock lock_;
+  std::stack<base::Closure> stack_;
+  AtExitManager* next_manager_;  // Stack of managers to allow shadowing.
+
+  DISALLOW_COPY_AND_ASSIGN(AtExitManager);
+};
+
+#if defined(UNIT_TEST)
+class ShadowingAtExitManager : public AtExitManager {
+ public:
+  ShadowingAtExitManager() : AtExitManager(true) {}
+};
+#endif  // defined(UNIT_TEST)
+
+}  // namespace base
+
+#endif  // BASE_AT_EXIT_H_
diff --git a/base/at_exit_unittest.cc b/base/at_exit_unittest.cc
new file mode 100644
index 0000000..cda7340
--- /dev/null
+++ b/base/at_exit_unittest.cc
@@ -0,0 +1,87 @@
+// Copyright (c) 2011 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/at_exit.h"
+#include "base/bind.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+int g_test_counter_1 = 0;
+int g_test_counter_2 = 0;
+
+void IncrementTestCounter1(void* unused) {
+  ++g_test_counter_1;
+}
+
+void IncrementTestCounter2(void* unused) {
+  ++g_test_counter_2;
+}
+
+void ZeroTestCounters() {
+  g_test_counter_1 = 0;
+  g_test_counter_2 = 0;
+}
+
+void ExpectCounter1IsZero(void* unused) {
+  EXPECT_EQ(0, g_test_counter_1);
+}
+
+void ExpectParamIsNull(void* param) {
+  EXPECT_EQ(static_cast<void*>(NULL), param);
+}
+
+void ExpectParamIsCounter(void* param) {
+  EXPECT_EQ(&g_test_counter_1, param);
+}
+
+}  // namespace
+
+class AtExitTest : public testing::Test {
+ private:
+  // Don't test the global AtExitManager, because asking it to process its
+  // AtExit callbacks can ruin the global state that other tests may depend on.
+  base::ShadowingAtExitManager exit_manager_;
+};
+
+TEST_F(AtExitTest, Basic) {
+  ZeroTestCounters();
+  base::AtExitManager::RegisterCallback(&IncrementTestCounter1, NULL);
+  base::AtExitManager::RegisterCallback(&IncrementTestCounter2, NULL);
+  base::AtExitManager::RegisterCallback(&IncrementTestCounter1, NULL);
+
+  EXPECT_EQ(0, g_test_counter_1);
+  EXPECT_EQ(0, g_test_counter_2);
+  base::AtExitManager::ProcessCallbacksNow();
+  EXPECT_EQ(2, g_test_counter_1);
+  EXPECT_EQ(1, g_test_counter_2);
+}
+
+TEST_F(AtExitTest, LIFOOrder) {
+  ZeroTestCounters();
+  base::AtExitManager::RegisterCallback(&IncrementTestCounter1, NULL);
+  base::AtExitManager::RegisterCallback(&ExpectCounter1IsZero, NULL);
+  base::AtExitManager::RegisterCallback(&IncrementTestCounter2, NULL);
+
+  EXPECT_EQ(0, g_test_counter_1);
+  EXPECT_EQ(0, g_test_counter_2);
+  base::AtExitManager::ProcessCallbacksNow();
+  EXPECT_EQ(1, g_test_counter_1);
+  EXPECT_EQ(1, g_test_counter_2);
+}
+
+TEST_F(AtExitTest, Param) {
+  base::AtExitManager::RegisterCallback(&ExpectParamIsNull, NULL);
+  base::AtExitManager::RegisterCallback(&ExpectParamIsCounter,
+                                        &g_test_counter_1);
+  base::AtExitManager::ProcessCallbacksNow();
+}
+
+TEST_F(AtExitTest, Task) {
+  ZeroTestCounters();
+  base::AtExitManager::RegisterTask(base::Bind(&ExpectParamIsCounter,
+                                               &g_test_counter_1));
+  base::AtExitManager::ProcessCallbacksNow();
+}
diff --git a/base/atomic_ref_count.h b/base/atomic_ref_count.h
new file mode 100644
index 0000000..2ab7242
--- /dev/null
+++ b/base/atomic_ref_count.h
@@ -0,0 +1,66 @@
+// Copyright (c) 2011 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 is a low level implementation of atomic semantics for reference
+// counting.  Please use base/memory/ref_counted.h directly instead.
+
+#ifndef BASE_ATOMIC_REF_COUNT_H_
+#define BASE_ATOMIC_REF_COUNT_H_
+
+#include "base/atomicops.h"
+
+namespace base {
+
+typedef subtle::Atomic32 AtomicRefCount;
+
+// Increment a reference count by "increment", which must exceed 0.
+inline void AtomicRefCountIncN(volatile AtomicRefCount *ptr,
+                               AtomicRefCount increment) {
+  subtle::NoBarrier_AtomicIncrement(ptr, increment);
+}
+
+// Decrement a reference count by "decrement", which must exceed 0,
+// and return whether the result is non-zero.
+// Insert barriers to ensure that state written before the reference count
+// became zero will be visible to a thread that has just made the count zero.
+inline bool AtomicRefCountDecN(volatile AtomicRefCount *ptr,
+                               AtomicRefCount decrement) {
+  bool res = (subtle::Barrier_AtomicIncrement(ptr, -decrement) != 0);
+  return res;
+}
+
+// Increment a reference count by 1.
+inline void AtomicRefCountInc(volatile AtomicRefCount *ptr) {
+  base::AtomicRefCountIncN(ptr, 1);
+}
+
+// Decrement a reference count by 1 and return whether the result is non-zero.
+// Insert barriers to ensure that state written before the reference count
+// became zero will be visible to a thread that has just made the count zero.
+inline bool AtomicRefCountDec(volatile AtomicRefCount *ptr) {
+  return base::AtomicRefCountDecN(ptr, 1);
+}
+
+// Return whether the reference count is one.  If the reference count is used
+// in the conventional way, a refrerence count of 1 implies that the current
+// thread owns the reference and no other thread shares it.  This call performs
+// the test for a reference count of one, and performs the memory barrier
+// needed for the owning thread to act on the object, knowing that it has
+// exclusive access to the object.
+inline bool AtomicRefCountIsOne(volatile AtomicRefCount *ptr) {
+  bool res = (subtle::Acquire_Load(ptr) == 1);
+  return res;
+}
+
+// Return whether the reference count is zero.  With conventional object
+// referencing counting, the object will be destroyed, so the reference count
+// should never be zero.  Hence this is generally used for a debug check.
+inline bool AtomicRefCountIsZero(volatile AtomicRefCount *ptr) {
+  bool res = (subtle::Acquire_Load(ptr) == 0);
+  return res;
+}
+
+}  // namespace base
+
+#endif  // BASE_ATOMIC_REF_COUNT_H_
diff --git a/base/atomic_sequence_num.h b/base/atomic_sequence_num.h
new file mode 100644
index 0000000..7bf2778
--- /dev/null
+++ b/base/atomic_sequence_num.h
@@ -0,0 +1,60 @@
+// Copyright (c) 2012 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_ATOMIC_SEQUENCE_NUM_H_
+#define BASE_ATOMIC_SEQUENCE_NUM_H_
+
+#include "base/atomicops.h"
+#include "base/basictypes.h"
+
+namespace base {
+
+class AtomicSequenceNumber;
+
+// Static (POD) AtomicSequenceNumber that MUST be used in global scope (or
+// non-function scope) ONLY. This implementation does not generate any static
+// initializer.  Note that it does not implement any constructor which means
+// that its fields are not initialized except when it is stored in the global
+// data section (.data in ELF). If you want to allocate an atomic sequence
+// number on the stack (or heap), please use the AtomicSequenceNumber class
+// declared below.
+class StaticAtomicSequenceNumber {
+ public:
+  inline int GetNext() {
+    return static_cast<int>(
+        base::subtle::NoBarrier_AtomicIncrement(&seq_, 1) - 1);
+  }
+
+ private:
+  friend class AtomicSequenceNumber;
+
+  inline void Reset() {
+    base::subtle::Release_Store(&seq_, 0);
+  }
+
+  base::subtle::Atomic32 seq_;
+};
+
+// AtomicSequenceNumber that can be stored and used safely (i.e. its fields are
+// always initialized as opposed to StaticAtomicSequenceNumber declared above).
+// Please use StaticAtomicSequenceNumber if you want to declare an atomic
+// sequence number in the global scope.
+class AtomicSequenceNumber {
+ public:
+  AtomicSequenceNumber() {
+    seq_.Reset();
+  }
+
+  inline int GetNext() {
+    return seq_.GetNext();
+  }
+
+ private:
+  StaticAtomicSequenceNumber seq_;
+  DISALLOW_COPY_AND_ASSIGN(AtomicSequenceNumber);
+};
+
+}  // namespace base
+
+#endif  // BASE_ATOMIC_SEQUENCE_NUM_H_
diff --git a/base/atomicops.h b/base/atomicops.h
new file mode 100644
index 0000000..6a5371c
--- /dev/null
+++ b/base/atomicops.h
@@ -0,0 +1,213 @@
+// Copyright (c) 2012 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.
+
+// For atomic operations on reference counts, see atomic_refcount.h.
+// For atomic operations on sequence numbers, see atomic_sequence_num.h.
+
+// The routines exported by this module are subtle.  If you use them, even if
+// you get the code right, it will depend on careful reasoning about atomicity
+// and memory ordering; it will be less readable, and harder to maintain.  If
+// you plan to use these routines, you should have a good reason, such as solid
+// evidence that performance would otherwise suffer, or there being no
+// alternative.  You should assume only properties explicitly guaranteed by the
+// specifications in this file.  You are almost certainly _not_ writing code
+// just for the x86; if you assume x86 semantics, x86 hardware bugs and
+// implementations on other archtectures will cause your code to break.  If you
+// do not know what you are doing, avoid these routines, and use a Mutex.
+//
+// It is incorrect to make direct assignments to/from an atomic variable.
+// You should use one of the Load or Store routines.  The NoBarrier
+// versions are provided when no barriers are needed:
+//   NoBarrier_Store()
+//   NoBarrier_Load()
+// Although there are currently no compiler enforcement, you are encouraged
+// to use these.
+//
+
+#ifndef BASE_ATOMICOPS_H_
+#define BASE_ATOMICOPS_H_
+
+#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"
+
+#if defined(OS_WIN) && defined(ARCH_CPU_64_BITS)
+// windows.h #defines this (only on x64). This causes problems because the
+// public API also uses MemoryBarrier at the public name for this fence. So, on
+// X64, undef it, and call its documented
+// (http://msdn.microsoft.com/en-us/library/windows/desktop/ms684208.aspx)
+// implementation directly.
+#undef MemoryBarrier
+#endif
+
+namespace base {
+namespace subtle {
+
+typedef int32_t Atomic32;
+#ifdef ARCH_CPU_64_BITS
+// We need to be able to go between Atomic64 and AtomicWord implicitly.  This
+// means Atomic64 and AtomicWord should be the same type on 64-bit.
+#if defined(__ILP32__) || defined(OS_NACL)
+// NaCl's intptr_t is not actually 64-bits on 64-bit!
+// http://code.google.com/p/nativeclient/issues/detail?id=1162
+typedef int64_t Atomic64;
+#else
+typedef intptr_t Atomic64;
+#endif
+#endif
+
+// Use AtomicWord for a machine-sized pointer.  It will use the Atomic32 or
+// Atomic64 routines below, depending on your architecture.
+typedef intptr_t AtomicWord;
+
+// Atomically execute:
+//      result = *ptr;
+//      if (*ptr == old_value)
+//        *ptr = new_value;
+//      return result;
+//
+// I.e., replace "*ptr" with "new_value" if "*ptr" used to be "old_value".
+// Always return the old value of "*ptr"
+//
+// This routine implies no memory barriers.
+Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+                                  Atomic32 old_value,
+                                  Atomic32 new_value);
+
+// Atomically store new_value into *ptr, returning the previous value held in
+// *ptr.  This routine implies no memory barriers.
+Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr, Atomic32 new_value);
+
+// Atomically increment *ptr by "increment".  Returns the new value of
+// *ptr with the increment applied.  This routine implies no memory barriers.
+Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr, Atomic32 increment);
+
+Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+                                 Atomic32 increment);
+
+// These following lower-level operations are typically useful only to people
+// implementing higher-level synchronization operations like spinlocks,
+// mutexes, and condition-variables.  They combine CompareAndSwap(), a load, or
+// a store with appropriate memory-ordering instructions.  "Acquire" operations
+// ensure that no later memory access can be reordered ahead of the operation.
+// "Release" operations ensure that no previous memory access can be reordered
+// after the operation.  "Barrier" operations have both "Acquire" and "Release"
+// semantics.   A MemoryBarrier() has "Barrier" semantics, but does no memory
+// access.
+Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+                                Atomic32 old_value,
+                                Atomic32 new_value);
+Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+                                Atomic32 old_value,
+                                Atomic32 new_value);
+
+void MemoryBarrier();
+void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value);
+void Acquire_Store(volatile Atomic32* ptr, Atomic32 value);
+void Release_Store(volatile Atomic32* ptr, Atomic32 value);
+
+Atomic32 NoBarrier_Load(volatile const Atomic32* ptr);
+Atomic32 Acquire_Load(volatile const Atomic32* ptr);
+Atomic32 Release_Load(volatile const Atomic32* ptr);
+
+// 64-bit atomic operations (only available on 64-bit processors).
+#ifdef ARCH_CPU_64_BITS
+Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
+                                  Atomic64 old_value,
+                                  Atomic64 new_value);
+Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr, Atomic64 new_value);
+Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment);
+Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment);
+
+Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
+                                Atomic64 old_value,
+                                Atomic64 new_value);
+Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
+                                Atomic64 old_value,
+                                Atomic64 new_value);
+void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value);
+void Acquire_Store(volatile Atomic64* ptr, Atomic64 value);
+void Release_Store(volatile Atomic64* ptr, Atomic64 value);
+Atomic64 NoBarrier_Load(volatile const Atomic64* ptr);
+Atomic64 Acquire_Load(volatile const Atomic64* ptr);
+Atomic64 Release_Load(volatile const Atomic64* ptr);
+#endif  // ARCH_CPU_64_BITS
+
+}  // namespace subtle
+}  // namespace base
+
+// The following x86 CPU features are used in atomicops_internals_x86_gcc.h, but
+// this file is duplicated inside of Chrome: protobuf and tcmalloc rely on the
+// struct being present at link time. Some parts of Chrome can currently use the
+// portable interface whereas others still use GCC one. The include guards are
+// the same as in atomicops_internals_x86_gcc.cc.
+#if defined(__i386__) || defined(__x86_64__)
+// This struct is not part of the public API of this module; clients may not
+// use it.  (However, it's exported via BASE_EXPORT because clients implicitly
+// do use it at link time by inlining these functions.)
+// Features of this x86.  Values may not be correct before main() is run,
+// but are set conservatively.
+struct AtomicOps_x86CPUFeatureStruct {
+  bool has_amd_lock_mb_bug; // Processor has AMD memory-barrier bug; do lfence
+                            // after acquire compare-and-swap.
+  // The following fields are unused by Chrome's base implementation but are
+  // still used by copies of the same code in other parts of the code base. This
+  // causes an ODR violation, and the other code is likely reading invalid
+  // memory.
+  // TODO(jfb) Delete these fields once the rest of the Chrome code base doesn't
+  //           depend on them.
+  bool has_sse2;            // Processor has SSE2.
+  bool has_cmpxchg16b;      // Processor supports cmpxchg16b instruction.
+};
+BASE_EXPORT extern struct AtomicOps_x86CPUFeatureStruct
+    AtomicOps_Internalx86CPUFeatures;
+#endif
+
+// Try to use a portable implementation based on C++11 atomics.
+//
+// Some toolchains support C++11 language features without supporting library
+// features (recent compiler, older STL). Whitelist libstdc++ and libc++ that we
+// know will have <atomic> when compiling C++11.
+#if ((__cplusplus >= 201103L) &&                            \
+     ((defined(__GLIBCXX__) && (__GLIBCXX__ > 20110216)) || \
+      (defined(_LIBCPP_VERSION) && (_LIBCPP_STD_VER >= 11))))
+#  include "base/atomicops_internals_portable.h"
+#else  // Otherwise use a platform specific implementation.
+#  if defined(THREAD_SANITIZER)
+#    error "Thread sanitizer must use the portable atomic operations"
+#  elif (defined(OS_WIN) && defined(COMPILER_MSVC) && \
+         defined(ARCH_CPU_X86_FAMILY))
+#    include "base/atomicops_internals_x86_msvc.h"
+#  elif defined(OS_MACOSX)
+#    include "base/atomicops_internals_mac.h"
+#  elif defined(OS_NACL)
+#    include "base/atomicops_internals_gcc.h"
+#  elif defined(COMPILER_GCC) && defined(ARCH_CPU_ARMEL)
+#    include "base/atomicops_internals_arm_gcc.h"
+#  elif defined(COMPILER_GCC) && defined(ARCH_CPU_ARM64)
+#    include "base/atomicops_internals_arm64_gcc.h"
+#  elif defined(COMPILER_GCC) && defined(ARCH_CPU_X86_FAMILY)
+#    include "base/atomicops_internals_x86_gcc.h"
+#  elif (defined(COMPILER_GCC) && \
+         (defined(ARCH_CPU_MIPS_FAMILY) || defined(ARCH_CPU_MIPS64_FAMILY)))
+#    include "base/atomicops_internals_mips_gcc.h"
+#  else
+#    error "Atomic operations are not supported on your platform"
+#  endif
+#endif   // Portable / non-portable includes.
+
+// On some platforms we need additional declarations to make
+// AtomicWord compatible with our other Atomic* types.
+#if defined(OS_MACOSX) || defined(OS_OPENBSD)
+#include "base/atomicops_internals_atomicword_compat.h"
+#endif
+
+#endif  // BASE_ATOMICOPS_H_
diff --git a/base/atomicops_internals_arm64_gcc.h b/base/atomicops_internals_arm64_gcc.h
new file mode 100644
index 0000000..ddcfec9
--- /dev/null
+++ b/base/atomicops_internals_arm64_gcc.h
@@ -0,0 +1,307 @@
+// 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 an internal atomic implementation, use base/atomicops.h instead.
+
+// TODO(rmcilroy): Investigate whether we can use __sync__ intrinsics instead of
+//                 the hand coded assembly without introducing perf regressions.
+// TODO(rmcilroy): Investigate whether we can use acquire / release versions of
+//                 exclusive load / store assembly instructions and do away with
+//                 the barriers.
+
+#ifndef BASE_ATOMICOPS_INTERNALS_ARM64_GCC_H_
+#define BASE_ATOMICOPS_INTERNALS_ARM64_GCC_H_
+
+#if defined(OS_QNX)
+#include <sys/cpuinline.h>
+#endif
+
+namespace base {
+namespace subtle {
+
+inline void MemoryBarrier() {
+  __asm__ __volatile__ ("dmb ish" ::: "memory");  // NOLINT
+}
+
+// NoBarrier versions of the operation include "memory" in the clobber list.
+// This is not required for direct usage of the NoBarrier versions of the
+// operations. However this is required for correctness when they are used as
+// part of the Acquire or Release versions, to ensure that nothing from outside
+// the call is reordered between the operation and the memory barrier. This does
+// not change the code generated, so has no or minimal impact on the
+// NoBarrier operations.
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+                                         Atomic32 old_value,
+                                         Atomic32 new_value) {
+  Atomic32 prev;
+  int32_t temp;
+
+  __asm__ __volatile__ (  // NOLINT
+    "0:                                    \n\t"
+    "ldxr %w[prev], %[ptr]                 \n\t"  // Load the previous value.
+    "cmp %w[prev], %w[old_value]           \n\t"
+    "bne 1f                                \n\t"
+    "stxr %w[temp], %w[new_value], %[ptr]  \n\t"  // Try to store the new value.
+    "cbnz %w[temp], 0b                     \n\t"  // Retry if it did not work.
+    "1:                                    \n\t"
+    : [prev]"=&r" (prev),
+      [temp]"=&r" (temp),
+      [ptr]"+Q" (*ptr)
+    : [old_value]"IJr" (old_value),
+      [new_value]"r" (new_value)
+    : "cc", "memory"
+  );  // NOLINT
+
+  return prev;
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+                                         Atomic32 new_value) {
+  Atomic32 result;
+  int32_t temp;
+
+  __asm__ __volatile__ (  // NOLINT
+    "0:                                    \n\t"
+    "ldxr %w[result], %[ptr]               \n\t"  // Load the previous value.
+    "stxr %w[temp], %w[new_value], %[ptr]  \n\t"  // Try to store the new value.
+    "cbnz %w[temp], 0b                     \n\t"  // Retry if it did not work.
+    : [result]"=&r" (result),
+      [temp]"=&r" (temp),
+      [ptr]"+Q" (*ptr)
+    : [new_value]"r" (new_value)
+    : "memory"
+  );  // NOLINT
+
+  return result;
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+                                          Atomic32 increment) {
+  Atomic32 result;
+  int32_t temp;
+
+  __asm__ __volatile__ (  // NOLINT
+    "0:                                       \n\t"
+    "ldxr %w[result], %[ptr]                  \n\t"  // Load the previous value.
+    "add %w[result], %w[result], %w[increment]\n\t"
+    "stxr %w[temp], %w[result], %[ptr]        \n\t"  // Try to store the result.
+    "cbnz %w[temp], 0b                        \n\t"  // Retry on failure.
+    : [result]"=&r" (result),
+      [temp]"=&r" (temp),
+      [ptr]"+Q" (*ptr)
+    : [increment]"IJr" (increment)
+    : "memory"
+  );  // NOLINT
+
+  return result;
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+                                        Atomic32 increment) {
+  MemoryBarrier();
+  Atomic32 result = NoBarrier_AtomicIncrement(ptr, increment);
+  MemoryBarrier();
+
+  return result;
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  Atomic32 prev = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+  MemoryBarrier();
+
+  return prev;
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  MemoryBarrier();
+  Atomic32 prev = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+
+  return prev;
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+  *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+  *ptr = value;
+  MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+  __asm__ __volatile__ (  // NOLINT
+    "stlr %w[value], %[ptr]  \n\t"
+    : [ptr]"=Q" (*ptr)
+    : [value]"r" (value)
+    : "memory"
+  );  // NOLINT
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+  return *ptr;
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+  Atomic32 value;
+
+  __asm__ __volatile__ (  // NOLINT
+    "ldar %w[value], %[ptr]  \n\t"
+    : [value]"=r" (value)
+    : [ptr]"Q" (*ptr)
+    : "memory"
+  );  // NOLINT
+
+  return value;
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+  MemoryBarrier();
+  return *ptr;
+}
+
+// 64-bit versions of the operations.
+// See the 32-bit versions for comments.
+
+inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
+                                         Atomic64 old_value,
+                                         Atomic64 new_value) {
+  Atomic64 prev;
+  int32_t temp;
+
+  __asm__ __volatile__ (  // NOLINT
+    "0:                                    \n\t"
+    "ldxr %[prev], %[ptr]                  \n\t"
+    "cmp %[prev], %[old_value]             \n\t"
+    "bne 1f                                \n\t"
+    "stxr %w[temp], %[new_value], %[ptr]   \n\t"
+    "cbnz %w[temp], 0b                     \n\t"
+    "1:                                    \n\t"
+    : [prev]"=&r" (prev),
+      [temp]"=&r" (temp),
+      [ptr]"+Q" (*ptr)
+    : [old_value]"IJr" (old_value),
+      [new_value]"r" (new_value)
+    : "cc", "memory"
+  );  // NOLINT
+
+  return prev;
+}
+
+inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
+                                         Atomic64 new_value) {
+  Atomic64 result;
+  int32_t temp;
+
+  __asm__ __volatile__ (  // NOLINT
+    "0:                                    \n\t"
+    "ldxr %[result], %[ptr]                \n\t"
+    "stxr %w[temp], %[new_value], %[ptr]   \n\t"
+    "cbnz %w[temp], 0b                     \n\t"
+    : [result]"=&r" (result),
+      [temp]"=&r" (temp),
+      [ptr]"+Q" (*ptr)
+    : [new_value]"r" (new_value)
+    : "memory"
+  );  // NOLINT
+
+  return result;
+}
+
+inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
+                                          Atomic64 increment) {
+  Atomic64 result;
+  int32_t temp;
+
+  __asm__ __volatile__ (  // NOLINT
+    "0:                                     \n\t"
+    "ldxr %[result], %[ptr]                 \n\t"
+    "add %[result], %[result], %[increment] \n\t"
+    "stxr %w[temp], %[result], %[ptr]       \n\t"
+    "cbnz %w[temp], 0b                      \n\t"
+    : [result]"=&r" (result),
+      [temp]"=&r" (temp),
+      [ptr]"+Q" (*ptr)
+    : [increment]"IJr" (increment)
+    : "memory"
+  );  // NOLINT
+
+  return result;
+}
+
+inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
+                                        Atomic64 increment) {
+  MemoryBarrier();
+  Atomic64 result = NoBarrier_AtomicIncrement(ptr, increment);
+  MemoryBarrier();
+
+  return result;
+}
+
+inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
+                                       Atomic64 old_value,
+                                       Atomic64 new_value) {
+  Atomic64 prev = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+  MemoryBarrier();
+
+  return prev;
+}
+
+inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
+                                       Atomic64 old_value,
+                                       Atomic64 new_value) {
+  MemoryBarrier();
+  Atomic64 prev = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+
+  return prev;
+}
+
+inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
+  *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
+  *ptr = value;
+  MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
+  __asm__ __volatile__ (  // NOLINT
+    "stlr %x[value], %[ptr]  \n\t"
+    : [ptr]"=Q" (*ptr)
+    : [value]"r" (value)
+    : "memory"
+  );  // NOLINT
+}
+
+inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
+  return *ptr;
+}
+
+inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
+  Atomic64 value;
+
+  __asm__ __volatile__ (  // NOLINT
+    "ldar %x[value], %[ptr]  \n\t"
+    : [value]"=r" (value)
+    : [ptr]"Q" (*ptr)
+    : "memory"
+  );  // NOLINT
+
+  return value;
+}
+
+inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
+  MemoryBarrier();
+  return *ptr;
+}
+
+}  // namespace subtle
+}  // namespace base
+
+#endif  // BASE_ATOMICOPS_INTERNALS_ARM64_GCC_H_
diff --git a/base/atomicops_internals_arm_gcc.h b/base/atomicops_internals_arm_gcc.h
new file mode 100644
index 0000000..44c91c8
--- /dev/null
+++ b/base/atomicops_internals_arm_gcc.h
@@ -0,0 +1,294 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is an internal atomic implementation, use base/atomicops.h instead.
+//
+// LinuxKernelCmpxchg and Barrier_AtomicIncrement are from Google Gears.
+
+#ifndef BASE_ATOMICOPS_INTERNALS_ARM_GCC_H_
+#define BASE_ATOMICOPS_INTERNALS_ARM_GCC_H_
+
+#if defined(OS_QNX)
+#include <sys/cpuinline.h>
+#endif
+
+namespace base {
+namespace subtle {
+
+// Memory barriers on ARM are funky, but the kernel is here to help:
+//
+// * ARMv5 didn't support SMP, there is no memory barrier instruction at
+//   all on this architecture, or when targeting its machine code.
+//
+// * Some ARMv6 CPUs support SMP. A full memory barrier can be produced by
+//   writing a random value to a very specific coprocessor register.
+//
+// * On ARMv7, the "dmb" instruction is used to perform a full memory
+//   barrier (though writing to the co-processor will still work).
+//   However, on single core devices (e.g. Nexus One, or Nexus S),
+//   this instruction will take up to 200 ns, which is huge, even though
+//   it's completely un-needed on these devices.
+//
+// * There is no easy way to determine at runtime if the device is
+//   single or multi-core. However, the kernel provides a useful helper
+//   function at a fixed memory address (0xffff0fa0), which will always
+//   perform a memory barrier in the most efficient way. I.e. on single
+//   core devices, this is an empty function that exits immediately.
+//   On multi-core devices, it implements a full memory barrier.
+//
+// * This source could be compiled to ARMv5 machine code that runs on a
+//   multi-core ARMv6 or ARMv7 device. In this case, memory barriers
+//   are needed for correct execution. Always call the kernel helper, even
+//   when targeting ARMv5TE.
+//
+
+inline void MemoryBarrier() {
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+  // Note: This is a function call, which is also an implicit compiler barrier.
+  typedef void (*KernelMemoryBarrierFunc)();
+  ((KernelMemoryBarrierFunc)0xffff0fa0)();
+#elif defined(OS_QNX)
+  __cpu_membarrier();
+#else
+#error MemoryBarrier() is not implemented on this platform.
+#endif
+}
+
+// An ARM toolchain would only define one of these depending on which
+// variant of the target architecture is being used. This tests against
+// any known ARMv6 or ARMv7 variant, where it is possible to directly
+// use ldrex/strex instructions to implement fast atomic operations.
+#if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || \
+    defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || \
+    defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || \
+    defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || \
+    defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__)
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+                                         Atomic32 old_value,
+                                         Atomic32 new_value) {
+  Atomic32 prev_value;
+  int reloop;
+  do {
+    // The following is equivalent to:
+    //
+    //   prev_value = LDREX(ptr)
+    //   reloop = 0
+    //   if (prev_value != old_value)
+    //      reloop = STREX(ptr, new_value)
+    __asm__ __volatile__("    ldrex %0, [%3]\n"
+                         "    mov %1, #0\n"
+                         "    cmp %0, %4\n"
+#ifdef __thumb2__
+                         "    it eq\n"
+#endif
+                         "    strexeq %1, %5, [%3]\n"
+                         : "=&r"(prev_value), "=&r"(reloop), "+m"(*ptr)
+                         : "r"(ptr), "r"(old_value), "r"(new_value)
+                         : "cc", "memory");
+  } while (reloop != 0);
+  return prev_value;
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  Atomic32 result = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+  MemoryBarrier();
+  return result;
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  MemoryBarrier();
+  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+                                          Atomic32 increment) {
+  Atomic32 value;
+  int reloop;
+  do {
+    // Equivalent to:
+    //
+    //  value = LDREX(ptr)
+    //  value += increment
+    //  reloop = STREX(ptr, value)
+    //
+    __asm__ __volatile__("    ldrex %0, [%3]\n"
+                         "    add %0, %0, %4\n"
+                         "    strex %1, %0, [%3]\n"
+                         : "=&r"(value), "=&r"(reloop), "+m"(*ptr)
+                         : "r"(ptr), "r"(increment)
+                         : "cc", "memory");
+  } while (reloop);
+  return value;
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+                                        Atomic32 increment) {
+  // TODO(digit): Investigate if it's possible to implement this with
+  // a single MemoryBarrier() operation between the LDREX and STREX.
+  // See http://crbug.com/246514
+  MemoryBarrier();
+  Atomic32 result = NoBarrier_AtomicIncrement(ptr, increment);
+  MemoryBarrier();
+  return result;
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+                                         Atomic32 new_value) {
+  Atomic32 old_value;
+  int reloop;
+  do {
+    // old_value = LDREX(ptr)
+    // reloop = STREX(ptr, new_value)
+    __asm__ __volatile__("   ldrex %0, [%3]\n"
+                         "   strex %1, %4, [%3]\n"
+                         : "=&r"(old_value), "=&r"(reloop), "+m"(*ptr)
+                         : "r"(ptr), "r"(new_value)
+                         : "cc", "memory");
+  } while (reloop != 0);
+  return old_value;
+}
+
+// This tests against any known ARMv5 variant.
+#elif defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) || \
+      defined(__ARM_ARCH_5TE__) || defined(__ARM_ARCH_5TEJ__)
+
+// The kernel also provides a helper function to perform an atomic
+// compare-and-swap operation at the hard-wired address 0xffff0fc0.
+// On ARMv5, this is implemented by a special code path that the kernel
+// detects and treats specially when thread pre-emption happens.
+// On ARMv6 and higher, it uses LDREX/STREX instructions instead.
+//
+// Note that this always perform a full memory barrier, there is no
+// need to add calls MemoryBarrier() before or after it. It also
+// returns 0 on success, and 1 on exit.
+//
+// Available and reliable since Linux 2.6.24. Both Android and ChromeOS
+// use newer kernel revisions, so this should not be a concern.
+namespace {
+
+inline int LinuxKernelCmpxchg(Atomic32 old_value,
+                              Atomic32 new_value,
+                              volatile Atomic32* ptr) {
+  typedef int (*KernelCmpxchgFunc)(Atomic32, Atomic32, volatile Atomic32*);
+  return ((KernelCmpxchgFunc)0xffff0fc0)(old_value, new_value, ptr);
+}
+
+}  // namespace
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+                                         Atomic32 old_value,
+                                         Atomic32 new_value) {
+  Atomic32 prev_value;
+  for (;;) {
+    prev_value = *ptr;
+    if (prev_value != old_value)
+      return prev_value;
+    if (!LinuxKernelCmpxchg(old_value, new_value, ptr))
+      return old_value;
+  }
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+                                         Atomic32 new_value) {
+  Atomic32 old_value;
+  do {
+    old_value = *ptr;
+  } while (LinuxKernelCmpxchg(old_value, new_value, ptr));
+  return old_value;
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+                                          Atomic32 increment) {
+  return Barrier_AtomicIncrement(ptr, increment);
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+                                        Atomic32 increment) {
+  for (;;) {
+    // Atomic exchange the old value with an incremented one.
+    Atomic32 old_value = *ptr;
+    Atomic32 new_value = old_value + increment;
+    if (!LinuxKernelCmpxchg(old_value, new_value, ptr)) {
+      // The exchange took place as expected.
+      return new_value;
+    }
+    // Otherwise, *ptr changed mid-loop and we need to retry.
+  }
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  Atomic32 prev_value;
+  for (;;) {
+    prev_value = *ptr;
+    if (prev_value != old_value) {
+      // Always ensure acquire semantics.
+      MemoryBarrier();
+      return prev_value;
+    }
+    if (!LinuxKernelCmpxchg(old_value, new_value, ptr))
+      return old_value;
+  }
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  // This could be implemented as:
+  //    MemoryBarrier();
+  //    return NoBarrier_CompareAndSwap();
+  //
+  // But would use 3 barriers per succesful CAS. To save performance,
+  // use Acquire_CompareAndSwap(). Its implementation guarantees that:
+  // - A succesful swap uses only 2 barriers (in the kernel helper).
+  // - An early return due to (prev_value != old_value) performs
+  //   a memory barrier with no store, which is equivalent to the
+  //   generic implementation above.
+  return Acquire_CompareAndSwap(ptr, old_value, new_value);
+}
+
+#else
+#  error "Your CPU's ARM architecture is not supported yet"
+#endif
+
+// NOTE: Atomicity of the following load and store operations is only
+// guaranteed in case of 32-bit alignement of |ptr| values.
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+  *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+  *ptr = value;
+  MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+  MemoryBarrier();
+  *ptr = value;
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) { return *ptr; }
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+  Atomic32 value = *ptr;
+  MemoryBarrier();
+  return value;
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+  MemoryBarrier();
+  return *ptr;
+}
+
+}  // namespace subtle
+}  // namespace base
+
+#endif  // BASE_ATOMICOPS_INTERNALS_ARM_GCC_H_
diff --git a/base/atomicops_internals_atomicword_compat.h b/base/atomicops_internals_atomicword_compat.h
new file mode 100644
index 0000000..342a6e4
--- /dev/null
+++ b/base/atomicops_internals_atomicword_compat.h
@@ -0,0 +1,100 @@
+// Copyright (c) 2011 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 an internal atomic implementation, use base/atomicops.h instead.
+
+#ifndef BASE_ATOMICOPS_INTERNALS_ATOMICWORD_COMPAT_H_
+#define BASE_ATOMICOPS_INTERNALS_ATOMICWORD_COMPAT_H_
+
+// AtomicWord is a synonym for intptr_t, and Atomic32 is a synonym for int32,
+// which in turn means int. On some LP32 platforms, intptr_t is an int, but
+// on others, it's a long. When AtomicWord and Atomic32 are based on different
+// fundamental types, their pointers are incompatible.
+//
+// This file defines function overloads to allow both AtomicWord and Atomic32
+// data to be used with this interface.
+//
+// On LP64 platforms, AtomicWord and Atomic64 are both always long,
+// so this problem doesn't occur.
+
+#if !defined(ARCH_CPU_64_BITS)
+
+namespace base {
+namespace subtle {
+
+inline AtomicWord NoBarrier_CompareAndSwap(volatile AtomicWord* ptr,
+                                           AtomicWord old_value,
+                                           AtomicWord new_value) {
+  return NoBarrier_CompareAndSwap(
+      reinterpret_cast<volatile Atomic32*>(ptr), old_value, new_value);
+}
+
+inline AtomicWord NoBarrier_AtomicExchange(volatile AtomicWord* ptr,
+                                           AtomicWord new_value) {
+  return NoBarrier_AtomicExchange(
+      reinterpret_cast<volatile Atomic32*>(ptr), new_value);
+}
+
+inline AtomicWord NoBarrier_AtomicIncrement(volatile AtomicWord* ptr,
+                                            AtomicWord increment) {
+  return NoBarrier_AtomicIncrement(
+      reinterpret_cast<volatile Atomic32*>(ptr), increment);
+}
+
+inline AtomicWord Barrier_AtomicIncrement(volatile AtomicWord* ptr,
+                                          AtomicWord increment) {
+  return Barrier_AtomicIncrement(
+      reinterpret_cast<volatile Atomic32*>(ptr), increment);
+}
+
+inline AtomicWord Acquire_CompareAndSwap(volatile AtomicWord* ptr,
+                                         AtomicWord old_value,
+                                         AtomicWord new_value) {
+  return base::subtle::Acquire_CompareAndSwap(
+      reinterpret_cast<volatile Atomic32*>(ptr), old_value, new_value);
+}
+
+inline AtomicWord Release_CompareAndSwap(volatile AtomicWord* ptr,
+                                         AtomicWord old_value,
+                                         AtomicWord new_value) {
+  return base::subtle::Release_CompareAndSwap(
+      reinterpret_cast<volatile Atomic32*>(ptr), old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile AtomicWord *ptr, AtomicWord value) {
+  NoBarrier_Store(
+      reinterpret_cast<volatile Atomic32*>(ptr), value);
+}
+
+inline void Acquire_Store(volatile AtomicWord* ptr, AtomicWord value) {
+  return base::subtle::Acquire_Store(
+      reinterpret_cast<volatile Atomic32*>(ptr), value);
+}
+
+inline void Release_Store(volatile AtomicWord* ptr, AtomicWord value) {
+  return base::subtle::Release_Store(
+      reinterpret_cast<volatile Atomic32*>(ptr), value);
+}
+
+inline AtomicWord NoBarrier_Load(volatile const AtomicWord *ptr) {
+  return NoBarrier_Load(
+      reinterpret_cast<volatile const Atomic32*>(ptr));
+}
+
+inline AtomicWord Acquire_Load(volatile const AtomicWord* ptr) {
+  return base::subtle::Acquire_Load(
+      reinterpret_cast<volatile const Atomic32*>(ptr));
+}
+
+inline AtomicWord Release_Load(volatile const AtomicWord* ptr) {
+  return base::subtle::Release_Load(
+      reinterpret_cast<volatile const Atomic32*>(ptr));
+}
+
+}  // namespace subtle
+}  // namespace base
+
+#endif  // !defined(ARCH_CPU_64_BITS)
+
+#endif  // BASE_ATOMICOPS_INTERNALS_ATOMICWORD_COMPAT_H_
diff --git a/base/atomicops_internals_gcc.h b/base/atomicops_internals_gcc.h
new file mode 100644
index 0000000..35c95fe
--- /dev/null
+++ b/base/atomicops_internals_gcc.h
@@ -0,0 +1,106 @@
+// Copyright (c) 2009 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 an internal atomic implementation, include base/atomicops.h
+// instead. This file is for platforms that use GCC intrinsics rather than
+// platform-specific assembly code for atomic operations.
+
+#ifndef BASE_ATOMICOPS_INTERNALS_GCC_H_
+#define BASE_ATOMICOPS_INTERNALS_GCC_H_
+
+namespace base {
+namespace subtle {
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+                                         Atomic32 old_value,
+                                         Atomic32 new_value) {
+  Atomic32 prev_value;
+  do {
+    if (__sync_bool_compare_and_swap(ptr, old_value, new_value))
+      return old_value;
+    prev_value = *ptr;
+  } while (prev_value == old_value);
+  return prev_value;
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+                                         Atomic32 new_value) {
+  Atomic32 old_value;
+  do {
+    old_value = *ptr;
+  } while (!__sync_bool_compare_and_swap(ptr, old_value, new_value));
+  return old_value;
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+                                          Atomic32 increment) {
+  return Barrier_AtomicIncrement(ptr, increment);
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+                                        Atomic32 increment) {
+  for (;;) {
+    // Atomic exchange the old value with an incremented one.
+    Atomic32 old_value = *ptr;
+    Atomic32 new_value = old_value + increment;
+    if (__sync_bool_compare_and_swap(ptr, old_value, new_value)) {
+      // The exchange took place as expected.
+      return new_value;
+    }
+    // Otherwise, *ptr changed mid-loop and we need to retry.
+  }
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  // Since NoBarrier_CompareAndSwap uses __sync_bool_compare_and_swap, which
+  // is a full memory barrier, none is needed here or below in Release.
+  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+  *ptr = value;
+}
+
+inline void MemoryBarrier() {
+  __sync_synchronize();
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+  *ptr = value;
+  MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+  MemoryBarrier();
+  *ptr = value;
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+  return *ptr;
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+  Atomic32 value = *ptr;
+  MemoryBarrier();
+  return value;
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+  MemoryBarrier();
+  return *ptr;
+}
+
+}  // namespace subtle
+}  // namespace base
+
+#endif  // BASE_ATOMICOPS_INTERNALS_GCC_H_
+
diff --git a/base/atomicops_internals_mac.h b/base/atomicops_internals_mac.h
new file mode 100644
index 0000000..98864a7
--- /dev/null
+++ b/base/atomicops_internals_mac.h
@@ -0,0 +1,197 @@
+// Copyright (c) 2012 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 an internal atomic implementation, use base/atomicops.h instead.
+
+#ifndef BASE_ATOMICOPS_INTERNALS_MAC_H_
+#define BASE_ATOMICOPS_INTERNALS_MAC_H_
+
+#include <libkern/OSAtomic.h>
+
+namespace base {
+namespace subtle {
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+                                         Atomic32 old_value,
+                                         Atomic32 new_value) {
+  Atomic32 prev_value;
+  do {
+    if (OSAtomicCompareAndSwap32(old_value, new_value,
+                                 const_cast<Atomic32*>(ptr))) {
+      return old_value;
+    }
+    prev_value = *ptr;
+  } while (prev_value == old_value);
+  return prev_value;
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+                                         Atomic32 new_value) {
+  Atomic32 old_value;
+  do {
+    old_value = *ptr;
+  } while (!OSAtomicCompareAndSwap32(old_value, new_value,
+                                     const_cast<Atomic32*>(ptr)));
+  return old_value;
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+                                          Atomic32 increment) {
+  return OSAtomicAdd32(increment, const_cast<Atomic32*>(ptr));
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+                                        Atomic32 increment) {
+  return OSAtomicAdd32Barrier(increment, const_cast<Atomic32*>(ptr));
+}
+
+inline void MemoryBarrier() {
+  OSMemoryBarrier();
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  Atomic32 prev_value;
+  do {
+    if (OSAtomicCompareAndSwap32Barrier(old_value, new_value,
+                                        const_cast<Atomic32*>(ptr))) {
+      return old_value;
+    }
+    prev_value = *ptr;
+  } while (prev_value == old_value);
+  return prev_value;
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  return Acquire_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+  *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+  *ptr = value;
+  MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+  MemoryBarrier();
+  *ptr = value;
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+  return *ptr;
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+  Atomic32 value = *ptr;
+  MemoryBarrier();
+  return value;
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+  MemoryBarrier();
+  return *ptr;
+}
+
+#ifdef __LP64__
+
+// 64-bit implementation on 64-bit platform
+
+inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
+                                         Atomic64 old_value,
+                                         Atomic64 new_value) {
+  Atomic64 prev_value;
+  do {
+    if (OSAtomicCompareAndSwap64(old_value, new_value,
+                                 reinterpret_cast<volatile int64_t*>(ptr))) {
+      return old_value;
+    }
+    prev_value = *ptr;
+  } while (prev_value == old_value);
+  return prev_value;
+}
+
+inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
+                                         Atomic64 new_value) {
+  Atomic64 old_value;
+  do {
+    old_value = *ptr;
+  } while (!OSAtomicCompareAndSwap64(old_value, new_value,
+                                     reinterpret_cast<volatile int64_t*>(ptr)));
+  return old_value;
+}
+
+inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
+                                          Atomic64 increment) {
+  return OSAtomicAdd64(increment, reinterpret_cast<volatile int64_t*>(ptr));
+}
+
+inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
+                                        Atomic64 increment) {
+  return OSAtomicAdd64Barrier(increment,
+                              reinterpret_cast<volatile int64_t*>(ptr));
+}
+
+inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
+                                       Atomic64 old_value,
+                                       Atomic64 new_value) {
+  Atomic64 prev_value;
+  do {
+    if (OSAtomicCompareAndSwap64Barrier(
+        old_value, new_value, reinterpret_cast<volatile int64_t*>(ptr))) {
+      return old_value;
+    }
+    prev_value = *ptr;
+  } while (prev_value == old_value);
+  return prev_value;
+}
+
+inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
+                                       Atomic64 old_value,
+                                       Atomic64 new_value) {
+  // The lib kern interface does not distinguish between
+  // Acquire and Release memory barriers; they are equivalent.
+  return Acquire_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
+  *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
+  *ptr = value;
+  MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
+  MemoryBarrier();
+  *ptr = value;
+}
+
+inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
+  return *ptr;
+}
+
+inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
+  Atomic64 value = *ptr;
+  MemoryBarrier();
+  return value;
+}
+
+inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
+  MemoryBarrier();
+  return *ptr;
+}
+
+#endif  // defined(__LP64__)
+
+}  // namespace subtle
+}  // namespace base
+
+#endif  // BASE_ATOMICOPS_INTERNALS_MAC_H_
diff --git a/base/atomicops_internals_mips_gcc.h b/base/atomicops_internals_mips_gcc.h
new file mode 100644
index 0000000..b4551b8
--- /dev/null
+++ b/base/atomicops_internals_mips_gcc.h
@@ -0,0 +1,280 @@
+// Copyright (c) 2012 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 an internal atomic implementation, use base/atomicops.h instead.
+//
+// LinuxKernelCmpxchg and Barrier_AtomicIncrement are from Google Gears.
+
+#ifndef BASE_ATOMICOPS_INTERNALS_MIPS_GCC_H_
+#define BASE_ATOMICOPS_INTERNALS_MIPS_GCC_H_
+
+namespace base {
+namespace subtle {
+
+// Atomically execute:
+//      result = *ptr;
+//      if (*ptr == old_value)
+//        *ptr = new_value;
+//      return result;
+//
+// I.e., replace "*ptr" with "new_value" if "*ptr" used to be "old_value".
+// Always return the old value of "*ptr"
+//
+// This routine implies no memory barriers.
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+                                         Atomic32 old_value,
+                                         Atomic32 new_value) {
+  Atomic32 prev, tmp;
+  __asm__ __volatile__(".set push\n"
+                       ".set noreorder\n"
+                       "1:\n"
+                       "ll %0, %5\n"  // prev = *ptr
+                       "bne %0, %3, 2f\n"  // if (prev != old_value) goto 2
+                       "move %2, %4\n"  // tmp = new_value
+                       "sc %2, %1\n"  // *ptr = tmp (with atomic check)
+                       "beqz %2, 1b\n"  // start again on atomic error
+                       "nop\n"  // delay slot nop
+                       "2:\n"
+                       ".set pop\n"
+                       : "=&r" (prev), "=m" (*ptr), "=&r" (tmp)
+                       : "r" (old_value), "r" (new_value), "m" (*ptr)
+                       : "memory");
+  return prev;
+}
+
+// Atomically store new_value into *ptr, returning the previous value held in
+// *ptr.  This routine implies no memory barriers.
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+                                         Atomic32 new_value) {
+  Atomic32 temp, old;
+  __asm__ __volatile__(".set push\n"
+                       ".set noreorder\n"
+                       "1:\n"
+                       "ll %1, %4\n"  // old = *ptr
+                       "move %0, %3\n"  // temp = new_value
+                       "sc %0, %2\n"  // *ptr = temp (with atomic check)
+                       "beqz %0, 1b\n"  // start again on atomic error
+                       "nop\n"  // delay slot nop
+                       ".set pop\n"
+                       : "=&r" (temp), "=&r" (old), "=m" (*ptr)
+                       : "r" (new_value), "m" (*ptr)
+                       : "memory");
+
+  return old;
+}
+
+// Atomically increment *ptr by "increment".  Returns the new value of
+// *ptr with the increment applied.  This routine implies no memory barriers.
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+                                          Atomic32 increment) {
+  Atomic32 temp, temp2;
+
+  __asm__ __volatile__(".set push\n"
+                       ".set noreorder\n"
+                       "1:\n"
+                       "ll %0, %4\n"  // temp = *ptr
+                       "addu %1, %0, %3\n"  // temp2 = temp + increment
+                       "sc %1, %2\n"  // *ptr = temp2 (with atomic check)
+                       "beqz %1, 1b\n"  // start again on atomic error
+                       "addu %1, %0, %3\n"  // temp2 = temp + increment
+                       ".set pop\n"
+                       : "=&r" (temp), "=&r" (temp2), "=m" (*ptr)
+                       : "Ir" (increment), "m" (*ptr)
+                       : "memory");
+  // temp2 now holds the final value.
+  return temp2;
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+                                        Atomic32 increment) {
+  MemoryBarrier();
+  Atomic32 res = NoBarrier_AtomicIncrement(ptr, increment);
+  MemoryBarrier();
+  return res;
+}
+
+// "Acquire" operations
+// ensure that no later memory access can be reordered ahead of the operation.
+// "Release" operations ensure that no previous memory access can be reordered
+// after the operation.  "Barrier" operations have both "Acquire" and "Release"
+// semantics.   A MemoryBarrier() has "Barrier" semantics, but does no memory
+// access.
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  Atomic32 res = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+  MemoryBarrier();
+  return res;
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  MemoryBarrier();
+  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+  *ptr = value;
+}
+
+inline void MemoryBarrier() {
+  __asm__ __volatile__("sync" : : : "memory");
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+  *ptr = value;
+  MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+  MemoryBarrier();
+  *ptr = value;
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+  return *ptr;
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+  Atomic32 value = *ptr;
+  MemoryBarrier();
+  return value;
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+  MemoryBarrier();
+  return *ptr;
+}
+
+#if defined(__LP64__)
+// 64-bit versions of the atomic ops.
+
+inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
+                                         Atomic64 old_value,
+                                         Atomic64 new_value) {
+  Atomic64 prev, tmp;
+  __asm__ __volatile__(".set push\n"
+                       ".set noreorder\n"
+                       "1:\n"
+                       "lld %0, %5\n"  // prev = *ptr
+                       "bne %0, %3, 2f\n"  // if (prev != old_value) goto 2
+                       "move %2, %4\n"  // tmp = new_value
+                       "scd %2, %1\n"  // *ptr = tmp (with atomic check)
+                       "beqz %2, 1b\n"  // start again on atomic error
+                       "nop\n"  // delay slot nop
+                       "2:\n"
+                       ".set pop\n"
+                       : "=&r" (prev), "=m" (*ptr), "=&r" (tmp)
+                       : "r" (old_value), "r" (new_value), "m" (*ptr)
+                       : "memory");
+  return prev;
+}
+
+// Atomically store new_value into *ptr, returning the previous value held in
+// *ptr.  This routine implies no memory barriers.
+inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
+                                         Atomic64 new_value) {
+  Atomic64 temp, old;
+  __asm__ __volatile__(".set push\n"
+                       ".set noreorder\n"
+                       "1:\n"
+                       "lld %1, %4\n"  // old = *ptr
+                       "move %0, %3\n"  // temp = new_value
+                       "scd %0, %2\n"  // *ptr = temp (with atomic check)
+                       "beqz %0, 1b\n"  // start again on atomic error
+                       "nop\n"  // delay slot nop
+                       ".set pop\n"
+                       : "=&r" (temp), "=&r" (old), "=m" (*ptr)
+                       : "r" (new_value), "m" (*ptr)
+                       : "memory");
+
+  return old;
+}
+
+// Atomically increment *ptr by "increment".  Returns the new value of
+// *ptr with the increment applied.  This routine implies no memory barriers.
+inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
+                                          Atomic64 increment) {
+  Atomic64 temp, temp2;
+
+  __asm__ __volatile__(".set push\n"
+                       ".set noreorder\n"
+                       "1:\n"
+                       "lld %0, %4\n"  // temp = *ptr
+                       "daddu %1, %0, %3\n"  // temp2 = temp + increment
+                       "scd %1, %2\n"  // *ptr = temp2 (with atomic check)
+                       "beqz %1, 1b\n"  // start again on atomic error
+                       "daddu %1, %0, %3\n"  // temp2 = temp + increment
+                       ".set pop\n"
+                       : "=&r" (temp), "=&r" (temp2), "=m" (*ptr)
+                       : "Ir" (increment), "m" (*ptr)
+                       : "memory");
+  // temp2 now holds the final value.
+  return temp2;
+}
+
+inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
+                                        Atomic64 increment) {
+  MemoryBarrier();
+  Atomic64 res = NoBarrier_AtomicIncrement(ptr, increment);
+  MemoryBarrier();
+  return res;
+}
+
+// "Acquire" operations
+// ensure that no later memory access can be reordered ahead of the operation.
+// "Release" operations ensure that no previous memory access can be reordered
+// after the operation.  "Barrier" operations have both "Acquire" and "Release"
+// semantics.   A MemoryBarrier() has "Barrier" semantics, but does no memory
+// access.
+inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
+                                       Atomic64 old_value,
+                                       Atomic64 new_value) {
+  Atomic64 res = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+  MemoryBarrier();
+  return res;
+}
+
+inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
+                                       Atomic64 old_value,
+                                       Atomic64 new_value) {
+  MemoryBarrier();
+  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
+  *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
+  *ptr = value;
+  MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
+  MemoryBarrier();
+  *ptr = value;
+}
+
+inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
+  return *ptr;
+}
+
+inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
+  Atomic64 value = *ptr;
+  MemoryBarrier();
+  return value;
+}
+
+inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
+  MemoryBarrier();
+  return *ptr;
+}
+#endif
+
+}  // namespace subtle
+}  // namespace base
+
+#endif  // BASE_ATOMICOPS_INTERNALS_MIPS_GCC_H_
diff --git a/base/atomicops_internals_portable.h b/base/atomicops_internals_portable.h
new file mode 100644
index 0000000..d285610
--- /dev/null
+++ b/base/atomicops_internals_portable.h
@@ -0,0 +1,227 @@
+// Copyright (c) 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 an internal atomic implementation, use atomicops.h instead.
+//
+// This implementation uses C++11 atomics' member functions. The code base is
+// currently written assuming atomicity revolves around accesses instead of
+// C++11's memory locations. The burden is on the programmer to ensure that all
+// memory locations accessed atomically are never accessed non-atomically (tsan
+// should help with this).
+//
+// TODO(jfb) Modify the atomicops.h API and user code to declare atomic
+//           locations as truly atomic. See the static_assert below.
+//
+// Of note in this implementation:
+//  * All NoBarrier variants are implemented as relaxed.
+//  * All Barrier variants are implemented as sequentially-consistent.
+//  * Compare exchange's failure ordering is always the same as the success one
+//    (except for release, which fails as relaxed): using a weaker ordering is
+//    only valid under certain uses of compare exchange.
+//  * Acquire store doesn't exist in the C11 memory model, it is instead
+//    implemented as a relaxed store followed by a sequentially consistent
+//    fence.
+//  * Release load doesn't exist in the C11 memory model, it is instead
+//    implemented as sequentially consistent fence followed by a relaxed load.
+//  * Atomic increment is expected to return the post-incremented value, whereas
+//    C11 fetch add returns the previous value. The implementation therefore
+//    needs to increment twice (which the compiler should be able to detect and
+//    optimize).
+
+#ifndef BASE_ATOMICOPS_INTERNALS_PORTABLE_H_
+#define BASE_ATOMICOPS_INTERNALS_PORTABLE_H_
+
+#include <atomic>
+
+namespace base {
+namespace subtle {
+
+// This implementation is transitional and maintains the original API for
+// atomicops.h. This requires casting memory locations to the atomic types, and
+// assumes that the API and the C++11 implementation are layout-compatible,
+// which isn't true for all implementations or hardware platforms. The static
+// assertion should detect this issue, were it to fire then this header
+// shouldn't be used.
+//
+// TODO(jfb) If this header manages to stay committed then the API should be
+//           modified, and all call sites updated.
+typedef volatile std::atomic<Atomic32>* AtomicLocation32;
+static_assert(sizeof(*(AtomicLocation32) nullptr) == sizeof(Atomic32),
+              "incompatible 32-bit atomic layout");
+
+inline void MemoryBarrier() {
+#if defined(__GLIBCXX__)
+  // Work around libstdc++ bug 51038 where atomic_thread_fence was declared but
+  // not defined, leading to the linker complaining about undefined references.
+  __atomic_thread_fence(std::memory_order_seq_cst);
+#else
+  std::atomic_thread_fence(std::memory_order_seq_cst);
+#endif
+}
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+                                         Atomic32 old_value,
+                                         Atomic32 new_value) {
+  ((AtomicLocation32)ptr)
+      ->compare_exchange_strong(old_value,
+                                new_value,
+                                std::memory_order_relaxed,
+                                std::memory_order_relaxed);
+  return old_value;
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+                                         Atomic32 new_value) {
+  return ((AtomicLocation32)ptr)
+      ->exchange(new_value, std::memory_order_relaxed);
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+                                          Atomic32 increment) {
+  return increment +
+         ((AtomicLocation32)ptr)
+             ->fetch_add(increment, std::memory_order_relaxed);
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+                                        Atomic32 increment) {
+  return increment + ((AtomicLocation32)ptr)->fetch_add(increment);
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  ((AtomicLocation32)ptr)
+      ->compare_exchange_strong(old_value,
+                                new_value,
+                                std::memory_order_acquire,
+                                std::memory_order_acquire);
+  return old_value;
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  ((AtomicLocation32)ptr)
+      ->compare_exchange_strong(old_value,
+                                new_value,
+                                std::memory_order_release,
+                                std::memory_order_relaxed);
+  return old_value;
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+  ((AtomicLocation32)ptr)->store(value, std::memory_order_relaxed);
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+  ((AtomicLocation32)ptr)->store(value, std::memory_order_relaxed);
+  MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+  ((AtomicLocation32)ptr)->store(value, std::memory_order_release);
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+  return ((AtomicLocation32)ptr)->load(std::memory_order_relaxed);
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+  return ((AtomicLocation32)ptr)->load(std::memory_order_acquire);
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+  MemoryBarrier();
+  return ((AtomicLocation32)ptr)->load(std::memory_order_relaxed);
+}
+
+#if defined(ARCH_CPU_64_BITS)
+
+typedef volatile std::atomic<Atomic64>* AtomicLocation64;
+static_assert(sizeof(*(AtomicLocation64) nullptr) == sizeof(Atomic64),
+              "incompatible 64-bit atomic layout");
+
+inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
+                                         Atomic64 old_value,
+                                         Atomic64 new_value) {
+  ((AtomicLocation64)ptr)
+      ->compare_exchange_strong(old_value,
+                                new_value,
+                                std::memory_order_relaxed,
+                                std::memory_order_relaxed);
+  return old_value;
+}
+
+inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
+                                         Atomic64 new_value) {
+  return ((AtomicLocation64)ptr)
+      ->exchange(new_value, std::memory_order_relaxed);
+}
+
+inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
+                                          Atomic64 increment) {
+  return increment +
+         ((AtomicLocation64)ptr)
+             ->fetch_add(increment, std::memory_order_relaxed);
+}
+
+inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
+                                        Atomic64 increment) {
+  return increment + ((AtomicLocation64)ptr)->fetch_add(increment);
+}
+
+inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
+                                       Atomic64 old_value,
+                                       Atomic64 new_value) {
+  ((AtomicLocation64)ptr)
+      ->compare_exchange_strong(old_value,
+                                new_value,
+                                std::memory_order_acquire,
+                                std::memory_order_acquire);
+  return old_value;
+}
+
+inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
+                                       Atomic64 old_value,
+                                       Atomic64 new_value) {
+  ((AtomicLocation64)ptr)
+      ->compare_exchange_strong(old_value,
+                                new_value,
+                                std::memory_order_release,
+                                std::memory_order_relaxed);
+  return old_value;
+}
+
+inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
+  ((AtomicLocation64)ptr)->store(value, std::memory_order_relaxed);
+}
+
+inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
+  ((AtomicLocation64)ptr)->store(value, std::memory_order_relaxed);
+  MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
+  ((AtomicLocation64)ptr)->store(value, std::memory_order_release);
+}
+
+inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
+  return ((AtomicLocation64)ptr)->load(std::memory_order_relaxed);
+}
+
+inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
+  return ((AtomicLocation64)ptr)->load(std::memory_order_acquire);
+}
+
+inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
+  MemoryBarrier();
+  return ((AtomicLocation64)ptr)->load(std::memory_order_relaxed);
+}
+
+#endif  // defined(ARCH_CPU_64_BITS)
+}  // namespace subtle
+}  // namespace base
+
+#endif  // BASE_ATOMICOPS_INTERNALS_PORTABLE_H_
diff --git a/base/atomicops_internals_x86_gcc.cc b/base/atomicops_internals_x86_gcc.cc
new file mode 100644
index 0000000..c21e96d
--- /dev/null
+++ b/base/atomicops_internals_x86_gcc.cc
@@ -0,0 +1,103 @@
+// Copyright (c) 2006-2008 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 module gets enough CPU information to optimize the
+// atomicops module on x86.
+
+#include <stdint.h>
+#include <string.h>
+
+#include "base/atomicops.h"
+
+// Inline cpuid instruction.  In PIC compilations, %ebx contains the address
+// of the global offset table.  To avoid breaking such executables, this code
+// must preserve that register's value across cpuid instructions.
+//
+// The include guards are the same as in atomicops.h.
+#if defined(__i386__)
+#define cpuid(a, b, c, d, inp) \
+  asm("mov %%ebx, %%edi\n"     \
+      "cpuid\n"                \
+      "xchg %%edi, %%ebx\n"    \
+      : "=a" (a), "=D" (b), "=c" (c), "=d" (d) : "a" (inp))
+#elif defined(__x86_64__)
+#define cpuid(a, b, c, d, inp) \
+  asm("mov %%rbx, %%rdi\n"     \
+      "cpuid\n"                \
+      "xchg %%rdi, %%rbx\n"    \
+      : "=a" (a), "=D" (b), "=c" (c), "=d" (d) : "a" (inp))
+#endif
+
+#if defined(cpuid)        // initialize the struct only on x86
+
+// Set the flags so that code will run correctly and conservatively, so even
+// if we haven't been initialized yet, we're probably single threaded, and our
+// default values should hopefully be pretty safe.
+struct AtomicOps_x86CPUFeatureStruct AtomicOps_Internalx86CPUFeatures = {
+  false, // bug can't exist before process spawns multiple threads
+  false, // Chrome requires SSE2, but for transition assume not and initialize
+         // this properly.
+  false, // cmpxchg16b isn't present on early AMD64 CPUs.
+};
+
+namespace {
+
+// Initialize the AtomicOps_Internalx86CPUFeatures struct.
+void AtomicOps_Internalx86CPUFeaturesInit() {
+  uint32_t eax;
+  uint32_t ebx;
+  uint32_t ecx;
+  uint32_t edx;
+
+  // Get vendor string (issue CPUID with eax = 0)
+  cpuid(eax, ebx, ecx, edx, 0);
+  char vendor[13];
+  memcpy(vendor, &ebx, 4);
+  memcpy(vendor + 4, &edx, 4);
+  memcpy(vendor + 8, &ecx, 4);
+  vendor[12] = 0;
+
+  // get feature flags in ecx/edx, and family/model in eax
+  cpuid(eax, ebx, ecx, edx, 1);
+
+  int family = (eax >> 8) & 0xf;        // family and model fields
+  int model = (eax >> 4) & 0xf;
+  if (family == 0xf) {                  // use extended family and model fields
+    family += (eax >> 20) & 0xff;
+    model += ((eax >> 16) & 0xf) << 4;
+  }
+
+  // Opteron Rev E has a bug in which on very rare occasions a locked
+  // instruction doesn't act as a read-acquire barrier if followed by a
+  // non-locked read-modify-write instruction.  Rev F has this bug in
+  // pre-release versions, but not in versions released to customers,
+  // so we test only for Rev E, which is family 15, model 32..63 inclusive.
+  if (strcmp(vendor, "AuthenticAMD") == 0 &&       // AMD
+      family == 15 &&
+      32 <= model && model <= 63) {
+    AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug = true;
+  } else {
+    AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug = false;
+  }
+
+  // edx bit 26 is SSE2 which we use to tell use whether we can use mfence
+  AtomicOps_Internalx86CPUFeatures.has_sse2 = ((edx >> 26) & 1);
+
+  // ecx bit 13 indicates whether the cmpxchg16b instruction is supported
+  AtomicOps_Internalx86CPUFeatures.has_cmpxchg16b = ((ecx >> 13) & 1);
+}
+
+class AtomicOpsx86Initializer {
+ public:
+  AtomicOpsx86Initializer() {
+    AtomicOps_Internalx86CPUFeaturesInit();
+  }
+};
+
+// A global to get use initialized on startup via static initialization :/
+AtomicOpsx86Initializer g_initer;
+
+}  // namespace
+
+#endif  // if x86
diff --git a/base/atomicops_internals_x86_gcc.h b/base/atomicops_internals_x86_gcc.h
new file mode 100644
index 0000000..f0d2242
--- /dev/null
+++ b/base/atomicops_internals_x86_gcc.h
@@ -0,0 +1,228 @@
+// Copyright (c) 2011 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 an internal atomic implementation, use base/atomicops.h instead.
+
+#ifndef BASE_ATOMICOPS_INTERNALS_X86_GCC_H_
+#define BASE_ATOMICOPS_INTERNALS_X86_GCC_H_
+
+#define ATOMICOPS_COMPILER_BARRIER() __asm__ __volatile__("" : : : "memory")
+
+namespace base {
+namespace subtle {
+
+// 32-bit low-level operations on any platform.
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+                                         Atomic32 old_value,
+                                         Atomic32 new_value) {
+  Atomic32 prev;
+  __asm__ __volatile__("lock; cmpxchgl %1,%2"
+                       : "=a" (prev)
+                       : "q" (new_value), "m" (*ptr), "0" (old_value)
+                       : "memory");
+  return prev;
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+                                         Atomic32 new_value) {
+  __asm__ __volatile__("xchgl %1,%0"  // The lock prefix is implicit for xchg.
+                       : "=r" (new_value)
+                       : "m" (*ptr), "0" (new_value)
+                       : "memory");
+  return new_value;  // Now it's the previous value.
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+                                          Atomic32 increment) {
+  Atomic32 temp = increment;
+  __asm__ __volatile__("lock; xaddl %0,%1"
+                       : "+r" (temp), "+m" (*ptr)
+                       : : "memory");
+  // temp now holds the old value of *ptr
+  return temp + increment;
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+                                        Atomic32 increment) {
+  Atomic32 temp = increment;
+  __asm__ __volatile__("lock; xaddl %0,%1"
+                       : "+r" (temp), "+m" (*ptr)
+                       : : "memory");
+  // temp now holds the old value of *ptr
+  if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
+    __asm__ __volatile__("lfence" : : : "memory");
+  }
+  return temp + increment;
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  Atomic32 x = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+  if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
+    __asm__ __volatile__("lfence" : : : "memory");
+  }
+  return x;
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+  *ptr = value;
+}
+
+inline void MemoryBarrier() {
+  __asm__ __volatile__("mfence" : : : "memory");
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+  *ptr = value;
+  MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+  ATOMICOPS_COMPILER_BARRIER();
+  *ptr = value; // An x86 store acts as a release barrier.
+  // See comments in Atomic64 version of Release_Store(), below.
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+  return *ptr;
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+  Atomic32 value = *ptr; // An x86 load acts as a acquire barrier.
+  // See comments in Atomic64 version of Release_Store(), below.
+  ATOMICOPS_COMPILER_BARRIER();
+  return value;
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+  MemoryBarrier();
+  return *ptr;
+}
+
+#if defined(__x86_64__)
+
+// 64-bit low-level operations on 64-bit platform.
+
+inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
+                                         Atomic64 old_value,
+                                         Atomic64 new_value) {
+  Atomic64 prev;
+  __asm__ __volatile__("lock; cmpxchgq %1,%2"
+                       : "=a" (prev)
+                       : "q" (new_value), "m" (*ptr), "0" (old_value)
+                       : "memory");
+  return prev;
+}
+
+inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
+                                         Atomic64 new_value) {
+  __asm__ __volatile__("xchgq %1,%0"  // The lock prefix is implicit for xchg.
+                       : "=r" (new_value)
+                       : "m" (*ptr), "0" (new_value)
+                       : "memory");
+  return new_value;  // Now it's the previous value.
+}
+
+inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
+                                          Atomic64 increment) {
+  Atomic64 temp = increment;
+  __asm__ __volatile__("lock; xaddq %0,%1"
+                       : "+r" (temp), "+m" (*ptr)
+                       : : "memory");
+  // temp now contains the previous value of *ptr
+  return temp + increment;
+}
+
+inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
+                                        Atomic64 increment) {
+  Atomic64 temp = increment;
+  __asm__ __volatile__("lock; xaddq %0,%1"
+                       : "+r" (temp), "+m" (*ptr)
+                       : : "memory");
+  // temp now contains the previous value of *ptr
+  if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
+    __asm__ __volatile__("lfence" : : : "memory");
+  }
+  return temp + increment;
+}
+
+inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
+  *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
+  *ptr = value;
+  MemoryBarrier();
+}
+
+inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
+  ATOMICOPS_COMPILER_BARRIER();
+
+  *ptr = value; // An x86 store acts as a release barrier
+                // for current AMD/Intel chips as of Jan 2008.
+                // See also Acquire_Load(), below.
+
+  // When new chips come out, check:
+  //  IA-32 Intel Architecture Software Developer's Manual, Volume 3:
+  //  System Programming Guide, Chatper 7: Multiple-processor management,
+  //  Section 7.2, Memory Ordering.
+  // Last seen at:
+  //   http://developer.intel.com/design/pentium4/manuals/index_new.htm
+  //
+  // x86 stores/loads fail to act as barriers for a few instructions (clflush
+  // maskmovdqu maskmovq movntdq movnti movntpd movntps movntq) but these are
+  // not generated by the compiler, and are rare.  Users of these instructions
+  // need to know about cache behaviour in any case since all of these involve
+  // either flushing cache lines or non-temporal cache hints.
+}
+
+inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
+  return *ptr;
+}
+
+inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
+  Atomic64 value = *ptr; // An x86 load acts as a acquire barrier,
+                         // for current AMD/Intel chips as of Jan 2008.
+                         // See also Release_Store(), above.
+  ATOMICOPS_COMPILER_BARRIER();
+  return value;
+}
+
+inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
+  MemoryBarrier();
+  return *ptr;
+}
+
+inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
+                                       Atomic64 old_value,
+                                       Atomic64 new_value) {
+  Atomic64 x = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+  if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
+    __asm__ __volatile__("lfence" : : : "memory");
+  }
+  return x;
+}
+
+inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
+                                       Atomic64 old_value,
+                                       Atomic64 new_value) {
+  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+#endif  // defined(__x86_64__)
+
+}  // namespace subtle
+}  // namespace base
+
+#undef ATOMICOPS_COMPILER_BARRIER
+
+#endif  // BASE_ATOMICOPS_INTERNALS_X86_GCC_H_
diff --git a/base/atomicops_internals_x86_msvc.h b/base/atomicops_internals_x86_msvc.h
new file mode 100644
index 0000000..71ddca2
--- /dev/null
+++ b/base/atomicops_internals_x86_msvc.h
@@ -0,0 +1,195 @@
+// Copyright (c) 2006-2008 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 an internal atomic implementation, use base/atomicops.h instead.
+
+#ifndef BASE_ATOMICOPS_INTERNALS_X86_MSVC_H_
+#define BASE_ATOMICOPS_INTERNALS_X86_MSVC_H_
+
+#include <windows.h>
+
+#include <intrin.h>
+
+#include "base/macros.h"
+
+#if defined(ARCH_CPU_64_BITS)
+// windows.h #defines this (only on x64). This causes problems because the
+// public API also uses MemoryBarrier at the public name for this fence. So, on
+// X64, undef it, and call its documented
+// (http://msdn.microsoft.com/en-us/library/windows/desktop/ms684208.aspx)
+// implementation directly.
+#undef MemoryBarrier
+#endif
+
+namespace base {
+namespace subtle {
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+                                         Atomic32 old_value,
+                                         Atomic32 new_value) {
+  LONG result = _InterlockedCompareExchange(
+      reinterpret_cast<volatile LONG*>(ptr),
+      static_cast<LONG>(new_value),
+      static_cast<LONG>(old_value));
+  return static_cast<Atomic32>(result);
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+                                         Atomic32 new_value) {
+  LONG result = _InterlockedExchange(
+      reinterpret_cast<volatile LONG*>(ptr),
+      static_cast<LONG>(new_value));
+  return static_cast<Atomic32>(result);
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+                                        Atomic32 increment) {
+  return _InterlockedExchangeAdd(
+      reinterpret_cast<volatile LONG*>(ptr),
+      static_cast<LONG>(increment)) + increment;
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+                                          Atomic32 increment) {
+  return Barrier_AtomicIncrement(ptr, increment);
+}
+
+inline void MemoryBarrier() {
+#if defined(ARCH_CPU_64_BITS)
+  // See #undef and note at the top of this file.
+  __faststorefence();
+#else
+  // We use MemoryBarrier from WinNT.h
+  ::MemoryBarrier();
+#endif
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+                                       Atomic32 old_value,
+                                       Atomic32 new_value) {
+  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+  *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+  NoBarrier_AtomicExchange(ptr, value);
+              // acts as a barrier in this implementation
+}
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+  *ptr = value; // works w/o barrier for current Intel chips as of June 2005
+  // See comments in Atomic64 version of Release_Store() below.
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+  return *ptr;
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+  Atomic32 value = *ptr;
+  return value;
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+  MemoryBarrier();
+  return *ptr;
+}
+
+#if defined(_WIN64)
+
+// 64-bit low-level operations on 64-bit platform.
+
+COMPILE_ASSERT(sizeof(Atomic64) == sizeof(PVOID), atomic_word_is_atomic);
+
+inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
+                                         Atomic64 old_value,
+                                         Atomic64 new_value) {
+  PVOID result = InterlockedCompareExchangePointer(
+    reinterpret_cast<volatile PVOID*>(ptr),
+    reinterpret_cast<PVOID>(new_value), reinterpret_cast<PVOID>(old_value));
+  return reinterpret_cast<Atomic64>(result);
+}
+
+inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
+                                         Atomic64 new_value) {
+  PVOID result = InterlockedExchangePointer(
+    reinterpret_cast<volatile PVOID*>(ptr),
+    reinterpret_cast<PVOID>(new_value));
+  return reinterpret_cast<Atomic64>(result);
+}
+
+inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
+                                        Atomic64 increment) {
+  return InterlockedExchangeAdd64(
+      reinterpret_cast<volatile LONGLONG*>(ptr),
+      static_cast<LONGLONG>(increment)) + increment;
+}
+
+inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
+                                          Atomic64 increment) {
+  return Barrier_AtomicIncrement(ptr, increment);
+}
+
+inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
+  *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
+  NoBarrier_AtomicExchange(ptr, value);
+              // acts as a barrier in this implementation
+}
+
+inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
+  *ptr = value; // works w/o barrier for current Intel chips as of June 2005
+
+  // When new chips come out, check:
+  //  IA-32 Intel Architecture Software Developer's Manual, Volume 3:
+  //  System Programming Guide, Chatper 7: Multiple-processor management,
+  //  Section 7.2, Memory Ordering.
+  // Last seen at:
+  //   http://developer.intel.com/design/pentium4/manuals/index_new.htm
+}
+
+inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
+  return *ptr;
+}
+
+inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
+  Atomic64 value = *ptr;
+  return value;
+}
+
+inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
+  MemoryBarrier();
+  return *ptr;
+}
+
+inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
+                                       Atomic64 old_value,
+                                       Atomic64 new_value) {
+  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
+                                       Atomic64 old_value,
+                                       Atomic64 new_value) {
+  return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+
+#endif  // defined(_WIN64)
+
+}  // namespace subtle
+}  // namespace base
+
+#endif  // BASE_ATOMICOPS_INTERNALS_X86_MSVC_H_
diff --git a/base/atomicops_unittest.cc b/base/atomicops_unittest.cc
new file mode 100644
index 0000000..3fd5597
--- /dev/null
+++ b/base/atomicops_unittest.cc
@@ -0,0 +1,241 @@
+// Copyright (c) 2011 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/atomicops.h"
+
+#include <stdint.h>
+#include <string.h>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+template <class AtomicType>
+static void TestAtomicIncrement() {
+  // For now, we just test single threaded execution
+
+  // use a guard value to make sure the NoBarrier_AtomicIncrement doesn't go
+  // outside the expected address bounds.  This is in particular to
+  // test that some future change to the asm code doesn't cause the
+  // 32-bit NoBarrier_AtomicIncrement doesn't do the wrong thing on 64-bit
+  // machines.
+  struct {
+    AtomicType prev_word;
+    AtomicType count;
+    AtomicType next_word;
+  } s;
+
+  AtomicType prev_word_value, next_word_value;
+  memset(&prev_word_value, 0xFF, sizeof(AtomicType));
+  memset(&next_word_value, 0xEE, sizeof(AtomicType));
+
+  s.prev_word = prev_word_value;
+  s.count = 0;
+  s.next_word = next_word_value;
+
+  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 1), 1);
+  EXPECT_EQ(s.count, 1);
+  EXPECT_EQ(s.prev_word, prev_word_value);
+  EXPECT_EQ(s.next_word, next_word_value);
+
+  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 2), 3);
+  EXPECT_EQ(s.count, 3);
+  EXPECT_EQ(s.prev_word, prev_word_value);
+  EXPECT_EQ(s.next_word, next_word_value);
+
+  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 3), 6);
+  EXPECT_EQ(s.count, 6);
+  EXPECT_EQ(s.prev_word, prev_word_value);
+  EXPECT_EQ(s.next_word, next_word_value);
+
+  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -3), 3);
+  EXPECT_EQ(s.count, 3);
+  EXPECT_EQ(s.prev_word, prev_word_value);
+  EXPECT_EQ(s.next_word, next_word_value);
+
+  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -2), 1);
+  EXPECT_EQ(s.count, 1);
+  EXPECT_EQ(s.prev_word, prev_word_value);
+  EXPECT_EQ(s.next_word, next_word_value);
+
+  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -1), 0);
+  EXPECT_EQ(s.count, 0);
+  EXPECT_EQ(s.prev_word, prev_word_value);
+  EXPECT_EQ(s.next_word, next_word_value);
+
+  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -1), -1);
+  EXPECT_EQ(s.count, -1);
+  EXPECT_EQ(s.prev_word, prev_word_value);
+  EXPECT_EQ(s.next_word, next_word_value);
+
+  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, -4), -5);
+  EXPECT_EQ(s.count, -5);
+  EXPECT_EQ(s.prev_word, prev_word_value);
+  EXPECT_EQ(s.next_word, next_word_value);
+
+  EXPECT_EQ(base::subtle::NoBarrier_AtomicIncrement(&s.count, 5), 0);
+  EXPECT_EQ(s.count, 0);
+  EXPECT_EQ(s.prev_word, prev_word_value);
+  EXPECT_EQ(s.next_word, next_word_value);
+}
+
+
+#define NUM_BITS(T) (sizeof(T) * 8)
+
+
+template <class AtomicType>
+static void TestCompareAndSwap() {
+  AtomicType value = 0;
+  AtomicType prev = base::subtle::NoBarrier_CompareAndSwap(&value, 0, 1);
+  EXPECT_EQ(1, value);
+  EXPECT_EQ(0, prev);
+
+  // Use test value that has non-zero bits in both halves, more for testing
+  // 64-bit implementation on 32-bit platforms.
+  const AtomicType k_test_val = (static_cast<uint64_t>(1) <<
+                                 (NUM_BITS(AtomicType) - 2)) + 11;
+  value = k_test_val;
+  prev = base::subtle::NoBarrier_CompareAndSwap(&value, 0, 5);
+  EXPECT_EQ(k_test_val, value);
+  EXPECT_EQ(k_test_val, prev);
+
+  value = k_test_val;
+  prev = base::subtle::NoBarrier_CompareAndSwap(&value, k_test_val, 5);
+  EXPECT_EQ(5, value);
+  EXPECT_EQ(k_test_val, prev);
+}
+
+
+template <class AtomicType>
+static void TestAtomicExchange() {
+  AtomicType value = 0;
+  AtomicType new_value = base::subtle::NoBarrier_AtomicExchange(&value, 1);
+  EXPECT_EQ(1, value);
+  EXPECT_EQ(0, new_value);
+
+  // Use test value that has non-zero bits in both halves, more for testing
+  // 64-bit implementation on 32-bit platforms.
+  const AtomicType k_test_val = (static_cast<uint64_t>(1) <<
+                                 (NUM_BITS(AtomicType) - 2)) + 11;
+  value = k_test_val;
+  new_value = base::subtle::NoBarrier_AtomicExchange(&value, k_test_val);
+  EXPECT_EQ(k_test_val, value);
+  EXPECT_EQ(k_test_val, new_value);
+
+  value = k_test_val;
+  new_value = base::subtle::NoBarrier_AtomicExchange(&value, 5);
+  EXPECT_EQ(5, value);
+  EXPECT_EQ(k_test_val, new_value);
+}
+
+
+template <class AtomicType>
+static void TestAtomicIncrementBounds() {
+  // Test at rollover boundary between int_max and int_min
+  AtomicType test_val = (static_cast<uint64_t>(1) <<
+                         (NUM_BITS(AtomicType) - 1));
+  AtomicType value = -1 ^ test_val;
+  AtomicType new_value = base::subtle::NoBarrier_AtomicIncrement(&value, 1);
+  EXPECT_EQ(test_val, value);
+  EXPECT_EQ(value, new_value);
+
+  base::subtle::NoBarrier_AtomicIncrement(&value, -1);
+  EXPECT_EQ(-1 ^ test_val, value);
+
+  // Test at 32-bit boundary for 64-bit atomic type.
+  test_val = static_cast<uint64_t>(1) << (NUM_BITS(AtomicType) / 2);
+  value = test_val - 1;
+  new_value = base::subtle::NoBarrier_AtomicIncrement(&value, 1);
+  EXPECT_EQ(test_val, value);
+  EXPECT_EQ(value, new_value);
+
+  base::subtle::NoBarrier_AtomicIncrement(&value, -1);
+  EXPECT_EQ(test_val - 1, value);
+}
+
+// Return an AtomicType with the value 0xa5a5a5..
+template <class AtomicType>
+static AtomicType TestFillValue() {
+  AtomicType val = 0;
+  memset(&val, 0xa5, sizeof(AtomicType));
+  return val;
+}
+
+// This is a simple sanity check that values are correct. Not testing
+// atomicity
+template <class AtomicType>
+static void TestStore() {
+  const AtomicType kVal1 = TestFillValue<AtomicType>();
+  const AtomicType kVal2 = static_cast<AtomicType>(-1);
+
+  AtomicType value;
+
+  base::subtle::NoBarrier_Store(&value, kVal1);
+  EXPECT_EQ(kVal1, value);
+  base::subtle::NoBarrier_Store(&value, kVal2);
+  EXPECT_EQ(kVal2, value);
+
+  base::subtle::Acquire_Store(&value, kVal1);
+  EXPECT_EQ(kVal1, value);
+  base::subtle::Acquire_Store(&value, kVal2);
+  EXPECT_EQ(kVal2, value);
+
+  base::subtle::Release_Store(&value, kVal1);
+  EXPECT_EQ(kVal1, value);
+  base::subtle::Release_Store(&value, kVal2);
+  EXPECT_EQ(kVal2, value);
+}
+
+// This is a simple sanity check that values are correct. Not testing
+// atomicity
+template <class AtomicType>
+static void TestLoad() {
+  const AtomicType kVal1 = TestFillValue<AtomicType>();
+  const AtomicType kVal2 = static_cast<AtomicType>(-1);
+
+  AtomicType value;
+
+  value = kVal1;
+  EXPECT_EQ(kVal1, base::subtle::NoBarrier_Load(&value));
+  value = kVal2;
+  EXPECT_EQ(kVal2, base::subtle::NoBarrier_Load(&value));
+
+  value = kVal1;
+  EXPECT_EQ(kVal1, base::subtle::Acquire_Load(&value));
+  value = kVal2;
+  EXPECT_EQ(kVal2, base::subtle::Acquire_Load(&value));
+
+  value = kVal1;
+  EXPECT_EQ(kVal1, base::subtle::Release_Load(&value));
+  value = kVal2;
+  EXPECT_EQ(kVal2, base::subtle::Release_Load(&value));
+}
+
+TEST(AtomicOpsTest, Inc) {
+  TestAtomicIncrement<base::subtle::Atomic32>();
+  TestAtomicIncrement<base::subtle::AtomicWord>();
+}
+
+TEST(AtomicOpsTest, CompareAndSwap) {
+  TestCompareAndSwap<base::subtle::Atomic32>();
+  TestCompareAndSwap<base::subtle::AtomicWord>();
+}
+
+TEST(AtomicOpsTest, Exchange) {
+  TestAtomicExchange<base::subtle::Atomic32>();
+  TestAtomicExchange<base::subtle::AtomicWord>();
+}
+
+TEST(AtomicOpsTest, IncrementBounds) {
+  TestAtomicIncrementBounds<base::subtle::Atomic32>();
+  TestAtomicIncrementBounds<base::subtle::AtomicWord>();
+}
+
+TEST(AtomicOpsTest, Store) {
+  TestStore<base::subtle::Atomic32>();
+  TestStore<base::subtle::AtomicWord>();
+}
+
+TEST(AtomicOpsTest, Load) {
+  TestLoad<base::subtle::Atomic32>();
+  TestLoad<base::subtle::AtomicWord>();
+}
diff --git a/base/auto_reset.h b/base/auto_reset.h
new file mode 100644
index 0000000..a5bcfaa
--- /dev/null
+++ b/base/auto_reset.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2011 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_AUTO_RESET_H_
+#define BASE_AUTO_RESET_H_
+
+#include "base/basictypes.h"
+
+// base::AutoReset<> is useful for setting a variable to a new value only within
+// a particular scope. An base::AutoReset<> object resets a variable to its
+// original value upon destruction, making it an alternative to writing
+// "var = false;" or "var = old_val;" at all of a block's exit points.
+//
+// This should be obvious, but note that an base::AutoReset<> instance should
+// have a shorter lifetime than its scoped_variable, to prevent invalid memory
+// writes when the base::AutoReset<> object is destroyed.
+
+namespace base {
+
+template<typename T>
+class AutoReset {
+ public:
+  AutoReset(T* scoped_variable, T new_value)
+      : scoped_variable_(scoped_variable),
+        original_value_(*scoped_variable) {
+    *scoped_variable_ = new_value;
+  }
+
+  ~AutoReset() { *scoped_variable_ = original_value_; }
+
+ private:
+  T* scoped_variable_;
+  T original_value_;
+
+  DISALLOW_COPY_AND_ASSIGN(AutoReset);
+};
+
+}  // namespace base
+
+#endif  // BASE_AUTO_RESET_H_
diff --git a/base/barrier_closure.cc b/base/barrier_closure.cc
new file mode 100644
index 0000000..1dcc502
--- /dev/null
+++ b/base/barrier_closure.cc
@@ -0,0 +1,53 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/barrier_closure.h"
+
+#include "base/atomic_ref_count.h"
+#include "base/bind.h"
+
+namespace {
+
+// Maintains state for a BarrierClosure.
+class BarrierInfo {
+ public:
+  BarrierInfo(int num_callbacks_left, const base::Closure& done_closure);
+  void Run();
+
+ private:
+  base::AtomicRefCount num_callbacks_left_;
+  base::Closure done_closure_;
+};
+
+BarrierInfo::BarrierInfo(int num_callbacks, const base::Closure& done_closure)
+    : num_callbacks_left_(num_callbacks),
+      done_closure_(done_closure) {
+}
+
+void BarrierInfo::Run() {
+  DCHECK(!base::AtomicRefCountIsZero(&num_callbacks_left_));
+  if (!base::AtomicRefCountDec(&num_callbacks_left_)) {
+    base::Closure done_closure = done_closure_;
+    done_closure_.Reset();
+    done_closure.Run();
+  }
+}
+
+}  // namespace
+
+namespace base {
+
+base::Closure BarrierClosure(int num_callbacks_left,
+                             const base::Closure& done_closure) {
+  DCHECK_GE(num_callbacks_left, 0);
+
+  if (num_callbacks_left == 0)
+    done_closure.Run();
+
+  return base::Bind(&BarrierInfo::Run,
+                    base::Owned(
+                        new BarrierInfo(num_callbacks_left, done_closure)));
+}
+
+}  // namespace base
diff --git a/base/barrier_closure.h b/base/barrier_closure.h
new file mode 100644
index 0000000..b1204d8
--- /dev/null
+++ b/base/barrier_closure.h
@@ -0,0 +1,30 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_BARRIER_CLOSURE_H_
+#define BASE_BARRIER_CLOSURE_H_
+
+#include "base/base_export.h"
+#include "base/callback_forward.h"
+
+namespace base {
+
+// BarrierClosure executes |done_closure| after it has been invoked
+// |num_closures| times.
+//
+// If |num_closures| is 0, |done_closure| is executed immediately.
+//
+// BarrierClosure is thread-safe - the count of remaining closures is
+// maintained as a base::AtomicRefCount. |done_closure| will be run on
+// the thread that calls the final Run() on the returned closures.
+//
+// |done_closure| is also Reset() on the final calling thread but due to the
+// refcounted nature of callbacks, it is hard to know what thread resources
+// will be released on.
+BASE_EXPORT base::Closure BarrierClosure(int num_closures,
+                                         const base::Closure& done_closure);
+
+}  // namespace base
+
+#endif  // BASE_BARRIER_CLOSURE_H_
diff --git a/base/barrier_closure_unittest.cc b/base/barrier_closure_unittest.cc
new file mode 100644
index 0000000..dcea09f
--- /dev/null
+++ b/base/barrier_closure_unittest.cc
@@ -0,0 +1,80 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/barrier_closure.h"
+
+#include "base/bind.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+void Increment(int* count) { (*count)++; }
+
+TEST(BarrierClosureTest, RunImmediatelyForZeroClosures) {
+  int count = 0;
+  base::Closure done_closure(base::Bind(&Increment, base::Unretained(&count)));
+
+  base::Closure barrier_closure = base::BarrierClosure(0, done_closure);
+  EXPECT_EQ(1, count);
+}
+
+TEST(BarrierClosureTest, RunAfterNumClosures) {
+  int count = 0;
+  base::Closure done_closure(base::Bind(&Increment, base::Unretained(&count)));
+
+  base::Closure barrier_closure = base::BarrierClosure(2, done_closure);
+  EXPECT_EQ(0, count);
+
+  barrier_closure.Run();
+  EXPECT_EQ(0, count);
+
+  barrier_closure.Run();
+  EXPECT_EQ(1, count);
+}
+
+class DestructionIndicator {
+ public:
+  // Sets |*destructed| to true in destructor.
+  DestructionIndicator(bool* destructed) : destructed_(destructed) {
+    *destructed_ = false;
+  }
+
+  ~DestructionIndicator() { *destructed_ = true; }
+
+  void DoNothing() {}
+
+ private:
+  bool* destructed_;
+};
+
+TEST(BarrierClosureTest, ReleasesDoneClosureWhenDone) {
+  bool done_destructed = false;
+  base::Closure barrier_closure = base::BarrierClosure(
+      1, base::Bind(&DestructionIndicator::DoNothing,
+                    base::Owned(new DestructionIndicator(&done_destructed))));
+  EXPECT_FALSE(done_destructed);
+  barrier_closure.Run();
+  EXPECT_TRUE(done_destructed);
+}
+
+void ResetBarrierClosure(base::Closure* closure) {
+  *closure = base::Closure();
+}
+
+// Tests a case when |done_closure| resets a |barrier_closure|.
+// |barrier_closure| is a Closure holding the |done_closure|. |done_closure|
+// holds a pointer back to the |barrier_closure|. When |barrier_closure| is
+// Run() it calls ResetBarrierClosure() which erases the |barrier_closure| while
+// still inside of its Run(). The Run() implementation (in base::BarrierClosure)
+// must not try use itself after executing ResetBarrierClosure() or this test
+// would crash inside Run().
+TEST(BarrierClosureTest, KeepingClosureAliveUntilDone) {
+  base::Closure barrier_closure;
+  base::Closure done_closure =
+      base::Bind(ResetBarrierClosure, &barrier_closure);
+  barrier_closure = base::BarrierClosure(1, done_closure);
+  barrier_closure.Run();
+}
+
+}  // namespace
diff --git a/base/base.gyp b/base/base.gyp
new file mode 100644
index 0000000..ed8e29e
--- /dev/null
+++ b/base/base.gyp
@@ -0,0 +1,1646 @@
+# Copyright (c) 2012 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.
+
+{
+  'variables': {
+    'chromium_code': 1,
+  },
+  'includes': [
+    '../build/win_precompile.gypi',
+    'base.gypi',
+  ],
+  'targets': [
+    {
+      'target_name': 'base',
+      'type': '<(component)',
+      'toolsets': ['host', 'target'],
+      'variables': {
+        'base_target': 1,
+        'enable_wexit_time_destructors': 1,
+        'optimize': 'max',
+      },
+      'dependencies': [
+        'base_static',
+        'allocator/allocator.gyp:allocator_extension_thunks',
+        '../testing/gtest.gyp:gtest_prod',
+        '../third_party/modp_b64/modp_b64.gyp:modp_b64',
+        'third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+      ],
+      # TODO(gregoryd): direct_dependent_settings should be shared with the
+      #  64-bit target, but it doesn't work due to a bug in gyp
+      'direct_dependent_settings': {
+        'include_dirs': [
+          '..',
+        ],
+      },
+      'conditions': [
+        ['desktop_linux == 1 or chromeos == 1', {
+          'conditions': [
+            ['chromeos==1', {
+              'sources/': [ ['include', '_chromeos\\.cc$'] ]
+            }],
+          ],
+          'dependencies': [
+            'symbolize',
+            'xdg_mime',
+          ],
+          'defines': [
+            'USE_SYMBOLIZE',
+          ],
+        }, {  # desktop_linux == 0 and chromeos == 0
+            'sources/': [
+              ['exclude', '/xdg_user_dirs/'],
+              ['exclude', '_nss\\.cc$'],
+            ],
+        }],
+        ['use_glib==1', {
+          'dependencies': [
+            '../build/linux/system.gyp:glib',
+          ],
+          'export_dependent_settings': [
+            '../build/linux/system.gyp:glib',
+          ],
+        }],
+        ['OS == "android" and _toolset == "host"', {
+          # Always build base as a static_library for host toolset, even if
+          # we're doing a component build. Specifically, we only care about the
+          # target toolset using components since that's what developers are
+          # focusing on. In theory we should do this more generally for all
+          # targets when building for host, but getting the gyp magic
+          # per-toolset for the "component" variable is hard, and we really only
+          # need base on host.
+          'type': 'static_library',
+          # Base for host support is the minimum required to run the
+          # ssl false start blacklist tool. It requires further changes
+          # to generically support host builds (and tests).
+          # Note: when building for host, gyp has OS == "android",
+          # hence the *_android.cc files are included but the actual code
+          # doesn't have OS_ANDROID / ANDROID defined.
+          'conditions': [
+            ['host_os == "mac"', {
+              'sources/': [
+                ['exclude', '^native_library_linux\\.cc$'],
+                ['exclude', '^process_util_linux\\.cc$'],
+                ['exclude', '^sys_info_linux\\.cc$'],
+                ['exclude', '^sys_string_conversions_linux\\.cc$'],
+                ['exclude', '^worker_pool_linux\\.cc$'],
+              ],
+            }],
+          ],
+        }],
+        ['OS == "android" and _toolset == "target"', {
+          'conditions': [
+            ['target_arch == "ia32" or target_arch == "x64"', {
+              'sources/': [
+                ['include', '^atomicops_internals_x86_gcc\\.cc$'],
+              ],
+            }],
+            ['target_arch == "mipsel"', {
+              'sources/': [
+                ['include', '^atomicops_internals_mips_gcc\\.cc$'],
+              ],
+            }],
+          ],
+          'dependencies': [
+            'base_java',
+            'base_jni_headers',
+            '../build/android/ndk.gyp:cpu_features',
+            '../third_party/ashmem/ashmem.gyp:ashmem',
+          ],
+          'link_settings': {
+            'libraries': [
+              '-llog',
+            ],
+          },
+          'sources!': [
+            'debug/stack_trace_posix.cc',
+          ],
+        }],
+        ['os_bsd==1', {
+          'include_dirs': [
+            '/usr/local/include',
+          ],
+          'link_settings': {
+            'libraries': [
+              '-L/usr/local/lib -lexecinfo',
+            ],
+          },
+        }],
+        ['OS == "linux"', {
+          'link_settings': {
+            'libraries': [
+              # We need rt for clock_gettime().
+              '-lrt',
+              # For 'native_library_linux.cc'
+              '-ldl',
+            ],
+          },
+          'conditions': [
+            ['use_allocator!="tcmalloc"', {
+              'defines': [
+                'NO_TCMALLOC',
+              ],
+              'direct_dependent_settings': {
+                'defines': [
+                  'NO_TCMALLOC',
+                ],
+              },
+            }],
+          ],
+        }],
+        ['OS == "win"', {
+          # Specify delayload for base.dll.
+          'msvs_settings': {
+            'VCLinkerTool': {
+              'DelayLoadDLLs': [
+                'cfgmgr32.dll',
+                'powrprof.dll',
+                'setupapi.dll',
+              ],
+              'AdditionalDependencies': [
+                'cfgmgr32.lib',
+                'powrprof.lib',
+                'setupapi.lib',
+              ],
+            },
+          },
+          # Specify delayload for components that link with base.lib.
+          'all_dependent_settings': {
+            'msvs_settings': {
+              'VCLinkerTool': {
+                'DelayLoadDLLs': [
+                  'cfgmgr32.dll',
+                  'powrprof.dll',
+                  'setupapi.dll',
+                ],
+                'AdditionalDependencies': [
+                  'cfgmgr32.lib',
+                  'powrprof.lib',
+                  'setupapi.lib',
+                ],
+              },
+            },
+          },
+          'copies': [
+            {
+              'destination': '<(PRODUCT_DIR)/',
+              'files': [
+                '../build/win/dbghelp_xp/dbghelp.dll',
+              ],
+            },
+          ],
+          'dependencies': [
+           'trace_event/etw_manifest/etw_manifest.gyp:etw_manifest',
+          ],
+        }],
+        ['OS == "mac" or (OS == "ios" and _toolset == "host")', {
+          'link_settings': {
+            'libraries': [
+              '$(SDKROOT)/System/Library/Frameworks/AppKit.framework',
+              '$(SDKROOT)/System/Library/Frameworks/ApplicationServices.framework',
+              '$(SDKROOT)/System/Library/Frameworks/Carbon.framework',
+              '$(SDKROOT)/System/Library/Frameworks/CoreFoundation.framework',
+              '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+              '$(SDKROOT)/System/Library/Frameworks/IOKit.framework',
+              '$(SDKROOT)/System/Library/Frameworks/Security.framework',
+            ],
+          },
+        }],
+        ['OS == "ios" and _toolset != "host"', {
+          'link_settings': {
+            'libraries': [
+              '$(SDKROOT)/System/Library/Frameworks/CoreFoundation.framework',
+              '$(SDKROOT)/System/Library/Frameworks/CoreGraphics.framework',
+              '$(SDKROOT)/System/Library/Frameworks/CoreText.framework',
+              '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+              '$(SDKROOT)/System/Library/Frameworks/UIKit.framework',
+            ],
+          },
+        }],
+        ['OS != "win" and (OS != "ios" or _toolset == "host")', {
+            'dependencies': ['../third_party/libevent/libevent.gyp:libevent'],
+        },],
+        ['component=="shared_library"', {
+          'conditions': [
+            ['OS=="win"', {
+              'sources!': [
+                'debug/debug_on_start_win.cc',
+              ],
+            }],
+          ],
+        }],
+      ],
+      'sources': [
+        'async_socket_io_handler.h',
+        'async_socket_io_handler_posix.cc',
+        'async_socket_io_handler_win.cc',
+        'auto_reset.h',
+        'linux_util.cc',
+        'linux_util.h',
+        'message_loop/message_pump_android.cc',
+        'message_loop/message_pump_android.h',
+        'message_loop/message_pump_glib.cc',
+        'message_loop/message_pump_glib.h',
+        'message_loop/message_pump_io_ios.cc',
+        'message_loop/message_pump_io_ios.h',
+        'message_loop/message_pump_libevent.cc',
+        'message_loop/message_pump_libevent.h',
+        'message_loop/message_pump_mac.h',
+        'message_loop/message_pump_mac.mm',
+        'metrics/field_trial.cc',
+        'metrics/field_trial.h',
+        'posix/file_descriptor_shuffle.cc',
+        'posix/file_descriptor_shuffle.h',
+        'sync_socket.h',
+        'sync_socket_posix.cc',
+        'sync_socket_win.cc',
+        'third_party/xdg_user_dirs/xdg_user_dir_lookup.cc',
+        'third_party/xdg_user_dirs/xdg_user_dir_lookup.h',
+      ],
+      'includes': [
+        '../build/android/increase_size_for_speed.gypi',
+      ],
+    },
+    {
+      'target_name': 'base_i18n',
+      'type': '<(component)',
+      'variables': {
+        'enable_wexit_time_destructors': 1,
+        'optimize': 'max',
+        'base_i18n_target': 1,
+      },
+      'dependencies': [
+        'base',
+        'third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+        '../third_party/icu/icu.gyp:icui18n',
+        '../third_party/icu/icu.gyp:icuuc',
+      ],
+      'conditions': [
+        ['OS == "win"', {
+          # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+          'msvs_disabled_warnings': [
+            4267,
+          ],
+        }],
+        ['icu_use_data_file_flag==1', {
+          'defines': ['ICU_UTIL_DATA_IMPL=ICU_UTIL_DATA_FILE'],
+        }, { # else icu_use_data_file_flag !=1
+          'conditions': [
+            ['OS=="win"', {
+              'defines': ['ICU_UTIL_DATA_IMPL=ICU_UTIL_DATA_SHARED'],
+            }, {
+              'defines': ['ICU_UTIL_DATA_IMPL=ICU_UTIL_DATA_STATIC'],
+            }],
+          ],
+        }],
+        ['OS == "ios"', {
+          'toolsets': ['host', 'target'],
+        }],
+      ],
+      'export_dependent_settings': [
+        'base',
+      ],
+      'includes': [
+        '../build/android/increase_size_for_speed.gypi',
+      ],
+    },
+    {
+      'target_name': 'base_message_loop_tests',
+      'type': 'static_library',
+      'dependencies': [
+        'base',
+        '../testing/gtest.gyp:gtest',
+      ],
+      'sources': [
+        'message_loop/message_loop_test.cc',
+        'message_loop/message_loop_test.h',
+      ],
+    },
+    {
+      'target_name': 'base_prefs',
+      'type': '<(component)',
+      'variables': {
+        'enable_wexit_time_destructors': 1,
+        'optimize': 'max',
+      },
+      'dependencies': [
+        'base',
+      ],
+      'export_dependent_settings': [
+        'base',
+      ],
+      'defines': [
+        'BASE_PREFS_IMPLEMENTATION',
+      ],
+      'sources': [
+        'prefs/base_prefs_export.h',
+        'prefs/default_pref_store.cc',
+        'prefs/default_pref_store.h',
+        'prefs/json_pref_store.cc',
+        'prefs/json_pref_store.h',
+        'prefs/overlay_user_pref_store.cc',
+        'prefs/overlay_user_pref_store.h',
+        'prefs/persistent_pref_store.h',
+        'prefs/pref_change_registrar.cc',
+        'prefs/pref_change_registrar.h',
+        'prefs/pref_filter.h',
+        'prefs/pref_member.cc',
+        'prefs/pref_member.h',
+        'prefs/pref_notifier.h',
+        'prefs/pref_notifier_impl.cc',
+        'prefs/pref_notifier_impl.h',
+        'prefs/pref_observer.h',
+        'prefs/pref_registry.cc',
+        'prefs/pref_registry.h',
+        'prefs/pref_registry_simple.cc',
+        'prefs/pref_registry_simple.h',
+        'prefs/pref_service.cc',
+        'prefs/pref_service.h',
+        'prefs/pref_service_factory.cc',
+        'prefs/pref_service_factory.h',
+        'prefs/pref_store.cc',
+        'prefs/pref_store.h',
+        'prefs/pref_value_map.cc',
+        'prefs/pref_value_map.h',
+        'prefs/pref_value_store.cc',
+        'prefs/pref_value_store.h',
+        'prefs/scoped_user_pref_update.cc',
+        'prefs/scoped_user_pref_update.h',
+        'prefs/value_map_pref_store.cc',
+        'prefs/value_map_pref_store.h',
+        'prefs/writeable_pref_store.h',
+      ],
+      'includes': [
+        '../build/android/increase_size_for_speed.gypi',
+      ],
+    },
+    {
+      'target_name': 'base_prefs_test_support',
+      'type': 'static_library',
+      'dependencies': [
+        'base',
+        'base_prefs',
+        '../testing/gmock.gyp:gmock',
+      ],
+      'sources': [
+        'prefs/mock_pref_change_callback.cc',
+        'prefs/pref_store_observer_mock.cc',
+        'prefs/pref_store_observer_mock.h',
+        'prefs/testing_pref_service.cc',
+        'prefs/testing_pref_service.h',
+        'prefs/testing_pref_store.cc',
+        'prefs/testing_pref_store.h',
+      ],
+    },
+    {
+      # This is the subset of files from base that should not be used with a
+      # dynamic library. Note that this library cannot depend on base because
+      # base depends on base_static.
+      'target_name': 'base_static',
+      'type': 'static_library',
+      'variables': {
+        'enable_wexit_time_destructors': 1,
+        'optimize': 'max',
+      },
+      'toolsets': ['host', 'target'],
+      'sources': [
+        'base_switches.cc',
+        'base_switches.h',
+        'win/pe_image.cc',
+        'win/pe_image.h',
+      ],
+      'include_dirs': [
+        '..',
+      ],
+      'includes': [
+        '../build/android/increase_size_for_speed.gypi',
+      ],
+    },
+    # Include this target for a main() function that simply instantiates
+    # and runs a base::TestSuite.
+    {
+      'target_name': 'run_all_unittests',
+      'type': 'static_library',
+      'dependencies': [
+        'test_support_base',
+      ],
+      'sources': [
+        'test/run_all_unittests.cc',
+      ],
+    },
+    {
+      'target_name': 'base_unittests',
+      'type': '<(gtest_target_type)',
+      'sources': [
+        'android/application_status_listener_unittest.cc',
+        'android/content_uri_utils_unittest.cc',
+        'android/jni_android_unittest.cc',
+        'android/jni_array_unittest.cc',
+        'android/jni_string_unittest.cc',
+        'android/library_loader/library_prefetcher_unittest.cc',
+        'android/path_utils_unittest.cc',
+        'android/scoped_java_ref_unittest.cc',
+        'android/sys_utils_unittest.cc',
+        'async_socket_io_handler_unittest.cc',
+        'at_exit_unittest.cc',
+        'atomicops_unittest.cc',
+        'barrier_closure_unittest.cc',
+        'base64_unittest.cc',
+        'big_endian_unittest.cc',
+        'bind_unittest.cc',
+        'bind_unittest.nc',
+        'bits_unittest.cc',
+        'build_time_unittest.cc',
+        'callback_helpers_unittest.cc',
+        'callback_list_unittest.cc',
+        'callback_list_unittest.nc',
+        'callback_unittest.cc',
+        'callback_unittest.nc',
+        'cancelable_callback_unittest.cc',
+        'command_line_unittest.cc',
+        'containers/adapters_unittest.cc',
+        'containers/hash_tables_unittest.cc',
+        'containers/linked_list_unittest.cc',
+        'containers/mru_cache_unittest.cc',
+        'containers/scoped_ptr_hash_map_unittest.cc',
+        'containers/scoped_ptr_map_unittest.cc',
+        'containers/small_map_unittest.cc',
+        'containers/stack_container_unittest.cc',
+        'cpu_unittest.cc',
+        'debug/crash_logging_unittest.cc',
+        'debug/debugger_unittest.cc',
+        'debug/leak_tracker_unittest.cc',
+        'debug/proc_maps_linux_unittest.cc',
+        'debug/stack_trace_unittest.cc',
+        'debug/task_annotator_unittest.cc',
+        'deferred_sequenced_task_runner_unittest.cc',
+        'environment_unittest.cc',
+        'file_version_info_unittest.cc',
+        'files/dir_reader_posix_unittest.cc',
+        'files/file_path_unittest.cc',
+        'files/file_path_watcher_unittest.cc',
+        'files/file_proxy_unittest.cc',
+        'files/file_unittest.cc',
+        'files/file_util_proxy_unittest.cc',
+        'files/file_util_unittest.cc',
+        'files/important_file_writer_unittest.cc',
+        'files/memory_mapped_file_unittest.cc',
+        'files/scoped_temp_dir_unittest.cc',
+        'gmock_unittest.cc',
+        'guid_unittest.cc',
+        'hash_unittest.cc',
+        'i18n/break_iterator_unittest.cc',
+        'i18n/case_conversion_unittest.cc',
+        'i18n/char_iterator_unittest.cc',
+        'i18n/file_util_icu_unittest.cc',
+        'i18n/icu_string_conversions_unittest.cc',
+        'i18n/number_formatting_unittest.cc',
+        'i18n/rtl_unittest.cc',
+        'i18n/streaming_utf8_validator_unittest.cc',
+        'i18n/string_search_unittest.cc',
+        'i18n/time_formatting_unittest.cc',
+        'i18n/timezone_unittest.cc',
+        'id_map_unittest.cc',
+        'ios/crb_protocol_observers_unittest.mm',
+        'ios/device_util_unittest.mm',
+        'ios/weak_nsobject_unittest.mm',
+        'json/json_parser_unittest.cc',
+        'json/json_reader_unittest.cc',
+        'json/json_value_converter_unittest.cc',
+        'json/json_value_serializer_unittest.cc',
+        'json/json_writer_unittest.cc',
+        'json/string_escape_unittest.cc',
+        'lazy_instance_unittest.cc',
+        'logging_unittest.cc',
+        'mac/bind_objc_block_unittest.mm',
+        'mac/dispatch_source_mach_unittest.cc',
+        'mac/foundation_util_unittest.mm',
+        'mac/libdispatch_task_runner_unittest.cc',
+        'mac/mac_util_unittest.mm',
+        'mac/objc_property_releaser_unittest.mm',
+        'mac/scoped_nsobject_unittest.mm',
+        'mac/scoped_objc_class_swizzler_unittest.mm',
+        'mac/scoped_sending_event_unittest.mm',
+        'md5_unittest.cc',
+        'memory/aligned_memory_unittest.cc',
+        'memory/discardable_shared_memory_unittest.cc',
+        'memory/linked_ptr_unittest.cc',
+        'memory/memory_pressure_monitor_chromeos_unittest.cc',
+        'memory/memory_pressure_monitor_mac_unittest.cc',
+        'memory/memory_pressure_monitor_win_unittest.cc',
+        'memory/ref_counted_memory_unittest.cc',
+        'memory/ref_counted_unittest.cc',
+        'memory/scoped_ptr_unittest.cc',
+        'memory/scoped_ptr_unittest.nc',
+        'memory/scoped_vector_unittest.cc',
+        'memory/shared_memory_unittest.cc',
+        'memory/singleton_unittest.cc',
+        'memory/weak_ptr_unittest.cc',
+        'memory/weak_ptr_unittest.nc',
+        'message_loop/message_loop_proxy_impl_unittest.cc',
+        'message_loop/message_loop_proxy_unittest.cc',
+        'message_loop/message_loop_unittest.cc',
+        'message_loop/message_pump_glib_unittest.cc',
+        'message_loop/message_pump_io_ios_unittest.cc',
+        'message_loop/message_pump_libevent_unittest.cc',
+        'metrics/bucket_ranges_unittest.cc',
+        'metrics/field_trial_unittest.cc',
+        'metrics/histogram_base_unittest.cc',
+        'metrics/histogram_delta_serialization_unittest.cc',
+        'metrics/histogram_macros_unittest.cc',
+        'metrics/histogram_snapshot_manager_unittest.cc',
+        'metrics/histogram_unittest.cc',
+        'metrics/sample_map_unittest.cc',
+        'metrics/sample_vector_unittest.cc',
+        'metrics/sparse_histogram_unittest.cc',
+        'metrics/statistics_recorder_unittest.cc',
+        'move_unittest.cc',
+        'numerics/safe_numerics_unittest.cc',
+        'observer_list_unittest.cc',
+        'os_compat_android_unittest.cc',
+        'path_service_unittest.cc',
+        'pickle_unittest.cc',
+        'posix/file_descriptor_shuffle_unittest.cc',
+        'posix/unix_domain_socket_linux_unittest.cc',
+        'power_monitor/power_monitor_unittest.cc',
+        'prefs/default_pref_store_unittest.cc',
+        'prefs/json_pref_store_unittest.cc',
+        'prefs/mock_pref_change_callback.h',
+        'prefs/overlay_user_pref_store_unittest.cc',
+        'prefs/pref_change_registrar_unittest.cc',
+        'prefs/pref_member_unittest.cc',
+        'prefs/pref_notifier_impl_unittest.cc',
+        'prefs/pref_service_unittest.cc',
+        'prefs/pref_value_map_unittest.cc',
+        'prefs/pref_value_store_unittest.cc',
+        'prefs/scoped_user_pref_update_unittest.cc',
+        'process/memory_unittest.cc',
+        'process/memory_unittest_mac.h',
+        'process/memory_unittest_mac.mm',
+        'process/process_metrics_unittest.cc',
+        'process/process_metrics_unittest_ios.cc',
+        'process/process_unittest.cc',
+        'process/process_util_unittest.cc',
+        'profiler/stack_sampling_profiler_unittest.cc',
+        'profiler/tracked_time_unittest.cc',
+        'rand_util_unittest.cc',
+        'scoped_clear_errno_unittest.cc',
+        'scoped_generic_unittest.cc',
+        'scoped_native_library_unittest.cc',
+        'security_unittest.cc',
+        'sequence_checker_unittest.cc',
+        'sha1_unittest.cc',
+        'stl_util_unittest.cc',
+        'strings/nullable_string16_unittest.cc',
+        'strings/safe_sprintf_unittest.cc',
+        'strings/string16_unittest.cc',
+        'strings/string_number_conversions_unittest.cc',
+        'strings/string_piece_unittest.cc',
+        'strings/string_split_unittest.cc',
+        'strings/string_tokenizer_unittest.cc',
+        'strings/string_util_unittest.cc',
+        'strings/stringize_macros_unittest.cc',
+        'strings/stringprintf_unittest.cc',
+        'strings/sys_string_conversions_mac_unittest.mm',
+        'strings/sys_string_conversions_unittest.cc',
+        'strings/utf_offset_string_conversions_unittest.cc',
+        'strings/utf_string_conversions_unittest.cc',
+        'supports_user_data_unittest.cc',
+        'sync_socket_unittest.cc',
+        'synchronization/cancellation_flag_unittest.cc',
+        'synchronization/condition_variable_unittest.cc',
+        'synchronization/lock_unittest.cc',
+        'synchronization/waitable_event_unittest.cc',
+        'synchronization/waitable_event_watcher_unittest.cc',
+        'sys_info_unittest.cc',
+        'system_monitor/system_monitor_unittest.cc',
+        'task/cancelable_task_tracker_unittest.cc',
+        'task_runner_util_unittest.cc',
+        'template_util_unittest.cc',
+        'test/expectations/expectation_unittest.cc',
+        'test/expectations/parser_unittest.cc',
+        'test/histogram_tester_unittest.cc',
+        'test/test_pending_task_unittest.cc',
+        'test/test_reg_util_win_unittest.cc',
+        'test/trace_event_analyzer_unittest.cc',
+        'test/user_action_tester_unittest.cc',
+        'threading/non_thread_safe_unittest.cc',
+        'threading/platform_thread_unittest.cc',
+        'threading/sequenced_worker_pool_unittest.cc',
+        'threading/simple_thread_unittest.cc',
+        'threading/thread_checker_unittest.cc',
+        'threading/thread_collision_warner_unittest.cc',
+        'threading/thread_id_name_manager_unittest.cc',
+        'threading/thread_local_storage_unittest.cc',
+        'threading/thread_local_unittest.cc',
+        'threading/thread_unittest.cc',
+        'threading/watchdog_unittest.cc',
+        'threading/worker_pool_posix_unittest.cc',
+        'threading/worker_pool_unittest.cc',
+        'time/pr_time_unittest.cc',
+        'time/time_unittest.cc',
+        'time/time_win_unittest.cc',
+        'timer/hi_res_timer_manager_unittest.cc',
+        'timer/mock_timer_unittest.cc',
+        'timer/timer_unittest.cc',
+        'tools_sanity_unittest.cc',
+        'tracked_objects_unittest.cc',
+        'tuple_unittest.cc',
+        'values_unittest.cc',
+        'version_unittest.cc',
+        'vlog_unittest.cc',
+        'win/dllmain.cc',
+        'win/enum_variant_unittest.cc',
+        'win/event_trace_consumer_unittest.cc',
+        'win/event_trace_controller_unittest.cc',
+        'win/event_trace_provider_unittest.cc',
+        'win/i18n_unittest.cc',
+        'win/iunknown_impl_unittest.cc',
+        'win/message_window_unittest.cc',
+        'win/object_watcher_unittest.cc',
+        'win/pe_image_unittest.cc',
+        'win/registry_unittest.cc',
+        'win/scoped_bstr_unittest.cc',
+        'win/scoped_comptr_unittest.cc',
+        'win/scoped_process_information_unittest.cc',
+        'win/scoped_variant_unittest.cc',
+        'win/shortcut_unittest.cc',
+        'win/startup_information_unittest.cc',
+        'win/win_util_unittest.cc',
+        'win/wrapped_window_proc_unittest.cc',
+        '<@(trace_event_test_sources)',
+      ],
+      'dependencies': [
+        'base',
+        'base_i18n',
+        'base_message_loop_tests',
+        'base_prefs',
+        'base_prefs_test_support',
+        'base_static',
+        'run_all_unittests',
+        'test_support_base',
+        'third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+        '../testing/gmock.gyp:gmock',
+        '../testing/gtest.gyp:gtest',
+        '../third_party/icu/icu.gyp:icui18n',
+        '../third_party/icu/icu.gyp:icuuc',
+      ],
+      'includes': ['../build/nocompile.gypi'],
+      'variables': {
+         # TODO(ajwong): Is there a way to autodetect this?
+        'module_dir': 'base'
+      },
+      'conditions': [
+        ['OS == "android"', {
+          'dependencies': [
+            'android/jni_generator/jni_generator.gyp:jni_generator_tests',
+            '../testing/android/native_test.gyp:native_test_native_code',
+          ],
+        }],
+        ['OS == "ios" and _toolset != "host"', {
+          'sources/': [
+            # Only test the iOS-meaningful portion of process_utils.
+            ['exclude', '^process/memory_unittest'],
+            ['exclude', '^process/process_unittest\\.cc$'],
+            ['exclude', '^process/process_util_unittest\\.cc$'],
+            ['include', '^process/process_util_unittest_ios\\.cc$'],
+            # iOS does not use message_pump_libevent.
+            ['exclude', '^message_loop/message_pump_libevent_unittest\\.cc$'],
+          ],
+          'actions': [
+            {
+              'action_name': 'copy_test_data',
+              'variables': {
+                'test_data_files': [
+                  'test/data',
+                ],
+                'test_data_prefix': 'base',
+              },
+              'includes': [ '../build/copy_test_data_ios.gypi' ],
+            },
+          ],
+        }],
+        ['desktop_linux == 1 or chromeos == 1', {
+          'defines': [
+            'USE_SYMBOLIZE',
+          ],
+          'sources!': [
+            'file_version_info_unittest.cc',
+          ],
+          'conditions': [
+            [ 'desktop_linux==1', {
+              'sources': [
+                'nix/xdg_util_unittest.cc',
+              ],
+            }],
+          ],
+        }],
+        ['use_glib == 1', {
+          'dependencies': [
+            '../build/linux/system.gyp:glib',
+          ],
+        }, {  # use_glib == 0
+          'sources!': [
+            'message_loop/message_pump_glib_unittest.cc',
+          ]
+        }],
+        ['use_ozone == 1', {
+          'sources!': [
+            'message_loop/message_pump_glib_unittest.cc',
+          ]
+        }],
+        ['OS == "linux"', {
+          'dependencies': [
+            'malloc_wrapper',
+          ],
+          'conditions': [
+            ['use_allocator!="none"', {
+              'dependencies': [
+                'allocator/allocator.gyp:allocator',
+              ],
+            }],
+          ]},
+        ],
+        ['OS == "win"', {
+          'sources!': [
+            'file_descriptor_shuffle_unittest.cc',
+            'files/dir_reader_posix_unittest.cc',
+            'message_loop/message_pump_libevent_unittest.cc',
+            'threading/worker_pool_posix_unittest.cc',
+          ],
+          # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+          'msvs_disabled_warnings': [
+            4267,
+          ],
+          'conditions': [
+            # This is needed so base_unittests uses the allocator shim, as
+            # SecurityTest.MemoryAllocationRestriction* tests are dependent
+            # on tcmalloc.
+            # TODO(wfh): crbug.com/246278 Move tcmalloc specific tests into
+            # their own test suite.
+            ['win_use_allocator_shim==1', {
+              'dependencies': [
+                'allocator/allocator.gyp:allocator',
+              ],
+            }],
+            ['icu_use_data_file_flag==0', {
+              # This is needed to trigger the dll copy step on windows.
+              # TODO(mark): This should not be necessary.
+              'dependencies': [
+                '../third_party/icu/icu.gyp:icudata',
+              ],
+            }],
+          ],
+        }, {  # OS != "win"
+          'dependencies': [
+            '../third_party/libevent/libevent.gyp:libevent'
+          ],
+        }],
+      ],  # conditions
+      'target_conditions': [
+        ['OS == "ios" and _toolset != "host"', {
+          'sources/': [
+            # Pull in specific Mac files for iOS (which have been filtered out
+            # by file name rules).
+            ['include', '^mac/bind_objc_block_unittest\\.mm$'],
+            ['include', '^mac/foundation_util_unittest\\.mm$',],
+            ['include', '^mac/objc_property_releaser_unittest\\.mm$'],
+            ['include', '^mac/scoped_nsobject_unittest\\.mm$'],
+            ['include', '^sys_string_conversions_mac_unittest\\.mm$'],
+          ],
+        }],
+        ['OS == "android"', {
+          'sources/': [
+            ['include', '^debug/proc_maps_linux_unittest\\.cc$'],
+          ],
+        }],
+        # Enable more direct string conversions on platforms with native utf8
+        # strings
+        ['OS=="mac" or OS=="ios" or <(chromeos)==1 or <(chromecast)==1', {
+          'defines': ['SYSTEM_NATIVE_UTF8'],
+        }],
+      ],  # target_conditions
+    },
+    {
+      # GN: //base:base_perftests
+      'target_name': 'base_perftests',
+      'type': '<(gtest_target_type)',
+      'dependencies': [
+        'base',
+        'test_support_base',
+        '../testing/gtest.gyp:gtest',
+      ],
+      'sources': [
+        'message_loop/message_pump_perftest.cc',
+        'test/run_all_unittests.cc',
+        'threading/thread_perftest.cc',
+        '../testing/perf/perf_test.cc'
+      ],
+      'conditions': [
+        ['OS == "android"', {
+          'dependencies': [
+            '../testing/android/native_test.gyp:native_test_native_code',
+          ],
+        }],
+      ],
+    },
+    {
+      # GN: //base:base_i18n_perftests
+      'target_name': 'base_i18n_perftests',
+      'type': '<(gtest_target_type)',
+      'dependencies': [
+        'test_support_base',
+        'test_support_perf',
+        '../testing/gtest.gyp:gtest',
+        'base_i18n',
+        'base',
+      ],
+      'sources': [
+        'i18n/streaming_utf8_validator_perftest.cc',
+      ],
+    },
+    {
+      # GN: //base/test:test_support
+      'target_name': 'test_support_base',
+      'type': 'static_library',
+      'dependencies': [
+        'base',
+        'base_static',
+        'base_i18n',
+        '../testing/gmock.gyp:gmock',
+        '../testing/gtest.gyp:gtest',
+        '../third_party/icu/icu.gyp:icuuc',
+        '../third_party/libxml/libxml.gyp:libxml',
+        'third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+      ],
+      'export_dependent_settings': [
+        'base',
+      ],
+      'conditions': [
+        ['os_posix==0', {
+          'sources!': [
+            'test/scoped_locale.cc',
+            'test/scoped_locale.h',
+          ],
+        }],
+        ['os_bsd==1', {
+          'sources!': [
+            'test/test_file_util_linux.cc',
+          ],
+        }],
+        ['OS == "android"', {
+          'dependencies': [
+            'base_unittests_jni_headers',
+            'base_java_unittest_support',
+          ],
+        }],
+        ['OS == "ios"', {
+          'toolsets': ['host', 'target'],
+        }],
+      ],
+      'sources': [
+        'test/expectations/expectation.cc',
+        'test/expectations/expectation.h',
+        'test/expectations/parser.cc',
+        'test/expectations/parser.h',
+        'test/gtest_util.cc',
+        'test/gtest_util.h',
+        'test/gtest_xml_unittest_result_printer.cc',
+        'test/gtest_xml_unittest_result_printer.h',
+        'test/gtest_xml_util.cc',
+        'test/gtest_xml_util.h',
+        'test/histogram_tester.cc',
+        'test/histogram_tester.h',
+        'test/ios/wait_util.h',
+        'test/ios/wait_util.mm',
+        'test/launcher/test_launcher.cc',
+        'test/launcher/test_launcher.h',
+        'test/launcher/test_result.cc',
+        'test/launcher/test_result.h',
+        'test/launcher/test_results_tracker.cc',
+        'test/launcher/test_results_tracker.h',
+        'test/launcher/unit_test_launcher.cc',
+        'test/launcher/unit_test_launcher.h',
+        'test/launcher/unit_test_launcher_ios.cc',
+        'test/mock_chrome_application_mac.h',
+        'test/mock_chrome_application_mac.mm',
+        'test/mock_devices_changed_observer.cc',
+        'test/mock_devices_changed_observer.h',
+        'test/mock_entropy_provider.cc',
+        'test/mock_entropy_provider.h',
+        'test/mock_log.cc',
+        'test/mock_log.h',
+        'test/multiprocess_test.cc',
+        'test/multiprocess_test.h',
+        'test/multiprocess_test_android.cc',
+        'test/null_task_runner.cc',
+        'test/null_task_runner.h',
+        'test/opaque_ref_counted.cc',
+        'test/opaque_ref_counted.h',
+        'test/perf_log.cc',
+        'test/perf_log.h',
+        'test/perf_test_suite.cc',
+        'test/perf_test_suite.h',
+        'test/perf_time_logger.cc',
+        'test/perf_time_logger.h',
+        'test/power_monitor_test_base.cc',
+        'test/power_monitor_test_base.h',
+        'test/scoped_locale.cc',
+        'test/scoped_locale.h',
+        'test/scoped_path_override.cc',
+        'test/scoped_path_override.h',
+        'test/sequenced_task_runner_test_template.cc',
+        'test/sequenced_task_runner_test_template.h',
+        'test/sequenced_worker_pool_owner.cc',
+        'test/sequenced_worker_pool_owner.h',
+        'test/simple_test_clock.cc',
+        'test/simple_test_clock.h',
+        'test/simple_test_tick_clock.cc',
+        'test/simple_test_tick_clock.h',
+        'test/task_runner_test_template.cc',
+        'test/task_runner_test_template.h',
+        'test/test_discardable_memory_allocator.cc',
+        'test/test_discardable_memory_allocator.h',
+        'test/test_file_util.cc',
+        'test/test_file_util.h',
+        'test/test_file_util_android.cc',
+        'test/test_file_util_linux.cc',
+        'test/test_file_util_mac.cc',
+        'test/test_file_util_posix.cc',
+        'test/test_file_util_win.cc',
+        'test/test_io_thread.cc',
+        'test/test_io_thread.h',
+        'test/test_listener_ios.h',
+        'test/test_listener_ios.mm',
+        'test/test_mock_time_task_runner.cc',
+        'test/test_mock_time_task_runner.h',
+        'test/test_pending_task.cc',
+        'test/test_pending_task.h',
+        'test/test_reg_util_win.cc',
+        'test/test_reg_util_win.h',
+        'test/test_shortcut_win.cc',
+        'test/test_shortcut_win.h',
+        'test/test_simple_task_runner.cc',
+        'test/test_simple_task_runner.h',
+        'test/test_suite.cc',
+        'test/test_suite.h',
+        'test/test_support_android.cc',
+        'test/test_support_android.h',
+        'test/test_support_ios.h',
+        'test/test_support_ios.mm',
+        'test/test_switches.cc',
+        'test/test_switches.h',
+        'test/test_timeouts.cc',
+        'test/test_timeouts.h',
+        'test/test_ui_thread_android.cc',
+        'test/test_ui_thread_android.h',
+        'test/thread_test_helper.cc',
+        'test/thread_test_helper.h',
+        'test/trace_event_analyzer.cc',
+        'test/trace_event_analyzer.h',
+        'test/trace_to_file.cc',
+        'test/trace_to_file.h',
+        'test/user_action_tester.cc',
+        'test/user_action_tester.h',
+        'test/values_test_util.cc',
+        'test/values_test_util.h',
+      ],
+      'target_conditions': [
+        ['OS == "ios"', {
+          'sources/': [
+            # Pull in specific Mac files for iOS (which have been filtered out
+            # by file name rules).
+            ['include', '^test/test_file_util_mac\\.cc$'],
+          ],
+        }],
+        ['OS == "ios" and _toolset == "target"', {
+          'sources!': [
+            # iOS uses its own unit test launcher.
+            'test/launcher/unit_test_launcher.cc',
+          ],
+        }],
+        ['OS == "ios" and _toolset == "host"', {
+          'sources!': [
+            'test/launcher/unit_test_launcher_ios.cc',
+            'test/test_support_ios.h',
+            'test/test_support_ios.mm',
+          ],
+        }],
+      ],  # target_conditions
+    },
+    {
+      'target_name': 'test_support_perf',
+      'type': 'static_library',
+      'dependencies': [
+        'base',
+        'test_support_base',
+        '../testing/gtest.gyp:gtest',
+      ],
+      'sources': [
+        'test/run_all_perftests.cc',
+      ],
+      'direct_dependent_settings': {
+        'defines': [
+          'PERF_TEST',
+        ],
+      },
+    },
+    {
+      'target_name': 'test_launcher_nacl_nonsfi',
+      'conditions': [
+        ['disable_nacl==0 and disable_nacl_untrusted==0 and enable_nacl_nonsfi_test==1', {
+          'type': 'static_library',
+          'sources': [
+            'test/launcher/test_launcher_nacl_nonsfi.cc',
+          ],
+          'dependencies': [
+            'test_support_base',
+          ],
+        }, {
+          'type': 'none',
+        }],
+      ],
+    },
+  ],
+  'conditions': [
+    ['OS=="ios" and "<(GENERATOR)"=="ninja"', {
+      'targets': [
+        {
+          'target_name': 'test_launcher',
+          'toolsets': ['host'],
+          'type': 'executable',
+          'dependencies': [
+            'test_support_base',
+          ],
+          'sources': [
+            'test/launcher/test_launcher_ios.cc',
+          ],
+        },
+      ],
+    }],
+    ['OS!="ios"', {
+      'targets': [
+        {
+          # GN: //base:check_example
+          'target_name': 'check_example',
+          'type': 'executable',
+          'sources': [
+            'check_example.cc',
+          ],
+          'dependencies': [
+            'base',
+          ],
+        },
+        {
+          'target_name': 'build_utf8_validator_tables',
+          'type': 'executable',
+          'toolsets': ['host'],
+          'dependencies': [
+            'base',
+            '../third_party/icu/icu.gyp:icuuc',
+          ],
+          'sources': [
+            'i18n/build_utf8_validator_tables.cc'
+          ],
+        },
+      ],
+    }],
+    ['OS == "win" and target_arch=="ia32"', {
+      'targets': [
+        # The base_win64 target here allows us to use base for Win64 targets
+        # (the normal build is 32 bits).
+        {
+          'target_name': 'base_win64',
+          'type': '<(component)',
+          'variables': {
+            'base_target': 1,
+          },
+          'dependencies': [
+            'base_static_win64',
+            'allocator/allocator.gyp:allocator_extension_thunks_win64',
+            '../third_party/modp_b64/modp_b64.gyp:modp_b64_win64',
+            'third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations_win64',
+            'trace_event/etw_manifest/etw_manifest.gyp:etw_manifest',
+          ],
+          # TODO(gregoryd): direct_dependent_settings should be shared with the
+          # 32-bit target, but it doesn't work due to a bug in gyp
+          'direct_dependent_settings': {
+            'include_dirs': [
+              '..',
+            ],
+          },
+          'defines': [
+            'BASE_WIN64',
+            '<@(nacl_win64_defines)',
+          ],
+          'configurations': {
+            'Common_Base': {
+              'msvs_target_platform': 'x64',
+            },
+          },
+          'conditions': [
+            ['component == "shared_library"', {
+              'sources!': [
+                'debug/debug_on_start_win.cc',
+              ],
+            }],
+          ],
+          # Specify delayload for base_win64.dll.
+          'msvs_settings': {
+            'VCLinkerTool': {
+              'DelayLoadDLLs': [
+                'cfgmgr32.dll',
+                'powrprof.dll',
+                'setupapi.dll',
+              ],
+              'AdditionalDependencies': [
+                'cfgmgr32.lib',
+                'powrprof.lib',
+                'setupapi.lib',
+              ],
+            },
+          },
+          # Specify delayload for components that link with base_win64.lib.
+          'all_dependent_settings': {
+            'msvs_settings': {
+              'VCLinkerTool': {
+                'DelayLoadDLLs': [
+                  'cfgmgr32.dll',
+                  'powrprof.dll',
+                  'setupapi.dll',
+                ],
+                'AdditionalDependencies': [
+                  'cfgmgr32.lib',
+                  'powrprof.lib',
+                  'setupapi.lib',
+                ],
+              },
+            },
+          },
+          # TODO(rvargas): Bug 78117. Remove this.
+          'msvs_disabled_warnings': [
+            4244,
+            4996,
+            4267,
+          ],
+          'sources': [
+            'async_socket_io_handler.h',
+            'async_socket_io_handler_posix.cc',
+            'async_socket_io_handler_win.cc',
+            'auto_reset.h',
+            'linux_util.cc',
+            'linux_util.h',
+            'md5.cc',
+            'md5.h',
+            'message_loop/message_pump_libevent.cc',
+            'message_loop/message_pump_libevent.h',
+            'metrics/field_trial.cc',
+            'metrics/field_trial.h',
+            'posix/file_descriptor_shuffle.cc',
+            'posix/file_descriptor_shuffle.h',
+            'sync_socket.h',
+            'sync_socket_posix.cc',
+            'sync_socket_win.cc',
+            'third_party/xdg_user_dirs/xdg_user_dir_lookup.cc',
+            'third_party/xdg_user_dirs/xdg_user_dir_lookup.h',
+          ],
+        },
+        {
+          'target_name': 'base_i18n_nacl_win64',
+          'type': '<(component)',
+          # TODO(gregoryd): direct_dependent_settings should be shared with the
+          # 32-bit target, but it doesn't work due to a bug in gyp
+          'direct_dependent_settings': {
+            'include_dirs': [
+              '..',
+            ],
+          },
+          'defines': [
+            '<@(nacl_win64_defines)',
+            'BASE_I18N_IMPLEMENTATION',
+          ],
+          'include_dirs': [
+            '..',
+          ],
+          'sources': [
+            'i18n/icu_util_nacl_win64.cc',
+          ],
+          'configurations': {
+            'Common_Base': {
+              'msvs_target_platform': 'x64',
+            },
+          },
+        },
+        {
+          # TODO(rvargas): Remove this when gyp finally supports a clean model.
+          # See bug 36232.
+          'target_name': 'base_static_win64',
+          'type': 'static_library',
+          'sources': [
+            'base_switches.cc',
+            'base_switches.h',
+            'win/pe_image.cc',
+            'win/pe_image.h',
+          ],
+          'sources!': [
+            # base64.cc depends on modp_b64.
+            'base64.cc',
+          ],
+          'include_dirs': [
+            '..',
+          ],
+          'configurations': {
+            'Common_Base': {
+              'msvs_target_platform': 'x64',
+            },
+          },
+          'defines': [
+            '<@(nacl_win64_defines)',
+          ],
+          # TODO(rvargas): Bug 78117. Remove this.
+          'msvs_disabled_warnings': [
+            4244,
+          ],
+        },
+      ],
+    }],
+    ['os_posix==1 and OS!="mac" and OS!="ios"', {
+      'targets': [
+        {
+          'target_name': 'symbolize',
+          'type': 'static_library',
+          'toolsets': ['host', 'target'],
+          'variables': {
+            'chromium_code': 0,
+          },
+          'conditions': [
+            ['OS == "solaris"', {
+              'include_dirs': [
+                '/usr/gnu/include',
+                '/usr/gnu/include/libelf',
+              ],
+            },],
+          ],
+          'cflags': [
+            '-Wno-sign-compare',
+          ],
+          'cflags!': [
+            '-Wextra',
+          ],
+          'defines': [
+            'GLOG_BUILD_CONFIG_INCLUDE="build/build_config.h"',
+          ],
+          'sources': [
+            'third_party/symbolize/config.h',
+            'third_party/symbolize/demangle.cc',
+            'third_party/symbolize/demangle.h',
+            'third_party/symbolize/glog/logging.h',
+            'third_party/symbolize/glog/raw_logging.h',
+            'third_party/symbolize/symbolize.cc',
+            'third_party/symbolize/symbolize.h',
+            'third_party/symbolize/utilities.h',
+          ],
+          'include_dirs': [
+            '..',
+          ],
+          'includes': [
+            '../build/android/increase_size_for_speed.gypi',
+          ],
+        },
+        {
+          'target_name': 'xdg_mime',
+          'type': 'static_library',
+          'toolsets': ['host', 'target'],
+          'variables': {
+            'chromium_code': 0,
+          },
+          'cflags!': [
+            '-Wextra',
+          ],
+          'sources': [
+            'third_party/xdg_mime/xdgmime.c',
+            'third_party/xdg_mime/xdgmime.h',
+            'third_party/xdg_mime/xdgmimealias.c',
+            'third_party/xdg_mime/xdgmimealias.h',
+            'third_party/xdg_mime/xdgmimecache.c',
+            'third_party/xdg_mime/xdgmimecache.h',
+            'third_party/xdg_mime/xdgmimeglob.c',
+            'third_party/xdg_mime/xdgmimeglob.h',
+            'third_party/xdg_mime/xdgmimeicon.c',
+            'third_party/xdg_mime/xdgmimeicon.h',
+            'third_party/xdg_mime/xdgmimeint.c',
+            'third_party/xdg_mime/xdgmimeint.h',
+            'third_party/xdg_mime/xdgmimemagic.c',
+            'third_party/xdg_mime/xdgmimemagic.h',
+            'third_party/xdg_mime/xdgmimeparent.c',
+            'third_party/xdg_mime/xdgmimeparent.h',
+          ],
+          'includes': [
+            '../build/android/increase_size_for_speed.gypi',
+          ],
+        },
+      ],
+    }],
+    ['OS == "linux"', {
+      'targets': [
+        {
+          'target_name': 'malloc_wrapper',
+          'type': 'shared_library',
+          'dependencies': [
+            'base',
+          ],
+          'sources': [
+            'test/malloc_wrapper.cc',
+          ],
+        }
+      ],
+    }],
+    ['OS == "android"', {
+      'targets': [
+        {
+          # GN: //base:base_jni_headers
+          'target_name': 'base_jni_headers',
+          'type': 'none',
+          'sources': [
+            'android/java/src/org/chromium/base/ApkAssets.java',
+            'android/java/src/org/chromium/base/ApplicationStatus.java',
+            'android/java/src/org/chromium/base/AnimationFrameTimeHistogram.java',
+            'android/java/src/org/chromium/base/BuildInfo.java',
+            'android/java/src/org/chromium/base/CommandLine.java',
+            'android/java/src/org/chromium/base/ContentUriUtils.java',
+            'android/java/src/org/chromium/base/CpuFeatures.java',
+            'android/java/src/org/chromium/base/EventLog.java',
+            'android/java/src/org/chromium/base/FieldTrialList.java',
+            'android/java/src/org/chromium/base/ImportantFileWriterAndroid.java',
+            'android/java/src/org/chromium/base/JNIUtils.java',
+            'android/java/src/org/chromium/base/JavaHandlerThread.java',
+            'android/java/src/org/chromium/base/LocaleUtils.java',
+            'android/java/src/org/chromium/base/MemoryPressureListener.java',
+            'android/java/src/org/chromium/base/PathService.java',
+            'android/java/src/org/chromium/base/PathUtils.java',
+            'android/java/src/org/chromium/base/PowerMonitor.java',
+            'android/java/src/org/chromium/base/SysUtils.java',
+            'android/java/src/org/chromium/base/SystemMessageHandler.java',
+            'android/java/src/org/chromium/base/ThreadUtils.java',
+            'android/java/src/org/chromium/base/TraceEvent.java',
+            'android/java/src/org/chromium/base/library_loader/LibraryLoader.java',
+            'android/java/src/org/chromium/base/metrics/RecordHistogram.java',
+            'android/java/src/org/chromium/base/metrics/RecordUserAction.java',
+          ],
+          'variables': {
+            'jni_gen_package': 'base',
+          },
+          'dependencies': [
+            'android_runtime_jni_headers',
+          ],
+          'includes': [ '../build/jni_generator.gypi' ],
+        },
+        {
+          # GN: //base:android_runtime_jni_headers
+          'target_name': 'android_runtime_jni_headers',
+          'type': 'none',
+          'variables': {
+            'jni_gen_package': 'base',
+            'input_java_class': 'java/lang/Runtime.class',
+          },
+          'includes': [ '../build/jar_file_jni_generator.gypi' ],
+        },
+        {
+          # TODO(GN)
+          'target_name': 'base_unittests_jni_headers',
+          'type': 'none',
+          'sources': [
+            'test/android/java/src/org/chromium/base/ContentUriTestUtils.java',
+            'test/android/java/src/org/chromium/base/TestUiThread.java',
+          ],
+          'variables': {
+            'jni_gen_package': 'base',
+          },
+          'includes': [ '../build/jni_generator.gypi' ],
+        },
+        {
+          # GN: //base:base_native_libraries_gen
+          'target_name': 'base_native_libraries_gen',
+          'type': 'none',
+          'sources': [
+            'android/java/templates/NativeLibraries.template',
+          ],
+          'variables': {
+            'package_name': 'org/chromium/base/library_loader',
+            'template_deps': [],
+          },
+          'includes': [ '../build/android/java_cpp_template.gypi' ],
+        },
+        {
+          # GN: //base:base_android_java_enums_srcjar
+          'target_name': 'base_java_library_process_type',
+          'type': 'none',
+          'variables': {
+            'source_file': 'android/library_loader/library_loader_hooks.h',
+          },
+          'includes': [ '../build/android/java_cpp_enum.gypi' ],
+        },
+        {
+          # GN: //base:base_java
+          'target_name': 'base_java',
+          'type': 'none',
+          'variables': {
+            'java_in_dir': '../base/android/java',
+            'jar_excluded_classes': [ '*/NativeLibraries.class' ],
+          },
+          'dependencies': [
+            'base_java_application_state',
+            'base_java_library_load_from_apk_status_codes',
+            'base_java_library_process_type',
+            'base_java_memory_pressure_level',
+            'base_native_libraries_gen',
+            '../third_party/jsr-305/jsr-305.gyp:jsr_305_javalib',
+          ],
+          'includes': [ '../build/java.gypi' ],
+        },
+        {
+          # GN: //base:base_java_unittest_support
+          'target_name': 'base_java_unittest_support',
+          'type': 'none',
+          'dependencies': [
+            'base_java',
+          ],
+          'variables': {
+            'java_in_dir': '../base/test/android/java',
+          },
+          'includes': [ '../build/java.gypi' ],
+        },
+        {
+          # GN: //base:base_android_java_enums_srcjar
+          'target_name': 'base_java_application_state',
+          'type': 'none',
+          'variables': {
+            'source_file': 'android/application_status_listener.h',
+          },
+          'includes': [ '../build/android/java_cpp_enum.gypi' ],
+        },
+        {
+          # GN: //base:base_android_java_enums_srcjar
+          'target_name': 'base_java_library_load_from_apk_status_codes',
+          'type': 'none',
+          'variables': {
+            'source_file': 'android/library_loader/library_load_from_apk_status_codes.h'
+          },
+          'includes': [ '../build/android/java_cpp_enum.gypi' ],
+        },
+        {
+          # GN: //base:base_android_java_enums_srcjar
+          'target_name': 'base_java_memory_pressure_level',
+          'type': 'none',
+          'variables': {
+            'source_file': 'memory/memory_pressure_listener.h',
+          },
+          'includes': [ '../build/android/java_cpp_enum.gypi' ],
+        },
+        {
+          # GN: //base:base_java_test_support
+          'target_name': 'base_java_test_support',
+          'type': 'none',
+          'dependencies': [
+            'base_java',
+            '../testing/android/on_device_instrumentation.gyp:reporter_java',
+          ],
+          'variables': {
+            'java_in_dir': '../base/test/android/javatests',
+          },
+          'includes': [ '../build/java.gypi' ],
+        },
+        {
+          # GN: //base:base_junit_tests
+          'target_name': 'base_junit_tests',
+          'type': 'none',
+          'dependencies': [
+            'base_java',
+            'base_java_test_support',
+            '../testing/android/junit/junit_test.gyp:junit_test_support',
+          ],
+          'variables': {
+             'main_class': 'org.chromium.testing.local.JunitTestMain',
+             'src_paths': [
+               '../base/android/junit/',
+             ],
+           },
+          'includes': [ '../build/host_jar.gypi' ],
+        },
+        {
+          # GN: //base:base_javatests
+          'target_name': 'base_javatests',
+          'type': 'none',
+          'dependencies': [
+            'base_java',
+            'base_java_test_support',
+          ],
+          'variables': {
+            'java_in_dir': '../base/android/javatests',
+          },
+          'includes': [ '../build/java.gypi' ],
+        },
+        {
+          # GN: //base/android/linker:chromium_android_linker
+          'target_name': 'chromium_android_linker',
+          'type': 'shared_library',
+          'sources': [
+            'android/linker/linker_jni.cc',
+          ],
+          # The crazy linker is never instrumented.
+          'cflags!': [
+            '-finstrument-functions',
+          ],
+          'dependencies': [
+            # The NDK contains the crazy_linker here:
+            #   '<(android_ndk_root)/crazy_linker.gyp:crazy_linker'
+            # However, we use our own fork.  See bug 384700.
+            '../third_party/android_crazy_linker/crazy_linker.gyp:crazy_linker',
+          ],
+        },
+        {
+          # TODO(GN)
+          'target_name': 'base_perftests_apk',
+          'type': 'none',
+          'dependencies': [
+            'base_perftests',
+          ],
+          'variables': {
+            'test_suite_name': 'base_perftests',
+          },
+          'includes': [ '../build/apk_test.gypi' ],
+        },
+        {
+          # GN: //base:base_unittests_apk
+          'target_name': 'base_unittests_apk',
+          'type': 'none',
+          'dependencies': [
+            'base_java',
+            'base_unittests',
+          ],
+          'variables': {
+            'test_suite_name': 'base_unittests',
+            'isolate_file': 'base_unittests.isolate',
+          },
+          'includes': [ '../build/apk_test.gypi' ],
+        },
+      ],
+    }],
+    ['OS == "win"', {
+      'targets': [
+        {
+          'target_name': 'debug_message',
+          'type': 'executable',
+          'sources': [
+            'debug_message.cc',
+          ],
+          'msvs_settings': {
+            'VCLinkerTool': {
+              'SubSystem': '2',         # Set /SUBSYSTEM:WINDOWS
+            },
+          },
+        },
+        {
+          # Target to manually rebuild pe_image_test.dll which is checked into
+          # base/test/data/pe_image.
+          'target_name': 'pe_image_test',
+          'type': 'shared_library',
+          'sources': [
+            'win/pe_image_test.cc',
+          ],
+          'msvs_settings': {
+            'VCLinkerTool': {
+              'SubSystem': '2',         # Set /SUBSYSTEM:WINDOWS
+              'DelayLoadDLLs': [
+                'cfgmgr32.dll',
+                'shell32.dll',
+              ],
+              'AdditionalDependencies': [
+                'cfgmgr32.lib',
+                'shell32.lib',
+              ],
+            },
+          },
+        },
+      ],
+    }],
+    ['test_isolation_mode != "noop"', {
+      'targets': [
+        {
+          'target_name': 'base_unittests_run',
+          'type': 'none',
+          'dependencies': [
+            'base_unittests',
+          ],
+          'includes': [
+            '../build/isolate.gypi',
+          ],
+          'sources': [
+            'base_unittests.isolate',
+          ],
+        },
+      ],
+    }],
+  ],
+}
diff --git a/base/base.gypi b/base/base.gypi
new file mode 100644
index 0000000..81a8c99
--- /dev/null
+++ b/base/base.gypi
@@ -0,0 +1,1039 @@
+# Copyright (c) 2012 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.
+
+{
+  'includes': [
+    'trace_event/trace_event.gypi',
+  ],
+  'target_defaults': {
+    'variables': {
+      'base_target': 0,
+      'base_i18n_target': 0,
+    },
+    'target_conditions': [
+      # This part is shared between the targets defined below.
+      ['base_target==1', {
+        'sources': [
+          '../build/build_config.h',
+          'allocator/allocator_extension.cc',
+          'allocator/allocator_extension.h',
+          'allocator/type_profiler_control.cc',
+          'allocator/type_profiler_control.h',
+          'android/animation_frame_time_histogram.cc',
+          'android/animation_frame_time_histogram.h',
+          'android/apk_assets.cc',
+          'android/apk_assets.h',
+          'android/application_status_listener.cc',
+          'android/application_status_listener.h',
+          'android/base_jni_onload.cc',
+          'android/base_jni_onload.h',
+          'android/base_jni_registrar.cc',
+          'android/base_jni_registrar.h',
+          'android/build_info.cc',
+          'android/build_info.h',
+          'android/command_line_android.cc',
+          'android/command_line_android.h',
+          'android/content_uri_utils.cc',
+          'android/content_uri_utils.h',
+          'android/cpu_features.cc',
+          'android/event_log.cc',
+          'android/event_log.h',
+          'android/field_trial_list.cc',
+          'android/field_trial_list.h',
+          'android/fifo_utils.cc',
+          'android/fifo_utils.h',
+          'android/important_file_writer_android.cc',
+          'android/important_file_writer_android.h',
+          'android/java_handler_thread.cc',
+          'android/java_handler_thread.h',
+          'android/java_runtime.cc',
+          'android/java_runtime.h',
+          'android/jni_android.cc',
+          'android/jni_android.h',
+          'android/jni_array.cc',
+          'android/jni_array.h',
+          'android/jni_registrar.cc',
+          'android/jni_registrar.h',
+          'android/jni_string.cc',
+          'android/jni_string.h',
+          'android/jni_utils.cc',
+          'android/jni_utils.h',
+          'android/jni_weak_ref.cc',
+          'android/jni_weak_ref.h',
+          'android/library_loader/library_load_from_apk_status_codes.h',
+          'android/library_loader/library_loader_hooks.cc',
+          'android/library_loader/library_loader_hooks.h',
+          'android/library_loader/library_prefetcher.cc',
+          'android/library_loader/library_prefetcher.h',
+          'android/locale_utils.cc',
+          'android/locale_utils.h',
+          'android/memory_pressure_listener_android.cc',
+          'android/memory_pressure_listener_android.h',
+          'android/path_service_android.cc',
+          'android/path_service_android.h',
+          'android/path_utils.cc',
+          'android/path_utils.h',
+          'android/record_histogram.cc',
+          'android/record_histogram.h',
+          'android/record_user_action.cc',
+          'android/record_user_action.h',
+          'android/scoped_java_ref.cc',
+          'android/scoped_java_ref.h',
+          'android/sys_utils.cc',
+          'android/sys_utils.h',
+          'android/thread_utils.h',
+          'android/trace_event_binding.cc',
+          'android/trace_event_binding.h',
+          'at_exit.cc',
+          'at_exit.h',
+          'atomic_ref_count.h',
+          'atomic_sequence_num.h',
+          'atomicops.h',
+          'atomicops_internals_gcc.h',
+          'atomicops_internals_mac.h',
+          'atomicops_internals_portable.h',
+          'atomicops_internals_x86_gcc.cc',
+          'atomicops_internals_x86_gcc.h',
+          'atomicops_internals_x86_msvc.h',
+          'barrier_closure.cc',
+          'barrier_closure.h',
+          'base64.cc',
+          'base64.h',
+          'base_export.h',
+          'base_paths.cc',
+          'base_paths.h',
+          'base_paths_android.cc',
+          'base_paths_android.h',
+          'base_paths_mac.h',
+          'base_paths_mac.mm',
+          'base_paths_posix.cc',
+          'base_paths_posix.h',
+          'base_paths_win.cc',
+          'base_paths_win.h',
+          'base_switches.h',
+          'basictypes.h',
+          'big_endian.cc',
+          'big_endian.h',
+          'bind.h',
+          'bind_helpers.cc',
+          'bind_helpers.h',
+          'bind_internal.h',
+          'bind_internal_win.h',
+          'bits.h',
+          'build_time.cc',
+          'build_time.h',
+          'callback.h',
+          'callback_helpers.cc',
+          'callback_helpers.h',
+          'callback_internal.cc',
+          'callback_internal.h',
+          'callback_list.h',
+          'cancelable_callback.h',
+          'command_line.cc',
+          'command_line.h',
+          'compiler_specific.h',
+          'containers/adapters.h',
+          'containers/hash_tables.h',
+          'containers/linked_list.h',
+          'containers/mru_cache.h',
+          'containers/scoped_ptr_hash_map.h',
+          'containers/scoped_ptr_map.h',
+          'containers/small_map.h',
+          'containers/stack_container.h',
+          'cpu.cc',
+          'cpu.h',
+          'critical_closure.h',
+          'critical_closure_internal_ios.mm',
+          'debug/alias.cc',
+          'debug/alias.h',
+          'debug/asan_invalid_access.cc',
+          'debug/asan_invalid_access.h',
+          'debug/crash_logging.cc',
+          'debug/crash_logging.h',
+          'debug/debugger.cc',
+          'debug/debugger.h',
+          'debug/debugger_posix.cc',
+          'debug/debugger_win.cc',
+          'debug/dump_without_crashing.cc',
+          'debug/dump_without_crashing.h',
+          'debug/gdi_debug_util_win.cc',
+          'debug/gdi_debug_util_win.h',
+          # This file depends on files from the 'allocator' target,
+          # but this target does not depend on 'allocator' (see
+          # allocator.gyp for details).
+          'debug/leak_annotations.h',
+          'debug/leak_tracker.h',
+          'debug/proc_maps_linux.cc',
+          'debug/proc_maps_linux.h',
+          'debug/profiler.cc',
+          'debug/profiler.h',
+          'debug/stack_trace.cc',
+          'debug/stack_trace.h',
+          'debug/stack_trace_android.cc',
+          'debug/stack_trace_posix.cc',
+          'debug/stack_trace_win.cc',
+          'debug/task_annotator.cc',
+          'debug/task_annotator.h',
+          'deferred_sequenced_task_runner.cc',
+          'deferred_sequenced_task_runner.h',
+          'environment.cc',
+          'environment.h',
+          'file_descriptor_posix.h',
+          'file_version_info.h',
+          'file_version_info_mac.h',
+          'file_version_info_mac.mm',
+          'file_version_info_win.cc',
+          'file_version_info_win.h',
+          'files/dir_reader_fallback.h',
+          'files/dir_reader_linux.h',
+          'files/dir_reader_posix.h',
+          'files/file.cc',
+          'files/file.h',
+          'files/file_enumerator.cc',
+          'files/file_enumerator.h',
+          'files/file_enumerator_posix.cc',
+          'files/file_enumerator_win.cc',
+          'files/file_path.cc',
+          'files/file_path.h',
+          'files/file_path_constants.cc',
+          'files/file_path_watcher.cc',
+          'files/file_path_watcher.h',
+          'files/file_path_watcher_fsevents.cc',
+          'files/file_path_watcher_fsevents.h',
+          'files/file_path_watcher_kqueue.cc',
+          'files/file_path_watcher_kqueue.h',
+          'files/file_path_watcher_linux.cc',
+          'files/file_path_watcher_mac.cc',
+          'files/file_path_watcher_stub.cc',
+          'files/file_path_watcher_win.cc',
+          'files/file_posix.cc',
+          'files/file_proxy.cc',
+          'files/file_proxy.h',
+          'files/file_tracing.cc',
+          'files/file_tracing.h',
+          'files/file_util.cc',
+          'files/file_util.h',
+          'files/file_util_android.cc',
+          'files/file_util_linux.cc',
+          'files/file_util_mac.mm',
+          'files/file_util_posix.cc',
+          'files/file_util_proxy.cc',
+          'files/file_util_proxy.h',
+          'files/file_util_win.cc',
+          'files/file_win.cc',
+          'files/important_file_writer.cc',
+          'files/important_file_writer.h',
+          'files/memory_mapped_file.cc',
+          'files/memory_mapped_file.h',
+          'files/memory_mapped_file_posix.cc',
+          'files/memory_mapped_file_win.cc',
+          'files/scoped_file.cc',
+          'files/scoped_file.h',
+          'files/scoped_temp_dir.cc',
+          'files/scoped_temp_dir.h',
+          'format_macros.h',
+          'gtest_prod_util.h',
+          'guid.cc',
+          'guid.h',
+          'guid_posix.cc',
+          'guid_win.cc',
+          'hash.cc',
+          'hash.h',
+          'id_map.h',
+          'ios/block_types.h',
+          'ios/crb_protocol_observers.h',
+          'ios/crb_protocol_observers.mm',
+          'ios/device_util.h',
+          'ios/device_util.mm',
+          'ios/ios_util.h',
+          'ios/ios_util.mm',
+          'ios/scoped_critical_action.h',
+          'ios/scoped_critical_action.mm',
+          'ios/weak_nsobject.h',
+          'ios/weak_nsobject.mm',
+          'json/json_file_value_serializer.cc',
+          'json/json_file_value_serializer.h',
+          'json/json_parser.cc',
+          'json/json_parser.h',
+          'json/json_reader.cc',
+          'json/json_reader.h',
+          'json/json_string_value_serializer.cc',
+          'json/json_string_value_serializer.h',
+          'json/json_value_converter.cc',
+          'json/json_value_converter.h',
+          'json/json_writer.cc',
+          'json/json_writer.h',
+          'json/string_escape.cc',
+          'json/string_escape.h',
+          'lazy_instance.cc',
+          'lazy_instance.h',
+          'location.cc',
+          'location.h',
+          'logging.cc',
+          'logging.h',
+          'logging_win.cc',
+          'logging_win.h',
+          'mac/authorization_util.h',
+          'mac/authorization_util.mm',
+          'mac/bind_objc_block.h',
+          'mac/bundle_locations.h',
+          'mac/bundle_locations.mm',
+          'mac/close_nocancel.cc',
+          'mac/cocoa_protocols.h',
+          'mac/dispatch_source_mach.cc',
+          'mac/dispatch_source_mach.h',
+          'mac/foundation_util.h',
+          'mac/foundation_util.mm',
+          'mac/launch_services_util.cc',
+          'mac/launch_services_util.h',
+          'mac/launchd.cc',
+          'mac/launchd.h',
+          'mac/libdispatch_task_runner.cc',
+          'mac/libdispatch_task_runner.h',
+          'mac/mac_logging.cc',
+          'mac/mac_logging.h',
+          'mac/mac_util.h',
+          'mac/mac_util.mm',
+          'mac/mach_logging.cc',
+          'mac/mach_logging.h',
+          'mac/objc_property_releaser.h',
+          'mac/objc_property_releaser.mm',
+          'mac/os_crash_dumps.cc',
+          'mac/os_crash_dumps.h',
+          'mac/scoped_aedesc.h',
+          'mac/scoped_authorizationref.h',
+          'mac/scoped_block.h',
+          'mac/scoped_cftyperef.h',
+          'mac/scoped_ioobject.h',
+          'mac/scoped_ioplugininterface.h',
+          'mac/scoped_launch_data.h',
+          'mac/scoped_mach_port.cc',
+          'mac/scoped_mach_port.h',
+          'mac/scoped_mach_vm.cc',
+          'mac/scoped_mach_vm.h',
+          'mac/scoped_nsautorelease_pool.h',
+          'mac/scoped_nsautorelease_pool.mm',
+          'mac/scoped_nsexception_enabler.h',
+          'mac/scoped_nsexception_enabler.mm',
+          'mac/scoped_nsobject.h',
+          'mac/scoped_objc_class_swizzler.h',
+          'mac/scoped_objc_class_swizzler.mm',
+          'mac/scoped_sending_event.h',
+          'mac/scoped_sending_event.mm',
+          'mac/scoped_typeref.h',
+          'mac/sdk_forward_declarations.h',
+          'mac/sdk_forward_declarations.mm',
+          'macros.h',
+          'md5.cc',
+          'md5.h',
+          'memory/aligned_memory.cc',
+          'memory/aligned_memory.h',
+          'memory/discardable_memory.cc',
+          'memory/discardable_memory.h',
+          'memory/discardable_memory_allocator.cc',
+          'memory/discardable_memory_allocator.h',
+          'memory/discardable_shared_memory.cc',
+          'memory/discardable_shared_memory.h',
+          'memory/linked_ptr.h',
+          'memory/manual_constructor.h',
+          'memory/memory_pressure_listener.cc',
+          'memory/memory_pressure_listener.h',
+          'memory/memory_pressure_monitor.cc',
+          'memory/memory_pressure_monitor.h',
+          'memory/memory_pressure_monitor_chromeos.cc',
+          'memory/memory_pressure_monitor_chromeos.h',
+          'memory/memory_pressure_monitor_mac.cc',
+          'memory/memory_pressure_monitor_mac.h',
+          'memory/memory_pressure_monitor_win.cc',
+          'memory/memory_pressure_monitor_win.h',
+          'memory/raw_scoped_refptr_mismatch_checker.h',
+          'memory/ref_counted.cc',
+          'memory/ref_counted.h',
+          'memory/ref_counted_delete_on_message_loop.h',
+          'memory/ref_counted_memory.cc',
+          'memory/ref_counted_memory.h',
+          'memory/scoped_policy.h',
+          'memory/scoped_ptr.h',
+          'memory/scoped_vector.h',
+          'memory/shared_memory.h',
+          'memory/shared_memory_android.cc',
+          'memory/shared_memory_nacl.cc',
+          'memory/shared_memory_posix.cc',
+          'memory/shared_memory_win.cc',
+          'memory/singleton.cc',
+          'memory/singleton.h',
+          'memory/weak_ptr.cc',
+          'memory/weak_ptr.h',
+          'message_loop/incoming_task_queue.cc',
+          'message_loop/incoming_task_queue.h',
+          'message_loop/message_loop.cc',
+          'message_loop/message_loop.h',
+          'message_loop/message_loop_proxy.cc',
+          'message_loop/message_loop_proxy.h',
+          'message_loop/message_loop_proxy_impl.cc',
+          'message_loop/message_loop_proxy_impl.h',
+          'message_loop/message_pump.cc',
+          'message_loop/message_pump.h',
+          'message_loop/message_pump_android.cc',
+          'message_loop/message_pump_android.h',
+          'message_loop/message_pump_default.cc',
+          'message_loop/message_pump_default.h',
+          'message_loop/message_pump_win.cc',
+          'message_loop/message_pump_win.h',
+          'message_loop/timer_slack.h',
+          'metrics/bucket_ranges.cc',
+          'metrics/bucket_ranges.h',
+          'metrics/histogram.cc',
+          'metrics/histogram.h',
+          'metrics/histogram_base.cc',
+          'metrics/histogram_base.h',
+          'metrics/histogram_delta_serialization.cc',
+          'metrics/histogram_delta_serialization.h',
+          'metrics/histogram_flattener.h',
+          'metrics/histogram_macros.h',
+          'metrics/histogram_samples.cc',
+          'metrics/histogram_samples.h',
+          'metrics/histogram_snapshot_manager.cc',
+          'metrics/histogram_snapshot_manager.h',
+          'metrics/sample_map.cc',
+          'metrics/sample_map.h',
+          'metrics/sample_vector.cc',
+          'metrics/sample_vector.h',
+          'metrics/sparse_histogram.cc',
+          'metrics/sparse_histogram.h',
+          'metrics/statistics_recorder.cc',
+          'metrics/statistics_recorder.h',
+          'metrics/user_metrics.cc',
+          'metrics/user_metrics.h',
+          'metrics/user_metrics_action.h',
+          'move.h',
+          'native_library.h',
+          'native_library_ios.mm',
+          'native_library_mac.mm',
+          'native_library_posix.cc',
+          'native_library_win.cc',
+          'nix/mime_util_xdg.cc',
+          'nix/mime_util_xdg.h',
+          'nix/xdg_util.cc',
+          'nix/xdg_util.h',
+          'numerics/safe_conversions.h',
+          'numerics/safe_conversions_impl.h',
+          'numerics/safe_math.h',
+          'numerics/safe_math_impl.h',
+          'observer_list.h',
+          'observer_list_threadsafe.h',
+          'os_compat_android.cc',
+          'os_compat_android.h',
+          'os_compat_nacl.cc',
+          'os_compat_nacl.h',
+          'path_service.cc',
+          'path_service.h',
+          'pending_task.cc',
+          'pending_task.h',
+          'pickle.cc',
+          'pickle.h',
+          'port.h',
+          'posix/eintr_wrapper.h',
+          'posix/global_descriptors.cc',
+          'posix/global_descriptors.h',
+          'posix/safe_strerror.cc',
+          'posix/safe_strerror.h',
+          'posix/unix_domain_socket_linux.cc',
+          'posix/unix_domain_socket_linux.h',
+          'power_monitor/power_monitor.cc',
+          'power_monitor/power_monitor.h',
+          'power_monitor/power_monitor_device_source.cc',
+          'power_monitor/power_monitor_device_source.h',
+          'power_monitor/power_monitor_device_source_android.cc',
+          'power_monitor/power_monitor_device_source_android.h',
+          'power_monitor/power_monitor_device_source_chromeos.cc',
+          'power_monitor/power_monitor_device_source_ios.mm',
+          'power_monitor/power_monitor_device_source_mac.mm',
+          'power_monitor/power_monitor_device_source_posix.cc',
+          'power_monitor/power_monitor_device_source_win.cc',
+          'power_monitor/power_monitor_source.cc',
+          'power_monitor/power_monitor_source.h',
+          'power_monitor/power_observer.h',
+          'process/internal_linux.cc',
+          'process/internal_linux.h',
+          'process/kill.cc',
+          'process/kill.h',
+          'process/kill_mac.cc',
+          'process/kill_posix.cc',
+          'process/kill_win.cc',
+          'process/launch.cc',
+          'process/launch.h',
+          'process/launch_ios.cc',
+          'process/launch_mac.cc',
+          'process/launch_posix.cc',
+          'process/launch_win.cc',
+          'process/memory.cc',
+          'process/memory.h',
+          'process/memory_linux.cc',
+          'process/memory_mac.mm',
+          'process/memory_win.cc',
+          'process/process.h',
+          'process/process_handle_freebsd.cc',
+          'process/process_handle_linux.cc',
+          'process/process_handle_mac.cc',
+          'process/process_handle_openbsd.cc',
+          'process/process_handle_posix.cc',
+          'process/process_handle_win.cc',
+          'process/process_info.h',
+          'process/process_info_linux.cc',
+          'process/process_info_mac.cc',
+          'process/process_info_win.cc',
+          'process/process_iterator.cc',
+          'process/process_iterator.h',
+          'process/process_iterator_freebsd.cc',
+          'process/process_iterator_linux.cc',
+          'process/process_iterator_mac.cc',
+          'process/process_iterator_openbsd.cc',
+          'process/process_iterator_win.cc',
+          'process/process_linux.cc',
+          'process/process_mac.cc',
+          'process/process_metrics.cc',
+          'process/process_metrics.h',
+          'process/process_metrics_freebsd.cc',
+          'process/process_metrics_ios.cc',
+          'process/process_metrics_linux.cc',
+          'process/process_metrics_mac.cc',
+          'process/process_metrics_openbsd.cc',
+          'process/process_metrics_posix.cc',
+          'process/process_metrics_win.cc',
+          'process/process_posix.cc',
+          'process/process_win.cc',
+          'profiler/alternate_timer.cc',
+          'profiler/alternate_timer.h',
+          'profiler/native_stack_sampler.cc',
+          'profiler/native_stack_sampler.h',
+          'profiler/scoped_profile.cc',
+          'profiler/scoped_profile.h',
+          'profiler/scoped_tracker.cc',
+          'profiler/scoped_tracker.h',
+          'profiler/stack_sampling_profiler.cc',
+          'profiler/stack_sampling_profiler.h',
+          'profiler/stack_sampling_profiler_posix.cc',
+          'profiler/stack_sampling_profiler_win.cc',
+          'profiler/tracked_time.cc',
+          'profiler/tracked_time.h',
+          'rand_util.cc',
+          'rand_util.h',
+          'rand_util_nacl.cc',
+          'rand_util_posix.cc',
+          'rand_util_win.cc',
+          'run_loop.cc',
+          'run_loop.h',
+          'scoped_generic.h',
+          'scoped_native_library.cc',
+          'scoped_native_library.h',
+          'scoped_observer.h',
+          'sequence_checker.h',
+          'sequence_checker_impl.cc',
+          'sequence_checker_impl.h',
+          'sequenced_task_runner.cc',
+          'sequenced_task_runner.h',
+          'sequenced_task_runner_helpers.h',
+          'sha1.h',
+          'sha1_portable.cc',
+          'sha1_win.cc',
+          'single_thread_task_runner.h',
+          'stl_util.h',
+          'strings/latin1_string_conversions.cc',
+          'strings/latin1_string_conversions.h',
+          'strings/nullable_string16.cc',
+          'strings/nullable_string16.h',
+          'strings/safe_sprintf.cc',
+          'strings/safe_sprintf.h',
+          'strings/string16.cc',
+          'strings/string16.h',
+          'strings/string_number_conversions.cc',
+          'strings/string_number_conversions.h',
+          'strings/string_piece.cc',
+          'strings/string_piece.h',
+          'strings/string_split.cc',
+          'strings/string_split.h',
+          'strings/string_tokenizer.h',
+          'strings/string_util.cc',
+          'strings/string_util.h',
+          'strings/string_util_constants.cc',
+          'strings/string_util_posix.h',
+          'strings/string_util_win.h',
+          'strings/stringize_macros.h',
+          'strings/stringprintf.cc',
+          'strings/stringprintf.h',
+          'strings/sys_string_conversions.h',
+          'strings/sys_string_conversions_mac.mm',
+          'strings/sys_string_conversions_posix.cc',
+          'strings/sys_string_conversions_win.cc',
+          'strings/utf_offset_string_conversions.cc',
+          'strings/utf_offset_string_conversions.h',
+          'strings/utf_string_conversion_utils.cc',
+          'strings/utf_string_conversion_utils.h',
+          'strings/utf_string_conversions.cc',
+          'strings/utf_string_conversions.h',
+          'supports_user_data.cc',
+          'supports_user_data.h',
+          'synchronization/cancellation_flag.cc',
+          'synchronization/cancellation_flag.h',
+          'synchronization/condition_variable.h',
+          'synchronization/condition_variable_posix.cc',
+          'synchronization/condition_variable_win.cc',
+          'synchronization/lock.cc',
+          'synchronization/lock.h',
+          'synchronization/lock_impl.h',
+          'synchronization/lock_impl_posix.cc',
+          'synchronization/lock_impl_win.cc',
+          'synchronization/spin_wait.h',
+          'synchronization/waitable_event.h',
+          'synchronization/waitable_event_posix.cc',
+          'synchronization/waitable_event_watcher.h',
+          'synchronization/waitable_event_watcher_posix.cc',
+          'synchronization/waitable_event_watcher_win.cc',
+          'synchronization/waitable_event_win.cc',
+          'sys_byteorder.h',
+          'sys_info.cc',
+          'sys_info.h',
+          'sys_info_android.cc',
+          'sys_info_chromeos.cc',
+          'sys_info_freebsd.cc',
+          'sys_info_internal.h',
+          'sys_info_ios.mm',
+          'sys_info_linux.cc',
+          'sys_info_mac.cc',
+          'sys_info_openbsd.cc',
+          'sys_info_posix.cc',
+          'sys_info_win.cc',
+          'system_monitor/system_monitor.cc',
+          'system_monitor/system_monitor.h',
+          'task/cancelable_task_tracker.cc',
+          'task/cancelable_task_tracker.h',
+          'task_runner.cc',
+          'task_runner.h',
+          'task_runner_util.h',
+          'template_util.h',
+          'third_party/dmg_fp/dmg_fp.h',
+          'third_party/dmg_fp/dtoa_wrapper.cc',
+          'third_party/dmg_fp/g_fmt.cc',
+          'third_party/icu/icu_utf.cc',
+          'third_party/icu/icu_utf.h',
+          'third_party/nspr/prtime.cc',
+          'third_party/nspr/prtime.h',
+          'third_party/superfasthash/superfasthash.c',
+          'third_party/xdg_mime/xdgmime.h',
+          'thread_task_runner_handle.cc',
+          'thread_task_runner_handle.h',
+          'threading/non_thread_safe.h',
+          'threading/non_thread_safe_impl.cc',
+          'threading/non_thread_safe_impl.h',
+          'threading/platform_thread.h',
+          'threading/platform_thread_android.cc',
+          'threading/platform_thread_internal_posix.cc',
+          'threading/platform_thread_internal_posix.h',
+          'threading/platform_thread_linux.cc',
+          'threading/platform_thread_mac.mm',
+          'threading/platform_thread_posix.cc',
+          'threading/platform_thread_win.cc',
+          'threading/post_task_and_reply_impl.cc',
+          'threading/post_task_and_reply_impl.h',
+          'threading/sequenced_worker_pool.cc',
+          'threading/sequenced_worker_pool.h',
+          'threading/simple_thread.cc',
+          'threading/simple_thread.h',
+          'threading/thread.cc',
+          'threading/thread.h',
+          'threading/thread_checker.h',
+          'threading/thread_checker_impl.cc',
+          'threading/thread_checker_impl.h',
+          'threading/thread_collision_warner.cc',
+          'threading/thread_collision_warner.h',
+          'threading/thread_id_name_manager.cc',
+          'threading/thread_id_name_manager.h',
+          'threading/thread_local.h',
+          'threading/thread_local_android.cc',
+          'threading/thread_local_posix.cc',
+          'threading/thread_local_storage.cc',
+          'threading/thread_local_storage.h',
+          'threading/thread_local_storage_posix.cc',
+          'threading/thread_local_storage_win.cc',
+          'threading/thread_local_win.cc',
+          'threading/thread_restrictions.cc',
+          'threading/thread_restrictions.h',
+          'threading/watchdog.cc',
+          'threading/watchdog.h',
+          'threading/worker_pool.cc',
+          'threading/worker_pool.h',
+          'threading/worker_pool_posix.cc',
+          'threading/worker_pool_posix.h',
+          'threading/worker_pool_win.cc',
+          'time/clock.cc',
+          'time/clock.h',
+          'time/default_clock.cc',
+          'time/default_clock.h',
+          'time/default_tick_clock.cc',
+          'time/default_tick_clock.h',
+          'time/tick_clock.cc',
+          'time/tick_clock.h',
+          'time/time.cc',
+          'time/time.h',
+          'time/time_mac.cc',
+          'time/time_posix.cc',
+          'time/time_win.cc',
+          'timer/elapsed_timer.cc',
+          'timer/elapsed_timer.h',
+          'timer/hi_res_timer_manager.h',
+          'timer/hi_res_timer_manager_posix.cc',
+          'timer/hi_res_timer_manager_win.cc',
+          'timer/mock_timer.cc',
+          'timer/mock_timer.h',
+          'timer/timer.cc',
+          'timer/timer.h',
+          'tracked_objects.cc',
+          'tracked_objects.h',
+          'tracking_info.cc',
+          'tracking_info.h',
+          'tuple.h',
+          'value_conversions.cc',
+          'value_conversions.h',
+          'values.cc',
+          'values.h',
+          'version.cc',
+          'version.h',
+          'vlog.cc',
+          'vlog.h',
+          'win/enum_variant.cc',
+          'win/enum_variant.h',
+          'win/event_trace_consumer.h',
+          'win/event_trace_controller.cc',
+          'win/event_trace_controller.h',
+          'win/event_trace_provider.cc',
+          'win/event_trace_provider.h',
+          'win/i18n.cc',
+          'win/i18n.h',
+          'win/iat_patch_function.cc',
+          'win/iat_patch_function.h',
+          'win/iunknown_impl.cc',
+          'win/iunknown_impl.h',
+          'win/message_window.cc',
+          'win/message_window.h',
+          'win/metro.cc',
+          'win/metro.h',
+          'win/object_watcher.cc',
+          'win/object_watcher.h',
+          'win/registry.cc',
+          'win/registry.h',
+          'win/resource_util.cc',
+          'win/resource_util.h',
+          'win/scoped_bstr.cc',
+          'win/scoped_bstr.h',
+          'win/scoped_co_mem.h',
+          'win/scoped_com_initializer.h',
+          'win/scoped_comptr.h',
+          'win/scoped_gdi_object.h',
+          'win/scoped_handle.cc',
+          'win/scoped_handle.h',
+          'win/scoped_hdc.h',
+          'win/scoped_hglobal.h',
+          'win/scoped_process_information.cc',
+          'win/scoped_process_information.h',
+          'win/scoped_propvariant.h',
+          'win/scoped_select_object.h',
+          'win/scoped_variant.cc',
+          'win/scoped_variant.h',
+          'win/shortcut.cc',
+          'win/shortcut.h',
+          'win/startup_information.cc',
+          'win/startup_information.h',
+          'win/win_util.cc',
+          'win/win_util.h',
+          'win/windows_version.cc',
+          'win/windows_version.h',
+          'win/wrapped_window_proc.cc',
+          'win/wrapped_window_proc.h',
+          '<@(trace_event_sources)',
+        ],
+        'defines': [
+          'BASE_IMPLEMENTATION',
+        ],
+        'include_dirs': [
+          '..',
+        ],
+        'msvs_disabled_warnings': [
+          4018,
+        ],
+        'target_conditions': [
+          ['(<(desktop_linux) == 0 and <(chromeos) == 0) or >(nacl_untrusted_build)==1', {
+              'sources/': [
+                ['exclude', '^nix/'],
+              ],
+              'sources!': [
+                'atomicops_internals_x86_gcc.cc',
+              ],
+          }],
+          ['<(use_glib)==0 or >(nacl_untrusted_build)==1', {
+              'sources!': [
+                'message_loop/message_pump_glib.cc',
+              ],
+          }],
+          ['(OS != "linux" and <(os_bsd) != 1 and OS != "android") or >(nacl_untrusted_build)==1', {
+              'sources!': [
+                # Not automatically excluded by the *linux.cc rules.
+                'linux_util.cc',
+              ],
+            },
+          ],
+          ['>(nacl_untrusted_build)==1', {
+            'sources!': [
+               'allocator/type_profiler_control.cc',
+               'allocator/type_profiler_control.h',
+               'base_paths.cc',
+               'cpu.cc',
+               'debug/stack_trace.cc',
+               'debug/stack_trace_posix.cc',
+               'files/file_enumerator_posix.cc',
+               'files/file_path_watcher_fsevents.cc',
+               'files/file_path_watcher_fsevents.h',
+               'files/file_path_watcher_kqueue.cc',
+               'files/file_path_watcher_kqueue.h',
+               'files/file_proxy.cc',
+               'files/file_util.cc',
+               'files/file_util_posix.cc',
+               'files/file_util_proxy.cc',
+               'files/important_file_writer.cc',
+               'files/scoped_temp_dir.cc',
+               'memory/shared_memory_posix.cc',
+               'native_library_posix.cc',
+               'path_service.cc',
+               'posix/unix_domain_socket_linux.cc',
+               'process/kill.cc',
+               'process/kill_posix.cc',
+               'process/launch.cc',
+               'process/launch_posix.cc',
+               'process/process_metrics.cc',
+               'process/process_metrics_posix.cc',
+               'process/process_posix.cc',
+               'rand_util_posix.cc',
+               'scoped_native_library.cc',
+               'sys_info.cc',
+               'sys_info_posix.cc',
+               'third_party/dynamic_annotations/dynamic_annotations.c',
+            ],
+            'sources/': [
+              ['include', '^threading/platform_thread_linux\\.cc$'],
+            ],
+          }],
+          ['OS == "android" and >(nacl_untrusted_build)==0', {
+            'sources!': [
+              'base_paths_posix.cc',
+              'files/file_path_watcher_fsevents.cc',
+              'files/file_path_watcher_fsevents.h',
+              'files/file_path_watcher_kqueue.cc',
+              'files/file_path_watcher_kqueue.h',
+              'files/file_path_watcher_stub.cc',
+              'power_monitor/power_monitor_device_source_posix.cc',
+            ],
+            'sources/': [
+              ['include', '^debug/proc_maps_linux\\.cc$'],
+              ['include', '^files/file_path_watcher_linux\\.cc$'],
+              ['include', '^process/memory_linux\\.cc$'],
+              ['include', '^process/internal_linux\\.cc$'],
+              ['include', '^process/process_handle_linux\\.cc$'],
+              ['include', '^process/process_iterator\\.cc$'],
+              ['include', '^process/process_iterator_linux\\.cc$'],
+              ['include', '^process/process_metrics_linux\\.cc$'],
+              ['include', '^posix/unix_domain_socket_linux\\.cc$'],
+              ['include', '^strings/sys_string_conversions_posix\\.cc$'],
+              ['include', '^sys_info_linux\\.cc$'],
+              ['include', '^worker_pool_linux\\.cc$'],
+            ],
+          }],
+          ['OS == "android" and _toolset == "host" and host_os == "linux"', {
+            'defines': [
+              'OS_ANDROID_HOST=Linux',
+            ],
+            'sources/': [
+              # Pull in specific files for host builds.
+              ['include', '^atomicops_internals_x86_gcc\\.cc$'],
+              ['include', '^threading/platform_thread_linux\\.cc$'],
+            ],
+          }],
+          ['<(chromeos) == 1', {
+            'sources!': [
+              'power_monitor/power_monitor_device_source_posix.cc',
+            ],
+          }],
+          ['OS == "ios" and _toolset != "host"', {
+            'sources/': [
+              # Pull in specific Mac files for iOS (which have been filtered out
+              # by file name rules).
+              ['include', '^atomicops_internals_mac\\.'],
+              ['include', '^base_paths_mac\\.'],
+              ['include', '^files/file_util_mac\\.'],
+              ['include', '^file_version_info_mac\\.'],
+              ['include', '^mac/bundle_locations\\.'],
+              ['include', '^mac/foundation_util\\.'],
+              ['include', '^mac/mac_logging\\.'],
+              ['include', '^mac/mach_logging\\.'],
+              ['include', '^mac/objc_property_releaser\\.'],
+              ['include', '^mac/scoped_mach_port\\.'],
+              ['include', '^mac/scoped_mach_vm\\.'],
+              ['include', '^mac/scoped_nsautorelease_pool\\.'],
+              ['include', '^mac/scoped_nsobject\\.'],
+              ['include', '^mac/scoped_objc_class_swizzler\\.'],
+              ['include', '^message_loop/message_pump_mac\\.'],
+              ['include', '^strings/sys_string_conversions_mac\\.'],
+              ['include', '^threading/platform_thread_mac\\.'],
+              ['include', '^time/time_mac\\.'],
+              ['include', '^worker_pool_mac\\.'],
+              # Exclude all process/ except the minimal implementation
+              # needed on iOS (mostly for unit tests).
+              ['exclude', '^process/.*'],
+              ['include', '^process/.*_ios\.(cc|mm)$'],
+              ['include', '^process/memory_stubs\.cc$'],
+              ['include', '^process/process_handle_posix\.cc$'],
+              ['include', '^process/process_metrics\\.cc$'],
+              ['exclude', '^threading/platform_thread_internal_posix\\.(h|cc)'],
+              ['exclude', 'files/file_path_watcher_fsevents.cc'],
+              ['exclude', 'files/file_path_watcher_fsevents.h'],
+              ['include', 'files/file_path_watcher_mac.cc'],
+            ],
+            'sources': [
+              'process/memory_stubs.cc',
+            ],
+            'sources!': [
+              'message_loop/message_pump_libevent.cc'
+            ],
+          }],
+          ['OS == "ios" and _toolset == "host"', {
+            'sources/': [
+              # Copied filename_rules to switch from iOS to Mac inclusions.
+              ['include', '_(cocoa|mac)(_unittest)?\\.(h|cc|mm?)$'],
+              ['include', '(^|/)(cocoa|mac)/'],
+              ['exclude', '_ios(_unittest)?\\.(h|cc|mm?)$'],
+              ['exclude', '(^|/)ios/'],
+              ['exclude', 'files/file_path_watcher_fsevents.cc'],
+              ['exclude', 'files/file_path_watcher_fsevents.h'],
+              ['include', 'files/file_path_watcher_mac.cc'],
+            ]
+          }],
+          # For now, just test the *BSD platforms enough to exclude them.
+          # Subsequent changes will include them further.
+          ['OS != "freebsd" or >(nacl_untrusted_build)==1', {
+              'sources/': [ ['exclude', '_freebsd\\.cc$'] ],
+            },
+          ],
+          ['OS != "openbsd" or >(nacl_untrusted_build)==1', {
+              'sources/': [ ['exclude', '_openbsd\\.cc$'] ],
+            },
+          ],
+          ['OS == "win" and >(nacl_untrusted_build)==0', {
+            'include_dirs': [
+              '<(DEPTH)/third_party/wtl/include',
+            ],
+            'sources!': [
+              'files/file_path_watcher_fsevents.cc',
+              'files/file_path_watcher_fsevents.h',
+              'files/file_path_watcher_kqueue.cc',
+              'files/file_path_watcher_kqueue.h',
+              'files/file_path_watcher_stub.cc',
+              'message_loop/message_pump_libevent.cc',
+              'posix/file_descriptor_shuffle.cc',
+              # Not using sha1_win.cc because it may have caused a
+              # regression to page cycler moz.
+              'sha1_win.cc',
+              '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',
+              'files/file_path_watcher_fsevents.h',
+              'files/file_path_watcher_kqueue.cc',
+              'files/file_path_watcher_kqueue.h',
+              'files/file_path_watcher_stub.cc',
+            ],
+          }],
+          ['(OS == "mac" or OS == "ios") and >(nacl_untrusted_build)==0', {
+            'sources/': [
+              ['exclude', '^base_paths_posix\\.cc$'],
+              ['exclude', '^files/file_path_watcher_stub\\.cc$'],
+              ['exclude', '^native_library_posix\\.cc$'],
+              ['exclude', '^strings/sys_string_conversions_posix\\.cc$'],
+              ['exclude', '^threading/platform_thread_internal_posix\\.cc$'],
+            ],
+          }],
+          ['<(os_bsd)==1 and >(nacl_untrusted_build)==0', {
+            'sources': [
+              'process/memory_stubs.cc',
+            ],
+            'sources/': [
+              ['exclude', '^files/file_path_watcher_linux\\.cc$'],
+              ['exclude', '^files/file_path_watcher_stub\\.cc$'],
+              ['exclude', '^files/file_util_linux\\.cc$'],
+              ['exclude', '^process/process_linux\\.cc$'],
+              ['exclude', '^sys_info_linux\\.cc$'],
+            ],
+          }],
+          # Remove all unnecessary files for build_nexe.py to avoid exceeding
+          # command-line-string limitation when building NaCl on Windows.
+          ['OS == "win" and >(nacl_untrusted_build)==1', {
+              'sources/': [ ['exclude', '\\.h$'] ],
+          }],
+          # Enable more direct string conversions on platforms with native utf8
+          # strings
+          ['OS=="mac" or OS=="ios" or <(chromeos)==1 or <(chromecast)==1', {
+            'defines': ['SYSTEM_NATIVE_UTF8'],
+          }],
+        ],
+      }],
+      ['base_i18n_target==1', {
+        'defines': [
+          'BASE_I18N_IMPLEMENTATION',
+        ],
+        'sources': [
+          'i18n/base_i18n_export.h',
+          'i18n/bidi_line_iterator.cc',
+          'i18n/bidi_line_iterator.h',
+          'i18n/break_iterator.cc',
+          'i18n/break_iterator.h',
+          'i18n/case_conversion.cc',
+          'i18n/case_conversion.h',
+          'i18n/char_iterator.cc',
+          'i18n/char_iterator.h',
+          'i18n/file_util_icu.cc',
+          'i18n/file_util_icu.h',
+          'i18n/i18n_constants.cc',
+          'i18n/i18n_constants.h',
+          'i18n/icu_encoding_detection.cc',
+          'i18n/icu_encoding_detection.h',
+          'i18n/icu_string_conversions.cc',
+          'i18n/icu_string_conversions.h',
+          'i18n/icu_util.cc',
+          'i18n/icu_util.h',
+          'i18n/number_formatting.cc',
+          'i18n/number_formatting.h',
+          'i18n/rtl.cc',
+          'i18n/rtl.h',
+          'i18n/streaming_utf8_validator.cc',
+          'i18n/streaming_utf8_validator.h',
+          'i18n/string_compare.cc',
+          'i18n/string_compare.h',
+          'i18n/string_search.cc',
+          'i18n/string_search.h',
+          'i18n/time_formatting.cc',
+          'i18n/time_formatting.h',
+          'i18n/timezone.cc',
+          'i18n/timezone.h',
+          'i18n/utf8_validator_tables.cc',
+          'i18n/utf8_validator_tables.h',
+        ],
+      }]
+    ],
+  },
+}
diff --git a/base/base.isolate b/base/base.isolate
new file mode 100644
index 0000000..c7ba651
--- /dev/null
+++ b/base/base.isolate
@@ -0,0 +1,98 @@
+# 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.
+{
+  'includes': [
+    # While the target 'base' doesn't depend on ../third_party/icu/icu.gyp
+    # itself, virtually all targets using it has to include icu. The only
+    # exception is the Windows sandbox (?).
+    '../third_party/icu/icu.isolate',
+    # Sanitizer-instrumented third-party libraries (if enabled).
+    '../third_party/instrumented_libraries/instrumented_libraries.isolate',
+  ],
+  'conditions': [
+    ['use_custom_libcxx==1', {
+      'variables': {
+        'files': [
+          '<(PRODUCT_DIR)/lib/libc++.so',
+        ],
+      },
+    }],
+    ['OS=="mac" and asan==1', {
+      'variables': {
+        'files': [
+          '<(PRODUCT_DIR)/libclang_rt.asan_osx_dynamic.dylib',
+        ],
+      },
+    }],
+    ['OS=="win"', {
+      # Required for base/stack_trace_win.cc to symbolize correctly.
+      'variables': {
+        'files': [
+          '<(PRODUCT_DIR)/dbghelp.dll',
+        ],
+      },
+    }],
+    ['OS=="win" and asan==1 and component=="shared_library"', {
+      'variables': {
+        'files': [
+          '../third_party/llvm-build/Release+Asserts/lib/clang/3.7.0/lib/windows/clang_rt.asan_dynamic-i386.dll',
+        ],
+      },
+    }],
+    ['OS=="linux" and (asan==1 or lsan==1 or msan==1 or tsan==1)', {
+      'variables': {
+        'files': [
+          # For llvm-symbolizer.
+          '../third_party/llvm-build/Release+Asserts/lib/libstdc++.so.6',
+        ],
+      },
+    }],
+    ['asan==1 or lsan==1 or msan==1 or tsan==1', {
+      'variables': {
+        'files': [
+          '../tools/valgrind/asan/',
+          '../third_party/llvm-build/Release+Asserts/bin/llvm-symbolizer<(EXECUTABLE_SUFFIX)',
+        ],
+      },
+    }],
+    # Copy the VS runtime DLLs into the isolate so that they
+    # don't have to be preinstalled on the target machine.
+    ['OS=="win" and component=="shared_library" and CONFIGURATION_NAME=="Debug"', {
+      'variables': {
+        'files': [
+          '<(PRODUCT_DIR)/x64/msvcp120d.dll',
+          '<(PRODUCT_DIR)/x64/msvcr120d.dll',
+        ],
+      },
+    }],
+    ['OS=="win" and component=="shared_library" and CONFIGURATION_NAME=="Release"', {
+      'variables': {
+        'files': [
+          '<(PRODUCT_DIR)/x64/msvcp120.dll',
+          '<(PRODUCT_DIR)/x64/msvcr120.dll',
+        ],
+      },
+    }],
+    ['OS=="win" and component=="shared_library" and (CONFIGURATION_NAME=="Debug" or CONFIGURATION_NAME=="Debug_x64")', {
+      'variables': {
+        'files': [
+          '<(PRODUCT_DIR)/msvcp120d.dll',
+          '<(PRODUCT_DIR)/msvcr120d.dll',
+        ],
+      },
+    }],
+    ['OS=="win" and component=="shared_library" and (CONFIGURATION_NAME=="Release" or CONFIGURATION_NAME=="Release_x64")', {
+      'variables': {
+        'files': [
+          '<(PRODUCT_DIR)/msvcp120.dll',
+          '<(PRODUCT_DIR)/msvcr120.dll',
+        ],
+      },
+    }],
+    # Workaround for https://code.google.com/p/swarming/issues/detail?id=211
+    ['asan==0 or lsan==0 or msan==0 or tsan==0', {
+      'variables': {},
+    }],
+  ],
+}
diff --git a/base/base64.cc b/base/base64.cc
new file mode 100644
index 0000000..8ed1249
--- /dev/null
+++ b/base/base64.cc
@@ -0,0 +1,37 @@
+// Copyright (c) 2012 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/base64.h"
+
+#include "third_party/modp_b64/modp_b64.h"
+
+namespace base {
+
+void Base64Encode(const StringPiece& input, std::string* output) {
+  std::string temp;
+  temp.resize(modp_b64_encode_len(input.size()));  // makes room for null byte
+
+  // modp_b64_encode_len() returns at least 1, so temp[0] is safe to use.
+  size_t output_size = modp_b64_encode(&(temp[0]), input.data(), input.size());
+
+  temp.resize(output_size);  // strips off null byte
+  output->swap(temp);
+}
+
+bool Base64Decode(const StringPiece& input, std::string* output) {
+  std::string temp;
+  temp.resize(modp_b64_decode_len(input.size()));
+
+  // does not null terminate result since result is binary data!
+  size_t input_size = input.size();
+  size_t output_size = modp_b64_decode(&(temp[0]), input.data(), input_size);
+  if (output_size == MODP_B64_ERROR)
+    return false;
+
+  temp.resize(output_size);
+  output->swap(temp);
+  return true;
+}
+
+}  // namespace base
diff --git a/base/base64.h b/base/base64.h
new file mode 100644
index 0000000..dd72c39
--- /dev/null
+++ b/base/base64.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2011 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_BASE64_H_
+#define BASE_BASE64_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+// Encodes the input string in base64. The encoding can be done in-place.
+BASE_EXPORT void Base64Encode(const StringPiece& input, std::string* output);
+
+// Decodes the base64 input string.  Returns true if successful and false
+// otherwise. The output string is only modified if successful. The decoding can
+// be done in-place.
+BASE_EXPORT bool Base64Decode(const StringPiece& input, std::string* output);
+
+}  // namespace base
+
+#endif  // BASE_BASE64_H_
diff --git a/base/base64_unittest.cc b/base/base64_unittest.cc
new file mode 100644
index 0000000..91651f4
--- /dev/null
+++ b/base/base64_unittest.cc
@@ -0,0 +1,40 @@
+// Copyright (c) 2012 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/base64.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(Base64Test, Basic) {
+  const std::string kText = "hello world";
+  const std::string kBase64Text = "aGVsbG8gd29ybGQ=";
+
+  std::string encoded;
+  std::string decoded;
+  bool ok;
+
+  Base64Encode(kText, &encoded);
+  EXPECT_EQ(kBase64Text, encoded);
+
+  ok = Base64Decode(encoded, &decoded);
+  EXPECT_TRUE(ok);
+  EXPECT_EQ(kText, decoded);
+}
+
+TEST(Base64Test, InPlace) {
+  const std::string kText = "hello world";
+  const std::string kBase64Text = "aGVsbG8gd29ybGQ=";
+  std::string text(kText);
+
+  Base64Encode(text, &text);
+  EXPECT_EQ(kBase64Text, text);
+
+  bool ok = Base64Decode(text, &text);
+  EXPECT_TRUE(ok);
+  EXPECT_EQ(text, kText);
+}
+
+}  // namespace base
diff --git a/base/base_export.h b/base/base_export.h
new file mode 100644
index 0000000..723b38a
--- /dev/null
+++ b/base/base_export.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2012 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_BASE_EXPORT_H_
+#define BASE_BASE_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(BASE_IMPLEMENTATION)
+#define BASE_EXPORT __declspec(dllexport)
+#define BASE_EXPORT_PRIVATE __declspec(dllexport)
+#else
+#define BASE_EXPORT __declspec(dllimport)
+#define BASE_EXPORT_PRIVATE __declspec(dllimport)
+#endif  // defined(BASE_IMPLEMENTATION)
+
+#else  // defined(WIN32)
+#if defined(BASE_IMPLEMENTATION)
+#define BASE_EXPORT __attribute__((visibility("default")))
+#define BASE_EXPORT_PRIVATE __attribute__((visibility("default")))
+#else
+#define BASE_EXPORT
+#define BASE_EXPORT_PRIVATE
+#endif  // defined(BASE_IMPLEMENTATION)
+#endif
+
+#else  // defined(COMPONENT_BUILD)
+#define BASE_EXPORT
+#define BASE_EXPORT_PRIVATE
+#endif
+
+#endif  // BASE_BASE_EXPORT_H_
diff --git a/base/base_nacl.gyp b/base/base_nacl.gyp
new file mode 100644
index 0000000..7e7d34f
--- /dev/null
+++ b/base/base_nacl.gyp
@@ -0,0 +1,143 @@
+# Copyright (c) 2012 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.
+
+{
+  'variables': {
+    'chromium_code': 1,
+  },
+  'includes': [
+    # base.gypi must be included before common_untrusted.gypi.
+    #
+    # TODO(sergeyu): Replace the target_defaults magic in base.gypi with a
+    # sources variables lists. That way order of includes will not matter.
+    'base.gypi',
+    '../build/common_untrusted.gypi',
+  ],
+  'conditions': [
+    ['disable_nacl==0 and disable_nacl_untrusted==0', {
+      'targets': [
+        {
+          'target_name': 'base_nacl',
+          'type': 'none',
+          'variables': {
+            'base_target': 1,
+            'nacl_untrusted_build': 1,
+            'nlib_target': 'libbase_nacl.a',
+            'build_glibc': 0,
+            'build_newlib': 0,
+            'build_irt': 1,
+            'build_pnacl_newlib': 1,
+            'sources': [
+              'base_switches.cc',
+              'base_switches.h',
+              'strings/string16.cc',
+              'sync_socket_nacl.cc',
+              'time/time_posix.cc',
+            ],
+            'gcc_compile_flags': [
+              '-fno-strict-aliasing',
+            ],
+          },
+        },
+        {
+          'target_name': 'base_i18n_nacl',
+          'type': 'none',
+          'variables': {
+            'base_i18n_target': 1,
+            'nacl_untrusted_build': 1,
+            'nlib_target': 'libbase_i18n_nacl.a',
+            'build_glibc': 0,
+            'build_newlib': 0,
+            'build_irt': 0,
+            'build_pnacl_newlib': 1,
+            'sources': [
+              'base_switches.cc',
+              'base_switches.h',
+              'strings/string16.cc',
+              'sync_socket_nacl.cc',
+              'time/time_posix.cc',
+            ],
+          },
+          'dependencies': [
+            '../third_party/icu/icu_nacl.gyp:icudata_nacl',
+            '../third_party/icu/icu_nacl.gyp:icui18n_nacl',
+            '../third_party/icu/icu_nacl.gyp:icuuc_nacl',
+          ],
+        },
+        {
+          'target_name': 'base_nacl_nonsfi',
+          'type': 'none',
+          'variables': {
+            'base_target': 1,
+            'nacl_untrusted_build': 1,
+            'nlib_target': 'libbase_nacl_nonsfi.a',
+            'build_glibc': 0,
+            'build_newlib': 0,
+            'build_irt': 0,
+            'build_pnacl_newlib': 0,
+            'build_nonsfi_helper': 1,
+
+            'sources': [
+              'base_switches.cc',
+              'base_switches.h',
+
+              # For PathExists and ReadFromFD.
+              'files/file_util.cc',
+              'files/file_util_posix.cc',
+
+              # For MessageLoopForIO based on libevent.
+              'message_loop/message_pump_libevent.cc',
+              'message_loop/message_pump_libevent.h',
+
+              # For UnixDomainSocket::SendMsg and RecvMsg.
+              'posix/unix_domain_socket_linux.cc',
+
+              # For GetKnownDeadTerminationStatus and GetTerminationStatus.
+              'process/kill_posix.cc',
+
+              # Unlike libbase_nacl, for Non-SFI build, we need to use
+              # rand_util_posix for random implementation, instead of
+              # rand_util_nacl.cc, which is based on IRT. rand_util_nacl.cc is
+              # excluded below.
+              'rand_util_posix.cc',
+
+              # For CancelableSyncSocket.
+              'sync_socket_nacl.cc',
+            ],
+          },
+          'sources!': [
+            'rand_util_nacl.cc',
+          ],
+          'dependencies': [
+            '../third_party/libevent/libevent_nacl_nonsfi.gyp:event_nacl_nonsfi',
+          ],
+        },
+        {
+          'target_name': 'test_support_base_nacl_nonsfi',
+          'type': 'none',
+          'variables': {
+            'nacl_untrusted_build': 1,
+            'nlib_target': 'libtest_support_base_nacl_nonsfi.a',
+            'build_glibc': 0,
+            'build_newlib': 0,
+            'build_irt': 0,
+            'build_pnacl_newlib': 0,
+            'build_nonsfi_helper': 1,
+
+            'sources': [
+              'test/gtest_util.cc',
+              'test/launcher/unit_test_launcher_nacl_nonsfi.cc',
+              'test/gtest_xml_unittest_result_printer.cc',
+              'test/test_switches.cc',
+            ],
+          },
+          'dependencies': [
+            'base_nacl_nonsfi',
+            '../testing/gtest_nacl.gyp:gtest_nacl',
+          ],
+        },
+      ],
+    }],
+  ],
+}
diff --git a/base/base_paths.cc b/base/base_paths.cc
new file mode 100644
index 0000000..7076ec3
--- /dev/null
+++ b/base/base_paths.cc
@@ -0,0 +1,46 @@
+// Copyright (c) 2006-2008 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/base_paths.h"
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/path_service.h"
+
+namespace base {
+
+bool PathProvider(int key, FilePath* result) {
+  // NOTE: DIR_CURRENT is a special case in PathService::Get
+
+  switch (key) {
+    case DIR_EXE:
+      PathService::Get(FILE_EXE, result);
+      *result = result->DirName();
+      return true;
+    case DIR_MODULE:
+      PathService::Get(FILE_MODULE, result);
+      *result = result->DirName();
+      return true;
+    case DIR_TEMP:
+      if (!GetTempDir(result))
+        return false;
+      return true;
+    case base::DIR_HOME:
+      *result = GetHomeDir();
+      return true;
+    case DIR_TEST_DATA:
+      if (!PathService::Get(DIR_SOURCE_ROOT, result))
+        return false;
+      *result = result->Append(FILE_PATH_LITERAL("base"));
+      *result = result->Append(FILE_PATH_LITERAL("test"));
+      *result = result->Append(FILE_PATH_LITERAL("data"));
+      if (!PathExists(*result))  // We don't want to create this.
+        return false;
+      return true;
+    default:
+      return false;
+  }
+}
+
+}  // namespace base
diff --git a/base/base_paths.h b/base/base_paths.h
new file mode 100644
index 0000000..26b2fd4
--- /dev/null
+++ b/base/base_paths.h
@@ -0,0 +1,55 @@
+// Copyright (c) 2012 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_BASE_PATHS_H_
+#define BASE_BASE_PATHS_H_
+
+// This file declares path keys for the base module.  These can be used with
+// the PathService to access various special directories and files.
+
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include "base/base_paths_win.h"
+#elif defined(OS_MACOSX)
+#include "base/base_paths_mac.h"
+#elif defined(OS_ANDROID)
+#include "base/base_paths_android.h"
+#endif
+
+#if defined(OS_POSIX)
+#include "base/base_paths_posix.h"
+#endif
+
+namespace base {
+
+enum BasePathKey {
+  PATH_START = 0,
+
+  DIR_CURRENT,       // Current directory.
+  DIR_EXE,           // Directory containing FILE_EXE.
+  DIR_MODULE,        // Directory containing FILE_MODULE.
+  DIR_TEMP,          // Temporary directory.
+  DIR_HOME,          // User's root home directory. On Windows this will look
+                     // like "C:\Users\you" (or on XP
+                     // "C:\Document and Settings\you") which isn't necessarily
+                     // a great place to put files.
+  FILE_EXE,          // Path and filename of the current executable.
+  FILE_MODULE,       // Path and filename of the module containing the code for
+                     // the PathService (which could differ from FILE_EXE if the
+                     // PathService were compiled into a shared object, for
+                     // example).
+  DIR_SOURCE_ROOT,   // Returns the root of the source tree. This key is useful
+                     // for tests that need to locate various resources. It
+                     // should not be used outside of test code.
+  DIR_USER_DESKTOP,  // The current user's Desktop.
+
+  DIR_TEST_DATA,     // Used only for testing.
+
+  PATH_END
+};
+
+}  // namespace base
+
+#endif  // BASE_BASE_PATHS_H_
diff --git a/base/base_paths_android.cc b/base/base_paths_android.cc
new file mode 100644
index 0000000..56c6cc7
--- /dev/null
+++ b/base/base_paths_android.cc
@@ -0,0 +1,60 @@
+// Copyright (c) 2012 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.
+
+// Defines base::PathProviderAndroid which replaces base::PathProviderPosix for
+// Android in base/path_service.cc.
+
+#include <unistd.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/path_utils.h"
+#include "base/base_paths.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/process/process_metrics.h"
+
+namespace base {
+
+bool PathProviderAndroid(int key, FilePath* result) {
+  switch (key) {
+    case base::FILE_EXE: {
+      char bin_dir[PATH_MAX + 1];
+      int bin_dir_size = readlink(kProcSelfExe, bin_dir, PATH_MAX);
+      if (bin_dir_size < 0 || bin_dir_size > PATH_MAX) {
+        NOTREACHED() << "Unable to resolve " << kProcSelfExe << ".";
+        return false;
+      }
+      bin_dir[bin_dir_size] = 0;
+      *result = FilePath(bin_dir);
+      return true;
+    }
+    case base::FILE_MODULE:
+      // dladdr didn't work in Android as only the file name was returned.
+      NOTIMPLEMENTED();
+      return false;
+    case base::DIR_MODULE:
+      return base::android::GetNativeLibraryDirectory(result);
+    case base::DIR_SOURCE_ROOT:
+      // This const is only used for tests.
+      return base::android::GetExternalStorageDirectory(result);
+    case base::DIR_USER_DESKTOP:
+      // Android doesn't support GetUserDesktop.
+      NOTIMPLEMENTED();
+      return false;
+    case base::DIR_CACHE:
+      return base::android::GetCacheDirectory(result);
+    case base::DIR_ANDROID_APP_DATA:
+      return base::android::GetDataDirectory(result);
+    case base::DIR_ANDROID_EXTERNAL_STORAGE:
+      return base::android::GetExternalStorageDirectory(result);
+    default:
+      // Note: the path system expects this function to override the default
+      // behavior. So no need to log an error if we don't support a given
+      // path. The system will just use the default.
+      return false;
+  }
+}
+
+}  // namespace base
diff --git a/base/base_paths_android.h b/base/base_paths_android.h
new file mode 100644
index 0000000..7a9ac4a
--- /dev/null
+++ b/base/base_paths_android.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2012 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_BASE_PATHS_ANDROID_H_
+#define BASE_BASE_PATHS_ANDROID_H_
+
+// This file declares Android-specific path keys for the base module.
+// These can be used with the PathService to access various special
+// directories and files.
+
+namespace base {
+
+enum {
+  PATH_ANDROID_START = 300,
+
+  DIR_ANDROID_APP_DATA,  // Directory where to put Android app's data.
+  DIR_ANDROID_EXTERNAL_STORAGE,  // Android external storage directory.
+
+  PATH_ANDROID_END
+};
+
+}  // namespace base
+
+#endif  // BASE_BASE_PATHS_ANDROID_H_
diff --git a/base/base_paths_mac.h b/base/base_paths_mac.h
new file mode 100644
index 0000000..ac75402
--- /dev/null
+++ b/base/base_paths_mac.h
@@ -0,0 +1,24 @@
+// Copyright (c) 2006-2008 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_BASE_PATHS_MAC_H_
+#define BASE_BASE_PATHS_MAC_H_
+
+// This file declares Mac-specific path keys for the base module.
+// These can be used with the PathService to access various special
+// directories and files.
+
+namespace base {
+
+enum {
+  PATH_MAC_START = 200,
+
+  DIR_APP_DATA,  // ~/Library/Application Support
+
+  PATH_MAC_END
+};
+
+}  // namespace base
+
+#endif  // BASE_BASE_PATHS_MAC_H_
diff --git a/base/base_paths_mac.mm b/base/base_paths_mac.mm
new file mode 100644
index 0000000..9864eb3
--- /dev/null
+++ b/base/base_paths_mac.mm
@@ -0,0 +1,114 @@
+// Copyright (c) 2012 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.
+
+// Defines base::PathProviderMac which replaces base::PathProviderPosix for Mac
+// in base/path_service.cc.
+
+#include <dlfcn.h>
+#import <Foundation/Foundation.h>
+#include <mach-o/dyld.h>
+
+#include "base/base_paths.h"
+#include "base/compiler_specific.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/path_service.h"
+#include "base/strings/string_util.h"
+#include "build/build_config.h"
+
+namespace {
+
+void GetNSExecutablePath(base::FilePath* path) {
+  DCHECK(path);
+  // Executable path can have relative references ("..") depending on
+  // how the app was launched.
+  uint32_t executable_length = 0;
+  _NSGetExecutablePath(NULL, &executable_length);
+  DCHECK_GT(executable_length, 1u);
+  std::string executable_path;
+  int rv = _NSGetExecutablePath(WriteInto(&executable_path, executable_length),
+                                &executable_length);
+  DCHECK_EQ(rv, 0);
+
+  // _NSGetExecutablePath may return paths containing ./ or ../ which makes
+  // FilePath::DirName() work incorrectly, convert it to absolute path so that
+  // paths such as DIR_SOURCE_ROOT can work, since we expect absolute paths to
+  // be returned here.
+  *path = base::MakeAbsoluteFilePath(base::FilePath(executable_path));
+}
+
+// Returns true if the module for |address| is found. |path| will contain
+// the path to the module. Note that |path| may not be absolute.
+bool GetModulePathForAddress(base::FilePath* path,
+                             const void* address) WARN_UNUSED_RESULT;
+
+bool GetModulePathForAddress(base::FilePath* path, const void* address) {
+  Dl_info info;
+  if (dladdr(address, &info) == 0)
+    return false;
+  *path = base::FilePath(info.dli_fname);
+  return true;
+}
+
+}  // namespace
+
+namespace base {
+
+bool PathProviderMac(int key, base::FilePath* result) {
+  switch (key) {
+    case base::FILE_EXE:
+      GetNSExecutablePath(result);
+      return true;
+    case base::FILE_MODULE:
+      return GetModulePathForAddress(result,
+          reinterpret_cast<const void*>(&base::PathProviderMac));
+    case base::DIR_APP_DATA: {
+      bool success = base::mac::GetUserDirectory(NSApplicationSupportDirectory,
+                                                 result);
+#if defined(OS_IOS)
+      // On IOS, this directory does not exist unless it is created explicitly.
+      if (success && !base::PathExists(*result))
+        success = base::CreateDirectory(*result);
+#endif  // defined(OS_IOS)
+      return success;
+    }
+    case base::DIR_SOURCE_ROOT:
+      // Go through PathService to catch overrides.
+      if (!PathService::Get(base::FILE_EXE, result))
+        return false;
+
+      // Start with the executable's directory.
+      *result = result->DirName();
+
+#if !defined(OS_IOS)
+      if (base::mac::AmIBundled()) {
+        // The bundled app executables (Chromium, TestShell, etc) live five
+        // levels down, eg:
+        // src/xcodebuild/{Debug|Release}/Chromium.app/Contents/MacOS/Chromium
+        *result = result->DirName().DirName().DirName().DirName().DirName();
+      } else {
+        // Unit tests execute two levels deep from the source root, eg:
+        // src/xcodebuild/{Debug|Release}/base_unittests
+        *result = result->DirName().DirName();
+      }
+#endif
+      return true;
+    case base::DIR_USER_DESKTOP:
+#if defined(OS_IOS)
+      // iOS does not have desktop directories.
+      NOTIMPLEMENTED();
+      return false;
+#else
+      return base::mac::GetUserDirectory(NSDesktopDirectory, result);
+#endif
+    case base::DIR_CACHE:
+      return base::mac::GetUserDirectory(NSCachesDirectory, result);
+    default:
+      return false;
+  }
+}
+
+}  // namespace base
diff --git a/base/base_paths_posix.cc b/base/base_paths_posix.cc
new file mode 100644
index 0000000..048434f
--- /dev/null
+++ b/base/base_paths_posix.cc
@@ -0,0 +1,116 @@
+// Copyright (c) 2012 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.
+
+// Defines base::PathProviderPosix, default path provider on POSIX OSes that
+// don't have their own base_paths_OS.cc implementation (i.e. all but Mac and
+// Android).
+
+#include <ostream>
+#include <string>
+
+#include "base/base_paths.h"
+#include "base/environment.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/nix/xdg_util.h"
+#include "base/path_service.h"
+#include "base/process/process_metrics.h"
+#include "build/build_config.h"
+
+#if defined(OS_FREEBSD)
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#elif defined(OS_SOLARIS)
+#include <stdlib.h>
+#endif
+
+namespace base {
+
+bool PathProviderPosix(int key, FilePath* result) {
+  FilePath path;
+  switch (key) {
+    case base::FILE_EXE:
+    case base::FILE_MODULE: {  // TODO(evanm): is this correct?
+#if defined(OS_LINUX)
+      FilePath bin_dir;
+      if (!ReadSymbolicLink(FilePath(kProcSelfExe), &bin_dir)) {
+        NOTREACHED() << "Unable to resolve " << kProcSelfExe << ".";
+        return false;
+      }
+      *result = bin_dir;
+      return true;
+#elif defined(OS_FREEBSD)
+      int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
+      char bin_dir[PATH_MAX + 1];
+      size_t length = sizeof(bin_dir);
+      // Upon return, |length| is the number of bytes written to |bin_dir|
+      // including the string terminator.
+      int error = sysctl(name, 4, bin_dir, &length, NULL, 0);
+      if (error < 0 || length <= 1) {
+        NOTREACHED() << "Unable to resolve path.";
+        return false;
+      }
+      *result = FilePath(FilePath::StringType(bin_dir, length - 1));
+      return true;
+#elif defined(OS_SOLARIS)
+      char bin_dir[PATH_MAX + 1];
+      if (realpath(getexecname(), bin_dir) == NULL) {
+        NOTREACHED() << "Unable to resolve " << getexecname() << ".";
+        return false;
+      }
+      *result = FilePath(bin_dir);
+      return true;
+#elif defined(OS_OPENBSD)
+      // There is currently no way to get the executable path on OpenBSD
+      char* cpath;
+      if ((cpath = getenv("CHROME_EXE_PATH")) != NULL)
+        *result = FilePath(cpath);
+      else
+        *result = FilePath("/usr/local/chrome/chrome");
+      return true;
+#endif
+    }
+    case base::DIR_SOURCE_ROOT: {
+      // Allow passing this in the environment, for more flexibility in build
+      // tree configurations (sub-project builds, gyp --output_dir, etc.)
+      scoped_ptr<base::Environment> env(base::Environment::Create());
+      std::string cr_source_root;
+      if (env->GetVar("CR_SOURCE_ROOT", &cr_source_root)) {
+        path = FilePath(cr_source_root);
+        if (base::PathExists(path)) {
+          *result = path;
+          return true;
+        } else {
+          DLOG(WARNING) << "CR_SOURCE_ROOT is set, but it appears to not "
+                        << "point to a directory.";
+        }
+      }
+      // On POSIX, unit tests execute two levels deep from the source root.
+      // For example:  out/{Debug|Release}/net_unittest
+      if (PathService::Get(base::DIR_EXE, &path)) {
+        *result = path.DirName().DirName();
+        return true;
+      }
+
+      DLOG(ERROR) << "Couldn't find your source root.  "
+                  << "Try running from your chromium/src directory.";
+      return false;
+    }
+    case base::DIR_USER_DESKTOP:
+      *result = base::nix::GetXDGUserDirectory("DESKTOP", "Desktop");
+      return true;
+    case base::DIR_CACHE: {
+      scoped_ptr<base::Environment> env(base::Environment::Create());
+      FilePath cache_dir(base::nix::GetXDGDirectory(env.get(), "XDG_CACHE_HOME",
+                                                    ".cache"));
+      *result = cache_dir;
+      return true;
+    }
+  }
+  return false;
+}
+
+}  // namespace base
diff --git a/base/base_paths_posix.h b/base/base_paths_posix.h
new file mode 100644
index 0000000..ef002ae
--- /dev/null
+++ b/base/base_paths_posix.h
@@ -0,0 +1,27 @@
+// Copyright (c) 2012 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_BASE_PATHS_POSIX_H_
+#define BASE_BASE_PATHS_POSIX_H_
+
+// This file declares windows-specific path keys for the base module.
+// These can be used with the PathService to access various special
+// directories and files.
+
+namespace base {
+
+enum {
+  PATH_POSIX_START = 400,
+
+  DIR_CACHE,    // Directory where to put cache data.  Note this is
+                // *not* where the browser cache lives, but the
+                // browser cache can be a subdirectory.
+                // This is $XDG_CACHE_HOME on Linux and
+                // ~/Library/Caches on Mac.
+  PATH_POSIX_END
+};
+
+}  // namespace base
+
+#endif  // BASE_BASE_PATHS_POSIX_H_
diff --git a/base/base_paths_win.cc b/base/base_paths_win.cc
new file mode 100644
index 0000000..4ecb59d
--- /dev/null
+++ b/base/base_paths_win.cc
@@ -0,0 +1,195 @@
+// Copyright (c) 2012 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 <windows.h>
+#include <shlobj.h>
+
+#include "base/base_paths.h"
+#include "base/environment.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/win/scoped_co_mem.h"
+#include "base/win/windows_version.h"
+
+// http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx
+extern "C" IMAGE_DOS_HEADER __ImageBase;
+
+using base::FilePath;
+
+namespace base {
+
+bool PathProviderWin(int key, FilePath* result) {
+  // We need to go compute the value. It would be nice to support paths with
+  // names longer than MAX_PATH, but the system functions don't seem to be
+  // designed for it either, with the exception of GetTempPath (but other
+  // things will surely break if the temp path is too long, so we don't bother
+  // handling it.
+  wchar_t system_buffer[MAX_PATH];
+  system_buffer[0] = 0;
+
+  FilePath cur;
+  switch (key) {
+    case base::FILE_EXE:
+      GetModuleFileName(NULL, system_buffer, MAX_PATH);
+      cur = FilePath(system_buffer);
+      break;
+    case base::FILE_MODULE: {
+      // the resource containing module is assumed to be the one that
+      // this code lives in, whether that's a dll or exe
+      HMODULE this_module = reinterpret_cast<HMODULE>(&__ImageBase);
+      GetModuleFileName(this_module, system_buffer, MAX_PATH);
+      cur = FilePath(system_buffer);
+      break;
+    }
+    case base::DIR_WINDOWS:
+      GetWindowsDirectory(system_buffer, MAX_PATH);
+      cur = FilePath(system_buffer);
+      break;
+    case base::DIR_SYSTEM:
+      GetSystemDirectory(system_buffer, MAX_PATH);
+      cur = FilePath(system_buffer);
+      break;
+    case base::DIR_PROGRAM_FILESX86:
+      if (base::win::OSInfo::GetInstance()->architecture() !=
+          base::win::OSInfo::X86_ARCHITECTURE) {
+        if (FAILED(SHGetFolderPath(NULL, CSIDL_PROGRAM_FILESX86, NULL,
+                                   SHGFP_TYPE_CURRENT, system_buffer)))
+          return false;
+        cur = FilePath(system_buffer);
+        break;
+      }
+      // Fall through to base::DIR_PROGRAM_FILES if we're on an X86 machine.
+    case base::DIR_PROGRAM_FILES:
+      if (FAILED(SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES, NULL,
+                                 SHGFP_TYPE_CURRENT, system_buffer)))
+        return false;
+      cur = FilePath(system_buffer);
+      break;
+    case base::DIR_PROGRAM_FILES6432:
+#if !defined(_WIN64)
+      if (base::win::OSInfo::GetInstance()->wow64_status() ==
+          base::win::OSInfo::WOW64_ENABLED) {
+        scoped_ptr<base::Environment> env(base::Environment::Create());
+        std::string programfiles_w6432;
+        // 32-bit process running in WOW64 sets ProgramW6432 environment
+        // variable. See
+        // https://msdn.microsoft.com/library/windows/desktop/aa384274.aspx.
+        if (!env->GetVar("ProgramW6432", &programfiles_w6432))
+          return false;
+        // GetVar returns UTF8 - convert back to Wide.
+        cur = FilePath(UTF8ToWide(programfiles_w6432));
+        break;
+      }
+#endif
+      if (FAILED(SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES, NULL,
+                                 SHGFP_TYPE_CURRENT, system_buffer)))
+        return false;
+      cur = FilePath(system_buffer);
+      break;
+    case base::DIR_IE_INTERNET_CACHE:
+      if (FAILED(SHGetFolderPath(NULL, CSIDL_INTERNET_CACHE, NULL,
+                                 SHGFP_TYPE_CURRENT, system_buffer)))
+        return false;
+      cur = FilePath(system_buffer);
+      break;
+    case base::DIR_COMMON_START_MENU:
+      if (FAILED(SHGetFolderPath(NULL, CSIDL_COMMON_PROGRAMS, NULL,
+                                 SHGFP_TYPE_CURRENT, system_buffer)))
+        return false;
+      cur = FilePath(system_buffer);
+      break;
+    case base::DIR_START_MENU:
+      if (FAILED(SHGetFolderPath(NULL, CSIDL_PROGRAMS, NULL,
+                                 SHGFP_TYPE_CURRENT, system_buffer)))
+        return false;
+      cur = FilePath(system_buffer);
+      break;
+    case base::DIR_APP_DATA:
+      if (FAILED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, SHGFP_TYPE_CURRENT,
+                                 system_buffer)))
+        return false;
+      cur = FilePath(system_buffer);
+      break;
+    case base::DIR_COMMON_APP_DATA:
+      if (FAILED(SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL,
+                                 SHGFP_TYPE_CURRENT, system_buffer)))
+        return false;
+      cur = FilePath(system_buffer);
+      break;
+    case base::DIR_LOCAL_APP_DATA:
+      if (FAILED(SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL,
+                                 SHGFP_TYPE_CURRENT, system_buffer)))
+        return false;
+      cur = FilePath(system_buffer);
+      break;
+    case base::DIR_SOURCE_ROOT: {
+      FilePath executableDir;
+      // On Windows, unit tests execute two levels deep from the source root.
+      // For example:  chrome/{Debug|Release}/ui_tests.exe
+      PathService::Get(base::DIR_EXE, &executableDir);
+      cur = executableDir.DirName().DirName();
+      break;
+    }
+    case base::DIR_APP_SHORTCUTS: {
+      if (win::GetVersion() < win::VERSION_WIN8)
+        return false;
+
+      base::win::ScopedCoMem<wchar_t> path_buf;
+      if (FAILED(SHGetKnownFolderPath(FOLDERID_ApplicationShortcuts, 0, NULL,
+                                      &path_buf)))
+        return false;
+
+      cur = FilePath(string16(path_buf));
+      break;
+    }
+    case base::DIR_USER_DESKTOP:
+      if (FAILED(SHGetFolderPath(NULL, CSIDL_DESKTOPDIRECTORY, NULL,
+                                 SHGFP_TYPE_CURRENT, system_buffer))) {
+        return false;
+      }
+      cur = FilePath(system_buffer);
+      break;
+    case base::DIR_COMMON_DESKTOP:
+      if (FAILED(SHGetFolderPath(NULL, CSIDL_COMMON_DESKTOPDIRECTORY, NULL,
+                                 SHGFP_TYPE_CURRENT, system_buffer))) {
+        return false;
+      }
+      cur = FilePath(system_buffer);
+      break;
+    case base::DIR_USER_QUICK_LAUNCH:
+      if (!PathService::Get(base::DIR_APP_DATA, &cur))
+        return false;
+      // According to various sources, appending
+      // "Microsoft\Internet Explorer\Quick Launch" to %appdata% is the only
+      // reliable way to get the quick launch folder across all versions of
+      // Windows.
+      // http://stackoverflow.com/questions/76080/how-do-you-reliably-get-the-quick-
+      // http://www.microsoft.com/technet/scriptcenter/resources/qanda/sept05/hey0901.mspx
+      cur = cur.AppendASCII("Microsoft")
+                .AppendASCII("Internet Explorer")
+                .AppendASCII("Quick Launch");
+      break;
+    case base::DIR_TASKBAR_PINS:
+      if (!PathService::Get(base::DIR_USER_QUICK_LAUNCH, &cur))
+        return false;
+      cur = cur.AppendASCII("User Pinned");
+      cur = cur.AppendASCII("TaskBar");
+      break;
+    case base::DIR_WINDOWS_FONTS:
+      if (FAILED(SHGetFolderPath(
+              NULL, CSIDL_FONTS, NULL, SHGFP_TYPE_CURRENT, system_buffer))) {
+        return false;
+      }
+      cur = FilePath(system_buffer);
+      break;
+    default:
+      return false;
+  }
+
+  *result = cur;
+  return true;
+}
+
+}  // namespace base
diff --git a/base/base_paths_win.h b/base/base_paths_win.h
new file mode 100644
index 0000000..9ac9e45
--- /dev/null
+++ b/base/base_paths_win.h
@@ -0,0 +1,54 @@
+// Copyright (c) 2012 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_BASE_PATHS_WIN_H_
+#define BASE_BASE_PATHS_WIN_H_
+
+// This file declares windows-specific path keys for the base module.
+// These can be used with the PathService to access various special
+// directories and files.
+
+namespace base {
+
+enum {
+  PATH_WIN_START = 100,
+
+  DIR_WINDOWS,  // Windows directory, usually "c:\windows"
+  DIR_SYSTEM,   // Usually c:\windows\system32"
+  //                         32-bit     32-bit on 64-bit   64-bit on 64-bit
+  // DIR_PROGRAM_FILES         1               2                  1
+  // DIR_PROGRAM_FILESX86      1               2                  2
+  // DIR_PROGRAM_FILES6432     1               1                  1
+  // 1 - C:\Program Files   2 - C:\Program Files (x86)
+  DIR_PROGRAM_FILES,      // See table above.
+  DIR_PROGRAM_FILESX86,   // See table above.
+  DIR_PROGRAM_FILES6432,  // See table above.
+
+  DIR_IE_INTERNET_CACHE,  // Temporary Internet Files directory.
+  DIR_COMMON_START_MENU,  // Usually "C:\Documents and Settings\All Users\
+                          // Start Menu\Programs"
+  DIR_START_MENU,         // Usually "C:\Documents and Settings\<user>\
+                          // Start Menu\Programs"
+  DIR_APP_DATA,           // Application Data directory under the user profile.
+  DIR_LOCAL_APP_DATA,     // "Local Settings\Application Data" directory under
+                          // the user profile.
+  DIR_COMMON_APP_DATA,    // W2K, XP, W2K3: "C:\Documents and Settings\
+                          // All Users\Application Data".
+                          // Vista, W2K8 and above: "C:\ProgramData".
+  DIR_APP_SHORTCUTS,      // Where tiles on the start screen are stored, only
+                          // for Windows 8. Maps to "Local\AppData\Microsoft\
+                          // Windows\Application Shortcuts\".
+  DIR_COMMON_DESKTOP,     // Directory for the common desktop (visible
+                          // on all user's Desktop).
+  DIR_USER_QUICK_LAUNCH,  // Directory for the quick launch shortcuts.
+  DIR_TASKBAR_PINS,       // Directory for the shortcuts pinned to taskbar via
+                          // base::win::TaskbarPinShortcutLink().
+  DIR_WINDOWS_FONTS,      // Usually C:\Windows\Fonts.
+
+  PATH_WIN_END
+};
+
+}  // namespace base
+
+#endif  // BASE_BASE_PATHS_WIN_H_
diff --git a/base/base_switches.cc b/base/base_switches.cc
new file mode 100644
index 0000000..3076540
--- /dev/null
+++ b/base/base_switches.cc
@@ -0,0 +1,77 @@
+// Copyright (c) 2012 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/base_switches.h"
+
+namespace switches {
+
+// Disables the crash reporting.
+const char kDisableBreakpad[]               = "disable-breakpad";
+
+// Indicates that crash reporting should be enabled. On platforms where helper
+// processes cannot access to files needed to make this decision, this flag is
+// generated internally.
+const char kEnableCrashReporter[]           = "enable-crash-reporter";
+
+// Generates full memory crash dump.
+const char kFullMemoryCrashReport[]         = "full-memory-crash-report";
+
+// Force low-end device mode when set.
+const char kEnableLowEndDeviceMode[]        = "enable-low-end-device-mode";
+
+// Force disabling of low-end device mode when set.
+const char kDisableLowEndDeviceMode[]       = "disable-low-end-device-mode";
+
+// Suppresses all error dialogs when present.
+const char kNoErrorDialogs[]                = "noerrdialogs";
+
+// When running certain tests that spawn child processes, this switch indicates
+// to the test framework that the current process is a child process.
+const char kTestChildProcess[]              = "test-child-process";
+
+// Gives the default maximal active V-logging level; 0 is the default.
+// Normally positive values are used for V-logging levels.
+const char kV[]                             = "v";
+
+// Gives the per-module maximal V-logging levels to override the value
+// given by --v.  E.g. "my_module=2,foo*=3" would change the logging
+// level for all code in source files "my_module.*" and "foo*.*"
+// ("-inl" suffixes are also disregarded for this matching).
+//
+// Any pattern containing a forward or backward slash will be tested
+// against the whole pathname and not just the module.  E.g.,
+// "*/foo/bar/*=2" would change the logging level for all code in
+// source files under a "foo/bar" directory.
+const char kVModule[]                       = "vmodule";
+
+// Will wait for 60 seconds for a debugger to come to attach to the process.
+const char kWaitForDebugger[]               = "wait-for-debugger";
+
+// Sends a pretty-printed version of tracing info to the console.
+const char kTraceToConsole[]                = "trace-to-console";
+
+// Sends trace events from these categories to a file.
+// --trace-to-file on its own sends to default categories.
+const char kTraceToFile[]                   = "trace-to-file";
+
+// Specifies the file name for --trace-to-file. If unspecified, it will
+// go to a default file name.
+const char kTraceToFileName[]               = "trace-to-file-name";
+
+// Configure whether chrome://profiler will contain timing information. This
+// option is enabled by default. A value of "0" will disable profiler timing,
+// while all other values will enable it.
+const char kProfilerTiming[]                = "profiler-timing";
+// Value of the --profiler-timing flag that will disable timing information for
+// chrome://profiler.
+const char kProfilerTimingDisabledValue[]   = "0";
+
+#if defined(OS_POSIX)
+// Used for turning on Breakpad crash reporting in a debug environment where
+// crash reporting is typically compiled but disabled.
+const char kEnableCrashReporterForTesting[] =
+    "enable-crash-reporter-for-testing";
+#endif
+
+}  // namespace switches
diff --git a/base/base_switches.h b/base/base_switches.h
new file mode 100644
index 0000000..c579f6a
--- /dev/null
+++ b/base/base_switches.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2012 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.
+
+// Defines all the "base" command-line switches.
+
+#ifndef BASE_BASE_SWITCHES_H_
+#define BASE_BASE_SWITCHES_H_
+
+#include "build/build_config.h"
+
+namespace switches {
+
+extern const char kDisableBreakpad[];
+extern const char kEnableCrashReporter[];
+extern const char kFullMemoryCrashReport[];
+extern const char kEnableLowEndDeviceMode[];
+extern const char kDisableLowEndDeviceMode[];
+extern const char kNoErrorDialogs[];
+extern const char kProfilerTiming[];
+extern const char kProfilerTimingDisabledValue[];
+extern const char kTestChildProcess[];
+extern const char kTraceToConsole[];
+extern const char kTraceToFile[];
+extern const char kTraceToFileName[];
+extern const char kV[];
+extern const char kVModule[];
+extern const char kWaitForDebugger[];
+
+#if defined(OS_POSIX)
+extern const char kEnableCrashReporterForTesting[];
+#endif
+
+}  // namespace switches
+
+#endif  // BASE_BASE_SWITCHES_H_
diff --git a/base/base_unittests.isolate b/base/base_unittests.isolate
new file mode 100644
index 0000000..57fc4d2
--- /dev/null
+++ b/base/base_unittests.isolate
@@ -0,0 +1,58 @@
+# Copyright (c) 2012 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.
+{
+  'variables': {
+    'command': [
+      '../testing/test_env.py',
+      '<(PRODUCT_DIR)/base_unittests<(EXECUTABLE_SUFFIX)',
+      '--brave-new-test-launcher',
+      '--test-launcher-bot-mode',
+      '--asan=<(asan)',
+      '--msan=<(msan)',
+      '--tsan=<(tsan)',
+    ],
+  },
+  'conditions': [
+    ['OS=="android" or OS=="linux" or OS=="mac" or OS=="win"', {
+      'variables': {
+        'files': [
+          'test/data/',
+        ],
+      },
+    }],
+    ['OS=="linux" or OS=="mac" or OS=="win"', {
+      'variables': {
+        'files': [
+          '../testing/test_env.py',
+          '<(PRODUCT_DIR)/base_unittests<(EXECUTABLE_SUFFIX)',
+        ],
+        'read_only': 1,
+      },
+    }],
+    ['OS=="linux"', {
+      'variables': {
+        'files': [
+          '<(PRODUCT_DIR)/lib/libmalloc_wrapper.so',
+        ],
+      },
+    }],
+    ['OS=="mac" and asan==1 and fastbuild==0', {
+      'variables': {
+        'files': [
+          '<(PRODUCT_DIR)/base_unittests.dSYM/',
+        ],
+      },
+    }],
+    ['OS=="win" and (fastbuild==0 or fastbuild==1)', {
+      'variables': {
+        'files': [
+          '<(PRODUCT_DIR)/base_unittests.exe.pdb',
+        ],
+      },
+    }],
+  ],
+  'includes': [
+    'base.isolate',
+  ],
+}
diff --git a/base/basictypes.h b/base/basictypes.h
new file mode 100644
index 0000000..d71abd9
--- /dev/null
+++ b/base/basictypes.h
@@ -0,0 +1,45 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains definitions of our old basic integral types
+// ((u)int{8,16,32,64}) and further includes. I recommend that you use the C99
+// standard types instead, and include <stdint.h>/<stddef.h>/etc. as needed.
+// Note that the macros and macro-like constructs that were formerly defined in
+// this file are now available separately in base/macros.h.
+
+#ifndef BASE_BASICTYPES_H_
+#define BASE_BASICTYPES_H_
+
+#include <limits.h>  // So we can set the bounds of our types.
+#include <stddef.h>  // For size_t.
+#include <stdint.h>  // For intptr_t.
+
+#include "base/macros.h"
+#include "build/build_config.h"
+
+// DEPRECATED: Please use (u)int{8,16,32,64}_t instead (and include <stdint.h>).
+typedef int8_t int8;
+typedef uint8_t uint8;
+typedef int16_t int16;
+typedef uint16_t uint16;
+typedef int32_t int32;
+typedef uint32_t uint32;
+typedef int64_t int64;
+typedef uint64_t uint64;
+
+// DEPRECATED: Please use std::numeric_limits (from <limits>) instead.
+const uint8  kuint8max  =  0xFF;
+const uint16 kuint16max =  0xFFFF;
+const uint32 kuint32max =  0xFFFFFFFF;
+const uint64 kuint64max =  0xFFFFFFFFFFFFFFFFULL;
+const  int8  kint8min   = -0x7F - 1;
+const  int8  kint8max   =  0x7F;
+const  int16 kint16min  = -0x7FFF - 1;
+const  int16 kint16max  =  0x7FFF;
+const  int32 kint32min  = -0x7FFFFFFF - 1;
+const  int32 kint32max  =  0x7FFFFFFF;
+const  int64 kint64min  = -0x7FFFFFFFFFFFFFFFLL - 1;
+const  int64 kint64max  =  0x7FFFFFFFFFFFFFFFLL;
+
+#endif  // BASE_BASICTYPES_H_
diff --git a/base/big_endian.cc b/base/big_endian.cc
new file mode 100644
index 0000000..9b69147
--- /dev/null
+++ b/base/big_endian.cc
@@ -0,0 +1,105 @@
+// 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.
+
+#include "base/big_endian.h"
+
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+BigEndianReader::BigEndianReader(const char* buf, size_t len)
+    : ptr_(buf), end_(ptr_ + len) {}
+
+bool BigEndianReader::Skip(size_t len) {
+  if (ptr_ + len > end_)
+    return false;
+  ptr_ += len;
+  return true;
+}
+
+bool BigEndianReader::ReadBytes(void* out, size_t len) {
+  if (ptr_ + len > end_)
+    return false;
+  memcpy(out, ptr_, len);
+  ptr_ += len;
+  return true;
+}
+
+bool BigEndianReader::ReadPiece(base::StringPiece* out, size_t len) {
+  if (ptr_ + len > end_)
+    return false;
+  *out = base::StringPiece(ptr_, len);
+  ptr_ += len;
+  return true;
+}
+
+template<typename T>
+bool BigEndianReader::Read(T* value) {
+  if (ptr_ + sizeof(T) > end_)
+    return false;
+  ReadBigEndian<T>(ptr_, value);
+  ptr_ += sizeof(T);
+  return true;
+}
+
+bool BigEndianReader::ReadU8(uint8* value) {
+  return Read(value);
+}
+
+bool BigEndianReader::ReadU16(uint16* value) {
+  return Read(value);
+}
+
+bool BigEndianReader::ReadU32(uint32* value) {
+  return Read(value);
+}
+
+bool BigEndianReader::ReadU64(uint64* value) {
+  return Read(value);
+}
+
+BigEndianWriter::BigEndianWriter(char* buf, size_t len)
+    : ptr_(buf), end_(ptr_ + len) {}
+
+bool BigEndianWriter::Skip(size_t len) {
+  if (ptr_ + len > end_)
+    return false;
+  ptr_ += len;
+  return true;
+}
+
+bool BigEndianWriter::WriteBytes(const void* buf, size_t len) {
+  if (ptr_ + len > end_)
+    return false;
+  memcpy(ptr_, buf, len);
+  ptr_ += len;
+  return true;
+}
+
+template<typename T>
+bool BigEndianWriter::Write(T value) {
+  if (ptr_ + sizeof(T) > end_)
+    return false;
+  WriteBigEndian<T>(ptr_, value);
+  ptr_ += sizeof(T);
+  return true;
+}
+
+bool BigEndianWriter::WriteU8(uint8 value) {
+  return Write(value);
+}
+
+bool BigEndianWriter::WriteU16(uint16 value) {
+  return Write(value);
+}
+
+bool BigEndianWriter::WriteU32(uint32 value) {
+  return Write(value);
+}
+
+bool BigEndianWriter::WriteU64(uint64 value) {
+  return Write(value);
+}
+
+}  // namespace base
diff --git a/base/big_endian.h b/base/big_endian.h
new file mode 100644
index 0000000..914767f
--- /dev/null
+++ b/base/big_endian.h
@@ -0,0 +1,104 @@
+// 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.
+
+#ifndef BASE_BIG_ENDIAN_H_
+#define BASE_BIG_ENDIAN_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+// Read an integer (signed or unsigned) from |buf| in Big Endian order.
+// Note: this loop is unrolled with -O1 and above.
+// NOTE(szym): glibc dns-canon.c and SpdyFrameBuilder use
+// ntohs(*(uint16_t*)ptr) which is potentially unaligned.
+// This would cause SIGBUS on ARMv5 or earlier and ARMv6-M.
+template<typename T>
+inline void ReadBigEndian(const char buf[], T* out) {
+  *out = buf[0];
+  for (size_t i = 1; i < sizeof(T); ++i) {
+    *out <<= 8;
+    // Must cast to uint8 to avoid clobbering by sign extension.
+    *out |= static_cast<uint8>(buf[i]);
+  }
+}
+
+// Write an integer (signed or unsigned) |val| to |buf| in Big Endian order.
+// Note: this loop is unrolled with -O1 and above.
+template<typename T>
+inline void WriteBigEndian(char buf[], T val) {
+  for (size_t i = 0; i < sizeof(T); ++i) {
+    buf[sizeof(T)-i-1] = static_cast<char>(val & 0xFF);
+    val >>= 8;
+  }
+}
+
+// Specializations to make clang happy about the (dead code) shifts above.
+template<>
+inline void ReadBigEndian<uint8>(const char buf[], uint8* out) {
+  *out = buf[0];
+}
+
+template<>
+inline void WriteBigEndian<uint8>(char buf[], uint8 val) {
+  buf[0] = static_cast<char>(val);
+}
+
+// Allows reading integers in network order (big endian) while iterating over
+// an underlying buffer. All the reading functions advance the internal pointer.
+class BASE_EXPORT BigEndianReader {
+ public:
+  BigEndianReader(const char* buf, size_t len);
+
+  const char* ptr() const { return ptr_; }
+  int remaining() const { return end_ - ptr_; }
+
+  bool Skip(size_t len);
+  bool ReadBytes(void* out, size_t len);
+  // Creates a StringPiece in |out| that points to the underlying buffer.
+  bool ReadPiece(base::StringPiece* out, size_t len);
+  bool ReadU8(uint8* value);
+  bool ReadU16(uint16* value);
+  bool ReadU32(uint32* value);
+  bool ReadU64(uint64* value);
+
+ private:
+  // Hidden to promote type safety.
+  template<typename T>
+  bool Read(T* v);
+
+  const char* ptr_;
+  const char* end_;
+};
+
+// Allows writing integers in network order (big endian) while iterating over
+// an underlying buffer. All the writing functions advance the internal pointer.
+class BASE_EXPORT BigEndianWriter {
+ public:
+  BigEndianWriter(char* buf, size_t len);
+
+  char* ptr() const { return ptr_; }
+  int remaining() const { return end_ - ptr_; }
+
+  bool Skip(size_t len);
+  bool WriteBytes(const void* buf, size_t len);
+  bool WriteU8(uint8 value);
+  bool WriteU16(uint16 value);
+  bool WriteU32(uint32 value);
+  bool WriteU64(uint64 value);
+
+ private:
+  // Hidden to promote type safety.
+  template<typename T>
+  bool Write(T v);
+
+  char* ptr_;
+  char* end_;
+};
+
+}  // namespace base
+
+#endif  // BASE_BIG_ENDIAN_H_
diff --git a/base/big_endian_unittest.cc b/base/big_endian_unittest.cc
new file mode 100644
index 0000000..0e4b3f1
--- /dev/null
+++ b/base/big_endian_unittest.cc
@@ -0,0 +1,114 @@
+// 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.
+
+#include "base/big_endian.h"
+
+#include "base/strings/string_piece.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(BigEndianReaderTest, ReadsValues) {
+  char data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF,
+                  0x1A, 0x2B, 0x3C, 0x4D, 0x5E };
+  char buf[2];
+  uint8 u8;
+  uint16 u16;
+  uint32 u32;
+  uint64 u64;
+  base::StringPiece piece;
+  BigEndianReader reader(data, sizeof(data));
+
+  EXPECT_TRUE(reader.Skip(2));
+  EXPECT_EQ(data + 2, reader.ptr());
+  EXPECT_EQ(reader.remaining(), static_cast<int>(sizeof(data)) - 2);
+  EXPECT_TRUE(reader.ReadBytes(buf, sizeof(buf)));
+  EXPECT_EQ(0x2, buf[0]);
+  EXPECT_EQ(0x3, buf[1]);
+  EXPECT_TRUE(reader.ReadU8(&u8));
+  EXPECT_EQ(0x4, u8);
+  EXPECT_TRUE(reader.ReadU16(&u16));
+  EXPECT_EQ(0x0506, u16);
+  EXPECT_TRUE(reader.ReadU32(&u32));
+  EXPECT_EQ(0x0708090Au, u32);
+  EXPECT_TRUE(reader.ReadU64(&u64));
+  EXPECT_EQ(0x0B0C0D0E0F1A2B3Cllu, u64);
+  base::StringPiece expected(reader.ptr(), 2);
+  EXPECT_TRUE(reader.ReadPiece(&piece, 2));
+  EXPECT_EQ(2u, piece.size());
+  EXPECT_EQ(expected.data(), piece.data());
+}
+
+TEST(BigEndianReaderTest, RespectsLength) {
+  char data[8];
+  char buf[2];
+  uint8 u8;
+  uint16 u16;
+  uint32 u32;
+  uint64 u64;
+  base::StringPiece piece;
+  BigEndianReader reader(data, sizeof(data));
+  // 8 left
+  EXPECT_FALSE(reader.Skip(9));
+  EXPECT_TRUE(reader.Skip(1));
+  // 7 left
+  EXPECT_FALSE(reader.ReadU64(&u64));
+  EXPECT_TRUE(reader.Skip(4));
+  // 3 left
+  EXPECT_FALSE(reader.ReadU32(&u32));
+  EXPECT_FALSE(reader.ReadPiece(&piece, 4));
+  EXPECT_TRUE(reader.Skip(2));
+  // 1 left
+  EXPECT_FALSE(reader.ReadU16(&u16));
+  EXPECT_FALSE(reader.ReadBytes(buf, 2));
+  EXPECT_TRUE(reader.Skip(1));
+  // 0 left
+  EXPECT_FALSE(reader.ReadU8(&u8));
+  EXPECT_EQ(0, reader.remaining());
+}
+
+TEST(BigEndianWriterTest, WritesValues) {
+  char expected[] = { 0, 0, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE,
+                      0xF, 0x1A, 0x2B, 0x3C };
+  char data[sizeof(expected)];
+  char buf[] = { 0x2, 0x3 };
+  memset(data, 0, sizeof(data));
+  BigEndianWriter writer(data, sizeof(data));
+
+  EXPECT_TRUE(writer.Skip(2));
+  EXPECT_TRUE(writer.WriteBytes(buf, sizeof(buf)));
+  EXPECT_TRUE(writer.WriteU8(0x4));
+  EXPECT_TRUE(writer.WriteU16(0x0506));
+  EXPECT_TRUE(writer.WriteU32(0x0708090A));
+  EXPECT_TRUE(writer.WriteU64(0x0B0C0D0E0F1A2B3Cllu));
+  EXPECT_EQ(0, memcmp(expected, data, sizeof(expected)));
+}
+
+TEST(BigEndianWriterTest, RespectsLength) {
+  char data[8];
+  char buf[2];
+  uint8 u8 = 0;
+  uint16 u16 = 0;
+  uint32 u32 = 0;
+  uint64 u64 = 0;
+  BigEndianWriter writer(data, sizeof(data));
+  // 8 left
+  EXPECT_FALSE(writer.Skip(9));
+  EXPECT_TRUE(writer.Skip(1));
+  // 7 left
+  EXPECT_FALSE(writer.WriteU64(u64));
+  EXPECT_TRUE(writer.Skip(4));
+  // 3 left
+  EXPECT_FALSE(writer.WriteU32(u32));
+  EXPECT_TRUE(writer.Skip(2));
+  // 1 left
+  EXPECT_FALSE(writer.WriteU16(u16));
+  EXPECT_FALSE(writer.WriteBytes(buf, 2));
+  EXPECT_TRUE(writer.Skip(1));
+  // 0 left
+  EXPECT_FALSE(writer.WriteU8(u8));
+  EXPECT_EQ(0, writer.remaining());
+}
+
+}  // namespace base
diff --git a/base/bind.h b/base/bind.h
new file mode 100644
index 0000000..51be10d
--- /dev/null
+++ b/base/bind.h
@@ -0,0 +1,118 @@
+// Copyright (c) 2011 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_BIND_H_
+#define BASE_BIND_H_
+
+#include "base/bind_internal.h"
+#include "base/callback_internal.h"
+
+// -----------------------------------------------------------------------------
+// Usage documentation
+// -----------------------------------------------------------------------------
+//
+// See base/callback.h for documentation.
+//
+//
+// -----------------------------------------------------------------------------
+// Implementation notes
+// -----------------------------------------------------------------------------
+//
+// If you're reading the implementation, before proceeding further, you should
+// read the top comment of base/bind_internal.h for a definition of common
+// terms and concepts.
+//
+// RETURN TYPES
+//
+// Though Bind()'s result is meant to be stored in a Callback<> type, it
+// cannot actually return the exact type without requiring a large amount
+// of extra template specializations. The problem is that in order to
+// discern the correct specialization of Callback<>, Bind would need to
+// unwrap the function signature to determine the signature's arity, and
+// whether or not it is a method.
+//
+// Each unique combination of (arity, function_type, num_prebound) where
+// function_type is one of {function, method, const_method} would require
+// one specialization.  We eventually have to do a similar number of
+// specializations anyways in the implementation (see the Invoker<>,
+// classes).  However, it is avoidable in Bind if we return the result
+// via an indirection like we do below.
+//
+// TODO(ajwong): We might be able to avoid this now, but need to test.
+//
+// It is possible to move most of the static_assert into BindState<>, but it
+// feels a little nicer to have the asserts here so people do not need to crack
+// open bind_internal.h.  On the other hand, it makes Bind() harder to read.
+
+namespace base {
+
+template <typename Functor>
+base::Callback<
+    typename internal::BindState<
+        typename internal::FunctorTraits<Functor>::RunnableType,
+        typename internal::FunctorTraits<Functor>::RunType,
+        internal::TypeList<>>::UnboundRunType>
+Bind(Functor functor) {
+  // Typedefs for how to store and run the functor.
+  typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
+  typedef typename internal::FunctorTraits<Functor>::RunType RunType;
+
+  typedef internal::BindState<RunnableType, RunType,
+                              internal::TypeList<>> BindState;
+
+  return Callback<typename BindState::UnboundRunType>(
+      new BindState(internal::MakeRunnable(functor)));
+}
+
+template <typename Functor, typename... Args>
+base::Callback<
+    typename internal::BindState<
+        typename internal::FunctorTraits<Functor>::RunnableType,
+        typename internal::FunctorTraits<Functor>::RunType,
+        internal::TypeList<
+            typename internal::CallbackParamTraits<Args>::StorageType...>>
+            ::UnboundRunType>
+Bind(Functor functor, const Args&... args) {
+  // Typedefs for how to store and run the functor.
+  typedef typename internal::FunctorTraits<Functor>::RunnableType RunnableType;
+  typedef typename internal::FunctorTraits<Functor>::RunType RunType;
+
+  // Use RunnableType::RunType instead of RunType above because our
+  // checks should below for bound references need to know what the actual
+  // functor is going to interpret the argument as.
+  typedef typename RunnableType::RunType BoundRunType;
+
+  // Do not allow binding a non-const reference parameter. Non-const reference
+  // parameters are disallowed by the Google style guide.  Also, binding a
+  // non-const reference parameter can make for subtle bugs because the
+  // invoked function will receive a reference to the stored copy of the
+  // argument and not the original.
+  static_assert(!internal::HasNonConstReferenceParam<BoundRunType>::value,
+                "do_not_bind_functions_with_nonconst_ref");
+
+  const bool is_method = internal::HasIsMethodTag<RunnableType>::value;
+
+  // For methods, we need to be careful for parameter 1.  We do not require
+  // a scoped_refptr because BindState<> itself takes care of AddRef() for
+  // methods. We also disallow binding of an array as the method's target
+  // object.
+  static_assert(!internal::BindsArrayToFirstArg<is_method, Args...>::value,
+                "first_bound_argument_to_method_cannot_be_array");
+  static_assert(
+      !internal::HasRefCountedParamAsRawPtr<is_method, Args...>::value,
+      "a_parameter_is_refcounted_type_and_needs_scoped_refptr");
+
+  typedef internal::BindState<
+      RunnableType, RunType,
+      internal::TypeList<
+          typename internal::CallbackParamTraits<Args>::StorageType...>>
+      BindState;
+
+  return Callback<typename BindState::UnboundRunType>(
+      new BindState(internal::MakeRunnable(functor), args...));
+}
+
+}  // namespace base
+
+#endif  // BASE_BIND_H_
diff --git a/base/bind_helpers.cc b/base/bind_helpers.cc
new file mode 100644
index 0000000..f1fe46d
--- /dev/null
+++ b/base/bind_helpers.cc
@@ -0,0 +1,14 @@
+// Copyright (c) 2012 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/bind_helpers.h"
+
+#include "base/callback.h"
+
+namespace base {
+
+void DoNothing() {
+}
+
+}  // namespace base
diff --git a/base/bind_helpers.h b/base/bind_helpers.h
new file mode 100644
index 0000000..24063ad
--- /dev/null
+++ b/base/bind_helpers.h
@@ -0,0 +1,602 @@
+// Copyright (c) 2011 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 defines a set of argument wrappers and related factory methods that
+// can be used specify the refcounting and reference semantics of arguments
+// that are bound by the Bind() function in base/bind.h.
+//
+// It also defines a set of simple functions and utilities that people want
+// when using Callback<> and Bind().
+//
+//
+// ARGUMENT BINDING WRAPPERS
+//
+// The wrapper functions are base::Unretained(), base::Owned(), base::Passed(),
+// base::ConstRef(), and base::IgnoreResult().
+//
+// Unretained() allows Bind() to bind a non-refcounted class, and to disable
+// refcounting on arguments that are refcounted objects.
+//
+// Owned() transfers ownership of an object to the Callback resulting from
+// bind; the object will be deleted when the Callback is deleted.
+//
+// Passed() is for transferring movable-but-not-copyable types (eg. scoped_ptr)
+// through a Callback. Logically, this signifies a destructive transfer of
+// the state of the argument into the target function.  Invoking
+// Callback::Run() twice on a Callback that was created with a Passed()
+// argument will CHECK() because the first invocation would have already
+// transferred ownership to the target function.
+//
+// ConstRef() allows binding a constant reference to an argument rather
+// than a copy.
+//
+// IgnoreResult() is used to adapt a function or Callback with a return type to
+// one with a void return. This is most useful if you have a function with,
+// say, a pesky ignorable bool return that you want to use with PostTask or
+// something else that expect a Callback with a void return.
+//
+// EXAMPLE OF Unretained():
+//
+//   class Foo {
+//    public:
+//     void func() { cout << "Foo:f" << endl; }
+//   };
+//
+//   // In some function somewhere.
+//   Foo foo;
+//   Closure foo_callback =
+//       Bind(&Foo::func, Unretained(&foo));
+//   foo_callback.Run();  // Prints "Foo:f".
+//
+// Without the Unretained() wrapper on |&foo|, the above call would fail
+// to compile because Foo does not support the AddRef() and Release() methods.
+//
+//
+// EXAMPLE OF Owned():
+//
+//   void foo(int* arg) { cout << *arg << endl }
+//
+//   int* pn = new int(1);
+//   Closure foo_callback = Bind(&foo, Owned(pn));
+//
+//   foo_callback.Run();  // Prints "1"
+//   foo_callback.Run();  // Prints "1"
+//   *n = 2;
+//   foo_callback.Run();  // Prints "2"
+//
+//   foo_callback.Reset();  // |pn| is deleted.  Also will happen when
+//                          // |foo_callback| goes out of scope.
+//
+// Without Owned(), someone would have to know to delete |pn| when the last
+// reference to the Callback is deleted.
+//
+//
+// EXAMPLE OF ConstRef():
+//
+//   void foo(int arg) { cout << arg << endl }
+//
+//   int n = 1;
+//   Closure no_ref = Bind(&foo, n);
+//   Closure has_ref = Bind(&foo, ConstRef(n));
+//
+//   no_ref.Run();  // Prints "1"
+//   has_ref.Run();  // Prints "1"
+//
+//   n = 2;
+//   no_ref.Run();  // Prints "1"
+//   has_ref.Run();  // Prints "2"
+//
+// Note that because ConstRef() takes a reference on |n|, |n| must outlive all
+// its bound callbacks.
+//
+//
+// EXAMPLE OF IgnoreResult():
+//
+//   int DoSomething(int arg) { cout << arg << endl; }
+//
+//   // Assign to a Callback with a void return type.
+//   Callback<void(int)> cb = Bind(IgnoreResult(&DoSomething));
+//   cb->Run(1);  // Prints "1".
+//
+//   // Prints "1" on |ml|.
+//   ml->PostTask(FROM_HERE, Bind(IgnoreResult(&DoSomething), 1);
+//
+//
+// EXAMPLE OF Passed():
+//
+//   void TakesOwnership(scoped_ptr<Foo> arg) { }
+//   scoped_ptr<Foo> CreateFoo() { return scoped_ptr<Foo>(new Foo()); }
+//
+//   scoped_ptr<Foo> f(new Foo());
+//
+//   // |cb| is given ownership of Foo(). |f| is now NULL.
+//   // You can use f.Pass() in place of &f, but it's more verbose.
+//   Closure cb = Bind(&TakesOwnership, Passed(&f));
+//
+//   // Run was never called so |cb| still owns Foo() and deletes
+//   // it on Reset().
+//   cb.Reset();
+//
+//   // |cb| is given a new Foo created by CreateFoo().
+//   cb = Bind(&TakesOwnership, Passed(CreateFoo()));
+//
+//   // |arg| in TakesOwnership() is given ownership of Foo(). |cb|
+//   // no longer owns Foo() and, if reset, would not delete Foo().
+//   cb.Run();  // Foo() is now transferred to |arg| and deleted.
+//   cb.Run();  // This CHECK()s since Foo() already been used once.
+//
+// Passed() is particularly useful with PostTask() when you are transferring
+// ownership of an argument into a task, but don't necessarily know if the
+// task will always be executed. This can happen if the task is cancellable
+// or if it is posted to a TaskRunner.
+//
+//
+// SIMPLE FUNCTIONS AND UTILITIES.
+//
+//   DoNothing() - Useful for creating a Closure that does nothing when called.
+//   DeletePointer<T>() - Useful for creating a Closure that will delete a
+//                        pointer when invoked. Only use this when necessary.
+//                        In most cases MessageLoop::DeleteSoon() is a better
+//                        fit.
+
+#ifndef BASE_BIND_HELPERS_H_
+#define BASE_BIND_HELPERS_H_
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "base/template_util.h"
+
+namespace base {
+namespace internal {
+
+// Use the Substitution Failure Is Not An Error (SFINAE) trick to inspect T
+// for the existence of AddRef() and Release() functions of the correct
+// signature.
+//
+// http://en.wikipedia.org/wiki/Substitution_failure_is_not_an_error
+// http://stackoverflow.com/questions/257288/is-it-possible-to-write-a-c-template-to-check-for-a-functions-existence
+// http://stackoverflow.com/questions/4358584/sfinae-approach-comparison
+// http://stackoverflow.com/questions/1966362/sfinae-to-check-for-inherited-member-functions
+//
+// The last link in particular show the method used below.
+//
+// For SFINAE to work with inherited methods, we need to pull some extra tricks
+// with multiple inheritance.  In the more standard formulation, the overloads
+// of Check would be:
+//
+//   template <typename C>
+//   Yes NotTheCheckWeWant(Helper<&C::TargetFunc>*);
+//
+//   template <typename C>
+//   No NotTheCheckWeWant(...);
+//
+//   static const bool value = sizeof(NotTheCheckWeWant<T>(0)) == sizeof(Yes);
+//
+// The problem here is that template resolution will not match
+// C::TargetFunc if TargetFunc does not exist directly in C.  That is, if
+// TargetFunc in inherited from an ancestor, &C::TargetFunc will not match,
+// |value| will be false.  This formulation only checks for whether or
+// not TargetFunc exist directly in the class being introspected.
+//
+// To get around this, we play a dirty trick with multiple inheritance.
+// First, We create a class BaseMixin that declares each function that we
+// want to probe for.  Then we create a class Base that inherits from both T
+// (the class we wish to probe) and BaseMixin.  Note that the function
+// signature in BaseMixin does not need to match the signature of the function
+// we are probing for; thus it's easiest to just use void(void).
+//
+// Now, if TargetFunc exists somewhere in T, then &Base::TargetFunc has an
+// ambiguous resolution between BaseMixin and T.  This lets us write the
+// following:
+//
+//   template <typename C>
+//   No GoodCheck(Helper<&C::TargetFunc>*);
+//
+//   template <typename C>
+//   Yes GoodCheck(...);
+//
+//   static const bool value = sizeof(GoodCheck<Base>(0)) == sizeof(Yes);
+//
+// Notice here that the variadic version of GoodCheck() returns Yes here
+// instead of No like the previous one. Also notice that we calculate |value|
+// by specializing GoodCheck() on Base instead of T.
+//
+// We've reversed the roles of the variadic, and Helper overloads.
+// GoodCheck(Helper<&C::TargetFunc>*), when C = Base, fails to be a valid
+// substitution if T::TargetFunc exists. Thus GoodCheck<Base>(0) will resolve
+// to the variadic version if T has TargetFunc.  If T::TargetFunc does not
+// exist, then &C::TargetFunc is not ambiguous, and the overload resolution
+// will prefer GoodCheck(Helper<&C::TargetFunc>*).
+//
+// This method of SFINAE will correctly probe for inherited names, but it cannot
+// typecheck those names.  It's still a good enough sanity check though.
+//
+// Works on gcc-4.2, gcc-4.4, and Visual Studio 2008.
+//
+// TODO(ajwong): Move to ref_counted.h or template_util.h when we've vetted
+// this works well.
+//
+// TODO(ajwong): Make this check for Release() as well.
+// See http://crbug.com/82038.
+template <typename T>
+class SupportsAddRefAndRelease {
+  typedef char Yes[1];
+  typedef char No[2];
+
+  struct BaseMixin {
+    void AddRef();
+  };
+
+// MSVC warns when you try to use Base if T has a private destructor, the
+// common pattern for refcounted types. It does this even though no attempt to
+// instantiate Base is made.  We disable the warning for this definition.
+#if defined(OS_WIN)
+#pragma warning(push)
+#pragma warning(disable:4624)
+#endif
+  struct Base : public T, public BaseMixin {
+  };
+#if defined(OS_WIN)
+#pragma warning(pop)
+#endif
+
+  template <void(BaseMixin::*)(void)> struct Helper {};
+
+  template <typename C>
+  static No& Check(Helper<&C::AddRef>*);
+
+  template <typename >
+  static Yes& Check(...);
+
+ public:
+  enum { value = sizeof(Check<Base>(0)) == sizeof(Yes) };
+};
+
+// Helpers to assert that arguments of a recounted type are bound with a
+// scoped_refptr.
+template <bool IsClasstype, typename T>
+struct UnsafeBindtoRefCountedArgHelper : false_type {
+};
+
+template <typename T>
+struct UnsafeBindtoRefCountedArgHelper<true, T>
+    : integral_constant<bool, SupportsAddRefAndRelease<T>::value> {
+};
+
+template <typename T>
+struct UnsafeBindtoRefCountedArg : false_type {
+};
+
+template <typename T>
+struct UnsafeBindtoRefCountedArg<T*>
+    : UnsafeBindtoRefCountedArgHelper<is_class<T>::value, T> {
+};
+
+template <typename T>
+class HasIsMethodTag {
+  typedef char Yes[1];
+  typedef char No[2];
+
+  template <typename U>
+  static Yes& Check(typename U::IsMethod*);
+
+  template <typename U>
+  static No& Check(...);
+
+ public:
+  enum { value = sizeof(Check<T>(0)) == sizeof(Yes) };
+};
+
+template <typename T>
+class UnretainedWrapper {
+ public:
+  explicit UnretainedWrapper(T* o) : ptr_(o) {}
+  T* get() const { return ptr_; }
+ private:
+  T* ptr_;
+};
+
+template <typename T>
+class ConstRefWrapper {
+ public:
+  explicit ConstRefWrapper(const T& o) : ptr_(&o) {}
+  const T& get() const { return *ptr_; }
+ private:
+  const T* ptr_;
+};
+
+template <typename T>
+struct IgnoreResultHelper {
+  explicit IgnoreResultHelper(T functor) : functor_(functor) {}
+
+  T functor_;
+};
+
+template <typename T>
+struct IgnoreResultHelper<Callback<T> > {
+  explicit IgnoreResultHelper(const Callback<T>& functor) : functor_(functor) {}
+
+  const Callback<T>& functor_;
+};
+
+// An alternate implementation is to avoid the destructive copy, and instead
+// specialize ParamTraits<> for OwnedWrapper<> to change the StorageType to
+// a class that is essentially a scoped_ptr<>.
+//
+// The current implementation has the benefit though of leaving ParamTraits<>
+// fully in callback_internal.h as well as avoiding type conversions during
+// storage.
+template <typename T>
+class OwnedWrapper {
+ public:
+  explicit OwnedWrapper(T* o) : ptr_(o) {}
+  ~OwnedWrapper() { delete ptr_; }
+  T* get() const { return ptr_; }
+  OwnedWrapper(const OwnedWrapper& other) {
+    ptr_ = other.ptr_;
+    other.ptr_ = NULL;
+  }
+
+ private:
+  mutable T* ptr_;
+};
+
+// PassedWrapper is a copyable adapter for a scoper that ignores const.
+//
+// It is needed to get around the fact that Bind() takes a const reference to
+// all its arguments.  Because Bind() takes a const reference to avoid
+// unnecessary copies, it is incompatible with movable-but-not-copyable
+// types; doing a destructive "move" of the type into Bind() would violate
+// the const correctness.
+//
+// This conundrum cannot be solved without either C++11 rvalue references or
+// a O(2^n) blowup of Bind() templates to handle each combination of regular
+// types and movable-but-not-copyable types.  Thus we introduce a wrapper type
+// that is copyable to transmit the correct type information down into
+// BindState<>. Ignoring const in this type makes sense because it is only
+// created when we are explicitly trying to do a destructive move.
+//
+// Two notes:
+//  1) PassedWrapper supports any type that has a "Pass()" function.
+//     This is intentional. The whitelisting of which specific types we
+//     support is maintained by CallbackParamTraits<>.
+//  2) is_valid_ is distinct from NULL because it is valid to bind a "NULL"
+//     scoper to a Callback and allow the Callback to execute once.
+template <typename T>
+class PassedWrapper {
+ public:
+  explicit PassedWrapper(T scoper) : is_valid_(true), scoper_(scoper.Pass()) {}
+  PassedWrapper(const PassedWrapper& other)
+      : is_valid_(other.is_valid_), scoper_(other.scoper_.Pass()) {
+  }
+  T Pass() const {
+    CHECK(is_valid_);
+    is_valid_ = false;
+    return scoper_.Pass();
+  }
+
+ private:
+  mutable bool is_valid_;
+  mutable T scoper_;
+};
+
+// Unwrap the stored parameters for the wrappers above.
+template <typename T>
+struct UnwrapTraits {
+  typedef const T& ForwardType;
+  static ForwardType Unwrap(const T& o) { return o; }
+};
+
+template <typename T>
+struct UnwrapTraits<UnretainedWrapper<T> > {
+  typedef T* ForwardType;
+  static ForwardType Unwrap(UnretainedWrapper<T> unretained) {
+    return unretained.get();
+  }
+};
+
+template <typename T>
+struct UnwrapTraits<ConstRefWrapper<T> > {
+  typedef const T& ForwardType;
+  static ForwardType Unwrap(ConstRefWrapper<T> const_ref) {
+    return const_ref.get();
+  }
+};
+
+template <typename T>
+struct UnwrapTraits<scoped_refptr<T> > {
+  typedef T* ForwardType;
+  static ForwardType Unwrap(const scoped_refptr<T>& o) { return o.get(); }
+};
+
+template <typename T>
+struct UnwrapTraits<WeakPtr<T> > {
+  typedef const WeakPtr<T>& ForwardType;
+  static ForwardType Unwrap(const WeakPtr<T>& o) { return o; }
+};
+
+template <typename T>
+struct UnwrapTraits<OwnedWrapper<T> > {
+  typedef T* ForwardType;
+  static ForwardType Unwrap(const OwnedWrapper<T>& o) {
+    return o.get();
+  }
+};
+
+template <typename T>
+struct UnwrapTraits<PassedWrapper<T> > {
+  typedef T ForwardType;
+  static T Unwrap(PassedWrapper<T>& o) {
+    return o.Pass();
+  }
+};
+
+// Utility for handling different refcounting semantics in the Bind()
+// function.
+template <bool is_method, typename... T>
+struct MaybeScopedRefPtr;
+
+template <bool is_method>
+struct MaybeScopedRefPtr<is_method> {
+  MaybeScopedRefPtr() {}
+};
+
+template <typename T, typename... Rest>
+struct MaybeScopedRefPtr<false, T, Rest...> {
+  MaybeScopedRefPtr(const T&, const Rest&...) {}
+};
+
+template <typename T, size_t n, typename... Rest>
+struct MaybeScopedRefPtr<false, T[n], Rest...> {
+  MaybeScopedRefPtr(const T*, const Rest&...) {}
+};
+
+template <typename T, typename... Rest>
+struct MaybeScopedRefPtr<true, T, Rest...> {
+  MaybeScopedRefPtr(const T& o, const Rest&...) {}
+};
+
+template <typename T, typename... Rest>
+struct MaybeScopedRefPtr<true, T*, Rest...> {
+  MaybeScopedRefPtr(T* o, const Rest&...) : ref_(o) {}
+  scoped_refptr<T> ref_;
+};
+
+// No need to additionally AddRef() and Release() since we are storing a
+// scoped_refptr<> inside the storage object already.
+template <typename T, typename... Rest>
+struct MaybeScopedRefPtr<true, scoped_refptr<T>, Rest...> {
+  MaybeScopedRefPtr(const scoped_refptr<T>&, const Rest&...) {}
+};
+
+template <typename T, typename... Rest>
+struct MaybeScopedRefPtr<true, const T*, Rest...> {
+  MaybeScopedRefPtr(const T* o, const Rest&...) : ref_(o) {}
+  scoped_refptr<const T> ref_;
+};
+
+// IsWeakMethod is a helper that determine if we are binding a WeakPtr<> to a
+// method.  It is used internally by Bind() to select the correct
+// InvokeHelper that will no-op itself in the event the WeakPtr<> for
+// the target object is invalidated.
+//
+// The first argument should be the type of the object that will be received by
+// the method.
+template <bool IsMethod, typename... Args>
+struct IsWeakMethod : public false_type {};
+
+template <typename T, typename... Args>
+struct IsWeakMethod<true, WeakPtr<T>, Args...> : public true_type {};
+
+template <typename T, typename... Args>
+struct IsWeakMethod<true, ConstRefWrapper<WeakPtr<T>>, Args...>
+    : public true_type {};
+
+
+// Packs a list of types to hold them in a single type.
+template <typename... Types>
+struct TypeList {};
+
+// Used for DropTypeListItem implementation.
+template <size_t n, typename List>
+struct DropTypeListItemImpl;
+
+// Do not use enable_if and SFINAE here to avoid MSVC2013 compile failure.
+template <size_t n, typename T, typename... List>
+struct DropTypeListItemImpl<n, TypeList<T, List...>>
+    : DropTypeListItemImpl<n - 1, TypeList<List...>> {};
+
+template <typename T, typename... List>
+struct DropTypeListItemImpl<0, TypeList<T, List...>> {
+  typedef TypeList<T, List...> Type;
+};
+
+template <>
+struct DropTypeListItemImpl<0, TypeList<>> {
+  typedef TypeList<> Type;
+};
+
+// A type-level function that drops |n| list item from given TypeList.
+template <size_t n, typename List>
+using DropTypeListItem = typename DropTypeListItemImpl<n, List>::Type;
+
+// Used for ConcatTypeLists implementation.
+template <typename List1, typename List2>
+struct ConcatTypeListsImpl;
+
+template <typename... Types1, typename... Types2>
+struct ConcatTypeListsImpl<TypeList<Types1...>, TypeList<Types2...>> {
+  typedef TypeList<Types1..., Types2...> Type;
+};
+
+// A type-level function that concats two TypeLists.
+template <typename List1, typename List2>
+using ConcatTypeLists = typename ConcatTypeListsImpl<List1, List2>::Type;
+
+// Used for MakeFunctionType implementation.
+template <typename R, typename ArgList>
+struct MakeFunctionTypeImpl;
+
+template <typename R, typename... Args>
+struct MakeFunctionTypeImpl<R, TypeList<Args...>> {
+  typedef R(Type)(Args...);
+};
+
+// A type-level function that constructs a function type that has |R| as its
+// return type and has TypeLists items as its arguments.
+template <typename R, typename ArgList>
+using MakeFunctionType = typename MakeFunctionTypeImpl<R, ArgList>::Type;
+
+}  // namespace internal
+
+template <typename T>
+static inline internal::UnretainedWrapper<T> Unretained(T* o) {
+  return internal::UnretainedWrapper<T>(o);
+}
+
+template <typename T>
+static inline internal::ConstRefWrapper<T> ConstRef(const T& o) {
+  return internal::ConstRefWrapper<T>(o);
+}
+
+template <typename T>
+static inline internal::OwnedWrapper<T> Owned(T* o) {
+  return internal::OwnedWrapper<T>(o);
+}
+
+// We offer 2 syntaxes for calling Passed().  The first takes a temporary and
+// is best suited for use with the return value of a function. The second
+// takes a pointer to the scoper and is just syntactic sugar to avoid having
+// to write Passed(scoper.Pass()).
+template <typename T>
+static inline internal::PassedWrapper<T> Passed(T scoper) {
+  return internal::PassedWrapper<T>(scoper.Pass());
+}
+template <typename T>
+static inline internal::PassedWrapper<T> Passed(T* scoper) {
+  return internal::PassedWrapper<T>(scoper->Pass());
+}
+
+template <typename T>
+static inline internal::IgnoreResultHelper<T> IgnoreResult(T data) {
+  return internal::IgnoreResultHelper<T>(data);
+}
+
+template <typename T>
+static inline internal::IgnoreResultHelper<Callback<T> >
+IgnoreResult(const Callback<T>& data) {
+  return internal::IgnoreResultHelper<Callback<T> >(data);
+}
+
+BASE_EXPORT void DoNothing();
+
+template<typename T>
+void DeletePointer(T* obj) {
+  delete obj;
+}
+
+}  // namespace base
+
+#endif  // BASE_BIND_HELPERS_H_
diff --git a/base/bind_internal.h b/base/bind_internal.h
new file mode 100644
index 0000000..e053218
--- /dev/null
+++ b/base/bind_internal.h
@@ -0,0 +1,422 @@
+// Copyright (c) 2011 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_BIND_INTERNAL_H_
+#define BASE_BIND_INTERNAL_H_
+
+#include "base/bind_helpers.h"
+#include "base/callback_internal.h"
+#include "base/memory/raw_scoped_refptr_mismatch_checker.h"
+#include "base/memory/weak_ptr.h"
+#include "base/template_util.h"
+#include "base/tuple.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include "base/bind_internal_win.h"
+#endif
+
+namespace base {
+namespace internal {
+
+// See base/callback.h for user documentation.
+//
+//
+// CONCEPTS:
+//  Runnable -- A type (really a type class) that has a single Run() method
+//              and a RunType typedef that corresponds to the type of Run().
+//              A Runnable can declare that it should treated like a method
+//              call by including a typedef named IsMethod.  The value of
+//              this typedef is NOT inspected, only the existence.  When a
+//              Runnable declares itself a method, Bind() will enforce special
+//              refcounting + WeakPtr handling semantics for the first
+//              parameter which is expected to be an object.
+//  Functor -- A copyable type representing something that should be called.
+//             All function pointers, Callback<>, and Runnables are functors
+//             even if the invocation syntax differs.
+//  RunType -- A function type (as opposed to function _pointer_ type) for
+//             a Run() function.  Usually just a convenience typedef.
+//  (Bound)ArgsType -- A function type that is being (ab)used to store the
+//                     types of set of arguments.  The "return" type is always
+//                     void here.  We use this hack so that we do not need
+//                     a new type name for each arity of type. (eg.,
+//                     BindState1, BindState2).  This makes forward
+//                     declarations and friending much much easier.
+//
+// Types:
+//  RunnableAdapter<> -- Wraps the various "function" pointer types into an
+//                       object that adheres to the Runnable interface.
+//  ForceVoidReturn<> -- Helper class for translating function signatures to
+//                       equivalent forms with a "void" return type.
+//  FunctorTraits<> -- Type traits used determine the correct RunType and
+//                     RunnableType for a Functor.  This is where function
+//                     signature adapters are applied.
+//  MakeRunnable<> -- Takes a Functor and returns an object in the Runnable
+//                    type class that represents the underlying Functor.
+//                    There are |O(1)| MakeRunnable types.
+//  InvokeHelper<> -- Take a Runnable + arguments and actully invokes it.
+//                    Handle the differing syntaxes needed for WeakPtr<>
+//                    support, and for ignoring return values.  This is separate
+//                    from Invoker to avoid creating multiple version of
+//                    Invoker<>.
+//  Invoker<> -- Unwraps the curried parameters and executes the Runnable.
+//  BindState<> -- Stores the curried parameters, and is the main entry point
+//                 into the Bind() system, doing most of the type resolution.
+//                 There are ARITY BindState types.
+
+// HasNonConstReferenceParam selects true_type when any of the parameters in
+// |Sig| is a non-const reference.
+// Implementation note: This non-specialized case handles zero-arity case only.
+// Non-zero-arity cases should be handled by the specialization below.
+template <typename Sig>
+struct HasNonConstReferenceParam : false_type {};
+
+// Implementation note: Select true_type if the first parameter is a non-const
+// reference.  Otherwise, skip the first parameter and check rest of parameters
+// recursively.
+template <typename R, typename T, typename... Args>
+struct HasNonConstReferenceParam<R(T, Args...)>
+    : SelectType<is_non_const_reference<T>::value,
+                 true_type,
+                 HasNonConstReferenceParam<R(Args...)>>::Type {};
+
+// HasRefCountedTypeAsRawPtr selects true_type when any of the |Args| is a raw
+// pointer to a RefCounted type.
+// Implementation note: This non-specialized case handles zero-arity case only.
+// Non-zero-arity cases should be handled by the specialization below.
+template <typename... Args>
+struct HasRefCountedTypeAsRawPtr : false_type {};
+
+// Implementation note: Select true_type if the first parameter is a raw pointer
+// to a RefCounted type. Otherwise, skip the first parameter and check rest of
+// parameters recursively.
+template <typename T, typename... Args>
+struct HasRefCountedTypeAsRawPtr<T, Args...>
+    : SelectType<NeedsScopedRefptrButGetsRawPtr<T>::value,
+                 true_type,
+                 HasRefCountedTypeAsRawPtr<Args...>>::Type {};
+
+// BindsArrayToFirstArg selects true_type when |is_method| is true and the first
+// item of |Args| is an array type.
+// Implementation note: This non-specialized case handles !is_method case and
+// zero-arity case only.  Other cases should be handled by the specialization
+// below.
+template <bool is_method, typename... Args>
+struct BindsArrayToFirstArg : false_type {};
+
+template <typename T, typename... Args>
+struct BindsArrayToFirstArg<true, T, Args...> : is_array<T> {};
+
+// HasRefCountedParamAsRawPtr is the same to HasRefCountedTypeAsRawPtr except
+// when |is_method| is true HasRefCountedParamAsRawPtr skips the first argument.
+// Implementation note: This non-specialized case handles !is_method case and
+// zero-arity case only.  Other cases should be handled by the specialization
+// below.
+template <bool is_method, typename... Args>
+struct HasRefCountedParamAsRawPtr : HasRefCountedTypeAsRawPtr<Args...> {};
+
+template <typename T, typename... Args>
+struct HasRefCountedParamAsRawPtr<true, T, Args...>
+    : HasRefCountedTypeAsRawPtr<Args...> {};
+
+// RunnableAdapter<>
+//
+// The RunnableAdapter<> templates provide a uniform interface for invoking
+// a function pointer, method pointer, or const method pointer. The adapter
+// exposes a Run() method with an appropriate signature. Using this wrapper
+// allows for writing code that supports all three pointer types without
+// undue repetition.  Without it, a lot of code would need to be repeated 3
+// times.
+//
+// For method pointers and const method pointers the first argument to Run()
+// is considered to be the received of the method.  This is similar to STL's
+// mem_fun().
+//
+// This class also exposes a RunType typedef that is the function type of the
+// Run() function.
+//
+// If and only if the wrapper contains a method or const method pointer, an
+// IsMethod typedef is exposed.  The existence of this typedef (NOT the value)
+// marks that the wrapper should be considered a method wrapper.
+
+template <typename Functor>
+class RunnableAdapter;
+
+// Function.
+template <typename R, typename... Args>
+class RunnableAdapter<R(*)(Args...)> {
+ public:
+  typedef R (RunType)(Args...);
+
+  explicit RunnableAdapter(R(*function)(Args...))
+      : function_(function) {
+  }
+
+  R Run(typename CallbackParamTraits<Args>::ForwardType... args) {
+    return function_(CallbackForward(args)...);
+  }
+
+ private:
+  R (*function_)(Args...);
+};
+
+// Method.
+template <typename R, typename T, typename... Args>
+class RunnableAdapter<R(T::*)(Args...)> {
+ public:
+  typedef R (RunType)(T*, Args...);
+  typedef true_type IsMethod;
+
+  explicit RunnableAdapter(R(T::*method)(Args...))
+      : method_(method) {
+  }
+
+  R Run(T* object, typename CallbackParamTraits<Args>::ForwardType... args) {
+    return (object->*method_)(CallbackForward(args)...);
+  }
+
+ private:
+  R (T::*method_)(Args...);
+};
+
+// Const Method.
+template <typename R, typename T, typename... Args>
+class RunnableAdapter<R(T::*)(Args...) const> {
+ public:
+  typedef R (RunType)(const T*, Args...);
+  typedef true_type IsMethod;
+
+  explicit RunnableAdapter(R(T::*method)(Args...) const)
+      : method_(method) {
+  }
+
+  R Run(const T* object,
+        typename CallbackParamTraits<Args>::ForwardType... args) {
+    return (object->*method_)(CallbackForward(args)...);
+  }
+
+ private:
+  R (T::*method_)(Args...) const;
+};
+
+
+// ForceVoidReturn<>
+//
+// Set of templates that support forcing the function return type to void.
+template <typename Sig>
+struct ForceVoidReturn;
+
+template <typename R, typename... Args>
+struct ForceVoidReturn<R(Args...)> {
+  typedef void(RunType)(Args...);
+};
+
+
+// FunctorTraits<>
+//
+// See description at top of file.
+template <typename T>
+struct FunctorTraits {
+  typedef RunnableAdapter<T> RunnableType;
+  typedef typename RunnableType::RunType RunType;
+};
+
+template <typename T>
+struct FunctorTraits<IgnoreResultHelper<T>> {
+  typedef typename FunctorTraits<T>::RunnableType RunnableType;
+  typedef typename ForceVoidReturn<
+      typename RunnableType::RunType>::RunType RunType;
+};
+
+template <typename T>
+struct FunctorTraits<Callback<T>> {
+  typedef Callback<T> RunnableType;
+  typedef typename Callback<T>::RunType RunType;
+};
+
+
+// MakeRunnable<>
+//
+// Converts a passed in functor to a RunnableType using type inference.
+
+template <typename T>
+typename FunctorTraits<T>::RunnableType MakeRunnable(const T& t) {
+  return RunnableAdapter<T>(t);
+}
+
+template <typename T>
+typename FunctorTraits<T>::RunnableType
+MakeRunnable(const IgnoreResultHelper<T>& t) {
+  return MakeRunnable(t.functor_);
+}
+
+template <typename T>
+const typename FunctorTraits<Callback<T>>::RunnableType&
+MakeRunnable(const Callback<T>& t) {
+  DCHECK(!t.is_null());
+  return t;
+}
+
+
+// InvokeHelper<>
+//
+// There are 3 logical InvokeHelper<> specializations: normal, void-return,
+// WeakCalls.
+//
+// The normal type just calls the underlying runnable.
+//
+// We need a InvokeHelper to handle void return types in order to support
+// IgnoreResult().  Normally, if the Runnable's RunType had a void return,
+// the template system would just accept "return functor.Run()" ignoring
+// the fact that a void function is being used with return. This piece of
+// sugar breaks though when the Runnable's RunType is not void.  Thus, we
+// need a partial specialization to change the syntax to drop the "return"
+// from the invocation call.
+//
+// WeakCalls similarly need special syntax that is applied to the first
+// argument to check if they should no-op themselves.
+template <bool IsWeakCall, typename ReturnType, typename Runnable,
+          typename ArgsType>
+struct InvokeHelper;
+
+template <typename ReturnType, typename Runnable, typename... Args>
+struct InvokeHelper<false, ReturnType, Runnable, TypeList<Args...>> {
+  static ReturnType MakeItSo(Runnable runnable, Args... args) {
+    return runnable.Run(CallbackForward(args)...);
+  }
+};
+
+template <typename Runnable, typename... Args>
+struct InvokeHelper<false, void, Runnable, TypeList<Args...>> {
+  static void MakeItSo(Runnable runnable, Args... args) {
+    runnable.Run(CallbackForward(args)...);
+  }
+};
+
+template <typename Runnable, typename BoundWeakPtr, typename... Args>
+struct InvokeHelper<true, void, Runnable, TypeList<BoundWeakPtr, Args...>> {
+  static void MakeItSo(Runnable runnable, BoundWeakPtr weak_ptr, Args... args) {
+    if (!weak_ptr.get()) {
+      return;
+    }
+    runnable.Run(weak_ptr.get(), CallbackForward(args)...);
+  }
+};
+
+#if !defined(_MSC_VER)
+
+template <typename ReturnType, typename Runnable, typename ArgsType>
+struct InvokeHelper<true, ReturnType, Runnable, ArgsType> {
+  // WeakCalls are only supported for functions with a void return type.
+  // Otherwise, the function result would be undefined if the the WeakPtr<>
+  // is invalidated.
+  COMPILE_ASSERT(is_void<ReturnType>::value,
+                 weak_ptrs_can_only_bind_to_methods_without_return_values);
+};
+
+#endif
+
+// Invoker<>
+//
+// See description at the top of the file.
+template <typename BoundIndices,
+          typename StorageType, typename Unwrappers,
+          typename InvokeHelperType, typename UnboundForwardRunType>
+struct Invoker;
+
+template <size_t... bound_indices,
+          typename StorageType,
+          typename... Unwrappers,
+          typename InvokeHelperType,
+          typename R,
+          typename... UnboundForwardArgs>
+struct Invoker<IndexSequence<bound_indices...>,
+               StorageType, TypeList<Unwrappers...>,
+               InvokeHelperType, R(UnboundForwardArgs...)> {
+  static R Run(BindStateBase* base,
+               UnboundForwardArgs... unbound_args) {
+    StorageType* storage = static_cast<StorageType*>(base);
+    // Local references to make debugger stepping easier. If in a debugger,
+    // you really want to warp ahead and step through the
+    // InvokeHelper<>::MakeItSo() call below.
+    return InvokeHelperType::MakeItSo(
+        storage->runnable_,
+        Unwrappers::Unwrap(get<bound_indices>(storage->bound_args_))...,
+        CallbackForward(unbound_args)...);
+  }
+};
+
+
+// BindState<>
+//
+// This stores all the state passed into Bind() and is also where most
+// of the template resolution magic occurs.
+//
+// Runnable is the functor we are binding arguments to.
+// RunType is type of the Run() function that the Invoker<> should use.
+// Normally, this is the same as the RunType of the Runnable, but it can
+// be different if an adapter like IgnoreResult() has been used.
+//
+// BoundArgsType contains the storage type for all the bound arguments by
+// (ab)using a function type.
+template <typename Runnable, typename RunType, typename BoundArgList>
+struct BindState;
+
+template <typename Runnable,
+          typename R,
+          typename... Args,
+          typename... BoundArgs>
+struct BindState<Runnable, R(Args...), TypeList<BoundArgs...>> final
+    : public BindStateBase {
+ private:
+  using StorageType = BindState<Runnable, R(Args...), TypeList<BoundArgs...>>;
+  using RunnableType = Runnable;
+
+  // true_type if Runnable is a method invocation and the first bound argument
+  // is a WeakPtr.
+  using IsWeakCall =
+      IsWeakMethod<HasIsMethodTag<Runnable>::value, BoundArgs...>;
+
+  using BoundIndices = MakeIndexSequence<sizeof...(BoundArgs)>;
+  using Unwrappers = TypeList<UnwrapTraits<BoundArgs>...>;
+  using UnboundForwardArgs = DropTypeListItem<
+      sizeof...(BoundArgs),
+      TypeList<typename CallbackParamTraits<Args>::ForwardType...>>;
+  using UnboundForwardRunType = MakeFunctionType<R, UnboundForwardArgs>;
+
+  using InvokeHelperArgs = ConcatTypeLists<
+      TypeList<typename UnwrapTraits<BoundArgs>::ForwardType...>,
+      UnboundForwardArgs>;
+  using InvokeHelperType =
+      InvokeHelper<IsWeakCall::value, R, Runnable, InvokeHelperArgs>;
+
+  using UnboundArgs = DropTypeListItem<sizeof...(BoundArgs), TypeList<Args...>>;
+
+ public:
+  using InvokerType = Invoker<BoundIndices, StorageType, Unwrappers,
+                              InvokeHelperType, UnboundForwardRunType>;
+  using UnboundRunType = MakeFunctionType<R, UnboundArgs>;
+
+  BindState(const Runnable& runnable, const BoundArgs&... bound_args)
+      : BindStateBase(&Destroy),
+        runnable_(runnable),
+        ref_(bound_args...),
+        bound_args_(bound_args...) {}
+
+  RunnableType runnable_;
+  MaybeScopedRefPtr<HasIsMethodTag<Runnable>::value, BoundArgs...> ref_;
+  Tuple<BoundArgs...> bound_args_;
+
+ private:
+  ~BindState() {}
+
+  static void Destroy(BindStateBase* self) {
+    delete static_cast<BindState*>(self);
+  }
+};
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_BIND_INTERNAL_H_
diff --git a/base/bind_internal_win.h b/base/bind_internal_win.h
new file mode 100644
index 0000000..c3f7477
--- /dev/null
+++ b/base/bind_internal_win.h
@@ -0,0 +1,63 @@
+// Copyright (c) 2011 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.
+
+// Specializations of RunnableAdapter<> for Windows specific calling
+// conventions.  Please see base/bind_internal.h for more info.
+
+#ifndef BASE_BIND_INTERNAL_WIN_H_
+#define BASE_BIND_INTERNAL_WIN_H_
+
+// In the x64 architecture in Windows, __fastcall, __stdcall, etc, are all
+// the same as __cdecl which would turn the following specializations into
+// multiple definitions.
+#if !defined(ARCH_CPU_X86_64)
+
+namespace base {
+namespace internal {
+
+template <typename Functor>
+class RunnableAdapter;
+
+// __stdcall Function.
+template <typename R, typename... Args>
+class RunnableAdapter<R(__stdcall *)(Args...)> {
+ public:
+  typedef R (RunType)(Args...);
+
+  explicit RunnableAdapter(R(__stdcall *function)(Args...))
+      : function_(function) {
+  }
+
+  R Run(typename CallbackParamTraits<Args>::ForwardType... args) {
+    return function_(args...);
+  }
+
+ private:
+  R (__stdcall *function_)(Args...);
+};
+
+// __fastcall Function.
+template <typename R, typename... Args>
+class RunnableAdapter<R(__fastcall *)(Args...)> {
+ public:
+  typedef R (RunType)(Args...);
+
+  explicit RunnableAdapter(R(__fastcall *function)(Args...))
+      : function_(function) {
+  }
+
+  R Run(typename CallbackParamTraits<Args>::ForwardType... args) {
+    return function_(args...);
+  }
+
+ private:
+  R (__fastcall *function_)(Args...);
+};
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // !defined(ARCH_CPU_X86_64)
+
+#endif  // BASE_BIND_INTERNAL_WIN_H_
diff --git a/base/bind_unittest.cc b/base/bind_unittest.cc
new file mode 100644
index 0000000..f885403
--- /dev/null
+++ b/base/bind_unittest.cc
@@ -0,0 +1,829 @@
+// Copyright (c) 2012 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/bind.h"
+
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::Mock;
+using ::testing::Return;
+using ::testing::StrictMock;
+
+namespace base {
+namespace {
+
+class IncompleteType;
+
+class NoRef {
+ public:
+  NoRef() {}
+
+  MOCK_METHOD0(VoidMethod0, void(void));
+  MOCK_CONST_METHOD0(VoidConstMethod0, void(void));
+
+  MOCK_METHOD0(IntMethod0, int(void));
+  MOCK_CONST_METHOD0(IntConstMethod0, int(void));
+
+ private:
+  // Particularly important in this test to ensure no copies are made.
+  DISALLOW_COPY_AND_ASSIGN(NoRef);
+};
+
+class HasRef : public NoRef {
+ public:
+  HasRef() {}
+
+  MOCK_CONST_METHOD0(AddRef, void(void));
+  MOCK_CONST_METHOD0(Release, bool(void));
+
+ private:
+  // Particularly important in this test to ensure no copies are made.
+  DISALLOW_COPY_AND_ASSIGN(HasRef);
+};
+
+class HasRefPrivateDtor : public HasRef {
+ private:
+  ~HasRefPrivateDtor() {}
+};
+
+static const int kParentValue = 1;
+static const int kChildValue = 2;
+
+class Parent {
+ public:
+  void AddRef(void) const {}
+  void Release(void) const {}
+  virtual void VirtualSet() { value = kParentValue; }
+  void NonVirtualSet() { value = kParentValue; }
+  int value;
+};
+
+class Child : public Parent {
+ public:
+  void VirtualSet() override { value = kChildValue; }
+  void NonVirtualSet() { value = kChildValue; }
+};
+
+class NoRefParent {
+ public:
+  virtual void VirtualSet() { value = kParentValue; }
+  void NonVirtualSet() { value = kParentValue; }
+  int value;
+};
+
+class NoRefChild : public NoRefParent {
+  void VirtualSet() override { value = kChildValue; }
+  void NonVirtualSet() { value = kChildValue; }
+};
+
+// Used for probing the number of copies that occur if a type must be coerced
+// during argument forwarding in the Run() methods.
+struct DerivedCopyCounter {
+  DerivedCopyCounter(int* copies, int* assigns)
+      : copies_(copies), assigns_(assigns) {
+  }
+  int* copies_;
+  int* assigns_;
+};
+
+// Used for probing the number of copies in an argument.
+class CopyCounter {
+ public:
+  CopyCounter(int* copies, int* assigns)
+      : copies_(copies), assigns_(assigns) {
+  }
+
+  CopyCounter(const CopyCounter& other)
+      : copies_(other.copies_),
+        assigns_(other.assigns_) {
+    (*copies_)++;
+  }
+
+  // Probing for copies from coercion.
+  explicit CopyCounter(const DerivedCopyCounter& other)
+      : copies_(other.copies_),
+        assigns_(other.assigns_) {
+    (*copies_)++;
+  }
+
+  const CopyCounter& operator=(const CopyCounter& rhs) {
+    copies_ = rhs.copies_;
+    assigns_ = rhs.assigns_;
+
+    if (assigns_) {
+      (*assigns_)++;
+    }
+
+    return *this;
+  }
+
+  int copies() const {
+    return *copies_;
+  }
+
+ private:
+  int* copies_;
+  int* assigns_;
+};
+
+class DeleteCounter {
+ public:
+  explicit DeleteCounter(int* deletes)
+      : deletes_(deletes) {
+  }
+
+  ~DeleteCounter() {
+    (*deletes_)++;
+  }
+
+  void VoidMethod0() {}
+
+ private:
+  int* deletes_;
+};
+
+template <typename T>
+T PassThru(T scoper) {
+  return scoper.Pass();
+}
+
+// Some test functions that we can Bind to.
+template <typename T>
+T PolymorphicIdentity(T t) {
+  return t;
+}
+
+template <typename T>
+void VoidPolymorphic1(T t) {
+}
+
+int Identity(int n) {
+  return n;
+}
+
+int ArrayGet(const int array[], int n) {
+  return array[n];
+}
+
+int Sum(int a, int b, int c, int d, int e, int f) {
+  return a + b + c + d + e + f;
+}
+
+const char* CStringIdentity(const char* s) {
+  return s;
+}
+
+int GetCopies(const CopyCounter& counter) {
+  return counter.copies();
+}
+
+int UnwrapNoRefParent(NoRefParent p) {
+  return p.value;
+}
+
+int UnwrapNoRefParentPtr(NoRefParent* p) {
+  return p->value;
+}
+
+int UnwrapNoRefParentConstRef(const NoRefParent& p) {
+  return p.value;
+}
+
+void RefArgSet(int &n) {
+  n = 2;
+}
+
+void PtrArgSet(int *n) {
+  *n = 2;
+}
+
+int FunctionWithWeakFirstParam(WeakPtr<NoRef> o, int n) {
+  return n;
+}
+
+int FunctionWithScopedRefptrFirstParam(const scoped_refptr<HasRef>& o, int n) {
+  return n;
+}
+
+void TakesACallback(const Closure& callback) {
+  callback.Run();
+}
+
+class BindTest : public ::testing::Test {
+ public:
+  BindTest() {
+    const_has_ref_ptr_ = &has_ref_;
+    const_no_ref_ptr_ = &no_ref_;
+    static_func_mock_ptr = &static_func_mock_;
+  }
+
+  virtual ~BindTest() {
+  }
+
+  static void VoidFunc0(void) {
+    static_func_mock_ptr->VoidMethod0();
+  }
+
+  static int IntFunc0(void) { return static_func_mock_ptr->IntMethod0(); }
+
+ protected:
+  StrictMock<NoRef> no_ref_;
+  StrictMock<HasRef> has_ref_;
+  const HasRef* const_has_ref_ptr_;
+  const NoRef* const_no_ref_ptr_;
+  StrictMock<NoRef> static_func_mock_;
+
+  // Used by the static functions to perform expectations.
+  static StrictMock<NoRef>* static_func_mock_ptr;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BindTest);
+};
+
+StrictMock<NoRef>* BindTest::static_func_mock_ptr;
+
+// Sanity check that we can instantiate a callback for each arity.
+TEST_F(BindTest, ArityTest) {
+  Callback<int(void)> c0 = Bind(&Sum, 32, 16, 8, 4, 2, 1);
+  EXPECT_EQ(63, c0.Run());
+
+  Callback<int(int)> c1 = Bind(&Sum, 32, 16, 8, 4, 2);
+  EXPECT_EQ(75, c1.Run(13));
+
+  Callback<int(int,int)> c2 = Bind(&Sum, 32, 16, 8, 4);
+  EXPECT_EQ(85, c2.Run(13, 12));
+
+  Callback<int(int,int,int)> c3 = Bind(&Sum, 32, 16, 8);
+  EXPECT_EQ(92, c3.Run(13, 12, 11));
+
+  Callback<int(int,int,int,int)> c4 = Bind(&Sum, 32, 16);
+  EXPECT_EQ(94, c4.Run(13, 12, 11, 10));
+
+  Callback<int(int,int,int,int,int)> c5 = Bind(&Sum, 32);
+  EXPECT_EQ(87, c5.Run(13, 12, 11, 10, 9));
+
+  Callback<int(int,int,int,int,int,int)> c6 = Bind(&Sum);
+  EXPECT_EQ(69, c6.Run(13, 12, 11, 10, 9, 14));
+}
+
+// Test the Currying ability of the Callback system.
+TEST_F(BindTest, CurryingTest) {
+  Callback<int(int,int,int,int,int,int)> c6 = Bind(&Sum);
+  EXPECT_EQ(69, c6.Run(13, 12, 11, 10, 9, 14));
+
+  Callback<int(int,int,int,int,int)> c5 = Bind(c6, 32);
+  EXPECT_EQ(87, c5.Run(13, 12, 11, 10, 9));
+
+  Callback<int(int,int,int,int)> c4 = Bind(c5, 16);
+  EXPECT_EQ(94, c4.Run(13, 12, 11, 10));
+
+  Callback<int(int,int,int)> c3 = Bind(c4, 8);
+  EXPECT_EQ(92, c3.Run(13, 12, 11));
+
+  Callback<int(int,int)> c2 = Bind(c3, 4);
+  EXPECT_EQ(85, c2.Run(13, 12));
+
+  Callback<int(int)> c1 = Bind(c2, 2);
+  EXPECT_EQ(75, c1.Run(13));
+
+  Callback<int(void)> c0 = Bind(c1, 1);
+  EXPECT_EQ(63, c0.Run());
+}
+
+// Test that currying the rvalue result of another Bind() works correctly.
+//   - rvalue should be usable as argument to Bind().
+//   - multiple runs of resulting Callback remain valid.
+TEST_F(BindTest, CurryingRvalueResultOfBind) {
+  int n = 0;
+  Closure cb = base::Bind(&TakesACallback, base::Bind(&PtrArgSet, &n));
+
+  // If we implement Bind() such that the return value has auto_ptr-like
+  // semantics, the second call here will fail because ownership of
+  // the internal BindState<> would have been transfered to a *temporary*
+  // constructon of a Callback object on the first call.
+  cb.Run();
+  EXPECT_EQ(2, n);
+
+  n = 0;
+  cb.Run();
+  EXPECT_EQ(2, n);
+}
+
+// Function type support.
+//   - Normal function.
+//   - Normal function bound with non-refcounted first argument.
+//   - Method bound to non-const object.
+//   - Method bound to scoped_refptr.
+//   - Const method bound to non-const object.
+//   - Const method bound to const object.
+//   - Derived classes can be used with pointers to non-virtual base functions.
+//   - Derived classes can be used with pointers to virtual base functions (and
+//     preserve virtual dispatch).
+TEST_F(BindTest, FunctionTypeSupport) {
+  EXPECT_CALL(static_func_mock_, VoidMethod0());
+  EXPECT_CALL(has_ref_, AddRef()).Times(5);
+  EXPECT_CALL(has_ref_, Release()).Times(5);
+  EXPECT_CALL(has_ref_, VoidMethod0()).Times(2);
+  EXPECT_CALL(has_ref_, VoidConstMethod0()).Times(2);
+
+  Closure normal_cb = Bind(&VoidFunc0);
+  Callback<NoRef*(void)> normal_non_refcounted_cb =
+      Bind(&PolymorphicIdentity<NoRef*>, &no_ref_);
+  normal_cb.Run();
+  EXPECT_EQ(&no_ref_, normal_non_refcounted_cb.Run());
+
+  Closure method_cb = Bind(&HasRef::VoidMethod0, &has_ref_);
+  Closure method_refptr_cb = Bind(&HasRef::VoidMethod0,
+                                  make_scoped_refptr(&has_ref_));
+  Closure const_method_nonconst_obj_cb = Bind(&HasRef::VoidConstMethod0,
+                                              &has_ref_);
+  Closure const_method_const_obj_cb = Bind(&HasRef::VoidConstMethod0,
+                                           const_has_ref_ptr_);
+  method_cb.Run();
+  method_refptr_cb.Run();
+  const_method_nonconst_obj_cb.Run();
+  const_method_const_obj_cb.Run();
+
+  Child child;
+  child.value = 0;
+  Closure virtual_set_cb = Bind(&Parent::VirtualSet, &child);
+  virtual_set_cb.Run();
+  EXPECT_EQ(kChildValue, child.value);
+
+  child.value = 0;
+  Closure non_virtual_set_cb = Bind(&Parent::NonVirtualSet, &child);
+  non_virtual_set_cb.Run();
+  EXPECT_EQ(kParentValue, child.value);
+}
+
+// Return value support.
+//   - Function with return value.
+//   - Method with return value.
+//   - Const method with return value.
+TEST_F(BindTest, ReturnValues) {
+  EXPECT_CALL(static_func_mock_, IntMethod0()).WillOnce(Return(1337));
+  EXPECT_CALL(has_ref_, AddRef()).Times(3);
+  EXPECT_CALL(has_ref_, Release()).Times(3);
+  EXPECT_CALL(has_ref_, IntMethod0()).WillOnce(Return(31337));
+  EXPECT_CALL(has_ref_, IntConstMethod0())
+      .WillOnce(Return(41337))
+      .WillOnce(Return(51337));
+
+  Callback<int(void)> normal_cb = Bind(&IntFunc0);
+  Callback<int(void)> method_cb = Bind(&HasRef::IntMethod0, &has_ref_);
+  Callback<int(void)> const_method_nonconst_obj_cb =
+      Bind(&HasRef::IntConstMethod0, &has_ref_);
+  Callback<int(void)> const_method_const_obj_cb =
+      Bind(&HasRef::IntConstMethod0, const_has_ref_ptr_);
+  EXPECT_EQ(1337, normal_cb.Run());
+  EXPECT_EQ(31337, method_cb.Run());
+  EXPECT_EQ(41337, const_method_nonconst_obj_cb.Run());
+  EXPECT_EQ(51337, const_method_const_obj_cb.Run());
+}
+
+// IgnoreResult adapter test.
+//   - Function with return value.
+//   - Method with return value.
+//   - Const Method with return.
+//   - Method with return value bound to WeakPtr<>.
+//   - Const Method with return bound to WeakPtr<>.
+TEST_F(BindTest, IgnoreResult) {
+  EXPECT_CALL(static_func_mock_, IntMethod0()).WillOnce(Return(1337));
+  EXPECT_CALL(has_ref_, AddRef()).Times(2);
+  EXPECT_CALL(has_ref_, Release()).Times(2);
+  EXPECT_CALL(has_ref_, IntMethod0()).WillOnce(Return(10));
+  EXPECT_CALL(has_ref_, IntConstMethod0()).WillOnce(Return(11));
+  EXPECT_CALL(no_ref_, IntMethod0()).WillOnce(Return(12));
+  EXPECT_CALL(no_ref_, IntConstMethod0()).WillOnce(Return(13));
+
+  Closure normal_func_cb = Bind(IgnoreResult(&IntFunc0));
+  normal_func_cb.Run();
+
+  Closure non_void_method_cb =
+      Bind(IgnoreResult(&HasRef::IntMethod0), &has_ref_);
+  non_void_method_cb.Run();
+
+  Closure non_void_const_method_cb =
+      Bind(IgnoreResult(&HasRef::IntConstMethod0), &has_ref_);
+  non_void_const_method_cb.Run();
+
+  WeakPtrFactory<NoRef> weak_factory(&no_ref_);
+  WeakPtrFactory<const NoRef> const_weak_factory(const_no_ref_ptr_);
+
+  Closure non_void_weak_method_cb  =
+      Bind(IgnoreResult(&NoRef::IntMethod0), weak_factory.GetWeakPtr());
+  non_void_weak_method_cb.Run();
+
+  Closure non_void_weak_const_method_cb =
+      Bind(IgnoreResult(&NoRef::IntConstMethod0), weak_factory.GetWeakPtr());
+  non_void_weak_const_method_cb.Run();
+
+  weak_factory.InvalidateWeakPtrs();
+  non_void_weak_const_method_cb.Run();
+  non_void_weak_method_cb.Run();
+}
+
+// Argument binding tests.
+//   - Argument binding to primitive.
+//   - Argument binding to primitive pointer.
+//   - Argument binding to a literal integer.
+//   - Argument binding to a literal string.
+//   - Argument binding with template function.
+//   - Argument binding to an object.
+//   - Argument binding to pointer to incomplete type.
+//   - Argument gets type converted.
+//   - Pointer argument gets converted.
+//   - Const Reference forces conversion.
+TEST_F(BindTest, ArgumentBinding) {
+  int n = 2;
+
+  Callback<int(void)> bind_primitive_cb = Bind(&Identity, n);
+  EXPECT_EQ(n, bind_primitive_cb.Run());
+
+  Callback<int*(void)> bind_primitive_pointer_cb =
+      Bind(&PolymorphicIdentity<int*>, &n);
+  EXPECT_EQ(&n, bind_primitive_pointer_cb.Run());
+
+  Callback<int(void)> bind_int_literal_cb = Bind(&Identity, 3);
+  EXPECT_EQ(3, bind_int_literal_cb.Run());
+
+  Callback<const char*(void)> bind_string_literal_cb =
+      Bind(&CStringIdentity, "hi");
+  EXPECT_STREQ("hi", bind_string_literal_cb.Run());
+
+  Callback<int(void)> bind_template_function_cb =
+      Bind(&PolymorphicIdentity<int>, 4);
+  EXPECT_EQ(4, bind_template_function_cb.Run());
+
+  NoRefParent p;
+  p.value = 5;
+  Callback<int(void)> bind_object_cb = Bind(&UnwrapNoRefParent, p);
+  EXPECT_EQ(5, bind_object_cb.Run());
+
+  IncompleteType* incomplete_ptr = reinterpret_cast<IncompleteType*>(123);
+  Callback<IncompleteType*(void)> bind_incomplete_ptr_cb =
+      Bind(&PolymorphicIdentity<IncompleteType*>, incomplete_ptr);
+  EXPECT_EQ(incomplete_ptr, bind_incomplete_ptr_cb.Run());
+
+  NoRefChild c;
+  c.value = 6;
+  Callback<int(void)> bind_promotes_cb = Bind(&UnwrapNoRefParent, c);
+  EXPECT_EQ(6, bind_promotes_cb.Run());
+
+  c.value = 7;
+  Callback<int(void)> bind_pointer_promotes_cb =
+      Bind(&UnwrapNoRefParentPtr, &c);
+  EXPECT_EQ(7, bind_pointer_promotes_cb.Run());
+
+  c.value = 8;
+  Callback<int(void)> bind_const_reference_promotes_cb =
+      Bind(&UnwrapNoRefParentConstRef, c);
+  EXPECT_EQ(8, bind_const_reference_promotes_cb.Run());
+}
+
+// Unbound argument type support tests.
+//   - Unbound value.
+//   - Unbound pointer.
+//   - Unbound reference.
+//   - Unbound const reference.
+//   - Unbound unsized array.
+//   - Unbound sized array.
+//   - Unbound array-of-arrays.
+TEST_F(BindTest, UnboundArgumentTypeSupport) {
+  Callback<void(int)> unbound_value_cb = Bind(&VoidPolymorphic1<int>);
+  Callback<void(int*)> unbound_pointer_cb = Bind(&VoidPolymorphic1<int*>);
+  Callback<void(int&)> unbound_ref_cb = Bind(&VoidPolymorphic1<int&>);
+  Callback<void(const int&)> unbound_const_ref_cb =
+      Bind(&VoidPolymorphic1<const int&>);
+  Callback<void(int[])> unbound_unsized_array_cb =
+      Bind(&VoidPolymorphic1<int[]>);
+  Callback<void(int[2])> unbound_sized_array_cb =
+      Bind(&VoidPolymorphic1<int[2]>);
+  Callback<void(int[][2])> unbound_array_of_arrays_cb =
+      Bind(&VoidPolymorphic1<int[][2]>);
+}
+
+// Function with unbound reference parameter.
+//   - Original parameter is modified by callback.
+TEST_F(BindTest, UnboundReferenceSupport) {
+  int n = 0;
+  Callback<void(int&)> unbound_ref_cb = Bind(&RefArgSet);
+  unbound_ref_cb.Run(n);
+  EXPECT_EQ(2, n);
+}
+
+// Functions that take reference parameters.
+//  - Forced reference parameter type still stores a copy.
+//  - Forced const reference parameter type still stores a copy.
+TEST_F(BindTest, ReferenceArgumentBinding) {
+  int n = 1;
+  int& ref_n = n;
+  const int& const_ref_n = n;
+
+  Callback<int(void)> ref_copies_cb = Bind(&Identity, ref_n);
+  EXPECT_EQ(n, ref_copies_cb.Run());
+  n++;
+  EXPECT_EQ(n - 1, ref_copies_cb.Run());
+
+  Callback<int(void)> const_ref_copies_cb = Bind(&Identity, const_ref_n);
+  EXPECT_EQ(n, const_ref_copies_cb.Run());
+  n++;
+  EXPECT_EQ(n - 1, const_ref_copies_cb.Run());
+}
+
+// Check that we can pass in arrays and have them be stored as a pointer.
+//  - Array of values stores a pointer.
+//  - Array of const values stores a pointer.
+TEST_F(BindTest, ArrayArgumentBinding) {
+  int array[4] = {1, 1, 1, 1};
+  const int (*const_array_ptr)[4] = &array;
+
+  Callback<int(void)> array_cb = Bind(&ArrayGet, array, 1);
+  EXPECT_EQ(1, array_cb.Run());
+
+  Callback<int(void)> const_array_cb = Bind(&ArrayGet, *const_array_ptr, 1);
+  EXPECT_EQ(1, const_array_cb.Run());
+
+  array[1] = 3;
+  EXPECT_EQ(3, array_cb.Run());
+  EXPECT_EQ(3, const_array_cb.Run());
+}
+
+// Verify SupportsAddRefAndRelease correctly introspects the class type for
+// AddRef() and Release().
+//  - Class with AddRef() and Release()
+//  - Class without AddRef() and Release()
+//  - Derived Class with AddRef() and Release()
+//  - Derived Class without AddRef() and Release()
+//  - Derived Class with AddRef() and Release() and a private destructor.
+TEST_F(BindTest, SupportsAddRefAndRelease) {
+  EXPECT_TRUE(internal::SupportsAddRefAndRelease<HasRef>::value);
+  EXPECT_FALSE(internal::SupportsAddRefAndRelease<NoRef>::value);
+
+  // StrictMock<T> is a derived class of T.  So, we use StrictMock<HasRef> and
+  // StrictMock<NoRef> to test that SupportsAddRefAndRelease works over
+  // inheritance.
+  EXPECT_TRUE(internal::SupportsAddRefAndRelease<StrictMock<HasRef> >::value);
+  EXPECT_FALSE(internal::SupportsAddRefAndRelease<StrictMock<NoRef> >::value);
+
+  // This matters because the implementation creates a dummy class that
+  // inherits from the template type.
+  EXPECT_TRUE(internal::SupportsAddRefAndRelease<HasRefPrivateDtor>::value);
+}
+
+// Unretained() wrapper support.
+//   - Method bound to Unretained() non-const object.
+//   - Const method bound to Unretained() non-const object.
+//   - Const method bound to Unretained() const object.
+TEST_F(BindTest, Unretained) {
+  EXPECT_CALL(no_ref_, VoidMethod0());
+  EXPECT_CALL(no_ref_, VoidConstMethod0()).Times(2);
+
+  Callback<void(void)> method_cb =
+      Bind(&NoRef::VoidMethod0, Unretained(&no_ref_));
+  method_cb.Run();
+
+  Callback<void(void)> const_method_cb =
+      Bind(&NoRef::VoidConstMethod0, Unretained(&no_ref_));
+  const_method_cb.Run();
+
+  Callback<void(void)> const_method_const_ptr_cb =
+      Bind(&NoRef::VoidConstMethod0, Unretained(const_no_ref_ptr_));
+  const_method_const_ptr_cb.Run();
+}
+
+// WeakPtr() support.
+//   - Method bound to WeakPtr<> to non-const object.
+//   - Const method bound to WeakPtr<> to non-const object.
+//   - Const method bound to WeakPtr<> to const object.
+//   - Normal Function with WeakPtr<> as P1 can have return type and is
+//     not canceled.
+TEST_F(BindTest, WeakPtr) {
+  EXPECT_CALL(no_ref_, VoidMethod0());
+  EXPECT_CALL(no_ref_, VoidConstMethod0()).Times(2);
+
+  WeakPtrFactory<NoRef> weak_factory(&no_ref_);
+  WeakPtrFactory<const NoRef> const_weak_factory(const_no_ref_ptr_);
+
+  Closure method_cb =
+      Bind(&NoRef::VoidMethod0, weak_factory.GetWeakPtr());
+  method_cb.Run();
+
+  Closure const_method_cb =
+      Bind(&NoRef::VoidConstMethod0, const_weak_factory.GetWeakPtr());
+  const_method_cb.Run();
+
+  Closure const_method_const_ptr_cb =
+      Bind(&NoRef::VoidConstMethod0, const_weak_factory.GetWeakPtr());
+  const_method_const_ptr_cb.Run();
+
+  Callback<int(int)> normal_func_cb =
+      Bind(&FunctionWithWeakFirstParam, weak_factory.GetWeakPtr());
+  EXPECT_EQ(1, normal_func_cb.Run(1));
+
+  weak_factory.InvalidateWeakPtrs();
+  const_weak_factory.InvalidateWeakPtrs();
+
+  method_cb.Run();
+  const_method_cb.Run();
+  const_method_const_ptr_cb.Run();
+
+  // Still runs even after the pointers are invalidated.
+  EXPECT_EQ(2, normal_func_cb.Run(2));
+}
+
+// ConstRef() wrapper support.
+//   - Binding w/o ConstRef takes a copy.
+//   - Binding a ConstRef takes a reference.
+//   - Binding ConstRef to a function ConstRef does not copy on invoke.
+TEST_F(BindTest, ConstRef) {
+  int n = 1;
+
+  Callback<int(void)> copy_cb = Bind(&Identity, n);
+  Callback<int(void)> const_ref_cb = Bind(&Identity, ConstRef(n));
+  EXPECT_EQ(n, copy_cb.Run());
+  EXPECT_EQ(n, const_ref_cb.Run());
+  n++;
+  EXPECT_EQ(n - 1, copy_cb.Run());
+  EXPECT_EQ(n, const_ref_cb.Run());
+
+  int copies = 0;
+  int assigns = 0;
+  CopyCounter counter(&copies, &assigns);
+  Callback<int(void)> all_const_ref_cb =
+      Bind(&GetCopies, ConstRef(counter));
+  EXPECT_EQ(0, all_const_ref_cb.Run());
+  EXPECT_EQ(0, copies);
+  EXPECT_EQ(0, assigns);
+}
+
+TEST_F(BindTest, ScopedRefptr) {
+  // BUG: The scoped_refptr should cause the only AddRef()/Release() pair. But
+  // due to a bug in base::Bind(), there's an extra call when invoking the
+  // callback.
+  // https://code.google.com/p/chromium/issues/detail?id=251937
+  EXPECT_CALL(has_ref_, AddRef()).Times(2);
+  EXPECT_CALL(has_ref_, Release()).Times(2);
+
+  const scoped_refptr<StrictMock<HasRef> > refptr(&has_ref_);
+
+  Callback<int(void)> scoped_refptr_const_ref_cb =
+      Bind(&FunctionWithScopedRefptrFirstParam, base::ConstRef(refptr), 1);
+  EXPECT_EQ(1, scoped_refptr_const_ref_cb.Run());
+}
+
+// Test Owned() support.
+TEST_F(BindTest, Owned) {
+  int deletes = 0;
+  DeleteCounter* counter = new DeleteCounter(&deletes);
+
+  // If we don't capture, delete happens on Callback destruction/reset.
+  // return the same value.
+  Callback<DeleteCounter*(void)> no_capture_cb =
+      Bind(&PolymorphicIdentity<DeleteCounter*>, Owned(counter));
+  ASSERT_EQ(counter, no_capture_cb.Run());
+  ASSERT_EQ(counter, no_capture_cb.Run());
+  EXPECT_EQ(0, deletes);
+  no_capture_cb.Reset();  // This should trigger a delete.
+  EXPECT_EQ(1, deletes);
+
+  deletes = 0;
+  counter = new DeleteCounter(&deletes);
+  base::Closure own_object_cb =
+      Bind(&DeleteCounter::VoidMethod0, Owned(counter));
+  own_object_cb.Run();
+  EXPECT_EQ(0, deletes);
+  own_object_cb.Reset();
+  EXPECT_EQ(1, deletes);
+}
+
+// Passed() wrapper support.
+//   - Passed() can be constructed from a pointer to scoper.
+//   - Passed() can be constructed from a scoper rvalue.
+//   - Using Passed() gives Callback Ownership.
+//   - Ownership is transferred from Callback to callee on the first Run().
+//   - Callback supports unbound arguments.
+TEST_F(BindTest, ScopedPtr) {
+  int deletes = 0;
+
+  // Tests the Passed() function's support for pointers.
+  scoped_ptr<DeleteCounter> ptr(new DeleteCounter(&deletes));
+  Callback<scoped_ptr<DeleteCounter>(void)> unused_callback =
+      Bind(&PassThru<scoped_ptr<DeleteCounter> >, Passed(&ptr));
+  EXPECT_FALSE(ptr.get());
+  EXPECT_EQ(0, deletes);
+
+  // If we never invoke the Callback, it retains ownership and deletes.
+  unused_callback.Reset();
+  EXPECT_EQ(1, deletes);
+
+  // Tests the Passed() function's support for rvalues.
+  deletes = 0;
+  DeleteCounter* counter = new DeleteCounter(&deletes);
+  Callback<scoped_ptr<DeleteCounter>(void)> callback =
+      Bind(&PassThru<scoped_ptr<DeleteCounter> >,
+           Passed(scoped_ptr<DeleteCounter>(counter)));
+  EXPECT_FALSE(ptr.get());
+  EXPECT_EQ(0, deletes);
+
+  // Check that ownership can be transferred back out.
+  scoped_ptr<DeleteCounter> result = callback.Run();
+  ASSERT_EQ(counter, result.get());
+  EXPECT_EQ(0, deletes);
+
+  // Resetting does not delete since ownership was transferred.
+  callback.Reset();
+  EXPECT_EQ(0, deletes);
+
+  // Ensure that we actually did get ownership.
+  result.reset();
+  EXPECT_EQ(1, deletes);
+
+  // Test unbound argument forwarding.
+  Callback<scoped_ptr<DeleteCounter>(scoped_ptr<DeleteCounter>)> cb_unbound =
+      Bind(&PassThru<scoped_ptr<DeleteCounter> >);
+  ptr.reset(new DeleteCounter(&deletes));
+  cb_unbound.Run(ptr.Pass());
+}
+
+// Argument Copy-constructor usage for non-reference parameters.
+//   - Bound arguments are only copied once.
+//   - Forwarded arguments are only copied once.
+//   - Forwarded arguments with coercions are only copied twice (once for the
+//     coercion, and one for the final dispatch).
+TEST_F(BindTest, ArgumentCopies) {
+  int copies = 0;
+  int assigns = 0;
+
+  CopyCounter counter(&copies, &assigns);
+
+  Callback<void(void)> copy_cb =
+      Bind(&VoidPolymorphic1<CopyCounter>, counter);
+  EXPECT_GE(1, copies);
+  EXPECT_EQ(0, assigns);
+
+  copies = 0;
+  assigns = 0;
+  Callback<void(CopyCounter)> forward_cb =
+      Bind(&VoidPolymorphic1<CopyCounter>);
+  forward_cb.Run(counter);
+  EXPECT_GE(1, copies);
+  EXPECT_EQ(0, assigns);
+
+  copies = 0;
+  assigns = 0;
+  DerivedCopyCounter derived(&copies, &assigns);
+  Callback<void(CopyCounter)> coerce_cb =
+      Bind(&VoidPolymorphic1<CopyCounter>);
+  coerce_cb.Run(CopyCounter(derived));
+  EXPECT_GE(2, copies);
+  EXPECT_EQ(0, assigns);
+}
+
+// Callback construction and assignment tests.
+//   - Construction from an InvokerStorageHolder should not cause ref/deref.
+//   - Assignment from other callback should only cause one ref
+//
+// TODO(ajwong): Is there actually a way to test this?
+
+#if defined(OS_WIN)
+int __fastcall FastCallFunc(int n) {
+  return n;
+}
+
+int __stdcall StdCallFunc(int n) {
+  return n;
+}
+
+// Windows specific calling convention support.
+//   - Can bind a __fastcall function.
+//   - Can bind a __stdcall function.
+TEST_F(BindTest, WindowsCallingConventions) {
+  Callback<int(void)> fastcall_cb = Bind(&FastCallFunc, 1);
+  EXPECT_EQ(1, fastcall_cb.Run());
+
+  Callback<int(void)> stdcall_cb = Bind(&StdCallFunc, 2);
+  EXPECT_EQ(2, stdcall_cb.Run());
+}
+#endif
+
+#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && GTEST_HAS_DEATH_TEST
+
+// Test null callbacks cause a DCHECK.
+TEST(BindDeathTest, NullCallback) {
+  base::Callback<void(int)> null_cb;
+  ASSERT_TRUE(null_cb.is_null());
+  EXPECT_DEATH(base::Bind(null_cb, 42), "");
+}
+
+#endif  // (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) &&
+        //     GTEST_HAS_DEATH_TEST
+
+}  // namespace
+}  // namespace base
diff --git a/base/bind_unittest.nc b/base/bind_unittest.nc
new file mode 100644
index 0000000..2596386
--- /dev/null
+++ b/base/bind_unittest.nc
@@ -0,0 +1,202 @@
+// Copyright (c) 2011 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/callback.h"
+#include "base/bind.h"
+#include "base/memory/ref_counted.h"
+
+namespace base {
+
+// Do not put everything inside an anonymous namespace.  If you do, many of the
+// helper function declarations will generate unused definition warnings.
+
+static const int kParentValue = 1;
+static const int kChildValue = 2;
+
+class NoRef {
+ public:
+  void VoidMethod0() {}
+  void VoidConstMethod0() const {}
+  int IntMethod0() { return 1; }
+};
+
+class HasRef : public NoRef, public base::RefCounted<HasRef> {
+};
+
+class Parent {
+ public:
+  void AddRef(void) const {}
+  void Release(void) const {}
+  virtual void VirtualSet() { value = kParentValue; }
+  void NonVirtualSet() { value = kParentValue; }
+  int value;
+};
+
+class Child : public Parent {
+ public:
+  virtual void VirtualSet() { value = kChildValue; }
+  void NonVirtualSet() { value = kChildValue; }
+};
+
+class NoRefParent {
+ public:
+  virtual void VirtualSet() { value = kParentValue; }
+  void NonVirtualSet() { value = kParentValue; }
+  int value;
+};
+
+class NoRefChild : public NoRefParent {
+  virtual void VirtualSet() { value = kChildValue; }
+  void NonVirtualSet() { value = kChildValue; }
+};
+
+template <typename T>
+T PolymorphicIdentity(T t) {
+  return t;
+}
+
+int UnwrapParentRef(Parent& p) {
+  return p.value;
+}
+
+template <typename T>
+void VoidPolymorphic1(T t) {
+}
+
+#if defined(NCTEST_METHOD_ON_CONST_OBJECT)  // [r"fatal error: cannot initialize a parameter of type 'base::NoRef \*' with an lvalue of type 'typename enable_if<!IsMoveOnlyType<const HasRef \*const>::value, const HasRef \*const>::type' \(aka 'const base::HasRef \*const'\)"]
+
+// Method bound to const-object.
+//
+// Only const methods should be allowed to work with const objects.
+void WontCompile() {
+  HasRef has_ref;
+  const HasRef* const_has_ref_ptr_ = &has_ref;
+  Callback<void(void)> method_to_const_cb =
+      Bind(&HasRef::VoidMethod0, const_has_ref_ptr_);
+  method_to_const_cb.Run();
+}
+
+#elif defined(NCTEST_METHOD_BIND_NEEDS_REFCOUNTED_OBJECT)  // [r"fatal error: no member named 'AddRef' in 'base::NoRef'"]
+
+// Method bound to non-refcounted object.
+//
+// We require refcounts unless you have Unretained().
+void WontCompile() {
+  NoRef no_ref;
+  Callback<void(void)> no_ref_cb =
+      Bind(&NoRef::VoidMethod0, &no_ref);
+  no_ref_cb.Run();
+}
+
+#elif defined(NCTEST_CONST_METHOD_NEEDS_REFCOUNTED_OBJECT)  // [r"fatal error: no member named 'AddRef' in 'base::NoRef'"]
+
+// Const Method bound to non-refcounted object.
+//
+// We require refcounts unless you have Unretained().
+void WontCompile() {
+  NoRef no_ref;
+  Callback<void(void)> no_ref_const_cb =
+      Bind(&NoRef::VoidConstMethod0, &no_ref);
+  no_ref_const_cb.Run();
+}
+
+#elif defined(NCTEST_CONST_POINTER)  // [r"fatal error: reference to type 'base::NoRef \*const' could not bind to an lvalue of type 'typename enable_if<!IsMoveOnlyType<const NoRef \*const>::value, const NoRef \*const>::type' \(aka 'const base::NoRef \*const'\)"]
+
+// Const argument used with non-const pointer parameter of same type.
+//
+// This is just a const-correctness check.
+void WontCompile() {
+  const NoRef* const_no_ref_ptr;
+  Callback<NoRef*(void)> pointer_same_cb =
+      Bind(&PolymorphicIdentity<NoRef*>, const_no_ref_ptr);
+  pointer_same_cb.Run();
+}
+
+#elif defined(NCTEST_CONST_POINTER_SUBTYPE)  // [r"fatal error: reference to type 'base::NoRefParent \*const' could not bind to an lvalue of type 'typename enable_if<!IsMoveOnlyType<const NoRefChild \*const>::value, const NoRefChild \*const>::type' \(aka 'const base::NoRefChild \*const'\)"]
+
+// Const argument used with non-const pointer parameter of super type.
+//
+// This is just a const-correctness check.
+void WontCompile() {
+  const NoRefChild* const_child_ptr;
+  Callback<NoRefParent*(void)> pointer_super_cb =
+    Bind(&PolymorphicIdentity<NoRefParent*>, const_child_ptr);
+  pointer_super_cb.Run();
+}
+
+#elif defined(DISABLED_NCTEST_DISALLOW_NON_CONST_REF_PARAM)  // [r"fatal error: no member named 'AddRef' in 'base::NoRef'"]
+// TODO(dcheng): I think there's a type safety promotion issue here where we can
+// pass a const ref to a non const-ref function, or vice versa accidentally. Or
+// we make a copy accidentally. Check.
+
+// Functions with reference parameters, unsupported.
+//
+// First, non-const reference parameters are disallowed by the Google
+// style guide. Second, since we are doing argument forwarding it becomes
+// very tricky to avoid copies, maintain const correctness, and not
+// accidentally have the function be modifying a temporary, or a copy.
+void WontCompile() {
+  Parent p;
+  Callback<int(Parent&)> ref_arg_cb = Bind(&UnwrapParentRef);
+  ref_arg_cb.Run(p);
+}
+
+#elif defined(NCTEST_DISALLOW_BIND_TO_NON_CONST_REF_PARAM)  // [r"fatal error: static_assert failed \"do_not_bind_functions_with_nonconst_ref\""]
+
+// Binding functions with reference parameters, unsupported.
+//
+// See comment in NCTEST_DISALLOW_NON_CONST_REF_PARAM
+void WontCompile() {
+  Parent p;
+  Callback<int(void)> ref_cb = Bind(&UnwrapParentRef, p);
+  ref_cb.Run();
+}
+
+#elif defined(NCTEST_NO_IMPLICIT_ARRAY_PTR_CONVERSION)  // [r"fatal error: static_assert failed \"first_bound_argument_to_method_cannot_be_array\""]
+
+// A method should not be bindable with an array of objects.
+//
+// This is likely not wanted behavior. We specifically check for it though
+// because it is possible, depending on how you implement prebinding, to
+// implicitly convert an array type to a pointer type.
+void WontCompile() {
+  HasRef p[10];
+  Callback<void(void)> method_bound_to_array_cb =
+      Bind(&HasRef::VoidMethod0, p);
+  method_bound_to_array_cb.Run();
+}
+
+#elif defined(NCTEST_NO_RAW_PTR_FOR_REFCOUNTED_TYPES)  // [r"fatal error: static_assert failed \"a_parameter_is_refcounted_type_and_needs_scoped_refptr\""]
+
+// Refcounted types should not be bound as a raw pointer.
+void WontCompile() {
+  HasRef for_raw_ptr;
+  int a;
+  Callback<void(void)> ref_count_as_raw_ptr_a =
+      Bind(&VoidPolymorphic1<int*>, &a);
+  Callback<void(void)> ref_count_as_raw_ptr =
+      Bind(&VoidPolymorphic1<HasRef*>, &for_raw_ptr);
+}
+
+#elif defined(NCTEST_WEAKPTR_BIND_MUST_RETURN_VOID)  // [r"fatal error: static_assert failed \"weak_ptrs_can_only_bind_to_methods_without_return_values\""]
+
+// WeakPtrs cannot be bound to methods with return types.
+void WontCompile() {
+  NoRef no_ref;
+  WeakPtrFactory<NoRef> weak_factory(&no_ref);
+  Callback<int(void)> weak_ptr_with_non_void_return_type =
+      Bind(&NoRef::IntMethod0, weak_factory.GetWeakPtr());
+  weak_ptr_with_non_void_return_type.Run();
+}
+
+#elif defined(NCTEST_DISALLOW_ASSIGN_DIFFERENT_TYPES)  // [r"fatal error: no viable conversion from 'Callback<typename internal::BindState<typename internal::FunctorTraits<void \(\*\)\(int\)>::RunnableType, typename internal::FunctorTraits<void \(\*\)\(int\)>::RunType, internal::TypeList<> >::UnboundRunType>' to 'Callback<void \(\)>'"]
+
+// Bind result cannot be assigned to Callbacks with a mismatching type.
+void WontCompile() {
+  Closure callback_mismatches_bind_type = Bind(&VoidPolymorphic1<int>);
+}
+
+#endif
+
+}  // namespace base
diff --git a/base/bits.h b/base/bits.h
new file mode 100644
index 0000000..b2209e8
--- /dev/null
+++ b/base/bits.h
@@ -0,0 +1,47 @@
+// Copyright (c) 2009 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 defines some bit utilities.
+
+#ifndef BASE_BITS_H_
+#define BASE_BITS_H_
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+namespace base {
+namespace bits {
+
+// Returns the integer i such as 2^i <= n < 2^(i+1)
+inline int Log2Floor(uint32 n) {
+  if (n == 0)
+    return -1;
+  int log = 0;
+  uint32 value = n;
+  for (int i = 4; i >= 0; --i) {
+    int shift = (1 << i);
+    uint32 x = value >> shift;
+    if (x != 0) {
+      value = x;
+      log += shift;
+    }
+  }
+  DCHECK_EQ(value, 1u);
+  return log;
+}
+
+// Returns the integer i such as 2^(i-1) < n <= 2^i
+inline int Log2Ceiling(uint32 n) {
+  if (n == 0) {
+    return -1;
+  } else {
+    // Log2Floor returns -1 for 0, so the following works correctly for n=1.
+    return 1 + Log2Floor(n - 1);
+  }
+}
+
+}  // namespace bits
+}  // namespace base
+
+#endif  // BASE_BITS_H_
diff --git a/base/bits_unittest.cc b/base/bits_unittest.cc
new file mode 100644
index 0000000..e913d6a
--- /dev/null
+++ b/base/bits_unittest.cc
@@ -0,0 +1,48 @@
+// Copyright (c) 2009 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 contains the unit tests for the bit utilities.
+
+#include "base/bits.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace bits {
+
+TEST(BitsTest, Log2Floor) {
+  EXPECT_EQ(-1, Log2Floor(0));
+  EXPECT_EQ(0, Log2Floor(1));
+  EXPECT_EQ(1, Log2Floor(2));
+  EXPECT_EQ(1, Log2Floor(3));
+  EXPECT_EQ(2, Log2Floor(4));
+  for (int i = 3; i < 31; ++i) {
+    unsigned int value = 1U << i;
+    EXPECT_EQ(i, Log2Floor(value));
+    EXPECT_EQ(i, Log2Floor(value + 1));
+    EXPECT_EQ(i, Log2Floor(value + 2));
+    EXPECT_EQ(i - 1, Log2Floor(value - 1));
+    EXPECT_EQ(i - 1, Log2Floor(value - 2));
+  }
+  EXPECT_EQ(31, Log2Floor(0xffffffffU));
+}
+
+TEST(BitsTest, Log2Ceiling) {
+  EXPECT_EQ(-1, Log2Ceiling(0));
+  EXPECT_EQ(0, Log2Ceiling(1));
+  EXPECT_EQ(1, Log2Ceiling(2));
+  EXPECT_EQ(2, Log2Ceiling(3));
+  EXPECT_EQ(2, Log2Ceiling(4));
+  for (int i = 3; i < 31; ++i) {
+    unsigned int value = 1U << i;
+    EXPECT_EQ(i, Log2Ceiling(value));
+    EXPECT_EQ(i + 1, Log2Ceiling(value + 1));
+    EXPECT_EQ(i + 1, Log2Ceiling(value + 2));
+    EXPECT_EQ(i, Log2Ceiling(value - 1));
+    EXPECT_EQ(i, Log2Ceiling(value - 2));
+  }
+  EXPECT_EQ(32, Log2Ceiling(0xffffffffU));
+}
+
+}  // namespace bits
+}  // namespace base
diff --git a/base/build_time.cc b/base/build_time.cc
new file mode 100644
index 0000000..b8b4296
--- /dev/null
+++ b/base/build_time.cc
@@ -0,0 +1,29 @@
+// Copyright (c) 2011 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/build_time.h"
+
+#include "base/logging.h"
+#include "base/time/time.h"
+
+namespace base {
+
+Time GetBuildTime() {
+  Time integral_build_time;
+  // The format of __DATE__ and __TIME__ is specified by the ANSI C Standard,
+  // section 6.8.8.
+  //
+  // __DATE__ is exactly "Mmm DD YYYY".
+  // __TIME__ is exactly "hh:mm:ss".
+#if defined(DONT_EMBED_BUILD_METADATA) && !defined(OFFICIAL_BUILD)
+  const char kDateTime[] = "Sep 02 2008 08:00:00 PST";
+#else
+  const char kDateTime[] = __DATE__ " " __TIME__ " PST";
+#endif
+  bool result = Time::FromString(kDateTime, &integral_build_time);
+  DCHECK(result);
+  return integral_build_time;
+}
+
+}  // namespace base
diff --git a/base/build_time.h b/base/build_time.h
new file mode 100644
index 0000000..4f0abc3
--- /dev/null
+++ b/base/build_time.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2011 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_BUILD_TIME_H_
+#define BASE_BUILD_TIME_H_
+
+#include "base/base_export.h"
+#include "base/time/time.h"
+
+namespace base {
+
+// GetBuildTime returns the time at which the current binary was built.
+//
+// This uses the __DATE__ and __TIME__ macros, which don't trigger a rebuild
+// when they change. However, official builds will always be rebuilt from
+// scratch.
+//
+// Also, since __TIME__ doesn't include a timezone, this value should only be
+// considered accurate to a day.
+//
+// NOTE: This function is disabled except for the official builds, by default
+// the date returned is "Sep 02 2008 08:00:00 PST".
+Time BASE_EXPORT GetBuildTime();
+
+}  // namespace base
+
+#endif  // BASE_BUILD_TIME_H_
diff --git a/base/build_time_unittest.cc b/base/build_time_unittest.cc
new file mode 100644
index 0000000..aac64a7
--- /dev/null
+++ b/base/build_time_unittest.cc
@@ -0,0 +1,38 @@
+// Copyright (c) 2011 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/build_time.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(BuildTime, DateLooksValid) {
+#if !defined(DONT_EMBED_BUILD_METADATA)
+  char build_date[] = __DATE__;
+#else
+  char build_date[] = "Sep 02 2008";
+#endif
+
+  EXPECT_EQ(11u, strlen(build_date));
+  EXPECT_EQ(' ', build_date[3]);
+  EXPECT_EQ(' ', build_date[6]);
+}
+
+TEST(BuildTime, TimeLooksValid) {
+#if defined(DONT_EMBED_BUILD_METADATA)
+  char build_time[] = "08:00:00";
+#else
+  char build_time[] = __TIME__;
+#endif
+
+  EXPECT_EQ(8u, strlen(build_time));
+  EXPECT_EQ(':', build_time[2]);
+  EXPECT_EQ(':', build_time[5]);
+}
+
+TEST(BuildTime, DoesntCrash) {
+  // Since __DATE__ isn't updated unless one does a clobber build, we can't
+  // really test the value returned by it, except to check that it doesn't
+  // crash.
+  base::GetBuildTime();
+}
diff --git a/base/callback.h b/base/callback.h
new file mode 100644
index 0000000..00669dd
--- /dev/null
+++ b/base/callback.h
@@ -0,0 +1,411 @@
+// Copyright (c) 2012 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_CALLBACK_H_
+#define BASE_CALLBACK_H_
+
+#include "base/callback_forward.h"
+#include "base/callback_internal.h"
+#include "base/template_util.h"
+
+// NOTE: Header files that do not require the full definition of Callback or
+// Closure should #include "base/callback_forward.h" instead of this file.
+
+// -----------------------------------------------------------------------------
+// Introduction
+// -----------------------------------------------------------------------------
+//
+// The templated Callback class is a generalized function object. Together
+// with the Bind() function in bind.h, they provide a type-safe method for
+// performing partial application of functions.
+//
+// Partial application (or "currying") is the process of binding a subset of
+// a function's arguments to produce another function that takes fewer
+// arguments. This can be used to pass around a unit of delayed execution,
+// much like lexical closures are used in other languages. For example, it
+// is used in Chromium code to schedule tasks on different MessageLoops.
+//
+// A callback with no unbound input parameters (base::Callback<void(void)>)
+// is called a base::Closure. Note that this is NOT the same as what other
+// languages refer to as a closure -- it does not retain a reference to its
+// enclosing environment.
+//
+// MEMORY MANAGEMENT AND PASSING
+//
+// The Callback objects themselves should be passed by const-reference, and
+// stored by copy. They internally store their state via a refcounted class
+// and thus do not need to be deleted.
+//
+// The reason to pass via a const-reference is to avoid unnecessary
+// AddRef/Release pairs to the internal state.
+//
+//
+// -----------------------------------------------------------------------------
+// Quick reference for basic stuff
+// -----------------------------------------------------------------------------
+//
+// BINDING A BARE FUNCTION
+//
+//   int Return5() { return 5; }
+//   base::Callback<int(void)> func_cb = base::Bind(&Return5);
+//   LOG(INFO) << func_cb.Run();  // Prints 5.
+//
+// BINDING A CLASS METHOD
+//
+//   The first argument to bind is the member function to call, the second is
+//   the object on which to call it.
+//
+//   class Ref : public base::RefCountedThreadSafe<Ref> {
+//    public:
+//     int Foo() { return 3; }
+//     void PrintBye() { LOG(INFO) << "bye."; }
+//   };
+//   scoped_refptr<Ref> ref = new Ref();
+//   base::Callback<void(void)> ref_cb = base::Bind(&Ref::Foo, ref);
+//   LOG(INFO) << ref_cb.Run();  // Prints out 3.
+//
+//   By default the object must support RefCounted or you will get a compiler
+//   error. If you're passing between threads, be sure it's
+//   RefCountedThreadSafe! See "Advanced binding of member functions" below if
+//   you don't want to use reference counting.
+//
+// RUNNING A CALLBACK
+//
+//   Callbacks can be run with their "Run" method, which has the same
+//   signature as the template argument to the callback.
+//
+//   void DoSomething(const base::Callback<void(int, std::string)>& callback) {
+//     callback.Run(5, "hello");
+//   }
+//
+//   Callbacks can be run more than once (they don't get deleted or marked when
+//   run). However, this precludes using base::Passed (see below).
+//
+//   void DoSomething(const base::Callback<double(double)>& callback) {
+//     double myresult = callback.Run(3.14159);
+//     myresult += callback.Run(2.71828);
+//   }
+//
+// PASSING UNBOUND INPUT PARAMETERS
+//
+//   Unbound parameters are specified at the time a callback is Run(). They are
+//   specified in the Callback template type:
+//
+//   void MyFunc(int i, const std::string& str) {}
+//   base::Callback<void(int, const std::string&)> cb = base::Bind(&MyFunc);
+//   cb.Run(23, "hello, world");
+//
+// PASSING BOUND INPUT PARAMETERS
+//
+//   Bound parameters are specified when you create thee callback as arguments
+//   to Bind(). They will be passed to the function and the Run()ner of the
+//   callback doesn't see those values or even know that the function it's
+//   calling.
+//
+//   void MyFunc(int i, const std::string& str) {}
+//   base::Callback<void(void)> cb = base::Bind(&MyFunc, 23, "hello world");
+//   cb.Run();
+//
+//   A callback with no unbound input parameters (base::Callback<void(void)>)
+//   is called a base::Closure. So we could have also written:
+//
+//   base::Closure cb = base::Bind(&MyFunc, 23, "hello world");
+//
+//   When calling member functions, bound parameters just go after the object
+//   pointer.
+//
+//   base::Closure cb = base::Bind(&MyClass::MyFunc, this, 23, "hello world");
+//
+// PARTIAL BINDING OF PARAMETERS
+//
+//   You can specify some parameters when you create the callback, and specify
+//   the rest when you execute the callback.
+//
+//   void MyFunc(int i, const std::string& str) {}
+//   base::Callback<void(const std::string&)> cb = base::Bind(&MyFunc, 23);
+//   cb.Run("hello world");
+//
+//   When calling a function bound parameters are first, followed by unbound
+//   parameters.
+//
+//
+// -----------------------------------------------------------------------------
+// Quick reference for advanced binding
+// -----------------------------------------------------------------------------
+//
+// BINDING A CLASS METHOD WITH WEAK POINTERS
+//
+//   base::Bind(&MyClass::Foo, GetWeakPtr());
+//
+//   The callback will not be run if the object has already been destroyed.
+//   DANGER: weak pointers are not threadsafe, so don't use this
+//   when passing between threads!
+//
+// BINDING A CLASS METHOD WITH MANUAL LIFETIME MANAGEMENT
+//
+//   base::Bind(&MyClass::Foo, base::Unretained(this));
+//
+//   This disables all lifetime management on the object. You're responsible
+//   for making sure the object is alive at the time of the call. You break it,
+//   you own it!
+//
+// BINDING A CLASS METHOD AND HAVING THE CALLBACK OWN THE CLASS
+//
+//   MyClass* myclass = new MyClass;
+//   base::Bind(&MyClass::Foo, base::Owned(myclass));
+//
+//   The object will be deleted when the callback is destroyed, even if it's
+//   not run (like if you post a task during shutdown). Potentially useful for
+//   "fire and forget" cases.
+//
+// IGNORING RETURN VALUES
+//
+//   Sometimes you want to call a function that returns a value in a callback
+//   that doesn't expect a return value.
+//
+//   int DoSomething(int arg) { cout << arg << endl; }
+//   base::Callback<void<int>) cb =
+//       base::Bind(base::IgnoreResult(&DoSomething));
+//
+//
+// -----------------------------------------------------------------------------
+// Quick reference for binding parameters to Bind()
+// -----------------------------------------------------------------------------
+//
+// Bound parameters are specified as arguments to Bind() and are passed to the
+// function. A callback with no parameters or no unbound parameters is called a
+// Closure (base::Callback<void(void)> and base::Closure are the same thing).
+//
+// PASSING PARAMETERS OWNED BY THE CALLBACK
+//
+//   void Foo(int* arg) { cout << *arg << endl; }
+//   int* pn = new int(1);
+//   base::Closure foo_callback = base::Bind(&foo, base::Owned(pn));
+//
+//   The parameter will be deleted when the callback is destroyed, even if it's
+//   not run (like if you post a task during shutdown).
+//
+// PASSING PARAMETERS AS A scoped_ptr
+//
+//   void TakesOwnership(scoped_ptr<Foo> arg) {}
+//   scoped_ptr<Foo> f(new Foo);
+//   // f becomes null during the following call.
+//   base::Closure cb = base::Bind(&TakesOwnership, base::Passed(&f));
+//
+//   Ownership of the parameter will be with the callback until the it is run,
+//   when ownership is passed to the callback function. This means the callback
+//   can only be run once. If the callback is never run, it will delete the
+//   object when it's destroyed.
+//
+// PASSING PARAMETERS AS A scoped_refptr
+//
+//   void TakesOneRef(scoped_refptr<Foo> arg) {}
+//   scoped_refptr<Foo> f(new Foo)
+//   base::Closure cb = base::Bind(&TakesOneRef, f);
+//
+//   This should "just work." The closure will take a reference as long as it
+//   is alive, and another reference will be taken for the called function.
+//
+// PASSING PARAMETERS BY REFERENCE
+//
+//   Const references are *copied* unless ConstRef is used. Example:
+//
+//   void foo(const int& arg) { printf("%d %p\n", arg, &arg); }
+//   int n = 1;
+//   base::Closure has_copy = base::Bind(&foo, n);
+//   base::Closure has_ref = base::Bind(&foo, base::ConstRef(n));
+//   n = 2;
+//   foo(n);                        // Prints "2 0xaaaaaaaaaaaa"
+//   has_copy.Run();                // Prints "1 0xbbbbbbbbbbbb"
+//   has_ref.Run();                 // Prints "2 0xaaaaaaaaaaaa"
+//
+//   Normally parameters are copied in the closure. DANGER: ConstRef stores a
+//   const reference instead, referencing the original parameter. This means
+//   that you must ensure the object outlives the callback!
+//
+//
+// -----------------------------------------------------------------------------
+// Implementation notes
+// -----------------------------------------------------------------------------
+//
+// WHERE IS THIS DESIGN FROM:
+//
+// The design Callback and Bind is heavily influenced by C++'s
+// tr1::function/tr1::bind, and by the "Google Callback" system used inside
+// Google.
+//
+//
+// HOW THE IMPLEMENTATION WORKS:
+//
+// There are three main components to the system:
+//   1) The Callback classes.
+//   2) The Bind() functions.
+//   3) The arguments wrappers (e.g., Unretained() and ConstRef()).
+//
+// The Callback classes represent a generic function pointer. Internally,
+// it stores a refcounted piece of state that represents the target function
+// and all its bound parameters.  Each Callback specialization has a templated
+// constructor that takes an BindState<>*.  In the context of the constructor,
+// the static type of this BindState<> pointer uniquely identifies the
+// function it is representing, all its bound parameters, and a Run() method
+// that is capable of invoking the target.
+//
+// Callback's constructor takes the BindState<>* that has the full static type
+// and erases the target function type as well as the types of the bound
+// parameters.  It does this by storing a pointer to the specific Run()
+// function, and upcasting the state of BindState<>* to a
+// BindStateBase*. This is safe as long as this BindStateBase pointer
+// is only used with the stored Run() pointer.
+//
+// To BindState<> objects are created inside the Bind() functions.
+// These functions, along with a set of internal templates, are responsible for
+//
+//  - Unwrapping the function signature into return type, and parameters
+//  - Determining the number of parameters that are bound
+//  - Creating the BindState storing the bound parameters
+//  - Performing compile-time asserts to avoid error-prone behavior
+//  - Returning an Callback<> with an arity matching the number of unbound
+//    parameters and that knows the correct refcounting semantics for the
+//    target object if we are binding a method.
+//
+// The Bind functions do the above using type-inference, and template
+// specializations.
+//
+// By default Bind() will store copies of all bound parameters, and attempt
+// to refcount a target object if the function being bound is a class method.
+// These copies are created even if the function takes parameters as const
+// references. (Binding to non-const references is forbidden, see bind.h.)
+//
+// To change this behavior, we introduce a set of argument wrappers
+// (e.g., Unretained(), and ConstRef()).  These are simple container templates
+// that are passed by value, and wrap a pointer to argument.  See the
+// file-level comment in base/bind_helpers.h for more info.
+//
+// These types are passed to the Unwrap() functions, and the MaybeRefcount()
+// functions respectively to modify the behavior of Bind().  The Unwrap()
+// and MaybeRefcount() functions change behavior by doing partial
+// specialization based on whether or not a parameter is a wrapper type.
+//
+// ConstRef() is similar to tr1::cref.  Unretained() is specific to Chromium.
+//
+//
+// WHY NOT TR1 FUNCTION/BIND?
+//
+// Direct use of tr1::function and tr1::bind was considered, but ultimately
+// rejected because of the number of copy constructors invocations involved
+// in the binding of arguments during construction, and the forwarding of
+// arguments during invocation.  These copies will no longer be an issue in
+// C++0x because C++0x will support rvalue reference allowing for the compiler
+// to avoid these copies.  However, waiting for C++0x is not an option.
+//
+// Measured with valgrind on gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5), the
+// tr1::bind call itself will invoke a non-trivial copy constructor three times
+// for each bound parameter.  Also, each when passing a tr1::function, each
+// bound argument will be copied again.
+//
+// In addition to the copies taken at binding and invocation, copying a
+// tr1::function causes a copy to be made of all the bound parameters and
+// state.
+//
+// Furthermore, in Chromium, it is desirable for the Callback to take a
+// reference on a target object when representing a class method call.  This
+// is not supported by tr1.
+//
+// Lastly, tr1::function and tr1::bind has a more general and flexible API.
+// This includes things like argument reordering by use of
+// tr1::bind::placeholder, support for non-const reference parameters, and some
+// limited amount of subtyping of the tr1::function object (e.g.,
+// tr1::function<int(int)> is convertible to tr1::function<void(int)>).
+//
+// These are not features that are required in Chromium. Some of them, such as
+// allowing for reference parameters, and subtyping of functions, may actually
+// become a source of errors. Removing support for these features actually
+// allows for a simpler implementation, and a terser Currying API.
+//
+//
+// WHY NOT GOOGLE CALLBACKS?
+//
+// The Google callback system also does not support refcounting.  Furthermore,
+// its implementation has a number of strange edge cases with respect to type
+// conversion of its arguments.  In particular, the argument's constness must
+// at times match exactly the function signature, or the type-inference might
+// break.  Given the above, writing a custom solution was easier.
+//
+//
+// MISSING FUNCTIONALITY
+//  - Invoking the return of Bind.  Bind(&foo).Run() does not work;
+//  - Binding arrays to functions that take a non-const pointer.
+//    Example:
+//      void Foo(const char* ptr);
+//      void Bar(char* ptr);
+//      Bind(&Foo, "test");
+//      Bind(&Bar, "test");  // This fails because ptr is not const.
+
+namespace base {
+
+// First, we forward declare the Callback class template. This informs the
+// compiler that the template only has 1 type parameter which is the function
+// signature that the Callback is representing.
+//
+// After this, create template specializations for 0-7 parameters. Note that
+// even though the template typelist grows, the specialization still
+// only has one type: the function signature.
+//
+// If you are thinking of forward declaring Callback in your own header file,
+// please include "base/callback_forward.h" instead.
+template <typename Sig>
+class Callback;
+
+namespace internal {
+template <typename Runnable, typename RunType, typename BoundArgsType>
+struct BindState;
+}  // namespace internal
+
+template <typename R, typename... Args>
+class Callback<R(Args...)> : public internal::CallbackBase {
+ public:
+  typedef R(RunType)(Args...);
+
+  Callback() : CallbackBase(NULL) { }
+
+  // Note that this constructor CANNOT be explicit, and that Bind() CANNOT
+  // return the exact Callback<> type.  See base/bind.h for details.
+  template <typename Runnable, typename BindRunType, typename BoundArgsType>
+  Callback(internal::BindState<Runnable, BindRunType,
+           BoundArgsType>* bind_state)
+      : CallbackBase(bind_state) {
+    // Force the assignment to a local variable of PolymorphicInvoke
+    // so the compiler will typecheck that the passed in Run() method has
+    // the correct type.
+    PolymorphicInvoke invoke_func =
+        &internal::BindState<Runnable, BindRunType, BoundArgsType>
+            ::InvokerType::Run;
+    polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
+  }
+
+  bool Equals(const Callback& other) const {
+    return CallbackBase::Equals(other);
+  }
+
+  R Run(typename internal::CallbackParamTraits<Args>::ForwardType... args)
+      const {
+    PolymorphicInvoke f =
+        reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
+
+    return f(bind_state_.get(), internal::CallbackForward(args)...);
+  }
+
+ private:
+  typedef R(*PolymorphicInvoke)(
+      internal::BindStateBase*,
+      typename internal::CallbackParamTraits<Args>::ForwardType...);
+};
+
+// Syntactic sugar to make Callback<void(void)> easier to declare since it
+// will be used in a lot of APIs with delayed execution.
+typedef Callback<void(void)> Closure;
+
+}  // namespace base
+
+#endif  // BASE_CALLBACK_H_
diff --git a/base/callback_forward.h b/base/callback_forward.h
new file mode 100644
index 0000000..262c306
--- /dev/null
+++ b/base/callback_forward.h
@@ -0,0 +1,17 @@
+// Copyright (c) 2011 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_CALLBACK_FORWARD_H_
+#define BASE_CALLBACK_FORWARD_H_
+
+namespace base {
+
+template <typename Sig>
+class Callback;
+
+typedef Callback<void(void)> Closure;
+
+}  // namespace base
+
+#endif  // BASE_CALLBACK_FORWARD_H_
diff --git a/base/callback_helpers.cc b/base/callback_helpers.cc
new file mode 100644
index 0000000..ef02b2b
--- /dev/null
+++ b/base/callback_helpers.cc
@@ -0,0 +1,42 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/callback_helpers.h"
+
+#include "base/callback.h"
+
+namespace base {
+
+ScopedClosureRunner::ScopedClosureRunner() {
+}
+
+ScopedClosureRunner::ScopedClosureRunner(const Closure& closure)
+    : closure_(closure) {
+}
+
+ScopedClosureRunner::~ScopedClosureRunner() {
+  if (!closure_.is_null())
+    closure_.Run();
+}
+
+void ScopedClosureRunner::Reset() {
+  Closure old_closure = Release();
+  if (!old_closure.is_null())
+    old_closure.Run();
+}
+
+void ScopedClosureRunner::Reset(const Closure& closure) {
+  Closure old_closure = Release();
+  closure_ = closure;
+  if (!old_closure.is_null())
+    old_closure.Run();
+}
+
+Closure ScopedClosureRunner::Release() {
+  Closure result = closure_;
+  closure_.Reset();
+  return result;
+}
+
+}  // namespace base
diff --git a/base/callback_helpers.h b/base/callback_helpers.h
new file mode 100644
index 0000000..8481e3e
--- /dev/null
+++ b/base/callback_helpers.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2012 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 defines helpful methods for dealing with Callbacks.  Because Callbacks
+// are implemented using templates, with a class per callback signature, adding
+// methods to Callback<> itself is unattractive (lots of extra code gets
+// generated).  Instead, consider adding methods here.
+//
+// ResetAndReturn(&cb) is like cb.Reset() but allows executing a callback (via a
+// copy) after the original callback is Reset().  This can be handy if Run()
+// reads/writes the variable holding the Callback.
+
+#ifndef BASE_CALLBACK_HELPERS_H_
+#define BASE_CALLBACK_HELPERS_H_
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+
+namespace base {
+
+template <typename Sig>
+base::Callback<Sig> ResetAndReturn(base::Callback<Sig>* cb) {
+  base::Callback<Sig> ret(*cb);
+  cb->Reset();
+  return ret;
+}
+
+// ScopedClosureRunner is akin to scoped_ptr for Closures. It ensures that the
+// Closure is executed and deleted no matter how the current scope exits.
+class BASE_EXPORT ScopedClosureRunner {
+ public:
+  ScopedClosureRunner();
+  explicit ScopedClosureRunner(const Closure& closure);
+  ~ScopedClosureRunner();
+
+  void Reset();
+  void Reset(const Closure& closure);
+  Closure Release() WARN_UNUSED_RESULT;
+
+ private:
+  Closure closure_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedClosureRunner);
+};
+
+}  // namespace base
+
+#endif  // BASE_CALLBACK_HELPERS_H_
diff --git a/base/callback_helpers_unittest.cc b/base/callback_helpers_unittest.cc
new file mode 100644
index 0000000..3b17a6b
--- /dev/null
+++ b/base/callback_helpers_unittest.cc
@@ -0,0 +1,61 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/callback_helpers.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+void Increment(int* value) {
+  (*value)++;
+}
+
+TEST(BindHelpersTest, TestScopedClosureRunnerExitScope) {
+  int run_count = 0;
+  {
+    base::ScopedClosureRunner runner(base::Bind(&Increment, &run_count));
+    EXPECT_EQ(0, run_count);
+  }
+  EXPECT_EQ(1, run_count);
+}
+
+TEST(BindHelpersTest, TestScopedClosureRunnerRelease) {
+  int run_count = 0;
+  base::Closure c;
+  {
+    base::ScopedClosureRunner runner(base::Bind(&Increment, &run_count));
+    c = runner.Release();
+    EXPECT_EQ(0, run_count);
+  }
+  EXPECT_EQ(0, run_count);
+  c.Run();
+  EXPECT_EQ(1, run_count);
+}
+
+TEST(BindHelpersTest, TestScopedClosureRunnerReset) {
+  int run_count_1 = 0;
+  int run_count_2 = 0;
+  {
+    base::ScopedClosureRunner runner;
+    runner.Reset(base::Bind(&Increment, &run_count_1));
+    runner.Reset(base::Bind(&Increment, &run_count_2));
+    EXPECT_EQ(1, run_count_1);
+    EXPECT_EQ(0, run_count_2);
+  }
+  EXPECT_EQ(1, run_count_2);
+
+  int run_count_3 = 0;
+  {
+    base::ScopedClosureRunner runner(base::Bind(&Increment, &run_count_3));
+    EXPECT_EQ(0, run_count_3);
+    runner.Reset();
+    EXPECT_EQ(1, run_count_3);
+  }
+  EXPECT_EQ(1, run_count_3);
+}
+
+}  // namespace
diff --git a/base/callback_internal.cc b/base/callback_internal.cc
new file mode 100644
index 0000000..2553fe7
--- /dev/null
+++ b/base/callback_internal.cc
@@ -0,0 +1,46 @@
+// Copyright (c) 2012 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/callback_internal.h"
+
+#include "base/logging.h"
+
+namespace base {
+namespace internal {
+
+void BindStateBase::AddRef() {
+  AtomicRefCountInc(&ref_count_);
+}
+
+void BindStateBase::Release() {
+  if (!AtomicRefCountDec(&ref_count_))
+    destructor_(this);
+}
+
+CallbackBase::CallbackBase(const CallbackBase& c) = default;
+CallbackBase& CallbackBase::operator=(const CallbackBase& c) = default;
+
+void CallbackBase::Reset() {
+  polymorphic_invoke_ = NULL;
+  // NULL the bind_state_ last, since it may be holding the last ref to whatever
+  // object owns us, and we may be deleted after that.
+  bind_state_ = NULL;
+}
+
+bool CallbackBase::Equals(const CallbackBase& other) const {
+  return bind_state_.get() == other.bind_state_.get() &&
+         polymorphic_invoke_ == other.polymorphic_invoke_;
+}
+
+CallbackBase::CallbackBase(BindStateBase* bind_state)
+    : bind_state_(bind_state),
+      polymorphic_invoke_(NULL) {
+  DCHECK(!bind_state_.get() || bind_state_->ref_count_ == 1);
+}
+
+CallbackBase::~CallbackBase() {
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/callback_internal.h b/base/callback_internal.h
new file mode 100644
index 0000000..fefd7a2
--- /dev/null
+++ b/base/callback_internal.h
@@ -0,0 +1,234 @@
+// Copyright (c) 2012 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 contains utility functions and classes that help the
+// implementation, and management of the Callback objects.
+
+#ifndef BASE_CALLBACK_INTERNAL_H_
+#define BASE_CALLBACK_INTERNAL_H_
+
+#include <stddef.h>
+
+#include "base/atomic_ref_count.h"
+#include "base/base_export.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/template_util.h"
+
+template <typename T>
+class ScopedVector;
+
+namespace base {
+namespace internal {
+class CallbackBase;
+
+// BindStateBase is used to provide an opaque handle that the Callback
+// class can use to represent a function object with bound arguments.  It
+// behaves as an existential type that is used by a corresponding
+// DoInvoke function to perform the function execution.  This allows
+// us to shield the Callback class from the types of the bound argument via
+// "type erasure."
+// At the base level, the only task is to add reference counting data. Don't use
+// RefCountedThreadSafe since it requires the destructor to be a virtual method.
+// Creating a vtable for every BindState template instantiation results in a lot
+// of bloat. Its only task is to call the destructor which can be done with a
+// function pointer.
+class BindStateBase {
+ protected:
+  explicit BindStateBase(void (*destructor)(BindStateBase*))
+      : ref_count_(0), destructor_(destructor) {}
+  ~BindStateBase() = default;
+
+ private:
+  friend class scoped_refptr<BindStateBase>;
+  friend class CallbackBase;
+
+  void AddRef();
+  void Release();
+
+  AtomicRefCount ref_count_;
+
+  // Pointer to a function that will properly destroy |this|.
+  void (*destructor_)(BindStateBase*);
+
+  DISALLOW_COPY_AND_ASSIGN(BindStateBase);
+};
+
+// Holds the Callback methods that don't require specialization to reduce
+// template bloat.
+class BASE_EXPORT CallbackBase {
+ public:
+  CallbackBase(const CallbackBase& c);
+  CallbackBase& operator=(const CallbackBase& c);
+
+  // Returns true if Callback is null (doesn't refer to anything).
+  bool is_null() const { return bind_state_.get() == NULL; }
+
+  // Returns the Callback into an uninitialized state.
+  void Reset();
+
+ protected:
+  // In C++, it is safe to cast function pointers to function pointers of
+  // another type. It is not okay to use void*. We create a InvokeFuncStorage
+  // that that can store our function pointer, and then cast it back to
+  // the original type on usage.
+  typedef void(*InvokeFuncStorage)(void);
+
+  // Returns true if this callback equals |other|. |other| may be null.
+  bool Equals(const CallbackBase& other) const;
+
+  // Allow initializing of |bind_state_| via the constructor to avoid default
+  // initialization of the scoped_refptr.  We do not also initialize
+  // |polymorphic_invoke_| here because doing a normal assignment in the
+  // derived Callback templates makes for much nicer compiler errors.
+  explicit CallbackBase(BindStateBase* bind_state);
+
+  // Force the destructor to be instantiated inside this translation unit so
+  // that our subclasses will not get inlined versions.  Avoids more template
+  // bloat.
+  ~CallbackBase();
+
+  scoped_refptr<BindStateBase> bind_state_;
+  InvokeFuncStorage polymorphic_invoke_;
+};
+
+// A helper template to determine if given type is non-const move-only-type,
+// i.e. if a value of the given type should be passed via .Pass() in a
+// destructive way.
+template <typename T> struct IsMoveOnlyType {
+  template <typename U>
+  static YesType Test(const typename U::MoveOnlyTypeForCPP03*);
+
+  template <typename U>
+  static NoType Test(...);
+
+  static const bool value = sizeof((Test<T>(0))) == sizeof(YesType) &&
+                            !is_const<T>::value;
+};
+
+// Returns |Then| as SelectType::Type if |condition| is true. Otherwise returns
+// |Else|.
+template <bool condition, typename Then, typename Else>
+struct SelectType {
+  typedef Then Type;
+};
+
+template <typename Then, typename Else>
+struct SelectType<false, Then, Else> {
+  typedef Else Type;
+};
+
+template <typename>
+struct CallbackParamTraitsForMoveOnlyType;
+
+template <typename>
+struct CallbackParamTraitsForNonMoveOnlyType;
+
+// TODO(tzik): Use a default parameter once MSVS supports variadic templates
+// with default values.
+// http://connect.microsoft.com/VisualStudio/feedbackdetail/view/957801/compilation-error-with-variadic-templates
+//
+// This is a typetraits object that's used to take an argument type, and
+// extract a suitable type for storing and forwarding arguments.
+//
+// In particular, it strips off references, and converts arrays to
+// pointers for storage; and it avoids accidentally trying to create a
+// "reference of a reference" if the argument is a reference type.
+//
+// This array type becomes an issue for storage because we are passing bound
+// parameters by const reference. In this case, we end up passing an actual
+// array type in the initializer list which C++ does not allow.  This will
+// break passing of C-string literals.
+template <typename T>
+struct CallbackParamTraits
+    : SelectType<IsMoveOnlyType<T>::value,
+         CallbackParamTraitsForMoveOnlyType<T>,
+         CallbackParamTraitsForNonMoveOnlyType<T> >::Type {
+};
+
+template <typename T>
+struct CallbackParamTraitsForNonMoveOnlyType {
+  typedef const T& ForwardType;
+  typedef T StorageType;
+};
+
+// The Storage should almost be impossible to trigger unless someone manually
+// specifies type of the bind parameters.  However, in case they do,
+// this will guard against us accidentally storing a reference parameter.
+//
+// The ForwardType should only be used for unbound arguments.
+template <typename T>
+struct CallbackParamTraitsForNonMoveOnlyType<T&> {
+  typedef T& ForwardType;
+  typedef T StorageType;
+};
+
+// Note that for array types, we implicitly add a const in the conversion. This
+// means that it is not possible to bind array arguments to functions that take
+// a non-const pointer. Trying to specialize the template based on a "const
+// T[n]" does not seem to match correctly, so we are stuck with this
+// restriction.
+template <typename T, size_t n>
+struct CallbackParamTraitsForNonMoveOnlyType<T[n]> {
+  typedef const T* ForwardType;
+  typedef const T* StorageType;
+};
+
+// See comment for CallbackParamTraits<T[n]>.
+template <typename T>
+struct CallbackParamTraitsForNonMoveOnlyType<T[]> {
+  typedef const T* ForwardType;
+  typedef const T* StorageType;
+};
+
+// Parameter traits for movable-but-not-copyable scopers.
+//
+// Callback<>/Bind() understands movable-but-not-copyable semantics where
+// the type cannot be copied but can still have its state destructively
+// transferred (aka. moved) to another instance of the same type by calling a
+// helper function.  When used with Bind(), this signifies transferal of the
+// object's state to the target function.
+//
+// For these types, the ForwardType must not be a const reference, or a
+// reference.  A const reference is inappropriate, and would break const
+// correctness, because we are implementing a destructive move.  A non-const
+// reference cannot be used with temporaries which means the result of a
+// function or a cast would not be usable with Callback<> or Bind().
+template <typename T>
+struct CallbackParamTraitsForMoveOnlyType {
+  typedef T ForwardType;
+  typedef T StorageType;
+};
+
+// CallbackForward() is a very limited simulation of C++11's std::forward()
+// used by the Callback/Bind system for a set of movable-but-not-copyable
+// types.  It is needed because forwarding a movable-but-not-copyable
+// argument to another function requires us to invoke the proper move
+// operator to create a rvalue version of the type.  The supported types are
+// whitelisted below as overloads of the CallbackForward() function. The
+// default template compiles out to be a no-op.
+//
+// In C++11, std::forward would replace all uses of this function.  However, it
+// is impossible to implement a general std::forward with C++11 due to a lack
+// of rvalue references.
+//
+// In addition to Callback/Bind, this is used by PostTaskAndReplyWithResult to
+// simulate std::forward() and forward the result of one Callback as a
+// parameter to another callback. This is to support Callbacks that return
+// the movable-but-not-copyable types whitelisted above.
+template <typename T>
+typename enable_if<!IsMoveOnlyType<T>::value, T>::type& CallbackForward(T& t) {
+  return t;
+}
+
+template <typename T>
+typename enable_if<IsMoveOnlyType<T>::value, T>::type CallbackForward(T& t) {
+  return t.Pass();
+}
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_CALLBACK_INTERNAL_H_
diff --git a/base/callback_list.h b/base/callback_list.h
new file mode 100644
index 0000000..aeed5f1
--- /dev/null
+++ b/base/callback_list.h
@@ -0,0 +1,230 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_CALLBACK_LIST_H_
+#define BASE_CALLBACK_LIST_H_
+
+#include <list>
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/callback_internal.h"
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+
+// OVERVIEW:
+//
+// A container for a list of callbacks.  Unlike a normal STL vector or list,
+// this container can be modified during iteration without invalidating the
+// iterator. It safely handles the case of a callback removing itself
+// or another callback from the list while callbacks are being run.
+//
+// TYPICAL USAGE:
+//
+// class MyWidget {
+//  public:
+//   ...
+//
+//   typedef base::Callback<void(const Foo&)> OnFooCallback;
+//
+//   scoped_ptr<base::CallbackList<void(const Foo&)>::Subscription>
+//   RegisterCallback(const OnFooCallback& cb) {
+//     return callback_list_.Add(cb);
+//   }
+//
+//  private:
+//   void NotifyFoo(const Foo& foo) {
+//      callback_list_.Notify(foo);
+//   }
+//
+//   base::CallbackList<void(const Foo&)> callback_list_;
+//
+//   DISALLOW_COPY_AND_ASSIGN(MyWidget);
+// };
+//
+//
+// class MyWidgetListener {
+//  public:
+//   MyWidgetListener::MyWidgetListener() {
+//     foo_subscription_ = MyWidget::GetCurrent()->RegisterCallback(
+//             base::Bind(&MyWidgetListener::OnFoo, this)));
+//   }
+//
+//   MyWidgetListener::~MyWidgetListener() {
+//      // Subscription gets deleted automatically and will deregister
+//      // the callback in the process.
+//   }
+//
+//  private:
+//   void OnFoo(const Foo& foo) {
+//     // Do something.
+//   }
+//
+//   scoped_ptr<base::CallbackList<void(const Foo&)>::Subscription>
+//       foo_subscription_;
+//
+//   DISALLOW_COPY_AND_ASSIGN(MyWidgetListener);
+// };
+
+namespace base {
+
+namespace internal {
+
+template <typename CallbackType>
+class CallbackListBase {
+ public:
+  class Subscription {
+   public:
+    Subscription(CallbackListBase<CallbackType>* list,
+                 typename std::list<CallbackType>::iterator iter)
+        : list_(list),
+          iter_(iter) {
+    }
+
+    ~Subscription() {
+      if (list_->active_iterator_count_) {
+        iter_->Reset();
+      } else {
+        list_->callbacks_.erase(iter_);
+        if (!list_->removal_callback_.is_null())
+          list_->removal_callback_.Run();
+      }
+    }
+
+   private:
+    CallbackListBase<CallbackType>* list_;
+    typename std::list<CallbackType>::iterator iter_;
+
+    DISALLOW_COPY_AND_ASSIGN(Subscription);
+  };
+
+  // Add a callback to the list. The callback will remain registered until the
+  // returned Subscription is destroyed, which must occur before the
+  // CallbackList is destroyed.
+  scoped_ptr<Subscription> Add(const CallbackType& cb) WARN_UNUSED_RESULT {
+    DCHECK(!cb.is_null());
+    return scoped_ptr<Subscription>(
+        new Subscription(this, callbacks_.insert(callbacks_.end(), cb)));
+  }
+
+  // Sets a callback which will be run when a subscription list is changed.
+  void set_removal_callback(const Closure& callback) {
+    removal_callback_ = callback;
+  }
+
+  // Returns true if there are no subscriptions. This is only valid to call when
+  // not looping through the list.
+  bool empty() {
+    DCHECK_EQ(0, active_iterator_count_);
+    return callbacks_.empty();
+  }
+
+ protected:
+  // An iterator class that can be used to access the list of callbacks.
+  class Iterator {
+   public:
+    explicit Iterator(CallbackListBase<CallbackType>* list)
+        : list_(list),
+          list_iter_(list_->callbacks_.begin()) {
+      ++list_->active_iterator_count_;
+    }
+
+    Iterator(const Iterator& iter)
+        : list_(iter.list_),
+          list_iter_(iter.list_iter_) {
+      ++list_->active_iterator_count_;
+    }
+
+    ~Iterator() {
+      if (list_ && --list_->active_iterator_count_ == 0) {
+        list_->Compact();
+      }
+    }
+
+    CallbackType* GetNext() {
+      while ((list_iter_ != list_->callbacks_.end()) && list_iter_->is_null())
+        ++list_iter_;
+
+      CallbackType* cb = NULL;
+      if (list_iter_ != list_->callbacks_.end()) {
+        cb = &(*list_iter_);
+        ++list_iter_;
+      }
+      return cb;
+    }
+
+   private:
+    CallbackListBase<CallbackType>* list_;
+    typename std::list<CallbackType>::iterator list_iter_;
+  };
+
+  CallbackListBase() : active_iterator_count_(0) {}
+
+  ~CallbackListBase() {
+    DCHECK_EQ(0, active_iterator_count_);
+    DCHECK_EQ(0U, callbacks_.size());
+  }
+
+  // Returns an instance of a CallbackListBase::Iterator which can be used
+  // to run callbacks.
+  Iterator GetIterator() {
+    return Iterator(this);
+  }
+
+  // Compact the list: remove any entries which were NULLed out during
+  // iteration.
+  void Compact() {
+    typename std::list<CallbackType>::iterator it = callbacks_.begin();
+    bool updated = false;
+    while (it != callbacks_.end()) {
+      if ((*it).is_null()) {
+        updated = true;
+        it = callbacks_.erase(it);
+      } else {
+        ++it;
+      }
+
+      if (updated && !removal_callback_.is_null())
+        removal_callback_.Run();
+    }
+  }
+
+ private:
+  std::list<CallbackType> callbacks_;
+  int active_iterator_count_;
+  Closure removal_callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(CallbackListBase);
+};
+
+}  // namespace internal
+
+template <typename Sig> class CallbackList;
+
+template <typename... Args>
+class CallbackList<void(Args...)>
+    : public internal::CallbackListBase<Callback<void(Args...)> > {
+ public:
+  typedef Callback<void(Args...)> CallbackType;
+
+  CallbackList() {}
+
+  void Notify(
+      typename internal::CallbackParamTraits<Args>::ForwardType... args) {
+    typename internal::CallbackListBase<CallbackType>::Iterator it =
+        this->GetIterator();
+    CallbackType* cb;
+    while ((cb = it.GetNext()) != NULL) {
+      cb->Run(args...);
+    }
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(CallbackList);
+};
+
+}  // namespace base
+
+#endif  // BASE_CALLBACK_LIST_H_
diff --git a/base/callback_list_unittest.cc b/base/callback_list_unittest.cc
new file mode 100644
index 0000000..9adbabb
--- /dev/null
+++ b/base/callback_list_unittest.cc
@@ -0,0 +1,291 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/callback_list.h"
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+class Listener {
+ public:
+  Listener() : total_(0), scaler_(1) {}
+  explicit Listener(int scaler) : total_(0), scaler_(scaler) {}
+  void IncrementTotal() { total_++; }
+  void IncrementByMultipleOfScaler(int x) { total_ += x * scaler_; }
+
+  int total() const { return total_; }
+
+ private:
+  int total_;
+  int scaler_;
+  DISALLOW_COPY_AND_ASSIGN(Listener);
+};
+
+class Remover {
+ public:
+  Remover() : total_(0) {}
+  void IncrementTotalAndRemove() {
+    total_++;
+    removal_subscription_.reset();
+  }
+  void SetSubscriptionToRemove(
+      scoped_ptr<CallbackList<void(void)>::Subscription> sub) {
+    removal_subscription_ = sub.Pass();
+  }
+
+  int total() const { return total_; }
+
+ private:
+  int total_;
+  scoped_ptr<CallbackList<void(void)>::Subscription> removal_subscription_;
+  DISALLOW_COPY_AND_ASSIGN(Remover);
+};
+
+class Adder {
+ public:
+  explicit Adder(CallbackList<void(void)>* cb_reg)
+      : added_(false),
+        total_(0),
+        cb_reg_(cb_reg) {
+  }
+  void AddCallback() {
+    if (!added_) {
+      added_ = true;
+      subscription_ =
+          cb_reg_->Add(Bind(&Adder::IncrementTotal, Unretained(this)));
+    }
+  }
+  void IncrementTotal() { total_++; }
+
+  bool added() const { return added_; }
+
+  int total() const { return total_; }
+
+ private:
+  bool added_;
+  int total_;
+  CallbackList<void(void)>* cb_reg_;
+  scoped_ptr<CallbackList<void(void)>::Subscription> subscription_;
+  DISALLOW_COPY_AND_ASSIGN(Adder);
+};
+
+class Summer {
+ public:
+  Summer() : value_(0) {}
+
+  void AddOneParam(int a) { value_ = a; }
+  void AddTwoParam(int a, int b) { value_ = a + b; }
+  void AddThreeParam(int a, int b, int c) { value_ = a + b + c; }
+  void AddFourParam(int a, int b, int c, int d) { value_ = a + b + c + d; }
+  void AddFiveParam(int a, int b, int c, int d, int e) {
+    value_ = a + b + c + d + e;
+  }
+  void AddSixParam(int a, int b, int c, int d, int e , int f) {
+    value_ = a + b + c + d + e + f;
+  }
+
+  int value() const { return value_; }
+
+ private:
+  int value_;
+  DISALLOW_COPY_AND_ASSIGN(Summer);
+};
+
+// Sanity check that we can instantiate a CallbackList for each arity.
+TEST(CallbackListTest, ArityTest) {
+  Summer s;
+
+  CallbackList<void(int)> c1;
+  scoped_ptr<CallbackList<void(int)>::Subscription> subscription1 =
+      c1.Add(Bind(&Summer::AddOneParam, Unretained(&s)));
+
+  c1.Notify(1);
+  EXPECT_EQ(1, s.value());
+
+  CallbackList<void(int, int)> c2;
+  scoped_ptr<CallbackList<void(int, int)>::Subscription> subscription2 =
+      c2.Add(Bind(&Summer::AddTwoParam, Unretained(&s)));
+
+  c2.Notify(1, 2);
+  EXPECT_EQ(3, s.value());
+
+  CallbackList<void(int, int, int)> c3;
+  scoped_ptr<CallbackList<void(int, int, int)>::Subscription>
+      subscription3 = c3.Add(Bind(&Summer::AddThreeParam, Unretained(&s)));
+
+  c3.Notify(1, 2, 3);
+  EXPECT_EQ(6, s.value());
+
+  CallbackList<void(int, int, int, int)> c4;
+  scoped_ptr<CallbackList<void(int, int, int, int)>::Subscription>
+      subscription4 = c4.Add(Bind(&Summer::AddFourParam, Unretained(&s)));
+
+  c4.Notify(1, 2, 3, 4);
+  EXPECT_EQ(10, s.value());
+
+  CallbackList<void(int, int, int, int, int)> c5;
+  scoped_ptr<CallbackList<void(int, int, int, int, int)>::Subscription>
+      subscription5 = c5.Add(Bind(&Summer::AddFiveParam, Unretained(&s)));
+
+  c5.Notify(1, 2, 3, 4, 5);
+  EXPECT_EQ(15, s.value());
+
+  CallbackList<void(int, int, int, int, int, int)> c6;
+  scoped_ptr<CallbackList<void(int, int, int, int, int, int)>::Subscription>
+      subscription6 = c6.Add(Bind(&Summer::AddSixParam, Unretained(&s)));
+
+  c6.Notify(1, 2, 3, 4, 5, 6);
+  EXPECT_EQ(21, s.value());
+}
+
+// Sanity check that closures added to the list will be run, and those removed
+// from the list will not be run.
+TEST(CallbackListTest, BasicTest) {
+  CallbackList<void(void)> cb_reg;
+  Listener a, b, c;
+
+  scoped_ptr<CallbackList<void(void)>::Subscription> a_subscription =
+      cb_reg.Add(Bind(&Listener::IncrementTotal, Unretained(&a)));
+  scoped_ptr<CallbackList<void(void)>::Subscription> b_subscription =
+      cb_reg.Add(Bind(&Listener::IncrementTotal, Unretained(&b)));
+
+  EXPECT_TRUE(a_subscription.get());
+  EXPECT_TRUE(b_subscription.get());
+
+  cb_reg.Notify();
+
+  EXPECT_EQ(1, a.total());
+  EXPECT_EQ(1, b.total());
+
+  b_subscription.reset();
+
+  scoped_ptr<CallbackList<void(void)>::Subscription> c_subscription =
+      cb_reg.Add(Bind(&Listener::IncrementTotal, Unretained(&c)));
+
+  cb_reg.Notify();
+
+  EXPECT_EQ(2, a.total());
+  EXPECT_EQ(1, b.total());
+  EXPECT_EQ(1, c.total());
+
+  a_subscription.reset();
+  b_subscription.reset();
+  c_subscription.reset();
+}
+
+// Sanity check that callbacks with details added to the list will be run, with
+// the correct details, and those removed from the list will not be run.
+TEST(CallbackListTest, BasicTestWithParams) {
+  CallbackList<void(int)> cb_reg;
+  Listener a(1), b(-1), c(1);
+
+  scoped_ptr<CallbackList<void(int)>::Subscription> a_subscription =
+      cb_reg.Add(Bind(&Listener::IncrementByMultipleOfScaler, Unretained(&a)));
+  scoped_ptr<CallbackList<void(int)>::Subscription> b_subscription =
+      cb_reg.Add(Bind(&Listener::IncrementByMultipleOfScaler, Unretained(&b)));
+
+  EXPECT_TRUE(a_subscription.get());
+  EXPECT_TRUE(b_subscription.get());
+
+  cb_reg.Notify(10);
+
+  EXPECT_EQ(10, a.total());
+  EXPECT_EQ(-10, b.total());
+
+  b_subscription.reset();
+
+  scoped_ptr<CallbackList<void(int)>::Subscription> c_subscription =
+      cb_reg.Add(Bind(&Listener::IncrementByMultipleOfScaler, Unretained(&c)));
+
+  cb_reg.Notify(10);
+
+  EXPECT_EQ(20, a.total());
+  EXPECT_EQ(-10, b.total());
+  EXPECT_EQ(10, c.total());
+
+  a_subscription.reset();
+  b_subscription.reset();
+  c_subscription.reset();
+}
+
+// Test the a callback can remove itself or a different callback from the list
+// during iteration without invalidating the iterator.
+TEST(CallbackListTest, RemoveCallbacksDuringIteration) {
+  CallbackList<void(void)> cb_reg;
+  Listener a, b;
+  Remover remover_1, remover_2;
+
+  scoped_ptr<CallbackList<void(void)>::Subscription> remover_1_sub =
+      cb_reg.Add(Bind(&Remover::IncrementTotalAndRemove,
+          Unretained(&remover_1)));
+  scoped_ptr<CallbackList<void(void)>::Subscription> remover_2_sub =
+      cb_reg.Add(Bind(&Remover::IncrementTotalAndRemove,
+          Unretained(&remover_2)));
+  scoped_ptr<CallbackList<void(void)>::Subscription> a_subscription =
+      cb_reg.Add(Bind(&Listener::IncrementTotal, Unretained(&a)));
+  scoped_ptr<CallbackList<void(void)>::Subscription> b_subscription =
+      cb_reg.Add(Bind(&Listener::IncrementTotal, Unretained(&b)));
+
+  // |remover_1| will remove itself.
+  remover_1.SetSubscriptionToRemove(remover_1_sub.Pass());
+  // |remover_2| will remove a.
+  remover_2.SetSubscriptionToRemove(a_subscription.Pass());
+
+  cb_reg.Notify();
+
+  // |remover_1| runs once (and removes itself), |remover_2| runs once (and
+  // removes a), |a| never runs, and |b| runs once.
+  EXPECT_EQ(1, remover_1.total());
+  EXPECT_EQ(1, remover_2.total());
+  EXPECT_EQ(0, a.total());
+  EXPECT_EQ(1, b.total());
+
+  cb_reg.Notify();
+
+  // Only |remover_2| and |b| run this time.
+  EXPECT_EQ(1, remover_1.total());
+  EXPECT_EQ(2, remover_2.total());
+  EXPECT_EQ(0, a.total());
+  EXPECT_EQ(2, b.total());
+}
+
+// Test that a callback can add another callback to the list durning iteration
+// without invalidating the iterator. The newly added callback should be run on
+// the current iteration as will all other callbacks in the list.
+TEST(CallbackListTest, AddCallbacksDuringIteration) {
+  CallbackList<void(void)> cb_reg;
+  Adder a(&cb_reg);
+  Listener b;
+  scoped_ptr<CallbackList<void(void)>::Subscription> a_subscription =
+      cb_reg.Add(Bind(&Adder::AddCallback, Unretained(&a)));
+  scoped_ptr<CallbackList<void(void)>::Subscription> b_subscription =
+      cb_reg.Add(Bind(&Listener::IncrementTotal, Unretained(&b)));
+
+  cb_reg.Notify();
+
+  EXPECT_EQ(1, a.total());
+  EXPECT_EQ(1, b.total());
+  EXPECT_TRUE(a.added());
+
+  cb_reg.Notify();
+
+  EXPECT_EQ(2, a.total());
+  EXPECT_EQ(2, b.total());
+}
+
+// Sanity check: notifying an empty list is a no-op.
+TEST(CallbackListTest, EmptyList) {
+  CallbackList<void(void)> cb_reg;
+
+  cb_reg.Notify();
+}
+
+}  // namespace
+}  // namespace base
diff --git a/base/callback_list_unittest.nc b/base/callback_list_unittest.nc
new file mode 100644
index 0000000..2d464cf
--- /dev/null
+++ b/base/callback_list_unittest.nc
@@ -0,0 +1,51 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/callback_list.h"
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/memory/scoped_ptr.h"
+
+namespace base {
+
+class Foo {
+ public:
+  Foo() {}
+  ~Foo() {}
+};
+
+class FooListener {
+ public:
+  FooListener() {}
+
+  void GotAScopedFoo(scoped_ptr<Foo> f) { foo_ = f.Pass(); }
+
+  scoped_ptr<Foo> foo_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(FooListener);
+};
+
+
+#if defined(NCTEST_MOVE_ONLY_TYPE_PARAMETER)  // [r"calling a private constructor of class"]
+
+// Callbacks run with a move-only typed parameter.
+//
+// CallbackList does not support move-only typed parameters. Notify() is
+// designed to take zero or more parameters, and run each registered callback
+// with them. With move-only types, the parameter will be set to NULL after the
+// first callback has been run.
+void WontCompile() {
+  FooListener f;
+  CallbackList<void(scoped_ptr<Foo>)> c1;
+  scoped_ptr<CallbackList<void(scoped_ptr<Foo>)>::Subscription> sub =
+      c1.Add(Bind(&FooListener::GotAScopedFoo, Unretained(&f)));
+  c1.Notify(scoped_ptr<Foo>(new Foo()));
+}
+
+#endif
+
+}  // namespace base
diff --git a/base/callback_unittest.cc b/base/callback_unittest.cc
new file mode 100644
index 0000000..2844aa9
--- /dev/null
+++ b/base/callback_unittest.cc
@@ -0,0 +1,192 @@
+// Copyright (c) 2012 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/bind.h"
+#include "base/callback.h"
+#include "base/callback_helpers.h"
+#include "base/callback_internal.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+struct FakeInvoker {
+  typedef void(RunType)(internal::BindStateBase*);
+  static void Run(internal::BindStateBase*) {
+  }
+};
+
+}  // namespace
+
+namespace internal {
+template <typename Runnable, typename RunType, typename BoundArgsType>
+struct BindState;
+
+// White-box testpoints to inject into a Callback<> object for checking
+// comparators and emptiness APIs.  Use a BindState that is specialized
+// based on a type we declared in the anonymous namespace above to remove any
+// chance of colliding with another instantiation and breaking the
+// one-definition-rule.
+template <>
+struct BindState<void(void), void(void), void(FakeInvoker)>
+    : public BindStateBase {
+ public:
+  BindState() : BindStateBase(&Destroy) {}
+  typedef FakeInvoker InvokerType;
+ private:
+  ~BindState() {}
+  static void Destroy(BindStateBase* self) {
+    delete static_cast<BindState*>(self);
+  }
+};
+
+template <>
+struct BindState<void(void), void(void),
+                           void(FakeInvoker, FakeInvoker)>
+    : public BindStateBase {
+ public:
+  BindState() : BindStateBase(&Destroy) {}
+  typedef FakeInvoker InvokerType;
+ private:
+  ~BindState() {}
+  static void Destroy(BindStateBase* self) {
+    delete static_cast<BindState*>(self);
+  }
+};
+}  // namespace internal
+
+namespace {
+
+typedef internal::BindState<void(void), void(void), void(FakeInvoker)>
+    FakeBindState1;
+typedef internal::BindState<void(void), void(void),
+                            void(FakeInvoker, FakeInvoker)>
+   FakeBindState2;
+
+class CallbackTest : public ::testing::Test {
+ public:
+  CallbackTest()
+      : callback_a_(new FakeBindState1()),
+        callback_b_(new FakeBindState2()) {
+  }
+
+  ~CallbackTest() override {}
+
+ protected:
+  Callback<void(void)> callback_a_;
+  const Callback<void(void)> callback_b_;  // Ensure APIs work with const.
+  Callback<void(void)> null_callback_;
+};
+
+// Ensure we can create unbound callbacks. We need this to be able to store
+// them in class members that can be initialized later.
+TEST_F(CallbackTest, DefaultConstruction) {
+  Callback<void(void)> c0;
+  Callback<void(int)> c1;
+  Callback<void(int,int)> c2;
+  Callback<void(int,int,int)> c3;
+  Callback<void(int,int,int,int)> c4;
+  Callback<void(int,int,int,int,int)> c5;
+  Callback<void(int,int,int,int,int,int)> c6;
+
+  EXPECT_TRUE(c0.is_null());
+  EXPECT_TRUE(c1.is_null());
+  EXPECT_TRUE(c2.is_null());
+  EXPECT_TRUE(c3.is_null());
+  EXPECT_TRUE(c4.is_null());
+  EXPECT_TRUE(c5.is_null());
+  EXPECT_TRUE(c6.is_null());
+}
+
+TEST_F(CallbackTest, IsNull) {
+  EXPECT_TRUE(null_callback_.is_null());
+  EXPECT_FALSE(callback_a_.is_null());
+  EXPECT_FALSE(callback_b_.is_null());
+}
+
+TEST_F(CallbackTest, Equals) {
+  EXPECT_TRUE(callback_a_.Equals(callback_a_));
+  EXPECT_FALSE(callback_a_.Equals(callback_b_));
+  EXPECT_FALSE(callback_b_.Equals(callback_a_));
+
+  // We should compare based on instance, not type.
+  Callback<void(void)> callback_c(new FakeBindState1());
+  Callback<void(void)> callback_a2 = callback_a_;
+  EXPECT_TRUE(callback_a_.Equals(callback_a2));
+  EXPECT_FALSE(callback_a_.Equals(callback_c));
+
+  // Empty, however, is always equal to empty.
+  Callback<void(void)> empty2;
+  EXPECT_TRUE(null_callback_.Equals(empty2));
+}
+
+TEST_F(CallbackTest, Reset) {
+  // Resetting should bring us back to empty.
+  ASSERT_FALSE(callback_a_.is_null());
+  ASSERT_FALSE(callback_a_.Equals(null_callback_));
+
+  callback_a_.Reset();
+
+  EXPECT_TRUE(callback_a_.is_null());
+  EXPECT_TRUE(callback_a_.Equals(null_callback_));
+}
+
+struct TestForReentrancy {
+  TestForReentrancy()
+      : cb_already_run(false),
+        cb(Bind(&TestForReentrancy::AssertCBIsNull, Unretained(this))) {
+  }
+  void AssertCBIsNull() {
+    ASSERT_TRUE(cb.is_null());
+    cb_already_run = true;
+  }
+  bool cb_already_run;
+  Closure cb;
+};
+
+TEST_F(CallbackTest, ResetAndReturn) {
+  TestForReentrancy tfr;
+  ASSERT_FALSE(tfr.cb.is_null());
+  ASSERT_FALSE(tfr.cb_already_run);
+  ResetAndReturn(&tfr.cb).Run();
+  ASSERT_TRUE(tfr.cb.is_null());
+  ASSERT_TRUE(tfr.cb_already_run);
+}
+
+class CallbackOwner : public base::RefCounted<CallbackOwner> {
+ public:
+  explicit CallbackOwner(bool* deleted) {
+    callback_ = Bind(&CallbackOwner::Unused, this);
+    deleted_ = deleted;
+  }
+  void Reset() {
+    callback_.Reset();
+    // We are deleted here if no-one else had a ref to us.
+  }
+
+ private:
+  friend class base::RefCounted<CallbackOwner>;
+  virtual ~CallbackOwner() {
+    *deleted_ = true;
+  }
+  void Unused() {
+    FAIL() << "Should never be called";
+  }
+
+  Closure callback_;
+  bool* deleted_;
+};
+
+TEST_F(CallbackTest, CallbackHasLastRefOnContainingObject) {
+  bool deleted = false;
+  CallbackOwner* owner = new CallbackOwner(&deleted);
+  owner->Reset();
+  ASSERT_TRUE(deleted);
+}
+
+}  // namespace
+}  // namespace base
diff --git a/base/callback_unittest.nc b/base/callback_unittest.nc
new file mode 100644
index 0000000..e7607d9
--- /dev/null
+++ b/base/callback_unittest.nc
@@ -0,0 +1,50 @@
+// Copyright (c) 2011 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/callback.h"
+
+namespace base {
+
+class Parent {
+};
+
+class Child : Parent {
+};
+
+#if defined(NCTEST_EQUALS_REQUIRES_SAMETYPE)  // [r"fatal error: no viable conversion from 'Callback<int \(\)>' to 'const Callback<void \(\)>'"]
+
+// Attempting to call comparison function on two callbacks of different type.
+//
+// This should be a compile time failure because each callback type should be
+// considered distinct.
+void WontCompile() {
+  Closure c1;
+  Callback<int(void)> c2;
+  c1.Equals(c2);
+}
+
+#elif defined(NCTEST_CONSTRUCTION_FROM_SUBTYPE)  // [r"fatal error: no viable conversion from 'Callback<base::Parent \(\)>' to 'Callback<base::Child \(\)>'"]
+
+// Construction of Callback<A> from Callback<B> if A is supertype of B.
+//
+// While this is technically safe, most people aren't used to it when coding
+// C++ so if this is happening, it is almost certainly an error.
+void WontCompile() {
+  Callback<Parent(void)> cb_a;
+  Callback<Child(void)> cb_b = cb_a;
+}
+
+#elif defined(NCTEST_ASSIGNMENT_FROM_SUBTYPE)  // [r"fatal error: no viable overloaded '='"]
+
+// Assignment of Callback<A> from Callback<B> if A is supertype of B.
+// See explanation for NCTEST_CONSTRUCTION_FROM_SUBTYPE
+void WontCompile() {
+  Callback<Parent(void)> cb_a;
+  Callback<Child(void)> cb_b;
+  cb_a = cb_b;
+}
+
+#endif
+
+}  // namespace base
diff --git a/base/cancelable_callback.h b/base/cancelable_callback.h
new file mode 100644
index 0000000..2b9d260
--- /dev/null
+++ b/base/cancelable_callback.h
@@ -0,0 +1,131 @@
+// Copyright (c) 2011 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.
+//
+// CancelableCallback is a wrapper around base::Callback that allows
+// cancellation of a callback. CancelableCallback takes a reference on the
+// wrapped callback until this object is destroyed or Reset()/Cancel() are
+// called.
+//
+// NOTE:
+//
+// Calling CancelableCallback::Cancel() brings the object back to its natural,
+// default-constructed state, i.e., CancelableCallback::callback() will return
+// a null callback.
+//
+// THREAD-SAFETY:
+//
+// CancelableCallback objects must be created on, posted to, cancelled on, and
+// destroyed on the same thread.
+//
+//
+// EXAMPLE USAGE:
+//
+// In the following example, the test is verifying that RunIntensiveTest()
+// Quit()s the message loop within 4 seconds. The cancelable callback is posted
+// to the message loop, the intensive test runs, the message loop is run,
+// then the callback is cancelled.
+//
+// void TimeoutCallback(const std::string& timeout_message) {
+//   FAIL() << timeout_message;
+//   MessageLoop::current()->QuitWhenIdle();
+// }
+//
+// CancelableClosure timeout(base::Bind(&TimeoutCallback, "Test timed out."));
+// MessageLoop::current()->PostDelayedTask(FROM_HERE, timeout.callback(),
+//                                         4000)  // 4 seconds to run.
+// RunIntensiveTest();
+// MessageLoop::current()->Run();
+// timeout.Cancel();  // Hopefully this is hit before the timeout callback runs.
+//
+
+#ifndef BASE_CANCELABLE_CALLBACK_H_
+#define BASE_CANCELABLE_CALLBACK_H_
+
+#include "base/base_export.h"
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/callback_internal.h"
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/memory/weak_ptr.h"
+
+namespace base {
+
+template <typename Sig>
+class CancelableCallback;
+
+template <typename... A>
+class CancelableCallback<void(A...)> {
+ public:
+  CancelableCallback() : weak_factory_(this) {}
+
+  // |callback| must not be null.
+  explicit CancelableCallback(const base::Callback<void(A...)>& callback)
+      : callback_(callback), weak_factory_(this) {
+    DCHECK(!callback.is_null());
+    InitializeForwarder();
+  }
+
+  ~CancelableCallback() {}
+
+  // Cancels and drops the reference to the wrapped callback.
+  void Cancel() {
+    weak_factory_.InvalidateWeakPtrs();
+    forwarder_.Reset();
+    callback_.Reset();
+  }
+
+  // Returns true if the wrapped callback has been cancelled.
+  bool IsCancelled() const {
+    return callback_.is_null();
+  }
+
+  // Sets |callback| as the closure that may be cancelled. |callback| may not
+  // be null. Outstanding and any previously wrapped callbacks are cancelled.
+  void Reset(const base::Callback<void(A...)>& callback) {
+    DCHECK(!callback.is_null());
+
+    // Outstanding tasks (e.g., posted to a message loop) must not be called.
+    Cancel();
+
+    // |forwarder_| is no longer valid after Cancel(), so re-bind.
+    InitializeForwarder();
+
+    callback_ = callback;
+  }
+
+  // Returns a callback that can be disabled by calling Cancel().
+  const base::Callback<void(A...)>& callback() const {
+    return forwarder_;
+  }
+
+ private:
+  void Forward(A... args) const {
+    callback_.Run(args...);
+  }
+
+  // Helper method to bind |forwarder_| using a weak pointer from
+  // |weak_factory_|.
+  void InitializeForwarder() {
+    forwarder_ = base::Bind(&CancelableCallback<void(A...)>::Forward,
+                            weak_factory_.GetWeakPtr());
+  }
+
+  // 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);
+};
+
+typedef CancelableCallback<void(void)> CancelableClosure;
+
+}  // namespace base
+
+#endif  // BASE_CANCELABLE_CALLBACK_H_
diff --git a/base/cancelable_callback_unittest.cc b/base/cancelable_callback_unittest.cc
new file mode 100644
index 0000000..6d0a114
--- /dev/null
+++ b/base/cancelable_callback_unittest.cc
@@ -0,0 +1,186 @@
+// Copyright (c) 2011 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/cancelable_callback.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/location.h"
+#include "base/memory/ref_counted.h"
+#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+class TestRefCounted : public RefCountedThreadSafe<TestRefCounted> {
+ private:
+  friend class RefCountedThreadSafe<TestRefCounted>;
+  ~TestRefCounted() {};
+};
+
+void Increment(int* count) { (*count)++; }
+void IncrementBy(int* count, int n) { (*count) += n; }
+void RefCountedParam(const scoped_refptr<TestRefCounted>& ref_counted) {}
+
+// Cancel().
+//  - Callback can be run multiple times.
+//  - After Cancel(), Run() completes but has no effect.
+TEST(CancelableCallbackTest, Cancel) {
+  int count = 0;
+  CancelableClosure cancelable(
+      base::Bind(&Increment, base::Unretained(&count)));
+
+  base::Closure callback = cancelable.callback();
+  callback.Run();
+  EXPECT_EQ(1, count);
+
+  callback.Run();
+  EXPECT_EQ(2, count);
+
+  cancelable.Cancel();
+  callback.Run();
+  EXPECT_EQ(2, count);
+}
+
+// Cancel() called multiple times.
+//  - Cancel() cancels all copies of the wrapped callback.
+//  - Calling Cancel() more than once has no effect.
+//  - After Cancel(), callback() returns a null callback.
+TEST(CancelableCallbackTest, MultipleCancel) {
+  int count = 0;
+  CancelableClosure cancelable(
+      base::Bind(&Increment, base::Unretained(&count)));
+
+  base::Closure callback1 = cancelable.callback();
+  base::Closure callback2 = cancelable.callback();
+  cancelable.Cancel();
+
+  callback1.Run();
+  EXPECT_EQ(0, count);
+
+  callback2.Run();
+  EXPECT_EQ(0, count);
+
+  // Calling Cancel() again has no effect.
+  cancelable.Cancel();
+
+  // callback() of a cancelled callback is null.
+  base::Closure callback3 = cancelable.callback();
+  EXPECT_TRUE(callback3.is_null());
+}
+
+// CancelableCallback destroyed before callback is run.
+//  - Destruction of CancelableCallback cancels outstanding callbacks.
+TEST(CancelableCallbackTest, CallbackCanceledOnDestruction) {
+  int count = 0;
+  base::Closure callback;
+
+  {
+    CancelableClosure cancelable(
+        base::Bind(&Increment, base::Unretained(&count)));
+
+    callback = cancelable.callback();
+    callback.Run();
+    EXPECT_EQ(1, count);
+  }
+
+  callback.Run();
+  EXPECT_EQ(1, count);
+}
+
+// Cancel() called on bound closure with a RefCounted parameter.
+//  - Cancel drops wrapped callback (and, implicitly, its bound arguments).
+TEST(CancelableCallbackTest, CancelDropsCallback) {
+  scoped_refptr<TestRefCounted> ref_counted = new TestRefCounted;
+  EXPECT_TRUE(ref_counted->HasOneRef());
+
+  CancelableClosure cancelable(base::Bind(RefCountedParam, ref_counted));
+  EXPECT_FALSE(cancelable.IsCancelled());
+  EXPECT_TRUE(ref_counted.get());
+  EXPECT_FALSE(ref_counted->HasOneRef());
+
+  // There is only one reference to |ref_counted| after the Cancel().
+  cancelable.Cancel();
+  EXPECT_TRUE(cancelable.IsCancelled());
+  EXPECT_TRUE(ref_counted.get());
+  EXPECT_TRUE(ref_counted->HasOneRef());
+}
+
+// Reset().
+//  - Reset() replaces the existing wrapped callback with a new callback.
+//  - Reset() deactivates outstanding callbacks.
+TEST(CancelableCallbackTest, Reset) {
+  int count = 0;
+  CancelableClosure cancelable(
+      base::Bind(&Increment, base::Unretained(&count)));
+
+  base::Closure callback = cancelable.callback();
+  callback.Run();
+  EXPECT_EQ(1, count);
+
+  callback.Run();
+  EXPECT_EQ(2, count);
+
+  cancelable.Reset(
+      base::Bind(&IncrementBy, base::Unretained(&count), 3));
+  EXPECT_FALSE(cancelable.IsCancelled());
+
+  // The stale copy of the cancelable callback is non-null.
+  ASSERT_FALSE(callback.is_null());
+
+  // The stale copy of the cancelable callback is no longer active.
+  callback.Run();
+  EXPECT_EQ(2, count);
+
+  base::Closure callback2 = cancelable.callback();
+  ASSERT_FALSE(callback2.is_null());
+
+  callback2.Run();
+  EXPECT_EQ(5, count);
+}
+
+// IsCanceled().
+//  - Cancel() transforms the CancelableCallback into a cancelled state.
+TEST(CancelableCallbackTest, IsNull) {
+  CancelableClosure cancelable;
+  EXPECT_TRUE(cancelable.IsCancelled());
+
+  int count = 0;
+  cancelable.Reset(base::Bind(&Increment,
+                              base::Unretained(&count)));
+  EXPECT_FALSE(cancelable.IsCancelled());
+
+  cancelable.Cancel();
+  EXPECT_TRUE(cancelable.IsCancelled());
+}
+
+// CancelableCallback posted to a MessageLoop with PostTask.
+//  - Callbacks posted to a MessageLoop can be cancelled.
+TEST(CancelableCallbackTest, PostTask) {
+  MessageLoop loop;
+
+  int count = 0;
+  CancelableClosure cancelable(base::Bind(&Increment,
+                                           base::Unretained(&count)));
+
+  ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, cancelable.callback());
+  RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(1, count);
+
+  ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, cancelable.callback());
+
+  // Cancel before running the message loop.
+  cancelable.Cancel();
+  RunLoop().RunUntilIdle();
+
+  // Callback never ran due to cancellation; count is the same.
+  EXPECT_EQ(1, count);
+}
+
+}  // namespace
+}  // namespace base
diff --git a/base/check_example.cc b/base/check_example.cc
new file mode 100644
index 0000000..4b3f428
--- /dev/null
+++ b/base/check_example.cc
@@ -0,0 +1,25 @@
+// Copyright (c) 2011 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 meant for analyzing the code generated by the CHECK
+// macros in a small executable file that's easy to disassemble.
+
+#include "base/logging.h"
+
+// An official build shouldn't generate code to print out messages for
+// the CHECK* macros, nor should it have the strings in the
+// executable.
+
+void DoCheck(bool b) {
+  CHECK(b) << "DoCheck " << b;
+}
+
+void DoCheckEq(int x, int y) {
+  CHECK_EQ(x, y);
+}
+
+int main(int argc, const char* argv[]) {
+  DoCheck(argc > 1);
+  DoCheckEq(argc, 1);
+}
diff --git a/base/command_line.cc b/base/command_line.cc
new file mode 100644
index 0000000..3fcf22a
--- /dev/null
+++ b/base/command_line.cc
@@ -0,0 +1,473 @@
+// Copyright (c) 2012 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/command_line.h"
+
+#include <algorithm>
+#include <ostream>
+
+#include "base/basictypes.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#include <shellapi.h>
+#endif
+
+namespace base {
+
+CommandLine* CommandLine::current_process_commandline_ = NULL;
+
+namespace {
+
+const CommandLine::CharType kSwitchTerminator[] = FILE_PATH_LITERAL("--");
+const CommandLine::CharType kSwitchValueSeparator[] = FILE_PATH_LITERAL("=");
+
+// Since we use a lazy match, make sure that longer versions (like "--") are
+// listed before shorter versions (like "-") of similar prefixes.
+#if defined(OS_WIN)
+// By putting slash last, we can control whether it is treaded as a switch
+// value by changing the value of switch_prefix_count to be one less than
+// the array size.
+const CommandLine::CharType* const kSwitchPrefixes[] = {L"--", L"-", L"/"};
+#elif defined(OS_POSIX)
+// Unixes don't use slash as a switch.
+const CommandLine::CharType* const kSwitchPrefixes[] = {"--", "-"};
+#endif
+size_t switch_prefix_count = arraysize(kSwitchPrefixes);
+
+size_t GetSwitchPrefixLength(const CommandLine::StringType& string) {
+  for (size_t i = 0; i < switch_prefix_count; ++i) {
+    CommandLine::StringType prefix(kSwitchPrefixes[i]);
+    if (string.compare(0, prefix.length(), prefix) == 0)
+      return prefix.length();
+  }
+  return 0;
+}
+
+// Fills in |switch_string| and |switch_value| if |string| is a switch.
+// This will preserve the input switch prefix in the output |switch_string|.
+bool IsSwitch(const CommandLine::StringType& string,
+              CommandLine::StringType* switch_string,
+              CommandLine::StringType* switch_value) {
+  switch_string->clear();
+  switch_value->clear();
+  size_t prefix_length = GetSwitchPrefixLength(string);
+  if (prefix_length == 0 || prefix_length == string.length())
+    return false;
+
+  const size_t equals_position = string.find(kSwitchValueSeparator);
+  *switch_string = string.substr(0, equals_position);
+  if (equals_position != CommandLine::StringType::npos)
+    *switch_value = string.substr(equals_position + 1);
+  return true;
+}
+
+// Append switches and arguments, keeping switches before arguments.
+void AppendSwitchesAndArguments(CommandLine* command_line,
+                                const CommandLine::StringVector& argv) {
+  bool parse_switches = true;
+  for (size_t i = 1; i < argv.size(); ++i) {
+    CommandLine::StringType arg = argv[i];
+    TrimWhitespace(arg, TRIM_ALL, &arg);
+
+    CommandLine::StringType switch_string;
+    CommandLine::StringType switch_value;
+    parse_switches &= (arg != kSwitchTerminator);
+    if (parse_switches && IsSwitch(arg, &switch_string, &switch_value)) {
+#if defined(OS_WIN)
+      command_line->AppendSwitchNative(UTF16ToASCII(switch_string),
+                                       switch_value);
+#elif defined(OS_POSIX)
+      command_line->AppendSwitchNative(switch_string, switch_value);
+#endif
+    } else {
+      command_line->AppendArgNative(arg);
+    }
+  }
+}
+
+#if defined(OS_WIN)
+// Quote a string as necessary for CommandLineToArgvW compatiblity *on Windows*.
+string16 QuoteForCommandLineToArgvW(const string16& arg,
+                                    bool quote_placeholders) {
+  // We follow the quoting rules of CommandLineToArgvW.
+  // http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
+  string16 quotable_chars(L" \\\"");
+  // We may also be required to quote '%', which is commonly used in a command
+  // line as a placeholder. (It may be substituted for a string with spaces.)
+  if (quote_placeholders)
+    quotable_chars.push_back(L'%');
+  if (arg.find_first_of(quotable_chars) == string16::npos) {
+    // No quoting necessary.
+    return arg;
+  }
+
+  string16 out;
+  out.push_back(L'"');
+  for (size_t i = 0; i < arg.size(); ++i) {
+    if (arg[i] == '\\') {
+      // Find the extent of this run of backslashes.
+      size_t start = i, end = start + 1;
+      for (; end < arg.size() && arg[end] == '\\'; ++end) {}
+      size_t backslash_count = end - start;
+
+      // Backslashes are escapes only if the run is followed by a double quote.
+      // Since we also will end the string with a double quote, we escape for
+      // either a double quote or the end of the string.
+      if (end == arg.size() || arg[end] == '"') {
+        // To quote, we need to output 2x as many backslashes.
+        backslash_count *= 2;
+      }
+      for (size_t j = 0; j < backslash_count; ++j)
+        out.push_back('\\');
+
+      // Advance i to one before the end to balance i++ in loop.
+      i = end - 1;
+    } else if (arg[i] == '"') {
+      out.push_back('\\');
+      out.push_back('"');
+    } else {
+      out.push_back(arg[i]);
+    }
+  }
+  out.push_back('"');
+
+  return out;
+}
+#endif
+
+}  // namespace
+
+CommandLine::CommandLine(NoProgram no_program)
+    : argv_(1),
+      begin_args_(1) {
+}
+
+CommandLine::CommandLine(const FilePath& program)
+    : argv_(1),
+      begin_args_(1) {
+  SetProgram(program);
+}
+
+CommandLine::CommandLine(int argc, const CommandLine::CharType* const* argv)
+    : argv_(1),
+      begin_args_(1) {
+  InitFromArgv(argc, argv);
+}
+
+CommandLine::CommandLine(const StringVector& argv)
+    : argv_(1),
+      begin_args_(1) {
+  InitFromArgv(argv);
+}
+
+CommandLine::CommandLine(const CommandLine& other)
+    : argv_(other.argv_),
+      switches_(other.switches_),
+      begin_args_(other.begin_args_) {
+  ResetStringPieces();
+}
+
+CommandLine& CommandLine::operator=(const CommandLine& other) {
+  argv_ = other.argv_;
+  switches_ = other.switches_;
+  begin_args_ = other.begin_args_;
+  ResetStringPieces();
+  return *this;
+}
+
+CommandLine::~CommandLine() {
+}
+
+#if defined(OS_WIN)
+// static
+void CommandLine::set_slash_is_not_a_switch() {
+  // The last switch prefix should be slash, so adjust the size to skip it.
+  DCHECK_EQ(wcscmp(kSwitchPrefixes[arraysize(kSwitchPrefixes) - 1], L"/"), 0);
+  switch_prefix_count = arraysize(kSwitchPrefixes) - 1;
+}
+#endif
+
+// static
+bool CommandLine::Init(int argc, const char* const* argv) {
+  if (current_process_commandline_) {
+    // If this is intentional, Reset() must be called first. If we are using
+    // the shared build mode, we have to share a single object across multiple
+    // shared libraries.
+    return false;
+  }
+
+  current_process_commandline_ = new CommandLine(NO_PROGRAM);
+#if defined(OS_WIN)
+  current_process_commandline_->ParseFromString(::GetCommandLineW());
+#elif defined(OS_POSIX)
+  current_process_commandline_->InitFromArgv(argc, argv);
+#endif
+
+  return true;
+}
+
+// static
+void CommandLine::Reset() {
+  DCHECK(current_process_commandline_);
+  delete current_process_commandline_;
+  current_process_commandline_ = NULL;
+}
+
+// static
+CommandLine* CommandLine::ForCurrentProcess() {
+  DCHECK(current_process_commandline_);
+  return current_process_commandline_;
+}
+
+// static
+bool CommandLine::InitializedForCurrentProcess() {
+  return !!current_process_commandline_;
+}
+
+#if defined(OS_WIN)
+// static
+CommandLine CommandLine::FromString(const string16& command_line) {
+  CommandLine cmd(NO_PROGRAM);
+  cmd.ParseFromString(command_line);
+  return cmd;
+}
+#endif
+
+void CommandLine::InitFromArgv(int argc,
+                               const CommandLine::CharType* const* argv) {
+  StringVector new_argv;
+  for (int i = 0; i < argc; ++i)
+    new_argv.push_back(argv[i]);
+  InitFromArgv(new_argv);
+}
+
+void CommandLine::InitFromArgv(const StringVector& argv) {
+  argv_ = StringVector(1);
+  switches_.clear();
+  switches_by_stringpiece_.clear();
+  begin_args_ = 1;
+  SetProgram(argv.empty() ? FilePath() : FilePath(argv[0]));
+  AppendSwitchesAndArguments(this, argv);
+}
+
+FilePath CommandLine::GetProgram() const {
+  return FilePath(argv_[0]);
+}
+
+void CommandLine::SetProgram(const FilePath& program) {
+  TrimWhitespace(program.value(), TRIM_ALL, &argv_[0]);
+}
+
+bool CommandLine::HasSwitch(const base::StringPiece& switch_string) const {
+  DCHECK_EQ(StringToLowerASCII(switch_string.as_string()), switch_string);
+  return switches_by_stringpiece_.find(switch_string) !=
+         switches_by_stringpiece_.end();
+}
+
+bool CommandLine::HasSwitch(const char switch_constant[]) const {
+  return HasSwitch(base::StringPiece(switch_constant));
+}
+
+std::string CommandLine::GetSwitchValueASCII(
+    const base::StringPiece& switch_string) const {
+  StringType value = GetSwitchValueNative(switch_string);
+  if (!IsStringASCII(value)) {
+    DLOG(WARNING) << "Value of switch (" << switch_string << ") must be ASCII.";
+    return std::string();
+  }
+#if defined(OS_WIN)
+  return UTF16ToASCII(value);
+#else
+  return value;
+#endif
+}
+
+FilePath CommandLine::GetSwitchValuePath(
+    const base::StringPiece& switch_string) const {
+  return FilePath(GetSwitchValueNative(switch_string));
+}
+
+CommandLine::StringType CommandLine::GetSwitchValueNative(
+    const base::StringPiece& switch_string) const {
+  DCHECK_EQ(StringToLowerASCII(switch_string.as_string()), switch_string);
+  auto result = switches_by_stringpiece_.find(switch_string);
+  return result == switches_by_stringpiece_.end() ? StringType()
+                                                  : *(result->second);
+}
+
+void CommandLine::AppendSwitch(const std::string& switch_string) {
+  AppendSwitchNative(switch_string, StringType());
+}
+
+void CommandLine::AppendSwitchPath(const std::string& switch_string,
+                                   const FilePath& path) {
+  AppendSwitchNative(switch_string, path.value());
+}
+
+void CommandLine::AppendSwitchNative(const std::string& switch_string,
+                                     const CommandLine::StringType& value) {
+#if defined(OS_WIN)
+  const std::string switch_key = StringToLowerASCII(switch_string);
+  StringType combined_switch_string(ASCIIToUTF16(switch_key));
+#elif defined(OS_POSIX)
+  const std::string& switch_key = switch_string;
+  StringType combined_switch_string(switch_key);
+#endif
+  size_t prefix_length = GetSwitchPrefixLength(combined_switch_string);
+  auto insertion =
+      switches_.insert(make_pair(switch_key.substr(prefix_length), value));
+  if (!insertion.second)
+    insertion.first->second = value;
+  switches_by_stringpiece_[insertion.first->first] = &(insertion.first->second);
+  // Preserve existing switch prefixes in |argv_|; only append one if necessary.
+  if (prefix_length == 0)
+    combined_switch_string = kSwitchPrefixes[0] + combined_switch_string;
+  if (!value.empty())
+    combined_switch_string += kSwitchValueSeparator + value;
+  // Append the switch and update the switches/arguments divider |begin_args_|.
+  argv_.insert(argv_.begin() + begin_args_++, combined_switch_string);
+}
+
+void CommandLine::AppendSwitchASCII(const std::string& switch_string,
+                                    const std::string& value_string) {
+#if defined(OS_WIN)
+  AppendSwitchNative(switch_string, ASCIIToUTF16(value_string));
+#elif defined(OS_POSIX)
+  AppendSwitchNative(switch_string, value_string);
+#endif
+}
+
+void CommandLine::CopySwitchesFrom(const CommandLine& source,
+                                   const char* const switches[],
+                                   size_t count) {
+  for (size_t i = 0; i < count; ++i) {
+    if (source.HasSwitch(switches[i]))
+      AppendSwitchNative(switches[i], source.GetSwitchValueNative(switches[i]));
+  }
+}
+
+CommandLine::StringVector CommandLine::GetArgs() const {
+  // Gather all arguments after the last switch (may include kSwitchTerminator).
+  StringVector args(argv_.begin() + begin_args_, argv_.end());
+  // Erase only the first kSwitchTerminator (maybe "--" is a legitimate page?)
+  StringVector::iterator switch_terminator =
+      std::find(args.begin(), args.end(), kSwitchTerminator);
+  if (switch_terminator != args.end())
+    args.erase(switch_terminator);
+  return args;
+}
+
+void CommandLine::AppendArg(const std::string& value) {
+#if defined(OS_WIN)
+  DCHECK(IsStringUTF8(value));
+  AppendArgNative(UTF8ToWide(value));
+#elif defined(OS_POSIX)
+  AppendArgNative(value);
+#endif
+}
+
+void CommandLine::AppendArgPath(const FilePath& path) {
+  AppendArgNative(path.value());
+}
+
+void CommandLine::AppendArgNative(const CommandLine::StringType& value) {
+  argv_.push_back(value);
+}
+
+void CommandLine::AppendArguments(const CommandLine& other,
+                                  bool include_program) {
+  if (include_program)
+    SetProgram(other.GetProgram());
+  AppendSwitchesAndArguments(this, other.argv());
+}
+
+void CommandLine::PrependWrapper(const CommandLine::StringType& wrapper) {
+  if (wrapper.empty())
+    return;
+  // The wrapper may have embedded arguments (like "gdb --args"). In this case,
+  // we don't pretend to do anything fancy, we just split on spaces.
+  StringVector wrapper_argv;
+  SplitString(wrapper, FILE_PATH_LITERAL(' '), &wrapper_argv);
+  // Prepend the wrapper and update the switches/arguments |begin_args_|.
+  argv_.insert(argv_.begin(), wrapper_argv.begin(), wrapper_argv.end());
+  begin_args_ += wrapper_argv.size();
+}
+
+#if defined(OS_WIN)
+void CommandLine::ParseFromString(const string16& command_line) {
+  string16 command_line_string;
+  TrimWhitespace(command_line, TRIM_ALL, &command_line_string);
+  if (command_line_string.empty())
+    return;
+
+  int num_args = 0;
+  wchar_t** args = NULL;
+  args = ::CommandLineToArgvW(command_line_string.c_str(), &num_args);
+
+  DPLOG_IF(FATAL, !args) << "CommandLineToArgvW failed on command line: "
+                         << UTF16ToUTF8(command_line);
+  InitFromArgv(num_args, args);
+  LocalFree(args);
+}
+#endif
+
+CommandLine::StringType CommandLine::GetCommandLineStringInternal(
+    bool quote_placeholders) const {
+  StringType string(argv_[0]);
+#if defined(OS_WIN)
+  string = QuoteForCommandLineToArgvW(string, quote_placeholders);
+#endif
+  StringType params(GetArgumentsStringInternal(quote_placeholders));
+  if (!params.empty()) {
+    string.append(StringType(FILE_PATH_LITERAL(" ")));
+    string.append(params);
+  }
+  return string;
+}
+
+CommandLine::StringType CommandLine::GetArgumentsStringInternal(
+    bool quote_placeholders) const {
+  StringType params;
+  // Append switches and arguments.
+  bool parse_switches = true;
+  for (size_t i = 1; i < argv_.size(); ++i) {
+    StringType arg = argv_[i];
+    StringType switch_string;
+    StringType switch_value;
+    parse_switches &= arg != kSwitchTerminator;
+    if (i > 1)
+      params.append(StringType(FILE_PATH_LITERAL(" ")));
+    if (parse_switches && IsSwitch(arg, &switch_string, &switch_value)) {
+      params.append(switch_string);
+      if (!switch_value.empty()) {
+#if defined(OS_WIN)
+        switch_value =
+            QuoteForCommandLineToArgvW(switch_value, quote_placeholders);
+#endif
+        params.append(kSwitchValueSeparator + switch_value);
+      }
+    } else {
+#if defined(OS_WIN)
+      arg = QuoteForCommandLineToArgvW(arg, quote_placeholders);
+#endif
+      params.append(arg);
+    }
+  }
+  return params;
+}
+
+void CommandLine::ResetStringPieces() {
+  switches_by_stringpiece_.clear();
+  for (const auto& entry : switches_)
+    switches_by_stringpiece_[entry.first] = &(entry.second);
+}
+
+}  // namespace base
diff --git a/base/command_line.h b/base/command_line.h
new file mode 100644
index 0000000..3de8873
--- /dev/null
+++ b/base/command_line.h
@@ -0,0 +1,251 @@
+// Copyright (c) 2012 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 class works with command lines: building and parsing.
+// Arguments with prefixes ('--', '-', and on Windows, '/') are switches.
+// Switches will precede all other arguments without switch prefixes.
+// Switches can optionally have values, delimited by '=', e.g., "-switch=value".
+// An argument of "--" will terminate switch parsing during initialization,
+// interpreting subsequent tokens as non-switch arguments, regardless of prefix.
+
+// There is a singleton read-only CommandLine that represents the command line
+// that the current process was started with.  It must be initialized in main().
+
+#ifndef BASE_COMMAND_LINE_H_
+#define BASE_COMMAND_LINE_H_
+
+#include <stddef.h>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
+#include "build/build_config.h"
+
+namespace base {
+
+class FilePath;
+
+class BASE_EXPORT CommandLine {
+ public:
+#if defined(OS_WIN)
+  // The native command line string type.
+  typedef base::string16 StringType;
+#elif defined(OS_POSIX)
+  typedef std::string StringType;
+#endif
+
+  typedef StringType::value_type CharType;
+  typedef std::vector<StringType> StringVector;
+  typedef std::map<std::string, StringType> SwitchMap;
+  typedef std::map<base::StringPiece, const StringType*> StringPieceSwitchMap;
+
+  // A constructor for CommandLines that only carry switches and arguments.
+  enum NoProgram { NO_PROGRAM };
+  explicit CommandLine(NoProgram no_program);
+
+  // Construct a new command line with |program| as argv[0].
+  explicit CommandLine(const FilePath& program);
+
+  // Construct a new command line from an argument list.
+  CommandLine(int argc, const CharType* const* argv);
+  explicit CommandLine(const StringVector& argv);
+
+  // Override copy and assign to ensure |switches_by_stringpiece_| is valid.
+  CommandLine(const CommandLine& other);
+  CommandLine& operator=(const CommandLine& other);
+
+  ~CommandLine();
+
+#if defined(OS_WIN)
+  // By default this class will treat command-line arguments beginning with
+  // slashes as switches on Windows, but not other platforms.
+  //
+  // If this behavior is inappropriate for your application, you can call this
+  // function BEFORE initializing the current process' global command line
+  // object and the behavior will be the same as Posix systems (only hyphens
+  // begin switches, everything else will be an arg).
+  static void set_slash_is_not_a_switch();
+#endif
+
+  // Initialize the current process CommandLine singleton. On Windows, ignores
+  // its arguments (we instead parse GetCommandLineW() directly) because we
+  // don't trust the CRT's parsing of the command line, but it still must be
+  // called to set up the command line. Returns false if initialization has
+  // already occurred, and true otherwise. Only the caller receiving a 'true'
+  // return value should take responsibility for calling Reset.
+  static bool Init(int argc, const char* const* argv);
+
+  // Destroys the current process CommandLine singleton. This is necessary if
+  // you want to reset the base library to its initial state (for example, in an
+  // outer library that needs to be able to terminate, and be re-initialized).
+  // If Init is called only once, as in main(), Reset() is not necessary.
+  static void Reset();
+
+  // Get the singleton CommandLine representing the current process's
+  // command line. Note: returned value is mutable, but not thread safe;
+  // only mutate if you know what you're doing!
+  static CommandLine* ForCurrentProcess();
+
+  // Returns true if the CommandLine has been initialized for the given process.
+  static bool InitializedForCurrentProcess();
+
+#if defined(OS_WIN)
+  static CommandLine FromString(const base::string16& command_line);
+#endif
+
+  // Initialize from an argv vector.
+  void InitFromArgv(int argc, const CharType* const* argv);
+  void InitFromArgv(const StringVector& argv);
+
+  // Constructs and returns the represented command line string.
+  // CAUTION! This should be avoided on POSIX because quoting behavior is
+  // unclear.
+  StringType GetCommandLineString() const {
+    return GetCommandLineStringInternal(false);
+  }
+
+#if defined(OS_WIN)
+  // Constructs and returns the represented command line string. Assumes the
+  // command line contains placeholders (eg, %1) and quotes any program or
+  // argument with a '%' in it. This should be avoided unless the placeholder is
+  // required by an external interface (eg, the Windows registry), because it is
+  // not generally safe to replace it with an arbitrary string. If possible,
+  // placeholders should be replaced *before* converting the command line to a
+  // string.
+  StringType GetCommandLineStringWithPlaceholders() const {
+    return GetCommandLineStringInternal(true);
+  }
+#endif
+
+  // Constructs and returns the represented arguments string.
+  // CAUTION! This should be avoided on POSIX because quoting behavior is
+  // unclear.
+  StringType GetArgumentsString() const {
+    return GetArgumentsStringInternal(false);
+  }
+
+#if defined(OS_WIN)
+  // Constructs and returns the represented arguments string. Assumes the
+  // command line contains placeholders (eg, %1) and quotes any argument with a
+  // '%' in it. This should be avoided unless the placeholder is required by an
+  // external interface (eg, the Windows registry), because it is not generally
+  // safe to replace it with an arbitrary string. If possible, placeholders
+  // should be replaced *before* converting the arguments to a string.
+  StringType GetArgumentsStringWithPlaceholders() const {
+    return GetArgumentsStringInternal(true);
+  }
+#endif
+
+  // Returns the original command line string as a vector of strings.
+  const StringVector& argv() const { return argv_; }
+
+  // Get and Set the program part of the command line string (the first item).
+  FilePath GetProgram() const;
+  void SetProgram(const FilePath& program);
+
+  // Returns true if this command line contains the given switch.
+  // Switch names must be lowercase.
+  // The second override provides an optimized version to avoid inlining codegen
+  // at every callsite to find the length of the constant and construct a
+  // StringPiece.
+  bool HasSwitch(const base::StringPiece& switch_string) const;
+  bool HasSwitch(const char switch_constant[]) const;
+
+  // Returns the value associated with the given switch. If the switch has no
+  // value or isn't present, this method returns the empty string.
+  // Switch names must be lowercase.
+  std::string GetSwitchValueASCII(const base::StringPiece& switch_string) const;
+  FilePath GetSwitchValuePath(const base::StringPiece& switch_string) const;
+  StringType GetSwitchValueNative(const base::StringPiece& switch_string) const;
+
+  // Get a copy of all switches, along with their values.
+  const SwitchMap& GetSwitches() const { return switches_; }
+
+  // Append a switch [with optional value] to the command line.
+  // Note: Switches will precede arguments regardless of appending order.
+  void AppendSwitch(const std::string& switch_string);
+  void AppendSwitchPath(const std::string& switch_string,
+                        const FilePath& path);
+  void AppendSwitchNative(const std::string& switch_string,
+                          const StringType& value);
+  void AppendSwitchASCII(const std::string& switch_string,
+                         const std::string& value);
+
+  // Copy a set of switches (and any values) from another command line.
+  // Commonly used when launching a subprocess.
+  void CopySwitchesFrom(const CommandLine& source,
+                        const char* const switches[],
+                        size_t count);
+
+  // Get the remaining arguments to the command.
+  StringVector GetArgs() const;
+
+  // Append an argument to the command line. Note that the argument is quoted
+  // properly such that it is interpreted as one argument to the target command.
+  // AppendArg is primarily for ASCII; non-ASCII input is interpreted as UTF-8.
+  // Note: Switches will precede arguments regardless of appending order.
+  void AppendArg(const std::string& value);
+  void AppendArgPath(const FilePath& value);
+  void AppendArgNative(const StringType& value);
+
+  // Append the switches and arguments from another command line to this one.
+  // If |include_program| is true, include |other|'s program as well.
+  void AppendArguments(const CommandLine& other, bool include_program);
+
+  // Insert a command before the current command.
+  // Common for debuggers, like "valgrind" or "gdb --args".
+  void PrependWrapper(const StringType& wrapper);
+
+#if defined(OS_WIN)
+  // Initialize by parsing the given command line string.
+  // The program name is assumed to be the first item in the string.
+  void ParseFromString(const base::string16& command_line);
+#endif
+
+ private:
+  // Disallow default constructor; a program name must be explicitly specified.
+  CommandLine();
+  // Allow the copy constructor. A common pattern is to copy of the current
+  // process's command line and then add some flags to it. For example:
+  //   CommandLine cl(*CommandLine::ForCurrentProcess());
+  //   cl.AppendSwitch(...);
+
+  // Internal version of GetCommandLineString. If |quote_placeholders| is true,
+  // also quotes parts with '%' in them.
+  StringType GetCommandLineStringInternal(bool quote_placeholders) const;
+
+  // Internal version of GetArgumentsString. If |quote_placeholders| is true,
+  // also quotes parts with '%' in them.
+  StringType GetArgumentsStringInternal(bool quote_placeholders) const;
+
+  // Reconstruct |switches_by_stringpiece| to be a mirror of |switches|.
+  // |switches_by_stringpiece| only contains pointers to objects owned by
+  // |switches|.
+  void ResetStringPieces();
+
+  // The singleton CommandLine representing the current process's command line.
+  static CommandLine* current_process_commandline_;
+
+  // The argv array: { program, [(--|-|/)switch[=value]]*, [--], [argument]* }
+  StringVector argv_;
+
+  // Parsed-out switch keys and values.
+  SwitchMap switches_;
+
+  // A mirror of |switches_| with only references to the actual strings.
+  // The StringPiece internally holds a pointer to a key in |switches_| while
+  // the mapped_type points to a value in |switches_|.
+  // Used for allocation-free lookups.
+  StringPieceSwitchMap switches_by_stringpiece_;
+
+  // The index after the program and switches, any arguments start here.
+  size_t begin_args_;
+};
+
+}  // namespace base
+
+#endif  // BASE_COMMAND_LINE_H_
diff --git a/base/command_line_unittest.cc b/base/command_line_unittest.cc
new file mode 100644
index 0000000..018d83f
--- /dev/null
+++ b/base/command_line_unittest.cc
@@ -0,0 +1,403 @@
+// Copyright (c) 2012 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 <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+// To test Windows quoting behavior, we use a string that has some backslashes
+// and quotes.
+// Consider the command-line argument: q\"bs1\bs2\\bs3q\\\"
+// Here it is with C-style escapes.
+static const CommandLine::StringType kTrickyQuoted =
+    FILE_PATH_LITERAL("q\\\"bs1\\bs2\\\\bs3q\\\\\\\"");
+// It should be parsed by Windows as: q"bs1\bs2\\bs3q\"
+// Here that is with C-style escapes.
+static const CommandLine::StringType kTricky =
+    FILE_PATH_LITERAL("q\"bs1\\bs2\\\\bs3q\\\"");
+
+TEST(CommandLineTest, CommandLineConstructor) {
+  const CommandLine::CharType* argv[] = {
+      FILE_PATH_LITERAL("program"),
+      FILE_PATH_LITERAL("--foo="),
+      FILE_PATH_LITERAL("-bAr"),
+      FILE_PATH_LITERAL("-spaetzel=pierogi"),
+      FILE_PATH_LITERAL("-baz"),
+      FILE_PATH_LITERAL("flim"),
+      FILE_PATH_LITERAL("--other-switches=--dog=canine --cat=feline"),
+      FILE_PATH_LITERAL("-spaetzle=Crepe"),
+      FILE_PATH_LITERAL("-=loosevalue"),
+      FILE_PATH_LITERAL("-"),
+      FILE_PATH_LITERAL("FLAN"),
+      FILE_PATH_LITERAL("a"),
+      FILE_PATH_LITERAL("--input-translation=45--output-rotation"),
+      FILE_PATH_LITERAL("--"),
+      FILE_PATH_LITERAL("--"),
+      FILE_PATH_LITERAL("--not-a-switch"),
+      FILE_PATH_LITERAL("\"in the time of submarines...\""),
+      FILE_PATH_LITERAL("unquoted arg-with-space")};
+  CommandLine cl(arraysize(argv), argv);
+
+  EXPECT_FALSE(cl.GetCommandLineString().empty());
+  EXPECT_FALSE(cl.HasSwitch("cruller"));
+  EXPECT_FALSE(cl.HasSwitch("flim"));
+  EXPECT_FALSE(cl.HasSwitch("program"));
+  EXPECT_FALSE(cl.HasSwitch("dog"));
+  EXPECT_FALSE(cl.HasSwitch("cat"));
+  EXPECT_FALSE(cl.HasSwitch("output-rotation"));
+  EXPECT_FALSE(cl.HasSwitch("not-a-switch"));
+  EXPECT_FALSE(cl.HasSwitch("--"));
+
+  EXPECT_EQ(FilePath(FILE_PATH_LITERAL("program")).value(),
+            cl.GetProgram().value());
+
+  EXPECT_TRUE(cl.HasSwitch("foo"));
+#if defined(OS_WIN)
+  EXPECT_TRUE(cl.HasSwitch("bar"));
+#else
+  EXPECT_FALSE(cl.HasSwitch("bar"));
+#endif
+  EXPECT_TRUE(cl.HasSwitch("baz"));
+  EXPECT_TRUE(cl.HasSwitch("spaetzle"));
+  EXPECT_TRUE(cl.HasSwitch("other-switches"));
+  EXPECT_TRUE(cl.HasSwitch("input-translation"));
+
+  EXPECT_EQ("Crepe", cl.GetSwitchValueASCII("spaetzle"));
+  EXPECT_EQ("", cl.GetSwitchValueASCII("foo"));
+  EXPECT_EQ("", cl.GetSwitchValueASCII("bar"));
+  EXPECT_EQ("", cl.GetSwitchValueASCII("cruller"));
+  EXPECT_EQ("--dog=canine --cat=feline", cl.GetSwitchValueASCII(
+      "other-switches"));
+  EXPECT_EQ("45--output-rotation", cl.GetSwitchValueASCII("input-translation"));
+
+  const CommandLine::StringVector& args = cl.GetArgs();
+  ASSERT_EQ(8U, args.size());
+
+  std::vector<CommandLine::StringType>::const_iterator iter = args.begin();
+  EXPECT_EQ(FILE_PATH_LITERAL("flim"), *iter);
+  ++iter;
+  EXPECT_EQ(FILE_PATH_LITERAL("-"), *iter);
+  ++iter;
+  EXPECT_EQ(FILE_PATH_LITERAL("FLAN"), *iter);
+  ++iter;
+  EXPECT_EQ(FILE_PATH_LITERAL("a"), *iter);
+  ++iter;
+  EXPECT_EQ(FILE_PATH_LITERAL("--"), *iter);
+  ++iter;
+  EXPECT_EQ(FILE_PATH_LITERAL("--not-a-switch"), *iter);
+  ++iter;
+  EXPECT_EQ(FILE_PATH_LITERAL("\"in the time of submarines...\""), *iter);
+  ++iter;
+  EXPECT_EQ(FILE_PATH_LITERAL("unquoted arg-with-space"), *iter);
+  ++iter;
+  EXPECT_TRUE(iter == args.end());
+}
+
+TEST(CommandLineTest, CommandLineFromString) {
+#if defined(OS_WIN)
+  CommandLine cl = CommandLine::FromString(
+      L"program --foo= -bAr  /Spaetzel=pierogi /Baz flim "
+      L"--other-switches=\"--dog=canine --cat=feline\" "
+      L"-spaetzle=Crepe   -=loosevalue  FLAN "
+      L"--input-translation=\"45\"--output-rotation "
+      L"--quotes=" + kTrickyQuoted + L" "
+      L"-- -- --not-a-switch "
+      L"\"in the time of submarines...\"");
+
+  EXPECT_FALSE(cl.GetCommandLineString().empty());
+  EXPECT_FALSE(cl.HasSwitch("cruller"));
+  EXPECT_FALSE(cl.HasSwitch("flim"));
+  EXPECT_FALSE(cl.HasSwitch("program"));
+  EXPECT_FALSE(cl.HasSwitch("dog"));
+  EXPECT_FALSE(cl.HasSwitch("cat"));
+  EXPECT_FALSE(cl.HasSwitch("output-rotation"));
+  EXPECT_FALSE(cl.HasSwitch("not-a-switch"));
+  EXPECT_FALSE(cl.HasSwitch("--"));
+
+  EXPECT_EQ(FilePath(FILE_PATH_LITERAL("program")).value(),
+            cl.GetProgram().value());
+
+  EXPECT_TRUE(cl.HasSwitch("foo"));
+  EXPECT_TRUE(cl.HasSwitch("bar"));
+  EXPECT_TRUE(cl.HasSwitch("baz"));
+  EXPECT_TRUE(cl.HasSwitch("spaetzle"));
+  EXPECT_TRUE(cl.HasSwitch("other-switches"));
+  EXPECT_TRUE(cl.HasSwitch("input-translation"));
+  EXPECT_TRUE(cl.HasSwitch("quotes"));
+
+  EXPECT_EQ("Crepe", cl.GetSwitchValueASCII("spaetzle"));
+  EXPECT_EQ("", cl.GetSwitchValueASCII("foo"));
+  EXPECT_EQ("", cl.GetSwitchValueASCII("bar"));
+  EXPECT_EQ("", cl.GetSwitchValueASCII("cruller"));
+  EXPECT_EQ("--dog=canine --cat=feline", cl.GetSwitchValueASCII(
+      "other-switches"));
+  EXPECT_EQ("45--output-rotation", cl.GetSwitchValueASCII("input-translation"));
+  EXPECT_EQ(kTricky, cl.GetSwitchValueNative("quotes"));
+
+  const CommandLine::StringVector& args = cl.GetArgs();
+  ASSERT_EQ(5U, args.size());
+
+  std::vector<CommandLine::StringType>::const_iterator iter = args.begin();
+  EXPECT_EQ(FILE_PATH_LITERAL("flim"), *iter);
+  ++iter;
+  EXPECT_EQ(FILE_PATH_LITERAL("FLAN"), *iter);
+  ++iter;
+  EXPECT_EQ(FILE_PATH_LITERAL("--"), *iter);
+  ++iter;
+  EXPECT_EQ(FILE_PATH_LITERAL("--not-a-switch"), *iter);
+  ++iter;
+  EXPECT_EQ(FILE_PATH_LITERAL("in the time of submarines..."), *iter);
+  ++iter;
+  EXPECT_TRUE(iter == args.end());
+
+  // Check that a generated string produces an equivalent command line.
+  CommandLine cl_duplicate = CommandLine::FromString(cl.GetCommandLineString());
+  EXPECT_EQ(cl.GetCommandLineString(), cl_duplicate.GetCommandLineString());
+#endif
+}
+
+// Tests behavior with an empty input string.
+TEST(CommandLineTest, EmptyString) {
+#if defined(OS_WIN)
+  CommandLine cl_from_string = CommandLine::FromString(L"");
+  EXPECT_TRUE(cl_from_string.GetCommandLineString().empty());
+  EXPECT_TRUE(cl_from_string.GetProgram().empty());
+  EXPECT_EQ(1U, cl_from_string.argv().size());
+  EXPECT_TRUE(cl_from_string.GetArgs().empty());
+#endif
+  CommandLine cl_from_argv(0, NULL);
+  EXPECT_TRUE(cl_from_argv.GetCommandLineString().empty());
+  EXPECT_TRUE(cl_from_argv.GetProgram().empty());
+  EXPECT_EQ(1U, cl_from_argv.argv().size());
+  EXPECT_TRUE(cl_from_argv.GetArgs().empty());
+}
+
+TEST(CommandLineTest, GetArgumentsString) {
+  static const FilePath::CharType kPath1[] =
+      FILE_PATH_LITERAL("C:\\Some File\\With Spaces.ggg");
+  static const FilePath::CharType kPath2[] =
+      FILE_PATH_LITERAL("C:\\no\\spaces.ggg");
+
+  static const char kFirstArgName[] = "first-arg";
+  static const char kSecondArgName[] = "arg2";
+  static const char kThirdArgName[] = "arg with space";
+  static const char kFourthArgName[] = "nospace";
+  static const char kFifthArgName[] = "%1";
+
+  CommandLine cl(CommandLine::NO_PROGRAM);
+  cl.AppendSwitchPath(kFirstArgName, FilePath(kPath1));
+  cl.AppendSwitchPath(kSecondArgName, FilePath(kPath2));
+  cl.AppendArg(kThirdArgName);
+  cl.AppendArg(kFourthArgName);
+  cl.AppendArg(kFifthArgName);
+
+#if defined(OS_WIN)
+  CommandLine::StringType expected_first_arg(UTF8ToUTF16(kFirstArgName));
+  CommandLine::StringType expected_second_arg(UTF8ToUTF16(kSecondArgName));
+  CommandLine::StringType expected_third_arg(UTF8ToUTF16(kThirdArgName));
+  CommandLine::StringType expected_fourth_arg(UTF8ToUTF16(kFourthArgName));
+  CommandLine::StringType expected_fifth_arg(UTF8ToUTF16(kFifthArgName));
+#elif defined(OS_POSIX)
+  CommandLine::StringType expected_first_arg(kFirstArgName);
+  CommandLine::StringType expected_second_arg(kSecondArgName);
+  CommandLine::StringType expected_third_arg(kThirdArgName);
+  CommandLine::StringType expected_fourth_arg(kFourthArgName);
+  CommandLine::StringType expected_fifth_arg(kFifthArgName);
+#endif
+
+#if defined(OS_WIN)
+#define QUOTE_ON_WIN FILE_PATH_LITERAL("\"")
+#else
+#define QUOTE_ON_WIN FILE_PATH_LITERAL("")
+#endif  // OS_WIN
+
+  CommandLine::StringType expected_str;
+  expected_str.append(FILE_PATH_LITERAL("--"))
+              .append(expected_first_arg)
+              .append(FILE_PATH_LITERAL("="))
+              .append(QUOTE_ON_WIN)
+              .append(kPath1)
+              .append(QUOTE_ON_WIN)
+              .append(FILE_PATH_LITERAL(" "))
+              .append(FILE_PATH_LITERAL("--"))
+              .append(expected_second_arg)
+              .append(FILE_PATH_LITERAL("="))
+              .append(QUOTE_ON_WIN)
+              .append(kPath2)
+              .append(QUOTE_ON_WIN)
+              .append(FILE_PATH_LITERAL(" "))
+              .append(QUOTE_ON_WIN)
+              .append(expected_third_arg)
+              .append(QUOTE_ON_WIN)
+              .append(FILE_PATH_LITERAL(" "))
+              .append(expected_fourth_arg)
+              .append(FILE_PATH_LITERAL(" "));
+
+  CommandLine::StringType expected_str_no_quote_placeholders(expected_str);
+  expected_str_no_quote_placeholders.append(expected_fifth_arg);
+  EXPECT_EQ(expected_str_no_quote_placeholders, cl.GetArgumentsString());
+
+#if defined(OS_WIN)
+  CommandLine::StringType expected_str_quote_placeholders(expected_str);
+  expected_str_quote_placeholders.append(QUOTE_ON_WIN)
+                                 .append(expected_fifth_arg)
+                                 .append(QUOTE_ON_WIN);
+  EXPECT_EQ(expected_str_quote_placeholders,
+            cl.GetArgumentsStringWithPlaceholders());
+#endif
+}
+
+// Test methods for appending switches to a command line.
+TEST(CommandLineTest, AppendSwitches) {
+  std::string switch1 = "switch1";
+  std::string switch2 = "switch2";
+  std::string value2 = "value";
+  std::string switch3 = "switch3";
+  std::string value3 = "a value with spaces";
+  std::string switch4 = "switch4";
+  std::string value4 = "\"a value with quotes\"";
+  std::string switch5 = "quotes";
+  CommandLine::StringType value5 = kTricky;
+
+  CommandLine cl(FilePath(FILE_PATH_LITERAL("Program")));
+
+  cl.AppendSwitch(switch1);
+  cl.AppendSwitchASCII(switch2, value2);
+  cl.AppendSwitchASCII(switch3, value3);
+  cl.AppendSwitchASCII(switch4, value4);
+  cl.AppendSwitchASCII(switch5, value4);
+  cl.AppendSwitchNative(switch5, value5);
+
+  EXPECT_TRUE(cl.HasSwitch(switch1));
+  EXPECT_TRUE(cl.HasSwitch(switch2));
+  EXPECT_EQ(value2, cl.GetSwitchValueASCII(switch2));
+  EXPECT_TRUE(cl.HasSwitch(switch3));
+  EXPECT_EQ(value3, cl.GetSwitchValueASCII(switch3));
+  EXPECT_TRUE(cl.HasSwitch(switch4));
+  EXPECT_EQ(value4, cl.GetSwitchValueASCII(switch4));
+  EXPECT_TRUE(cl.HasSwitch(switch5));
+  EXPECT_EQ(value5, cl.GetSwitchValueNative(switch5));
+
+#if defined(OS_WIN)
+  EXPECT_EQ(L"Program "
+            L"--switch1 "
+            L"--switch2=value "
+            L"--switch3=\"a value with spaces\" "
+            L"--switch4=\"\\\"a value with quotes\\\"\" "
+            // Even though the switches are unique, appending can add repeat
+            // switches to argv.
+            L"--quotes=\"\\\"a value with quotes\\\"\" "
+            L"--quotes=\"" + kTrickyQuoted + L"\"",
+            cl.GetCommandLineString());
+#endif
+}
+
+TEST(CommandLineTest, AppendSwitchesDashDash) {
+ const CommandLine::CharType* raw_argv[] = { FILE_PATH_LITERAL("prog"),
+                                             FILE_PATH_LITERAL("--"),
+                                             FILE_PATH_LITERAL("--arg1") };
+  CommandLine cl(arraysize(raw_argv), raw_argv);
+
+  cl.AppendSwitch("switch1");
+  cl.AppendSwitchASCII("switch2", "foo");
+
+  cl.AppendArg("--arg2");
+
+  EXPECT_EQ(FILE_PATH_LITERAL("prog --switch1 --switch2=foo -- --arg1 --arg2"),
+            cl.GetCommandLineString());
+  CommandLine::StringVector cl_argv = cl.argv();
+  EXPECT_EQ(FILE_PATH_LITERAL("prog"), cl_argv[0]);
+  EXPECT_EQ(FILE_PATH_LITERAL("--switch1"), cl_argv[1]);
+  EXPECT_EQ(FILE_PATH_LITERAL("--switch2=foo"), cl_argv[2]);
+  EXPECT_EQ(FILE_PATH_LITERAL("--"), cl_argv[3]);
+  EXPECT_EQ(FILE_PATH_LITERAL("--arg1"), cl_argv[4]);
+  EXPECT_EQ(FILE_PATH_LITERAL("--arg2"), cl_argv[5]);
+}
+
+// Tests that when AppendArguments is called that the program is set correctly
+// on the target CommandLine object and the switches from the source
+// CommandLine are added to the target.
+TEST(CommandLineTest, AppendArguments) {
+  CommandLine cl1(FilePath(FILE_PATH_LITERAL("Program")));
+  cl1.AppendSwitch("switch1");
+  cl1.AppendSwitchASCII("switch2", "foo");
+
+  CommandLine cl2(CommandLine::NO_PROGRAM);
+  cl2.AppendArguments(cl1, true);
+  EXPECT_EQ(cl1.GetProgram().value(), cl2.GetProgram().value());
+  EXPECT_EQ(cl1.GetCommandLineString(), cl2.GetCommandLineString());
+
+  CommandLine c1(FilePath(FILE_PATH_LITERAL("Program1")));
+  c1.AppendSwitch("switch1");
+  CommandLine c2(FilePath(FILE_PATH_LITERAL("Program2")));
+  c2.AppendSwitch("switch2");
+
+  c1.AppendArguments(c2, true);
+  EXPECT_EQ(c1.GetProgram().value(), c2.GetProgram().value());
+  EXPECT_TRUE(c1.HasSwitch("switch1"));
+  EXPECT_TRUE(c1.HasSwitch("switch2"));
+}
+
+#if defined(OS_WIN)
+// Make sure that the command line string program paths are quoted as necessary.
+// This only makes sense on Windows and the test is basically here to guard
+// against regressions.
+TEST(CommandLineTest, ProgramQuotes) {
+  // Check that quotes are not added for paths without spaces.
+  const FilePath kProgram(L"Program");
+  CommandLine cl_program(kProgram);
+  EXPECT_EQ(kProgram.value(), cl_program.GetProgram().value());
+  EXPECT_EQ(kProgram.value(), cl_program.GetCommandLineString());
+
+  const FilePath kProgramPath(L"Program Path");
+
+  // Check that quotes are not returned from GetProgram().
+  CommandLine cl_program_path(kProgramPath);
+  EXPECT_EQ(kProgramPath.value(), cl_program_path.GetProgram().value());
+
+  // Check that quotes are added to command line string paths containing spaces.
+  CommandLine::StringType cmd_string(cl_program_path.GetCommandLineString());
+  EXPECT_EQ(L"\"Program Path\"", cmd_string);
+
+  // Check the optional quoting of placeholders in programs.
+  CommandLine cl_quote_placeholder(FilePath(L"%1"));
+  EXPECT_EQ(L"%1", cl_quote_placeholder.GetCommandLineString());
+  EXPECT_EQ(L"\"%1\"",
+            cl_quote_placeholder.GetCommandLineStringWithPlaceholders());
+}
+#endif
+
+// Calling Init multiple times should not modify the previous CommandLine.
+TEST(CommandLineTest, Init) {
+  CommandLine* initial = CommandLine::ForCurrentProcess();
+  EXPECT_FALSE(CommandLine::Init(0, NULL));
+  CommandLine* current = CommandLine::ForCurrentProcess();
+  EXPECT_EQ(initial, current);
+}
+
+// Test that copies of CommandLine have a valid StringPiece map.
+TEST(CommandLineTest, Copy) {
+  scoped_ptr<CommandLine> initial(new CommandLine(CommandLine::NO_PROGRAM));
+  initial->AppendSwitch("a");
+  initial->AppendSwitch("bbbbbbbbbbbbbbb");
+  initial->AppendSwitch("c");
+  CommandLine copy_constructed(*initial);
+  CommandLine assigned = *initial;
+  CommandLine::SwitchMap switch_map = initial->GetSwitches();
+  initial.reset();
+  for (const auto& pair : switch_map)
+    EXPECT_TRUE(copy_constructed.HasSwitch(pair.first));
+  for (const auto& pair : switch_map)
+    EXPECT_TRUE(assigned.HasSwitch(pair.first));
+}
+
+} // namespace base
diff --git a/base/compiler_specific.h b/base/compiler_specific.h
new file mode 100644
index 0000000..63297dc
--- /dev/null
+++ b/base/compiler_specific.h
@@ -0,0 +1,207 @@
+// Copyright (c) 2012 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_COMPILER_SPECIFIC_H_
+#define BASE_COMPILER_SPECIFIC_H_
+
+#include "build/build_config.h"
+
+#if defined(COMPILER_MSVC)
+
+// Macros for suppressing and disabling warnings on MSVC.
+//
+// Warning numbers are enumerated at:
+// http://msdn.microsoft.com/en-us/library/8x5x43k7(VS.80).aspx
+//
+// The warning pragma:
+// http://msdn.microsoft.com/en-us/library/2c8f766e(VS.80).aspx
+//
+// Using __pragma instead of #pragma inside macros:
+// http://msdn.microsoft.com/en-us/library/d9x1s805.aspx
+
+// MSVC_SUPPRESS_WARNING disables warning |n| for the remainder of the line and
+// for the next line of the source file.
+#define MSVC_SUPPRESS_WARNING(n) __pragma(warning(suppress:n))
+
+// MSVC_PUSH_DISABLE_WARNING pushes |n| onto a stack of warnings to be disabled.
+// The warning remains disabled until popped by MSVC_POP_WARNING.
+#define MSVC_PUSH_DISABLE_WARNING(n) __pragma(warning(push)) \
+                                     __pragma(warning(disable:n))
+
+// MSVC_PUSH_WARNING_LEVEL pushes |n| as the global warning level.  The level
+// remains in effect until popped by MSVC_POP_WARNING().  Use 0 to disable all
+// warnings.
+#define MSVC_PUSH_WARNING_LEVEL(n) __pragma(warning(push, n))
+
+// Pop effects of innermost MSVC_PUSH_* macro.
+#define MSVC_POP_WARNING() __pragma(warning(pop))
+
+#define MSVC_DISABLE_OPTIMIZE() __pragma(optimize("", off))
+#define MSVC_ENABLE_OPTIMIZE() __pragma(optimize("", on))
+
+// Allows exporting a class that inherits from a non-exported base class.
+// This uses suppress instead of push/pop because the delimiter after the
+// declaration (either "," or "{") has to be placed before the pop macro.
+//
+// Example usage:
+// class EXPORT_API Foo : NON_EXPORTED_BASE(public Bar) {
+//
+// MSVC Compiler warning C4275:
+// non dll-interface class 'Bar' used as base for dll-interface class 'Foo'.
+// Note that this is intended to be used only when no access to the base class'
+// static data is done through derived classes or inline methods. For more info,
+// see http://msdn.microsoft.com/en-us/library/3tdb471s(VS.80).aspx
+#define NON_EXPORTED_BASE(code) MSVC_SUPPRESS_WARNING(4275) \
+                                code
+
+#else  // Not MSVC
+
+#define MSVC_SUPPRESS_WARNING(n)
+#define MSVC_PUSH_DISABLE_WARNING(n)
+#define MSVC_PUSH_WARNING_LEVEL(n)
+#define MSVC_POP_WARNING()
+#define MSVC_DISABLE_OPTIMIZE()
+#define MSVC_ENABLE_OPTIMIZE()
+#define NON_EXPORTED_BASE(code) code
+
+#endif  // COMPILER_MSVC
+
+
+// The C++ standard requires that static const members have an out-of-class
+// definition (in a single compilation unit), but MSVC chokes on this (when
+// language extensions, which are required, are enabled). (You're only likely to
+// notice the need for a definition if you take the address of the member or,
+// more commonly, pass it to a function that takes it as a reference argument --
+// probably an STL function.) This macro makes MSVC do the right thing. See
+// http://msdn.microsoft.com/en-us/library/34h23df8(v=vs.100).aspx for more
+// information. Use like:
+//
+// In .h file:
+//   struct Foo {
+//     static const int kBar = 5;
+//   };
+//
+// In .cc file:
+//   STATIC_CONST_MEMBER_DEFINITION const int Foo::kBar;
+#if defined(COMPILER_MSVC)
+#define STATIC_CONST_MEMBER_DEFINITION __declspec(selectany)
+#else
+#define STATIC_CONST_MEMBER_DEFINITION
+#endif
+
+// Annotate a variable indicating it's ok if the variable is not used.
+// (Typically used to silence a compiler warning when the assignment
+// is important for some other reason.)
+// Use like:
+//   int x = ...;
+//   ALLOW_UNUSED_LOCAL(x);
+#define ALLOW_UNUSED_LOCAL(x) false ? (void)x : (void)0
+
+// Annotate a typedef or function indicating it's ok if it's not used.
+// Use like:
+//   typedef Foo Bar ALLOW_UNUSED_TYPE;
+#if defined(COMPILER_GCC)
+#define ALLOW_UNUSED_TYPE __attribute__((unused))
+#else
+#define ALLOW_UNUSED_TYPE
+#endif
+
+// Annotate a function indicating it should not be inlined.
+// Use like:
+//   NOINLINE void DoStuff() { ... }
+#if defined(COMPILER_GCC)
+#define NOINLINE __attribute__((noinline))
+#elif defined(COMPILER_MSVC)
+#define NOINLINE __declspec(noinline)
+#else
+#define NOINLINE
+#endif
+
+// Specify memory alignment for structs, classes, etc.
+// Use like:
+//   class ALIGNAS(16) MyClass { ... }
+//   ALIGNAS(16) int array[4];
+#if defined(COMPILER_MSVC)
+#define ALIGNAS(byte_alignment) __declspec(align(byte_alignment))
+#elif defined(COMPILER_GCC)
+#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))
+#endif
+
+// Return the byte alignment of the given type (available at compile time).
+// Use like:
+//   ALIGNOF(int32)  // this would be 4
+#if defined(COMPILER_MSVC)
+#define ALIGNOF(type) __alignof(type)
+#elif defined(COMPILER_GCC)
+#define ALIGNOF(type) __alignof__(type)
+#endif
+
+// Annotate a function indicating the caller must examine the return value.
+// Use like:
+//   int foo() WARN_UNUSED_RESULT;
+// To explicitly ignore a result, see |ignore_result()| in <base/basictypes.h>.
+#if defined(COMPILER_GCC)
+#define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
+#else
+#define WARN_UNUSED_RESULT
+#endif
+
+// Tell the compiler a function is using a printf-style format string.
+// |format_param| is the one-based index of the format string parameter;
+// |dots_param| is the one-based index of the "..." parameter.
+// For v*printf functions (which take a va_list), pass 0 for dots_param.
+// (This is undocumented but matches what the system C headers do.)
+#if defined(COMPILER_GCC)
+#define PRINTF_FORMAT(format_param, dots_param) \
+    __attribute__((format(printf, format_param, dots_param)))
+#else
+#define PRINTF_FORMAT(format_param, dots_param)
+#endif
+
+// WPRINTF_FORMAT is the same, but for wide format strings.
+// This doesn't appear to yet be implemented in any compiler.
+// See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=38308 .
+#define WPRINTF_FORMAT(format_param, dots_param)
+// If available, it would look like:
+//   __attribute__((format(wprintf, format_param, dots_param)))
+
+// MemorySanitizer annotations.
+#if defined(MEMORY_SANITIZER) && !defined(OS_NACL)
+#include <sanitizer/msan_interface.h>
+
+// Mark a memory region fully initialized.
+// Use this to annotate code that deliberately reads uninitialized data, for
+// example a GC scavenging root set pointers from the stack.
+#define MSAN_UNPOISON(p, size)  __msan_unpoison(p, size)
+
+// Check a memory region for initializedness, as if it was being used here.
+// If any bits are uninitialized, crash with an MSan report.
+// Use this to sanitize data which MSan won't be able to track, e.g. before
+// passing data to another process via shared memory.
+#define MSAN_CHECK_MEM_IS_INITIALIZED(p, size) \
+    __msan_check_mem_is_initialized(p, size)
+#else  // MEMORY_SANITIZER
+#define MSAN_UNPOISON(p, size)
+#define MSAN_CHECK_MEM_IS_INITIALIZED(p, size)
+#endif  // MEMORY_SANITIZER
+
+// Macro useful for writing cross-platform function pointers.
+#if !defined(CDECL)
+#if defined(OS_WIN)
+#define CDECL __cdecl
+#else  // defined(OS_WIN)
+#define CDECL
+#endif  // defined(OS_WIN)
+#endif  // !defined(CDECL)
+
+// Macro for hinting that an expression is likely to be false.
+#if !defined(UNLIKELY)
+#if defined(COMPILER_GCC)
+#define UNLIKELY(x) __builtin_expect(!!(x), 0)
+#else
+#define UNLIKELY(x) (x)
+#endif  // defined(COMPILER_GCC)
+#endif  // !defined(UNLIKELY)
+
+#endif  // BASE_COMPILER_SPECIFIC_H_
diff --git a/base/containers/adapters.h b/base/containers/adapters.h
new file mode 100644
index 0000000..cc151fc
--- /dev/null
+++ b/base/containers/adapters.h
@@ -0,0 +1,50 @@
+// 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.
+
+#ifndef BASE_CONTAINERS_ADAPTERS_H_
+#define BASE_CONTAINERS_ADAPTERS_H_
+
+#include "base/macros.h"
+
+namespace base {
+
+namespace internal {
+
+// Internal adapter class for implementing base::Reversed.
+template <typename T>
+class ReversedAdapter {
+ public:
+  typedef decltype(static_cast<T*>(nullptr)->rbegin()) Iterator;
+
+  explicit ReversedAdapter(T& t) : t_(t) {}
+  ReversedAdapter(const ReversedAdapter& ra) : t_(ra.t_) {}
+
+  Iterator begin() const { return t_.rbegin(); }
+  Iterator end() const { return t_.rend(); }
+
+ private:
+  T& t_;
+
+  DISALLOW_ASSIGN(ReversedAdapter);
+};
+
+}  // namespace internal
+
+// Reversed returns a container adapter usable in a range-based "for" statement
+// for iterating a reversible container in reverse order.
+//
+// Example:
+//
+//   std::vector<int> v = ...;
+//   for (int i : base::Reversed(v)) {
+//     // iterates through v from back to front
+//   }
+template <typename T>
+internal::ReversedAdapter<T> Reversed(T& t) {
+  return internal::ReversedAdapter<T>(t);
+}
+
+}  // namespace base
+
+#endif  // BASE_CONTAINERS_ADAPTERS_H_
diff --git a/base/containers/adapters_unittest.cc b/base/containers/adapters_unittest.cc
new file mode 100644
index 0000000..4c87472
--- /dev/null
+++ b/base/containers/adapters_unittest.cc
@@ -0,0 +1,40 @@
+// 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.
+
+#include "base/containers/adapters.h"
+
+#include <vector>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+TEST(AdaptersTest, Reversed) {
+  std::vector<int> v;
+  v.push_back(3);
+  v.push_back(2);
+  v.push_back(1);
+  int j = 0;
+  for (int& i : base::Reversed(v)) {
+    EXPECT_EQ(++j, i);
+    i += 100;
+  }
+  EXPECT_EQ(103, v[0]);
+  EXPECT_EQ(102, v[1]);
+  EXPECT_EQ(101, v[2]);
+}
+
+TEST(AdaptersTest, ConstReversed) {
+  std::vector<int> v;
+  v.push_back(3);
+  v.push_back(2);
+  v.push_back(1);
+  const std::vector<int>& cv = v;
+  int j = 0;
+  for (int i : base::Reversed(cv)) {
+    EXPECT_EQ(++j, i);
+  }
+}
+
+}  // namespace
diff --git a/base/containers/hash_tables.h b/base/containers/hash_tables.h
new file mode 100644
index 0000000..5ce9161
--- /dev/null
+++ b/base/containers/hash_tables.h
@@ -0,0 +1,320 @@
+// Copyright (c) 2011 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.
+//
+
+//
+// Deal with the differences between Microsoft and GNU implemenations
+// of hash_map. Allows all platforms to use |base::hash_map| and
+// |base::hash_set|.
+//  eg:
+//   base::hash_map<int> my_map;
+//   base::hash_set<int> my_set;
+//
+// NOTE: It is an explicit non-goal of this class to provide a generic hash
+// function for pointers.  If you want to hash a pointers to a particular class,
+// please define the template specialization elsewhere (for example, in its
+// header file) and keep it specific to just pointers to that class.  This is
+// because identity hashes are not desirable for all types that might show up
+// in containers as pointers.
+
+#ifndef BASE_CONTAINERS_HASH_TABLES_H_
+#define BASE_CONTAINERS_HASH_TABLES_H_
+
+#include <utility>
+
+#include "base/basictypes.h"
+#include "base/strings/string16.h"
+#include "build/build_config.h"
+
+#if defined(COMPILER_MSVC)
+#include <unordered_map>
+#include <unordered_set>
+
+#define BASE_HASH_NAMESPACE std
+
+#elif defined(COMPILER_GCC)
+
+#define BASE_HASH_NAMESPACE base_hash
+
+// This is a hack to disable the gcc 4.4 warning about hash_map and hash_set
+// being deprecated.  We can get rid of this when we upgrade to VS2008 and we
+// can use <tr1/unordered_map> and <tr1/unordered_set>.
+#ifdef __DEPRECATED
+#define CHROME_OLD__DEPRECATED __DEPRECATED
+#undef __DEPRECATED
+#endif
+
+#include <ext/hash_map>
+#include <ext/hash_set>
+#define BASE_HASH_IMPL_NAMESPACE __gnu_cxx
+
+#include <string>
+
+#ifdef CHROME_OLD__DEPRECATED
+#define __DEPRECATED CHROME_OLD__DEPRECATED
+#undef CHROME_OLD__DEPRECATED
+#endif
+
+namespace BASE_HASH_NAMESPACE {
+
+// The pre-standard hash behaves like C++11's std::hash, except around pointers.
+// const char* is specialized to hash the C string and hash functions for
+// general T* are missing. Define a BASE_HASH_NAMESPACE::hash which aligns with
+// the C++11 behavior.
+
+template<typename T>
+struct hash {
+  std::size_t operator()(const T& value) const {
+    return BASE_HASH_IMPL_NAMESPACE::hash<T>()(value);
+  }
+};
+
+template<typename T>
+struct hash<T*> {
+  std::size_t operator()(T* value) const {
+    return BASE_HASH_IMPL_NAMESPACE::hash<uintptr_t>()(
+        reinterpret_cast<uintptr_t>(value));
+  }
+};
+
+// The GNU C++ library provides identity hash functions for many integral types,
+// but not for |long long|.  This hash function will truncate if |size_t| is
+// narrower than |long long|.  This is probably good enough for what we will
+// use it for.
+
+#define DEFINE_TRIVIAL_HASH(integral_type) \
+    template<> \
+    struct hash<integral_type> { \
+      std::size_t operator()(integral_type value) const { \
+        return static_cast<std::size_t>(value); \
+      } \
+    }
+
+DEFINE_TRIVIAL_HASH(long long);
+DEFINE_TRIVIAL_HASH(unsigned long long);
+
+#undef DEFINE_TRIVIAL_HASH
+
+// Implement string hash functions so that strings of various flavors can
+// be used as keys in STL maps and sets.  The hash algorithm comes from the
+// GNU C++ library, in <tr1/functional>.  It is duplicated here because GCC
+// versions prior to 4.3.2 are unable to compile <tr1/functional> when RTTI
+// is disabled, as it is in our build.
+
+#define DEFINE_STRING_HASH(string_type) \
+    template<> \
+    struct hash<string_type> { \
+      std::size_t operator()(const string_type& s) const { \
+        std::size_t result = 0; \
+        for (string_type::const_iterator i = s.begin(); i != s.end(); ++i) \
+          result = (result * 131) + *i; \
+        return result; \
+      } \
+    }
+
+DEFINE_STRING_HASH(std::string);
+DEFINE_STRING_HASH(base::string16);
+
+#undef DEFINE_STRING_HASH
+
+}  // namespace BASE_HASH_NAMESPACE
+
+#else  // COMPILER
+#error define BASE_HASH_NAMESPACE for your compiler
+#endif  // COMPILER
+
+namespace base {
+
+// On MSVC, use the C++11 containers.
+#if defined(COMPILER_MSVC)
+
+template<class Key, class T,
+         class Hash = std::hash<Key>,
+         class Pred = std::equal_to<Key>,
+         class Alloc = std::allocator<std::pair<const Key, T>>>
+using hash_map = std::unordered_map<Key, T, Hash, Pred, Alloc>;
+
+template<class Key, class T,
+         class Hash = std::hash<Key>,
+         class Pred = std::equal_to<Key>,
+         class Alloc = std::allocator<std::pair<const Key, T>>>
+using hash_multimap = std::unordered_multimap<Key, T, Hash, Pred, Alloc>;
+
+template<class Key,
+         class Hash = std::hash<Key>,
+         class Pred = std::equal_to<Key>,
+         class Alloc = std::allocator<Key>>
+using hash_multiset = std::unordered_multiset<Key, Hash, Pred, Alloc>;
+
+template<class Key,
+         class Hash = std::hash<Key>,
+         class Pred = std::equal_to<Key>,
+         class Alloc = std::allocator<Key>>
+using hash_set = std::unordered_set<Key, Hash, Pred, Alloc>;
+
+#else  // !COMPILER_MSVC
+
+// Otherwise, use the pre-standard ones, but override the default hash to match
+// C++11.
+template<class Key, class T,
+         class Hash = BASE_HASH_NAMESPACE::hash<Key>,
+         class Pred = std::equal_to<Key>,
+         class Alloc = std::allocator<std::pair<const Key, T>>>
+using hash_map = BASE_HASH_IMPL_NAMESPACE::hash_map<Key, T, Hash, Pred, Alloc>;
+
+template<class Key, class T,
+         class Hash = BASE_HASH_NAMESPACE::hash<Key>,
+         class Pred = std::equal_to<Key>,
+         class Alloc = std::allocator<std::pair<const Key, T>>>
+using hash_multimap =
+    BASE_HASH_IMPL_NAMESPACE::hash_multimap<Key, T, Hash, Pred, Alloc>;
+
+template<class Key,
+         class Hash = BASE_HASH_NAMESPACE::hash<Key>,
+         class Pred = std::equal_to<Key>,
+         class Alloc = std::allocator<Key>>
+using hash_multiset =
+    BASE_HASH_IMPL_NAMESPACE::hash_multiset<Key, Hash, Pred, Alloc>;
+
+template<class Key,
+         class Hash = BASE_HASH_NAMESPACE::hash<Key>,
+         class Pred = std::equal_to<Key>,
+         class Alloc = std::allocator<Key>>
+using hash_set = BASE_HASH_IMPL_NAMESPACE::hash_set<Key, Hash, Pred, Alloc>;
+
+#undef BASE_HASH_IMPL_NAMESPACE
+
+#endif  // COMPILER_MSVC
+
+// Implement hashing for pairs of at-most 32 bit integer values.
+// When size_t is 32 bits, we turn the 64-bit hash code into 32 bits by using
+// multiply-add hashing. This algorithm, as described in
+// Theorem 4.3.3 of the thesis "Über die Komplexität der Multiplikation in
+// eingeschränkten Branchingprogrammmodellen" by Woelfel, is:
+//
+//   h32(x32, y32) = (h64(x32, y32) * rand_odd64 + rand16 * 2^16) % 2^64 / 2^32
+//
+// Contact danakj@chromium.org for any questions.
+inline std::size_t HashInts32(uint32 value1, uint32 value2) {
+  uint64 value1_64 = value1;
+  uint64 hash64 = (value1_64 << 32) | value2;
+
+  if (sizeof(std::size_t) >= sizeof(uint64))
+    return static_cast<std::size_t>(hash64);
+
+  uint64 odd_random = 481046412LL << 32 | 1025306955LL;
+  uint32 shift_random = 10121U << 16;
+
+  hash64 = hash64 * odd_random + shift_random;
+  std::size_t high_bits = static_cast<std::size_t>(
+      hash64 >> (8 * (sizeof(uint64) - sizeof(std::size_t))));
+  return high_bits;
+}
+
+// Implement hashing for pairs of up-to 64-bit integer values.
+// We use the compound integer hash method to produce a 64-bit hash code, by
+// breaking the two 64-bit inputs into 4 32-bit values:
+// http://opendatastructures.org/versions/edition-0.1d/ods-java/node33.html#SECTION00832000000000000000
+// Then we reduce our result to 32 bits if required, similar to above.
+inline std::size_t HashInts64(uint64 value1, uint64 value2) {
+  uint32 short_random1 = 842304669U;
+  uint32 short_random2 = 619063811U;
+  uint32 short_random3 = 937041849U;
+  uint32 short_random4 = 3309708029U;
+
+  uint32 value1a = static_cast<uint32>(value1 & 0xffffffff);
+  uint32 value1b = static_cast<uint32>((value1 >> 32) & 0xffffffff);
+  uint32 value2a = static_cast<uint32>(value2 & 0xffffffff);
+  uint32 value2b = static_cast<uint32>((value2 >> 32) & 0xffffffff);
+
+  uint64 product1 = static_cast<uint64>(value1a) * short_random1;
+  uint64 product2 = static_cast<uint64>(value1b) * short_random2;
+  uint64 product3 = static_cast<uint64>(value2a) * short_random3;
+  uint64 product4 = static_cast<uint64>(value2b) * short_random4;
+
+  uint64 hash64 = product1 + product2 + product3 + product4;
+
+  if (sizeof(std::size_t) >= sizeof(uint64))
+    return static_cast<std::size_t>(hash64);
+
+  uint64 odd_random = 1578233944LL << 32 | 194370989LL;
+  uint32 shift_random = 20591U << 16;
+
+  hash64 = hash64 * odd_random + shift_random;
+  std::size_t high_bits = static_cast<std::size_t>(
+      hash64 >> (8 * (sizeof(uint64) - sizeof(std::size_t))));
+  return high_bits;
+}
+
+#define DEFINE_32BIT_PAIR_HASH(Type1, Type2) \
+inline std::size_t HashPair(Type1 value1, Type2 value2) { \
+  return HashInts32(value1, value2); \
+}
+
+DEFINE_32BIT_PAIR_HASH(int16, int16);
+DEFINE_32BIT_PAIR_HASH(int16, uint16);
+DEFINE_32BIT_PAIR_HASH(int16, int32);
+DEFINE_32BIT_PAIR_HASH(int16, uint32);
+DEFINE_32BIT_PAIR_HASH(uint16, int16);
+DEFINE_32BIT_PAIR_HASH(uint16, uint16);
+DEFINE_32BIT_PAIR_HASH(uint16, int32);
+DEFINE_32BIT_PAIR_HASH(uint16, uint32);
+DEFINE_32BIT_PAIR_HASH(int32, int16);
+DEFINE_32BIT_PAIR_HASH(int32, uint16);
+DEFINE_32BIT_PAIR_HASH(int32, int32);
+DEFINE_32BIT_PAIR_HASH(int32, uint32);
+DEFINE_32BIT_PAIR_HASH(uint32, int16);
+DEFINE_32BIT_PAIR_HASH(uint32, uint16);
+DEFINE_32BIT_PAIR_HASH(uint32, int32);
+DEFINE_32BIT_PAIR_HASH(uint32, uint32);
+
+#undef DEFINE_32BIT_PAIR_HASH
+
+#define DEFINE_64BIT_PAIR_HASH(Type1, Type2) \
+inline std::size_t HashPair(Type1 value1, Type2 value2) { \
+  return HashInts64(value1, value2); \
+}
+
+DEFINE_64BIT_PAIR_HASH(int16, int64);
+DEFINE_64BIT_PAIR_HASH(int16, uint64);
+DEFINE_64BIT_PAIR_HASH(uint16, int64);
+DEFINE_64BIT_PAIR_HASH(uint16, uint64);
+DEFINE_64BIT_PAIR_HASH(int32, int64);
+DEFINE_64BIT_PAIR_HASH(int32, uint64);
+DEFINE_64BIT_PAIR_HASH(uint32, int64);
+DEFINE_64BIT_PAIR_HASH(uint32, uint64);
+DEFINE_64BIT_PAIR_HASH(int64, int16);
+DEFINE_64BIT_PAIR_HASH(int64, uint16);
+DEFINE_64BIT_PAIR_HASH(int64, int32);
+DEFINE_64BIT_PAIR_HASH(int64, uint32);
+DEFINE_64BIT_PAIR_HASH(int64, int64);
+DEFINE_64BIT_PAIR_HASH(int64, uint64);
+DEFINE_64BIT_PAIR_HASH(uint64, int16);
+DEFINE_64BIT_PAIR_HASH(uint64, uint16);
+DEFINE_64BIT_PAIR_HASH(uint64, int32);
+DEFINE_64BIT_PAIR_HASH(uint64, uint32);
+DEFINE_64BIT_PAIR_HASH(uint64, int64);
+DEFINE_64BIT_PAIR_HASH(uint64, uint64);
+
+#undef DEFINE_64BIT_PAIR_HASH
+}  // namespace base
+
+namespace BASE_HASH_NAMESPACE {
+
+// Implement methods for hashing a pair of integers, so they can be used as
+// keys in STL containers.
+
+template<typename Type1, typename Type2>
+struct hash<std::pair<Type1, Type2> > {
+  std::size_t operator()(std::pair<Type1, Type2> value) const {
+    return base::HashPair(value.first, value.second);
+  }
+};
+
+}  // namespace BASE_HASH_NAMESPACE
+
+#undef DEFINE_PAIR_HASH_FUNCTION_START
+#undef DEFINE_PAIR_HASH_FUNCTION_END
+
+#endif  // BASE_CONTAINERS_HASH_TABLES_H_
diff --git a/base/containers/hash_tables_unittest.cc b/base/containers/hash_tables_unittest.cc
new file mode 100644
index 0000000..f775dff
--- /dev/null
+++ b/base/containers/hash_tables_unittest.cc
@@ -0,0 +1,68 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/containers/hash_tables.h"
+
+#include <stdint.h>
+#include <string>
+
+#include "base/basictypes.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class HashPairTest : public testing::Test {
+};
+
+#define INSERT_PAIR_TEST(Type, value1, value2) \
+  { \
+    Type pair(value1, value2); \
+    base::hash_map<Type, int> map; \
+    map[pair] = 1; \
+  }
+
+// Verify that a hash_map can be constructed for pairs of integers of various
+// sizes.
+TEST_F(HashPairTest, IntegerPairs) {
+  typedef std::pair<int16, int16> Int16Int16Pair;
+  typedef std::pair<int16, int32> Int16Int32Pair;
+  typedef std::pair<int16, int64> Int16Int64Pair;
+
+  INSERT_PAIR_TEST(Int16Int16Pair, 4, 6);
+  INSERT_PAIR_TEST(Int16Int32Pair, 9, (1 << 29) + 378128932);
+  INSERT_PAIR_TEST(Int16Int64Pair, 10,
+                   (INT64_C(1) << 60) + INT64_C(78931732321));
+
+  typedef std::pair<int32, int16> Int32Int16Pair;
+  typedef std::pair<int32, int32> Int32Int32Pair;
+  typedef std::pair<int32, int64> Int32Int64Pair;
+
+  INSERT_PAIR_TEST(Int32Int16Pair, 4, 6);
+  INSERT_PAIR_TEST(Int32Int32Pair, 9, (1 << 29) + 378128932);
+  INSERT_PAIR_TEST(Int32Int64Pair, 10,
+                   (INT64_C(1) << 60) + INT64_C(78931732321));
+
+  typedef std::pair<int64, int16> Int64Int16Pair;
+  typedef std::pair<int64, int32> Int64Int32Pair;
+  typedef std::pair<int64, int64> Int64Int64Pair;
+
+  INSERT_PAIR_TEST(Int64Int16Pair, 4, 6);
+  INSERT_PAIR_TEST(Int64Int32Pair, 9, (1 << 29) + 378128932);
+  INSERT_PAIR_TEST(Int64Int64Pair, 10,
+                   (INT64_C(1) << 60) + INT64_C(78931732321));
+}
+
+// Verify that base::hash_set<const char*> compares by pointer value, not as C
+// strings.
+TEST(HashTableTest, CharPointers) {
+  std::string str1("hello");
+  std::string str2("hello");
+  base::hash_set<const char*> set;
+
+  set.insert(str1.c_str());
+  EXPECT_EQ(1u, set.count(str1.c_str()));
+  EXPECT_EQ(0u, set.count(str2.c_str()));
+}
+
+}  // namespace
diff --git a/base/containers/linked_list.h b/base/containers/linked_list.h
new file mode 100644
index 0000000..41461ff
--- /dev/null
+++ b/base/containers/linked_list.h
@@ -0,0 +1,176 @@
+// Copyright (c) 2009 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_CONTAINERS_LINKED_LIST_H_
+#define BASE_CONTAINERS_LINKED_LIST_H_
+
+#include "base/macros.h"
+
+// Simple LinkedList type. (See the Q&A section to understand how this
+// differs from std::list).
+//
+// To use, start by declaring the class which will be contained in the linked
+// list, as extending LinkNode (this gives it next/previous pointers).
+//
+//   class MyNodeType : public LinkNode<MyNodeType> {
+//     ...
+//   };
+//
+// Next, to keep track of the list's head/tail, use a LinkedList instance:
+//
+//   LinkedList<MyNodeType> list;
+//
+// To add elements to the list, use any of LinkedList::Append,
+// LinkNode::InsertBefore, or LinkNode::InsertAfter:
+//
+//   LinkNode<MyNodeType>* n1 = ...;
+//   LinkNode<MyNodeType>* n2 = ...;
+//   LinkNode<MyNodeType>* n3 = ...;
+//
+//   list.Append(n1);
+//   list.Append(n3);
+//   n3->InsertBefore(n3);
+//
+// Lastly, to iterate through the linked list forwards:
+//
+//   for (LinkNode<MyNodeType>* node = list.head();
+//        node != list.end();
+//        node = node->next()) {
+//     MyNodeType* value = node->value();
+//     ...
+//   }
+//
+// Or to iterate the linked list backwards:
+//
+//   for (LinkNode<MyNodeType>* node = list.tail();
+//        node != list.end();
+//        node = node->previous()) {
+//     MyNodeType* value = node->value();
+//     ...
+//   }
+//
+// Questions and Answers:
+//
+// Q. Should I use std::list or base::LinkedList?
+//
+// A. The main reason to use base::LinkedList over std::list is
+//    performance. If you don't care about the performance differences
+//    then use an STL container, as it makes for better code readability.
+//
+//    Comparing the performance of base::LinkedList<T> to std::list<T*>:
+//
+//    * Erasing an element of type T* from base::LinkedList<T> is
+//      an O(1) operation. Whereas for std::list<T*> it is O(n).
+//      That is because with std::list<T*> you must obtain an
+//      iterator to the T* element before you can call erase(iterator).
+//
+//    * Insertion operations with base::LinkedList<T> never require
+//      heap allocations.
+//
+// Q. How does base::LinkedList implementation differ from std::list?
+//
+// A. Doubly-linked lists are made up of nodes that contain "next" and
+//    "previous" pointers that reference other nodes in the list.
+//
+//    With base::LinkedList<T>, the type being inserted already reserves
+//    space for the "next" and "previous" pointers (base::LinkNode<T>*).
+//    Whereas with std::list<T> the type can be anything, so the implementation
+//    needs to glue on the "next" and "previous" pointers using
+//    some internal node type.
+
+namespace base {
+
+template <typename T>
+class LinkNode {
+ public:
+  LinkNode() : previous_(NULL), next_(NULL) {}
+  LinkNode(LinkNode<T>* previous, LinkNode<T>* next)
+      : previous_(previous), next_(next) {}
+
+  // Insert |this| into the linked list, before |e|.
+  void InsertBefore(LinkNode<T>* e) {
+    this->next_ = e;
+    this->previous_ = e->previous_;
+    e->previous_->next_ = this;
+    e->previous_ = this;
+  }
+
+  // Insert |this| into the linked list, after |e|.
+  void InsertAfter(LinkNode<T>* e) {
+    this->next_ = e->next_;
+    this->previous_ = e;
+    e->next_->previous_ = this;
+    e->next_ = this;
+  }
+
+  // Remove |this| from the linked list.
+  void RemoveFromList() {
+    this->previous_->next_ = this->next_;
+    this->next_->previous_ = this->previous_;
+    // next() and previous() return non-NULL if and only this node is not in any
+    // list.
+    this->next_ = NULL;
+    this->previous_ = NULL;
+  }
+
+  LinkNode<T>* previous() const {
+    return previous_;
+  }
+
+  LinkNode<T>* next() const {
+    return next_;
+  }
+
+  // Cast from the node-type to the value type.
+  const T* value() const {
+    return static_cast<const T*>(this);
+  }
+
+  T* value() {
+    return static_cast<T*>(this);
+  }
+
+ private:
+  LinkNode<T>* previous_;
+  LinkNode<T>* next_;
+
+  DISALLOW_COPY_AND_ASSIGN(LinkNode);
+};
+
+template <typename T>
+class LinkedList {
+ public:
+  // The "root" node is self-referential, and forms the basis of a circular
+  // list (root_.next() will point back to the start of the list,
+  // and root_->previous() wraps around to the end of the list).
+  LinkedList() : root_(&root_, &root_) {}
+
+  // Appends |e| to the end of the linked list.
+  void Append(LinkNode<T>* e) {
+    e->InsertBefore(&root_);
+  }
+
+  LinkNode<T>* head() const {
+    return root_.next();
+  }
+
+  LinkNode<T>* tail() const {
+    return root_.previous();
+  }
+
+  const LinkNode<T>* end() const {
+    return &root_;
+  }
+
+  bool empty() const { return head() == end(); }
+
+ private:
+  LinkNode<T> root_;
+
+  DISALLOW_COPY_AND_ASSIGN(LinkedList);
+};
+
+}  // namespace base
+
+#endif  // BASE_CONTAINERS_LINKED_LIST_H_
diff --git a/base/containers/linked_list_unittest.cc b/base/containers/linked_list_unittest.cc
new file mode 100644
index 0000000..93a9f38
--- /dev/null
+++ b/base/containers/linked_list_unittest.cc
@@ -0,0 +1,308 @@
+// Copyright (c) 2009 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/basictypes.h"
+#include "base/containers/linked_list.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+class Node : public LinkNode<Node> {
+ public:
+  explicit Node(int id) : id_(id) {}
+
+  int id() const { return id_; }
+
+ private:
+  int id_;
+};
+
+class MultipleInheritanceNodeBase {
+ public:
+  MultipleInheritanceNodeBase() : field_taking_up_space_(0) {}
+  int field_taking_up_space_;
+};
+
+class MultipleInheritanceNode : public MultipleInheritanceNodeBase,
+                                public LinkNode<MultipleInheritanceNode> {
+ public:
+  MultipleInheritanceNode() {}
+};
+
+// Checks that when iterating |list| (either from head to tail, or from
+// tail to head, as determined by |forward|), we get back |node_ids|,
+// which is an array of size |num_nodes|.
+void ExpectListContentsForDirection(const LinkedList<Node>& list,
+  int num_nodes, const int* node_ids, bool forward) {
+  int i = 0;
+  for (const LinkNode<Node>* node = (forward ? list.head() : list.tail());
+       node != list.end();
+       node = (forward ? node->next() : node->previous())) {
+    ASSERT_LT(i, num_nodes);
+    int index_of_id = forward ? i : num_nodes - i - 1;
+    EXPECT_EQ(node_ids[index_of_id], node->value()->id());
+    ++i;
+  }
+  EXPECT_EQ(num_nodes, i);
+}
+
+void ExpectListContents(const LinkedList<Node>& list,
+                        int num_nodes,
+                        const int* node_ids) {
+  {
+    SCOPED_TRACE("Iterating forward (from head to tail)");
+    ExpectListContentsForDirection(list, num_nodes, node_ids, true);
+  }
+  {
+    SCOPED_TRACE("Iterating backward (from tail to head)");
+    ExpectListContentsForDirection(list, num_nodes, node_ids, false);
+  }
+}
+
+TEST(LinkedList, Empty) {
+  LinkedList<Node> list;
+  EXPECT_EQ(list.end(), list.head());
+  EXPECT_EQ(list.end(), list.tail());
+  ExpectListContents(list, 0, NULL);
+}
+
+TEST(LinkedList, Append) {
+  LinkedList<Node> list;
+  ExpectListContents(list, 0, NULL);
+
+  Node n1(1);
+  list.Append(&n1);
+
+  EXPECT_EQ(&n1, list.head());
+  EXPECT_EQ(&n1, list.tail());
+  {
+    const int expected[] = {1};
+    ExpectListContents(list, arraysize(expected), expected);
+  }
+
+  Node n2(2);
+  list.Append(&n2);
+
+  EXPECT_EQ(&n1, list.head());
+  EXPECT_EQ(&n2, list.tail());
+  {
+    const int expected[] = {1, 2};
+    ExpectListContents(list, arraysize(expected), expected);
+  }
+
+  Node n3(3);
+  list.Append(&n3);
+
+  EXPECT_EQ(&n1, list.head());
+  EXPECT_EQ(&n3, list.tail());
+  {
+    const int expected[] = {1, 2, 3};
+    ExpectListContents(list, arraysize(expected), expected);
+  }
+}
+
+TEST(LinkedList, RemoveFromList) {
+  LinkedList<Node> list;
+
+  Node n1(1);
+  Node n2(2);
+  Node n3(3);
+  Node n4(4);
+  Node n5(5);
+
+  list.Append(&n1);
+  list.Append(&n2);
+  list.Append(&n3);
+  list.Append(&n4);
+  list.Append(&n5);
+
+  EXPECT_EQ(&n1, list.head());
+  EXPECT_EQ(&n5, list.tail());
+  {
+    const int expected[] = {1, 2, 3, 4, 5};
+    ExpectListContents(list, arraysize(expected), expected);
+  }
+
+  // Remove from the middle.
+  n3.RemoveFromList();
+
+  EXPECT_EQ(&n1, list.head());
+  EXPECT_EQ(&n5, list.tail());
+  {
+    const int expected[] = {1, 2, 4, 5};
+    ExpectListContents(list, arraysize(expected), expected);
+  }
+
+  // Remove from the tail.
+  n5.RemoveFromList();
+
+  EXPECT_EQ(&n1, list.head());
+  EXPECT_EQ(&n4, list.tail());
+  {
+    const int expected[] = {1, 2, 4};
+    ExpectListContents(list, arraysize(expected), expected);
+  }
+
+  // Remove from the head.
+  n1.RemoveFromList();
+
+  EXPECT_EQ(&n2, list.head());
+  EXPECT_EQ(&n4, list.tail());
+  {
+    const int expected[] = {2, 4};
+    ExpectListContents(list, arraysize(expected), expected);
+  }
+
+  // Empty the list.
+  n2.RemoveFromList();
+  n4.RemoveFromList();
+
+  ExpectListContents(list, 0, NULL);
+  EXPECT_EQ(list.end(), list.head());
+  EXPECT_EQ(list.end(), list.tail());
+
+  // Fill the list once again.
+  list.Append(&n1);
+  list.Append(&n2);
+  list.Append(&n3);
+  list.Append(&n4);
+  list.Append(&n5);
+
+  EXPECT_EQ(&n1, list.head());
+  EXPECT_EQ(&n5, list.tail());
+  {
+    const int expected[] = {1, 2, 3, 4, 5};
+    ExpectListContents(list, arraysize(expected), expected);
+  }
+}
+
+TEST(LinkedList, InsertBefore) {
+  LinkedList<Node> list;
+
+  Node n1(1);
+  Node n2(2);
+  Node n3(3);
+  Node n4(4);
+
+  list.Append(&n1);
+  list.Append(&n2);
+
+  EXPECT_EQ(&n1, list.head());
+  EXPECT_EQ(&n2, list.tail());
+  {
+    const int expected[] = {1, 2};
+    ExpectListContents(list, arraysize(expected), expected);
+  }
+
+  n3.InsertBefore(&n2);
+
+  EXPECT_EQ(&n1, list.head());
+  EXPECT_EQ(&n2, list.tail());
+  {
+    const int expected[] = {1, 3, 2};
+    ExpectListContents(list, arraysize(expected), expected);
+  }
+
+  n4.InsertBefore(&n1);
+
+  EXPECT_EQ(&n4, list.head());
+  EXPECT_EQ(&n2, list.tail());
+  {
+    const int expected[] = {4, 1, 3, 2};
+    ExpectListContents(list, arraysize(expected), expected);
+  }
+}
+
+TEST(LinkedList, InsertAfter) {
+  LinkedList<Node> list;
+
+  Node n1(1);
+  Node n2(2);
+  Node n3(3);
+  Node n4(4);
+
+  list.Append(&n1);
+  list.Append(&n2);
+
+  EXPECT_EQ(&n1, list.head());
+  EXPECT_EQ(&n2, list.tail());
+  {
+    const int expected[] = {1, 2};
+    ExpectListContents(list, arraysize(expected), expected);
+  }
+
+  n3.InsertAfter(&n2);
+
+  EXPECT_EQ(&n1, list.head());
+  EXPECT_EQ(&n3, list.tail());
+  {
+    const int expected[] = {1, 2, 3};
+    ExpectListContents(list, arraysize(expected), expected);
+  }
+
+  n4.InsertAfter(&n1);
+
+  EXPECT_EQ(&n1, list.head());
+  EXPECT_EQ(&n3, list.tail());
+  {
+    const int expected[] = {1, 4, 2, 3};
+    ExpectListContents(list, arraysize(expected), expected);
+  }
+}
+
+TEST(LinkedList, MultipleInheritanceNode) {
+  MultipleInheritanceNode node;
+  EXPECT_EQ(&node, node.value());
+}
+
+TEST(LinkedList, EmptyListIsEmpty) {
+  LinkedList<Node> list;
+  EXPECT_TRUE(list.empty());
+}
+
+TEST(LinkedList, NonEmptyListIsNotEmpty) {
+  LinkedList<Node> list;
+
+  Node n(1);
+  list.Append(&n);
+
+  EXPECT_FALSE(list.empty());
+}
+
+TEST(LinkedList, EmptiedListIsEmptyAgain) {
+  LinkedList<Node> list;
+
+  Node n(1);
+  list.Append(&n);
+  n.RemoveFromList();
+
+  EXPECT_TRUE(list.empty());
+}
+
+TEST(LinkedList, NodesCanBeReused) {
+  LinkedList<Node> list1;
+  LinkedList<Node> list2;
+
+  Node n(1);
+  list1.Append(&n);
+  n.RemoveFromList();
+  list2.Append(&n);
+
+  EXPECT_EQ(list2.head()->value(), &n);
+}
+
+TEST(LinkedList, RemovedNodeHasNullNextPrevious) {
+  LinkedList<Node> list;
+
+  Node n(1);
+  list.Append(&n);
+  n.RemoveFromList();
+
+  EXPECT_EQ(NULL, n.next());
+  EXPECT_EQ(NULL, n.previous());
+}
+
+}  // namespace
+}  // namespace base
diff --git a/base/containers/mru_cache.h b/base/containers/mru_cache.h
new file mode 100644
index 0000000..ed1ad25
--- /dev/null
+++ b/base/containers/mru_cache.h
@@ -0,0 +1,307 @@
+// Copyright (c) 2011 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 contains a template for a Most Recently Used cache that allows
+// constant-time access to items using a key, but easy identification of the
+// least-recently-used items for removal.  Each key can only be associated with
+// one payload item at a time.
+//
+// The key object will be stored twice, so it should support efficient copying.
+//
+// NOTE: While all operations are O(1), this code is written for
+// legibility rather than optimality. If future profiling identifies this as
+// a bottleneck, there is room for smaller values of 1 in the O(1). :]
+
+#ifndef BASE_CONTAINERS_MRU_CACHE_H_
+#define BASE_CONTAINERS_MRU_CACHE_H_
+
+#include <list>
+#include <map>
+#include <utility>
+
+#include "base/basictypes.h"
+#include "base/containers/hash_tables.h"
+#include "base/logging.h"
+
+namespace base {
+
+// MRUCacheBase ----------------------------------------------------------------
+
+// This template is used to standardize map type containers that can be used
+// by MRUCacheBase. This level of indirection is necessary because of the way
+// that template template params and default template params interact.
+template <class KeyType, class ValueType>
+struct MRUCacheStandardMap {
+  typedef std::map<KeyType, ValueType> Type;
+};
+
+// Base class for the MRU cache specializations defined below.
+// The deletor will get called on all payloads that are being removed or
+// replaced.
+template <class KeyType, class PayloadType, class DeletorType,
+          template <typename, typename> class MapType = MRUCacheStandardMap>
+class MRUCacheBase {
+ public:
+  // The payload of the list. This maintains a copy of the key so we can
+  // efficiently delete things given an element of the list.
+  typedef std::pair<KeyType, PayloadType> value_type;
+
+ private:
+  typedef std::list<value_type> PayloadList;
+  typedef typename MapType<KeyType,
+                           typename PayloadList::iterator>::Type KeyIndex;
+
+ public:
+  typedef typename PayloadList::size_type size_type;
+
+  typedef typename PayloadList::iterator iterator;
+  typedef typename PayloadList::const_iterator const_iterator;
+  typedef typename PayloadList::reverse_iterator reverse_iterator;
+  typedef typename PayloadList::const_reverse_iterator const_reverse_iterator;
+
+  enum { NO_AUTO_EVICT = 0 };
+
+  // The max_size is the size at which the cache will prune its members to when
+  // a new item is inserted. If the caller wants to manager this itself (for
+  // example, maybe it has special work to do when something is evicted), it
+  // can pass NO_AUTO_EVICT to not restrict the cache size.
+  explicit MRUCacheBase(size_type max_size) : max_size_(max_size) {
+  }
+
+  MRUCacheBase(size_type max_size, const DeletorType& deletor)
+      : max_size_(max_size), deletor_(deletor) {
+  }
+
+  virtual ~MRUCacheBase() {
+    iterator i = begin();
+    while (i != end())
+      i = Erase(i);
+  }
+
+  size_type max_size() const { return max_size_; }
+
+  // Inserts a payload item with the given key. If an existing item has
+  // the same key, it is removed prior to insertion. An iterator indicating the
+  // inserted item will be returned (this will always be the front of the list).
+  //
+  // The payload will be copied. In the case of an OwningMRUCache, this function
+  // will take ownership of the pointer.
+  iterator Put(const KeyType& key, const PayloadType& payload) {
+    // Remove any existing payload with that key.
+    typename KeyIndex::iterator index_iter = index_.find(key);
+    if (index_iter != index_.end()) {
+      // Erase the reference to it. This will call the deletor on the removed
+      // element. The index reference will be replaced in the code below.
+      Erase(index_iter->second);
+    } else if (max_size_ != NO_AUTO_EVICT) {
+      // New item is being inserted which might make it larger than the maximum
+      // size: kick the oldest thing out if necessary.
+      ShrinkToSize(max_size_ - 1);
+    }
+
+    ordering_.push_front(value_type(key, payload));
+    index_.insert(std::make_pair(key, ordering_.begin()));
+    return ordering_.begin();
+  }
+
+  // Retrieves the contents of the given key, or end() if not found. This method
+  // has the side effect of moving the requested item to the front of the
+  // recency list.
+  //
+  // TODO(brettw) We may want a const version of this function in the future.
+  iterator Get(const KeyType& key) {
+    typename KeyIndex::iterator index_iter = index_.find(key);
+    if (index_iter == index_.end())
+      return end();
+    typename PayloadList::iterator iter = index_iter->second;
+
+    // Move the touched item to the front of the recency ordering.
+    ordering_.splice(ordering_.begin(), ordering_, iter);
+    return ordering_.begin();
+  }
+
+  // Retrieves the payload associated with a given key and returns it via
+  // result without affecting the ordering (unlike Get).
+  iterator Peek(const KeyType& key) {
+    typename KeyIndex::const_iterator index_iter = index_.find(key);
+    if (index_iter == index_.end())
+      return end();
+    return index_iter->second;
+  }
+
+  const_iterator Peek(const KeyType& key) const {
+    typename KeyIndex::const_iterator index_iter = index_.find(key);
+    if (index_iter == index_.end())
+      return end();
+    return index_iter->second;
+  }
+
+  // Erases the item referenced by the given iterator. An iterator to the item
+  // following it will be returned. The iterator must be valid.
+  iterator Erase(iterator pos) {
+    deletor_(pos->second);
+    index_.erase(pos->first);
+    return ordering_.erase(pos);
+  }
+
+  // MRUCache entries are often processed in reverse order, so we add this
+  // convenience function (not typically defined by STL containers).
+  reverse_iterator Erase(reverse_iterator pos) {
+    // We have to actually give it the incremented iterator to delete, since
+    // the forward iterator that base() returns is actually one past the item
+    // being iterated over.
+    return reverse_iterator(Erase((++pos).base()));
+  }
+
+  // Shrinks the cache so it only holds |new_size| items. If |new_size| is
+  // bigger or equal to the current number of items, this will do nothing.
+  void ShrinkToSize(size_type new_size) {
+    for (size_type i = size(); i > new_size; i--)
+      Erase(rbegin());
+  }
+
+  // Deletes everything from the cache.
+  void Clear() {
+    for (typename PayloadList::iterator i(ordering_.begin());
+         i != ordering_.end(); ++i)
+      deletor_(i->second);
+    index_.clear();
+    ordering_.clear();
+  }
+
+  // Returns the number of elements in the cache.
+  size_type size() const {
+    // We don't use ordering_.size() for the return value because
+    // (as a linked list) it can be O(n).
+    DCHECK(index_.size() == ordering_.size());
+    return index_.size();
+  }
+
+  // Allows iteration over the list. Forward iteration starts with the most
+  // recent item and works backwards.
+  //
+  // Note that since these iterators are actually iterators over a list, you
+  // can keep them as you insert or delete things (as long as you don't delete
+  // the one you are pointing to) and they will still be valid.
+  iterator begin() { return ordering_.begin(); }
+  const_iterator begin() const { return ordering_.begin(); }
+  iterator end() { return ordering_.end(); }
+  const_iterator end() const { return ordering_.end(); }
+
+  reverse_iterator rbegin() { return ordering_.rbegin(); }
+  const_reverse_iterator rbegin() const { return ordering_.rbegin(); }
+  reverse_iterator rend() { return ordering_.rend(); }
+  const_reverse_iterator rend() const { return ordering_.rend(); }
+
+  bool empty() const { return ordering_.empty(); }
+
+ private:
+  PayloadList ordering_;
+  KeyIndex index_;
+
+  size_type max_size_;
+
+  DeletorType deletor_;
+
+  DISALLOW_COPY_AND_ASSIGN(MRUCacheBase);
+};
+
+// MRUCache --------------------------------------------------------------------
+
+// A functor that does nothing. Used by the MRUCache.
+template<class PayloadType>
+class MRUCacheNullDeletor {
+ public:
+  void operator()(const PayloadType& payload) {}
+};
+
+// A container that does not do anything to free its data. Use this when storing
+// value types (as opposed to pointers) in the list.
+template <class KeyType, class PayloadType>
+class MRUCache : public MRUCacheBase<KeyType,
+                                     PayloadType,
+                                     MRUCacheNullDeletor<PayloadType> > {
+ private:
+  typedef MRUCacheBase<KeyType, PayloadType,
+      MRUCacheNullDeletor<PayloadType> > ParentType;
+
+ public:
+  // See MRUCacheBase, noting the possibility of using NO_AUTO_EVICT.
+  explicit MRUCache(typename ParentType::size_type max_size)
+      : ParentType(max_size) {
+  }
+  virtual ~MRUCache() {
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MRUCache);
+};
+
+// OwningMRUCache --------------------------------------------------------------
+
+template<class PayloadType>
+class MRUCachePointerDeletor {
+ public:
+  void operator()(const PayloadType& payload) { delete payload; }
+};
+
+// A cache that owns the payload type, which must be a non-const pointer type.
+// The pointers will be deleted when they are removed, replaced, or when the
+// cache is destroyed.
+template <class KeyType, class PayloadType>
+class OwningMRUCache
+    : public MRUCacheBase<KeyType,
+                          PayloadType,
+                          MRUCachePointerDeletor<PayloadType> > {
+ private:
+  typedef MRUCacheBase<KeyType, PayloadType,
+      MRUCachePointerDeletor<PayloadType> > ParentType;
+
+ public:
+  // See MRUCacheBase, noting the possibility of using NO_AUTO_EVICT.
+  explicit OwningMRUCache(typename ParentType::size_type max_size)
+      : ParentType(max_size) {
+  }
+  virtual ~OwningMRUCache() {
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(OwningMRUCache);
+};
+
+// HashingMRUCache ------------------------------------------------------------
+
+template <class KeyType, class ValueType>
+struct MRUCacheHashMap {
+  typedef base::hash_map<KeyType, ValueType> Type;
+};
+
+// This class is similar to MRUCache, except that it uses base::hash_map as
+// the map type instead of std::map. Note that your KeyType must be hashable
+// to use this cache.
+template <class KeyType, class PayloadType>
+class HashingMRUCache : public MRUCacheBase<KeyType,
+                                            PayloadType,
+                                            MRUCacheNullDeletor<PayloadType>,
+                                            MRUCacheHashMap> {
+ private:
+  typedef MRUCacheBase<KeyType, PayloadType,
+                       MRUCacheNullDeletor<PayloadType>,
+                       MRUCacheHashMap> ParentType;
+
+ public:
+  // See MRUCacheBase, noting the possibility of using NO_AUTO_EVICT.
+  explicit HashingMRUCache(typename ParentType::size_type max_size)
+      : ParentType(max_size) {
+  }
+  virtual ~HashingMRUCache() {
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HashingMRUCache);
+};
+
+}  // namespace base
+
+#endif  // BASE_CONTAINERS_MRU_CACHE_H_
diff --git a/base/containers/mru_cache_unittest.cc b/base/containers/mru_cache_unittest.cc
new file mode 100644
index 0000000..a8e8932
--- /dev/null
+++ b/base/containers/mru_cache_unittest.cc
@@ -0,0 +1,271 @@
+// Copyright (c) 2011 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/basictypes.h"
+#include "base/containers/mru_cache.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+int cached_item_live_count = 0;
+
+struct CachedItem {
+  CachedItem() : value(0) {
+    cached_item_live_count++;
+  }
+
+  explicit CachedItem(int new_value) : value(new_value) {
+    cached_item_live_count++;
+  }
+
+  explicit CachedItem(const CachedItem& other) : value(other.value) {
+    cached_item_live_count++;
+  }
+
+  ~CachedItem() {
+    cached_item_live_count--;
+  }
+
+  int value;
+};
+
+}  // namespace
+
+TEST(MRUCacheTest, Basic) {
+  typedef base::MRUCache<int, CachedItem> Cache;
+  Cache cache(Cache::NO_AUTO_EVICT);
+
+  // Check failure conditions
+  {
+    CachedItem test_item;
+    EXPECT_TRUE(cache.Get(0) == cache.end());
+    EXPECT_TRUE(cache.Peek(0) == cache.end());
+  }
+
+  static const int kItem1Key = 5;
+  CachedItem item1(10);
+  Cache::iterator inserted_item = cache.Put(kItem1Key, item1);
+  EXPECT_EQ(1U, cache.size());
+
+  // Check that item1 was properly inserted.
+  {
+    Cache::iterator found = cache.Get(kItem1Key);
+    EXPECT_TRUE(inserted_item == cache.begin());
+    EXPECT_TRUE(found != cache.end());
+
+    found = cache.Peek(kItem1Key);
+    EXPECT_TRUE(found != cache.end());
+
+    EXPECT_EQ(kItem1Key, found->first);
+    EXPECT_EQ(item1.value, found->second.value);
+  }
+
+  static const int kItem2Key = 7;
+  CachedItem item2(12);
+  cache.Put(kItem2Key, item2);
+  EXPECT_EQ(2U, cache.size());
+
+  // Check that item1 is the oldest since item2 was added afterwards.
+  {
+    Cache::reverse_iterator oldest = cache.rbegin();
+    ASSERT_TRUE(oldest != cache.rend());
+    EXPECT_EQ(kItem1Key, oldest->first);
+    EXPECT_EQ(item1.value, oldest->second.value);
+  }
+
+  // Check that item1 is still accessible by key.
+  {
+    Cache::iterator test_item = cache.Get(kItem1Key);
+    ASSERT_TRUE(test_item != cache.end());
+    EXPECT_EQ(kItem1Key, test_item->first);
+    EXPECT_EQ(item1.value, test_item->second.value);
+  }
+
+  // Check that retrieving item1 pushed item2 to oldest.
+  {
+    Cache::reverse_iterator oldest = cache.rbegin();
+    ASSERT_TRUE(oldest != cache.rend());
+    EXPECT_EQ(kItem2Key, oldest->first);
+    EXPECT_EQ(item2.value, oldest->second.value);
+  }
+
+  // Remove the oldest item and check that item1 is now the only member.
+  {
+    Cache::reverse_iterator next = cache.Erase(cache.rbegin());
+
+    EXPECT_EQ(1U, cache.size());
+
+    EXPECT_TRUE(next == cache.rbegin());
+    EXPECT_EQ(kItem1Key, next->first);
+    EXPECT_EQ(item1.value, next->second.value);
+
+    cache.Erase(cache.begin());
+    EXPECT_EQ(0U, cache.size());
+  }
+
+  // Check that Clear() works properly.
+  cache.Put(kItem1Key, item1);
+  cache.Put(kItem2Key, item2);
+  EXPECT_EQ(2U, cache.size());
+  cache.Clear();
+  EXPECT_EQ(0U, cache.size());
+}
+
+TEST(MRUCacheTest, GetVsPeek) {
+  typedef base::MRUCache<int, CachedItem> Cache;
+  Cache cache(Cache::NO_AUTO_EVICT);
+
+  static const int kItem1Key = 1;
+  CachedItem item1(10);
+  cache.Put(kItem1Key, item1);
+
+  static const int kItem2Key = 2;
+  CachedItem item2(20);
+  cache.Put(kItem2Key, item2);
+
+  // This should do nothing since the size is bigger than the number of items.
+  cache.ShrinkToSize(100);
+
+  // Check that item1 starts out as oldest
+  {
+    Cache::reverse_iterator iter = cache.rbegin();
+    ASSERT_TRUE(iter != cache.rend());
+    EXPECT_EQ(kItem1Key, iter->first);
+    EXPECT_EQ(item1.value, iter->second.value);
+  }
+
+  // Check that Peek doesn't change ordering
+  {
+    Cache::iterator peekiter = cache.Peek(kItem1Key);
+    ASSERT_TRUE(peekiter != cache.end());
+
+    Cache::reverse_iterator iter = cache.rbegin();
+    ASSERT_TRUE(iter != cache.rend());
+    EXPECT_EQ(kItem1Key, iter->first);
+    EXPECT_EQ(item1.value, iter->second.value);
+  }
+}
+
+TEST(MRUCacheTest, KeyReplacement) {
+  typedef base::MRUCache<int, CachedItem> Cache;
+  Cache cache(Cache::NO_AUTO_EVICT);
+
+  static const int kItem1Key = 1;
+  CachedItem item1(10);
+  cache.Put(kItem1Key, item1);
+
+  static const int kItem2Key = 2;
+  CachedItem item2(20);
+  cache.Put(kItem2Key, item2);
+
+  static const int kItem3Key = 3;
+  CachedItem item3(30);
+  cache.Put(kItem3Key, item3);
+
+  static const int kItem4Key = 4;
+  CachedItem item4(40);
+  cache.Put(kItem4Key, item4);
+
+  CachedItem item5(50);
+  cache.Put(kItem3Key, item5);
+
+  EXPECT_EQ(4U, cache.size());
+  for (int i = 0; i < 3; ++i) {
+    Cache::reverse_iterator iter = cache.rbegin();
+    ASSERT_TRUE(iter != cache.rend());
+  }
+
+  // Make it so only the most important element is there.
+  cache.ShrinkToSize(1);
+
+  Cache::iterator iter = cache.begin();
+  EXPECT_EQ(kItem3Key, iter->first);
+  EXPECT_EQ(item5.value, iter->second.value);
+}
+
+// Make sure that the owning version release its pointers properly.
+TEST(MRUCacheTest, Owning) {
+  typedef base::OwningMRUCache<int, CachedItem*> Cache;
+  Cache cache(Cache::NO_AUTO_EVICT);
+
+  int initial_count = cached_item_live_count;
+
+  // First insert and item and then overwrite it.
+  static const int kItem1Key = 1;
+  cache.Put(kItem1Key, new CachedItem(20));
+  cache.Put(kItem1Key, new CachedItem(22));
+
+  // There should still be one item, and one extra live item.
+  Cache::iterator iter = cache.Get(kItem1Key);
+  EXPECT_EQ(1U, cache.size());
+  EXPECT_TRUE(iter != cache.end());
+  EXPECT_EQ(initial_count + 1, cached_item_live_count);
+
+  // Now remove it.
+  cache.Erase(cache.begin());
+  EXPECT_EQ(initial_count, cached_item_live_count);
+
+  // Now try another cache that goes out of scope to make sure its pointers
+  // go away.
+  {
+    Cache cache2(Cache::NO_AUTO_EVICT);
+    cache2.Put(1, new CachedItem(20));
+    cache2.Put(2, new CachedItem(20));
+  }
+
+  // There should be no objects leaked.
+  EXPECT_EQ(initial_count, cached_item_live_count);
+
+  // Check that Clear() also frees things correctly.
+  {
+    Cache cache2(Cache::NO_AUTO_EVICT);
+    cache2.Put(1, new CachedItem(20));
+    cache2.Put(2, new CachedItem(20));
+    EXPECT_EQ(initial_count + 2, cached_item_live_count);
+    cache2.Clear();
+    EXPECT_EQ(initial_count, cached_item_live_count);
+  }
+}
+
+TEST(MRUCacheTest, AutoEvict) {
+  typedef base::OwningMRUCache<int, CachedItem*> Cache;
+  static const Cache::size_type kMaxSize = 3;
+
+  int initial_count = cached_item_live_count;
+
+  {
+    Cache cache(kMaxSize);
+
+    static const int kItem1Key = 1, kItem2Key = 2, kItem3Key = 3, kItem4Key = 4;
+    cache.Put(kItem1Key, new CachedItem(20));
+    cache.Put(kItem2Key, new CachedItem(21));
+    cache.Put(kItem3Key, new CachedItem(22));
+    cache.Put(kItem4Key, new CachedItem(23));
+
+    // The cache should only have kMaxSize items in it even though we inserted
+    // more.
+    EXPECT_EQ(kMaxSize, cache.size());
+  }
+
+  // There should be no objects leaked.
+  EXPECT_EQ(initial_count, cached_item_live_count);
+}
+
+TEST(MRUCacheTest, HashingMRUCache) {
+  // Very simple test to make sure that the hashing cache works correctly.
+  typedef base::HashingMRUCache<std::string, CachedItem> Cache;
+  Cache cache(Cache::NO_AUTO_EVICT);
+
+  CachedItem one(1);
+  cache.Put("First", one);
+
+  CachedItem two(2);
+  cache.Put("Second", two);
+
+  EXPECT_EQ(one.value, cache.Get("First")->second.value);
+  EXPECT_EQ(two.value, cache.Get("Second")->second.value);
+  cache.ShrinkToSize(1);
+  EXPECT_EQ(two.value, cache.Get("Second")->second.value);
+  EXPECT_TRUE(cache.Get("First") == cache.end());
+}
diff --git a/base/containers/scoped_ptr_hash_map.h b/base/containers/scoped_ptr_hash_map.h
new file mode 100644
index 0000000..8fe550e
--- /dev/null
+++ b/base/containers/scoped_ptr_hash_map.h
@@ -0,0 +1,172 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_CONTAINERS_SCOPED_PTR_HASH_MAP_H_
+#define BASE_CONTAINERS_SCOPED_PTR_HASH_MAP_H_
+
+#include <algorithm>
+#include <utility>
+
+#include "base/basictypes.h"
+#include "base/containers/hash_tables.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/stl_util.h"
+
+namespace base {
+
+// This type acts like a hash_map<K, scoped_ptr<V, D> >, based on top of
+// base::hash_map. The ScopedPtrHashMap has ownership of all values in the data
+// structure.
+template <typename Key, typename ScopedPtr>
+class ScopedPtrHashMap {
+  typedef base::hash_map<Key, typename ScopedPtr::element_type*> Container;
+
+ public:
+  typedef typename Container::key_type key_type;
+  typedef typename Container::mapped_type mapped_type;
+  typedef typename Container::value_type value_type;
+  typedef typename Container::iterator iterator;
+  typedef typename Container::const_iterator const_iterator;
+
+  ScopedPtrHashMap() {}
+
+  ~ScopedPtrHashMap() { clear(); }
+
+  void swap(ScopedPtrHashMap<Key, ScopedPtr>& other) {
+    data_.swap(other.data_);
+  }
+
+  // Replaces value but not key if key is already present.
+  iterator set(const Key& key, ScopedPtr data) {
+    iterator it = find(key);
+    if (it != end()) {
+      // Let ScopedPtr decide how to delete. For example, it may use custom
+      // deleter.
+      ScopedPtr(it->second).reset();
+      it->second = data.release();
+      return it;
+    }
+
+    return data_.insert(std::make_pair(key, data.release())).first;
+  }
+
+  // Does nothing if key is already present
+  std::pair<iterator, bool> add(const Key& key, ScopedPtr data) {
+    std::pair<iterator, bool> result =
+        data_.insert(std::make_pair(key, data.get()));
+    if (result.second)
+      ignore_result(data.release());
+    return result;
+  }
+
+  void erase(iterator it) {
+    // Let ScopedPtr decide how to delete.
+    ScopedPtr(it->second).reset();
+    data_.erase(it);
+  }
+
+  size_t erase(const Key& k) {
+    iterator it = data_.find(k);
+    if (it == data_.end())
+      return 0;
+    erase(it);
+    return 1;
+  }
+
+  ScopedPtr take(iterator it) {
+    DCHECK(it != data_.end());
+    if (it == data_.end())
+      return ScopedPtr();
+
+    ScopedPtr ret(it->second);
+    it->second = NULL;
+    return ret.Pass();
+  }
+
+  ScopedPtr take(const Key& k) {
+    iterator it = find(k);
+    if (it == data_.end())
+      return ScopedPtr();
+
+    return take(it);
+  }
+
+  ScopedPtr take_and_erase(iterator it) {
+    DCHECK(it != data_.end());
+    if (it == data_.end())
+      return ScopedPtr();
+
+    ScopedPtr ret(it->second);
+    data_.erase(it);
+    return ret.Pass();
+  }
+
+  ScopedPtr take_and_erase(const Key& k) {
+    iterator it = find(k);
+    if (it == data_.end())
+      return ScopedPtr();
+
+    return take_and_erase(it);
+  }
+
+  // Returns the element in the hash_map that matches the given key.
+  // If no such element exists it returns NULL.
+  typename ScopedPtr::element_type* get(const Key& k) const {
+    const_iterator it = find(k);
+    if (it == end())
+      return NULL;
+    return it->second;
+  }
+
+  inline bool contains(const Key& k) const { return data_.count(k) > 0; }
+
+  inline void clear() {
+    auto it = data_.begin();
+    while (it != data_.end()) {
+      // NOTE: Like STLDeleteContainerPointers, deleting behind the iterator.
+      // Deleting the value does not always invalidate the iterator, but it may
+      // do so if the key is a pointer into the value object.
+      auto temp = it;
+      ++it;
+      // Let ScopedPtr decide how to delete.
+      ScopedPtr(temp->second).reset();
+    }
+    data_.clear();
+  }
+
+  inline const_iterator find(const Key& k) const { return data_.find(k); }
+  inline iterator find(const Key& k) { return data_.find(k); }
+
+  inline size_t count(const Key& k) const { return data_.count(k); }
+  inline std::pair<const_iterator, const_iterator> equal_range(
+      const Key& k) const {
+    return data_.equal_range(k);
+  }
+  inline std::pair<iterator, iterator> equal_range(const Key& k) {
+    return data_.equal_range(k);
+  }
+
+  inline size_t size() const { return data_.size(); }
+  inline size_t max_size() const { return data_.max_size(); }
+
+  inline bool empty() const { return data_.empty(); }
+
+  inline size_t bucket_count() const { return data_.bucket_count(); }
+  inline void resize(size_t size) { return data_.resize(size); }
+
+  inline iterator begin() { return data_.begin(); }
+  inline const_iterator begin() const { return data_.begin(); }
+  inline iterator end() { return data_.end(); }
+  inline const_iterator end() const { return data_.end(); }
+
+ private:
+  Container data_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedPtrHashMap);
+};
+
+}  // namespace base
+
+#endif  // BASE_CONTAINERS_SCOPED_PTR_HASH_MAP_H_
diff --git a/base/containers/scoped_ptr_hash_map_unittest.cc b/base/containers/scoped_ptr_hash_map_unittest.cc
new file mode 100644
index 0000000..88fe41f
--- /dev/null
+++ b/base/containers/scoped_ptr_hash_map_unittest.cc
@@ -0,0 +1,85 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/containers/scoped_ptr_hash_map.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+struct DeleteCounter {
+ public:
+  DeleteCounter() {}
+  ~DeleteCounter() { g_delete_count++; }
+
+  static void ResetCounter() { g_delete_count = 0; }
+  static int delete_count() { return g_delete_count; }
+
+ private:
+  static int g_delete_count;
+};
+
+int DeleteCounter::g_delete_count = 0;
+
+struct CountingDeleter {
+ public:
+  inline void operator()(DeleteCounter* ptr) const {
+    g_deleter_call_count++;
+    delete ptr;
+  }
+
+  static int count() { return g_deleter_call_count; }
+  static void ResetCounter() { g_deleter_call_count = 0; }
+
+ private:
+  static int g_deleter_call_count;
+};
+
+int CountingDeleter::g_deleter_call_count = 0;
+
+TEST(ScopedPtrHashMapTest, CustomDeleter) {
+  int key = 123;
+
+  // Test dtor.
+  DeleteCounter::ResetCounter();
+  CountingDeleter::ResetCounter();
+  {
+    ScopedPtrHashMap<int, scoped_ptr<DeleteCounter, CountingDeleter>> map;
+    map.set(key, scoped_ptr<DeleteCounter, CountingDeleter>(new DeleteCounter));
+  }
+  EXPECT_EQ(1, DeleteCounter::delete_count());
+  EXPECT_EQ(1, CountingDeleter::count());
+
+  // Test set and erase.
+  DeleteCounter::ResetCounter();
+  CountingDeleter::ResetCounter();
+  {
+    ScopedPtrHashMap<int, scoped_ptr<DeleteCounter, CountingDeleter>> map;
+    map.erase(map.set(
+        key, scoped_ptr<DeleteCounter, CountingDeleter>(new DeleteCounter)));
+    EXPECT_EQ(1, DeleteCounter::delete_count());
+    EXPECT_EQ(1, CountingDeleter::count());
+  }
+  EXPECT_EQ(1, DeleteCounter::delete_count());
+  EXPECT_EQ(1, CountingDeleter::count());
+
+  // Test set more than once.
+  DeleteCounter::ResetCounter();
+  CountingDeleter::ResetCounter();
+  {
+    ScopedPtrHashMap<int, scoped_ptr<DeleteCounter, CountingDeleter>> map;
+    map.set(key, scoped_ptr<DeleteCounter, CountingDeleter>(new DeleteCounter));
+    map.set(key, scoped_ptr<DeleteCounter, CountingDeleter>(new DeleteCounter));
+    map.set(key, scoped_ptr<DeleteCounter, CountingDeleter>(new DeleteCounter));
+    EXPECT_EQ(2, DeleteCounter::delete_count());
+    EXPECT_EQ(2, CountingDeleter::count());
+  }
+  EXPECT_EQ(3, DeleteCounter::delete_count());
+  EXPECT_EQ(3, CountingDeleter::count());
+}
+
+}  // namespace
+}  // namespace base
diff --git a/base/containers/scoped_ptr_map.h b/base/containers/scoped_ptr_map.h
new file mode 100644
index 0000000..19a1153
--- /dev/null
+++ b/base/containers/scoped_ptr_map.h
@@ -0,0 +1,137 @@
+// 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_CONTAINERS_SCOPED_PTR_MAP_H_
+#define BASE_CONTAINERS_SCOPED_PTR_MAP_H_
+
+#include <map>
+#include <utility>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/move.h"
+#include "base/stl_util.h"
+
+// ScopedPtrMap provides a std::map that supports scoped_ptr values. It ensures
+// that the map's values are properly deleted when removed from the map, or when
+// the map is destroyed.
+//
+// |ScopedPtr| must be a type scoped_ptr<T>. This is for compatibility with
+// std::map in C++11.
+template <class Key, class ScopedPtr>
+class ScopedPtrMap {
+  MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(ScopedPtrMap)
+
+  using Container = std::map<Key, typename ScopedPtr::element_type*>;
+
+ public:
+  using allocator_type = typename Container::allocator_type;
+  using size_type = typename Container::size_type;
+  using difference_type = typename Container::difference_type;
+  using reference = typename Container::reference;
+  using const_reference = typename Container::const_reference;
+  using key_type = typename Container::key_type;
+  using const_iterator = typename Container::const_iterator;
+  using const_reverse_iterator = typename Container::const_reverse_iterator;
+
+  ScopedPtrMap() {}
+  ~ScopedPtrMap() { clear(); }
+  ScopedPtrMap(ScopedPtrMap<Key, ScopedPtr>&& other) { swap(other); }
+
+  ScopedPtrMap& operator=(ScopedPtrMap<Key, ScopedPtr>&& rhs) {
+    swap(rhs);
+    return *this;
+  }
+
+  const_iterator find(const Key& k) const { return data_.find(k); }
+  size_type count(const Key& k) const { return data_.count(k); }
+
+  bool empty() const { return data_.empty(); }
+  size_t size() const { return data_.size(); }
+
+  const_reverse_iterator rbegin() const { return data_.rbegin(); }
+  const_reverse_iterator rend() const { return data_.rend(); }
+
+  const_iterator begin() const { return data_.begin(); }
+  const_iterator end() const { return data_.end(); }
+
+  void swap(ScopedPtrMap<Key, ScopedPtr>& other) { data_.swap(other.data_); }
+
+  void clear() { STLDeleteValues(&data_); }
+
+  // Inserts |val| into the map, associated with |key|.
+  std::pair<const_iterator, bool> insert(const Key& key, ScopedPtr val) {
+    auto result = data_.insert(std::make_pair(key, val.get()));
+    if (result.second)
+      ignore_result(val.release());
+    return result;
+  }
+
+  // Inserts |val| into the map, associated with |key|. Overwrites any existing
+  // element at |key|.
+  void set(const Key& key, ScopedPtr val) {
+    typename ScopedPtr::element_type*& val_ref = data_[key];
+    delete val_ref;
+    val_ref = val.release();
+  }
+
+  void erase(const_iterator position) {
+    DCHECK(position != end());
+    delete position->second;
+    // Key-based lookup (cannot use const_iterator overload in C++03 library).
+    data_.erase(position->first);
+  }
+
+  size_type erase(const Key& k) {
+    typename Container::iterator it = data_.find(k);
+    if (it == end())
+      return 0;
+
+    delete it->second;
+    data_.erase(it);
+    return 1;
+  }
+
+  void erase(const_iterator first, const_iterator last) {
+    STLDeleteContainerPairSecondPointers(first, last);
+    // Need non-const iterators as required by the C++03 library.
+    data_.erase(ConstIteratorToIterator(first), ConstIteratorToIterator(last));
+  }
+
+  // Like |erase()|, but returns the element instead of deleting it.
+  ScopedPtr take_and_erase(const_iterator position) {
+    DCHECK(position != end());
+    if (position == end())
+      return ScopedPtr();
+
+    ScopedPtr ret(position->second);
+    // Key-based lookup (cannot use const_iterator overload in C++03 library).
+    data_.erase(position->first);
+    return ret.Pass();
+  }
+
+  // Like |erase()|, but returns the element instead of deleting it.
+  ScopedPtr take_and_erase(const Key& k) {
+    typename Container::iterator it = data_.find(k);
+    if (it == end())
+      return ScopedPtr();
+
+    ScopedPtr ret(it->second);
+    data_.erase(it);
+    return ret.Pass();
+  }
+
+ private:
+  Container data_;
+
+  typename Container::iterator ConstIteratorToIterator(const_iterator it) {
+    // This is the only way to convert a const iterator to a non-const iterator
+    // in C++03 (get the key and do the lookup again).
+    if (it == data_.end())
+      return data_.end();
+    return data_.find(it->first);
+  };
+};
+
+#endif  // BASE_CONTAINERS_SCOPED_PTR_MAP_H_
diff --git a/base/containers/scoped_ptr_map_unittest.cc b/base/containers/scoped_ptr_map_unittest.cc
new file mode 100644
index 0000000..ef70440
--- /dev/null
+++ b/base/containers/scoped_ptr_map_unittest.cc
@@ -0,0 +1,224 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/containers/scoped_ptr_map.h"
+
+#include <map>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// A ScopedDestroyer sets a Boolean to true upon destruction.
+class ScopedDestroyer {
+ public:
+  ScopedDestroyer(bool* destroyed) : destroyed_(destroyed) {
+    *destroyed_ = false;
+  }
+
+  ~ScopedDestroyer() { *destroyed_ = true; }
+
+ private:
+  bool* destroyed_;
+};
+
+TEST(ScopedPtrMapTest, Insert) {
+  bool destroyed1 = false;
+  bool destroyed2 = false;
+  {
+    ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
+
+    // Insert to new key.
+    ScopedDestroyer* elem1 = new ScopedDestroyer(&destroyed1);
+    EXPECT_FALSE(destroyed1);
+    EXPECT_TRUE(scoped_map.insert(0, make_scoped_ptr(elem1)).second);
+    EXPECT_EQ(elem1, scoped_map.find(0)->second);
+    EXPECT_FALSE(destroyed1);
+
+    // Insert to existing key.
+    ScopedDestroyer* elem2 = new ScopedDestroyer(&destroyed2);
+    EXPECT_FALSE(destroyed2);
+    EXPECT_FALSE(scoped_map.insert(0, make_scoped_ptr(elem2)).second);
+    EXPECT_EQ(elem1, scoped_map.find(0)->second);
+
+    EXPECT_FALSE(destroyed1);
+    EXPECT_TRUE(destroyed2);
+  }
+  EXPECT_TRUE(destroyed1);
+}
+
+TEST(ScopedPtrMapTest, Set) {
+  bool destroyed1 = false;
+  bool destroyed2 = false;
+  {
+    ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
+
+    // Set a new key.
+    ScopedDestroyer* elem1 = new ScopedDestroyer(&destroyed1);
+    EXPECT_FALSE(destroyed1);
+    scoped_map.set(0, make_scoped_ptr(elem1));
+    EXPECT_EQ(elem1, scoped_map.find(0)->second);
+    EXPECT_FALSE(destroyed1);
+
+    // Set to replace an existing key.
+    ScopedDestroyer* elem2 = new ScopedDestroyer(&destroyed2);
+    EXPECT_FALSE(destroyed2);
+    scoped_map.set(0, make_scoped_ptr(elem2));
+    EXPECT_EQ(elem2, scoped_map.find(0)->second);
+
+    EXPECT_TRUE(destroyed1);
+    EXPECT_FALSE(destroyed2);
+  }
+  EXPECT_TRUE(destroyed1);
+  EXPECT_TRUE(destroyed2);
+}
+
+TEST(ScopedPtrMapTest, EraseIterator) {
+  bool destroyed = false;
+  ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
+  scoped_map.insert(0, make_scoped_ptr(new ScopedDestroyer(&destroyed)));
+  EXPECT_FALSE(destroyed);
+  scoped_map.erase(scoped_map.find(0));
+  EXPECT_TRUE(destroyed);
+  EXPECT_TRUE(scoped_map.empty());
+}
+
+TEST(ScopedPtrMapTest, EraseKey) {
+  bool destroyed = false;
+  ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
+  scoped_map.insert(0, make_scoped_ptr(new ScopedDestroyer(&destroyed)));
+  EXPECT_FALSE(destroyed);
+  EXPECT_EQ(1u, scoped_map.erase(0));
+  EXPECT_TRUE(destroyed);
+  EXPECT_TRUE(scoped_map.empty());
+
+  // Test erase of a non-existent key.
+  EXPECT_EQ(0u, scoped_map.erase(7));
+}
+
+TEST(ScopedPtrMapTest, EraseRange) {
+  bool destroyed1 = false;
+  bool destroyed2 = false;
+  ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
+
+  scoped_map.insert(0, make_scoped_ptr(new ScopedDestroyer(&destroyed1)));
+  EXPECT_FALSE(destroyed1);
+
+  scoped_map.insert(1, make_scoped_ptr(new ScopedDestroyer(&destroyed2)));
+  EXPECT_FALSE(destroyed2);
+
+  scoped_map.erase(scoped_map.find(0), scoped_map.end());
+  EXPECT_TRUE(destroyed1);
+  EXPECT_TRUE(destroyed2);
+  EXPECT_TRUE(scoped_map.empty());
+}
+
+TEST(ScopedPtrMapTest, TakeAndErase) {
+  bool destroyed = false;
+  ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
+  ScopedDestroyer* elem = new ScopedDestroyer(&destroyed);
+  scoped_map.insert(0, make_scoped_ptr(elem));
+  EXPECT_EQ(elem, scoped_map.find(0)->second);
+  EXPECT_FALSE(destroyed);
+  scoped_ptr<ScopedDestroyer> object = scoped_map.take_and_erase(0);
+  EXPECT_EQ(elem, object.get());
+  EXPECT_FALSE(destroyed);
+  EXPECT_TRUE(scoped_map.empty());
+  object.reset();
+  EXPECT_TRUE(destroyed);
+}
+
+TEST(ScopedPtrMapTest, Clear) {
+  bool destroyed = false;
+  ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
+  scoped_map.insert(0, make_scoped_ptr(new ScopedDestroyer(&destroyed)));
+  EXPECT_FALSE(destroyed);
+  scoped_map.clear();
+  EXPECT_TRUE(destroyed);
+  EXPECT_TRUE(scoped_map.empty());
+}
+
+TEST(ScopedPtrMapTest, Scope) {
+  bool destroyed = false;
+  {
+    ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
+    scoped_map.insert(0, make_scoped_ptr(new ScopedDestroyer(&destroyed)));
+    EXPECT_FALSE(destroyed);
+  }
+  EXPECT_TRUE(destroyed);
+}
+
+TEST(ScopedPtrMapTest, MoveConstruct) {
+  bool destroyed = false;
+  {
+    ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
+    ScopedDestroyer* elem = new ScopedDestroyer(&destroyed);
+    scoped_map.insert(0, make_scoped_ptr(elem));
+    EXPECT_EQ(elem, scoped_map.find(0)->second);
+    EXPECT_FALSE(destroyed);
+    EXPECT_FALSE(scoped_map.empty());
+
+    ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map_copy(
+        scoped_map.Pass());
+    EXPECT_TRUE(scoped_map.empty());
+    EXPECT_FALSE(scoped_map_copy.empty());
+    EXPECT_EQ(elem, scoped_map_copy.find(0)->second);
+    EXPECT_FALSE(destroyed);
+  }
+  EXPECT_TRUE(destroyed);
+}
+
+TEST(ScopedPtrMapTest, MoveAssign) {
+  bool destroyed = false;
+  {
+    ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
+    ScopedDestroyer* elem = new ScopedDestroyer(&destroyed);
+    scoped_map.insert(0, make_scoped_ptr(elem));
+    EXPECT_EQ(elem, scoped_map.find(0)->second);
+    EXPECT_FALSE(destroyed);
+    EXPECT_FALSE(scoped_map.empty());
+
+    ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map_assign;
+    scoped_map_assign = scoped_map.Pass();
+    EXPECT_TRUE(scoped_map.empty());
+    EXPECT_FALSE(scoped_map_assign.empty());
+    EXPECT_EQ(elem, scoped_map_assign.find(0)->second);
+    EXPECT_FALSE(destroyed);
+  }
+  EXPECT_TRUE(destroyed);
+}
+
+template <typename Key, typename ScopedPtr>
+ScopedPtrMap<Key, ScopedPtr> PassThru(ScopedPtrMap<Key, ScopedPtr> scoper) {
+  return scoper;
+}
+
+TEST(ScopedPtrMapTest, Passed) {
+  bool destroyed = false;
+  ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
+  ScopedDestroyer* elem = new ScopedDestroyer(&destroyed);
+  scoped_map.insert(0, make_scoped_ptr(elem));
+  EXPECT_EQ(elem, scoped_map.find(0)->second);
+  EXPECT_FALSE(destroyed);
+
+  base::Callback<ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>>(void)>
+      callback = base::Bind(&PassThru<int, scoped_ptr<ScopedDestroyer>>,
+                            base::Passed(&scoped_map));
+  EXPECT_TRUE(scoped_map.empty());
+  EXPECT_FALSE(destroyed);
+
+  ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> result = callback.Run();
+  EXPECT_TRUE(scoped_map.empty());
+  EXPECT_EQ(elem, result.find(0)->second);
+  EXPECT_FALSE(destroyed);
+
+  result.clear();
+  EXPECT_TRUE(destroyed);
+};
+
+}  // namespace
diff --git a/base/containers/small_map.h b/base/containers/small_map.h
new file mode 100644
index 0000000..df3d22a
--- /dev/null
+++ b/base/containers/small_map.h
@@ -0,0 +1,652 @@
+// Copyright (c) 2012 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_CONTAINERS_SMALL_MAP_H_
+#define BASE_CONTAINERS_SMALL_MAP_H_
+
+#include <map>
+#include <string>
+#include <utility>
+
+#include "base/basictypes.h"
+#include "base/containers/hash_tables.h"
+#include "base/logging.h"
+#include "base/memory/manual_constructor.h"
+
+namespace base {
+
+// An STL-like associative container which starts out backed by a simple
+// array but switches to some other container type if it grows beyond a
+// fixed size.
+//
+// WHAT TYPE OF MAP SHOULD YOU USE?
+// --------------------------------
+//
+//  - std::map should be the default if you're not sure, since it's the most
+//    difficult to mess up. Generally this is backed by a red-black tree. It
+//    will generate a lot of code (if you use a common key type like int or
+//    string the linker will probably emiminate the duplicates). It will
+//    do heap allocations for each element.
+//
+//  - If you only ever keep a couple of items and have very simple usage,
+//    consider whether a using a vector and brute-force searching it will be
+//    the most efficient. It's not a lot of generated code (less then a
+//    red-black tree if your key is "weird" and not eliminated as duplicate of
+//    something else) and will probably be faster and do fewer heap allocations
+//    than std::map if you have just a couple of items.
+//
+//  - base::hash_map should be used if you need O(1) lookups. It may waste
+//    space in the hash table, and it can be easy to write correct-looking
+//    code with the default hash function being wrong or poorly-behaving.
+//
+//  - SmallMap combines the performance benefits of the brute-force-searched
+//    vector for small cases (no extra heap allocations), but can efficiently
+//    fall back if you end up adding many items. It will generate more code
+//    than std::map (at least 160 bytes for operator[]) which is bad if you
+//    have a "weird" key where map functions can't be
+//    duplicate-code-eliminated. If you have a one-off key and aren't in
+//    performance-critical code, this bloat may negate some of the benefits and
+//    you should consider on of the other options.
+//
+// SmallMap will pick up the comparator from the underlying map type. In
+// std::map (and in MSVC additionally hash_map) only a "less" operator is
+// defined, which requires us to do two comparisons per element when doing the
+// brute-force search in the simple array.
+//
+// We define default overrides for the common map types to avoid this
+// double-compare, but you should be aware of this if you use your own
+// operator< for your map and supply yor own version of == to the SmallMap.
+// You can use regular operator== by just doing:
+//
+//   base::SmallMap<std::map<MyKey, MyValue>, 4, std::equal_to<KyKey> >
+//
+//
+// USAGE
+// -----
+//
+// NormalMap:  The map type to fall back to.  This also defines the key
+//             and value types for the SmallMap.
+// kArraySize:  The size of the initial array of results. This will be
+//              allocated with the SmallMap object rather than separately on
+//              the heap. Once the map grows beyond this size, the map type
+//              will be used instead.
+// EqualKey:  A functor which tests two keys for equality.  If the wrapped
+//            map type has a "key_equal" member (hash_map does), then that will
+//            be used by default. If the wrapped map type has a strict weak
+//            ordering "key_compare" (std::map does), that will be used to
+//            implement equality by default.
+// MapInit: A functor that takes a ManualConstructor<NormalMap>* and uses it to
+//          initialize the map. This functor will be called at most once per
+//          SmallMap, when the map exceeds the threshold of kArraySize and we
+//          are about to copy values from the array to the map. The functor
+//          *must* call one of the Init() methods provided by
+//          ManualConstructor, since after it runs we assume that the NormalMap
+//          has been initialized.
+//
+// example:
+//   base::SmallMap< std::map<string, int> > days;
+//   days["sunday"   ] = 0;
+//   days["monday"   ] = 1;
+//   days["tuesday"  ] = 2;
+//   days["wednesday"] = 3;
+//   days["thursday" ] = 4;
+//   days["friday"   ] = 5;
+//   days["saturday" ] = 6;
+//
+// You should assume that SmallMap might invalidate all the iterators
+// on any call to erase(), insert() and operator[].
+
+namespace internal {
+
+template <typename NormalMap>
+class SmallMapDefaultInit {
+ public:
+  void operator()(ManualConstructor<NormalMap>* map) const {
+    map->Init();
+  }
+};
+
+// has_key_equal<M>::value is true iff there exists a type M::key_equal. This is
+// used to dispatch to one of the select_equal_key<> metafunctions below.
+template <typename M>
+struct has_key_equal {
+  typedef char sml;  // "small" is sometimes #defined so we use an abbreviation.
+  typedef struct { char dummy[2]; } big;
+  // Two functions, one accepts types that have a key_equal member, and one that
+  // accepts anything. They each return a value of a different size, so we can
+  // determine at compile-time which function would have been called.
+  template <typename U> static big test(typename U::key_equal*);
+  template <typename> static sml test(...);
+  // Determines if M::key_equal exists by looking at the size of the return
+  // type of the compiler-chosen test() function.
+  static const bool value = (sizeof(test<M>(0)) == sizeof(big));
+};
+template <typename M> const bool has_key_equal<M>::value;
+
+// Base template used for map types that do NOT have an M::key_equal member,
+// e.g., std::map<>. These maps have a strict weak ordering comparator rather
+// than an equality functor, so equality will be implemented in terms of that
+// comparator.
+//
+// There's a partial specialization of this template below for map types that do
+// have an M::key_equal member.
+template <typename M, bool has_key_equal_value>
+struct select_equal_key {
+  struct equal_key {
+    bool operator()(const typename M::key_type& left,
+                    const typename M::key_type& right) {
+      // Implements equality in terms of a strict weak ordering comparator.
+      typename M::key_compare comp;
+      return !comp(left, right) && !comp(right, left);
+    }
+  };
+};
+
+// Provide overrides to use operator== for key compare for the "normal" map and
+// hash map types. If you override the default comparator or allocator for a
+// map or hash_map, or use another type of map, this won't get used.
+//
+// If we switch to using std::unordered_map for base::hash_map, then the
+// hash_map specialization can be removed.
+template <typename KeyType, typename ValueType>
+struct select_equal_key< std::map<KeyType, ValueType>, false> {
+  struct equal_key {
+    bool operator()(const KeyType& left, const KeyType& right) {
+      return left == right;
+    }
+  };
+};
+template <typename KeyType, typename ValueType>
+struct select_equal_key< base::hash_map<KeyType, ValueType>, false> {
+  struct equal_key {
+    bool operator()(const KeyType& left, const KeyType& right) {
+      return left == right;
+    }
+  };
+};
+
+// Partial template specialization handles case where M::key_equal exists, e.g.,
+// hash_map<>.
+template <typename M>
+struct select_equal_key<M, true> {
+  typedef typename M::key_equal equal_key;
+};
+
+}  // namespace internal
+
+template <typename NormalMap,
+          int kArraySize = 4,
+          typename EqualKey =
+              typename internal::select_equal_key<
+                  NormalMap,
+                  internal::has_key_equal<NormalMap>::value>::equal_key,
+          typename MapInit = internal::SmallMapDefaultInit<NormalMap> >
+class SmallMap {
+  // We cannot rely on the compiler to reject array of size 0.  In
+  // particular, gcc 2.95.3 does it but later versions allow 0-length
+  // arrays.  Therefore, we explicitly reject non-positive kArraySize
+  // here.
+  COMPILE_ASSERT(kArraySize > 0, default_initial_size_should_be_positive);
+
+ public:
+  typedef typename NormalMap::key_type key_type;
+  typedef typename NormalMap::mapped_type data_type;
+  typedef typename NormalMap::mapped_type mapped_type;
+  typedef typename NormalMap::value_type value_type;
+  typedef EqualKey key_equal;
+
+  SmallMap() : size_(0), functor_(MapInit()) {}
+
+  explicit SmallMap(const MapInit& functor) : size_(0), functor_(functor) {}
+
+  // Allow copy-constructor and assignment, since STL allows them too.
+  SmallMap(const SmallMap& src) {
+    // size_ and functor_ are initted in InitFrom()
+    InitFrom(src);
+  }
+  void operator=(const SmallMap& src) {
+    if (&src == this) return;
+
+    // This is not optimal. If src and dest are both using the small
+    // array, we could skip the teardown and reconstruct. One problem
+    // to be resolved is that the value_type itself is pair<const K,
+    // V>, and const K is not assignable.
+    Destroy();
+    InitFrom(src);
+  }
+  ~SmallMap() {
+    Destroy();
+  }
+
+  class const_iterator;
+
+  class iterator {
+   public:
+    typedef typename NormalMap::iterator::iterator_category iterator_category;
+    typedef typename NormalMap::iterator::value_type value_type;
+    typedef typename NormalMap::iterator::difference_type difference_type;
+    typedef typename NormalMap::iterator::pointer pointer;
+    typedef typename NormalMap::iterator::reference reference;
+
+    inline iterator(): array_iter_(NULL) {}
+
+    inline iterator& operator++() {
+      if (array_iter_ != NULL) {
+        ++array_iter_;
+      } else {
+        ++hash_iter_;
+      }
+      return *this;
+    }
+    inline iterator operator++(int /*unused*/) {
+      iterator result(*this);
+      ++(*this);
+      return result;
+    }
+    inline iterator& operator--() {
+      if (array_iter_ != NULL) {
+        --array_iter_;
+      } else {
+        --hash_iter_;
+      }
+      return *this;
+    }
+    inline iterator operator--(int /*unused*/) {
+      iterator result(*this);
+      --(*this);
+      return result;
+    }
+    inline value_type* operator->() const {
+      if (array_iter_ != NULL) {
+        return array_iter_->get();
+      } else {
+        return hash_iter_.operator->();
+      }
+    }
+
+    inline value_type& operator*() const {
+      if (array_iter_ != NULL) {
+        return *array_iter_->get();
+      } else {
+        return *hash_iter_;
+      }
+    }
+
+    inline bool operator==(const iterator& other) const {
+      if (array_iter_ != NULL) {
+        return array_iter_ == other.array_iter_;
+      } else {
+        return other.array_iter_ == NULL && hash_iter_ == other.hash_iter_;
+      }
+    }
+
+    inline bool operator!=(const iterator& other) const {
+      return !(*this == other);
+    }
+
+    bool operator==(const const_iterator& other) const;
+    bool operator!=(const const_iterator& other) const;
+
+   private:
+    friend class SmallMap;
+    friend class const_iterator;
+    inline explicit iterator(ManualConstructor<value_type>* init)
+      : array_iter_(init) {}
+    inline explicit iterator(const typename NormalMap::iterator& init)
+      : array_iter_(NULL), hash_iter_(init) {}
+
+    ManualConstructor<value_type>* array_iter_;
+    typename NormalMap::iterator hash_iter_;
+  };
+
+  class const_iterator {
+   public:
+    typedef typename NormalMap::const_iterator::iterator_category
+        iterator_category;
+    typedef typename NormalMap::const_iterator::value_type value_type;
+    typedef typename NormalMap::const_iterator::difference_type difference_type;
+    typedef typename NormalMap::const_iterator::pointer pointer;
+    typedef typename NormalMap::const_iterator::reference reference;
+
+    inline const_iterator(): array_iter_(NULL) {}
+    // Non-explicit ctor lets us convert regular iterators to const iterators
+    inline const_iterator(const iterator& other)
+      : array_iter_(other.array_iter_), hash_iter_(other.hash_iter_) {}
+
+    inline const_iterator& operator++() {
+      if (array_iter_ != NULL) {
+        ++array_iter_;
+      } else {
+        ++hash_iter_;
+      }
+      return *this;
+    }
+    inline const_iterator operator++(int /*unused*/) {
+      const_iterator result(*this);
+      ++(*this);
+      return result;
+    }
+
+    inline const_iterator& operator--() {
+      if (array_iter_ != NULL) {
+        --array_iter_;
+      } else {
+        --hash_iter_;
+      }
+      return *this;
+    }
+    inline const_iterator operator--(int /*unused*/) {
+      const_iterator result(*this);
+      --(*this);
+      return result;
+    }
+
+    inline const value_type* operator->() const {
+      if (array_iter_ != NULL) {
+        return array_iter_->get();
+      } else {
+        return hash_iter_.operator->();
+      }
+    }
+
+    inline const value_type& operator*() const {
+      if (array_iter_ != NULL) {
+        return *array_iter_->get();
+      } else {
+        return *hash_iter_;
+      }
+    }
+
+    inline bool operator==(const const_iterator& other) const {
+      if (array_iter_ != NULL) {
+        return array_iter_ == other.array_iter_;
+      } else {
+        return other.array_iter_ == NULL && hash_iter_ == other.hash_iter_;
+      }
+    }
+
+    inline bool operator!=(const const_iterator& other) const {
+      return !(*this == other);
+    }
+
+   private:
+    friend class SmallMap;
+    inline explicit const_iterator(
+        const ManualConstructor<value_type>* init)
+      : array_iter_(init) {}
+    inline explicit const_iterator(
+        const typename NormalMap::const_iterator& init)
+      : array_iter_(NULL), hash_iter_(init) {}
+
+    const ManualConstructor<value_type>* array_iter_;
+    typename NormalMap::const_iterator hash_iter_;
+  };
+
+  iterator find(const key_type& key) {
+    key_equal compare;
+    if (size_ >= 0) {
+      for (int i = 0; i < size_; i++) {
+        if (compare(array_[i]->first, key)) {
+          return iterator(array_ + i);
+        }
+      }
+      return iterator(array_ + size_);
+    } else {
+      return iterator(map()->find(key));
+    }
+  }
+
+  const_iterator find(const key_type& key) const {
+    key_equal compare;
+    if (size_ >= 0) {
+      for (int i = 0; i < size_; i++) {
+        if (compare(array_[i]->first, key)) {
+          return const_iterator(array_ + i);
+        }
+      }
+      return const_iterator(array_ + size_);
+    } else {
+      return const_iterator(map()->find(key));
+    }
+  }
+
+  // Invalidates iterators.
+  data_type& operator[](const key_type& key) {
+    key_equal compare;
+
+    if (size_ >= 0) {
+      // operator[] searches backwards, favoring recently-added
+      // elements.
+      for (int i = size_-1; i >= 0; --i) {
+        if (compare(array_[i]->first, key)) {
+          return array_[i]->second;
+        }
+      }
+      if (size_ == kArraySize) {
+        ConvertToRealMap();
+        return (*map_)[key];
+      } else {
+        array_[size_].Init(key, data_type());
+        return array_[size_++]->second;
+      }
+    } else {
+      return (*map_)[key];
+    }
+  }
+
+  // Invalidates iterators.
+  std::pair<iterator, bool> insert(const value_type& x) {
+    key_equal compare;
+
+    if (size_ >= 0) {
+      for (int i = 0; i < size_; i++) {
+        if (compare(array_[i]->first, x.first)) {
+          return std::make_pair(iterator(array_ + i), false);
+        }
+      }
+      if (size_ == kArraySize) {
+        ConvertToRealMap();  // Invalidates all iterators!
+        std::pair<typename NormalMap::iterator, bool> ret = map_->insert(x);
+        return std::make_pair(iterator(ret.first), ret.second);
+      } else {
+        array_[size_].Init(x);
+        return std::make_pair(iterator(array_ + size_++), true);
+      }
+    } else {
+      std::pair<typename NormalMap::iterator, bool> ret = map_->insert(x);
+      return std::make_pair(iterator(ret.first), ret.second);
+    }
+  }
+
+  // Invalidates iterators.
+  template <class InputIterator>
+  void insert(InputIterator f, InputIterator l) {
+    while (f != l) {
+      insert(*f);
+      ++f;
+    }
+  }
+
+  iterator begin() {
+    if (size_ >= 0) {
+      return iterator(array_);
+    } else {
+      return iterator(map_->begin());
+    }
+  }
+  const_iterator begin() const {
+    if (size_ >= 0) {
+      return const_iterator(array_);
+    } else {
+      return const_iterator(map_->begin());
+    }
+  }
+
+  iterator end() {
+    if (size_ >= 0) {
+      return iterator(array_ + size_);
+    } else {
+      return iterator(map_->end());
+    }
+  }
+  const_iterator end() const {
+    if (size_ >= 0) {
+      return const_iterator(array_ + size_);
+    } else {
+      return const_iterator(map_->end());
+    }
+  }
+
+  void clear() {
+    if (size_ >= 0) {
+      for (int i = 0; i < size_; i++) {
+        array_[i].Destroy();
+      }
+    } else {
+      map_.Destroy();
+    }
+    size_ = 0;
+  }
+
+  // Invalidates iterators.
+  void erase(const iterator& position) {
+    if (size_ >= 0) {
+      int i = position.array_iter_ - array_;
+      array_[i].Destroy();
+      --size_;
+      if (i != size_) {
+        array_[i].Init(*array_[size_]);
+        array_[size_].Destroy();
+      }
+    } else {
+      map_->erase(position.hash_iter_);
+    }
+  }
+
+  size_t erase(const key_type& key) {
+    iterator iter = find(key);
+    if (iter == end()) return 0u;
+    erase(iter);
+    return 1u;
+  }
+
+  size_t count(const key_type& key) const {
+    return (find(key) == end()) ? 0 : 1;
+  }
+
+  size_t size() const {
+    if (size_ >= 0) {
+      return static_cast<size_t>(size_);
+    } else {
+      return map_->size();
+    }
+  }
+
+  bool empty() const {
+    if (size_ >= 0) {
+      return (size_ == 0);
+    } else {
+      return map_->empty();
+    }
+  }
+
+  // Returns true if we have fallen back to using the underlying map
+  // representation.
+  bool UsingFullMap() const {
+    return size_ < 0;
+  }
+
+  inline NormalMap* map() {
+    CHECK(UsingFullMap());
+    return map_.get();
+  }
+  inline const NormalMap* map() const {
+    CHECK(UsingFullMap());
+    return map_.get();
+  }
+
+ private:
+  int size_;  // negative = using hash_map
+
+  MapInit functor_;
+
+  // We want to call constructors and destructors manually, but we don't
+  // want to allocate and deallocate the memory used for them separately.
+  // So, we use this crazy ManualConstructor class.
+  //
+  // Since array_ and map_ are mutually exclusive, we'll put them in a
+  // union, too.  We add in a dummy_ value which quiets MSVC from otherwise
+  // giving an erroneous "union member has copy constructor" error message
+  // (C2621). This dummy member has to come before array_ to quiet the
+  // compiler.
+  //
+  // TODO(brettw) remove this and use C++11 unions when we require C++11.
+  union {
+    ManualConstructor<value_type> dummy_;
+    ManualConstructor<value_type> array_[kArraySize];
+    ManualConstructor<NormalMap> map_;
+  };
+
+  void ConvertToRealMap() {
+    // Move the current elements into a temporary array.
+    ManualConstructor<value_type> temp_array[kArraySize];
+
+    for (int i = 0; i < kArraySize; i++) {
+      temp_array[i].Init(*array_[i]);
+      array_[i].Destroy();
+    }
+
+    // Initialize the map.
+    size_ = -1;
+    functor_(&map_);
+
+    // Insert elements into it.
+    for (int i = 0; i < kArraySize; i++) {
+      map_->insert(*temp_array[i]);
+      temp_array[i].Destroy();
+    }
+  }
+
+  // Helpers for constructors and destructors.
+  void InitFrom(const SmallMap& src) {
+    functor_ = src.functor_;
+    size_ = src.size_;
+    if (src.size_ >= 0) {
+      for (int i = 0; i < size_; i++) {
+        array_[i].Init(*src.array_[i]);
+      }
+    } else {
+      functor_(&map_);
+      (*map_.get()) = (*src.map_.get());
+    }
+  }
+  void Destroy() {
+    if (size_ >= 0) {
+      for (int i = 0; i < size_; i++) {
+        array_[i].Destroy();
+      }
+    } else {
+      map_.Destroy();
+    }
+  }
+};
+
+template <typename NormalMap, int kArraySize, typename EqualKey,
+          typename Functor>
+inline bool SmallMap<NormalMap, kArraySize, EqualKey,
+                     Functor>::iterator::operator==(
+    const const_iterator& other) const {
+  return other == *this;
+}
+template <typename NormalMap, int kArraySize, typename EqualKey,
+          typename Functor>
+inline bool SmallMap<NormalMap, kArraySize, EqualKey,
+                     Functor>::iterator::operator!=(
+    const const_iterator& other) const {
+  return other != *this;
+}
+
+}  // namespace base
+
+#endif  // BASE_CONTAINERS_SMALL_MAP_H_
diff --git a/base/containers/small_map_unittest.cc b/base/containers/small_map_unittest.cc
new file mode 100644
index 0000000..f87a8f0
--- /dev/null
+++ b/base/containers/small_map_unittest.cc
@@ -0,0 +1,482 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/containers/small_map.h"
+
+#include <stddef.h>
+
+#include <algorithm>
+#include <functional>
+#include <map>
+
+#include "base/containers/hash_tables.h"
+#include "base/logging.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(SmallMap, General) {
+  SmallMap<hash_map<int, int> > m;
+
+  EXPECT_TRUE(m.empty());
+
+  m[0] = 5;
+
+  EXPECT_FALSE(m.empty());
+  EXPECT_EQ(m.size(), 1u);
+
+  m[9] = 2;
+
+  EXPECT_FALSE(m.empty());
+  EXPECT_EQ(m.size(), 2u);
+
+  EXPECT_EQ(m[9], 2);
+  EXPECT_EQ(m[0], 5);
+  EXPECT_FALSE(m.UsingFullMap());
+
+  SmallMap<hash_map<int, int> >::iterator iter(m.begin());
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, 0);
+  EXPECT_EQ(iter->second, 5);
+  ++iter;
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ((*iter).first, 9);
+  EXPECT_EQ((*iter).second, 2);
+  ++iter;
+  EXPECT_TRUE(iter == m.end());
+
+  m[8] = 23;
+  m[1234] = 90;
+  m[-5] = 6;
+
+  EXPECT_EQ(m[   9],  2);
+  EXPECT_EQ(m[   0],  5);
+  EXPECT_EQ(m[1234], 90);
+  EXPECT_EQ(m[   8], 23);
+  EXPECT_EQ(m[  -5],  6);
+  EXPECT_EQ(m.size(), 5u);
+  EXPECT_FALSE(m.empty());
+  EXPECT_TRUE(m.UsingFullMap());
+
+  iter = m.begin();
+  for (int i = 0; i < 5; i++) {
+    EXPECT_TRUE(iter != m.end());
+    ++iter;
+  }
+  EXPECT_TRUE(iter == m.end());
+
+  const SmallMap<hash_map<int, int> >& ref = m;
+  EXPECT_TRUE(ref.find(1234) != m.end());
+  EXPECT_TRUE(ref.find(5678) == m.end());
+}
+
+TEST(SmallMap, PostFixIteratorIncrement) {
+  SmallMap<hash_map<int, int> > m;
+  m[0] = 5;
+  m[2] = 3;
+
+  {
+    SmallMap<hash_map<int, int> >::iterator iter(m.begin());
+    SmallMap<hash_map<int, int> >::iterator last(iter++);
+    ++last;
+    EXPECT_TRUE(last == iter);
+  }
+
+  {
+    SmallMap<hash_map<int, int> >::const_iterator iter(m.begin());
+    SmallMap<hash_map<int, int> >::const_iterator last(iter++);
+    ++last;
+    EXPECT_TRUE(last == iter);
+  }
+}
+
+// Based on the General testcase.
+TEST(SmallMap, CopyConstructor) {
+  SmallMap<hash_map<int, int> > src;
+
+  {
+    SmallMap<hash_map<int, int> > m(src);
+    EXPECT_TRUE(m.empty());
+  }
+
+  src[0] = 5;
+
+  {
+    SmallMap<hash_map<int, int> > m(src);
+    EXPECT_FALSE(m.empty());
+    EXPECT_EQ(m.size(), 1u);
+  }
+
+  src[9] = 2;
+
+  {
+    SmallMap<hash_map<int, int> > m(src);
+    EXPECT_FALSE(m.empty());
+    EXPECT_EQ(m.size(), 2u);
+
+    EXPECT_EQ(m[9], 2);
+    EXPECT_EQ(m[0], 5);
+    EXPECT_FALSE(m.UsingFullMap());
+  }
+
+  src[8] = 23;
+  src[1234] = 90;
+  src[-5] = 6;
+
+  {
+    SmallMap<hash_map<int, int> > m(src);
+    EXPECT_EQ(m[   9],  2);
+    EXPECT_EQ(m[   0],  5);
+    EXPECT_EQ(m[1234], 90);
+    EXPECT_EQ(m[   8], 23);
+    EXPECT_EQ(m[  -5],  6);
+    EXPECT_EQ(m.size(), 5u);
+    EXPECT_FALSE(m.empty());
+    EXPECT_TRUE(m.UsingFullMap());
+  }
+}
+
+template<class inner>
+static bool SmallMapIsSubset(SmallMap<inner> const& a,
+                             SmallMap<inner> const& b) {
+  typename SmallMap<inner>::const_iterator it;
+  for (it = a.begin(); it != a.end(); ++it) {
+    typename SmallMap<inner>::const_iterator it_in_b = b.find(it->first);
+    if (it_in_b == b.end() || it_in_b->second != it->second)
+      return false;
+  }
+  return true;
+}
+
+template<class inner>
+static bool SmallMapEqual(SmallMap<inner> const& a,
+                          SmallMap<inner> const& b) {
+  return SmallMapIsSubset(a, b) && SmallMapIsSubset(b, a);
+}
+
+TEST(SmallMap, AssignmentOperator) {
+  SmallMap<hash_map<int, int> > src_small;
+  SmallMap<hash_map<int, int> > src_large;
+
+  src_small[1] = 20;
+  src_small[2] = 21;
+  src_small[3] = 22;
+  EXPECT_FALSE(src_small.UsingFullMap());
+
+  src_large[1] = 20;
+  src_large[2] = 21;
+  src_large[3] = 22;
+  src_large[5] = 23;
+  src_large[6] = 24;
+  src_large[7] = 25;
+  EXPECT_TRUE(src_large.UsingFullMap());
+
+  // Assignments to empty.
+  SmallMap<hash_map<int, int> > dest_small;
+  dest_small = src_small;
+  EXPECT_TRUE(SmallMapEqual(dest_small, src_small));
+  EXPECT_EQ(dest_small.UsingFullMap(),
+            src_small.UsingFullMap());
+
+  SmallMap<hash_map<int, int> > dest_large;
+  dest_large = src_large;
+  EXPECT_TRUE(SmallMapEqual(dest_large, src_large));
+  EXPECT_EQ(dest_large.UsingFullMap(),
+            src_large.UsingFullMap());
+
+  // Assignments which assign from full to small, and vice versa.
+  dest_small = src_large;
+  EXPECT_TRUE(SmallMapEqual(dest_small, src_large));
+  EXPECT_EQ(dest_small.UsingFullMap(),
+            src_large.UsingFullMap());
+
+  dest_large = src_small;
+  EXPECT_TRUE(SmallMapEqual(dest_large, src_small));
+  EXPECT_EQ(dest_large.UsingFullMap(),
+            src_small.UsingFullMap());
+
+  // Double check that SmallMapEqual works:
+  dest_large[42] = 666;
+  EXPECT_FALSE(SmallMapEqual(dest_large, src_small));
+}
+
+TEST(SmallMap, Insert) {
+  SmallMap<hash_map<int, int> > sm;
+
+  // loop through the transition from small map to map.
+  for (int i = 1; i <= 10; ++i) {
+    VLOG(1) << "Iteration " << i;
+    // insert an element
+    std::pair<SmallMap<hash_map<int, int> >::iterator,
+        bool> ret;
+    ret = sm.insert(std::make_pair(i, 100*i));
+    EXPECT_TRUE(ret.second);
+    EXPECT_TRUE(ret.first == sm.find(i));
+    EXPECT_EQ(ret.first->first, i);
+    EXPECT_EQ(ret.first->second, 100*i);
+
+    // try to insert it again with different value, fails, but we still get an
+    // iterator back with the original value.
+    ret = sm.insert(std::make_pair(i, -i));
+    EXPECT_FALSE(ret.second);
+    EXPECT_TRUE(ret.first == sm.find(i));
+    EXPECT_EQ(ret.first->first, i);
+    EXPECT_EQ(ret.first->second, 100*i);
+
+    // check the state of the map.
+    for (int j = 1; j <= i; ++j) {
+      SmallMap<hash_map<int, int> >::iterator it = sm.find(j);
+      EXPECT_TRUE(it != sm.end());
+      EXPECT_EQ(it->first, j);
+      EXPECT_EQ(it->second, j * 100);
+    }
+    EXPECT_EQ(sm.size(), static_cast<size_t>(i));
+    EXPECT_FALSE(sm.empty());
+  }
+}
+
+TEST(SmallMap, InsertRange) {
+  // loop through the transition from small map to map.
+  for (int elements = 0; elements <= 10; ++elements) {
+    VLOG(1) << "Elements " << elements;
+    hash_map<int, int> normal_map;
+    for (int i = 1; i <= elements; ++i) {
+      normal_map.insert(std::make_pair(i, 100*i));
+    }
+
+    SmallMap<hash_map<int, int> > sm;
+    sm.insert(normal_map.begin(), normal_map.end());
+    EXPECT_EQ(normal_map.size(), sm.size());
+    for (int i = 1; i <= elements; ++i) {
+      VLOG(1) << "Iteration " << i;
+      EXPECT_TRUE(sm.find(i) != sm.end());
+      EXPECT_EQ(sm.find(i)->first, i);
+      EXPECT_EQ(sm.find(i)->second, 100*i);
+    }
+  }
+}
+
+TEST(SmallMap, Erase) {
+  SmallMap<hash_map<std::string, int> > m;
+  SmallMap<hash_map<std::string, int> >::iterator iter;
+
+  m["monday"] = 1;
+  m["tuesday"] = 2;
+  m["wednesday"] = 3;
+
+  EXPECT_EQ(m["monday"   ], 1);
+  EXPECT_EQ(m["tuesday"  ], 2);
+  EXPECT_EQ(m["wednesday"], 3);
+  EXPECT_EQ(m.count("tuesday"), 1u);
+  EXPECT_FALSE(m.UsingFullMap());
+
+  iter = m.begin();
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, "monday");
+  EXPECT_EQ(iter->second, 1);
+  ++iter;
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, "tuesday");
+  EXPECT_EQ(iter->second, 2);
+  ++iter;
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, "wednesday");
+  EXPECT_EQ(iter->second, 3);
+  ++iter;
+  EXPECT_TRUE(iter == m.end());
+
+  EXPECT_EQ(m.erase("tuesday"), 1u);
+
+  EXPECT_EQ(m["monday"   ], 1);
+  EXPECT_EQ(m["wednesday"], 3);
+  EXPECT_EQ(m.count("tuesday"), 0u);
+  EXPECT_EQ(m.erase("tuesday"), 0u);
+
+  iter = m.begin();
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, "monday");
+  EXPECT_EQ(iter->second, 1);
+  ++iter;
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, "wednesday");
+  EXPECT_EQ(iter->second, 3);
+  ++iter;
+  EXPECT_TRUE(iter == m.end());
+
+  m["thursday"] = 4;
+  m["friday"] = 5;
+  EXPECT_EQ(m.size(), 4u);
+  EXPECT_FALSE(m.empty());
+  EXPECT_FALSE(m.UsingFullMap());
+
+  m["saturday"] = 6;
+  EXPECT_TRUE(m.UsingFullMap());
+
+  EXPECT_EQ(m.count("friday"), 1u);
+  EXPECT_EQ(m.erase("friday"), 1u);
+  EXPECT_TRUE(m.UsingFullMap());
+  EXPECT_EQ(m.count("friday"), 0u);
+  EXPECT_EQ(m.erase("friday"), 0u);
+
+  EXPECT_EQ(m.size(), 4u);
+  EXPECT_FALSE(m.empty());
+  EXPECT_EQ(m.erase("monday"), 1u);
+  EXPECT_EQ(m.size(), 3u);
+  EXPECT_FALSE(m.empty());
+
+  m.clear();
+  EXPECT_FALSE(m.UsingFullMap());
+  EXPECT_EQ(m.size(), 0u);
+  EXPECT_TRUE(m.empty());
+}
+
+TEST(SmallMap, NonHashMap) {
+  SmallMap<std::map<int, int>, 4, std::equal_to<int> > m;
+  EXPECT_TRUE(m.empty());
+
+  m[9] = 2;
+  m[0] = 5;
+
+  EXPECT_EQ(m[9], 2);
+  EXPECT_EQ(m[0], 5);
+  EXPECT_EQ(m.size(), 2u);
+  EXPECT_FALSE(m.empty());
+  EXPECT_FALSE(m.UsingFullMap());
+
+  SmallMap<std::map<int, int>, 4, std::equal_to<int> >::iterator iter(
+      m.begin());
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, 9);
+  EXPECT_EQ(iter->second, 2);
+  ++iter;
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, 0);
+  EXPECT_EQ(iter->second, 5);
+  ++iter;
+  EXPECT_TRUE(iter == m.end());
+  --iter;
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, 0);
+  EXPECT_EQ(iter->second, 5);
+
+  m[8] = 23;
+  m[1234] = 90;
+  m[-5] = 6;
+
+  EXPECT_EQ(m[   9],  2);
+  EXPECT_EQ(m[   0],  5);
+  EXPECT_EQ(m[1234], 90);
+  EXPECT_EQ(m[   8], 23);
+  EXPECT_EQ(m[  -5],  6);
+  EXPECT_EQ(m.size(), 5u);
+  EXPECT_FALSE(m.empty());
+  EXPECT_TRUE(m.UsingFullMap());
+
+  iter = m.begin();
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, -5);
+  EXPECT_EQ(iter->second, 6);
+  ++iter;
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, 0);
+  EXPECT_EQ(iter->second, 5);
+  ++iter;
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, 8);
+  EXPECT_EQ(iter->second, 23);
+  ++iter;
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, 9);
+  EXPECT_EQ(iter->second, 2);
+  ++iter;
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, 1234);
+  EXPECT_EQ(iter->second, 90);
+  ++iter;
+  EXPECT_TRUE(iter == m.end());
+  --iter;
+  ASSERT_TRUE(iter != m.end());
+  EXPECT_EQ(iter->first, 1234);
+  EXPECT_EQ(iter->second, 90);
+}
+
+TEST(SmallMap, DefaultEqualKeyWorks) {
+  // If these tests compile, they pass. The EXPECT calls are only there to avoid
+  // unused variable warnings.
+  SmallMap<hash_map<int, int> > hm;
+  EXPECT_EQ(0u, hm.size());
+  SmallMap<std::map<int, int> > m;
+  EXPECT_EQ(0u, m.size());
+}
+
+namespace {
+
+class hash_map_add_item : public hash_map<int, int> {
+ public:
+  hash_map_add_item() {}
+  explicit hash_map_add_item(const std::pair<int, int>& item) {
+    insert(item);
+  }
+};
+
+void InitMap(ManualConstructor<hash_map_add_item>* map_ctor) {
+  map_ctor->Init(std::make_pair(0, 0));
+}
+
+class hash_map_add_item_initializer {
+ public:
+  explicit hash_map_add_item_initializer(int item_to_add)
+      : item_(item_to_add) {}
+  hash_map_add_item_initializer()
+      : item_(0) {}
+  void operator()(ManualConstructor<hash_map_add_item>* map_ctor) const {
+    map_ctor->Init(std::make_pair(item_, item_));
+  }
+
+  int item_;
+};
+
+}  // anonymous namespace
+
+TEST(SmallMap, SubclassInitializationWithFunctionPointer) {
+  SmallMap<hash_map_add_item, 4, std::equal_to<int>,
+      void (&)(ManualConstructor<hash_map_add_item>*)> m(InitMap);
+
+  EXPECT_TRUE(m.empty());
+
+  m[1] = 1;
+  m[2] = 2;
+  m[3] = 3;
+  m[4] = 4;
+
+  EXPECT_EQ(4u, m.size());
+  EXPECT_EQ(0u, m.count(0));
+
+  m[5] = 5;
+  EXPECT_EQ(6u, m.size());
+  // Our function adds an extra item when we convert to a map.
+  EXPECT_EQ(1u, m.count(0));
+}
+
+TEST(SmallMap, SubclassInitializationWithFunctionObject) {
+  SmallMap<hash_map_add_item, 4, std::equal_to<int>,
+      hash_map_add_item_initializer> m(hash_map_add_item_initializer(-1));
+
+  EXPECT_TRUE(m.empty());
+
+  m[1] = 1;
+  m[2] = 2;
+  m[3] = 3;
+  m[4] = 4;
+
+  EXPECT_EQ(4u, m.size());
+  EXPECT_EQ(0u, m.count(-1));
+
+  m[5] = 5;
+  EXPECT_EQ(6u, m.size());
+  // Our functor adds an extra item when we convert to a map.
+  EXPECT_EQ(1u, m.count(-1));
+}
+
+}  // namespace base
diff --git a/base/containers/stack_container.h b/base/containers/stack_container.h
new file mode 100644
index 0000000..54090d3
--- /dev/null
+++ b/base/containers/stack_container.h
@@ -0,0 +1,266 @@
+// Copyright (c) 2012 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_CONTAINERS_STACK_CONTAINER_H_
+#define BASE_CONTAINERS_STACK_CONTAINER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/memory/aligned_memory.h"
+#include "base/strings/string16.h"
+#include "build/build_config.h"
+
+namespace base {
+
+// This allocator can be used with STL containers to provide a stack buffer
+// from which to allocate memory and overflows onto the heap. This stack buffer
+// would be allocated on the stack and allows us to avoid heap operations in
+// some situations.
+//
+// STL likes to make copies of allocators, so the allocator itself can't hold
+// the data. Instead, we make the creator responsible for creating a
+// StackAllocator::Source which contains the data. Copying the allocator
+// merely copies the pointer to this shared source, so all allocators created
+// based on our allocator will share the same stack buffer.
+//
+// This stack buffer implementation is very simple. The first allocation that
+// fits in the stack buffer will use the stack buffer. Any subsequent
+// allocations will not use the stack buffer, even if there is unused room.
+// This makes it appropriate for array-like containers, but the caller should
+// be sure to reserve() in the container up to the stack buffer size. Otherwise
+// the container will allocate a small array which will "use up" the stack
+// buffer.
+template<typename T, size_t stack_capacity>
+class StackAllocator : public std::allocator<T> {
+ public:
+  typedef typename std::allocator<T>::pointer pointer;
+  typedef typename std::allocator<T>::size_type size_type;
+
+  // Backing store for the allocator. The container owner is responsible for
+  // maintaining this for as long as any containers using this allocator are
+  // live.
+  struct Source {
+    Source() : used_stack_buffer_(false) {
+    }
+
+    // Casts the buffer in its right type.
+    T* stack_buffer() { return stack_buffer_.template data_as<T>(); }
+    const T* stack_buffer() const {
+      return stack_buffer_.template data_as<T>();
+    }
+
+    // The buffer itself. It is not of type T because we don't want the
+    // constructors and destructors to be automatically called. Define a POD
+    // buffer of the right size instead.
+    base::AlignedMemory<sizeof(T[stack_capacity]), ALIGNOF(T)> stack_buffer_;
+#if defined(__GNUC__) && !defined(ARCH_CPU_X86_FAMILY)
+    COMPILE_ASSERT(ALIGNOF(T) <= 16, crbug_115612);
+#endif
+
+    // Set when the stack buffer is used for an allocation. We do not track
+    // how much of the buffer is used, only that somebody is using it.
+    bool used_stack_buffer_;
+  };
+
+  // Used by containers when they want to refer to an allocator of type U.
+  template<typename U>
+  struct rebind {
+    typedef StackAllocator<U, stack_capacity> other;
+  };
+
+  // For the straight up copy c-tor, we can share storage.
+  StackAllocator(const StackAllocator<T, stack_capacity>& rhs)
+      : std::allocator<T>(), source_(rhs.source_) {
+  }
+
+  // ISO C++ requires the following constructor to be defined,
+  // and std::vector in VC++2008SP1 Release fails with an error
+  // in the class _Container_base_aux_alloc_real (from <xutility>)
+  // if the constructor does not exist.
+  // For this constructor, we cannot share storage; there's
+  // no guarantee that the Source buffer of Ts is large enough
+  // for Us.
+  // TODO: If we were fancy pants, perhaps we could share storage
+  // iff sizeof(T) == sizeof(U).
+  template<typename U, size_t other_capacity>
+  StackAllocator(const StackAllocator<U, other_capacity>& other)
+      : source_(NULL) {
+  }
+
+  // This constructor must exist. It creates a default allocator that doesn't
+  // actually have a stack buffer. glibc's std::string() will compare the
+  // current allocator against the default-constructed allocator, so this
+  // should be fast.
+  StackAllocator() : source_(NULL) {
+  }
+
+  explicit StackAllocator(Source* source) : source_(source) {
+  }
+
+  // Actually do the allocation. Use the stack buffer if nobody has used it yet
+  // and the size requested fits. Otherwise, fall through to the standard
+  // allocator.
+  pointer allocate(size_type n, void* hint = 0) {
+    if (source_ != NULL && !source_->used_stack_buffer_
+        && n <= stack_capacity) {
+      source_->used_stack_buffer_ = true;
+      return source_->stack_buffer();
+    } else {
+      return std::allocator<T>::allocate(n, hint);
+    }
+  }
+
+  // Free: when trying to free the stack buffer, just mark it as free. For
+  // non-stack-buffer pointers, just fall though to the standard allocator.
+  void deallocate(pointer p, size_type n) {
+    if (source_ != NULL && p == source_->stack_buffer())
+      source_->used_stack_buffer_ = false;
+    else
+      std::allocator<T>::deallocate(p, n);
+  }
+
+ private:
+  Source* source_;
+};
+
+// A wrapper around STL containers that maintains a stack-sized buffer that the
+// initial capacity of the vector is based on. Growing the container beyond the
+// stack capacity will transparently overflow onto the heap. The container must
+// support reserve().
+//
+// WATCH OUT: the ContainerType MUST use the proper StackAllocator for this
+// type. This object is really intended to be used only internally. You'll want
+// to use the wrappers below for different types.
+template<typename TContainerType, int stack_capacity>
+class StackContainer {
+ public:
+  typedef TContainerType ContainerType;
+  typedef typename ContainerType::value_type ContainedType;
+  typedef StackAllocator<ContainedType, stack_capacity> Allocator;
+
+  // Allocator must be constructed before the container!
+  StackContainer() : allocator_(&stack_data_), container_(allocator_) {
+    // Make the container use the stack allocation by reserving our buffer size
+    // before doing anything else.
+    container_.reserve(stack_capacity);
+  }
+
+  // Getters for the actual container.
+  //
+  // Danger: any copies of this made using the copy constructor must have
+  // shorter lifetimes than the source. The copy will share the same allocator
+  // and therefore the same stack buffer as the original. Use std::copy to
+  // copy into a "real" container for longer-lived objects.
+  ContainerType& container() { return container_; }
+  const ContainerType& container() const { return container_; }
+
+  // Support operator-> to get to the container. This allows nicer syntax like:
+  //   StackContainer<...> foo;
+  //   std::sort(foo->begin(), foo->end());
+  ContainerType* operator->() { return &container_; }
+  const ContainerType* operator->() const { return &container_; }
+
+#ifdef UNIT_TEST
+  // Retrieves the stack source so that that unit tests can verify that the
+  // buffer is being used properly.
+  const typename Allocator::Source& stack_data() const {
+    return stack_data_;
+  }
+#endif
+
+ protected:
+  typename Allocator::Source stack_data_;
+  Allocator allocator_;
+  ContainerType container_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(StackContainer);
+};
+
+// StackString -----------------------------------------------------------------
+
+template<size_t stack_capacity>
+class StackString : public StackContainer<
+    std::basic_string<char,
+                      std::char_traits<char>,
+                      StackAllocator<char, stack_capacity> >,
+    stack_capacity> {
+ public:
+  StackString() : StackContainer<
+      std::basic_string<char,
+                        std::char_traits<char>,
+                        StackAllocator<char, stack_capacity> >,
+      stack_capacity>() {
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(StackString);
+};
+
+// StackStrin16 ----------------------------------------------------------------
+
+template<size_t stack_capacity>
+class StackString16 : public StackContainer<
+    std::basic_string<char16,
+                      base::string16_char_traits,
+                      StackAllocator<char16, stack_capacity> >,
+    stack_capacity> {
+ public:
+  StackString16() : StackContainer<
+      std::basic_string<char16,
+                        base::string16_char_traits,
+                        StackAllocator<char16, stack_capacity> >,
+      stack_capacity>() {
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(StackString16);
+};
+
+// StackVector -----------------------------------------------------------------
+
+// Example:
+//   StackVector<int, 16> foo;
+//   foo->push_back(22);  // we have overloaded operator->
+//   foo[0] = 10;         // as well as operator[]
+template<typename T, size_t stack_capacity>
+class StackVector : public StackContainer<
+    std::vector<T, StackAllocator<T, stack_capacity> >,
+    stack_capacity> {
+ public:
+  StackVector() : StackContainer<
+      std::vector<T, StackAllocator<T, stack_capacity> >,
+      stack_capacity>() {
+  }
+
+  // We need to put this in STL containers sometimes, which requires a copy
+  // constructor. We can't call the regular copy constructor because that will
+  // take the stack buffer from the original. Here, we create an empty object
+  // and make a stack buffer of its own.
+  StackVector(const StackVector<T, stack_capacity>& other)
+      : StackContainer<
+            std::vector<T, StackAllocator<T, stack_capacity> >,
+            stack_capacity>() {
+    this->container().assign(other->begin(), other->end());
+  }
+
+  StackVector<T, stack_capacity>& operator=(
+      const StackVector<T, stack_capacity>& other) {
+    this->container().assign(other->begin(), other->end());
+    return *this;
+  }
+
+  // Vectors are commonly indexed, which isn't very convenient even with
+  // operator-> (using "->at()" does exception stuff we don't want).
+  T& operator[](size_t i) { return this->container().operator[](i); }
+  const T& operator[](size_t i) const {
+    return this->container().operator[](i);
+  }
+};
+
+}  // namespace base
+
+#endif  // BASE_CONTAINERS_STACK_CONTAINER_H_
diff --git a/base/containers/stack_container_unittest.cc b/base/containers/stack_container_unittest.cc
new file mode 100644
index 0000000..e6c1914
--- /dev/null
+++ b/base/containers/stack_container_unittest.cc
@@ -0,0 +1,143 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/containers/stack_container.h"
+
+#include <algorithm>
+
+#include "base/memory/aligned_memory.h"
+#include "base/memory/ref_counted.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+class Dummy : public base::RefCounted<Dummy> {
+ public:
+  explicit Dummy(int* alive) : alive_(alive) {
+    ++*alive_;
+  }
+
+ private:
+  friend class base::RefCounted<Dummy>;
+
+  ~Dummy() {
+    --*alive_;
+  }
+
+  int* const alive_;
+};
+
+}  // namespace
+
+TEST(StackContainer, Vector) {
+  const int stack_size = 3;
+  StackVector<int, stack_size> vect;
+  const int* stack_buffer = &vect.stack_data().stack_buffer()[0];
+
+  // The initial |stack_size| elements should appear in the stack buffer.
+  EXPECT_EQ(static_cast<size_t>(stack_size), vect.container().capacity());
+  for (int i = 0; i < stack_size; i++) {
+    vect.container().push_back(i);
+    EXPECT_EQ(stack_buffer, &vect.container()[0]);
+    EXPECT_TRUE(vect.stack_data().used_stack_buffer_);
+  }
+
+  // Adding more elements should push the array onto the heap.
+  for (int i = 0; i < stack_size; i++) {
+    vect.container().push_back(i + stack_size);
+    EXPECT_NE(stack_buffer, &vect.container()[0]);
+    EXPECT_FALSE(vect.stack_data().used_stack_buffer_);
+  }
+
+  // The array should still be in order.
+  for (int i = 0; i < stack_size * 2; i++)
+    EXPECT_EQ(i, vect.container()[i]);
+
+  // Resize to smaller. Our STL implementation won't reallocate in this case,
+  // otherwise it might use our stack buffer. We reserve right after the resize
+  // to guarantee it isn't using the stack buffer, even though it doesn't have
+  // much data.
+  vect.container().resize(stack_size);
+  vect.container().reserve(stack_size * 2);
+  EXPECT_FALSE(vect.stack_data().used_stack_buffer_);
+
+  // Copying the small vector to another should use the same allocator and use
+  // the now-unused stack buffer. GENERALLY CALLERS SHOULD NOT DO THIS since
+  // they have to get the template types just right and it can cause errors.
+  std::vector<int, StackAllocator<int, stack_size> > other(vect.container());
+  EXPECT_EQ(stack_buffer, &other.front());
+  EXPECT_TRUE(vect.stack_data().used_stack_buffer_);
+  for (int i = 0; i < stack_size; i++)
+    EXPECT_EQ(i, other[i]);
+}
+
+TEST(StackContainer, VectorDoubleDelete) {
+  // Regression testing for double-delete.
+  typedef StackVector<scoped_refptr<Dummy>, 2> Vector;
+  typedef Vector::ContainerType Container;
+  Vector vect;
+
+  int alive = 0;
+  scoped_refptr<Dummy> dummy(new Dummy(&alive));
+  EXPECT_EQ(alive, 1);
+
+  vect->push_back(dummy);
+  EXPECT_EQ(alive, 1);
+
+  Dummy* dummy_unref = dummy.get();
+  dummy = NULL;
+  EXPECT_EQ(alive, 1);
+
+  Container::iterator itr = std::find(vect->begin(), vect->end(), dummy_unref);
+  EXPECT_EQ(itr->get(), dummy_unref);
+  vect->erase(itr);
+  EXPECT_EQ(alive, 0);
+
+  // Shouldn't crash at exit.
+}
+
+namespace {
+
+template <size_t alignment>
+class AlignedData {
+ public:
+  AlignedData() { memset(data_.void_data(), 0, alignment); }
+  ~AlignedData() {}
+  base::AlignedMemory<alignment, alignment> data_;
+};
+
+}  // anonymous namespace
+
+#define EXPECT_ALIGNED(ptr, align) \
+    EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(ptr) & (align - 1))
+
+TEST(StackContainer, BufferAlignment) {
+  StackVector<wchar_t, 16> text;
+  text->push_back(L'A');
+  EXPECT_ALIGNED(&text[0], ALIGNOF(wchar_t));
+
+  StackVector<double, 1> doubles;
+  doubles->push_back(0.0);
+  EXPECT_ALIGNED(&doubles[0], ALIGNOF(double));
+
+  StackVector<AlignedData<16>, 1> aligned16;
+  aligned16->push_back(AlignedData<16>());
+  EXPECT_ALIGNED(&aligned16[0], 16);
+
+#if !defined(__GNUC__) || defined(ARCH_CPU_X86_FAMILY)
+  // It seems that non-X86 gcc doesn't respect greater than 16 byte alignment.
+  // See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=33721 for details.
+  // TODO(sbc):re-enable this if GCC starts respecting higher alignments.
+  StackVector<AlignedData<256>, 1> aligned256;
+  aligned256->push_back(AlignedData<256>());
+  EXPECT_ALIGNED(&aligned256[0], 256);
+#endif
+}
+
+template class StackVector<int, 2>;
+template class StackVector<scoped_refptr<Dummy>, 2>;
+
+}  // namespace base
diff --git a/base/cpu.cc b/base/cpu.cc
new file mode 100644
index 0000000..ef3309d
--- /dev/null
+++ b/base/cpu.cc
@@ -0,0 +1,288 @@
+// Copyright (c) 2012 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/cpu.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <algorithm>
+
+#include "base/basictypes.h"
+#include "base/strings/string_piece.h"
+#include "build/build_config.h"
+
+#if defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX))
+#include "base/files/file_util.h"
+#include "base/lazy_instance.h"
+#endif
+
+#if defined(ARCH_CPU_X86_FAMILY)
+#if defined(_MSC_VER)
+#include <intrin.h>
+#include <immintrin.h>  // For _xgetbv()
+#endif
+#endif
+
+namespace base {
+
+CPU::CPU()
+  : signature_(0),
+    type_(0),
+    family_(0),
+    model_(0),
+    stepping_(0),
+    ext_model_(0),
+    ext_family_(0),
+    has_mmx_(false),
+    has_sse_(false),
+    has_sse2_(false),
+    has_sse3_(false),
+    has_ssse3_(false),
+    has_sse41_(false),
+    has_sse42_(false),
+    has_avx_(false),
+    has_avx_hardware_(false),
+    has_aesni_(false),
+    has_non_stop_time_stamp_counter_(false),
+    has_broken_neon_(false),
+    cpu_vendor_("unknown") {
+  Initialize();
+}
+
+namespace {
+
+#if defined(ARCH_CPU_X86_FAMILY)
+#ifndef _MSC_VER
+
+#if defined(__pic__) && defined(__i386__)
+
+void __cpuid(int cpu_info[4], int info_type) {
+  __asm__ volatile (
+    "mov %%ebx, %%edi\n"
+    "cpuid\n"
+    "xchg %%edi, %%ebx\n"
+    : "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
+    : "a"(info_type)
+  );
+}
+
+#else
+
+void __cpuid(int cpu_info[4], int info_type) {
+  __asm__ volatile (
+    "cpuid \n\t"
+    : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
+    : "a"(info_type)
+  );
+}
+
+#endif
+
+// _xgetbv returns the value of an Intel Extended Control Register (XCR).
+// Currently only XCR0 is defined by Intel so |xcr| should always be zero.
+uint64 _xgetbv(uint32 xcr) {
+  uint32 eax, edx;
+
+  __asm__ volatile ("xgetbv" : "=a" (eax), "=d" (edx) : "c" (xcr));
+  return (static_cast<uint64>(edx) << 32) | eax;
+}
+
+#endif  // !_MSC_VER
+#endif  // ARCH_CPU_X86_FAMILY
+
+#if defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX))
+class LazyCpuInfoValue {
+ public:
+  LazyCpuInfoValue() : has_broken_neon_(false) {
+    // This function finds the value from /proc/cpuinfo under the key "model
+    // name" or "Processor". "model name" is used in Linux 3.8 and later (3.7
+    // and later for arm64) and is shown once per CPU. "Processor" is used in
+    // earler versions and is shown only once at the top of /proc/cpuinfo
+    // regardless of the number CPUs.
+    const char kModelNamePrefix[] = "model name\t: ";
+    const char kProcessorPrefix[] = "Processor\t: ";
+
+    // This function also calculates whether we believe that this CPU has a
+    // broken NEON unit based on these fields from cpuinfo:
+    unsigned implementer = 0, architecture = 0, variant = 0, part = 0,
+             revision = 0;
+    const struct {
+      const char key[17];
+      unsigned *result;
+    } kUnsignedValues[] = {
+      {"CPU implementer", &implementer},
+      {"CPU architecture", &architecture},
+      {"CPU variant", &variant},
+      {"CPU part", &part},
+      {"CPU revision", &revision},
+    };
+
+    std::string contents;
+    ReadFileToString(FilePath("/proc/cpuinfo"), &contents);
+    DCHECK(!contents.empty());
+    if (contents.empty()) {
+      return;
+    }
+
+    std::istringstream iss(contents);
+    std::string line;
+    while (std::getline(iss, line)) {
+      if (brand_.empty() &&
+          (line.compare(0, strlen(kModelNamePrefix), kModelNamePrefix) == 0 ||
+           line.compare(0, strlen(kProcessorPrefix), kProcessorPrefix) == 0)) {
+        brand_.assign(line.substr(strlen(kModelNamePrefix)));
+      }
+
+      for (size_t i = 0; i < arraysize(kUnsignedValues); i++) {
+        const char *key = kUnsignedValues[i].key;
+        const size_t len = strlen(key);
+
+        if (line.compare(0, len, key) == 0 &&
+            line.size() >= len + 1 &&
+            (line[len] == '\t' || line[len] == ' ' || line[len] == ':')) {
+          size_t colon_pos = line.find(':', len);
+          if (colon_pos == std::string::npos) {
+            continue;
+          }
+
+          const StringPiece line_sp(line);
+          StringPiece value_sp = line_sp.substr(colon_pos + 1);
+          while (!value_sp.empty() &&
+                 (value_sp[0] == ' ' || value_sp[0] == '\t')) {
+            value_sp = value_sp.substr(1);
+          }
+
+          // The string may have leading "0x" or not, so we use strtoul to
+          // handle that.
+          char *endptr;
+          std::string value(value_sp.as_string());
+          unsigned long int result = strtoul(value.c_str(), &endptr, 0);
+          if (*endptr == 0 && result <= UINT_MAX) {
+            *kUnsignedValues[i].result = result;
+          }
+        }
+      }
+    }
+
+    has_broken_neon_ =
+      implementer == 0x51 &&
+      architecture == 7 &&
+      variant == 1 &&
+      part == 0x4d &&
+      revision == 0;
+  }
+
+  const std::string& brand() const { return brand_; }
+  bool has_broken_neon() const { return has_broken_neon_; }
+
+ private:
+  std::string brand_;
+  bool has_broken_neon_;
+  DISALLOW_COPY_AND_ASSIGN(LazyCpuInfoValue);
+};
+
+base::LazyInstance<LazyCpuInfoValue>::Leaky g_lazy_cpuinfo =
+    LAZY_INSTANCE_INITIALIZER;
+
+#endif  // defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) ||
+        // defined(OS_LINUX))
+
+}  // anonymous namespace
+
+void CPU::Initialize() {
+#if defined(ARCH_CPU_X86_FAMILY)
+  int cpu_info[4] = {-1};
+  char cpu_string[48];
+
+  // __cpuid with an InfoType argument of 0 returns the number of
+  // valid Ids in CPUInfo[0] and the CPU identification string in
+  // the other three array elements. The CPU identification string is
+  // not in linear order. The code below arranges the information
+  // in a human readable form. The human readable order is CPUInfo[1] |
+  // CPUInfo[3] | CPUInfo[2]. CPUInfo[2] and CPUInfo[3] are swapped
+  // before using memcpy to copy these three array elements to cpu_string.
+  __cpuid(cpu_info, 0);
+  int num_ids = cpu_info[0];
+  std::swap(cpu_info[2], cpu_info[3]);
+  memcpy(cpu_string, &cpu_info[1], 3 * sizeof(cpu_info[1]));
+  cpu_vendor_.assign(cpu_string, 3 * sizeof(cpu_info[1]));
+
+  // Interpret CPU feature information.
+  if (num_ids > 0) {
+    __cpuid(cpu_info, 1);
+    signature_ = cpu_info[0];
+    stepping_ = cpu_info[0] & 0xf;
+    model_ = ((cpu_info[0] >> 4) & 0xf) + ((cpu_info[0] >> 12) & 0xf0);
+    family_ = (cpu_info[0] >> 8) & 0xf;
+    type_ = (cpu_info[0] >> 12) & 0x3;
+    ext_model_ = (cpu_info[0] >> 16) & 0xf;
+    ext_family_ = (cpu_info[0] >> 20) & 0xff;
+    has_mmx_ =   (cpu_info[3] & 0x00800000) != 0;
+    has_sse_ =   (cpu_info[3] & 0x02000000) != 0;
+    has_sse2_ =  (cpu_info[3] & 0x04000000) != 0;
+    has_sse3_ =  (cpu_info[2] & 0x00000001) != 0;
+    has_ssse3_ = (cpu_info[2] & 0x00000200) != 0;
+    has_sse41_ = (cpu_info[2] & 0x00080000) != 0;
+    has_sse42_ = (cpu_info[2] & 0x00100000) != 0;
+    has_avx_hardware_ =
+                 (cpu_info[2] & 0x10000000) != 0;
+    // AVX instructions will generate an illegal instruction exception unless
+    //   a) they are supported by the CPU,
+    //   b) XSAVE is supported by the CPU and
+    //   c) XSAVE is enabled by the kernel.
+    // See http://software.intel.com/en-us/blogs/2011/04/14/is-avx-enabled
+    //
+    // In addition, we have observed some crashes with the xgetbv instruction
+    // even after following Intel's example code. (See crbug.com/375968.)
+    // Because of that, we also test the XSAVE bit because its description in
+    // the CPUID documentation suggests that it signals xgetbv support.
+    has_avx_ =
+        has_avx_hardware_ &&
+        (cpu_info[2] & 0x04000000) != 0 /* XSAVE */ &&
+        (cpu_info[2] & 0x08000000) != 0 /* OSXSAVE */ &&
+        (_xgetbv(0) & 6) == 6 /* XSAVE enabled by kernel */;
+    has_aesni_ = (cpu_info[2] & 0x02000000) != 0;
+  }
+
+  // Get the brand string of the cpu.
+  __cpuid(cpu_info, 0x80000000);
+  const int parameter_end = 0x80000004;
+  int max_parameter = cpu_info[0];
+
+  if (cpu_info[0] >= parameter_end) {
+    char* cpu_string_ptr = cpu_string;
+
+    for (int parameter = 0x80000002; parameter <= parameter_end &&
+         cpu_string_ptr < &cpu_string[sizeof(cpu_string)]; parameter++) {
+      __cpuid(cpu_info, parameter);
+      memcpy(cpu_string_ptr, cpu_info, sizeof(cpu_info));
+      cpu_string_ptr += sizeof(cpu_info);
+    }
+    cpu_brand_.assign(cpu_string, cpu_string_ptr - cpu_string);
+  }
+
+  const int parameter_containing_non_stop_time_stamp_counter = 0x80000007;
+  if (max_parameter >= parameter_containing_non_stop_time_stamp_counter) {
+    __cpuid(cpu_info, parameter_containing_non_stop_time_stamp_counter);
+    has_non_stop_time_stamp_counter_ = (cpu_info[3] & (1 << 8)) != 0;
+  }
+#elif defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX))
+  cpu_brand_.assign(g_lazy_cpuinfo.Get().brand());
+  has_broken_neon_ = g_lazy_cpuinfo.Get().has_broken_neon();
+#endif
+}
+
+CPU::IntelMicroArchitecture CPU::GetIntelMicroArchitecture() const {
+  if (has_avx()) return AVX;
+  if (has_sse42()) return SSE42;
+  if (has_sse41()) return SSE41;
+  if (has_ssse3()) return SSSE3;
+  if (has_sse3()) return SSE3;
+  if (has_sse2()) return SSE2;
+  if (has_sse()) return SSE;
+  return PENTIUM;
+}
+
+}  // namespace base
diff --git a/base/cpu.h b/base/cpu.h
new file mode 100644
index 0000000..0c809f0
--- /dev/null
+++ b/base/cpu.h
@@ -0,0 +1,96 @@
+// Copyright (c) 2012 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_CPU_H_
+#define BASE_CPU_H_
+
+#include <string>
+
+#include "base/base_export.h"
+
+namespace base {
+
+// Query information about the processor.
+class BASE_EXPORT CPU {
+ public:
+  // Constructor
+  CPU();
+
+  enum IntelMicroArchitecture {
+    PENTIUM,
+    SSE,
+    SSE2,
+    SSE3,
+    SSSE3,
+    SSE41,
+    SSE42,
+    AVX,
+    MAX_INTEL_MICRO_ARCHITECTURE
+  };
+
+  // Accessors for CPU information.
+  const std::string& vendor_name() const { return cpu_vendor_; }
+  int signature() const { return signature_; }
+  int stepping() const { return stepping_; }
+  int model() const { return model_; }
+  int family() const { return family_; }
+  int type() const { return type_; }
+  int extended_model() const { return ext_model_; }
+  int extended_family() const { return ext_family_; }
+  bool has_mmx() const { return has_mmx_; }
+  bool has_sse() const { return has_sse_; }
+  bool has_sse2() const { return has_sse2_; }
+  bool has_sse3() const { return has_sse3_; }
+  bool has_ssse3() const { return has_ssse3_; }
+  bool has_sse41() const { return has_sse41_; }
+  bool has_sse42() const { return has_sse42_; }
+  bool has_avx() const { return has_avx_; }
+  // has_avx_hardware returns true when AVX is present in the CPU. This might
+  // differ from the value of |has_avx()| because |has_avx()| also tests for
+  // operating system support needed to actually call AVX instuctions.
+  // Note: you should never need to call this function. It was added in order
+  // to workaround a bug in NSS but |has_avx()| is what you want.
+  bool has_avx_hardware() const { return has_avx_hardware_; }
+  bool has_aesni() const { return has_aesni_; }
+  bool has_non_stop_time_stamp_counter() const {
+    return has_non_stop_time_stamp_counter_;
+  }
+  // has_broken_neon is only valid on ARM chips. If true, it indicates that we
+  // believe that the NEON unit on the current CPU is flawed and cannot execute
+  // some code. See https://code.google.com/p/chromium/issues/detail?id=341598
+  bool has_broken_neon() const { return has_broken_neon_; }
+
+  IntelMicroArchitecture GetIntelMicroArchitecture() const;
+  const std::string& cpu_brand() const { return cpu_brand_; }
+
+ private:
+  // Query the processor for CPUID information.
+  void Initialize();
+
+  int signature_;  // raw form of type, family, model, and stepping
+  int type_;  // process type
+  int family_;  // family of the processor
+  int model_;  // model of processor
+  int stepping_;  // processor revision number
+  int ext_model_;
+  int ext_family_;
+  bool has_mmx_;
+  bool has_sse_;
+  bool has_sse2_;
+  bool has_sse3_;
+  bool has_ssse3_;
+  bool has_sse41_;
+  bool has_sse42_;
+  bool has_avx_;
+  bool has_avx_hardware_;
+  bool has_aesni_;
+  bool has_non_stop_time_stamp_counter_;
+  bool has_broken_neon_;
+  std::string cpu_vendor_;
+  std::string cpu_brand_;
+};
+
+}  // namespace base
+
+#endif  // BASE_CPU_H_
diff --git a/base/cpu_unittest.cc b/base/cpu_unittest.cc
new file mode 100644
index 0000000..18bf959
--- /dev/null
+++ b/base/cpu_unittest.cc
@@ -0,0 +1,93 @@
+// Copyright (c) 2012 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/cpu.h"
+#include "build/build_config.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Tests whether we can run extended instructions represented by the CPU
+// information. This test actually executes some extended instructions (such as
+// MMX, SSE, etc.) supported by the CPU and sees we can run them without
+// "undefined instruction" exceptions. That is, this test succeeds when this
+// test finishes without a crash.
+TEST(CPU, RunExtendedInstructions) {
+#if defined(ARCH_CPU_X86_FAMILY)
+  // Retrieve the CPU information.
+  base::CPU cpu;
+
+// TODO(jschuh): crbug.com/168866 Find a way to enable this on Win64.
+#if defined(OS_WIN) && !defined(_M_X64)
+  ASSERT_TRUE(cpu.has_mmx());
+
+  // Execute an MMX instruction.
+  __asm emms;
+
+  if (cpu.has_sse()) {
+    // Execute an SSE instruction.
+    __asm xorps xmm0, xmm0;
+  }
+
+  if (cpu.has_sse2()) {
+    // Execute an SSE 2 instruction.
+    __asm psrldq xmm0, 0;
+  }
+
+  if (cpu.has_sse3()) {
+    // Execute an SSE 3 instruction.
+    __asm addsubpd xmm0, xmm0;
+  }
+
+  if (cpu.has_ssse3()) {
+    // Execute a Supplimental SSE 3 instruction.
+    __asm psignb xmm0, xmm0;
+  }
+
+  if (cpu.has_sse41()) {
+    // Execute an SSE 4.1 instruction.
+    __asm pmuldq xmm0, xmm0;
+  }
+
+  if (cpu.has_sse42()) {
+    // Execute an SSE 4.2 instruction.
+    __asm crc32 eax, eax;
+  }
+#elif defined(OS_POSIX) && defined(__x86_64__)
+  ASSERT_TRUE(cpu.has_mmx());
+
+  // Execute an MMX instruction.
+  __asm__ __volatile__("emms\n" : : : "mm0");
+
+  if (cpu.has_sse()) {
+    // Execute an SSE instruction.
+    __asm__ __volatile__("xorps %%xmm0, %%xmm0\n" : : : "xmm0");
+  }
+
+  if (cpu.has_sse2()) {
+    // Execute an SSE 2 instruction.
+    __asm__ __volatile__("psrldq $0, %%xmm0\n" : : : "xmm0");
+  }
+
+  if (cpu.has_sse3()) {
+    // Execute an SSE 3 instruction.
+    __asm__ __volatile__("addsubpd %%xmm0, %%xmm0\n" : : : "xmm0");
+  }
+
+  if (cpu.has_ssse3()) {
+    // Execute a Supplimental SSE 3 instruction.
+    __asm__ __volatile__("psignb %%xmm0, %%xmm0\n" : : : "xmm0");
+  }
+
+  if (cpu.has_sse41()) {
+    // Execute an SSE 4.1 instruction.
+    __asm__ __volatile__("pmuldq %%xmm0, %%xmm0\n" : : : "xmm0");
+  }
+
+  if (cpu.has_sse42()) {
+    // Execute an SSE 4.2 instruction.
+    __asm__ __volatile__("crc32 %%eax, %%eax\n" : : : "eax");
+  }
+#endif
+#endif
+}
diff --git a/base/critical_closure.h b/base/critical_closure.h
new file mode 100644
index 0000000..75e3704
--- /dev/null
+++ b/base/critical_closure.h
@@ -0,0 +1,80 @@
+// Copyright (c) 2012 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_CRITICAL_CLOSURE_H_
+#define BASE_CRITICAL_CLOSURE_H_
+
+#include "base/callback.h"
+
+#if defined(OS_IOS)
+#include "base/bind.h"
+#include "base/ios/scoped_critical_action.h"
+#endif
+
+namespace base {
+
+namespace internal {
+
+#if defined(OS_IOS)
+// Returns true if multi-tasking is supported on this iOS device.
+bool IsMultiTaskingSupported();
+
+// This class wraps a closure so it can continue to run for a period of time
+// when the application goes to the background by using
+// |ios::ScopedCriticalAction|.
+template <typename R>
+class CriticalClosure {
+ public:
+  explicit CriticalClosure(const Callback<R(void)>& closure)
+      : closure_(closure) {}
+
+  ~CriticalClosure() {}
+
+  R Run() {
+    return closure_.Run();
+  }
+
+ private:
+  ios::ScopedCriticalAction critical_action_;
+  Callback<R(void)> closure_;
+
+  DISALLOW_COPY_AND_ASSIGN(CriticalClosure);
+};
+#endif  // defined(OS_IOS)
+
+}  // namespace internal
+
+// Returns a closure (which may return a result, but must not require any extra
+// arguments) that will continue to run for a period of time when the
+// application goes to the background if possible on platforms where
+// applications don't execute while backgrounded, otherwise the original task is
+// returned.
+//
+// Example:
+//   file_task_runner_->PostTask(
+//       FROM_HERE,
+//       MakeCriticalClosure(base::Bind(&WriteToDiskTask, path_, data)));
+//
+// Note new closures might be posted in this closure. If the new closures need
+// background running time, |MakeCriticalClosure| should be applied on them
+// before posting.
+#if defined(OS_IOS)
+template <typename R>
+Callback<R(void)> MakeCriticalClosure(const Callback<R(void)>& closure) {
+  DCHECK(internal::IsMultiTaskingSupported());
+  return base::Bind(&internal::CriticalClosure<R>::Run,
+                    Owned(new internal::CriticalClosure<R>(closure)));
+}
+#else  // defined(OS_IOS)
+template <typename R>
+inline Callback<R(void)> MakeCriticalClosure(const Callback<R(void)>& closure) {
+  // No-op for platforms where the application does not need to acquire
+  // background time for closures to finish when it goes into the background.
+  return closure;
+}
+#endif  // defined(OS_IOS)
+
+}  // namespace base
+
+#endif  // BASE_CRITICAL_CLOSURE_H_
diff --git a/base/critical_closure_internal_ios.mm b/base/critical_closure_internal_ios.mm
new file mode 100644
index 0000000..b8fec14
--- /dev/null
+++ b/base/critical_closure_internal_ios.mm
@@ -0,0 +1,17 @@
+// 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.
+
+#include "base/critical_closure.h"
+
+#import <UIKit/UIKit.h>
+
+namespace base {
+namespace internal {
+
+bool IsMultiTaskingSupported() {
+  return [[UIDevice currentDevice] isMultitaskingSupported];
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/debug/BUILD.gn b/base/debug/BUILD.gn
new file mode 100644
index 0000000..8ed623b
--- /dev/null
+++ b/base/debug/BUILD.gn
@@ -0,0 +1,76 @@
+# Copyright (c) 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("debug") {
+  sources = [
+    "alias.cc",
+    "alias.h",
+    "asan_invalid_access.cc",
+    "asan_invalid_access.h",
+    "crash_logging.cc",
+    "crash_logging.h",
+    "debugger.cc",
+    "debugger.h",
+    "debugger_posix.cc",
+    "debugger_win.cc",
+    "dump_without_crashing.cc",
+    "dump_without_crashing.h",
+    "gdi_debug_util_win.cc",
+    "gdi_debug_util_win.h",
+
+    # This file depends on files from the "allocator" target,
+    # but this target does not depend on "allocator" (see
+    # allocator.gyp for details).
+    "leak_annotations.h",
+    "leak_tracker.h",
+    "proc_maps_linux.cc",
+    "proc_maps_linux.h",
+    "profiler.cc",
+    "profiler.h",
+    "stack_trace.cc",
+    "stack_trace.h",
+    "stack_trace_android.cc",
+    "stack_trace_posix.cc",
+    "stack_trace_win.cc",
+    "task_annotator.cc",
+    "task_annotator.h",
+  ]
+
+  if (is_android) {
+    # Android uses some Linux sources, put those back.
+    set_sources_assignment_filter([])
+    sources += [ "proc_maps_linux.cc" ]
+    set_sources_assignment_filter(sources_assignment_filter)
+
+    sources -= [ "stack_trace_posix.cc" ]
+  }
+
+  if (is_nacl) {
+    sources -= [
+      "crash_logging.cc",
+      "crash_logging.h",
+      "stack_trace.cc",
+      "stack_trace_posix.cc",
+    ]
+  }
+
+  configs += [ "//base:base_implementation" ]
+
+  deps = [
+    "//base/memory",
+    "//base/process",
+  ]
+
+  if (is_linux) {
+    defines = [ "USE_SYMBOLIZE" ]
+    deps += [ "//base/third_party/symbolize" ]
+  }
+
+  allow_circular_includes_from = [
+    "//base/memory",
+    "//base/process",
+  ]
+
+  visibility = [ "//base/*" ]
+}
diff --git a/base/debug/OWNERS b/base/debug/OWNERS
new file mode 100644
index 0000000..4976ab1
--- /dev/null
+++ b/base/debug/OWNERS
@@ -0,0 +1,3 @@
+per-file trace_event*=nduca@chromium.org
+per-file trace_event*=dsinclair@chromium.org
+per-file trace_event_android.cc=wangxianzhu@chromium.org
diff --git a/base/debug/alias.cc b/base/debug/alias.cc
new file mode 100644
index 0000000..6b0caaa
--- /dev/null
+++ b/base/debug/alias.cc
@@ -0,0 +1,23 @@
+// Copyright (c) 2011 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/debug/alias.h"
+#include "build/build_config.h"
+
+namespace base {
+namespace debug {
+
+#if defined(COMPILER_MSVC)
+#pragma optimize("", off)
+#endif
+
+void Alias(const void* var) {
+}
+
+#if defined(COMPILER_MSVC)
+#pragma optimize("", on)
+#endif
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/alias.h b/base/debug/alias.h
new file mode 100644
index 0000000..3b2ab64
--- /dev/null
+++ b/base/debug/alias.h
@@ -0,0 +1,21 @@
+// Copyright (c) 2011 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_DEBUG_ALIAS_H_
+#define BASE_DEBUG_ALIAS_H_
+
+#include "base/base_export.h"
+
+namespace base {
+namespace debug {
+
+// Make the optimizer think that var is aliased. This is to prevent it from
+// optimizing out variables that that would not otherwise be live at the point
+// of a potential crash.
+void BASE_EXPORT Alias(const void* var);
+
+}  // namespace debug
+}  // namespace base
+
+#endif  // BASE_DEBUG_ALIAS_H_
diff --git a/base/debug/asan_invalid_access.cc b/base/debug/asan_invalid_access.cc
new file mode 100644
index 0000000..cee2106
--- /dev/null
+++ b/base/debug/asan_invalid_access.cc
@@ -0,0 +1,105 @@
+// 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.
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
+#include "base/debug/alias.h"
+#include "base/debug/asan_invalid_access.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+
+namespace base {
+namespace debug {
+
+namespace {
+
+#if defined(SYZYASAN) && defined(COMPILER_MSVC)
+// Disable warning C4530: "C++ exception handler used, but unwind semantics are
+// not enabled". We don't want to change the compilation flags just for this
+// test, and no exception should be triggered here, so this warning has no value
+// here.
+#pragma warning(push)
+#pragma warning(disable: 4530)
+// Corrupt a memory block and make sure that the corruption gets detected either
+// when we free it or when another crash happens (if |induce_crash| is set to
+// true).
+NOINLINE void CorruptMemoryBlock(bool induce_crash) {
+  // NOTE(sebmarchand): We intentionally corrupt a memory block here in order to
+  //     trigger an Address Sanitizer (ASAN) error report.
+  static const int kArraySize = 5;
+  int* array = new int[kArraySize];
+  // Encapsulate the invalid memory access into a try-catch statement to prevent
+  // this function from being instrumented. This way the underflow won't be
+  // detected but the corruption will (as the allocator will still be hooked).
+  try {
+    // Declares the dummy value as volatile to make sure it doesn't get
+    // optimized away.
+    int volatile dummy = array[-1]--;
+    base::debug::Alias(const_cast<int*>(&dummy));
+  } catch (...) {
+  }
+  if (induce_crash)
+    CHECK(false);
+  delete[] array;
+}
+#pragma warning(pop)
+#endif  // SYZYASAN && COMPILER_MSVC
+
+}  // namespace
+
+#if defined(ADDRESS_SANITIZER) || defined(SYZYASAN)
+// NOTE(sebmarchand): We intentionally perform some invalid heap access here in
+//     order to trigger an AddressSanitizer (ASan) error report.
+
+static const size_t kArraySize = 5;
+
+void AsanHeapOverflow() {
+  scoped_ptr<int[]> array(new int[kArraySize]);
+  // Declares the dummy value as volatile to make sure it doesn't get optimized
+  // away.
+  int volatile dummy = 0;
+  dummy = array[kArraySize];
+  base::debug::Alias(const_cast<int*>(&dummy));
+}
+
+void AsanHeapUnderflow() {
+  scoped_ptr<int[]> array(new int[kArraySize]);
+  // Declares the dummy value as volatile to make sure it doesn't get optimized
+  // away.
+  int volatile dummy = 0;
+  // We need to store the underflow address in a temporary variable as trying to
+  // access array[-1] will trigger a warning C4245: "conversion from 'int' to
+  // 'size_t', signed/unsigned mismatch".
+  int* underflow_address = &array[0] - 1;
+  dummy = *underflow_address;
+  base::debug::Alias(const_cast<int*>(&dummy));
+}
+
+void AsanHeapUseAfterFree() {
+  scoped_ptr<int[]> array(new int[kArraySize]);
+  // Declares the dummy value as volatile to make sure it doesn't get optimized
+  // away.
+  int volatile dummy = 0;
+  int* dangling = array.get();
+  array.reset();
+  dummy = dangling[kArraySize / 2];
+  base::debug::Alias(const_cast<int*>(&dummy));
+}
+
+#endif  // ADDRESS_SANITIZER || SYZYASAN
+
+#if defined(SYZYASAN) && defined(COMPILER_MSVC)
+void AsanCorruptHeapBlock() {
+  CorruptMemoryBlock(false);
+}
+
+void AsanCorruptHeap() {
+  CorruptMemoryBlock(true);
+}
+#endif  // SYZYASAN && COMPILER_MSVC
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/asan_invalid_access.h b/base/debug/asan_invalid_access.h
new file mode 100644
index 0000000..bc9390e
--- /dev/null
+++ b/base/debug/asan_invalid_access.h
@@ -0,0 +1,47 @@
+// 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.
+//
+// Defines some functions that intentionally do an invalid memory access in
+// order to trigger an AddressSanitizer (ASan) error report.
+
+#ifndef BASE_DEBUG_ASAN_INVALID_ACCESS_H_
+#define BASE_DEBUG_ASAN_INVALID_ACCESS_H_
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+
+namespace base {
+namespace debug {
+
+#if defined(ADDRESS_SANITIZER) || defined(SYZYASAN)
+
+// Generates an heap buffer overflow.
+BASE_EXPORT NOINLINE void AsanHeapOverflow();
+
+// Generates an heap buffer underflow.
+BASE_EXPORT NOINLINE void AsanHeapUnderflow();
+
+// Generates an use after free.
+BASE_EXPORT NOINLINE void AsanHeapUseAfterFree();
+
+#endif  // ADDRESS_SANITIZER || SYZYASAN
+
+// The "corrupt-block" and "corrupt-heap" classes of bugs is specific to
+// SyzyASan.
+#if defined(SYZYASAN) && defined(COMPILER_MSVC)
+
+// Corrupts a memory block and makes sure that the corruption gets detected when
+// we try to free this block.
+BASE_EXPORT NOINLINE void AsanCorruptHeapBlock();
+
+// Corrupts the heap and makes sure that the corruption gets detected when a
+// crash occur.
+BASE_EXPORT NOINLINE void AsanCorruptHeap();
+
+#endif  // SYZYASAN && COMPILER_MSVC
+
+}  // namespace debug
+}  // namespace base
+
+#endif  // BASE_DEBUG_ASAN_INVALID_ACCESS_H_
diff --git a/base/debug/crash_logging.cc b/base/debug/crash_logging.cc
new file mode 100644
index 0000000..f9b4449
--- /dev/null
+++ b/base/debug/crash_logging.cc
@@ -0,0 +1,203 @@
+// Copyright (c) 2012 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/debug/crash_logging.h"
+
+#include <cmath>
+#include <map>
+
+#include "base/debug/stack_trace.h"
+#include "base/format_macros.h"
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+
+namespace base {
+namespace debug {
+
+namespace {
+
+// Global map of crash key names to registration entries.
+typedef std::map<base::StringPiece, CrashKey> CrashKeyMap;
+CrashKeyMap* g_crash_keys_ = NULL;
+
+// The maximum length of a single chunk.
+size_t g_chunk_max_length_ = 0;
+
+// String used to format chunked key names.
+const char kChunkFormatString[] = "%s-%" PRIuS;
+
+// The functions that are called to actually set the key-value pairs in the
+// crash reportng system.
+SetCrashKeyValueFuncT g_set_key_func_ = NULL;
+ClearCrashKeyValueFuncT g_clear_key_func_ = NULL;
+
+// For a given |length|, computes the number of chunks a value of that size
+// will occupy.
+size_t NumChunksForLength(size_t length) {
+  // Compute (length / g_chunk_max_length_), rounded up.
+  return (length + g_chunk_max_length_ - 1) / g_chunk_max_length_;
+}
+
+// The longest max_length allowed by the system.
+const size_t kLargestValueAllowed = 1024;
+
+}  // namespace
+
+void SetCrashKeyValue(const base::StringPiece& key,
+                      const base::StringPiece& value) {
+  if (!g_set_key_func_ || !g_crash_keys_)
+    return;
+
+  const CrashKey* crash_key = LookupCrashKey(key);
+
+  DCHECK(crash_key) << "All crash keys must be registered before use "
+                    << "(key = " << key << ")";
+
+  // Handle the un-chunked case.
+  if (!crash_key || crash_key->max_length <= g_chunk_max_length_) {
+    g_set_key_func_(key, value);
+    return;
+  }
+
+  // Unset the unused chunks.
+  std::vector<std::string> chunks =
+      ChunkCrashKeyValue(*crash_key, value, g_chunk_max_length_);
+  for (size_t i = chunks.size();
+       i < NumChunksForLength(crash_key->max_length);
+       ++i) {
+    g_clear_key_func_(base::StringPrintf(kChunkFormatString, key.data(), i+1));
+  }
+
+  // Set the chunked keys.
+  for (size_t i = 0; i < chunks.size(); ++i) {
+    g_set_key_func_(base::StringPrintf(kChunkFormatString, key.data(), i+1),
+                    chunks[i]);
+  }
+}
+
+void ClearCrashKey(const base::StringPiece& key) {
+  if (!g_clear_key_func_ || !g_crash_keys_)
+    return;
+
+  const CrashKey* crash_key = LookupCrashKey(key);
+
+  // Handle the un-chunked case.
+  if (!crash_key || crash_key->max_length <= g_chunk_max_length_) {
+    g_clear_key_func_(key);
+    return;
+  }
+
+  for (size_t i = 0; i < NumChunksForLength(crash_key->max_length); ++i) {
+    g_clear_key_func_(base::StringPrintf(kChunkFormatString, key.data(), i+1));
+  }
+}
+
+void SetCrashKeyToStackTrace(const base::StringPiece& key,
+                             const StackTrace& trace) {
+  size_t count = 0;
+  const void* const* addresses = trace.Addresses(&count);
+  SetCrashKeyFromAddresses(key, addresses, count);
+}
+
+void SetCrashKeyFromAddresses(const base::StringPiece& key,
+                              const void* const* addresses,
+                              size_t count) {
+  std::string value = "<null>";
+  if (addresses && count) {
+    const size_t kBreakpadValueMax = 255;
+
+    std::vector<std::string> hex_backtrace;
+    size_t length = 0;
+
+    for (size_t i = 0; i < count; ++i) {
+      std::string s = base::StringPrintf("%p", addresses[i]);
+      length += s.length() + 1;
+      if (length > kBreakpadValueMax)
+        break;
+      hex_backtrace.push_back(s);
+    }
+
+    value = JoinString(hex_backtrace, ' ');
+
+    // Warn if this exceeds the breakpad limits.
+    DCHECK_LE(value.length(), kBreakpadValueMax);
+  }
+
+  SetCrashKeyValue(key, value);
+}
+
+ScopedCrashKey::ScopedCrashKey(const base::StringPiece& key,
+                               const base::StringPiece& value)
+    : key_(key.as_string()) {
+  SetCrashKeyValue(key, value);
+}
+
+ScopedCrashKey::~ScopedCrashKey() {
+  ClearCrashKey(key_);
+}
+
+size_t InitCrashKeys(const CrashKey* const keys, size_t count,
+                     size_t chunk_max_length) {
+  DCHECK(!g_crash_keys_) << "Crash logging may only be initialized once";
+  if (!keys) {
+    delete g_crash_keys_;
+    g_crash_keys_ = NULL;
+    return 0;
+  }
+
+  g_crash_keys_ = new CrashKeyMap;
+  g_chunk_max_length_ = chunk_max_length;
+
+  size_t total_keys = 0;
+  for (size_t i = 0; i < count; ++i) {
+    g_crash_keys_->insert(std::make_pair(keys[i].key_name, keys[i]));
+    total_keys += NumChunksForLength(keys[i].max_length);
+    DCHECK_LT(keys[i].max_length, kLargestValueAllowed);
+  }
+  DCHECK_EQ(count, g_crash_keys_->size())
+      << "Duplicate crash keys were registered";
+
+  return total_keys;
+}
+
+const CrashKey* LookupCrashKey(const base::StringPiece& key) {
+  if (!g_crash_keys_)
+    return NULL;
+  CrashKeyMap::const_iterator it = g_crash_keys_->find(key.as_string());
+  if (it == g_crash_keys_->end())
+    return NULL;
+  return &(it->second);
+}
+
+void SetCrashKeyReportingFunctions(
+    SetCrashKeyValueFuncT set_key_func,
+    ClearCrashKeyValueFuncT clear_key_func) {
+  g_set_key_func_ = set_key_func;
+  g_clear_key_func_ = clear_key_func;
+}
+
+std::vector<std::string> ChunkCrashKeyValue(const CrashKey& crash_key,
+                                            const base::StringPiece& value,
+                                            size_t chunk_max_length) {
+  std::string value_string = value.substr(0, crash_key.max_length).as_string();
+  std::vector<std::string> chunks;
+  for (size_t offset = 0; offset < value_string.length(); ) {
+    std::string chunk = value_string.substr(offset, chunk_max_length);
+    chunks.push_back(chunk);
+    offset += chunk.length();
+  }
+  return chunks;
+}
+
+void ResetCrashLoggingForTesting() {
+  delete g_crash_keys_;
+  g_crash_keys_ = NULL;
+  g_chunk_max_length_ = 0;
+  g_set_key_func_ = NULL;
+  g_clear_key_func_ = NULL;
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/crash_logging.h b/base/debug/crash_logging.h
new file mode 100644
index 0000000..90e6687
--- /dev/null
+++ b/base/debug/crash_logging.h
@@ -0,0 +1,104 @@
+// Copyright (c) 2012 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_DEBUG_CRASH_LOGGING_H_
+#define BASE_DEBUG_CRASH_LOGGING_H_
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/strings/string_piece.h"
+
+// These functions add metadata to the upload payload when sending crash reports
+// to the crash server.
+//
+// IMPORTANT: On OS X and Linux, the key/value pairs are only sent as part of
+// the upload and are not included in the minidump!
+
+namespace base {
+namespace debug {
+
+class StackTrace;
+
+// Set or clear a specific key-value pair from the crash metadata. Keys and
+// values are terminated at the null byte.
+BASE_EXPORT void SetCrashKeyValue(const base::StringPiece& key,
+                                  const base::StringPiece& value);
+BASE_EXPORT void ClearCrashKey(const base::StringPiece& key);
+
+// Records the given StackTrace into a crash key.
+BASE_EXPORT void SetCrashKeyToStackTrace(const base::StringPiece& key,
+                                         const StackTrace& trace);
+
+// Formats |count| instruction pointers from |addresses| using %p and
+// sets the resulting string as a value for crash key |key|. A maximum of 23
+// items will be encoded, since breakpad limits values to 255 bytes.
+BASE_EXPORT void SetCrashKeyFromAddresses(const base::StringPiece& key,
+                                          const void* const* addresses,
+                                          size_t count);
+
+// A scoper that sets the specified key to value for the lifetime of the
+// object, and clears it on destruction.
+class BASE_EXPORT ScopedCrashKey {
+ public:
+  ScopedCrashKey(const base::StringPiece& key, const base::StringPiece& value);
+  ~ScopedCrashKey();
+
+ private:
+  std::string key_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedCrashKey);
+};
+
+// Before setting values for a key, all the keys must be registered.
+struct BASE_EXPORT CrashKey {
+  // The name of the crash key, used in the above functions.
+  const char* key_name;
+
+  // The maximum length for a value. If the value is longer than this, it will
+  // be truncated. If the value is larger than the |chunk_max_length| passed to
+  // InitCrashKeys() but less than this value, it will be split into multiple
+  // numbered chunks.
+  size_t max_length;
+};
+
+// Before the crash key logging mechanism can be used, all crash keys must be
+// registered with this function. The function returns the amount of space
+// the crash reporting implementation should allocate space for the registered
+// crash keys. |chunk_max_length| is the maximum size that a value in a single
+// chunk can be.
+BASE_EXPORT size_t InitCrashKeys(const CrashKey* const keys, size_t count,
+                                 size_t chunk_max_length);
+
+// Returns the correspnding crash key object or NULL for a given key.
+BASE_EXPORT const CrashKey* LookupCrashKey(const base::StringPiece& key);
+
+// In the platform crash reporting implementation, these functions set and
+// clear the NUL-termianted key-value pairs.
+typedef void (*SetCrashKeyValueFuncT)(const base::StringPiece&,
+                                      const base::StringPiece&);
+typedef void (*ClearCrashKeyValueFuncT)(const base::StringPiece&);
+
+// Sets the function pointers that are used to integrate with the platform-
+// specific crash reporting libraries.
+BASE_EXPORT void SetCrashKeyReportingFunctions(
+    SetCrashKeyValueFuncT set_key_func,
+    ClearCrashKeyValueFuncT clear_key_func);
+
+// Helper function that breaks up a value according to the parameters
+// specified by the crash key object.
+BASE_EXPORT std::vector<std::string> ChunkCrashKeyValue(
+    const CrashKey& crash_key,
+    const base::StringPiece& value,
+    size_t chunk_max_length);
+
+// Resets the crash key system so it can be reinitialized. For testing only.
+BASE_EXPORT void ResetCrashLoggingForTesting();
+
+}  // namespace debug
+}  // namespace base
+
+#endif  // BASE_DEBUG_CRASH_LOGGING_H_
diff --git a/base/debug/crash_logging_unittest.cc b/base/debug/crash_logging_unittest.cc
new file mode 100644
index 0000000..4cd9f3e
--- /dev/null
+++ b/base/debug/crash_logging_unittest.cc
@@ -0,0 +1,182 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/debug/crash_logging.h"
+
+#include <map>
+#include <string>
+
+#include "base/bind.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+std::map<std::string, std::string>* key_values_ = NULL;
+
+}  // namespace
+
+class CrashLoggingTest : public testing::Test {
+ public:
+  void SetUp() override {
+    key_values_ = new std::map<std::string, std::string>;
+    base::debug::SetCrashKeyReportingFunctions(
+        &CrashLoggingTest::SetKeyValue,
+        &CrashLoggingTest::ClearKeyValue);
+  }
+
+  void TearDown() override {
+    base::debug::ResetCrashLoggingForTesting();
+
+    delete key_values_;
+    key_values_ = NULL;
+  }
+
+ private:
+  static void SetKeyValue(const base::StringPiece& key,
+                          const base::StringPiece& value) {
+    (*key_values_)[key.as_string()] = value.as_string();
+  }
+
+  static void ClearKeyValue(const base::StringPiece& key) {
+    key_values_->erase(key.as_string());
+  }
+};
+
+TEST_F(CrashLoggingTest, SetClearSingle) {
+  const char kTestKey[] = "test-key";
+  base::debug::CrashKey keys[] = { { kTestKey, 255 } };
+  base::debug::InitCrashKeys(keys, arraysize(keys), 255);
+
+  base::debug::SetCrashKeyValue(kTestKey, "value");
+  EXPECT_EQ("value", (*key_values_)[kTestKey]);
+
+  base::debug::ClearCrashKey(kTestKey);
+  EXPECT_TRUE(key_values_->end() == key_values_->find(kTestKey));
+}
+
+TEST_F(CrashLoggingTest, SetChunked) {
+  const char kTestKey[] = "chunky";
+  const char kChunk1[] = "chunky-1";
+  const char kChunk2[] = "chunky-2";
+  const char kChunk3[] = "chunky-3";
+  base::debug::CrashKey keys[] = { { kTestKey, 15 } };
+  base::debug::InitCrashKeys(keys, arraysize(keys), 5);
+
+  std::map<std::string, std::string>& values = *key_values_;
+
+  // Fill only the first chunk.
+  base::debug::SetCrashKeyValue(kTestKey, "foo");
+  EXPECT_EQ(1u, values.size());
+  EXPECT_EQ("foo", values[kChunk1]);
+  EXPECT_TRUE(values.end() == values.find(kChunk2));
+  EXPECT_TRUE(values.end() == values.find(kChunk3));
+
+  // Fill three chunks with truncation (max length is 15, this string is 20).
+  base::debug::SetCrashKeyValue(kTestKey, "five four three two");
+  EXPECT_EQ(3u, values.size());
+  EXPECT_EQ("five ", values[kChunk1]);
+  EXPECT_EQ("four ", values[kChunk2]);
+  EXPECT_EQ("three", values[kChunk3]);
+
+  // Clear everything.
+  base::debug::ClearCrashKey(kTestKey);
+  EXPECT_EQ(0u, values.size());
+  EXPECT_TRUE(values.end() == values.find(kChunk1));
+  EXPECT_TRUE(values.end() == values.find(kChunk2));
+  EXPECT_TRUE(values.end() == values.find(kChunk3));
+
+  // Refill all three chunks with truncation, then test that setting a smaller
+  // value clears the third chunk.
+  base::debug::SetCrashKeyValue(kTestKey, "five four three two");
+  base::debug::SetCrashKeyValue(kTestKey, "allays");
+  EXPECT_EQ(2u, values.size());
+  EXPECT_EQ("allay", values[kChunk1]);
+  EXPECT_EQ("s", values[kChunk2]);
+  EXPECT_TRUE(values.end() == values.find(kChunk3));
+
+  // Clear everything.
+  base::debug::ClearCrashKey(kTestKey);
+  EXPECT_EQ(0u, values.size());
+  EXPECT_TRUE(values.end() == values.find(kChunk1));
+  EXPECT_TRUE(values.end() == values.find(kChunk2));
+  EXPECT_TRUE(values.end() == values.find(kChunk3));
+}
+
+TEST_F(CrashLoggingTest, ScopedCrashKey) {
+  const char kTestKey[] = "test-key";
+  base::debug::CrashKey keys[] = { { kTestKey, 255 } };
+  base::debug::InitCrashKeys(keys, arraysize(keys), 255);
+
+  EXPECT_EQ(0u, key_values_->size());
+  EXPECT_TRUE(key_values_->end() == key_values_->find(kTestKey));
+  {
+    base::debug::ScopedCrashKey scoped_crash_key(kTestKey, "value");
+    EXPECT_EQ("value", (*key_values_)[kTestKey]);
+    EXPECT_EQ(1u, key_values_->size());
+  }
+  EXPECT_EQ(0u, key_values_->size());
+  EXPECT_TRUE(key_values_->end() == key_values_->find(kTestKey));
+}
+
+TEST_F(CrashLoggingTest, InitSize) {
+  base::debug::CrashKey keys[] = {
+    { "chunked-3", 15 },
+    { "single", 5 },
+    { "chunked-6", 30 },
+  };
+
+  size_t num_keys = base::debug::InitCrashKeys(keys, arraysize(keys), 5);
+
+  EXPECT_EQ(10u, num_keys);
+
+  EXPECT_TRUE(base::debug::LookupCrashKey("chunked-3"));
+  EXPECT_TRUE(base::debug::LookupCrashKey("single"));
+  EXPECT_TRUE(base::debug::LookupCrashKey("chunked-6"));
+  EXPECT_FALSE(base::debug::LookupCrashKey("chunked-6-4"));
+}
+
+TEST_F(CrashLoggingTest, ChunkValue) {
+  using base::debug::ChunkCrashKeyValue;
+
+  // Test truncation.
+  base::debug::CrashKey key = { "chunky", 10 };
+  std::vector<std::string> results =
+      ChunkCrashKeyValue(key, "hello world", 64);
+  ASSERT_EQ(1u, results.size());
+  EXPECT_EQ("hello worl", results[0]);
+
+  // Test short string.
+  results = ChunkCrashKeyValue(key, "hi", 10);
+  ASSERT_EQ(1u, results.size());
+  EXPECT_EQ("hi", results[0]);
+
+  // Test chunk pair.
+  key.max_length = 6;
+  results = ChunkCrashKeyValue(key, "foobar", 3);
+  ASSERT_EQ(2u, results.size());
+  EXPECT_EQ("foo", results[0]);
+  EXPECT_EQ("bar", results[1]);
+
+  // Test chunk pair truncation.
+  results = ChunkCrashKeyValue(key, "foobared", 3);
+  ASSERT_EQ(2u, results.size());
+  EXPECT_EQ("foo", results[0]);
+  EXPECT_EQ("bar", results[1]);
+
+  // Test extra chunks.
+  key.max_length = 100;
+  results = ChunkCrashKeyValue(key, "hello world", 3);
+  ASSERT_EQ(4u, results.size());
+  EXPECT_EQ("hel", results[0]);
+  EXPECT_EQ("lo ", results[1]);
+  EXPECT_EQ("wor", results[2]);
+  EXPECT_EQ("ld",  results[3]);
+}
+
+TEST_F(CrashLoggingTest, ChunkRounding) {
+  // If max_length=12 and max_chunk_length=5, there should be 3 chunks,
+  // not 2.
+  base::debug::CrashKey key = { "round", 12 };
+  EXPECT_EQ(3u, base::debug::InitCrashKeys(&key, 1, 5));
+}
diff --git a/base/debug/debugger.cc b/base/debug/debugger.cc
new file mode 100644
index 0000000..79233c5
--- /dev/null
+++ b/base/debug/debugger.cc
@@ -0,0 +1,41 @@
+// Copyright (c) 2011 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/debug/debugger.h"
+#include "base/logging.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+namespace debug {
+
+static bool is_debug_ui_suppressed = false;
+
+bool WaitForDebugger(int wait_seconds, bool silent) {
+#if defined(OS_ANDROID)
+  // The pid from which we know which process to attach to are not output by
+  // android ddms, so we have to print it out explicitly.
+  DLOG(INFO) << "DebugUtil::WaitForDebugger(pid=" << static_cast<int>(getpid())
+             << ")";
+#endif
+  for (int i = 0; i < wait_seconds * 10; ++i) {
+    if (BeingDebugged()) {
+      if (!silent)
+        BreakDebugger();
+      return true;
+    }
+    PlatformThread::Sleep(TimeDelta::FromMilliseconds(100));
+  }
+  return false;
+}
+
+void SetSuppressDebugUI(bool suppress) {
+  is_debug_ui_suppressed = suppress;
+}
+
+bool IsDebugUISuppressed() {
+  return is_debug_ui_suppressed;
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/debugger.h b/base/debug/debugger.h
new file mode 100644
index 0000000..8680e28
--- /dev/null
+++ b/base/debug/debugger.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2011 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 is a cross platform interface for helper functions related to
+// debuggers.  You should use this to test if you're running under a debugger,
+// and if you would like to yield (breakpoint) into the debugger.
+
+#ifndef BASE_DEBUG_DEBUGGER_H_
+#define BASE_DEBUG_DEBUGGER_H_
+
+#include "base/base_export.h"
+
+namespace base {
+namespace debug {
+
+// Waits wait_seconds seconds for a debugger to attach to the current process.
+// When silent is false, an exception is thrown when a debugger is detected.
+BASE_EXPORT bool WaitForDebugger(int wait_seconds, bool silent);
+
+// Returns true if the given process is being run under a debugger.
+//
+// On OS X, the underlying mechanism doesn't work when the sandbox is enabled.
+// To get around this, this function caches its value.
+//
+// WARNING: Because of this, on OS X, a call MUST be made to this function
+// BEFORE the sandbox is enabled.
+BASE_EXPORT bool BeingDebugged();
+
+// Break into the debugger, assumes a debugger is present.
+BASE_EXPORT void BreakDebugger();
+
+// Used in test code, this controls whether showing dialogs and breaking into
+// the debugger is suppressed for debug errors, even in debug mode (normally
+// release mode doesn't do this stuff --  this is controlled separately).
+// Normally UI is not suppressed.  This is normally used when running automated
+// tests where we want a crash rather than a dialog or a debugger.
+BASE_EXPORT void SetSuppressDebugUI(bool suppress);
+BASE_EXPORT bool IsDebugUISuppressed();
+
+}  // namespace debug
+}  // namespace base
+
+#endif  // BASE_DEBUG_DEBUGGER_H_
diff --git a/base/debug/debugger_posix.cc b/base/debug/debugger_posix.cc
new file mode 100644
index 0000000..8599571
--- /dev/null
+++ b/base/debug/debugger_posix.cc
@@ -0,0 +1,254 @@
+// Copyright (c) 2012 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/debug/debugger.h"
+#include "build/build_config.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <vector>
+
+#if defined(__GLIBCXX__)
+#include <cxxabi.h>
+#endif
+
+#if defined(OS_MACOSX)
+#include <AvailabilityMacros.h>
+#endif
+
+#if defined(OS_MACOSX) || defined(OS_BSD)
+#include <sys/sysctl.h>
+#endif
+
+#if defined(OS_FREEBSD)
+#include <sys/user.h>
+#endif
+
+#include <ostream>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/strings/string_piece.h"
+
+#if defined(USE_SYMBOLIZE)
+#include "base/third_party/symbolize/symbolize.h"
+#endif
+
+#if defined(OS_ANDROID)
+#include "base/threading/platform_thread.h"
+#endif
+
+namespace base {
+namespace debug {
+
+#if defined(OS_MACOSX) || defined(OS_BSD)
+
+// Based on Apple's recommended method as described in
+// http://developer.apple.com/qa/qa2004/qa1361.html
+bool BeingDebugged() {
+  // NOTE: This code MUST be async-signal safe (it's used by in-process
+  // stack dumping signal handler). NO malloc or stdio is allowed here.
+  //
+  // While some code used below may be async-signal unsafe, note how
+  // the result is cached (see |is_set| and |being_debugged| static variables
+  // right below). If this code is properly warmed-up early
+  // in the start-up process, it should be safe to use later.
+
+  // If the process is sandboxed then we can't use the sysctl, so cache the
+  // value.
+  static bool is_set = false;
+  static bool being_debugged = false;
+
+  if (is_set)
+    return being_debugged;
+
+  // Initialize mib, which tells sysctl what info we want.  In this case,
+  // we're looking for information about a specific process ID.
+  int mib[] = {
+    CTL_KERN,
+    KERN_PROC,
+    KERN_PROC_PID,
+    getpid()
+#if defined(OS_OPENBSD)
+    , sizeof(struct kinfo_proc),
+    0
+#endif
+  };
+
+  // Caution: struct kinfo_proc is marked __APPLE_API_UNSTABLE.  The source and
+  // binary interfaces may change.
+  struct kinfo_proc info;
+  size_t info_size = sizeof(info);
+
+#if defined(OS_OPENBSD)
+  if (sysctl(mib, arraysize(mib), NULL, &info_size, NULL, 0) < 0)
+    return -1;
+
+  mib[5] = (info_size / sizeof(struct kinfo_proc));
+#endif
+
+  int sysctl_result = sysctl(mib, arraysize(mib), &info, &info_size, NULL, 0);
+  DCHECK_EQ(sysctl_result, 0);
+  if (sysctl_result != 0) {
+    is_set = true;
+    being_debugged = false;
+    return being_debugged;
+  }
+
+  // This process is being debugged if the P_TRACED flag is set.
+  is_set = true;
+#if defined(OS_FREEBSD)
+  being_debugged = (info.ki_flag & P_TRACED) != 0;
+#elif defined(OS_BSD)
+  being_debugged = (info.p_flag & P_TRACED) != 0;
+#else
+  being_debugged = (info.kp_proc.p_flag & P_TRACED) != 0;
+#endif
+  return being_debugged;
+}
+
+#elif defined(OS_LINUX) || defined(OS_ANDROID)
+
+// We can look in /proc/self/status for TracerPid.  We are likely used in crash
+// handling, so we are careful not to use the heap or have side effects.
+// Another option that is common is to try to ptrace yourself, but then we
+// can't detach without forking(), and that's not so great.
+// static
+bool BeingDebugged() {
+  // NOTE: This code MUST be async-signal safe (it's used by in-process
+  // stack dumping signal handler). NO malloc or stdio is allowed here.
+
+  int status_fd = open("/proc/self/status", O_RDONLY);
+  if (status_fd == -1)
+    return false;
+
+  // We assume our line will be in the first 1024 characters and that we can
+  // read this much all at once.  In practice this will generally be true.
+  // This simplifies and speeds up things considerably.
+  char buf[1024];
+
+  ssize_t num_read = HANDLE_EINTR(read(status_fd, buf, sizeof(buf)));
+  if (IGNORE_EINTR(close(status_fd)) < 0)
+    return false;
+
+  if (num_read <= 0)
+    return false;
+
+  StringPiece status(buf, num_read);
+  StringPiece tracer("TracerPid:\t");
+
+  StringPiece::size_type pid_index = status.find(tracer);
+  if (pid_index == StringPiece::npos)
+    return false;
+
+  // Our pid is 0 without a debugger, assume this for any pid starting with 0.
+  pid_index += tracer.size();
+  return pid_index < status.size() && status[pid_index] != '0';
+}
+
+#else
+
+bool BeingDebugged() {
+  NOTIMPLEMENTED();
+  return false;
+}
+
+#endif
+
+// We want to break into the debugger in Debug mode, and cause a crash dump in
+// Release mode. Breakpad behaves as follows:
+//
+// +-------+-----------------+-----------------+
+// | OS    | Dump on SIGTRAP | Dump on SIGABRT |
+// +-------+-----------------+-----------------+
+// | Linux |       N         |        Y        |
+// | Mac   |       Y         |        N        |
+// +-------+-----------------+-----------------+
+//
+// Thus we do the following:
+// Linux: Debug mode if a debugger is attached, send SIGTRAP; otherwise send
+//        SIGABRT
+// Mac: Always send SIGTRAP.
+
+#if defined(ARCH_CPU_ARMEL)
+#define DEBUG_BREAK_ASM() asm("bkpt 0")
+#elif defined(ARCH_CPU_ARM64)
+#define DEBUG_BREAK_ASM() asm("brk 0")
+#elif defined(ARCH_CPU_MIPS_FAMILY)
+#define DEBUG_BREAK_ASM() asm("break 2")
+#elif defined(ARCH_CPU_X86_FAMILY)
+#define DEBUG_BREAK_ASM() asm("int3")
+#endif
+
+#if defined(NDEBUG) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
+#define DEBUG_BREAK() abort()
+#elif defined(OS_NACL)
+// The NaCl verifier doesn't let use use int3.  For now, we call abort().  We
+// should ask for advice from some NaCl experts about the optimum thing here.
+// http://code.google.com/p/nativeclient/issues/detail?id=645
+#define DEBUG_BREAK() abort()
+#elif !defined(OS_MACOSX)
+// Though Android has a "helpful" process called debuggerd to catch native
+// signals on the general assumption that they are fatal errors. If no debugger
+// is attached, we call abort since Breakpad needs SIGABRT to create a dump.
+// When debugger is attached, for ARM platform the bkpt instruction appears
+// to cause SIGBUS which is trapped by debuggerd, and we've had great
+// difficulty continuing in a debugger once we stop from SIG triggered by native
+// code, use GDB to set |go| to 1 to resume execution; for X86 platform, use
+// "int3" to setup breakpiont and raise SIGTRAP.
+//
+// On other POSIX architectures, except Mac OS X, we use the same logic to
+// ensure that breakpad creates a dump on crashes while it is still possible to
+// use a debugger.
+namespace {
+void DebugBreak() {
+  if (!BeingDebugged()) {
+    abort();
+  } else {
+#if defined(DEBUG_BREAK_ASM)
+    DEBUG_BREAK_ASM();
+#else
+    volatile int go = 0;
+    while (!go) {
+      base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
+    }
+#endif
+  }
+}
+}  // namespace
+#define DEBUG_BREAK() DebugBreak()
+#elif defined(DEBUG_BREAK_ASM)
+#define DEBUG_BREAK() DEBUG_BREAK_ASM()
+#else
+#error "Don't know how to debug break on this architecture/OS"
+#endif
+
+void BreakDebugger() {
+  // NOTE: This code MUST be async-signal safe (it's used by in-process
+  // stack dumping signal handler). NO malloc or stdio is allowed here.
+
+  DEBUG_BREAK();
+#if defined(OS_ANDROID) && !defined(OFFICIAL_BUILD)
+  // For Android development we always build release (debug builds are
+  // unmanageably large), so the unofficial build is used for debugging. It is
+  // helpful to be able to insert BreakDebugger() statements in the source,
+  // attach the debugger, inspect the state of the program and then resume it by
+  // setting the 'go' variable above.
+#elif defined(NDEBUG)
+  // Terminate the program after signaling the debug break.
+  _exit(1);
+#endif
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/debugger_unittest.cc b/base/debug/debugger_unittest.cc
new file mode 100644
index 0000000..0a5a039
--- /dev/null
+++ b/base/debug/debugger_unittest.cc
@@ -0,0 +1,43 @@
+// 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.
+
+#include "base/debug/debugger.h"
+
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+#if defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
+void CrashWithBreakDebugger() {
+  base::debug::SetSuppressDebugUI(false);
+  base::debug::BreakDebugger();
+
+#if defined(OS_WIN)
+  // This should not be executed.
+  _exit(125);
+#endif
+}
+#endif  // defined(GTEST_HAS_DEATH_TEST)
+
+}  // namespace
+
+// Death tests misbehave on Android.
+#if defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
+
+TEST(Debugger, CrashAtBreakpoint) {
+  EXPECT_DEATH(CrashWithBreakDebugger(), "");
+}
+
+#if defined(OS_WIN)
+TEST(Debugger, DoesntExecuteBeyondBreakpoint) {
+  EXPECT_EXIT(CrashWithBreakDebugger(),
+              ::testing::ExitedWithCode(0x80000003), "");
+}
+#endif  // defined(OS_WIN)
+
+#else  // defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
+TEST(Debugger, NoTest) {
+}
+#endif  // defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
diff --git a/base/debug/debugger_win.cc b/base/debug/debugger_win.cc
new file mode 100644
index 0000000..a1d86e4
--- /dev/null
+++ b/base/debug/debugger_win.cc
@@ -0,0 +1,25 @@
+// Copyright (c) 2010 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/debug/debugger.h"
+
+#include <stdlib.h>
+#include <windows.h>
+
+namespace base {
+namespace debug {
+
+bool BeingDebugged() {
+  return ::IsDebuggerPresent() != 0;
+}
+
+void BreakDebugger() {
+  if (IsDebugUISuppressed())
+    _exit(1);
+
+  __debugbreak();
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/dump_without_crashing.cc b/base/debug/dump_without_crashing.cc
new file mode 100644
index 0000000..47fd873
--- /dev/null
+++ b/base/debug/dump_without_crashing.cc
@@ -0,0 +1,32 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/debug/dump_without_crashing.h"
+
+#include "base/logging.h"
+
+namespace {
+
+// Pointer to the function that's called by DumpWithoutCrashing() to dump the
+// process's memory.
+void (CDECL *dump_without_crashing_function_)() = NULL;
+
+}  // namespace
+
+namespace base {
+
+namespace debug {
+
+void DumpWithoutCrashing() {
+  if (dump_without_crashing_function_)
+    (*dump_without_crashing_function_)();
+}
+
+void SetDumpWithoutCrashingFunction(void (CDECL *function)()) {
+  dump_without_crashing_function_ = function;
+}
+
+}  // namespace debug
+
+}  // namespace base
diff --git a/base/debug/dump_without_crashing.h b/base/debug/dump_without_crashing.h
new file mode 100644
index 0000000..b8ed174
--- /dev/null
+++ b/base/debug/dump_without_crashing.h
@@ -0,0 +1,30 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_DEBUG_DUMP_WITHOUT_CRASHING_H_
+#define BASE_DEBUG_DUMP_WITHOUT_CRASHING_H_
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "build/build_config.h"
+
+namespace base {
+
+namespace debug {
+
+// Handler to silently dump the current process without crashing.
+// Before calling this function, call SetDumpWithoutCrashingFunction to pass a
+// function pointer, typically chrome!DumpProcessWithoutCrash.  See example code
+// in chrome_main.cc that does this for chrome.dll.
+BASE_EXPORT void DumpWithoutCrashing();
+
+// Sets a function that'll be invoked to dump the current process when
+// DumpWithoutCrashing() is called.
+BASE_EXPORT void SetDumpWithoutCrashingFunction(void (CDECL *function)());
+
+}  // namespace debug
+
+}  // namespace base
+
+#endif  // BASE_DEBUG_DUMP_WITHOUT_CRASHING_H_
diff --git a/base/debug/gdi_debug_util_win.cc b/base/debug/gdi_debug_util_win.cc
new file mode 100644
index 0000000..3cd71f1
--- /dev/null
+++ b/base/debug/gdi_debug_util_win.cc
@@ -0,0 +1,124 @@
+// 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.
+#include "base/debug/gdi_debug_util_win.h"
+
+#include <cmath>
+
+#include <psapi.h>
+#include <TlHelp32.h>
+
+#include "base/debug/alias.h"
+#include "base/logging.h"
+#include "base/win/scoped_handle.h"
+
+namespace {
+
+void CollectChildGDIUsageAndDie(DWORD parent_pid) {
+  HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+  CHECK_NE(INVALID_HANDLE_VALUE, snapshot);
+
+  int child_count = 0;
+  base::debug::Alias(&child_count);
+  int peak_gdi_count = 0;
+  base::debug::Alias(&peak_gdi_count);
+  int sum_gdi_count = 0;
+  base::debug::Alias(&sum_gdi_count);
+  int sum_user_count = 0;
+  base::debug::Alias(&sum_user_count);
+
+  PROCESSENTRY32 proc_entry = {0};
+  proc_entry.dwSize = sizeof(PROCESSENTRY32);
+  CHECK(Process32First(snapshot, &proc_entry));
+
+  do {
+    if (parent_pid != proc_entry.th32ParentProcessID)
+      continue;
+    // Got a child process. Compute GDI usage.
+    base::win::ScopedHandle process(
+        OpenProcess(PROCESS_QUERY_INFORMATION,
+                    FALSE,
+                    proc_entry.th32ParentProcessID));
+    if (!process.IsValid())
+      continue;
+
+    int num_gdi_handles = GetGuiResources(process.Get(), GR_GDIOBJECTS);
+    int num_user_handles = GetGuiResources(process.Get(), GR_USEROBJECTS);
+
+    // Compute sum and peak counts.
+    ++child_count;
+    sum_user_count += num_user_handles;
+    sum_gdi_count += num_gdi_handles;
+    if (peak_gdi_count < num_gdi_handles)
+      peak_gdi_count = num_gdi_handles;
+
+  } while (Process32Next(snapshot, &proc_entry));
+
+  CloseHandle(snapshot);
+  CHECK(false);
+}
+
+}  // namespace
+
+namespace base {
+namespace debug {
+
+void GDIBitmapAllocFailure(BITMAPINFOHEADER* header, HANDLE shared_section) {
+  // Make sure parameters are saved in the minidump.
+  DWORD last_error = GetLastError();
+
+  LONG width = header->biWidth;
+  LONG heigth = header->biHeight;
+
+  base::debug::Alias(&last_error);
+  base::debug::Alias(&width);
+  base::debug::Alias(&heigth);
+  base::debug::Alias(&shared_section);
+
+  int num_user_handles = GetGuiResources(GetCurrentProcess(),
+                                         GR_USEROBJECTS);
+
+  int num_gdi_handles = GetGuiResources(GetCurrentProcess(),
+                                        GR_GDIOBJECTS);
+  if (num_gdi_handles == 0) {
+    DWORD get_gui_resources_error = GetLastError();
+    base::debug::Alias(&get_gui_resources_error);
+    CHECK(false);
+  }
+
+  base::debug::Alias(&num_gdi_handles);
+  base::debug::Alias(&num_user_handles);
+
+  const DWORD kLotsOfHandles = 9990;
+  CHECK_LE(num_gdi_handles, kLotsOfHandles);
+
+  PROCESS_MEMORY_COUNTERS_EX pmc;
+  pmc.cb = sizeof(pmc);
+  CHECK(GetProcessMemoryInfo(GetCurrentProcess(),
+                             reinterpret_cast<PROCESS_MEMORY_COUNTERS*>(&pmc),
+                             sizeof(pmc)));
+  const size_t kLotsOfMemory = 1500 * 1024 * 1024; // 1.5GB
+  CHECK_LE(pmc.PagefileUsage, kLotsOfMemory);
+  CHECK_LE(pmc.PrivateUsage, kLotsOfMemory);
+
+  void* small_data = NULL;
+  base::debug::Alias(&small_data);
+
+  if (std::abs(heigth) * width > 100) {
+    // Huh, that's weird.  We don't have crazy handle count, we don't have
+    // ridiculous memory usage. Try to allocate a small bitmap and see if that
+    // fails too.
+    header->biWidth = 5;
+    header->biHeight = -5;
+    HBITMAP small_bitmap = CreateDIBSection(
+        NULL, reinterpret_cast<BITMAPINFO*>(&header),
+        0, &small_data, shared_section, 0);
+    CHECK(small_bitmap != NULL);
+    DeleteObject(small_bitmap);
+  }
+  // Maybe the child processes are the ones leaking GDI or USER resouces.
+  CollectChildGDIUsageAndDie(GetCurrentProcessId());
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/gdi_debug_util_win.h b/base/debug/gdi_debug_util_win.h
new file mode 100644
index 0000000..5887ecb
--- /dev/null
+++ b/base/debug/gdi_debug_util_win.h
@@ -0,0 +1,23 @@
+// 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.
+
+#ifndef BASE_DEBUG_GDI_DEBUG_UTIL_WIN_H_
+#define BASE_DEBUG_GDI_DEBUG_UTIL_WIN_H_
+
+#include <windows.h>
+
+#include "base/base_export.h"
+
+namespace base {
+namespace debug {
+
+// Crashes the process leaving valuable information on the dump via
+// debug::alias so we can find what is causing the allocation failures.
+void BASE_EXPORT GDIBitmapAllocFailure(BITMAPINFOHEADER* header,
+                                       HANDLE shared_section);
+
+}  // namespace debug
+}  // namespace base
+
+#endif  // BASE_DEBUG_GDI_DEBUG_UTIL_WIN_H_
diff --git a/base/debug/leak_annotations.h b/base/debug/leak_annotations.h
new file mode 100644
index 0000000..ef37959
--- /dev/null
+++ b/base/debug/leak_annotations.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2011 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_DEBUG_LEAK_ANNOTATIONS_H_
+#define BASE_DEBUG_LEAK_ANNOTATIONS_H_
+
+#include "base/basictypes.h"
+#include "build/build_config.h"
+
+// This file defines macros which can be used to annotate intentional memory
+// leaks. Support for annotations is implemented in LeakSanitizer. Annotated
+// objects will be treated as a source of live pointers, i.e. any heap objects
+// reachable by following pointers from an annotated object will not be
+// reported as leaks.
+//
+// ANNOTATE_SCOPED_MEMORY_LEAK: all allocations made in the current scope
+// will be annotated as leaks.
+// ANNOTATE_LEAKING_OBJECT_PTR(X): the heap object referenced by pointer X will
+// be annotated as a leak.
+
+#if defined(LEAK_SANITIZER) && !defined(OS_NACL)
+
+#include <sanitizer/lsan_interface.h>
+
+class ScopedLeakSanitizerDisabler {
+ public:
+  ScopedLeakSanitizerDisabler() { __lsan_disable(); }
+  ~ScopedLeakSanitizerDisabler() { __lsan_enable(); }
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ScopedLeakSanitizerDisabler);
+};
+
+#define ANNOTATE_SCOPED_MEMORY_LEAK \
+    ScopedLeakSanitizerDisabler leak_sanitizer_disabler; static_cast<void>(0)
+
+#define ANNOTATE_LEAKING_OBJECT_PTR(X) __lsan_ignore_object(X);
+
+#else
+
+#define ANNOTATE_SCOPED_MEMORY_LEAK ((void)0)
+#define ANNOTATE_LEAKING_OBJECT_PTR(X) ((void)0)
+
+#endif
+
+#endif  // BASE_DEBUG_LEAK_ANNOTATIONS_H_
diff --git a/base/debug/leak_tracker.h b/base/debug/leak_tracker.h
new file mode 100644
index 0000000..8c5aaf3
--- /dev/null
+++ b/base/debug/leak_tracker.h
@@ -0,0 +1,138 @@
+// Copyright (c) 2012 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_DEBUG_LEAK_TRACKER_H_
+#define BASE_DEBUG_LEAK_TRACKER_H_
+
+#include "build/build_config.h"
+
+// Only enable leak tracking in non-uClibc debug builds.
+#if !defined(NDEBUG) && !defined(__UCLIBC__)
+#define ENABLE_LEAK_TRACKER
+#endif
+
+#ifdef ENABLE_LEAK_TRACKER
+#include "base/containers/linked_list.h"
+#include "base/debug/stack_trace.h"
+#include "base/logging.h"
+#endif  // ENABLE_LEAK_TRACKER
+
+// LeakTracker is a helper to verify that all instances of a class
+// have been destroyed.
+//
+// It is particularly useful for classes that are bound to a single thread --
+// before destroying that thread, one can check that there are no remaining
+// instances of that class.
+//
+// For example, to enable leak tracking for class net::URLRequest, start by
+// adding a member variable of type LeakTracker<net::URLRequest>.
+//
+//   class URLRequest {
+//     ...
+//    private:
+//     base::LeakTracker<URLRequest> leak_tracker_;
+//   };
+//
+//
+// Next, when we believe all instances of net::URLRequest have been deleted:
+//
+//   LeakTracker<net::URLRequest>::CheckForLeaks();
+//
+// Should the check fail (because there are live instances of net::URLRequest),
+// then the allocation callstack for each leaked instances is dumped to
+// the error log.
+//
+// If ENABLE_LEAK_TRACKER is not defined, then the check has no effect.
+
+namespace base {
+namespace debug {
+
+#ifndef ENABLE_LEAK_TRACKER
+
+// If leak tracking is disabled, do nothing.
+template<typename T>
+class LeakTracker {
+ public:
+  ~LeakTracker() {}
+  static void CheckForLeaks() {}
+  static int NumLiveInstances() { return -1; }
+};
+
+#else
+
+// If leak tracking is enabled we track where the object was allocated from.
+
+template<typename T>
+class LeakTracker : public LinkNode<LeakTracker<T> > {
+ public:
+  LeakTracker() {
+    instances()->Append(this);
+  }
+
+  ~LeakTracker() {
+    this->RemoveFromList();
+  }
+
+  static void CheckForLeaks() {
+    // Walk the allocation list and print each entry it contains.
+    size_t count = 0;
+
+    // Copy the first 3 leak allocation callstacks onto the stack.
+    // This way if we hit the CHECK() in a release build, the leak
+    // information will be available in mini-dump.
+    const size_t kMaxStackTracesToCopyOntoStack = 3;
+    StackTrace stacktraces[kMaxStackTracesToCopyOntoStack];
+
+    for (LinkNode<LeakTracker<T> >* node = instances()->head();
+         node != instances()->end();
+         node = node->next()) {
+      StackTrace& allocation_stack = node->value()->allocation_stack_;
+
+      if (count < kMaxStackTracesToCopyOntoStack)
+        stacktraces[count] = allocation_stack;
+
+      ++count;
+      if (LOG_IS_ON(ERROR)) {
+        LOG_STREAM(ERROR) << "Leaked " << node << " which was allocated by:";
+        allocation_stack.OutputToStream(&LOG_STREAM(ERROR));
+      }
+    }
+
+    CHECK_EQ(0u, count);
+
+    // Hack to keep |stacktraces| and |count| alive (so compiler
+    // doesn't optimize it out, and it will appear in mini-dumps).
+    if (count == 0x1234) {
+      for (size_t i = 0; i < kMaxStackTracesToCopyOntoStack; ++i)
+        stacktraces[i].Print();
+    }
+  }
+
+  static int NumLiveInstances() {
+    // Walk the allocation list and count how many entries it has.
+    int count = 0;
+    for (LinkNode<LeakTracker<T> >* node = instances()->head();
+         node != instances()->end();
+         node = node->next()) {
+      ++count;
+    }
+    return count;
+  }
+
+ private:
+  // Each specialization of LeakTracker gets its own static storage.
+  static LinkedList<LeakTracker<T> >* instances() {
+    static LinkedList<LeakTracker<T> > list;
+    return &list;
+  }
+
+  StackTrace allocation_stack_;
+};
+
+#endif  // ENABLE_LEAK_TRACKER
+
+}  // namespace debug
+}  // namespace base
+
+#endif  // BASE_DEBUG_LEAK_TRACKER_H_
diff --git a/base/debug/leak_tracker_unittest.cc b/base/debug/leak_tracker_unittest.cc
new file mode 100644
index 0000000..99df4c1
--- /dev/null
+++ b/base/debug/leak_tracker_unittest.cc
@@ -0,0 +1,113 @@
+// Copyright (c) 2011 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/debug/leak_tracker.h"
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace debug {
+
+namespace {
+
+class ClassA {
+ private:
+  LeakTracker<ClassA> leak_tracker_;
+};
+
+class ClassB {
+ private:
+  LeakTracker<ClassB> leak_tracker_;
+};
+
+#ifndef ENABLE_LEAK_TRACKER
+
+// If leak tracking is disabled, we should do nothing.
+TEST(LeakTrackerTest, NotEnabled) {
+  EXPECT_EQ(-1, LeakTracker<ClassA>::NumLiveInstances());
+  EXPECT_EQ(-1, LeakTracker<ClassB>::NumLiveInstances());
+
+  // Use scoped_ptr so compiler doesn't complain about unused variables.
+  scoped_ptr<ClassA> a1(new ClassA);
+  scoped_ptr<ClassB> b1(new ClassB);
+  scoped_ptr<ClassB> b2(new ClassB);
+
+  EXPECT_EQ(-1, LeakTracker<ClassA>::NumLiveInstances());
+  EXPECT_EQ(-1, LeakTracker<ClassB>::NumLiveInstances());
+}
+
+#else
+
+TEST(LeakTrackerTest, Basic) {
+  {
+    ClassA a1;
+
+    EXPECT_EQ(1, LeakTracker<ClassA>::NumLiveInstances());
+    EXPECT_EQ(0, LeakTracker<ClassB>::NumLiveInstances());
+
+    ClassB b1;
+    ClassB b2;
+
+    EXPECT_EQ(1, LeakTracker<ClassA>::NumLiveInstances());
+    EXPECT_EQ(2, LeakTracker<ClassB>::NumLiveInstances());
+
+    scoped_ptr<ClassA> a2(new ClassA);
+
+    EXPECT_EQ(2, LeakTracker<ClassA>::NumLiveInstances());
+    EXPECT_EQ(2, LeakTracker<ClassB>::NumLiveInstances());
+
+    a2.reset();
+
+    EXPECT_EQ(1, LeakTracker<ClassA>::NumLiveInstances());
+    EXPECT_EQ(2, LeakTracker<ClassB>::NumLiveInstances());
+  }
+
+  EXPECT_EQ(0, LeakTracker<ClassA>::NumLiveInstances());
+  EXPECT_EQ(0, LeakTracker<ClassB>::NumLiveInstances());
+}
+
+// Try some orderings of create/remove to hit different cases in the linked-list
+// assembly.
+TEST(LeakTrackerTest, LinkedList) {
+  EXPECT_EQ(0, LeakTracker<ClassB>::NumLiveInstances());
+
+  scoped_ptr<ClassA> a1(new ClassA);
+  scoped_ptr<ClassA> a2(new ClassA);
+  scoped_ptr<ClassA> a3(new ClassA);
+  scoped_ptr<ClassA> a4(new ClassA);
+
+  EXPECT_EQ(4, LeakTracker<ClassA>::NumLiveInstances());
+
+  // Remove the head of the list (a1).
+  a1.reset();
+  EXPECT_EQ(3, LeakTracker<ClassA>::NumLiveInstances());
+
+  // Remove the tail of the list (a4).
+  a4.reset();
+  EXPECT_EQ(2, LeakTracker<ClassA>::NumLiveInstances());
+
+  // Append to the new tail of the list (a3).
+  scoped_ptr<ClassA> a5(new ClassA);
+  EXPECT_EQ(3, LeakTracker<ClassA>::NumLiveInstances());
+
+  a2.reset();
+  a3.reset();
+
+  EXPECT_EQ(1, LeakTracker<ClassA>::NumLiveInstances());
+
+  a5.reset();
+  EXPECT_EQ(0, LeakTracker<ClassA>::NumLiveInstances());
+}
+
+TEST(LeakTrackerTest, NoOpCheckForLeaks) {
+  // There are no live instances of ClassA, so this should do nothing.
+  LeakTracker<ClassA>::CheckForLeaks();
+}
+
+#endif  // ENABLE_LEAK_TRACKER
+
+}  // namespace
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/proc_maps_linux.cc b/base/debug/proc_maps_linux.cc
new file mode 100644
index 0000000..4c1aedf
--- /dev/null
+++ b/base/debug/proc_maps_linux.cc
@@ -0,0 +1,167 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/debug/proc_maps_linux.h"
+
+#include <fcntl.h>
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+#include <inttypes.h>
+#endif
+
+#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
+#include "base/strings/string_split.h"
+
+#if defined(OS_ANDROID) && !defined(__LP64__)
+// In 32-bit mode, Bionic's inttypes.h defines PRI/SCNxPTR as an
+// unsigned long int, which is incompatible with Bionic's stdint.h
+// defining uintptr_t as an unsigned int:
+// https://code.google.com/p/android/issues/detail?id=57218
+#undef SCNxPTR
+#define SCNxPTR "x"
+#endif
+
+namespace base {
+namespace debug {
+
+// Scans |proc_maps| starting from |pos| returning true if the gate VMA was
+// found, otherwise returns false.
+static bool ContainsGateVMA(std::string* proc_maps, size_t pos) {
+#if defined(ARCH_CPU_ARM_FAMILY)
+  // The gate VMA on ARM kernels is the interrupt vectors page.
+  return proc_maps->find(" [vectors]\n", pos) != std::string::npos;
+#elif defined(ARCH_CPU_X86_64)
+  // The gate VMA on x86 64-bit kernels is the virtual system call page.
+  return proc_maps->find(" [vsyscall]\n", pos) != std::string::npos;
+#else
+  // Otherwise assume there is no gate VMA in which case we shouldn't
+  // get duplicate entires.
+  return false;
+#endif
+}
+
+bool ReadProcMaps(std::string* proc_maps) {
+  // seq_file only writes out a page-sized amount on each call. Refer to header
+  // file for details.
+  const long kReadSize = sysconf(_SC_PAGESIZE);
+
+  base::ScopedFD fd(HANDLE_EINTR(open("/proc/self/maps", O_RDONLY)));
+  if (!fd.is_valid()) {
+    DPLOG(ERROR) << "Couldn't open /proc/self/maps";
+    return false;
+  }
+  proc_maps->clear();
+
+  while (true) {
+    // To avoid a copy, resize |proc_maps| so read() can write directly into it.
+    // Compute |buffer| afterwards since resize() may reallocate.
+    size_t pos = proc_maps->size();
+    proc_maps->resize(pos + kReadSize);
+    void* buffer = &(*proc_maps)[pos];
+
+    ssize_t bytes_read = HANDLE_EINTR(read(fd.get(), buffer, kReadSize));
+    if (bytes_read < 0) {
+      DPLOG(ERROR) << "Couldn't read /proc/self/maps";
+      proc_maps->clear();
+      return false;
+    }
+
+    // ... and don't forget to trim off excess bytes.
+    proc_maps->resize(pos + bytes_read);
+
+    if (bytes_read == 0)
+      break;
+
+    // The gate VMA is handled as a special case after seq_file has finished
+    // iterating through all entries in the virtual memory table.
+    //
+    // Unfortunately, if additional entries are added at this point in time
+    // seq_file gets confused and the next call to read() will return duplicate
+    // entries including the gate VMA again.
+    //
+    // Avoid this by searching for the gate VMA and breaking early.
+    if (ContainsGateVMA(proc_maps, pos))
+      break;
+  }
+
+  return true;
+}
+
+bool ParseProcMaps(const std::string& input,
+                   std::vector<MappedMemoryRegion>* regions_out) {
+  CHECK(regions_out);
+  std::vector<MappedMemoryRegion> regions;
+
+  // This isn't async safe nor terribly efficient, but it doesn't need to be at
+  // this point in time.
+  std::vector<std::string> lines;
+  SplitString(input, '\n', &lines);
+
+  for (size_t i = 0; i < lines.size(); ++i) {
+    // Due to splitting on '\n' the last line should be empty.
+    if (i == lines.size() - 1) {
+      if (!lines[i].empty()) {
+        DLOG(WARNING) << "Last line not empty";
+        return false;
+      }
+      break;
+    }
+
+    MappedMemoryRegion region;
+    const char* line = lines[i].c_str();
+    char permissions[5] = {'\0'};  // Ensure NUL-terminated string.
+    uint8 dev_major = 0;
+    uint8 dev_minor = 0;
+    long inode = 0;
+    int path_index = 0;
+
+    // Sample format from man 5 proc:
+    //
+    // address           perms offset  dev   inode   pathname
+    // 08048000-08056000 r-xp 00000000 03:0c 64593   /usr/sbin/gpm
+    //
+    // The final %n term captures the offset in the input string, which is used
+    // to determine the path name. It *does not* increment the return value.
+    // Refer to man 3 sscanf for details.
+    if (sscanf(line, "%" SCNxPTR "-%" SCNxPTR " %4c %llx %hhx:%hhx %ld %n",
+               &region.start, &region.end, permissions, &region.offset,
+               &dev_major, &dev_minor, &inode, &path_index) < 7) {
+      DPLOG(WARNING) << "sscanf failed for line: " << line;
+      return false;
+    }
+
+    region.permissions = 0;
+
+    if (permissions[0] == 'r')
+      region.permissions |= MappedMemoryRegion::READ;
+    else if (permissions[0] != '-')
+      return false;
+
+    if (permissions[1] == 'w')
+      region.permissions |= MappedMemoryRegion::WRITE;
+    else if (permissions[1] != '-')
+      return false;
+
+    if (permissions[2] == 'x')
+      region.permissions |= MappedMemoryRegion::EXECUTE;
+    else if (permissions[2] != '-')
+      return false;
+
+    if (permissions[3] == 'p')
+      region.permissions |= MappedMemoryRegion::PRIVATE;
+    else if (permissions[3] != 's' && permissions[3] != 'S')  // Shared memory.
+      return false;
+
+    // Pushing then assigning saves us a string copy.
+    regions.push_back(region);
+    regions.back().path.assign(line + path_index);
+  }
+
+  regions_out->swap(regions);
+  return true;
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/proc_maps_linux.h b/base/debug/proc_maps_linux.h
new file mode 100644
index 0000000..9fbd478
--- /dev/null
+++ b/base/debug/proc_maps_linux.h
@@ -0,0 +1,90 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_DEBUG_PROC_MAPS_LINUX_H_
+#define BASE_DEBUG_PROC_MAPS_LINUX_H_
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace debug {
+
+// Describes a region of mapped memory and the path of the file mapped.
+struct MappedMemoryRegion {
+  enum Permission {
+    READ = 1 << 0,
+    WRITE = 1 << 1,
+    EXECUTE = 1 << 2,
+    PRIVATE = 1 << 3,  // If set, region is private, otherwise it is shared.
+  };
+
+  // The address range [start,end) of mapped memory.
+  uintptr_t start;
+  uintptr_t end;
+
+  // Byte offset into |path| of the range mapped into memory.
+  unsigned long long offset;
+
+  // Bitmask of read/write/execute/private/shared permissions.
+  uint8 permissions;
+
+  // Name of the file mapped into memory.
+  //
+  // NOTE: path names aren't guaranteed to point at valid files. For example,
+  // "[heap]" and "[stack]" are used to represent the location of the process'
+  // heap and stack, respectively.
+  std::string path;
+};
+
+// Reads the data from /proc/self/maps and stores the result in |proc_maps|.
+// Returns true if successful, false otherwise.
+//
+// There is *NO* guarantee that the resulting contents will be free of
+// duplicates or even contain valid entries by time the method returns.
+//
+//
+// THE GORY DETAILS
+//
+// Did you know it's next-to-impossible to atomically read the whole contents
+// of /proc/<pid>/maps? You would think that if we passed in a large-enough
+// buffer to read() that It Should Just Work(tm), but sadly that's not the case.
+//
+// Linux's procfs uses seq_file [1] for handling iteration, text formatting,
+// and dealing with resulting data that is larger than the size of a page. That
+// last bit is especially important because it means that seq_file will never
+// return more than the size of a page in a single call to read().
+//
+// Unfortunately for a program like Chrome the size of /proc/self/maps is
+// larger than the size of page so we're forced to call read() multiple times.
+// If the virtual memory table changed in any way between calls to read() (e.g.,
+// a different thread calling mprotect()), it can make seq_file generate
+// duplicate entries or skip entries.
+//
+// Even if seq_file was changed to keep flushing the contents of its page-sized
+// buffer to the usermode buffer inside a single call to read(), it has to
+// release its lock on the virtual memory table to handle page faults while
+// copying data to usermode. This puts us in the same situation where the table
+// can change while we're copying data.
+//
+// Alternatives such as fork()-and-suspend-the-parent-while-child-reads were
+// attempted, but they present more subtle problems than it's worth. Depending
+// on your use case your best bet may be to read /proc/<pid>/maps prior to
+// starting other threads.
+//
+// [1] http://kernelnewbies.org/Documents/SeqFileHowTo
+BASE_EXPORT bool ReadProcMaps(std::string* proc_maps);
+
+// Parses /proc/<pid>/maps input data and stores in |regions|. Returns true
+// and updates |regions| if and only if all of |input| was successfully parsed.
+BASE_EXPORT bool ParseProcMaps(const std::string& input,
+                               std::vector<MappedMemoryRegion>* regions);
+
+}  // namespace debug
+}  // namespace base
+
+#endif  // BASE_DEBUG_PROC_MAPS_LINUX_H_
diff --git a/base/debug/proc_maps_linux_unittest.cc b/base/debug/proc_maps_linux_unittest.cc
new file mode 100644
index 0000000..cbc0dd0
--- /dev/null
+++ b/base/debug/proc_maps_linux_unittest.cc
@@ -0,0 +1,338 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/debug/proc_maps_linux.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "base/strings/stringprintf.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "base/threading/platform_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace debug {
+
+TEST(ProcMapsTest, Empty) {
+  std::vector<MappedMemoryRegion> regions;
+  EXPECT_TRUE(ParseProcMaps("", &regions));
+  EXPECT_EQ(0u, regions.size());
+}
+
+TEST(ProcMapsTest, NoSpaces) {
+  static const char kNoSpaces[] =
+      "00400000-0040b000 r-xp 00002200 fc:00 794418 /bin/cat\n";
+
+  std::vector<MappedMemoryRegion> regions;
+  ASSERT_TRUE(ParseProcMaps(kNoSpaces, &regions));
+  ASSERT_EQ(1u, regions.size());
+
+  EXPECT_EQ(0x00400000u, regions[0].start);
+  EXPECT_EQ(0x0040b000u, regions[0].end);
+  EXPECT_EQ(0x00002200u, regions[0].offset);
+  EXPECT_EQ("/bin/cat", regions[0].path);
+}
+
+TEST(ProcMapsTest, Spaces) {
+  static const char kSpaces[] =
+      "00400000-0040b000 r-xp 00002200 fc:00 794418 /bin/space cat\n";
+
+  std::vector<MappedMemoryRegion> regions;
+  ASSERT_TRUE(ParseProcMaps(kSpaces, &regions));
+  ASSERT_EQ(1u, regions.size());
+
+  EXPECT_EQ(0x00400000u, regions[0].start);
+  EXPECT_EQ(0x0040b000u, regions[0].end);
+  EXPECT_EQ(0x00002200u, regions[0].offset);
+  EXPECT_EQ("/bin/space cat", regions[0].path);
+}
+
+TEST(ProcMapsTest, NoNewline) {
+  static const char kNoSpaces[] =
+      "00400000-0040b000 r-xp 00002200 fc:00 794418 /bin/cat";
+
+  std::vector<MappedMemoryRegion> regions;
+  ASSERT_FALSE(ParseProcMaps(kNoSpaces, &regions));
+}
+
+TEST(ProcMapsTest, NoPath) {
+  static const char kNoPath[] =
+      "00400000-0040b000 rw-p 00000000 00:00 0 \n";
+
+  std::vector<MappedMemoryRegion> regions;
+  ASSERT_TRUE(ParseProcMaps(kNoPath, &regions));
+  ASSERT_EQ(1u, regions.size());
+
+  EXPECT_EQ(0x00400000u, regions[0].start);
+  EXPECT_EQ(0x0040b000u, regions[0].end);
+  EXPECT_EQ(0x00000000u, regions[0].offset);
+  EXPECT_EQ("", regions[0].path);
+}
+
+TEST(ProcMapsTest, Heap) {
+  static const char kHeap[] =
+      "022ac000-022cd000 rw-p 00000000 00:00 0 [heap]\n";
+
+  std::vector<MappedMemoryRegion> regions;
+  ASSERT_TRUE(ParseProcMaps(kHeap, &regions));
+  ASSERT_EQ(1u, regions.size());
+
+  EXPECT_EQ(0x022ac000u, regions[0].start);
+  EXPECT_EQ(0x022cd000u, regions[0].end);
+  EXPECT_EQ(0x00000000u, regions[0].offset);
+  EXPECT_EQ("[heap]", regions[0].path);
+}
+
+#if defined(ARCH_CPU_32_BITS)
+TEST(ProcMapsTest, Stack32) {
+  static const char kStack[] =
+      "beb04000-beb25000 rw-p 00000000 00:00 0 [stack]\n";
+
+  std::vector<MappedMemoryRegion> regions;
+  ASSERT_TRUE(ParseProcMaps(kStack, &regions));
+  ASSERT_EQ(1u, regions.size());
+
+  EXPECT_EQ(0xbeb04000u, regions[0].start);
+  EXPECT_EQ(0xbeb25000u, regions[0].end);
+  EXPECT_EQ(0x00000000u, regions[0].offset);
+  EXPECT_EQ("[stack]", regions[0].path);
+}
+#elif defined(ARCH_CPU_64_BITS)
+TEST(ProcMapsTest, Stack64) {
+  static const char kStack[] =
+      "7fff69c5b000-7fff69c7d000 rw-p 00000000 00:00 0 [stack]\n";
+
+  std::vector<MappedMemoryRegion> regions;
+  ASSERT_TRUE(ParseProcMaps(kStack, &regions));
+  ASSERT_EQ(1u, regions.size());
+
+  EXPECT_EQ(0x7fff69c5b000u, regions[0].start);
+  EXPECT_EQ(0x7fff69c7d000u, regions[0].end);
+  EXPECT_EQ(0x00000000u, regions[0].offset);
+  EXPECT_EQ("[stack]", regions[0].path);
+}
+#endif
+
+TEST(ProcMapsTest, Multiple) {
+  static const char kMultiple[] =
+      "00400000-0040b000 r-xp 00000000 fc:00 794418 /bin/cat\n"
+      "0060a000-0060b000 r--p 0000a000 fc:00 794418 /bin/cat\n"
+      "0060b000-0060c000 rw-p 0000b000 fc:00 794418 /bin/cat\n";
+
+  std::vector<MappedMemoryRegion> regions;
+  ASSERT_TRUE(ParseProcMaps(kMultiple, &regions));
+  ASSERT_EQ(3u, regions.size());
+
+  EXPECT_EQ(0x00400000u, regions[0].start);
+  EXPECT_EQ(0x0040b000u, regions[0].end);
+  EXPECT_EQ(0x00000000u, regions[0].offset);
+  EXPECT_EQ("/bin/cat", regions[0].path);
+
+  EXPECT_EQ(0x0060a000u, regions[1].start);
+  EXPECT_EQ(0x0060b000u, regions[1].end);
+  EXPECT_EQ(0x0000a000u, regions[1].offset);
+  EXPECT_EQ("/bin/cat", regions[1].path);
+
+  EXPECT_EQ(0x0060b000u, regions[2].start);
+  EXPECT_EQ(0x0060c000u, regions[2].end);
+  EXPECT_EQ(0x0000b000u, regions[2].offset);
+  EXPECT_EQ("/bin/cat", regions[2].path);
+}
+
+TEST(ProcMapsTest, Permissions) {
+  static struct {
+    const char* input;
+    uint8 permissions;
+  } kTestCases[] = {
+    {"00400000-0040b000 ---s 00000000 fc:00 794418 /bin/cat\n", 0},
+    {"00400000-0040b000 ---S 00000000 fc:00 794418 /bin/cat\n", 0},
+    {"00400000-0040b000 r--s 00000000 fc:00 794418 /bin/cat\n",
+     MappedMemoryRegion::READ},
+    {"00400000-0040b000 -w-s 00000000 fc:00 794418 /bin/cat\n",
+     MappedMemoryRegion::WRITE},
+    {"00400000-0040b000 --xs 00000000 fc:00 794418 /bin/cat\n",
+     MappedMemoryRegion::EXECUTE},
+    {"00400000-0040b000 rwxs 00000000 fc:00 794418 /bin/cat\n",
+     MappedMemoryRegion::READ | MappedMemoryRegion::WRITE |
+         MappedMemoryRegion::EXECUTE},
+    {"00400000-0040b000 ---p 00000000 fc:00 794418 /bin/cat\n",
+     MappedMemoryRegion::PRIVATE},
+    {"00400000-0040b000 r--p 00000000 fc:00 794418 /bin/cat\n",
+     MappedMemoryRegion::READ | MappedMemoryRegion::PRIVATE},
+    {"00400000-0040b000 -w-p 00000000 fc:00 794418 /bin/cat\n",
+     MappedMemoryRegion::WRITE | MappedMemoryRegion::PRIVATE},
+    {"00400000-0040b000 --xp 00000000 fc:00 794418 /bin/cat\n",
+     MappedMemoryRegion::EXECUTE | MappedMemoryRegion::PRIVATE},
+    {"00400000-0040b000 rwxp 00000000 fc:00 794418 /bin/cat\n",
+     MappedMemoryRegion::READ | MappedMemoryRegion::WRITE |
+         MappedMemoryRegion::EXECUTE | MappedMemoryRegion::PRIVATE},
+  };
+
+  for (size_t i = 0; i < arraysize(kTestCases); ++i) {
+    SCOPED_TRACE(
+        base::StringPrintf("kTestCases[%zu] = %s", i, kTestCases[i].input));
+
+    std::vector<MappedMemoryRegion> regions;
+    EXPECT_TRUE(ParseProcMaps(kTestCases[i].input, &regions));
+    EXPECT_EQ(1u, regions.size());
+    if (regions.empty())
+      continue;
+    EXPECT_EQ(kTestCases[i].permissions, regions[0].permissions);
+  }
+}
+
+#if defined(ADDRESS_SANITIZER)
+// AddressSanitizer may move local variables to a dedicated "fake stack" which
+// is outside the stack region listed in /proc/self/maps. We disable ASan
+// instrumentation for this function to force the variable to be local.
+__attribute__((no_sanitize_address))
+#endif
+void CheckProcMapsRegions(const std::vector<MappedMemoryRegion> &regions) {
+  // We should be able to find both the current executable as well as the stack
+  // mapped into memory. Use the address of |exe_path| as a way of finding the
+  // stack.
+  FilePath exe_path;
+  EXPECT_TRUE(PathService::Get(FILE_EXE, &exe_path));
+  uintptr_t address = reinterpret_cast<uintptr_t>(&exe_path);
+  bool found_exe = false;
+  bool found_stack = false;
+  bool found_address = false;
+
+  for (size_t i = 0; i < regions.size(); ++i) {
+    if (regions[i].path == exe_path.value()) {
+      // It's OK to find the executable mapped multiple times as there'll be
+      // multiple sections (e.g., text, data).
+      found_exe = true;
+    }
+
+    // Valgrind uses its own allocated stacks instead of the kernel-provided
+    // stack without letting the kernel know via prctl(PR_SET_MM_START_STACK).
+    // Depending on which kernel you're running it'll impact the output of
+    // /proc/self/maps.
+    //
+    // Prior to version 3.4, the kernel completely ignores other stacks and
+    // always prints out the vma lying within mm->start_stack as [stack] even
+    // if the program was currently executing on a different stack.
+    //
+    // Starting in 3.4, the kernel will print out the vma containing the current
+    // stack pointer as [stack:TID] as long as that vma does not lie within
+    // mm->start_stack.
+    //
+    // Because this has gotten too complicated and brittle of a test, completely
+    // ignore checking for the stack and address when running under Valgrind.
+    // See http://crbug.com/431702 for more details.
+    if (!RunningOnValgrind() && regions[i].path == "[stack]") {
+      EXPECT_GE(address, regions[i].start);
+      EXPECT_LT(address, regions[i].end);
+      EXPECT_TRUE(regions[i].permissions & MappedMemoryRegion::READ);
+      EXPECT_TRUE(regions[i].permissions & MappedMemoryRegion::WRITE);
+      EXPECT_FALSE(regions[i].permissions & MappedMemoryRegion::EXECUTE);
+      EXPECT_TRUE(regions[i].permissions & MappedMemoryRegion::PRIVATE);
+      EXPECT_FALSE(found_stack) << "Found duplicate stacks";
+      found_stack = true;
+    }
+
+    if (address >= regions[i].start && address < regions[i].end) {
+      EXPECT_FALSE(found_address) << "Found same address in multiple regions";
+      found_address = true;
+    }
+  }
+
+  EXPECT_TRUE(found_exe);
+  if (!RunningOnValgrind()) {
+    EXPECT_TRUE(found_stack);
+    EXPECT_TRUE(found_address);
+  }
+}
+
+TEST(ProcMapsTest, ReadProcMaps) {
+  std::string proc_maps;
+  ASSERT_TRUE(ReadProcMaps(&proc_maps));
+
+  std::vector<MappedMemoryRegion> regions;
+  ASSERT_TRUE(ParseProcMaps(proc_maps, &regions));
+  ASSERT_FALSE(regions.empty());
+
+  CheckProcMapsRegions(regions);
+}
+
+TEST(ProcMapsTest, ReadProcMapsNonEmptyString) {
+  std::string old_string("I forgot to clear the string");
+  std::string proc_maps(old_string);
+  ASSERT_TRUE(ReadProcMaps(&proc_maps));
+  EXPECT_EQ(std::string::npos, proc_maps.find(old_string));
+}
+
+TEST(ProcMapsTest, MissingFields) {
+  static const char* const kTestCases[] = {
+    "00400000\n",                               // Missing end + beyond.
+    "00400000-0040b000\n",                      // Missing perms + beyond.
+    "00400000-0040b000 r-xp\n",                 // Missing offset + beyond.
+    "00400000-0040b000 r-xp 00000000\n",        // Missing device + beyond.
+    "00400000-0040b000 r-xp 00000000 fc:00\n",  // Missing inode + beyond.
+    "00400000-0040b000 00000000 fc:00 794418 /bin/cat\n",  // Missing perms.
+    "00400000-0040b000 r-xp fc:00 794418 /bin/cat\n",      // Missing offset.
+    "00400000-0040b000 r-xp 00000000 fc:00 /bin/cat\n",    // Missing inode.
+    "00400000 r-xp 00000000 fc:00 794418 /bin/cat\n",      // Missing end.
+    "-0040b000 r-xp 00000000 fc:00 794418 /bin/cat\n",     // Missing start.
+    "00400000-0040b000 r-xp 00000000 794418 /bin/cat\n",   // Missing device.
+  };
+
+  for (size_t i = 0; i < arraysize(kTestCases); ++i) {
+    SCOPED_TRACE(base::StringPrintf("kTestCases[%zu] = %s", i, kTestCases[i]));
+    std::vector<MappedMemoryRegion> regions;
+    EXPECT_FALSE(ParseProcMaps(kTestCases[i], &regions));
+  }
+}
+
+TEST(ProcMapsTest, InvalidInput) {
+  static const char* const kTestCases[] = {
+    "thisisal-0040b000 rwxp 00000000 fc:00 794418 /bin/cat\n",
+    "0040000d-linvalid rwxp 00000000 fc:00 794418 /bin/cat\n",
+    "00400000-0040b000 inpu 00000000 fc:00 794418 /bin/cat\n",
+    "00400000-0040b000 rwxp tforproc fc:00 794418 /bin/cat\n",
+    "00400000-0040b000 rwxp 00000000 ma:ps 794418 /bin/cat\n",
+    "00400000-0040b000 rwxp 00000000 fc:00 parse! /bin/cat\n",
+  };
+
+  for (size_t i = 0; i < arraysize(kTestCases); ++i) {
+    SCOPED_TRACE(base::StringPrintf("kTestCases[%zu] = %s", i, kTestCases[i]));
+    std::vector<MappedMemoryRegion> regions;
+    EXPECT_FALSE(ParseProcMaps(kTestCases[i], &regions));
+  }
+}
+
+TEST(ProcMapsTest, ParseProcMapsEmptyString) {
+  std::vector<MappedMemoryRegion> regions;
+  EXPECT_TRUE(ParseProcMaps("", &regions));
+  EXPECT_EQ(0ULL, regions.size());
+}
+
+// Testing a couple of remotely possible weird things in the input:
+// - Line ending with \r\n or \n\r.
+// - File name contains quotes.
+// - File name has whitespaces.
+TEST(ProcMapsTest, ParseProcMapsWeirdCorrectInput) {
+  std::vector<MappedMemoryRegion> regions;
+  const std::string kContents =
+    "00400000-0040b000 r-xp 00000000 fc:00 2106562 "
+      "               /bin/cat\r\n"
+    "7f53b7dad000-7f53b7f62000 r-xp 00000000 fc:00 263011 "
+      "       /lib/x86_64-linux-gnu/libc-2.15.so\n\r"
+    "7f53b816d000-7f53b818f000 r-xp 00000000 fc:00 264284 "
+      "        /lib/x86_64-linux-gnu/ld-2.15.so\n"
+    "7fff9c7ff000-7fff9c800000 r-xp 00000000 00:00 0 "
+      "               \"vd so\"\n"
+    "ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 "
+      "               [vsys call]\n";
+  EXPECT_TRUE(ParseProcMaps(kContents, &regions));
+  EXPECT_EQ(5ULL, regions.size());
+  EXPECT_EQ("/bin/cat", regions[0].path);
+  EXPECT_EQ("/lib/x86_64-linux-gnu/libc-2.15.so", regions[1].path);
+  EXPECT_EQ("/lib/x86_64-linux-gnu/ld-2.15.so", regions[2].path);
+  EXPECT_EQ("\"vd so\"", regions[3].path);
+  EXPECT_EQ("[vsys call]", regions[4].path);
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/profiler.cc b/base/debug/profiler.cc
new file mode 100644
index 0000000..ed553cd
--- /dev/null
+++ b/base/debug/profiler.cc
@@ -0,0 +1,219 @@
+// Copyright (c) 2012 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/debug/profiler.h"
+
+#include <string>
+
+#include "base/process/process_handle.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+
+#if defined(OS_WIN)
+#include "base/win/pe_image.h"
+#endif  // defined(OS_WIN)
+
+// TODO(peria): Enable profiling on Windows.
+#if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC) && !defined(OS_WIN)
+#include "third_party/tcmalloc/chromium/src/gperftools/profiler.h"
+#endif
+
+namespace base {
+namespace debug {
+
+// TODO(peria): Enable profiling on Windows.
+#if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC) && !defined(OS_WIN)
+
+static int profile_count = 0;
+
+void StartProfiling(const std::string& name) {
+  ++profile_count;
+  std::string full_name(name);
+  std::string pid = StringPrintf("%d", GetCurrentProcId());
+  std::string count = StringPrintf("%d", profile_count);
+  ReplaceSubstringsAfterOffset(&full_name, 0, "{pid}", pid);
+  ReplaceSubstringsAfterOffset(&full_name, 0, "{count}", count);
+  ProfilerStart(full_name.c_str());
+}
+
+void StopProfiling() {
+  ProfilerFlush();
+  ProfilerStop();
+}
+
+void FlushProfiling() {
+  ProfilerFlush();
+}
+
+bool BeingProfiled() {
+  return ProfilingIsEnabledForAllThreads();
+}
+
+void RestartProfilingAfterFork() {
+  ProfilerRegisterThread();
+}
+
+#else
+
+void StartProfiling(const std::string& name) {
+}
+
+void StopProfiling() {
+}
+
+void FlushProfiling() {
+}
+
+bool BeingProfiled() {
+  return false;
+}
+
+void RestartProfilingAfterFork() {
+}
+
+#endif
+
+#if !defined(OS_WIN)
+
+bool IsBinaryInstrumented() {
+  return false;
+}
+
+ReturnAddressLocationResolver GetProfilerReturnAddrResolutionFunc() {
+  return NULL;
+}
+
+DynamicFunctionEntryHook GetProfilerDynamicFunctionEntryHookFunc() {
+  return NULL;
+}
+
+AddDynamicSymbol GetProfilerAddDynamicSymbolFunc() {
+  return NULL;
+}
+
+MoveDynamicSymbol GetProfilerMoveDynamicSymbolFunc() {
+  return NULL;
+}
+
+#else  // defined(OS_WIN)
+
+// http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx
+extern "C" IMAGE_DOS_HEADER __ImageBase;
+
+bool IsBinaryInstrumented() {
+  enum InstrumentationCheckState {
+    UNINITIALIZED,
+    INSTRUMENTED_IMAGE,
+    NON_INSTRUMENTED_IMAGE,
+  };
+
+  static InstrumentationCheckState state = UNINITIALIZED;
+
+  if (state == UNINITIALIZED) {
+    HMODULE this_module = reinterpret_cast<HMODULE>(&__ImageBase);
+    base::win::PEImage image(this_module);
+
+    // Check to be sure our image is structured as we'd expect.
+    DCHECK(image.VerifyMagic());
+
+    // Syzygy-instrumented binaries contain a PE image section named ".thunks",
+    // and all Syzygy-modified binaries contain the ".syzygy" image section.
+    // This is a very fast check, as it only looks at the image header.
+    if ((image.GetImageSectionHeaderByName(".thunks") != NULL) &&
+        (image.GetImageSectionHeaderByName(".syzygy") != NULL)) {
+      state = INSTRUMENTED_IMAGE;
+    } else {
+      state = NON_INSTRUMENTED_IMAGE;
+    }
+  }
+  DCHECK(state != UNINITIALIZED);
+
+  return state == INSTRUMENTED_IMAGE;
+}
+
+namespace {
+
+struct FunctionSearchContext {
+  const char* name;
+  FARPROC function;
+};
+
+// Callback function to PEImage::EnumImportChunks.
+bool FindResolutionFunctionInImports(
+    const base::win::PEImage &image, const char* module_name,
+    PIMAGE_THUNK_DATA unused_name_table, PIMAGE_THUNK_DATA import_address_table,
+    PVOID cookie) {
+  FunctionSearchContext* context =
+      reinterpret_cast<FunctionSearchContext*>(cookie);
+
+  DCHECK_NE(static_cast<FunctionSearchContext*>(NULL), context);
+  DCHECK_EQ(static_cast<FARPROC>(NULL), context->function);
+
+  // Our import address table contains pointers to the functions we import
+  // at this point. Let's retrieve the first such function and use it to
+  // find the module this import was resolved to by the loader.
+  const wchar_t* function_in_module =
+      reinterpret_cast<const wchar_t*>(import_address_table->u1.Function);
+
+  // Retrieve the module by a function in the module.
+  const DWORD kFlags = GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
+                       GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT;
+  HMODULE module = NULL;
+  if (!::GetModuleHandleEx(kFlags, function_in_module, &module)) {
+    // This can happen if someone IAT patches us to a thunk.
+    return true;
+  }
+
+  // See whether this module exports the function we're looking for.
+  FARPROC exported_func = ::GetProcAddress(module, context->name);
+  if (exported_func != NULL) {
+    // We found it, return the function and terminate the enumeration.
+    context->function = exported_func;
+    return false;
+  }
+
+  // Keep going.
+  return true;
+}
+
+template <typename FunctionType>
+FunctionType FindFunctionInImports(const char* function_name) {
+  if (!IsBinaryInstrumented())
+    return NULL;
+
+  HMODULE this_module = reinterpret_cast<HMODULE>(&__ImageBase);
+  base::win::PEImage image(this_module);
+
+  FunctionSearchContext ctx = { function_name, NULL };
+  image.EnumImportChunks(FindResolutionFunctionInImports, &ctx);
+
+  return reinterpret_cast<FunctionType>(ctx.function);
+}
+
+}  // namespace
+
+ReturnAddressLocationResolver GetProfilerReturnAddrResolutionFunc() {
+  return FindFunctionInImports<ReturnAddressLocationResolver>(
+      "ResolveReturnAddressLocation");
+}
+
+DynamicFunctionEntryHook GetProfilerDynamicFunctionEntryHookFunc() {
+  return FindFunctionInImports<DynamicFunctionEntryHook>(
+      "OnDynamicFunctionEntry");
+}
+
+AddDynamicSymbol GetProfilerAddDynamicSymbolFunc() {
+  return FindFunctionInImports<AddDynamicSymbol>(
+      "AddDynamicSymbol");
+}
+
+MoveDynamicSymbol GetProfilerMoveDynamicSymbolFunc() {
+  return FindFunctionInImports<MoveDynamicSymbol>(
+      "MoveDynamicSymbol");
+}
+
+#endif  // defined(OS_WIN)
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/profiler.h b/base/debug/profiler.h
new file mode 100644
index 0000000..2920d8a
--- /dev/null
+++ b/base/debug/profiler.h
@@ -0,0 +1,90 @@
+// Copyright (c) 2012 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_DEBUG_PROFILER_H_
+#define BASE_DEBUG_PROFILER_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+// The Profiler functions allow usage of the underlying sampling based
+// profiler. If the application has not been built with the necessary
+// flags (-DENABLE_PROFILING and not -DNO_TCMALLOC) then these functions
+// are noops.
+namespace base {
+namespace debug {
+
+// Start profiling with the supplied name.
+// {pid} will be replaced by the process' pid and {count} will be replaced
+// by the count of the profile run (starts at 1 with each process).
+BASE_EXPORT void StartProfiling(const std::string& name);
+
+// Stop profiling and write out data.
+BASE_EXPORT void StopProfiling();
+
+// Force data to be written to file.
+BASE_EXPORT void FlushProfiling();
+
+// Returns true if process is being profiled.
+BASE_EXPORT bool BeingProfiled();
+
+// Reset profiling after a fork, which disables timers.
+BASE_EXPORT void RestartProfilingAfterFork();
+
+// Returns true iff this executable is instrumented with the Syzygy profiler.
+BASE_EXPORT bool IsBinaryInstrumented();
+
+// There's a class of profilers that use "return address swizzling" to get a
+// hook on function exits. This class of profilers uses some form of entry hook,
+// like e.g. binary instrumentation, or a compiler flag, that calls a hook each
+// time a function is invoked. The hook then switches the return address on the
+// stack for the address of an exit hook function, and pushes the original
+// return address to a shadow stack of some type. When in due course the CPU
+// executes a return to the exit hook, the exit hook will do whatever work it
+// does on function exit, then arrange to return to the original return address.
+// This class of profiler does not play well with programs that look at the
+// return address, as does e.g. V8. V8 uses the return address to certain
+// runtime functions to find the JIT code that called it, and from there finds
+// the V8 data structures associated to the JS function involved.
+// A return address resolution function is used to fix this. It allows such
+// programs to resolve a location on stack where a return address originally
+// resided, to the shadow stack location where the profiler stashed it.
+typedef uintptr_t (*ReturnAddressLocationResolver)(
+    uintptr_t return_addr_location);
+
+// This type declaration must match V8's FunctionEntryHook.
+typedef void (*DynamicFunctionEntryHook)(uintptr_t function,
+                                         uintptr_t return_addr_location);
+
+// The functions below here are to support profiling V8-generated code.
+// V8 has provisions for generating a call to an entry hook for newly generated
+// JIT code, and it can push symbol information on code generation and advise
+// when the garbage collector moves code. The functions declarations below here
+// make glue between V8's facilities and a profiler.
+
+// This type declaration must match V8's FunctionEntryHook.
+typedef void (*DynamicFunctionEntryHook)(uintptr_t function,
+                                         uintptr_t return_addr_location);
+
+typedef void (*AddDynamicSymbol)(const void* address,
+                                 size_t length,
+                                 const char* name,
+                                 size_t name_len);
+typedef void (*MoveDynamicSymbol)(const void* address, const void* new_address);
+
+
+// If this binary is instrumented and the instrumentation supplies a function
+// for each of those purposes, find and return the function in question.
+// Otherwise returns NULL.
+BASE_EXPORT ReturnAddressLocationResolver GetProfilerReturnAddrResolutionFunc();
+BASE_EXPORT DynamicFunctionEntryHook GetProfilerDynamicFunctionEntryHookFunc();
+BASE_EXPORT AddDynamicSymbol GetProfilerAddDynamicSymbolFunc();
+BASE_EXPORT MoveDynamicSymbol GetProfilerMoveDynamicSymbolFunc();
+
+}  // namespace debug
+}  // namespace base
+
+#endif  // BASE_DEBUG_PROFILER_H_
diff --git a/base/debug/stack_trace.cc b/base/debug/stack_trace.cc
new file mode 100644
index 0000000..ce9e9ad
--- /dev/null
+++ b/base/debug/stack_trace.cc
@@ -0,0 +1,43 @@
+// Copyright (c) 2012 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/debug/stack_trace.h"
+
+#include "base/basictypes.h"
+
+#include <string.h>
+
+#include <algorithm>
+#include <sstream>
+
+namespace base {
+namespace debug {
+
+StackTrace::StackTrace(const void* const* trace, size_t count) {
+  count = std::min(count, arraysize(trace_));
+  if (count)
+    memcpy(trace_, trace, count * sizeof(trace_[0]));
+  count_ = count;
+}
+
+StackTrace::~StackTrace() {
+}
+
+const void *const *StackTrace::Addresses(size_t* count) const {
+  *count = count_;
+  if (count_)
+    return trace_;
+  return NULL;
+}
+
+std::string StackTrace::ToString() const {
+  std::stringstream stream;
+#if !defined(__UCLIBC__)
+  OutputToStream(&stream);
+#endif
+  return stream.str();
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/stack_trace.h b/base/debug/stack_trace.h
new file mode 100644
index 0000000..fb271b6
--- /dev/null
+++ b/base/debug/stack_trace.h
@@ -0,0 +1,118 @@
+// Copyright (c) 2012 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_DEBUG_STACK_TRACE_H_
+#define BASE_DEBUG_STACK_TRACE_H_
+
+#include <iosfwd>
+#include <string>
+
+#include "base/base_export.h"
+#include "build/build_config.h"
+
+#if defined(OS_POSIX)
+#include <unistd.h>
+#endif
+
+#if defined(OS_WIN)
+struct _EXCEPTION_POINTERS;
+struct _CONTEXT;
+#endif
+
+namespace base {
+namespace debug {
+
+// Enables stack dump to console output on exception and signals.
+// When enabled, the process will quit immediately. This is meant to be used in
+// unit_tests only! This is not thread-safe: only call from main thread.
+BASE_EXPORT bool EnableInProcessStackDumping();
+
+// A different version of EnableInProcessStackDumping that also works for
+// sandboxed processes.  For more details take a look at the description
+// of EnableInProcessStackDumping.
+// Calling this function on Linux opens /proc/self/maps and caches its
+// contents. In DEBUG builds, this function also opens the object files that
+// are loaded in memory and caches their file descriptors (this cannot be
+// done in official builds because it has security implications).
+BASE_EXPORT bool EnableInProcessStackDumpingForSandbox();
+
+// A stacktrace can be helpful in debugging. For example, you can include a
+// stacktrace member in a object (probably around #ifndef NDEBUG) so that you
+// can later see where the given object was created from.
+class BASE_EXPORT StackTrace {
+ public:
+  // Creates a stacktrace from the current location.
+  StackTrace();
+
+  // Creates a stacktrace from an existing array of instruction
+  // pointers (such as returned by Addresses()).  |count| will be
+  // trimmed to |kMaxTraces|.
+  StackTrace(const void* const* trace, size_t count);
+
+#if defined(OS_WIN)
+  // Creates a stacktrace for an exception.
+  // Note: this function will throw an import not found (StackWalk64) exception
+  // on system without dbghelp 5.1.
+  StackTrace(const _EXCEPTION_POINTERS* exception_pointers);
+  StackTrace(const _CONTEXT* context);
+#endif
+
+  // Copying and assignment are allowed with the default functions.
+
+  ~StackTrace();
+
+  // Gets an array of instruction pointer values. |*count| will be set to the
+  // number of elements in the returned array.
+  const void* const* Addresses(size_t* count) const;
+
+  // Prints the stack trace to stderr.
+  void Print() const;
+
+#if !defined(__UCLIBC__)
+  // Resolves backtrace to symbols and write to stream.
+  void OutputToStream(std::ostream* os) const;
+#endif
+
+  // Resolves backtrace to symbols and returns as string.
+  std::string ToString() const;
+
+ private:
+#if defined(OS_WIN)
+  void InitTrace(_CONTEXT* context_record);
+#endif
+
+  // From http://msdn.microsoft.com/en-us/library/bb204633.aspx,
+  // the sum of FramesToSkip and FramesToCapture must be less than 63,
+  // so set it to 62. Even if on POSIX it could be a larger value, it usually
+  // doesn't give much more information.
+  static const int kMaxTraces = 62;
+
+  void* trace_[kMaxTraces];
+
+  // The number of valid frames in |trace_|.
+  size_t count_;
+};
+
+namespace internal {
+
+#if defined(OS_POSIX) && !defined(OS_ANDROID)
+// POSIX doesn't define any async-signal safe function for converting
+// an integer to ASCII. We'll have to define our own version.
+// itoa_r() converts a (signed) integer to ASCII. It returns "buf", if the
+// conversion was successful or NULL otherwise. It never writes more than "sz"
+// bytes. Output will be truncated as needed, and a NUL character is always
+// appended.
+BASE_EXPORT char *itoa_r(intptr_t i,
+                         char *buf,
+                         size_t sz,
+                         int base,
+                         size_t padding);
+#endif  // defined(OS_POSIX) && !defined(OS_ANDROID)
+
+}  // namespace internal
+
+}  // namespace debug
+}  // namespace base
+
+#endif  // BASE_DEBUG_STACK_TRACE_H_
diff --git a/base/debug/stack_trace_android.cc b/base/debug/stack_trace_android.cc
new file mode 100644
index 0000000..5168b18
--- /dev/null
+++ b/base/debug/stack_trace_android.cc
@@ -0,0 +1,129 @@
+// Copyright (c) 2012 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/debug/stack_trace.h"
+
+#include <android/log.h>
+#include <unwind.h>
+#include <ostream>
+
+#include "base/debug/proc_maps_linux.h"
+#include "base/strings/stringprintf.h"
+#include "base/threading/thread_restrictions.h"
+
+#ifdef __LP64__
+#define FMT_ADDR  "0x%016lx"
+#else
+#define FMT_ADDR  "0x%08x"
+#endif
+
+namespace {
+
+struct StackCrawlState {
+  StackCrawlState(uintptr_t* frames, size_t max_depth)
+      : frames(frames),
+        frame_count(0),
+        max_depth(max_depth),
+        have_skipped_self(false) {}
+
+  uintptr_t* frames;
+  size_t frame_count;
+  size_t max_depth;
+  bool have_skipped_self;
+};
+
+_Unwind_Reason_Code TraceStackFrame(_Unwind_Context* context, void* arg) {
+  StackCrawlState* state = static_cast<StackCrawlState*>(arg);
+  uintptr_t ip = _Unwind_GetIP(context);
+
+  // The first stack frame is this function itself.  Skip it.
+  if (ip != 0 && !state->have_skipped_self) {
+    state->have_skipped_self = true;
+    return _URC_NO_REASON;
+  }
+
+  state->frames[state->frame_count++] = ip;
+  if (state->frame_count >= state->max_depth)
+    return _URC_END_OF_STACK;
+  return _URC_NO_REASON;
+}
+
+}  // namespace
+
+namespace base {
+namespace debug {
+
+bool EnableInProcessStackDumping() {
+  // When running in an application, our code typically expects SIGPIPE
+  // to be ignored.  Therefore, when testing that same code, it should run
+  // with SIGPIPE ignored as well.
+  // TODO(phajdan.jr): De-duplicate this SIGPIPE code.
+  struct sigaction action;
+  memset(&action, 0, sizeof(action));
+  action.sa_handler = SIG_IGN;
+  sigemptyset(&action.sa_mask);
+  return (sigaction(SIGPIPE, &action, NULL) == 0);
+}
+
+StackTrace::StackTrace() {
+  StackCrawlState state(reinterpret_cast<uintptr_t*>(trace_), kMaxTraces);
+  _Unwind_Backtrace(&TraceStackFrame, &state);
+  count_ = state.frame_count;
+}
+
+void StackTrace::Print() const {
+  std::string backtrace = ToString();
+  __android_log_write(ANDROID_LOG_ERROR, "chromium", backtrace.c_str());
+}
+
+// NOTE: Native libraries in APKs are stripped before installing. Print out the
+// relocatable address and library names so host computers can use tools to
+// symbolize and demangle (e.g., addr2line, c++filt).
+void StackTrace::OutputToStream(std::ostream* os) const {
+  std::string proc_maps;
+  std::vector<MappedMemoryRegion> regions;
+  // Allow IO to read /proc/self/maps. Reading this file doesn't hit the disk
+  // since it lives in procfs, and this is currently used to print a stack trace
+  // on fatal log messages in debug builds only. If the restriction is enabled
+  // then it will recursively trigger fatal failures when this enters on the
+  // UI thread.
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
+  if (!ReadProcMaps(&proc_maps)) {
+    __android_log_write(
+        ANDROID_LOG_ERROR, "chromium", "Failed to read /proc/self/maps");
+  } else if (!ParseProcMaps(proc_maps, &regions)) {
+    __android_log_write(
+        ANDROID_LOG_ERROR, "chromium", "Failed to parse /proc/self/maps");
+  }
+
+  for (size_t i = 0; i < count_; ++i) {
+    // Subtract one as return address of function may be in the next
+    // function when a function is annotated as noreturn.
+    uintptr_t address = reinterpret_cast<uintptr_t>(trace_[i]) - 1;
+
+    std::vector<MappedMemoryRegion>::iterator iter = regions.begin();
+    while (iter != regions.end()) {
+      if (address >= iter->start && address < iter->end &&
+          !iter->path.empty()) {
+        break;
+      }
+      ++iter;
+    }
+
+    *os << base::StringPrintf("#%02zd " FMT_ADDR " ", i, address);
+
+    if (iter != regions.end()) {
+      uintptr_t rel_pc = address - iter->start + iter->offset;
+      const char* path = iter->path.c_str();
+      *os << base::StringPrintf("%s+" FMT_ADDR, path, rel_pc);
+    } else {
+      *os << "<unknown>";
+    }
+
+    *os << "\n";
+  }
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/stack_trace_posix.cc b/base/debug/stack_trace_posix.cc
new file mode 100644
index 0000000..2eac14e
--- /dev/null
+++ b/base/debug/stack_trace_posix.cc
@@ -0,0 +1,833 @@
+// Copyright (c) 2012 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/debug/stack_trace.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <map>
+#include <ostream>
+#include <string>
+#include <vector>
+
+#if defined(__GLIBCXX__)
+#include <cxxabi.h>
+#endif
+#if !defined(__UCLIBC__)
+#include <execinfo.h>
+#endif
+
+#if defined(OS_MACOSX)
+#include <AvailabilityMacros.h>
+#endif
+
+#include "base/basictypes.h"
+#include "base/debug/debugger.h"
+#include "base/debug/proc_maps_linux.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/singleton.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/strings/string_number_conversions.h"
+#include "build/build_config.h"
+
+#if defined(USE_SYMBOLIZE)
+#include "base/third_party/symbolize/symbolize.h"
+#endif
+
+namespace base {
+namespace debug {
+
+namespace {
+
+volatile sig_atomic_t in_signal_handler = 0;
+
+#if !defined(USE_SYMBOLIZE) && defined(__GLIBCXX__)
+// The prefix used for mangled symbols, per the Itanium C++ ABI:
+// http://www.codesourcery.com/cxx-abi/abi.html#mangling
+const char kMangledSymbolPrefix[] = "_Z";
+
+// Characters that can be used for symbols, generated by Ruby:
+// (('a'..'z').to_a+('A'..'Z').to_a+('0'..'9').to_a + ['_']).join
+const char kSymbolCharacters[] =
+    "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
+#endif  // !defined(USE_SYMBOLIZE) && defined(__GLIBCXX__)
+
+#if !defined(USE_SYMBOLIZE)
+// Demangles C++ symbols in the given text. Example:
+//
+// "out/Debug/base_unittests(_ZN10StackTraceC1Ev+0x20) [0x817778c]"
+// =>
+// "out/Debug/base_unittests(StackTrace::StackTrace()+0x20) [0x817778c]"
+void DemangleSymbols(std::string* text) {
+  // Note: code in this function is NOT async-signal safe (std::string uses
+  // malloc internally).
+
+#if defined(__GLIBCXX__) && !defined(__UCLIBC__)
+
+  std::string::size_type search_from = 0;
+  while (search_from < text->size()) {
+    // Look for the start of a mangled symbol, from search_from.
+    std::string::size_type mangled_start =
+        text->find(kMangledSymbolPrefix, search_from);
+    if (mangled_start == std::string::npos) {
+      break;  // Mangled symbol not found.
+    }
+
+    // Look for the end of the mangled symbol.
+    std::string::size_type mangled_end =
+        text->find_first_not_of(kSymbolCharacters, mangled_start);
+    if (mangled_end == std::string::npos) {
+      mangled_end = text->size();
+    }
+    std::string mangled_symbol =
+        text->substr(mangled_start, mangled_end - mangled_start);
+
+    // Try to demangle the mangled symbol candidate.
+    int status = 0;
+    scoped_ptr<char, base::FreeDeleter> demangled_symbol(
+        abi::__cxa_demangle(mangled_symbol.c_str(), NULL, 0, &status));
+    if (status == 0) {  // Demangling is successful.
+      // Remove the mangled symbol.
+      text->erase(mangled_start, mangled_end - mangled_start);
+      // Insert the demangled symbol.
+      text->insert(mangled_start, demangled_symbol.get());
+      // Next time, we'll start right after the demangled symbol we inserted.
+      search_from = mangled_start + strlen(demangled_symbol.get());
+    } else {
+      // Failed to demangle.  Retry after the "_Z" we just found.
+      search_from = mangled_start + 2;
+    }
+  }
+
+#endif  // defined(__GLIBCXX__) && !defined(__UCLIBC__)
+}
+#endif  // !defined(USE_SYMBOLIZE)
+
+class BacktraceOutputHandler {
+ public:
+  virtual void HandleOutput(const char* output) = 0;
+
+ protected:
+  virtual ~BacktraceOutputHandler() {}
+};
+
+void OutputPointer(void* pointer, BacktraceOutputHandler* handler) {
+  // This should be more than enough to store a 64-bit number in hex:
+  // 16 hex digits + 1 for null-terminator.
+  char buf[17] = { '\0' };
+  handler->HandleOutput("0x");
+  internal::itoa_r(reinterpret_cast<intptr_t>(pointer),
+                   buf, sizeof(buf), 16, 12);
+  handler->HandleOutput(buf);
+}
+
+#if defined(USE_SYMBOLIZE)
+void OutputFrameId(intptr_t frame_id, BacktraceOutputHandler* handler) {
+  // Max unsigned 64-bit number in decimal has 20 digits (18446744073709551615).
+  // Hence, 30 digits should be more than enough to represent it in decimal
+  // (including the null-terminator).
+  char buf[30] = { '\0' };
+  handler->HandleOutput("#");
+  internal::itoa_r(frame_id, buf, sizeof(buf), 10, 1);
+  handler->HandleOutput(buf);
+}
+#endif  // defined(USE_SYMBOLIZE)
+
+void ProcessBacktrace(void *const *trace,
+                      size_t size,
+                      BacktraceOutputHandler* handler) {
+  // NOTE: This code MUST be async-signal safe (it's used by in-process
+  // stack dumping signal handler). NO malloc or stdio is allowed here.
+
+#if defined(USE_SYMBOLIZE)
+  for (size_t i = 0; i < size; ++i) {
+    OutputFrameId(i, handler);
+    handler->HandleOutput(" ");
+    OutputPointer(trace[i], handler);
+    handler->HandleOutput(" ");
+
+    char buf[1024] = { '\0' };
+
+    // Subtract by one as return address of function may be in the next
+    // function when a function is annotated as noreturn.
+    void* address = static_cast<char*>(trace[i]) - 1;
+    if (google::Symbolize(address, buf, sizeof(buf)))
+      handler->HandleOutput(buf);
+    else
+      handler->HandleOutput("<unknown>");
+
+    handler->HandleOutput("\n");
+  }
+#elif !defined(__UCLIBC__)
+  bool printed = false;
+
+  // Below part is async-signal unsafe (uses malloc), so execute it only
+  // when we are not executing the signal handler.
+  if (in_signal_handler == 0) {
+    scoped_ptr<char*, FreeDeleter>
+        trace_symbols(backtrace_symbols(trace, size));
+    if (trace_symbols.get()) {
+      for (size_t i = 0; i < size; ++i) {
+        std::string trace_symbol = trace_symbols.get()[i];
+        DemangleSymbols(&trace_symbol);
+        handler->HandleOutput(trace_symbol.c_str());
+        handler->HandleOutput("\n");
+      }
+
+      printed = true;
+    }
+  }
+
+  if (!printed) {
+    for (size_t i = 0; i < size; ++i) {
+      handler->HandleOutput(" [");
+      OutputPointer(trace[i], handler);
+      handler->HandleOutput("]\n");
+    }
+  }
+#endif  // defined(USE_SYMBOLIZE)
+}
+
+void PrintToStderr(const char* output) {
+  // NOTE: This code MUST be async-signal safe (it's used by in-process
+  // stack dumping signal handler). NO malloc or stdio is allowed here.
+  ignore_result(HANDLE_EINTR(write(STDERR_FILENO, output, strlen(output))));
+}
+
+void StackDumpSignalHandler(int signal, siginfo_t* info, void* void_context) {
+  // NOTE: This code MUST be async-signal safe.
+  // NO malloc or stdio is allowed here.
+
+  // Record the fact that we are in the signal handler now, so that the rest
+  // of StackTrace can behave in an async-signal-safe manner.
+  in_signal_handler = 1;
+
+  if (BeingDebugged())
+    BreakDebugger();
+
+  PrintToStderr("Received signal ");
+  char buf[1024] = { 0 };
+  internal::itoa_r(signal, buf, sizeof(buf), 10, 0);
+  PrintToStderr(buf);
+  if (signal == SIGBUS) {
+    if (info->si_code == BUS_ADRALN)
+      PrintToStderr(" BUS_ADRALN ");
+    else if (info->si_code == BUS_ADRERR)
+      PrintToStderr(" BUS_ADRERR ");
+    else if (info->si_code == BUS_OBJERR)
+      PrintToStderr(" BUS_OBJERR ");
+    else
+      PrintToStderr(" <unknown> ");
+  } else if (signal == SIGFPE) {
+    if (info->si_code == FPE_FLTDIV)
+      PrintToStderr(" FPE_FLTDIV ");
+    else if (info->si_code == FPE_FLTINV)
+      PrintToStderr(" FPE_FLTINV ");
+    else if (info->si_code == FPE_FLTOVF)
+      PrintToStderr(" FPE_FLTOVF ");
+    else if (info->si_code == FPE_FLTRES)
+      PrintToStderr(" FPE_FLTRES ");
+    else if (info->si_code == FPE_FLTSUB)
+      PrintToStderr(" FPE_FLTSUB ");
+    else if (info->si_code == FPE_FLTUND)
+      PrintToStderr(" FPE_FLTUND ");
+    else if (info->si_code == FPE_INTDIV)
+      PrintToStderr(" FPE_INTDIV ");
+    else if (info->si_code == FPE_INTOVF)
+      PrintToStderr(" FPE_INTOVF ");
+    else
+      PrintToStderr(" <unknown> ");
+  } else if (signal == SIGILL) {
+    if (info->si_code == ILL_BADSTK)
+      PrintToStderr(" ILL_BADSTK ");
+    else if (info->si_code == ILL_COPROC)
+      PrintToStderr(" ILL_COPROC ");
+    else if (info->si_code == ILL_ILLOPN)
+      PrintToStderr(" ILL_ILLOPN ");
+    else if (info->si_code == ILL_ILLADR)
+      PrintToStderr(" ILL_ILLADR ");
+    else if (info->si_code == ILL_ILLTRP)
+      PrintToStderr(" ILL_ILLTRP ");
+    else if (info->si_code == ILL_PRVOPC)
+      PrintToStderr(" ILL_PRVOPC ");
+    else if (info->si_code == ILL_PRVREG)
+      PrintToStderr(" ILL_PRVREG ");
+    else
+      PrintToStderr(" <unknown> ");
+  } else if (signal == SIGSEGV) {
+    if (info->si_code == SEGV_MAPERR)
+      PrintToStderr(" SEGV_MAPERR ");
+    else if (info->si_code == SEGV_ACCERR)
+      PrintToStderr(" SEGV_ACCERR ");
+    else
+      PrintToStderr(" <unknown> ");
+  }
+  if (signal == SIGBUS || signal == SIGFPE ||
+      signal == SIGILL || signal == SIGSEGV) {
+    internal::itoa_r(reinterpret_cast<intptr_t>(info->si_addr),
+                     buf, sizeof(buf), 16, 12);
+    PrintToStderr(buf);
+  }
+  PrintToStderr("\n");
+
+  debug::StackTrace().Print();
+
+#if defined(OS_LINUX)
+#if ARCH_CPU_X86_FAMILY
+  ucontext_t* context = reinterpret_cast<ucontext_t*>(void_context);
+  const struct {
+    const char* label;
+    greg_t value;
+  } registers[] = {
+#if ARCH_CPU_32_BITS
+    { "  gs: ", context->uc_mcontext.gregs[REG_GS] },
+    { "  fs: ", context->uc_mcontext.gregs[REG_FS] },
+    { "  es: ", context->uc_mcontext.gregs[REG_ES] },
+    { "  ds: ", context->uc_mcontext.gregs[REG_DS] },
+    { " edi: ", context->uc_mcontext.gregs[REG_EDI] },
+    { " esi: ", context->uc_mcontext.gregs[REG_ESI] },
+    { " ebp: ", context->uc_mcontext.gregs[REG_EBP] },
+    { " esp: ", context->uc_mcontext.gregs[REG_ESP] },
+    { " ebx: ", context->uc_mcontext.gregs[REG_EBX] },
+    { " edx: ", context->uc_mcontext.gregs[REG_EDX] },
+    { " ecx: ", context->uc_mcontext.gregs[REG_ECX] },
+    { " eax: ", context->uc_mcontext.gregs[REG_EAX] },
+    { " trp: ", context->uc_mcontext.gregs[REG_TRAPNO] },
+    { " err: ", context->uc_mcontext.gregs[REG_ERR] },
+    { "  ip: ", context->uc_mcontext.gregs[REG_EIP] },
+    { "  cs: ", context->uc_mcontext.gregs[REG_CS] },
+    { " efl: ", context->uc_mcontext.gregs[REG_EFL] },
+    { " usp: ", context->uc_mcontext.gregs[REG_UESP] },
+    { "  ss: ", context->uc_mcontext.gregs[REG_SS] },
+#elif ARCH_CPU_64_BITS
+    { "  r8: ", context->uc_mcontext.gregs[REG_R8] },
+    { "  r9: ", context->uc_mcontext.gregs[REG_R9] },
+    { " r10: ", context->uc_mcontext.gregs[REG_R10] },
+    { " r11: ", context->uc_mcontext.gregs[REG_R11] },
+    { " r12: ", context->uc_mcontext.gregs[REG_R12] },
+    { " r13: ", context->uc_mcontext.gregs[REG_R13] },
+    { " r14: ", context->uc_mcontext.gregs[REG_R14] },
+    { " r15: ", context->uc_mcontext.gregs[REG_R15] },
+    { "  di: ", context->uc_mcontext.gregs[REG_RDI] },
+    { "  si: ", context->uc_mcontext.gregs[REG_RSI] },
+    { "  bp: ", context->uc_mcontext.gregs[REG_RBP] },
+    { "  bx: ", context->uc_mcontext.gregs[REG_RBX] },
+    { "  dx: ", context->uc_mcontext.gregs[REG_RDX] },
+    { "  ax: ", context->uc_mcontext.gregs[REG_RAX] },
+    { "  cx: ", context->uc_mcontext.gregs[REG_RCX] },
+    { "  sp: ", context->uc_mcontext.gregs[REG_RSP] },
+    { "  ip: ", context->uc_mcontext.gregs[REG_RIP] },
+    { " efl: ", context->uc_mcontext.gregs[REG_EFL] },
+    { " cgf: ", context->uc_mcontext.gregs[REG_CSGSFS] },
+    { " erf: ", context->uc_mcontext.gregs[REG_ERR] },
+    { " trp: ", context->uc_mcontext.gregs[REG_TRAPNO] },
+    { " msk: ", context->uc_mcontext.gregs[REG_OLDMASK] },
+    { " cr2: ", context->uc_mcontext.gregs[REG_CR2] },
+#endif
+  };
+
+#if ARCH_CPU_32_BITS
+  const int kRegisterPadding = 8;
+#elif ARCH_CPU_64_BITS
+  const int kRegisterPadding = 16;
+#endif
+
+  for (size_t i = 0; i < arraysize(registers); i++) {
+    PrintToStderr(registers[i].label);
+    internal::itoa_r(registers[i].value, buf, sizeof(buf),
+                     16, kRegisterPadding);
+    PrintToStderr(buf);
+
+    if ((i + 1) % 4 == 0)
+      PrintToStderr("\n");
+  }
+  PrintToStderr("\n");
+#endif
+#elif defined(OS_MACOSX)
+  // TODO(shess): Port to 64-bit, and ARM architecture (32 and 64-bit).
+#if ARCH_CPU_X86_FAMILY && ARCH_CPU_32_BITS
+  ucontext_t* context = reinterpret_cast<ucontext_t*>(void_context);
+  size_t len;
+
+  // NOTE: Even |snprintf()| is not on the approved list for signal
+  // handlers, but buffered I/O is definitely not on the list due to
+  // potential for |malloc()|.
+  len = static_cast<size_t>(
+      snprintf(buf, sizeof(buf),
+               "ax: %x, bx: %x, cx: %x, dx: %x\n",
+               context->uc_mcontext->__ss.__eax,
+               context->uc_mcontext->__ss.__ebx,
+               context->uc_mcontext->__ss.__ecx,
+               context->uc_mcontext->__ss.__edx));
+  write(STDERR_FILENO, buf, std::min(len, sizeof(buf) - 1));
+
+  len = static_cast<size_t>(
+      snprintf(buf, sizeof(buf),
+               "di: %x, si: %x, bp: %x, sp: %x, ss: %x, flags: %x\n",
+               context->uc_mcontext->__ss.__edi,
+               context->uc_mcontext->__ss.__esi,
+               context->uc_mcontext->__ss.__ebp,
+               context->uc_mcontext->__ss.__esp,
+               context->uc_mcontext->__ss.__ss,
+               context->uc_mcontext->__ss.__eflags));
+  write(STDERR_FILENO, buf, std::min(len, sizeof(buf) - 1));
+
+  len = static_cast<size_t>(
+      snprintf(buf, sizeof(buf),
+               "ip: %x, cs: %x, ds: %x, es: %x, fs: %x, gs: %x\n",
+               context->uc_mcontext->__ss.__eip,
+               context->uc_mcontext->__ss.__cs,
+               context->uc_mcontext->__ss.__ds,
+               context->uc_mcontext->__ss.__es,
+               context->uc_mcontext->__ss.__fs,
+               context->uc_mcontext->__ss.__gs));
+  write(STDERR_FILENO, buf, std::min(len, sizeof(buf) - 1));
+#endif  // ARCH_CPU_32_BITS
+#endif  // defined(OS_MACOSX)
+  _exit(1);
+}
+
+class PrintBacktraceOutputHandler : public BacktraceOutputHandler {
+ public:
+  PrintBacktraceOutputHandler() {}
+
+  void HandleOutput(const char* output) override {
+    // NOTE: This code MUST be async-signal safe (it's used by in-process
+    // stack dumping signal handler). NO malloc or stdio is allowed here.
+    PrintToStderr(output);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(PrintBacktraceOutputHandler);
+};
+
+class StreamBacktraceOutputHandler : public BacktraceOutputHandler {
+ public:
+  explicit StreamBacktraceOutputHandler(std::ostream* os) : os_(os) {
+  }
+
+  void HandleOutput(const char* output) override { (*os_) << output; }
+
+ private:
+  std::ostream* os_;
+
+  DISALLOW_COPY_AND_ASSIGN(StreamBacktraceOutputHandler);
+};
+
+void WarmUpBacktrace() {
+  // Warm up stack trace infrastructure. It turns out that on the first
+  // call glibc initializes some internal data structures using pthread_once,
+  // and even backtrace() can call malloc(), leading to hangs.
+  //
+  // Example stack trace snippet (with tcmalloc):
+  //
+  // #8  0x0000000000a173b5 in tc_malloc
+  //             at ./third_party/tcmalloc/chromium/src/debugallocation.cc:1161
+  // #9  0x00007ffff7de7900 in _dl_map_object_deps at dl-deps.c:517
+  // #10 0x00007ffff7ded8a9 in dl_open_worker at dl-open.c:262
+  // #11 0x00007ffff7de9176 in _dl_catch_error at dl-error.c:178
+  // #12 0x00007ffff7ded31a in _dl_open (file=0x7ffff625e298 "libgcc_s.so.1")
+  //             at dl-open.c:639
+  // #13 0x00007ffff6215602 in do_dlopen at dl-libc.c:89
+  // #14 0x00007ffff7de9176 in _dl_catch_error at dl-error.c:178
+  // #15 0x00007ffff62156c4 in dlerror_run at dl-libc.c:48
+  // #16 __GI___libc_dlopen_mode at dl-libc.c:165
+  // #17 0x00007ffff61ef8f5 in init
+  //             at ../sysdeps/x86_64/../ia64/backtrace.c:53
+  // #18 0x00007ffff6aad400 in pthread_once
+  //             at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_once.S:104
+  // #19 0x00007ffff61efa14 in __GI___backtrace
+  //             at ../sysdeps/x86_64/../ia64/backtrace.c:104
+  // #20 0x0000000000752a54 in base::debug::StackTrace::StackTrace
+  //             at base/debug/stack_trace_posix.cc:175
+  // #21 0x00000000007a4ae5 in
+  //             base::(anonymous namespace)::StackDumpSignalHandler
+  //             at base/process_util_posix.cc:172
+  // #22 <signal handler called>
+  StackTrace stack_trace;
+}
+
+}  // namespace
+
+#if defined(USE_SYMBOLIZE)
+
+// class SandboxSymbolizeHelper.
+//
+// The purpose of this class is to prepare and install a "file open" callback
+// needed by the stack trace symbolization code
+// (base/third_party/symbolize/symbolize.h) so that it can function properly
+// in a sandboxed process.  The caveat is that this class must be instantiated
+// before the sandboxing is enabled so that it can get the chance to open all
+// the object files that are loaded in the virtual address space of the current
+// process.
+class SandboxSymbolizeHelper {
+ public:
+  // Returns the singleton instance.
+  static SandboxSymbolizeHelper* GetInstance() {
+    return Singleton<SandboxSymbolizeHelper>::get();
+  }
+
+ private:
+  friend struct DefaultSingletonTraits<SandboxSymbolizeHelper>;
+
+  SandboxSymbolizeHelper()
+      : is_initialized_(false) {
+    Init();
+  }
+
+  ~SandboxSymbolizeHelper() {
+    UnregisterCallback();
+    CloseObjectFiles();
+  }
+
+  // Returns a O_RDONLY file descriptor for |file_path| if it was opened
+  // sucessfully during the initialization.  The file is repositioned at
+  // offset 0.
+  // IMPORTANT: This function must be async-signal-safe because it can be
+  // called from a signal handler (symbolizing stack frames for a crash).
+  int GetFileDescriptor(const char* file_path) {
+    int fd = -1;
+
+#if !defined(NDEBUG)
+    if (file_path) {
+      // The assumption here is that iterating over std::map<std::string, int>
+      // using a const_iterator does not allocate dynamic memory, hense it is
+      // async-signal-safe.
+      std::map<std::string, int>::const_iterator it;
+      for (it = modules_.begin(); it != modules_.end(); ++it) {
+        if (strcmp((it->first).c_str(), file_path) == 0) {
+          // POSIX.1-2004 requires an implementation to guarantee that dup()
+          // is async-signal-safe.
+          fd = dup(it->second);
+          break;
+        }
+      }
+      // POSIX.1-2004 requires an implementation to guarantee that lseek()
+      // is async-signal-safe.
+      if (fd >= 0 && lseek(fd, 0, SEEK_SET) < 0) {
+        // Failed to seek.
+        fd = -1;
+      }
+    }
+#endif  // !defined(NDEBUG)
+
+    return fd;
+  }
+
+  // Searches for the object file (from /proc/self/maps) that contains
+  // the specified pc.  If found, sets |start_address| to the start address
+  // of where this object file is mapped in memory, sets the module base
+  // address into |base_address|, copies the object file name into
+  // |out_file_name|, and attempts to open the object file.  If the object
+  // file is opened successfully, returns the file descriptor.  Otherwise,
+  // returns -1.  |out_file_name_size| is the size of the file name buffer
+  // (including the null terminator).
+  // IMPORTANT: This function must be async-signal-safe because it can be
+  // called from a signal handler (symbolizing stack frames for a crash).
+  static int OpenObjectFileContainingPc(uint64_t pc, uint64_t& start_address,
+                                        uint64_t& base_address, char* file_path,
+                                        int file_path_size) {
+    // This method can only be called after the singleton is instantiated.
+    // This is ensured by the following facts:
+    // * This is the only static method in this class, it is private, and
+    //   the class has no friends (except for the DefaultSingletonTraits).
+    //   The compiler guarantees that it can only be called after the
+    //   singleton is instantiated.
+    // * This method is used as a callback for the stack tracing code and
+    //   the callback registration is done in the constructor, so logically
+    //   it cannot be called before the singleton is created.
+    SandboxSymbolizeHelper* instance = GetInstance();
+
+    // The assumption here is that iterating over
+    // std::vector<MappedMemoryRegion> using a const_iterator does not allocate
+    // dynamic memory, hence it is async-signal-safe.
+    std::vector<MappedMemoryRegion>::const_iterator it;
+    bool is_first = true;
+    for (it = instance->regions_.begin(); it != instance->regions_.end();
+         ++it, is_first = false) {
+      const MappedMemoryRegion& region = *it;
+      if (region.start <= pc && pc < region.end) {
+        start_address = region.start;
+        // Don't subtract 'start_address' from the first entry:
+        // * If a binary is compiled w/o -pie, then the first entry in
+        //   process maps is likely the binary itself (all dynamic libs
+        //   are mapped higher in address space). For such a binary,
+        //   instruction offset in binary coincides with the actual
+        //   instruction address in virtual memory (as code section
+        //   is mapped to a fixed memory range).
+        // * If a binary is compiled with -pie, all the modules are
+        //   mapped high at address space (in particular, higher than
+        //   shadow memory of the tool), so the module can't be the
+        //   first entry.
+        base_address = (is_first ? 0U : start_address) - region.offset;
+        if (file_path && file_path_size > 0) {
+          strncpy(file_path, region.path.c_str(), file_path_size);
+          // Ensure null termination.
+          file_path[file_path_size - 1] = '\0';
+        }
+        return instance->GetFileDescriptor(region.path.c_str());
+      }
+    }
+    return -1;
+  }
+
+  // Parses /proc/self/maps in order to compile a list of all object file names
+  // for the modules that are loaded in the current process.
+  // Returns true on success.
+  bool CacheMemoryRegions() {
+    // Reads /proc/self/maps.
+    std::string contents;
+    if (!ReadProcMaps(&contents)) {
+      LOG(ERROR) << "Failed to read /proc/self/maps";
+      return false;
+    }
+
+    // Parses /proc/self/maps.
+    if (!ParseProcMaps(contents, &regions_)) {
+      LOG(ERROR) << "Failed to parse the contents of /proc/self/maps";
+      return false;
+    }
+
+    is_initialized_ = true;
+    return true;
+  }
+
+  // Opens all object files and caches their file descriptors.
+  void OpenSymbolFiles() {
+    // Pre-opening and caching the file descriptors of all loaded modules is
+    // not considered safe for retail builds.  Hence it is only done in debug
+    // builds.  For more details, take a look at: http://crbug.com/341966
+    // Enabling this to release mode would require approval from the security
+    // team.
+#if !defined(NDEBUG)
+    // Open the object files for all read-only executable regions and cache
+    // their file descriptors.
+    std::vector<MappedMemoryRegion>::const_iterator it;
+    for (it = regions_.begin(); it != regions_.end(); ++it) {
+      const MappedMemoryRegion& region = *it;
+      // Only interesed in read-only executable regions.
+      if ((region.permissions & MappedMemoryRegion::READ) ==
+              MappedMemoryRegion::READ &&
+          (region.permissions & MappedMemoryRegion::WRITE) == 0 &&
+          (region.permissions & MappedMemoryRegion::EXECUTE) ==
+              MappedMemoryRegion::EXECUTE) {
+        if (region.path.empty()) {
+          // Skip regions with empty file names.
+          continue;
+        }
+        if (region.path[0] == '[') {
+          // Skip pseudo-paths, like [stack], [vdso], [heap], etc ...
+          continue;
+        }
+        // Avoid duplicates.
+        if (modules_.find(region.path) == modules_.end()) {
+          int fd = open(region.path.c_str(), O_RDONLY | O_CLOEXEC);
+          if (fd >= 0) {
+            modules_.insert(std::make_pair(region.path, fd));
+          } else {
+            LOG(WARNING) << "Failed to open file: " << region.path
+                         << "\n  Error: " << strerror(errno);
+          }
+        }
+      }
+    }
+#endif  // !defined(NDEBUG)
+  }
+
+  // Initializes and installs the symbolization callback.
+  void Init() {
+    if (CacheMemoryRegions()) {
+      OpenSymbolFiles();
+      google::InstallSymbolizeOpenObjectFileCallback(
+          &OpenObjectFileContainingPc);
+    }
+  }
+
+  // Unregister symbolization callback.
+  void UnregisterCallback() {
+    if (is_initialized_) {
+      google::InstallSymbolizeOpenObjectFileCallback(NULL);
+      is_initialized_ = false;
+    }
+  }
+
+  // Closes all file descriptors owned by this instance.
+  void CloseObjectFiles() {
+#if !defined(NDEBUG)
+    std::map<std::string, int>::iterator it;
+    for (it = modules_.begin(); it != modules_.end(); ++it) {
+      int ret = IGNORE_EINTR(close(it->second));
+      DCHECK(!ret);
+      it->second = -1;
+    }
+    modules_.clear();
+#endif  // !defined(NDEBUG)
+  }
+
+  // Set to true upon successful initialization.
+  bool is_initialized_;
+
+#if !defined(NDEBUG)
+  // Mapping from file name to file descriptor.  Includes file descriptors
+  // for all successfully opened object files and the file descriptor for
+  // /proc/self/maps.  This code is not safe for release builds so
+  // this is only done for DEBUG builds.
+  std::map<std::string, int> modules_;
+#endif  // !defined(NDEBUG)
+
+  // Cache for the process memory regions.  Produced by parsing the contents
+  // of /proc/self/maps cache.
+  std::vector<MappedMemoryRegion> regions_;
+
+  DISALLOW_COPY_AND_ASSIGN(SandboxSymbolizeHelper);
+};
+#endif  // USE_SYMBOLIZE
+
+bool EnableInProcessStackDumpingForSandbox() {
+#if defined(USE_SYMBOLIZE)
+  SandboxSymbolizeHelper::GetInstance();
+#endif  // USE_SYMBOLIZE
+
+  return EnableInProcessStackDumping();
+}
+
+bool EnableInProcessStackDumping() {
+  // When running in an application, our code typically expects SIGPIPE
+  // to be ignored.  Therefore, when testing that same code, it should run
+  // with SIGPIPE ignored as well.
+  struct sigaction sigpipe_action;
+  memset(&sigpipe_action, 0, sizeof(sigpipe_action));
+  sigpipe_action.sa_handler = SIG_IGN;
+  sigemptyset(&sigpipe_action.sa_mask);
+  bool success = (sigaction(SIGPIPE, &sigpipe_action, NULL) == 0);
+
+  // Avoid hangs during backtrace initialization, see above.
+  WarmUpBacktrace();
+
+  struct sigaction action;
+  memset(&action, 0, sizeof(action));
+  action.sa_flags = SA_RESETHAND | SA_SIGINFO;
+  action.sa_sigaction = &StackDumpSignalHandler;
+  sigemptyset(&action.sa_mask);
+
+  success &= (sigaction(SIGILL, &action, NULL) == 0);
+  success &= (sigaction(SIGABRT, &action, NULL) == 0);
+  success &= (sigaction(SIGFPE, &action, NULL) == 0);
+  success &= (sigaction(SIGBUS, &action, NULL) == 0);
+  success &= (sigaction(SIGSEGV, &action, NULL) == 0);
+// On Linux, SIGSYS is reserved by the kernel for seccomp-bpf sandboxing.
+#if !defined(OS_LINUX)
+  success &= (sigaction(SIGSYS, &action, NULL) == 0);
+#endif  // !defined(OS_LINUX)
+
+  return success;
+}
+
+StackTrace::StackTrace() {
+  // NOTE: This code MUST be async-signal safe (it's used by in-process
+  // stack dumping signal handler). NO malloc or stdio is allowed here.
+
+#if !defined(__UCLIBC__)
+  // Though the backtrace API man page does not list any possible negative
+  // return values, we take no chance.
+  count_ = base::saturated_cast<size_t>(backtrace(trace_, arraysize(trace_)));
+#else
+  count_ = 0;
+#endif
+}
+
+void StackTrace::Print() const {
+  // NOTE: This code MUST be async-signal safe (it's used by in-process
+  // stack dumping signal handler). NO malloc or stdio is allowed here.
+
+#if !defined(__UCLIBC__)
+  PrintBacktraceOutputHandler handler;
+  ProcessBacktrace(trace_, count_, &handler);
+#endif
+}
+
+#if !defined(__UCLIBC__)
+void StackTrace::OutputToStream(std::ostream* os) const {
+  StreamBacktraceOutputHandler handler(os);
+  ProcessBacktrace(trace_, count_, &handler);
+}
+#endif
+
+namespace internal {
+
+// NOTE: code from sandbox/linux/seccomp-bpf/demo.cc.
+char *itoa_r(intptr_t i, char *buf, size_t sz, int base, size_t padding) {
+  // Make sure we can write at least one NUL byte.
+  size_t n = 1;
+  if (n > sz)
+    return NULL;
+
+  if (base < 2 || base > 16) {
+    buf[0] = '\000';
+    return NULL;
+  }
+
+  char *start = buf;
+
+  uintptr_t j = i;
+
+  // Handle negative numbers (only for base 10).
+  if (i < 0 && base == 10) {
+    j = -i;
+
+    // Make sure we can write the '-' character.
+    if (++n > sz) {
+      buf[0] = '\000';
+      return NULL;
+    }
+    *start++ = '-';
+  }
+
+  // Loop until we have converted the entire number. Output at least one
+  // character (i.e. '0').
+  char *ptr = start;
+  do {
+    // Make sure there is still enough space left in our output buffer.
+    if (++n > sz) {
+      buf[0] = '\000';
+      return NULL;
+    }
+
+    // Output the next digit.
+    *ptr++ = "0123456789abcdef"[j % base];
+    j /= base;
+
+    if (padding > 0)
+      padding--;
+  } while (j > 0 || padding > 0);
+
+  // Terminate the output with a NUL character.
+  *ptr = '\000';
+
+  // Conversion to ASCII actually resulted in the digits being in reverse
+  // order. We can't easily generate them in forward order, as we can't tell
+  // the number of characters needed until we are done converting.
+  // So, now, we reverse the string (except for the possible "-" sign).
+  while (--ptr > start) {
+    char ch = *ptr;
+    *ptr = *start;
+    *start++ = ch;
+  }
+  return buf;
+}
+
+}  // namespace internal
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/stack_trace_unittest.cc b/base/debug/stack_trace_unittest.cc
new file mode 100644
index 0000000..804587e
--- /dev/null
+++ b/base/debug/stack_trace_unittest.cc
@@ -0,0 +1,239 @@
+// Copyright (c) 2011 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 <limits>
+#include <sstream>
+#include <string>
+
+#include "base/debug/stack_trace.h"
+#include "base/logging.h"
+#include "base/process/kill.h"
+#include "base/process/process_handle.h"
+#include "base/test/test_timeouts.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/multiprocess_func_list.h"
+
+#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_IOS)
+#include "base/test/multiprocess_test.h"
+#endif
+
+namespace base {
+namespace debug {
+
+#if defined(OS_POSIX) && !defined(OS_ANDROID) && !defined(OS_IOS)
+typedef MultiProcessTest StackTraceTest;
+#else
+typedef testing::Test StackTraceTest;
+#endif
+
+// Note: On Linux, this test currently only fully works on Debug builds.
+// See comments in the #ifdef soup if you intend to change this.
+#if defined(OS_WIN)
+// Always fails on Windows: crbug.com/32070
+#define MAYBE_OutputToStream DISABLED_OutputToStream
+#else
+#define MAYBE_OutputToStream OutputToStream
+#endif
+#if !defined(__UCLIBC__)
+TEST_F(StackTraceTest, MAYBE_OutputToStream) {
+  StackTrace trace;
+
+  // Dump the trace into a string.
+  std::ostringstream os;
+  trace.OutputToStream(&os);
+  std::string backtrace_message = os.str();
+
+  // ToString() should produce the same output.
+  EXPECT_EQ(backtrace_message, trace.ToString());
+
+#if defined(OS_POSIX) && !defined(OS_MACOSX) && NDEBUG
+  // Stack traces require an extra data table that bloats our binaries,
+  // so they're turned off for release builds.  We stop the test here,
+  // at least letting us verify that the calls don't crash.
+  return;
+#endif  // defined(OS_POSIX) && !defined(OS_MACOSX) && NDEBUG
+
+  size_t frames_found = 0;
+  trace.Addresses(&frames_found);
+  ASSERT_GE(frames_found, 5u) <<
+      "No stack frames found.  Skipping rest of test.";
+
+  // Check if the output has symbol initialization warning.  If it does, fail.
+  ASSERT_EQ(backtrace_message.find("Dumping unresolved backtrace"),
+            std::string::npos) <<
+      "Unable to resolve symbols.  Skipping rest of test.";
+
+#if defined(OS_MACOSX)
+#if 0
+  // Disabled due to -fvisibility=hidden in build config.
+
+  // Symbol resolution via the backtrace_symbol function does not work well
+  // in OS X.
+  // See this thread:
+  //
+  //    http://lists.apple.com/archives/darwin-dev/2009/Mar/msg00111.html
+  //
+  // Just check instead that we find our way back to the "start" symbol
+  // which should be the first symbol in the trace.
+  //
+  // TODO(port): Find a more reliable way to resolve symbols.
+
+  // Expect to at least find main.
+  EXPECT_TRUE(backtrace_message.find("start") != std::string::npos)
+      << "Expected to find start in backtrace:\n"
+      << backtrace_message;
+
+#endif
+#elif defined(USE_SYMBOLIZE)
+  // This branch is for gcc-compiled code, but not Mac due to the
+  // above #if.
+  // Expect a demangled symbol.
+  EXPECT_TRUE(backtrace_message.find("testing::Test::Run()") !=
+              std::string::npos)
+      << "Expected a demangled symbol in backtrace:\n"
+      << backtrace_message;
+
+#elif 0
+  // This is the fall-through case; it used to cover Windows.
+  // But it's disabled because of varying buildbot configs;
+  // some lack symbols.
+
+  // Expect to at least find main.
+  EXPECT_TRUE(backtrace_message.find("main") != std::string::npos)
+      << "Expected to find main in backtrace:\n"
+      << backtrace_message;
+
+#if defined(OS_WIN)
+// MSVC doesn't allow the use of C99's __func__ within C++, so we fake it with
+// MSVC's __FUNCTION__ macro.
+#define __func__ __FUNCTION__
+#endif
+
+  // Expect to find this function as well.
+  // Note: This will fail if not linked with -rdynamic (aka -export_dynamic)
+  EXPECT_TRUE(backtrace_message.find(__func__) != std::string::npos)
+      << "Expected to find " << __func__ << " in backtrace:\n"
+      << backtrace_message;
+
+#endif  // define(OS_MACOSX)
+}
+
+// The test is used for manual testing, e.g., to see the raw output.
+TEST_F(StackTraceTest, DebugOutputToStream) {
+  StackTrace trace;
+  std::ostringstream os;
+  trace.OutputToStream(&os);
+  VLOG(1) << os.str();
+}
+
+// The test is used for manual testing, e.g., to see the raw output.
+TEST_F(StackTraceTest, DebugPrintBacktrace) {
+  StackTrace().Print();
+}
+#endif  // !defined(__UCLIBC__)
+
+#if defined(OS_POSIX) && !defined(OS_ANDROID)
+#if !defined(OS_IOS)
+static char* newArray() {
+  // Clang warns about the mismatched new[]/delete if they occur in the same
+  // function.
+  return new char[10];
+}
+
+MULTIPROCESS_TEST_MAIN(MismatchedMallocChildProcess) {
+  char* pointer = newArray();
+  delete pointer;
+  return 2;
+}
+
+// Regression test for StackDumpingSignalHandler async-signal unsafety.
+// Combined with tcmalloc's debugallocation, that signal handler
+// and e.g. mismatched new[]/delete would cause a hang because
+// of re-entering malloc.
+TEST_F(StackTraceTest, AsyncSignalUnsafeSignalHandlerHang) {
+  Process child = SpawnChild("MismatchedMallocChildProcess");
+  ASSERT_TRUE(child.IsValid());
+  int exit_code;
+  ASSERT_TRUE(child.WaitForExitWithTimeout(TestTimeouts::action_timeout(),
+                                           &exit_code));
+}
+#endif  // !defined(OS_IOS)
+
+namespace {
+
+std::string itoa_r_wrapper(intptr_t i, size_t sz, int base, size_t padding) {
+  char buffer[1024];
+  CHECK_LE(sz, sizeof(buffer));
+
+  char* result = internal::itoa_r(i, buffer, sz, base, padding);
+  EXPECT_TRUE(result);
+  return std::string(buffer);
+}
+
+}  // namespace
+
+TEST_F(StackTraceTest, itoa_r) {
+  EXPECT_EQ("0", itoa_r_wrapper(0, 128, 10, 0));
+  EXPECT_EQ("-1", itoa_r_wrapper(-1, 128, 10, 0));
+
+  // Test edge cases.
+  if (sizeof(intptr_t) == 4) {
+    EXPECT_EQ("ffffffff", itoa_r_wrapper(-1, 128, 16, 0));
+    EXPECT_EQ("-2147483648",
+              itoa_r_wrapper(std::numeric_limits<intptr_t>::min(), 128, 10, 0));
+    EXPECT_EQ("2147483647",
+              itoa_r_wrapper(std::numeric_limits<intptr_t>::max(), 128, 10, 0));
+
+    EXPECT_EQ("80000000",
+              itoa_r_wrapper(std::numeric_limits<intptr_t>::min(), 128, 16, 0));
+    EXPECT_EQ("7fffffff",
+              itoa_r_wrapper(std::numeric_limits<intptr_t>::max(), 128, 16, 0));
+  } else if (sizeof(intptr_t) == 8) {
+    EXPECT_EQ("ffffffffffffffff", itoa_r_wrapper(-1, 128, 16, 0));
+    EXPECT_EQ("-9223372036854775808",
+              itoa_r_wrapper(std::numeric_limits<intptr_t>::min(), 128, 10, 0));
+    EXPECT_EQ("9223372036854775807",
+              itoa_r_wrapper(std::numeric_limits<intptr_t>::max(), 128, 10, 0));
+
+    EXPECT_EQ("8000000000000000",
+              itoa_r_wrapper(std::numeric_limits<intptr_t>::min(), 128, 16, 0));
+    EXPECT_EQ("7fffffffffffffff",
+              itoa_r_wrapper(std::numeric_limits<intptr_t>::max(), 128, 16, 0));
+  } else {
+    ADD_FAILURE() << "Missing test case for your size of intptr_t ("
+                  << sizeof(intptr_t) << ")";
+  }
+
+  // Test hex output.
+  EXPECT_EQ("688", itoa_r_wrapper(0x688, 128, 16, 0));
+  EXPECT_EQ("deadbeef", itoa_r_wrapper(0xdeadbeef, 128, 16, 0));
+
+  // Check that itoa_r respects passed buffer size limit.
+  char buffer[1024];
+  EXPECT_TRUE(internal::itoa_r(0xdeadbeef, buffer, 10, 16, 0));
+  EXPECT_TRUE(internal::itoa_r(0xdeadbeef, buffer, 9, 16, 0));
+  EXPECT_FALSE(internal::itoa_r(0xdeadbeef, buffer, 8, 16, 0));
+  EXPECT_FALSE(internal::itoa_r(0xdeadbeef, buffer, 7, 16, 0));
+  EXPECT_TRUE(internal::itoa_r(0xbeef, buffer, 5, 16, 4));
+  EXPECT_FALSE(internal::itoa_r(0xbeef, buffer, 5, 16, 5));
+  EXPECT_FALSE(internal::itoa_r(0xbeef, buffer, 5, 16, 6));
+
+  // Test padding.
+  EXPECT_EQ("1", itoa_r_wrapper(1, 128, 10, 0));
+  EXPECT_EQ("1", itoa_r_wrapper(1, 128, 10, 1));
+  EXPECT_EQ("01", itoa_r_wrapper(1, 128, 10, 2));
+  EXPECT_EQ("001", itoa_r_wrapper(1, 128, 10, 3));
+  EXPECT_EQ("0001", itoa_r_wrapper(1, 128, 10, 4));
+  EXPECT_EQ("00001", itoa_r_wrapper(1, 128, 10, 5));
+  EXPECT_EQ("688", itoa_r_wrapper(0x688, 128, 16, 0));
+  EXPECT_EQ("688", itoa_r_wrapper(0x688, 128, 16, 1));
+  EXPECT_EQ("688", itoa_r_wrapper(0x688, 128, 16, 2));
+  EXPECT_EQ("688", itoa_r_wrapper(0x688, 128, 16, 3));
+  EXPECT_EQ("0688", itoa_r_wrapper(0x688, 128, 16, 4));
+  EXPECT_EQ("00688", itoa_r_wrapper(0x688, 128, 16, 5));
+}
+#endif  // defined(OS_POSIX) && !defined(OS_ANDROID)
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/stack_trace_win.cc b/base/debug/stack_trace_win.cc
new file mode 100644
index 0000000..55d5562
--- /dev/null
+++ b/base/debug/stack_trace_win.cc
@@ -0,0 +1,283 @@
+// Copyright (c) 2012 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/debug/stack_trace.h"
+
+#include <windows.h>
+#include <dbghelp.h>
+
+#include <iostream>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/memory/singleton.h"
+#include "base/process/launch.h"
+#include "base/strings/string_util.h"
+#include "base/synchronization/lock.h"
+#include "base/win/windows_version.h"
+
+namespace base {
+namespace debug {
+
+namespace {
+
+// Previous unhandled filter. Will be called if not NULL when we intercept an
+// exception. Only used in unit tests.
+LPTOP_LEVEL_EXCEPTION_FILTER g_previous_filter = NULL;
+
+// Prints the exception call stack.
+// This is the unit tests exception filter.
+long WINAPI StackDumpExceptionFilter(EXCEPTION_POINTERS* info) {
+  debug::StackTrace(info).Print();
+  if (g_previous_filter)
+    return g_previous_filter(info);
+  return EXCEPTION_CONTINUE_SEARCH;
+}
+
+FilePath GetExePath() {
+  wchar_t system_buffer[MAX_PATH];
+  GetModuleFileName(NULL, system_buffer, MAX_PATH);
+  system_buffer[MAX_PATH - 1] = L'\0';
+  return FilePath(system_buffer);
+}
+
+// SymbolContext is a threadsafe singleton that wraps the DbgHelp Sym* family
+// of functions.  The Sym* family of functions may only be invoked by one
+// thread at a time.  SymbolContext code may access a symbol server over the
+// network while holding the lock for this singleton.  In the case of high
+// latency, this code will adversely affect performance.
+//
+// There is also a known issue where this backtrace code can interact
+// badly with breakpad if breakpad is invoked in a separate thread while
+// we are using the Sym* functions.  This is because breakpad does now
+// share a lock with this function.  See this related bug:
+//
+//   http://code.google.com/p/google-breakpad/issues/detail?id=311
+//
+// This is a very unlikely edge case, and the current solution is to
+// just ignore it.
+class SymbolContext {
+ public:
+  static SymbolContext* GetInstance() {
+    // We use a leaky singleton because code may call this during process
+    // termination.
+    return
+      Singleton<SymbolContext, LeakySingletonTraits<SymbolContext> >::get();
+  }
+
+  // Returns the error code of a failed initialization.
+  DWORD init_error() const {
+    return init_error_;
+  }
+
+  // For the given trace, attempts to resolve the symbols, and output a trace
+  // to the ostream os.  The format for each line of the backtrace is:
+  //
+  //    <tab>SymbolName[0xAddress+Offset] (FileName:LineNo)
+  //
+  // This function should only be called if Init() has been called.  We do not
+  // LOG(FATAL) here because this code is called might be triggered by a
+  // LOG(FATAL) itself. Also, it should not be calling complex code that is
+  // extensible like PathService since that can in turn fire CHECKs.
+  void OutputTraceToStream(const void* const* trace,
+                           size_t count,
+                           std::ostream* os) {
+    base::AutoLock lock(lock_);
+
+    for (size_t i = 0; (i < count) && os->good(); ++i) {
+      const int kMaxNameLength = 256;
+      DWORD_PTR frame = reinterpret_cast<DWORD_PTR>(trace[i]);
+
+      // Code adapted from MSDN example:
+      // http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx
+      ULONG64 buffer[
+        (sizeof(SYMBOL_INFO) +
+          kMaxNameLength * sizeof(wchar_t) +
+          sizeof(ULONG64) - 1) /
+        sizeof(ULONG64)];
+      memset(buffer, 0, sizeof(buffer));
+
+      // Initialize symbol information retrieval structures.
+      DWORD64 sym_displacement = 0;
+      PSYMBOL_INFO symbol = reinterpret_cast<PSYMBOL_INFO>(&buffer[0]);
+      symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
+      symbol->MaxNameLen = kMaxNameLength - 1;
+      BOOL has_symbol = SymFromAddr(GetCurrentProcess(), frame,
+                                    &sym_displacement, symbol);
+
+      // Attempt to retrieve line number information.
+      DWORD line_displacement = 0;
+      IMAGEHLP_LINE64 line = {};
+      line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
+      BOOL has_line = SymGetLineFromAddr64(GetCurrentProcess(), frame,
+                                           &line_displacement, &line);
+
+      // Output the backtrace line.
+      (*os) << "\t";
+      if (has_symbol) {
+        (*os) << symbol->Name << " [0x" << trace[i] << "+"
+              << sym_displacement << "]";
+      } else {
+        // If there is no symbol information, add a spacer.
+        (*os) << "(No symbol) [0x" << trace[i] << "]";
+      }
+      if (has_line) {
+        (*os) << " (" << line.FileName << ":" << line.LineNumber << ")";
+      }
+      (*os) << "\n";
+    }
+  }
+
+ private:
+  friend struct DefaultSingletonTraits<SymbolContext>;
+
+  SymbolContext() : init_error_(ERROR_SUCCESS) {
+    // Initializes the symbols for the process.
+    // Defer symbol load until they're needed, use undecorated names, and
+    // get line numbers.
+    SymSetOptions(SYMOPT_DEFERRED_LOADS |
+                  SYMOPT_UNDNAME |
+                  SYMOPT_LOAD_LINES);
+    if (!SymInitialize(GetCurrentProcess(), NULL, TRUE)) {
+      init_error_ = GetLastError();
+      // TODO(awong): Handle error: SymInitialize can fail with
+      // ERROR_INVALID_PARAMETER.
+      // When it fails, we should not call debugbreak since it kills the current
+      // process (prevents future tests from running or kills the browser
+      // process).
+      DLOG(ERROR) << "SymInitialize failed: " << init_error_;
+      return;
+    }
+
+    init_error_ = ERROR_SUCCESS;
+
+    // When transferring the binaries e.g. between bots, path put
+    // into the executable will get off. To still retrieve symbols correctly,
+    // add the directory of the executable to symbol search path.
+    // All following errors are non-fatal.
+    const size_t kSymbolsArraySize = 1024;
+    scoped_ptr<wchar_t[]> symbols_path(new wchar_t[kSymbolsArraySize]);
+
+    // Note: The below function takes buffer size as number of characters,
+    // not number of bytes!
+    if (!SymGetSearchPathW(GetCurrentProcess(),
+                           symbols_path.get(),
+                           kSymbolsArraySize)) {
+      DLOG(WARNING) << "SymGetSearchPath failed: ";
+      return;
+    }
+
+    std::wstring new_path(std::wstring(symbols_path.get()) +
+                          L";" + GetExePath().DirName().value());
+    if (!SymSetSearchPathW(GetCurrentProcess(), new_path.c_str())) {
+      DLOG(WARNING) << "SymSetSearchPath failed.";
+      return;
+    }
+  }
+
+  DWORD init_error_;
+  base::Lock lock_;
+  DISALLOW_COPY_AND_ASSIGN(SymbolContext);
+};
+
+}  // namespace
+
+bool EnableInProcessStackDumping() {
+  // Add stack dumping support on exception on windows. Similar to OS_POSIX
+  // signal() handling in process_util_posix.cc.
+  g_previous_filter = SetUnhandledExceptionFilter(&StackDumpExceptionFilter);
+  RouteStdioToConsole();
+  return true;
+}
+
+// Disable optimizations for the StackTrace::StackTrace function. It is
+// important to disable at least frame pointer optimization ("y"), since
+// that breaks CaptureStackBackTrace() and prevents StackTrace from working
+// in Release builds (it may still be janky if other frames are using FPO,
+// but at least it will make it further).
+#if defined(COMPILER_MSVC)
+#pragma optimize("", off)
+#endif
+
+StackTrace::StackTrace() {
+  // When walking our own stack, use CaptureStackBackTrace().
+  count_ = CaptureStackBackTrace(0, arraysize(trace_), trace_, NULL);
+}
+
+#if defined(COMPILER_MSVC)
+#pragma optimize("", on)
+#endif
+
+StackTrace::StackTrace(const EXCEPTION_POINTERS* exception_pointers) {
+  // StackWalk64() may modify context record passed to it, so we will
+  // use a copy.
+  CONTEXT context_record = *exception_pointers->ContextRecord;
+  InitTrace(&context_record);
+}
+
+StackTrace::StackTrace(const CONTEXT* context) {
+  // StackWalk64() may modify context record passed to it, so we will
+  // use a copy.
+  CONTEXT context_record = *context;
+  InitTrace(&context_record);
+}
+
+void StackTrace::InitTrace(CONTEXT* context_record) {
+  // When walking an exception stack, we need to use StackWalk64().
+  count_ = 0;
+  // Initialize stack walking.
+  STACKFRAME64 stack_frame;
+  memset(&stack_frame, 0, sizeof(stack_frame));
+#if defined(_WIN64)
+  int machine_type = IMAGE_FILE_MACHINE_AMD64;
+  stack_frame.AddrPC.Offset = context_record->Rip;
+  stack_frame.AddrFrame.Offset = context_record->Rbp;
+  stack_frame.AddrStack.Offset = context_record->Rsp;
+#else
+  int machine_type = IMAGE_FILE_MACHINE_I386;
+  stack_frame.AddrPC.Offset = context_record->Eip;
+  stack_frame.AddrFrame.Offset = context_record->Ebp;
+  stack_frame.AddrStack.Offset = context_record->Esp;
+#endif
+  stack_frame.AddrPC.Mode = AddrModeFlat;
+  stack_frame.AddrFrame.Mode = AddrModeFlat;
+  stack_frame.AddrStack.Mode = AddrModeFlat;
+  while (StackWalk64(machine_type,
+                     GetCurrentProcess(),
+                     GetCurrentThread(),
+                     &stack_frame,
+                     context_record,
+                     NULL,
+                     &SymFunctionTableAccess64,
+                     &SymGetModuleBase64,
+                     NULL) &&
+         count_ < arraysize(trace_)) {
+    trace_[count_++] = reinterpret_cast<void*>(stack_frame.AddrPC.Offset);
+  }
+
+  for (size_t i = count_; i < arraysize(trace_); ++i)
+    trace_[i] = NULL;
+}
+
+void StackTrace::Print() const {
+  OutputToStream(&std::cerr);
+}
+
+void StackTrace::OutputToStream(std::ostream* os) const {
+  SymbolContext* context = SymbolContext::GetInstance();
+  DWORD error = context->init_error();
+  if (error != ERROR_SUCCESS) {
+    (*os) << "Error initializing symbols (" << error
+          << ").  Dumping unresolved backtrace:\n";
+    for (size_t i = 0; (i < count_) && os->good(); ++i) {
+      (*os) << "\t" << trace_[i] << "\n";
+    }
+  } else {
+    (*os) << "Backtrace:\n";
+    context->OutputTraceToStream(trace_, count_, os);
+  }
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/task_annotator.cc b/base/debug/task_annotator.cc
new file mode 100644
index 0000000..19df8cb
--- /dev/null
+++ b/base/debug/task_annotator.cc
@@ -0,0 +1,75 @@
+// 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.
+
+#include "base/debug/task_annotator.h"
+
+#include "base/debug/alias.h"
+#include "base/pending_task.h"
+#include "base/trace_event/trace_event.h"
+#include "base/tracked_objects.h"
+
+namespace base {
+namespace debug {
+
+TaskAnnotator::TaskAnnotator() {
+}
+
+TaskAnnotator::~TaskAnnotator() {
+}
+
+void TaskAnnotator::DidQueueTask(const char* queue_function,
+                                 const PendingTask& pending_task) {
+  TRACE_EVENT_FLOW_BEGIN0(TRACE_DISABLED_BY_DEFAULT("toplevel.flow"),
+                          queue_function,
+                          TRACE_ID_MANGLE(GetTaskTraceID(pending_task)));
+}
+
+void TaskAnnotator::RunTask(const char* queue_function,
+                            const char* run_function,
+                            const PendingTask& pending_task) {
+  tracked_objects::TaskStopwatch stopwatch;
+  stopwatch.Start();
+  tracked_objects::Duration queue_duration =
+      stopwatch.StartTime() - pending_task.EffectiveTimePosted();
+
+  TRACE_EVENT_FLOW_END1(TRACE_DISABLED_BY_DEFAULT("toplevel.flow"),
+                        queue_function,
+                        TRACE_ID_MANGLE(GetTaskTraceID(pending_task)),
+                        "queue_duration",
+                        queue_duration.InMilliseconds());
+
+  // When tracing memory for posted tasks it's more valuable to attribute the
+  // memory allocations to the source function than generically to the task
+  // runner.
+  TRACE_EVENT_WITH_MEMORY_TAG2(
+      "toplevel",
+      run_function,
+      pending_task.posted_from.function_name(),  // Name for memory tracking.
+      "src_file",
+      pending_task.posted_from.file_name(),
+      "src_func",
+      pending_task.posted_from.function_name());
+
+  // Before running the task, store the program counter where it was posted
+  // and deliberately alias it to ensure it is on the stack if the task
+  // crashes. Be careful not to assume that the variable itself will have the
+  // expected value when displayed by the optimizer in an optimized build.
+  // Look at a memory dump of the stack.
+  const void* program_counter = pending_task.posted_from.program_counter();
+  debug::Alias(&program_counter);
+
+  pending_task.task.Run();
+
+  stopwatch.Stop();
+  tracked_objects::ThreadData::TallyRunOnNamedThreadIfTracking(
+      pending_task, stopwatch);
+}
+
+uint64 TaskAnnotator::GetTaskTraceID(const PendingTask& task) const {
+  return (static_cast<uint64>(task.sequence_num) << 32) |
+         ((static_cast<uint64>(reinterpret_cast<intptr_t>(this)) << 32) >> 32);
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug/task_annotator.h b/base/debug/task_annotator.h
new file mode 100644
index 0000000..aa5f17b
--- /dev/null
+++ b/base/debug/task_annotator.h
@@ -0,0 +1,46 @@
+// 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.
+
+#ifndef BASE_DEBUG_TASK_ANNOTATOR_H_
+#define BASE_DEBUG_TASK_ANNOTATOR_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+struct PendingTask;
+namespace debug {
+
+// Implements common debug annotations for posted tasks. This includes data
+// such as task origins, queueing durations and memory usage.
+class BASE_EXPORT TaskAnnotator {
+ public:
+  TaskAnnotator();
+  ~TaskAnnotator();
+
+  // Called to indicate that a task has been queued to run in the future.
+  // |queue_function| is used as the trace flow event name.
+  void DidQueueTask(const char* queue_function,
+                    const PendingTask& pending_task);
+
+  // Run a previously queued task. |queue_function| should match what was
+  // passed into |DidQueueTask| for this task. |run_function| is used as the
+  // name for the trace event that surrounds the task's execution.
+  void RunTask(const char* queue_function,
+               const char* run_function,
+               const PendingTask& pending_task);
+
+ private:
+  // Creates a process-wide unique ID to represent this task in trace events.
+  // This will be mangled with a Process ID hash to reduce the likelyhood of
+  // colliding with TaskAnnotator pointers on other processes.
+  uint64 GetTaskTraceID(const PendingTask& task) const;
+
+  DISALLOW_COPY_AND_ASSIGN(TaskAnnotator);
+};
+
+}  // namespace debug
+}  // namespace base
+
+#endif  // BASE_DEBUG_TASK_ANNOTATOR_H_
diff --git a/base/debug/task_annotator_unittest.cc b/base/debug/task_annotator_unittest.cc
new file mode 100644
index 0000000..ddffc21
--- /dev/null
+++ b/base/debug/task_annotator_unittest.cc
@@ -0,0 +1,33 @@
+// 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.
+
+#include "base/debug/task_annotator.h"
+#include "base/bind.h"
+#include "base/pending_task.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace debug {
+namespace {
+
+void TestTask(int* result) {
+  *result = 123;
+}
+
+}  // namespace
+
+TEST(TaskAnnotatorTest, QueueAndRunTask) {
+  int result = 0;
+  PendingTask pending_task(FROM_HERE, Bind(&TestTask, &result));
+
+  TaskAnnotator annotator;
+  annotator.DidQueueTask("TaskAnnotatorTest::Queue", pending_task);
+  EXPECT_EQ(0, result);
+  annotator.RunTask(
+      "TaskAnnotatorTest::Queue", "TaskAnnotatorTest::Run", pending_task);
+  EXPECT_EQ(123, result);
+}
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/debug_message.cc b/base/debug_message.cc
new file mode 100644
index 0000000..10f441d
--- /dev/null
+++ b/base/debug_message.cc
@@ -0,0 +1,17 @@
+// Copyright (c) 2006-2008 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 <windows.h>
+
+// Display the command line. This program is designed to be called from
+// another process to display assertions. Since the other process has
+// complete control of our command line, we assume that it did *not*
+// add the program name as the first parameter. This allows us to just
+// show the command line directly as the message.
+int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
+                     LPSTR lpCmdLine, int nCmdShow) {
+  LPWSTR cmdline = GetCommandLineW();
+  MessageBox(NULL, cmdline, L"Kr\x00d8m", MB_TOPMOST);
+  return 0;
+}
diff --git a/base/deferred_sequenced_task_runner.cc b/base/deferred_sequenced_task_runner.cc
new file mode 100644
index 0000000..dc118f3
--- /dev/null
+++ b/base/deferred_sequenced_task_runner.cc
@@ -0,0 +1,100 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/deferred_sequenced_task_runner.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+
+namespace base {
+
+DeferredSequencedTaskRunner::DeferredTask::DeferredTask()
+    : is_non_nestable(false) {
+}
+
+DeferredSequencedTaskRunner::DeferredTask::~DeferredTask() {
+}
+
+DeferredSequencedTaskRunner::DeferredSequencedTaskRunner(
+    const scoped_refptr<SequencedTaskRunner>& target_task_runner)
+    : started_(false),
+      target_task_runner_(target_task_runner) {
+}
+
+DeferredSequencedTaskRunner::~DeferredSequencedTaskRunner() {
+}
+
+bool DeferredSequencedTaskRunner::PostDelayedTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay) {
+  AutoLock lock(lock_);
+  if (started_) {
+    DCHECK(deferred_tasks_queue_.empty());
+    return target_task_runner_->PostDelayedTask(from_here, task, delay);
+  }
+
+  QueueDeferredTask(from_here, task, delay, false /* is_non_nestable */);
+  return true;
+}
+
+bool DeferredSequencedTaskRunner::RunsTasksOnCurrentThread() const {
+  return target_task_runner_->RunsTasksOnCurrentThread();
+}
+
+bool DeferredSequencedTaskRunner::PostNonNestableDelayedTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay) {
+  AutoLock lock(lock_);
+  if (started_) {
+    DCHECK(deferred_tasks_queue_.empty());
+    return target_task_runner_->PostNonNestableDelayedTask(from_here,
+                                                           task,
+                                                           delay);
+  }
+  QueueDeferredTask(from_here, task, delay, true /* is_non_nestable */);
+  return true;
+}
+
+void DeferredSequencedTaskRunner::QueueDeferredTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay,
+    bool is_non_nestable) {
+  DeferredTask deferred_task;
+  deferred_task.posted_from = from_here;
+  deferred_task.task = task;
+  deferred_task.delay = delay;
+  deferred_task.is_non_nestable = is_non_nestable;
+  deferred_tasks_queue_.push_back(deferred_task);
+}
+
+
+void DeferredSequencedTaskRunner::Start() {
+  AutoLock lock(lock_);
+  DCHECK(!started_);
+  started_ = true;
+  for (std::vector<DeferredTask>::iterator i = deferred_tasks_queue_.begin();
+      i != deferred_tasks_queue_.end();
+      ++i) {
+    const DeferredTask& task = *i;
+    if (task.is_non_nestable) {
+      target_task_runner_->PostNonNestableDelayedTask(task.posted_from,
+                                                      task.task,
+                                                      task.delay);
+    } else {
+      target_task_runner_->PostDelayedTask(task.posted_from,
+                                           task.task,
+                                           task.delay);
+    }
+    // Replace the i-th element in the |deferred_tasks_queue_| with an empty
+    // |DelayedTask| to ensure that |task| is destroyed before the next task
+    // is posted.
+    *i = DeferredTask();
+  }
+  deferred_tasks_queue_.clear();
+}
+
+}  // namespace base
diff --git a/base/deferred_sequenced_task_runner.h b/base/deferred_sequenced_task_runner.h
new file mode 100644
index 0000000..110d988
--- /dev/null
+++ b/base/deferred_sequenced_task_runner.h
@@ -0,0 +1,78 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_DEFERRED_SEQUENCED_TASK_RUNNER_H_
+#define BASE_DEFERRED_SEQUENCED_TASK_RUNNER_H_
+
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "base/sequenced_task_runner.h"
+#include "base/synchronization/lock.h"
+#include "base/time/time.h"
+#include "base/tracked_objects.h"
+
+namespace base {
+
+// A DeferredSequencedTaskRunner is a subclass of SequencedTaskRunner that
+// queues up all requests until the first call to Start() is issued.
+class BASE_EXPORT DeferredSequencedTaskRunner : public SequencedTaskRunner {
+ public:
+  explicit DeferredSequencedTaskRunner(
+      const scoped_refptr<SequencedTaskRunner>& target_runner);
+
+  // TaskRunner implementation
+  bool PostDelayedTask(const tracked_objects::Location& from_here,
+                       const Closure& task,
+                       TimeDelta delay) override;
+  bool RunsTasksOnCurrentThread() const override;
+
+  // SequencedTaskRunner implementation
+  bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
+                                  const Closure& task,
+                                  TimeDelta delay) override;
+
+  // Start the execution - posts all queued tasks to the target executor. The
+  // deferred tasks are posted with their initial delay, meaning that the task
+  // execution delay is actually measured from Start.
+  // Fails when called a second time.
+  void Start();
+
+ private:
+  struct DeferredTask  {
+    DeferredTask();
+    ~DeferredTask();
+
+    tracked_objects::Location posted_from;
+    Closure task;
+    // The delay this task was initially posted with.
+    TimeDelta delay;
+    bool is_non_nestable;
+  };
+
+  ~DeferredSequencedTaskRunner() override;
+
+  // Creates a |Task| object and adds it to |deferred_tasks_queue_|.
+  void QueueDeferredTask(const tracked_objects::Location& from_here,
+                         const Closure& task,
+                         TimeDelta delay,
+                         bool is_non_nestable);
+
+  // // Protects |started_| and |deferred_tasks_queue_|.
+  mutable Lock lock_;
+
+  bool started_;
+  const scoped_refptr<SequencedTaskRunner> target_task_runner_;
+  std::vector<DeferredTask> deferred_tasks_queue_;
+
+  DISALLOW_COPY_AND_ASSIGN(DeferredSequencedTaskRunner);
+};
+
+}  // namespace base
+
+#endif  // BASE_DEFERRED_SEQUENCED_TASK_RUNNER_H_
diff --git a/base/deferred_sequenced_task_runner_unittest.cc b/base/deferred_sequenced_task_runner_unittest.cc
new file mode 100644
index 0000000..6e17ad9
--- /dev/null
+++ b/base/deferred_sequenced_task_runner_unittest.cc
@@ -0,0 +1,178 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/deferred_sequenced_task_runner.h"
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/location.h"
+#include "base/memory/ref_counted.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/non_thread_safe.h"
+#include "base/threading/thread.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class DeferredSequencedTaskRunnerTest : public testing::Test,
+                                        public base::NonThreadSafe {
+ public:
+  class ExecuteTaskOnDestructor :
+      public base::RefCounted<ExecuteTaskOnDestructor> {
+   public:
+    ExecuteTaskOnDestructor(
+        DeferredSequencedTaskRunnerTest* executor,
+        int task_id)
+        : executor_(executor),
+          task_id_(task_id) {
+    }
+  private:
+    friend class base::RefCounted<ExecuteTaskOnDestructor>;
+    virtual ~ExecuteTaskOnDestructor() {
+      executor_->ExecuteTask(task_id_);
+    }
+    DeferredSequencedTaskRunnerTest* executor_;
+    int task_id_;
+  };
+
+  void ExecuteTask(int task_id) {
+    base::AutoLock lock(lock_);
+    executed_task_ids_.push_back(task_id);
+  }
+
+  void PostExecuteTask(int task_id) {
+    runner_->PostTask(FROM_HERE,
+                      base::Bind(&DeferredSequencedTaskRunnerTest::ExecuteTask,
+                                 base::Unretained(this),
+                                 task_id));
+  }
+
+  void StartRunner() {
+    runner_->Start();
+  }
+
+  void DoNothing(ExecuteTaskOnDestructor* object) {
+  }
+
+ protected:
+  DeferredSequencedTaskRunnerTest()
+      : loop_(),
+        runner_(new base::DeferredSequencedTaskRunner(loop_.task_runner())) {}
+
+  base::MessageLoop loop_;
+  scoped_refptr<base::DeferredSequencedTaskRunner> runner_;
+  mutable base::Lock lock_;
+  std::vector<int> executed_task_ids_;
+};
+
+TEST_F(DeferredSequencedTaskRunnerTest, Stopped) {
+  PostExecuteTask(1);
+  loop_.RunUntilIdle();
+  EXPECT_THAT(executed_task_ids_, testing::ElementsAre());
+}
+
+TEST_F(DeferredSequencedTaskRunnerTest, Start) {
+  StartRunner();
+  PostExecuteTask(1);
+  loop_.RunUntilIdle();
+  EXPECT_THAT(executed_task_ids_, testing::ElementsAre(1));
+}
+
+TEST_F(DeferredSequencedTaskRunnerTest, StartWithMultipleElements) {
+  StartRunner();
+  for (int i = 1; i < 5; ++i)
+    PostExecuteTask(i);
+
+  loop_.RunUntilIdle();
+  EXPECT_THAT(executed_task_ids_, testing::ElementsAre(1, 2, 3, 4));
+}
+
+TEST_F(DeferredSequencedTaskRunnerTest, DeferredStart) {
+  PostExecuteTask(1);
+  loop_.RunUntilIdle();
+  EXPECT_THAT(executed_task_ids_, testing::ElementsAre());
+
+  StartRunner();
+  loop_.RunUntilIdle();
+  EXPECT_THAT(executed_task_ids_, testing::ElementsAre(1));
+
+  PostExecuteTask(2);
+  loop_.RunUntilIdle();
+  EXPECT_THAT(executed_task_ids_, testing::ElementsAre(1, 2));
+}
+
+TEST_F(DeferredSequencedTaskRunnerTest, DeferredStartWithMultipleElements) {
+  for (int i = 1; i < 5; ++i)
+    PostExecuteTask(i);
+  loop_.RunUntilIdle();
+  EXPECT_THAT(executed_task_ids_, testing::ElementsAre());
+
+  StartRunner();
+  for (int i = 5; i < 9; ++i)
+    PostExecuteTask(i);
+  loop_.RunUntilIdle();
+  EXPECT_THAT(executed_task_ids_, testing::ElementsAre(1, 2, 3, 4, 5, 6, 7, 8));
+}
+
+TEST_F(DeferredSequencedTaskRunnerTest, DeferredStartWithMultipleThreads) {
+  {
+    base::Thread thread1("DeferredSequencedTaskRunnerTestThread1");
+    base::Thread thread2("DeferredSequencedTaskRunnerTestThread2");
+    thread1.Start();
+    thread2.Start();
+    for (int i = 0; i < 5; ++i) {
+      thread1.task_runner()->PostTask(
+          FROM_HERE,
+          base::Bind(&DeferredSequencedTaskRunnerTest::PostExecuteTask,
+                     base::Unretained(this), 2 * i));
+      thread2.task_runner()->PostTask(
+          FROM_HERE,
+          base::Bind(&DeferredSequencedTaskRunnerTest::PostExecuteTask,
+                     base::Unretained(this), 2 * i + 1));
+      if (i == 2) {
+        thread1.task_runner()->PostTask(
+            FROM_HERE, base::Bind(&DeferredSequencedTaskRunnerTest::StartRunner,
+                                  base::Unretained(this)));
+      }
+    }
+  }
+
+  loop_.RunUntilIdle();
+  EXPECT_THAT(executed_task_ids_,
+      testing::WhenSorted(testing::ElementsAre(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)));
+}
+
+TEST_F(DeferredSequencedTaskRunnerTest, ObjectDestructionOrder) {
+  {
+    base::Thread thread("DeferredSequencedTaskRunnerTestThread");
+    thread.Start();
+    runner_ = new base::DeferredSequencedTaskRunner(thread.task_runner());
+    for (int i = 0; i < 5; ++i) {
+      {
+        // Use a block to ensure that no reference to |short_lived_object|
+        // is kept on the main thread after it is posted to |runner_|.
+        scoped_refptr<ExecuteTaskOnDestructor> short_lived_object =
+            new ExecuteTaskOnDestructor(this, 2 * i);
+        runner_->PostTask(
+            FROM_HERE,
+            base::Bind(&DeferredSequencedTaskRunnerTest::DoNothing,
+                       base::Unretained(this),
+                       short_lived_object));
+      }
+      // |short_lived_object| with id |2 * i| should be destroyed before the
+      // task |2 * i + 1| is executed.
+      PostExecuteTask(2 * i + 1);
+    }
+    StartRunner();
+  }
+
+  // All |short_lived_object| with id |2 * i| are destroyed before the task
+  // |2 * i + 1| is executed.
+  EXPECT_THAT(executed_task_ids_,
+              testing::ElementsAre(0, 1, 2, 3, 4, 5, 6, 7, 8, 9));
+}
+
+}  // namespace
diff --git a/base/environment.cc b/base/environment.cc
new file mode 100644
index 0000000..245051d
--- /dev/null
+++ b/base/environment.cc
@@ -0,0 +1,236 @@
+// Copyright (c) 2012 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/environment.h"
+
+#include <vector>
+
+#include "base/strings/string_piece.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+
+#if defined(OS_POSIX)
+#include <stdlib.h>
+#elif defined(OS_WIN)
+#include <windows.h>
+#endif
+
+namespace base {
+
+namespace {
+
+class EnvironmentImpl : public Environment {
+ public:
+  bool GetVar(const char* variable_name, std::string* result) override {
+    if (GetVarImpl(variable_name, result))
+      return true;
+
+    // Some commonly used variable names are uppercase while others
+    // are lowercase, which is inconsistent. Let's try to be helpful
+    // and look for a variable name with the reverse case.
+    // I.e. HTTP_PROXY may be http_proxy for some users/systems.
+    char first_char = variable_name[0];
+    std::string alternate_case_var;
+    if (first_char >= 'a' && first_char <= 'z')
+      alternate_case_var = StringToUpperASCII(std::string(variable_name));
+    else if (first_char >= 'A' && first_char <= 'Z')
+      alternate_case_var = StringToLowerASCII(std::string(variable_name));
+    else
+      return false;
+    return GetVarImpl(alternate_case_var.c_str(), result);
+  }
+
+  bool SetVar(const char* variable_name,
+              const std::string& new_value) override {
+    return SetVarImpl(variable_name, new_value);
+  }
+
+  bool UnSetVar(const char* variable_name) override {
+    return UnSetVarImpl(variable_name);
+  }
+
+ private:
+  bool GetVarImpl(const char* variable_name, std::string* result) {
+#if defined(OS_POSIX)
+    const char* env_value = getenv(variable_name);
+    if (!env_value)
+      return false;
+    // Note that the variable may be defined but empty.
+    if (result)
+      *result = env_value;
+    return true;
+#elif defined(OS_WIN)
+    DWORD value_length = ::GetEnvironmentVariable(
+        UTF8ToWide(variable_name).c_str(), NULL, 0);
+    if (value_length == 0)
+      return false;
+    if (result) {
+      scoped_ptr<wchar_t[]> value(new wchar_t[value_length]);
+      ::GetEnvironmentVariable(UTF8ToWide(variable_name).c_str(), value.get(),
+                               value_length);
+      *result = WideToUTF8(value.get());
+    }
+    return true;
+#else
+#error need to port
+#endif
+  }
+
+  bool SetVarImpl(const char* variable_name, const std::string& new_value) {
+#if defined(OS_POSIX)
+    // On success, zero is returned.
+    return !setenv(variable_name, new_value.c_str(), 1);
+#elif defined(OS_WIN)
+    // On success, a nonzero value is returned.
+    return !!SetEnvironmentVariable(UTF8ToWide(variable_name).c_str(),
+                                    UTF8ToWide(new_value).c_str());
+#endif
+  }
+
+  bool UnSetVarImpl(const char* variable_name) {
+#if defined(OS_POSIX)
+    // On success, zero is returned.
+    return !unsetenv(variable_name);
+#elif defined(OS_WIN)
+    // On success, a nonzero value is returned.
+    return !!SetEnvironmentVariable(UTF8ToWide(variable_name).c_str(), NULL);
+#endif
+  }
+};
+
+// Parses a null-terminated input string of an environment block. The key is
+// placed into the given string, and the total length of the line, including
+// the terminating null, is returned.
+size_t ParseEnvLine(const NativeEnvironmentString::value_type* input,
+                    NativeEnvironmentString* key) {
+  // Skip to the equals or end of the string, this is the key.
+  size_t cur = 0;
+  while (input[cur] && input[cur] != '=')
+    cur++;
+  *key = NativeEnvironmentString(&input[0], cur);
+
+  // Now just skip to the end of the string.
+  while (input[cur])
+    cur++;
+  return cur + 1;
+}
+
+}  // namespace
+
+namespace env_vars {
+
+#if defined(OS_POSIX)
+// On Posix systems, this variable contains the location of the user's home
+// directory. (e.g, /home/username/).
+const char kHome[] = "HOME";
+#endif
+
+}  // namespace env_vars
+
+Environment::~Environment() {}
+
+// static
+Environment* Environment::Create() {
+  return new EnvironmentImpl();
+}
+
+bool Environment::HasVar(const char* variable_name) {
+  return GetVar(variable_name, NULL);
+}
+
+#if defined(OS_WIN)
+
+string16 AlterEnvironment(const wchar_t* env,
+                          const EnvironmentMap& changes) {
+  string16 result;
+
+  // First copy all unmodified values to the output.
+  size_t cur_env = 0;
+  string16 key;
+  while (env[cur_env]) {
+    const wchar_t* line = &env[cur_env];
+    size_t line_length = ParseEnvLine(line, &key);
+
+    // Keep only values not specified in the change vector.
+    EnvironmentMap::const_iterator found_change = changes.find(key);
+    if (found_change == changes.end())
+      result.append(line, line_length);
+
+    cur_env += line_length;
+  }
+
+  // Now append all modified and new values.
+  for (EnvironmentMap::const_iterator i = changes.begin();
+       i != changes.end(); ++i) {
+    if (!i->second.empty()) {
+      result.append(i->first);
+      result.push_back('=');
+      result.append(i->second);
+      result.push_back(0);
+    }
+  }
+
+  // An additional null marks the end of the list. We always need a double-null
+  // in case nothing was added above.
+  if (result.empty())
+    result.push_back(0);
+  result.push_back(0);
+  return result;
+}
+
+#elif defined(OS_POSIX)
+
+scoped_ptr<char*[]> AlterEnvironment(const char* const* const env,
+                                     const EnvironmentMap& changes) {
+  std::string value_storage;  // Holds concatenated null-terminated strings.
+  std::vector<size_t> result_indices;  // Line indices into value_storage.
+
+  // First build up all of the unchanged environment strings. These are
+  // null-terminated of the form "key=value".
+  std::string key;
+  for (size_t i = 0; env[i]; i++) {
+    size_t line_length = ParseEnvLine(env[i], &key);
+
+    // Keep only values not specified in the change vector.
+    EnvironmentMap::const_iterator found_change = changes.find(key);
+    if (found_change == changes.end()) {
+      result_indices.push_back(value_storage.size());
+      value_storage.append(env[i], line_length);
+    }
+  }
+
+  // Now append all modified and new values.
+  for (EnvironmentMap::const_iterator i = changes.begin();
+       i != changes.end(); ++i) {
+    if (!i->second.empty()) {
+      result_indices.push_back(value_storage.size());
+      value_storage.append(i->first);
+      value_storage.push_back('=');
+      value_storage.append(i->second);
+      value_storage.push_back(0);
+    }
+  }
+
+  size_t pointer_count_required =
+      result_indices.size() + 1 +  // Null-terminated array of pointers.
+      (value_storage.size() + sizeof(char*) - 1) / sizeof(char*);  // Buffer.
+  scoped_ptr<char*[]> result(new char*[pointer_count_required]);
+
+  // The string storage goes after the array of pointers.
+  char* storage_data = reinterpret_cast<char*>(
+      &result.get()[result_indices.size() + 1]);
+  if (!value_storage.empty())
+    memcpy(storage_data, value_storage.data(), value_storage.size());
+
+  // Fill array of pointers at the beginning of the result.
+  for (size_t i = 0; i < result_indices.size(); i++)
+    result[i] = &storage_data[result_indices[i]];
+  result[result_indices.size()] = 0;  // Null terminator.
+
+  return result.Pass();
+}
+
+#endif  // OS_POSIX
+
+}  // namespace base
diff --git a/base/environment.h b/base/environment.h
new file mode 100644
index 0000000..c8811e2
--- /dev/null
+++ b/base/environment.h
@@ -0,0 +1,90 @@
+// Copyright (c) 2011 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_ENVIRONMENT_H_
+#define BASE_ENVIRONMENT_H_
+
+#include <map>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string16.h"
+#include "build/build_config.h"
+
+namespace base {
+
+namespace env_vars {
+
+#if defined(OS_POSIX)
+BASE_EXPORT extern const char kHome[];
+#endif
+
+}  // namespace env_vars
+
+class BASE_EXPORT Environment {
+ public:
+  virtual ~Environment();
+
+  // Static factory method that returns the implementation that provide the
+  // appropriate platform-specific instance.
+  static Environment* Create();
+
+  // Gets an environment variable's value and stores it in |result|.
+  // Returns false if the key is unset.
+  virtual bool GetVar(const char* variable_name, std::string* result) = 0;
+
+  // Syntactic sugar for GetVar(variable_name, NULL);
+  virtual bool HasVar(const char* variable_name);
+
+  // Returns true on success, otherwise returns false.
+  virtual bool SetVar(const char* variable_name,
+                      const std::string& new_value) = 0;
+
+  // Returns true on success, otherwise returns false.
+  virtual bool UnSetVar(const char* variable_name) = 0;
+};
+
+
+#if defined(OS_WIN)
+
+typedef string16 NativeEnvironmentString;
+typedef std::map<NativeEnvironmentString, NativeEnvironmentString>
+    EnvironmentMap;
+
+// Returns a modified environment vector constructed from the given environment
+// and the list of changes given in |changes|. Each key in the environment is
+// matched against the first element of the pairs. In the event of a match, the
+// value is replaced by the second of the pair, unless the second is empty, in
+// which case the key-value is removed.
+//
+// This Windows version takes and returns a Windows-style environment block
+// which is a concatenated list of null-terminated 16-bit strings. The end is
+// marked by a double-null terminator. The size of the returned string will
+// include the terminators.
+BASE_EXPORT string16 AlterEnvironment(const wchar_t* env,
+                                      const EnvironmentMap& changes);
+
+#elif defined(OS_POSIX)
+
+typedef std::string NativeEnvironmentString;
+typedef std::map<NativeEnvironmentString, NativeEnvironmentString>
+    EnvironmentMap;
+
+// See general comments for the Windows version above.
+//
+// This Posix version takes and returns a Posix-style environment block, which
+// is a null-terminated list of pointers to null-terminated strings. The
+// returned array will have appended to it the storage for the array itself so
+// there is only one pointer to manage, but this means that you can't copy the
+// array without keeping the original around.
+BASE_EXPORT scoped_ptr<char*[]> AlterEnvironment(
+    const char* const* env,
+    const EnvironmentMap& changes);
+
+#endif
+
+}  // namespace base
+
+#endif  // BASE_ENVIRONMENT_H_
diff --git a/base/environment_unittest.cc b/base/environment_unittest.cc
new file mode 100644
index 0000000..f0577a8
--- /dev/null
+++ b/base/environment_unittest.cc
@@ -0,0 +1,164 @@
+// Copyright (c) 2011 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/environment.h"
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+typedef PlatformTest EnvironmentTest;
+
+namespace base {
+
+TEST_F(EnvironmentTest, GetVar) {
+  // Every setup should have non-empty PATH...
+  scoped_ptr<Environment> env(Environment::Create());
+  std::string env_value;
+  EXPECT_TRUE(env->GetVar("PATH", &env_value));
+  EXPECT_NE(env_value, "");
+}
+
+TEST_F(EnvironmentTest, GetVarReverse) {
+  scoped_ptr<Environment> env(Environment::Create());
+  const char kFooUpper[] = "FOO";
+  const char kFooLower[] = "foo";
+
+  // Set a variable in UPPER case.
+  EXPECT_TRUE(env->SetVar(kFooUpper, kFooLower));
+
+  // And then try to get this variable passing the lower case.
+  std::string env_value;
+  EXPECT_TRUE(env->GetVar(kFooLower, &env_value));
+
+  EXPECT_STREQ(env_value.c_str(), kFooLower);
+
+  EXPECT_TRUE(env->UnSetVar(kFooUpper));
+
+  const char kBar[] = "bar";
+  // Now do the opposite, set the variable in the lower case.
+  EXPECT_TRUE(env->SetVar(kFooLower, kBar));
+
+  // And then try to get this variable passing the UPPER case.
+  EXPECT_TRUE(env->GetVar(kFooUpper, &env_value));
+
+  EXPECT_STREQ(env_value.c_str(), kBar);
+
+  EXPECT_TRUE(env->UnSetVar(kFooLower));
+}
+
+TEST_F(EnvironmentTest, HasVar) {
+  // Every setup should have PATH...
+  scoped_ptr<Environment> env(Environment::Create());
+  EXPECT_TRUE(env->HasVar("PATH"));
+}
+
+TEST_F(EnvironmentTest, SetVar) {
+  scoped_ptr<Environment> env(Environment::Create());
+
+  const char kFooUpper[] = "FOO";
+  const char kFooLower[] = "foo";
+  EXPECT_TRUE(env->SetVar(kFooUpper, kFooLower));
+
+  // Now verify that the environment has the new variable.
+  EXPECT_TRUE(env->HasVar(kFooUpper));
+
+  std::string var_value;
+  EXPECT_TRUE(env->GetVar(kFooUpper, &var_value));
+  EXPECT_EQ(var_value, kFooLower);
+}
+
+TEST_F(EnvironmentTest, UnSetVar) {
+  scoped_ptr<Environment> env(Environment::Create());
+
+  const char kFooUpper[] = "FOO";
+  const char kFooLower[] = "foo";
+  // First set some environment variable.
+  EXPECT_TRUE(env->SetVar(kFooUpper, kFooLower));
+
+  // Now verify that the environment has the new variable.
+  EXPECT_TRUE(env->HasVar(kFooUpper));
+
+  // Finally verify that the environment variable was erased.
+  EXPECT_TRUE(env->UnSetVar(kFooUpper));
+
+  // And check that the variable has been unset.
+  EXPECT_FALSE(env->HasVar(kFooUpper));
+}
+
+#if defined(OS_WIN)
+
+TEST_F(EnvironmentTest, AlterEnvironment) {
+  const wchar_t empty[] = L"\0";
+  const wchar_t a2[] = L"A=2\0";
+  EnvironmentMap changes;
+  string16 e;
+
+  e = AlterEnvironment(empty, changes);
+  EXPECT_EQ(0, e[0]);
+
+  changes[L"A"] = L"1";
+  e = AlterEnvironment(empty, changes);
+  EXPECT_EQ(string16(L"A=1\0\0", 5), e);
+
+  changes.clear();
+  changes[L"A"] = string16();
+  e = AlterEnvironment(empty, changes);
+  EXPECT_EQ(string16(L"\0\0", 2), e);
+
+  changes.clear();
+  e = AlterEnvironment(a2, changes);
+  EXPECT_EQ(string16(L"A=2\0\0", 5), e);
+
+  changes.clear();
+  changes[L"A"] = L"1";
+  e = AlterEnvironment(a2, changes);
+  EXPECT_EQ(string16(L"A=1\0\0", 5), e);
+
+  changes.clear();
+  changes[L"A"] = string16();
+  e = AlterEnvironment(a2, changes);
+  EXPECT_EQ(string16(L"\0\0", 2), e);
+}
+
+#else
+
+TEST_F(EnvironmentTest, AlterEnvironment) {
+  const char* const empty[] = { NULL };
+  const char* const a2[] = { "A=2", NULL };
+  EnvironmentMap changes;
+  scoped_ptr<char*[]> e;
+
+  e = AlterEnvironment(empty, changes).Pass();
+  EXPECT_TRUE(e[0] == NULL);
+
+  changes["A"] = "1";
+  e = AlterEnvironment(empty, changes);
+  EXPECT_EQ(std::string("A=1"), e[0]);
+  EXPECT_TRUE(e[1] == NULL);
+
+  changes.clear();
+  changes["A"] = std::string();
+  e = AlterEnvironment(empty, changes);
+  EXPECT_TRUE(e[0] == NULL);
+
+  changes.clear();
+  e = AlterEnvironment(a2, changes);
+  EXPECT_EQ(std::string("A=2"), e[0]);
+  EXPECT_TRUE(e[1] == NULL);
+
+  changes.clear();
+  changes["A"] = "1";
+  e = AlterEnvironment(a2, changes);
+  EXPECT_EQ(std::string("A=1"), e[0]);
+  EXPECT_TRUE(e[1] == NULL);
+
+  changes.clear();
+  changes["A"] = std::string();
+  e = AlterEnvironment(a2, changes);
+  EXPECT_TRUE(e[0] == NULL);
+}
+
+#endif
+
+}  // namespace base
diff --git a/base/event_types.h b/base/event_types.h
new file mode 100644
index 0000000..9905800
--- /dev/null
+++ b/base/event_types.h
@@ -0,0 +1,37 @@
+// Copyright (c) 2012 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_EVENT_TYPES_H_
+#define BASE_EVENT_TYPES_H_
+
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#elif defined(USE_X11)
+typedef union _XEvent XEvent;
+#elif defined(OS_MACOSX)
+#if defined(__OBJC__)
+@class NSEvent;
+#else  // __OBJC__
+class NSEvent;
+#endif // __OBJC__
+#endif
+
+namespace base {
+
+// Cross platform typedefs for native event types.
+#if defined(OS_WIN)
+typedef MSG NativeEvent;
+#elif defined(USE_X11)
+typedef XEvent* NativeEvent;
+#elif defined(OS_MACOSX)
+typedef NSEvent* NativeEvent;
+#else
+typedef void* NativeEvent;
+#endif
+
+} // namespace base
+
+#endif  // BASE_EVENT_TYPES_H_
diff --git a/base/file_descriptor_posix.h b/base/file_descriptor_posix.h
new file mode 100644
index 0000000..376ad39
--- /dev/null
+++ b/base/file_descriptor_posix.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2006-2009 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_FILE_DESCRIPTOR_POSIX_H_
+#define BASE_FILE_DESCRIPTOR_POSIX_H_
+
+#include "base/files/file.h"
+#include "base/files/scoped_file.h"
+
+namespace base {
+
+// -----------------------------------------------------------------------------
+// We introduct a special structure for file descriptors in order that we are
+// able to use template specialisation to special-case their handling.
+//
+// WARNING: (Chromium only) There are subtleties to consider if serialising
+// these objects over IPC. See comments in ipc/ipc_message_utils.h
+// above the template specialisation for this structure.
+// -----------------------------------------------------------------------------
+struct FileDescriptor {
+  FileDescriptor() : fd(-1), auto_close(false) {}
+
+  FileDescriptor(int ifd, bool iauto_close) : fd(ifd), auto_close(iauto_close) {
+  }
+
+  FileDescriptor(File file) : fd(file.TakePlatformFile()), auto_close(true) {}
+  explicit FileDescriptor(ScopedFD fd) : fd(fd.release()), auto_close(true) {}
+
+  bool operator==(const FileDescriptor& other) const {
+    return (fd == other.fd && auto_close == other.auto_close);
+  }
+
+  bool operator!=(const FileDescriptor& other) const {
+    return !operator==(other);
+  }
+
+  // A comparison operator so that we can use these as keys in a std::map.
+  bool operator<(const FileDescriptor& other) const {
+    return other.fd < fd;
+  }
+
+  int fd;
+  // If true, this file descriptor should be closed after it has been used. For
+  // example an IPC system might interpret this flag as indicating that the
+  // file descriptor it has been given should be closed after use.
+  bool auto_close;
+};
+
+}  // namespace base
+
+#endif  // BASE_FILE_DESCRIPTOR_POSIX_H_
diff --git a/base/file_version_info.h b/base/file_version_info.h
new file mode 100644
index 0000000..57b837c
--- /dev/null
+++ b/base/file_version_info.h
@@ -0,0 +1,86 @@
+// Copyright (c) 2011 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_FILE_VERSION_INFO_H_
+#define BASE_FILE_VERSION_INFO_H_
+
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+// http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx
+extern "C" IMAGE_DOS_HEADER __ImageBase;
+#endif  // OS_WIN
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/strings/string16.h"
+
+namespace base {
+class FilePath;
+}
+
+// Provides an interface for accessing the version information for a file. This
+// is the information you access when you select a file in the Windows Explorer,
+// right-click select Properties, then click the Version tab, and on the Mac
+// when you select a file in the Finder and do a Get Info.
+//
+// This list of properties is straight out of Win32's VerQueryValue
+// <http://msdn.microsoft.com/en-us/library/ms647464.aspx> and the Mac
+// version returns values from the Info.plist as appropriate. TODO(avi): make
+// this a less-obvious Windows-ism.
+
+class BASE_EXPORT FileVersionInfo {
+ public:
+  virtual ~FileVersionInfo() {}
+#if defined(OS_WIN) || defined(OS_MACOSX)
+  // Creates a FileVersionInfo for the specified path. Returns NULL if something
+  // goes wrong (typically the file does not exit or cannot be opened). The
+  // returned object should be deleted when you are done with it.
+  static FileVersionInfo* CreateFileVersionInfo(
+      const base::FilePath& file_path);
+#endif  // OS_WIN || OS_MACOSX
+
+#if defined(OS_WIN)
+  // Creates a FileVersionInfo for the specified module. Returns NULL in case
+  // of error. The returned object should be deleted when you are done with it.
+  static FileVersionInfo* CreateFileVersionInfoForModule(HMODULE module);
+
+  // Creates a FileVersionInfo for the current module. Returns NULL in case
+  // of error. The returned object should be deleted when you are done with it.
+  // This function should be inlined so that the "current module" is evaluated
+  // correctly, instead of being the module that contains base.
+  __forceinline static FileVersionInfo*
+  CreateFileVersionInfoForCurrentModule() {
+    HMODULE module = reinterpret_cast<HMODULE>(&__ImageBase);
+    return CreateFileVersionInfoForModule(module);
+  }
+#else
+  // Creates a FileVersionInfo for the current module. Returns NULL in case
+  // of error. The returned object should be deleted when you are done with it.
+  static FileVersionInfo* CreateFileVersionInfoForCurrentModule();
+#endif  // OS_WIN
+
+  // Accessors to the different version properties.
+  // Returns an empty string if the property is not found.
+  virtual base::string16 company_name() = 0;
+  virtual base::string16 company_short_name() = 0;
+  virtual base::string16 product_name() = 0;
+  virtual base::string16 product_short_name() = 0;
+  virtual base::string16 internal_name() = 0;
+  virtual base::string16 product_version() = 0;
+  virtual base::string16 private_build() = 0;
+  virtual base::string16 special_build() = 0;
+  virtual base::string16 comments() = 0;
+  virtual base::string16 original_filename() = 0;
+  virtual base::string16 file_description() = 0;
+  virtual base::string16 file_version() = 0;
+  virtual base::string16 legal_copyright() = 0;
+  virtual base::string16 legal_trademarks() = 0;
+  virtual base::string16 last_change() = 0;
+  virtual bool is_official_build() = 0;
+};
+
+#endif  // BASE_FILE_VERSION_INFO_H_
diff --git a/base/file_version_info_mac.h b/base/file_version_info_mac.h
new file mode 100644
index 0000000..e677838
--- /dev/null
+++ b/base/file_version_info_mac.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2011 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_FILE_VERSION_INFO_MAC_H_
+#define BASE_FILE_VERSION_INFO_MAC_H_
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <string>
+
+#include "base/file_version_info.h"
+#include "base/mac/scoped_nsobject.h"
+
+@class NSBundle;
+
+class FileVersionInfoMac : public FileVersionInfo {
+ public:
+  explicit FileVersionInfoMac(NSBundle *bundle);
+  ~FileVersionInfoMac() override;
+
+  // Accessors to the different version properties.
+  // Returns an empty string if the property is not found.
+  base::string16 company_name() override;
+  base::string16 company_short_name() override;
+  base::string16 product_name() override;
+  base::string16 product_short_name() override;
+  base::string16 internal_name() override;
+  base::string16 product_version() override;
+  base::string16 private_build() override;
+  base::string16 special_build() override;
+  base::string16 comments() override;
+  base::string16 original_filename() override;
+  base::string16 file_description() override;
+  base::string16 file_version() override;
+  base::string16 legal_copyright() override;
+  base::string16 legal_trademarks() override;
+  base::string16 last_change() override;
+  bool is_official_build() override;
+
+ private:
+  // Returns a base::string16 value for a property name.
+  // Returns the empty string if the property does not exist.
+  base::string16 GetString16Value(CFStringRef name);
+
+  base::scoped_nsobject<NSBundle> bundle_;
+
+  DISALLOW_COPY_AND_ASSIGN(FileVersionInfoMac);
+};
+
+#endif  // BASE_FILE_VERSION_INFO_MAC_H_
diff --git a/base/file_version_info_mac.mm b/base/file_version_info_mac.mm
new file mode 100644
index 0000000..8542b19
--- /dev/null
+++ b/base/file_version_info_mac.mm
@@ -0,0 +1,123 @@
+// Copyright (c) 2012 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/file_version_info_mac.h"
+
+#import <Foundation/Foundation.h>
+
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/mac/bundle_locations.h"
+#include "base/mac/foundation_util.h"
+#include "base/strings/sys_string_conversions.h"
+
+FileVersionInfoMac::FileVersionInfoMac(NSBundle *bundle)
+    : bundle_([bundle retain]) {
+}
+
+FileVersionInfoMac::~FileVersionInfoMac() {}
+
+// static
+FileVersionInfo* FileVersionInfo::CreateFileVersionInfoForCurrentModule() {
+  return CreateFileVersionInfo(base::mac::FrameworkBundlePath());
+}
+
+// static
+FileVersionInfo* FileVersionInfo::CreateFileVersionInfo(
+    const base::FilePath& file_path) {
+  NSString* path = base::SysUTF8ToNSString(file_path.value());
+  NSBundle* bundle = [NSBundle bundleWithPath:path];
+  return new FileVersionInfoMac(bundle);
+}
+
+base::string16 FileVersionInfoMac::company_name() {
+  return base::string16();
+}
+
+base::string16 FileVersionInfoMac::company_short_name() {
+  return base::string16();
+}
+
+base::string16 FileVersionInfoMac::internal_name() {
+  return base::string16();
+}
+
+base::string16 FileVersionInfoMac::product_name() {
+  return GetString16Value(kCFBundleNameKey);
+}
+
+base::string16 FileVersionInfoMac::product_short_name() {
+  return GetString16Value(kCFBundleNameKey);
+}
+
+base::string16 FileVersionInfoMac::comments() {
+  return base::string16();
+}
+
+base::string16 FileVersionInfoMac::legal_copyright() {
+  return GetString16Value(CFSTR("CFBundleGetInfoString"));
+}
+
+base::string16 FileVersionInfoMac::product_version() {
+  // On OS X, CFBundleVersion is used by LaunchServices, and must follow
+  // specific formatting rules, so the four-part Chrome version is in
+  // CFBundleShortVersionString. On iOS, both have a policy-enfoced limit
+  // of three version components, so the full version is stored in a custom
+  // key (CrBundleVersion) falling back to CFBundleVersion if not present.
+#if defined(OS_IOS)
+  base::string16 version(GetString16Value(CFSTR("CrBundleVersion")));
+  if (version.length() > 0)
+    return version;
+  return GetString16Value(CFSTR("CFBundleVersion"));
+#else
+  return GetString16Value(CFSTR("CFBundleShortVersionString"));
+#endif  // defined(OS_IOS)
+}
+
+base::string16 FileVersionInfoMac::file_description() {
+  return base::string16();
+}
+
+base::string16 FileVersionInfoMac::legal_trademarks() {
+  return base::string16();
+}
+
+base::string16 FileVersionInfoMac::private_build() {
+  return base::string16();
+}
+
+base::string16 FileVersionInfoMac::file_version() {
+  return product_version();
+}
+
+base::string16 FileVersionInfoMac::original_filename() {
+  return GetString16Value(kCFBundleNameKey);
+}
+
+base::string16 FileVersionInfoMac::special_build() {
+  return base::string16();
+}
+
+base::string16 FileVersionInfoMac::last_change() {
+  return GetString16Value(CFSTR("SCMRevision"));
+}
+
+bool FileVersionInfoMac::is_official_build() {
+#if defined (GOOGLE_CHROME_BUILD)
+  return true;
+#else
+  return false;
+#endif
+}
+
+base::string16 FileVersionInfoMac::GetString16Value(CFStringRef name) {
+  if (bundle_) {
+    NSString *ns_name = base::mac::CFToNSCast(name);
+    NSString* value = [bundle_ objectForInfoDictionaryKey:ns_name];
+    if (value) {
+      return base::SysNSStringToUTF16(value);
+    }
+  }
+  return base::string16();
+}
diff --git a/base/file_version_info_unittest.cc b/base/file_version_info_unittest.cc
new file mode 100644
index 0000000..9b10d04
--- /dev/null
+++ b/base/file_version_info_unittest.cc
@@ -0,0 +1,141 @@
+// Copyright (c) 2011 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/file_version_info.h"
+#include "base/files/file_path.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/path_service.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_WIN)
+#include "base/file_version_info_win.h"
+#endif
+
+using base::FilePath;
+
+namespace {
+
+#if defined(OS_WIN)
+FilePath GetTestDataPath() {
+  FilePath path;
+  PathService::Get(base::DIR_SOURCE_ROOT, &path);
+  path = path.AppendASCII("base");
+  path = path.AppendASCII("test");
+  path = path.AppendASCII("data");
+  path = path.AppendASCII("file_version_info_unittest");
+  return path;
+}
+#endif
+
+}  // namespace
+
+#if defined(OS_WIN)
+TEST(FileVersionInfoTest, HardCodedProperties) {
+  const wchar_t* kDLLNames[] = {
+    L"FileVersionInfoTest1.dll"
+  };
+
+  const wchar_t* kExpectedValues[1][15] = {
+      // FileVersionInfoTest.dll
+      L"Goooooogle",                      // company_name
+      L"Google",                          // company_short_name
+      L"This is the product name",        // product_name
+      L"This is the product short name",  // product_short_name
+      L"The Internal Name",               // internal_name
+      L"4.3.2.1",                         // product_version
+      L"Private build property",          // private_build
+      L"Special build property",          // special_build
+      L"This is a particularly interesting comment",  // comments
+      L"This is the original filename",   // original_filename
+      L"This is my file description",     // file_description
+      L"1.2.3.4",                         // file_version
+      L"This is the legal copyright",     // legal_copyright
+      L"This is the legal trademarks",    // legal_trademarks
+      L"This is the last change",         // last_change
+  };
+
+  for (int i = 0; i < arraysize(kDLLNames); ++i) {
+    FilePath dll_path = GetTestDataPath();
+    dll_path = dll_path.Append(kDLLNames[i]);
+
+    scoped_ptr<FileVersionInfo> version_info(
+        FileVersionInfo::CreateFileVersionInfo(dll_path));
+
+    int j = 0;
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->company_name());
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->company_short_name());
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->product_name());
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->product_short_name());
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->internal_name());
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->product_version());
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->private_build());
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->special_build());
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->comments());
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->original_filename());
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->file_description());
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->file_version());
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->legal_copyright());
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->legal_trademarks());
+    EXPECT_EQ(kExpectedValues[i][j++], version_info->last_change());
+  }
+}
+#endif
+
+#if defined(OS_WIN)
+TEST(FileVersionInfoTest, IsOfficialBuild) {
+  const wchar_t* kDLLNames[] = {
+    L"FileVersionInfoTest1.dll",
+    L"FileVersionInfoTest2.dll"
+  };
+
+  const bool kExpected[] = {
+    true,
+    false,
+  };
+
+  // Test consistency check.
+  ASSERT_EQ(arraysize(kDLLNames), arraysize(kExpected));
+
+  for (int i = 0; i < arraysize(kDLLNames); ++i) {
+    FilePath dll_path = GetTestDataPath();
+    dll_path = dll_path.Append(kDLLNames[i]);
+
+    scoped_ptr<FileVersionInfo> version_info(
+        FileVersionInfo::CreateFileVersionInfo(dll_path));
+
+    EXPECT_EQ(kExpected[i], version_info->is_official_build());
+  }
+}
+#endif
+
+#if defined(OS_WIN)
+TEST(FileVersionInfoTest, CustomProperties) {
+  FilePath dll_path = GetTestDataPath();
+  dll_path = dll_path.AppendASCII("FileVersionInfoTest1.dll");
+
+  scoped_ptr<FileVersionInfo> version_info(
+      FileVersionInfo::CreateFileVersionInfo(dll_path));
+
+  // Test few existing properties.
+  std::wstring str;
+  FileVersionInfoWin* version_info_win =
+      static_cast<FileVersionInfoWin*>(version_info.get());
+  EXPECT_TRUE(version_info_win->GetValue(L"Custom prop 1",  &str));
+  EXPECT_EQ(L"Un", str);
+  EXPECT_EQ(L"Un", version_info_win->GetStringValue(L"Custom prop 1"));
+
+  EXPECT_TRUE(version_info_win->GetValue(L"Custom prop 2",  &str));
+  EXPECT_EQ(L"Deux", str);
+  EXPECT_EQ(L"Deux", version_info_win->GetStringValue(L"Custom prop 2"));
+
+  EXPECT_TRUE(version_info_win->GetValue(L"Custom prop 3",  &str));
+  EXPECT_EQ(L"1600 Amphitheatre Parkway Mountain View, CA 94043", str);
+  EXPECT_EQ(L"1600 Amphitheatre Parkway Mountain View, CA 94043",
+            version_info_win->GetStringValue(L"Custom prop 3"));
+
+  // Test an non-existing property.
+  EXPECT_FALSE(version_info_win->GetValue(L"Unknown property",  &str));
+  EXPECT_EQ(L"", version_info_win->GetStringValue(L"Unknown property"));
+}
+#endif
diff --git a/base/file_version_info_win.cc b/base/file_version_info_win.cc
new file mode 100644
index 0000000..ca3e4b1
--- /dev/null
+++ b/base/file_version_info_win.cc
@@ -0,0 +1,190 @@
+// Copyright (c) 2011 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/file_version_info_win.h"
+
+#include <windows.h>
+
+#include "base/file_version_info.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/threading/thread_restrictions.h"
+
+using base::FilePath;
+
+FileVersionInfoWin::FileVersionInfoWin(void* data,
+                                       WORD language,
+                                       WORD code_page)
+    : language_(language), code_page_(code_page) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  data_.reset((char*) data);
+  fixed_file_info_ = NULL;
+  UINT size;
+  ::VerQueryValue(data_.get(), L"\\", (LPVOID*)&fixed_file_info_, &size);
+}
+
+FileVersionInfoWin::~FileVersionInfoWin() {
+  DCHECK(data_.get());
+}
+
+typedef struct {
+  WORD language;
+  WORD code_page;
+} LanguageAndCodePage;
+
+// static
+FileVersionInfo* FileVersionInfo::CreateFileVersionInfoForModule(
+    HMODULE module) {
+  // Note that the use of MAX_PATH is basically in line with what we do for
+  // all registered paths (PathProviderWin).
+  wchar_t system_buffer[MAX_PATH];
+  system_buffer[0] = 0;
+  if (!GetModuleFileName(module, system_buffer, MAX_PATH))
+    return NULL;
+
+  FilePath app_path(system_buffer);
+  return CreateFileVersionInfo(app_path);
+}
+
+// static
+FileVersionInfo* FileVersionInfo::CreateFileVersionInfo(
+    const FilePath& file_path) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  DWORD dummy;
+  const wchar_t* path = file_path.value().c_str();
+  DWORD length = ::GetFileVersionInfoSize(path, &dummy);
+  if (length == 0)
+    return NULL;
+
+  void* data = calloc(length, 1);
+  if (!data)
+    return NULL;
+
+  if (!::GetFileVersionInfo(path, dummy, length, data)) {
+    free(data);
+    return NULL;
+  }
+
+  LanguageAndCodePage* translate = NULL;
+  uint32 page_count;
+  BOOL query_result = VerQueryValue(data, L"\\VarFileInfo\\Translation",
+                                   (void**) &translate, &page_count);
+
+  if (query_result && translate) {
+    return new FileVersionInfoWin(data, translate->language,
+                                  translate->code_page);
+
+  } else {
+    free(data);
+    return NULL;
+  }
+}
+
+base::string16 FileVersionInfoWin::company_name() {
+  return GetStringValue(L"CompanyName");
+}
+
+base::string16 FileVersionInfoWin::company_short_name() {
+  return GetStringValue(L"CompanyShortName");
+}
+
+base::string16 FileVersionInfoWin::internal_name() {
+  return GetStringValue(L"InternalName");
+}
+
+base::string16 FileVersionInfoWin::product_name() {
+  return GetStringValue(L"ProductName");
+}
+
+base::string16 FileVersionInfoWin::product_short_name() {
+  return GetStringValue(L"ProductShortName");
+}
+
+base::string16 FileVersionInfoWin::comments() {
+  return GetStringValue(L"Comments");
+}
+
+base::string16 FileVersionInfoWin::legal_copyright() {
+  return GetStringValue(L"LegalCopyright");
+}
+
+base::string16 FileVersionInfoWin::product_version() {
+  return GetStringValue(L"ProductVersion");
+}
+
+base::string16 FileVersionInfoWin::file_description() {
+  return GetStringValue(L"FileDescription");
+}
+
+base::string16 FileVersionInfoWin::legal_trademarks() {
+  return GetStringValue(L"LegalTrademarks");
+}
+
+base::string16 FileVersionInfoWin::private_build() {
+  return GetStringValue(L"PrivateBuild");
+}
+
+base::string16 FileVersionInfoWin::file_version() {
+  return GetStringValue(L"FileVersion");
+}
+
+base::string16 FileVersionInfoWin::original_filename() {
+  return GetStringValue(L"OriginalFilename");
+}
+
+base::string16 FileVersionInfoWin::special_build() {
+  return GetStringValue(L"SpecialBuild");
+}
+
+base::string16 FileVersionInfoWin::last_change() {
+  return GetStringValue(L"LastChange");
+}
+
+bool FileVersionInfoWin::is_official_build() {
+  return (GetStringValue(L"Official Build").compare(L"1") == 0);
+}
+
+bool FileVersionInfoWin::GetValue(const wchar_t* name,
+                                  std::wstring* value_str) {
+  WORD lang_codepage[8];
+  int i = 0;
+  // Use the language and codepage from the DLL.
+  lang_codepage[i++] = language_;
+  lang_codepage[i++] = code_page_;
+  // Use the default language and codepage from the DLL.
+  lang_codepage[i++] = ::GetUserDefaultLangID();
+  lang_codepage[i++] = code_page_;
+  // Use the language from the DLL and Latin codepage (most common).
+  lang_codepage[i++] = language_;
+  lang_codepage[i++] = 1252;
+  // Use the default language and Latin codepage (most common).
+  lang_codepage[i++] = ::GetUserDefaultLangID();
+  lang_codepage[i++] = 1252;
+
+  i = 0;
+  while (i < arraysize(lang_codepage)) {
+    wchar_t sub_block[MAX_PATH];
+    WORD language = lang_codepage[i++];
+    WORD code_page = lang_codepage[i++];
+    _snwprintf_s(sub_block, MAX_PATH, MAX_PATH,
+                 L"\\StringFileInfo\\%04x%04x\\%ls", language, code_page, name);
+    LPVOID value = NULL;
+    uint32 size;
+    BOOL r = ::VerQueryValue(data_.get(), sub_block, &value, &size);
+    if (r && value) {
+      value_str->assign(static_cast<wchar_t*>(value));
+      return true;
+    }
+  }
+  return false;
+}
+
+std::wstring FileVersionInfoWin::GetStringValue(const wchar_t* name) {
+  std::wstring str;
+  if (GetValue(name, &str))
+    return str;
+  else
+    return L"";
+}
diff --git a/base/file_version_info_win.h b/base/file_version_info_win.h
new file mode 100644
index 0000000..09d8d37
--- /dev/null
+++ b/base/file_version_info_win.h
@@ -0,0 +1,62 @@
+// Copyright (c) 2011 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_FILE_VERSION_INFO_WIN_H_
+#define BASE_FILE_VERSION_INFO_WIN_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/file_version_info.h"
+#include "base/memory/scoped_ptr.h"
+
+struct tagVS_FIXEDFILEINFO;
+typedef tagVS_FIXEDFILEINFO VS_FIXEDFILEINFO;
+
+class BASE_EXPORT FileVersionInfoWin : public FileVersionInfo {
+ public:
+  FileVersionInfoWin(void* data, WORD language, WORD code_page);
+  ~FileVersionInfoWin() override;
+
+  // Accessors to the different version properties.
+  // Returns an empty string if the property is not found.
+  base::string16 company_name() override;
+  base::string16 company_short_name() override;
+  base::string16 product_name() override;
+  base::string16 product_short_name() override;
+  base::string16 internal_name() override;
+  base::string16 product_version() override;
+  base::string16 private_build() override;
+  base::string16 special_build() override;
+  base::string16 comments() override;
+  base::string16 original_filename() override;
+  base::string16 file_description() override;
+  base::string16 file_version() override;
+  base::string16 legal_copyright() override;
+  base::string16 legal_trademarks() override;
+  base::string16 last_change() override;
+  bool is_official_build() override;
+
+  // Lets you access other properties not covered above.
+  bool GetValue(const wchar_t* name, std::wstring* value);
+
+  // Similar to GetValue but returns a wstring (empty string if the property
+  // does not exist).
+  std::wstring GetStringValue(const wchar_t* name);
+
+  // Get the fixed file info if it exists. Otherwise NULL
+  VS_FIXEDFILEINFO* fixed_file_info() { return fixed_file_info_; }
+
+ private:
+  scoped_ptr<char, base::FreeDeleter> data_;
+  WORD language_;
+  WORD code_page_;
+  // This is a pointer into the data_ if it exists. Otherwise NULL.
+  VS_FIXEDFILEINFO* fixed_file_info_;
+
+  DISALLOW_COPY_AND_ASSIGN(FileVersionInfoWin);
+};
+
+#endif  // BASE_FILE_VERSION_INFO_WIN_H_
diff --git a/base/files/OWNERS b/base/files/OWNERS
new file mode 100644
index 0000000..b99e8a2
--- /dev/null
+++ b/base/files/OWNERS
@@ -0,0 +1,3 @@
+rvargas@chromium.org
+
+per-file file_path_watcher*=mnissler@chromium.org
diff --git a/base/files/dir_reader_fallback.h b/base/files/dir_reader_fallback.h
new file mode 100644
index 0000000..a435f25
--- /dev/null
+++ b/base/files/dir_reader_fallback.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2012 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_FILES_DIR_READER_FALLBACK_H_
+#define BASE_FILES_DIR_READER_FALLBACK_H_
+
+namespace base {
+
+class DirReaderFallback {
+ public:
+  // Open a directory. If |IsValid| is true, then |Next| can be called to start
+  // the iteration at the beginning of the directory.
+  explicit DirReaderFallback(const char* directory_path) {}
+
+  // After construction, IsValid returns true iff the directory was
+  // successfully opened.
+  bool IsValid() const { return false; }
+
+  // Move to the next entry returning false if the iteration is complete.
+  bool Next() { return false; }
+
+  // Return the name of the current directory entry.
+  const char* name() { return 0;}
+
+  // Return the file descriptor which is being used.
+  int fd() const { return -1; }
+
+  // Returns true if this is a no-op fallback class (for testing).
+  static bool IsFallback() { return true; }
+};
+
+}  // namespace base
+
+#endif  // BASE_FILES_DIR_READER_FALLBACK_H_
diff --git a/base/files/dir_reader_linux.h b/base/files/dir_reader_linux.h
new file mode 100644
index 0000000..abf2595
--- /dev/null
+++ b/base/files/dir_reader_linux.h
@@ -0,0 +1,98 @@
+// Copyright (c) 2012 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_FILES_DIR_READER_LINUX_H_
+#define BASE_FILES_DIR_READER_LINUX_H_
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+
+// See the comments in dir_reader_posix.h about this.
+
+namespace base {
+
+struct linux_dirent {
+  uint64_t        d_ino;
+  int64_t         d_off;
+  unsigned short  d_reclen;
+  unsigned char   d_type;
+  char            d_name[0];
+};
+
+class DirReaderLinux {
+ public:
+  explicit DirReaderLinux(const char* directory_path)
+      : fd_(open(directory_path, O_RDONLY | O_DIRECTORY)),
+        offset_(0),
+        size_(0) {
+    memset(buf_, 0, sizeof(buf_));
+  }
+
+  ~DirReaderLinux() {
+    if (fd_ >= 0) {
+      if (IGNORE_EINTR(close(fd_)))
+        RAW_LOG(ERROR, "Failed to close directory handle");
+    }
+  }
+
+  bool IsValid() const {
+    return fd_ >= 0;
+  }
+
+  // Move to the next entry returning false if the iteration is complete.
+  bool Next() {
+    if (size_) {
+      linux_dirent* dirent = reinterpret_cast<linux_dirent*>(&buf_[offset_]);
+      offset_ += dirent->d_reclen;
+    }
+
+    if (offset_ != size_)
+      return true;
+
+    const int r = syscall(__NR_getdents64, fd_, buf_, sizeof(buf_));
+    if (r == 0)
+      return false;
+    if (r == -1) {
+      DPLOG(FATAL) << "getdents64 returned an error: " << errno;
+      return false;
+    }
+    size_ = r;
+    offset_ = 0;
+    return true;
+  }
+
+  const char* name() const {
+    if (!size_)
+      return NULL;
+
+    const linux_dirent* dirent =
+        reinterpret_cast<const linux_dirent*>(&buf_[offset_]);
+    return dirent->d_name;
+  }
+
+  int fd() const {
+    return fd_;
+  }
+
+  static bool IsFallback() {
+    return false;
+  }
+
+ private:
+  const int fd_;
+  unsigned char buf_[512];
+  size_t offset_, size_;
+
+  DISALLOW_COPY_AND_ASSIGN(DirReaderLinux);
+};
+
+}  // namespace base
+
+#endif  // BASE_FILES_DIR_READER_LINUX_H_
diff --git a/base/files/dir_reader_posix.h b/base/files/dir_reader_posix.h
new file mode 100644
index 0000000..6a32d9f
--- /dev/null
+++ b/base/files/dir_reader_posix.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2012 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_FILES_DIR_READER_POSIX_H_
+#define BASE_FILES_DIR_READER_POSIX_H_
+
+#include "build/build_config.h"
+
+// This header provides a class, DirReaderPosix, which allows one to open and
+// read from directories without allocating memory. For the interface, see
+// the generic fallback in dir_reader_fallback.h.
+
+// Mac note: OS X has getdirentries, but it only works if we restrict Chrome to
+// 32-bit inodes. There is a getdirentries64 syscall in 10.6, but it's not
+// wrapped and the direct syscall interface is unstable. Using an unstable API
+// seems worse than falling back to enumerating all file descriptors so we will
+// probably never implement this on the Mac.
+
+#if defined(OS_LINUX)
+#include "base/files/dir_reader_linux.h"
+#else
+#include "base/files/dir_reader_fallback.h"
+#endif
+
+namespace base {
+
+#if defined(OS_LINUX)
+typedef DirReaderLinux DirReaderPosix;
+#else
+typedef DirReaderFallback DirReaderPosix;
+#endif
+
+}  // namespace base
+
+#endif  // BASE_FILES_DIR_READER_POSIX_H_
diff --git a/base/files/dir_reader_posix_unittest.cc b/base/files/dir_reader_posix_unittest.cc
new file mode 100644
index 0000000..0685031
--- /dev/null
+++ b/base/files/dir_reader_posix_unittest.cc
@@ -0,0 +1,92 @@
+// Copyright (c) 2012 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/files/dir_reader_posix.h"
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "base/logging.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_ANDROID)
+#include "base/os_compat_android.h"
+#endif
+
+namespace base {
+
+TEST(DirReaderPosixUnittest, Read) {
+  static const unsigned kNumFiles = 100;
+
+  if (DirReaderPosix::IsFallback())
+    return;
+
+  char kDirTemplate[] = "/tmp/org.chromium.dir-reader-posix-XXXXXX";
+  const char* dir = mkdtemp(kDirTemplate);
+  ASSERT_TRUE(dir);
+
+  const int prev_wd = open(".", O_RDONLY | O_DIRECTORY);
+  DCHECK_GE(prev_wd, 0);
+
+  PCHECK(chdir(dir) == 0);
+
+  for (unsigned i = 0; i < kNumFiles; i++) {
+    char buf[16];
+    snprintf(buf, sizeof(buf), "%d", i);
+    const int fd = open(buf, O_CREAT | O_RDONLY | O_EXCL, 0600);
+    PCHECK(fd >= 0);
+    PCHECK(close(fd) == 0);
+  }
+
+  std::set<unsigned> seen;
+
+  DirReaderPosix reader(dir);
+  EXPECT_TRUE(reader.IsValid());
+
+  if (!reader.IsValid())
+    return;
+
+  bool seen_dot = false, seen_dotdot = false;
+
+  for (; reader.Next(); ) {
+    if (strcmp(reader.name(), ".") == 0) {
+      seen_dot = true;
+      continue;
+    }
+    if (strcmp(reader.name(), "..") == 0) {
+      seen_dotdot = true;
+      continue;
+    }
+
+    SCOPED_TRACE(testing::Message() << "reader.name(): " << reader.name());
+
+    char *endptr;
+    const unsigned long value = strtoul(reader.name(), &endptr, 10);
+
+    EXPECT_FALSE(*endptr);
+    EXPECT_LT(value, kNumFiles);
+    EXPECT_EQ(0u, seen.count(value));
+    seen.insert(value);
+  }
+
+  for (unsigned i = 0; i < kNumFiles; i++) {
+    char buf[16];
+    snprintf(buf, sizeof(buf), "%d", i);
+    PCHECK(unlink(buf) == 0);
+  }
+
+  PCHECK(rmdir(dir) == 0);
+
+  PCHECK(fchdir(prev_wd) == 0);
+  PCHECK(close(prev_wd) == 0);
+
+  EXPECT_TRUE(seen_dot);
+  EXPECT_TRUE(seen_dotdot);
+  EXPECT_EQ(kNumFiles, seen.size());
+}
+
+}  // namespace base
diff --git a/base/files/file.cc b/base/files/file.cc
new file mode 100644
index 0000000..58f80c5
--- /dev/null
+++ b/base/files/file.cc
@@ -0,0 +1,142 @@
+// Copyright (c) 2011 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/files/file.h"
+#include "base/files/file_path.h"
+#include "base/files/file_tracing.h"
+#include "base/metrics/histogram.h"
+#include "base/timer/elapsed_timer.h"
+
+namespace base {
+
+File::Info::Info()
+    : size(0),
+      is_directory(false),
+      is_symbolic_link(false) {
+}
+
+File::Info::~Info() {
+}
+
+File::File()
+    : error_details_(FILE_ERROR_FAILED),
+      created_(false),
+      async_(false) {
+}
+
+#if !defined(OS_NACL)
+File::File(const FilePath& path, uint32 flags)
+    : error_details_(FILE_OK),
+      created_(false),
+      async_(false) {
+  Initialize(path, flags);
+}
+#endif
+
+File::File(PlatformFile platform_file)
+    : file_(platform_file),
+      error_details_(FILE_OK),
+      created_(false),
+      async_(false) {
+#if defined(OS_POSIX)
+  DCHECK_GE(platform_file, -1);
+#endif
+}
+
+File::File(Error error_details)
+    : error_details_(error_details),
+      created_(false),
+      async_(false) {
+}
+
+File::File(RValue other)
+    : file_(other.object->TakePlatformFile()),
+      path_(other.object->path_),
+      error_details_(other.object->error_details()),
+      created_(other.object->created()),
+      async_(other.object->async_) {
+}
+
+File::~File() {
+  // Go through the AssertIOAllowed logic.
+  Close();
+}
+
+File& File::operator=(RValue other) {
+  if (this != other.object) {
+    Close();
+    SetPlatformFile(other.object->TakePlatformFile());
+    path_ = other.object->path_;
+    error_details_ = other.object->error_details();
+    created_ = other.object->created();
+    async_ = other.object->async_;
+  }
+  return *this;
+}
+
+#if !defined(OS_NACL)
+void File::Initialize(const FilePath& path, uint32 flags) {
+  if (path.ReferencesParent()) {
+    error_details_ = FILE_ERROR_ACCESS_DENIED;
+    return;
+  }
+  path_ = path;
+  SCOPED_FILE_TRACE("Initialize");
+  DoInitialize(flags);
+}
+#endif
+
+std::string File::ErrorToString(Error error) {
+  switch (error) {
+    case FILE_OK:
+      return "FILE_OK";
+    case FILE_ERROR_FAILED:
+      return "FILE_ERROR_FAILED";
+    case FILE_ERROR_IN_USE:
+      return "FILE_ERROR_IN_USE";
+    case FILE_ERROR_EXISTS:
+      return "FILE_ERROR_EXISTS";
+    case FILE_ERROR_NOT_FOUND:
+      return "FILE_ERROR_NOT_FOUND";
+    case FILE_ERROR_ACCESS_DENIED:
+      return "FILE_ERROR_ACCESS_DENIED";
+    case FILE_ERROR_TOO_MANY_OPENED:
+      return "FILE_ERROR_TOO_MANY_OPENED";
+    case FILE_ERROR_NO_MEMORY:
+      return "FILE_ERROR_NO_MEMORY";
+    case FILE_ERROR_NO_SPACE:
+      return "FILE_ERROR_NO_SPACE";
+    case FILE_ERROR_NOT_A_DIRECTORY:
+      return "FILE_ERROR_NOT_A_DIRECTORY";
+    case FILE_ERROR_INVALID_OPERATION:
+      return "FILE_ERROR_INVALID_OPERATION";
+    case FILE_ERROR_SECURITY:
+      return "FILE_ERROR_SECURITY";
+    case FILE_ERROR_ABORT:
+      return "FILE_ERROR_ABORT";
+    case FILE_ERROR_NOT_A_FILE:
+      return "FILE_ERROR_NOT_A_FILE";
+    case FILE_ERROR_NOT_EMPTY:
+      return "FILE_ERROR_NOT_EMPTY";
+    case FILE_ERROR_INVALID_URL:
+      return "FILE_ERROR_INVALID_URL";
+    case FILE_ERROR_IO:
+      return "FILE_ERROR_IO";
+    case FILE_ERROR_MAX:
+      break;
+  }
+
+  NOTREACHED();
+  return "";
+}
+
+bool File::Flush() {
+  ElapsedTimer timer;
+  SCOPED_FILE_TRACE("Flush");
+  bool return_value = DoFlush();
+  UMA_HISTOGRAM_TIMES("PlatformFile.FlushTime", timer.Elapsed());
+  return return_value;
+}
+
+}  // namespace base
diff --git a/base/files/file.h b/base/files/file.h
new file mode 100644
index 0000000..b21b159
--- /dev/null
+++ b/base/files/file.h
@@ -0,0 +1,384 @@
+// Copyright (c) 2012 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_FILES_FILE_H_
+#define BASE_FILES_FILE_H_
+
+#include "build/build_config.h"
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
+#if defined(OS_POSIX)
+#include <sys/stat.h>
+#endif
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/files/file_path.h"
+#include "base/files/file_tracing.h"
+#include "base/files/scoped_file.h"
+#include "base/gtest_prod_util.h"
+#include "base/move.h"
+#include "base/time/time.h"
+
+#if defined(OS_WIN)
+#include "base/win/scoped_handle.h"
+#endif
+
+FORWARD_DECLARE_TEST(FileTest, MemoryCorruption);
+
+namespace base {
+
+#if defined(OS_WIN)
+typedef HANDLE PlatformFile;
+#elif defined(OS_POSIX)
+typedef int PlatformFile;
+
+#if defined(OS_BSD) || defined(OS_MACOSX) || defined(OS_NACL)
+typedef struct stat stat_wrapper_t;
+#else
+typedef struct stat64 stat_wrapper_t;
+#endif
+#endif  // defined(OS_POSIX)
+
+// Thin wrapper around an OS-level file.
+// Note that this class does not provide any support for asynchronous IO, other
+// than the ability to create asynchronous handles on Windows.
+//
+// Note about const: this class does not attempt to determine if the underlying
+// file system object is affected by a particular method in order to consider
+// that method const or not. Only methods that deal with member variables in an
+// obvious non-modifying way are marked as const. Any method that forward calls
+// to the OS is not considered const, even if there is no apparent change to
+// member variables.
+class BASE_EXPORT File {
+  MOVE_ONLY_TYPE_FOR_CPP_03(File, RValue)
+
+ public:
+  // FLAG_(OPEN|CREATE).* are mutually exclusive. You should specify exactly one
+  // of the five (possibly combining with other flags) when opening or creating
+  // a file.
+  // FLAG_(WRITE|APPEND) are mutually exclusive. This is so that APPEND behavior
+  // will be consistent with O_APPEND on POSIX.
+  // FLAG_EXCLUSIVE_(READ|WRITE) only grant exclusive access to the file on
+  // creation on POSIX; for existing files, consider using Lock().
+  enum Flags {
+    FLAG_OPEN = 1 << 0,             // Opens a file, only if it exists.
+    FLAG_CREATE = 1 << 1,           // Creates a new file, only if it does not
+                                    // already exist.
+    FLAG_OPEN_ALWAYS = 1 << 2,      // May create a new file.
+    FLAG_CREATE_ALWAYS = 1 << 3,    // May overwrite an old file.
+    FLAG_OPEN_TRUNCATED = 1 << 4,   // Opens a file and truncates it, only if it
+                                    // exists.
+    FLAG_READ = 1 << 5,
+    FLAG_WRITE = 1 << 6,
+    FLAG_APPEND = 1 << 7,
+    FLAG_EXCLUSIVE_READ = 1 << 8,   // EXCLUSIVE is opposite of Windows SHARE.
+    FLAG_EXCLUSIVE_WRITE = 1 << 9,
+    FLAG_ASYNC = 1 << 10,
+    FLAG_TEMPORARY = 1 << 11,       // Used on Windows only.
+    FLAG_HIDDEN = 1 << 12,          // Used on Windows only.
+    FLAG_DELETE_ON_CLOSE = 1 << 13,
+    FLAG_WRITE_ATTRIBUTES = 1 << 14,  // Used on Windows only.
+    FLAG_SHARE_DELETE = 1 << 15,      // Used on Windows only.
+    FLAG_TERMINAL_DEVICE = 1 << 16,   // Serial port flags.
+    FLAG_BACKUP_SEMANTICS = 1 << 17,  // Used on Windows only.
+    FLAG_EXECUTE = 1 << 18,           // Used on Windows only.
+  };
+
+  // This enum has been recorded in multiple histograms. If the order of the
+  // fields needs to change, please ensure that those histograms are obsolete or
+  // have been moved to a different enum.
+  //
+  // FILE_ERROR_ACCESS_DENIED is returned when a call fails because of a
+  // filesystem restriction. FILE_ERROR_SECURITY is returned when a browser
+  // policy doesn't allow the operation to be executed.
+  enum Error {
+    FILE_OK = 0,
+    FILE_ERROR_FAILED = -1,
+    FILE_ERROR_IN_USE = -2,
+    FILE_ERROR_EXISTS = -3,
+    FILE_ERROR_NOT_FOUND = -4,
+    FILE_ERROR_ACCESS_DENIED = -5,
+    FILE_ERROR_TOO_MANY_OPENED = -6,
+    FILE_ERROR_NO_MEMORY = -7,
+    FILE_ERROR_NO_SPACE = -8,
+    FILE_ERROR_NOT_A_DIRECTORY = -9,
+    FILE_ERROR_INVALID_OPERATION = -10,
+    FILE_ERROR_SECURITY = -11,
+    FILE_ERROR_ABORT = -12,
+    FILE_ERROR_NOT_A_FILE = -13,
+    FILE_ERROR_NOT_EMPTY = -14,
+    FILE_ERROR_INVALID_URL = -15,
+    FILE_ERROR_IO = -16,
+    // Put new entries here and increment FILE_ERROR_MAX.
+    FILE_ERROR_MAX = -17
+  };
+
+  // This explicit mapping matches both FILE_ on Windows and SEEK_ on Linux.
+  enum Whence {
+    FROM_BEGIN   = 0,
+    FROM_CURRENT = 1,
+    FROM_END     = 2
+  };
+
+  // Used to hold information about a given file.
+  // If you add more fields to this structure (platform-specific fields are OK),
+  // make sure to update all functions that use it in file_util_{win|posix}.cc,
+  // too, and the ParamTraits<base::File::Info> implementation in
+  // ipc/ipc_message_utils.cc.
+  struct BASE_EXPORT Info {
+    Info();
+    ~Info();
+#if defined(OS_POSIX)
+    // Fills this struct with values from |stat_info|.
+    void FromStat(const stat_wrapper_t& stat_info);
+#endif
+
+    // The size of the file in bytes.  Undefined when is_directory is true.
+    int64 size;
+
+    // True if the file corresponds to a directory.
+    bool is_directory;
+
+    // True if the file corresponds to a symbolic link.  For Windows currently
+    // not supported and thus always false.
+    bool is_symbolic_link;
+
+    // The last modified time of a file.
+    Time last_modified;
+
+    // The last accessed time of a file.
+    Time last_accessed;
+
+    // The creation time of a file.
+    Time creation_time;
+  };
+
+  File();
+
+  // Creates or opens the given file. This will fail with 'access denied' if the
+  // |path| contains path traversal ('..') components.
+  File(const FilePath& path, uint32 flags);
+
+  // Takes ownership of |platform_file|.
+  explicit File(PlatformFile platform_file);
+
+  // Creates an object with a specific error_details code.
+  explicit File(Error error_details);
+
+  // Move constructor for C++03 move emulation of this type.
+  File(RValue other);
+
+  ~File();
+
+  // Move operator= for C++03 move emulation of this type.
+  File& operator=(RValue other);
+
+  // Creates or opens the given file.
+  void Initialize(const FilePath& path, uint32 flags);
+
+  bool IsValid() const;
+
+  // Returns true if a new file was created (or an old one truncated to zero
+  // length to simulate a new file, which can happen with
+  // FLAG_CREATE_ALWAYS), and false otherwise.
+  bool created() const { return created_; }
+
+  // Returns the OS result of opening this file. Note that the way to verify
+  // the success of the operation is to use IsValid(), not this method:
+  //   File file(path, flags);
+  //   if (!file.IsValid())
+  //     return;
+  Error error_details() const { return error_details_; }
+
+  PlatformFile GetPlatformFile() const;
+  PlatformFile TakePlatformFile();
+
+  // Destroying this object closes the file automatically.
+  void Close();
+
+  // Changes current position in the file to an |offset| relative to an origin
+  // defined by |whence|. Returns the resultant current position in the file
+  // (relative to the start) or -1 in case of error.
+  int64 Seek(Whence whence, int64 offset);
+
+  // Reads the given number of bytes (or until EOF is reached) starting with the
+  // given offset. Returns the number of bytes read, or -1 on error. Note that
+  // this function makes a best effort to read all data on all platforms, so it
+  // is not intended for stream oriented files but instead for cases when the
+  // normal expectation is that actually |size| bytes are read unless there is
+  // an error.
+  int Read(int64 offset, char* data, int size);
+
+  // Same as above but without seek.
+  int ReadAtCurrentPos(char* data, int size);
+
+  // Reads the given number of bytes (or until EOF is reached) starting with the
+  // given offset, but does not make any effort to read all data on all
+  // platforms. Returns the number of bytes read, or -1 on error.
+  int ReadNoBestEffort(int64 offset, char* data, int size);
+
+  // Same as above but without seek.
+  int ReadAtCurrentPosNoBestEffort(char* data, int size);
+
+  // Writes the given buffer into the file at the given offset, overwritting any
+  // data that was previously there. Returns the number of bytes written, or -1
+  // on error. Note that this function makes a best effort to write all data on
+  // all platforms.
+  // Ignores the offset and writes to the end of the file if the file was opened
+  // with FLAG_APPEND.
+  int Write(int64 offset, const char* data, int size);
+
+  // Save as above but without seek.
+  int WriteAtCurrentPos(const char* data, int size);
+
+  // Save as above but does not make any effort to write all data on all
+  // platforms. Returns the number of bytes written, or -1 on error.
+  int WriteAtCurrentPosNoBestEffort(const char* data, int size);
+
+  // Returns the current size of this file, or a negative number on failure.
+  int64 GetLength();
+
+  // Truncates the file to the given length. If |length| is greater than the
+  // current size of the file, the file is extended with zeros. If the file
+  // doesn't exist, |false| is returned.
+  bool SetLength(int64 length);
+
+  // Instructs the filesystem to flush the file to disk. (POSIX: fsync, Windows:
+  // FlushFileBuffers).
+  bool Flush();
+
+  // Updates the file times.
+  bool SetTimes(Time last_access_time, Time last_modified_time);
+
+  // Returns some basic information for the given file.
+  bool GetInfo(Info* info);
+
+  // Attempts to take an exclusive write lock on the file. Returns immediately
+  // (i.e. does not wait for another process to unlock the file). If the lock
+  // was obtained, the result will be FILE_OK. A lock only guarantees
+  // that other processes may not also take a lock on the same file with the
+  // same API - it may still be opened, renamed, unlinked, etc.
+  //
+  // Common semantics:
+  //  * Locks are held by processes, but not inherited by child processes.
+  //  * Locks are released by the OS on file close or process termination.
+  //  * Locks are reliable only on local filesystems.
+  //  * Duplicated file handles may also write to locked files.
+  // Windows-specific semantics:
+  //  * Locks are mandatory for read/write APIs, advisory for mapping APIs.
+  //  * Within a process, locking the same file (by the same or new handle)
+  //    will fail.
+  // POSIX-specific semantics:
+  //  * Locks are advisory only.
+  //  * Within a process, locking the same file (by the same or new handle)
+  //    will succeed.
+  //  * Closing any descriptor on a given file releases the lock.
+  Error Lock();
+
+  // Unlock a file previously locked.
+  Error Unlock();
+
+  // Returns a new object referencing this file for use within the current
+  // process. Handling of FLAG_DELETE_ON_CLOSE varies by OS. On POSIX, the File
+  // object that was created or initialized with this flag will have unlinked
+  // the underlying file when it was created or opened. On Windows, the
+  // underlying file is deleted when the last handle to it is closed.
+  File Duplicate();
+
+  bool async() const { return async_; }
+
+#if defined(OS_WIN)
+  static Error OSErrorToFileError(DWORD last_error);
+#elif defined(OS_POSIX)
+  static Error OSErrorToFileError(int saved_errno);
+#endif
+
+  // Converts an error value to a human-readable form. Used for logging.
+  static std::string ErrorToString(Error error);
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(::FileTest, MemoryCorruption);
+
+  friend class FileTracing::ScopedTrace;
+
+#if defined(OS_POSIX)
+  // Encloses a single ScopedFD, saving a cheap tamper resistent memory checksum
+  // alongside it. This checksum is validated at every access, allowing early
+  // detection of memory corruption.
+
+  // TODO(gavinp): This is in place temporarily to help us debug
+  // https://crbug.com/424562 , which can't be reproduced in valgrind. Remove
+  // this code after we have fixed this issue.
+  class MemoryCheckingScopedFD {
+   public:
+    MemoryCheckingScopedFD();
+    MemoryCheckingScopedFD(int fd);
+    ~MemoryCheckingScopedFD();
+
+    bool is_valid() const { Check(); return file_.is_valid(); }
+    int get() const { Check(); return file_.get(); }
+
+    void reset() { Check(); file_.reset(); UpdateChecksum(); }
+    void reset(int fd) { Check(); file_.reset(fd); UpdateChecksum(); }
+    int release() {
+      Check();
+      int fd = file_.release();
+      UpdateChecksum();
+      return fd;
+    }
+
+   private:
+    FRIEND_TEST_ALL_PREFIXES(::FileTest, MemoryCorruption);
+
+    // Computes the checksum for the current value of |file_|. Returns via an
+    // out parameter to guard against implicit conversions of unsigned integral
+    // types.
+    void ComputeMemoryChecksum(unsigned int* out_checksum) const;
+
+    // Confirms that the current |file_| and |file_memory_checksum_| agree,
+    // failing a CHECK if they do not.
+    void Check() const;
+
+    void UpdateChecksum();
+
+    ScopedFD file_;
+    unsigned int file_memory_checksum_;
+  };
+#endif
+
+  // Creates or opens the given file. Only called if |path_| has no
+  // traversal ('..') components.
+  void DoInitialize(uint32 flags);
+
+  // TODO(tnagel): Reintegrate into Flush() once histogram isn't needed anymore,
+  // cf. issue 473337.
+  bool DoFlush();
+
+  void SetPlatformFile(PlatformFile file);
+
+#if defined(OS_WIN)
+  win::ScopedHandle file_;
+#elif defined(OS_POSIX)
+  MemoryCheckingScopedFD file_;
+#endif
+
+  // Path that |Initialize()| was called with. Only set if safe (i.e. no '..').
+  FilePath path_;
+
+  // Object tied to the lifetime of |this| that enables/disables tracing.
+  FileTracing::ScopedEnabler trace_enabler_;
+
+  Error error_details_;
+  bool created_;
+  bool async_;
+};
+
+}  // namespace base
+
+#endif  // BASE_FILES_FILE_H_
diff --git a/base/files/file_enumerator.cc b/base/files/file_enumerator.cc
new file mode 100644
index 0000000..9749980
--- /dev/null
+++ b/base/files/file_enumerator.cc
@@ -0,0 +1,21 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/file_enumerator.h"
+
+#include "base/files/file_util.h"
+
+namespace base {
+
+FileEnumerator::FileInfo::~FileInfo() {
+}
+
+bool FileEnumerator::ShouldSkip(const FilePath& path) {
+  FilePath::StringType basename = path.BaseName().value();
+  return basename == FILE_PATH_LITERAL(".") ||
+         (basename == FILE_PATH_LITERAL("..") &&
+          !(INCLUDE_DOT_DOT & file_type_));
+}
+
+}  // namespace base
diff --git a/base/files/file_enumerator.h b/base/files/file_enumerator.h
new file mode 100644
index 0000000..38bb833
--- /dev/null
+++ b/base/files/file_enumerator.h
@@ -0,0 +1,159 @@
+// Copyright (c) 2012 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_FILES_FILE_ENUMERATOR_H_
+#define BASE_FILES_FILE_ENUMERATOR_H_
+
+#include <stack>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/files/file_path.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#elif defined(OS_POSIX)
+#include <sys/stat.h>
+#include <unistd.h>
+#endif
+
+namespace base {
+
+// A class for enumerating the files in a provided path. The order of the
+// results is not guaranteed.
+//
+// This is blocking. Do not use on critical threads.
+//
+// Example:
+//
+//   base::FileEnumerator enum(my_dir, false, base::FileEnumerator::FILES,
+//                             FILE_PATH_LITERAL("*.txt"));
+//   for (base::FilePath name = enum.Next(); !name.empty(); name = enum.Next())
+//     ...
+class BASE_EXPORT FileEnumerator {
+ public:
+  // Note: copy & assign supported.
+  class BASE_EXPORT FileInfo {
+   public:
+    FileInfo();
+    ~FileInfo();
+
+    bool IsDirectory() const;
+
+    // The name of the file. This will not include any path information. This
+    // is in constrast to the value returned by FileEnumerator.Next() which
+    // includes the |root_path| passed into the FileEnumerator constructor.
+    FilePath GetName() const;
+
+    int64 GetSize() const;
+    Time GetLastModifiedTime() const;
+
+#if defined(OS_WIN)
+    // Note that the cAlternateFileName (used to hold the "short" 8.3 name)
+    // of the WIN32_FIND_DATA will be empty. Since we don't use short file
+    // names, we tell Windows to omit it which speeds up the query slightly.
+    const WIN32_FIND_DATA& find_data() const { return find_data_; }
+#elif defined(OS_POSIX)
+    const struct stat& stat() const { return stat_; }
+#endif
+
+   private:
+    friend class FileEnumerator;
+
+#if defined(OS_WIN)
+    WIN32_FIND_DATA find_data_;
+#elif defined(OS_POSIX)
+    struct stat stat_;
+    FilePath filename_;
+#endif
+  };
+
+  enum FileType {
+    FILES                 = 1 << 0,
+    DIRECTORIES           = 1 << 1,
+    INCLUDE_DOT_DOT       = 1 << 2,
+#if defined(OS_POSIX)
+    SHOW_SYM_LINKS        = 1 << 4,
+#endif
+  };
+
+  // |root_path| is the starting directory to search for. It may or may not end
+  // in a slash.
+  //
+  // If |recursive| is true, this will enumerate all matches in any
+  // subdirectories matched as well. It does a breadth-first search, so all
+  // files in one directory will be returned before any files in a
+  // subdirectory.
+  //
+  // |file_type|, a bit mask of FileType, specifies whether the enumerator
+  // should match files, directories, or both.
+  //
+  // |pattern| is an optional pattern for which files to match. This
+  // works like shell globbing. For example, "*.txt" or "Foo???.doc".
+  // However, be careful in specifying patterns that aren't cross platform
+  // since the underlying code uses OS-specific matching routines.  In general,
+  // Windows matching is less featureful than others, so test there first.
+  // If unspecified, this will match all files.
+  // NOTE: the pattern only matches the contents of root_path, not files in
+  // recursive subdirectories.
+  // TODO(erikkay): Fix the pattern matching to work at all levels.
+  FileEnumerator(const FilePath& root_path,
+                 bool recursive,
+                 int file_type);
+  FileEnumerator(const FilePath& root_path,
+                 bool recursive,
+                 int file_type,
+                 const FilePath::StringType& pattern);
+  ~FileEnumerator();
+
+  // Returns the next file or an empty string if there are no more results.
+  //
+  // The returned path will incorporate the |root_path| passed in the
+  // constructor: "<root_path>/file_name.txt". If the |root_path| is absolute,
+  // then so will be the result of Next().
+  FilePath Next();
+
+  // Write the file info into |info|.
+  FileInfo GetInfo() const;
+
+ private:
+  // Returns true if the given path should be skipped in enumeration.
+  bool ShouldSkip(const FilePath& path);
+
+#if defined(OS_WIN)
+  // True when find_data_ is valid.
+  bool has_find_data_;
+  WIN32_FIND_DATA find_data_;
+  HANDLE find_handle_;
+#elif defined(OS_POSIX)
+
+  // Read the filenames in source into the vector of DirectoryEntryInfo's
+  static bool ReadDirectory(std::vector<FileInfo>* entries,
+                            const FilePath& source, bool show_links);
+
+  // The files in the current directory
+  std::vector<FileInfo> directory_entries_;
+
+  // The next entry to use from the directory_entries_ vector
+  size_t current_directory_entry_;
+#endif
+
+  FilePath root_path_;
+  bool recursive_;
+  int file_type_;
+  FilePath::StringType pattern_;  // Empty when we want to find everything.
+
+  // A stack that keeps track of which subdirectories we still need to
+  // enumerate in the breadth-first search.
+  std::stack<FilePath> pending_paths_;
+
+  DISALLOW_COPY_AND_ASSIGN(FileEnumerator);
+};
+
+}  // namespace base
+
+#endif  // BASE_FILES_FILE_ENUMERATOR_H_
diff --git a/base/files/file_enumerator_posix.cc b/base/files/file_enumerator_posix.cc
new file mode 100644
index 0000000..7533a24
--- /dev/null
+++ b/base/files/file_enumerator_posix.cc
@@ -0,0 +1,160 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/file_enumerator.h"
+
+#include <dirent.h>
+#include <errno.h>
+#include <fnmatch.h>
+
+#include "base/logging.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace base {
+
+// FileEnumerator::FileInfo ----------------------------------------------------
+
+FileEnumerator::FileInfo::FileInfo() {
+  memset(&stat_, 0, sizeof(stat_));
+}
+
+bool FileEnumerator::FileInfo::IsDirectory() const {
+  return S_ISDIR(stat_.st_mode);
+}
+
+FilePath FileEnumerator::FileInfo::GetName() const {
+  return filename_;
+}
+
+int64 FileEnumerator::FileInfo::GetSize() const {
+  return stat_.st_size;
+}
+
+base::Time FileEnumerator::FileInfo::GetLastModifiedTime() const {
+  return base::Time::FromTimeT(stat_.st_mtime);
+}
+
+// FileEnumerator --------------------------------------------------------------
+
+FileEnumerator::FileEnumerator(const FilePath& root_path,
+                               bool recursive,
+                               int file_type)
+    : current_directory_entry_(0),
+      root_path_(root_path),
+      recursive_(recursive),
+      file_type_(file_type) {
+  // INCLUDE_DOT_DOT must not be specified if recursive.
+  DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_)));
+  pending_paths_.push(root_path);
+}
+
+FileEnumerator::FileEnumerator(const FilePath& root_path,
+                               bool recursive,
+                               int file_type,
+                               const FilePath::StringType& pattern)
+    : current_directory_entry_(0),
+      root_path_(root_path),
+      recursive_(recursive),
+      file_type_(file_type),
+      pattern_(root_path.Append(pattern).value()) {
+  // INCLUDE_DOT_DOT must not be specified if recursive.
+  DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_)));
+  // The Windows version of this code appends the pattern to the root_path,
+  // potentially only matching against items in the top-most directory.
+  // Do the same here.
+  if (pattern.empty())
+    pattern_ = FilePath::StringType();
+  pending_paths_.push(root_path);
+}
+
+FileEnumerator::~FileEnumerator() {
+}
+
+FilePath FileEnumerator::Next() {
+  ++current_directory_entry_;
+
+  // While we've exhausted the entries in the current directory, do the next
+  while (current_directory_entry_ >= directory_entries_.size()) {
+    if (pending_paths_.empty())
+      return FilePath();
+
+    root_path_ = pending_paths_.top();
+    root_path_ = root_path_.StripTrailingSeparators();
+    pending_paths_.pop();
+
+    std::vector<FileInfo> entries;
+    if (!ReadDirectory(&entries, root_path_, file_type_ & SHOW_SYM_LINKS))
+      continue;
+
+    directory_entries_.clear();
+    current_directory_entry_ = 0;
+    for (std::vector<FileInfo>::const_iterator i = entries.begin();
+         i != entries.end(); ++i) {
+      FilePath full_path = root_path_.Append(i->filename_);
+      if (ShouldSkip(full_path))
+        continue;
+
+      if (pattern_.size() &&
+          fnmatch(pattern_.c_str(), full_path.value().c_str(), FNM_NOESCAPE))
+        continue;
+
+      if (recursive_ && S_ISDIR(i->stat_.st_mode))
+        pending_paths_.push(full_path);
+
+      if ((S_ISDIR(i->stat_.st_mode) && (file_type_ & DIRECTORIES)) ||
+          (!S_ISDIR(i->stat_.st_mode) && (file_type_ & FILES)))
+        directory_entries_.push_back(*i);
+    }
+  }
+
+  return root_path_.Append(
+      directory_entries_[current_directory_entry_].filename_);
+}
+
+FileEnumerator::FileInfo FileEnumerator::GetInfo() const {
+  return directory_entries_[current_directory_entry_];
+}
+
+bool FileEnumerator::ReadDirectory(std::vector<FileInfo>* entries,
+                                   const FilePath& source, bool show_links) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  DIR* dir = opendir(source.value().c_str());
+  if (!dir)
+    return false;
+
+#if !defined(OS_LINUX) && !defined(OS_MACOSX) && !defined(OS_BSD) && \
+    !defined(OS_SOLARIS) && !defined(OS_ANDROID)
+  #error Port warning: depending on the definition of struct dirent, \
+         additional space for pathname may be needed
+#endif
+
+  struct dirent dent_buf;
+  struct dirent* dent;
+  while (readdir_r(dir, &dent_buf, &dent) == 0 && dent) {
+    FileInfo info;
+    info.filename_ = FilePath(dent->d_name);
+
+    FilePath full_name = source.Append(dent->d_name);
+    int ret;
+    if (show_links)
+      ret = lstat(full_name.value().c_str(), &info.stat_);
+    else
+      ret = stat(full_name.value().c_str(), &info.stat_);
+    if (ret < 0) {
+      // Print the stat() error message unless it was ENOENT and we're
+      // following symlinks.
+      if (!(errno == ENOENT && !show_links)) {
+        DPLOG(ERROR) << "Couldn't stat "
+                     << source.Append(dent->d_name).value();
+      }
+      memset(&info.stat_, 0, sizeof(info.stat_));
+    }
+    entries->push_back(info);
+  }
+
+  closedir(dir);
+  return true;
+}
+
+}  // namespace base
diff --git a/base/files/file_enumerator_win.cc b/base/files/file_enumerator_win.cc
new file mode 100644
index 0000000..931d154
--- /dev/null
+++ b/base/files/file_enumerator_win.cc
@@ -0,0 +1,164 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/file_enumerator.h"
+
+#include <string.h>
+
+#include "base/logging.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/win/windows_version.h"
+
+namespace base {
+
+// FileEnumerator::FileInfo ----------------------------------------------------
+
+FileEnumerator::FileInfo::FileInfo() {
+  memset(&find_data_, 0, sizeof(find_data_));
+}
+
+bool FileEnumerator::FileInfo::IsDirectory() const {
+  return (find_data_.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
+}
+
+FilePath FileEnumerator::FileInfo::GetName() const {
+  return FilePath(find_data_.cFileName);
+}
+
+int64 FileEnumerator::FileInfo::GetSize() const {
+  ULARGE_INTEGER size;
+  size.HighPart = find_data_.nFileSizeHigh;
+  size.LowPart = find_data_.nFileSizeLow;
+  DCHECK_LE(size.QuadPart, std::numeric_limits<int64>::max());
+  return static_cast<int64>(size.QuadPart);
+}
+
+base::Time FileEnumerator::FileInfo::GetLastModifiedTime() const {
+  return base::Time::FromFileTime(find_data_.ftLastWriteTime);
+}
+
+// FileEnumerator --------------------------------------------------------------
+
+FileEnumerator::FileEnumerator(const FilePath& root_path,
+                               bool recursive,
+                               int file_type)
+    : recursive_(recursive),
+      file_type_(file_type),
+      has_find_data_(false),
+      find_handle_(INVALID_HANDLE_VALUE) {
+  // INCLUDE_DOT_DOT must not be specified if recursive.
+  DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_)));
+  memset(&find_data_, 0, sizeof(find_data_));
+  pending_paths_.push(root_path);
+}
+
+FileEnumerator::FileEnumerator(const FilePath& root_path,
+                               bool recursive,
+                               int file_type,
+                               const FilePath::StringType& pattern)
+    : recursive_(recursive),
+      file_type_(file_type),
+      has_find_data_(false),
+      pattern_(pattern),
+      find_handle_(INVALID_HANDLE_VALUE) {
+  // INCLUDE_DOT_DOT must not be specified if recursive.
+  DCHECK(!(recursive && (INCLUDE_DOT_DOT & file_type_)));
+  memset(&find_data_, 0, sizeof(find_data_));
+  pending_paths_.push(root_path);
+}
+
+FileEnumerator::~FileEnumerator() {
+  if (find_handle_ != INVALID_HANDLE_VALUE)
+    FindClose(find_handle_);
+}
+
+FileEnumerator::FileInfo FileEnumerator::GetInfo() const {
+  if (!has_find_data_) {
+    NOTREACHED();
+    return FileInfo();
+  }
+  FileInfo ret;
+  memcpy(&ret.find_data_, &find_data_, sizeof(find_data_));
+  return ret;
+}
+
+FilePath FileEnumerator::Next() {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  while (has_find_data_ || !pending_paths_.empty()) {
+    if (!has_find_data_) {
+      // The last find FindFirstFile operation is done, prepare a new one.
+      root_path_ = pending_paths_.top();
+      pending_paths_.pop();
+
+      // Start a new find operation.
+      FilePath src = root_path_;
+
+      if (pattern_.empty())
+        src = src.Append(L"*");  // No pattern = match everything.
+      else
+        src = src.Append(pattern_);
+
+      if (base::win::GetVersion() >= base::win::VERSION_WIN7) {
+        // Use a "large fetch" on newer Windows which should speed up large
+        // enumerations (we seldom abort in the middle).
+        find_handle_ = FindFirstFileEx(src.value().c_str(),
+                                       FindExInfoBasic,  // Omit short name.
+                                       &find_data_,
+                                       FindExSearchNameMatch,
+                                       NULL,
+                                       FIND_FIRST_EX_LARGE_FETCH);
+      } else {
+        find_handle_ = FindFirstFile(src.value().c_str(), &find_data_);
+      }
+      has_find_data_ = true;
+    } else {
+      // Search for the next file/directory.
+      if (!FindNextFile(find_handle_, &find_data_)) {
+        FindClose(find_handle_);
+        find_handle_ = INVALID_HANDLE_VALUE;
+      }
+    }
+
+    if (INVALID_HANDLE_VALUE == find_handle_) {
+      has_find_data_ = false;
+
+      // This is reached when we have finished a directory and are advancing to
+      // the next one in the queue. We applied the pattern (if any) to the files
+      // in the root search directory, but for those directories which were
+      // matched, we want to enumerate all files inside them. This will happen
+      // when the handle is empty.
+      pattern_ = FilePath::StringType();
+
+      continue;
+    }
+
+    FilePath cur_file(find_data_.cFileName);
+    if (ShouldSkip(cur_file))
+      continue;
+
+    // Construct the absolute filename.
+    cur_file = root_path_.Append(find_data_.cFileName);
+
+    if (find_data_.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+      if (recursive_) {
+        // If |cur_file| is a directory, and we are doing recursive searching,
+        // add it to pending_paths_ so we scan it after we finish scanning this
+        // directory. However, don't do recursion through reparse points or we
+        // may end up with an infinite cycle.
+        DWORD attributes = GetFileAttributes(cur_file.value().c_str());
+        if (!(attributes & FILE_ATTRIBUTE_REPARSE_POINT))
+          pending_paths_.push(cur_file);
+      }
+      if (file_type_ & FileEnumerator::DIRECTORIES)
+        return cur_file;
+    } else if (file_type_ & FileEnumerator::FILES) {
+      return cur_file;
+    }
+  }
+
+  return FilePath();
+}
+
+}  // namespace base
diff --git a/base/files/file_path.cc b/base/files/file_path.cc
new file mode 100644
index 0000000..de8927a
--- /dev/null
+++ b/base/files/file_path.cc
@@ -0,0 +1,1320 @@
+// Copyright (c) 2012 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/files/file_path.h"
+
+#include <string.h>
+#include <algorithm>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/pickle.h"
+
+// These includes are just for the *Hack functions, and should be removed
+// when those functions are removed.
+#include "base/strings/string_piece.h"
+#include "base/strings/string_util.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+
+#if defined(OS_MACOSX)
+#include "base/mac/scoped_cftyperef.h"
+#include "base/third_party/icu/icu_utf.h"
+#endif
+
+#if defined(OS_WIN)
+#include <windows.h>
+#elif defined(OS_MACOSX)
+#include <CoreFoundation/CoreFoundation.h>
+#endif
+
+namespace base {
+
+typedef FilePath::StringType StringType;
+
+namespace {
+
+const char* const kCommonDoubleExtensionSuffixes[] = { "gz", "z", "bz2", "bz" };
+const char* const kCommonDoubleExtensions[] = { "user.js" };
+
+const FilePath::CharType kStringTerminator = FILE_PATH_LITERAL('\0');
+
+// If this FilePath contains a drive letter specification, returns the
+// position of the last character of the drive letter specification,
+// otherwise returns npos.  This can only be true on Windows, when a pathname
+// begins with a letter followed by a colon.  On other platforms, this always
+// returns npos.
+StringType::size_type FindDriveLetter(const StringType& path) {
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+  // This is dependent on an ASCII-based character set, but that's a
+  // reasonable assumption.  iswalpha can be too inclusive here.
+  if (path.length() >= 2 && path[1] == L':' &&
+      ((path[0] >= L'A' && path[0] <= L'Z') ||
+       (path[0] >= L'a' && path[0] <= L'z'))) {
+    return 1;
+  }
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+  return StringType::npos;
+}
+
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+bool EqualDriveLetterCaseInsensitive(const StringType& a,
+                                     const StringType& b) {
+  size_t a_letter_pos = FindDriveLetter(a);
+  size_t b_letter_pos = FindDriveLetter(b);
+
+  if (a_letter_pos == StringType::npos || b_letter_pos == StringType::npos)
+    return a == b;
+
+  StringType a_letter(a.substr(0, a_letter_pos + 1));
+  StringType b_letter(b.substr(0, b_letter_pos + 1));
+  if (!StartsWith(a_letter, b_letter, false))
+    return false;
+
+  StringType a_rest(a.substr(a_letter_pos + 1));
+  StringType b_rest(b.substr(b_letter_pos + 1));
+  return a_rest == b_rest;
+}
+#endif  // defined(FILE_PATH_USES_DRIVE_LETTERS)
+
+bool IsPathAbsolute(const StringType& path) {
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+  StringType::size_type letter = FindDriveLetter(path);
+  if (letter != StringType::npos) {
+    // Look for a separator right after the drive specification.
+    return path.length() > letter + 1 &&
+        FilePath::IsSeparator(path[letter + 1]);
+  }
+  // Look for a pair of leading separators.
+  return path.length() > 1 &&
+      FilePath::IsSeparator(path[0]) && FilePath::IsSeparator(path[1]);
+#else  // FILE_PATH_USES_DRIVE_LETTERS
+  // Look for a separator in the first position.
+  return path.length() > 0 && FilePath::IsSeparator(path[0]);
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+}
+
+bool AreAllSeparators(const StringType& input) {
+  for (StringType::const_iterator it = input.begin();
+      it != input.end(); ++it) {
+    if (!FilePath::IsSeparator(*it))
+      return false;
+  }
+
+  return true;
+}
+
+// Find the position of the '.' that separates the extension from the rest
+// of the file name. The position is relative to BaseName(), not value().
+// Returns npos if it can't find an extension.
+StringType::size_type FinalExtensionSeparatorPosition(const StringType& path) {
+  // Special case "." and ".."
+  if (path == FilePath::kCurrentDirectory || path == FilePath::kParentDirectory)
+    return StringType::npos;
+
+  return path.rfind(FilePath::kExtensionSeparator);
+}
+
+// Same as above, but allow a second extension component of up to 4
+// characters when the rightmost extension component is a common double
+// extension (gz, bz2, Z).  For example, foo.tar.gz or foo.tar.Z would have
+// extension components of '.tar.gz' and '.tar.Z' respectively.
+StringType::size_type ExtensionSeparatorPosition(const StringType& path) {
+  const StringType::size_type last_dot = FinalExtensionSeparatorPosition(path);
+
+  // No extension, or the extension is the whole filename.
+  if (last_dot == StringType::npos || last_dot == 0U)
+    return last_dot;
+
+  const StringType::size_type penultimate_dot =
+      path.rfind(FilePath::kExtensionSeparator, last_dot - 1);
+  const StringType::size_type last_separator =
+      path.find_last_of(FilePath::kSeparators, last_dot - 1,
+                        FilePath::kSeparatorsLength - 1);
+
+  if (penultimate_dot == StringType::npos ||
+      (last_separator != StringType::npos &&
+       penultimate_dot < last_separator)) {
+    return last_dot;
+  }
+
+  for (size_t i = 0; i < arraysize(kCommonDoubleExtensions); ++i) {
+    StringType extension(path, penultimate_dot + 1);
+    if (LowerCaseEqualsASCII(extension, kCommonDoubleExtensions[i]))
+      return penultimate_dot;
+  }
+
+  StringType extension(path, last_dot + 1);
+  for (size_t i = 0; i < arraysize(kCommonDoubleExtensionSuffixes); ++i) {
+    if (LowerCaseEqualsASCII(extension, kCommonDoubleExtensionSuffixes[i])) {
+      if ((last_dot - penultimate_dot) <= 5U &&
+          (last_dot - penultimate_dot) > 1U) {
+        return penultimate_dot;
+      }
+    }
+  }
+
+  return last_dot;
+}
+
+// Returns true if path is "", ".", or "..".
+bool IsEmptyOrSpecialCase(const StringType& path) {
+  // Special cases "", ".", and ".."
+  if (path.empty() || path == FilePath::kCurrentDirectory ||
+      path == FilePath::kParentDirectory) {
+    return true;
+  }
+
+  return false;
+}
+
+}  // namespace
+
+FilePath::FilePath() {
+}
+
+FilePath::FilePath(const FilePath& that) : path_(that.path_) {
+}
+
+FilePath::FilePath(const StringType& path) : path_(path) {
+  StringType::size_type nul_pos = path_.find(kStringTerminator);
+  if (nul_pos != StringType::npos)
+    path_.erase(nul_pos, StringType::npos);
+}
+
+FilePath::~FilePath() {
+}
+
+FilePath& FilePath::operator=(const FilePath& that) {
+  path_ = that.path_;
+  return *this;
+}
+
+bool FilePath::operator==(const FilePath& that) const {
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+  return EqualDriveLetterCaseInsensitive(this->path_, that.path_);
+#else  // defined(FILE_PATH_USES_DRIVE_LETTERS)
+  return path_ == that.path_;
+#endif  // defined(FILE_PATH_USES_DRIVE_LETTERS)
+}
+
+bool FilePath::operator!=(const FilePath& that) const {
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+  return !EqualDriveLetterCaseInsensitive(this->path_, that.path_);
+#else  // defined(FILE_PATH_USES_DRIVE_LETTERS)
+  return path_ != that.path_;
+#endif  // defined(FILE_PATH_USES_DRIVE_LETTERS)
+}
+
+// static
+bool FilePath::IsSeparator(CharType character) {
+  for (size_t i = 0; i < kSeparatorsLength - 1; ++i) {
+    if (character == kSeparators[i]) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+void FilePath::GetComponents(std::vector<StringType>* components) const {
+  DCHECK(components);
+  if (!components)
+    return;
+  components->clear();
+  if (value().empty())
+    return;
+
+  std::vector<StringType> ret_val;
+  FilePath current = *this;
+  FilePath base;
+
+  // Capture path components.
+  while (current != current.DirName()) {
+    base = current.BaseName();
+    if (!AreAllSeparators(base.value()))
+      ret_val.push_back(base.value());
+    current = current.DirName();
+  }
+
+  // Capture root, if any.
+  base = current.BaseName();
+  if (!base.value().empty() && base.value() != kCurrentDirectory)
+    ret_val.push_back(current.BaseName().value());
+
+  // Capture drive letter, if any.
+  FilePath dir = current.DirName();
+  StringType::size_type letter = FindDriveLetter(dir.value());
+  if (letter != StringType::npos) {
+    ret_val.push_back(StringType(dir.value(), 0, letter + 1));
+  }
+
+  *components = std::vector<StringType>(ret_val.rbegin(), ret_val.rend());
+}
+
+bool FilePath::IsParent(const FilePath& child) const {
+  return AppendRelativePath(child, NULL);
+}
+
+bool FilePath::AppendRelativePath(const FilePath& child,
+                                  FilePath* path) const {
+  std::vector<StringType> parent_components;
+  std::vector<StringType> child_components;
+  GetComponents(&parent_components);
+  child.GetComponents(&child_components);
+
+  if (parent_components.empty() ||
+      parent_components.size() >= child_components.size())
+    return false;
+
+  std::vector<StringType>::const_iterator parent_comp =
+      parent_components.begin();
+  std::vector<StringType>::const_iterator child_comp =
+      child_components.begin();
+
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+  // Windows can access case sensitive filesystems, so component
+  // comparisions must be case sensitive, but drive letters are
+  // never case sensitive.
+  if ((FindDriveLetter(*parent_comp) != StringType::npos) &&
+      (FindDriveLetter(*child_comp) != StringType::npos)) {
+    if (!StartsWith(*parent_comp, *child_comp, false))
+      return false;
+    ++parent_comp;
+    ++child_comp;
+  }
+#endif  // defined(FILE_PATH_USES_DRIVE_LETTERS)
+
+  while (parent_comp != parent_components.end()) {
+    if (*parent_comp != *child_comp)
+      return false;
+    ++parent_comp;
+    ++child_comp;
+  }
+
+  if (path != NULL) {
+    for (; child_comp != child_components.end(); ++child_comp) {
+      *path = path->Append(*child_comp);
+    }
+  }
+  return true;
+}
+
+// libgen's dirname and basename aren't guaranteed to be thread-safe and aren't
+// guaranteed to not modify their input strings, and in fact are implemented
+// differently in this regard on different platforms.  Don't use them, but
+// adhere to their behavior.
+FilePath FilePath::DirName() const {
+  FilePath new_path(path_);
+  new_path.StripTrailingSeparatorsInternal();
+
+  // The drive letter, if any, always needs to remain in the output.  If there
+  // is no drive letter, as will always be the case on platforms which do not
+  // support drive letters, letter will be npos, or -1, so the comparisons and
+  // resizes below using letter will still be valid.
+  StringType::size_type letter = FindDriveLetter(new_path.path_);
+
+  StringType::size_type last_separator =
+      new_path.path_.find_last_of(kSeparators, StringType::npos,
+                                  kSeparatorsLength - 1);
+  if (last_separator == StringType::npos) {
+    // path_ is in the current directory.
+    new_path.path_.resize(letter + 1);
+  } else if (last_separator == letter + 1) {
+    // path_ is in the root directory.
+    new_path.path_.resize(letter + 2);
+  } else if (last_separator == letter + 2 &&
+             IsSeparator(new_path.path_[letter + 1])) {
+    // path_ is in "//" (possibly with a drive letter); leave the double
+    // separator intact indicating alternate root.
+    new_path.path_.resize(letter + 3);
+  } else if (last_separator != 0) {
+    // path_ is somewhere else, trim the basename.
+    new_path.path_.resize(last_separator);
+  }
+
+  new_path.StripTrailingSeparatorsInternal();
+  if (!new_path.path_.length())
+    new_path.path_ = kCurrentDirectory;
+
+  return new_path;
+}
+
+FilePath FilePath::BaseName() const {
+  FilePath new_path(path_);
+  new_path.StripTrailingSeparatorsInternal();
+
+  // The drive letter, if any, is always stripped.
+  StringType::size_type letter = FindDriveLetter(new_path.path_);
+  if (letter != StringType::npos) {
+    new_path.path_.erase(0, letter + 1);
+  }
+
+  // Keep everything after the final separator, but if the pathname is only
+  // one character and it's a separator, leave it alone.
+  StringType::size_type last_separator =
+      new_path.path_.find_last_of(kSeparators, StringType::npos,
+                                  kSeparatorsLength - 1);
+  if (last_separator != StringType::npos &&
+      last_separator < new_path.path_.length() - 1) {
+    new_path.path_.erase(0, last_separator + 1);
+  }
+
+  return new_path;
+}
+
+StringType FilePath::Extension() const {
+  FilePath base(BaseName());
+  const StringType::size_type dot = ExtensionSeparatorPosition(base.path_);
+  if (dot == StringType::npos)
+    return StringType();
+
+  return base.path_.substr(dot, StringType::npos);
+}
+
+StringType FilePath::FinalExtension() const {
+  FilePath base(BaseName());
+  const StringType::size_type dot = FinalExtensionSeparatorPosition(base.path_);
+  if (dot == StringType::npos)
+    return StringType();
+
+  return base.path_.substr(dot, StringType::npos);
+}
+
+FilePath FilePath::RemoveExtension() const {
+  if (Extension().empty())
+    return *this;
+
+  const StringType::size_type dot = ExtensionSeparatorPosition(path_);
+  if (dot == StringType::npos)
+    return *this;
+
+  return FilePath(path_.substr(0, dot));
+}
+
+FilePath FilePath::RemoveFinalExtension() const {
+  if (FinalExtension().empty())
+    return *this;
+
+  const StringType::size_type dot = FinalExtensionSeparatorPosition(path_);
+  if (dot == StringType::npos)
+    return *this;
+
+  return FilePath(path_.substr(0, dot));
+}
+
+FilePath FilePath::InsertBeforeExtension(const StringType& suffix) const {
+  if (suffix.empty())
+    return FilePath(path_);
+
+  if (IsEmptyOrSpecialCase(BaseName().value()))
+    return FilePath();
+
+  StringType ext = Extension();
+  StringType ret = RemoveExtension().value();
+  ret.append(suffix);
+  ret.append(ext);
+  return FilePath(ret);
+}
+
+FilePath FilePath::InsertBeforeExtensionASCII(const StringPiece& suffix)
+    const {
+  DCHECK(IsStringASCII(suffix));
+#if defined(OS_WIN)
+  return InsertBeforeExtension(ASCIIToUTF16(suffix.as_string()));
+#elif defined(OS_POSIX)
+  return InsertBeforeExtension(suffix.as_string());
+#endif
+}
+
+FilePath FilePath::AddExtension(const StringType& extension) const {
+  if (IsEmptyOrSpecialCase(BaseName().value()))
+    return FilePath();
+
+  // If the new extension is "" or ".", then just return the current FilePath.
+  if (extension.empty() || extension == StringType(1, kExtensionSeparator))
+    return *this;
+
+  StringType str = path_;
+  if (extension[0] != kExtensionSeparator &&
+      *(str.end() - 1) != kExtensionSeparator) {
+    str.append(1, kExtensionSeparator);
+  }
+  str.append(extension);
+  return FilePath(str);
+}
+
+FilePath FilePath::ReplaceExtension(const StringType& extension) const {
+  if (IsEmptyOrSpecialCase(BaseName().value()))
+    return FilePath();
+
+  FilePath no_ext = RemoveExtension();
+  // If the new extension is "" or ".", then just remove the current extension.
+  if (extension.empty() || extension == StringType(1, kExtensionSeparator))
+    return no_ext;
+
+  StringType str = no_ext.value();
+  if (extension[0] != kExtensionSeparator)
+    str.append(1, kExtensionSeparator);
+  str.append(extension);
+  return FilePath(str);
+}
+
+bool FilePath::MatchesExtension(const StringType& extension) const {
+  DCHECK(extension.empty() || extension[0] == kExtensionSeparator);
+
+  StringType current_extension = Extension();
+
+  if (current_extension.length() != extension.length())
+    return false;
+
+  return FilePath::CompareEqualIgnoreCase(extension, current_extension);
+}
+
+FilePath FilePath::Append(const StringType& component) const {
+  const StringType* appended = &component;
+  StringType without_nuls;
+
+  StringType::size_type nul_pos = component.find(kStringTerminator);
+  if (nul_pos != StringType::npos) {
+    without_nuls = component.substr(0, nul_pos);
+    appended = &without_nuls;
+  }
+
+  DCHECK(!IsPathAbsolute(*appended));
+
+  if (path_.compare(kCurrentDirectory) == 0) {
+    // Append normally doesn't do any normalization, but as a special case,
+    // when appending to kCurrentDirectory, just return a new path for the
+    // component argument.  Appending component to kCurrentDirectory would
+    // serve no purpose other than needlessly lengthening the path, and
+    // it's likely in practice to wind up with FilePath objects containing
+    // only kCurrentDirectory when calling DirName on a single relative path
+    // component.
+    return FilePath(*appended);
+  }
+
+  FilePath new_path(path_);
+  new_path.StripTrailingSeparatorsInternal();
+
+  // Don't append a separator if the path is empty (indicating the current
+  // directory) or if the path component is empty (indicating nothing to
+  // append).
+  if (appended->length() > 0 && new_path.path_.length() > 0) {
+    // Don't append a separator if the path still ends with a trailing
+    // separator after stripping (indicating the root directory).
+    if (!IsSeparator(new_path.path_[new_path.path_.length() - 1])) {
+      // Don't append a separator if the path is just a drive letter.
+      if (FindDriveLetter(new_path.path_) + 1 != new_path.path_.length()) {
+        new_path.path_.append(1, kSeparators[0]);
+      }
+    }
+  }
+
+  new_path.path_.append(*appended);
+  return new_path;
+}
+
+FilePath FilePath::Append(const FilePath& component) const {
+  return Append(component.value());
+}
+
+FilePath FilePath::AppendASCII(const StringPiece& component) const {
+  DCHECK(base::IsStringASCII(component));
+#if defined(OS_WIN)
+  return Append(ASCIIToUTF16(component.as_string()));
+#elif defined(OS_POSIX)
+  return Append(component.as_string());
+#endif
+}
+
+bool FilePath::IsAbsolute() const {
+  return IsPathAbsolute(path_);
+}
+
+bool FilePath::EndsWithSeparator() const {
+  if (empty())
+    return false;
+  return IsSeparator(path_[path_.size() - 1]);
+}
+
+FilePath FilePath::AsEndingWithSeparator() const {
+  if (EndsWithSeparator() || path_.empty())
+    return *this;
+
+  StringType path_str;
+  path_str.reserve(path_.length() + 1);  // Only allocate string once.
+
+  path_str = path_;
+  path_str.append(&kSeparators[0], 1);
+  return FilePath(path_str);
+}
+
+FilePath FilePath::StripTrailingSeparators() const {
+  FilePath new_path(path_);
+  new_path.StripTrailingSeparatorsInternal();
+
+  return new_path;
+}
+
+bool FilePath::ReferencesParent() const {
+  std::vector<StringType> components;
+  GetComponents(&components);
+
+  std::vector<StringType>::const_iterator it = components.begin();
+  for (; it != components.end(); ++it) {
+    const StringType& component = *it;
+    // Windows has odd, undocumented behavior with path components containing
+    // only whitespace and . characters. So, if all we see is . and
+    // whitespace, then we treat any .. sequence as referencing parent.
+    // For simplicity we enforce this on all platforms.
+    if (component.find_first_not_of(FILE_PATH_LITERAL(". \n\r\t")) ==
+            std::string::npos &&
+        component.find(kParentDirectory) != std::string::npos) {
+      return true;
+    }
+  }
+  return false;
+}
+
+#if defined(OS_POSIX)
+// See file_path.h for a discussion of the encoding of paths on POSIX
+// platforms.  These encoding conversion functions are not quite correct.
+
+string16 FilePath::LossyDisplayName() const {
+  return WideToUTF16(SysNativeMBToWide(path_));
+}
+
+std::string FilePath::MaybeAsASCII() const {
+  if (base::IsStringASCII(path_))
+    return path_;
+  return std::string();
+}
+
+std::string FilePath::AsUTF8Unsafe() const {
+#if defined(SYSTEM_NATIVE_UTF8)
+  return value();
+#else
+  return WideToUTF8(SysNativeMBToWide(value()));
+#endif
+}
+
+string16 FilePath::AsUTF16Unsafe() const {
+#if defined(SYSTEM_NATIVE_UTF8)
+  return UTF8ToUTF16(value());
+#else
+  return WideToUTF16(SysNativeMBToWide(value()));
+#endif
+}
+
+// static
+FilePath FilePath::FromUTF8Unsafe(const std::string& utf8) {
+#if defined(SYSTEM_NATIVE_UTF8)
+  return FilePath(utf8);
+#else
+  return FilePath(SysWideToNativeMB(UTF8ToWide(utf8)));
+#endif
+}
+
+// static
+FilePath FilePath::FromUTF16Unsafe(const string16& utf16) {
+#if defined(SYSTEM_NATIVE_UTF8)
+  return FilePath(UTF16ToUTF8(utf16));
+#else
+  return FilePath(SysWideToNativeMB(UTF16ToWide(utf16)));
+#endif
+}
+
+#elif defined(OS_WIN)
+string16 FilePath::LossyDisplayName() const {
+  return path_;
+}
+
+std::string FilePath::MaybeAsASCII() const {
+  if (base::IsStringASCII(path_))
+    return UTF16ToASCII(path_);
+  return std::string();
+}
+
+std::string FilePath::AsUTF8Unsafe() const {
+  return WideToUTF8(value());
+}
+
+string16 FilePath::AsUTF16Unsafe() const {
+  return value();
+}
+
+// static
+FilePath FilePath::FromUTF8Unsafe(const std::string& utf8) {
+  return FilePath(UTF8ToWide(utf8));
+}
+
+// static
+FilePath FilePath::FromUTF16Unsafe(const string16& utf16) {
+  return FilePath(utf16);
+}
+#endif
+
+void FilePath::WriteToPickle(Pickle* pickle) const {
+#if defined(OS_WIN)
+  pickle->WriteString16(path_);
+#else
+  pickle->WriteString(path_);
+#endif
+}
+
+bool FilePath::ReadFromPickle(PickleIterator* iter) {
+#if defined(OS_WIN)
+  if (!iter->ReadString16(&path_))
+    return false;
+#else
+  if (!iter->ReadString(&path_))
+    return false;
+#endif
+
+  if (path_.find(kStringTerminator) != StringType::npos)
+    return false;
+
+  return true;
+}
+
+#if defined(OS_WIN)
+// Windows specific implementation of file string comparisons
+
+int FilePath::CompareIgnoreCase(const StringType& string1,
+                                const StringType& string2) {
+  // Perform character-wise upper case comparison rather than using the
+  // fully Unicode-aware CompareString(). For details see:
+  // http://blogs.msdn.com/michkap/archive/2005/10/17/481600.aspx
+  StringType::const_iterator i1 = string1.begin();
+  StringType::const_iterator i2 = string2.begin();
+  StringType::const_iterator string1end = string1.end();
+  StringType::const_iterator string2end = string2.end();
+  for ( ; i1 != string1end && i2 != string2end; ++i1, ++i2) {
+    wchar_t c1 =
+        (wchar_t)LOWORD(::CharUpperW((LPWSTR)(DWORD_PTR)MAKELONG(*i1, 0)));
+    wchar_t c2 =
+        (wchar_t)LOWORD(::CharUpperW((LPWSTR)(DWORD_PTR)MAKELONG(*i2, 0)));
+    if (c1 < c2)
+      return -1;
+    if (c1 > c2)
+      return 1;
+  }
+  if (i1 != string1end)
+    return 1;
+  if (i2 != string2end)
+    return -1;
+  return 0;
+}
+
+#elif defined(OS_MACOSX)
+// Mac OS X specific implementation of file string comparisons
+
+// cf. http://developer.apple.com/mac/library/technotes/tn/tn1150.html#UnicodeSubtleties
+//
+// "When using CreateTextEncoding to create a text encoding, you should set
+// the TextEncodingBase to kTextEncodingUnicodeV2_0, set the
+// TextEncodingVariant to kUnicodeCanonicalDecompVariant, and set the
+// TextEncodingFormat to kUnicode16BitFormat. Using these values ensures that
+// the Unicode will be in the same form as on an HFS Plus volume, even as the
+// Unicode standard evolves."
+//
+// Another technical article for X 10.4 updates this: one should use
+// the new (unambiguous) kUnicodeHFSPlusDecompVariant.
+// cf. http://developer.apple.com/mac/library/releasenotes/TextFonts/RN-TEC/index.html
+//
+// This implementation uses CFStringGetFileSystemRepresentation() to get the
+// decomposed form, and an adapted version of the FastUnicodeCompare as
+// described in the tech note to compare the strings.
+
+// Character conversion table for FastUnicodeCompare()
+//
+// The lower case table consists of a 256-entry high-byte table followed by
+// some number of 256-entry subtables. The high-byte table contains either an
+// offset to the subtable for characters with that high byte or zero, which
+// means that there are no case mappings or ignored characters in that block.
+// Ignored characters are mapped to zero.
+//
+// cf. downloadable file linked in
+// http://developer.apple.com/mac/library/technotes/tn/tn1150.html#StringComparisonAlgorithm
+
+namespace {
+
+const UInt16 lower_case_table[] = {
+  // High-byte indices ( == 0 iff no case mapping and no ignorables )
+
+  /* 0 */ 0x0100, 0x0200, 0x0000, 0x0300, 0x0400, 0x0500, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* 1 */ 0x0600, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* 2 */ 0x0700, 0x0800, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* 3 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* 4 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* 5 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* 6 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* 7 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* 8 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* 9 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* A */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* B */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* C */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* D */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* E */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* F */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+          0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0900, 0x0A00,
+
+  // Table 1 (for high byte 0x00)
+
+  /* 0 */ 0xFFFF, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+          0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+  /* 1 */ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+          0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+  /* 2 */ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+          0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+  /* 3 */ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+          0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+  /* 4 */ 0x0040, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+          0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+  /* 5 */ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+          0x0078, 0x0079, 0x007A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+  /* 6 */ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+          0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+  /* 7 */ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+          0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+  /* 8 */ 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
+          0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F,
+  /* 9 */ 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
+          0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F,
+  /* A */ 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+          0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF,
+  /* B */ 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7,
+          0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF,
+  /* C */ 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00E6, 0x00C7,
+          0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF,
+  /* D */ 0x00F0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7,
+          0x00F8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00FE, 0x00DF,
+  /* E */ 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7,
+          0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF,
+  /* F */ 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7,
+          0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF,
+
+  // Table 2 (for high byte 0x01)
+
+  /* 0 */ 0x0100, 0x0101, 0x0102, 0x0103, 0x0104, 0x0105, 0x0106, 0x0107,
+          0x0108, 0x0109, 0x010A, 0x010B, 0x010C, 0x010D, 0x010E, 0x010F,
+  /* 1 */ 0x0111, 0x0111, 0x0112, 0x0113, 0x0114, 0x0115, 0x0116, 0x0117,
+          0x0118, 0x0119, 0x011A, 0x011B, 0x011C, 0x011D, 0x011E, 0x011F,
+  /* 2 */ 0x0120, 0x0121, 0x0122, 0x0123, 0x0124, 0x0125, 0x0127, 0x0127,
+          0x0128, 0x0129, 0x012A, 0x012B, 0x012C, 0x012D, 0x012E, 0x012F,
+  /* 3 */ 0x0130, 0x0131, 0x0133, 0x0133, 0x0134, 0x0135, 0x0136, 0x0137,
+          0x0138, 0x0139, 0x013A, 0x013B, 0x013C, 0x013D, 0x013E, 0x0140,
+  /* 4 */ 0x0140, 0x0142, 0x0142, 0x0143, 0x0144, 0x0145, 0x0146, 0x0147,
+          0x0148, 0x0149, 0x014B, 0x014B, 0x014C, 0x014D, 0x014E, 0x014F,
+  /* 5 */ 0x0150, 0x0151, 0x0153, 0x0153, 0x0154, 0x0155, 0x0156, 0x0157,
+          0x0158, 0x0159, 0x015A, 0x015B, 0x015C, 0x015D, 0x015E, 0x015F,
+  /* 6 */ 0x0160, 0x0161, 0x0162, 0x0163, 0x0164, 0x0165, 0x0167, 0x0167,
+          0x0168, 0x0169, 0x016A, 0x016B, 0x016C, 0x016D, 0x016E, 0x016F,
+  /* 7 */ 0x0170, 0x0171, 0x0172, 0x0173, 0x0174, 0x0175, 0x0176, 0x0177,
+          0x0178, 0x0179, 0x017A, 0x017B, 0x017C, 0x017D, 0x017E, 0x017F,
+  /* 8 */ 0x0180, 0x0253, 0x0183, 0x0183, 0x0185, 0x0185, 0x0254, 0x0188,
+          0x0188, 0x0256, 0x0257, 0x018C, 0x018C, 0x018D, 0x01DD, 0x0259,
+  /* 9 */ 0x025B, 0x0192, 0x0192, 0x0260, 0x0263, 0x0195, 0x0269, 0x0268,
+          0x0199, 0x0199, 0x019A, 0x019B, 0x026F, 0x0272, 0x019E, 0x0275,
+  /* A */ 0x01A0, 0x01A1, 0x01A3, 0x01A3, 0x01A5, 0x01A5, 0x01A6, 0x01A8,
+          0x01A8, 0x0283, 0x01AA, 0x01AB, 0x01AD, 0x01AD, 0x0288, 0x01AF,
+  /* B */ 0x01B0, 0x028A, 0x028B, 0x01B4, 0x01B4, 0x01B6, 0x01B6, 0x0292,
+          0x01B9, 0x01B9, 0x01BA, 0x01BB, 0x01BD, 0x01BD, 0x01BE, 0x01BF,
+  /* C */ 0x01C0, 0x01C1, 0x01C2, 0x01C3, 0x01C6, 0x01C6, 0x01C6, 0x01C9,
+          0x01C9, 0x01C9, 0x01CC, 0x01CC, 0x01CC, 0x01CD, 0x01CE, 0x01CF,
+  /* D */ 0x01D0, 0x01D1, 0x01D2, 0x01D3, 0x01D4, 0x01D5, 0x01D6, 0x01D7,
+          0x01D8, 0x01D9, 0x01DA, 0x01DB, 0x01DC, 0x01DD, 0x01DE, 0x01DF,
+  /* E */ 0x01E0, 0x01E1, 0x01E2, 0x01E3, 0x01E5, 0x01E5, 0x01E6, 0x01E7,
+          0x01E8, 0x01E9, 0x01EA, 0x01EB, 0x01EC, 0x01ED, 0x01EE, 0x01EF,
+  /* F */ 0x01F0, 0x01F3, 0x01F3, 0x01F3, 0x01F4, 0x01F5, 0x01F6, 0x01F7,
+          0x01F8, 0x01F9, 0x01FA, 0x01FB, 0x01FC, 0x01FD, 0x01FE, 0x01FF,
+
+  // Table 3 (for high byte 0x03)
+
+  /* 0 */ 0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306, 0x0307,
+          0x0308, 0x0309, 0x030A, 0x030B, 0x030C, 0x030D, 0x030E, 0x030F,
+  /* 1 */ 0x0310, 0x0311, 0x0312, 0x0313, 0x0314, 0x0315, 0x0316, 0x0317,
+          0x0318, 0x0319, 0x031A, 0x031B, 0x031C, 0x031D, 0x031E, 0x031F,
+  /* 2 */ 0x0320, 0x0321, 0x0322, 0x0323, 0x0324, 0x0325, 0x0326, 0x0327,
+          0x0328, 0x0329, 0x032A, 0x032B, 0x032C, 0x032D, 0x032E, 0x032F,
+  /* 3 */ 0x0330, 0x0331, 0x0332, 0x0333, 0x0334, 0x0335, 0x0336, 0x0337,
+          0x0338, 0x0339, 0x033A, 0x033B, 0x033C, 0x033D, 0x033E, 0x033F,
+  /* 4 */ 0x0340, 0x0341, 0x0342, 0x0343, 0x0344, 0x0345, 0x0346, 0x0347,
+          0x0348, 0x0349, 0x034A, 0x034B, 0x034C, 0x034D, 0x034E, 0x034F,
+  /* 5 */ 0x0350, 0x0351, 0x0352, 0x0353, 0x0354, 0x0355, 0x0356, 0x0357,
+          0x0358, 0x0359, 0x035A, 0x035B, 0x035C, 0x035D, 0x035E, 0x035F,
+  /* 6 */ 0x0360, 0x0361, 0x0362, 0x0363, 0x0364, 0x0365, 0x0366, 0x0367,
+          0x0368, 0x0369, 0x036A, 0x036B, 0x036C, 0x036D, 0x036E, 0x036F,
+  /* 7 */ 0x0370, 0x0371, 0x0372, 0x0373, 0x0374, 0x0375, 0x0376, 0x0377,
+          0x0378, 0x0379, 0x037A, 0x037B, 0x037C, 0x037D, 0x037E, 0x037F,
+  /* 8 */ 0x0380, 0x0381, 0x0382, 0x0383, 0x0384, 0x0385, 0x0386, 0x0387,
+          0x0388, 0x0389, 0x038A, 0x038B, 0x038C, 0x038D, 0x038E, 0x038F,
+  /* 9 */ 0x0390, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7,
+          0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
+  /* A */ 0x03C0, 0x03C1, 0x03A2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7,
+          0x03C8, 0x03C9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF,
+  /* B */ 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7,
+          0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
+  /* C */ 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7,
+          0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0x03CF,
+  /* D */ 0x03D0, 0x03D1, 0x03D2, 0x03D3, 0x03D4, 0x03D5, 0x03D6, 0x03D7,
+          0x03D8, 0x03D9, 0x03DA, 0x03DB, 0x03DC, 0x03DD, 0x03DE, 0x03DF,
+  /* E */ 0x03E0, 0x03E1, 0x03E3, 0x03E3, 0x03E5, 0x03E5, 0x03E7, 0x03E7,
+          0x03E9, 0x03E9, 0x03EB, 0x03EB, 0x03ED, 0x03ED, 0x03EF, 0x03EF,
+  /* F */ 0x03F0, 0x03F1, 0x03F2, 0x03F3, 0x03F4, 0x03F5, 0x03F6, 0x03F7,
+          0x03F8, 0x03F9, 0x03FA, 0x03FB, 0x03FC, 0x03FD, 0x03FE, 0x03FF,
+
+  // Table 4 (for high byte 0x04)
+
+  /* 0 */ 0x0400, 0x0401, 0x0452, 0x0403, 0x0454, 0x0455, 0x0456, 0x0407,
+          0x0458, 0x0459, 0x045A, 0x045B, 0x040C, 0x040D, 0x040E, 0x045F,
+  /* 1 */ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+          0x0438, 0x0419, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
+  /* 2 */ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+          0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
+  /* 3 */ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+          0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
+  /* 4 */ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+          0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
+  /* 5 */ 0x0450, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457,
+          0x0458, 0x0459, 0x045A, 0x045B, 0x045C, 0x045D, 0x045E, 0x045F,
+  /* 6 */ 0x0461, 0x0461, 0x0463, 0x0463, 0x0465, 0x0465, 0x0467, 0x0467,
+          0x0469, 0x0469, 0x046B, 0x046B, 0x046D, 0x046D, 0x046F, 0x046F,
+  /* 7 */ 0x0471, 0x0471, 0x0473, 0x0473, 0x0475, 0x0475, 0x0476, 0x0477,
+          0x0479, 0x0479, 0x047B, 0x047B, 0x047D, 0x047D, 0x047F, 0x047F,
+  /* 8 */ 0x0481, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487,
+          0x0488, 0x0489, 0x048A, 0x048B, 0x048C, 0x048D, 0x048E, 0x048F,
+  /* 9 */ 0x0491, 0x0491, 0x0493, 0x0493, 0x0495, 0x0495, 0x0497, 0x0497,
+          0x0499, 0x0499, 0x049B, 0x049B, 0x049D, 0x049D, 0x049F, 0x049F,
+  /* A */ 0x04A1, 0x04A1, 0x04A3, 0x04A3, 0x04A5, 0x04A5, 0x04A7, 0x04A7,
+          0x04A9, 0x04A9, 0x04AB, 0x04AB, 0x04AD, 0x04AD, 0x04AF, 0x04AF,
+  /* B */ 0x04B1, 0x04B1, 0x04B3, 0x04B3, 0x04B5, 0x04B5, 0x04B7, 0x04B7,
+          0x04B9, 0x04B9, 0x04BB, 0x04BB, 0x04BD, 0x04BD, 0x04BF, 0x04BF,
+  /* C */ 0x04C0, 0x04C1, 0x04C2, 0x04C4, 0x04C4, 0x04C5, 0x04C6, 0x04C8,
+          0x04C8, 0x04C9, 0x04CA, 0x04CC, 0x04CC, 0x04CD, 0x04CE, 0x04CF,
+  /* D */ 0x04D0, 0x04D1, 0x04D2, 0x04D3, 0x04D4, 0x04D5, 0x04D6, 0x04D7,
+          0x04D8, 0x04D9, 0x04DA, 0x04DB, 0x04DC, 0x04DD, 0x04DE, 0x04DF,
+  /* E */ 0x04E0, 0x04E1, 0x04E2, 0x04E3, 0x04E4, 0x04E5, 0x04E6, 0x04E7,
+          0x04E8, 0x04E9, 0x04EA, 0x04EB, 0x04EC, 0x04ED, 0x04EE, 0x04EF,
+  /* F */ 0x04F0, 0x04F1, 0x04F2, 0x04F3, 0x04F4, 0x04F5, 0x04F6, 0x04F7,
+          0x04F8, 0x04F9, 0x04FA, 0x04FB, 0x04FC, 0x04FD, 0x04FE, 0x04FF,
+
+  // Table 5 (for high byte 0x05)
+
+  /* 0 */ 0x0500, 0x0501, 0x0502, 0x0503, 0x0504, 0x0505, 0x0506, 0x0507,
+          0x0508, 0x0509, 0x050A, 0x050B, 0x050C, 0x050D, 0x050E, 0x050F,
+  /* 1 */ 0x0510, 0x0511, 0x0512, 0x0513, 0x0514, 0x0515, 0x0516, 0x0517,
+          0x0518, 0x0519, 0x051A, 0x051B, 0x051C, 0x051D, 0x051E, 0x051F,
+  /* 2 */ 0x0520, 0x0521, 0x0522, 0x0523, 0x0524, 0x0525, 0x0526, 0x0527,
+          0x0528, 0x0529, 0x052A, 0x052B, 0x052C, 0x052D, 0x052E, 0x052F,
+  /* 3 */ 0x0530, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567,
+          0x0568, 0x0569, 0x056A, 0x056B, 0x056C, 0x056D, 0x056E, 0x056F,
+  /* 4 */ 0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577,
+          0x0578, 0x0579, 0x057A, 0x057B, 0x057C, 0x057D, 0x057E, 0x057F,
+  /* 5 */ 0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0557,
+          0x0558, 0x0559, 0x055A, 0x055B, 0x055C, 0x055D, 0x055E, 0x055F,
+  /* 6 */ 0x0560, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567,
+          0x0568, 0x0569, 0x056A, 0x056B, 0x056C, 0x056D, 0x056E, 0x056F,
+  /* 7 */ 0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577,
+          0x0578, 0x0579, 0x057A, 0x057B, 0x057C, 0x057D, 0x057E, 0x057F,
+  /* 8 */ 0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0587,
+          0x0588, 0x0589, 0x058A, 0x058B, 0x058C, 0x058D, 0x058E, 0x058F,
+  /* 9 */ 0x0590, 0x0591, 0x0592, 0x0593, 0x0594, 0x0595, 0x0596, 0x0597,
+          0x0598, 0x0599, 0x059A, 0x059B, 0x059C, 0x059D, 0x059E, 0x059F,
+  /* A */ 0x05A0, 0x05A1, 0x05A2, 0x05A3, 0x05A4, 0x05A5, 0x05A6, 0x05A7,
+          0x05A8, 0x05A9, 0x05AA, 0x05AB, 0x05AC, 0x05AD, 0x05AE, 0x05AF,
+  /* B */ 0x05B0, 0x05B1, 0x05B2, 0x05B3, 0x05B4, 0x05B5, 0x05B6, 0x05B7,
+          0x05B8, 0x05B9, 0x05BA, 0x05BB, 0x05BC, 0x05BD, 0x05BE, 0x05BF,
+  /* C */ 0x05C0, 0x05C1, 0x05C2, 0x05C3, 0x05C4, 0x05C5, 0x05C6, 0x05C7,
+          0x05C8, 0x05C9, 0x05CA, 0x05CB, 0x05CC, 0x05CD, 0x05CE, 0x05CF,
+  /* D */ 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7,
+          0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
+  /* E */ 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7,
+          0x05E8, 0x05E9, 0x05EA, 0x05EB, 0x05EC, 0x05ED, 0x05EE, 0x05EF,
+  /* F */ 0x05F0, 0x05F1, 0x05F2, 0x05F3, 0x05F4, 0x05F5, 0x05F6, 0x05F7,
+          0x05F8, 0x05F9, 0x05FA, 0x05FB, 0x05FC, 0x05FD, 0x05FE, 0x05FF,
+
+  // Table 6 (for high byte 0x10)
+
+  /* 0 */ 0x1000, 0x1001, 0x1002, 0x1003, 0x1004, 0x1005, 0x1006, 0x1007,
+          0x1008, 0x1009, 0x100A, 0x100B, 0x100C, 0x100D, 0x100E, 0x100F,
+  /* 1 */ 0x1010, 0x1011, 0x1012, 0x1013, 0x1014, 0x1015, 0x1016, 0x1017,
+          0x1018, 0x1019, 0x101A, 0x101B, 0x101C, 0x101D, 0x101E, 0x101F,
+  /* 2 */ 0x1020, 0x1021, 0x1022, 0x1023, 0x1024, 0x1025, 0x1026, 0x1027,
+          0x1028, 0x1029, 0x102A, 0x102B, 0x102C, 0x102D, 0x102E, 0x102F,
+  /* 3 */ 0x1030, 0x1031, 0x1032, 0x1033, 0x1034, 0x1035, 0x1036, 0x1037,
+          0x1038, 0x1039, 0x103A, 0x103B, 0x103C, 0x103D, 0x103E, 0x103F,
+  /* 4 */ 0x1040, 0x1041, 0x1042, 0x1043, 0x1044, 0x1045, 0x1046, 0x1047,
+          0x1048, 0x1049, 0x104A, 0x104B, 0x104C, 0x104D, 0x104E, 0x104F,
+  /* 5 */ 0x1050, 0x1051, 0x1052, 0x1053, 0x1054, 0x1055, 0x1056, 0x1057,
+          0x1058, 0x1059, 0x105A, 0x105B, 0x105C, 0x105D, 0x105E, 0x105F,
+  /* 6 */ 0x1060, 0x1061, 0x1062, 0x1063, 0x1064, 0x1065, 0x1066, 0x1067,
+          0x1068, 0x1069, 0x106A, 0x106B, 0x106C, 0x106D, 0x106E, 0x106F,
+  /* 7 */ 0x1070, 0x1071, 0x1072, 0x1073, 0x1074, 0x1075, 0x1076, 0x1077,
+          0x1078, 0x1079, 0x107A, 0x107B, 0x107C, 0x107D, 0x107E, 0x107F,
+  /* 8 */ 0x1080, 0x1081, 0x1082, 0x1083, 0x1084, 0x1085, 0x1086, 0x1087,
+          0x1088, 0x1089, 0x108A, 0x108B, 0x108C, 0x108D, 0x108E, 0x108F,
+  /* 9 */ 0x1090, 0x1091, 0x1092, 0x1093, 0x1094, 0x1095, 0x1096, 0x1097,
+          0x1098, 0x1099, 0x109A, 0x109B, 0x109C, 0x109D, 0x109E, 0x109F,
+  /* A */ 0x10D0, 0x10D1, 0x10D2, 0x10D3, 0x10D4, 0x10D5, 0x10D6, 0x10D7,
+          0x10D8, 0x10D9, 0x10DA, 0x10DB, 0x10DC, 0x10DD, 0x10DE, 0x10DF,
+  /* B */ 0x10E0, 0x10E1, 0x10E2, 0x10E3, 0x10E4, 0x10E5, 0x10E6, 0x10E7,
+          0x10E8, 0x10E9, 0x10EA, 0x10EB, 0x10EC, 0x10ED, 0x10EE, 0x10EF,
+  /* C */ 0x10F0, 0x10F1, 0x10F2, 0x10F3, 0x10F4, 0x10F5, 0x10C6, 0x10C7,
+          0x10C8, 0x10C9, 0x10CA, 0x10CB, 0x10CC, 0x10CD, 0x10CE, 0x10CF,
+  /* D */ 0x10D0, 0x10D1, 0x10D2, 0x10D3, 0x10D4, 0x10D5, 0x10D6, 0x10D7,
+          0x10D8, 0x10D9, 0x10DA, 0x10DB, 0x10DC, 0x10DD, 0x10DE, 0x10DF,
+  /* E */ 0x10E0, 0x10E1, 0x10E2, 0x10E3, 0x10E4, 0x10E5, 0x10E6, 0x10E7,
+          0x10E8, 0x10E9, 0x10EA, 0x10EB, 0x10EC, 0x10ED, 0x10EE, 0x10EF,
+  /* F */ 0x10F0, 0x10F1, 0x10F2, 0x10F3, 0x10F4, 0x10F5, 0x10F6, 0x10F7,
+          0x10F8, 0x10F9, 0x10FA, 0x10FB, 0x10FC, 0x10FD, 0x10FE, 0x10FF,
+
+  // Table 7 (for high byte 0x20)
+
+  /* 0 */ 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007,
+          0x2008, 0x2009, 0x200A, 0x200B, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* 1 */ 0x2010, 0x2011, 0x2012, 0x2013, 0x2014, 0x2015, 0x2016, 0x2017,
+          0x2018, 0x2019, 0x201A, 0x201B, 0x201C, 0x201D, 0x201E, 0x201F,
+  /* 2 */ 0x2020, 0x2021, 0x2022, 0x2023, 0x2024, 0x2025, 0x2026, 0x2027,
+          0x2028, 0x2029, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x202F,
+  /* 3 */ 0x2030, 0x2031, 0x2032, 0x2033, 0x2034, 0x2035, 0x2036, 0x2037,
+          0x2038, 0x2039, 0x203A, 0x203B, 0x203C, 0x203D, 0x203E, 0x203F,
+  /* 4 */ 0x2040, 0x2041, 0x2042, 0x2043, 0x2044, 0x2045, 0x2046, 0x2047,
+          0x2048, 0x2049, 0x204A, 0x204B, 0x204C, 0x204D, 0x204E, 0x204F,
+  /* 5 */ 0x2050, 0x2051, 0x2052, 0x2053, 0x2054, 0x2055, 0x2056, 0x2057,
+          0x2058, 0x2059, 0x205A, 0x205B, 0x205C, 0x205D, 0x205E, 0x205F,
+  /* 6 */ 0x2060, 0x2061, 0x2062, 0x2063, 0x2064, 0x2065, 0x2066, 0x2067,
+          0x2068, 0x2069, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+  /* 7 */ 0x2070, 0x2071, 0x2072, 0x2073, 0x2074, 0x2075, 0x2076, 0x2077,
+          0x2078, 0x2079, 0x207A, 0x207B, 0x207C, 0x207D, 0x207E, 0x207F,
+  /* 8 */ 0x2080, 0x2081, 0x2082, 0x2083, 0x2084, 0x2085, 0x2086, 0x2087,
+          0x2088, 0x2089, 0x208A, 0x208B, 0x208C, 0x208D, 0x208E, 0x208F,
+  /* 9 */ 0x2090, 0x2091, 0x2092, 0x2093, 0x2094, 0x2095, 0x2096, 0x2097,
+          0x2098, 0x2099, 0x209A, 0x209B, 0x209C, 0x209D, 0x209E, 0x209F,
+  /* A */ 0x20A0, 0x20A1, 0x20A2, 0x20A3, 0x20A4, 0x20A5, 0x20A6, 0x20A7,
+          0x20A8, 0x20A9, 0x20AA, 0x20AB, 0x20AC, 0x20AD, 0x20AE, 0x20AF,
+  /* B */ 0x20B0, 0x20B1, 0x20B2, 0x20B3, 0x20B4, 0x20B5, 0x20B6, 0x20B7,
+          0x20B8, 0x20B9, 0x20BA, 0x20BB, 0x20BC, 0x20BD, 0x20BE, 0x20BF,
+  /* C */ 0x20C0, 0x20C1, 0x20C2, 0x20C3, 0x20C4, 0x20C5, 0x20C6, 0x20C7,
+          0x20C8, 0x20C9, 0x20CA, 0x20CB, 0x20CC, 0x20CD, 0x20CE, 0x20CF,
+  /* D */ 0x20D0, 0x20D1, 0x20D2, 0x20D3, 0x20D4, 0x20D5, 0x20D6, 0x20D7,
+          0x20D8, 0x20D9, 0x20DA, 0x20DB, 0x20DC, 0x20DD, 0x20DE, 0x20DF,
+  /* E */ 0x20E0, 0x20E1, 0x20E2, 0x20E3, 0x20E4, 0x20E5, 0x20E6, 0x20E7,
+          0x20E8, 0x20E9, 0x20EA, 0x20EB, 0x20EC, 0x20ED, 0x20EE, 0x20EF,
+  /* F */ 0x20F0, 0x20F1, 0x20F2, 0x20F3, 0x20F4, 0x20F5, 0x20F6, 0x20F7,
+          0x20F8, 0x20F9, 0x20FA, 0x20FB, 0x20FC, 0x20FD, 0x20FE, 0x20FF,
+
+  // Table 8 (for high byte 0x21)
+
+  /* 0 */ 0x2100, 0x2101, 0x2102, 0x2103, 0x2104, 0x2105, 0x2106, 0x2107,
+          0x2108, 0x2109, 0x210A, 0x210B, 0x210C, 0x210D, 0x210E, 0x210F,
+  /* 1 */ 0x2110, 0x2111, 0x2112, 0x2113, 0x2114, 0x2115, 0x2116, 0x2117,
+          0x2118, 0x2119, 0x211A, 0x211B, 0x211C, 0x211D, 0x211E, 0x211F,
+  /* 2 */ 0x2120, 0x2121, 0x2122, 0x2123, 0x2124, 0x2125, 0x2126, 0x2127,
+          0x2128, 0x2129, 0x212A, 0x212B, 0x212C, 0x212D, 0x212E, 0x212F,
+  /* 3 */ 0x2130, 0x2131, 0x2132, 0x2133, 0x2134, 0x2135, 0x2136, 0x2137,
+          0x2138, 0x2139, 0x213A, 0x213B, 0x213C, 0x213D, 0x213E, 0x213F,
+  /* 4 */ 0x2140, 0x2141, 0x2142, 0x2143, 0x2144, 0x2145, 0x2146, 0x2147,
+          0x2148, 0x2149, 0x214A, 0x214B, 0x214C, 0x214D, 0x214E, 0x214F,
+  /* 5 */ 0x2150, 0x2151, 0x2152, 0x2153, 0x2154, 0x2155, 0x2156, 0x2157,
+          0x2158, 0x2159, 0x215A, 0x215B, 0x215C, 0x215D, 0x215E, 0x215F,
+  /* 6 */ 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177,
+          0x2178, 0x2179, 0x217A, 0x217B, 0x217C, 0x217D, 0x217E, 0x217F,
+  /* 7 */ 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177,
+          0x2178, 0x2179, 0x217A, 0x217B, 0x217C, 0x217D, 0x217E, 0x217F,
+  /* 8 */ 0x2180, 0x2181, 0x2182, 0x2183, 0x2184, 0x2185, 0x2186, 0x2187,
+          0x2188, 0x2189, 0x218A, 0x218B, 0x218C, 0x218D, 0x218E, 0x218F,
+  /* 9 */ 0x2190, 0x2191, 0x2192, 0x2193, 0x2194, 0x2195, 0x2196, 0x2197,
+          0x2198, 0x2199, 0x219A, 0x219B, 0x219C, 0x219D, 0x219E, 0x219F,
+  /* A */ 0x21A0, 0x21A1, 0x21A2, 0x21A3, 0x21A4, 0x21A5, 0x21A6, 0x21A7,
+          0x21A8, 0x21A9, 0x21AA, 0x21AB, 0x21AC, 0x21AD, 0x21AE, 0x21AF,
+  /* B */ 0x21B0, 0x21B1, 0x21B2, 0x21B3, 0x21B4, 0x21B5, 0x21B6, 0x21B7,
+          0x21B8, 0x21B9, 0x21BA, 0x21BB, 0x21BC, 0x21BD, 0x21BE, 0x21BF,
+  /* C */ 0x21C0, 0x21C1, 0x21C2, 0x21C3, 0x21C4, 0x21C5, 0x21C6, 0x21C7,
+          0x21C8, 0x21C9, 0x21CA, 0x21CB, 0x21CC, 0x21CD, 0x21CE, 0x21CF,
+  /* D */ 0x21D0, 0x21D1, 0x21D2, 0x21D3, 0x21D4, 0x21D5, 0x21D6, 0x21D7,
+          0x21D8, 0x21D9, 0x21DA, 0x21DB, 0x21DC, 0x21DD, 0x21DE, 0x21DF,
+  /* E */ 0x21E0, 0x21E1, 0x21E2, 0x21E3, 0x21E4, 0x21E5, 0x21E6, 0x21E7,
+          0x21E8, 0x21E9, 0x21EA, 0x21EB, 0x21EC, 0x21ED, 0x21EE, 0x21EF,
+  /* F */ 0x21F0, 0x21F1, 0x21F2, 0x21F3, 0x21F4, 0x21F5, 0x21F6, 0x21F7,
+          0x21F8, 0x21F9, 0x21FA, 0x21FB, 0x21FC, 0x21FD, 0x21FE, 0x21FF,
+
+  // Table 9 (for high byte 0xFE)
+
+  /* 0 */ 0xFE00, 0xFE01, 0xFE02, 0xFE03, 0xFE04, 0xFE05, 0xFE06, 0xFE07,
+          0xFE08, 0xFE09, 0xFE0A, 0xFE0B, 0xFE0C, 0xFE0D, 0xFE0E, 0xFE0F,
+  /* 1 */ 0xFE10, 0xFE11, 0xFE12, 0xFE13, 0xFE14, 0xFE15, 0xFE16, 0xFE17,
+          0xFE18, 0xFE19, 0xFE1A, 0xFE1B, 0xFE1C, 0xFE1D, 0xFE1E, 0xFE1F,
+  /* 2 */ 0xFE20, 0xFE21, 0xFE22, 0xFE23, 0xFE24, 0xFE25, 0xFE26, 0xFE27,
+          0xFE28, 0xFE29, 0xFE2A, 0xFE2B, 0xFE2C, 0xFE2D, 0xFE2E, 0xFE2F,
+  /* 3 */ 0xFE30, 0xFE31, 0xFE32, 0xFE33, 0xFE34, 0xFE35, 0xFE36, 0xFE37,
+          0xFE38, 0xFE39, 0xFE3A, 0xFE3B, 0xFE3C, 0xFE3D, 0xFE3E, 0xFE3F,
+  /* 4 */ 0xFE40, 0xFE41, 0xFE42, 0xFE43, 0xFE44, 0xFE45, 0xFE46, 0xFE47,
+          0xFE48, 0xFE49, 0xFE4A, 0xFE4B, 0xFE4C, 0xFE4D, 0xFE4E, 0xFE4F,
+  /* 5 */ 0xFE50, 0xFE51, 0xFE52, 0xFE53, 0xFE54, 0xFE55, 0xFE56, 0xFE57,
+          0xFE58, 0xFE59, 0xFE5A, 0xFE5B, 0xFE5C, 0xFE5D, 0xFE5E, 0xFE5F,
+  /* 6 */ 0xFE60, 0xFE61, 0xFE62, 0xFE63, 0xFE64, 0xFE65, 0xFE66, 0xFE67,
+          0xFE68, 0xFE69, 0xFE6A, 0xFE6B, 0xFE6C, 0xFE6D, 0xFE6E, 0xFE6F,
+  /* 7 */ 0xFE70, 0xFE71, 0xFE72, 0xFE73, 0xFE74, 0xFE75, 0xFE76, 0xFE77,
+          0xFE78, 0xFE79, 0xFE7A, 0xFE7B, 0xFE7C, 0xFE7D, 0xFE7E, 0xFE7F,
+  /* 8 */ 0xFE80, 0xFE81, 0xFE82, 0xFE83, 0xFE84, 0xFE85, 0xFE86, 0xFE87,
+          0xFE88, 0xFE89, 0xFE8A, 0xFE8B, 0xFE8C, 0xFE8D, 0xFE8E, 0xFE8F,
+  /* 9 */ 0xFE90, 0xFE91, 0xFE92, 0xFE93, 0xFE94, 0xFE95, 0xFE96, 0xFE97,
+          0xFE98, 0xFE99, 0xFE9A, 0xFE9B, 0xFE9C, 0xFE9D, 0xFE9E, 0xFE9F,
+  /* A */ 0xFEA0, 0xFEA1, 0xFEA2, 0xFEA3, 0xFEA4, 0xFEA5, 0xFEA6, 0xFEA7,
+          0xFEA8, 0xFEA9, 0xFEAA, 0xFEAB, 0xFEAC, 0xFEAD, 0xFEAE, 0xFEAF,
+  /* B */ 0xFEB0, 0xFEB1, 0xFEB2, 0xFEB3, 0xFEB4, 0xFEB5, 0xFEB6, 0xFEB7,
+          0xFEB8, 0xFEB9, 0xFEBA, 0xFEBB, 0xFEBC, 0xFEBD, 0xFEBE, 0xFEBF,
+  /* C */ 0xFEC0, 0xFEC1, 0xFEC2, 0xFEC3, 0xFEC4, 0xFEC5, 0xFEC6, 0xFEC7,
+          0xFEC8, 0xFEC9, 0xFECA, 0xFECB, 0xFECC, 0xFECD, 0xFECE, 0xFECF,
+  /* D */ 0xFED0, 0xFED1, 0xFED2, 0xFED3, 0xFED4, 0xFED5, 0xFED6, 0xFED7,
+          0xFED8, 0xFED9, 0xFEDA, 0xFEDB, 0xFEDC, 0xFEDD, 0xFEDE, 0xFEDF,
+  /* E */ 0xFEE0, 0xFEE1, 0xFEE2, 0xFEE3, 0xFEE4, 0xFEE5, 0xFEE6, 0xFEE7,
+          0xFEE8, 0xFEE9, 0xFEEA, 0xFEEB, 0xFEEC, 0xFEED, 0xFEEE, 0xFEEF,
+  /* F */ 0xFEF0, 0xFEF1, 0xFEF2, 0xFEF3, 0xFEF4, 0xFEF5, 0xFEF6, 0xFEF7,
+          0xFEF8, 0xFEF9, 0xFEFA, 0xFEFB, 0xFEFC, 0xFEFD, 0xFEFE, 0x0000,
+
+  // Table 10 (for high byte 0xFF)
+
+  /* 0 */ 0xFF00, 0xFF01, 0xFF02, 0xFF03, 0xFF04, 0xFF05, 0xFF06, 0xFF07,
+          0xFF08, 0xFF09, 0xFF0A, 0xFF0B, 0xFF0C, 0xFF0D, 0xFF0E, 0xFF0F,
+  /* 1 */ 0xFF10, 0xFF11, 0xFF12, 0xFF13, 0xFF14, 0xFF15, 0xFF16, 0xFF17,
+          0xFF18, 0xFF19, 0xFF1A, 0xFF1B, 0xFF1C, 0xFF1D, 0xFF1E, 0xFF1F,
+  /* 2 */ 0xFF20, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47,
+          0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F,
+  /* 3 */ 0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57,
+          0xFF58, 0xFF59, 0xFF5A, 0xFF3B, 0xFF3C, 0xFF3D, 0xFF3E, 0xFF3F,
+  /* 4 */ 0xFF40, 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47,
+          0xFF48, 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F,
+  /* 5 */ 0xFF50, 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57,
+          0xFF58, 0xFF59, 0xFF5A, 0xFF5B, 0xFF5C, 0xFF5D, 0xFF5E, 0xFF5F,
+  /* 6 */ 0xFF60, 0xFF61, 0xFF62, 0xFF63, 0xFF64, 0xFF65, 0xFF66, 0xFF67,
+          0xFF68, 0xFF69, 0xFF6A, 0xFF6B, 0xFF6C, 0xFF6D, 0xFF6E, 0xFF6F,
+  /* 7 */ 0xFF70, 0xFF71, 0xFF72, 0xFF73, 0xFF74, 0xFF75, 0xFF76, 0xFF77,
+          0xFF78, 0xFF79, 0xFF7A, 0xFF7B, 0xFF7C, 0xFF7D, 0xFF7E, 0xFF7F,
+  /* 8 */ 0xFF80, 0xFF81, 0xFF82, 0xFF83, 0xFF84, 0xFF85, 0xFF86, 0xFF87,
+          0xFF88, 0xFF89, 0xFF8A, 0xFF8B, 0xFF8C, 0xFF8D, 0xFF8E, 0xFF8F,
+  /* 9 */ 0xFF90, 0xFF91, 0xFF92, 0xFF93, 0xFF94, 0xFF95, 0xFF96, 0xFF97,
+          0xFF98, 0xFF99, 0xFF9A, 0xFF9B, 0xFF9C, 0xFF9D, 0xFF9E, 0xFF9F,
+  /* A */ 0xFFA0, 0xFFA1, 0xFFA2, 0xFFA3, 0xFFA4, 0xFFA5, 0xFFA6, 0xFFA7,
+          0xFFA8, 0xFFA9, 0xFFAA, 0xFFAB, 0xFFAC, 0xFFAD, 0xFFAE, 0xFFAF,
+  /* B */ 0xFFB0, 0xFFB1, 0xFFB2, 0xFFB3, 0xFFB4, 0xFFB5, 0xFFB6, 0xFFB7,
+          0xFFB8, 0xFFB9, 0xFFBA, 0xFFBB, 0xFFBC, 0xFFBD, 0xFFBE, 0xFFBF,
+  /* C */ 0xFFC0, 0xFFC1, 0xFFC2, 0xFFC3, 0xFFC4, 0xFFC5, 0xFFC6, 0xFFC7,
+          0xFFC8, 0xFFC9, 0xFFCA, 0xFFCB, 0xFFCC, 0xFFCD, 0xFFCE, 0xFFCF,
+  /* D */ 0xFFD0, 0xFFD1, 0xFFD2, 0xFFD3, 0xFFD4, 0xFFD5, 0xFFD6, 0xFFD7,
+          0xFFD8, 0xFFD9, 0xFFDA, 0xFFDB, 0xFFDC, 0xFFDD, 0xFFDE, 0xFFDF,
+  /* E */ 0xFFE0, 0xFFE1, 0xFFE2, 0xFFE3, 0xFFE4, 0xFFE5, 0xFFE6, 0xFFE7,
+          0xFFE8, 0xFFE9, 0xFFEA, 0xFFEB, 0xFFEC, 0xFFED, 0xFFEE, 0xFFEF,
+  /* F */ 0xFFF0, 0xFFF1, 0xFFF2, 0xFFF3, 0xFFF4, 0xFFF5, 0xFFF6, 0xFFF7,
+          0xFFF8, 0xFFF9, 0xFFFA, 0xFFFB, 0xFFFC, 0xFFFD, 0xFFFE, 0xFFFF,
+};
+
+// Returns the next non-ignorable codepoint within string starting from the
+// position indicated by index, or zero if there are no more.
+// The passed-in index is automatically advanced as the characters in the input
+// HFS-decomposed UTF-8 strings are read.
+inline int HFSReadNextNonIgnorableCodepoint(const char* string,
+                                            int length,
+                                            int* index) {
+  int codepoint = 0;
+  while (*index < length && codepoint == 0) {
+    // CBU8_NEXT returns a value < 0 in error cases. For purposes of string
+    // comparison, we just use that value and flag it with DCHECK.
+    CBU8_NEXT(string, *index, length, codepoint);
+    DCHECK_GT(codepoint, 0);
+    if (codepoint > 0) {
+      // Check if there is a subtable for this upper byte.
+      int lookup_offset = lower_case_table[codepoint >> 8];
+      if (lookup_offset != 0)
+        codepoint = lower_case_table[lookup_offset + (codepoint & 0x00FF)];
+      // Note: codepoint1 may be again 0 at this point if the character was
+      // an ignorable.
+    }
+  }
+  return codepoint;
+}
+
+}  // anonymous namespace
+
+// Special UTF-8 version of FastUnicodeCompare. Cf:
+// http://developer.apple.com/mac/library/technotes/tn/tn1150.html#StringComparisonAlgorithm
+// The input strings must be in the special HFS decomposed form.
+int FilePath::HFSFastUnicodeCompare(const StringType& string1,
+                                    const StringType& string2) {
+  int length1 = string1.length();
+  int length2 = string2.length();
+  int index1 = 0;
+  int index2 = 0;
+
+  for (;;) {
+    int codepoint1 = HFSReadNextNonIgnorableCodepoint(string1.c_str(),
+                                                      length1,
+                                                      &index1);
+    int codepoint2 = HFSReadNextNonIgnorableCodepoint(string2.c_str(),
+                                                      length2,
+                                                      &index2);
+    if (codepoint1 != codepoint2)
+      return (codepoint1 < codepoint2) ? -1 : 1;
+    if (codepoint1 == 0) {
+      DCHECK_EQ(index1, length1);
+      DCHECK_EQ(index2, length2);
+      return 0;
+    }
+  }
+}
+
+StringType FilePath::GetHFSDecomposedForm(const StringType& string) {
+  ScopedCFTypeRef<CFStringRef> cfstring(
+      CFStringCreateWithBytesNoCopy(
+          NULL,
+          reinterpret_cast<const UInt8*>(string.c_str()),
+          string.length(),
+          kCFStringEncodingUTF8,
+          false,
+          kCFAllocatorNull));
+  // Query the maximum length needed to store the result. In most cases this
+  // will overestimate the required space. The return value also already
+  // includes the space needed for a terminating 0.
+  CFIndex length = CFStringGetMaximumSizeOfFileSystemRepresentation(cfstring);
+  DCHECK_GT(length, 0);  // should be at least 1 for the 0-terminator.
+  // Reserve enough space for CFStringGetFileSystemRepresentation to write into.
+  // Also set the length to the maximum so that we can shrink it later.
+  // (Increasing rather than decreasing it would clobber the string contents!)
+  StringType result;
+  result.reserve(length);
+  result.resize(length - 1);
+  Boolean success = CFStringGetFileSystemRepresentation(cfstring,
+                                                        &result[0],
+                                                        length);
+  if (success) {
+    // Reduce result.length() to actual string length.
+    result.resize(strlen(result.c_str()));
+  } else {
+    // An error occurred -> clear result.
+    result.clear();
+  }
+  return result;
+}
+
+int FilePath::CompareIgnoreCase(const StringType& string1,
+                                const StringType& string2) {
+  // Quick checks for empty strings - these speed things up a bit and make the
+  // following code cleaner.
+  if (string1.empty())
+    return string2.empty() ? 0 : -1;
+  if (string2.empty())
+    return 1;
+
+  StringType hfs1 = GetHFSDecomposedForm(string1);
+  StringType hfs2 = GetHFSDecomposedForm(string2);
+
+  // GetHFSDecomposedForm() returns an empty string in an error case.
+  if (hfs1.empty() || hfs2.empty()) {
+    NOTREACHED();
+    ScopedCFTypeRef<CFStringRef> cfstring1(
+        CFStringCreateWithBytesNoCopy(
+            NULL,
+            reinterpret_cast<const UInt8*>(string1.c_str()),
+            string1.length(),
+            kCFStringEncodingUTF8,
+            false,
+            kCFAllocatorNull));
+    ScopedCFTypeRef<CFStringRef> cfstring2(
+        CFStringCreateWithBytesNoCopy(
+            NULL,
+            reinterpret_cast<const UInt8*>(string2.c_str()),
+            string2.length(),
+            kCFStringEncodingUTF8,
+            false,
+            kCFAllocatorNull));
+    return CFStringCompare(cfstring1,
+                           cfstring2,
+                           kCFCompareCaseInsensitive);
+  }
+
+  return HFSFastUnicodeCompare(hfs1, hfs2);
+}
+
+#else  // << WIN. MACOSX | other (POSIX) >>
+
+// Generic (POSIX) implementation of file string comparison.
+// TODO(rolandsteiner) check if this is sufficient/correct.
+int FilePath::CompareIgnoreCase(const StringType& string1,
+                                const StringType& string2) {
+  int comparison = strcasecmp(string1.c_str(), string2.c_str());
+  if (comparison < 0)
+    return -1;
+  if (comparison > 0)
+    return 1;
+  return 0;
+}
+
+#endif  // OS versions of CompareIgnoreCase()
+
+
+void FilePath::StripTrailingSeparatorsInternal() {
+  // If there is no drive letter, start will be 1, which will prevent stripping
+  // the leading separator if there is only one separator.  If there is a drive
+  // letter, start will be set appropriately to prevent stripping the first
+  // separator following the drive letter, if a separator immediately follows
+  // the drive letter.
+  StringType::size_type start = FindDriveLetter(path_) + 2;
+
+  StringType::size_type last_stripped = StringType::npos;
+  for (StringType::size_type pos = path_.length();
+       pos > start && IsSeparator(path_[pos - 1]);
+       --pos) {
+    // If the string only has two separators and they're at the beginning,
+    // don't strip them, unless the string began with more than two separators.
+    if (pos != start + 1 || last_stripped == start + 2 ||
+        !IsSeparator(path_[start - 1])) {
+      path_.resize(pos - 1);
+      last_stripped = pos;
+    }
+  }
+}
+
+FilePath FilePath::NormalizePathSeparators() const {
+  return NormalizePathSeparatorsTo(kSeparators[0]);
+}
+
+FilePath FilePath::NormalizePathSeparatorsTo(CharType separator) const {
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+  DCHECK_NE(kSeparators + kSeparatorsLength,
+            std::find(kSeparators, kSeparators + kSeparatorsLength, separator));
+  StringType copy = path_;
+  for (size_t i = 0; i < kSeparatorsLength; ++i) {
+    std::replace(copy.begin(), copy.end(), kSeparators[i], separator);
+  }
+  return FilePath(copy);
+#else
+  return *this;
+#endif
+}
+
+#if defined(OS_ANDROID)
+bool FilePath::IsContentUri() const {
+  return StartsWithASCII(path_, "content://", false /*case_sensitive*/);
+}
+#endif
+
+}  // namespace base
diff --git a/base/files/file_path.h b/base/files/file_path.h
new file mode 100644
index 0000000..0c84af6
--- /dev/null
+++ b/base/files/file_path.h
@@ -0,0 +1,469 @@
+// Copyright (c) 2012 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.
+
+// FilePath is a container for pathnames stored in a platform's native string
+// type, providing containers for manipulation in according with the
+// platform's conventions for pathnames.  It supports the following path
+// types:
+//
+//                   POSIX            Windows
+//                   ---------------  ----------------------------------
+// Fundamental type  char[]           wchar_t[]
+// Encoding          unspecified*     UTF-16
+// Separator         /                \, tolerant of /
+// Drive letters     no               case-insensitive A-Z followed by :
+// Alternate root    // (surprise!)   \\, for UNC paths
+//
+// * The encoding need not be specified on POSIX systems, although some
+//   POSIX-compliant systems do specify an encoding.  Mac OS X uses UTF-8.
+//   Chrome OS also uses UTF-8.
+//   Linux does not specify an encoding, but in practice, the locale's
+//   character set may be used.
+//
+// For more arcane bits of path trivia, see below.
+//
+// FilePath objects are intended to be used anywhere paths are.  An
+// application may pass FilePath objects around internally, masking the
+// underlying differences between systems, only differing in implementation
+// where interfacing directly with the system.  For example, a single
+// OpenFile(const FilePath &) function may be made available, allowing all
+// callers to operate without regard to the underlying implementation.  On
+// POSIX-like platforms, OpenFile might wrap fopen, and on Windows, it might
+// wrap _wfopen_s, perhaps both by calling file_path.value().c_str().  This
+// allows each platform to pass pathnames around without requiring conversions
+// between encodings, which has an impact on performance, but more imporantly,
+// has an impact on correctness on platforms that do not have well-defined
+// encodings for pathnames.
+//
+// Several methods are available to perform common operations on a FilePath
+// object, such as determining the parent directory (DirName), isolating the
+// final path component (BaseName), and appending a relative pathname string
+// to an existing FilePath object (Append).  These methods are highly
+// recommended over attempting to split and concatenate strings directly.
+// These methods are based purely on string manipulation and knowledge of
+// platform-specific pathname conventions, and do not consult the filesystem
+// at all, making them safe to use without fear of blocking on I/O operations.
+// These methods do not function as mutators but instead return distinct
+// instances of FilePath objects, and are therefore safe to use on const
+// objects.  The objects themselves are safe to share between threads.
+//
+// To aid in initialization of FilePath objects from string literals, a
+// FILE_PATH_LITERAL macro is provided, which accounts for the difference
+// between char[]-based pathnames on POSIX systems and wchar_t[]-based
+// pathnames on Windows.
+//
+// As a precaution against premature truncation, paths can't contain NULs.
+//
+// Because a FilePath object should not be instantiated at the global scope,
+// instead, use a FilePath::CharType[] and initialize it with
+// FILE_PATH_LITERAL.  At runtime, a FilePath object can be created from the
+// character array.  Example:
+//
+// | const FilePath::CharType kLogFileName[] = FILE_PATH_LITERAL("log.txt");
+// |
+// | void Function() {
+// |   FilePath log_file_path(kLogFileName);
+// |   [...]
+// | }
+//
+// WARNING: FilePaths should ALWAYS be displayed with LTR directionality, even
+// when the UI language is RTL. This means you always need to pass filepaths
+// through base::i18n::WrapPathWithLTRFormatting() before displaying it in the
+// RTL UI.
+//
+// This is a very common source of bugs, please try to keep this in mind.
+//
+// ARCANE BITS OF PATH TRIVIA
+//
+//  - A double leading slash is actually part of the POSIX standard.  Systems
+//    are allowed to treat // as an alternate root, as Windows does for UNC
+//    (network share) paths.  Most POSIX systems don't do anything special
+//    with two leading slashes, but FilePath handles this case properly
+//    in case it ever comes across such a system.  FilePath needs this support
+//    for Windows UNC paths, anyway.
+//    References:
+//    The Open Group Base Specifications Issue 7, sections 3.267 ("Pathname")
+//    and 4.12 ("Pathname Resolution"), available at:
+//    http://www.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_267
+//    http://www.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_12
+//
+//  - Windows treats c:\\ the same way it treats \\.  This was intended to
+//    allow older applications that require drive letters to support UNC paths
+//    like \\server\share\path, by permitting c:\\server\share\path as an
+//    equivalent.  Since the OS treats these paths specially, FilePath needs
+//    to do the same.  Since Windows can use either / or \ as the separator,
+//    FilePath treats c://, c:\\, //, and \\ all equivalently.
+//    Reference:
+//    The Old New Thing, "Why is a drive letter permitted in front of UNC
+//    paths (sometimes)?", available at:
+//    http://blogs.msdn.com/oldnewthing/archive/2005/11/22/495740.aspx
+
+#ifndef BASE_FILES_FILE_PATH_H_
+#define BASE_FILES_FILE_PATH_H_
+
+#include <stddef.h>
+
+#include <iosfwd>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/containers/hash_tables.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"  // For implicit conversions.
+#include "build/build_config.h"
+
+// Windows-style drive letter support and pathname separator characters can be
+// enabled and disabled independently, to aid testing.  These #defines are
+// here so that the same setting can be used in both the implementation and
+// in the unit test.
+#if defined(OS_WIN)
+#define FILE_PATH_USES_DRIVE_LETTERS
+#define FILE_PATH_USES_WIN_SEPARATORS
+#endif  // OS_WIN
+
+namespace base {
+
+class Pickle;
+class PickleIterator;
+
+// An abstraction to isolate users from the differences between native
+// pathnames on different platforms.
+class BASE_EXPORT FilePath {
+ public:
+#if defined(OS_POSIX)
+  // On most platforms, native pathnames are char arrays, and the encoding
+  // may or may not be specified.  On Mac OS X, native pathnames are encoded
+  // in UTF-8.
+  typedef std::string StringType;
+#elif defined(OS_WIN)
+  // On Windows, for Unicode-aware applications, native pathnames are wchar_t
+  // arrays encoded in UTF-16.
+  typedef std::wstring StringType;
+#endif  // OS_WIN
+
+  typedef StringType::value_type CharType;
+
+  // Null-terminated array of separators used to separate components in
+  // hierarchical paths.  Each character in this array is a valid separator,
+  // but kSeparators[0] is treated as the canonical separator and will be used
+  // when composing pathnames.
+  static const CharType kSeparators[];
+
+  // arraysize(kSeparators).
+  static const size_t kSeparatorsLength;
+
+  // A special path component meaning "this directory."
+  static const CharType kCurrentDirectory[];
+
+  // A special path component meaning "the parent directory."
+  static const CharType kParentDirectory[];
+
+  // The character used to identify a file extension.
+  static const CharType kExtensionSeparator;
+
+  FilePath();
+  FilePath(const FilePath& that);
+  explicit FilePath(const StringType& path);
+  ~FilePath();
+  FilePath& operator=(const FilePath& that);
+
+  bool operator==(const FilePath& that) const;
+
+  bool operator!=(const FilePath& that) const;
+
+  // Required for some STL containers and operations
+  bool operator<(const FilePath& that) const {
+    return path_ < that.path_;
+  }
+
+  const StringType& value() const { return path_; }
+
+  bool empty() const { return path_.empty(); }
+
+  void clear() { path_.clear(); }
+
+  // Returns true if |character| is in kSeparators.
+  static bool IsSeparator(CharType character);
+
+  // Returns a vector of all of the components of the provided path. It is
+  // equivalent to calling DirName().value() on the path's root component,
+  // and BaseName().value() on each child component.
+  //
+  // To make sure this is lossless so we can differentiate absolute and
+  // relative paths, the root slash will be included even though no other
+  // slashes will be. The precise behavior is:
+  //
+  // Posix:  "/foo/bar"  ->  [ "/", "foo", "bar" ]
+  // Windows:  "C:\foo\bar"  ->  [ "C:", "\\", "foo", "bar" ]
+  void GetComponents(std::vector<FilePath::StringType>* components) const;
+
+  // Returns true if this FilePath is a strict parent of the |child|. Absolute
+  // and relative paths are accepted i.e. is /foo parent to /foo/bar and
+  // is foo parent to foo/bar. Does not convert paths to absolute, follow
+  // symlinks or directory navigation (e.g. ".."). A path is *NOT* its own
+  // parent.
+  bool IsParent(const FilePath& child) const;
+
+  // If IsParent(child) holds, appends to path (if non-NULL) the
+  // relative path to child and returns true.  For example, if parent
+  // holds "/Users/johndoe/Library/Application Support", child holds
+  // "/Users/johndoe/Library/Application Support/Google/Chrome/Default", and
+  // *path holds "/Users/johndoe/Library/Caches", then after
+  // parent.AppendRelativePath(child, path) is called *path will hold
+  // "/Users/johndoe/Library/Caches/Google/Chrome/Default".  Otherwise,
+  // returns false.
+  bool AppendRelativePath(const FilePath& child, FilePath* path) const;
+
+  // Returns a FilePath corresponding to the directory containing the path
+  // named by this object, stripping away the file component.  If this object
+  // only contains one component, returns a FilePath identifying
+  // kCurrentDirectory.  If this object already refers to the root directory,
+  // returns a FilePath identifying the root directory.
+  FilePath DirName() const WARN_UNUSED_RESULT;
+
+  // Returns a FilePath corresponding to the last path component of this
+  // object, either a file or a directory.  If this object already refers to
+  // the root directory, returns a FilePath identifying the root directory;
+  // this is the only situation in which BaseName will return an absolute path.
+  FilePath BaseName() const WARN_UNUSED_RESULT;
+
+  // Returns ".jpg" for path "C:\pics\jojo.jpg", or an empty string if
+  // the file has no extension.  If non-empty, Extension() will always start
+  // with precisely one ".".  The following code should always work regardless
+  // of the value of path.  For common double-extensions like .tar.gz and
+  // .user.js, this method returns the combined extension.  For a single
+  // component, use FinalExtension().
+  // new_path = path.RemoveExtension().value().append(path.Extension());
+  // 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 WARN_UNUSED_RESULT;
+
+  // Returns the path's file extension, as in Extension(), but will
+  // never return a double extension.
+  //
+  // TODO(davidben): Check all our extension-sensitive code to see if
+  // 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 WARN_UNUSED_RESULT;
+
+  // Returns "C:\pics\jojo" for path "C:\pics\jojo.jpg"
+  // NOTE: this is slightly different from the similar file_util implementation
+  // which returned simply 'jojo'.
+  FilePath RemoveExtension() const WARN_UNUSED_RESULT;
+
+  // Removes the path's file extension, as in RemoveExtension(), but
+  // ignores double extensions.
+  FilePath RemoveFinalExtension() const WARN_UNUSED_RESULT;
+
+  // Inserts |suffix| after the file name portion of |path| but before the
+  // extension.  Returns "" if BaseName() == "." or "..".
+  // Examples:
+  // path == "C:\pics\jojo.jpg" suffix == " (1)", returns "C:\pics\jojo (1).jpg"
+  // path == "jojo.jpg"         suffix == " (1)", returns "jojo (1).jpg"
+  // path == "C:\pics\jojo"     suffix == " (1)", returns "C:\pics\jojo (1)"
+  // path == "C:\pics.old\jojo" suffix == " (1)", returns "C:\pics.old\jojo (1)"
+  FilePath InsertBeforeExtension(
+      const StringType& suffix) const WARN_UNUSED_RESULT;
+  FilePath InsertBeforeExtensionASCII(
+      const base::StringPiece& suffix) const WARN_UNUSED_RESULT;
+
+  // Adds |extension| to |file_name|. Returns the current FilePath if
+  // |extension| is empty. Returns "" if BaseName() == "." or "..".
+  FilePath AddExtension(
+      const StringType& extension) const WARN_UNUSED_RESULT;
+
+  // Replaces the extension of |file_name| with |extension|.  If |file_name|
+  // does not have an extension, then |extension| is added.  If |extension| is
+  // empty, then the extension is removed from |file_name|.
+  // Returns "" if BaseName() == "." or "..".
+  FilePath ReplaceExtension(
+      const StringType& extension) const WARN_UNUSED_RESULT;
+
+  // Returns true if the file path matches the specified extension. The test is
+  // case insensitive. Don't forget the leading period if appropriate.
+  bool MatchesExtension(const StringType& extension) const;
+
+  // Returns a FilePath by appending a separator and the supplied path
+  // component to this object's path.  Append takes care to avoid adding
+  // excessive separators if this object's path already ends with a separator.
+  // If this object's path is kCurrentDirectory, a new FilePath corresponding
+  // only to |component| is returned.  |component| must be a relative path;
+  // it is an error to pass an absolute path.
+  FilePath Append(const StringType& component) const WARN_UNUSED_RESULT;
+  FilePath Append(const FilePath& component) const WARN_UNUSED_RESULT;
+
+  // Although Windows StringType is std::wstring, since the encoding it uses for
+  // paths is well defined, it can handle ASCII path components as well.
+  // Mac uses UTF8, and since ASCII is a subset of that, it works there as well.
+  // On Linux, although it can use any 8-bit encoding for paths, we assume that
+  // ASCII is a valid subset, regardless of the encoding, since many operating
+  // system paths will always be ASCII.
+  FilePath AppendASCII(const base::StringPiece& component)
+      const WARN_UNUSED_RESULT;
+
+  // Returns true if this FilePath contains an absolute path.  On Windows, an
+  // absolute path begins with either a drive letter specification followed by
+  // a separator character, or with two separator characters.  On POSIX
+  // platforms, an absolute path begins with a separator character.
+  bool IsAbsolute() const;
+
+  // Returns true if the patch ends with a path separator character.
+  bool EndsWithSeparator() const WARN_UNUSED_RESULT;
+
+  // Returns a copy of this FilePath that ends with a trailing separator. If
+  // the input path is empty, an empty FilePath will be returned.
+  FilePath AsEndingWithSeparator() const WARN_UNUSED_RESULT;
+
+  // Returns a copy of this FilePath that does not end with a trailing
+  // separator.
+  FilePath StripTrailingSeparators() const WARN_UNUSED_RESULT;
+
+  // Returns true if this FilePath contains an attempt to reference a parent
+  // directory (e.g. has a path component that is "..").
+  bool ReferencesParent() const;
+
+  // Return a Unicode human-readable version of this path.
+  // Warning: you can *not*, in general, go from a display name back to a real
+  // path.  Only use this when displaying paths to users, not just when you
+  // want to stuff a string16 into some other API.
+  string16 LossyDisplayName() const;
+
+  // Return the path as ASCII, or the empty string if the path is not ASCII.
+  // This should only be used for cases where the FilePath is representing a
+  // known-ASCII filename.
+  std::string MaybeAsASCII() const;
+
+  // Return the path as UTF-8.
+  //
+  // This function is *unsafe* as there is no way to tell what encoding is
+  // used in file names on POSIX systems other than Mac and Chrome OS,
+  // although UTF-8 is practically used everywhere these days. To mitigate
+  // the encoding issue, this function internally calls
+  // SysNativeMBToWide() on POSIX systems other than Mac and Chrome OS,
+  // per assumption that the current locale's encoding is used in file
+  // names, but this isn't a perfect solution.
+  //
+  // Once it becomes safe to to stop caring about non-UTF-8 file names,
+  // the SysNativeMBToWide() hack will be removed from the code, along
+  // with "Unsafe" in the function name.
+  std::string AsUTF8Unsafe() const;
+
+  // Similar to AsUTF8Unsafe, but returns UTF-16 instead.
+  string16 AsUTF16Unsafe() const;
+
+  // Returns a FilePath object from a path name in UTF-8. This function
+  // should only be used for cases where you are sure that the input
+  // string is UTF-8.
+  //
+  // Like AsUTF8Unsafe(), this function is unsafe. This function
+  // internally calls SysWideToNativeMB() on POSIX systems other than Mac
+  // and Chrome OS, to mitigate the encoding issue. See the comment at
+  // AsUTF8Unsafe() for details.
+  static FilePath FromUTF8Unsafe(const std::string& utf8);
+
+  // Similar to FromUTF8Unsafe, but accepts UTF-16 instead.
+  static FilePath FromUTF16Unsafe(const string16& utf16);
+
+  void WriteToPickle(Pickle* pickle) const;
+  bool ReadFromPickle(PickleIterator* iter);
+
+  // Normalize all path separators to backslash on Windows
+  // (if FILE_PATH_USES_WIN_SEPARATORS is true), or do nothing on POSIX systems.
+  FilePath NormalizePathSeparators() const;
+
+  // Normalize all path separattors to given type on Windows
+  // (if FILE_PATH_USES_WIN_SEPARATORS is true), or do nothing on POSIX systems.
+  FilePath NormalizePathSeparatorsTo(CharType separator) const;
+
+  // Compare two strings in the same way the file system does.
+  // Note that these always ignore case, even on file systems that are case-
+  // sensitive. If case-sensitive comparison is ever needed, add corresponding
+  // methods here.
+  // The methods are written as a static method so that they can also be used
+  // on parts of a file path, e.g., just the extension.
+  // CompareIgnoreCase() returns -1, 0 or 1 for less-than, equal-to and
+  // greater-than respectively.
+  static int CompareIgnoreCase(const StringType& string1,
+                               const StringType& string2);
+  static bool CompareEqualIgnoreCase(const StringType& string1,
+                                     const StringType& string2) {
+    return CompareIgnoreCase(string1, string2) == 0;
+  }
+  static bool CompareLessIgnoreCase(const StringType& string1,
+                                    const StringType& string2) {
+    return CompareIgnoreCase(string1, string2) < 0;
+  }
+
+#if defined(OS_MACOSX)
+  // Returns the string in the special canonical decomposed form as defined for
+  // HFS, which is close to, but not quite, decomposition form D. See
+  // http://developer.apple.com/mac/library/technotes/tn/tn1150.html#UnicodeSubtleties
+  // for further comments.
+  // Returns the epmty string if the conversion failed.
+  static StringType GetHFSDecomposedForm(const FilePath::StringType& string);
+
+  // Special UTF-8 version of FastUnicodeCompare. Cf:
+  // http://developer.apple.com/mac/library/technotes/tn/tn1150.html#StringComparisonAlgorithm
+  // IMPORTANT: The input strings must be in the special HFS decomposed form!
+  // (cf. above GetHFSDecomposedForm method)
+  static int HFSFastUnicodeCompare(const StringType& string1,
+                                   const StringType& string2);
+#endif
+
+#if defined(OS_ANDROID)
+  // On android, file selection dialog can return a file with content uri
+  // scheme(starting with content://). Content uri needs to be opened with
+  // ContentResolver to guarantee that the app has appropriate permissions
+  // to access it.
+  // Returns true if the path is a content uri, or false otherwise.
+  bool IsContentUri() const;
+#endif
+
+ private:
+  // Remove trailing separators from this object.  If the path is absolute, it
+  // will never be stripped any more than to refer to the absolute root
+  // directory, so "////" will become "/", not "".  A leading pair of
+  // separators is never stripped, to support alternate roots.  This is used to
+  // support UNC paths on Windows.
+  void StripTrailingSeparatorsInternal();
+
+  StringType path_;
+};
+
+// This is required by googletest to print a readable output on test failures.
+// This is declared here for use in gtest-based unit tests but is defined in
+// the test_support_base target. Depend on that to use this in your unit test.
+// This should not be used in production code - call ToString() instead.
+void PrintTo(const FilePath& path, std::ostream* out);
+
+}  // namespace base
+
+// Macros for string literal initialization of FilePath::CharType[], and for
+// using a FilePath::CharType[] in a printf-style format string.
+#if defined(OS_POSIX)
+#define FILE_PATH_LITERAL(x) x
+#define PRFilePath "s"
+#elif defined(OS_WIN)
+#define FILE_PATH_LITERAL(x) L ## x
+#define PRFilePath "ls"
+#endif  // OS_WIN
+
+// Provide a hash function so that hash_sets and maps can contain FilePath
+// objects.
+namespace BASE_HASH_NAMESPACE {
+
+template<>
+struct hash<base::FilePath> {
+  size_t operator()(const base::FilePath& f) const {
+    return hash<base::FilePath::StringType>()(f.value());
+  }
+};
+
+}  // namespace BASE_HASH_NAMESPACE
+
+#endif  // BASE_FILES_FILE_PATH_H_
diff --git a/base/files/file_path_constants.cc b/base/files/file_path_constants.cc
new file mode 100644
index 0000000..34b17a6
--- /dev/null
+++ b/base/files/file_path_constants.cc
@@ -0,0 +1,22 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/file_path.h"
+
+namespace base {
+
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+const FilePath::CharType FilePath::kSeparators[] = FILE_PATH_LITERAL("\\/");
+#else  // FILE_PATH_USES_WIN_SEPARATORS
+const FilePath::CharType FilePath::kSeparators[] = FILE_PATH_LITERAL("/");
+#endif  // FILE_PATH_USES_WIN_SEPARATORS
+
+const size_t FilePath::kSeparatorsLength = arraysize(kSeparators);
+
+const FilePath::CharType FilePath::kCurrentDirectory[] = FILE_PATH_LITERAL(".");
+const FilePath::CharType FilePath::kParentDirectory[] = FILE_PATH_LITERAL("..");
+
+const FilePath::CharType FilePath::kExtensionSeparator = FILE_PATH_LITERAL('.');
+
+}  // namespace base
diff --git a/base/files/file_path_unittest.cc b/base/files/file_path_unittest.cc
new file mode 100644
index 0000000..60eaa8f
--- /dev/null
+++ b/base/files/file_path_unittest.cc
@@ -0,0 +1,1287 @@
+// Copyright (c) 2012 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 <sstream>
+
+#include "base/basictypes.h"
+#include "base/files/file_path.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+// This macro helps avoid wrapped lines in the test structs.
+#define FPL(x) FILE_PATH_LITERAL(x)
+
+// This macro constructs strings which can contain NULs.
+#define FPS(x) FilePath::StringType(FPL(x), arraysize(FPL(x)) - 1)
+
+namespace base {
+
+struct UnaryTestData {
+  const FilePath::CharType* input;
+  const FilePath::CharType* expected;
+};
+
+struct UnaryBooleanTestData {
+  const FilePath::CharType* input;
+  bool expected;
+};
+
+struct BinaryTestData {
+  const FilePath::CharType* inputs[2];
+  const FilePath::CharType* expected;
+};
+
+struct BinaryBooleanTestData {
+  const FilePath::CharType* inputs[2];
+  bool expected;
+};
+
+struct BinaryIntTestData {
+  const FilePath::CharType* inputs[2];
+  int expected;
+};
+
+struct UTF8TestData {
+  const FilePath::CharType* native;
+  const char* utf8;
+};
+
+// file_util winds up using autoreleased objects on the Mac, so this needs
+// to be a PlatformTest
+typedef PlatformTest FilePathTest;
+
+TEST_F(FilePathTest, DirName) {
+  const struct UnaryTestData cases[] = {
+    { FPL(""),              FPL(".") },
+    { FPL("aa"),            FPL(".") },
+    { FPL("/aa/bb"),        FPL("/aa") },
+    { FPL("/aa/bb/"),       FPL("/aa") },
+    { FPL("/aa/bb//"),      FPL("/aa") },
+    { FPL("/aa/bb/ccc"),    FPL("/aa/bb") },
+    { FPL("/aa"),           FPL("/") },
+    { FPL("/aa/"),          FPL("/") },
+    { FPL("/"),             FPL("/") },
+    { FPL("//"),            FPL("//") },
+    { FPL("///"),           FPL("/") },
+    { FPL("aa/"),           FPL(".") },
+    { FPL("aa/bb"),         FPL("aa") },
+    { FPL("aa/bb/"),        FPL("aa") },
+    { FPL("aa/bb//"),       FPL("aa") },
+    { FPL("aa//bb//"),      FPL("aa") },
+    { FPL("aa//bb/"),       FPL("aa") },
+    { FPL("aa//bb"),        FPL("aa") },
+    { FPL("//aa/bb"),       FPL("//aa") },
+    { FPL("//aa/"),         FPL("//") },
+    { FPL("//aa"),          FPL("//") },
+    { FPL("0:"),            FPL(".") },
+    { FPL("@:"),            FPL(".") },
+    { FPL("[:"),            FPL(".") },
+    { FPL("`:"),            FPL(".") },
+    { FPL("{:"),            FPL(".") },
+    { FPL("\xB3:"),         FPL(".") },
+    { FPL("\xC5:"),         FPL(".") },
+#if defined(OS_WIN)
+    { FPL("\x0143:"),       FPL(".") },
+#endif  // OS_WIN
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+    { FPL("c:"),            FPL("c:") },
+    { FPL("C:"),            FPL("C:") },
+    { FPL("A:"),            FPL("A:") },
+    { FPL("Z:"),            FPL("Z:") },
+    { FPL("a:"),            FPL("a:") },
+    { FPL("z:"),            FPL("z:") },
+    { FPL("c:aa"),          FPL("c:") },
+    { FPL("c:/"),           FPL("c:/") },
+    { FPL("c://"),          FPL("c://") },
+    { FPL("c:///"),         FPL("c:/") },
+    { FPL("c:/aa"),         FPL("c:/") },
+    { FPL("c:/aa/"),        FPL("c:/") },
+    { FPL("c:/aa/bb"),      FPL("c:/aa") },
+    { FPL("c:aa/bb"),       FPL("c:aa") },
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+    { FPL("\\aa\\bb"),      FPL("\\aa") },
+    { FPL("\\aa\\bb\\"),    FPL("\\aa") },
+    { FPL("\\aa\\bb\\\\"),  FPL("\\aa") },
+    { FPL("\\aa\\bb\\ccc"), FPL("\\aa\\bb") },
+    { FPL("\\aa"),          FPL("\\") },
+    { FPL("\\aa\\"),        FPL("\\") },
+    { FPL("\\"),            FPL("\\") },
+    { FPL("\\\\"),          FPL("\\\\") },
+    { FPL("\\\\\\"),        FPL("\\") },
+    { FPL("aa\\"),          FPL(".") },
+    { FPL("aa\\bb"),        FPL("aa") },
+    { FPL("aa\\bb\\"),      FPL("aa") },
+    { FPL("aa\\bb\\\\"),    FPL("aa") },
+    { FPL("aa\\\\bb\\\\"),  FPL("aa") },
+    { FPL("aa\\\\bb\\"),    FPL("aa") },
+    { FPL("aa\\\\bb"),      FPL("aa") },
+    { FPL("\\\\aa\\bb"),    FPL("\\\\aa") },
+    { FPL("\\\\aa\\"),      FPL("\\\\") },
+    { FPL("\\\\aa"),        FPL("\\\\") },
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+    { FPL("c:\\"),          FPL("c:\\") },
+    { FPL("c:\\\\"),        FPL("c:\\\\") },
+    { FPL("c:\\\\\\"),      FPL("c:\\") },
+    { FPL("c:\\aa"),        FPL("c:\\") },
+    { FPL("c:\\aa\\"),      FPL("c:\\") },
+    { FPL("c:\\aa\\bb"),    FPL("c:\\aa") },
+    { FPL("c:aa\\bb"),      FPL("c:aa") },
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+#endif  // FILE_PATH_USES_WIN_SEPARATORS
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    FilePath input(cases[i].input);
+    FilePath observed = input.DirName();
+    EXPECT_EQ(FilePath::StringType(cases[i].expected), observed.value()) <<
+              "i: " << i << ", input: " << input.value();
+  }
+}
+
+TEST_F(FilePathTest, BaseName) {
+  const struct UnaryTestData cases[] = {
+    { FPL(""),              FPL("") },
+    { FPL("aa"),            FPL("aa") },
+    { FPL("/aa/bb"),        FPL("bb") },
+    { FPL("/aa/bb/"),       FPL("bb") },
+    { FPL("/aa/bb//"),      FPL("bb") },
+    { FPL("/aa/bb/ccc"),    FPL("ccc") },
+    { FPL("/aa"),           FPL("aa") },
+    { FPL("/"),             FPL("/") },
+    { FPL("//"),            FPL("//") },
+    { FPL("///"),           FPL("/") },
+    { FPL("aa/"),           FPL("aa") },
+    { FPL("aa/bb"),         FPL("bb") },
+    { FPL("aa/bb/"),        FPL("bb") },
+    { FPL("aa/bb//"),       FPL("bb") },
+    { FPL("aa//bb//"),      FPL("bb") },
+    { FPL("aa//bb/"),       FPL("bb") },
+    { FPL("aa//bb"),        FPL("bb") },
+    { FPL("//aa/bb"),       FPL("bb") },
+    { FPL("//aa/"),         FPL("aa") },
+    { FPL("//aa"),          FPL("aa") },
+    { FPL("0:"),            FPL("0:") },
+    { FPL("@:"),            FPL("@:") },
+    { FPL("[:"),            FPL("[:") },
+    { FPL("`:"),            FPL("`:") },
+    { FPL("{:"),            FPL("{:") },
+    { FPL("\xB3:"),         FPL("\xB3:") },
+    { FPL("\xC5:"),         FPL("\xC5:") },
+#if defined(OS_WIN)
+    { FPL("\x0143:"),       FPL("\x0143:") },
+#endif  // OS_WIN
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+    { FPL("c:"),            FPL("") },
+    { FPL("C:"),            FPL("") },
+    { FPL("A:"),            FPL("") },
+    { FPL("Z:"),            FPL("") },
+    { FPL("a:"),            FPL("") },
+    { FPL("z:"),            FPL("") },
+    { FPL("c:aa"),          FPL("aa") },
+    { FPL("c:/"),           FPL("/") },
+    { FPL("c://"),          FPL("//") },
+    { FPL("c:///"),         FPL("/") },
+    { FPL("c:/aa"),         FPL("aa") },
+    { FPL("c:/aa/"),        FPL("aa") },
+    { FPL("c:/aa/bb"),      FPL("bb") },
+    { FPL("c:aa/bb"),       FPL("bb") },
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+    { FPL("\\aa\\bb"),      FPL("bb") },
+    { FPL("\\aa\\bb\\"),    FPL("bb") },
+    { FPL("\\aa\\bb\\\\"),  FPL("bb") },
+    { FPL("\\aa\\bb\\ccc"), FPL("ccc") },
+    { FPL("\\aa"),          FPL("aa") },
+    { FPL("\\"),            FPL("\\") },
+    { FPL("\\\\"),          FPL("\\\\") },
+    { FPL("\\\\\\"),        FPL("\\") },
+    { FPL("aa\\"),          FPL("aa") },
+    { FPL("aa\\bb"),        FPL("bb") },
+    { FPL("aa\\bb\\"),      FPL("bb") },
+    { FPL("aa\\bb\\\\"),    FPL("bb") },
+    { FPL("aa\\\\bb\\\\"),  FPL("bb") },
+    { FPL("aa\\\\bb\\"),    FPL("bb") },
+    { FPL("aa\\\\bb"),      FPL("bb") },
+    { FPL("\\\\aa\\bb"),    FPL("bb") },
+    { FPL("\\\\aa\\"),      FPL("aa") },
+    { FPL("\\\\aa"),        FPL("aa") },
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+    { FPL("c:\\"),          FPL("\\") },
+    { FPL("c:\\\\"),        FPL("\\\\") },
+    { FPL("c:\\\\\\"),      FPL("\\") },
+    { FPL("c:\\aa"),        FPL("aa") },
+    { FPL("c:\\aa\\"),      FPL("aa") },
+    { FPL("c:\\aa\\bb"),    FPL("bb") },
+    { FPL("c:aa\\bb"),      FPL("bb") },
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+#endif  // FILE_PATH_USES_WIN_SEPARATORS
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    FilePath input(cases[i].input);
+    FilePath observed = input.BaseName();
+    EXPECT_EQ(FilePath::StringType(cases[i].expected), observed.value()) <<
+              "i: " << i << ", input: " << input.value();
+  }
+}
+
+TEST_F(FilePathTest, Append) {
+  const struct BinaryTestData cases[] = {
+    { { FPL(""),           FPL("cc") }, FPL("cc") },
+    { { FPL("."),          FPL("ff") }, FPL("ff") },
+    { { FPL("/"),          FPL("cc") }, FPL("/cc") },
+    { { FPL("/aa"),        FPL("") },   FPL("/aa") },
+    { { FPL("/aa/"),       FPL("") },   FPL("/aa") },
+    { { FPL("//aa"),       FPL("") },   FPL("//aa") },
+    { { FPL("//aa/"),      FPL("") },   FPL("//aa") },
+    { { FPL("//"),         FPL("aa") }, FPL("//aa") },
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+    { { FPL("c:"),         FPL("a") },  FPL("c:a") },
+    { { FPL("c:"),         FPL("") },   FPL("c:") },
+    { { FPL("c:/"),        FPL("a") },  FPL("c:/a") },
+    { { FPL("c://"),       FPL("a") },  FPL("c://a") },
+    { { FPL("c:///"),      FPL("a") },  FPL("c:/a") },
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+    // Append introduces the default separator character, so these test cases
+    // need to be defined with different expected results on platforms that use
+    // different default separator characters.
+    { { FPL("\\"),         FPL("cc") }, FPL("\\cc") },
+    { { FPL("\\aa"),       FPL("") },   FPL("\\aa") },
+    { { FPL("\\aa\\"),     FPL("") },   FPL("\\aa") },
+    { { FPL("\\\\aa"),     FPL("") },   FPL("\\\\aa") },
+    { { FPL("\\\\aa\\"),   FPL("") },   FPL("\\\\aa") },
+    { { FPL("\\\\"),       FPL("aa") }, FPL("\\\\aa") },
+    { { FPL("/aa/bb"),     FPL("cc") }, FPL("/aa/bb\\cc") },
+    { { FPL("/aa/bb/"),    FPL("cc") }, FPL("/aa/bb\\cc") },
+    { { FPL("aa/bb/"),     FPL("cc") }, FPL("aa/bb\\cc") },
+    { { FPL("aa/bb"),      FPL("cc") }, FPL("aa/bb\\cc") },
+    { { FPL("a/b"),        FPL("c") },  FPL("a/b\\c") },
+    { { FPL("a/b/"),       FPL("c") },  FPL("a/b\\c") },
+    { { FPL("//aa"),       FPL("bb") }, FPL("//aa\\bb") },
+    { { FPL("//aa/"),      FPL("bb") }, FPL("//aa\\bb") },
+    { { FPL("\\aa\\bb"),   FPL("cc") }, FPL("\\aa\\bb\\cc") },
+    { { FPL("\\aa\\bb\\"), FPL("cc") }, FPL("\\aa\\bb\\cc") },
+    { { FPL("aa\\bb\\"),   FPL("cc") }, FPL("aa\\bb\\cc") },
+    { { FPL("aa\\bb"),     FPL("cc") }, FPL("aa\\bb\\cc") },
+    { { FPL("a\\b"),       FPL("c") },  FPL("a\\b\\c") },
+    { { FPL("a\\b\\"),     FPL("c") },  FPL("a\\b\\c") },
+    { { FPL("\\\\aa"),     FPL("bb") }, FPL("\\\\aa\\bb") },
+    { { FPL("\\\\aa\\"),   FPL("bb") }, FPL("\\\\aa\\bb") },
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+    { { FPL("c:\\"),       FPL("a") },  FPL("c:\\a") },
+    { { FPL("c:\\\\"),     FPL("a") },  FPL("c:\\\\a") },
+    { { FPL("c:\\\\\\"),   FPL("a") },  FPL("c:\\a") },
+    { { FPL("c:\\"),       FPL("") },   FPL("c:\\") },
+    { { FPL("c:\\a"),      FPL("b") },  FPL("c:\\a\\b") },
+    { { FPL("c:\\a\\"),    FPL("b") },  FPL("c:\\a\\b") },
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+#else  // FILE_PATH_USES_WIN_SEPARATORS
+    { { FPL("/aa/bb"),     FPL("cc") }, FPL("/aa/bb/cc") },
+    { { FPL("/aa/bb/"),    FPL("cc") }, FPL("/aa/bb/cc") },
+    { { FPL("aa/bb/"),     FPL("cc") }, FPL("aa/bb/cc") },
+    { { FPL("aa/bb"),      FPL("cc") }, FPL("aa/bb/cc") },
+    { { FPL("a/b"),        FPL("c") },  FPL("a/b/c") },
+    { { FPL("a/b/"),       FPL("c") },  FPL("a/b/c") },
+    { { FPL("//aa"),       FPL("bb") }, FPL("//aa/bb") },
+    { { FPL("//aa/"),      FPL("bb") }, FPL("//aa/bb") },
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+    { { FPL("c:/"),        FPL("a") },  FPL("c:/a") },
+    { { FPL("c:/"),        FPL("") },   FPL("c:/") },
+    { { FPL("c:/a"),       FPL("b") },  FPL("c:/a/b") },
+    { { FPL("c:/a/"),      FPL("b") },  FPL("c:/a/b") },
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+#endif  // FILE_PATH_USES_WIN_SEPARATORS
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    FilePath root(cases[i].inputs[0]);
+    FilePath::StringType leaf(cases[i].inputs[1]);
+    FilePath observed_str = root.Append(leaf);
+    EXPECT_EQ(FilePath::StringType(cases[i].expected), observed_str.value()) <<
+              "i: " << i << ", root: " << root.value() << ", leaf: " << leaf;
+    FilePath observed_path = root.Append(FilePath(leaf));
+    EXPECT_EQ(FilePath::StringType(cases[i].expected), observed_path.value()) <<
+              "i: " << i << ", root: " << root.value() << ", leaf: " << leaf;
+
+    // TODO(erikkay): It would be nice to have a unicode test append value to
+    // handle the case when AppendASCII is passed UTF8
+#if defined(OS_WIN)
+    std::string ascii = WideToUTF8(leaf);
+#elif defined(OS_POSIX)
+    std::string ascii = leaf;
+#endif
+    observed_str = root.AppendASCII(ascii);
+    EXPECT_EQ(FilePath::StringType(cases[i].expected), observed_str.value()) <<
+              "i: " << i << ", root: " << root.value() << ", leaf: " << leaf;
+  }
+}
+
+TEST_F(FilePathTest, StripTrailingSeparators) {
+  const struct UnaryTestData cases[] = {
+    { FPL(""),              FPL("") },
+    { FPL("/"),             FPL("/") },
+    { FPL("//"),            FPL("//") },
+    { FPL("///"),           FPL("/") },
+    { FPL("////"),          FPL("/") },
+    { FPL("a/"),            FPL("a") },
+    { FPL("a//"),           FPL("a") },
+    { FPL("a///"),          FPL("a") },
+    { FPL("a////"),         FPL("a") },
+    { FPL("/a"),            FPL("/a") },
+    { FPL("/a/"),           FPL("/a") },
+    { FPL("/a//"),          FPL("/a") },
+    { FPL("/a///"),         FPL("/a") },
+    { FPL("/a////"),        FPL("/a") },
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+    { FPL("c:"),            FPL("c:") },
+    { FPL("c:/"),           FPL("c:/") },
+    { FPL("c://"),          FPL("c://") },
+    { FPL("c:///"),         FPL("c:/") },
+    { FPL("c:////"),        FPL("c:/") },
+    { FPL("c:/a"),          FPL("c:/a") },
+    { FPL("c:/a/"),         FPL("c:/a") },
+    { FPL("c:/a//"),        FPL("c:/a") },
+    { FPL("c:/a///"),       FPL("c:/a") },
+    { FPL("c:/a////"),      FPL("c:/a") },
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+    { FPL("\\"),            FPL("\\") },
+    { FPL("\\\\"),          FPL("\\\\") },
+    { FPL("\\\\\\"),        FPL("\\") },
+    { FPL("\\\\\\\\"),      FPL("\\") },
+    { FPL("a\\"),           FPL("a") },
+    { FPL("a\\\\"),         FPL("a") },
+    { FPL("a\\\\\\"),       FPL("a") },
+    { FPL("a\\\\\\\\"),     FPL("a") },
+    { FPL("\\a"),           FPL("\\a") },
+    { FPL("\\a\\"),         FPL("\\a") },
+    { FPL("\\a\\\\"),       FPL("\\a") },
+    { FPL("\\a\\\\\\"),     FPL("\\a") },
+    { FPL("\\a\\\\\\\\"),   FPL("\\a") },
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+    { FPL("c:\\"),          FPL("c:\\") },
+    { FPL("c:\\\\"),        FPL("c:\\\\") },
+    { FPL("c:\\\\\\"),      FPL("c:\\") },
+    { FPL("c:\\\\\\\\"),    FPL("c:\\") },
+    { FPL("c:\\a"),         FPL("c:\\a") },
+    { FPL("c:\\a\\"),       FPL("c:\\a") },
+    { FPL("c:\\a\\\\"),     FPL("c:\\a") },
+    { FPL("c:\\a\\\\\\"),   FPL("c:\\a") },
+    { FPL("c:\\a\\\\\\\\"), FPL("c:\\a") },
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+#endif  // FILE_PATH_USES_WIN_SEPARATORS
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    FilePath input(cases[i].input);
+    FilePath observed = input.StripTrailingSeparators();
+    EXPECT_EQ(FilePath::StringType(cases[i].expected), observed.value()) <<
+              "i: " << i << ", input: " << input.value();
+  }
+}
+
+TEST_F(FilePathTest, IsAbsolute) {
+  const struct UnaryBooleanTestData cases[] = {
+    { FPL(""),       false },
+    { FPL("a"),      false },
+    { FPL("c:"),     false },
+    { FPL("c:a"),    false },
+    { FPL("a/b"),    false },
+    { FPL("//"),     true },
+    { FPL("//a"),    true },
+    { FPL("c:a/b"),  false },
+    { FPL("?:/a"),   false },
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+    { FPL("/"),      false },
+    { FPL("/a"),     false },
+    { FPL("/."),     false },
+    { FPL("/.."),    false },
+    { FPL("c:/"),    true },
+    { FPL("c:/a"),   true },
+    { FPL("c:/."),   true },
+    { FPL("c:/.."),  true },
+    { FPL("C:/a"),   true },
+    { FPL("d:/a"),   true },
+#else  // FILE_PATH_USES_DRIVE_LETTERS
+    { FPL("/"),      true },
+    { FPL("/a"),     true },
+    { FPL("/."),     true },
+    { FPL("/.."),    true },
+    { FPL("c:/"),    false },
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+    { FPL("a\\b"),   false },
+    { FPL("\\\\"),   true },
+    { FPL("\\\\a"),  true },
+    { FPL("a\\b"),   false },
+    { FPL("\\\\"),   true },
+    { FPL("//a"),    true },
+    { FPL("c:a\\b"), false },
+    { FPL("?:\\a"),  false },
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+    { FPL("\\"),     false },
+    { FPL("\\a"),    false },
+    { FPL("\\."),    false },
+    { FPL("\\.."),   false },
+    { FPL("c:\\"),   true },
+    { FPL("c:\\"),   true },
+    { FPL("c:\\a"),  true },
+    { FPL("c:\\."),  true },
+    { FPL("c:\\.."), true },
+    { FPL("C:\\a"),  true },
+    { FPL("d:\\a"),  true },
+#else  // FILE_PATH_USES_DRIVE_LETTERS
+    { FPL("\\"),     true },
+    { FPL("\\a"),    true },
+    { FPL("\\."),    true },
+    { FPL("\\.."),   true },
+    { FPL("c:\\"),   false },
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+#endif  // FILE_PATH_USES_WIN_SEPARATORS
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    FilePath input(cases[i].input);
+    bool observed = input.IsAbsolute();
+    EXPECT_EQ(cases[i].expected, observed) <<
+              "i: " << i << ", input: " << input.value();
+  }
+}
+
+TEST_F(FilePathTest, PathComponentsTest) {
+  const struct UnaryTestData cases[] = {
+    { FPL("//foo/bar/baz/"),          FPL("|//|foo|bar|baz")},
+    { FPL("///"),                     FPL("|/")},
+    { FPL("/foo//bar//baz/"),         FPL("|/|foo|bar|baz")},
+    { FPL("/foo/bar/baz/"),           FPL("|/|foo|bar|baz")},
+    { FPL("/foo/bar/baz//"),          FPL("|/|foo|bar|baz")},
+    { FPL("/foo/bar/baz///"),         FPL("|/|foo|bar|baz")},
+    { FPL("/foo/bar/baz"),            FPL("|/|foo|bar|baz")},
+    { FPL("/foo/bar.bot/baz.txt"),    FPL("|/|foo|bar.bot|baz.txt")},
+    { FPL("//foo//bar/baz"),          FPL("|//|foo|bar|baz")},
+    { FPL("/"),                       FPL("|/")},
+    { FPL("foo"),                     FPL("|foo")},
+    { FPL(""),                        FPL("")},
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+    { FPL("e:/foo"),                  FPL("|e:|/|foo")},
+    { FPL("e:/"),                     FPL("|e:|/")},
+    { FPL("e:"),                      FPL("|e:")},
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+    { FPL("../foo"),                  FPL("|..|foo")},
+    { FPL("./foo"),                   FPL("|foo")},
+    { FPL("../foo/bar/"),             FPL("|..|foo|bar") },
+    { FPL("\\\\foo\\bar\\baz\\"),     FPL("|\\\\|foo|bar|baz")},
+    { FPL("\\\\\\"),                  FPL("|\\")},
+    { FPL("\\foo\\\\bar\\\\baz\\"),   FPL("|\\|foo|bar|baz")},
+    { FPL("\\foo\\bar\\baz\\"),       FPL("|\\|foo|bar|baz")},
+    { FPL("\\foo\\bar\\baz\\\\"),     FPL("|\\|foo|bar|baz")},
+    { FPL("\\foo\\bar\\baz\\\\\\"),   FPL("|\\|foo|bar|baz")},
+    { FPL("\\foo\\bar\\baz"),         FPL("|\\|foo|bar|baz")},
+    { FPL("\\foo\\bar/baz\\\\\\"),    FPL("|\\|foo|bar|baz")},
+    { FPL("/foo\\bar\\baz"),          FPL("|/|foo|bar|baz")},
+    { FPL("\\foo\\bar.bot\\baz.txt"), FPL("|\\|foo|bar.bot|baz.txt")},
+    { FPL("\\\\foo\\\\bar\\baz"),     FPL("|\\\\|foo|bar|baz")},
+    { FPL("\\"),                      FPL("|\\")},
+#endif  // FILE_PATH_USES_WIN_SEPARATORS
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    FilePath input(cases[i].input);
+    std::vector<FilePath::StringType> comps;
+    input.GetComponents(&comps);
+
+    FilePath::StringType observed;
+    for (size_t j = 0; j < comps.size(); ++j) {
+      observed.append(FILE_PATH_LITERAL("|"), 1);
+      observed.append(comps[j]);
+    }
+    EXPECT_EQ(FilePath::StringType(cases[i].expected), observed) <<
+              "i: " << i << ", input: " << input.value();
+  }
+}
+
+TEST_F(FilePathTest, IsParentTest) {
+  const struct BinaryBooleanTestData cases[] = {
+    { { FPL("/"),             FPL("/foo/bar/baz") },      true},
+    { { FPL("/foo/bar"),      FPL("/foo/bar/baz") },      true},
+    { { FPL("/foo/bar/"),     FPL("/foo/bar/baz") },      true},
+    { { FPL("//foo/bar/"),    FPL("//foo/bar/baz") },     true},
+    { { FPL("/foo/bar"),      FPL("/foo2/bar/baz") },     false},
+    { { FPL("/foo/bar.txt"),  FPL("/foo/bar/baz") },      false},
+    { { FPL("/foo/bar"),      FPL("/foo/bar2/baz") },     false},
+    { { FPL("/foo/bar"),      FPL("/foo/bar") },          false},
+    { { FPL("/foo/bar/baz"),  FPL("/foo/bar") },          false},
+    { { FPL("foo/bar"),       FPL("foo/bar/baz") },       true},
+    { { FPL("foo/bar"),       FPL("foo2/bar/baz") },      false},
+    { { FPL("foo/bar"),       FPL("foo/bar2/baz") },      false},
+    { { FPL(""),              FPL("foo") },               false},
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+    { { FPL("c:/foo/bar"),    FPL("c:/foo/bar/baz") },    true},
+    { { FPL("E:/foo/bar"),    FPL("e:/foo/bar/baz") },    true},
+    { { FPL("f:/foo/bar"),    FPL("F:/foo/bar/baz") },    true},
+    { { FPL("E:/Foo/bar"),    FPL("e:/foo/bar/baz") },    false},
+    { { FPL("f:/foo/bar"),    FPL("F:/foo/Bar/baz") },    false},
+    { { FPL("c:/"),           FPL("c:/foo/bar/baz") },    true},
+    { { FPL("c:"),            FPL("c:/foo/bar/baz") },    true},
+    { { FPL("c:/foo/bar"),    FPL("d:/foo/bar/baz") },    false},
+    { { FPL("c:/foo/bar"),    FPL("D:/foo/bar/baz") },    false},
+    { { FPL("C:/foo/bar"),    FPL("d:/foo/bar/baz") },    false},
+    { { FPL("c:/foo/bar"),    FPL("c:/foo2/bar/baz") },   false},
+    { { FPL("e:/foo/bar"),    FPL("E:/foo2/bar/baz") },   false},
+    { { FPL("F:/foo/bar"),    FPL("f:/foo2/bar/baz") },   false},
+    { { FPL("c:/foo/bar"),    FPL("c:/foo/bar2/baz") },   false},
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+    { { FPL("\\foo\\bar"),    FPL("\\foo\\bar\\baz") },   true},
+    { { FPL("\\foo/bar"),     FPL("\\foo\\bar\\baz") },   true},
+    { { FPL("\\foo/bar"),     FPL("\\foo/bar/baz") },     true},
+    { { FPL("\\"),            FPL("\\foo\\bar\\baz") },   true},
+    { { FPL(""),              FPL("\\foo\\bar\\baz") },   false},
+    { { FPL("\\foo\\bar"),    FPL("\\foo2\\bar\\baz") },  false},
+    { { FPL("\\foo\\bar"),    FPL("\\foo\\bar2\\baz") },  false},
+#endif  // FILE_PATH_USES_WIN_SEPARATORS
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    FilePath parent(cases[i].inputs[0]);
+    FilePath child(cases[i].inputs[1]);
+
+    EXPECT_EQ(parent.IsParent(child), cases[i].expected) <<
+        "i: " << i << ", parent: " << parent.value() << ", child: " <<
+        child.value();
+  }
+}
+
+TEST_F(FilePathTest, AppendRelativePathTest) {
+  const struct BinaryTestData cases[] = {
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+    { { FPL("/"),             FPL("/foo/bar/baz") },      FPL("foo\\bar\\baz")},
+#else  // FILE_PATH_USES_WIN_SEPARATORS
+    { { FPL("/"),             FPL("/foo/bar/baz") },      FPL("foo/bar/baz")},
+#endif  // FILE_PATH_USES_WIN_SEPARATORS
+    { { FPL("/foo/bar"),      FPL("/foo/bar/baz") },      FPL("baz")},
+    { { FPL("/foo/bar/"),     FPL("/foo/bar/baz") },      FPL("baz")},
+    { { FPL("//foo/bar/"),    FPL("//foo/bar/baz") },     FPL("baz")},
+    { { FPL("/foo/bar"),      FPL("/foo2/bar/baz") },     FPL("")},
+    { { FPL("/foo/bar.txt"),  FPL("/foo/bar/baz") },      FPL("")},
+    { { FPL("/foo/bar"),      FPL("/foo/bar2/baz") },     FPL("")},
+    { { FPL("/foo/bar"),      FPL("/foo/bar") },          FPL("")},
+    { { FPL("/foo/bar/baz"),  FPL("/foo/bar") },          FPL("")},
+    { { FPL("foo/bar"),       FPL("foo/bar/baz") },       FPL("baz")},
+    { { FPL("foo/bar"),       FPL("foo2/bar/baz") },      FPL("")},
+    { { FPL("foo/bar"),       FPL("foo/bar2/baz") },      FPL("")},
+    { { FPL(""),              FPL("foo") },               FPL("")},
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+    { { FPL("c:/foo/bar"),    FPL("c:/foo/bar/baz") },    FPL("baz")},
+    { { FPL("E:/foo/bar"),    FPL("e:/foo/bar/baz") },    FPL("baz")},
+    { { FPL("f:/foo/bar"),    FPL("F:/foo/bar/baz") },    FPL("baz")},
+    { { FPL("E:/Foo/bar"),    FPL("e:/foo/bar/baz") },    FPL("")},
+    { { FPL("f:/foo/bar"),    FPL("F:/foo/Bar/baz") },    FPL("")},
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+    { { FPL("c:/"),           FPL("c:/foo/bar/baz") },    FPL("foo\\bar\\baz")},
+    // TODO(akalin): Figure out how to handle the corner case in the
+    // commented-out test case below.  Appending to an empty path gives
+    // /foo\bar\baz but appending to a nonempty path "blah" gives
+    // blah\foo\bar\baz.
+    // { { FPL("c:"),            FPL("c:/foo/bar/baz") }, FPL("foo\\bar\\baz")},
+#endif  // FILE_PATH_USES_WIN_SEPARATORS
+    { { FPL("c:/foo/bar"),    FPL("d:/foo/bar/baz") },    FPL("")},
+    { { FPL("c:/foo/bar"),    FPL("D:/foo/bar/baz") },    FPL("")},
+    { { FPL("C:/foo/bar"),    FPL("d:/foo/bar/baz") },    FPL("")},
+    { { FPL("c:/foo/bar"),    FPL("c:/foo2/bar/baz") },   FPL("")},
+    { { FPL("e:/foo/bar"),    FPL("E:/foo2/bar/baz") },   FPL("")},
+    { { FPL("F:/foo/bar"),    FPL("f:/foo2/bar/baz") },   FPL("")},
+    { { FPL("c:/foo/bar"),    FPL("c:/foo/bar2/baz") },   FPL("")},
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+    { { FPL("\\foo\\bar"),    FPL("\\foo\\bar\\baz") },   FPL("baz")},
+    { { FPL("\\foo/bar"),     FPL("\\foo\\bar\\baz") },   FPL("baz")},
+    { { FPL("\\foo/bar"),     FPL("\\foo/bar/baz") },     FPL("baz")},
+    { { FPL("\\"),            FPL("\\foo\\bar\\baz") },   FPL("foo\\bar\\baz")},
+    { { FPL(""),              FPL("\\foo\\bar\\baz") },   FPL("")},
+    { { FPL("\\foo\\bar"),    FPL("\\foo2\\bar\\baz") },  FPL("")},
+    { { FPL("\\foo\\bar"),    FPL("\\foo\\bar2\\baz") },  FPL("")},
+#endif  // FILE_PATH_USES_WIN_SEPARATORS
+  };
+
+  const FilePath base(FPL("blah"));
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    FilePath parent(cases[i].inputs[0]);
+    FilePath child(cases[i].inputs[1]);
+    {
+      FilePath result;
+      bool success = parent.AppendRelativePath(child, &result);
+      EXPECT_EQ(cases[i].expected[0] != '\0', success) <<
+        "i: " << i << ", parent: " << parent.value() << ", child: " <<
+        child.value();
+      EXPECT_STREQ(cases[i].expected, result.value().c_str()) <<
+        "i: " << i << ", parent: " << parent.value() << ", child: " <<
+        child.value();
+    }
+    {
+      FilePath result(base);
+      bool success = parent.AppendRelativePath(child, &result);
+      EXPECT_EQ(cases[i].expected[0] != '\0', success) <<
+        "i: " << i << ", parent: " << parent.value() << ", child: " <<
+        child.value();
+      EXPECT_EQ(base.Append(cases[i].expected).value(), result.value()) <<
+        "i: " << i << ", parent: " << parent.value() << ", child: " <<
+        child.value();
+    }
+  }
+}
+
+TEST_F(FilePathTest, EqualityTest) {
+  const struct BinaryBooleanTestData cases[] = {
+    { { FPL("/foo/bar/baz"),  FPL("/foo/bar/baz") },      true},
+    { { FPL("/foo/bar"),      FPL("/foo/bar/baz") },      false},
+    { { FPL("/foo/bar/baz"),  FPL("/foo/bar") },          false},
+    { { FPL("//foo/bar/"),    FPL("//foo/bar/") },        true},
+    { { FPL("/foo/bar"),      FPL("/foo2/bar") },         false},
+    { { FPL("/foo/bar.txt"),  FPL("/foo/bar") },          false},
+    { { FPL("foo/bar"),       FPL("foo/bar") },           true},
+    { { FPL("foo/bar"),       FPL("foo/bar/baz") },       false},
+    { { FPL(""),              FPL("foo") },               false},
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+    { { FPL("c:/foo/bar"),    FPL("c:/foo/bar") },        true},
+    { { FPL("E:/foo/bar"),    FPL("e:/foo/bar") },        true},
+    { { FPL("f:/foo/bar"),    FPL("F:/foo/bar") },        true},
+    { { FPL("E:/Foo/bar"),    FPL("e:/foo/bar") },        false},
+    { { FPL("f:/foo/bar"),    FPL("F:/foo/Bar") },        false},
+    { { FPL("c:/"),           FPL("c:/") },               true},
+    { { FPL("c:"),            FPL("c:") },                true},
+    { { FPL("c:/foo/bar"),    FPL("d:/foo/bar") },        false},
+    { { FPL("c:/foo/bar"),    FPL("D:/foo/bar") },        false},
+    { { FPL("C:/foo/bar"),    FPL("d:/foo/bar") },        false},
+    { { FPL("c:/foo/bar"),    FPL("c:/foo2/bar") },       false},
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+    { { FPL("\\foo\\bar"),    FPL("\\foo\\bar") },        true},
+    { { FPL("\\foo/bar"),     FPL("\\foo/bar") },         true},
+    { { FPL("\\foo/bar"),     FPL("\\foo\\bar") },        false},
+    { { FPL("\\"),            FPL("\\") },                true},
+    { { FPL("\\"),            FPL("/") },                 false},
+    { { FPL(""),              FPL("\\") },                false},
+    { { FPL("\\foo\\bar"),    FPL("\\foo2\\bar") },       false},
+    { { FPL("\\foo\\bar"),    FPL("\\foo\\bar2") },       false},
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+    { { FPL("c:\\foo\\bar"),    FPL("c:\\foo\\bar") },    true},
+    { { FPL("E:\\foo\\bar"),    FPL("e:\\foo\\bar") },    true},
+    { { FPL("f:\\foo\\bar"),    FPL("F:\\foo/bar") },     false},
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+#endif  // FILE_PATH_USES_WIN_SEPARATORS
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    FilePath a(cases[i].inputs[0]);
+    FilePath b(cases[i].inputs[1]);
+
+    EXPECT_EQ(a == b, cases[i].expected) <<
+      "equality i: " << i << ", a: " << a.value() << ", b: " <<
+      b.value();
+  }
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    FilePath a(cases[i].inputs[0]);
+    FilePath b(cases[i].inputs[1]);
+
+    EXPECT_EQ(a != b, !cases[i].expected) <<
+      "inequality i: " << i << ", a: " << a.value() << ", b: " <<
+      b.value();
+  }
+}
+
+TEST_F(FilePathTest, Extension) {
+  FilePath base_dir(FILE_PATH_LITERAL("base_dir"));
+
+  FilePath jpg = base_dir.Append(FILE_PATH_LITERAL("foo.jpg"));
+  EXPECT_EQ(FILE_PATH_LITERAL(".jpg"), jpg.Extension());
+  EXPECT_EQ(FILE_PATH_LITERAL(".jpg"), jpg.FinalExtension());
+
+  FilePath base = jpg.BaseName().RemoveExtension();
+  EXPECT_EQ(FILE_PATH_LITERAL("foo"), base.value());
+
+  FilePath path_no_ext = base_dir.Append(base);
+  EXPECT_EQ(path_no_ext.value(), jpg.RemoveExtension().value());
+
+  EXPECT_EQ(path_no_ext.value(), path_no_ext.RemoveExtension().value());
+  EXPECT_EQ(FILE_PATH_LITERAL(""), path_no_ext.Extension());
+  EXPECT_EQ(FILE_PATH_LITERAL(""), path_no_ext.FinalExtension());
+}
+
+TEST_F(FilePathTest, Extension2) {
+  const struct UnaryTestData cases[] = {
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+    { FPL("C:\\a\\b\\c.ext"),        FPL(".ext") },
+    { FPL("C:\\a\\b\\c."),           FPL(".") },
+    { FPL("C:\\a\\b\\c"),            FPL("") },
+    { FPL("C:\\a\\b\\"),             FPL("") },
+    { FPL("C:\\a\\b.\\"),            FPL(".") },
+    { FPL("C:\\a\\b\\c.ext1.ext2"),  FPL(".ext2") },
+    { FPL("C:\\foo.bar\\\\\\"),      FPL(".bar") },
+    { FPL("C:\\foo.bar\\.."),        FPL("") },
+    { FPL("C:\\foo.bar\\..\\\\"),    FPL("") },
+#endif
+    { FPL("/foo/bar/baz.ext"),       FPL(".ext") },
+    { FPL("/foo/bar/baz."),          FPL(".") },
+    { FPL("/foo/bar/baz.."),         FPL(".") },
+    { FPL("/foo/bar/baz"),           FPL("") },
+    { FPL("/foo/bar/"),              FPL("") },
+    { FPL("/foo/bar./"),             FPL(".") },
+    { FPL("/foo/bar/baz.ext1.ext2"), FPL(".ext2") },
+    { FPL("/subversion-1.6.12.zip"), FPL(".zip") },
+    { FPL("/foo.12345.gz"),          FPL(".gz") },
+    { FPL("/foo..gz"),               FPL(".gz") },
+    { FPL("."),                      FPL("") },
+    { FPL(".."),                     FPL("") },
+    { FPL("./foo"),                  FPL("") },
+    { FPL("./foo.ext"),              FPL(".ext") },
+    { FPL("/foo.ext1/bar.ext2"),     FPL(".ext2") },
+    { FPL("/foo.bar////"),           FPL(".bar") },
+    { FPL("/foo.bar/.."),            FPL("") },
+    { FPL("/foo.bar/..////"),        FPL("") },
+    { FPL("/foo.1234.luser.js"),     FPL(".js") },
+    { FPL("/user.js"),               FPL(".js") },
+  };
+  const struct UnaryTestData double_extension_cases[] = {
+    { FPL("/foo.tar.gz"),            FPL(".tar.gz") },
+    { FPL("/foo.tar.Z"),             FPL(".tar.Z") },
+    { FPL("/foo.tar.bz2"),           FPL(".tar.bz2") },
+    { FPL("/foo.1234.gz"),           FPL(".1234.gz") },
+    { FPL("/foo.1234.tar.gz"),       FPL(".tar.gz") },
+    { FPL("/foo.tar.tar.gz"),        FPL(".tar.gz") },
+    { FPL("/foo.tar.gz.gz"),         FPL(".gz.gz") },
+    { FPL("/foo.1234.user.js"),      FPL(".user.js") },
+    { FPL("foo.user.js"),            FPL(".user.js") },
+    { FPL("/foo.tar.bz"),            FPL(".tar.bz") },
+  };
+  for (unsigned int i = 0; i < arraysize(cases); ++i) {
+    FilePath path(cases[i].input);
+    FilePath::StringType extension = path.Extension();
+    FilePath::StringType final_extension = path.FinalExtension();
+    EXPECT_STREQ(cases[i].expected, extension.c_str())
+        << "i: " << i << ", path: " << path.value();
+    EXPECT_STREQ(cases[i].expected, final_extension.c_str())
+        << "i: " << i << ", path: " << path.value();
+  }
+  for (unsigned int i = 0; i < arraysize(double_extension_cases); ++i) {
+    FilePath path(double_extension_cases[i].input);
+    FilePath::StringType extension = path.Extension();
+    EXPECT_STREQ(double_extension_cases[i].expected, extension.c_str())
+        << "i: " << i << ", path: " << path.value();
+  }
+}
+
+TEST_F(FilePathTest, InsertBeforeExtension) {
+  const struct BinaryTestData cases[] = {
+    { { FPL(""),                FPL("") },        FPL("") },
+    { { FPL(""),                FPL("txt") },     FPL("") },
+    { { FPL("."),               FPL("txt") },     FPL("") },
+    { { FPL(".."),              FPL("txt") },     FPL("") },
+    { { FPL("foo.dll"),         FPL("txt") },     FPL("footxt.dll") },
+    { { FPL("."),               FPL("") },        FPL(".") },
+    { { FPL("foo.dll"),         FPL(".txt") },    FPL("foo.txt.dll") },
+    { { FPL("foo"),             FPL("txt") },     FPL("footxt") },
+    { { FPL("foo"),             FPL(".txt") },    FPL("foo.txt") },
+    { { FPL("foo.baz.dll"),     FPL("txt") },     FPL("foo.baztxt.dll") },
+    { { FPL("foo.baz.dll"),     FPL(".txt") },    FPL("foo.baz.txt.dll") },
+    { { FPL("foo.dll"),         FPL("") },        FPL("foo.dll") },
+    { { FPL("foo.dll"),         FPL(".") },       FPL("foo..dll") },
+    { { FPL("foo"),             FPL("") },        FPL("foo") },
+    { { FPL("foo"),             FPL(".") },       FPL("foo.") },
+    { { FPL("foo.baz.dll"),     FPL("") },        FPL("foo.baz.dll") },
+    { { FPL("foo.baz.dll"),     FPL(".") },       FPL("foo.baz..dll") },
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+    { { FPL("\\"),              FPL("") },        FPL("\\") },
+    { { FPL("\\"),              FPL("txt") },     FPL("\\txt") },
+    { { FPL("\\."),             FPL("txt") },     FPL("") },
+    { { FPL("\\.."),            FPL("txt") },     FPL("") },
+    { { FPL("\\."),             FPL("") },        FPL("\\.") },
+    { { FPL("C:\\bar\\foo.dll"), FPL("txt") },
+        FPL("C:\\bar\\footxt.dll") },
+    { { FPL("C:\\bar.baz\\foodll"), FPL("txt") },
+        FPL("C:\\bar.baz\\foodlltxt") },
+    { { FPL("C:\\bar.baz\\foo.dll"), FPL("txt") },
+        FPL("C:\\bar.baz\\footxt.dll") },
+    { { FPL("C:\\bar.baz\\foo.dll.exe"), FPL("txt") },
+        FPL("C:\\bar.baz\\foo.dlltxt.exe") },
+    { { FPL("C:\\bar.baz\\foo"), FPL("") },
+        FPL("C:\\bar.baz\\foo") },
+    { { FPL("C:\\bar.baz\\foo.exe"), FPL("") },
+        FPL("C:\\bar.baz\\foo.exe") },
+    { { FPL("C:\\bar.baz\\foo.dll.exe"), FPL("") },
+        FPL("C:\\bar.baz\\foo.dll.exe") },
+    { { FPL("C:\\bar\\baz\\foo.exe"), FPL(" (1)") },
+        FPL("C:\\bar\\baz\\foo (1).exe") },
+    { { FPL("C:\\foo.baz\\\\"), FPL(" (1)") },    FPL("C:\\foo (1).baz") },
+    { { FPL("C:\\foo.baz\\..\\"), FPL(" (1)") },  FPL("") },
+#endif
+    { { FPL("/"),               FPL("") },        FPL("/") },
+    { { FPL("/"),               FPL("txt") },     FPL("/txt") },
+    { { FPL("/."),              FPL("txt") },     FPL("") },
+    { { FPL("/.."),             FPL("txt") },     FPL("") },
+    { { FPL("/."),              FPL("") },        FPL("/.") },
+    { { FPL("/bar/foo.dll"),    FPL("txt") },     FPL("/bar/footxt.dll") },
+    { { FPL("/bar.baz/foodll"), FPL("txt") },     FPL("/bar.baz/foodlltxt") },
+    { { FPL("/bar.baz/foo.dll"), FPL("txt") },    FPL("/bar.baz/footxt.dll") },
+    { { FPL("/bar.baz/foo.dll.exe"), FPL("txt") },
+        FPL("/bar.baz/foo.dlltxt.exe") },
+    { { FPL("/bar.baz/foo"),    FPL("") },        FPL("/bar.baz/foo") },
+    { { FPL("/bar.baz/foo.exe"), FPL("") },       FPL("/bar.baz/foo.exe") },
+    { { FPL("/bar.baz/foo.dll.exe"), FPL("") },   FPL("/bar.baz/foo.dll.exe") },
+    { { FPL("/bar/baz/foo.exe"), FPL(" (1)") },   FPL("/bar/baz/foo (1).exe") },
+    { { FPL("/bar/baz/..////"), FPL(" (1)") },    FPL("") },
+  };
+  for (unsigned int i = 0; i < arraysize(cases); ++i) {
+    FilePath path(cases[i].inputs[0]);
+    FilePath result = path.InsertBeforeExtension(cases[i].inputs[1]);
+    EXPECT_EQ(cases[i].expected, result.value()) << "i: " << i <<
+        ", path: " << path.value() << ", insert: " << cases[i].inputs[1];
+  }
+}
+
+TEST_F(FilePathTest, RemoveExtension) {
+  const struct UnaryTestData cases[] = {
+    { FPL(""),                    FPL("") },
+    { FPL("."),                   FPL(".") },
+    { FPL(".."),                  FPL("..") },
+    { FPL("foo.dll"),             FPL("foo") },
+    { FPL("./foo.dll"),           FPL("./foo") },
+    { FPL("foo..dll"),            FPL("foo.") },
+    { FPL("foo"),                 FPL("foo") },
+    { FPL("foo."),                FPL("foo") },
+    { FPL("foo.."),               FPL("foo.") },
+    { FPL("foo.baz.dll"),         FPL("foo.baz") },
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+    { FPL("C:\\foo.bar\\foo"),    FPL("C:\\foo.bar\\foo") },
+    { FPL("C:\\foo.bar\\..\\\\"), FPL("C:\\foo.bar\\..\\\\") },
+#endif
+    { FPL("/foo.bar/foo"),        FPL("/foo.bar/foo") },
+    { FPL("/foo.bar/..////"),     FPL("/foo.bar/..////") },
+  };
+  for (unsigned int i = 0; i < arraysize(cases); ++i) {
+    FilePath path(cases[i].input);
+    FilePath removed = path.RemoveExtension();
+    FilePath removed_final = path.RemoveFinalExtension();
+    EXPECT_EQ(cases[i].expected, removed.value()) << "i: " << i <<
+        ", path: " << path.value();
+    EXPECT_EQ(cases[i].expected, removed_final.value()) << "i: " << i <<
+        ", path: " << path.value();
+  }
+  {
+    FilePath path(FPL("foo.tar.gz"));
+    FilePath removed = path.RemoveExtension();
+    FilePath removed_final = path.RemoveFinalExtension();
+    EXPECT_EQ(FPL("foo"), removed.value()) << ", path: " << path.value();
+    EXPECT_EQ(FPL("foo.tar"), removed_final.value()) << ", path: "
+                                                     << path.value();
+  }
+}
+
+TEST_F(FilePathTest, ReplaceExtension) {
+  const struct BinaryTestData cases[] = {
+    { { FPL(""),              FPL("") },      FPL("") },
+    { { FPL(""),              FPL("txt") },   FPL("") },
+    { { FPL("."),             FPL("txt") },   FPL("") },
+    { { FPL(".."),            FPL("txt") },   FPL("") },
+    { { FPL("."),             FPL("") },      FPL("") },
+    { { FPL("foo.dll"),       FPL("txt") },   FPL("foo.txt") },
+    { { FPL("./foo.dll"),     FPL("txt") },   FPL("./foo.txt") },
+    { { FPL("foo..dll"),      FPL("txt") },   FPL("foo..txt") },
+    { { FPL("foo.dll"),       FPL(".txt") },  FPL("foo.txt") },
+    { { FPL("foo"),           FPL("txt") },   FPL("foo.txt") },
+    { { FPL("foo."),          FPL("txt") },   FPL("foo.txt") },
+    { { FPL("foo.."),         FPL("txt") },   FPL("foo..txt") },
+    { { FPL("foo"),           FPL(".txt") },  FPL("foo.txt") },
+    { { FPL("foo.baz.dll"),   FPL("txt") },   FPL("foo.baz.txt") },
+    { { FPL("foo.baz.dll"),   FPL(".txt") },  FPL("foo.baz.txt") },
+    { { FPL("foo.dll"),       FPL("") },      FPL("foo") },
+    { { FPL("foo.dll"),       FPL(".") },     FPL("foo") },
+    { { FPL("foo"),           FPL("") },      FPL("foo") },
+    { { FPL("foo"),           FPL(".") },     FPL("foo") },
+    { { FPL("foo.baz.dll"),   FPL("") },      FPL("foo.baz") },
+    { { FPL("foo.baz.dll"),   FPL(".") },     FPL("foo.baz") },
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+    { { FPL("C:\\foo.bar\\foo"),    FPL("baz") }, FPL("C:\\foo.bar\\foo.baz") },
+    { { FPL("C:\\foo.bar\\..\\\\"), FPL("baz") }, FPL("") },
+#endif
+    { { FPL("/foo.bar/foo"),        FPL("baz") }, FPL("/foo.bar/foo.baz") },
+    { { FPL("/foo.bar/..////"),     FPL("baz") }, FPL("") },
+  };
+  for (unsigned int i = 0; i < arraysize(cases); ++i) {
+    FilePath path(cases[i].inputs[0]);
+    FilePath replaced = path.ReplaceExtension(cases[i].inputs[1]);
+    EXPECT_EQ(cases[i].expected, replaced.value()) << "i: " << i <<
+        ", path: " << path.value() << ", replace: " << cases[i].inputs[1];
+  }
+}
+
+TEST_F(FilePathTest, AddExtension) {
+  const struct BinaryTestData cases[] = {
+    { { FPL(""),              FPL("") },      FPL("") },
+    { { FPL(""),              FPL("txt") },   FPL("") },
+    { { FPL("."),             FPL("txt") },   FPL("") },
+    { { FPL(".."),            FPL("txt") },   FPL("") },
+    { { FPL("."),             FPL("") },      FPL("") },
+    { { FPL("foo.dll"),       FPL("txt") },   FPL("foo.dll.txt") },
+    { { FPL("./foo.dll"),     FPL("txt") },   FPL("./foo.dll.txt") },
+    { { FPL("foo..dll"),      FPL("txt") },   FPL("foo..dll.txt") },
+    { { FPL("foo.dll"),       FPL(".txt") },  FPL("foo.dll.txt") },
+    { { FPL("foo"),           FPL("txt") },   FPL("foo.txt") },
+    { { FPL("foo."),          FPL("txt") },   FPL("foo.txt") },
+    { { FPL("foo.."),         FPL("txt") },   FPL("foo..txt") },
+    { { FPL("foo"),           FPL(".txt") },  FPL("foo.txt") },
+    { { FPL("foo.baz.dll"),   FPL("txt") },   FPL("foo.baz.dll.txt") },
+    { { FPL("foo.baz.dll"),   FPL(".txt") },  FPL("foo.baz.dll.txt") },
+    { { FPL("foo.dll"),       FPL("") },      FPL("foo.dll") },
+    { { FPL("foo.dll"),       FPL(".") },     FPL("foo.dll") },
+    { { FPL("foo"),           FPL("") },      FPL("foo") },
+    { { FPL("foo"),           FPL(".") },     FPL("foo") },
+    { { FPL("foo.baz.dll"),   FPL("") },      FPL("foo.baz.dll") },
+    { { FPL("foo.baz.dll"),   FPL(".") },     FPL("foo.baz.dll") },
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+    { { FPL("C:\\foo.bar\\foo"),    FPL("baz") }, FPL("C:\\foo.bar\\foo.baz") },
+    { { FPL("C:\\foo.bar\\..\\\\"), FPL("baz") }, FPL("") },
+#endif
+    { { FPL("/foo.bar/foo"),        FPL("baz") }, FPL("/foo.bar/foo.baz") },
+    { { FPL("/foo.bar/..////"),     FPL("baz") }, FPL("") },
+  };
+  for (unsigned int i = 0; i < arraysize(cases); ++i) {
+    FilePath path(cases[i].inputs[0]);
+    FilePath added = path.AddExtension(cases[i].inputs[1]);
+    EXPECT_EQ(cases[i].expected, added.value()) << "i: " << i <<
+        ", path: " << path.value() << ", add: " << cases[i].inputs[1];
+  }
+}
+
+TEST_F(FilePathTest, MatchesExtension) {
+  const struct BinaryBooleanTestData cases[] = {
+    { { FPL("foo"),                     FPL("") },                    true},
+    { { FPL("foo"),                     FPL(".") },                   false},
+    { { FPL("foo."),                    FPL("") },                    false},
+    { { FPL("foo."),                    FPL(".") },                   true},
+    { { FPL("foo.txt"),                 FPL(".dll") },                false},
+    { { FPL("foo.txt"),                 FPL(".txt") },                true},
+    { { FPL("foo.txt.dll"),             FPL(".txt") },                false},
+    { { FPL("foo.txt.dll"),             FPL(".dll") },                true},
+    { { FPL("foo.TXT"),                 FPL(".txt") },                true},
+    { { FPL("foo.txt"),                 FPL(".TXT") },                true},
+    { { FPL("foo.tXt"),                 FPL(".txt") },                true},
+    { { FPL("foo.txt"),                 FPL(".tXt") },                true},
+    { { FPL("foo.tXt"),                 FPL(".TXT") },                true},
+    { { FPL("foo.tXt"),                 FPL(".tXt") },                true},
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+    { { FPL("c:/foo.txt.dll"),          FPL(".txt") },                false},
+    { { FPL("c:/foo.txt"),              FPL(".txt") },                true},
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+    { { FPL("c:\\bar\\foo.txt.dll"),    FPL(".txt") },                false},
+    { { FPL("c:\\bar\\foo.txt"),        FPL(".txt") },                true},
+#endif  // FILE_PATH_USES_DRIVE_LETTERS
+    { { FPL("/bar/foo.txt.dll"),        FPL(".txt") },                false},
+    { { FPL("/bar/foo.txt"),            FPL(".txt") },                true},
+#if defined(OS_WIN) || defined(OS_MACOSX)
+    // Umlauts A, O, U: direct comparison, and upper case vs. lower case
+    { { FPL("foo.\u00E4\u00F6\u00FC"),  FPL(".\u00E4\u00F6\u00FC") }, true},
+    { { FPL("foo.\u00C4\u00D6\u00DC"),  FPL(".\u00E4\u00F6\u00FC") }, true},
+    // C with circumflex: direct comparison, and upper case vs. lower case
+    { { FPL("foo.\u0109"),              FPL(".\u0109") },             true},
+    { { FPL("foo.\u0108"),              FPL(".\u0109") },             true},
+#endif
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    FilePath path(cases[i].inputs[0]);
+    FilePath::StringType ext(cases[i].inputs[1]);
+
+    EXPECT_EQ(cases[i].expected, path.MatchesExtension(ext)) <<
+        "i: " << i << ", path: " << path.value() << ", ext: " << ext;
+  }
+}
+
+TEST_F(FilePathTest, CompareIgnoreCase) {
+  const struct BinaryIntTestData cases[] = {
+    { { FPL("foo"),                          FPL("foo") },                  0},
+    { { FPL("FOO"),                          FPL("foo") },                  0},
+    { { FPL("foo.ext"),                      FPL("foo.ext") },              0},
+    { { FPL("FOO.EXT"),                      FPL("foo.ext") },              0},
+    { { FPL("Foo.Ext"),                      FPL("foo.ext") },              0},
+    { { FPL("foO"),                          FPL("foo") },                  0},
+    { { FPL("foo"),                          FPL("foO") },                  0},
+    { { FPL("fOo"),                          FPL("foo") },                  0},
+    { { FPL("foo"),                          FPL("fOo") },                  0},
+    { { FPL("bar"),                          FPL("foo") },                 -1},
+    { { FPL("foo"),                          FPL("bar") },                  1},
+    { { FPL("BAR"),                          FPL("foo") },                 -1},
+    { { FPL("FOO"),                          FPL("bar") },                  1},
+    { { FPL("bar"),                          FPL("FOO") },                 -1},
+    { { FPL("foo"),                          FPL("BAR") },                  1},
+    { { FPL("BAR"),                          FPL("FOO") },                 -1},
+    { { FPL("FOO"),                          FPL("BAR") },                  1},
+    // German "Eszett" (lower case and the new-fangled upper case)
+    // Note that uc(<lowercase eszett>) => "SS", NOT <uppercase eszett>!
+    // However, neither Windows nor Mac OSX converts these.
+    // (or even have glyphs for <uppercase eszett>)
+    { { FPL("\u00DF"),                       FPL("\u00DF") },               0},
+    { { FPL("\u1E9E"),                       FPL("\u1E9E") },               0},
+    { { FPL("\u00DF"),                       FPL("\u1E9E") },              -1},
+    { { FPL("SS"),                           FPL("\u00DF") },              -1},
+    { { FPL("SS"),                           FPL("\u1E9E") },              -1},
+#if defined(OS_WIN) || defined(OS_MACOSX)
+    // Umlauts A, O, U: direct comparison, and upper case vs. lower case
+    { { FPL("\u00E4\u00F6\u00FC"),           FPL("\u00E4\u00F6\u00FC") },   0},
+    { { FPL("\u00C4\u00D6\u00DC"),           FPL("\u00E4\u00F6\u00FC") },   0},
+    // C with circumflex: direct comparison, and upper case vs. lower case
+    { { FPL("\u0109"),                       FPL("\u0109") },               0},
+    { { FPL("\u0108"),                       FPL("\u0109") },               0},
+    // Cyrillic letter SHA: direct comparison, and upper case vs. lower case
+    { { FPL("\u0428"),                       FPL("\u0428") },               0},
+    { { FPL("\u0428"),                       FPL("\u0448") },               0},
+    // Greek letter DELTA: direct comparison, and upper case vs. lower case
+    { { FPL("\u0394"),                       FPL("\u0394") },               0},
+    { { FPL("\u0394"),                       FPL("\u03B4") },               0},
+    // Japanese full-width A: direct comparison, and upper case vs. lower case
+    // Note that full-width and standard characters are considered different.
+    { { FPL("\uFF21"),                       FPL("\uFF21") },               0},
+    { { FPL("\uFF21"),                       FPL("\uFF41") },               0},
+    { { FPL("A"),                            FPL("\uFF21") },              -1},
+    { { FPL("A"),                            FPL("\uFF41") },              -1},
+    { { FPL("a"),                            FPL("\uFF21") },              -1},
+    { { FPL("a"),                            FPL("\uFF41") },              -1},
+#endif
+#if defined(OS_MACOSX)
+    // Codepoints > 0x1000
+    // Georgian letter DON: direct comparison, and upper case vs. lower case
+    { { FPL("\u10A3"),                       FPL("\u10A3") },               0},
+    { { FPL("\u10A3"),                       FPL("\u10D3") },               0},
+    // Combining characters vs. pre-composed characters, upper and lower case
+    { { FPL("k\u0301u\u032Do\u0304\u0301n"), FPL("\u1E31\u1E77\u1E53n") },  0},
+    { { FPL("k\u0301u\u032Do\u0304\u0301n"), FPL("kuon") },                 1},
+    { { FPL("kuon"), FPL("k\u0301u\u032Do\u0304\u0301n") },                -1},
+    { { FPL("K\u0301U\u032DO\u0304\u0301N"), FPL("KUON") },                 1},
+    { { FPL("KUON"), FPL("K\u0301U\u032DO\u0304\u0301N") },                -1},
+    { { FPL("k\u0301u\u032Do\u0304\u0301n"), FPL("KUON") },                 1},
+    { { FPL("K\u0301U\u032DO\u0304\u0301N"), FPL("\u1E31\u1E77\u1E53n") },  0},
+    { { FPL("k\u0301u\u032Do\u0304\u0301n"), FPL("\u1E30\u1E76\u1E52n") },  0},
+    { { FPL("k\u0301u\u032Do\u0304\u0302n"), FPL("\u1E30\u1E76\u1E52n") },  1},
+#endif
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    FilePath::StringType s1(cases[i].inputs[0]);
+    FilePath::StringType s2(cases[i].inputs[1]);
+    int result = FilePath::CompareIgnoreCase(s1, s2);
+    EXPECT_EQ(cases[i].expected, result) <<
+        "i: " << i << ", s1: " << s1 << ", s2: " << s2;
+  }
+}
+
+TEST_F(FilePathTest, ReferencesParent) {
+  const struct UnaryBooleanTestData cases[] = {
+    { FPL("."),        false },
+    { FPL(".."),       true },
+    { FPL(".. "),      true },
+    { FPL(" .."),      true },
+    { FPL("..."),      true },
+    { FPL("a.."),      false },
+    { FPL("..a"),      false },
+    { FPL("../"),      true },
+    { FPL("/.."),      true },
+    { FPL("/../"),     true },
+    { FPL("/a../"),    false },
+    { FPL("/..a/"),    false },
+    { FPL("//.."),     true },
+    { FPL("..//"),     true },
+    { FPL("//..//"),   true },
+    { FPL("a//..//c"), true },
+    { FPL("../b/c"),   true },
+    { FPL("/../b/c"),  true },
+    { FPL("a/b/.."),   true },
+    { FPL("a/b/../"),  true },
+    { FPL("a/../c"),   true },
+    { FPL("a/b/c"),    false },
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    FilePath input(cases[i].input);
+    bool observed = input.ReferencesParent();
+    EXPECT_EQ(cases[i].expected, observed) <<
+              "i: " << i << ", input: " << input.value();
+  }
+}
+
+TEST_F(FilePathTest, FromUTF8Unsafe_And_AsUTF8Unsafe) {
+  const struct UTF8TestData cases[] = {
+    { FPL("foo.txt"), "foo.txt" },
+    // "aeo" with accents. Use http://0xcc.net/jsescape/ to decode them.
+    { FPL("\u00E0\u00E8\u00F2.txt"), "\xC3\xA0\xC3\xA8\xC3\xB2.txt" },
+    // Full-width "ABC".
+    { FPL("\uFF21\uFF22\uFF23.txt"),
+      "\xEF\xBC\xA1\xEF\xBC\xA2\xEF\xBC\xA3.txt" },
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    // Test FromUTF8Unsafe() works.
+    FilePath from_utf8 = FilePath::FromUTF8Unsafe(cases[i].utf8);
+    EXPECT_EQ(cases[i].native, from_utf8.value())
+        << "i: " << i << ", input: " << cases[i].native;
+    // Test AsUTF8Unsafe() works.
+    FilePath from_native = FilePath(cases[i].native);
+    EXPECT_EQ(cases[i].utf8, from_native.AsUTF8Unsafe())
+        << "i: " << i << ", input: " << cases[i].native;
+    // Test the two file paths are identical.
+    EXPECT_EQ(from_utf8.value(), from_native.value());
+  }
+}
+
+TEST_F(FilePathTest, ConstructWithNUL) {
+  // Assert FPS() works.
+  ASSERT_EQ(3U, FPS("a\0b").length());
+
+  // Test constructor strips '\0'
+  FilePath path(FPS("a\0b"));
+  EXPECT_EQ(1U, path.value().length());
+  EXPECT_EQ(FPL("a"), path.value());
+}
+
+TEST_F(FilePathTest, AppendWithNUL) {
+  // Assert FPS() works.
+  ASSERT_EQ(3U, FPS("b\0b").length());
+
+  // Test Append() strips '\0'
+  FilePath path(FPL("a"));
+  path = path.Append(FPS("b\0b"));
+  EXPECT_EQ(3U, path.value().length());
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+  EXPECT_EQ(FPL("a\\b"), path.value());
+#else
+  EXPECT_EQ(FPL("a/b"), path.value());
+#endif
+}
+
+TEST_F(FilePathTest, ReferencesParentWithNUL) {
+  // Assert FPS() works.
+  ASSERT_EQ(3U, FPS("..\0").length());
+
+  // Test ReferencesParent() doesn't break with "..\0"
+  FilePath path(FPS("..\0"));
+  EXPECT_TRUE(path.ReferencesParent());
+}
+
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+TEST_F(FilePathTest, NormalizePathSeparators) {
+  const struct UnaryTestData cases[] = {
+    { FPL("foo/bar"), FPL("foo\\bar") },
+    { FPL("foo/bar\\betz"), FPL("foo\\bar\\betz") },
+    { FPL("foo\\bar"), FPL("foo\\bar") },
+    { FPL("foo\\bar/betz"), FPL("foo\\bar\\betz") },
+    { FPL("foo"), FPL("foo") },
+    // Trailing slashes don't automatically get stripped.  That's what
+    // StripTrailingSeparators() is for.
+    { FPL("foo\\"), FPL("foo\\") },
+    { FPL("foo/"), FPL("foo\\") },
+    { FPL("foo/bar\\"), FPL("foo\\bar\\") },
+    { FPL("foo\\bar/"), FPL("foo\\bar\\") },
+    { FPL("foo/bar/"), FPL("foo\\bar\\") },
+    { FPL("foo\\bar\\"), FPL("foo\\bar\\") },
+    { FPL("\\foo/bar"), FPL("\\foo\\bar") },
+    { FPL("/foo\\bar"), FPL("\\foo\\bar") },
+    { FPL("c:/foo/bar/"), FPL("c:\\foo\\bar\\") },
+    { FPL("/foo/bar/"), FPL("\\foo\\bar\\") },
+    { FPL("\\foo\\bar\\"), FPL("\\foo\\bar\\") },
+    { FPL("c:\\foo/bar"), FPL("c:\\foo\\bar") },
+    { FPL("//foo\\bar\\"), FPL("\\\\foo\\bar\\") },
+    { FPL("\\\\foo\\bar\\"), FPL("\\\\foo\\bar\\") },
+    { FPL("//foo\\bar\\"), FPL("\\\\foo\\bar\\") },
+    // This method does not normalize the number of path separators.
+    { FPL("foo\\\\bar"), FPL("foo\\\\bar") },
+    { FPL("foo//bar"), FPL("foo\\\\bar") },
+    { FPL("foo/\\bar"), FPL("foo\\\\bar") },
+    { FPL("foo\\/bar"), FPL("foo\\\\bar") },
+    { FPL("///foo\\\\bar"), FPL("\\\\\\foo\\\\bar") },
+    { FPL("foo//bar///"), FPL("foo\\\\bar\\\\\\") },
+    { FPL("foo/\\bar/\\"), FPL("foo\\\\bar\\\\") },
+    { FPL("/\\foo\\/bar"), FPL("\\\\foo\\\\bar") },
+  };
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    FilePath input(cases[i].input);
+    FilePath observed = input.NormalizePathSeparators();
+    EXPECT_EQ(FilePath::StringType(cases[i].expected), observed.value()) <<
+              "i: " << i << ", input: " << input.value();
+  }
+}
+#endif
+
+TEST_F(FilePathTest, EndsWithSeparator) {
+  const UnaryBooleanTestData cases[] = {
+    { FPL(""), false },
+    { FPL("/"), true },
+    { FPL("foo/"), true },
+    { FPL("bar"), false },
+    { FPL("/foo/bar"), false },
+  };
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    FilePath input = FilePath(cases[i].input).NormalizePathSeparators();
+    EXPECT_EQ(cases[i].expected, input.EndsWithSeparator());
+  }
+}
+
+TEST_F(FilePathTest, AsEndingWithSeparator) {
+  const UnaryTestData cases[] = {
+    { FPL(""), FPL("") },
+    { FPL("/"), FPL("/") },
+    { FPL("foo"), FPL("foo/") },
+    { FPL("foo/"), FPL("foo/") }
+  };
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    FilePath input = FilePath(cases[i].input).NormalizePathSeparators();
+    FilePath expected = FilePath(cases[i].expected).NormalizePathSeparators();
+    EXPECT_EQ(expected.value(), input.AsEndingWithSeparator().value());
+  }
+}
+
+#if defined(OS_ANDROID)
+TEST_F(FilePathTest, ContentUriTest) {
+  const struct UnaryBooleanTestData cases[] = {
+    { FPL("content://foo.bar"),    true },
+    { FPL("content://foo.bar/"),   true },
+    { FPL("content://foo/bar"),    true },
+    { FPL("CoNTenT://foo.bar"),    true },
+    { FPL("content://"),           true },
+    { FPL("content:///foo.bar"),   true },
+    { FPL("content://3foo/bar"),   true },
+    { FPL("content://_foo/bar"),   true },
+    { FPL(".. "),                  false },
+    { FPL("foo.bar"),              false },
+    { FPL("content:foo.bar"),      false },
+    { FPL("content:/foo.ba"),      false },
+    { FPL("content:/dir/foo.bar"), false },
+    { FPL("content: //foo.bar"),   false },
+    { FPL("content%2a%2f%2f"),     false },
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    FilePath input(cases[i].input);
+    bool observed = input.IsContentUri();
+    EXPECT_EQ(cases[i].expected, observed) <<
+              "i: " << i << ", input: " << input.value();
+  }
+}
+#endif
+
+// Test the PrintTo overload for FilePath (used when a test fails to compare two
+// FilePaths).
+TEST_F(FilePathTest, PrintTo) {
+  std::stringstream ss;
+  FilePath fp(FPL("foo"));
+  base::PrintTo(fp, &ss);
+  EXPECT_EQ("foo", ss.str());
+}
+
+}  // namespace base
diff --git a/base/files/file_path_watcher.cc b/base/files/file_path_watcher.cc
new file mode 100644
index 0000000..59ae705
--- /dev/null
+++ b/base/files/file_path_watcher.cc
@@ -0,0 +1,56 @@
+// Copyright (c) 2011 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.
+
+// Cross platform methods for FilePathWatcher. See the various platform
+// specific implementation files, too.
+
+#include "base/files/file_path_watcher.h"
+
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+#include "base/mac/mac_util.h"
+#endif
+
+namespace base {
+
+FilePathWatcher::~FilePathWatcher() {
+  impl_->Cancel();
+}
+
+// static
+void FilePathWatcher::CancelWatch(
+    const scoped_refptr<PlatformDelegate>& delegate) {
+  delegate->CancelOnMessageLoopThread();
+}
+
+// static
+bool FilePathWatcher::RecursiveWatchAvailable() {
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+  // FSEvents isn't available on iOS and is broken on OSX 10.6 and earlier.
+  // See http://crbug.com/54822#c31
+  return mac::IsOSLionOrLater();
+#elif defined(OS_WIN) || defined(OS_LINUX) || defined(OS_ANDROID)
+  return true;
+#else
+  return false;
+#endif
+}
+
+FilePathWatcher::PlatformDelegate::PlatformDelegate(): cancelled_(false) {
+}
+
+FilePathWatcher::PlatformDelegate::~PlatformDelegate() {
+  DCHECK(is_cancelled());
+}
+
+bool FilePathWatcher::Watch(const FilePath& path,
+                            bool recursive,
+                            const Callback& callback) {
+  DCHECK(path.IsAbsolute());
+  return impl_->Watch(path, recursive, callback);
+}
+
+}  // namespace base
diff --git a/base/files/file_path_watcher.h b/base/files/file_path_watcher.h
new file mode 100644
index 0000000..4f132af
--- /dev/null
+++ b/base/files/file_path_watcher.h
@@ -0,0 +1,112 @@
+// Copyright (c) 2012 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 module provides a way to monitor a file or directory for changes.
+
+#ifndef BASE_FILES_FILE_PATH_WATCHER_H_
+#define BASE_FILES_FILE_PATH_WATCHER_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/memory/ref_counted.h"
+#include "base/single_thread_task_runner.h"
+
+namespace base {
+
+// This class lets you register interest in changes on a FilePath.
+// The callback will get called whenever the file or directory referenced by the
+// FilePath is changed, including created or deleted. Due to limitations in the
+// underlying OS APIs, FilePathWatcher has slightly different semantics on OS X
+// than on Windows or Linux. FilePathWatcher on Linux and Windows will detect
+// modifications to files in a watched directory. FilePathWatcher on Mac will
+// detect the creation and deletion of files in a watched directory, but will
+// not detect modifications to those files. See file_path_watcher_kqueue.cc for
+// details.
+class BASE_EXPORT FilePathWatcher {
+ public:
+  // Callback type for Watch(). |path| points to the file that was updated,
+  // and |error| is true if the platform specific code detected an error. In
+  // that case, the callback won't be invoked again.
+  typedef base::Callback<void(const FilePath& path, bool error)> Callback;
+
+  // Used internally to encapsulate different members on different platforms.
+  class PlatformDelegate : public base::RefCountedThreadSafe<PlatformDelegate> {
+   public:
+    PlatformDelegate();
+
+    // Start watching for the given |path| and notify |delegate| about changes.
+    virtual bool Watch(const FilePath& path,
+                       bool recursive,
+                       const Callback& callback) WARN_UNUSED_RESULT = 0;
+
+    // Stop watching. This is called from FilePathWatcher's dtor in order to
+    // allow to shut down properly while the object is still alive.
+    // It can be called from any thread.
+    virtual void Cancel() = 0;
+
+   protected:
+    friend class base::RefCountedThreadSafe<PlatformDelegate>;
+    friend class FilePathWatcher;
+
+    virtual ~PlatformDelegate();
+
+    // Stop watching. This is only called on the thread of the appropriate
+    // message loop. Since it can also be called more than once, it should
+    // check |is_cancelled()| to avoid duplicate work.
+    virtual void CancelOnMessageLoopThread() = 0;
+
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner() const {
+      return task_runner_;
+    }
+
+    void set_task_runner(
+        scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
+      task_runner_ = task_runner.Pass();
+    }
+
+    // Must be called before the PlatformDelegate is deleted.
+    void set_cancelled() {
+      cancelled_ = true;
+    }
+
+    bool is_cancelled() const {
+      return cancelled_;
+    }
+
+   private:
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+    bool cancelled_;
+  };
+
+  FilePathWatcher();
+  virtual ~FilePathWatcher();
+
+  // A callback that always cleans up the PlatformDelegate, either when executed
+  // or when deleted without having been executed at all, as can happen during
+  // shutdown.
+  static void CancelWatch(const scoped_refptr<PlatformDelegate>& delegate);
+
+  // Returns true if the platform and OS version support recursive watches.
+  static bool RecursiveWatchAvailable();
+
+  // Invokes |callback| whenever updates to |path| are detected. This should be
+  // called at most once, and from a MessageLoop of TYPE_IO. Set |recursive| to
+  // true, to watch |path| and its children. The callback will be invoked on
+  // the same loop. Returns true on success.
+  //
+  // Recursive watch is not supported on all platforms and file systems.
+  // Watch() will return false in the case of failure.
+  bool Watch(const FilePath& path, bool recursive, const Callback& callback);
+
+ private:
+  scoped_refptr<PlatformDelegate> impl_;
+
+  DISALLOW_COPY_AND_ASSIGN(FilePathWatcher);
+};
+
+}  // namespace base
+
+#endif  // BASE_FILES_FILE_PATH_WATCHER_H_
diff --git a/base/files/file_path_watcher_fsevents.cc b/base/files/file_path_watcher_fsevents.cc
new file mode 100644
index 0000000..da01c43
--- /dev/null
+++ b/base/files/file_path_watcher_fsevents.cc
@@ -0,0 +1,284 @@
+// 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.
+
+#include "base/files/file_path_watcher_fsevents.h"
+
+#include <list>
+
+#include "base/bind.h"
+#include "base/files/file_util.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/mac/libdispatch_task_runner.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/message_loop/message_loop.h"
+#include "base/thread_task_runner_handle.h"
+
+namespace base {
+
+namespace {
+
+// The latency parameter passed to FSEventsStreamCreate().
+const CFAbsoluteTime kEventLatencySeconds = 0.3;
+
+class FSEventsTaskRunner : public mac::LibDispatchTaskRunner {
+ public:
+   FSEventsTaskRunner()
+       : mac::LibDispatchTaskRunner("org.chromium.FilePathWatcherFSEvents") {
+   }
+
+ protected:
+  ~FSEventsTaskRunner() override {}
+};
+
+static LazyInstance<FSEventsTaskRunner>::Leaky g_task_runner =
+    LAZY_INSTANCE_INITIALIZER;
+
+// Resolve any symlinks in the path.
+FilePath ResolvePath(const FilePath& path) {
+  const unsigned kMaxLinksToResolve = 255;
+
+  std::vector<FilePath::StringType> component_vector;
+  path.GetComponents(&component_vector);
+  std::list<FilePath::StringType>
+      components(component_vector.begin(), component_vector.end());
+
+  FilePath result;
+  unsigned resolve_count = 0;
+  while (resolve_count < kMaxLinksToResolve && !components.empty()) {
+    FilePath component(*components.begin());
+    components.pop_front();
+
+    FilePath current;
+    if (component.IsAbsolute()) {
+      current = component;
+    } else {
+      current = result.Append(component);
+    }
+
+    FilePath target;
+    if (ReadSymbolicLink(current, &target)) {
+      if (target.IsAbsolute())
+        result.clear();
+      std::vector<FilePath::StringType> target_components;
+      target.GetComponents(&target_components);
+      components.insert(components.begin(), target_components.begin(),
+                        target_components.end());
+      resolve_count++;
+    } else {
+      result = current;
+    }
+  }
+
+  if (resolve_count >= kMaxLinksToResolve)
+    result.clear();
+  return result;
+}
+
+}  // namespace
+
+FilePathWatcherFSEvents::FilePathWatcherFSEvents() : fsevent_stream_(NULL) {
+}
+
+bool FilePathWatcherFSEvents::Watch(const FilePath& path,
+                                    bool recursive,
+                                    const FilePathWatcher::Callback& callback) {
+  DCHECK(MessageLoopForIO::current());
+  DCHECK(!callback.is_null());
+  DCHECK(callback_.is_null());
+
+  // This class could support non-recursive watches, but that is currently
+  // left to FilePathWatcherKQueue.
+  if (!recursive)
+    return false;
+
+  set_task_runner(ThreadTaskRunnerHandle::Get());
+  callback_ = callback;
+
+  FSEventStreamEventId start_event = FSEventsGetCurrentEventId();
+  g_task_runner.Get().PostTask(
+      FROM_HERE, Bind(&FilePathWatcherFSEvents::StartEventStream, this,
+                      start_event, path));
+  return true;
+}
+
+void FilePathWatcherFSEvents::Cancel() {
+  set_cancelled();
+  callback_.Reset();
+
+  // Switch to the dispatch queue thread to tear down the event stream.
+  g_task_runner.Get().PostTask(
+      FROM_HERE,
+      Bind(&FilePathWatcherFSEvents::CancelOnMessageLoopThread, this));
+}
+
+// static
+void FilePathWatcherFSEvents::FSEventsCallback(
+    ConstFSEventStreamRef stream,
+    void* event_watcher,
+    size_t num_events,
+    void* event_paths,
+    const FSEventStreamEventFlags flags[],
+    const FSEventStreamEventId event_ids[]) {
+  FilePathWatcherFSEvents* watcher =
+      reinterpret_cast<FilePathWatcherFSEvents*>(event_watcher);
+  DCHECK(g_task_runner.Get().RunsTasksOnCurrentThread());
+
+  bool root_changed = watcher->ResolveTargetPath();
+  std::vector<FilePath> paths;
+  FSEventStreamEventId root_change_at = FSEventStreamGetLatestEventId(stream);
+  for (size_t i = 0; i < num_events; i++) {
+    if (flags[i] & kFSEventStreamEventFlagRootChanged)
+      root_changed = true;
+    if (event_ids[i])
+      root_change_at = std::min(root_change_at, event_ids[i]);
+    paths.push_back(FilePath(
+        reinterpret_cast<char**>(event_paths)[i]).StripTrailingSeparators());
+  }
+
+  // Reinitialize the event stream if we find changes to the root. This is
+  // necessary since FSEvents doesn't report any events for the subtree after
+  // the directory to be watched gets created.
+  if (root_changed) {
+    // Resetting the event stream from within the callback fails (FSEvents spews
+    // bad file descriptor errors), so post a task to do the reset.
+    g_task_runner.Get().PostTask(
+        FROM_HERE,
+        Bind(&FilePathWatcherFSEvents::UpdateEventStream, watcher,
+             root_change_at));
+  }
+
+  watcher->OnFilePathsChanged(paths);
+}
+
+FilePathWatcherFSEvents::~FilePathWatcherFSEvents() {
+  // This method may be called on either the libdispatch or task_runner()
+  // thread. Checking callback_ on the libdispatch thread here is safe because
+  // it is executing in a task posted by Cancel() which first reset callback_.
+  // PostTask forms a sufficient memory barrier to ensure that the value is
+  // consistent on the target thread.
+  DCHECK(callback_.is_null())
+      << "Cancel() must be called before FilePathWatcher is destroyed.";
+}
+
+void FilePathWatcherFSEvents::OnFilePathsChanged(
+    const std::vector<FilePath>& paths) {
+  DCHECK(g_task_runner.Get().RunsTasksOnCurrentThread());
+  DCHECK(!resolved_target_.empty());
+  task_runner()->PostTask(
+      FROM_HERE, Bind(&FilePathWatcherFSEvents::DispatchEvents, this, paths,
+                      target_, resolved_target_));
+}
+
+void FilePathWatcherFSEvents::DispatchEvents(const std::vector<FilePath>& paths,
+                                             const FilePath& target,
+                                             const FilePath& resolved_target) {
+  DCHECK(task_runner()->RunsTasksOnCurrentThread());
+
+  // Don't issue callbacks after Cancel() has been called.
+  if (is_cancelled() || callback_.is_null()) {
+    return;
+  }
+
+  for (const FilePath& path : paths) {
+    if (resolved_target.IsParent(path) || resolved_target == path) {
+      callback_.Run(target, false);
+      return;
+    }
+  }
+}
+
+void FilePathWatcherFSEvents::CancelOnMessageLoopThread() {
+  // For all other implementations, the "message loop thread" is the IO thread,
+  // as returned by task_runner(). This implementation, however, needs to
+  // cancel pending work on the Dispatch Queue thread.
+  DCHECK(g_task_runner.Get().RunsTasksOnCurrentThread());
+
+  if (fsevent_stream_) {
+    DestroyEventStream();
+    target_.clear();
+    resolved_target_.clear();
+  }
+}
+
+void FilePathWatcherFSEvents::UpdateEventStream(
+    FSEventStreamEventId start_event) {
+  DCHECK(g_task_runner.Get().RunsTasksOnCurrentThread());
+
+  // It can happen that the watcher gets canceled while tasks that call this
+  // function are still in flight, so abort if this situation is detected.
+  if (resolved_target_.empty())
+    return;
+
+  if (fsevent_stream_)
+    DestroyEventStream();
+
+  ScopedCFTypeRef<CFStringRef> cf_path(CFStringCreateWithCString(
+      NULL, resolved_target_.value().c_str(), kCFStringEncodingMacHFS));
+  ScopedCFTypeRef<CFStringRef> cf_dir_path(CFStringCreateWithCString(
+      NULL, resolved_target_.DirName().value().c_str(),
+      kCFStringEncodingMacHFS));
+  CFStringRef paths_array[] = { cf_path.get(), cf_dir_path.get() };
+  ScopedCFTypeRef<CFArrayRef> watched_paths(CFArrayCreate(
+      NULL, reinterpret_cast<const void**>(paths_array), arraysize(paths_array),
+      &kCFTypeArrayCallBacks));
+
+  FSEventStreamContext context;
+  context.version = 0;
+  context.info = this;
+  context.retain = NULL;
+  context.release = NULL;
+  context.copyDescription = NULL;
+
+  fsevent_stream_ = FSEventStreamCreate(NULL, &FSEventsCallback, &context,
+                                        watched_paths,
+                                        start_event,
+                                        kEventLatencySeconds,
+                                        kFSEventStreamCreateFlagWatchRoot);
+  FSEventStreamSetDispatchQueue(fsevent_stream_,
+                                g_task_runner.Get().GetDispatchQueue());
+
+  if (!FSEventStreamStart(fsevent_stream_)) {
+    task_runner()->PostTask(
+        FROM_HERE, Bind(&FilePathWatcherFSEvents::ReportError, this, target_));
+  }
+}
+
+bool FilePathWatcherFSEvents::ResolveTargetPath() {
+  DCHECK(g_task_runner.Get().RunsTasksOnCurrentThread());
+  FilePath resolved = ResolvePath(target_).StripTrailingSeparators();
+  bool changed = resolved != resolved_target_;
+  resolved_target_ = resolved;
+  if (resolved_target_.empty()) {
+    task_runner()->PostTask(
+        FROM_HERE, Bind(&FilePathWatcherFSEvents::ReportError, this, target_));
+  }
+  return changed;
+}
+
+void FilePathWatcherFSEvents::ReportError(const FilePath& target) {
+  DCHECK(task_runner()->RunsTasksOnCurrentThread());
+  if (!callback_.is_null()) {
+    callback_.Run(target, true);
+  }
+}
+
+void FilePathWatcherFSEvents::DestroyEventStream() {
+  FSEventStreamStop(fsevent_stream_);
+  FSEventStreamInvalidate(fsevent_stream_);
+  FSEventStreamRelease(fsevent_stream_);
+  fsevent_stream_ = NULL;
+}
+
+void FilePathWatcherFSEvents::StartEventStream(FSEventStreamEventId start_event,
+                                               const FilePath& path) {
+  DCHECK(g_task_runner.Get().RunsTasksOnCurrentThread());
+  DCHECK(resolved_target_.empty());
+
+  target_ = path;
+  ResolveTargetPath();
+  UpdateEventStream(start_event);
+}
+
+}  // namespace base
diff --git a/base/files/file_path_watcher_fsevents.h b/base/files/file_path_watcher_fsevents.h
new file mode 100644
index 0000000..300aa76
--- /dev/null
+++ b/base/files/file_path_watcher_fsevents.h
@@ -0,0 +1,94 @@
+// 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.
+
+#ifndef BASE_FILES_FILE_PATH_WATCHER_FSEVENTS_H_
+#define BASE_FILES_FILE_PATH_WATCHER_FSEVENTS_H_
+
+#include <CoreServices/CoreServices.h>
+
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/files/file_path_watcher.h"
+
+namespace base {
+
+// Mac-specific file watcher implementation based on FSEvents.
+// There are trade-offs between the FSEvents implementation and a kqueue
+// implementation. The biggest issues are that FSEvents on 10.6 sometimes drops
+// events and kqueue does not trigger for modifications to a file in a watched
+// directory. See file_path_watcher_mac.cc for the code that decides when to
+// use which one.
+class FilePathWatcherFSEvents : public FilePathWatcher::PlatformDelegate {
+ public:
+  FilePathWatcherFSEvents();
+
+  // FilePathWatcher::PlatformDelegate overrides.
+  bool Watch(const FilePath& path,
+             bool recursive,
+             const FilePathWatcher::Callback& callback) override;
+  void Cancel() override;
+
+ private:
+  static void FSEventsCallback(ConstFSEventStreamRef stream,
+                               void* event_watcher,
+                               size_t num_events,
+                               void* event_paths,
+                               const FSEventStreamEventFlags flags[],
+                               const FSEventStreamEventId event_ids[]);
+
+  ~FilePathWatcherFSEvents() override;
+
+  // Called from FSEventsCallback whenever there is a change to the paths.
+  void OnFilePathsChanged(const std::vector<FilePath>& paths);
+
+  // Called on the message_loop() thread to dispatch path events. Can't access
+  // target_ and resolved_target_ directly as those are modified on the
+  // libdispatch thread.
+  void DispatchEvents(const std::vector<FilePath>& paths,
+                      const FilePath& target,
+                      const FilePath& resolved_target);
+
+  // Cleans up and stops the event stream.
+  void CancelOnMessageLoopThread() override;
+
+  // (Re-)Initialize the event stream to start reporting events from
+  // |start_event|.
+  void UpdateEventStream(FSEventStreamEventId start_event);
+
+  // Returns true if resolving the target path got a different result than
+  // last time it was done.
+  bool ResolveTargetPath();
+
+  // Report an error watching the given target.
+  void ReportError(const FilePath& target);
+
+  // Destroy the event stream.
+  void DestroyEventStream();
+
+  // Start watching the FSEventStream.
+  void StartEventStream(FSEventStreamEventId start_event, const FilePath& path);
+
+  // Callback to notify upon changes.
+  // (Only accessed from the message_loop() thread.)
+  FilePathWatcher::Callback callback_;
+
+  // Target path to watch (passed to callback).
+  // (Only accessed from the libdispatch thread.)
+  FilePath target_;
+
+  // Target path with all symbolic links resolved.
+  // (Only accessed from the libdispatch thread.)
+  FilePath resolved_target_;
+
+  // Backend stream we receive event callbacks from (strong reference).
+  // (Only accessed from the libdispatch thread.)
+  FSEventStreamRef fsevent_stream_;
+
+  DISALLOW_COPY_AND_ASSIGN(FilePathWatcherFSEvents);
+};
+
+}  // namespace base
+
+#endif  // BASE_FILES_FILE_PATH_WATCHER_FSEVENTS_H_
diff --git a/base/files/file_path_watcher_kqueue.cc b/base/files/file_path_watcher_kqueue.cc
new file mode 100644
index 0000000..e15cba7
--- /dev/null
+++ b/base/files/file_path_watcher_kqueue.cc
@@ -0,0 +1,390 @@
+// Copyright (c) 2012 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/files/file_path_watcher_kqueue.h"
+
+#include <fcntl.h>
+#include <sys/param.h>
+
+#include "base/bind.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "base/thread_task_runner_handle.h"
+
+// On some platforms these are not defined.
+#if !defined(EV_RECEIPT)
+#define EV_RECEIPT 0
+#endif
+#if !defined(O_EVTONLY)
+#define O_EVTONLY O_RDONLY
+#endif
+
+namespace base {
+
+FilePathWatcherKQueue::FilePathWatcherKQueue() : kqueue_(-1) {}
+
+FilePathWatcherKQueue::~FilePathWatcherKQueue() {}
+
+void FilePathWatcherKQueue::ReleaseEvent(struct kevent& event) {
+  CloseFileDescriptor(&event.ident);
+  EventData* entry = EventDataForKevent(event);
+  delete entry;
+  event.udata = NULL;
+}
+
+int FilePathWatcherKQueue::EventsForPath(FilePath path, EventVector* events) {
+  DCHECK(MessageLoopForIO::current());
+  // Make sure that we are working with a clean slate.
+  DCHECK(events->empty());
+
+  std::vector<FilePath::StringType> components;
+  path.GetComponents(&components);
+
+  if (components.size() < 1) {
+    return -1;
+  }
+
+  int last_existing_entry = 0;
+  FilePath built_path;
+  bool path_still_exists = true;
+  for (std::vector<FilePath::StringType>::iterator i = components.begin();
+      i != components.end(); ++i) {
+    if (i == components.begin()) {
+      built_path = FilePath(*i);
+    } else {
+      built_path = built_path.Append(*i);
+    }
+    uintptr_t fd = kNoFileDescriptor;
+    if (path_still_exists) {
+      fd = FileDescriptorForPath(built_path);
+      if (fd == kNoFileDescriptor) {
+        path_still_exists = false;
+      } else {
+        ++last_existing_entry;
+      }
+    }
+    FilePath::StringType subdir = (i != (components.end() - 1)) ? *(i + 1) : "";
+    EventData* data = new EventData(built_path, subdir);
+    struct kevent event;
+    EV_SET(&event, fd, EVFILT_VNODE, (EV_ADD | EV_CLEAR | EV_RECEIPT),
+           (NOTE_DELETE | NOTE_WRITE | NOTE_ATTRIB |
+            NOTE_RENAME | NOTE_REVOKE | NOTE_EXTEND), 0, data);
+    events->push_back(event);
+  }
+  return last_existing_entry;
+}
+
+uintptr_t FilePathWatcherKQueue::FileDescriptorForPath(const FilePath& path) {
+  int fd = HANDLE_EINTR(open(path.value().c_str(), O_EVTONLY));
+  if (fd == -1)
+    return kNoFileDescriptor;
+  return fd;
+}
+
+void FilePathWatcherKQueue::CloseFileDescriptor(uintptr_t* fd) {
+  if (*fd == kNoFileDescriptor) {
+    return;
+  }
+
+  if (IGNORE_EINTR(close(*fd)) != 0) {
+    DPLOG(ERROR) << "close";
+  }
+  *fd = kNoFileDescriptor;
+}
+
+bool FilePathWatcherKQueue::AreKeventValuesValid(struct kevent* kevents,
+                                               int count) {
+  if (count < 0) {
+    DPLOG(ERROR) << "kevent";
+    return false;
+  }
+  bool valid = true;
+  for (int i = 0; i < count; ++i) {
+    if (kevents[i].flags & EV_ERROR && kevents[i].data) {
+      // Find the kevent in |events_| that matches the kevent with the error.
+      EventVector::iterator event = events_.begin();
+      for (; event != events_.end(); ++event) {
+        if (event->ident == kevents[i].ident) {
+          break;
+        }
+      }
+      std::string path_name;
+      if (event != events_.end()) {
+        EventData* event_data = EventDataForKevent(*event);
+        if (event_data != NULL) {
+          path_name = event_data->path_.value();
+        }
+      }
+      if (path_name.empty()) {
+        path_name = base::StringPrintf(
+            "fd %ld", reinterpret_cast<long>(&kevents[i].ident));
+      }
+      DLOG(ERROR) << "Error: " << kevents[i].data << " for " << path_name;
+      valid = false;
+    }
+  }
+  return valid;
+}
+
+void FilePathWatcherKQueue::HandleAttributesChange(
+    const EventVector::iterator& event,
+    bool* target_file_affected,
+    bool* update_watches) {
+  EventVector::iterator next_event = event + 1;
+  EventData* next_event_data = EventDataForKevent(*next_event);
+  // Check to see if the next item in path is still accessible.
+  uintptr_t have_access = FileDescriptorForPath(next_event_data->path_);
+  if (have_access == kNoFileDescriptor) {
+    *target_file_affected = true;
+    *update_watches = true;
+    EventVector::iterator local_event(event);
+    for (; local_event != events_.end(); ++local_event) {
+      // Close all nodes from the event down. This has the side effect of
+      // potentially rendering other events in |updates| invalid.
+      // There is no need to remove the events from |kqueue_| because this
+      // happens as a side effect of closing the file descriptor.
+      CloseFileDescriptor(&local_event->ident);
+    }
+  } else {
+    CloseFileDescriptor(&have_access);
+  }
+}
+
+void FilePathWatcherKQueue::HandleDeleteOrMoveChange(
+    const EventVector::iterator& event,
+    bool* target_file_affected,
+    bool* update_watches) {
+  *target_file_affected = true;
+  *update_watches = true;
+  EventVector::iterator local_event(event);
+  for (; local_event != events_.end(); ++local_event) {
+    // Close all nodes from the event down. This has the side effect of
+    // potentially rendering other events in |updates| invalid.
+    // There is no need to remove the events from |kqueue_| because this
+    // happens as a side effect of closing the file descriptor.
+    CloseFileDescriptor(&local_event->ident);
+  }
+}
+
+void FilePathWatcherKQueue::HandleCreateItemChange(
+    const EventVector::iterator& event,
+    bool* target_file_affected,
+    bool* update_watches) {
+  // Get the next item in the path.
+  EventVector::iterator next_event = event + 1;
+  // Check to see if it already has a valid file descriptor.
+  if (!IsKeventFileDescriptorOpen(*next_event)) {
+    EventData* next_event_data = EventDataForKevent(*next_event);
+    // If not, attempt to open a file descriptor for it.
+    next_event->ident = FileDescriptorForPath(next_event_data->path_);
+    if (IsKeventFileDescriptorOpen(*next_event)) {
+      *update_watches = true;
+      if (next_event_data->subdir_.empty()) {
+        *target_file_affected = true;
+      }
+    }
+  }
+}
+
+bool FilePathWatcherKQueue::UpdateWatches(bool* target_file_affected) {
+  // Iterate over events adding kevents for items that exist to the kqueue.
+  // Then check to see if new components in the path have been created.
+  // Repeat until no new components in the path are detected.
+  // This is to get around races in directory creation in a watched path.
+  bool update_watches = true;
+  while (update_watches) {
+    size_t valid;
+    for (valid = 0; valid < events_.size(); ++valid) {
+      if (!IsKeventFileDescriptorOpen(events_[valid])) {
+        break;
+      }
+    }
+    if (valid == 0) {
+      // The root of the file path is inaccessible?
+      return false;
+    }
+
+    EventVector updates(valid);
+    int count = HANDLE_EINTR(kevent(kqueue_, &events_[0], valid, &updates[0],
+                                    valid, NULL));
+    if (!AreKeventValuesValid(&updates[0], count)) {
+      return false;
+    }
+    update_watches = false;
+    for (; valid < events_.size(); ++valid) {
+      EventData* event_data = EventDataForKevent(events_[valid]);
+      events_[valid].ident = FileDescriptorForPath(event_data->path_);
+      if (IsKeventFileDescriptorOpen(events_[valid])) {
+        update_watches = true;
+        if (event_data->subdir_.empty()) {
+          *target_file_affected = true;
+        }
+      } else {
+        break;
+      }
+    }
+  }
+  return true;
+}
+
+void FilePathWatcherKQueue::OnFileCanReadWithoutBlocking(int fd) {
+  DCHECK(MessageLoopForIO::current());
+  DCHECK_EQ(fd, kqueue_);
+  DCHECK(events_.size());
+
+  // Request the file system update notifications that have occurred and return
+  // them in |updates|. |count| will contain the number of updates that have
+  // occurred.
+  EventVector updates(events_.size());
+  struct timespec timeout = {0, 0};
+  int count = HANDLE_EINTR(kevent(kqueue_, NULL, 0, &updates[0], updates.size(),
+                                  &timeout));
+
+  // Error values are stored within updates, so check to make sure that no
+  // errors occurred.
+  if (!AreKeventValuesValid(&updates[0], count)) {
+    callback_.Run(target_, true /* error */);
+    Cancel();
+    return;
+  }
+
+  bool update_watches = false;
+  bool send_notification = false;
+
+  // Iterate through each of the updates and react to them.
+  for (int i = 0; i < count; ++i) {
+    // Find our kevent record that matches the update notification.
+    EventVector::iterator event = events_.begin();
+    for (; event != events_.end(); ++event) {
+      if (!IsKeventFileDescriptorOpen(*event) ||
+          event->ident == updates[i].ident) {
+        break;
+      }
+    }
+    if (event == events_.end() || !IsKeventFileDescriptorOpen(*event)) {
+      // The event may no longer exist in |events_| because another event
+      // modified |events_| in such a way to make it invalid. For example if
+      // the path is /foo/bar/bam and foo is deleted, NOTE_DELETE events for
+      // foo, bar and bam will be sent. If foo is processed first, then
+      // the file descriptors for bar and bam will already be closed and set
+      // to -1 before they get a chance to be processed.
+      continue;
+    }
+
+    EventData* event_data = EventDataForKevent(*event);
+
+    // If the subdir is empty, this is the last item on the path and is the
+    // target file.
+    bool target_file_affected = event_data->subdir_.empty();
+    if ((updates[i].fflags & NOTE_ATTRIB) && !target_file_affected) {
+      HandleAttributesChange(event, &target_file_affected, &update_watches);
+    }
+    if (updates[i].fflags & (NOTE_DELETE | NOTE_REVOKE | NOTE_RENAME)) {
+      HandleDeleteOrMoveChange(event, &target_file_affected, &update_watches);
+    }
+    if ((updates[i].fflags & NOTE_WRITE) && !target_file_affected) {
+      HandleCreateItemChange(event, &target_file_affected, &update_watches);
+    }
+    send_notification |= target_file_affected;
+  }
+
+  if (update_watches) {
+    if (!UpdateWatches(&send_notification)) {
+      callback_.Run(target_, true /* error */);
+      Cancel();
+    }
+  }
+
+  if (send_notification) {
+    callback_.Run(target_, false);
+  }
+}
+
+void FilePathWatcherKQueue::OnFileCanWriteWithoutBlocking(int fd) {
+  NOTREACHED();
+}
+
+void FilePathWatcherKQueue::WillDestroyCurrentMessageLoop() {
+  CancelOnMessageLoopThread();
+}
+
+bool FilePathWatcherKQueue::Watch(const FilePath& path,
+                                  bool recursive,
+                                  const FilePathWatcher::Callback& callback) {
+  DCHECK(MessageLoopForIO::current());
+  DCHECK(target_.value().empty());  // Can only watch one path.
+  DCHECK(!callback.is_null());
+  DCHECK_EQ(kqueue_, -1);
+
+  if (recursive) {
+    // Recursive watch is not supported using kqueue.
+    NOTIMPLEMENTED();
+    return false;
+  }
+
+  callback_ = callback;
+  target_ = path;
+
+  MessageLoop::current()->AddDestructionObserver(this);
+  io_task_runner_ = ThreadTaskRunnerHandle::Get();
+
+  kqueue_ = kqueue();
+  if (kqueue_ == -1) {
+    DPLOG(ERROR) << "kqueue";
+    return false;
+  }
+
+  int last_entry = EventsForPath(target_, &events_);
+  DCHECK_NE(last_entry, 0);
+
+  EventVector responses(last_entry);
+
+  int count = HANDLE_EINTR(kevent(kqueue_, &events_[0], last_entry,
+                                  &responses[0], last_entry, NULL));
+  if (!AreKeventValuesValid(&responses[0], count)) {
+    // Calling Cancel() here to close any file descriptors that were opened.
+    // This would happen in the destructor anyways, but FilePathWatchers tend to
+    // be long lived, and if an error has occurred, there is no reason to waste
+    // the file descriptors.
+    Cancel();
+    return false;
+  }
+
+  return MessageLoopForIO::current()->WatchFileDescriptor(
+      kqueue_, true, MessageLoopForIO::WATCH_READ, &kqueue_watcher_, this);
+}
+
+void FilePathWatcherKQueue::Cancel() {
+  SingleThreadTaskRunner* task_runner = io_task_runner_.get();
+  if (!task_runner) {
+    set_cancelled();
+    return;
+  }
+  if (!task_runner->BelongsToCurrentThread()) {
+    task_runner->PostTask(FROM_HERE,
+                          base::Bind(&FilePathWatcherKQueue::Cancel, this));
+    return;
+  }
+  CancelOnMessageLoopThread();
+}
+
+void FilePathWatcherKQueue::CancelOnMessageLoopThread() {
+  DCHECK(MessageLoopForIO::current());
+  if (!is_cancelled()) {
+    set_cancelled();
+    kqueue_watcher_.StopWatchingFileDescriptor();
+    if (IGNORE_EINTR(close(kqueue_)) != 0) {
+      DPLOG(ERROR) << "close kqueue";
+    }
+    kqueue_ = -1;
+    std::for_each(events_.begin(), events_.end(), ReleaseEvent);
+    events_.clear();
+    io_task_runner_ = NULL;
+    MessageLoop::current()->RemoveDestructionObserver(this);
+    callback_.Reset();
+  }
+}
+
+}  // namespace base
diff --git a/base/files/file_path_watcher_kqueue.h b/base/files/file_path_watcher_kqueue.h
new file mode 100644
index 0000000..69555a3
--- /dev/null
+++ b/base/files/file_path_watcher_kqueue.h
@@ -0,0 +1,132 @@
+// 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.
+
+#ifndef BASE_FILES_FILE_PATH_WATCHER_KQUEUE_H_
+#define BASE_FILES_FILE_PATH_WATCHER_KQUEUE_H_
+
+#include <sys/event.h>
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/files/file_path_watcher.h"
+#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
+
+namespace base {
+
+// Mac-specific file watcher implementation based on kqueue.
+// The Linux and Windows versions are able to detect:
+// - file creation/deletion/modification in a watched directory
+// - file creation/deletion/modification for a watched file
+// - modifications to the paths to a watched object that would affect the
+//   object such as renaming/attibute changes etc.
+// The kqueue implementation will handle all of the items in the list above
+// except for detecting modifications to files in a watched directory. It will
+// detect the creation and deletion of files, just not the modification of
+// files. It does however detect the attribute changes that the FSEvents impl
+// would miss.
+class FilePathWatcherKQueue : public FilePathWatcher::PlatformDelegate,
+                              public MessageLoopForIO::Watcher,
+                              public MessageLoop::DestructionObserver {
+ public:
+  FilePathWatcherKQueue();
+
+  // MessageLoopForIO::Watcher overrides.
+  void OnFileCanReadWithoutBlocking(int fd) override;
+  void OnFileCanWriteWithoutBlocking(int fd) override;
+
+  // MessageLoop::DestructionObserver overrides.
+  void WillDestroyCurrentMessageLoop() override;
+
+  // FilePathWatcher::PlatformDelegate overrides.
+  bool Watch(const FilePath& path,
+             bool recursive,
+             const FilePathWatcher::Callback& callback) override;
+  void Cancel() override;
+
+ protected:
+  ~FilePathWatcherKQueue() override;
+
+ private:
+  class EventData {
+   public:
+    EventData(const FilePath& path, const FilePath::StringType& subdir)
+        : path_(path), subdir_(subdir) { }
+    FilePath path_;  // Full path to this item.
+    FilePath::StringType subdir_;  // Path to any sub item.
+  };
+
+  typedef std::vector<struct kevent> EventVector;
+
+  // Can only be called on |io_task_runner_|'s thread.
+  void CancelOnMessageLoopThread() override;
+
+  // Returns true if the kevent values are error free.
+  bool AreKeventValuesValid(struct kevent* kevents, int count);
+
+  // Respond to a change of attributes of the path component represented by
+  // |event|. Sets |target_file_affected| to true if |target_| is affected.
+  // Sets |update_watches| to true if |events_| need to be updated.
+  void HandleAttributesChange(const EventVector::iterator& event,
+                              bool* target_file_affected,
+                              bool* update_watches);
+
+  // Respond to a move or deletion of the path component represented by
+  // |event|. Sets |target_file_affected| to true if |target_| is affected.
+  // Sets |update_watches| to true if |events_| need to be updated.
+  void HandleDeleteOrMoveChange(const EventVector::iterator& event,
+                                bool* target_file_affected,
+                                bool* update_watches);
+
+  // Respond to a creation of an item in the path component represented by
+  // |event|. Sets |target_file_affected| to true if |target_| is affected.
+  // Sets |update_watches| to true if |events_| need to be updated.
+  void HandleCreateItemChange(const EventVector::iterator& event,
+                              bool* target_file_affected,
+                              bool* update_watches);
+
+  // Update |events_| with the current status of the system.
+  // Sets |target_file_affected| to true if |target_| is affected.
+  // Returns false if an error occurs.
+  bool UpdateWatches(bool* target_file_affected);
+
+  // Fills |events| with one kevent per component in |path|.
+  // Returns the number of valid events created where a valid event is
+  // defined as one that has a ident (file descriptor) field != -1.
+  static int EventsForPath(FilePath path, EventVector *events);
+
+  // Release a kevent generated by EventsForPath.
+  static void ReleaseEvent(struct kevent& event);
+
+  // Returns a file descriptor that will not block the system from deleting
+  // the file it references.
+  static uintptr_t FileDescriptorForPath(const FilePath& path);
+
+  static const uintptr_t kNoFileDescriptor = static_cast<uintptr_t>(-1);
+
+  // Closes |*fd| and sets |*fd| to -1.
+  static void CloseFileDescriptor(uintptr_t* fd);
+
+  // Returns true if kevent has open file descriptor.
+  static bool IsKeventFileDescriptorOpen(const struct kevent& event) {
+    return event.ident != kNoFileDescriptor;
+  }
+
+  static EventData* EventDataForKevent(const struct kevent& event) {
+    return reinterpret_cast<EventData*>(event.udata);
+  }
+
+  EventVector events_;
+  scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
+  MessageLoopForIO::FileDescriptorWatcher kqueue_watcher_;
+  FilePathWatcher::Callback callback_;
+  FilePath target_;
+  int kqueue_;
+
+  DISALLOW_COPY_AND_ASSIGN(FilePathWatcherKQueue);
+};
+
+}  // namespace base
+
+#endif  // BASE_FILES_FILE_PATH_WATCHER_KQUEUE_H_
diff --git a/base/files/file_path_watcher_linux.cc b/base/files/file_path_watcher_linux.cc
new file mode 100644
index 0000000..ba2f1d9
--- /dev/null
+++ b/base/files/file_path_watcher_linux.cc
@@ -0,0 +1,690 @@
+// Copyright (c) 2012 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/files/file_path_watcher.h"
+
+#include <errno.h>
+#include <string.h>
+#include <sys/inotify.h>
+#include <sys/ioctl.h>
+#include <sys/select.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <map>
+#include <set>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/containers/hash_tables.h"
+#include "base/files/file_enumerator.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/lazy_instance.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/lock.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/thread.h"
+#include "base/trace_event/trace_event.h"
+
+namespace base {
+
+namespace {
+
+class FilePathWatcherImpl;
+
+// Singleton to manage all inotify watches.
+// TODO(tony): It would be nice if this wasn't a singleton.
+// http://crbug.com/38174
+class InotifyReader {
+ public:
+  typedef int Watch;  // Watch descriptor used by AddWatch and RemoveWatch.
+  static const Watch kInvalidWatch = -1;
+
+  // Watch directory |path| for changes. |watcher| will be notified on each
+  // change. Returns kInvalidWatch on failure.
+  Watch AddWatch(const FilePath& path, FilePathWatcherImpl* watcher);
+
+  // Remove |watch| if it's valid.
+  void RemoveWatch(Watch watch, FilePathWatcherImpl* watcher);
+
+  // Callback for InotifyReaderTask.
+  void OnInotifyEvent(const inotify_event* event);
+
+ private:
+  friend struct DefaultLazyInstanceTraits<InotifyReader>;
+
+  typedef std::set<FilePathWatcherImpl*> WatcherSet;
+
+  InotifyReader();
+  ~InotifyReader();
+
+  // We keep track of which delegates want to be notified on which watches.
+  hash_map<Watch, WatcherSet> watchers_;
+
+  // Lock to protect watchers_.
+  Lock lock_;
+
+  // Separate thread on which we run blocking read for inotify events.
+  Thread thread_;
+
+  // File descriptor returned by inotify_init.
+  const int inotify_fd_;
+
+  // Use self-pipe trick to unblock select during shutdown.
+  int shutdown_pipe_[2];
+
+  // Flag set to true when startup was successful.
+  bool valid_;
+
+  DISALLOW_COPY_AND_ASSIGN(InotifyReader);
+};
+
+class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate,
+                            public MessageLoop::DestructionObserver {
+ public:
+  FilePathWatcherImpl();
+
+  // Called for each event coming from the watch. |fired_watch| identifies the
+  // watch that fired, |child| indicates what has changed, and is relative to
+  // the currently watched path for |fired_watch|.
+  //
+  // |created| is true if the object appears.
+  // |deleted| is true if the object disappears.
+  // |is_dir| is true if the object is a directory.
+  void OnFilePathChanged(InotifyReader::Watch fired_watch,
+                         const FilePath::StringType& child,
+                         bool created,
+                         bool deleted,
+                         bool is_dir);
+
+ protected:
+  ~FilePathWatcherImpl() override {}
+
+ private:
+  // Start watching |path| for changes and notify |delegate| on each change.
+  // Returns true if watch for |path| has been added successfully.
+  bool Watch(const FilePath& path,
+             bool recursive,
+             const FilePathWatcher::Callback& callback) override;
+
+  // Cancel the watch. This unregisters the instance with InotifyReader.
+  void Cancel() override;
+
+  // Cleans up and stops observing the message_loop() thread.
+  void CancelOnMessageLoopThread() override;
+
+  // Deletion of the FilePathWatcher will call Cancel() to dispose of this
+  // object in the right thread. This also observes destruction of the required
+  // cleanup thread, in case it quits before Cancel() is called.
+  void WillDestroyCurrentMessageLoop() override;
+
+  // Inotify watches are installed for all directory components of |target_|.
+  // A WatchEntry instance holds:
+  // - |watch|: the watch descriptor for a component.
+  // - |subdir|: the subdirectory that identifies the next component.
+  //   - For the last component, there is no next component, so it is empty.
+  // - |linkname|: the target of the symlink.
+  //   - Only if the target being watched is a symbolic link.
+  struct WatchEntry {
+    explicit WatchEntry(const FilePath::StringType& dirname)
+        : watch(InotifyReader::kInvalidWatch),
+          subdir(dirname) {}
+
+    InotifyReader::Watch watch;
+    FilePath::StringType subdir;
+    FilePath::StringType linkname;
+  };
+  typedef std::vector<WatchEntry> WatchVector;
+
+  // Reconfigure to watch for the most specific parent directory of |target_|
+  // that exists. Also calls UpdateRecursiveWatches() below.
+  void UpdateWatches();
+
+  // Reconfigure to recursively watch |target_| and all its sub-directories.
+  // - This is a no-op if the watch is not recursive.
+  // - If |target_| does not exist, then clear all the recursive watches.
+  // - Assuming |target_| exists, passing kInvalidWatch as |fired_watch| forces
+  //   addition of recursive watches for |target_|.
+  // - Otherwise, only the directory associated with |fired_watch| and its
+  //   sub-directories will be reconfigured.
+  void UpdateRecursiveWatches(InotifyReader::Watch fired_watch, bool is_dir);
+
+  // Enumerate recursively through |path| and add / update watches.
+  void UpdateRecursiveWatchesForPath(const FilePath& path);
+
+  // Do internal bookkeeping to update mappings between |watch| and its
+  // associated full path |path|.
+  void TrackWatchForRecursion(InotifyReader::Watch watch, const FilePath& path);
+
+  // Remove all the recursive watches.
+  void RemoveRecursiveWatches();
+
+  // |path| is a symlink to a non-existent target. Attempt to add a watch to
+  // the link target's parent directory. Returns true and update |watch_entry|
+  // on success.
+  bool AddWatchForBrokenSymlink(const FilePath& path, WatchEntry* watch_entry);
+
+  bool HasValidWatchVector() const;
+
+  // Callback to notify upon changes.
+  FilePathWatcher::Callback callback_;
+
+  // The file or directory we're supposed to watch.
+  FilePath target_;
+
+  bool recursive_;
+
+  // The vector of watches and next component names for all path components,
+  // starting at the root directory. The last entry corresponds to the watch for
+  // |target_| and always stores an empty next component name in |subdir|.
+  WatchVector watches_;
+
+  hash_map<InotifyReader::Watch, FilePath> recursive_paths_by_watch_;
+  std::map<FilePath, InotifyReader::Watch> recursive_watches_by_path_;
+
+  DISALLOW_COPY_AND_ASSIGN(FilePathWatcherImpl);
+};
+
+void InotifyReaderCallback(InotifyReader* reader, int inotify_fd,
+                           int shutdown_fd) {
+  // Make sure the file descriptors are good for use with select().
+  CHECK_LE(0, inotify_fd);
+  CHECK_GT(FD_SETSIZE, inotify_fd);
+  CHECK_LE(0, shutdown_fd);
+  CHECK_GT(FD_SETSIZE, shutdown_fd);
+
+  trace_event::TraceLog::GetInstance()->SetCurrentThreadBlocksMessageLoop();
+
+  while (true) {
+    fd_set rfds;
+    FD_ZERO(&rfds);
+    FD_SET(inotify_fd, &rfds);
+    FD_SET(shutdown_fd, &rfds);
+
+    // Wait until some inotify events are available.
+    int select_result =
+      HANDLE_EINTR(select(std::max(inotify_fd, shutdown_fd) + 1,
+                          &rfds, NULL, NULL, NULL));
+    if (select_result < 0) {
+      DPLOG(WARNING) << "select failed";
+      return;
+    }
+
+    if (FD_ISSET(shutdown_fd, &rfds))
+      return;
+
+    // Adjust buffer size to current event queue size.
+    int buffer_size;
+    int ioctl_result = HANDLE_EINTR(ioctl(inotify_fd, FIONREAD,
+                                          &buffer_size));
+
+    if (ioctl_result != 0) {
+      DPLOG(WARNING) << "ioctl failed";
+      return;
+    }
+
+    std::vector<char> buffer(buffer_size);
+
+    ssize_t bytes_read = HANDLE_EINTR(read(inotify_fd, &buffer[0],
+                                           buffer_size));
+
+    if (bytes_read < 0) {
+      DPLOG(WARNING) << "read from inotify fd failed";
+      return;
+    }
+
+    ssize_t i = 0;
+    while (i < bytes_read) {
+      inotify_event* event = reinterpret_cast<inotify_event*>(&buffer[i]);
+      size_t event_size = sizeof(inotify_event) + event->len;
+      DCHECK(i + event_size <= static_cast<size_t>(bytes_read));
+      reader->OnInotifyEvent(event);
+      i += event_size;
+    }
+  }
+}
+
+static LazyInstance<InotifyReader>::Leaky g_inotify_reader =
+    LAZY_INSTANCE_INITIALIZER;
+
+InotifyReader::InotifyReader()
+    : thread_("inotify_reader"),
+      inotify_fd_(inotify_init()),
+      valid_(false) {
+  if (inotify_fd_ < 0)
+    PLOG(ERROR) << "inotify_init() failed";
+
+  shutdown_pipe_[0] = -1;
+  shutdown_pipe_[1] = -1;
+  if (inotify_fd_ >= 0 && pipe(shutdown_pipe_) == 0 && thread_.Start()) {
+    thread_.task_runner()->PostTask(
+        FROM_HERE,
+        Bind(&InotifyReaderCallback, this, inotify_fd_, shutdown_pipe_[0]));
+    valid_ = true;
+  }
+}
+
+InotifyReader::~InotifyReader() {
+  if (valid_) {
+    // Write to the self-pipe so that the select call in InotifyReaderTask
+    // returns.
+    ssize_t ret = HANDLE_EINTR(write(shutdown_pipe_[1], "", 1));
+    DPCHECK(ret > 0);
+    DCHECK_EQ(ret, 1);
+    thread_.Stop();
+  }
+  if (inotify_fd_ >= 0)
+    close(inotify_fd_);
+  if (shutdown_pipe_[0] >= 0)
+    close(shutdown_pipe_[0]);
+  if (shutdown_pipe_[1] >= 0)
+    close(shutdown_pipe_[1]);
+}
+
+InotifyReader::Watch InotifyReader::AddWatch(
+    const FilePath& path, FilePathWatcherImpl* watcher) {
+  if (!valid_)
+    return kInvalidWatch;
+
+  AutoLock auto_lock(lock_);
+
+  Watch watch = inotify_add_watch(inotify_fd_, path.value().c_str(),
+                                  IN_ATTRIB | IN_CREATE | IN_DELETE |
+                                  IN_CLOSE_WRITE | IN_MOVE |
+                                  IN_ONLYDIR);
+
+  if (watch == kInvalidWatch)
+    return kInvalidWatch;
+
+  watchers_[watch].insert(watcher);
+
+  return watch;
+}
+
+void InotifyReader::RemoveWatch(Watch watch, FilePathWatcherImpl* watcher) {
+  if (!valid_ || (watch == kInvalidWatch))
+    return;
+
+  AutoLock auto_lock(lock_);
+
+  watchers_[watch].erase(watcher);
+
+  if (watchers_[watch].empty()) {
+    watchers_.erase(watch);
+    inotify_rm_watch(inotify_fd_, watch);
+  }
+}
+
+void InotifyReader::OnInotifyEvent(const inotify_event* event) {
+  if (event->mask & IN_IGNORED)
+    return;
+
+  FilePath::StringType child(event->len ? event->name : FILE_PATH_LITERAL(""));
+  AutoLock auto_lock(lock_);
+
+  for (WatcherSet::iterator watcher = watchers_[event->wd].begin();
+       watcher != watchers_[event->wd].end();
+       ++watcher) {
+    (*watcher)->OnFilePathChanged(event->wd,
+                                  child,
+                                  event->mask & (IN_CREATE | IN_MOVED_TO),
+                                  event->mask & (IN_DELETE | IN_MOVED_FROM),
+                                  event->mask & IN_ISDIR);
+  }
+}
+
+FilePathWatcherImpl::FilePathWatcherImpl()
+    : recursive_(false) {
+}
+
+void FilePathWatcherImpl::OnFilePathChanged(InotifyReader::Watch fired_watch,
+                                            const FilePath::StringType& child,
+                                            bool created,
+                                            bool deleted,
+                                            bool is_dir) {
+  if (!task_runner()->BelongsToCurrentThread()) {
+    // Switch to task_runner() to access |watches_| safely.
+    task_runner()->PostTask(FROM_HERE,
+                            Bind(&FilePathWatcherImpl::OnFilePathChanged, this,
+                                 fired_watch, child, created, deleted, is_dir));
+    return;
+  }
+
+  // Check to see if CancelOnMessageLoopThread() has already been called.
+  // May happen when code flow reaches here from the PostTask() above.
+  if (watches_.empty()) {
+    DCHECK(target_.empty());
+    return;
+  }
+
+  DCHECK(MessageLoopForIO::current());
+  DCHECK(HasValidWatchVector());
+
+  // Used below to avoid multiple recursive updates.
+  bool did_update = false;
+
+  // Find the entry in |watches_| that corresponds to |fired_watch|.
+  for (size_t i = 0; i < watches_.size(); ++i) {
+    const WatchEntry& watch_entry = watches_[i];
+    if (fired_watch != watch_entry.watch)
+      continue;
+
+    // Check whether a path component of |target_| changed.
+    bool change_on_target_path =
+        child.empty() ||
+        (child == watch_entry.linkname) ||
+        (child == watch_entry.subdir);
+
+    // Check if the change references |target_| or a direct child of |target_|.
+    bool target_changed;
+    if (watch_entry.subdir.empty()) {
+      // The fired watch is for a WatchEntry without a subdir. Thus for a given
+      // |target_| = "/path/to/foo", this is for "foo". Here, check either:
+      // - the target has no symlink: it is the target and it changed.
+      // - the target has a symlink, and it matches |child|.
+      target_changed = (watch_entry.linkname.empty() ||
+                        child == watch_entry.linkname);
+    } else {
+      // The fired watch is for a WatchEntry with a subdir. Thus for a given
+      // |target_| = "/path/to/foo", this is for {"/", "/path", "/path/to"}.
+      // So we can safely access the next WatchEntry since we have not reached
+      // the end yet. Check |watch_entry| is for "/path/to", i.e. the next
+      // element is "foo".
+      bool next_watch_may_be_for_target = watches_[i + 1].subdir.empty();
+      if (next_watch_may_be_for_target) {
+        // The current |watch_entry| is for "/path/to", so check if the |child|
+        // that changed is "foo".
+        target_changed = watch_entry.subdir == child;
+      } else {
+        // The current |watch_entry| is not for "/path/to", so the next entry
+        // cannot be "foo". Thus |target_| has not changed.
+        target_changed = false;
+      }
+    }
+
+    // Update watches if a directory component of the |target_| path
+    // (dis)appears. Note that we don't add the additional restriction of
+    // checking the event mask to see if it is for a directory here as changes
+    // to symlinks on the target path will not have IN_ISDIR set in the event
+    // masks. As a result we may sometimes call UpdateWatches() unnecessarily.
+    if (change_on_target_path && (created || deleted) && !did_update) {
+      UpdateWatches();
+      did_update = true;
+    }
+
+    // Report the following events:
+    //  - The target or a direct child of the target got changed (in case the
+    //    watched path refers to a directory).
+    //  - One of the parent directories got moved or deleted, since the target
+    //    disappears in this case.
+    //  - One of the parent directories appears. The event corresponding to
+    //    the target appearing might have been missed in this case, so recheck.
+    if (target_changed ||
+        (change_on_target_path && deleted) ||
+        (change_on_target_path && created && PathExists(target_))) {
+      if (!did_update) {
+        UpdateRecursiveWatches(fired_watch, is_dir);
+        did_update = true;
+      }
+      callback_.Run(target_, false /* error */);
+      return;
+    }
+  }
+
+  if (ContainsKey(recursive_paths_by_watch_, fired_watch)) {
+    if (!did_update)
+      UpdateRecursiveWatches(fired_watch, is_dir);
+    callback_.Run(target_, false /* error */);
+  }
+}
+
+bool FilePathWatcherImpl::Watch(const FilePath& path,
+                                bool recursive,
+                                const FilePathWatcher::Callback& callback) {
+  DCHECK(target_.empty());
+  DCHECK(MessageLoopForIO::current());
+
+  set_task_runner(ThreadTaskRunnerHandle::Get());
+  callback_ = callback;
+  target_ = path;
+  recursive_ = recursive;
+  MessageLoop::current()->AddDestructionObserver(this);
+
+  std::vector<FilePath::StringType> comps;
+  target_.GetComponents(&comps);
+  DCHECK(!comps.empty());
+  for (size_t i = 1; i < comps.size(); ++i)
+    watches_.push_back(WatchEntry(comps[i]));
+  watches_.push_back(WatchEntry(FilePath::StringType()));
+  UpdateWatches();
+  return true;
+}
+
+void FilePathWatcherImpl::Cancel() {
+  if (callback_.is_null()) {
+    // Watch was never called, or the message_loop() thread is already gone.
+    set_cancelled();
+    return;
+  }
+
+  // Switch to the message_loop() if necessary so we can access |watches_|.
+  if (!task_runner()->BelongsToCurrentThread()) {
+    task_runner()->PostTask(FROM_HERE, Bind(&FilePathWatcher::CancelWatch,
+                                            make_scoped_refptr(this)));
+  } else {
+    CancelOnMessageLoopThread();
+  }
+}
+
+void FilePathWatcherImpl::CancelOnMessageLoopThread() {
+  DCHECK(task_runner()->BelongsToCurrentThread());
+  set_cancelled();
+
+  if (!callback_.is_null()) {
+    MessageLoop::current()->RemoveDestructionObserver(this);
+    callback_.Reset();
+  }
+
+  for (size_t i = 0; i < watches_.size(); ++i)
+    g_inotify_reader.Get().RemoveWatch(watches_[i].watch, this);
+  watches_.clear();
+  target_.clear();
+
+  if (recursive_)
+    RemoveRecursiveWatches();
+}
+
+void FilePathWatcherImpl::WillDestroyCurrentMessageLoop() {
+  CancelOnMessageLoopThread();
+}
+
+void FilePathWatcherImpl::UpdateWatches() {
+  // Ensure this runs on the message_loop() exclusively in order to avoid
+  // concurrency issues.
+  DCHECK(task_runner()->BelongsToCurrentThread());
+  DCHECK(HasValidWatchVector());
+
+  // Walk the list of watches and update them as we go.
+  FilePath path(FILE_PATH_LITERAL("/"));
+  bool path_valid = true;
+  for (size_t i = 0; i < watches_.size(); ++i) {
+    WatchEntry& watch_entry = watches_[i];
+    InotifyReader::Watch old_watch = watch_entry.watch;
+    watch_entry.watch = InotifyReader::kInvalidWatch;
+    watch_entry.linkname.clear();
+    if (path_valid) {
+      watch_entry.watch = g_inotify_reader.Get().AddWatch(path, this);
+      if (watch_entry.watch == InotifyReader::kInvalidWatch) {
+        if (IsLink(path)) {
+          path_valid = AddWatchForBrokenSymlink(path, &watch_entry);
+        } else {
+          path_valid = false;
+        }
+      }
+    }
+    if (old_watch != watch_entry.watch)
+      g_inotify_reader.Get().RemoveWatch(old_watch, this);
+    path = path.Append(watch_entry.subdir);
+  }
+
+  UpdateRecursiveWatches(InotifyReader::kInvalidWatch,
+                         false /* is directory? */);
+}
+
+void FilePathWatcherImpl::UpdateRecursiveWatches(
+    InotifyReader::Watch fired_watch,
+    bool is_dir) {
+  if (!recursive_)
+    return;
+
+  if (!DirectoryExists(target_)) {
+    RemoveRecursiveWatches();
+    return;
+  }
+
+  // Check to see if this is a forced update or if some component of |target_|
+  // has changed. For these cases, redo the watches for |target_| and below.
+  if (!ContainsKey(recursive_paths_by_watch_, fired_watch)) {
+    UpdateRecursiveWatchesForPath(target_);
+    return;
+  }
+
+  // Underneath |target_|, only directory changes trigger watch updates.
+  if (!is_dir)
+    return;
+
+  const FilePath& changed_dir = recursive_paths_by_watch_[fired_watch];
+
+  std::map<FilePath, InotifyReader::Watch>::iterator start_it =
+      recursive_watches_by_path_.lower_bound(changed_dir);
+  std::map<FilePath, InotifyReader::Watch>::iterator end_it = start_it;
+  for (; end_it != recursive_watches_by_path_.end(); ++end_it) {
+    const FilePath& cur_path = end_it->first;
+    if (!changed_dir.IsParent(cur_path))
+      break;
+    if (!DirectoryExists(cur_path))
+      g_inotify_reader.Get().RemoveWatch(end_it->second, this);
+  }
+  recursive_watches_by_path_.erase(start_it, end_it);
+  UpdateRecursiveWatchesForPath(changed_dir);
+}
+
+void FilePathWatcherImpl::UpdateRecursiveWatchesForPath(const FilePath& path) {
+  DCHECK(recursive_);
+  DCHECK(!path.empty());
+  DCHECK(DirectoryExists(path));
+
+  // Note: SHOW_SYM_LINKS exposes symlinks as symlinks, so they are ignored
+  // rather than followed. Following symlinks can easily lead to the undesirable
+  // situation where the entire file system is being watched.
+  FileEnumerator enumerator(
+      path,
+      true /* recursive enumeration */,
+      FileEnumerator::DIRECTORIES | FileEnumerator::SHOW_SYM_LINKS);
+  for (FilePath current = enumerator.Next();
+       !current.empty();
+       current = enumerator.Next()) {
+    DCHECK(enumerator.GetInfo().IsDirectory());
+
+    if (!ContainsKey(recursive_watches_by_path_, current)) {
+      // Add new watches.
+      InotifyReader::Watch watch =
+          g_inotify_reader.Get().AddWatch(current, this);
+      TrackWatchForRecursion(watch, current);
+    } else {
+      // Update existing watches.
+      InotifyReader::Watch old_watch = recursive_watches_by_path_[current];
+      DCHECK_NE(InotifyReader::kInvalidWatch, old_watch);
+      InotifyReader::Watch watch =
+          g_inotify_reader.Get().AddWatch(current, this);
+      if (watch != old_watch) {
+        g_inotify_reader.Get().RemoveWatch(old_watch, this);
+        recursive_paths_by_watch_.erase(old_watch);
+        recursive_watches_by_path_.erase(current);
+        TrackWatchForRecursion(watch, current);
+      }
+    }
+  }
+}
+
+void FilePathWatcherImpl::TrackWatchForRecursion(InotifyReader::Watch watch,
+                                                 const FilePath& path) {
+  DCHECK(recursive_);
+  DCHECK(!path.empty());
+  DCHECK(target_.IsParent(path));
+
+  if (watch == InotifyReader::kInvalidWatch)
+    return;
+
+  DCHECK(!ContainsKey(recursive_paths_by_watch_, watch));
+  DCHECK(!ContainsKey(recursive_watches_by_path_, path));
+  recursive_paths_by_watch_[watch] = path;
+  recursive_watches_by_path_[path] = watch;
+}
+
+void FilePathWatcherImpl::RemoveRecursiveWatches() {
+  if (!recursive_)
+    return;
+
+  for (hash_map<InotifyReader::Watch, FilePath>::const_iterator it =
+           recursive_paths_by_watch_.begin();
+       it != recursive_paths_by_watch_.end();
+       ++it) {
+    g_inotify_reader.Get().RemoveWatch(it->first, this);
+  }
+  recursive_paths_by_watch_.clear();
+  recursive_watches_by_path_.clear();
+}
+
+bool FilePathWatcherImpl::AddWatchForBrokenSymlink(const FilePath& path,
+                                                   WatchEntry* watch_entry) {
+  DCHECK_EQ(InotifyReader::kInvalidWatch, watch_entry->watch);
+  FilePath link;
+  if (!ReadSymbolicLink(path, &link))
+    return false;
+
+  if (!link.IsAbsolute())
+    link = path.DirName().Append(link);
+
+  // Try watching symlink target directory. If the link target is "/", then we
+  // shouldn't get here in normal situations and if we do, we'd watch "/" for
+  // changes to a component "/" which is harmless so no special treatment of
+  // this case is required.
+  InotifyReader::Watch watch =
+      g_inotify_reader.Get().AddWatch(link.DirName(), this);
+  if (watch == InotifyReader::kInvalidWatch) {
+    // TODO(craig) Symlinks only work if the parent directory for the target
+    // exist. Ideally we should make sure we've watched all the components of
+    // the symlink path for changes. See crbug.com/91561 for details.
+    DPLOG(WARNING) << "Watch failed for "  << link.DirName().value();
+    return false;
+  }
+  watch_entry->watch = watch;
+  watch_entry->linkname = link.BaseName().value();
+  return true;
+}
+
+bool FilePathWatcherImpl::HasValidWatchVector() const {
+  if (watches_.empty())
+    return false;
+  for (size_t i = 0; i < watches_.size() - 1; ++i) {
+    if (watches_[i].subdir.empty())
+      return false;
+  }
+  return watches_[watches_.size() - 1].subdir.empty();
+}
+
+}  // namespace
+
+FilePathWatcher::FilePathWatcher() {
+  impl_ = new FilePathWatcherImpl();
+}
+
+}  // namespace base
diff --git a/base/files/file_path_watcher_mac.cc b/base/files/file_path_watcher_mac.cc
new file mode 100644
index 0000000..6f55ba4
--- /dev/null
+++ b/base/files/file_path_watcher_mac.cc
@@ -0,0 +1,60 @@
+// 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.
+
+#include "base/files/file_path_watcher.h"
+#include "base/files/file_path_watcher_kqueue.h"
+
+#if !defined(OS_IOS)
+#include "base/files/file_path_watcher_fsevents.h"
+#endif
+
+namespace base {
+
+namespace {
+
+class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate {
+ public:
+  bool Watch(const FilePath& path,
+             bool recursive,
+             const FilePathWatcher::Callback& callback) override {
+    // Use kqueue for non-recursive watches and FSEvents for recursive ones.
+    DCHECK(!impl_.get());
+    if (recursive) {
+      if (!FilePathWatcher::RecursiveWatchAvailable())
+        return false;
+#if !defined(OS_IOS)
+      impl_ = new FilePathWatcherFSEvents();
+#endif  // OS_IOS
+    } else {
+      impl_ = new FilePathWatcherKQueue();
+    }
+    DCHECK(impl_.get());
+    return impl_->Watch(path, recursive, callback);
+  }
+
+  void Cancel() override {
+    if (impl_.get())
+      impl_->Cancel();
+    set_cancelled();
+  }
+
+  void CancelOnMessageLoopThread() override {
+    if (impl_.get())
+      impl_->Cancel();
+    set_cancelled();
+  }
+
+ protected:
+  ~FilePathWatcherImpl() override {}
+
+  scoped_refptr<PlatformDelegate> impl_;
+};
+
+}  // namespace
+
+FilePathWatcher::FilePathWatcher() {
+  impl_ = new FilePathWatcherImpl();
+}
+
+}  // namespace base
diff --git a/base/files/file_path_watcher_stub.cc b/base/files/file_path_watcher_stub.cc
new file mode 100644
index 0000000..8138692
--- /dev/null
+++ b/base/files/file_path_watcher_stub.cc
@@ -0,0 +1,36 @@
+// Copyright (c) 2012 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 exists for Unix systems which don't have the inotify headers, and
+// thus cannot build file_watcher_inotify.cc
+
+#include "base/files/file_path_watcher.h"
+
+namespace base {
+
+namespace {
+
+class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate {
+ public:
+  bool Watch(const FilePath& path,
+             bool recursive,
+             const FilePathWatcher::Callback& callback) override {
+    return false;
+  }
+
+  void Cancel() override {}
+
+  void CancelOnMessageLoopThread() override {}
+
+ protected:
+  ~FilePathWatcherImpl() override {}
+};
+
+}  // namespace
+
+FilePathWatcher::FilePathWatcher() {
+  impl_ = new FilePathWatcherImpl();
+}
+
+}  // namespace base
diff --git a/base/files/file_path_watcher_unittest.cc b/base/files/file_path_watcher_unittest.cc
new file mode 100644
index 0000000..21e9dd1
--- /dev/null
+++ b/base/files/file_path_watcher_unittest.cc
@@ -0,0 +1,908 @@
+// Copyright (c) 2012 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/files/file_path_watcher.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#include <aclapi.h>
+#elif defined(OS_POSIX)
+#include <sys/stat.h>
+#endif
+
+#include <set>
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/compiler_specific.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/location.h"
+#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/stl_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/test/test_file_util.h"
+#include "base/test/test_timeouts.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_ANDROID)
+#include "base/android/path_utils.h"
+#endif  // defined(OS_ANDROID)
+
+namespace base {
+
+namespace {
+
+class TestDelegate;
+
+// Aggregates notifications from the test delegates and breaks the message loop
+// the test thread is waiting on once they all came in.
+class NotificationCollector
+    : public base::RefCountedThreadSafe<NotificationCollector> {
+ public:
+  NotificationCollector() : task_runner_(base::ThreadTaskRunnerHandle::Get()) {}
+
+  // Called from the file thread by the delegates.
+  void OnChange(TestDelegate* delegate) {
+    task_runner_->PostTask(
+        FROM_HERE, base::Bind(&NotificationCollector::RecordChange, this,
+                              base::Unretained(delegate)));
+  }
+
+  void Register(TestDelegate* delegate) {
+    delegates_.insert(delegate);
+  }
+
+  void Reset() {
+    signaled_.clear();
+  }
+
+  bool Success() {
+    return signaled_ == delegates_;
+  }
+
+ private:
+  friend class base::RefCountedThreadSafe<NotificationCollector>;
+  ~NotificationCollector() {}
+
+  void RecordChange(TestDelegate* delegate) {
+    // Warning: |delegate| is Unretained. Do not dereference.
+    ASSERT_TRUE(task_runner_->BelongsToCurrentThread());
+    ASSERT_TRUE(delegates_.count(delegate));
+    signaled_.insert(delegate);
+
+    // Check whether all delegates have been signaled.
+    if (signaled_ == delegates_)
+      task_runner_->PostTask(FROM_HERE, MessageLoop::QuitWhenIdleClosure());
+  }
+
+  // Set of registered delegates.
+  std::set<TestDelegate*> delegates_;
+
+  // Set of signaled delegates.
+  std::set<TestDelegate*> signaled_;
+
+  // The loop we should break after all delegates signaled.
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+};
+
+class TestDelegateBase : public SupportsWeakPtr<TestDelegateBase> {
+ public:
+  TestDelegateBase() {}
+  virtual ~TestDelegateBase() {}
+
+  virtual void OnFileChanged(const FilePath& path, bool error) = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestDelegateBase);
+};
+
+// A mock class for testing. Gmock is not appropriate because it is not
+// thread-safe for setting expectations. Thus the test code cannot safely
+// reset expectations while the file watcher is running.
+// Instead, TestDelegate gets the notifications from FilePathWatcher and uses
+// NotificationCollector to aggregate the results.
+class TestDelegate : public TestDelegateBase {
+ public:
+  explicit TestDelegate(NotificationCollector* collector)
+      : collector_(collector) {
+    collector_->Register(this);
+  }
+  ~TestDelegate() override {}
+
+  void OnFileChanged(const FilePath& path, bool error) override {
+    if (error)
+      ADD_FAILURE() << "Error " << path.value();
+    else
+      collector_->OnChange(this);
+  }
+
+ private:
+  scoped_refptr<NotificationCollector> collector_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestDelegate);
+};
+
+void SetupWatchCallback(const FilePath& target,
+                        FilePathWatcher* watcher,
+                        TestDelegateBase* delegate,
+                        bool recursive_watch,
+                        bool* result,
+                        base::WaitableEvent* completion) {
+  *result = watcher->Watch(target, recursive_watch,
+                           base::Bind(&TestDelegateBase::OnFileChanged,
+                                      delegate->AsWeakPtr()));
+  completion->Signal();
+}
+
+class FilePathWatcherTest : public testing::Test {
+ public:
+  FilePathWatcherTest()
+      : file_thread_("FilePathWatcherTest") {}
+
+  ~FilePathWatcherTest() override {}
+
+ protected:
+  void SetUp() override {
+    // Create a separate file thread in order to test proper thread usage.
+    base::Thread::Options options(MessageLoop::TYPE_IO, 0);
+    ASSERT_TRUE(file_thread_.StartWithOptions(options));
+#if defined(OS_ANDROID)
+    // Watching files is only permitted when all parent directories are
+    // accessible, which is not the case for the default temp directory
+    // on Android which is under /data/data.  Use /sdcard instead.
+    // TODO(pauljensen): Remove this when crbug.com/475568 is fixed.
+    FilePath parent_dir;
+    ASSERT_TRUE(android::GetExternalStorageDirectory(&parent_dir));
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDirUnderPath(parent_dir));
+#else   // defined(OS_ANDROID)
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+#endif  // defined(OS_ANDROID)
+    collector_ = new NotificationCollector();
+  }
+
+  void TearDown() override { RunLoop().RunUntilIdle(); }
+
+  void DeleteDelegateOnFileThread(TestDelegate* delegate) {
+    file_thread_.task_runner()->DeleteSoon(FROM_HERE, delegate);
+  }
+
+  FilePath test_file() {
+    return temp_dir_.path().AppendASCII("FilePathWatcherTest");
+  }
+
+  FilePath test_link() {
+    return temp_dir_.path().AppendASCII("FilePathWatcherTest.lnk");
+  }
+
+  // Write |content| to |file|. Returns true on success.
+  bool WriteFile(const FilePath& file, const std::string& content) {
+    int write_size = ::base::WriteFile(file, content.c_str(), content.length());
+    return write_size == static_cast<int>(content.length());
+  }
+
+  bool SetupWatch(const FilePath& target,
+                  FilePathWatcher* watcher,
+                  TestDelegateBase* delegate,
+                  bool recursive_watch) WARN_UNUSED_RESULT;
+
+  bool WaitForEvents() WARN_UNUSED_RESULT {
+    collector_->Reset();
+    loop_.Run();
+    return collector_->Success();
+  }
+
+  NotificationCollector* collector() { return collector_.get(); }
+
+  MessageLoop loop_;
+  base::Thread file_thread_;
+  ScopedTempDir temp_dir_;
+  scoped_refptr<NotificationCollector> collector_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(FilePathWatcherTest);
+};
+
+bool FilePathWatcherTest::SetupWatch(const FilePath& target,
+                                     FilePathWatcher* watcher,
+                                     TestDelegateBase* delegate,
+                                     bool recursive_watch) {
+  base::WaitableEvent completion(false, false);
+  bool result;
+  file_thread_.task_runner()->PostTask(
+      FROM_HERE, base::Bind(SetupWatchCallback, target, watcher, delegate,
+                            recursive_watch, &result, &completion));
+  completion.Wait();
+  return result;
+}
+
+// Basic test: Create the file and verify that we notice.
+TEST_F(FilePathWatcherTest, NewFile) {
+  FilePathWatcher watcher;
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get(), false));
+
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+// Verify that modifying the file is caught.
+TEST_F(FilePathWatcherTest, ModifiedFile) {
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+
+  FilePathWatcher watcher;
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get(), false));
+
+  // Now make sure we get notified if the file is modified.
+  ASSERT_TRUE(WriteFile(test_file(), "new content"));
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+// Verify that moving the file into place is caught.
+TEST_F(FilePathWatcherTest, MovedFile) {
+  FilePath source_file(temp_dir_.path().AppendASCII("source"));
+  ASSERT_TRUE(WriteFile(source_file, "content"));
+
+  FilePathWatcher watcher;
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get(), false));
+
+  // Now make sure we get notified if the file is modified.
+  ASSERT_TRUE(base::Move(source_file, test_file()));
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+TEST_F(FilePathWatcherTest, DeletedFile) {
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+
+  FilePathWatcher watcher;
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get(), false));
+
+  // Now make sure we get notified if the file is deleted.
+  base::DeleteFile(test_file(), false);
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+// Used by the DeleteDuringNotify test below.
+// Deletes the FilePathWatcher when it's notified.
+class Deleter : public TestDelegateBase {
+ public:
+  Deleter(FilePathWatcher* watcher, MessageLoop* loop)
+      : watcher_(watcher),
+        loop_(loop) {
+  }
+  ~Deleter() override {}
+
+  void OnFileChanged(const FilePath&, bool) override {
+    watcher_.reset();
+    loop_->task_runner()->PostTask(FROM_HERE,
+                                   MessageLoop::QuitWhenIdleClosure());
+  }
+
+  FilePathWatcher* watcher() const { return watcher_.get(); }
+
+ private:
+  scoped_ptr<FilePathWatcher> watcher_;
+  MessageLoop* loop_;
+
+  DISALLOW_COPY_AND_ASSIGN(Deleter);
+};
+
+// Verify that deleting a watcher during the callback doesn't crash.
+TEST_F(FilePathWatcherTest, DeleteDuringNotify) {
+  FilePathWatcher* watcher = new FilePathWatcher;
+  // Takes ownership of watcher.
+  scoped_ptr<Deleter> deleter(new Deleter(watcher, &loop_));
+  ASSERT_TRUE(SetupWatch(test_file(), watcher, deleter.get(), false));
+
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+  ASSERT_TRUE(WaitForEvents());
+
+  // We win if we haven't crashed yet.
+  // Might as well double-check it got deleted, too.
+  ASSERT_TRUE(deleter->watcher() == NULL);
+}
+
+// Verify that deleting the watcher works even if there is a pending
+// notification.
+// Flaky on MacOS (and ARM linux): http://crbug.com/85930
+TEST_F(FilePathWatcherTest, DISABLED_DestroyWithPendingNotification) {
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  FilePathWatcher* watcher = new FilePathWatcher;
+  ASSERT_TRUE(SetupWatch(test_file(), watcher, delegate.get(), false));
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+  file_thread_.task_runner()->DeleteSoon(FROM_HERE, watcher);
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+TEST_F(FilePathWatcherTest, MultipleWatchersSingleFile) {
+  FilePathWatcher watcher1, watcher2;
+  scoped_ptr<TestDelegate> delegate1(new TestDelegate(collector()));
+  scoped_ptr<TestDelegate> delegate2(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(test_file(), &watcher1, delegate1.get(), false));
+  ASSERT_TRUE(SetupWatch(test_file(), &watcher2, delegate2.get(), false));
+
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate1.release());
+  DeleteDelegateOnFileThread(delegate2.release());
+}
+
+// Verify that watching a file whose parent directory doesn't exist yet works if
+// the directory and file are created eventually.
+TEST_F(FilePathWatcherTest, NonExistentDirectory) {
+  FilePathWatcher watcher;
+  FilePath dir(temp_dir_.path().AppendASCII("dir"));
+  FilePath file(dir.AppendASCII("file"));
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(file, &watcher, delegate.get(), false));
+
+  ASSERT_TRUE(base::CreateDirectory(dir));
+
+  ASSERT_TRUE(WriteFile(file, "content"));
+
+  VLOG(1) << "Waiting for file creation";
+  ASSERT_TRUE(WaitForEvents());
+
+  ASSERT_TRUE(WriteFile(file, "content v2"));
+  VLOG(1) << "Waiting for file change";
+  ASSERT_TRUE(WaitForEvents());
+
+  ASSERT_TRUE(base::DeleteFile(file, false));
+  VLOG(1) << "Waiting for file deletion";
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+// Exercises watch reconfiguration for the case that directories on the path
+// are rapidly created.
+TEST_F(FilePathWatcherTest, DirectoryChain) {
+  FilePath path(temp_dir_.path());
+  std::vector<std::string> dir_names;
+  for (int i = 0; i < 20; i++) {
+    std::string dir(base::StringPrintf("d%d", i));
+    dir_names.push_back(dir);
+    path = path.AppendASCII(dir);
+  }
+
+  FilePathWatcher watcher;
+  FilePath file(path.AppendASCII("file"));
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(file, &watcher, delegate.get(), false));
+
+  FilePath sub_path(temp_dir_.path());
+  for (std::vector<std::string>::const_iterator d(dir_names.begin());
+       d != dir_names.end(); ++d) {
+    sub_path = sub_path.AppendASCII(*d);
+    ASSERT_TRUE(base::CreateDirectory(sub_path));
+  }
+  VLOG(1) << "Create File";
+  ASSERT_TRUE(WriteFile(file, "content"));
+  VLOG(1) << "Waiting for file creation";
+  ASSERT_TRUE(WaitForEvents());
+
+  ASSERT_TRUE(WriteFile(file, "content v2"));
+  VLOG(1) << "Waiting for file modification";
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+#if defined(OS_MACOSX)
+// http://crbug.com/85930
+#define DisappearingDirectory DISABLED_DisappearingDirectory
+#endif
+TEST_F(FilePathWatcherTest, DisappearingDirectory) {
+  FilePathWatcher watcher;
+  FilePath dir(temp_dir_.path().AppendASCII("dir"));
+  FilePath file(dir.AppendASCII("file"));
+  ASSERT_TRUE(base::CreateDirectory(dir));
+  ASSERT_TRUE(WriteFile(file, "content"));
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(file, &watcher, delegate.get(), false));
+
+  ASSERT_TRUE(base::DeleteFile(dir, true));
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+// Tests that a file that is deleted and reappears is tracked correctly.
+TEST_F(FilePathWatcherTest, DeleteAndRecreate) {
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+  FilePathWatcher watcher;
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get(), false));
+
+  ASSERT_TRUE(base::DeleteFile(test_file(), false));
+  VLOG(1) << "Waiting for file deletion";
+  ASSERT_TRUE(WaitForEvents());
+
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+  VLOG(1) << "Waiting for file creation";
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+TEST_F(FilePathWatcherTest, WatchDirectory) {
+  FilePathWatcher watcher;
+  FilePath dir(temp_dir_.path().AppendASCII("dir"));
+  FilePath file1(dir.AppendASCII("file1"));
+  FilePath file2(dir.AppendASCII("file2"));
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(dir, &watcher, delegate.get(), false));
+
+  ASSERT_TRUE(base::CreateDirectory(dir));
+  VLOG(1) << "Waiting for directory creation";
+  ASSERT_TRUE(WaitForEvents());
+
+  ASSERT_TRUE(WriteFile(file1, "content"));
+  VLOG(1) << "Waiting for file1 creation";
+  ASSERT_TRUE(WaitForEvents());
+
+#if !defined(OS_MACOSX)
+  // Mac implementation does not detect files modified in a directory.
+  ASSERT_TRUE(WriteFile(file1, "content v2"));
+  VLOG(1) << "Waiting for file1 modification";
+  ASSERT_TRUE(WaitForEvents());
+#endif  // !OS_MACOSX
+
+  ASSERT_TRUE(base::DeleteFile(file1, false));
+  VLOG(1) << "Waiting for file1 deletion";
+  ASSERT_TRUE(WaitForEvents());
+
+  ASSERT_TRUE(WriteFile(file2, "content"));
+  VLOG(1) << "Waiting for file2 creation";
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+TEST_F(FilePathWatcherTest, MoveParent) {
+  FilePathWatcher file_watcher;
+  FilePathWatcher subdir_watcher;
+  FilePath dir(temp_dir_.path().AppendASCII("dir"));
+  FilePath dest(temp_dir_.path().AppendASCII("dest"));
+  FilePath subdir(dir.AppendASCII("subdir"));
+  FilePath file(subdir.AppendASCII("file"));
+  scoped_ptr<TestDelegate> file_delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(file, &file_watcher, file_delegate.get(), false));
+  scoped_ptr<TestDelegate> subdir_delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(subdir, &subdir_watcher, subdir_delegate.get(),
+                         false));
+
+  // Setup a directory hierarchy.
+  ASSERT_TRUE(base::CreateDirectory(subdir));
+  ASSERT_TRUE(WriteFile(file, "content"));
+  VLOG(1) << "Waiting for file creation";
+  ASSERT_TRUE(WaitForEvents());
+
+  // Move the parent directory.
+  base::Move(dir, dest);
+  VLOG(1) << "Waiting for directory move";
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(file_delegate.release());
+  DeleteDelegateOnFileThread(subdir_delegate.release());
+}
+
+TEST_F(FilePathWatcherTest, RecursiveWatch) {
+  FilePathWatcher watcher;
+  FilePath dir(temp_dir_.path().AppendASCII("dir"));
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  bool setup_result = SetupWatch(dir, &watcher, delegate.get(), true);
+  if (!FilePathWatcher::RecursiveWatchAvailable()) {
+    ASSERT_FALSE(setup_result);
+    DeleteDelegateOnFileThread(delegate.release());
+    return;
+  }
+  ASSERT_TRUE(setup_result);
+
+  // Main directory("dir") creation.
+  ASSERT_TRUE(base::CreateDirectory(dir));
+  ASSERT_TRUE(WaitForEvents());
+
+  // Create "$dir/file1".
+  FilePath file1(dir.AppendASCII("file1"));
+  ASSERT_TRUE(WriteFile(file1, "content"));
+  ASSERT_TRUE(WaitForEvents());
+
+  // Create "$dir/subdir".
+  FilePath subdir(dir.AppendASCII("subdir"));
+  ASSERT_TRUE(base::CreateDirectory(subdir));
+  ASSERT_TRUE(WaitForEvents());
+
+  // Create "$dir/subdir/subdir_file1".
+  FilePath subdir_file1(subdir.AppendASCII("subdir_file1"));
+  ASSERT_TRUE(WriteFile(subdir_file1, "content"));
+  ASSERT_TRUE(WaitForEvents());
+
+  // Create "$dir/subdir/subdir_child_dir".
+  FilePath subdir_child_dir(subdir.AppendASCII("subdir_child_dir"));
+  ASSERT_TRUE(base::CreateDirectory(subdir_child_dir));
+  ASSERT_TRUE(WaitForEvents());
+
+  // Create "$dir/subdir/subdir_child_dir/child_dir_file1".
+  FilePath child_dir_file1(subdir_child_dir.AppendASCII("child_dir_file1"));
+  ASSERT_TRUE(WriteFile(child_dir_file1, "content v2"));
+  ASSERT_TRUE(WaitForEvents());
+
+  // Write into "$dir/subdir/subdir_child_dir/child_dir_file1".
+  ASSERT_TRUE(WriteFile(child_dir_file1, "content"));
+  ASSERT_TRUE(WaitForEvents());
+
+// Apps cannot change file attributes on Android in /sdcard as /sdcard uses the
+// "fuse" file system, while /data uses "ext4".  Running these tests in /data
+// would be preferable and allow testing file attributes and symlinks.
+// TODO(pauljensen): Re-enable when crbug.com/475568 is fixed and SetUp() places
+// the |temp_dir_| in /data.
+#if !defined(OS_ANDROID)
+  // Modify "$dir/subdir/subdir_child_dir/child_dir_file1" attributes.
+  ASSERT_TRUE(base::MakeFileUnreadable(child_dir_file1));
+  ASSERT_TRUE(WaitForEvents());
+#endif
+
+  // Delete "$dir/subdir/subdir_file1".
+  ASSERT_TRUE(base::DeleteFile(subdir_file1, false));
+  ASSERT_TRUE(WaitForEvents());
+
+  // Delete "$dir/subdir/subdir_child_dir/child_dir_file1".
+  ASSERT_TRUE(base::DeleteFile(child_dir_file1, false));
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+#if defined(OS_POSIX)
+#if defined(OS_ANDROID)
+// Apps cannot create symlinks on Android in /sdcard as /sdcard uses the
+// "fuse" file system, while /data uses "ext4".  Running these tests in /data
+// would be preferable and allow testing file attributes and symlinks.
+// TODO(pauljensen): Re-enable when crbug.com/475568 is fixed and SetUp() places
+// the |temp_dir_| in /data.
+#define RecursiveWithSymLink DISABLED_RecursiveWithSymLink
+#endif  // defined(OS_ANDROID)
+TEST_F(FilePathWatcherTest, RecursiveWithSymLink) {
+  if (!FilePathWatcher::RecursiveWatchAvailable())
+    return;
+
+  FilePathWatcher watcher;
+  FilePath test_dir(temp_dir_.path().AppendASCII("test_dir"));
+  ASSERT_TRUE(base::CreateDirectory(test_dir));
+  FilePath symlink(test_dir.AppendASCII("symlink"));
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(symlink, &watcher, delegate.get(), true));
+
+  // Link creation.
+  FilePath target1(temp_dir_.path().AppendASCII("target1"));
+  ASSERT_TRUE(base::CreateSymbolicLink(target1, symlink));
+  ASSERT_TRUE(WaitForEvents());
+
+  // Target1 creation.
+  ASSERT_TRUE(base::CreateDirectory(target1));
+  ASSERT_TRUE(WaitForEvents());
+
+  // Create a file in target1.
+  FilePath target1_file(target1.AppendASCII("file"));
+  ASSERT_TRUE(WriteFile(target1_file, "content"));
+  ASSERT_TRUE(WaitForEvents());
+
+  // Link change.
+  FilePath target2(temp_dir_.path().AppendASCII("target2"));
+  ASSERT_TRUE(base::CreateDirectory(target2));
+  ASSERT_TRUE(base::DeleteFile(symlink, false));
+  ASSERT_TRUE(base::CreateSymbolicLink(target2, symlink));
+  ASSERT_TRUE(WaitForEvents());
+
+  // Create a file in target2.
+  FilePath target2_file(target2.AppendASCII("file"));
+  ASSERT_TRUE(WriteFile(target2_file, "content"));
+  ASSERT_TRUE(WaitForEvents());
+
+  DeleteDelegateOnFileThread(delegate.release());
+}
+#endif  // OS_POSIX
+
+TEST_F(FilePathWatcherTest, MoveChild) {
+  FilePathWatcher file_watcher;
+  FilePathWatcher subdir_watcher;
+  FilePath source_dir(temp_dir_.path().AppendASCII("source"));
+  FilePath source_subdir(source_dir.AppendASCII("subdir"));
+  FilePath source_file(source_subdir.AppendASCII("file"));
+  FilePath dest_dir(temp_dir_.path().AppendASCII("dest"));
+  FilePath dest_subdir(dest_dir.AppendASCII("subdir"));
+  FilePath dest_file(dest_subdir.AppendASCII("file"));
+
+  // Setup a directory hierarchy.
+  ASSERT_TRUE(base::CreateDirectory(source_subdir));
+  ASSERT_TRUE(WriteFile(source_file, "content"));
+
+  scoped_ptr<TestDelegate> file_delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(dest_file, &file_watcher, file_delegate.get(), false));
+  scoped_ptr<TestDelegate> subdir_delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(dest_subdir, &subdir_watcher, subdir_delegate.get(),
+                         false));
+
+  // Move the directory into place, s.t. the watched file appears.
+  ASSERT_TRUE(base::Move(source_dir, dest_dir));
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(file_delegate.release());
+  DeleteDelegateOnFileThread(subdir_delegate.release());
+}
+
+// Verify that changing attributes on a file is caught
+#if defined(OS_ANDROID)
+// Apps cannot change file attributes on Android in /sdcard as /sdcard uses the
+// "fuse" file system, while /data uses "ext4".  Running these tests in /data
+// would be preferable and allow testing file attributes and symlinks.
+// TODO(pauljensen): Re-enable when crbug.com/475568 is fixed and SetUp() places
+// the |temp_dir_| in /data.
+#define FileAttributesChanged DISABLED_FileAttributesChanged
+#endif  // defined(OS_ANDROID
+TEST_F(FilePathWatcherTest, FileAttributesChanged) {
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+  FilePathWatcher watcher;
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(test_file(), &watcher, delegate.get(), false));
+
+  // Now make sure we get notified if the file is modified.
+  ASSERT_TRUE(base::MakeFileUnreadable(test_file()));
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+#if defined(OS_LINUX)
+
+// Verify that creating a symlink is caught.
+TEST_F(FilePathWatcherTest, CreateLink) {
+  FilePathWatcher watcher;
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  // Note that we are watching the symlink
+  ASSERT_TRUE(SetupWatch(test_link(), &watcher, delegate.get(), false));
+
+  // Now make sure we get notified if the link is created.
+  // Note that test_file() doesn't have to exist.
+  ASSERT_TRUE(CreateSymbolicLink(test_file(), test_link()));
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+// Verify that deleting a symlink is caught.
+TEST_F(FilePathWatcherTest, DeleteLink) {
+  // Unfortunately this test case only works if the link target exists.
+  // TODO(craig) fix this as part of crbug.com/91561.
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+  ASSERT_TRUE(CreateSymbolicLink(test_file(), test_link()));
+  FilePathWatcher watcher;
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(test_link(), &watcher, delegate.get(), false));
+
+  // Now make sure we get notified if the link is deleted.
+  ASSERT_TRUE(base::DeleteFile(test_link(), false));
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+// Verify that modifying a target file that a link is pointing to
+// when we are watching the link is caught.
+TEST_F(FilePathWatcherTest, ModifiedLinkedFile) {
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+  ASSERT_TRUE(CreateSymbolicLink(test_file(), test_link()));
+  FilePathWatcher watcher;
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  // Note that we are watching the symlink.
+  ASSERT_TRUE(SetupWatch(test_link(), &watcher, delegate.get(), false));
+
+  // Now make sure we get notified if the file is modified.
+  ASSERT_TRUE(WriteFile(test_file(), "new content"));
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+// Verify that creating a target file that a link is pointing to
+// when we are watching the link is caught.
+TEST_F(FilePathWatcherTest, CreateTargetLinkedFile) {
+  ASSERT_TRUE(CreateSymbolicLink(test_file(), test_link()));
+  FilePathWatcher watcher;
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  // Note that we are watching the symlink.
+  ASSERT_TRUE(SetupWatch(test_link(), &watcher, delegate.get(), false));
+
+  // Now make sure we get notified if the target file is created.
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+// Verify that deleting a target file that a link is pointing to
+// when we are watching the link is caught.
+TEST_F(FilePathWatcherTest, DeleteTargetLinkedFile) {
+  ASSERT_TRUE(WriteFile(test_file(), "content"));
+  ASSERT_TRUE(CreateSymbolicLink(test_file(), test_link()));
+  FilePathWatcher watcher;
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  // Note that we are watching the symlink.
+  ASSERT_TRUE(SetupWatch(test_link(), &watcher, delegate.get(), false));
+
+  // Now make sure we get notified if the target file is deleted.
+  ASSERT_TRUE(base::DeleteFile(test_file(), false));
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+// Verify that watching a file whose parent directory is a link that
+// doesn't exist yet works if the symlink is created eventually.
+TEST_F(FilePathWatcherTest, LinkedDirectoryPart1) {
+  FilePathWatcher watcher;
+  FilePath dir(temp_dir_.path().AppendASCII("dir"));
+  FilePath link_dir(temp_dir_.path().AppendASCII("dir.lnk"));
+  FilePath file(dir.AppendASCII("file"));
+  FilePath linkfile(link_dir.AppendASCII("file"));
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  // dir/file should exist.
+  ASSERT_TRUE(base::CreateDirectory(dir));
+  ASSERT_TRUE(WriteFile(file, "content"));
+  // Note that we are watching dir.lnk/file which doesn't exist yet.
+  ASSERT_TRUE(SetupWatch(linkfile, &watcher, delegate.get(), false));
+
+  ASSERT_TRUE(CreateSymbolicLink(dir, link_dir));
+  VLOG(1) << "Waiting for link creation";
+  ASSERT_TRUE(WaitForEvents());
+
+  ASSERT_TRUE(WriteFile(file, "content v2"));
+  VLOG(1) << "Waiting for file change";
+  ASSERT_TRUE(WaitForEvents());
+
+  ASSERT_TRUE(base::DeleteFile(file, false));
+  VLOG(1) << "Waiting for file deletion";
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+// Verify that watching a file whose parent directory is a
+// dangling symlink works if the directory is created eventually.
+TEST_F(FilePathWatcherTest, LinkedDirectoryPart2) {
+  FilePathWatcher watcher;
+  FilePath dir(temp_dir_.path().AppendASCII("dir"));
+  FilePath link_dir(temp_dir_.path().AppendASCII("dir.lnk"));
+  FilePath file(dir.AppendASCII("file"));
+  FilePath linkfile(link_dir.AppendASCII("file"));
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  // Now create the link from dir.lnk pointing to dir but
+  // neither dir nor dir/file exist yet.
+  ASSERT_TRUE(CreateSymbolicLink(dir, link_dir));
+  // Note that we are watching dir.lnk/file.
+  ASSERT_TRUE(SetupWatch(linkfile, &watcher, delegate.get(), false));
+
+  ASSERT_TRUE(base::CreateDirectory(dir));
+  ASSERT_TRUE(WriteFile(file, "content"));
+  VLOG(1) << "Waiting for dir/file creation";
+  ASSERT_TRUE(WaitForEvents());
+
+  ASSERT_TRUE(WriteFile(file, "content v2"));
+  VLOG(1) << "Waiting for file change";
+  ASSERT_TRUE(WaitForEvents());
+
+  ASSERT_TRUE(base::DeleteFile(file, false));
+  VLOG(1) << "Waiting for file deletion";
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+// Verify that watching a file with a symlink on the path
+// to the file works.
+TEST_F(FilePathWatcherTest, LinkedDirectoryPart3) {
+  FilePathWatcher watcher;
+  FilePath dir(temp_dir_.path().AppendASCII("dir"));
+  FilePath link_dir(temp_dir_.path().AppendASCII("dir.lnk"));
+  FilePath file(dir.AppendASCII("file"));
+  FilePath linkfile(link_dir.AppendASCII("file"));
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(base::CreateDirectory(dir));
+  ASSERT_TRUE(CreateSymbolicLink(dir, link_dir));
+  // Note that we are watching dir.lnk/file but the file doesn't exist yet.
+  ASSERT_TRUE(SetupWatch(linkfile, &watcher, delegate.get(), false));
+
+  ASSERT_TRUE(WriteFile(file, "content"));
+  VLOG(1) << "Waiting for file creation";
+  ASSERT_TRUE(WaitForEvents());
+
+  ASSERT_TRUE(WriteFile(file, "content v2"));
+  VLOG(1) << "Waiting for file change";
+  ASSERT_TRUE(WaitForEvents());
+
+  ASSERT_TRUE(base::DeleteFile(file, false));
+  VLOG(1) << "Waiting for file deletion";
+  ASSERT_TRUE(WaitForEvents());
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+#endif  // OS_LINUX
+
+enum Permission {
+  Read,
+  Write,
+  Execute
+};
+
+#if defined(OS_MACOSX)
+bool ChangeFilePermissions(const FilePath& path, Permission perm, bool allow) {
+  struct stat stat_buf;
+
+  if (stat(path.value().c_str(), &stat_buf) != 0)
+    return false;
+
+  mode_t mode = 0;
+  switch (perm) {
+    case Read:
+      mode = S_IRUSR | S_IRGRP | S_IROTH;
+      break;
+    case Write:
+      mode = S_IWUSR | S_IWGRP | S_IWOTH;
+      break;
+    case Execute:
+      mode = S_IXUSR | S_IXGRP | S_IXOTH;
+      break;
+    default:
+      ADD_FAILURE() << "unknown perm " << perm;
+      return false;
+  }
+  if (allow) {
+    stat_buf.st_mode |= mode;
+  } else {
+    stat_buf.st_mode &= ~mode;
+  }
+  return chmod(path.value().c_str(), stat_buf.st_mode) == 0;
+}
+#endif  // defined(OS_MACOSX)
+
+#if defined(OS_MACOSX)
+// Linux implementation of FilePathWatcher doesn't catch attribute changes.
+// http://crbug.com/78043
+// Windows implementation of FilePathWatcher catches attribute changes that
+// don't affect the path being watched.
+// http://crbug.com/78045
+
+// Verify that changing attributes on a directory works.
+TEST_F(FilePathWatcherTest, DirAttributesChanged) {
+  FilePath test_dir1(temp_dir_.path().AppendASCII("DirAttributesChangedDir1"));
+  FilePath test_dir2(test_dir1.AppendASCII("DirAttributesChangedDir2"));
+  FilePath test_file(test_dir2.AppendASCII("DirAttributesChangedFile"));
+  // Setup a directory hierarchy.
+  ASSERT_TRUE(base::CreateDirectory(test_dir1));
+  ASSERT_TRUE(base::CreateDirectory(test_dir2));
+  ASSERT_TRUE(WriteFile(test_file, "content"));
+
+  FilePathWatcher watcher;
+  scoped_ptr<TestDelegate> delegate(new TestDelegate(collector()));
+  ASSERT_TRUE(SetupWatch(test_file, &watcher, delegate.get(), false));
+
+  // We should not get notified in this case as it hasn't affected our ability
+  // to access the file.
+  ASSERT_TRUE(ChangeFilePermissions(test_dir1, Read, false));
+  loop_.PostDelayedTask(FROM_HERE,
+                        MessageLoop::QuitWhenIdleClosure(),
+                        TestTimeouts::tiny_timeout());
+  ASSERT_FALSE(WaitForEvents());
+  ASSERT_TRUE(ChangeFilePermissions(test_dir1, Read, true));
+
+  // We should get notified in this case because filepathwatcher can no
+  // longer access the file
+  ASSERT_TRUE(ChangeFilePermissions(test_dir1, Execute, false));
+  ASSERT_TRUE(WaitForEvents());
+  ASSERT_TRUE(ChangeFilePermissions(test_dir1, Execute, true));
+  DeleteDelegateOnFileThread(delegate.release());
+}
+
+#endif  // OS_MACOSX
+}  // namespace
+
+}  // namespace base
diff --git a/base/files/file_path_watcher_win.cc b/base/files/file_path_watcher_win.cc
new file mode 100644
index 0000000..081698f
--- /dev/null
+++ b/base/files/file_path_watcher_win.cc
@@ -0,0 +1,300 @@
+// Copyright (c) 2011 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/files/file_path_watcher.h"
+
+#include "base/bind.h"
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "base/win/object_watcher.h"
+
+namespace base {
+
+namespace {
+
+class FilePathWatcherImpl : public FilePathWatcher::PlatformDelegate,
+                            public base::win::ObjectWatcher::Delegate,
+                            public MessageLoop::DestructionObserver {
+ public:
+  FilePathWatcherImpl()
+      : handle_(INVALID_HANDLE_VALUE),
+        recursive_watch_(false) {}
+
+  // FilePathWatcher::PlatformDelegate overrides.
+  bool Watch(const FilePath& path,
+             bool recursive,
+             const FilePathWatcher::Callback& callback) override;
+  void Cancel() override;
+
+  // Deletion of the FilePathWatcher will call Cancel() to dispose of this
+  // object in the right thread. This also observes destruction of the required
+  // cleanup thread, in case it quits before Cancel() is called.
+  void WillDestroyCurrentMessageLoop() override;
+
+  // Callback from MessageLoopForIO.
+  void OnObjectSignaled(HANDLE object) override;
+
+ private:
+  ~FilePathWatcherImpl() override {}
+
+  // Setup a watch handle for directory |dir|. Set |recursive| to true to watch
+  // the directory sub trees. Returns true if no fatal error occurs. |handle|
+  // will receive the handle value if |dir| is watchable, otherwise
+  // INVALID_HANDLE_VALUE.
+  static bool SetupWatchHandle(const FilePath& dir,
+                               bool recursive,
+                               HANDLE* handle) WARN_UNUSED_RESULT;
+
+  // (Re-)Initialize the watch handle.
+  bool UpdateWatch() WARN_UNUSED_RESULT;
+
+  // Destroy the watch handle.
+  void DestroyWatch();
+
+  // Cleans up and stops observing the |task_runner_| thread.
+  void CancelOnMessageLoopThread() override;
+
+  // Callback to notify upon changes.
+  FilePathWatcher::Callback callback_;
+
+  // Path we're supposed to watch (passed to callback).
+  FilePath target_;
+
+  // Handle for FindFirstChangeNotification.
+  HANDLE handle_;
+
+  // ObjectWatcher to watch handle_ for events.
+  base::win::ObjectWatcher watcher_;
+
+  // Set to true to watch the sub trees of the specified directory file path.
+  bool recursive_watch_;
+
+  // Keep track of the last modified time of the file.  We use nulltime
+  // to represent the file not existing.
+  Time last_modified_;
+
+  // The time at which we processed the first notification with the
+  // |last_modified_| time stamp.
+  Time first_notification_;
+
+  DISALLOW_COPY_AND_ASSIGN(FilePathWatcherImpl);
+};
+
+bool FilePathWatcherImpl::Watch(const FilePath& path,
+                                bool recursive,
+                                const FilePathWatcher::Callback& callback) {
+  DCHECK(target_.value().empty());  // Can only watch one path.
+
+  set_task_runner(ThreadTaskRunnerHandle::Get());
+  callback_ = callback;
+  target_ = path;
+  recursive_watch_ = recursive;
+  MessageLoop::current()->AddDestructionObserver(this);
+
+  File::Info file_info;
+  if (GetFileInfo(target_, &file_info)) {
+    last_modified_ = file_info.last_modified;
+    first_notification_ = Time::Now();
+  }
+
+  if (!UpdateWatch())
+    return false;
+
+  watcher_.StartWatching(handle_, this);
+
+  return true;
+}
+
+void FilePathWatcherImpl::Cancel() {
+  if (callback_.is_null()) {
+    // Watch was never called, or the |task_runner_| has already quit.
+    set_cancelled();
+    return;
+  }
+
+  // Switch to the file thread if necessary so we can stop |watcher_|.
+  if (!task_runner()->BelongsToCurrentThread()) {
+    task_runner()->PostTask(FROM_HERE, Bind(&FilePathWatcher::CancelWatch,
+                                            make_scoped_refptr(this)));
+  } else {
+    CancelOnMessageLoopThread();
+  }
+}
+
+void FilePathWatcherImpl::CancelOnMessageLoopThread() {
+  DCHECK(task_runner()->BelongsToCurrentThread());
+  set_cancelled();
+
+  if (handle_ != INVALID_HANDLE_VALUE)
+    DestroyWatch();
+
+  if (!callback_.is_null()) {
+    MessageLoop::current()->RemoveDestructionObserver(this);
+    callback_.Reset();
+  }
+}
+
+void FilePathWatcherImpl::WillDestroyCurrentMessageLoop() {
+  CancelOnMessageLoopThread();
+}
+
+void FilePathWatcherImpl::OnObjectSignaled(HANDLE object) {
+  DCHECK(object == handle_);
+  // Make sure we stay alive through the body of this function.
+  scoped_refptr<FilePathWatcherImpl> keep_alive(this);
+
+  if (!UpdateWatch()) {
+    callback_.Run(target_, true /* error */);
+    return;
+  }
+
+  // Check whether the event applies to |target_| and notify the callback.
+  File::Info file_info;
+  bool file_exists = GetFileInfo(target_, &file_info);
+  if (recursive_watch_) {
+    // Only the mtime of |target_| is tracked but in a recursive watch,
+    // some other file or directory may have changed so all notifications
+    // are passed through. It is possible to figure out which file changed
+    // using ReadDirectoryChangesW() instead of FindFirstChangeNotification(),
+    // but that function is quite complicated:
+    // http://qualapps.blogspot.com/2010/05/understanding-readdirectorychangesw.html
+    callback_.Run(target_, false);
+  } else if (file_exists && (last_modified_.is_null() ||
+             last_modified_ != file_info.last_modified)) {
+    last_modified_ = file_info.last_modified;
+    first_notification_ = Time::Now();
+    callback_.Run(target_, false);
+  } else if (file_exists && last_modified_ == file_info.last_modified &&
+             !first_notification_.is_null()) {
+    // The target's last modification time is equal to what's on record. This
+    // means that either an unrelated event occurred, or the target changed
+    // again (file modification times only have a resolution of 1s). Comparing
+    // file modification times against the wall clock is not reliable to find
+    // out whether the change is recent, since this code might just run too
+    // late. Moreover, there's no guarantee that file modification time and wall
+    // clock times come from the same source.
+    //
+    // Instead, the time at which the first notification carrying the current
+    // |last_notified_| time stamp is recorded. Later notifications that find
+    // the same file modification time only need to be forwarded until wall
+    // clock has advanced one second from the initial notification. After that
+    // interval, client code is guaranteed to having seen the current revision
+    // of the file.
+    if (Time::Now() - first_notification_ > TimeDelta::FromSeconds(1)) {
+      // Stop further notifications for this |last_modification_| time stamp.
+      first_notification_ = Time();
+    }
+    callback_.Run(target_, false);
+  } else if (!file_exists && !last_modified_.is_null()) {
+    last_modified_ = Time();
+    callback_.Run(target_, false);
+  }
+
+  // The watch may have been cancelled by the callback.
+  if (handle_ != INVALID_HANDLE_VALUE)
+    watcher_.StartWatching(handle_, this);
+}
+
+// static
+bool FilePathWatcherImpl::SetupWatchHandle(const FilePath& dir,
+                                           bool recursive,
+                                           HANDLE* handle) {
+  *handle = FindFirstChangeNotification(
+      dir.value().c_str(),
+      recursive,
+      FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_SIZE |
+      FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_DIR_NAME |
+      FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SECURITY);
+  if (*handle != INVALID_HANDLE_VALUE) {
+    // Make sure the handle we got points to an existing directory. It seems
+    // that windows sometimes hands out watches to directories that are
+    // about to go away, but doesn't sent notifications if that happens.
+    if (!DirectoryExists(dir)) {
+      FindCloseChangeNotification(*handle);
+      *handle = INVALID_HANDLE_VALUE;
+    }
+    return true;
+  }
+
+  // If FindFirstChangeNotification failed because the target directory
+  // doesn't exist, access is denied (happens if the file is already gone but
+  // there are still handles open), or the target is not a directory, try the
+  // immediate parent directory instead.
+  DWORD error_code = GetLastError();
+  if (error_code != ERROR_FILE_NOT_FOUND &&
+      error_code != ERROR_PATH_NOT_FOUND &&
+      error_code != ERROR_ACCESS_DENIED &&
+      error_code != ERROR_SHARING_VIOLATION &&
+      error_code != ERROR_DIRECTORY) {
+    DPLOG(ERROR) << "FindFirstChangeNotification failed for "
+                 << dir.value();
+    return false;
+  }
+
+  return true;
+}
+
+bool FilePathWatcherImpl::UpdateWatch() {
+  if (handle_ != INVALID_HANDLE_VALUE)
+    DestroyWatch();
+
+  // Start at the target and walk up the directory chain until we succesfully
+  // create a watch handle in |handle_|. |child_dirs| keeps a stack of child
+  // directories stripped from target, in reverse order.
+  std::vector<FilePath> child_dirs;
+  FilePath watched_path(target_);
+  while (true) {
+    if (!SetupWatchHandle(watched_path, recursive_watch_, &handle_))
+      return false;
+
+    // Break if a valid handle is returned. Try the parent directory otherwise.
+    if (handle_ != INVALID_HANDLE_VALUE)
+      break;
+
+    // Abort if we hit the root directory.
+    child_dirs.push_back(watched_path.BaseName());
+    FilePath parent(watched_path.DirName());
+    if (parent == watched_path) {
+      DLOG(ERROR) << "Reached the root directory";
+      return false;
+    }
+    watched_path = parent;
+  }
+
+  // At this point, handle_ is valid. However, the bottom-up search that the
+  // above code performs races against directory creation. So try to walk back
+  // down and see whether any children appeared in the mean time.
+  while (!child_dirs.empty()) {
+    watched_path = watched_path.Append(child_dirs.back());
+    child_dirs.pop_back();
+    HANDLE temp_handle = INVALID_HANDLE_VALUE;
+    if (!SetupWatchHandle(watched_path, recursive_watch_, &temp_handle))
+      return false;
+    if (temp_handle == INVALID_HANDLE_VALUE)
+      break;
+    FindCloseChangeNotification(handle_);
+    handle_ = temp_handle;
+  }
+
+  return true;
+}
+
+void FilePathWatcherImpl::DestroyWatch() {
+  watcher_.StopWatching();
+  FindCloseChangeNotification(handle_);
+  handle_ = INVALID_HANDLE_VALUE;
+}
+
+}  // namespace
+
+FilePathWatcher::FilePathWatcher() {
+  impl_ = new FilePathWatcherImpl();
+}
+
+}  // namespace base
diff --git a/base/files/file_posix.cc b/base/files/file_posix.cc
new file mode 100644
index 0000000..bb49d2d
--- /dev/null
+++ b/base/files/file_posix.cc
@@ -0,0 +1,574 @@
+// Copyright (c) 2012 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/files/file.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "base/logging.h"
+#include "base/metrics/sparse_histogram.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
+
+#if defined(OS_ANDROID)
+#include "base/os_compat_android.h"
+#endif
+
+namespace base {
+
+// Make sure our Whence mappings match the system headers.
+COMPILE_ASSERT(File::FROM_BEGIN   == SEEK_SET &&
+               File::FROM_CURRENT == SEEK_CUR &&
+               File::FROM_END     == SEEK_END, whence_matches_system);
+
+namespace {
+
+#if defined(OS_BSD) || defined(OS_MACOSX) || defined(OS_NACL)
+static int CallFstat(int fd, stat_wrapper_t *sb) {
+  ThreadRestrictions::AssertIOAllowed();
+  return fstat(fd, sb);
+}
+#else
+static int CallFstat(int fd, stat_wrapper_t *sb) {
+  ThreadRestrictions::AssertIOAllowed();
+  return fstat64(fd, sb);
+}
+#endif
+
+// NaCl doesn't provide the following system calls, so either simulate them or
+// wrap them in order to minimize the number of #ifdef's in this file.
+#if !defined(OS_NACL)
+static bool IsOpenAppend(PlatformFile file) {
+  return (fcntl(file, F_GETFL) & O_APPEND) != 0;
+}
+
+static int CallFtruncate(PlatformFile file, int64 length) {
+  return HANDLE_EINTR(ftruncate(file, length));
+}
+
+static int CallFutimes(PlatformFile file, const struct timeval times[2]) {
+#ifdef __USE_XOPEN2K8
+  // futimens should be available, but futimes might not be
+  // http://pubs.opengroup.org/onlinepubs/9699919799/
+
+  timespec ts_times[2];
+  ts_times[0].tv_sec  = times[0].tv_sec;
+  ts_times[0].tv_nsec = times[0].tv_usec * 1000;
+  ts_times[1].tv_sec  = times[1].tv_sec;
+  ts_times[1].tv_nsec = times[1].tv_usec * 1000;
+
+  return futimens(file, ts_times);
+#else
+  return futimes(file, times);
+#endif
+}
+
+static File::Error CallFctnlFlock(PlatformFile file, bool do_lock) {
+  struct flock lock;
+  lock.l_type = F_WRLCK;
+  lock.l_whence = SEEK_SET;
+  lock.l_start = 0;
+  lock.l_len = 0;  // Lock entire file.
+  if (HANDLE_EINTR(fcntl(file, do_lock ? F_SETLK : F_UNLCK, &lock)) == -1)
+    return File::OSErrorToFileError(errno);
+  return File::FILE_OK;
+}
+#else  // defined(OS_NACL)
+
+static bool IsOpenAppend(PlatformFile file) {
+  // NaCl doesn't implement fcntl. Since NaCl's write conforms to the POSIX
+  // standard and always appends if the file is opened with O_APPEND, just
+  // return false here.
+  return false;
+}
+
+static int CallFtruncate(PlatformFile file, int64 length) {
+  NOTIMPLEMENTED();  // NaCl doesn't implement ftruncate.
+  return 0;
+}
+
+static int CallFutimes(PlatformFile file, const struct timeval times[2]) {
+  NOTIMPLEMENTED();  // NaCl doesn't implement futimes.
+  return 0;
+}
+
+static File::Error CallFctnlFlock(PlatformFile file, bool do_lock) {
+  NOTIMPLEMENTED();  // NaCl doesn't implement flock struct.
+  return File::FILE_ERROR_INVALID_OPERATION;
+}
+#endif  // defined(OS_NACL)
+
+}  // namespace
+
+void File::Info::FromStat(const stat_wrapper_t& stat_info) {
+  is_directory = S_ISDIR(stat_info.st_mode);
+  is_symbolic_link = S_ISLNK(stat_info.st_mode);
+  size = stat_info.st_size;
+
+#if defined(OS_LINUX)
+  time_t last_modified_sec = stat_info.st_mtim.tv_sec;
+  int64 last_modified_nsec = stat_info.st_mtim.tv_nsec;
+  time_t last_accessed_sec = stat_info.st_atim.tv_sec;
+  int64 last_accessed_nsec = stat_info.st_atim.tv_nsec;
+  time_t creation_time_sec = stat_info.st_ctim.tv_sec;
+  int64 creation_time_nsec = stat_info.st_ctim.tv_nsec;
+#elif defined(OS_ANDROID)
+  time_t last_modified_sec = stat_info.st_mtime;
+  int64 last_modified_nsec = stat_info.st_mtime_nsec;
+  time_t last_accessed_sec = stat_info.st_atime;
+  int64 last_accessed_nsec = stat_info.st_atime_nsec;
+  time_t creation_time_sec = stat_info.st_ctime;
+  int64 creation_time_nsec = stat_info.st_ctime_nsec;
+#elif defined(OS_MACOSX) || defined(OS_IOS) || defined(OS_BSD)
+  time_t last_modified_sec = stat_info.st_mtimespec.tv_sec;
+  int64 last_modified_nsec = stat_info.st_mtimespec.tv_nsec;
+  time_t last_accessed_sec = stat_info.st_atimespec.tv_sec;
+  int64 last_accessed_nsec = stat_info.st_atimespec.tv_nsec;
+  time_t creation_time_sec = stat_info.st_ctimespec.tv_sec;
+  int64 creation_time_nsec = stat_info.st_ctimespec.tv_nsec;
+#else
+  time_t last_modified_sec = stat_info.st_mtime;
+  int64 last_modified_nsec = 0;
+  time_t last_accessed_sec = stat_info.st_atime;
+  int64 last_accessed_nsec = 0;
+  time_t creation_time_sec = stat_info.st_ctime;
+  int64 creation_time_nsec = 0;
+#endif
+
+  last_modified =
+      Time::FromTimeT(last_modified_sec) +
+      TimeDelta::FromMicroseconds(last_modified_nsec /
+                                  Time::kNanosecondsPerMicrosecond);
+
+  last_accessed =
+      Time::FromTimeT(last_accessed_sec) +
+      TimeDelta::FromMicroseconds(last_accessed_nsec /
+                                  Time::kNanosecondsPerMicrosecond);
+
+  creation_time =
+      Time::FromTimeT(creation_time_sec) +
+      TimeDelta::FromMicroseconds(creation_time_nsec /
+                                  Time::kNanosecondsPerMicrosecond);
+}
+
+bool File::IsValid() const {
+  return file_.is_valid();
+}
+
+PlatformFile File::GetPlatformFile() const {
+  return file_.get();
+}
+
+PlatformFile File::TakePlatformFile() {
+  return file_.release();
+}
+
+void File::Close() {
+  if (!IsValid())
+    return;
+
+  SCOPED_FILE_TRACE("Close");
+  ThreadRestrictions::AssertIOAllowed();
+  file_.reset();
+}
+
+int64 File::Seek(Whence whence, int64 offset) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(IsValid());
+
+  SCOPED_FILE_TRACE_WITH_SIZE("Seek", offset);
+
+#if defined(OS_ANDROID)
+  COMPILE_ASSERT(sizeof(int64) == sizeof(off64_t), off64_t_64_bit);
+  return lseek64(file_.get(), static_cast<off64_t>(offset),
+                 static_cast<int>(whence));
+#else
+  COMPILE_ASSERT(sizeof(int64) == sizeof(off_t), off_t_64_bit);
+  return lseek(file_.get(), static_cast<off_t>(offset),
+               static_cast<int>(whence));
+#endif
+}
+
+int File::Read(int64 offset, char* data, int size) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(IsValid());
+  if (size < 0)
+    return -1;
+
+  SCOPED_FILE_TRACE_WITH_SIZE("Read", size);
+
+  int bytes_read = 0;
+  int rv;
+  do {
+    rv = HANDLE_EINTR(pread(file_.get(), data + bytes_read,
+                            size - bytes_read, offset + bytes_read));
+    if (rv <= 0)
+      break;
+
+    bytes_read += rv;
+  } while (bytes_read < size);
+
+  return bytes_read ? bytes_read : rv;
+}
+
+int File::ReadAtCurrentPos(char* data, int size) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(IsValid());
+  if (size < 0)
+    return -1;
+
+  SCOPED_FILE_TRACE_WITH_SIZE("ReadAtCurrentPos", size);
+
+  int bytes_read = 0;
+  int rv;
+  do {
+    rv = HANDLE_EINTR(read(file_.get(), data + bytes_read, size - bytes_read));
+    if (rv <= 0)
+      break;
+
+    bytes_read += rv;
+  } while (bytes_read < size);
+
+  return bytes_read ? bytes_read : rv;
+}
+
+int File::ReadNoBestEffort(int64 offset, char* data, int size) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(IsValid());
+  SCOPED_FILE_TRACE_WITH_SIZE("ReadNoBestEffort", size);
+  return HANDLE_EINTR(pread(file_.get(), data, size, offset));
+}
+
+int File::ReadAtCurrentPosNoBestEffort(char* data, int size) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(IsValid());
+  if (size < 0)
+    return -1;
+
+  SCOPED_FILE_TRACE_WITH_SIZE("ReadAtCurrentPosNoBestEffort", size);
+  return HANDLE_EINTR(read(file_.get(), data, size));
+}
+
+int File::Write(int64 offset, const char* data, int size) {
+  ThreadRestrictions::AssertIOAllowed();
+
+  if (IsOpenAppend(file_.get()))
+    return WriteAtCurrentPos(data, size);
+
+  DCHECK(IsValid());
+  if (size < 0)
+    return -1;
+
+  SCOPED_FILE_TRACE_WITH_SIZE("Write", size);
+
+  int bytes_written = 0;
+  int rv;
+  do {
+    rv = HANDLE_EINTR(pwrite(file_.get(), data + bytes_written,
+                             size - bytes_written, offset + bytes_written));
+    if (rv <= 0)
+      break;
+
+    bytes_written += rv;
+  } while (bytes_written < size);
+
+  return bytes_written ? bytes_written : rv;
+}
+
+int File::WriteAtCurrentPos(const char* data, int size) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(IsValid());
+  if (size < 0)
+    return -1;
+
+  SCOPED_FILE_TRACE_WITH_SIZE("WriteAtCurrentPos", size);
+
+  int bytes_written = 0;
+  int rv;
+  do {
+    rv = HANDLE_EINTR(write(file_.get(), data + bytes_written,
+                            size - bytes_written));
+    if (rv <= 0)
+      break;
+
+    bytes_written += rv;
+  } while (bytes_written < size);
+
+  return bytes_written ? bytes_written : rv;
+}
+
+int File::WriteAtCurrentPosNoBestEffort(const char* data, int size) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(IsValid());
+  if (size < 0)
+    return -1;
+
+  SCOPED_FILE_TRACE_WITH_SIZE("WriteAtCurrentPosNoBestEffort", size);
+  return HANDLE_EINTR(write(file_.get(), data, size));
+}
+
+int64 File::GetLength() {
+  DCHECK(IsValid());
+
+  SCOPED_FILE_TRACE("GetLength");
+
+  stat_wrapper_t file_info;
+  if (CallFstat(file_.get(), &file_info))
+    return false;
+
+  return file_info.st_size;
+}
+
+bool File::SetLength(int64 length) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(IsValid());
+
+  SCOPED_FILE_TRACE_WITH_SIZE("SetLength", length);
+  return !CallFtruncate(file_.get(), length);
+}
+
+bool File::SetTimes(Time last_access_time, Time last_modified_time) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(IsValid());
+
+  SCOPED_FILE_TRACE("SetTimes");
+
+  timeval times[2];
+  times[0] = last_access_time.ToTimeVal();
+  times[1] = last_modified_time.ToTimeVal();
+
+  return !CallFutimes(file_.get(), times);
+}
+
+bool File::GetInfo(Info* info) {
+  DCHECK(IsValid());
+
+  SCOPED_FILE_TRACE("GetInfo");
+
+  stat_wrapper_t file_info;
+  if (CallFstat(file_.get(), &file_info))
+    return false;
+
+  info->FromStat(file_info);
+  return true;
+}
+
+File::Error File::Lock() {
+  SCOPED_FILE_TRACE("Lock");
+  return CallFctnlFlock(file_.get(), true);
+}
+
+File::Error File::Unlock() {
+  SCOPED_FILE_TRACE("Unlock");
+  return CallFctnlFlock(file_.get(), false);
+}
+
+File File::Duplicate() {
+  if (!IsValid())
+    return File();
+
+  SCOPED_FILE_TRACE("Duplicate");
+
+  PlatformFile other_fd = dup(GetPlatformFile());
+  if (other_fd == -1)
+    return File(OSErrorToFileError(errno));
+
+  File other(other_fd);
+  if (async())
+    other.async_ = true;
+  return other.Pass();
+}
+
+// Static.
+File::Error File::OSErrorToFileError(int saved_errno) {
+  switch (saved_errno) {
+    case EACCES:
+    case EISDIR:
+    case EROFS:
+    case EPERM:
+      return FILE_ERROR_ACCESS_DENIED;
+    case EBUSY:
+#if !defined(OS_NACL)  // ETXTBSY not defined by NaCl.
+    case ETXTBSY:
+#endif
+      return FILE_ERROR_IN_USE;
+    case EEXIST:
+      return FILE_ERROR_EXISTS;
+    case EIO:
+      return FILE_ERROR_IO;
+    case ENOENT:
+      return FILE_ERROR_NOT_FOUND;
+    case EMFILE:
+      return FILE_ERROR_TOO_MANY_OPENED;
+    case ENOMEM:
+      return FILE_ERROR_NO_MEMORY;
+    case ENOSPC:
+      return FILE_ERROR_NO_SPACE;
+    case ENOTDIR:
+      return FILE_ERROR_NOT_A_DIRECTORY;
+    default:
+#if !defined(OS_NACL)  // NaCl build has no metrics code.
+      UMA_HISTOGRAM_SPARSE_SLOWLY("PlatformFile.UnknownErrors.Posix",
+                                  saved_errno);
+#endif
+      return FILE_ERROR_FAILED;
+  }
+}
+
+File::MemoryCheckingScopedFD::MemoryCheckingScopedFD() {
+  UpdateChecksum();
+}
+
+File::MemoryCheckingScopedFD::MemoryCheckingScopedFD(int fd) : file_(fd) {
+  UpdateChecksum();
+}
+
+File::MemoryCheckingScopedFD::~MemoryCheckingScopedFD() {}
+
+// static
+void File::MemoryCheckingScopedFD::ComputeMemoryChecksum(
+    unsigned int* out_checksum) const {
+  // Use a single iteration of a linear congruentional generator (lcg) to
+  // provide a cheap checksum unlikely to be accidentally matched by a random
+  // memory corruption.
+
+  // By choosing constants that satisfy the Hull-Duebell Theorem on lcg cycle
+  // length, we insure that each distinct fd value maps to a distinct checksum,
+  // which maximises the utility of our checksum.
+
+  // This code uses "unsigned int" throughout for its defined modular semantics,
+  // which implicitly gives us a divisor that is a power of two.
+
+  const unsigned int kMultiplier = 13035 * 4 + 1;
+  COMPILE_ASSERT(((kMultiplier - 1) & 3) == 0, pred_must_be_multiple_of_four);
+  const unsigned int kIncrement = 1595649551;
+  COMPILE_ASSERT(kIncrement & 1, must_be_coprime_to_powers_of_two);
+
+  *out_checksum =
+      static_cast<unsigned int>(file_.get()) * kMultiplier + kIncrement;
+}
+
+void File::MemoryCheckingScopedFD::Check() const {
+  unsigned int computed_checksum;
+  ComputeMemoryChecksum(&computed_checksum);
+  CHECK_EQ(file_memory_checksum_, computed_checksum) << "corrupted fd memory";
+}
+
+void File::MemoryCheckingScopedFD::UpdateChecksum() {
+  ComputeMemoryChecksum(&file_memory_checksum_);
+}
+
+// NaCl doesn't implement system calls to open files directly.
+#if !defined(OS_NACL)
+// TODO(erikkay): does it make sense to support FLAG_EXCLUSIVE_* here?
+void File::DoInitialize(uint32 flags) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(!IsValid());
+
+  int open_flags = 0;
+  if (flags & FLAG_CREATE)
+    open_flags = O_CREAT | O_EXCL;
+
+  created_ = false;
+
+  if (flags & FLAG_CREATE_ALWAYS) {
+    DCHECK(!open_flags);
+    DCHECK(flags & FLAG_WRITE);
+    open_flags = O_CREAT | O_TRUNC;
+  }
+
+  if (flags & FLAG_OPEN_TRUNCATED) {
+    DCHECK(!open_flags);
+    DCHECK(flags & FLAG_WRITE);
+    open_flags = O_TRUNC;
+  }
+
+  if (!open_flags && !(flags & FLAG_OPEN) && !(flags & FLAG_OPEN_ALWAYS)) {
+    NOTREACHED();
+    errno = EOPNOTSUPP;
+    error_details_ = FILE_ERROR_FAILED;
+    return;
+  }
+
+  if (flags & FLAG_WRITE && flags & FLAG_READ) {
+    open_flags |= O_RDWR;
+  } else if (flags & FLAG_WRITE) {
+    open_flags |= O_WRONLY;
+  } else if (!(flags & FLAG_READ) &&
+             !(flags & FLAG_WRITE_ATTRIBUTES) &&
+             !(flags & FLAG_APPEND) &&
+             !(flags & FLAG_OPEN_ALWAYS)) {
+    NOTREACHED();
+  }
+
+  if (flags & FLAG_TERMINAL_DEVICE)
+    open_flags |= O_NOCTTY | O_NDELAY;
+
+  if (flags & FLAG_APPEND && flags & FLAG_READ)
+    open_flags |= O_APPEND | O_RDWR;
+  else if (flags & FLAG_APPEND)
+    open_flags |= O_APPEND | O_WRONLY;
+
+  COMPILE_ASSERT(O_RDONLY == 0, O_RDONLY_must_equal_zero);
+
+  int mode = S_IRUSR | S_IWUSR;
+#if defined(OS_CHROMEOS)
+  mode |= S_IRGRP | S_IROTH;
+#endif
+
+  int descriptor = HANDLE_EINTR(open(path_.value().c_str(), open_flags, mode));
+
+  if (flags & FLAG_OPEN_ALWAYS) {
+    if (descriptor < 0) {
+      open_flags |= O_CREAT;
+      if (flags & FLAG_EXCLUSIVE_READ || flags & FLAG_EXCLUSIVE_WRITE)
+        open_flags |= O_EXCL;   // together with O_CREAT implies O_NOFOLLOW
+
+      descriptor = HANDLE_EINTR(open(path_.value().c_str(), open_flags, mode));
+      if (descriptor >= 0)
+        created_ = true;
+    }
+  }
+
+  if (descriptor < 0) {
+    error_details_ = File::OSErrorToFileError(errno);
+    return;
+  }
+
+  if (flags & (FLAG_CREATE_ALWAYS | FLAG_CREATE))
+    created_ = true;
+
+  if (flags & FLAG_DELETE_ON_CLOSE)
+    unlink(path_.value().c_str());
+
+  async_ = ((flags & FLAG_ASYNC) == FLAG_ASYNC);
+  error_details_ = FILE_OK;
+  file_.reset(descriptor);
+}
+#endif  // !defined(OS_NACL)
+
+bool File::DoFlush() {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(IsValid());
+
+#if defined(OS_NACL)
+  NOTIMPLEMENTED();  // NaCl doesn't implement fsync.
+  return true;
+#elif defined(OS_LINUX) || defined(OS_ANDROID)
+  return !HANDLE_EINTR(fdatasync(file_.get()));
+#else
+  return !HANDLE_EINTR(fsync(file_.get()));
+#endif
+}
+
+void File::SetPlatformFile(PlatformFile file) {
+  DCHECK(!file_.is_valid());
+  file_.reset(file);
+}
+
+}  // namespace base
diff --git a/base/files/file_proxy.cc b/base/files/file_proxy.cc
new file mode 100644
index 0000000..f995735
--- /dev/null
+++ b/base/files/file_proxy.cc
@@ -0,0 +1,358 @@
+// 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.
+
+#include "base/files/file_proxy.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/files/file.h"
+#include "base/files/file_util.h"
+#include "base/location.h"
+#include "base/task_runner.h"
+#include "base/task_runner_util.h"
+
+namespace {
+
+void FileDeleter(base::File file) {
+}
+
+}  // namespace
+
+namespace base {
+
+class FileHelper {
+ public:
+   FileHelper(FileProxy* proxy, File file)
+      : file_(file.Pass()),
+        error_(File::FILE_ERROR_FAILED),
+        task_runner_(proxy->task_runner()),
+        proxy_(AsWeakPtr(proxy)) {
+   }
+
+   void PassFile() {
+     if (proxy_)
+       proxy_->SetFile(file_.Pass());
+     else if (file_.IsValid())
+       task_runner_->PostTask(FROM_HERE, Bind(&FileDeleter, Passed(&file_)));
+   }
+
+ protected:
+  File file_;
+  File::Error error_;
+
+ private:
+  scoped_refptr<TaskRunner> task_runner_;
+  WeakPtr<FileProxy> proxy_;
+  DISALLOW_COPY_AND_ASSIGN(FileHelper);
+};
+
+namespace {
+
+class GenericFileHelper : public FileHelper {
+ public:
+  GenericFileHelper(FileProxy* proxy, File file)
+      : FileHelper(proxy, file.Pass()) {
+  }
+
+  void Close() {
+    file_.Close();
+    error_ = File::FILE_OK;
+  }
+
+  void SetTimes(Time last_access_time, Time last_modified_time) {
+    bool rv = file_.SetTimes(last_access_time, last_modified_time);
+    error_ = rv ? File::FILE_OK : File::FILE_ERROR_FAILED;
+  }
+
+  void SetLength(int64 length) {
+    if (file_.SetLength(length))
+      error_ = File::FILE_OK;
+  }
+
+  void Flush() {
+    if (file_.Flush())
+      error_ = File::FILE_OK;
+  }
+
+  void Reply(const FileProxy::StatusCallback& callback) {
+    PassFile();
+    if (!callback.is_null())
+      callback.Run(error_);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(GenericFileHelper);
+};
+
+class CreateOrOpenHelper : public FileHelper {
+ public:
+  CreateOrOpenHelper(FileProxy* proxy, File file)
+      : FileHelper(proxy, file.Pass()) {
+  }
+
+  void RunWork(const FilePath& file_path, int file_flags) {
+    file_.Initialize(file_path, file_flags);
+    error_ = file_.IsValid() ? File::FILE_OK : file_.error_details();
+  }
+
+  void Reply(const FileProxy::StatusCallback& callback) {
+    DCHECK(!callback.is_null());
+    PassFile();
+    callback.Run(error_);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(CreateOrOpenHelper);
+};
+
+class CreateTemporaryHelper : public FileHelper {
+ public:
+  CreateTemporaryHelper(FileProxy* proxy, File file)
+      : FileHelper(proxy, file.Pass()) {
+  }
+
+  void RunWork(uint32 additional_file_flags) {
+    // TODO(darin): file_util should have a variant of CreateTemporaryFile
+    // that returns a FilePath and a File.
+    if (!CreateTemporaryFile(&file_path_)) {
+      // TODO(davidben): base::CreateTemporaryFile should preserve the error
+      // code.
+      error_ = File::FILE_ERROR_FAILED;
+      return;
+    }
+
+    uint32 file_flags = File::FLAG_WRITE |
+                        File::FLAG_TEMPORARY |
+                        File::FLAG_CREATE_ALWAYS |
+                        additional_file_flags;
+
+    file_.Initialize(file_path_, file_flags);
+    if (file_.IsValid()) {
+      error_ = File::FILE_OK;
+    } else {
+      error_ = file_.error_details();
+      DeleteFile(file_path_, false);
+      file_path_.clear();
+    }
+  }
+
+  void Reply(const FileProxy::CreateTemporaryCallback& callback) {
+    DCHECK(!callback.is_null());
+    PassFile();
+    callback.Run(error_, file_path_);
+  }
+
+ private:
+  FilePath file_path_;
+  DISALLOW_COPY_AND_ASSIGN(CreateTemporaryHelper);
+};
+
+class GetInfoHelper : public FileHelper {
+ public:
+  GetInfoHelper(FileProxy* proxy, File file)
+      : FileHelper(proxy, file.Pass()) {
+  }
+
+  void RunWork() {
+    if (file_.GetInfo(&file_info_))
+      error_  = File::FILE_OK;
+  }
+
+  void Reply(const FileProxy::GetFileInfoCallback& callback) {
+    PassFile();
+    DCHECK(!callback.is_null());
+    callback.Run(error_, file_info_);
+  }
+
+ private:
+  File::Info file_info_;
+  DISALLOW_COPY_AND_ASSIGN(GetInfoHelper);
+};
+
+class ReadHelper : public FileHelper {
+ public:
+  ReadHelper(FileProxy* proxy, File file, int bytes_to_read)
+      : FileHelper(proxy, file.Pass()),
+        buffer_(new char[bytes_to_read]),
+        bytes_to_read_(bytes_to_read),
+        bytes_read_(0) {
+  }
+
+  void RunWork(int64 offset) {
+    bytes_read_ = file_.Read(offset, buffer_.get(), bytes_to_read_);
+    error_ = (bytes_read_ < 0) ? File::FILE_ERROR_FAILED : File::FILE_OK;
+  }
+
+  void Reply(const FileProxy::ReadCallback& callback) {
+    PassFile();
+    DCHECK(!callback.is_null());
+    callback.Run(error_, buffer_.get(), bytes_read_);
+  }
+
+ private:
+  scoped_ptr<char[]> buffer_;
+  int bytes_to_read_;
+  int bytes_read_;
+  DISALLOW_COPY_AND_ASSIGN(ReadHelper);
+};
+
+class WriteHelper : public FileHelper {
+ public:
+  WriteHelper(FileProxy* proxy,
+              File file,
+              const char* buffer, int bytes_to_write)
+      : FileHelper(proxy, file.Pass()),
+        buffer_(new char[bytes_to_write]),
+        bytes_to_write_(bytes_to_write),
+        bytes_written_(0) {
+    memcpy(buffer_.get(), buffer, bytes_to_write);
+  }
+
+  void RunWork(int64 offset) {
+    bytes_written_ = file_.Write(offset, buffer_.get(), bytes_to_write_);
+    error_ = (bytes_written_ < 0) ? File::FILE_ERROR_FAILED : File::FILE_OK;
+  }
+
+  void Reply(const FileProxy::WriteCallback& callback) {
+    PassFile();
+    if (!callback.is_null())
+      callback.Run(error_, bytes_written_);
+  }
+
+ private:
+  scoped_ptr<char[]> buffer_;
+  int bytes_to_write_;
+  int bytes_written_;
+  DISALLOW_COPY_AND_ASSIGN(WriteHelper);
+};
+
+}  // namespace
+
+FileProxy::FileProxy(TaskRunner* task_runner) : task_runner_(task_runner) {
+}
+
+FileProxy::~FileProxy() {
+  if (file_.IsValid())
+    task_runner_->PostTask(FROM_HERE, Bind(&FileDeleter, Passed(&file_)));
+}
+
+bool FileProxy::CreateOrOpen(const FilePath& file_path,
+                             uint32 file_flags,
+                             const StatusCallback& callback) {
+  DCHECK(!file_.IsValid());
+  CreateOrOpenHelper* helper = new CreateOrOpenHelper(this, File());
+  return task_runner_->PostTaskAndReply(
+      FROM_HERE,
+      Bind(&CreateOrOpenHelper::RunWork, Unretained(helper), file_path,
+           file_flags),
+      Bind(&CreateOrOpenHelper::Reply, Owned(helper), callback));
+}
+
+bool FileProxy::CreateTemporary(uint32 additional_file_flags,
+                                const CreateTemporaryCallback& callback) {
+  DCHECK(!file_.IsValid());
+  CreateTemporaryHelper* helper = new CreateTemporaryHelper(this, File());
+  return task_runner_->PostTaskAndReply(
+      FROM_HERE,
+      Bind(&CreateTemporaryHelper::RunWork, Unretained(helper),
+           additional_file_flags),
+      Bind(&CreateTemporaryHelper::Reply, Owned(helper), callback));
+}
+
+bool FileProxy::IsValid() const {
+  return file_.IsValid();
+}
+
+void FileProxy::SetFile(File file) {
+  DCHECK(!file_.IsValid());
+  file_ = file.Pass();
+}
+
+File FileProxy::TakeFile() {
+  return file_.Pass();
+}
+
+PlatformFile FileProxy::GetPlatformFile() const {
+  return file_.GetPlatformFile();
+}
+
+bool FileProxy::Close(const StatusCallback& callback) {
+  DCHECK(file_.IsValid());
+  GenericFileHelper* helper = new GenericFileHelper(this, file_.Pass());
+  return task_runner_->PostTaskAndReply(
+      FROM_HERE,
+      Bind(&GenericFileHelper::Close, Unretained(helper)),
+      Bind(&GenericFileHelper::Reply, Owned(helper), callback));
+}
+
+bool FileProxy::GetInfo(const GetFileInfoCallback& callback) {
+  DCHECK(file_.IsValid());
+  GetInfoHelper* helper = new GetInfoHelper(this, file_.Pass());
+  return task_runner_->PostTaskAndReply(
+      FROM_HERE,
+      Bind(&GetInfoHelper::RunWork, Unretained(helper)),
+      Bind(&GetInfoHelper::Reply, Owned(helper), callback));
+}
+
+bool FileProxy::Read(int64 offset,
+                     int bytes_to_read,
+                     const ReadCallback& callback) {
+  DCHECK(file_.IsValid());
+  if (bytes_to_read < 0)
+    return false;
+
+  ReadHelper* helper = new ReadHelper(this, file_.Pass(), bytes_to_read);
+  return task_runner_->PostTaskAndReply(
+      FROM_HERE,
+      Bind(&ReadHelper::RunWork, Unretained(helper), offset),
+      Bind(&ReadHelper::Reply, Owned(helper), callback));
+}
+
+bool FileProxy::Write(int64 offset,
+                      const char* buffer,
+                      int bytes_to_write,
+                      const WriteCallback& callback) {
+  DCHECK(file_.IsValid());
+  if (bytes_to_write <= 0 || buffer == NULL)
+    return false;
+
+  WriteHelper* helper =
+      new WriteHelper(this, file_.Pass(), buffer, bytes_to_write);
+  return task_runner_->PostTaskAndReply(
+      FROM_HERE,
+      Bind(&WriteHelper::RunWork, Unretained(helper), offset),
+      Bind(&WriteHelper::Reply, Owned(helper), callback));
+}
+
+bool FileProxy::SetTimes(Time last_access_time,
+                         Time last_modified_time,
+                         const StatusCallback& callback) {
+  DCHECK(file_.IsValid());
+  GenericFileHelper* helper = new GenericFileHelper(this, file_.Pass());
+  return task_runner_->PostTaskAndReply(
+      FROM_HERE,
+      Bind(&GenericFileHelper::SetTimes, Unretained(helper), last_access_time,
+           last_modified_time),
+      Bind(&GenericFileHelper::Reply, Owned(helper), callback));
+}
+
+bool FileProxy::SetLength(int64 length, const StatusCallback& callback) {
+  DCHECK(file_.IsValid());
+  GenericFileHelper* helper = new GenericFileHelper(this, file_.Pass());
+  return task_runner_->PostTaskAndReply(
+      FROM_HERE,
+      Bind(&GenericFileHelper::SetLength, Unretained(helper), length),
+      Bind(&GenericFileHelper::Reply, Owned(helper), callback));
+}
+
+bool FileProxy::Flush(const StatusCallback& callback) {
+  DCHECK(file_.IsValid());
+  GenericFileHelper* helper = new GenericFileHelper(this, file_.Pass());
+  return task_runner_->PostTaskAndReply(
+      FROM_HERE,
+      Bind(&GenericFileHelper::Flush, Unretained(helper)),
+      Bind(&GenericFileHelper::Reply, Owned(helper), callback));
+}
+
+}  // namespace base
diff --git a/base/files/file_proxy.h b/base/files/file_proxy.h
new file mode 100644
index 0000000..f990d04
--- /dev/null
+++ b/base/files/file_proxy.h
@@ -0,0 +1,142 @@
+// 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.
+
+#ifndef BASE_FILES_FILE_PROXY_H_
+#define BASE_FILES_FILE_PROXY_H_
+
+#include "base/base_export.h"
+#include "base/callback_forward.h"
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+
+namespace tracked_objects {
+class Location;
+};
+
+namespace base {
+
+class TaskRunner;
+class Time;
+
+// This class provides asynchronous access to a File. All methods follow the
+// same rules of the equivalent File method, as they are implemented by bouncing
+// the operation to File using a TaskRunner.
+//
+// This class performs automatic proxying to close the underlying file at
+// destruction.
+//
+// The TaskRunner is in charge of any sequencing of the operations, but a single
+// operation can be proxied at a time, regardless of the use of a callback.
+// In other words, having a sequence like
+//
+//   proxy.Write(...);
+//   proxy.Write(...);
+//
+// means the second Write will always fail.
+class BASE_EXPORT FileProxy : public SupportsWeakPtr<FileProxy> {
+ public:
+  // This callback is used by methods that report only an error code. It is
+  // valid to pass a null callback to some functions that takes a
+  // StatusCallback, in which case the operation will complete silently.
+  typedef Callback<void(File::Error)> StatusCallback;
+
+  typedef Callback<void(File::Error,
+                        const FilePath&)> CreateTemporaryCallback;
+  typedef Callback<void(File::Error,
+                        const File::Info&)> GetFileInfoCallback;
+  typedef Callback<void(File::Error,
+                        const char* data,
+                        int bytes_read)> ReadCallback;
+  typedef Callback<void(File::Error,
+                        int bytes_written)> WriteCallback;
+
+  FileProxy();
+  explicit FileProxy(TaskRunner* task_runner);
+  ~FileProxy();
+
+  // Creates or opens a file with the given flags. It is invalid to pass a null
+  // callback. If File::FLAG_CREATE is set in |file_flags| it always tries to
+  // create a new file at the given |file_path| and fails if the file already
+  // exists.
+  //
+  // This returns false if task posting to |task_runner| has failed.
+  bool CreateOrOpen(const FilePath& file_path,
+                    uint32 file_flags,
+                    const StatusCallback& callback);
+
+  // Creates a temporary file for writing. The path and an open file are
+  // returned. It is invalid to pass a null callback. The additional file flags
+  // will be added on top of the default file flags which are:
+  //   File::FLAG_CREATE_ALWAYS
+  //   File::FLAG_WRITE
+  //   File::FLAG_TEMPORARY.
+  //
+  // This returns false if task posting to |task_runner| has failed.
+  bool CreateTemporary(uint32 additional_file_flags,
+                       const CreateTemporaryCallback& callback);
+
+  // Returns true if the underlying |file_| is valid.
+  bool IsValid() const;
+
+  // Returns true if a new file was created (or an old one truncated to zero
+  // length to simulate a new file), and false otherwise.
+  bool created() const { return file_.created(); }
+
+  // Claims ownership of |file|. It is an error to call this method when
+  // IsValid() returns true.
+  void SetFile(File file);
+
+  File TakeFile();
+
+  PlatformFile GetPlatformFile() const;
+
+  // Proxies File::Close. The callback can be null.
+  // This returns false if task posting to |task_runner| has failed.
+  bool Close(const StatusCallback& callback);
+
+  // Proxies File::GetInfo. The callback can't be null.
+  // This returns false if task posting to |task_runner| has failed.
+  bool GetInfo(const GetFileInfoCallback& callback);
+
+  // Proxies File::Read. The callback can't be null.
+  // This returns false if |bytes_to_read| is less than zero, or
+  // if task posting to |task_runner| has failed.
+  bool Read(int64 offset, int bytes_to_read, const ReadCallback& callback);
+
+  // Proxies File::Write. The callback can be null.
+  // This returns false if |bytes_to_write| is less than or equal to zero,
+  // if |buffer| is NULL, or if task posting to |task_runner| has failed.
+  bool Write(int64 offset,
+             const char* buffer,
+             int bytes_to_write,
+             const WriteCallback& callback);
+
+  // Proxies File::SetTimes. The callback can be null.
+  // This returns false if task posting to |task_runner| has failed.
+  bool SetTimes(Time last_access_time,
+                Time last_modified_time,
+                const StatusCallback& callback);
+
+  // Proxies File::SetLength. The callback can be null.
+  // This returns false if task posting to |task_runner| has failed.
+  bool SetLength(int64 length, const StatusCallback& callback);
+
+  // Proxies File::Flush. The callback can be null.
+  // This returns false if task posting to |task_runner| has failed.
+  bool Flush(const StatusCallback& callback);
+
+ private:
+  friend class FileHelper;
+  TaskRunner* task_runner() { return task_runner_.get(); }
+
+  scoped_refptr<TaskRunner> task_runner_;
+  File file_;
+  DISALLOW_COPY_AND_ASSIGN(FileProxy);
+};
+
+}  // namespace base
+
+#endif  // BASE_FILES_FILE_PROXY_H_
diff --git a/base/files/file_proxy_unittest.cc b/base/files/file_proxy_unittest.cc
new file mode 100644
index 0000000..df0bbc8
--- /dev/null
+++ b/base/files/file_proxy_unittest.cc
@@ -0,0 +1,369 @@
+// 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.
+
+#include "base/files/file_proxy.h"
+
+#include "base/bind.h"
+#include "base/files/file.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/memory/weak_ptr.h"
+#include "base/threading/thread.h"
+#include "base/threading/thread_restrictions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+class FileProxyTest : public testing::Test {
+ public:
+  FileProxyTest()
+      : file_thread_("FileProxyTestFileThread"),
+        error_(File::FILE_OK),
+        bytes_written_(-1),
+        weak_factory_(this) {}
+
+  void SetUp() override {
+    ASSERT_TRUE(dir_.CreateUniqueTempDir());
+    ASSERT_TRUE(file_thread_.Start());
+  }
+
+  void DidFinish(File::Error error) {
+    error_ = error;
+    MessageLoop::current()->QuitWhenIdle();
+  }
+
+  void DidCreateOrOpen(File::Error error) {
+    error_ = error;
+    MessageLoop::current()->QuitWhenIdle();
+  }
+
+  void DidCreateTemporary(File::Error error,
+                          const FilePath& path) {
+    error_ = error;
+    path_ = path;
+    MessageLoop::current()->QuitWhenIdle();
+  }
+
+  void DidGetFileInfo(File::Error error,
+                      const File::Info& file_info) {
+    error_ = error;
+    file_info_ = file_info;
+    MessageLoop::current()->QuitWhenIdle();
+  }
+
+  void DidRead(File::Error error,
+               const char* data,
+               int bytes_read) {
+    error_ = error;
+    buffer_.resize(bytes_read);
+    memcpy(&buffer_[0], data, bytes_read);
+    MessageLoop::current()->QuitWhenIdle();
+  }
+
+  void DidWrite(File::Error error,
+                int bytes_written) {
+    error_ = error;
+    bytes_written_ = bytes_written;
+    MessageLoop::current()->QuitWhenIdle();
+  }
+
+ protected:
+  void CreateProxy(uint32 flags, FileProxy* proxy) {
+    proxy->CreateOrOpen(
+        test_path(), flags,
+        Bind(&FileProxyTest::DidCreateOrOpen, weak_factory_.GetWeakPtr()));
+    MessageLoop::current()->Run();
+    EXPECT_TRUE(proxy->IsValid());
+  }
+
+  TaskRunner* file_task_runner() const {
+    return file_thread_.task_runner().get();
+  }
+  const FilePath& test_dir_path() const { return dir_.path(); }
+  const FilePath test_path() const { return dir_.path().AppendASCII("test"); }
+
+  MessageLoopForIO message_loop_;
+  Thread file_thread_;
+
+  ScopedTempDir dir_;
+  File::Error error_;
+  FilePath path_;
+  File::Info file_info_;
+  std::vector<char> buffer_;
+  int bytes_written_;
+  WeakPtrFactory<FileProxyTest> weak_factory_;
+};
+
+TEST_F(FileProxyTest, CreateOrOpen_Create) {
+  FileProxy proxy(file_task_runner());
+  proxy.CreateOrOpen(
+      test_path(),
+      File::FLAG_CREATE | File::FLAG_READ,
+      Bind(&FileProxyTest::DidCreateOrOpen, weak_factory_.GetWeakPtr()));
+  MessageLoop::current()->Run();
+
+  EXPECT_EQ(File::FILE_OK, error_);
+  EXPECT_TRUE(proxy.IsValid());
+  EXPECT_TRUE(proxy.created());
+  EXPECT_TRUE(PathExists(test_path()));
+}
+
+TEST_F(FileProxyTest, CreateOrOpen_Open) {
+  // Creates a file.
+  base::WriteFile(test_path(), NULL, 0);
+  ASSERT_TRUE(PathExists(test_path()));
+
+  // Opens the created file.
+  FileProxy proxy(file_task_runner());
+  proxy.CreateOrOpen(
+      test_path(),
+      File::FLAG_OPEN | File::FLAG_READ,
+      Bind(&FileProxyTest::DidCreateOrOpen, weak_factory_.GetWeakPtr()));
+  MessageLoop::current()->Run();
+
+  EXPECT_EQ(File::FILE_OK, error_);
+  EXPECT_TRUE(proxy.IsValid());
+  EXPECT_FALSE(proxy.created());
+}
+
+TEST_F(FileProxyTest, CreateOrOpen_OpenNonExistent) {
+  FileProxy proxy(file_task_runner());
+  proxy.CreateOrOpen(
+      test_path(),
+      File::FLAG_OPEN | File::FLAG_READ,
+      Bind(&FileProxyTest::DidCreateOrOpen, weak_factory_.GetWeakPtr()));
+  MessageLoop::current()->Run();
+  EXPECT_EQ(File::FILE_ERROR_NOT_FOUND, error_);
+  EXPECT_FALSE(proxy.IsValid());
+  EXPECT_FALSE(proxy.created());
+  EXPECT_FALSE(PathExists(test_path()));
+}
+
+TEST_F(FileProxyTest, CreateOrOpen_AbandonedCreate) {
+  bool prev = ThreadRestrictions::SetIOAllowed(false);
+  {
+    FileProxy proxy(file_task_runner());
+    proxy.CreateOrOpen(
+        test_path(),
+        File::FLAG_CREATE | File::FLAG_READ,
+        Bind(&FileProxyTest::DidCreateOrOpen, weak_factory_.GetWeakPtr()));
+  }
+  MessageLoop::current()->Run();
+  ThreadRestrictions::SetIOAllowed(prev);
+
+  EXPECT_TRUE(PathExists(test_path()));
+}
+
+TEST_F(FileProxyTest, Close) {
+  // Creates a file.
+  FileProxy proxy(file_task_runner());
+  CreateProxy(File::FLAG_CREATE | File::FLAG_WRITE, &proxy);
+
+#if defined(OS_WIN)
+  // This fails on Windows if the file is not closed.
+  EXPECT_FALSE(base::Move(test_path(), test_dir_path().AppendASCII("new")));
+#endif
+
+  proxy.Close(Bind(&FileProxyTest::DidFinish, weak_factory_.GetWeakPtr()));
+  MessageLoop::current()->Run();
+  EXPECT_EQ(File::FILE_OK, error_);
+  EXPECT_FALSE(proxy.IsValid());
+
+  // Now it should pass on all platforms.
+  EXPECT_TRUE(base::Move(test_path(), test_dir_path().AppendASCII("new")));
+}
+
+TEST_F(FileProxyTest, CreateTemporary) {
+  {
+    FileProxy proxy(file_task_runner());
+    proxy.CreateTemporary(
+        0 /* additional_file_flags */,
+        Bind(&FileProxyTest::DidCreateTemporary, weak_factory_.GetWeakPtr()));
+    MessageLoop::current()->Run();
+
+    EXPECT_TRUE(proxy.IsValid());
+    EXPECT_EQ(File::FILE_OK, error_);
+    EXPECT_TRUE(PathExists(path_));
+
+    // The file should be writable.
+    proxy.Write(0, "test", 4,
+                Bind(&FileProxyTest::DidWrite, weak_factory_.GetWeakPtr()));
+    MessageLoop::current()->Run();
+    EXPECT_EQ(File::FILE_OK, error_);
+    EXPECT_EQ(4, bytes_written_);
+  }
+
+  // Make sure the written data can be read from the returned path.
+  std::string data;
+  EXPECT_TRUE(ReadFileToString(path_, &data));
+  EXPECT_EQ("test", data);
+
+  // Make sure we can & do delete the created file to prevent leaks on the bots.
+  EXPECT_TRUE(base::DeleteFile(path_, false));
+}
+
+TEST_F(FileProxyTest, SetAndTake) {
+  File file(test_path(), File::FLAG_CREATE | File::FLAG_READ);
+  ASSERT_TRUE(file.IsValid());
+  FileProxy proxy(file_task_runner());
+  EXPECT_FALSE(proxy.IsValid());
+  proxy.SetFile(file.Pass());
+  EXPECT_TRUE(proxy.IsValid());
+  EXPECT_FALSE(file.IsValid());
+
+  file = proxy.TakeFile();
+  EXPECT_FALSE(proxy.IsValid());
+  EXPECT_TRUE(file.IsValid());
+}
+
+TEST_F(FileProxyTest, GetInfo) {
+  // Setup.
+  ASSERT_EQ(4, base::WriteFile(test_path(), "test", 4));
+  File::Info expected_info;
+  GetFileInfo(test_path(), &expected_info);
+
+  // Run.
+  FileProxy proxy(file_task_runner());
+  CreateProxy(File::FLAG_OPEN | File::FLAG_READ, &proxy);
+  proxy.GetInfo(
+      Bind(&FileProxyTest::DidGetFileInfo, weak_factory_.GetWeakPtr()));
+  MessageLoop::current()->Run();
+
+  // Verify.
+  EXPECT_EQ(File::FILE_OK, error_);
+  EXPECT_EQ(expected_info.size, file_info_.size);
+  EXPECT_EQ(expected_info.is_directory, file_info_.is_directory);
+  EXPECT_EQ(expected_info.is_symbolic_link, file_info_.is_symbolic_link);
+  EXPECT_EQ(expected_info.last_modified, file_info_.last_modified);
+  EXPECT_EQ(expected_info.creation_time, file_info_.creation_time);
+}
+
+TEST_F(FileProxyTest, Read) {
+  // Setup.
+  const char expected_data[] = "bleh";
+  int expected_bytes = arraysize(expected_data);
+  ASSERT_EQ(expected_bytes,
+            base::WriteFile(test_path(), expected_data, expected_bytes));
+
+  // Run.
+  FileProxy proxy(file_task_runner());
+  CreateProxy(File::FLAG_OPEN | File::FLAG_READ, &proxy);
+
+  proxy.Read(0, 128, Bind(&FileProxyTest::DidRead, weak_factory_.GetWeakPtr()));
+  MessageLoop::current()->Run();
+
+  // Verify.
+  EXPECT_EQ(File::FILE_OK, error_);
+  EXPECT_EQ(expected_bytes, static_cast<int>(buffer_.size()));
+  for (size_t i = 0; i < buffer_.size(); ++i) {
+    EXPECT_EQ(expected_data[i], buffer_[i]);
+  }
+}
+
+TEST_F(FileProxyTest, WriteAndFlush) {
+  FileProxy proxy(file_task_runner());
+  CreateProxy(File::FLAG_CREATE | File::FLAG_WRITE, &proxy);
+
+  const char data[] = "foo!";
+  int data_bytes = arraysize(data);
+  proxy.Write(0, data, data_bytes,
+              Bind(&FileProxyTest::DidWrite, weak_factory_.GetWeakPtr()));
+  MessageLoop::current()->Run();
+  EXPECT_EQ(File::FILE_OK, error_);
+  EXPECT_EQ(data_bytes, bytes_written_);
+
+  // Flush the written data.  (So that the following read should always
+  // succeed.  On some platforms it may work with or without this flush.)
+  proxy.Flush(Bind(&FileProxyTest::DidFinish, weak_factory_.GetWeakPtr()));
+  MessageLoop::current()->Run();
+  EXPECT_EQ(File::FILE_OK, error_);
+
+  // Verify the written data.
+  char buffer[10];
+  EXPECT_EQ(data_bytes, base::ReadFile(test_path(), buffer, data_bytes));
+  for (int i = 0; i < data_bytes; ++i) {
+    EXPECT_EQ(data[i], buffer[i]);
+  }
+}
+
+TEST_F(FileProxyTest, SetTimes) {
+  FileProxy proxy(file_task_runner());
+  CreateProxy(
+      File::FLAG_CREATE | File::FLAG_WRITE | File::FLAG_WRITE_ATTRIBUTES,
+      &proxy);
+
+  Time last_accessed_time = Time::Now() - TimeDelta::FromDays(12345);
+  Time last_modified_time = Time::Now() - TimeDelta::FromHours(98765);
+
+  proxy.SetTimes(last_accessed_time, last_modified_time,
+                 Bind(&FileProxyTest::DidFinish, weak_factory_.GetWeakPtr()));
+  MessageLoop::current()->Run();
+  EXPECT_EQ(File::FILE_OK, error_);
+
+  File::Info info;
+  GetFileInfo(test_path(), &info);
+
+  // The returned values may only have the seconds precision, so we cast
+  // the double values to int here.
+  EXPECT_EQ(static_cast<int>(last_modified_time.ToDoubleT()),
+            static_cast<int>(info.last_modified.ToDoubleT()));
+  EXPECT_EQ(static_cast<int>(last_accessed_time.ToDoubleT()),
+            static_cast<int>(info.last_accessed.ToDoubleT()));
+}
+
+TEST_F(FileProxyTest, SetLength_Shrink) {
+  // Setup.
+  const char kTestData[] = "0123456789";
+  ASSERT_EQ(10, base::WriteFile(test_path(), kTestData, 10));
+  File::Info info;
+  GetFileInfo(test_path(), &info);
+  ASSERT_EQ(10, info.size);
+
+  // Run.
+  FileProxy proxy(file_task_runner());
+  CreateProxy(File::FLAG_OPEN | File::FLAG_WRITE, &proxy);
+  proxy.SetLength(7,
+                  Bind(&FileProxyTest::DidFinish, weak_factory_.GetWeakPtr()));
+  MessageLoop::current()->Run();
+
+  // Verify.
+  GetFileInfo(test_path(), &info);
+  ASSERT_EQ(7, info.size);
+
+  char buffer[7];
+  EXPECT_EQ(7, base::ReadFile(test_path(), buffer, 7));
+  int i = 0;
+  for (; i < 7; ++i)
+    EXPECT_EQ(kTestData[i], buffer[i]);
+}
+
+TEST_F(FileProxyTest, SetLength_Expand) {
+  // Setup.
+  const char kTestData[] = "9876543210";
+  ASSERT_EQ(10, base::WriteFile(test_path(), kTestData, 10));
+  File::Info info;
+  GetFileInfo(test_path(), &info);
+  ASSERT_EQ(10, info.size);
+
+  // Run.
+  FileProxy proxy(file_task_runner());
+  CreateProxy(File::FLAG_OPEN | File::FLAG_WRITE, &proxy);
+  proxy.SetLength(53,
+                  Bind(&FileProxyTest::DidFinish, weak_factory_.GetWeakPtr()));
+  MessageLoop::current()->Run();
+
+  // Verify.
+  GetFileInfo(test_path(), &info);
+  ASSERT_EQ(53, info.size);
+
+  char buffer[53];
+  EXPECT_EQ(53, base::ReadFile(test_path(), buffer, 53));
+  int i = 0;
+  for (; i < 10; ++i)
+    EXPECT_EQ(kTestData[i], buffer[i]);
+  for (; i < 53; ++i)
+    EXPECT_EQ(0, buffer[i]);
+}
+
+}  // namespace base
diff --git a/base/files/file_tracing.cc b/base/files/file_tracing.cc
new file mode 100644
index 0000000..c25772d
--- /dev/null
+++ b/base/files/file_tracing.cc
@@ -0,0 +1,52 @@
+// 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/files/file_tracing.h"
+
+#include "base/files/file.h"
+
+namespace base {
+
+namespace {
+FileTracing::Provider* g_provider = nullptr;
+}
+
+// static
+void FileTracing::SetProvider(FileTracing::Provider* provider) {
+  g_provider = provider;
+}
+
+FileTracing::ScopedEnabler::ScopedEnabler() {
+  if (g_provider)
+    g_provider->FileTracingEnable(this);
+}
+
+FileTracing::ScopedEnabler::~ScopedEnabler() {
+  if (g_provider)
+    g_provider->FileTracingDisable(this);
+}
+
+FileTracing::ScopedTrace::ScopedTrace() : id_(nullptr) {}
+
+FileTracing::ScopedTrace::~ScopedTrace() {
+  if (id_ && g_provider)
+    g_provider->FileTracingEventEnd(name_, id_);
+}
+
+bool FileTracing::ScopedTrace::ShouldInitialize() const {
+  return g_provider && g_provider->FileTracingCategoryIsEnabled();
+}
+
+void FileTracing::ScopedTrace::Initialize(
+    const char* name, File* file, int64 size) {
+  if (!g_provider)
+    return;
+
+  id_ = &file->trace_enabler_;
+  name_ = name;
+
+  g_provider->FileTracingEventBegin(name_, id_, file->path_, size);
+}
+
+}  // namespace base
diff --git a/base/files/file_tracing.h b/base/files/file_tracing.h
new file mode 100644
index 0000000..149bd78
--- /dev/null
+++ b/base/files/file_tracing.h
@@ -0,0 +1,90 @@
+// 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_FILES_FILE_TRACING_H_
+#define BASE_FILES_FILE_TRACING_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/macros.h"
+
+#define FILE_TRACING_PREFIX "File"
+
+#define SCOPED_FILE_TRACE_WITH_SIZE(name, size) \
+    FileTracing::ScopedTrace scoped_file_trace; \
+    if (scoped_file_trace.ShouldInitialize()) \
+      scoped_file_trace.Initialize(FILE_TRACING_PREFIX "::" name, this, size)
+
+#define SCOPED_FILE_TRACE(name) SCOPED_FILE_TRACE_WITH_SIZE(name, 0)
+
+namespace base {
+
+class File;
+class FilePath;
+
+class BASE_EXPORT FileTracing {
+ public:
+  class Provider {
+   public:
+    // Whether the file tracing category is currently enabled.
+    virtual bool FileTracingCategoryIsEnabled() const = 0;
+
+    // Enables file tracing for |id|. Must be called before recording events.
+    virtual void FileTracingEnable(void* id) = 0;
+
+    // Disables file tracing for |id|.
+    virtual void FileTracingDisable(void* id) = 0;
+
+    // Begins an event for |id| with |name|. |path| tells where in the directory
+    // structure the event is happening (and may be blank). |size| is the number
+    // of bytes involved in the event.
+    virtual void FileTracingEventBegin(
+        const char* name, void* id, const FilePath& path, int64 size) = 0;
+
+    // Ends an event for |id| with |name|.
+    virtual void FileTracingEventEnd(const char* name, void* id) = 0;
+  };
+
+  // Sets a global file tracing provider to query categories and record events.
+  static void SetProvider(Provider* provider);
+
+  // Enables file tracing while in scope.
+  class ScopedEnabler {
+   public:
+    ScopedEnabler();
+    ~ScopedEnabler();
+  };
+
+  class ScopedTrace {
+   public:
+    ScopedTrace();
+    ~ScopedTrace();
+
+    // Whether this trace should be initialized or not.
+    bool ShouldInitialize() const;
+
+    // Called only if the tracing category is enabled. |name| is the name of the
+    // event to trace (e.g. "Read", "Write") and must have an application
+    // lifetime (e.g. static or literal). |file| is the file being traced; must
+    // outlive this class. |size| is the size (in bytes) of this event.
+    void Initialize(const char* name, File* file, int64 size);
+
+   private:
+    // The ID of this trace. Based on the |file| passed to |Initialize()|. Must
+    // outlive this class.
+    void* id_;
+
+    // The name of the event to trace (e.g. "Read", "Write"). Prefixed with
+    // "File".
+    const char* name_;
+
+    DISALLOW_COPY_AND_ASSIGN(ScopedTrace);
+  };
+
+  DISALLOW_COPY_AND_ASSIGN(FileTracing);
+};
+
+}  // namespace base
+
+#endif  // BASE_FILES_FILE_TRACING_H_
diff --git a/base/files/file_unittest.cc b/base/files/file_unittest.cc
new file mode 100644
index 0000000..5c59424
--- /dev/null
+++ b/base/files/file_unittest.cc
@@ -0,0 +1,580 @@
+// Copyright (c) 2012 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/files/file.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::File;
+using base::FilePath;
+
+TEST(FileTest, Create) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  FilePath file_path = temp_dir.path().AppendASCII("create_file_1");
+
+  {
+    // Don't create a File at all.
+    File file;
+    EXPECT_FALSE(file.IsValid());
+    EXPECT_EQ(base::File::FILE_ERROR_FAILED, file.error_details());
+
+    File file2(base::File::FILE_ERROR_TOO_MANY_OPENED);
+    EXPECT_FALSE(file2.IsValid());
+    EXPECT_EQ(base::File::FILE_ERROR_TOO_MANY_OPENED, file2.error_details());
+  }
+
+  {
+    // Open a file that doesn't exist.
+    File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
+    EXPECT_FALSE(file.IsValid());
+    EXPECT_EQ(base::File::FILE_ERROR_NOT_FOUND, file.error_details());
+  }
+
+  {
+    // Open or create a file.
+    File file(file_path, base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_READ);
+    EXPECT_TRUE(file.IsValid());
+    EXPECT_TRUE(file.created());
+    EXPECT_EQ(base::File::FILE_OK, file.error_details());
+  }
+
+  {
+    // Open an existing file.
+    File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
+    EXPECT_TRUE(file.IsValid());
+    EXPECT_FALSE(file.created());
+    EXPECT_EQ(base::File::FILE_OK, file.error_details());
+
+    // This time verify closing the file.
+    file.Close();
+    EXPECT_FALSE(file.IsValid());
+  }
+
+  {
+    // Open an existing file through Initialize
+    File file;
+    file.Initialize(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
+    EXPECT_TRUE(file.IsValid());
+    EXPECT_FALSE(file.created());
+    EXPECT_EQ(base::File::FILE_OK, file.error_details());
+
+    // This time verify closing the file.
+    file.Close();
+    EXPECT_FALSE(file.IsValid());
+  }
+
+  {
+    // Create a file that exists.
+    File file(file_path, base::File::FLAG_CREATE | base::File::FLAG_READ);
+    EXPECT_FALSE(file.IsValid());
+    EXPECT_FALSE(file.created());
+    EXPECT_EQ(base::File::FILE_ERROR_EXISTS, file.error_details());
+  }
+
+  {
+    // Create or overwrite a file.
+    File file(file_path,
+              base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
+    EXPECT_TRUE(file.IsValid());
+    EXPECT_TRUE(file.created());
+    EXPECT_EQ(base::File::FILE_OK, file.error_details());
+  }
+
+  {
+    // Create a delete-on-close file.
+    file_path = temp_dir.path().AppendASCII("create_file_2");
+    File file(file_path,
+              base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_READ |
+                  base::File::FLAG_DELETE_ON_CLOSE);
+    EXPECT_TRUE(file.IsValid());
+    EXPECT_TRUE(file.created());
+    EXPECT_EQ(base::File::FILE_OK, file.error_details());
+  }
+
+  EXPECT_FALSE(base::PathExists(file_path));
+}
+
+TEST(FileTest, Async) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  FilePath file_path = temp_dir.path().AppendASCII("create_file");
+
+  {
+    File file(file_path, base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_ASYNC);
+    EXPECT_TRUE(file.IsValid());
+    EXPECT_TRUE(file.async());
+  }
+
+  {
+    File file(file_path, base::File::FLAG_OPEN_ALWAYS);
+    EXPECT_TRUE(file.IsValid());
+    EXPECT_FALSE(file.async());
+  }
+}
+
+TEST(FileTest, DeleteOpenFile) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  FilePath file_path = temp_dir.path().AppendASCII("create_file_1");
+
+  // Create a file.
+  File file(file_path,
+            base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_READ |
+                base::File::FLAG_SHARE_DELETE);
+  EXPECT_TRUE(file.IsValid());
+  EXPECT_TRUE(file.created());
+  EXPECT_EQ(base::File::FILE_OK, file.error_details());
+
+  // Open an existing file and mark it as delete on close.
+  File same_file(file_path,
+                 base::File::FLAG_OPEN | base::File::FLAG_DELETE_ON_CLOSE |
+                     base::File::FLAG_READ);
+  EXPECT_TRUE(file.IsValid());
+  EXPECT_FALSE(same_file.created());
+  EXPECT_EQ(base::File::FILE_OK, same_file.error_details());
+
+  // Close both handles and check that the file is gone.
+  file.Close();
+  same_file.Close();
+  EXPECT_FALSE(base::PathExists(file_path));
+}
+
+TEST(FileTest, ReadWrite) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  FilePath file_path = temp_dir.path().AppendASCII("read_write_file");
+  File file(file_path,
+            base::File::FLAG_CREATE | base::File::FLAG_READ |
+                base::File::FLAG_WRITE);
+  ASSERT_TRUE(file.IsValid());
+
+  char data_to_write[] = "test";
+  const int kTestDataSize = 4;
+
+  // Write 0 bytes to the file.
+  int bytes_written = file.Write(0, data_to_write, 0);
+  EXPECT_EQ(0, bytes_written);
+
+  // Write "test" to the file.
+  bytes_written = file.Write(0, data_to_write, kTestDataSize);
+  EXPECT_EQ(kTestDataSize, bytes_written);
+
+  // Read from EOF.
+  char data_read_1[32];
+  int bytes_read = file.Read(kTestDataSize, data_read_1, kTestDataSize);
+  EXPECT_EQ(0, bytes_read);
+
+  // Read from somewhere in the middle of the file.
+  const int kPartialReadOffset = 1;
+  bytes_read = file.Read(kPartialReadOffset, data_read_1, kTestDataSize);
+  EXPECT_EQ(kTestDataSize - kPartialReadOffset, bytes_read);
+  for (int i = 0; i < bytes_read; i++)
+    EXPECT_EQ(data_to_write[i + kPartialReadOffset], data_read_1[i]);
+
+  // Read 0 bytes.
+  bytes_read = file.Read(0, data_read_1, 0);
+  EXPECT_EQ(0, bytes_read);
+
+  // Read the entire file.
+  bytes_read = file.Read(0, data_read_1, kTestDataSize);
+  EXPECT_EQ(kTestDataSize, bytes_read);
+  for (int i = 0; i < bytes_read; i++)
+    EXPECT_EQ(data_to_write[i], data_read_1[i]);
+
+  // Read again, but using the trivial native wrapper.
+  bytes_read = file.ReadNoBestEffort(0, data_read_1, kTestDataSize);
+  EXPECT_LE(bytes_read, kTestDataSize);
+  for (int i = 0; i < bytes_read; i++)
+    EXPECT_EQ(data_to_write[i], data_read_1[i]);
+
+  // Write past the end of the file.
+  const int kOffsetBeyondEndOfFile = 10;
+  const int kPartialWriteLength = 2;
+  bytes_written = file.Write(kOffsetBeyondEndOfFile,
+                             data_to_write, kPartialWriteLength);
+  EXPECT_EQ(kPartialWriteLength, bytes_written);
+
+  // Make sure the file was extended.
+  int64 file_size = 0;
+  EXPECT_TRUE(GetFileSize(file_path, &file_size));
+  EXPECT_EQ(kOffsetBeyondEndOfFile + kPartialWriteLength, file_size);
+
+  // Make sure the file was zero-padded.
+  char data_read_2[32];
+  bytes_read = file.Read(0, data_read_2, static_cast<int>(file_size));
+  EXPECT_EQ(file_size, bytes_read);
+  for (int i = 0; i < kTestDataSize; i++)
+    EXPECT_EQ(data_to_write[i], data_read_2[i]);
+  for (int i = kTestDataSize; i < kOffsetBeyondEndOfFile; i++)
+    EXPECT_EQ(0, data_read_2[i]);
+  for (int i = kOffsetBeyondEndOfFile; i < file_size; i++)
+    EXPECT_EQ(data_to_write[i - kOffsetBeyondEndOfFile], data_read_2[i]);
+}
+
+TEST(FileTest, Append) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  FilePath file_path = temp_dir.path().AppendASCII("append_file");
+  File file(file_path, base::File::FLAG_CREATE | base::File::FLAG_APPEND);
+  ASSERT_TRUE(file.IsValid());
+
+  char data_to_write[] = "test";
+  const int kTestDataSize = 4;
+
+  // Write 0 bytes to the file.
+  int bytes_written = file.Write(0, data_to_write, 0);
+  EXPECT_EQ(0, bytes_written);
+
+  // Write "test" to the file.
+  bytes_written = file.Write(0, data_to_write, kTestDataSize);
+  EXPECT_EQ(kTestDataSize, bytes_written);
+
+  file.Close();
+  File file2(file_path,
+             base::File::FLAG_OPEN | base::File::FLAG_READ |
+                 base::File::FLAG_APPEND);
+  ASSERT_TRUE(file2.IsValid());
+
+  // Test passing the file around.
+  file = file2.Pass();
+  EXPECT_FALSE(file2.IsValid());
+  ASSERT_TRUE(file.IsValid());
+
+  char append_data_to_write[] = "78";
+  const int kAppendDataSize = 2;
+
+  // Append "78" to the file.
+  bytes_written = file.Write(0, append_data_to_write, kAppendDataSize);
+  EXPECT_EQ(kAppendDataSize, bytes_written);
+
+  // Read the entire file.
+  char data_read_1[32];
+  int bytes_read = file.Read(0, data_read_1,
+                             kTestDataSize + kAppendDataSize);
+  EXPECT_EQ(kTestDataSize + kAppendDataSize, bytes_read);
+  for (int i = 0; i < kTestDataSize; i++)
+    EXPECT_EQ(data_to_write[i], data_read_1[i]);
+  for (int i = 0; i < kAppendDataSize; i++)
+    EXPECT_EQ(append_data_to_write[i], data_read_1[kTestDataSize + i]);
+}
+
+
+TEST(FileTest, Length) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  FilePath file_path = temp_dir.path().AppendASCII("truncate_file");
+  File file(file_path,
+            base::File::FLAG_CREATE | base::File::FLAG_READ |
+                base::File::FLAG_WRITE);
+  ASSERT_TRUE(file.IsValid());
+  EXPECT_EQ(0, file.GetLength());
+
+  // Write "test" to the file.
+  char data_to_write[] = "test";
+  int kTestDataSize = 4;
+  int bytes_written = file.Write(0, data_to_write, kTestDataSize);
+  EXPECT_EQ(kTestDataSize, bytes_written);
+
+  // Extend the file.
+  const int kExtendedFileLength = 10;
+  int64 file_size = 0;
+  EXPECT_TRUE(file.SetLength(kExtendedFileLength));
+  EXPECT_EQ(kExtendedFileLength, file.GetLength());
+  EXPECT_TRUE(GetFileSize(file_path, &file_size));
+  EXPECT_EQ(kExtendedFileLength, file_size);
+
+  // Make sure the file was zero-padded.
+  char data_read[32];
+  int bytes_read = file.Read(0, data_read, static_cast<int>(file_size));
+  EXPECT_EQ(file_size, bytes_read);
+  for (int i = 0; i < kTestDataSize; i++)
+    EXPECT_EQ(data_to_write[i], data_read[i]);
+  for (int i = kTestDataSize; i < file_size; i++)
+    EXPECT_EQ(0, data_read[i]);
+
+  // Truncate the file.
+  const int kTruncatedFileLength = 2;
+  EXPECT_TRUE(file.SetLength(kTruncatedFileLength));
+  EXPECT_EQ(kTruncatedFileLength, file.GetLength());
+  EXPECT_TRUE(GetFileSize(file_path, &file_size));
+  EXPECT_EQ(kTruncatedFileLength, file_size);
+
+  // Make sure the file was truncated.
+  bytes_read = file.Read(0, data_read, kTestDataSize);
+  EXPECT_EQ(file_size, bytes_read);
+  for (int i = 0; i < file_size; i++)
+    EXPECT_EQ(data_to_write[i], data_read[i]);
+}
+
+// Flakily fails: http://crbug.com/86494
+#if defined(OS_ANDROID)
+TEST(FileTest, TouchGetInfo) {
+#else
+TEST(FileTest, DISABLED_TouchGetInfo) {
+#endif
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  File file(temp_dir.path().AppendASCII("touch_get_info_file"),
+            base::File::FLAG_CREATE | base::File::FLAG_WRITE |
+                base::File::FLAG_WRITE_ATTRIBUTES);
+  ASSERT_TRUE(file.IsValid());
+
+  // Get info for a newly created file.
+  base::File::Info info;
+  EXPECT_TRUE(file.GetInfo(&info));
+
+  // Add 2 seconds to account for possible rounding errors on
+  // filesystems that use a 1s or 2s timestamp granularity.
+  base::Time now = base::Time::Now() + base::TimeDelta::FromSeconds(2);
+  EXPECT_EQ(0, info.size);
+  EXPECT_FALSE(info.is_directory);
+  EXPECT_FALSE(info.is_symbolic_link);
+  EXPECT_LE(info.last_accessed.ToInternalValue(), now.ToInternalValue());
+  EXPECT_LE(info.last_modified.ToInternalValue(), now.ToInternalValue());
+  EXPECT_LE(info.creation_time.ToInternalValue(), now.ToInternalValue());
+  base::Time creation_time = info.creation_time;
+
+  // Write "test" to the file.
+  char data[] = "test";
+  const int kTestDataSize = 4;
+  int bytes_written = file.Write(0, data, kTestDataSize);
+  EXPECT_EQ(kTestDataSize, bytes_written);
+
+  // Change the last_accessed and last_modified dates.
+  // It's best to add values that are multiples of 2 (in seconds)
+  // to the current last_accessed and last_modified times, because
+  // FATxx uses a 2s timestamp granularity.
+  base::Time new_last_accessed =
+      info.last_accessed + base::TimeDelta::FromSeconds(234);
+  base::Time new_last_modified =
+      info.last_modified + base::TimeDelta::FromMinutes(567);
+
+  EXPECT_TRUE(file.SetTimes(new_last_accessed, new_last_modified));
+
+  // Make sure the file info was updated accordingly.
+  EXPECT_TRUE(file.GetInfo(&info));
+  EXPECT_EQ(info.size, kTestDataSize);
+  EXPECT_FALSE(info.is_directory);
+  EXPECT_FALSE(info.is_symbolic_link);
+
+  // ext2/ext3 and HPS/HPS+ seem to have a timestamp granularity of 1s.
+#if defined(OS_POSIX)
+  EXPECT_EQ(info.last_accessed.ToTimeVal().tv_sec,
+            new_last_accessed.ToTimeVal().tv_sec);
+  EXPECT_EQ(info.last_modified.ToTimeVal().tv_sec,
+            new_last_modified.ToTimeVal().tv_sec);
+#else
+  EXPECT_EQ(info.last_accessed.ToInternalValue(),
+            new_last_accessed.ToInternalValue());
+  EXPECT_EQ(info.last_modified.ToInternalValue(),
+            new_last_modified.ToInternalValue());
+#endif
+
+  EXPECT_EQ(info.creation_time.ToInternalValue(),
+            creation_time.ToInternalValue());
+}
+
+TEST(FileTest, ReadAtCurrentPosition) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  FilePath file_path = temp_dir.path().AppendASCII("read_at_current_position");
+  File file(file_path,
+            base::File::FLAG_CREATE | base::File::FLAG_READ |
+                base::File::FLAG_WRITE);
+  EXPECT_TRUE(file.IsValid());
+
+  const char kData[] = "test";
+  const int kDataSize = sizeof(kData) - 1;
+  EXPECT_EQ(kDataSize, file.Write(0, kData, kDataSize));
+
+  EXPECT_EQ(0, file.Seek(base::File::FROM_BEGIN, 0));
+
+  char buffer[kDataSize];
+  int first_chunk_size = kDataSize / 2;
+  EXPECT_EQ(first_chunk_size, file.ReadAtCurrentPos(buffer, first_chunk_size));
+  EXPECT_EQ(kDataSize - first_chunk_size,
+            file.ReadAtCurrentPos(buffer + first_chunk_size,
+                                  kDataSize - first_chunk_size));
+  EXPECT_EQ(std::string(buffer, buffer + kDataSize), std::string(kData));
+}
+
+TEST(FileTest, WriteAtCurrentPosition) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  FilePath file_path = temp_dir.path().AppendASCII("write_at_current_position");
+  File file(file_path,
+            base::File::FLAG_CREATE | base::File::FLAG_READ |
+                base::File::FLAG_WRITE);
+  EXPECT_TRUE(file.IsValid());
+
+  const char kData[] = "test";
+  const int kDataSize = sizeof(kData) - 1;
+
+  int first_chunk_size = kDataSize / 2;
+  EXPECT_EQ(first_chunk_size, file.WriteAtCurrentPos(kData, first_chunk_size));
+  EXPECT_EQ(kDataSize - first_chunk_size,
+            file.WriteAtCurrentPos(kData + first_chunk_size,
+                                   kDataSize - first_chunk_size));
+
+  char buffer[kDataSize];
+  EXPECT_EQ(kDataSize, file.Read(0, buffer, kDataSize));
+  EXPECT_EQ(std::string(buffer, buffer + kDataSize), std::string(kData));
+}
+
+TEST(FileTest, Seek) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  FilePath file_path = temp_dir.path().AppendASCII("seek_file");
+  File file(file_path,
+            base::File::FLAG_CREATE | base::File::FLAG_READ |
+                base::File::FLAG_WRITE);
+  ASSERT_TRUE(file.IsValid());
+
+  const int64 kOffset = 10;
+  EXPECT_EQ(kOffset, file.Seek(base::File::FROM_BEGIN, kOffset));
+  EXPECT_EQ(2 * kOffset, file.Seek(base::File::FROM_CURRENT, kOffset));
+  EXPECT_EQ(kOffset, file.Seek(base::File::FROM_CURRENT, -kOffset));
+  EXPECT_TRUE(file.SetLength(kOffset * 2));
+  EXPECT_EQ(kOffset, file.Seek(base::File::FROM_END, -kOffset));
+}
+
+TEST(FileTest, Duplicate) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  FilePath file_path = temp_dir.path().AppendASCII("file");
+  File file(file_path,(base::File::FLAG_CREATE |
+                       base::File::FLAG_READ |
+                       base::File::FLAG_WRITE));
+  ASSERT_TRUE(file.IsValid());
+
+  File file2(file.Duplicate());
+  ASSERT_TRUE(file2.IsValid());
+
+  // Write through one handle, close it, read through the other.
+  static const char kData[] = "now is a good time.";
+  static const int kDataLen = sizeof(kData) - 1;
+
+  ASSERT_EQ(0, file.Seek(base::File::FROM_CURRENT, 0));
+  ASSERT_EQ(0, file2.Seek(base::File::FROM_CURRENT, 0));
+  ASSERT_EQ(kDataLen, file.WriteAtCurrentPos(kData, kDataLen));
+  ASSERT_EQ(kDataLen, file.Seek(base::File::FROM_CURRENT, 0));
+  ASSERT_EQ(kDataLen, file2.Seek(base::File::FROM_CURRENT, 0));
+  file.Close();
+  char buf[kDataLen];
+  ASSERT_EQ(kDataLen, file2.Read(0, &buf[0], kDataLen));
+  ASSERT_EQ(std::string(kData, kDataLen), std::string(&buf[0], kDataLen));
+}
+
+TEST(FileTest, DuplicateDeleteOnClose) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  FilePath file_path = temp_dir.path().AppendASCII("file");
+  File file(file_path,(base::File::FLAG_CREATE |
+                       base::File::FLAG_READ |
+                       base::File::FLAG_WRITE |
+                       base::File::FLAG_DELETE_ON_CLOSE));
+  ASSERT_TRUE(file.IsValid());
+  File file2(file.Duplicate());
+  ASSERT_TRUE(file2.IsValid());
+  file.Close();
+  file2.Close();
+  ASSERT_FALSE(base::PathExists(file_path));
+}
+
+#if defined(OS_WIN)
+TEST(FileTest, GetInfoForDirectory) {
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  FilePath empty_dir = temp_dir.path().Append(FILE_PATH_LITERAL("gpfi_test"));
+  ASSERT_TRUE(CreateDirectory(empty_dir));
+
+  base::File dir(
+      ::CreateFile(empty_dir.value().c_str(),
+                   FILE_ALL_ACCESS,
+                   FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                   NULL,
+                   OPEN_EXISTING,
+                   FILE_FLAG_BACKUP_SEMANTICS,  // Needed to open a directory.
+                   NULL));
+  ASSERT_TRUE(dir.IsValid());
+
+  base::File::Info info;
+  EXPECT_TRUE(dir.GetInfo(&info));
+  EXPECT_TRUE(info.is_directory);
+  EXPECT_FALSE(info.is_symbolic_link);
+  EXPECT_EQ(0, info.size);
+}
+#endif  // defined(OS_WIN)
+
+#if defined(OS_POSIX) && defined(GTEST_HAS_DEATH_TEST)
+TEST(FileTest, MemoryCorruption) {
+  {
+    // Test that changing the checksum value is detected.
+    base::File file;
+    EXPECT_NE(file.file_.file_memory_checksum_,
+              implicit_cast<unsigned int>(file.GetPlatformFile()));
+    file.file_.file_memory_checksum_ = file.GetPlatformFile();
+    EXPECT_DEATH(file.IsValid(), "");
+
+    file.file_.UpdateChecksum();  // Do not crash on File::~File().
+  }
+
+  {
+    // Test that changing the file descriptor value is detected.
+    base::File file;
+    file.file_.file_.reset(17);
+    EXPECT_DEATH(file.IsValid(), "");
+
+    // Do not crash on File::~File().
+    ignore_result(file.file_.file_.release());
+    file.file_.UpdateChecksum();
+  }
+
+  {
+    // Test that GetPlatformFile() checks for corruption.
+    base::File file;
+    file.file_.file_memory_checksum_ = file.GetPlatformFile();
+    EXPECT_DEATH(file.GetPlatformFile(), "");
+
+    file.file_.UpdateChecksum();  // Do not crash on File::~File().
+  }
+
+  {
+    // Test that the base::File destructor checks for corruption.
+    scoped_ptr<base::File> file(new File());
+    file->file_.file_memory_checksum_ = file->GetPlatformFile();
+    EXPECT_DEATH(file.reset(), "");
+
+    // Do not crash on this thread's destructor call.
+    file->file_.UpdateChecksum();
+  }
+
+  {
+    // Test that the base::File constructor checks for corruption.
+    base::File file;
+    file.file_.file_memory_checksum_ = file.GetPlatformFile();
+    EXPECT_DEATH(File f(file.Pass()), "");
+
+    file.file_.UpdateChecksum();  // Do not crash on File::~File().
+  }
+
+  {
+    // Test that doing IO checks for corruption.
+    base::File file;
+    file.file_.file_.reset(17);  // A fake open FD value.
+
+    EXPECT_DEATH(file.Seek(File::FROM_BEGIN, 0), "");
+    EXPECT_DEATH(file.Read(0, NULL, 0), "");
+    EXPECT_DEATH(file.ReadAtCurrentPos(NULL, 0), "");
+    EXPECT_DEATH(file.Write(0, NULL, 0), "");
+
+    ignore_result(file.file_.file_.release());
+    file.file_.UpdateChecksum();
+  }
+}
+#endif  // defined(OS_POSIX)
diff --git a/base/files/file_util.cc b/base/files/file_util.cc
new file mode 100644
index 0000000..4b6b888
--- /dev/null
+++ b/base/files/file_util.cc
@@ -0,0 +1,261 @@
+// Copyright (c) 2012 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/files/file_util.h"
+
+#if defined(OS_WIN)
+#include <io.h>
+#endif
+#include <stdio.h>
+
+#include <fstream>
+#include <limits>
+
+#include "base/files/file_enumerator.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+
+namespace base {
+
+#if !defined(OS_NACL_NONSFI)
+namespace {
+
+// The maximum number of 'uniquified' files we will try to create.
+// This is used when the filename we're trying to download is already in use,
+// so we create a new unique filename by appending " (nnn)" before the
+// extension, where 1 <= nnn <= kMaxUniqueFiles.
+// Also used by code that cleans up said files.
+static const int kMaxUniqueFiles = 100;
+
+}  // namespace
+
+int64 ComputeDirectorySize(const FilePath& root_path) {
+  int64 running_size = 0;
+  FileEnumerator file_iter(root_path, true, FileEnumerator::FILES);
+  while (!file_iter.Next().empty())
+    running_size += file_iter.GetInfo().GetSize();
+  return running_size;
+}
+
+bool Move(const FilePath& from_path, const FilePath& to_path) {
+  if (from_path.ReferencesParent() || to_path.ReferencesParent())
+    return false;
+  return internal::MoveUnsafe(from_path, to_path);
+}
+
+bool ContentsEqual(const FilePath& filename1, const FilePath& filename2) {
+  // We open the file in binary format even if they are text files because
+  // we are just comparing that bytes are exactly same in both files and not
+  // doing anything smart with text formatting.
+  std::ifstream file1(filename1.value().c_str(),
+                      std::ios::in | std::ios::binary);
+  std::ifstream file2(filename2.value().c_str(),
+                      std::ios::in | std::ios::binary);
+
+  // Even if both files aren't openable (and thus, in some sense, "equal"),
+  // any unusable file yields a result of "false".
+  if (!file1.is_open() || !file2.is_open())
+    return false;
+
+  const int BUFFER_SIZE = 2056;
+  char buffer1[BUFFER_SIZE], buffer2[BUFFER_SIZE];
+  do {
+    file1.read(buffer1, BUFFER_SIZE);
+    file2.read(buffer2, BUFFER_SIZE);
+
+    if ((file1.eof() != file2.eof()) ||
+        (file1.gcount() != file2.gcount()) ||
+        (memcmp(buffer1, buffer2, static_cast<size_t>(file1.gcount())))) {
+      file1.close();
+      file2.close();
+      return false;
+    }
+  } while (!file1.eof() || !file2.eof());
+
+  file1.close();
+  file2.close();
+  return true;
+}
+
+bool TextContentsEqual(const FilePath& filename1, const FilePath& filename2) {
+  std::ifstream file1(filename1.value().c_str(), std::ios::in);
+  std::ifstream file2(filename2.value().c_str(), std::ios::in);
+
+  // Even if both files aren't openable (and thus, in some sense, "equal"),
+  // any unusable file yields a result of "false".
+  if (!file1.is_open() || !file2.is_open())
+    return false;
+
+  do {
+    std::string line1, line2;
+    getline(file1, line1);
+    getline(file2, line2);
+
+    // Check for mismatched EOF states, or any error state.
+    if ((file1.eof() != file2.eof()) ||
+        file1.bad() || file2.bad()) {
+      return false;
+    }
+
+    // Trim all '\r' and '\n' characters from the end of the line.
+    std::string::size_type end1 = line1.find_last_not_of("\r\n");
+    if (end1 == std::string::npos)
+      line1.clear();
+    else if (end1 + 1 < line1.length())
+      line1.erase(end1 + 1);
+
+    std::string::size_type end2 = line2.find_last_not_of("\r\n");
+    if (end2 == std::string::npos)
+      line2.clear();
+    else if (end2 + 1 < line2.length())
+      line2.erase(end2 + 1);
+
+    if (line1 != line2)
+      return false;
+  } while (!file1.eof() || !file2.eof());
+
+  return true;
+}
+#endif  // !defined(OS_NACL_NONSFI)
+
+bool ReadFileToString(const FilePath& path,
+                      std::string* contents,
+                      size_t max_size) {
+  if (contents)
+    contents->clear();
+  if (path.ReferencesParent())
+    return false;
+  FILE* file = OpenFile(path, "rb");
+  if (!file) {
+    return false;
+  }
+
+  const size_t kBufferSize = 1 << 16;
+  scoped_ptr<char[]> buf(new char[kBufferSize]);
+  size_t len;
+  size_t size = 0;
+  bool read_status = true;
+
+  // Many files supplied in |path| have incorrect size (proc files etc).
+  // Hence, the file is read sequentially as opposed to a one-shot read.
+  while ((len = fread(buf.get(), 1, kBufferSize, file)) > 0) {
+    if (contents)
+      contents->append(buf.get(), std::min(len, max_size - size));
+
+    if ((max_size - size) < len) {
+      read_status = false;
+      break;
+    }
+
+    size += len;
+  }
+  read_status = read_status && !ferror(file);
+  CloseFile(file);
+
+  return read_status;
+}
+
+bool ReadFileToString(const FilePath& path, std::string* contents) {
+  return ReadFileToString(path, contents, std::numeric_limits<size_t>::max());
+}
+
+#if !defined(OS_NACL_NONSFI)
+bool IsDirectoryEmpty(const FilePath& dir_path) {
+  FileEnumerator files(dir_path, false,
+      FileEnumerator::FILES | FileEnumerator::DIRECTORIES);
+  if (files.Next().empty())
+    return true;
+  return false;
+}
+
+FILE* CreateAndOpenTemporaryFile(FilePath* path) {
+  FilePath directory;
+  if (!GetTempDir(&directory))
+    return NULL;
+
+  return CreateAndOpenTemporaryFileInDir(directory, path);
+}
+
+bool CreateDirectory(const FilePath& full_path) {
+  return CreateDirectoryAndGetError(full_path, NULL);
+}
+
+bool GetFileSize(const FilePath& file_path, int64* file_size) {
+  File::Info info;
+  if (!GetFileInfo(file_path, &info))
+    return false;
+  *file_size = info.size;
+  return true;
+}
+
+bool TouchFile(const FilePath& path,
+               const Time& last_accessed,
+               const Time& last_modified) {
+  int flags = File::FLAG_OPEN | File::FLAG_WRITE_ATTRIBUTES;
+
+#if defined(OS_WIN)
+  // On Windows, FILE_FLAG_BACKUP_SEMANTICS is needed to open a directory.
+  if (DirectoryExists(path))
+    flags |= File::FLAG_BACKUP_SEMANTICS;
+#endif  // OS_WIN
+
+  File file(path, flags);
+  if (!file.IsValid())
+    return false;
+
+  return file.SetTimes(last_accessed, last_modified);
+}
+#endif  // !defined(OS_NACL_NONSFI)
+
+bool CloseFile(FILE* file) {
+  if (file == NULL)
+    return true;
+  return fclose(file) == 0;
+}
+
+#if !defined(OS_NACL_NONSFI)
+bool TruncateFile(FILE* file) {
+  if (file == NULL)
+    return false;
+  long current_offset = ftell(file);
+  if (current_offset == -1)
+    return false;
+#if defined(OS_WIN)
+  int fd = _fileno(file);
+  if (_chsize(fd, current_offset) != 0)
+    return false;
+#else
+  int fd = fileno(file);
+  if (ftruncate(fd, current_offset) != 0)
+    return false;
+#endif
+  return true;
+}
+
+int GetUniquePathNumber(const FilePath& path,
+                        const FilePath::StringType& suffix) {
+  bool have_suffix = !suffix.empty();
+  if (!PathExists(path) &&
+      (!have_suffix || !PathExists(FilePath(path.value() + suffix)))) {
+    return 0;
+  }
+
+  FilePath new_path;
+  for (int count = 1; count <= kMaxUniqueFiles; ++count) {
+    new_path = path.InsertBeforeExtensionASCII(StringPrintf(" (%d)", count));
+    if (!PathExists(new_path) &&
+        (!have_suffix || !PathExists(FilePath(new_path.value() + suffix)))) {
+      return count;
+    }
+  }
+
+  return -1;
+}
+#endif  // !defined(OS_NACL_NONSFI)
+
+}  // namespace base
diff --git a/base/files/file_util.h b/base/files/file_util.h
new file mode 100644
index 0000000..7f169f1
--- /dev/null
+++ b/base/files/file_util.h
@@ -0,0 +1,436 @@
+// Copyright (c) 2012 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 contains utility functions for dealing with the local
+// filesystem.
+
+#ifndef BASE_FILES_FILE_UTIL_H_
+#define BASE_FILES_FILE_UTIL_H_
+
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#elif defined(OS_POSIX)
+#include <sys/stat.h>
+#include <unistd.h>
+#endif
+
+#include <stdio.h>
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string16.h"
+
+#if defined(OS_POSIX)
+#include "base/file_descriptor_posix.h"
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#endif
+
+namespace base {
+
+class Time;
+
+//-----------------------------------------------------------------------------
+// Functions that involve filesystem access or modification:
+
+// Returns an absolute version of a relative path. Returns an empty path on
+// error. On POSIX, this function fails if the path does not exist. This
+// function can result in I/O so it can be slow.
+BASE_EXPORT FilePath MakeAbsoluteFilePath(const FilePath& input);
+
+// Returns the total number of bytes used by all the files under |root_path|.
+// If the path does not exist the function returns 0.
+//
+// This function is implemented using the FileEnumerator class so it is not
+// particularly speedy in any platform.
+BASE_EXPORT int64 ComputeDirectorySize(const FilePath& root_path);
+
+// Deletes the given path, whether it's a file or a directory.
+// If it's a directory, it's perfectly happy to delete all of the
+// directory's contents.  Passing true to recursive deletes
+// subdirectories and their contents as well.
+// Returns true if successful, false otherwise. It is considered successful
+// to attempt to delete a file that does not exist.
+//
+// In posix environment and if |path| is a symbolic link, this deletes only
+// the symlink. (even if the symlink points to a non-existent file)
+//
+// WARNING: USING THIS WITH recursive==true IS EQUIVALENT
+//          TO "rm -rf", SO USE WITH CAUTION.
+BASE_EXPORT bool DeleteFile(const FilePath& path, bool recursive);
+
+#if defined(OS_WIN)
+// Schedules to delete the given path, whether it's a file or a directory, until
+// the operating system is restarted.
+// Note:
+// 1) The file/directory to be deleted should exist in a temp folder.
+// 2) The directory to be deleted must be empty.
+BASE_EXPORT bool DeleteFileAfterReboot(const FilePath& path);
+#endif
+
+// Moves the given path, whether it's a file or a directory.
+// If a simple rename is not possible, such as in the case where the paths are
+// on different volumes, this will attempt to copy and delete. Returns
+// true for success.
+// This function fails if either path contains traversal components ('..').
+BASE_EXPORT bool Move(const FilePath& from_path, const FilePath& to_path);
+
+// Renames file |from_path| to |to_path|. Both paths must be on the same
+// volume, or the function will fail. Destination file will be created
+// if it doesn't exist. Prefer this function over Move when dealing with
+// temporary files. On Windows it preserves attributes of the target file.
+// Returns true on success, leaving *error unchanged.
+// Returns false on failure and sets *error appropriately, if it is non-NULL.
+BASE_EXPORT bool ReplaceFile(const FilePath& from_path,
+                             const FilePath& to_path,
+                             File::Error* error);
+
+// Copies a single file. Use CopyDirectory to copy directories.
+// This function fails if either path contains traversal components ('..').
+//
+// This function keeps the metadata on Windows. The read only bit on Windows is
+// not kept.
+BASE_EXPORT bool CopyFile(const FilePath& from_path, const FilePath& to_path);
+
+// Copies the given path, and optionally all subdirectories and their contents
+// as well.
+//
+// If there are files existing under to_path, always overwrite. Returns true
+// if successful, false otherwise. Wildcards on the names are not supported.
+//
+// This function calls into CopyFile() so the same behavior w.r.t. metadata
+// applies.
+//
+// If you only need to copy a file use CopyFile, it's faster.
+BASE_EXPORT bool CopyDirectory(const FilePath& from_path,
+                               const FilePath& to_path,
+                               bool recursive);
+
+// Returns true if the given path exists on the local filesystem,
+// false otherwise.
+BASE_EXPORT bool PathExists(const FilePath& path);
+
+// Returns true if the given path is writable by the user, false otherwise.
+BASE_EXPORT bool PathIsWritable(const FilePath& path);
+
+// Returns true if the given path exists and is a directory, false otherwise.
+BASE_EXPORT bool DirectoryExists(const FilePath& path);
+
+// Returns true if the contents of the two files given are equal, false
+// otherwise.  If either file can't be read, returns false.
+BASE_EXPORT bool ContentsEqual(const FilePath& filename1,
+                               const FilePath& filename2);
+
+// Returns true if the contents of the two text files given are equal, false
+// otherwise.  This routine treats "\r\n" and "\n" as equivalent.
+BASE_EXPORT bool TextContentsEqual(const FilePath& filename1,
+                                   const FilePath& filename2);
+
+// Reads the file at |path| into |contents| and returns true on success and
+// false on error.  For security reasons, a |path| containing path traversal
+// components ('..') is treated as a read error and |contents| is set to empty.
+// In case of I/O error, |contents| holds the data that could be read from the
+// file before the error occurred.
+// |contents| may be NULL, in which case this function is useful for its side
+// effect of priming the disk cache (could be used for unit tests).
+BASE_EXPORT bool ReadFileToString(const FilePath& path, std::string* contents);
+
+// Reads the file at |path| into |contents| and returns true on success and
+// false on error.  For security reasons, a |path| containing path traversal
+// components ('..') is treated as a read error and |contents| is set to empty.
+// In case of I/O error, |contents| holds the data that could be read from the
+// file before the error occurred.  When the file size exceeds |max_size|, the
+// function returns false with |contents| holding the file truncated to
+// |max_size|.
+// |contents| may be NULL, in which case this function is useful for its side
+// effect of priming the disk cache (could be used for unit tests).
+BASE_EXPORT bool ReadFileToString(const FilePath& path,
+                                  std::string* contents,
+                                  size_t max_size);
+
+#if defined(OS_POSIX)
+
+// Read exactly |bytes| bytes from file descriptor |fd|, storing the result
+// in |buffer|. This function is protected against EINTR and partial reads.
+// Returns true iff |bytes| bytes have been successfully read from |fd|.
+BASE_EXPORT bool ReadFromFD(int fd, char* buffer, size_t bytes);
+
+// Creates a symbolic link at |symlink| pointing to |target|.  Returns
+// false on failure.
+BASE_EXPORT bool CreateSymbolicLink(const FilePath& target,
+                                    const FilePath& symlink);
+
+// Reads the given |symlink| and returns where it points to in |target|.
+// Returns false upon failure.
+BASE_EXPORT bool ReadSymbolicLink(const FilePath& symlink, FilePath* target);
+
+// Bits and masks of the file permission.
+enum FilePermissionBits {
+  FILE_PERMISSION_MASK              = S_IRWXU | S_IRWXG | S_IRWXO,
+  FILE_PERMISSION_USER_MASK         = S_IRWXU,
+  FILE_PERMISSION_GROUP_MASK        = S_IRWXG,
+  FILE_PERMISSION_OTHERS_MASK       = S_IRWXO,
+
+  FILE_PERMISSION_READ_BY_USER      = S_IRUSR,
+  FILE_PERMISSION_WRITE_BY_USER     = S_IWUSR,
+  FILE_PERMISSION_EXECUTE_BY_USER   = S_IXUSR,
+  FILE_PERMISSION_READ_BY_GROUP     = S_IRGRP,
+  FILE_PERMISSION_WRITE_BY_GROUP    = S_IWGRP,
+  FILE_PERMISSION_EXECUTE_BY_GROUP  = S_IXGRP,
+  FILE_PERMISSION_READ_BY_OTHERS    = S_IROTH,
+  FILE_PERMISSION_WRITE_BY_OTHERS   = S_IWOTH,
+  FILE_PERMISSION_EXECUTE_BY_OTHERS = S_IXOTH,
+};
+
+// Reads the permission of the given |path|, storing the file permission
+// bits in |mode|. If |path| is symbolic link, |mode| is the permission of
+// a file which the symlink points to.
+BASE_EXPORT bool GetPosixFilePermissions(const FilePath& path, int* mode);
+// Sets the permission of the given |path|. If |path| is symbolic link, sets
+// the permission of a file which the symlink points to.
+BASE_EXPORT bool SetPosixFilePermissions(const FilePath& path, int mode);
+
+#endif  // OS_POSIX
+
+// Returns true if the given directory is empty
+BASE_EXPORT bool IsDirectoryEmpty(const FilePath& dir_path);
+
+// Get the temporary directory provided by the system.
+//
+// WARNING: In general, you should use CreateTemporaryFile variants below
+// instead of this function. Those variants will ensure that the proper
+// permissions are set so that other users on the system can't edit them while
+// they're open (which can lead to security issues).
+BASE_EXPORT bool GetTempDir(FilePath* path);
+
+// Get the home directory. This is more complicated than just getenv("HOME")
+// as it knows to fall back on getpwent() etc.
+//
+// You should not generally call this directly. Instead use DIR_HOME with the
+// path service which will use this function but cache the value.
+// Path service may also override DIR_HOME.
+BASE_EXPORT FilePath GetHomeDir();
+
+// Creates a temporary file. The full path is placed in |path|, and the
+// function returns true if was successful in creating the file. The file will
+// be empty and all handles closed after this function returns.
+BASE_EXPORT bool CreateTemporaryFile(FilePath* path);
+
+// Same as CreateTemporaryFile but the file is created in |dir|.
+BASE_EXPORT bool CreateTemporaryFileInDir(const FilePath& dir,
+                                          FilePath* temp_file);
+
+// Create and open a temporary file.  File is opened for read/write.
+// The full path is placed in |path|.
+// Returns a handle to the opened file or NULL if an error occurred.
+BASE_EXPORT FILE* CreateAndOpenTemporaryFile(FilePath* path);
+
+// Similar to CreateAndOpenTemporaryFile, but the file is created in |dir|.
+BASE_EXPORT FILE* CreateAndOpenTemporaryFileInDir(const FilePath& dir,
+                                                  FilePath* path);
+
+// Create a new directory. If prefix is provided, the new directory name is in
+// the format of prefixyyyy.
+// NOTE: prefix is ignored in the POSIX implementation.
+// If success, return true and output the full path of the directory created.
+BASE_EXPORT bool CreateNewTempDirectory(const FilePath::StringType& prefix,
+                                        FilePath* new_temp_path);
+
+// Create a directory within another directory.
+// Extra characters will be appended to |prefix| to ensure that the
+// new directory does not have the same name as an existing directory.
+BASE_EXPORT bool CreateTemporaryDirInDir(const FilePath& base_dir,
+                                         const FilePath::StringType& prefix,
+                                         FilePath* new_dir);
+
+// Creates a directory, as well as creating any parent directories, if they
+// don't exist. Returns 'true' on successful creation, or if the directory
+// already exists.  The directory is only readable by the current user.
+// Returns true on success, leaving *error unchanged.
+// Returns false on failure and sets *error appropriately, if it is non-NULL.
+BASE_EXPORT bool CreateDirectoryAndGetError(const FilePath& full_path,
+                                            File::Error* error);
+
+// Backward-compatible convenience method for the above.
+BASE_EXPORT bool CreateDirectory(const FilePath& full_path);
+
+// Returns the file size. Returns true on success.
+BASE_EXPORT bool GetFileSize(const FilePath& file_path, int64* file_size);
+
+// Sets |real_path| to |path| with symbolic links and junctions expanded.
+// On windows, make sure the path starts with a lettered drive.
+// |path| must reference a file.  Function will fail if |path| points to
+// a directory or to a nonexistent path.  On windows, this function will
+// fail if |path| is a junction or symlink that points to an empty file,
+// or if |real_path| would be longer than MAX_PATH characters.
+BASE_EXPORT bool NormalizeFilePath(const FilePath& path, FilePath* real_path);
+
+#if defined(OS_WIN)
+
+// Given a path in NT native form ("\Device\HarddiskVolumeXX\..."),
+// return in |drive_letter_path| the equivalent path that starts with
+// a drive letter ("C:\...").  Return false if no such path exists.
+BASE_EXPORT bool DevicePathToDriveLetterPath(const FilePath& device_path,
+                                             FilePath* drive_letter_path);
+
+// Given an existing file in |path|, set |real_path| to the path
+// in native NT format, of the form "\Device\HarddiskVolumeXX\..".
+// Returns false if the path can not be found. Empty files cannot
+// be resolved with this function.
+BASE_EXPORT bool NormalizeToNativeFilePath(const FilePath& path,
+                                           FilePath* nt_path);
+#endif
+
+// This function will return if the given file is a symlink or not.
+BASE_EXPORT bool IsLink(const FilePath& file_path);
+
+// Returns information about the given file path.
+BASE_EXPORT bool GetFileInfo(const FilePath& file_path, File::Info* info);
+
+// Sets the time of the last access and the time of the last modification.
+BASE_EXPORT bool TouchFile(const FilePath& path,
+                           const Time& last_accessed,
+                           const Time& last_modified);
+
+// Wrapper for fopen-like calls. Returns non-NULL FILE* on success.
+BASE_EXPORT FILE* OpenFile(const FilePath& filename, const char* mode);
+
+// Closes file opened by OpenFile. Returns true on success.
+BASE_EXPORT bool CloseFile(FILE* file);
+
+// Associates a standard FILE stream with an existing File. Note that this
+// functions take ownership of the existing File.
+BASE_EXPORT FILE* FileToFILE(File file, const char* mode);
+
+// Truncates an open file to end at the location of the current file pointer.
+// This is a cross-platform analog to Windows' SetEndOfFile() function.
+BASE_EXPORT bool TruncateFile(FILE* file);
+
+// Reads at most the given number of bytes from the file into the buffer.
+// Returns the number of read bytes, or -1 on error.
+BASE_EXPORT int ReadFile(const FilePath& filename, char* data, int max_size);
+
+// Writes the given buffer into the file, overwriting any data that was
+// previously there.  Returns the number of bytes written, or -1 on error.
+BASE_EXPORT int WriteFile(const FilePath& filename, const char* data,
+                          int size);
+
+#if defined(OS_POSIX)
+// Appends |data| to |fd|. Does not close |fd| when done.  Returns true iff
+// |size| bytes of |data| were written to |fd|.
+BASE_EXPORT bool WriteFileDescriptor(const int fd, const char* data, int size);
+#endif
+
+// Appends |data| to |filename|.  Returns true iff |size| bytes of |data| were
+// written to |filename|.
+BASE_EXPORT bool AppendToFile(const FilePath& filename,
+                              const char* data,
+                              int size);
+
+// Gets the current working directory for the process.
+BASE_EXPORT bool GetCurrentDirectory(FilePath* path);
+
+// Sets the current working directory for the process.
+BASE_EXPORT bool SetCurrentDirectory(const FilePath& path);
+
+// Attempts to find a number that can be appended to the |path| to make it
+// unique. If |path| does not exist, 0 is returned.  If it fails to find such
+// a number, -1 is returned. If |suffix| is not empty, also checks the
+// existence of it with the given suffix.
+BASE_EXPORT int GetUniquePathNumber(const FilePath& path,
+                                    const FilePath::StringType& suffix);
+
+#if defined(OS_POSIX)
+// Test that |path| can only be changed by a given user and members of
+// a given set of groups.
+// Specifically, test that all parts of |path| under (and including) |base|:
+// * Exist.
+// * Are owned by a specific user.
+// * Are not writable by all users.
+// * Are owned by a member of a given set of groups, or are not writable by
+//   their group.
+// * Are not symbolic links.
+// This is useful for checking that a config file is administrator-controlled.
+// |base| must contain |path|.
+BASE_EXPORT bool VerifyPathControlledByUser(const base::FilePath& base,
+                                            const base::FilePath& path,
+                                            uid_t owner_uid,
+                                            const std::set<gid_t>& group_gids);
+#endif  // defined(OS_POSIX)
+
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+// Is |path| writable only by a user with administrator privileges?
+// This function uses Mac OS conventions.  The super user is assumed to have
+// uid 0, and the administrator group is assumed to be named "admin".
+// Testing that |path|, and every parent directory including the root of
+// the filesystem, are owned by the superuser, controlled by the group
+// "admin", are not writable by all users, and contain no symbolic links.
+// Will return false if |path| does not exist.
+BASE_EXPORT bool VerifyPathControlledByAdmin(const base::FilePath& path);
+#endif  // defined(OS_MACOSX) && !defined(OS_IOS)
+
+// Returns the maximum length of path component on the volume containing
+// the directory |path|, in the number of FilePath::CharType, or -1 on failure.
+BASE_EXPORT int GetMaximumPathComponentLength(const base::FilePath& path);
+
+#if defined(OS_LINUX)
+// Broad categories of file systems as returned by statfs() on Linux.
+enum FileSystemType {
+  FILE_SYSTEM_UNKNOWN,  // statfs failed.
+  FILE_SYSTEM_0,        // statfs.f_type == 0 means unknown, may indicate AFS.
+  FILE_SYSTEM_ORDINARY,       // on-disk filesystem like ext2
+  FILE_SYSTEM_NFS,
+  FILE_SYSTEM_SMB,
+  FILE_SYSTEM_CODA,
+  FILE_SYSTEM_MEMORY,         // in-memory file system
+  FILE_SYSTEM_CGROUP,         // cgroup control.
+  FILE_SYSTEM_OTHER,          // any other value.
+  FILE_SYSTEM_TYPE_COUNT
+};
+
+// Attempts determine the FileSystemType for |path|.
+// Returns false if |path| doesn't exist.
+BASE_EXPORT bool GetFileSystemType(const FilePath& path, FileSystemType* type);
+#endif
+
+#if defined(OS_POSIX)
+// Get a temporary directory for shared memory files. The directory may depend
+// on whether the destination is intended for executable files, which in turn
+// depends on how /dev/shmem was mounted. As a result, you must supply whether
+// you intend to create executable shmem segments so this function can find
+// an appropriate location.
+BASE_EXPORT bool GetShmemTempDir(bool executable, FilePath* path);
+#endif
+
+// Internal --------------------------------------------------------------------
+
+namespace internal {
+
+// Same as Move but allows paths with traversal components.
+// Use only with extreme care.
+BASE_EXPORT bool MoveUnsafe(const FilePath& from_path,
+                            const FilePath& to_path);
+
+#if defined(OS_WIN)
+// Copy from_path to to_path recursively and then delete from_path recursively.
+// Returns true if all operations succeed.
+// This function simulates Move(), but unlike Move() it works across volumes.
+// This function is not transactional.
+BASE_EXPORT bool CopyAndDeleteDirectory(const FilePath& from_path,
+                                        const FilePath& to_path);
+#endif  // defined(OS_WIN)
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_FILES_FILE_UTIL_H_
diff --git a/base/files/file_util_android.cc b/base/files/file_util_android.cc
new file mode 100644
index 0000000..b8b3b37
--- /dev/null
+++ b/base/files/file_util_android.cc
@@ -0,0 +1,16 @@
+// Copyright (c) 2012 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/files/file_util.h"
+
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+
+namespace base {
+
+bool GetShmemTempDir(bool executable, base::FilePath* path) {
+  return PathService::Get(base::DIR_CACHE, path);
+}
+
+}  // namespace base
diff --git a/base/files/file_util_linux.cc b/base/files/file_util_linux.cc
new file mode 100644
index 0000000..b230fd9
--- /dev/null
+++ b/base/files/file_util_linux.cc
@@ -0,0 +1,63 @@
+// Copyright (c) 2011 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/files/file_util.h"
+
+#include <errno.h>
+#include <linux/magic.h>
+#include <sys/vfs.h>
+
+#include "base/files/file_path.h"
+
+namespace base {
+
+bool GetFileSystemType(const FilePath& path, FileSystemType* type) {
+  struct statfs statfs_buf;
+  if (statfs(path.value().c_str(), &statfs_buf) < 0) {
+    if (errno == ENOENT)
+      return false;
+    *type = FILE_SYSTEM_UNKNOWN;
+    return true;
+  }
+
+  // Not all possible |statfs_buf.f_type| values are in linux/magic.h.
+  // Missing values are copied from the statfs man page.
+  switch (statfs_buf.f_type) {
+    case 0:
+      *type = FILE_SYSTEM_0;
+      break;
+    case EXT2_SUPER_MAGIC:  // Also ext3 and ext4
+    case MSDOS_SUPER_MAGIC:
+    case REISERFS_SUPER_MAGIC:
+    case BTRFS_SUPER_MAGIC:
+    case 0x5346544E:  // NTFS
+    case 0x58465342:  // XFS
+    case 0x3153464A:  // JFS
+      *type = FILE_SYSTEM_ORDINARY;
+      break;
+    case NFS_SUPER_MAGIC:
+      *type = FILE_SYSTEM_NFS;
+      break;
+    case SMB_SUPER_MAGIC:
+    case 0xFF534D42:  // CIFS
+      *type = FILE_SYSTEM_SMB;
+      break;
+    case CODA_SUPER_MAGIC:
+      *type = FILE_SYSTEM_CODA;
+      break;
+    case HUGETLBFS_MAGIC:
+    case RAMFS_MAGIC:
+    case TMPFS_MAGIC:
+      *type = FILE_SYSTEM_MEMORY;
+      break;
+    case CGROUP_SUPER_MAGIC:
+      *type = FILE_SYSTEM_CGROUP;
+      break;
+    default:
+      *type = FILE_SYSTEM_OTHER;
+  }
+  return true;
+}
+
+}  // namespace base
diff --git a/base/files/file_util_mac.mm b/base/files/file_util_mac.mm
new file mode 100644
index 0000000..a701bad
--- /dev/null
+++ b/base/files/file_util_mac.mm
@@ -0,0 +1,51 @@
+// Copyright (c) 2012 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/files/file_util.h"
+
+#include <copyfile.h>
+#import <Foundation/Foundation.h>
+
+#include "base/basictypes.h"
+#include "base/files/file_path.h"
+#include "base/mac/foundation_util.h"
+#include "base/strings/string_util.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace base {
+
+bool CopyFile(const FilePath& from_path, const FilePath& to_path) {
+  ThreadRestrictions::AssertIOAllowed();
+  if (from_path.ReferencesParent() || to_path.ReferencesParent())
+    return false;
+  return (copyfile(from_path.value().c_str(),
+                   to_path.value().c_str(), NULL, COPYFILE_DATA) == 0);
+}
+
+bool GetTempDir(base::FilePath* path) {
+  NSString* tmp = NSTemporaryDirectory();
+  if (tmp == nil)
+    return false;
+  *path = base::mac::NSStringToFilePath(tmp);
+  return true;
+}
+
+FilePath GetHomeDir() {
+  NSString* tmp = NSHomeDirectory();
+  if (tmp != nil) {
+    FilePath mac_home_dir = base::mac::NSStringToFilePath(tmp);
+    if (!mac_home_dir.empty())
+      return mac_home_dir;
+  }
+
+  // Fall back on temp dir if no home directory is defined.
+  FilePath rv;
+  if (GetTempDir(&rv))
+    return rv;
+
+  // Last resort.
+  return FilePath("/tmp");
+}
+
+}  // namespace base
diff --git a/base/files/file_util_posix.cc b/base/files/file_util_posix.cc
new file mode 100644
index 0000000..a8c5d44
--- /dev/null
+++ b/base/files/file_util_posix.cc
@@ -0,0 +1,935 @@
+// Copyright (c) 2012 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/files/file_util.h"
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/errno.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#if defined(OS_MACOSX)
+#include <AvailabilityMacros.h>
+#include "base/mac/foundation_util.h"
+#elif !defined(OS_CHROMEOS) && defined(USE_GLIB)
+#include <glib.h>  // for g_get_home_dir()
+#endif
+
+#include "base/basictypes.h"
+#include "base/files/file_enumerator.h"
+#include "base/files/file_path.h"
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/singleton.h"
+#include "base/path_service.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/stl_util.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/sys_info.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/time/time.h"
+
+#if defined(OS_ANDROID)
+#include "base/android/content_uri_utils.h"
+#include "base/os_compat_android.h"
+#endif
+
+#if !defined(OS_IOS)
+#include <grp.h>
+#endif
+
+namespace base {
+
+namespace {
+
+#if defined(OS_BSD) || defined(OS_MACOSX) || defined(OS_NACL)
+static int CallStat(const char *path, stat_wrapper_t *sb) {
+  ThreadRestrictions::AssertIOAllowed();
+  return stat(path, sb);
+}
+static int CallLstat(const char *path, stat_wrapper_t *sb) {
+  ThreadRestrictions::AssertIOAllowed();
+  return lstat(path, sb);
+}
+#else  //  defined(OS_BSD) || defined(OS_MACOSX) || defined(OS_NACL)
+static int CallStat(const char *path, stat_wrapper_t *sb) {
+  ThreadRestrictions::AssertIOAllowed();
+  return stat64(path, sb);
+}
+static int CallLstat(const char *path, stat_wrapper_t *sb) {
+  ThreadRestrictions::AssertIOAllowed();
+  return lstat64(path, sb);
+}
+#endif  // !(defined(OS_BSD) || defined(OS_MACOSX) || defined(OS_NACL))
+
+#if !defined(OS_NACL_NONSFI)
+// Helper for NormalizeFilePath(), defined below.
+bool RealPath(const FilePath& path, FilePath* real_path) {
+  ThreadRestrictions::AssertIOAllowed();  // For realpath().
+  FilePath::CharType buf[PATH_MAX];
+  if (!realpath(path.value().c_str(), buf))
+    return false;
+
+  *real_path = FilePath(buf);
+  return true;
+}
+
+// Helper for VerifyPathControlledByUser.
+bool VerifySpecificPathControlledByUser(const FilePath& path,
+                                        uid_t owner_uid,
+                                        const std::set<gid_t>& group_gids) {
+  stat_wrapper_t stat_info;
+  if (CallLstat(path.value().c_str(), &stat_info) != 0) {
+    DPLOG(ERROR) << "Failed to get information on path "
+                 << path.value();
+    return false;
+  }
+
+  if (S_ISLNK(stat_info.st_mode)) {
+    DLOG(ERROR) << "Path " << path.value()
+               << " is a symbolic link.";
+    return false;
+  }
+
+  if (stat_info.st_uid != owner_uid) {
+    DLOG(ERROR) << "Path " << path.value()
+                << " is owned by the wrong user.";
+    return false;
+  }
+
+  if ((stat_info.st_mode & S_IWGRP) &&
+      !ContainsKey(group_gids, stat_info.st_gid)) {
+    DLOG(ERROR) << "Path " << path.value()
+                << " is writable by an unprivileged group.";
+    return false;
+  }
+
+  if (stat_info.st_mode & S_IWOTH) {
+    DLOG(ERROR) << "Path " << path.value()
+                << " is writable by any user.";
+    return false;
+  }
+
+  return true;
+}
+
+std::string TempFileName() {
+#if defined(OS_MACOSX)
+  return StringPrintf(".%s.XXXXXX", base::mac::BaseBundleID());
+#endif
+
+#if defined(GOOGLE_CHROME_BUILD)
+  return std::string(".com.google.Chrome.XXXXXX");
+#else
+  return std::string(".org.chromium.Chromium.XXXXXX");
+#endif
+}
+
+// Creates and opens a temporary file in |directory|, returning the
+// file descriptor. |path| is set to the temporary file path.
+// This function does NOT unlink() the file.
+int CreateAndOpenFdForTemporaryFile(FilePath directory, FilePath* path) {
+  ThreadRestrictions::AssertIOAllowed();  // For call to mkstemp().
+  *path = directory.Append(base::TempFileName());
+  const std::string& tmpdir_string = path->value();
+  // this should be OK since mkstemp just replaces characters in place
+  char* buffer = const_cast<char*>(tmpdir_string.c_str());
+
+  return HANDLE_EINTR(mkstemp(buffer));
+}
+
+#if defined(OS_LINUX)
+// Determine if /dev/shm files can be mapped and then mprotect'd PROT_EXEC.
+// This depends on the mount options used for /dev/shm, which vary among
+// different Linux distributions and possibly local configuration.  It also
+// depends on details of kernel--ChromeOS uses the noexec option for /dev/shm
+// but its kernel allows mprotect with PROT_EXEC anyway.
+bool DetermineDevShmExecutable() {
+  bool result = false;
+  FilePath path;
+
+  ScopedFD fd(CreateAndOpenFdForTemporaryFile(FilePath("/dev/shm"), &path));
+  if (fd.is_valid()) {
+    DeleteFile(path, false);
+    long sysconf_result = sysconf(_SC_PAGESIZE);
+    CHECK_GE(sysconf_result, 0);
+    size_t pagesize = static_cast<size_t>(sysconf_result);
+    CHECK_GE(sizeof(pagesize), sizeof(sysconf_result));
+    void* mapping = mmap(NULL, pagesize, PROT_READ, MAP_SHARED, fd.get(), 0);
+    if (mapping != MAP_FAILED) {
+      if (mprotect(mapping, pagesize, PROT_READ | PROT_EXEC) == 0)
+        result = true;
+      munmap(mapping, pagesize);
+    }
+  }
+  return result;
+}
+#endif  // defined(OS_LINUX)
+#endif  // !defined(OS_NACL_NONSFI)
+
+}  // namespace
+
+#if !defined(OS_NACL_NONSFI)
+FilePath MakeAbsoluteFilePath(const FilePath& input) {
+  ThreadRestrictions::AssertIOAllowed();
+  char full_path[PATH_MAX];
+  if (realpath(input.value().c_str(), full_path) == NULL)
+    return FilePath();
+  return FilePath(full_path);
+}
+
+// TODO(erikkay): The Windows version of this accepts paths like "foo/bar/*"
+// which works both with and without the recursive flag.  I'm not sure we need
+// that functionality. If not, remove from file_util_win.cc, otherwise add it
+// here.
+bool DeleteFile(const FilePath& path, bool recursive) {
+  ThreadRestrictions::AssertIOAllowed();
+  const char* path_str = path.value().c_str();
+  stat_wrapper_t file_info;
+  int test = CallLstat(path_str, &file_info);
+  if (test != 0) {
+    // The Windows version defines this condition as success.
+    bool ret = (errno == ENOENT || errno == ENOTDIR);
+    return ret;
+  }
+  if (!S_ISDIR(file_info.st_mode))
+    return (unlink(path_str) == 0);
+  if (!recursive)
+    return (rmdir(path_str) == 0);
+
+  bool success = true;
+  std::stack<std::string> directories;
+  directories.push(path.value());
+  FileEnumerator traversal(path, true,
+      FileEnumerator::FILES | FileEnumerator::DIRECTORIES |
+      FileEnumerator::SHOW_SYM_LINKS);
+  for (FilePath current = traversal.Next(); success && !current.empty();
+       current = traversal.Next()) {
+    if (traversal.GetInfo().IsDirectory())
+      directories.push(current.value());
+    else
+      success = (unlink(current.value().c_str()) == 0);
+  }
+
+  while (success && !directories.empty()) {
+    FilePath dir = FilePath(directories.top());
+    directories.pop();
+    success = (rmdir(dir.value().c_str()) == 0);
+  }
+  return success;
+}
+
+bool ReplaceFile(const FilePath& from_path,
+                 const FilePath& to_path,
+                 File::Error* error) {
+  ThreadRestrictions::AssertIOAllowed();
+  if (rename(from_path.value().c_str(), to_path.value().c_str()) == 0)
+    return true;
+  if (error)
+    *error = File::OSErrorToFileError(errno);
+  return false;
+}
+
+bool CopyDirectory(const FilePath& from_path,
+                   const FilePath& to_path,
+                   bool recursive) {
+  ThreadRestrictions::AssertIOAllowed();
+  // Some old callers of CopyDirectory want it to support wildcards.
+  // After some discussion, we decided to fix those callers.
+  // Break loudly here if anyone tries to do this.
+  DCHECK(to_path.value().find('*') == std::string::npos);
+  DCHECK(from_path.value().find('*') == std::string::npos);
+
+  if (from_path.value().size() >= PATH_MAX) {
+    return false;
+  }
+
+  // This function does not properly handle destinations within the source
+  FilePath real_to_path = to_path;
+  if (PathExists(real_to_path)) {
+    real_to_path = MakeAbsoluteFilePath(real_to_path);
+    if (real_to_path.empty())
+      return false;
+  } else {
+    real_to_path = MakeAbsoluteFilePath(real_to_path.DirName());
+    if (real_to_path.empty())
+      return false;
+  }
+  FilePath real_from_path = MakeAbsoluteFilePath(from_path);
+  if (real_from_path.empty())
+    return false;
+  if (real_to_path.value().size() >= real_from_path.value().size() &&
+      real_to_path.value().compare(0, real_from_path.value().size(),
+                                   real_from_path.value()) == 0) {
+    return false;
+  }
+
+  int traverse_type = FileEnumerator::FILES | FileEnumerator::SHOW_SYM_LINKS;
+  if (recursive)
+    traverse_type |= FileEnumerator::DIRECTORIES;
+  FileEnumerator traversal(from_path, recursive, traverse_type);
+
+  // We have to mimic windows behavior here. |to_path| may not exist yet,
+  // start the loop with |to_path|.
+  struct stat from_stat;
+  FilePath current = from_path;
+  if (stat(from_path.value().c_str(), &from_stat) < 0) {
+    DLOG(ERROR) << "CopyDirectory() couldn't stat source directory: "
+                << from_path.value() << " errno = " << errno;
+    return false;
+  }
+  struct stat to_path_stat;
+  FilePath from_path_base = from_path;
+  if (recursive && stat(to_path.value().c_str(), &to_path_stat) == 0 &&
+      S_ISDIR(to_path_stat.st_mode)) {
+    // If the destination already exists and is a directory, then the
+    // top level of source needs to be copied.
+    from_path_base = from_path.DirName();
+  }
+
+  // The Windows version of this function assumes that non-recursive calls
+  // will always have a directory for from_path.
+  // TODO(maruel): This is not necessary anymore.
+  DCHECK(recursive || S_ISDIR(from_stat.st_mode));
+
+  bool success = true;
+  while (success && !current.empty()) {
+    // current is the source path, including from_path, so append
+    // the suffix after from_path to to_path to create the target_path.
+    FilePath target_path(to_path);
+    if (from_path_base != current) {
+      if (!from_path_base.AppendRelativePath(current, &target_path)) {
+        success = false;
+        break;
+      }
+    }
+
+    if (S_ISDIR(from_stat.st_mode)) {
+      if (mkdir(target_path.value().c_str(),
+                (from_stat.st_mode & 01777) | S_IRUSR | S_IXUSR | S_IWUSR) !=
+              0 &&
+          errno != EEXIST) {
+        DLOG(ERROR) << "CopyDirectory() couldn't create directory: "
+                    << target_path.value() << " errno = " << errno;
+        success = false;
+      }
+    } else if (S_ISREG(from_stat.st_mode)) {
+      if (!CopyFile(current, target_path)) {
+        DLOG(ERROR) << "CopyDirectory() couldn't create file: "
+                    << target_path.value();
+        success = false;
+      }
+    } else {
+      DLOG(WARNING) << "CopyDirectory() skipping non-regular file: "
+                    << current.value();
+    }
+
+    current = traversal.Next();
+    if (!current.empty())
+      from_stat = traversal.GetInfo().stat();
+  }
+
+  return success;
+}
+#endif  // !defined(OS_NACL_NONSFI)
+
+bool PathExists(const FilePath& path) {
+  ThreadRestrictions::AssertIOAllowed();
+#if defined(OS_ANDROID)
+  if (path.IsContentUri()) {
+    return ContentUriExists(path);
+  }
+#endif
+  return access(path.value().c_str(), F_OK) == 0;
+}
+
+#if !defined(OS_NACL_NONSFI)
+bool PathIsWritable(const FilePath& path) {
+  ThreadRestrictions::AssertIOAllowed();
+  return access(path.value().c_str(), W_OK) == 0;
+}
+#endif  // !defined(OS_NACL_NONSFI)
+
+bool DirectoryExists(const FilePath& path) {
+  ThreadRestrictions::AssertIOAllowed();
+  stat_wrapper_t file_info;
+  if (CallStat(path.value().c_str(), &file_info) == 0)
+    return S_ISDIR(file_info.st_mode);
+  return false;
+}
+
+bool ReadFromFD(int fd, char* buffer, size_t bytes) {
+  size_t total_read = 0;
+  while (total_read < bytes) {
+    ssize_t bytes_read =
+        HANDLE_EINTR(read(fd, buffer + total_read, bytes - total_read));
+    if (bytes_read <= 0)
+      break;
+    total_read += bytes_read;
+  }
+  return total_read == bytes;
+}
+
+#if !defined(OS_NACL_NONSFI)
+bool CreateSymbolicLink(const FilePath& target_path,
+                        const FilePath& symlink_path) {
+  DCHECK(!symlink_path.empty());
+  DCHECK(!target_path.empty());
+  return ::symlink(target_path.value().c_str(),
+                   symlink_path.value().c_str()) != -1;
+}
+
+bool ReadSymbolicLink(const FilePath& symlink_path, FilePath* target_path) {
+  DCHECK(!symlink_path.empty());
+  DCHECK(target_path);
+  char buf[PATH_MAX];
+  ssize_t count = ::readlink(symlink_path.value().c_str(), buf, arraysize(buf));
+
+  if (count <= 0) {
+    target_path->clear();
+    return false;
+  }
+
+  *target_path = FilePath(FilePath::StringType(buf, count));
+  return true;
+}
+
+bool GetPosixFilePermissions(const FilePath& path, int* mode) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(mode);
+
+  stat_wrapper_t file_info;
+  // Uses stat(), because on symbolic link, lstat() does not return valid
+  // permission bits in st_mode
+  if (CallStat(path.value().c_str(), &file_info) != 0)
+    return false;
+
+  *mode = file_info.st_mode & FILE_PERMISSION_MASK;
+  return true;
+}
+
+bool SetPosixFilePermissions(const FilePath& path,
+                             int mode) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK_EQ(mode & ~FILE_PERMISSION_MASK, 0);
+
+  // Calls stat() so that we can preserve the higher bits like S_ISGID.
+  stat_wrapper_t stat_buf;
+  if (CallStat(path.value().c_str(), &stat_buf) != 0)
+    return false;
+
+  // Clears the existing permission bits, and adds the new ones.
+  mode_t updated_mode_bits = stat_buf.st_mode & ~FILE_PERMISSION_MASK;
+  updated_mode_bits |= mode & FILE_PERMISSION_MASK;
+
+  if (HANDLE_EINTR(chmod(path.value().c_str(), updated_mode_bits)) != 0)
+    return false;
+
+  return true;
+}
+
+#if !defined(OS_MACOSX)
+// This is implemented in file_util_mac.mm for Mac.
+bool GetTempDir(FilePath* path) {
+  const char* tmp = getenv("TMPDIR");
+  if (tmp) {
+    *path = FilePath(tmp);
+  } else {
+#if defined(OS_ANDROID)
+    return PathService::Get(base::DIR_CACHE, path);
+#else
+    *path = FilePath("/tmp");
+#endif
+  }
+  return true;
+}
+#endif  // !defined(OS_MACOSX)
+
+#if !defined(OS_MACOSX)  // Mac implementation is in file_util_mac.mm.
+FilePath GetHomeDir() {
+#if defined(OS_CHROMEOS)
+  if (SysInfo::IsRunningOnChromeOS()) {
+    // On Chrome OS chrome::DIR_USER_DATA is overridden with a primary user
+    // homedir once it becomes available. Return / as the safe option.
+    return FilePath("/");
+  }
+#endif
+
+  const char* home_dir = getenv("HOME");
+  if (home_dir && home_dir[0])
+    return FilePath(home_dir);
+
+#if defined(OS_ANDROID)
+  DLOG(WARNING) << "OS_ANDROID: Home directory lookup not yet implemented.";
+#elif defined(USE_GLIB) && !defined(OS_CHROMEOS)
+  // g_get_home_dir calls getpwent, which can fall through to LDAP calls so
+  // this may do I/O. However, it should be rare that $HOME is not defined and
+  // this is typically called from the path service which has no threading
+  // restrictions. The path service will cache the result which limits the
+  // badness of blocking on I/O. As a result, we don't have a thread
+  // restriction here.
+  home_dir = g_get_home_dir();
+  if (home_dir && home_dir[0])
+    return FilePath(home_dir);
+#endif
+
+  FilePath rv;
+  if (GetTempDir(&rv))
+    return rv;
+
+  // Last resort.
+  return FilePath("/tmp");
+}
+#endif  // !defined(OS_MACOSX)
+
+bool CreateTemporaryFile(FilePath* path) {
+  ThreadRestrictions::AssertIOAllowed();  // For call to close().
+  FilePath directory;
+  if (!GetTempDir(&directory))
+    return false;
+  int fd = CreateAndOpenFdForTemporaryFile(directory, path);
+  if (fd < 0)
+    return false;
+  close(fd);
+  return true;
+}
+
+FILE* CreateAndOpenTemporaryFileInDir(const FilePath& dir, FilePath* path) {
+  int fd = CreateAndOpenFdForTemporaryFile(dir, path);
+  if (fd < 0)
+    return NULL;
+
+  FILE* file = fdopen(fd, "a+");
+  if (!file)
+    close(fd);
+  return file;
+}
+
+bool CreateTemporaryFileInDir(const FilePath& dir, FilePath* temp_file) {
+  ThreadRestrictions::AssertIOAllowed();  // For call to close().
+  int fd = CreateAndOpenFdForTemporaryFile(dir, temp_file);
+  return ((fd >= 0) && !IGNORE_EINTR(close(fd)));
+}
+
+static bool CreateTemporaryDirInDirImpl(const FilePath& base_dir,
+                                        const FilePath::StringType& name_tmpl,
+                                        FilePath* new_dir) {
+  ThreadRestrictions::AssertIOAllowed();  // For call to mkdtemp().
+  DCHECK(name_tmpl.find("XXXXXX") != FilePath::StringType::npos)
+      << "Directory name template must contain \"XXXXXX\".";
+
+  FilePath sub_dir = base_dir.Append(name_tmpl);
+  std::string sub_dir_string = sub_dir.value();
+
+  // this should be OK since mkdtemp just replaces characters in place
+  char* buffer = const_cast<char*>(sub_dir_string.c_str());
+  char* dtemp = mkdtemp(buffer);
+  if (!dtemp) {
+    DPLOG(ERROR) << "mkdtemp";
+    return false;
+  }
+  *new_dir = FilePath(dtemp);
+  return true;
+}
+
+bool CreateTemporaryDirInDir(const FilePath& base_dir,
+                             const FilePath::StringType& prefix,
+                             FilePath* new_dir) {
+  FilePath::StringType mkdtemp_template = prefix;
+  mkdtemp_template.append(FILE_PATH_LITERAL("XXXXXX"));
+  return CreateTemporaryDirInDirImpl(base_dir, mkdtemp_template, new_dir);
+}
+
+bool CreateNewTempDirectory(const FilePath::StringType& prefix,
+                            FilePath* new_temp_path) {
+  FilePath tmpdir;
+  if (!GetTempDir(&tmpdir))
+    return false;
+
+  return CreateTemporaryDirInDirImpl(tmpdir, TempFileName(), new_temp_path);
+}
+
+bool CreateDirectoryAndGetError(const FilePath& full_path,
+                                File::Error* error) {
+  ThreadRestrictions::AssertIOAllowed();  // For call to mkdir().
+  std::vector<FilePath> subpaths;
+
+  // Collect a list of all parent directories.
+  FilePath last_path = full_path;
+  subpaths.push_back(full_path);
+  for (FilePath path = full_path.DirName();
+       path.value() != last_path.value(); path = path.DirName()) {
+    subpaths.push_back(path);
+    last_path = path;
+  }
+
+  // Iterate through the parents and create the missing ones.
+  for (std::vector<FilePath>::reverse_iterator i = subpaths.rbegin();
+       i != subpaths.rend(); ++i) {
+    if (DirectoryExists(*i))
+      continue;
+    if (mkdir(i->value().c_str(), 0700) == 0)
+      continue;
+    // Mkdir failed, but it might have failed with EEXIST, or some other error
+    // due to the the directory appearing out of thin air. This can occur if
+    // two processes are trying to create the same file system tree at the same
+    // time. Check to see if it exists and make sure it is a directory.
+    int saved_errno = errno;
+    if (!DirectoryExists(*i)) {
+      if (error)
+        *error = File::OSErrorToFileError(saved_errno);
+      return false;
+    }
+  }
+  return true;
+}
+
+bool NormalizeFilePath(const FilePath& path, FilePath* normalized_path) {
+  FilePath real_path_result;
+  if (!RealPath(path, &real_path_result))
+    return false;
+
+  // To be consistant with windows, fail if |real_path_result| is a
+  // directory.
+  stat_wrapper_t file_info;
+  if (CallStat(real_path_result.value().c_str(), &file_info) != 0 ||
+      S_ISDIR(file_info.st_mode))
+    return false;
+
+  *normalized_path = real_path_result;
+  return true;
+}
+
+// TODO(rkc): Refactor GetFileInfo and FileEnumerator to handle symlinks
+// correctly. http://code.google.com/p/chromium-os/issues/detail?id=15948
+bool IsLink(const FilePath& file_path) {
+  stat_wrapper_t st;
+  // If we can't lstat the file, it's safe to assume that the file won't at
+  // least be a 'followable' link.
+  if (CallLstat(file_path.value().c_str(), &st) != 0)
+    return false;
+
+  if (S_ISLNK(st.st_mode))
+    return true;
+  else
+    return false;
+}
+
+bool GetFileInfo(const FilePath& file_path, File::Info* results) {
+  stat_wrapper_t file_info;
+#if defined(OS_ANDROID)
+  if (file_path.IsContentUri()) {
+    File file = OpenContentUriForRead(file_path);
+    if (!file.IsValid())
+      return false;
+    return file.GetInfo(results);
+  } else {
+#endif  // defined(OS_ANDROID)
+    if (CallStat(file_path.value().c_str(), &file_info) != 0)
+      return false;
+#if defined(OS_ANDROID)
+  }
+#endif  // defined(OS_ANDROID)
+
+  results->FromStat(file_info);
+  return true;
+}
+#endif  // !defined(OS_NACL_NONSFI)
+
+FILE* OpenFile(const FilePath& filename, const char* mode) {
+  ThreadRestrictions::AssertIOAllowed();
+  FILE* result = NULL;
+  do {
+    result = fopen(filename.value().c_str(), mode);
+  } while (!result && errno == EINTR);
+  return result;
+}
+
+// NaCl doesn't implement system calls to open files directly.
+#if !defined(OS_NACL)
+FILE* FileToFILE(File file, const char* mode) {
+  FILE* stream = fdopen(file.GetPlatformFile(), mode);
+  if (stream)
+    file.TakePlatformFile();
+  return stream;
+}
+#endif  // !defined(OS_NACL)
+
+int ReadFile(const FilePath& filename, char* data, int max_size) {
+  ThreadRestrictions::AssertIOAllowed();
+  int fd = HANDLE_EINTR(open(filename.value().c_str(), O_RDONLY));
+  if (fd < 0)
+    return -1;
+
+  ssize_t bytes_read = HANDLE_EINTR(read(fd, data, max_size));
+  if (IGNORE_EINTR(close(fd)) < 0)
+    return -1;
+  return bytes_read;
+}
+
+int WriteFile(const FilePath& filename, const char* data, int size) {
+  ThreadRestrictions::AssertIOAllowed();
+  int fd = HANDLE_EINTR(creat(filename.value().c_str(), 0640));
+  if (fd < 0)
+    return -1;
+
+  int bytes_written = WriteFileDescriptor(fd, data, size) ? size : -1;
+  if (IGNORE_EINTR(close(fd)) < 0)
+    return -1;
+  return bytes_written;
+}
+
+bool WriteFileDescriptor(const int fd, const char* data, int size) {
+  // Allow for partial writes.
+  ssize_t bytes_written_total = 0;
+  for (ssize_t bytes_written_partial = 0; bytes_written_total < size;
+       bytes_written_total += bytes_written_partial) {
+    bytes_written_partial =
+        HANDLE_EINTR(write(fd, data + bytes_written_total,
+                           size - bytes_written_total));
+    if (bytes_written_partial < 0)
+      return false;
+  }
+
+  return true;
+}
+
+#if !defined(OS_NACL_NONSFI)
+
+bool AppendToFile(const FilePath& filename, const char* data, int size) {
+  ThreadRestrictions::AssertIOAllowed();
+  bool ret = true;
+  int fd = HANDLE_EINTR(open(filename.value().c_str(), O_WRONLY | O_APPEND));
+  if (fd < 0) {
+    VPLOG(1) << "Unable to create file " << filename.value();
+    return false;
+  }
+
+  // This call will either write all of the data or return false.
+  if (!WriteFileDescriptor(fd, data, size)) {
+    VPLOG(1) << "Error while writing to file " << filename.value();
+    ret = false;
+  }
+
+  if (IGNORE_EINTR(close(fd)) < 0) {
+    VPLOG(1) << "Error while closing file " << filename.value();
+    return false;
+  }
+
+  return ret;
+}
+
+// Gets the current working directory for the process.
+bool GetCurrentDirectory(FilePath* dir) {
+  // getcwd can return ENOENT, which implies it checks against the disk.
+  ThreadRestrictions::AssertIOAllowed();
+
+  char system_buffer[PATH_MAX] = "";
+  if (!getcwd(system_buffer, sizeof(system_buffer))) {
+    NOTREACHED();
+    return false;
+  }
+  *dir = FilePath(system_buffer);
+  return true;
+}
+
+// Sets the current working directory for the process.
+bool SetCurrentDirectory(const FilePath& path) {
+  ThreadRestrictions::AssertIOAllowed();
+  int ret = chdir(path.value().c_str());
+  return !ret;
+}
+
+bool VerifyPathControlledByUser(const FilePath& base,
+                                const FilePath& path,
+                                uid_t owner_uid,
+                                const std::set<gid_t>& group_gids) {
+  if (base != path && !base.IsParent(path)) {
+     DLOG(ERROR) << "|base| must be a subdirectory of |path|.  base = \""
+                 << base.value() << "\", path = \"" << path.value() << "\"";
+     return false;
+  }
+
+  std::vector<FilePath::StringType> base_components;
+  std::vector<FilePath::StringType> path_components;
+
+  base.GetComponents(&base_components);
+  path.GetComponents(&path_components);
+
+  std::vector<FilePath::StringType>::const_iterator ib, ip;
+  for (ib = base_components.begin(), ip = path_components.begin();
+       ib != base_components.end(); ++ib, ++ip) {
+    // |base| must be a subpath of |path|, so all components should match.
+    // If these CHECKs fail, look at the test that base is a parent of
+    // path at the top of this function.
+    DCHECK(ip != path_components.end());
+    DCHECK(*ip == *ib);
+  }
+
+  FilePath current_path = base;
+  if (!VerifySpecificPathControlledByUser(current_path, owner_uid, group_gids))
+    return false;
+
+  for (; ip != path_components.end(); ++ip) {
+    current_path = current_path.Append(*ip);
+    if (!VerifySpecificPathControlledByUser(
+            current_path, owner_uid, group_gids))
+      return false;
+  }
+  return true;
+}
+
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+bool VerifyPathControlledByAdmin(const FilePath& path) {
+  const unsigned kRootUid = 0;
+  const FilePath kFileSystemRoot("/");
+
+  // The name of the administrator group on mac os.
+  const char* const kAdminGroupNames[] = {
+    "admin",
+    "wheel"
+  };
+
+  // Reading the groups database may touch the file system.
+  ThreadRestrictions::AssertIOAllowed();
+
+  std::set<gid_t> allowed_group_ids;
+  for (int i = 0, ie = arraysize(kAdminGroupNames); i < ie; ++i) {
+    struct group *group_record = getgrnam(kAdminGroupNames[i]);
+    if (!group_record) {
+      DPLOG(ERROR) << "Could not get the group ID of group \""
+                   << kAdminGroupNames[i] << "\".";
+      continue;
+    }
+
+    allowed_group_ids.insert(group_record->gr_gid);
+  }
+
+  return VerifyPathControlledByUser(
+      kFileSystemRoot, path, kRootUid, allowed_group_ids);
+}
+#endif  // defined(OS_MACOSX) && !defined(OS_IOS)
+
+int GetMaximumPathComponentLength(const FilePath& path) {
+  ThreadRestrictions::AssertIOAllowed();
+  return pathconf(path.value().c_str(), _PC_NAME_MAX);
+}
+
+#if !defined(OS_ANDROID)
+// This is implemented in file_util_android.cc for that platform.
+bool GetShmemTempDir(bool executable, FilePath* path) {
+#if defined(OS_LINUX)
+  bool use_dev_shm = true;
+  if (executable) {
+    static const bool s_dev_shm_executable = DetermineDevShmExecutable();
+    use_dev_shm = s_dev_shm_executable;
+  }
+  if (use_dev_shm) {
+    *path = FilePath("/dev/shm");
+    return true;
+  }
+#endif
+  return GetTempDir(path);
+}
+#endif  // !defined(OS_ANDROID)
+
+#if !defined(OS_MACOSX)
+// Mac has its own implementation, this is for all other Posix systems.
+bool CopyFile(const FilePath& from_path, const FilePath& to_path) {
+  ThreadRestrictions::AssertIOAllowed();
+  File infile;
+#if defined(OS_ANDROID)
+  if (from_path.IsContentUri()) {
+    infile = OpenContentUriForRead(from_path);
+  } else {
+    infile = File(from_path, File::FLAG_OPEN | File::FLAG_READ);
+  }
+#else
+  infile = File(from_path, File::FLAG_OPEN | File::FLAG_READ);
+#endif
+  if (!infile.IsValid())
+    return false;
+
+  File outfile(to_path, File::FLAG_WRITE | File::FLAG_CREATE_ALWAYS);
+  if (!outfile.IsValid())
+    return false;
+
+  const size_t kBufferSize = 32768;
+  std::vector<char> buffer(kBufferSize);
+  bool result = true;
+
+  while (result) {
+    ssize_t bytes_read = infile.ReadAtCurrentPos(&buffer[0], buffer.size());
+    if (bytes_read < 0) {
+      result = false;
+      break;
+    }
+    if (bytes_read == 0)
+      break;
+    // Allow for partial writes
+    ssize_t bytes_written_per_read = 0;
+    do {
+      ssize_t bytes_written_partial = outfile.WriteAtCurrentPos(
+          &buffer[bytes_written_per_read], bytes_read - bytes_written_per_read);
+      if (bytes_written_partial < 0) {
+        result = false;
+        break;
+      }
+      bytes_written_per_read += bytes_written_partial;
+    } while (bytes_written_per_read < bytes_read);
+  }
+
+  return result;
+}
+#endif  // !defined(OS_MACOSX)
+
+// -----------------------------------------------------------------------------
+
+namespace internal {
+
+bool MoveUnsafe(const FilePath& from_path, const FilePath& to_path) {
+  ThreadRestrictions::AssertIOAllowed();
+  // Windows compatibility: if to_path exists, from_path and to_path
+  // must be the same type, either both files, or both directories.
+  stat_wrapper_t to_file_info;
+  if (CallStat(to_path.value().c_str(), &to_file_info) == 0) {
+    stat_wrapper_t from_file_info;
+    if (CallStat(from_path.value().c_str(), &from_file_info) == 0) {
+      if (S_ISDIR(to_file_info.st_mode) != S_ISDIR(from_file_info.st_mode))
+        return false;
+    } else {
+      return false;
+    }
+  }
+
+  if (rename(from_path.value().c_str(), to_path.value().c_str()) == 0)
+    return true;
+
+  if (!CopyDirectory(from_path, to_path, true))
+    return false;
+
+  DeleteFile(from_path, true);
+  return true;
+}
+
+}  // namespace internal
+
+#endif  // !defined(OS_NACL_NONSFI)
+}  // namespace base
diff --git a/base/files/file_util_proxy.cc b/base/files/file_util_proxy.cc
new file mode 100644
index 0000000..0942e7a
--- /dev/null
+++ b/base/files/file_util_proxy.cc
@@ -0,0 +1,104 @@
+// Copyright (c) 2012 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/files/file_util_proxy.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/files/file_util.h"
+#include "base/location.h"
+#include "base/task_runner.h"
+#include "base/task_runner_util.h"
+
+namespace base {
+
+namespace {
+
+void CallWithTranslatedParameter(const FileUtilProxy::StatusCallback& callback,
+                                 bool value) {
+  DCHECK(!callback.is_null());
+  callback.Run(value ? File::FILE_OK : File::FILE_ERROR_FAILED);
+}
+
+class GetFileInfoHelper {
+ public:
+  GetFileInfoHelper()
+      : error_(File::FILE_OK) {}
+
+  void RunWorkForFilePath(const FilePath& file_path) {
+    if (!PathExists(file_path)) {
+      error_ = File::FILE_ERROR_NOT_FOUND;
+      return;
+    }
+    if (!GetFileInfo(file_path, &file_info_))
+      error_ = File::FILE_ERROR_FAILED;
+  }
+
+  void Reply(const FileUtilProxy::GetFileInfoCallback& callback) {
+    if (!callback.is_null()) {
+      callback.Run(error_, file_info_);
+    }
+  }
+
+ private:
+  File::Error error_;
+  File::Info file_info_;
+  DISALLOW_COPY_AND_ASSIGN(GetFileInfoHelper);
+};
+
+File::Error DeleteAdapter(const FilePath& file_path, bool recursive) {
+  if (!PathExists(file_path)) {
+    return File::FILE_ERROR_NOT_FOUND;
+  }
+  if (!base::DeleteFile(file_path, recursive)) {
+    if (!recursive && !base::IsDirectoryEmpty(file_path)) {
+      return File::FILE_ERROR_NOT_EMPTY;
+    }
+    return File::FILE_ERROR_FAILED;
+  }
+  return File::FILE_OK;
+}
+
+}  // namespace
+
+// Retrieves the information about a file. It is invalid to pass NULL for the
+// callback.
+bool FileUtilProxy::GetFileInfo(
+    TaskRunner* task_runner,
+    const FilePath& file_path,
+    const GetFileInfoCallback& callback) {
+  GetFileInfoHelper* helper = new GetFileInfoHelper;
+  return task_runner->PostTaskAndReply(
+      FROM_HERE,
+      Bind(&GetFileInfoHelper::RunWorkForFilePath,
+           Unretained(helper), file_path),
+      Bind(&GetFileInfoHelper::Reply, Owned(helper), callback));
+}
+
+// static
+bool FileUtilProxy::DeleteFile(TaskRunner* task_runner,
+                               const FilePath& file_path,
+                               bool recursive,
+                               const StatusCallback& callback) {
+  return base::PostTaskAndReplyWithResult(
+      task_runner, FROM_HERE,
+      Bind(&DeleteAdapter, file_path, recursive),
+      callback);
+}
+
+// static
+bool FileUtilProxy::Touch(
+    TaskRunner* task_runner,
+    const FilePath& file_path,
+    const Time& last_access_time,
+    const Time& last_modified_time,
+    const StatusCallback& callback) {
+  return base::PostTaskAndReplyWithResult(
+      task_runner,
+      FROM_HERE,
+      Bind(&TouchFile, file_path, last_access_time, last_modified_time),
+      Bind(&CallWithTranslatedParameter, callback));
+}
+
+}  // namespace base
diff --git a/base/files/file_util_proxy.h b/base/files/file_util_proxy.h
new file mode 100644
index 0000000..80688cf
--- /dev/null
+++ b/base/files/file_util_proxy.h
@@ -0,0 +1,60 @@
+// Copyright (c) 2012 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_FILES_FILE_UTIL_PROXY_H_
+#define BASE_FILES_FILE_UTIL_PROXY_H_
+
+#include "base/base_export.h"
+#include "base/callback_forward.h"
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+
+namespace base {
+
+class TaskRunner;
+class Time;
+
+// This class provides asynchronous access to common file routines.
+class BASE_EXPORT FileUtilProxy {
+ public:
+  // This callback is used by methods that report only an error code.  It is
+  // valid to pass a null callback to any function that takes a StatusCallback,
+  // in which case the operation will complete silently.
+  typedef Callback<void(File::Error)> StatusCallback;
+
+  typedef Callback<void(File::Error,
+                        const File::Info&)> GetFileInfoCallback;
+
+  // Retrieves the information about a file. It is invalid to pass a null
+  // callback.
+  // This returns false if task posting to |task_runner| has failed.
+  static bool GetFileInfo(
+      TaskRunner* task_runner,
+      const FilePath& file_path,
+      const GetFileInfoCallback& callback);
+
+  // Deletes a file or a directory.
+  // It is an error to delete a non-empty directory with recursive=false.
+  // This returns false if task posting to |task_runner| has failed.
+  static bool DeleteFile(TaskRunner* task_runner,
+                         const FilePath& file_path,
+                         bool recursive,
+                         const StatusCallback& callback);
+
+  // Touches a file. The callback can be null.
+  // This returns false if task posting to |task_runner| has failed.
+  static bool Touch(
+      TaskRunner* task_runner,
+      const FilePath& file_path,
+      const Time& last_access_time,
+      const Time& last_modified_time,
+      const StatusCallback& callback);
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(FileUtilProxy);
+};
+
+}  // namespace base
+
+#endif  // BASE_FILES_FILE_UTIL_PROXY_H_
diff --git a/base/files/file_util_proxy_unittest.cc b/base/files/file_util_proxy_unittest.cc
new file mode 100644
index 0000000..7408369
--- /dev/null
+++ b/base/files/file_util_proxy_unittest.cc
@@ -0,0 +1,130 @@
+// Copyright (c) 2012 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/files/file_util_proxy.h"
+
+#include "base/bind.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/memory/weak_ptr.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+class FileUtilProxyTest : public testing::Test {
+ public:
+  FileUtilProxyTest()
+      : file_thread_("FileUtilProxyTestFileThread"),
+        error_(File::FILE_OK),
+        weak_factory_(this) {}
+
+  void SetUp() override {
+    ASSERT_TRUE(dir_.CreateUniqueTempDir());
+    ASSERT_TRUE(file_thread_.Start());
+  }
+
+  void DidFinish(File::Error error) {
+    error_ = error;
+    MessageLoop::current()->QuitWhenIdle();
+  }
+
+  void DidGetFileInfo(File::Error error,
+                      const File::Info& file_info) {
+    error_ = error;
+    file_info_ = file_info;
+    MessageLoop::current()->QuitWhenIdle();
+  }
+
+ protected:
+  TaskRunner* file_task_runner() const {
+    return file_thread_.task_runner().get();
+  }
+  const FilePath& test_dir_path() const { return dir_.path(); }
+  const FilePath test_path() const { return dir_.path().AppendASCII("test"); }
+
+  MessageLoopForIO message_loop_;
+  Thread file_thread_;
+
+  ScopedTempDir dir_;
+  File::Error error_;
+  FilePath path_;
+  File::Info file_info_;
+  std::vector<char> buffer_;
+  WeakPtrFactory<FileUtilProxyTest> weak_factory_;
+};
+
+
+TEST_F(FileUtilProxyTest, GetFileInfo_File) {
+  // Setup.
+  ASSERT_EQ(4, WriteFile(test_path(), "test", 4));
+  File::Info expected_info;
+  GetFileInfo(test_path(), &expected_info);
+
+  // Run.
+  FileUtilProxy::GetFileInfo(
+      file_task_runner(),
+      test_path(),
+      Bind(&FileUtilProxyTest::DidGetFileInfo, weak_factory_.GetWeakPtr()));
+  MessageLoop::current()->Run();
+
+  // Verify.
+  EXPECT_EQ(File::FILE_OK, error_);
+  EXPECT_EQ(expected_info.size, file_info_.size);
+  EXPECT_EQ(expected_info.is_directory, file_info_.is_directory);
+  EXPECT_EQ(expected_info.is_symbolic_link, file_info_.is_symbolic_link);
+  EXPECT_EQ(expected_info.last_modified, file_info_.last_modified);
+  EXPECT_EQ(expected_info.last_accessed, file_info_.last_accessed);
+  EXPECT_EQ(expected_info.creation_time, file_info_.creation_time);
+}
+
+TEST_F(FileUtilProxyTest, GetFileInfo_Directory) {
+  // Setup.
+  ASSERT_TRUE(base::CreateDirectory(test_path()));
+  File::Info expected_info;
+  GetFileInfo(test_path(), &expected_info);
+
+  // Run.
+  FileUtilProxy::GetFileInfo(
+      file_task_runner(),
+      test_path(),
+      Bind(&FileUtilProxyTest::DidGetFileInfo, weak_factory_.GetWeakPtr()));
+  MessageLoop::current()->Run();
+
+  // Verify.
+  EXPECT_EQ(File::FILE_OK, error_);
+  EXPECT_EQ(expected_info.size, file_info_.size);
+  EXPECT_EQ(expected_info.is_directory, file_info_.is_directory);
+  EXPECT_EQ(expected_info.is_symbolic_link, file_info_.is_symbolic_link);
+  EXPECT_EQ(expected_info.last_modified, file_info_.last_modified);
+  EXPECT_EQ(expected_info.last_accessed, file_info_.last_accessed);
+  EXPECT_EQ(expected_info.creation_time, file_info_.creation_time);
+}
+
+TEST_F(FileUtilProxyTest, Touch) {
+  ASSERT_EQ(4, WriteFile(test_path(), "test", 4));
+  Time last_accessed_time = Time::Now() - TimeDelta::FromDays(12345);
+  Time last_modified_time = Time::Now() - TimeDelta::FromHours(98765);
+
+  FileUtilProxy::Touch(
+      file_task_runner(),
+      test_path(),
+      last_accessed_time,
+      last_modified_time,
+      Bind(&FileUtilProxyTest::DidFinish, weak_factory_.GetWeakPtr()));
+  MessageLoop::current()->Run();
+  EXPECT_EQ(File::FILE_OK, error_);
+
+  File::Info info;
+  GetFileInfo(test_path(), &info);
+
+  // The returned values may only have the seconds precision, so we cast
+  // the double values to int here.
+  EXPECT_EQ(static_cast<int>(last_modified_time.ToDoubleT()),
+            static_cast<int>(info.last_modified.ToDoubleT()));
+  EXPECT_EQ(static_cast<int>(last_accessed_time.ToDoubleT()),
+            static_cast<int>(info.last_accessed.ToDoubleT()));
+}
+
+}  // namespace base
diff --git a/base/files/file_util_unittest.cc b/base/files/file_util_unittest.cc
new file mode 100644
index 0000000..52581f8
--- /dev/null
+++ b/base/files/file_util_unittest.cc
@@ -0,0 +1,2536 @@
+// Copyright (c) 2012 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 "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#include <shellapi.h>
+#include <shlobj.h>
+#include <tchar.h>
+#include <winioctl.h>
+#endif
+
+#if defined(OS_POSIX)
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#endif
+
+#include <algorithm>
+#include <fstream>
+#include <set>
+#include <vector>
+
+#include "base/base_paths.h"
+#include "base/files/file_enumerator.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/path_service.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/test_file_util.h"
+#include "base/threading/platform_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+#if defined(OS_WIN)
+#include "base/win/scoped_handle.h"
+#include "base/win/windows_version.h"
+#endif
+
+#if defined(OS_ANDROID)
+#include "base/android/content_uri_utils.h"
+#endif
+
+// This macro helps avoid wrapped lines in the test structs.
+#define FPL(x) FILE_PATH_LITERAL(x)
+
+namespace base {
+
+namespace {
+
+// To test that NormalizeFilePath() deals with NTFS reparse points correctly,
+// we need functions to create and delete reparse points.
+#if defined(OS_WIN)
+typedef struct _REPARSE_DATA_BUFFER {
+  ULONG  ReparseTag;
+  USHORT  ReparseDataLength;
+  USHORT  Reserved;
+  union {
+    struct {
+      USHORT SubstituteNameOffset;
+      USHORT SubstituteNameLength;
+      USHORT PrintNameOffset;
+      USHORT PrintNameLength;
+      ULONG Flags;
+      WCHAR PathBuffer[1];
+    } SymbolicLinkReparseBuffer;
+    struct {
+      USHORT SubstituteNameOffset;
+      USHORT SubstituteNameLength;
+      USHORT PrintNameOffset;
+      USHORT PrintNameLength;
+      WCHAR PathBuffer[1];
+    } MountPointReparseBuffer;
+    struct {
+      UCHAR DataBuffer[1];
+    } GenericReparseBuffer;
+  };
+} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
+
+// Sets a reparse point. |source| will now point to |target|. Returns true if
+// the call succeeds, false otherwise.
+bool SetReparsePoint(HANDLE source, const FilePath& target_path) {
+  std::wstring kPathPrefix = L"\\??\\";
+  std::wstring target_str;
+  // The juction will not work if the target path does not start with \??\ .
+  if (kPathPrefix != target_path.value().substr(0, kPathPrefix.size()))
+    target_str += kPathPrefix;
+  target_str += target_path.value();
+  const wchar_t* target = target_str.c_str();
+  USHORT size_target = static_cast<USHORT>(wcslen(target)) * sizeof(target[0]);
+  char buffer[2000] = {0};
+  DWORD returned;
+
+  REPARSE_DATA_BUFFER* data = reinterpret_cast<REPARSE_DATA_BUFFER*>(buffer);
+
+  data->ReparseTag = 0xa0000003;
+  memcpy(data->MountPointReparseBuffer.PathBuffer, target, size_target + 2);
+
+  data->MountPointReparseBuffer.SubstituteNameLength = size_target;
+  data->MountPointReparseBuffer.PrintNameOffset = size_target + 2;
+  data->ReparseDataLength = size_target + 4 + 8;
+
+  int data_size = data->ReparseDataLength + 8;
+
+  if (!DeviceIoControl(source, FSCTL_SET_REPARSE_POINT, &buffer, data_size,
+                       NULL, 0, &returned, NULL)) {
+    return false;
+  }
+  return true;
+}
+
+// Delete the reparse point referenced by |source|. Returns true if the call
+// succeeds, false otherwise.
+bool DeleteReparsePoint(HANDLE source) {
+  DWORD returned;
+  REPARSE_DATA_BUFFER data = {0};
+  data.ReparseTag = 0xa0000003;
+  if (!DeviceIoControl(source, FSCTL_DELETE_REPARSE_POINT, &data, 8, NULL, 0,
+                       &returned, NULL)) {
+    return false;
+  }
+  return true;
+}
+
+// Manages a reparse point for a test.
+class ReparsePoint {
+ public:
+  // Creates a reparse point from |source| (an empty directory) to |target|.
+  ReparsePoint(const FilePath& source, const FilePath& target) {
+    dir_.Set(
+      ::CreateFile(source.value().c_str(),
+                   FILE_ALL_ACCESS,
+                   FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+                   NULL,
+                   OPEN_EXISTING,
+                   FILE_FLAG_BACKUP_SEMANTICS,  // Needed to open a directory.
+                   NULL));
+    created_ = dir_.IsValid() && SetReparsePoint(dir_.Get(), target);
+  }
+
+  ~ReparsePoint() {
+    if (created_)
+      DeleteReparsePoint(dir_.Get());
+  }
+
+  bool IsValid() { return created_; }
+
+ private:
+  win::ScopedHandle dir_;
+  bool created_;
+  DISALLOW_COPY_AND_ASSIGN(ReparsePoint);
+};
+
+#endif
+
+#if defined(OS_POSIX)
+// Provide a simple way to change the permissions bits on |path| in tests.
+// ASSERT failures will return, but not stop the test.  Caller should wrap
+// calls to this function in ASSERT_NO_FATAL_FAILURE().
+void ChangePosixFilePermissions(const FilePath& path,
+                                int mode_bits_to_set,
+                                int mode_bits_to_clear) {
+  ASSERT_FALSE(mode_bits_to_set & mode_bits_to_clear)
+      << "Can't set and clear the same bits.";
+
+  int mode = 0;
+  ASSERT_TRUE(GetPosixFilePermissions(path, &mode));
+  mode |= mode_bits_to_set;
+  mode &= ~mode_bits_to_clear;
+  ASSERT_TRUE(SetPosixFilePermissions(path, mode));
+}
+#endif  // defined(OS_POSIX)
+
+const wchar_t bogus_content[] = L"I'm cannon fodder.";
+
+const int FILES_AND_DIRECTORIES =
+    FileEnumerator::FILES | FileEnumerator::DIRECTORIES;
+
+// file_util winds up using autoreleased objects on the Mac, so this needs
+// to be a PlatformTest
+class FileUtilTest : public PlatformTest {
+ protected:
+  void SetUp() override {
+    PlatformTest::SetUp();
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+  }
+
+  ScopedTempDir temp_dir_;
+};
+
+// Collects all the results from the given file enumerator, and provides an
+// interface to query whether a given file is present.
+class FindResultCollector {
+ public:
+  explicit FindResultCollector(FileEnumerator* enumerator) {
+    FilePath cur_file;
+    while (!(cur_file = enumerator->Next()).value().empty()) {
+      FilePath::StringType path = cur_file.value();
+      // The file should not be returned twice.
+      EXPECT_TRUE(files_.end() == files_.find(path))
+          << "Same file returned twice";
+
+      // Save for later.
+      files_.insert(path);
+    }
+  }
+
+  // Returns true if the enumerator found the file.
+  bool HasFile(const FilePath& file) const {
+    return files_.find(file.value()) != files_.end();
+  }
+
+  int size() {
+    return static_cast<int>(files_.size());
+  }
+
+ private:
+  std::set<FilePath::StringType> files_;
+};
+
+// Simple function to dump some text into a new file.
+void CreateTextFile(const FilePath& filename,
+                    const std::wstring& contents) {
+  std::wofstream file;
+  file.open(filename.value().c_str());
+  ASSERT_TRUE(file.is_open());
+  file << contents;
+  file.close();
+}
+
+// Simple function to take out some text from a file.
+std::wstring ReadTextFile(const FilePath& filename) {
+  wchar_t contents[64];
+  std::wifstream file;
+  file.open(filename.value().c_str());
+  EXPECT_TRUE(file.is_open());
+  file.getline(contents, arraysize(contents));
+  file.close();
+  return std::wstring(contents);
+}
+
+#if defined(OS_WIN)
+uint64 FileTimeAsUint64(const FILETIME& ft) {
+  ULARGE_INTEGER u;
+  u.LowPart = ft.dwLowDateTime;
+  u.HighPart = ft.dwHighDateTime;
+  return u.QuadPart;
+}
+#endif
+
+TEST_F(FileUtilTest, FileAndDirectorySize) {
+  // Create three files of 20, 30 and 3 chars (utf8). ComputeDirectorySize
+  // should return 53 bytes.
+  FilePath file_01 = temp_dir_.path().Append(FPL("The file 01.txt"));
+  CreateTextFile(file_01, L"12345678901234567890");
+  int64 size_f1 = 0;
+  ASSERT_TRUE(GetFileSize(file_01, &size_f1));
+  EXPECT_EQ(20ll, size_f1);
+
+  FilePath subdir_path = temp_dir_.path().Append(FPL("Level2"));
+  CreateDirectory(subdir_path);
+
+  FilePath file_02 = subdir_path.Append(FPL("The file 02.txt"));
+  CreateTextFile(file_02, L"123456789012345678901234567890");
+  int64 size_f2 = 0;
+  ASSERT_TRUE(GetFileSize(file_02, &size_f2));
+  EXPECT_EQ(30ll, size_f2);
+
+  FilePath subsubdir_path = subdir_path.Append(FPL("Level3"));
+  CreateDirectory(subsubdir_path);
+
+  FilePath file_03 = subsubdir_path.Append(FPL("The file 03.txt"));
+  CreateTextFile(file_03, L"123");
+
+  int64 computed_size = ComputeDirectorySize(temp_dir_.path());
+  EXPECT_EQ(size_f1 + size_f2 + 3, computed_size);
+}
+
+TEST_F(FileUtilTest, NormalizeFilePathBasic) {
+  // Create a directory under the test dir.  Because we create it,
+  // we know it is not a link.
+  FilePath file_a_path = temp_dir_.path().Append(FPL("file_a"));
+  FilePath dir_path = temp_dir_.path().Append(FPL("dir"));
+  FilePath file_b_path = dir_path.Append(FPL("file_b"));
+  CreateDirectory(dir_path);
+
+  FilePath normalized_file_a_path, normalized_file_b_path;
+  ASSERT_FALSE(PathExists(file_a_path));
+  ASSERT_FALSE(NormalizeFilePath(file_a_path, &normalized_file_a_path))
+    << "NormalizeFilePath() should fail on nonexistent paths.";
+
+  CreateTextFile(file_a_path, bogus_content);
+  ASSERT_TRUE(PathExists(file_a_path));
+  ASSERT_TRUE(NormalizeFilePath(file_a_path, &normalized_file_a_path));
+
+  CreateTextFile(file_b_path, bogus_content);
+  ASSERT_TRUE(PathExists(file_b_path));
+  ASSERT_TRUE(NormalizeFilePath(file_b_path, &normalized_file_b_path));
+
+  // Beacuse this test created |dir_path|, we know it is not a link
+  // or junction.  So, the real path of the directory holding file a
+  // must be the parent of the path holding file b.
+  ASSERT_TRUE(normalized_file_a_path.DirName()
+      .IsParent(normalized_file_b_path.DirName()));
+}
+
+#if defined(OS_WIN)
+
+TEST_F(FileUtilTest, NormalizeFilePathReparsePoints) {
+  // Build the following directory structure:
+  //
+  // temp_dir
+  // |-> base_a
+  // |   |-> sub_a
+  // |       |-> file.txt
+  // |       |-> long_name___... (Very long name.)
+  // |           |-> sub_long
+  // |              |-> deep.txt
+  // |-> base_b
+  //     |-> to_sub_a (reparse point to temp_dir\base_a\sub_a)
+  //     |-> to_base_b (reparse point to temp_dir\base_b)
+  //     |-> to_sub_long (reparse point to temp_dir\sub_a\long_name_\sub_long)
+
+  FilePath base_a = temp_dir_.path().Append(FPL("base_a"));
+#if defined(OS_WIN)
+  // TEMP can have a lower case drive letter.
+  string16 temp_base_a = base_a.value();
+  ASSERT_FALSE(temp_base_a.empty());
+  *temp_base_a.begin() = ToUpperASCII(*temp_base_a.begin());
+  base_a = FilePath(temp_base_a);
+#endif
+  ASSERT_TRUE(CreateDirectory(base_a));
+
+  FilePath sub_a = base_a.Append(FPL("sub_a"));
+  ASSERT_TRUE(CreateDirectory(sub_a));
+
+  FilePath file_txt = sub_a.Append(FPL("file.txt"));
+  CreateTextFile(file_txt, bogus_content);
+
+  // Want a directory whose name is long enough to make the path to the file
+  // inside just under MAX_PATH chars.  This will be used to test that when
+  // a junction expands to a path over MAX_PATH chars in length,
+  // NormalizeFilePath() fails without crashing.
+  FilePath sub_long_rel(FPL("sub_long"));
+  FilePath deep_txt(FPL("deep.txt"));
+
+  int target_length = MAX_PATH;
+  target_length -= (sub_a.value().length() + 1);  // +1 for the sepperator '\'.
+  target_length -= (sub_long_rel.Append(deep_txt).value().length() + 1);
+  // Without making the path a bit shorter, CreateDirectory() fails.
+  // the resulting path is still long enough to hit the failing case in
+  // NormalizePath().
+  const int kCreateDirLimit = 4;
+  target_length -= kCreateDirLimit;
+  FilePath::StringType long_name_str = FPL("long_name_");
+  long_name_str.resize(target_length, '_');
+
+  FilePath long_name = sub_a.Append(FilePath(long_name_str));
+  FilePath deep_file = long_name.Append(sub_long_rel).Append(deep_txt);
+  ASSERT_EQ(MAX_PATH - kCreateDirLimit, deep_file.value().length());
+
+  FilePath sub_long = deep_file.DirName();
+  ASSERT_TRUE(CreateDirectory(sub_long));
+  CreateTextFile(deep_file, bogus_content);
+
+  FilePath base_b = temp_dir_.path().Append(FPL("base_b"));
+  ASSERT_TRUE(CreateDirectory(base_b));
+
+  FilePath to_sub_a = base_b.Append(FPL("to_sub_a"));
+  ASSERT_TRUE(CreateDirectory(to_sub_a));
+  FilePath normalized_path;
+  {
+    ReparsePoint reparse_to_sub_a(to_sub_a, sub_a);
+    ASSERT_TRUE(reparse_to_sub_a.IsValid());
+
+    FilePath to_base_b = base_b.Append(FPL("to_base_b"));
+    ASSERT_TRUE(CreateDirectory(to_base_b));
+    ReparsePoint reparse_to_base_b(to_base_b, base_b);
+    ASSERT_TRUE(reparse_to_base_b.IsValid());
+
+    FilePath to_sub_long = base_b.Append(FPL("to_sub_long"));
+    ASSERT_TRUE(CreateDirectory(to_sub_long));
+    ReparsePoint reparse_to_sub_long(to_sub_long, sub_long);
+    ASSERT_TRUE(reparse_to_sub_long.IsValid());
+
+    // Normalize a junction free path: base_a\sub_a\file.txt .
+    ASSERT_TRUE(NormalizeFilePath(file_txt, &normalized_path));
+    ASSERT_STREQ(file_txt.value().c_str(), normalized_path.value().c_str());
+
+    // Check that the path base_b\to_sub_a\file.txt can be normalized to exclude
+    // the junction to_sub_a.
+    ASSERT_TRUE(NormalizeFilePath(to_sub_a.Append(FPL("file.txt")),
+                                             &normalized_path));
+    ASSERT_STREQ(file_txt.value().c_str(), normalized_path.value().c_str());
+
+    // Check that the path base_b\to_base_b\to_base_b\to_sub_a\file.txt can be
+    // normalized to exclude junctions to_base_b and to_sub_a .
+    ASSERT_TRUE(NormalizeFilePath(base_b.Append(FPL("to_base_b"))
+                                                   .Append(FPL("to_base_b"))
+                                                   .Append(FPL("to_sub_a"))
+                                                   .Append(FPL("file.txt")),
+                                             &normalized_path));
+    ASSERT_STREQ(file_txt.value().c_str(), normalized_path.value().c_str());
+
+    // A long enough path will cause NormalizeFilePath() to fail.  Make a long
+    // path using to_base_b many times, and check that paths long enough to fail
+    // do not cause a crash.
+    FilePath long_path = base_b;
+    const int kLengthLimit = MAX_PATH + 200;
+    while (long_path.value().length() <= kLengthLimit) {
+      long_path = long_path.Append(FPL("to_base_b"));
+    }
+    long_path = long_path.Append(FPL("to_sub_a"))
+                         .Append(FPL("file.txt"));
+
+    ASSERT_FALSE(NormalizeFilePath(long_path, &normalized_path));
+
+    // Normalizing the junction to deep.txt should fail, because the expanded
+    // path to deep.txt is longer than MAX_PATH.
+    ASSERT_FALSE(NormalizeFilePath(to_sub_long.Append(deep_txt),
+                                              &normalized_path));
+
+    // Delete the reparse points, and see that NormalizeFilePath() fails
+    // to traverse them.
+  }
+
+  ASSERT_FALSE(NormalizeFilePath(to_sub_a.Append(FPL("file.txt")),
+                                            &normalized_path));
+}
+
+TEST_F(FileUtilTest, DevicePathToDriveLetter) {
+  // Get a drive letter.
+  std::wstring real_drive_letter = temp_dir_.path().value().substr(0, 2);
+  StringToUpperASCII(&real_drive_letter);
+  if (!isalpha(real_drive_letter[0]) || ':' != real_drive_letter[1]) {
+    LOG(ERROR) << "Can't get a drive letter to test with.";
+    return;
+  }
+
+  // Get the NT style path to that drive.
+  wchar_t device_path[MAX_PATH] = {'\0'};
+  ASSERT_TRUE(
+      ::QueryDosDevice(real_drive_letter.c_str(), device_path, MAX_PATH));
+  FilePath actual_device_path(device_path);
+  FilePath win32_path;
+
+  // Run DevicePathToDriveLetterPath() on the NT style path we got from
+  // QueryDosDevice().  Expect the drive letter we started with.
+  ASSERT_TRUE(DevicePathToDriveLetterPath(actual_device_path, &win32_path));
+  ASSERT_EQ(real_drive_letter, win32_path.value());
+
+  // Add some directories to the path.  Expect those extra path componenets
+  // to be preserved.
+  FilePath kRelativePath(FPL("dir1\\dir2\\file.txt"));
+  ASSERT_TRUE(DevicePathToDriveLetterPath(
+      actual_device_path.Append(kRelativePath),
+      &win32_path));
+  EXPECT_EQ(FilePath(real_drive_letter + L"\\").Append(kRelativePath).value(),
+            win32_path.value());
+
+  // Deform the real path so that it is invalid by removing the last four
+  // characters.  The way windows names devices that are hard disks
+  // (\Device\HardDiskVolume${NUMBER}) guarantees that the string is longer
+  // than three characters.  The only way the truncated string could be a
+  // real drive is if more than 10^3 disks are mounted:
+  // \Device\HardDiskVolume10000 would be truncated to \Device\HardDiskVolume1
+  // Check that DevicePathToDriveLetterPath fails.
+  int path_length = actual_device_path.value().length();
+  int new_length = path_length - 4;
+  ASSERT_LT(0, new_length);
+  FilePath prefix_of_real_device_path(
+      actual_device_path.value().substr(0, new_length));
+  ASSERT_FALSE(DevicePathToDriveLetterPath(prefix_of_real_device_path,
+                                           &win32_path));
+
+  ASSERT_FALSE(DevicePathToDriveLetterPath(
+      prefix_of_real_device_path.Append(kRelativePath),
+      &win32_path));
+
+  // Deform the real path so that it is invalid by adding some characters. For
+  // example, if C: maps to \Device\HardDiskVolume8, then we simulate a
+  // request for the drive letter whose native path is
+  // \Device\HardDiskVolume812345 .  We assume such a device does not exist,
+  // because drives are numbered in order and mounting 112345 hard disks will
+  // never happen.
+  const FilePath::StringType kExtraChars = FPL("12345");
+
+  FilePath real_device_path_plus_numbers(
+      actual_device_path.value() + kExtraChars);
+
+  ASSERT_FALSE(DevicePathToDriveLetterPath(
+      real_device_path_plus_numbers,
+      &win32_path));
+
+  ASSERT_FALSE(DevicePathToDriveLetterPath(
+      real_device_path_plus_numbers.Append(kRelativePath),
+      &win32_path));
+}
+
+TEST_F(FileUtilTest, CreateTemporaryFileInDirLongPathTest) {
+  // Test that CreateTemporaryFileInDir() creates a path and returns a long path
+  // if it is available. This test requires that:
+  // - the filesystem at |temp_dir_| supports long filenames.
+  // - the account has FILE_LIST_DIRECTORY permission for all ancestor
+  //   directories of |temp_dir_|.
+  const FilePath::CharType kLongDirName[] = FPL("A long path");
+  const FilePath::CharType kTestSubDirName[] = FPL("test");
+  FilePath long_test_dir = temp_dir_.path().Append(kLongDirName);
+  ASSERT_TRUE(CreateDirectory(long_test_dir));
+
+  // kLongDirName is not a 8.3 component. So GetShortName() should give us a
+  // different short name.
+  WCHAR path_buffer[MAX_PATH];
+  DWORD path_buffer_length = GetShortPathName(long_test_dir.value().c_str(),
+                                              path_buffer, MAX_PATH);
+  ASSERT_LT(path_buffer_length, DWORD(MAX_PATH));
+  ASSERT_NE(DWORD(0), path_buffer_length);
+  FilePath short_test_dir(path_buffer);
+  ASSERT_STRNE(kLongDirName, short_test_dir.BaseName().value().c_str());
+
+  FilePath temp_file;
+  ASSERT_TRUE(CreateTemporaryFileInDir(short_test_dir, &temp_file));
+  EXPECT_STREQ(kLongDirName, temp_file.DirName().BaseName().value().c_str());
+  EXPECT_TRUE(PathExists(temp_file));
+
+  // Create a subdirectory of |long_test_dir| and make |long_test_dir|
+  // unreadable. We should still be able to create a temp file in the
+  // subdirectory, but we won't be able to determine the long path for it. This
+  // mimics the environment that some users run where their user profiles reside
+  // in a location where the don't have full access to the higher level
+  // directories. (Note that this assumption is true for NTFS, but not for some
+  // network file systems. E.g. AFS).
+  FilePath access_test_dir = long_test_dir.Append(kTestSubDirName);
+  ASSERT_TRUE(CreateDirectory(access_test_dir));
+  FilePermissionRestorer long_test_dir_restorer(long_test_dir);
+  ASSERT_TRUE(MakeFileUnreadable(long_test_dir));
+
+  // Use the short form of the directory to create a temporary filename.
+  ASSERT_TRUE(CreateTemporaryFileInDir(
+      short_test_dir.Append(kTestSubDirName), &temp_file));
+  EXPECT_TRUE(PathExists(temp_file));
+  EXPECT_TRUE(short_test_dir.IsParent(temp_file.DirName()));
+
+  // Check that the long path can't be determined for |temp_file|.
+  path_buffer_length = GetLongPathName(temp_file.value().c_str(),
+                                       path_buffer, MAX_PATH);
+  EXPECT_EQ(DWORD(0), path_buffer_length);
+}
+
+#endif  // defined(OS_WIN)
+
+#if defined(OS_POSIX)
+
+TEST_F(FileUtilTest, CreateAndReadSymlinks) {
+  FilePath link_from = temp_dir_.path().Append(FPL("from_file"));
+  FilePath link_to = temp_dir_.path().Append(FPL("to_file"));
+  CreateTextFile(link_to, bogus_content);
+
+  ASSERT_TRUE(CreateSymbolicLink(link_to, link_from))
+    << "Failed to create file symlink.";
+
+  // If we created the link properly, we should be able to read the contents
+  // through it.
+  std::wstring contents = ReadTextFile(link_from);
+  EXPECT_EQ(bogus_content, contents);
+
+  FilePath result;
+  ASSERT_TRUE(ReadSymbolicLink(link_from, &result));
+  EXPECT_EQ(link_to.value(), result.value());
+
+  // Link to a directory.
+  link_from = temp_dir_.path().Append(FPL("from_dir"));
+  link_to = temp_dir_.path().Append(FPL("to_dir"));
+  ASSERT_TRUE(CreateDirectory(link_to));
+  ASSERT_TRUE(CreateSymbolicLink(link_to, link_from))
+    << "Failed to create directory symlink.";
+
+  // Test failures.
+  EXPECT_FALSE(CreateSymbolicLink(link_to, link_to));
+  EXPECT_FALSE(ReadSymbolicLink(link_to, &result));
+  FilePath missing = temp_dir_.path().Append(FPL("missing"));
+  EXPECT_FALSE(ReadSymbolicLink(missing, &result));
+}
+
+// The following test of NormalizeFilePath() require that we create a symlink.
+// This can not be done on Windows before Vista.  On Vista, creating a symlink
+// requires privilege "SeCreateSymbolicLinkPrivilege".
+// TODO(skerner): Investigate the possibility of giving base_unittests the
+// privileges required to create a symlink.
+TEST_F(FileUtilTest, NormalizeFilePathSymlinks) {
+  // Link one file to another.
+  FilePath link_from = temp_dir_.path().Append(FPL("from_file"));
+  FilePath link_to = temp_dir_.path().Append(FPL("to_file"));
+  CreateTextFile(link_to, bogus_content);
+
+  ASSERT_TRUE(CreateSymbolicLink(link_to, link_from))
+    << "Failed to create file symlink.";
+
+  // Check that NormalizeFilePath sees the link.
+  FilePath normalized_path;
+  ASSERT_TRUE(NormalizeFilePath(link_from, &normalized_path));
+  EXPECT_NE(link_from, link_to);
+  EXPECT_EQ(link_to.BaseName().value(), normalized_path.BaseName().value());
+  EXPECT_EQ(link_to.BaseName().value(), normalized_path.BaseName().value());
+
+  // Link to a directory.
+  link_from = temp_dir_.path().Append(FPL("from_dir"));
+  link_to = temp_dir_.path().Append(FPL("to_dir"));
+  ASSERT_TRUE(CreateDirectory(link_to));
+  ASSERT_TRUE(CreateSymbolicLink(link_to, link_from))
+    << "Failed to create directory symlink.";
+
+  EXPECT_FALSE(NormalizeFilePath(link_from, &normalized_path))
+    << "Links to directories should return false.";
+
+  // Test that a loop in the links causes NormalizeFilePath() to return false.
+  link_from = temp_dir_.path().Append(FPL("link_a"));
+  link_to = temp_dir_.path().Append(FPL("link_b"));
+  ASSERT_TRUE(CreateSymbolicLink(link_to, link_from))
+    << "Failed to create loop symlink a.";
+  ASSERT_TRUE(CreateSymbolicLink(link_from, link_to))
+    << "Failed to create loop symlink b.";
+
+  // Infinite loop!
+  EXPECT_FALSE(NormalizeFilePath(link_from, &normalized_path));
+}
+#endif  // defined(OS_POSIX)
+
+TEST_F(FileUtilTest, DeleteNonExistent) {
+  FilePath non_existent = temp_dir_.path().AppendASCII("bogus_file_dne.foobar");
+  ASSERT_FALSE(PathExists(non_existent));
+
+  EXPECT_TRUE(DeleteFile(non_existent, false));
+  ASSERT_FALSE(PathExists(non_existent));
+  EXPECT_TRUE(DeleteFile(non_existent, true));
+  ASSERT_FALSE(PathExists(non_existent));
+}
+
+TEST_F(FileUtilTest, DeleteNonExistentWithNonExistentParent) {
+  FilePath non_existent = temp_dir_.path().AppendASCII("bogus_topdir");
+  non_existent = non_existent.AppendASCII("bogus_subdir");
+  ASSERT_FALSE(PathExists(non_existent));
+
+  EXPECT_TRUE(DeleteFile(non_existent, false));
+  ASSERT_FALSE(PathExists(non_existent));
+  EXPECT_TRUE(DeleteFile(non_existent, true));
+  ASSERT_FALSE(PathExists(non_existent));
+}
+
+TEST_F(FileUtilTest, DeleteFile) {
+  // Create a file
+  FilePath file_name = temp_dir_.path().Append(FPL("Test DeleteFile 1.txt"));
+  CreateTextFile(file_name, bogus_content);
+  ASSERT_TRUE(PathExists(file_name));
+
+  // Make sure it's deleted
+  EXPECT_TRUE(DeleteFile(file_name, false));
+  EXPECT_FALSE(PathExists(file_name));
+
+  // Test recursive case, create a new file
+  file_name = temp_dir_.path().Append(FPL("Test DeleteFile 2.txt"));
+  CreateTextFile(file_name, bogus_content);
+  ASSERT_TRUE(PathExists(file_name));
+
+  // Make sure it's deleted
+  EXPECT_TRUE(DeleteFile(file_name, true));
+  EXPECT_FALSE(PathExists(file_name));
+}
+
+#if defined(OS_POSIX)
+TEST_F(FileUtilTest, DeleteSymlinkToExistentFile) {
+  // Create a file.
+  FilePath file_name = temp_dir_.path().Append(FPL("Test DeleteFile 2.txt"));
+  CreateTextFile(file_name, bogus_content);
+  ASSERT_TRUE(PathExists(file_name));
+
+  // Create a symlink to the file.
+  FilePath file_link = temp_dir_.path().Append("file_link_2");
+  ASSERT_TRUE(CreateSymbolicLink(file_name, file_link))
+      << "Failed to create symlink.";
+
+  // Delete the symbolic link.
+  EXPECT_TRUE(DeleteFile(file_link, false));
+
+  // Make sure original file is not deleted.
+  EXPECT_FALSE(PathExists(file_link));
+  EXPECT_TRUE(PathExists(file_name));
+}
+
+TEST_F(FileUtilTest, DeleteSymlinkToNonExistentFile) {
+  // Create a non-existent file path.
+  FilePath non_existent = temp_dir_.path().Append(FPL("Test DeleteFile 3.txt"));
+  EXPECT_FALSE(PathExists(non_existent));
+
+  // Create a symlink to the non-existent file.
+  FilePath file_link = temp_dir_.path().Append("file_link_3");
+  ASSERT_TRUE(CreateSymbolicLink(non_existent, file_link))
+      << "Failed to create symlink.";
+
+  // Make sure the symbolic link is exist.
+  EXPECT_TRUE(IsLink(file_link));
+  EXPECT_FALSE(PathExists(file_link));
+
+  // Delete the symbolic link.
+  EXPECT_TRUE(DeleteFile(file_link, false));
+
+  // Make sure the symbolic link is deleted.
+  EXPECT_FALSE(IsLink(file_link));
+}
+
+TEST_F(FileUtilTest, ChangeFilePermissionsAndRead) {
+  // Create a file path.
+  FilePath file_name = temp_dir_.path().Append(FPL("Test Readable File.txt"));
+  EXPECT_FALSE(PathExists(file_name));
+
+  const std::string kData("hello");
+
+  int buffer_size = kData.length();
+  char* buffer = new char[buffer_size];
+
+  // Write file.
+  EXPECT_EQ(static_cast<int>(kData.length()),
+            WriteFile(file_name, kData.data(), kData.length()));
+  EXPECT_TRUE(PathExists(file_name));
+
+  // Make sure the file is readable.
+  int32 mode = 0;
+  EXPECT_TRUE(GetPosixFilePermissions(file_name, &mode));
+  EXPECT_TRUE(mode & FILE_PERMISSION_READ_BY_USER);
+
+  // Get rid of the read permission.
+  EXPECT_TRUE(SetPosixFilePermissions(file_name, 0u));
+  EXPECT_TRUE(GetPosixFilePermissions(file_name, &mode));
+  EXPECT_FALSE(mode & FILE_PERMISSION_READ_BY_USER);
+  // Make sure the file can't be read.
+  EXPECT_EQ(-1, ReadFile(file_name, buffer, buffer_size));
+
+  // Give the read permission.
+  EXPECT_TRUE(SetPosixFilePermissions(file_name, FILE_PERMISSION_READ_BY_USER));
+  EXPECT_TRUE(GetPosixFilePermissions(file_name, &mode));
+  EXPECT_TRUE(mode & FILE_PERMISSION_READ_BY_USER);
+  // Make sure the file can be read.
+  EXPECT_EQ(static_cast<int>(kData.length()),
+            ReadFile(file_name, buffer, buffer_size));
+
+  // Delete the file.
+  EXPECT_TRUE(DeleteFile(file_name, false));
+  EXPECT_FALSE(PathExists(file_name));
+
+  delete[] buffer;
+}
+
+TEST_F(FileUtilTest, ChangeFilePermissionsAndWrite) {
+  // Create a file path.
+  FilePath file_name = temp_dir_.path().Append(FPL("Test Readable File.txt"));
+  EXPECT_FALSE(PathExists(file_name));
+
+  const std::string kData("hello");
+
+  // Write file.
+  EXPECT_EQ(static_cast<int>(kData.length()),
+            WriteFile(file_name, kData.data(), kData.length()));
+  EXPECT_TRUE(PathExists(file_name));
+
+  // Make sure the file is writable.
+  int mode = 0;
+  EXPECT_TRUE(GetPosixFilePermissions(file_name, &mode));
+  EXPECT_TRUE(mode & FILE_PERMISSION_WRITE_BY_USER);
+  EXPECT_TRUE(PathIsWritable(file_name));
+
+  // Get rid of the write permission.
+  EXPECT_TRUE(SetPosixFilePermissions(file_name, 0u));
+  EXPECT_TRUE(GetPosixFilePermissions(file_name, &mode));
+  EXPECT_FALSE(mode & FILE_PERMISSION_WRITE_BY_USER);
+  // Make sure the file can't be write.
+  EXPECT_EQ(-1, WriteFile(file_name, kData.data(), kData.length()));
+  EXPECT_FALSE(PathIsWritable(file_name));
+
+  // Give read permission.
+  EXPECT_TRUE(SetPosixFilePermissions(file_name,
+                                      FILE_PERMISSION_WRITE_BY_USER));
+  EXPECT_TRUE(GetPosixFilePermissions(file_name, &mode));
+  EXPECT_TRUE(mode & FILE_PERMISSION_WRITE_BY_USER);
+  // Make sure the file can be write.
+  EXPECT_EQ(static_cast<int>(kData.length()),
+            WriteFile(file_name, kData.data(), kData.length()));
+  EXPECT_TRUE(PathIsWritable(file_name));
+
+  // Delete the file.
+  EXPECT_TRUE(DeleteFile(file_name, false));
+  EXPECT_FALSE(PathExists(file_name));
+}
+
+TEST_F(FileUtilTest, ChangeDirectoryPermissionsAndEnumerate) {
+  // Create a directory path.
+  FilePath subdir_path =
+      temp_dir_.path().Append(FPL("PermissionTest1"));
+  CreateDirectory(subdir_path);
+  ASSERT_TRUE(PathExists(subdir_path));
+
+  // Create a dummy file to enumerate.
+  FilePath file_name = subdir_path.Append(FPL("Test Readable File.txt"));
+  EXPECT_FALSE(PathExists(file_name));
+  const std::string kData("hello");
+  EXPECT_EQ(static_cast<int>(kData.length()),
+            WriteFile(file_name, kData.data(), kData.length()));
+  EXPECT_TRUE(PathExists(file_name));
+
+  // Make sure the directory has the all permissions.
+  int mode = 0;
+  EXPECT_TRUE(GetPosixFilePermissions(subdir_path, &mode));
+  EXPECT_EQ(FILE_PERMISSION_USER_MASK, mode & FILE_PERMISSION_USER_MASK);
+
+  // Get rid of the permissions from the directory.
+  EXPECT_TRUE(SetPosixFilePermissions(subdir_path, 0u));
+  EXPECT_TRUE(GetPosixFilePermissions(subdir_path, &mode));
+  EXPECT_FALSE(mode & FILE_PERMISSION_USER_MASK);
+
+  // Make sure the file in the directory can't be enumerated.
+  FileEnumerator f1(subdir_path, true, FileEnumerator::FILES);
+  EXPECT_TRUE(PathExists(subdir_path));
+  FindResultCollector c1(&f1);
+  EXPECT_EQ(0, c1.size());
+  EXPECT_FALSE(GetPosixFilePermissions(file_name, &mode));
+
+  // Give the permissions to the directory.
+  EXPECT_TRUE(SetPosixFilePermissions(subdir_path, FILE_PERMISSION_USER_MASK));
+  EXPECT_TRUE(GetPosixFilePermissions(subdir_path, &mode));
+  EXPECT_EQ(FILE_PERMISSION_USER_MASK, mode & FILE_PERMISSION_USER_MASK);
+
+  // Make sure the file in the directory can be enumerated.
+  FileEnumerator f2(subdir_path, true, FileEnumerator::FILES);
+  FindResultCollector c2(&f2);
+  EXPECT_TRUE(c2.HasFile(file_name));
+  EXPECT_EQ(1, c2.size());
+
+  // Delete the file.
+  EXPECT_TRUE(DeleteFile(subdir_path, true));
+  EXPECT_FALSE(PathExists(subdir_path));
+}
+
+#endif  // defined(OS_POSIX)
+
+#if defined(OS_WIN)
+// Tests that the Delete function works for wild cards, especially
+// with the recursion flag.  Also coincidentally tests PathExists.
+// TODO(erikkay): see if anyone's actually using this feature of the API
+TEST_F(FileUtilTest, DeleteWildCard) {
+  // Create a file and a directory
+  FilePath file_name = temp_dir_.path().Append(FPL("Test DeleteWildCard.txt"));
+  CreateTextFile(file_name, bogus_content);
+  ASSERT_TRUE(PathExists(file_name));
+
+  FilePath subdir_path = temp_dir_.path().Append(FPL("DeleteWildCardDir"));
+  CreateDirectory(subdir_path);
+  ASSERT_TRUE(PathExists(subdir_path));
+
+  // Create the wildcard path
+  FilePath directory_contents = temp_dir_.path();
+  directory_contents = directory_contents.Append(FPL("*"));
+
+  // Delete non-recursively and check that only the file is deleted
+  EXPECT_TRUE(DeleteFile(directory_contents, false));
+  EXPECT_FALSE(PathExists(file_name));
+  EXPECT_TRUE(PathExists(subdir_path));
+
+  // Delete recursively and make sure all contents are deleted
+  EXPECT_TRUE(DeleteFile(directory_contents, true));
+  EXPECT_FALSE(PathExists(file_name));
+  EXPECT_FALSE(PathExists(subdir_path));
+}
+
+// TODO(erikkay): see if anyone's actually using this feature of the API
+TEST_F(FileUtilTest, DeleteNonExistantWildCard) {
+  // Create a file and a directory
+  FilePath subdir_path =
+      temp_dir_.path().Append(FPL("DeleteNonExistantWildCard"));
+  CreateDirectory(subdir_path);
+  ASSERT_TRUE(PathExists(subdir_path));
+
+  // Create the wildcard path
+  FilePath directory_contents = subdir_path;
+  directory_contents = directory_contents.Append(FPL("*"));
+
+  // Delete non-recursively and check nothing got deleted
+  EXPECT_TRUE(DeleteFile(directory_contents, false));
+  EXPECT_TRUE(PathExists(subdir_path));
+
+  // Delete recursively and check nothing got deleted
+  EXPECT_TRUE(DeleteFile(directory_contents, true));
+  EXPECT_TRUE(PathExists(subdir_path));
+}
+#endif
+
+// Tests non-recursive Delete() for a directory.
+TEST_F(FileUtilTest, DeleteDirNonRecursive) {
+  // Create a subdirectory and put a file and two directories inside.
+  FilePath test_subdir = temp_dir_.path().Append(FPL("DeleteDirNonRecursive"));
+  CreateDirectory(test_subdir);
+  ASSERT_TRUE(PathExists(test_subdir));
+
+  FilePath file_name = test_subdir.Append(FPL("Test DeleteDir.txt"));
+  CreateTextFile(file_name, bogus_content);
+  ASSERT_TRUE(PathExists(file_name));
+
+  FilePath subdir_path1 = test_subdir.Append(FPL("TestSubDir1"));
+  CreateDirectory(subdir_path1);
+  ASSERT_TRUE(PathExists(subdir_path1));
+
+  FilePath subdir_path2 = test_subdir.Append(FPL("TestSubDir2"));
+  CreateDirectory(subdir_path2);
+  ASSERT_TRUE(PathExists(subdir_path2));
+
+  // Delete non-recursively and check that the empty dir got deleted
+  EXPECT_TRUE(DeleteFile(subdir_path2, false));
+  EXPECT_FALSE(PathExists(subdir_path2));
+
+  // Delete non-recursively and check that nothing got deleted
+  EXPECT_FALSE(DeleteFile(test_subdir, false));
+  EXPECT_TRUE(PathExists(test_subdir));
+  EXPECT_TRUE(PathExists(file_name));
+  EXPECT_TRUE(PathExists(subdir_path1));
+}
+
+// Tests recursive Delete() for a directory.
+TEST_F(FileUtilTest, DeleteDirRecursive) {
+  // Create a subdirectory and put a file and two directories inside.
+  FilePath test_subdir = temp_dir_.path().Append(FPL("DeleteDirRecursive"));
+  CreateDirectory(test_subdir);
+  ASSERT_TRUE(PathExists(test_subdir));
+
+  FilePath file_name = test_subdir.Append(FPL("Test DeleteDirRecursive.txt"));
+  CreateTextFile(file_name, bogus_content);
+  ASSERT_TRUE(PathExists(file_name));
+
+  FilePath subdir_path1 = test_subdir.Append(FPL("TestSubDir1"));
+  CreateDirectory(subdir_path1);
+  ASSERT_TRUE(PathExists(subdir_path1));
+
+  FilePath subdir_path2 = test_subdir.Append(FPL("TestSubDir2"));
+  CreateDirectory(subdir_path2);
+  ASSERT_TRUE(PathExists(subdir_path2));
+
+  // Delete recursively and check that the empty dir got deleted
+  EXPECT_TRUE(DeleteFile(subdir_path2, true));
+  EXPECT_FALSE(PathExists(subdir_path2));
+
+  // Delete recursively and check that everything got deleted
+  EXPECT_TRUE(DeleteFile(test_subdir, true));
+  EXPECT_FALSE(PathExists(file_name));
+  EXPECT_FALSE(PathExists(subdir_path1));
+  EXPECT_FALSE(PathExists(test_subdir));
+}
+
+TEST_F(FileUtilTest, MoveFileNew) {
+  // Create a file
+  FilePath file_name_from =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Move_Test_File.txt"));
+  CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(PathExists(file_name_from));
+
+  // The destination.
+  FilePath file_name_to = temp_dir_.path().Append(
+      FILE_PATH_LITERAL("Move_Test_File_Destination.txt"));
+  ASSERT_FALSE(PathExists(file_name_to));
+
+  EXPECT_TRUE(Move(file_name_from, file_name_to));
+
+  // Check everything has been moved.
+  EXPECT_FALSE(PathExists(file_name_from));
+  EXPECT_TRUE(PathExists(file_name_to));
+}
+
+TEST_F(FileUtilTest, MoveFileExists) {
+  // Create a file
+  FilePath file_name_from =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Move_Test_File.txt"));
+  CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(PathExists(file_name_from));
+
+  // The destination name.
+  FilePath file_name_to = temp_dir_.path().Append(
+      FILE_PATH_LITERAL("Move_Test_File_Destination.txt"));
+  CreateTextFile(file_name_to, L"Old file content");
+  ASSERT_TRUE(PathExists(file_name_to));
+
+  EXPECT_TRUE(Move(file_name_from, file_name_to));
+
+  // Check everything has been moved.
+  EXPECT_FALSE(PathExists(file_name_from));
+  EXPECT_TRUE(PathExists(file_name_to));
+  EXPECT_TRUE(L"Gooooooooooooooooooooogle" == ReadTextFile(file_name_to));
+}
+
+TEST_F(FileUtilTest, MoveFileDirExists) {
+  // Create a file
+  FilePath file_name_from =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Move_Test_File.txt"));
+  CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(PathExists(file_name_from));
+
+  // The destination directory
+  FilePath dir_name_to =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Destination"));
+  CreateDirectory(dir_name_to);
+  ASSERT_TRUE(PathExists(dir_name_to));
+
+  EXPECT_FALSE(Move(file_name_from, dir_name_to));
+}
+
+
+TEST_F(FileUtilTest, MoveNew) {
+  // Create a directory
+  FilePath dir_name_from =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Move_From_Subdir"));
+  CreateDirectory(dir_name_from);
+  ASSERT_TRUE(PathExists(dir_name_from));
+
+  // Create a file under the directory
+  FilePath txt_file_name(FILE_PATH_LITERAL("Move_Test_File.txt"));
+  FilePath file_name_from = dir_name_from.Append(txt_file_name);
+  CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(PathExists(file_name_from));
+
+  // Move the directory.
+  FilePath dir_name_to =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Move_To_Subdir"));
+  FilePath file_name_to =
+      dir_name_to.Append(FILE_PATH_LITERAL("Move_Test_File.txt"));
+
+  ASSERT_FALSE(PathExists(dir_name_to));
+
+  EXPECT_TRUE(Move(dir_name_from, dir_name_to));
+
+  // Check everything has been moved.
+  EXPECT_FALSE(PathExists(dir_name_from));
+  EXPECT_FALSE(PathExists(file_name_from));
+  EXPECT_TRUE(PathExists(dir_name_to));
+  EXPECT_TRUE(PathExists(file_name_to));
+
+  // Test path traversal.
+  file_name_from = dir_name_to.Append(txt_file_name);
+  file_name_to = dir_name_to.Append(FILE_PATH_LITERAL(".."));
+  file_name_to = file_name_to.Append(txt_file_name);
+  EXPECT_FALSE(Move(file_name_from, file_name_to));
+  EXPECT_TRUE(PathExists(file_name_from));
+  EXPECT_FALSE(PathExists(file_name_to));
+  EXPECT_TRUE(internal::MoveUnsafe(file_name_from, file_name_to));
+  EXPECT_FALSE(PathExists(file_name_from));
+  EXPECT_TRUE(PathExists(file_name_to));
+}
+
+TEST_F(FileUtilTest, MoveExist) {
+  // Create a directory
+  FilePath dir_name_from =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Move_From_Subdir"));
+  CreateDirectory(dir_name_from);
+  ASSERT_TRUE(PathExists(dir_name_from));
+
+  // Create a file under the directory
+  FilePath file_name_from =
+      dir_name_from.Append(FILE_PATH_LITERAL("Move_Test_File.txt"));
+  CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(PathExists(file_name_from));
+
+  // Move the directory
+  FilePath dir_name_exists =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Destination"));
+
+  FilePath dir_name_to =
+      dir_name_exists.Append(FILE_PATH_LITERAL("Move_To_Subdir"));
+  FilePath file_name_to =
+      dir_name_to.Append(FILE_PATH_LITERAL("Move_Test_File.txt"));
+
+  // Create the destination directory.
+  CreateDirectory(dir_name_exists);
+  ASSERT_TRUE(PathExists(dir_name_exists));
+
+  EXPECT_TRUE(Move(dir_name_from, dir_name_to));
+
+  // Check everything has been moved.
+  EXPECT_FALSE(PathExists(dir_name_from));
+  EXPECT_FALSE(PathExists(file_name_from));
+  EXPECT_TRUE(PathExists(dir_name_to));
+  EXPECT_TRUE(PathExists(file_name_to));
+}
+
+TEST_F(FileUtilTest, CopyDirectoryRecursivelyNew) {
+  // Create a directory.
+  FilePath dir_name_from =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
+  CreateDirectory(dir_name_from);
+  ASSERT_TRUE(PathExists(dir_name_from));
+
+  // Create a file under the directory.
+  FilePath file_name_from =
+      dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(PathExists(file_name_from));
+
+  // Create a subdirectory.
+  FilePath subdir_name_from =
+      dir_name_from.Append(FILE_PATH_LITERAL("Subdir"));
+  CreateDirectory(subdir_name_from);
+  ASSERT_TRUE(PathExists(subdir_name_from));
+
+  // Create a file under the subdirectory.
+  FilePath file_name2_from =
+      subdir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  CreateTextFile(file_name2_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(PathExists(file_name2_from));
+
+  // Copy the directory recursively.
+  FilePath dir_name_to =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_To_Subdir"));
+  FilePath file_name_to =
+      dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  FilePath subdir_name_to =
+      dir_name_to.Append(FILE_PATH_LITERAL("Subdir"));
+  FilePath file_name2_to =
+      subdir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+
+  ASSERT_FALSE(PathExists(dir_name_to));
+
+  EXPECT_TRUE(CopyDirectory(dir_name_from, dir_name_to, true));
+
+  // Check everything has been copied.
+  EXPECT_TRUE(PathExists(dir_name_from));
+  EXPECT_TRUE(PathExists(file_name_from));
+  EXPECT_TRUE(PathExists(subdir_name_from));
+  EXPECT_TRUE(PathExists(file_name2_from));
+  EXPECT_TRUE(PathExists(dir_name_to));
+  EXPECT_TRUE(PathExists(file_name_to));
+  EXPECT_TRUE(PathExists(subdir_name_to));
+  EXPECT_TRUE(PathExists(file_name2_to));
+}
+
+TEST_F(FileUtilTest, CopyDirectoryRecursivelyExists) {
+  // Create a directory.
+  FilePath dir_name_from =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
+  CreateDirectory(dir_name_from);
+  ASSERT_TRUE(PathExists(dir_name_from));
+
+  // Create a file under the directory.
+  FilePath file_name_from =
+      dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(PathExists(file_name_from));
+
+  // Create a subdirectory.
+  FilePath subdir_name_from =
+      dir_name_from.Append(FILE_PATH_LITERAL("Subdir"));
+  CreateDirectory(subdir_name_from);
+  ASSERT_TRUE(PathExists(subdir_name_from));
+
+  // Create a file under the subdirectory.
+  FilePath file_name2_from =
+      subdir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  CreateTextFile(file_name2_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(PathExists(file_name2_from));
+
+  // Copy the directory recursively.
+  FilePath dir_name_exists =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Destination"));
+
+  FilePath dir_name_to =
+      dir_name_exists.Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
+  FilePath file_name_to =
+      dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  FilePath subdir_name_to =
+      dir_name_to.Append(FILE_PATH_LITERAL("Subdir"));
+  FilePath file_name2_to =
+      subdir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+
+  // Create the destination directory.
+  CreateDirectory(dir_name_exists);
+  ASSERT_TRUE(PathExists(dir_name_exists));
+
+  EXPECT_TRUE(CopyDirectory(dir_name_from, dir_name_exists, true));
+
+  // Check everything has been copied.
+  EXPECT_TRUE(PathExists(dir_name_from));
+  EXPECT_TRUE(PathExists(file_name_from));
+  EXPECT_TRUE(PathExists(subdir_name_from));
+  EXPECT_TRUE(PathExists(file_name2_from));
+  EXPECT_TRUE(PathExists(dir_name_to));
+  EXPECT_TRUE(PathExists(file_name_to));
+  EXPECT_TRUE(PathExists(subdir_name_to));
+  EXPECT_TRUE(PathExists(file_name2_to));
+}
+
+TEST_F(FileUtilTest, CopyDirectoryNew) {
+  // Create a directory.
+  FilePath dir_name_from =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
+  CreateDirectory(dir_name_from);
+  ASSERT_TRUE(PathExists(dir_name_from));
+
+  // Create a file under the directory.
+  FilePath file_name_from =
+      dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(PathExists(file_name_from));
+
+  // Create a subdirectory.
+  FilePath subdir_name_from =
+      dir_name_from.Append(FILE_PATH_LITERAL("Subdir"));
+  CreateDirectory(subdir_name_from);
+  ASSERT_TRUE(PathExists(subdir_name_from));
+
+  // Create a file under the subdirectory.
+  FilePath file_name2_from =
+      subdir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  CreateTextFile(file_name2_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(PathExists(file_name2_from));
+
+  // Copy the directory not recursively.
+  FilePath dir_name_to =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_To_Subdir"));
+  FilePath file_name_to =
+      dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  FilePath subdir_name_to =
+      dir_name_to.Append(FILE_PATH_LITERAL("Subdir"));
+
+  ASSERT_FALSE(PathExists(dir_name_to));
+
+  EXPECT_TRUE(CopyDirectory(dir_name_from, dir_name_to, false));
+
+  // Check everything has been copied.
+  EXPECT_TRUE(PathExists(dir_name_from));
+  EXPECT_TRUE(PathExists(file_name_from));
+  EXPECT_TRUE(PathExists(subdir_name_from));
+  EXPECT_TRUE(PathExists(file_name2_from));
+  EXPECT_TRUE(PathExists(dir_name_to));
+  EXPECT_TRUE(PathExists(file_name_to));
+  EXPECT_FALSE(PathExists(subdir_name_to));
+}
+
+TEST_F(FileUtilTest, CopyDirectoryExists) {
+  // Create a directory.
+  FilePath dir_name_from =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
+  CreateDirectory(dir_name_from);
+  ASSERT_TRUE(PathExists(dir_name_from));
+
+  // Create a file under the directory.
+  FilePath file_name_from =
+      dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(PathExists(file_name_from));
+
+  // Create a subdirectory.
+  FilePath subdir_name_from =
+      dir_name_from.Append(FILE_PATH_LITERAL("Subdir"));
+  CreateDirectory(subdir_name_from);
+  ASSERT_TRUE(PathExists(subdir_name_from));
+
+  // Create a file under the subdirectory.
+  FilePath file_name2_from =
+      subdir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  CreateTextFile(file_name2_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(PathExists(file_name2_from));
+
+  // Copy the directory not recursively.
+  FilePath dir_name_to =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_To_Subdir"));
+  FilePath file_name_to =
+      dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  FilePath subdir_name_to =
+      dir_name_to.Append(FILE_PATH_LITERAL("Subdir"));
+
+  // Create the destination directory.
+  CreateDirectory(dir_name_to);
+  ASSERT_TRUE(PathExists(dir_name_to));
+
+  EXPECT_TRUE(CopyDirectory(dir_name_from, dir_name_to, false));
+
+  // Check everything has been copied.
+  EXPECT_TRUE(PathExists(dir_name_from));
+  EXPECT_TRUE(PathExists(file_name_from));
+  EXPECT_TRUE(PathExists(subdir_name_from));
+  EXPECT_TRUE(PathExists(file_name2_from));
+  EXPECT_TRUE(PathExists(dir_name_to));
+  EXPECT_TRUE(PathExists(file_name_to));
+  EXPECT_FALSE(PathExists(subdir_name_to));
+}
+
+TEST_F(FileUtilTest, CopyFileWithCopyDirectoryRecursiveToNew) {
+  // Create a file
+  FilePath file_name_from =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(PathExists(file_name_from));
+
+  // The destination name
+  FilePath file_name_to = temp_dir_.path().Append(
+      FILE_PATH_LITERAL("Copy_Test_File_Destination.txt"));
+  ASSERT_FALSE(PathExists(file_name_to));
+
+  EXPECT_TRUE(CopyDirectory(file_name_from, file_name_to, true));
+
+  // Check the has been copied
+  EXPECT_TRUE(PathExists(file_name_to));
+}
+
+TEST_F(FileUtilTest, CopyFileWithCopyDirectoryRecursiveToExisting) {
+  // Create a file
+  FilePath file_name_from =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(PathExists(file_name_from));
+
+  // The destination name
+  FilePath file_name_to = temp_dir_.path().Append(
+      FILE_PATH_LITERAL("Copy_Test_File_Destination.txt"));
+  CreateTextFile(file_name_to, L"Old file content");
+  ASSERT_TRUE(PathExists(file_name_to));
+
+  EXPECT_TRUE(CopyDirectory(file_name_from, file_name_to, true));
+
+  // Check the has been copied
+  EXPECT_TRUE(PathExists(file_name_to));
+  EXPECT_TRUE(L"Gooooooooooooooooooooogle" == ReadTextFile(file_name_to));
+}
+
+TEST_F(FileUtilTest, CopyFileWithCopyDirectoryRecursiveToExistingDirectory) {
+  // Create a file
+  FilePath file_name_from =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(PathExists(file_name_from));
+
+  // The destination
+  FilePath dir_name_to =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Destination"));
+  CreateDirectory(dir_name_to);
+  ASSERT_TRUE(PathExists(dir_name_to));
+  FilePath file_name_to =
+      dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+
+  EXPECT_TRUE(CopyDirectory(file_name_from, dir_name_to, true));
+
+  // Check the has been copied
+  EXPECT_TRUE(PathExists(file_name_to));
+}
+
+TEST_F(FileUtilTest, CopyDirectoryWithTrailingSeparators) {
+  // Create a directory.
+  FilePath dir_name_from =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
+  CreateDirectory(dir_name_from);
+  ASSERT_TRUE(PathExists(dir_name_from));
+
+  // Create a file under the directory.
+  FilePath file_name_from =
+      dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(PathExists(file_name_from));
+
+  // Copy the directory recursively.
+  FilePath dir_name_to =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_To_Subdir"));
+  FilePath file_name_to =
+      dir_name_to.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+
+  // Create from path with trailing separators.
+#if defined(OS_WIN)
+  FilePath from_path =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_From_Subdir\\\\\\"));
+#elif defined (OS_POSIX)
+  FilePath from_path =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_From_Subdir///"));
+#endif
+
+  EXPECT_TRUE(CopyDirectory(from_path, dir_name_to, true));
+
+  // Check everything has been copied.
+  EXPECT_TRUE(PathExists(dir_name_from));
+  EXPECT_TRUE(PathExists(file_name_from));
+  EXPECT_TRUE(PathExists(dir_name_to));
+  EXPECT_TRUE(PathExists(file_name_to));
+}
+
+// Sets the source file to read-only.
+void SetReadOnly(const FilePath& path, bool read_only) {
+#if defined(OS_WIN)
+  // On Windows, it involves setting/removing the 'readonly' bit.
+  DWORD attrs = GetFileAttributes(path.value().c_str());
+  ASSERT_NE(INVALID_FILE_ATTRIBUTES, attrs);
+  ASSERT_TRUE(SetFileAttributes(
+      path.value().c_str(),
+      read_only ? (attrs | FILE_ATTRIBUTE_READONLY) :
+          (attrs & ~FILE_ATTRIBUTE_READONLY)));
+
+  DWORD expected = read_only ?
+      ((attrs & (FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_DIRECTORY)) |
+          FILE_ATTRIBUTE_READONLY) :
+      (attrs & (FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_DIRECTORY));
+
+  // Ignore FILE_ATTRIBUTE_NOT_CONTENT_INDEXED if present.
+  attrs = GetFileAttributes(path.value().c_str()) &
+          ~FILE_ATTRIBUTE_NOT_CONTENT_INDEXED;
+  ASSERT_EQ(expected, attrs);
+#else
+  // On all other platforms, it involves removing/setting the write bit.
+  mode_t mode = read_only ? S_IRUSR : (S_IRUSR | S_IWUSR);
+  EXPECT_TRUE(SetPosixFilePermissions(
+      path, DirectoryExists(path) ? (mode | S_IXUSR) : mode));
+#endif
+}
+
+bool IsReadOnly(const FilePath& path) {
+#if defined(OS_WIN)
+  DWORD attrs = GetFileAttributes(path.value().c_str());
+  EXPECT_NE(INVALID_FILE_ATTRIBUTES, attrs);
+  return attrs & FILE_ATTRIBUTE_READONLY;
+#else
+  int mode = 0;
+  EXPECT_TRUE(GetPosixFilePermissions(path, &mode));
+  return !(mode & S_IWUSR);
+#endif
+}
+
+TEST_F(FileUtilTest, CopyDirectoryACL) {
+  // Create source directories.
+  FilePath src = temp_dir_.path().Append(FILE_PATH_LITERAL("src"));
+  FilePath src_subdir = src.Append(FILE_PATH_LITERAL("subdir"));
+  CreateDirectory(src_subdir);
+  ASSERT_TRUE(PathExists(src_subdir));
+
+  // Create a file under the directory.
+  FilePath src_file = src.Append(FILE_PATH_LITERAL("src.txt"));
+  CreateTextFile(src_file, L"Gooooooooooooooooooooogle");
+  SetReadOnly(src_file, true);
+  ASSERT_TRUE(IsReadOnly(src_file));
+
+  // Make directory read-only.
+  SetReadOnly(src_subdir, true);
+  ASSERT_TRUE(IsReadOnly(src_subdir));
+
+  // Copy the directory recursively.
+  FilePath dst = temp_dir_.path().Append(FILE_PATH_LITERAL("dst"));
+  FilePath dst_file = dst.Append(FILE_PATH_LITERAL("src.txt"));
+  EXPECT_TRUE(CopyDirectory(src, dst, true));
+
+  FilePath dst_subdir = dst.Append(FILE_PATH_LITERAL("subdir"));
+  ASSERT_FALSE(IsReadOnly(dst_subdir));
+  ASSERT_FALSE(IsReadOnly(dst_file));
+
+  // Give write permissions to allow deletion.
+  SetReadOnly(src_subdir, false);
+  ASSERT_FALSE(IsReadOnly(src_subdir));
+}
+
+TEST_F(FileUtilTest, CopyFile) {
+  // Create a directory
+  FilePath dir_name_from =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("Copy_From_Subdir"));
+  CreateDirectory(dir_name_from);
+  ASSERT_TRUE(PathExists(dir_name_from));
+
+  // Create a file under the directory
+  FilePath file_name_from =
+      dir_name_from.Append(FILE_PATH_LITERAL("Copy_Test_File.txt"));
+  const std::wstring file_contents(L"Gooooooooooooooooooooogle");
+  CreateTextFile(file_name_from, file_contents);
+  ASSERT_TRUE(PathExists(file_name_from));
+
+  // Copy the file.
+  FilePath dest_file = dir_name_from.Append(FILE_PATH_LITERAL("DestFile.txt"));
+  ASSERT_TRUE(CopyFile(file_name_from, dest_file));
+
+  // Try to copy the file to another location using '..' in the path.
+  FilePath dest_file2(dir_name_from);
+  dest_file2 = dest_file2.AppendASCII("..");
+  dest_file2 = dest_file2.AppendASCII("DestFile.txt");
+  ASSERT_FALSE(CopyFile(file_name_from, dest_file2));
+
+  FilePath dest_file2_test(dir_name_from);
+  dest_file2_test = dest_file2_test.DirName();
+  dest_file2_test = dest_file2_test.AppendASCII("DestFile.txt");
+
+  // Check expected copy results.
+  EXPECT_TRUE(PathExists(file_name_from));
+  EXPECT_TRUE(PathExists(dest_file));
+  const std::wstring read_contents = ReadTextFile(dest_file);
+  EXPECT_EQ(file_contents, read_contents);
+  EXPECT_FALSE(PathExists(dest_file2_test));
+  EXPECT_FALSE(PathExists(dest_file2));
+}
+
+TEST_F(FileUtilTest, CopyFileACL) {
+  // While FileUtilTest.CopyFile asserts the content is correctly copied over,
+  // this test case asserts the access control bits are meeting expectations in
+  // CopyFile().
+  FilePath src = temp_dir_.path().Append(FILE_PATH_LITERAL("src.txt"));
+  const std::wstring file_contents(L"Gooooooooooooooooooooogle");
+  CreateTextFile(src, file_contents);
+
+  // Set the source file to read-only.
+  ASSERT_FALSE(IsReadOnly(src));
+  SetReadOnly(src, true);
+  ASSERT_TRUE(IsReadOnly(src));
+
+  // Copy the file.
+  FilePath dst = temp_dir_.path().Append(FILE_PATH_LITERAL("dst.txt"));
+  ASSERT_TRUE(CopyFile(src, dst));
+  EXPECT_EQ(file_contents, ReadTextFile(dst));
+
+  ASSERT_FALSE(IsReadOnly(dst));
+}
+
+// file_util winds up using autoreleased objects on the Mac, so this needs
+// to be a PlatformTest.
+typedef PlatformTest ReadOnlyFileUtilTest;
+
+TEST_F(ReadOnlyFileUtilTest, ContentsEqual) {
+  FilePath data_dir;
+  ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &data_dir));
+  data_dir = data_dir.AppendASCII("file_util");
+  ASSERT_TRUE(PathExists(data_dir));
+
+  FilePath original_file =
+      data_dir.Append(FILE_PATH_LITERAL("original.txt"));
+  FilePath same_file =
+      data_dir.Append(FILE_PATH_LITERAL("same.txt"));
+  FilePath same_length_file =
+      data_dir.Append(FILE_PATH_LITERAL("same_length.txt"));
+  FilePath different_file =
+      data_dir.Append(FILE_PATH_LITERAL("different.txt"));
+  FilePath different_first_file =
+      data_dir.Append(FILE_PATH_LITERAL("different_first.txt"));
+  FilePath different_last_file =
+      data_dir.Append(FILE_PATH_LITERAL("different_last.txt"));
+  FilePath empty1_file =
+      data_dir.Append(FILE_PATH_LITERAL("empty1.txt"));
+  FilePath empty2_file =
+      data_dir.Append(FILE_PATH_LITERAL("empty2.txt"));
+  FilePath shortened_file =
+      data_dir.Append(FILE_PATH_LITERAL("shortened.txt"));
+  FilePath binary_file =
+      data_dir.Append(FILE_PATH_LITERAL("binary_file.bin"));
+  FilePath binary_file_same =
+      data_dir.Append(FILE_PATH_LITERAL("binary_file_same.bin"));
+  FilePath binary_file_diff =
+      data_dir.Append(FILE_PATH_LITERAL("binary_file_diff.bin"));
+
+  EXPECT_TRUE(ContentsEqual(original_file, original_file));
+  EXPECT_TRUE(ContentsEqual(original_file, same_file));
+  EXPECT_FALSE(ContentsEqual(original_file, same_length_file));
+  EXPECT_FALSE(ContentsEqual(original_file, different_file));
+  EXPECT_FALSE(ContentsEqual(FilePath(FILE_PATH_LITERAL("bogusname")),
+                             FilePath(FILE_PATH_LITERAL("bogusname"))));
+  EXPECT_FALSE(ContentsEqual(original_file, different_first_file));
+  EXPECT_FALSE(ContentsEqual(original_file, different_last_file));
+  EXPECT_TRUE(ContentsEqual(empty1_file, empty2_file));
+  EXPECT_FALSE(ContentsEqual(original_file, shortened_file));
+  EXPECT_FALSE(ContentsEqual(shortened_file, original_file));
+  EXPECT_TRUE(ContentsEqual(binary_file, binary_file_same));
+  EXPECT_FALSE(ContentsEqual(binary_file, binary_file_diff));
+}
+
+TEST_F(ReadOnlyFileUtilTest, TextContentsEqual) {
+  FilePath data_dir;
+  ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &data_dir));
+  data_dir = data_dir.AppendASCII("file_util");
+  ASSERT_TRUE(PathExists(data_dir));
+
+  FilePath original_file =
+      data_dir.Append(FILE_PATH_LITERAL("original.txt"));
+  FilePath same_file =
+      data_dir.Append(FILE_PATH_LITERAL("same.txt"));
+  FilePath crlf_file =
+      data_dir.Append(FILE_PATH_LITERAL("crlf.txt"));
+  FilePath shortened_file =
+      data_dir.Append(FILE_PATH_LITERAL("shortened.txt"));
+  FilePath different_file =
+      data_dir.Append(FILE_PATH_LITERAL("different.txt"));
+  FilePath different_first_file =
+      data_dir.Append(FILE_PATH_LITERAL("different_first.txt"));
+  FilePath different_last_file =
+      data_dir.Append(FILE_PATH_LITERAL("different_last.txt"));
+  FilePath first1_file =
+      data_dir.Append(FILE_PATH_LITERAL("first1.txt"));
+  FilePath first2_file =
+      data_dir.Append(FILE_PATH_LITERAL("first2.txt"));
+  FilePath empty1_file =
+      data_dir.Append(FILE_PATH_LITERAL("empty1.txt"));
+  FilePath empty2_file =
+      data_dir.Append(FILE_PATH_LITERAL("empty2.txt"));
+  FilePath blank_line_file =
+      data_dir.Append(FILE_PATH_LITERAL("blank_line.txt"));
+  FilePath blank_line_crlf_file =
+      data_dir.Append(FILE_PATH_LITERAL("blank_line_crlf.txt"));
+
+  EXPECT_TRUE(TextContentsEqual(original_file, same_file));
+  EXPECT_TRUE(TextContentsEqual(original_file, crlf_file));
+  EXPECT_FALSE(TextContentsEqual(original_file, shortened_file));
+  EXPECT_FALSE(TextContentsEqual(original_file, different_file));
+  EXPECT_FALSE(TextContentsEqual(original_file, different_first_file));
+  EXPECT_FALSE(TextContentsEqual(original_file, different_last_file));
+  EXPECT_FALSE(TextContentsEqual(first1_file, first2_file));
+  EXPECT_TRUE(TextContentsEqual(empty1_file, empty2_file));
+  EXPECT_FALSE(TextContentsEqual(original_file, empty1_file));
+  EXPECT_TRUE(TextContentsEqual(blank_line_file, blank_line_crlf_file));
+}
+
+// We don't need equivalent functionality outside of Windows.
+#if defined(OS_WIN)
+TEST_F(FileUtilTest, CopyAndDeleteDirectoryTest) {
+  // Create a directory
+  FilePath dir_name_from =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("CopyAndDelete_From_Subdir"));
+  CreateDirectory(dir_name_from);
+  ASSERT_TRUE(PathExists(dir_name_from));
+
+  // Create a file under the directory
+  FilePath file_name_from =
+      dir_name_from.Append(FILE_PATH_LITERAL("CopyAndDelete_Test_File.txt"));
+  CreateTextFile(file_name_from, L"Gooooooooooooooooooooogle");
+  ASSERT_TRUE(PathExists(file_name_from));
+
+  // Move the directory by using CopyAndDeleteDirectory
+  FilePath dir_name_to = temp_dir_.path().Append(
+      FILE_PATH_LITERAL("CopyAndDelete_To_Subdir"));
+  FilePath file_name_to =
+      dir_name_to.Append(FILE_PATH_LITERAL("CopyAndDelete_Test_File.txt"));
+
+  ASSERT_FALSE(PathExists(dir_name_to));
+
+  EXPECT_TRUE(internal::CopyAndDeleteDirectory(dir_name_from,
+                                                     dir_name_to));
+
+  // Check everything has been moved.
+  EXPECT_FALSE(PathExists(dir_name_from));
+  EXPECT_FALSE(PathExists(file_name_from));
+  EXPECT_TRUE(PathExists(dir_name_to));
+  EXPECT_TRUE(PathExists(file_name_to));
+}
+
+TEST_F(FileUtilTest, GetTempDirTest) {
+  static const TCHAR* kTmpKey = _T("TMP");
+  static const TCHAR* kTmpValues[] = {
+    _T(""), _T("C:"), _T("C:\\"), _T("C:\\tmp"), _T("C:\\tmp\\")
+  };
+  // Save the original $TMP.
+  size_t original_tmp_size;
+  TCHAR* original_tmp;
+  ASSERT_EQ(0, ::_tdupenv_s(&original_tmp, &original_tmp_size, kTmpKey));
+  // original_tmp may be NULL.
+
+  for (unsigned int i = 0; i < arraysize(kTmpValues); ++i) {
+    FilePath path;
+    ::_tputenv_s(kTmpKey, kTmpValues[i]);
+    GetTempDir(&path);
+    EXPECT_TRUE(path.IsAbsolute()) << "$TMP=" << kTmpValues[i] <<
+        " result=" << path.value();
+  }
+
+  // Restore the original $TMP.
+  if (original_tmp) {
+    ::_tputenv_s(kTmpKey, original_tmp);
+    free(original_tmp);
+  } else {
+    ::_tputenv_s(kTmpKey, _T(""));
+  }
+}
+#endif  // OS_WIN
+
+TEST_F(FileUtilTest, CreateTemporaryFileTest) {
+  FilePath temp_files[3];
+  for (int i = 0; i < 3; i++) {
+    ASSERT_TRUE(CreateTemporaryFile(&(temp_files[i])));
+    EXPECT_TRUE(PathExists(temp_files[i]));
+    EXPECT_FALSE(DirectoryExists(temp_files[i]));
+  }
+  for (int i = 0; i < 3; i++)
+    EXPECT_FALSE(temp_files[i] == temp_files[(i+1)%3]);
+  for (int i = 0; i < 3; i++)
+    EXPECT_TRUE(DeleteFile(temp_files[i], false));
+}
+
+TEST_F(FileUtilTest, CreateAndOpenTemporaryFileTest) {
+  FilePath names[3];
+  FILE* fps[3];
+  int i;
+
+  // Create; make sure they are open and exist.
+  for (i = 0; i < 3; ++i) {
+    fps[i] = CreateAndOpenTemporaryFile(&(names[i]));
+    ASSERT_TRUE(fps[i]);
+    EXPECT_TRUE(PathExists(names[i]));
+  }
+
+  // Make sure all names are unique.
+  for (i = 0; i < 3; ++i) {
+    EXPECT_FALSE(names[i] == names[(i+1)%3]);
+  }
+
+  // Close and delete.
+  for (i = 0; i < 3; ++i) {
+    EXPECT_TRUE(CloseFile(fps[i]));
+    EXPECT_TRUE(DeleteFile(names[i], false));
+  }
+}
+
+TEST_F(FileUtilTest, FileToFILE) {
+  File file;
+  FILE* stream = FileToFILE(file.Pass(), "w");
+  EXPECT_FALSE(stream);
+
+  FilePath file_name = temp_dir_.path().Append(FPL("The file.txt"));
+  file = File(file_name, File::FLAG_CREATE | File::FLAG_WRITE);
+  EXPECT_TRUE(file.IsValid());
+
+  stream = FileToFILE(file.Pass(), "w");
+  EXPECT_TRUE(stream);
+  EXPECT_FALSE(file.IsValid());
+  EXPECT_TRUE(CloseFile(stream));
+}
+
+TEST_F(FileUtilTest, CreateNewTempDirectoryTest) {
+  FilePath temp_dir;
+  ASSERT_TRUE(CreateNewTempDirectory(FilePath::StringType(), &temp_dir));
+  EXPECT_TRUE(PathExists(temp_dir));
+  EXPECT_TRUE(DeleteFile(temp_dir, false));
+}
+
+TEST_F(FileUtilTest, CreateNewTemporaryDirInDirTest) {
+  FilePath new_dir;
+  ASSERT_TRUE(CreateTemporaryDirInDir(
+                  temp_dir_.path(),
+                  FILE_PATH_LITERAL("CreateNewTemporaryDirInDirTest"),
+                  &new_dir));
+  EXPECT_TRUE(PathExists(new_dir));
+  EXPECT_TRUE(temp_dir_.path().IsParent(new_dir));
+  EXPECT_TRUE(DeleteFile(new_dir, false));
+}
+
+#if defined(OS_POSIX)
+TEST_F(FileUtilTest, GetShmemTempDirTest) {
+  FilePath dir;
+  EXPECT_TRUE(GetShmemTempDir(false, &dir));
+  EXPECT_TRUE(DirectoryExists(dir));
+}
+#endif
+
+TEST_F(FileUtilTest, GetHomeDirTest) {
+#if !defined(OS_ANDROID)  // Not implemented on Android.
+  // We don't actually know what the home directory is supposed to be without
+  // calling some OS functions which would just duplicate the implementation.
+  // So here we just test that it returns something "reasonable".
+  FilePath home = GetHomeDir();
+  ASSERT_FALSE(home.empty());
+  ASSERT_TRUE(home.IsAbsolute());
+#endif
+}
+
+TEST_F(FileUtilTest, CreateDirectoryTest) {
+  FilePath test_root =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("create_directory_test"));
+#if defined(OS_WIN)
+  FilePath test_path =
+      test_root.Append(FILE_PATH_LITERAL("dir\\tree\\likely\\doesnt\\exist\\"));
+#elif defined(OS_POSIX)
+  FilePath test_path =
+      test_root.Append(FILE_PATH_LITERAL("dir/tree/likely/doesnt/exist/"));
+#endif
+
+  EXPECT_FALSE(PathExists(test_path));
+  EXPECT_TRUE(CreateDirectory(test_path));
+  EXPECT_TRUE(PathExists(test_path));
+  // CreateDirectory returns true if the DirectoryExists returns true.
+  EXPECT_TRUE(CreateDirectory(test_path));
+
+  // Doesn't work to create it on top of a non-dir
+  test_path = test_path.Append(FILE_PATH_LITERAL("foobar.txt"));
+  EXPECT_FALSE(PathExists(test_path));
+  CreateTextFile(test_path, L"test file");
+  EXPECT_TRUE(PathExists(test_path));
+  EXPECT_FALSE(CreateDirectory(test_path));
+
+  EXPECT_TRUE(DeleteFile(test_root, true));
+  EXPECT_FALSE(PathExists(test_root));
+  EXPECT_FALSE(PathExists(test_path));
+
+  // Verify assumptions made by the Windows implementation:
+  // 1. The current directory always exists.
+  // 2. The root directory always exists.
+  ASSERT_TRUE(DirectoryExists(FilePath(FilePath::kCurrentDirectory)));
+  FilePath top_level = test_root;
+  while (top_level != top_level.DirName()) {
+    top_level = top_level.DirName();
+  }
+  ASSERT_TRUE(DirectoryExists(top_level));
+
+  // Given these assumptions hold, it should be safe to
+  // test that "creating" these directories succeeds.
+  EXPECT_TRUE(CreateDirectory(
+      FilePath(FilePath::kCurrentDirectory)));
+  EXPECT_TRUE(CreateDirectory(top_level));
+
+#if defined(OS_WIN)
+  FilePath invalid_drive(FILE_PATH_LITERAL("o:\\"));
+  FilePath invalid_path =
+      invalid_drive.Append(FILE_PATH_LITERAL("some\\inaccessible\\dir"));
+  if (!PathExists(invalid_drive)) {
+    EXPECT_FALSE(CreateDirectory(invalid_path));
+  }
+#endif
+}
+
+TEST_F(FileUtilTest, DetectDirectoryTest) {
+  // Check a directory
+  FilePath test_root =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("detect_directory_test"));
+  EXPECT_FALSE(PathExists(test_root));
+  EXPECT_TRUE(CreateDirectory(test_root));
+  EXPECT_TRUE(PathExists(test_root));
+  EXPECT_TRUE(DirectoryExists(test_root));
+  // Check a file
+  FilePath test_path =
+      test_root.Append(FILE_PATH_LITERAL("foobar.txt"));
+  EXPECT_FALSE(PathExists(test_path));
+  CreateTextFile(test_path, L"test file");
+  EXPECT_TRUE(PathExists(test_path));
+  EXPECT_FALSE(DirectoryExists(test_path));
+  EXPECT_TRUE(DeleteFile(test_path, false));
+
+  EXPECT_TRUE(DeleteFile(test_root, true));
+}
+
+TEST_F(FileUtilTest, FileEnumeratorTest) {
+  // Test an empty directory.
+  FileEnumerator f0(temp_dir_.path(), true, FILES_AND_DIRECTORIES);
+  EXPECT_EQ(FPL(""), f0.Next().value());
+  EXPECT_EQ(FPL(""), f0.Next().value());
+
+  // Test an empty directory, non-recursively, including "..".
+  FileEnumerator f0_dotdot(temp_dir_.path(), false,
+      FILES_AND_DIRECTORIES | FileEnumerator::INCLUDE_DOT_DOT);
+  EXPECT_EQ(temp_dir_.path().Append(FPL("..")).value(),
+            f0_dotdot.Next().value());
+  EXPECT_EQ(FPL(""), f0_dotdot.Next().value());
+
+  // create the directories
+  FilePath dir1 = temp_dir_.path().Append(FPL("dir1"));
+  EXPECT_TRUE(CreateDirectory(dir1));
+  FilePath dir2 = temp_dir_.path().Append(FPL("dir2"));
+  EXPECT_TRUE(CreateDirectory(dir2));
+  FilePath dir2inner = dir2.Append(FPL("inner"));
+  EXPECT_TRUE(CreateDirectory(dir2inner));
+
+  // create the files
+  FilePath dir2file = dir2.Append(FPL("dir2file.txt"));
+  CreateTextFile(dir2file, std::wstring());
+  FilePath dir2innerfile = dir2inner.Append(FPL("innerfile.txt"));
+  CreateTextFile(dir2innerfile, std::wstring());
+  FilePath file1 = temp_dir_.path().Append(FPL("file1.txt"));
+  CreateTextFile(file1, std::wstring());
+  FilePath file2_rel = dir2.Append(FilePath::kParentDirectory)
+      .Append(FPL("file2.txt"));
+  CreateTextFile(file2_rel, std::wstring());
+  FilePath file2_abs = temp_dir_.path().Append(FPL("file2.txt"));
+
+  // Only enumerate files.
+  FileEnumerator f1(temp_dir_.path(), true, FileEnumerator::FILES);
+  FindResultCollector c1(&f1);
+  EXPECT_TRUE(c1.HasFile(file1));
+  EXPECT_TRUE(c1.HasFile(file2_abs));
+  EXPECT_TRUE(c1.HasFile(dir2file));
+  EXPECT_TRUE(c1.HasFile(dir2innerfile));
+  EXPECT_EQ(4, c1.size());
+
+  // Only enumerate directories.
+  FileEnumerator f2(temp_dir_.path(), true, FileEnumerator::DIRECTORIES);
+  FindResultCollector c2(&f2);
+  EXPECT_TRUE(c2.HasFile(dir1));
+  EXPECT_TRUE(c2.HasFile(dir2));
+  EXPECT_TRUE(c2.HasFile(dir2inner));
+  EXPECT_EQ(3, c2.size());
+
+  // Only enumerate directories non-recursively.
+  FileEnumerator f2_non_recursive(
+      temp_dir_.path(), false, FileEnumerator::DIRECTORIES);
+  FindResultCollector c2_non_recursive(&f2_non_recursive);
+  EXPECT_TRUE(c2_non_recursive.HasFile(dir1));
+  EXPECT_TRUE(c2_non_recursive.HasFile(dir2));
+  EXPECT_EQ(2, c2_non_recursive.size());
+
+  // Only enumerate directories, non-recursively, including "..".
+  FileEnumerator f2_dotdot(temp_dir_.path(), false,
+                           FileEnumerator::DIRECTORIES |
+                           FileEnumerator::INCLUDE_DOT_DOT);
+  FindResultCollector c2_dotdot(&f2_dotdot);
+  EXPECT_TRUE(c2_dotdot.HasFile(dir1));
+  EXPECT_TRUE(c2_dotdot.HasFile(dir2));
+  EXPECT_TRUE(c2_dotdot.HasFile(temp_dir_.path().Append(FPL(".."))));
+  EXPECT_EQ(3, c2_dotdot.size());
+
+  // Enumerate files and directories.
+  FileEnumerator f3(temp_dir_.path(), true, FILES_AND_DIRECTORIES);
+  FindResultCollector c3(&f3);
+  EXPECT_TRUE(c3.HasFile(dir1));
+  EXPECT_TRUE(c3.HasFile(dir2));
+  EXPECT_TRUE(c3.HasFile(file1));
+  EXPECT_TRUE(c3.HasFile(file2_abs));
+  EXPECT_TRUE(c3.HasFile(dir2file));
+  EXPECT_TRUE(c3.HasFile(dir2inner));
+  EXPECT_TRUE(c3.HasFile(dir2innerfile));
+  EXPECT_EQ(7, c3.size());
+
+  // Non-recursive operation.
+  FileEnumerator f4(temp_dir_.path(), false, FILES_AND_DIRECTORIES);
+  FindResultCollector c4(&f4);
+  EXPECT_TRUE(c4.HasFile(dir2));
+  EXPECT_TRUE(c4.HasFile(dir2));
+  EXPECT_TRUE(c4.HasFile(file1));
+  EXPECT_TRUE(c4.HasFile(file2_abs));
+  EXPECT_EQ(4, c4.size());
+
+  // Enumerate with a pattern.
+  FileEnumerator f5(temp_dir_.path(), true, FILES_AND_DIRECTORIES, FPL("dir*"));
+  FindResultCollector c5(&f5);
+  EXPECT_TRUE(c5.HasFile(dir1));
+  EXPECT_TRUE(c5.HasFile(dir2));
+  EXPECT_TRUE(c5.HasFile(dir2file));
+  EXPECT_TRUE(c5.HasFile(dir2inner));
+  EXPECT_TRUE(c5.HasFile(dir2innerfile));
+  EXPECT_EQ(5, c5.size());
+
+#if defined(OS_WIN)
+  {
+    // Make dir1 point to dir2.
+    ReparsePoint reparse_point(dir1, dir2);
+    EXPECT_TRUE(reparse_point.IsValid());
+
+    if ((win::GetVersion() >= win::VERSION_VISTA)) {
+      // There can be a delay for the enumeration code to see the change on
+      // the file system so skip this test for XP.
+      // Enumerate the reparse point.
+      FileEnumerator f6(dir1, true, FILES_AND_DIRECTORIES);
+      FindResultCollector c6(&f6);
+      FilePath inner2 = dir1.Append(FPL("inner"));
+      EXPECT_TRUE(c6.HasFile(inner2));
+      EXPECT_TRUE(c6.HasFile(inner2.Append(FPL("innerfile.txt"))));
+      EXPECT_TRUE(c6.HasFile(dir1.Append(FPL("dir2file.txt"))));
+      EXPECT_EQ(3, c6.size());
+    }
+
+    // No changes for non recursive operation.
+    FileEnumerator f7(temp_dir_.path(), false, FILES_AND_DIRECTORIES);
+    FindResultCollector c7(&f7);
+    EXPECT_TRUE(c7.HasFile(dir2));
+    EXPECT_TRUE(c7.HasFile(dir2));
+    EXPECT_TRUE(c7.HasFile(file1));
+    EXPECT_TRUE(c7.HasFile(file2_abs));
+    EXPECT_EQ(4, c7.size());
+
+    // Should not enumerate inside dir1 when using recursion.
+    FileEnumerator f8(temp_dir_.path(), true, FILES_AND_DIRECTORIES);
+    FindResultCollector c8(&f8);
+    EXPECT_TRUE(c8.HasFile(dir1));
+    EXPECT_TRUE(c8.HasFile(dir2));
+    EXPECT_TRUE(c8.HasFile(file1));
+    EXPECT_TRUE(c8.HasFile(file2_abs));
+    EXPECT_TRUE(c8.HasFile(dir2file));
+    EXPECT_TRUE(c8.HasFile(dir2inner));
+    EXPECT_TRUE(c8.HasFile(dir2innerfile));
+    EXPECT_EQ(7, c8.size());
+  }
+#endif
+
+  // Make sure the destructor closes the find handle while in the middle of a
+  // query to allow TearDown to delete the directory.
+  FileEnumerator f9(temp_dir_.path(), true, FILES_AND_DIRECTORIES);
+  EXPECT_FALSE(f9.Next().value().empty());  // Should have found something
+                                            // (we don't care what).
+}
+
+TEST_F(FileUtilTest, AppendToFile) {
+  FilePath data_dir =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("FilePathTest"));
+
+  // Create a fresh, empty copy of this directory.
+  if (PathExists(data_dir)) {
+    ASSERT_TRUE(DeleteFile(data_dir, true));
+  }
+  ASSERT_TRUE(CreateDirectory(data_dir));
+
+  // Create a fresh, empty copy of this directory.
+  if (PathExists(data_dir)) {
+    ASSERT_TRUE(DeleteFile(data_dir, true));
+  }
+  ASSERT_TRUE(CreateDirectory(data_dir));
+  FilePath foobar(data_dir.Append(FILE_PATH_LITERAL("foobar.txt")));
+
+  std::string data("hello");
+  EXPECT_FALSE(AppendToFile(foobar, data.c_str(), data.size()));
+  EXPECT_EQ(static_cast<int>(data.length()),
+            WriteFile(foobar, data.c_str(), data.length()));
+  EXPECT_TRUE(AppendToFile(foobar, data.c_str(), data.size()));
+
+  const std::wstring read_content = ReadTextFile(foobar);
+  EXPECT_EQ(L"hellohello", read_content);
+}
+
+TEST_F(FileUtilTest, ReadFile) {
+  // Create a test file to be read.
+  const std::string kTestData("The quick brown fox jumps over the lazy dog.");
+  FilePath file_path =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("ReadFileTest"));
+
+  ASSERT_EQ(static_cast<int>(kTestData.size()),
+            WriteFile(file_path, kTestData.data(), kTestData.size()));
+
+  // Make buffers with various size.
+  std::vector<char> small_buffer(kTestData.size() / 2);
+  std::vector<char> exact_buffer(kTestData.size());
+  std::vector<char> large_buffer(kTestData.size() * 2);
+
+  // Read the file with smaller buffer.
+  int bytes_read_small = ReadFile(
+      file_path, &small_buffer[0], static_cast<int>(small_buffer.size()));
+  EXPECT_EQ(static_cast<int>(small_buffer.size()), bytes_read_small);
+  EXPECT_EQ(
+      std::string(kTestData.begin(), kTestData.begin() + small_buffer.size()),
+      std::string(small_buffer.begin(), small_buffer.end()));
+
+  // Read the file with buffer which have exactly same size.
+  int bytes_read_exact = ReadFile(
+      file_path, &exact_buffer[0], static_cast<int>(exact_buffer.size()));
+  EXPECT_EQ(static_cast<int>(kTestData.size()), bytes_read_exact);
+  EXPECT_EQ(kTestData, std::string(exact_buffer.begin(), exact_buffer.end()));
+
+  // Read the file with larger buffer.
+  int bytes_read_large = ReadFile(
+      file_path, &large_buffer[0], static_cast<int>(large_buffer.size()));
+  EXPECT_EQ(static_cast<int>(kTestData.size()), bytes_read_large);
+  EXPECT_EQ(kTestData, std::string(large_buffer.begin(),
+                                   large_buffer.begin() + kTestData.size()));
+
+  // Make sure the return value is -1 if the file doesn't exist.
+  FilePath file_path_not_exist =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("ReadFileNotExistTest"));
+  EXPECT_EQ(-1,
+            ReadFile(file_path_not_exist,
+                     &exact_buffer[0],
+                     static_cast<int>(exact_buffer.size())));
+}
+
+TEST_F(FileUtilTest, ReadFileToString) {
+  const char kTestData[] = "0123";
+  std::string data;
+
+  FilePath file_path =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("ReadFileToStringTest"));
+  FilePath file_path_dangerous =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("..")).
+      Append(temp_dir_.path().BaseName()).
+      Append(FILE_PATH_LITERAL("ReadFileToStringTest"));
+
+  // Create test file.
+  ASSERT_EQ(4, WriteFile(file_path, kTestData, 4));
+
+  EXPECT_TRUE(ReadFileToString(file_path, &data));
+  EXPECT_EQ(kTestData, data);
+
+  data = "temp";
+  EXPECT_FALSE(ReadFileToString(file_path, &data, 0));
+  EXPECT_EQ(0u, data.length());
+
+  data = "temp";
+  EXPECT_FALSE(ReadFileToString(file_path, &data, 2));
+  EXPECT_EQ("01", data);
+
+  data.clear();
+  EXPECT_FALSE(ReadFileToString(file_path, &data, 3));
+  EXPECT_EQ("012", data);
+
+  data.clear();
+  EXPECT_TRUE(ReadFileToString(file_path, &data, 4));
+  EXPECT_EQ("0123", data);
+
+  data.clear();
+  EXPECT_TRUE(ReadFileToString(file_path, &data, 6));
+  EXPECT_EQ("0123", data);
+
+  EXPECT_TRUE(ReadFileToString(file_path, NULL, 6));
+
+  EXPECT_TRUE(ReadFileToString(file_path, NULL));
+
+  data = "temp";
+  EXPECT_FALSE(ReadFileToString(file_path_dangerous, &data));
+  EXPECT_EQ(0u, data.length());
+
+  // Delete test file.
+  EXPECT_TRUE(DeleteFile(file_path, false));
+
+  data = "temp";
+  EXPECT_FALSE(ReadFileToString(file_path, &data));
+  EXPECT_EQ(0u, data.length());
+
+  data = "temp";
+  EXPECT_FALSE(ReadFileToString(file_path, &data, 6));
+  EXPECT_EQ(0u, data.length());
+}
+
+TEST_F(FileUtilTest, TouchFile) {
+  FilePath data_dir =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("FilePathTest"));
+
+  // Create a fresh, empty copy of this directory.
+  if (PathExists(data_dir)) {
+    ASSERT_TRUE(DeleteFile(data_dir, true));
+  }
+  ASSERT_TRUE(CreateDirectory(data_dir));
+
+  FilePath foobar(data_dir.Append(FILE_PATH_LITERAL("foobar.txt")));
+  std::string data("hello");
+  ASSERT_TRUE(WriteFile(foobar, data.c_str(), data.length()));
+
+  Time access_time;
+  // This timestamp is divisible by one day (in local timezone),
+  // to make it work on FAT too.
+  ASSERT_TRUE(Time::FromString("Wed, 16 Nov 1994, 00:00:00",
+                               &access_time));
+
+  Time modification_time;
+  // Note that this timestamp is divisible by two (seconds) - FAT stores
+  // modification times with 2s resolution.
+  ASSERT_TRUE(Time::FromString("Tue, 15 Nov 1994, 12:45:26 GMT",
+              &modification_time));
+
+  ASSERT_TRUE(TouchFile(foobar, access_time, modification_time));
+  File::Info file_info;
+  ASSERT_TRUE(GetFileInfo(foobar, &file_info));
+  EXPECT_EQ(access_time.ToInternalValue(),
+            file_info.last_accessed.ToInternalValue());
+  EXPECT_EQ(modification_time.ToInternalValue(),
+            file_info.last_modified.ToInternalValue());
+}
+
+TEST_F(FileUtilTest, IsDirectoryEmpty) {
+  FilePath empty_dir = temp_dir_.path().Append(FILE_PATH_LITERAL("EmptyDir"));
+
+  ASSERT_FALSE(PathExists(empty_dir));
+
+  ASSERT_TRUE(CreateDirectory(empty_dir));
+
+  EXPECT_TRUE(IsDirectoryEmpty(empty_dir));
+
+  FilePath foo(empty_dir.Append(FILE_PATH_LITERAL("foo.txt")));
+  std::string bar("baz");
+  ASSERT_TRUE(WriteFile(foo, bar.c_str(), bar.length()));
+
+  EXPECT_FALSE(IsDirectoryEmpty(empty_dir));
+}
+
+#if defined(OS_POSIX)
+
+// Testing VerifyPathControlledByAdmin() is hard, because there is no
+// way a test can make a file owned by root, or change file paths
+// at the root of the file system.  VerifyPathControlledByAdmin()
+// is implemented as a call to VerifyPathControlledByUser, which gives
+// us the ability to test with paths under the test's temp directory,
+// using a user id we control.
+// Pull tests of VerifyPathControlledByUserTest() into a separate test class
+// with a common SetUp() method.
+class VerifyPathControlledByUserTest : public FileUtilTest {
+ protected:
+  void SetUp() override {
+    FileUtilTest::SetUp();
+
+    // Create a basic structure used by each test.
+    // base_dir_
+    //  |-> sub_dir_
+    //       |-> text_file_
+
+    base_dir_ = temp_dir_.path().AppendASCII("base_dir");
+    ASSERT_TRUE(CreateDirectory(base_dir_));
+
+    sub_dir_ = base_dir_.AppendASCII("sub_dir");
+    ASSERT_TRUE(CreateDirectory(sub_dir_));
+
+    text_file_ = sub_dir_.AppendASCII("file.txt");
+    CreateTextFile(text_file_, L"This text file has some text in it.");
+
+    // Get the user and group files are created with from |base_dir_|.
+    struct stat stat_buf;
+    ASSERT_EQ(0, stat(base_dir_.value().c_str(), &stat_buf));
+    uid_ = stat_buf.st_uid;
+    ok_gids_.insert(stat_buf.st_gid);
+    bad_gids_.insert(stat_buf.st_gid + 1);
+
+    ASSERT_EQ(uid_, getuid());  // This process should be the owner.
+
+    // To ensure that umask settings do not cause the initial state
+    // of permissions to be different from what we expect, explicitly
+    // set permissions on the directories we create.
+    // Make all files and directories non-world-writable.
+
+    // Users and group can read, write, traverse
+    int enabled_permissions =
+        FILE_PERMISSION_USER_MASK | FILE_PERMISSION_GROUP_MASK;
+    // Other users can't read, write, traverse
+    int disabled_permissions = FILE_PERMISSION_OTHERS_MASK;
+
+    ASSERT_NO_FATAL_FAILURE(
+        ChangePosixFilePermissions(
+            base_dir_, enabled_permissions, disabled_permissions));
+    ASSERT_NO_FATAL_FAILURE(
+        ChangePosixFilePermissions(
+            sub_dir_, enabled_permissions, disabled_permissions));
+  }
+
+  FilePath base_dir_;
+  FilePath sub_dir_;
+  FilePath text_file_;
+  uid_t uid_;
+
+  std::set<gid_t> ok_gids_;
+  std::set<gid_t> bad_gids_;
+};
+
+TEST_F(VerifyPathControlledByUserTest, BadPaths) {
+  // File does not exist.
+  FilePath does_not_exist = base_dir_.AppendASCII("does")
+                                     .AppendASCII("not")
+                                     .AppendASCII("exist");
+  EXPECT_FALSE(
+      VerifyPathControlledByUser(base_dir_, does_not_exist, uid_, ok_gids_));
+
+  // |base| not a subpath of |path|.
+  EXPECT_FALSE(VerifyPathControlledByUser(sub_dir_, base_dir_, uid_, ok_gids_));
+
+  // An empty base path will fail to be a prefix for any path.
+  FilePath empty;
+  EXPECT_FALSE(VerifyPathControlledByUser(empty, base_dir_, uid_, ok_gids_));
+
+  // Finding that a bad call fails proves nothing unless a good call succeeds.
+  EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_));
+}
+
+TEST_F(VerifyPathControlledByUserTest, Symlinks) {
+  // Symlinks in the path should cause failure.
+
+  // Symlink to the file at the end of the path.
+  FilePath file_link =  base_dir_.AppendASCII("file_link");
+  ASSERT_TRUE(CreateSymbolicLink(text_file_, file_link))
+      << "Failed to create symlink.";
+
+  EXPECT_FALSE(
+      VerifyPathControlledByUser(base_dir_, file_link, uid_, ok_gids_));
+  EXPECT_FALSE(
+      VerifyPathControlledByUser(file_link, file_link, uid_, ok_gids_));
+
+  // Symlink from one directory to another within the path.
+  FilePath link_to_sub_dir =  base_dir_.AppendASCII("link_to_sub_dir");
+  ASSERT_TRUE(CreateSymbolicLink(sub_dir_, link_to_sub_dir))
+    << "Failed to create symlink.";
+
+  FilePath file_path_with_link = link_to_sub_dir.AppendASCII("file.txt");
+  ASSERT_TRUE(PathExists(file_path_with_link));
+
+  EXPECT_FALSE(VerifyPathControlledByUser(base_dir_, file_path_with_link, uid_,
+                                          ok_gids_));
+
+  EXPECT_FALSE(VerifyPathControlledByUser(link_to_sub_dir, file_path_with_link,
+                                          uid_, ok_gids_));
+
+  // Symlinks in parents of base path are allowed.
+  EXPECT_TRUE(VerifyPathControlledByUser(file_path_with_link,
+                                         file_path_with_link, uid_, ok_gids_));
+}
+
+TEST_F(VerifyPathControlledByUserTest, OwnershipChecks) {
+  // Get a uid that is not the uid of files we create.
+  uid_t bad_uid = uid_ + 1;
+
+  // Make all files and directories non-world-writable.
+  ASSERT_NO_FATAL_FAILURE(
+      ChangePosixFilePermissions(base_dir_, 0u, S_IWOTH));
+  ASSERT_NO_FATAL_FAILURE(
+      ChangePosixFilePermissions(sub_dir_, 0u, S_IWOTH));
+  ASSERT_NO_FATAL_FAILURE(
+      ChangePosixFilePermissions(text_file_, 0u, S_IWOTH));
+
+  // We control these paths.
+  EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_));
+  EXPECT_TRUE(
+      VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_));
+  EXPECT_TRUE(VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_));
+
+  // Another user does not control these paths.
+  EXPECT_FALSE(
+      VerifyPathControlledByUser(base_dir_, sub_dir_, bad_uid, ok_gids_));
+  EXPECT_FALSE(
+      VerifyPathControlledByUser(base_dir_, text_file_, bad_uid, ok_gids_));
+  EXPECT_FALSE(
+      VerifyPathControlledByUser(sub_dir_, text_file_, bad_uid, ok_gids_));
+
+  // Another group does not control the paths.
+  EXPECT_FALSE(
+      VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, bad_gids_));
+  EXPECT_FALSE(
+      VerifyPathControlledByUser(base_dir_, text_file_, uid_, bad_gids_));
+  EXPECT_FALSE(
+      VerifyPathControlledByUser(sub_dir_, text_file_, uid_, bad_gids_));
+}
+
+TEST_F(VerifyPathControlledByUserTest, GroupWriteTest) {
+  // Make all files and directories writable only by their owner.
+  ASSERT_NO_FATAL_FAILURE(
+      ChangePosixFilePermissions(base_dir_, 0u, S_IWOTH|S_IWGRP));
+  ASSERT_NO_FATAL_FAILURE(
+      ChangePosixFilePermissions(sub_dir_, 0u, S_IWOTH|S_IWGRP));
+  ASSERT_NO_FATAL_FAILURE(
+      ChangePosixFilePermissions(text_file_, 0u, S_IWOTH|S_IWGRP));
+
+  // Any group is okay because the path is not group-writable.
+  EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_));
+  EXPECT_TRUE(
+      VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_));
+  EXPECT_TRUE(VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_));
+
+  EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, bad_gids_));
+  EXPECT_TRUE(
+      VerifyPathControlledByUser(base_dir_, text_file_, uid_, bad_gids_));
+  EXPECT_TRUE(
+      VerifyPathControlledByUser(sub_dir_, text_file_, uid_, bad_gids_));
+
+  // No group is okay, because we don't check the group
+  // if no group can write.
+  std::set<gid_t> no_gids;  // Empty set of gids.
+  EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, no_gids));
+  EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, text_file_, uid_, no_gids));
+  EXPECT_TRUE(VerifyPathControlledByUser(sub_dir_, text_file_, uid_, no_gids));
+
+  // Make all files and directories writable by their group.
+  ASSERT_NO_FATAL_FAILURE(ChangePosixFilePermissions(base_dir_, S_IWGRP, 0u));
+  ASSERT_NO_FATAL_FAILURE(ChangePosixFilePermissions(sub_dir_, S_IWGRP, 0u));
+  ASSERT_NO_FATAL_FAILURE(ChangePosixFilePermissions(text_file_, S_IWGRP, 0u));
+
+  // Now |ok_gids_| works, but |bad_gids_| fails.
+  EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_));
+  EXPECT_TRUE(
+      VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_));
+  EXPECT_TRUE(VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_));
+
+  EXPECT_FALSE(
+      VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, bad_gids_));
+  EXPECT_FALSE(
+      VerifyPathControlledByUser(base_dir_, text_file_, uid_, bad_gids_));
+  EXPECT_FALSE(
+      VerifyPathControlledByUser(sub_dir_, text_file_, uid_, bad_gids_));
+
+  // Because any group in the group set is allowed,
+  // the union of good and bad gids passes.
+
+  std::set<gid_t> multiple_gids;
+  std::set_union(
+      ok_gids_.begin(), ok_gids_.end(),
+      bad_gids_.begin(), bad_gids_.end(),
+      std::inserter(multiple_gids, multiple_gids.begin()));
+
+  EXPECT_TRUE(
+      VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, multiple_gids));
+  EXPECT_TRUE(
+      VerifyPathControlledByUser(base_dir_, text_file_, uid_, multiple_gids));
+  EXPECT_TRUE(
+      VerifyPathControlledByUser(sub_dir_, text_file_, uid_, multiple_gids));
+}
+
+TEST_F(VerifyPathControlledByUserTest, WriteBitChecks) {
+  // Make all files and directories non-world-writable.
+  ASSERT_NO_FATAL_FAILURE(
+      ChangePosixFilePermissions(base_dir_, 0u, S_IWOTH));
+  ASSERT_NO_FATAL_FAILURE(
+      ChangePosixFilePermissions(sub_dir_, 0u, S_IWOTH));
+  ASSERT_NO_FATAL_FAILURE(
+      ChangePosixFilePermissions(text_file_, 0u, S_IWOTH));
+
+  // Initialy, we control all parts of the path.
+  EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_));
+  EXPECT_TRUE(
+      VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_));
+  EXPECT_TRUE(VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_));
+
+  // Make base_dir_ world-writable.
+  ASSERT_NO_FATAL_FAILURE(
+      ChangePosixFilePermissions(base_dir_, S_IWOTH, 0u));
+  EXPECT_FALSE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_));
+  EXPECT_FALSE(
+      VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_));
+  EXPECT_TRUE(VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_));
+
+  // Make sub_dir_ world writable.
+  ASSERT_NO_FATAL_FAILURE(
+      ChangePosixFilePermissions(sub_dir_, S_IWOTH, 0u));
+  EXPECT_FALSE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_));
+  EXPECT_FALSE(
+      VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_));
+  EXPECT_FALSE(
+      VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_));
+
+  // Make text_file_ world writable.
+  ASSERT_NO_FATAL_FAILURE(
+      ChangePosixFilePermissions(text_file_, S_IWOTH, 0u));
+  EXPECT_FALSE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_));
+  EXPECT_FALSE(
+      VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_));
+  EXPECT_FALSE(
+      VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_));
+
+  // Make sub_dir_ non-world writable.
+  ASSERT_NO_FATAL_FAILURE(
+      ChangePosixFilePermissions(sub_dir_, 0u, S_IWOTH));
+  EXPECT_FALSE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_));
+  EXPECT_FALSE(
+      VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_));
+  EXPECT_FALSE(
+      VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_));
+
+  // Make base_dir_ non-world-writable.
+  ASSERT_NO_FATAL_FAILURE(
+      ChangePosixFilePermissions(base_dir_, 0u, S_IWOTH));
+  EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_));
+  EXPECT_FALSE(
+      VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_));
+  EXPECT_FALSE(
+      VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_));
+
+  // Back to the initial state: Nothing is writable, so every path
+  // should pass.
+  ASSERT_NO_FATAL_FAILURE(
+      ChangePosixFilePermissions(text_file_, 0u, S_IWOTH));
+  EXPECT_TRUE(VerifyPathControlledByUser(base_dir_, sub_dir_, uid_, ok_gids_));
+  EXPECT_TRUE(
+      VerifyPathControlledByUser(base_dir_, text_file_, uid_, ok_gids_));
+  EXPECT_TRUE(VerifyPathControlledByUser(sub_dir_, text_file_, uid_, ok_gids_));
+}
+
+#if defined(OS_ANDROID)
+TEST_F(FileUtilTest, ValidContentUriTest) {
+  // Get the test image path.
+  FilePath data_dir;
+  ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &data_dir));
+  data_dir = data_dir.AppendASCII("file_util");
+  ASSERT_TRUE(PathExists(data_dir));
+  FilePath image_file = data_dir.Append(FILE_PATH_LITERAL("red.png"));
+  int64 image_size;
+  GetFileSize(image_file, &image_size);
+  EXPECT_LT(0, image_size);
+
+  // Insert the image into MediaStore. MediaStore will do some conversions, and
+  // return the content URI.
+  FilePath path = InsertImageIntoMediaStore(image_file);
+  EXPECT_TRUE(path.IsContentUri());
+  EXPECT_TRUE(PathExists(path));
+  // The file size may not equal to the input image as MediaStore may convert
+  // the image.
+  int64 content_uri_size;
+  GetFileSize(path, &content_uri_size);
+  EXPECT_EQ(image_size, content_uri_size);
+
+  // We should be able to read the file.
+  char* buffer = new char[image_size];
+  File file = OpenContentUriForRead(path);
+  EXPECT_TRUE(file.IsValid());
+  EXPECT_TRUE(file.ReadAtCurrentPos(buffer, image_size));
+  delete[] buffer;
+}
+
+TEST_F(FileUtilTest, NonExistentContentUriTest) {
+  FilePath path("content://foo.bar");
+  EXPECT_TRUE(path.IsContentUri());
+  EXPECT_FALSE(PathExists(path));
+  // Size should be smaller than 0.
+  int64 size;
+  EXPECT_FALSE(GetFileSize(path, &size));
+
+  // We should not be able to read the file.
+  File file = OpenContentUriForRead(path);
+  EXPECT_FALSE(file.IsValid());
+}
+#endif
+
+TEST(ScopedFD, ScopedFDDoesClose) {
+  int fds[2];
+  char c = 0;
+  ASSERT_EQ(0, pipe(fds));
+  const int write_end = fds[1];
+  ScopedFD read_end_closer(fds[0]);
+  {
+    ScopedFD write_end_closer(fds[1]);
+  }
+  // This is the only thread. This file descriptor should no longer be valid.
+  int ret = close(write_end);
+  EXPECT_EQ(-1, ret);
+  EXPECT_EQ(EBADF, errno);
+  // Make sure read(2) won't block.
+  ASSERT_EQ(0, fcntl(fds[0], F_SETFL, O_NONBLOCK));
+  // Reading the pipe should EOF.
+  EXPECT_EQ(0, read(fds[0], &c, 1));
+}
+
+#if defined(GTEST_HAS_DEATH_TEST)
+void CloseWithScopedFD(int fd) {
+  ScopedFD fd_closer(fd);
+}
+#endif
+
+TEST(ScopedFD, ScopedFDCrashesOnCloseFailure) {
+  int fds[2];
+  ASSERT_EQ(0, pipe(fds));
+  ScopedFD read_end_closer(fds[0]);
+  EXPECT_EQ(0, IGNORE_EINTR(close(fds[1])));
+#if defined(GTEST_HAS_DEATH_TEST)
+  // This is the only thread. This file descriptor should no longer be valid.
+  // Trying to close it should crash. This is important for security.
+  EXPECT_DEATH(CloseWithScopedFD(fds[1]), "");
+#endif
+}
+
+#endif  // defined(OS_POSIX)
+
+}  // namespace
+
+}  // namespace base
diff --git a/base/files/file_util_win.cc b/base/files/file_util_win.cc
new file mode 100644
index 0000000..e254232
--- /dev/null
+++ b/base/files/file_util_win.cc
@@ -0,0 +1,810 @@
+// Copyright (c) 2012 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/files/file_util.h"
+
+#include <windows.h>
+#include <io.h>
+#include <psapi.h>
+#include <shellapi.h>
+#include <shlobj.h>
+#include <time.h>
+
+#include <algorithm>
+#include <limits>
+#include <string>
+
+#include "base/files/file_enumerator.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/metrics/histogram.h"
+#include "base/process/process_handle.h"
+#include "base/rand_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/time/time.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/windows_version.h"
+
+namespace base {
+
+namespace {
+
+const DWORD kFileShareAll =
+    FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
+
+}  // namespace
+
+FilePath MakeAbsoluteFilePath(const FilePath& input) {
+  ThreadRestrictions::AssertIOAllowed();
+  wchar_t file_path[MAX_PATH];
+  if (!_wfullpath(file_path, input.value().c_str(), MAX_PATH))
+    return FilePath();
+  return FilePath(file_path);
+}
+
+bool DeleteFile(const FilePath& path, bool recursive) {
+  ThreadRestrictions::AssertIOAllowed();
+
+  if (path.value().length() >= MAX_PATH)
+    return false;
+
+  // On XP SHFileOperation will return ERROR_ACCESS_DENIED instead of
+  // ERROR_FILE_NOT_FOUND, so just shortcut this here.
+  if (path.empty())
+    return true;
+
+  if (!recursive) {
+    // If not recursing, then first check to see if |path| is a directory.
+    // If it is, then remove it with RemoveDirectory.
+    File::Info file_info;
+    if (GetFileInfo(path, &file_info) && file_info.is_directory)
+      return RemoveDirectory(path.value().c_str()) != 0;
+
+    // Otherwise, it's a file, wildcard or non-existant. Try DeleteFile first
+    // because it should be faster. If DeleteFile fails, then we fall through
+    // to SHFileOperation, which will do the right thing.
+    if (::DeleteFile(path.value().c_str()) != 0)
+      return true;
+  }
+
+  // SHFILEOPSTRUCT wants the path to be terminated with two NULLs,
+  // so we have to use wcscpy because wcscpy_s writes non-NULLs
+  // into the rest of the buffer.
+  wchar_t double_terminated_path[MAX_PATH + 1] = {0};
+#pragma warning(suppress:4996)  // don't complain about wcscpy deprecation
+  wcscpy(double_terminated_path, path.value().c_str());
+
+  SHFILEOPSTRUCT file_operation = {0};
+  file_operation.wFunc = FO_DELETE;
+  file_operation.pFrom = double_terminated_path;
+  file_operation.fFlags = FOF_NOERRORUI | FOF_SILENT | FOF_NOCONFIRMATION;
+  if (!recursive)
+    file_operation.fFlags |= FOF_NORECURSION | FOF_FILESONLY;
+  int err = SHFileOperation(&file_operation);
+
+  // Since we're passing flags to the operation telling it to be silent,
+  // it's possible for the operation to be aborted/cancelled without err
+  // being set (although MSDN doesn't give any scenarios for how this can
+  // happen).  See MSDN for SHFileOperation and SHFILEOPTSTRUCT.
+  if (file_operation.fAnyOperationsAborted)
+    return false;
+
+  // Some versions of Windows return ERROR_FILE_NOT_FOUND (0x2) when deleting
+  // an empty directory and some return 0x402 when they should be returning
+  // ERROR_FILE_NOT_FOUND. MSDN says Vista and up won't return 0x402.  Windows 7
+  // can return DE_INVALIDFILES (0x7C) for nonexistent directories.
+  return (err == 0 || err == ERROR_FILE_NOT_FOUND || err == 0x402 ||
+          err == 0x7C);
+}
+
+bool DeleteFileAfterReboot(const FilePath& path) {
+  ThreadRestrictions::AssertIOAllowed();
+
+  if (path.value().length() >= MAX_PATH)
+    return false;
+
+  return MoveFileEx(path.value().c_str(), NULL,
+                    MOVEFILE_DELAY_UNTIL_REBOOT |
+                        MOVEFILE_REPLACE_EXISTING) != FALSE;
+}
+
+bool ReplaceFile(const FilePath& from_path,
+                 const FilePath& to_path,
+                 File::Error* error) {
+  ThreadRestrictions::AssertIOAllowed();
+  // Try a simple move first.  It will only succeed when |to_path| doesn't
+  // already exist.
+  if (::MoveFile(from_path.value().c_str(), to_path.value().c_str()))
+    return true;
+  // Try the full-blown replace if the move fails, as ReplaceFile will only
+  // succeed when |to_path| does exist. When writing to a network share, we may
+  // not be able to change the ACLs. Ignore ACL errors then
+  // (REPLACEFILE_IGNORE_MERGE_ERRORS).
+  if (::ReplaceFile(to_path.value().c_str(), from_path.value().c_str(), NULL,
+                    REPLACEFILE_IGNORE_MERGE_ERRORS, NULL, NULL)) {
+    return true;
+  }
+  if (error)
+    *error = File::OSErrorToFileError(GetLastError());
+  return false;
+}
+
+bool CopyDirectory(const FilePath& from_path, const FilePath& to_path,
+                   bool recursive) {
+  // NOTE(maruel): Previous version of this function used to call
+  // SHFileOperation().  This used to copy the file attributes and extended
+  // attributes, OLE structured storage, NTFS file system alternate data
+  // streams, SECURITY_DESCRIPTOR. In practice, this is not what we want, we
+  // want the containing directory to propagate its SECURITY_DESCRIPTOR.
+  ThreadRestrictions::AssertIOAllowed();
+
+  // NOTE: I suspect we could support longer paths, but that would involve
+  // analyzing all our usage of files.
+  if (from_path.value().length() >= MAX_PATH ||
+      to_path.value().length() >= MAX_PATH) {
+    return false;
+  }
+
+  // This function does not properly handle destinations within the source.
+  FilePath real_to_path = to_path;
+  if (PathExists(real_to_path)) {
+    real_to_path = MakeAbsoluteFilePath(real_to_path);
+    if (real_to_path.empty())
+      return false;
+  } else {
+    real_to_path = MakeAbsoluteFilePath(real_to_path.DirName());
+    if (real_to_path.empty())
+      return false;
+  }
+  FilePath real_from_path = MakeAbsoluteFilePath(from_path);
+  if (real_from_path.empty())
+    return false;
+  if (real_to_path.value().size() >= real_from_path.value().size() &&
+      real_to_path.value().compare(0, real_from_path.value().size(),
+                                   real_from_path.value()) == 0) {
+    return false;
+  }
+
+  int traverse_type = FileEnumerator::FILES;
+  if (recursive)
+    traverse_type |= FileEnumerator::DIRECTORIES;
+  FileEnumerator traversal(from_path, recursive, traverse_type);
+
+  if (!PathExists(from_path)) {
+    DLOG(ERROR) << "CopyDirectory() couldn't stat source directory: "
+                << from_path.value().c_str();
+    return false;
+  }
+  // TODO(maruel): This is not necessary anymore.
+  DCHECK(recursive || DirectoryExists(from_path));
+
+  FilePath current = from_path;
+  bool from_is_dir = DirectoryExists(from_path);
+  bool success = true;
+  FilePath from_path_base = from_path;
+  if (recursive && DirectoryExists(to_path)) {
+    // If the destination already exists and is a directory, then the
+    // top level of source needs to be copied.
+    from_path_base = from_path.DirName();
+  }
+
+  while (success && !current.empty()) {
+    // current is the source path, including from_path, so append
+    // the suffix after from_path to to_path to create the target_path.
+    FilePath target_path(to_path);
+    if (from_path_base != current) {
+      if (!from_path_base.AppendRelativePath(current, &target_path)) {
+        success = false;
+        break;
+      }
+    }
+
+    if (from_is_dir) {
+      if (!DirectoryExists(target_path) &&
+          !::CreateDirectory(target_path.value().c_str(), NULL)) {
+        DLOG(ERROR) << "CopyDirectory() couldn't create directory: "
+                    << target_path.value().c_str();
+        success = false;
+      }
+    } else if (!CopyFile(current, target_path)) {
+      DLOG(ERROR) << "CopyDirectory() couldn't create file: "
+                  << target_path.value().c_str();
+      success = false;
+    }
+
+    current = traversal.Next();
+    if (!current.empty())
+      from_is_dir = traversal.GetInfo().IsDirectory();
+  }
+
+  return success;
+}
+
+bool PathExists(const FilePath& path) {
+  ThreadRestrictions::AssertIOAllowed();
+  return (GetFileAttributes(path.value().c_str()) != INVALID_FILE_ATTRIBUTES);
+}
+
+bool PathIsWritable(const FilePath& path) {
+  ThreadRestrictions::AssertIOAllowed();
+  HANDLE dir =
+      CreateFile(path.value().c_str(), FILE_ADD_FILE, kFileShareAll,
+                 NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+
+  if (dir == INVALID_HANDLE_VALUE)
+    return false;
+
+  CloseHandle(dir);
+  return true;
+}
+
+bool DirectoryExists(const FilePath& path) {
+  ThreadRestrictions::AssertIOAllowed();
+  DWORD fileattr = GetFileAttributes(path.value().c_str());
+  if (fileattr != INVALID_FILE_ATTRIBUTES)
+    return (fileattr & FILE_ATTRIBUTE_DIRECTORY) != 0;
+  return false;
+}
+
+bool GetTempDir(FilePath* path) {
+  wchar_t temp_path[MAX_PATH + 1];
+  DWORD path_len = ::GetTempPath(MAX_PATH, temp_path);
+  if (path_len >= MAX_PATH || path_len <= 0)
+    return false;
+  // TODO(evanm): the old behavior of this function was to always strip the
+  // trailing slash.  We duplicate this here, but it shouldn't be necessary
+  // when everyone is using the appropriate FilePath APIs.
+  *path = FilePath(temp_path).StripTrailingSeparators();
+  return true;
+}
+
+FilePath GetHomeDir() {
+  char16 result[MAX_PATH];
+  if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PROFILE, NULL, SHGFP_TYPE_CURRENT,
+                                result)) &&
+      result[0]) {
+    return FilePath(result);
+  }
+
+  // Fall back to the temporary directory on failure.
+  FilePath temp;
+  if (GetTempDir(&temp))
+    return temp;
+
+  // Last resort.
+  return FilePath(L"C:\\");
+}
+
+bool CreateTemporaryFile(FilePath* path) {
+  ThreadRestrictions::AssertIOAllowed();
+
+  FilePath temp_file;
+
+  if (!GetTempDir(path))
+    return false;
+
+  if (CreateTemporaryFileInDir(*path, &temp_file)) {
+    *path = temp_file;
+    return true;
+  }
+
+  return false;
+}
+
+// On POSIX we have semantics to create and open a temporary file
+// atomically.
+// TODO(jrg): is there equivalent call to use on Windows instead of
+// going 2-step?
+FILE* CreateAndOpenTemporaryFileInDir(const FilePath& dir, FilePath* path) {
+  ThreadRestrictions::AssertIOAllowed();
+  if (!CreateTemporaryFileInDir(dir, path)) {
+    return NULL;
+  }
+  // Open file in binary mode, to avoid problems with fwrite. On Windows
+  // it replaces \n's with \r\n's, which may surprise you.
+  // Reference: http://msdn.microsoft.com/en-us/library/h9t88zwz(VS.71).aspx
+  return OpenFile(*path, "wb+");
+}
+
+bool CreateTemporaryFileInDir(const FilePath& dir, FilePath* temp_file) {
+  ThreadRestrictions::AssertIOAllowed();
+
+  wchar_t temp_name[MAX_PATH + 1];
+
+  if (!GetTempFileName(dir.value().c_str(), L"", 0, temp_name)) {
+    DPLOG(WARNING) << "Failed to get temporary file name in "
+                   << UTF16ToUTF8(dir.value());
+    return false;
+  }
+
+  wchar_t long_temp_name[MAX_PATH + 1];
+  DWORD long_name_len = GetLongPathName(temp_name, long_temp_name, MAX_PATH);
+  if (long_name_len > MAX_PATH || long_name_len == 0) {
+    // GetLongPathName() failed, but we still have a temporary file.
+    *temp_file = FilePath(temp_name);
+    return true;
+  }
+
+  FilePath::StringType long_temp_name_str;
+  long_temp_name_str.assign(long_temp_name, long_name_len);
+  *temp_file = FilePath(long_temp_name_str);
+  return true;
+}
+
+bool CreateTemporaryDirInDir(const FilePath& base_dir,
+                             const FilePath::StringType& prefix,
+                             FilePath* new_dir) {
+  ThreadRestrictions::AssertIOAllowed();
+
+  FilePath path_to_create;
+
+  for (int count = 0; count < 50; ++count) {
+    // Try create a new temporary directory with random generated name. If
+    // the one exists, keep trying another path name until we reach some limit.
+    string16 new_dir_name;
+    new_dir_name.assign(prefix);
+    new_dir_name.append(IntToString16(GetCurrentProcId()));
+    new_dir_name.push_back('_');
+    new_dir_name.append(IntToString16(RandInt(0, kint16max)));
+
+    path_to_create = base_dir.Append(new_dir_name);
+    if (::CreateDirectory(path_to_create.value().c_str(), NULL)) {
+      *new_dir = path_to_create;
+      return true;
+    }
+  }
+
+  return false;
+}
+
+bool CreateNewTempDirectory(const FilePath::StringType& prefix,
+                            FilePath* new_temp_path) {
+  ThreadRestrictions::AssertIOAllowed();
+
+  FilePath system_temp_dir;
+  if (!GetTempDir(&system_temp_dir))
+    return false;
+
+  return CreateTemporaryDirInDir(system_temp_dir, prefix, new_temp_path);
+}
+
+bool CreateDirectoryAndGetError(const FilePath& full_path,
+                                File::Error* error) {
+  ThreadRestrictions::AssertIOAllowed();
+
+  // If the path exists, we've succeeded if it's a directory, failed otherwise.
+  const wchar_t* full_path_str = full_path.value().c_str();
+  DWORD fileattr = ::GetFileAttributes(full_path_str);
+  if (fileattr != INVALID_FILE_ATTRIBUTES) {
+    if ((fileattr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
+      DVLOG(1) << "CreateDirectory(" << full_path_str << "), "
+               << "directory already exists.";
+      return true;
+    }
+    DLOG(WARNING) << "CreateDirectory(" << full_path_str << "), "
+                  << "conflicts with existing file.";
+    if (error) {
+      *error = File::FILE_ERROR_NOT_A_DIRECTORY;
+    }
+    return false;
+  }
+
+  // Invariant:  Path does not exist as file or directory.
+
+  // Attempt to create the parent recursively.  This will immediately return
+  // true if it already exists, otherwise will create all required parent
+  // directories starting with the highest-level missing parent.
+  FilePath parent_path(full_path.DirName());
+  if (parent_path.value() == full_path.value()) {
+    if (error) {
+      *error = File::FILE_ERROR_NOT_FOUND;
+    }
+    return false;
+  }
+  if (!CreateDirectoryAndGetError(parent_path, error)) {
+    DLOG(WARNING) << "Failed to create one of the parent directories.";
+    if (error) {
+      DCHECK(*error != File::FILE_OK);
+    }
+    return false;
+  }
+
+  if (!::CreateDirectory(full_path_str, NULL)) {
+    DWORD error_code = ::GetLastError();
+    if (error_code == ERROR_ALREADY_EXISTS && DirectoryExists(full_path)) {
+      // This error code ERROR_ALREADY_EXISTS doesn't indicate whether we
+      // were racing with someone creating the same directory, or a file
+      // with the same path.  If DirectoryExists() returns true, we lost the
+      // race to create the same directory.
+      return true;
+    } else {
+      if (error)
+        *error = File::OSErrorToFileError(error_code);
+      DLOG(WARNING) << "Failed to create directory " << full_path_str
+                    << ", last error is " << error_code << ".";
+      return false;
+    }
+  } else {
+    return true;
+  }
+}
+
+bool NormalizeFilePath(const FilePath& path, FilePath* real_path) {
+  ThreadRestrictions::AssertIOAllowed();
+  FilePath mapped_file;
+  if (!NormalizeToNativeFilePath(path, &mapped_file))
+    return false;
+  // NormalizeToNativeFilePath() will return a path that starts with
+  // "\Device\Harddisk...".  Helper DevicePathToDriveLetterPath()
+  // will find a drive letter which maps to the path's device, so
+  // that we return a path starting with a drive letter.
+  return DevicePathToDriveLetterPath(mapped_file, real_path);
+}
+
+bool DevicePathToDriveLetterPath(const FilePath& nt_device_path,
+                                 FilePath* out_drive_letter_path) {
+  ThreadRestrictions::AssertIOAllowed();
+
+  // Get the mapping of drive letters to device paths.
+  const int kDriveMappingSize = 1024;
+  wchar_t drive_mapping[kDriveMappingSize] = {'\0'};
+  if (!::GetLogicalDriveStrings(kDriveMappingSize - 1, drive_mapping)) {
+    DLOG(ERROR) << "Failed to get drive mapping.";
+    return false;
+  }
+
+  // The drive mapping is a sequence of null terminated strings.
+  // The last string is empty.
+  wchar_t* drive_map_ptr = drive_mapping;
+  wchar_t device_path_as_string[MAX_PATH];
+  wchar_t drive[] = L" :";
+
+  // For each string in the drive mapping, get the junction that links
+  // to it.  If that junction is a prefix of |device_path|, then we
+  // know that |drive| is the real path prefix.
+  while (*drive_map_ptr) {
+    drive[0] = drive_map_ptr[0];  // Copy the drive letter.
+
+    if (QueryDosDevice(drive, device_path_as_string, MAX_PATH)) {
+      FilePath device_path(device_path_as_string);
+      if (device_path == nt_device_path ||
+          device_path.IsParent(nt_device_path)) {
+        *out_drive_letter_path = FilePath(drive +
+            nt_device_path.value().substr(wcslen(device_path_as_string)));
+        return true;
+      }
+    }
+    // Move to the next drive letter string, which starts one
+    // increment after the '\0' that terminates the current string.
+    while (*drive_map_ptr++) {}
+  }
+
+  // No drive matched.  The path does not start with a device junction
+  // that is mounted as a drive letter.  This means there is no drive
+  // letter path to the volume that holds |device_path|, so fail.
+  return false;
+}
+
+bool NormalizeToNativeFilePath(const FilePath& path, FilePath* nt_path) {
+  ThreadRestrictions::AssertIOAllowed();
+  // In Vista, GetFinalPathNameByHandle() would give us the real path
+  // from a file handle.  If we ever deprecate XP, consider changing the
+  // code below to a call to GetFinalPathNameByHandle().  The method this
+  // function uses is explained in the following msdn article:
+  // http://msdn.microsoft.com/en-us/library/aa366789(VS.85).aspx
+  win::ScopedHandle file_handle(
+      ::CreateFile(path.value().c_str(),
+                   GENERIC_READ,
+                   kFileShareAll,
+                   NULL,
+                   OPEN_EXISTING,
+                   FILE_ATTRIBUTE_NORMAL,
+                   NULL));
+  if (!file_handle.IsValid())
+    return false;
+
+  // Create a file mapping object.  Can't easily use MemoryMappedFile, because
+  // we only map the first byte, and need direct access to the handle. You can
+  // not map an empty file, this call fails in that case.
+  win::ScopedHandle file_map_handle(
+      ::CreateFileMapping(file_handle.Get(),
+                          NULL,
+                          PAGE_READONLY,
+                          0,
+                          1,  // Just one byte.  No need to look at the data.
+                          NULL));
+  if (!file_map_handle.IsValid())
+    return false;
+
+  // Use a view of the file to get the path to the file.
+  void* file_view = MapViewOfFile(file_map_handle.Get(),
+                                  FILE_MAP_READ, 0, 0, 1);
+  if (!file_view)
+    return false;
+
+  // The expansion of |path| into a full path may make it longer.
+  // GetMappedFileName() will fail if the result is longer than MAX_PATH.
+  // Pad a bit to be safe.  If kMaxPathLength is ever changed to be less
+  // than MAX_PATH, it would be nessisary to test that GetMappedFileName()
+  // not return kMaxPathLength.  This would mean that only part of the
+  // path fit in |mapped_file_path|.
+  const int kMaxPathLength = MAX_PATH + 10;
+  wchar_t mapped_file_path[kMaxPathLength];
+  bool success = false;
+  HANDLE cp = GetCurrentProcess();
+  if (::GetMappedFileNameW(cp, file_view, mapped_file_path, kMaxPathLength)) {
+    *nt_path = FilePath(mapped_file_path);
+    success = true;
+  }
+  ::UnmapViewOfFile(file_view);
+  return success;
+}
+
+// TODO(rkc): Work out if we want to handle NTFS junctions here or not, handle
+// them if we do decide to.
+bool IsLink(const FilePath& file_path) {
+  return false;
+}
+
+bool GetFileInfo(const FilePath& file_path, File::Info* results) {
+  ThreadRestrictions::AssertIOAllowed();
+
+  WIN32_FILE_ATTRIBUTE_DATA attr;
+  if (!GetFileAttributesEx(file_path.value().c_str(),
+                           GetFileExInfoStandard, &attr)) {
+    return false;
+  }
+
+  ULARGE_INTEGER size;
+  size.HighPart = attr.nFileSizeHigh;
+  size.LowPart = attr.nFileSizeLow;
+  results->size = size.QuadPart;
+
+  results->is_directory =
+      (attr.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
+  results->last_modified = Time::FromFileTime(attr.ftLastWriteTime);
+  results->last_accessed = Time::FromFileTime(attr.ftLastAccessTime);
+  results->creation_time = Time::FromFileTime(attr.ftCreationTime);
+
+  return true;
+}
+
+FILE* OpenFile(const FilePath& filename, const char* mode) {
+  ThreadRestrictions::AssertIOAllowed();
+  string16 w_mode = ASCIIToUTF16(mode);
+  return _wfsopen(filename.value().c_str(), w_mode.c_str(), _SH_DENYNO);
+}
+
+FILE* FileToFILE(File file, const char* mode) {
+  if (!file.IsValid())
+    return NULL;
+  int fd =
+      _open_osfhandle(reinterpret_cast<intptr_t>(file.GetPlatformFile()), 0);
+  if (fd < 0)
+    return NULL;
+  file.TakePlatformFile();
+  FILE* stream = _fdopen(fd, mode);
+  if (!stream)
+    _close(fd);
+  return stream;
+}
+
+int ReadFile(const FilePath& filename, char* data, int max_size) {
+  ThreadRestrictions::AssertIOAllowed();
+  win::ScopedHandle file(CreateFile(filename.value().c_str(),
+                                    GENERIC_READ,
+                                    FILE_SHARE_READ | FILE_SHARE_WRITE,
+                                    NULL,
+                                    OPEN_EXISTING,
+                                    FILE_FLAG_SEQUENTIAL_SCAN,
+                                    NULL));
+  if (!file.IsValid())
+    return -1;
+
+  DWORD read;
+  if (::ReadFile(file.Get(), data, max_size, &read, NULL))
+    return read;
+
+  return -1;
+}
+
+int WriteFile(const FilePath& filename, const char* data, int size) {
+  ThreadRestrictions::AssertIOAllowed();
+  win::ScopedHandle file(CreateFile(filename.value().c_str(),
+                                    GENERIC_WRITE,
+                                    0,
+                                    NULL,
+                                    CREATE_ALWAYS,
+                                    0,
+                                    NULL));
+  if (!file.IsValid()) {
+    DPLOG(WARNING) << "CreateFile failed for path "
+                   << UTF16ToUTF8(filename.value());
+    return -1;
+  }
+
+  DWORD written;
+  BOOL result = ::WriteFile(file.Get(), data, size, &written, NULL);
+  if (result && static_cast<int>(written) == size)
+    return written;
+
+  if (!result) {
+    // WriteFile failed.
+    DPLOG(WARNING) << "writing file " << UTF16ToUTF8(filename.value())
+                   << " failed";
+  } else {
+    // Didn't write all the bytes.
+    DLOG(WARNING) << "wrote" << written << " bytes to "
+                  << UTF16ToUTF8(filename.value()) << " expected " << size;
+  }
+  return -1;
+}
+
+bool AppendToFile(const FilePath& filename, const char* data, int size) {
+  ThreadRestrictions::AssertIOAllowed();
+  win::ScopedHandle file(CreateFile(filename.value().c_str(),
+                                    FILE_APPEND_DATA,
+                                    0,
+                                    NULL,
+                                    OPEN_EXISTING,
+                                    0,
+                                    NULL));
+  if (!file.IsValid()) {
+    VPLOG(1) << "CreateFile failed for path " << UTF16ToUTF8(filename.value());
+    return false;
+  }
+
+  DWORD written;
+  BOOL result = ::WriteFile(file.Get(), data, size, &written, NULL);
+  if (result && static_cast<int>(written) == size)
+    return true;
+
+  if (!result) {
+    // WriteFile failed.
+    VPLOG(1) << "Writing file " << UTF16ToUTF8(filename.value()) << " failed";
+  } else {
+    // Didn't write all the bytes.
+    VPLOG(1) << "Only wrote " << written << " out of " << size << " byte(s) to "
+             << UTF16ToUTF8(filename.value());
+  }
+  return false;
+}
+
+// Gets the current working directory for the process.
+bool GetCurrentDirectory(FilePath* dir) {
+  ThreadRestrictions::AssertIOAllowed();
+
+  wchar_t system_buffer[MAX_PATH];
+  system_buffer[0] = 0;
+  DWORD len = ::GetCurrentDirectory(MAX_PATH, system_buffer);
+  if (len == 0 || len > MAX_PATH)
+    return false;
+  // TODO(evanm): the old behavior of this function was to always strip the
+  // trailing slash.  We duplicate this here, but it shouldn't be necessary
+  // when everyone is using the appropriate FilePath APIs.
+  std::wstring dir_str(system_buffer);
+  *dir = FilePath(dir_str).StripTrailingSeparators();
+  return true;
+}
+
+// Sets the current working directory for the process.
+bool SetCurrentDirectory(const FilePath& directory) {
+  ThreadRestrictions::AssertIOAllowed();
+  BOOL ret = ::SetCurrentDirectory(directory.value().c_str());
+  return ret != 0;
+}
+
+int GetMaximumPathComponentLength(const FilePath& path) {
+  ThreadRestrictions::AssertIOAllowed();
+
+  wchar_t volume_path[MAX_PATH];
+  if (!GetVolumePathNameW(path.NormalizePathSeparators().value().c_str(),
+                          volume_path,
+                          arraysize(volume_path))) {
+    return -1;
+  }
+
+  DWORD max_length = 0;
+  if (!GetVolumeInformationW(volume_path, NULL, 0, NULL, &max_length, NULL,
+                             NULL, 0)) {
+    return -1;
+  }
+
+  // Length of |path| with path separator appended.
+  size_t prefix = path.StripTrailingSeparators().value().size() + 1;
+  // The whole path string must be shorter than MAX_PATH. That is, it must be
+  // prefix + component_length < MAX_PATH (or equivalently, <= MAX_PATH - 1).
+  int whole_path_limit = std::max(0, MAX_PATH - 1 - static_cast<int>(prefix));
+  return std::min(whole_path_limit, static_cast<int>(max_length));
+}
+
+bool CopyFile(const FilePath& from_path, const FilePath& to_path) {
+  ThreadRestrictions::AssertIOAllowed();
+  if (from_path.ReferencesParent() || to_path.ReferencesParent())
+    return false;
+
+  // NOTE: I suspect we could support longer paths, but that would involve
+  // analyzing all our usage of files.
+  if (from_path.value().length() >= MAX_PATH ||
+      to_path.value().length() >= MAX_PATH) {
+    return false;
+  }
+
+  // Unlike the posix implementation that copies the file manually and discards
+  // the ACL bits, CopyFile() copies the complete SECURITY_DESCRIPTOR and access
+  // bits, which is usually not what we want. We can't do much about the
+  // SECURITY_DESCRIPTOR but at least remove the read only bit.
+  const wchar_t* dest = to_path.value().c_str();
+  if (!::CopyFile(from_path.value().c_str(), dest, false)) {
+    // Copy failed.
+    return false;
+  }
+  DWORD attrs = GetFileAttributes(dest);
+  if (attrs == INVALID_FILE_ATTRIBUTES) {
+    return false;
+  }
+  if (attrs & FILE_ATTRIBUTE_READONLY) {
+    SetFileAttributes(dest, attrs & ~FILE_ATTRIBUTE_READONLY);
+  }
+  return true;
+}
+
+// -----------------------------------------------------------------------------
+
+namespace internal {
+
+bool MoveUnsafe(const FilePath& from_path, const FilePath& to_path) {
+  ThreadRestrictions::AssertIOAllowed();
+
+  // NOTE: I suspect we could support longer paths, but that would involve
+  // analyzing all our usage of files.
+  if (from_path.value().length() >= MAX_PATH ||
+      to_path.value().length() >= MAX_PATH) {
+    return false;
+  }
+  if (MoveFileEx(from_path.value().c_str(), to_path.value().c_str(),
+                 MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING) != 0)
+    return true;
+
+  // Keep the last error value from MoveFileEx around in case the below
+  // fails.
+  bool ret = false;
+  DWORD last_error = ::GetLastError();
+
+  if (DirectoryExists(from_path)) {
+    // MoveFileEx fails if moving directory across volumes. We will simulate
+    // the move by using Copy and Delete. Ideally we could check whether
+    // from_path and to_path are indeed in different volumes.
+    ret = internal::CopyAndDeleteDirectory(from_path, to_path);
+  }
+
+  if (!ret) {
+    // Leave a clue about what went wrong so that it can be (at least) picked
+    // up by a PLOG entry.
+    ::SetLastError(last_error);
+  }
+
+  return ret;
+}
+
+bool CopyAndDeleteDirectory(const FilePath& from_path,
+                            const FilePath& to_path) {
+  ThreadRestrictions::AssertIOAllowed();
+  if (CopyDirectory(from_path, to_path, true)) {
+    if (DeleteFile(from_path, true))
+      return true;
+
+    // Like Move, this function is not transactional, so we just
+    // leave the copied bits behind if deleting from_path fails.
+    // If to_path exists previously then we have already overwritten
+    // it by now, we don't get better off by deleting the new bits.
+  }
+  return false;
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/files/file_win.cc b/base/files/file_win.cc
new file mode 100644
index 0000000..9792852
--- /dev/null
+++ b/base/files/file_win.cc
@@ -0,0 +1,405 @@
+// Copyright (c) 2012 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/files/file.h"
+
+#include <io.h>
+
+#include "base/logging.h"
+#include "base/metrics/sparse_histogram.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace base {
+
+// Make sure our Whence mappings match the system headers.
+COMPILE_ASSERT(File::FROM_BEGIN   == FILE_BEGIN &&
+               File::FROM_CURRENT == FILE_CURRENT &&
+               File::FROM_END     == FILE_END, whence_matches_system);
+
+bool File::IsValid() const {
+  return file_.IsValid();
+}
+
+PlatformFile File::GetPlatformFile() const {
+  return file_.Get();
+}
+
+PlatformFile File::TakePlatformFile() {
+  return file_.Take();
+}
+
+void File::Close() {
+  if (!file_.IsValid())
+    return;
+
+  ThreadRestrictions::AssertIOAllowed();
+  SCOPED_FILE_TRACE("Close");
+  file_.Close();
+}
+
+int64 File::Seek(Whence whence, int64 offset) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(IsValid());
+
+  SCOPED_FILE_TRACE_WITH_SIZE("Seek", offset);
+
+  LARGE_INTEGER distance, res;
+  distance.QuadPart = offset;
+  DWORD move_method = static_cast<DWORD>(whence);
+  if (!SetFilePointerEx(file_.Get(), distance, &res, move_method))
+    return -1;
+  return res.QuadPart;
+}
+
+int File::Read(int64 offset, char* data, int size) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(IsValid());
+  DCHECK(!async_);
+  if (size < 0)
+    return -1;
+
+  SCOPED_FILE_TRACE_WITH_SIZE("Read", size);
+
+  LARGE_INTEGER offset_li;
+  offset_li.QuadPart = offset;
+
+  OVERLAPPED overlapped = {0};
+  overlapped.Offset = offset_li.LowPart;
+  overlapped.OffsetHigh = offset_li.HighPart;
+
+  DWORD bytes_read;
+  if (::ReadFile(file_.Get(), data, size, &bytes_read, &overlapped))
+    return bytes_read;
+  if (ERROR_HANDLE_EOF == GetLastError())
+    return 0;
+
+  return -1;
+}
+
+int File::ReadAtCurrentPos(char* data, int size) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(IsValid());
+  DCHECK(!async_);
+  if (size < 0)
+    return -1;
+
+  SCOPED_FILE_TRACE_WITH_SIZE("ReadAtCurrentPos", size);
+
+  DWORD bytes_read;
+  if (::ReadFile(file_.Get(), data, size, &bytes_read, NULL))
+    return bytes_read;
+  if (ERROR_HANDLE_EOF == GetLastError())
+    return 0;
+
+  return -1;
+}
+
+int File::ReadNoBestEffort(int64 offset, char* data, int size) {
+  // TODO(dbeam): trace this separately?
+  return Read(offset, data, size);
+}
+
+int File::ReadAtCurrentPosNoBestEffort(char* data, int size) {
+  // TODO(dbeam): trace this separately?
+  return ReadAtCurrentPos(data, size);
+}
+
+int File::Write(int64 offset, const char* data, int size) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(IsValid());
+  DCHECK(!async_);
+
+  SCOPED_FILE_TRACE_WITH_SIZE("Write", size);
+
+  LARGE_INTEGER offset_li;
+  offset_li.QuadPart = offset;
+
+  OVERLAPPED overlapped = {0};
+  overlapped.Offset = offset_li.LowPart;
+  overlapped.OffsetHigh = offset_li.HighPart;
+
+  DWORD bytes_written;
+  if (::WriteFile(file_.Get(), data, size, &bytes_written, &overlapped))
+    return bytes_written;
+
+  return -1;
+}
+
+int File::WriteAtCurrentPos(const char* data, int size) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(IsValid());
+  DCHECK(!async_);
+  if (size < 0)
+    return -1;
+
+  SCOPED_FILE_TRACE_WITH_SIZE("WriteAtCurrentPos", size);
+
+  DWORD bytes_written;
+  if (::WriteFile(file_.Get(), data, size, &bytes_written, NULL))
+    return bytes_written;
+
+  return -1;
+}
+
+int File::WriteAtCurrentPosNoBestEffort(const char* data, int size) {
+  return WriteAtCurrentPos(data, size);
+}
+
+int64 File::GetLength() {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(IsValid());
+
+  SCOPED_FILE_TRACE("GetLength");
+
+  LARGE_INTEGER size;
+  if (!::GetFileSizeEx(file_.Get(), &size))
+    return -1;
+
+  return static_cast<int64>(size.QuadPart);
+}
+
+bool File::SetLength(int64 length) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(IsValid());
+
+  SCOPED_FILE_TRACE_WITH_SIZE("SetLength", length);
+
+  // Get the current file pointer.
+  LARGE_INTEGER file_pointer;
+  LARGE_INTEGER zero;
+  zero.QuadPart = 0;
+  if (!::SetFilePointerEx(file_.Get(), zero, &file_pointer, FILE_CURRENT))
+    return false;
+
+  LARGE_INTEGER length_li;
+  length_li.QuadPart = length;
+  // If length > file size, SetFilePointerEx() should extend the file
+  // with zeroes on all Windows standard file systems (NTFS, FATxx).
+  if (!::SetFilePointerEx(file_.Get(), length_li, NULL, FILE_BEGIN))
+    return false;
+
+  // Set the new file length and move the file pointer to its old position.
+  // This is consistent with ftruncate()'s behavior, even when the file
+  // pointer points to a location beyond the end of the file.
+  // TODO(rvargas): Emulating ftruncate details seem suspicious and it is not
+  // promised by the interface (nor was promised by PlatformFile). See if this
+  // implementation detail can be removed.
+  return ((::SetEndOfFile(file_.Get()) != FALSE) &&
+          (::SetFilePointerEx(file_.Get(), file_pointer, NULL, FILE_BEGIN) !=
+           FALSE));
+}
+
+bool File::SetTimes(Time last_access_time, Time last_modified_time) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(IsValid());
+
+  SCOPED_FILE_TRACE("SetTimes");
+
+  FILETIME last_access_filetime = last_access_time.ToFileTime();
+  FILETIME last_modified_filetime = last_modified_time.ToFileTime();
+  return (::SetFileTime(file_.Get(), NULL, &last_access_filetime,
+                        &last_modified_filetime) != FALSE);
+}
+
+bool File::GetInfo(Info* info) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(IsValid());
+
+  SCOPED_FILE_TRACE("GetInfo");
+
+  BY_HANDLE_FILE_INFORMATION file_info;
+  if (!GetFileInformationByHandle(file_.Get(), &file_info))
+    return false;
+
+  LARGE_INTEGER size;
+  size.HighPart = file_info.nFileSizeHigh;
+  size.LowPart = file_info.nFileSizeLow;
+  info->size = size.QuadPart;
+  info->is_directory =
+      (file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
+  info->is_symbolic_link = false;  // Windows doesn't have symbolic links.
+  info->last_modified = Time::FromFileTime(file_info.ftLastWriteTime);
+  info->last_accessed = Time::FromFileTime(file_info.ftLastAccessTime);
+  info->creation_time = Time::FromFileTime(file_info.ftCreationTime);
+  return true;
+}
+
+File::Error File::Lock() {
+  DCHECK(IsValid());
+
+  SCOPED_FILE_TRACE("Lock");
+
+  BOOL result = LockFile(file_.Get(), 0, 0, MAXDWORD, MAXDWORD);
+  if (!result)
+    return OSErrorToFileError(GetLastError());
+  return FILE_OK;
+}
+
+File::Error File::Unlock() {
+  DCHECK(IsValid());
+
+  SCOPED_FILE_TRACE("Unlock");
+
+  BOOL result = UnlockFile(file_.Get(), 0, 0, MAXDWORD, MAXDWORD);
+  if (!result)
+    return OSErrorToFileError(GetLastError());
+  return FILE_OK;
+}
+
+File File::Duplicate() {
+  if (!IsValid())
+    return File();
+
+  SCOPED_FILE_TRACE("Duplicate");
+
+  HANDLE other_handle = nullptr;
+
+  if (!::DuplicateHandle(GetCurrentProcess(),  // hSourceProcessHandle
+                         GetPlatformFile(),
+                         GetCurrentProcess(),  // hTargetProcessHandle
+                         &other_handle,
+                         0,  // dwDesiredAccess ignored due to SAME_ACCESS
+                         FALSE,  // !bInheritHandle
+                         DUPLICATE_SAME_ACCESS)) {
+    return File(OSErrorToFileError(GetLastError()));
+  }
+
+  File other(other_handle);
+  if (async())
+    other.async_ = true;
+  return other.Pass();
+}
+
+// Static.
+File::Error File::OSErrorToFileError(DWORD last_error) {
+  switch (last_error) {
+    case ERROR_SHARING_VIOLATION:
+      return FILE_ERROR_IN_USE;
+    case ERROR_FILE_EXISTS:
+      return FILE_ERROR_EXISTS;
+    case ERROR_FILE_NOT_FOUND:
+    case ERROR_PATH_NOT_FOUND:
+      return FILE_ERROR_NOT_FOUND;
+    case ERROR_ACCESS_DENIED:
+      return FILE_ERROR_ACCESS_DENIED;
+    case ERROR_TOO_MANY_OPEN_FILES:
+      return FILE_ERROR_TOO_MANY_OPENED;
+    case ERROR_OUTOFMEMORY:
+    case ERROR_NOT_ENOUGH_MEMORY:
+      return FILE_ERROR_NO_MEMORY;
+    case ERROR_HANDLE_DISK_FULL:
+    case ERROR_DISK_FULL:
+    case ERROR_DISK_RESOURCES_EXHAUSTED:
+      return FILE_ERROR_NO_SPACE;
+    case ERROR_USER_MAPPED_FILE:
+      return FILE_ERROR_INVALID_OPERATION;
+    case ERROR_NOT_READY:
+    case ERROR_SECTOR_NOT_FOUND:
+    case ERROR_DEV_NOT_EXIST:
+    case ERROR_IO_DEVICE:
+    case ERROR_FILE_CORRUPT:
+    case ERROR_DISK_CORRUPT:
+      return FILE_ERROR_IO;
+    default:
+      UMA_HISTOGRAM_SPARSE_SLOWLY("PlatformFile.UnknownErrors.Windows",
+                                  last_error);
+      return FILE_ERROR_FAILED;
+  }
+}
+
+void File::DoInitialize(uint32 flags) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(!IsValid());
+
+  DWORD disposition = 0;
+
+  if (flags & FLAG_OPEN)
+    disposition = OPEN_EXISTING;
+
+  if (flags & FLAG_CREATE) {
+    DCHECK(!disposition);
+    disposition = CREATE_NEW;
+  }
+
+  if (flags & FLAG_OPEN_ALWAYS) {
+    DCHECK(!disposition);
+    disposition = OPEN_ALWAYS;
+  }
+
+  if (flags & FLAG_CREATE_ALWAYS) {
+    DCHECK(!disposition);
+    DCHECK(flags & FLAG_WRITE);
+    disposition = CREATE_ALWAYS;
+  }
+
+  if (flags & FLAG_OPEN_TRUNCATED) {
+    DCHECK(!disposition);
+    DCHECK(flags & FLAG_WRITE);
+    disposition = TRUNCATE_EXISTING;
+  }
+
+  if (!disposition) {
+    NOTREACHED();
+    return;
+  }
+
+  DWORD access = 0;
+  if (flags & FLAG_WRITE)
+    access = GENERIC_WRITE;
+  if (flags & FLAG_APPEND) {
+    DCHECK(!access);
+    access = FILE_APPEND_DATA;
+  }
+  if (flags & FLAG_READ)
+    access |= GENERIC_READ;
+  if (flags & FLAG_WRITE_ATTRIBUTES)
+    access |= FILE_WRITE_ATTRIBUTES;
+  if (flags & FLAG_EXECUTE)
+    access |= GENERIC_EXECUTE;
+
+  DWORD sharing = (flags & FLAG_EXCLUSIVE_READ) ? 0 : FILE_SHARE_READ;
+  if (!(flags & FLAG_EXCLUSIVE_WRITE))
+    sharing |= FILE_SHARE_WRITE;
+  if (flags & FLAG_SHARE_DELETE)
+    sharing |= FILE_SHARE_DELETE;
+
+  DWORD create_flags = 0;
+  if (flags & FLAG_ASYNC)
+    create_flags |= FILE_FLAG_OVERLAPPED;
+  if (flags & FLAG_TEMPORARY)
+    create_flags |= FILE_ATTRIBUTE_TEMPORARY;
+  if (flags & FLAG_HIDDEN)
+    create_flags |= FILE_ATTRIBUTE_HIDDEN;
+  if (flags & FLAG_DELETE_ON_CLOSE)
+    create_flags |= FILE_FLAG_DELETE_ON_CLOSE;
+  if (flags & FLAG_BACKUP_SEMANTICS)
+    create_flags |= FILE_FLAG_BACKUP_SEMANTICS;
+
+  file_.Set(CreateFile(path_.value().c_str(), access, sharing, NULL,
+                       disposition, create_flags, NULL));
+
+  if (file_.IsValid()) {
+    error_details_ = FILE_OK;
+    async_ = ((flags & FLAG_ASYNC) == FLAG_ASYNC);
+
+    if (flags & (FLAG_OPEN_ALWAYS))
+      created_ = (ERROR_ALREADY_EXISTS != GetLastError());
+    else if (flags & (FLAG_CREATE_ALWAYS | FLAG_CREATE))
+      created_ = true;
+  } else {
+    error_details_ = OSErrorToFileError(GetLastError());
+  }
+}
+
+bool File::DoFlush() {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK(IsValid());
+  return ::FlushFileBuffers(file_.Get()) != FALSE;
+}
+
+void File::SetPlatformFile(PlatformFile file) {
+  file_.Set(file);
+}
+
+}  // namespace base
diff --git a/base/files/important_file_writer.cc b/base/files/important_file_writer.cc
new file mode 100644
index 0000000..814fc7b
--- /dev/null
+++ b/base/files/important_file_writer.cc
@@ -0,0 +1,226 @@
+// Copyright (c) 2011 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/files/important_file_writer.h"
+
+#include <stdio.h>
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/critical_closure.h"
+#include "base/debug/alias.h"
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/metrics/histogram.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/task_runner.h"
+#include "base/task_runner_util.h"
+#include "base/threading/thread.h"
+#include "base/time/time.h"
+
+namespace base {
+
+namespace {
+
+const int kDefaultCommitIntervalMs = 10000;
+
+// This enum is used to define the buckets for an enumerated UMA histogram.
+// Hence,
+//   (a) existing enumerated constants should never be deleted or reordered, and
+//   (b) new constants should only be appended at the end of the enumeration.
+enum TempFileFailure {
+  FAILED_CREATING,
+  FAILED_OPENING,
+  FAILED_CLOSING,  // Unused.
+  FAILED_WRITING,
+  FAILED_RENAMING,
+  FAILED_FLUSHING,
+  TEMP_FILE_FAILURE_MAX
+};
+
+void LogFailure(const FilePath& path, TempFileFailure failure_code,
+                const std::string& message) {
+  UMA_HISTOGRAM_ENUMERATION("ImportantFile.TempFileFailures", failure_code,
+                            TEMP_FILE_FAILURE_MAX);
+  DPLOG(WARNING) << "temp file failure: " << path.value().c_str()
+                 << " : " << message;
+}
+
+// Helper function to call WriteFileAtomically() with a scoped_ptr<std::string>.
+bool WriteScopedStringToFileAtomically(const FilePath& path,
+                                       scoped_ptr<std::string> data) {
+  return ImportantFileWriter::WriteFileAtomically(path, *data);
+}
+
+}  // namespace
+
+// static
+bool ImportantFileWriter::WriteFileAtomically(const FilePath& path,
+                                              const std::string& data) {
+#if defined(OS_CHROMEOS)
+  // On Chrome OS, chrome gets killed when it cannot finish shutdown quickly,
+  // and this function seems to be one of the slowest shutdown steps.
+  // Include some info to the report for investigation. crbug.com/418627
+  // TODO(hashimoto): Remove this.
+  struct {
+    size_t data_size;
+    char path[128];
+  } file_info;
+  file_info.data_size = data.size();
+  base::strlcpy(file_info.path, path.value().c_str(),
+                arraysize(file_info.path));
+  base::debug::Alias(&file_info);
+#endif
+  // Write the data to a temp file then rename to avoid data loss if we crash
+  // while writing the file. Ensure that the temp file is on the same volume
+  // as target file, so it can be moved in one step, and that the temp file
+  // is securely created.
+  FilePath tmp_file_path;
+  if (!base::CreateTemporaryFileInDir(path.DirName(), &tmp_file_path)) {
+    LogFailure(path, FAILED_CREATING, "could not create temporary file");
+    return false;
+  }
+
+  File tmp_file(tmp_file_path, File::FLAG_OPEN | File::FLAG_WRITE);
+  if (!tmp_file.IsValid()) {
+    LogFailure(path, FAILED_OPENING, "could not open temporary file");
+    return false;
+  }
+
+  // If this happens in the wild something really bad is going on.
+  CHECK_LE(data.length(), static_cast<size_t>(kint32max));
+  int bytes_written = tmp_file.Write(0, data.data(),
+                                     static_cast<int>(data.length()));
+  bool flush_success = tmp_file.Flush();
+  tmp_file.Close();
+
+  if (bytes_written < static_cast<int>(data.length())) {
+    LogFailure(path, FAILED_WRITING, "error writing, bytes_written=" +
+               IntToString(bytes_written));
+    base::DeleteFile(tmp_file_path, false);
+    return false;
+  }
+
+  if (!flush_success) {
+    LogFailure(path, FAILED_FLUSHING, "error flushing");
+    base::DeleteFile(tmp_file_path, false);
+    return false;
+  }
+
+  if (!base::ReplaceFile(tmp_file_path, path, NULL)) {
+    LogFailure(path, FAILED_RENAMING, "could not rename temporary file");
+    base::DeleteFile(tmp_file_path, false);
+    return false;
+  }
+
+  return true;
+}
+
+ImportantFileWriter::ImportantFileWriter(
+    const FilePath& path,
+    const scoped_refptr<base::SequencedTaskRunner>& task_runner)
+    : path_(path),
+      task_runner_(task_runner),
+      serializer_(NULL),
+      commit_interval_(TimeDelta::FromMilliseconds(kDefaultCommitIntervalMs)),
+      weak_factory_(this) {
+  DCHECK(CalledOnValidThread());
+  DCHECK(task_runner_);
+}
+
+ImportantFileWriter::~ImportantFileWriter() {
+  // We're usually a member variable of some other object, which also tends
+  // to be our serializer. It may not be safe to call back to the parent object
+  // being destructed.
+  DCHECK(!HasPendingWrite());
+}
+
+bool ImportantFileWriter::HasPendingWrite() const {
+  DCHECK(CalledOnValidThread());
+  return timer_.IsRunning();
+}
+
+void ImportantFileWriter::WriteNow(scoped_ptr<std::string> data) {
+  DCHECK(CalledOnValidThread());
+  if (data->length() > static_cast<size_t>(kint32max)) {
+    NOTREACHED();
+    return;
+  }
+
+  if (HasPendingWrite())
+    timer_.Stop();
+
+  auto task = Bind(&WriteScopedStringToFileAtomically, path_, Passed(&data));
+  if (!PostWriteTask(task)) {
+    // Posting the task to background message loop is not expected
+    // to fail, but if it does, avoid losing data and just hit the disk
+    // on the current thread.
+    NOTREACHED();
+
+    task.Run();
+  }
+}
+
+void ImportantFileWriter::ScheduleWrite(DataSerializer* serializer) {
+  DCHECK(CalledOnValidThread());
+
+  DCHECK(serializer);
+  serializer_ = serializer;
+
+  if (!timer_.IsRunning()) {
+    timer_.Start(FROM_HERE, commit_interval_, this,
+                 &ImportantFileWriter::DoScheduledWrite);
+  }
+}
+
+void ImportantFileWriter::DoScheduledWrite() {
+  DCHECK(serializer_);
+  scoped_ptr<std::string> data(new std::string);
+  if (serializer_->SerializeData(data.get())) {
+    WriteNow(data.Pass());
+  } else {
+    DLOG(WARNING) << "failed to serialize data to be saved in "
+                  << path_.value().c_str();
+  }
+  serializer_ = NULL;
+}
+
+void ImportantFileWriter::RegisterOnNextSuccessfulWriteCallback(
+    const base::Closure& on_next_successful_write) {
+  DCHECK(on_next_successful_write_.is_null());
+  on_next_successful_write_ = on_next_successful_write;
+}
+
+bool ImportantFileWriter::PostWriteTask(const Callback<bool()>& task) {
+  // TODO(gab): This code could always use PostTaskAndReplyWithResult and let
+  // ForwardSuccessfulWrite() no-op if |on_next_successful_write_| is null, but
+  // PostTaskAndReply causes memory leaks in tests (crbug.com/371974) and
+  // suppressing all of those is unrealistic hence we avoid most of them by
+  // using PostTask() in the typical scenario below.
+  if (!on_next_successful_write_.is_null()) {
+    return base::PostTaskAndReplyWithResult(
+        task_runner_.get(),
+        FROM_HERE,
+        MakeCriticalClosure(task),
+        Bind(&ImportantFileWriter::ForwardSuccessfulWrite,
+             weak_factory_.GetWeakPtr()));
+  }
+  return task_runner_->PostTask(
+      FROM_HERE,
+      MakeCriticalClosure(base::Bind(IgnoreResult(task))));
+}
+
+void ImportantFileWriter::ForwardSuccessfulWrite(bool result) {
+  DCHECK(CalledOnValidThread());
+  if (result && !on_next_successful_write_.is_null()) {
+    on_next_successful_write_.Run();
+    on_next_successful_write_.Reset();
+  }
+}
+
+}  // namespace base
diff --git a/base/files/important_file_writer.h b/base/files/important_file_writer.h
new file mode 100644
index 0000000..99f1a7c
--- /dev/null
+++ b/base/files/important_file_writer.h
@@ -0,0 +1,140 @@
+// Copyright (c) 2012 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_FILES_IMPORTANT_FILE_WRITER_H_
+#define BASE_FILES_IMPORTANT_FILE_WRITER_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/memory/ref_counted.h"
+#include "base/threading/non_thread_safe.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
+
+namespace base {
+
+class SequencedTaskRunner;
+class Thread;
+
+// Helper to ensure that a file won't be corrupted by the write (for example on
+// application crash). Consider a naive way to save an important file F:
+//
+// 1. Open F for writing, truncating it.
+// 2. Write new data to F.
+//
+// It's good when it works, but it gets very bad if step 2. doesn't complete.
+// It can be caused by a crash, a computer hang, or a weird I/O error. And you
+// end up with a broken file.
+//
+// To be safe, we don't start with writing directly to F. Instead, we write to
+// to a temporary file. Only after that write is successful, we rename the
+// temporary file to target filename.
+//
+// If you want to know more about this approach and ext3/ext4 fsync issues, see
+// http://valhenson.livejournal.com/37921.html
+class BASE_EXPORT ImportantFileWriter : public NonThreadSafe {
+ public:
+  // Used by ScheduleSave to lazily provide the data to be saved. Allows us
+  // to also batch data serializations.
+  class BASE_EXPORT DataSerializer {
+   public:
+    // Should put serialized string in |data| and return true on successful
+    // serialization. Will be called on the same thread on which
+    // ImportantFileWriter has been created.
+    virtual bool SerializeData(std::string* data) = 0;
+
+   protected:
+    virtual ~DataSerializer() {}
+  };
+
+  // Save |data| to |path| in an atomic manner (see the class comment above).
+  // Blocks and writes data on the current thread.
+  static bool WriteFileAtomically(const FilePath& path,
+                                  const std::string& data);
+
+  // Initialize the writer.
+  // |path| is the name of file to write.
+  // |task_runner| is the SequencedTaskRunner instance where on which we will
+  // execute file I/O operations.
+  // All non-const methods, ctor and dtor must be called on the same thread.
+  ImportantFileWriter(
+      const FilePath& path,
+      const scoped_refptr<base::SequencedTaskRunner>& task_runner);
+
+  // You have to ensure that there are no pending writes at the moment
+  // of destruction.
+  ~ImportantFileWriter();
+
+  const FilePath& path() const { return path_; }
+
+  // Returns true if there is a scheduled write pending which has not yet
+  // been started.
+  bool HasPendingWrite() const;
+
+  // Save |data| to target filename. Does not block. If there is a pending write
+  // scheduled by ScheduleWrite, it is cancelled.
+  void WriteNow(scoped_ptr<std::string> data);
+
+  // Schedule a save to target filename. Data will be serialized and saved
+  // to disk after the commit interval. If another ScheduleWrite is issued
+  // before that, only one serialization and write to disk will happen, and
+  // the most recent |serializer| will be used. This operation does not block.
+  // |serializer| should remain valid through the lifetime of
+  // ImportantFileWriter.
+  void ScheduleWrite(DataSerializer* serializer);
+
+  // Serialize data pending to be saved and execute write on backend thread.
+  void DoScheduledWrite();
+
+  // Registers |on_next_successful_write| to be called once, on the next
+  // successful write event. Only one callback can be set at once.
+  void RegisterOnNextSuccessfulWriteCallback(
+      const base::Closure& on_next_successful_write);
+
+  TimeDelta commit_interval() const {
+    return commit_interval_;
+  }
+
+  void set_commit_interval(const TimeDelta& interval) {
+    commit_interval_ = interval;
+  }
+
+ private:
+  // Helper method for WriteNow().
+  bool PostWriteTask(const Callback<bool()>& task);
+
+  // If |result| is true and |on_next_successful_write_| is set, invokes
+  // |on_successful_write_| and then resets it; no-ops otherwise.
+  void ForwardSuccessfulWrite(bool result);
+
+  // Invoked once and then reset on the next successful write event.
+  base::Closure on_next_successful_write_;
+
+  // Path being written to.
+  const FilePath path_;
+
+  // TaskRunner for the thread on which file I/O can be done.
+  const scoped_refptr<base::SequencedTaskRunner> task_runner_;
+
+  // Timer used to schedule commit after ScheduleWrite.
+  OneShotTimer<ImportantFileWriter> timer_;
+
+  // Serializer which will provide the data to be saved.
+  DataSerializer* serializer_;
+
+  // Time delta after which scheduled data will be written to disk.
+  TimeDelta commit_interval_;
+
+  WeakPtrFactory<ImportantFileWriter> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(ImportantFileWriter);
+};
+
+}  // namespace base
+
+#endif  // BASE_FILES_IMPORTANT_FILE_WRITER_H_
diff --git a/base/files/important_file_writer_unittest.cc b/base/files/important_file_writer_unittest.cc
new file mode 100644
index 0000000..d376cdc
--- /dev/null
+++ b/base/files/important_file_writer_unittest.cc
@@ -0,0 +1,194 @@
+// Copyright (c) 2012 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/files/important_file_writer.h"
+
+#include "base/bind.h"
+#include "base/compiler_specific.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/thread.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+std::string GetFileContent(const FilePath& path) {
+  std::string content;
+  if (!ReadFileToString(path, &content)) {
+    NOTREACHED();
+  }
+  return content;
+}
+
+class DataSerializer : public ImportantFileWriter::DataSerializer {
+ public:
+  explicit DataSerializer(const std::string& data) : data_(data) {
+  }
+
+  bool SerializeData(std::string* output) override {
+    output->assign(data_);
+    return true;
+  }
+
+ private:
+  const std::string data_;
+};
+
+class SuccessfulWriteObserver {
+ public:
+  SuccessfulWriteObserver() : successful_write_observed_(false) {}
+
+  // Register on_successful_write() to be called on the next successful write
+  // of |writer|.
+  void ObserveNextSuccessfulWrite(ImportantFileWriter* writer);
+
+  // Returns true if a successful write was observed via on_successful_write()
+  // and resets the observation state to false regardless.
+  bool GetAndResetObservationState();
+
+ private:
+  void on_successful_write() {
+    EXPECT_FALSE(successful_write_observed_);
+    successful_write_observed_ = true;
+  }
+
+  bool successful_write_observed_;
+
+  DISALLOW_COPY_AND_ASSIGN(SuccessfulWriteObserver);
+};
+
+void SuccessfulWriteObserver::ObserveNextSuccessfulWrite(
+    ImportantFileWriter* writer) {
+  writer->RegisterOnNextSuccessfulWriteCallback(base::Bind(
+      &SuccessfulWriteObserver::on_successful_write, base::Unretained(this)));
+}
+
+bool SuccessfulWriteObserver::GetAndResetObservationState() {
+  bool was_successful_write_observed = successful_write_observed_;
+  successful_write_observed_ = false;
+  return was_successful_write_observed;
+}
+
+}  // namespace
+
+class ImportantFileWriterTest : public testing::Test {
+ public:
+  ImportantFileWriterTest() { }
+  void SetUp() override {
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+    file_ = temp_dir_.path().AppendASCII("test-file");
+  }
+
+ protected:
+  SuccessfulWriteObserver successful_write_observer_;
+  FilePath file_;
+  MessageLoop loop_;
+
+ private:
+  ScopedTempDir temp_dir_;
+};
+
+TEST_F(ImportantFileWriterTest, Basic) {
+  ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get());
+  EXPECT_FALSE(PathExists(writer.path()));
+  EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
+  writer.WriteNow(make_scoped_ptr(new std::string("foo")));
+  RunLoop().RunUntilIdle();
+
+  EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
+  ASSERT_TRUE(PathExists(writer.path()));
+  EXPECT_EQ("foo", GetFileContent(writer.path()));
+}
+
+TEST_F(ImportantFileWriterTest, BasicWithSuccessfulWriteObserver) {
+  ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get());
+  EXPECT_FALSE(PathExists(writer.path()));
+  EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
+  successful_write_observer_.ObserveNextSuccessfulWrite(&writer);
+  writer.WriteNow(make_scoped_ptr(new std::string("foo")));
+  RunLoop().RunUntilIdle();
+
+  // Confirm that the observer is invoked.
+  EXPECT_TRUE(successful_write_observer_.GetAndResetObservationState());
+  ASSERT_TRUE(PathExists(writer.path()));
+  EXPECT_EQ("foo", GetFileContent(writer.path()));
+
+  // Confirm that re-installing the observer works for another write.
+  EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
+  successful_write_observer_.ObserveNextSuccessfulWrite(&writer);
+  writer.WriteNow(make_scoped_ptr(new std::string("bar")));
+  RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(successful_write_observer_.GetAndResetObservationState());
+  ASSERT_TRUE(PathExists(writer.path()));
+  EXPECT_EQ("bar", GetFileContent(writer.path()));
+
+  // Confirm that writing again without re-installing the observer doesn't
+  // result in a notification.
+  EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
+  writer.WriteNow(make_scoped_ptr(new std::string("baz")));
+  RunLoop().RunUntilIdle();
+
+  EXPECT_FALSE(successful_write_observer_.GetAndResetObservationState());
+  ASSERT_TRUE(PathExists(writer.path()));
+  EXPECT_EQ("baz", GetFileContent(writer.path()));
+}
+
+TEST_F(ImportantFileWriterTest, ScheduleWrite) {
+  ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get());
+  writer.set_commit_interval(TimeDelta::FromMilliseconds(25));
+  EXPECT_FALSE(writer.HasPendingWrite());
+  DataSerializer serializer("foo");
+  writer.ScheduleWrite(&serializer);
+  EXPECT_TRUE(writer.HasPendingWrite());
+  ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, MessageLoop::QuitWhenIdleClosure(),
+      TimeDelta::FromMilliseconds(100));
+  MessageLoop::current()->Run();
+  EXPECT_FALSE(writer.HasPendingWrite());
+  ASSERT_TRUE(PathExists(writer.path()));
+  EXPECT_EQ("foo", GetFileContent(writer.path()));
+}
+
+TEST_F(ImportantFileWriterTest, DoScheduledWrite) {
+  ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get());
+  EXPECT_FALSE(writer.HasPendingWrite());
+  DataSerializer serializer("foo");
+  writer.ScheduleWrite(&serializer);
+  EXPECT_TRUE(writer.HasPendingWrite());
+  writer.DoScheduledWrite();
+  ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, MessageLoop::QuitWhenIdleClosure(),
+      TimeDelta::FromMilliseconds(100));
+  MessageLoop::current()->Run();
+  EXPECT_FALSE(writer.HasPendingWrite());
+  ASSERT_TRUE(PathExists(writer.path()));
+  EXPECT_EQ("foo", GetFileContent(writer.path()));
+}
+
+TEST_F(ImportantFileWriterTest, BatchingWrites) {
+  ImportantFileWriter writer(file_, ThreadTaskRunnerHandle::Get());
+  writer.set_commit_interval(TimeDelta::FromMilliseconds(25));
+  DataSerializer foo("foo"), bar("bar"), baz("baz");
+  writer.ScheduleWrite(&foo);
+  writer.ScheduleWrite(&bar);
+  writer.ScheduleWrite(&baz);
+  ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, MessageLoop::QuitWhenIdleClosure(),
+      TimeDelta::FromMilliseconds(100));
+  MessageLoop::current()->Run();
+  ASSERT_TRUE(PathExists(writer.path()));
+  EXPECT_EQ("baz", GetFileContent(writer.path()));
+}
+
+}  // namespace base
diff --git a/base/files/memory_mapped_file.cc b/base/files/memory_mapped_file.cc
new file mode 100644
index 0000000..bad1792
--- /dev/null
+++ b/base/files/memory_mapped_file.cc
@@ -0,0 +1,102 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/memory_mapped_file.h"
+
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/sys_info.h"
+
+namespace base {
+
+const MemoryMappedFile::Region MemoryMappedFile::Region::kWholeFile(
+    base::LINKER_INITIALIZED);
+
+MemoryMappedFile::Region::Region(base::LinkerInitialized) : offset(0), size(0) {
+}
+
+MemoryMappedFile::Region::Region() : offset(-1), size(-1) {
+}
+
+MemoryMappedFile::Region::Region(int64 offset, int64 size)
+    : offset(offset), size(size) {
+}
+
+bool MemoryMappedFile::Region::operator==(
+    const MemoryMappedFile::Region& other) const {
+  return other.offset == offset && other.size == size;
+}
+
+bool MemoryMappedFile::Region::operator!=(
+    const MemoryMappedFile::Region& other) const {
+  return other.offset != offset || other.size != size;
+}
+
+MemoryMappedFile::~MemoryMappedFile() {
+  CloseHandles();
+}
+
+#if !defined(OS_NACL)
+bool MemoryMappedFile::Initialize(const FilePath& file_name) {
+  if (IsValid())
+    return false;
+
+  file_.Initialize(file_name, File::FLAG_OPEN | File::FLAG_READ);
+
+  if (!file_.IsValid()) {
+    DLOG(ERROR) << "Couldn't open " << file_name.AsUTF8Unsafe();
+    return false;
+  }
+
+  if (!MapFileRegionToMemory(Region::kWholeFile)) {
+    CloseHandles();
+    return false;
+  }
+
+  return true;
+}
+
+bool MemoryMappedFile::Initialize(File file) {
+  return Initialize(file.Pass(), Region::kWholeFile);
+}
+
+bool MemoryMappedFile::Initialize(File file, const Region& region) {
+  if (IsValid())
+    return false;
+
+  if (region != Region::kWholeFile) {
+    DCHECK_GE(region.offset, 0);
+    DCHECK_GT(region.size, 0);
+  }
+
+  file_ = file.Pass();
+
+  if (!MapFileRegionToMemory(region)) {
+    CloseHandles();
+    return false;
+  }
+
+  return true;
+}
+
+bool MemoryMappedFile::IsValid() const {
+  return data_ != NULL;
+}
+
+// static
+void MemoryMappedFile::CalculateVMAlignedBoundaries(int64 start,
+                                                    int64 size,
+                                                    int64* aligned_start,
+                                                    int64* aligned_size,
+                                                    int32* offset) {
+  // Sadly, on Windows, the mmap alignment is not just equal to the page size.
+  const int64 mask = static_cast<int64>(SysInfo::VMAllocationGranularity()) - 1;
+  DCHECK_LT(mask, std::numeric_limits<int32>::max());
+  *offset = start & mask;
+  *aligned_start = start & ~mask;
+  *aligned_size = (size + *offset + mask) & ~mask;
+}
+#endif
+
+}  // namespace base
diff --git a/base/files/memory_mapped_file.h b/base/files/memory_mapped_file.h
new file mode 100644
index 0000000..96d1d91
--- /dev/null
+++ b/base/files/memory_mapped_file.h
@@ -0,0 +1,108 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_FILES_MEMORY_MAPPED_FILE_H_
+#define BASE_FILES_MEMORY_MAPPED_FILE_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/files/file.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
+namespace base {
+
+class FilePath;
+
+class BASE_EXPORT MemoryMappedFile {
+ public:
+  // The default constructor sets all members to invalid/null values.
+  MemoryMappedFile();
+  ~MemoryMappedFile();
+
+  // Used to hold information about a region [offset + size] of a file.
+  struct BASE_EXPORT Region {
+    static const Region kWholeFile;
+
+    Region();
+    Region(int64 offset, int64 size);
+
+    bool operator==(const Region& other) const;
+    bool operator!=(const Region& other) const;
+
+    // Start of the region (measured in bytes from the beginning of the file).
+    int64 offset;
+
+    // Length of the region in bytes.
+    int64 size;
+
+   private:
+    // Used by kWholeFile.
+    Region(base::LinkerInitialized);
+  };
+
+  // Opens an existing file and maps it into memory. Access is restricted to
+  // read only. If this object already points to a valid memory mapped file
+  // then this method will fail and return false. If it cannot open the file,
+  // the file does not exist, or the memory mapping fails, it will return false.
+  // Later we may want to allow the user to specify access.
+  bool Initialize(const FilePath& file_name);
+
+  // As above, but works with an already-opened file. MemoryMappedFile takes
+  // ownership of |file| and closes it when done.
+  bool Initialize(File file);
+
+  // As above, but works with a region of an already-opened file.
+  bool Initialize(File file, const Region& region);
+
+#if defined(OS_WIN)
+  // Opens an existing file and maps it as an image section. Please refer to
+  // the Initialize function above for additional information.
+  bool InitializeAsImageSection(const FilePath& file_name);
+#endif  // OS_WIN
+
+  const uint8* data() const { return data_; }
+  size_t length() const { return length_; }
+
+  // Is file_ a valid file handle that points to an open, memory mapped file?
+  bool IsValid() const;
+
+ private:
+  // Given the arbitrarily aligned memory region [start, size], returns the
+  // boundaries of the region aligned to the granularity specified by the OS,
+  // (a page on Linux, ~32k on Windows) as follows:
+  // - |aligned_start| is page aligned and <= |start|.
+  // - |aligned_size| is a multiple of the VM granularity and >= |size|.
+  // - |offset| is the displacement of |start| w.r.t |aligned_start|.
+  static void CalculateVMAlignedBoundaries(int64 start,
+                                           int64 size,
+                                           int64* aligned_start,
+                                           int64* aligned_size,
+                                           int32* offset);
+
+  // Map the file to memory, set data_ to that memory address. Return true on
+  // success, false on any kind of failure. This is a helper for Initialize().
+  bool MapFileRegionToMemory(const Region& region);
+
+  // Closes all open handles.
+  void CloseHandles();
+
+  File file_;
+  uint8* data_;
+  size_t length_;
+
+#if defined(OS_WIN)
+  win::ScopedHandle file_mapping_;
+  bool image_;  // Map as an image.
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(MemoryMappedFile);
+};
+
+}  // namespace base
+
+#endif  // BASE_FILES_MEMORY_MAPPED_FILE_H_
diff --git a/base/files/memory_mapped_file_posix.cc b/base/files/memory_mapped_file_posix.cc
new file mode 100644
index 0000000..168da92
--- /dev/null
+++ b/base/files/memory_mapped_file_posix.cc
@@ -0,0 +1,91 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/memory_mapped_file.h"
+
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "base/logging.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace base {
+
+MemoryMappedFile::MemoryMappedFile() : data_(NULL), length_(0) {
+}
+
+#if !defined(OS_NACL)
+bool MemoryMappedFile::MapFileRegionToMemory(
+    const MemoryMappedFile::Region& region) {
+  ThreadRestrictions::AssertIOAllowed();
+
+  off_t map_start = 0;
+  size_t map_size = 0;
+  int32 data_offset = 0;
+
+  if (region == MemoryMappedFile::Region::kWholeFile) {
+    int64 file_len = file_.GetLength();
+    if (file_len == -1) {
+      DPLOG(ERROR) << "fstat " << file_.GetPlatformFile();
+      return false;
+    }
+    map_size = static_cast<size_t>(file_len);
+    length_ = map_size;
+  } else {
+    // The region can be arbitrarily aligned. mmap, instead, requires both the
+    // start and size to be page-aligned. Hence, we map here the page-aligned
+    // outer region [|aligned_start|, |aligned_start| + |size|] which contains
+    // |region| and then add up the |data_offset| displacement.
+    int64 aligned_start = 0;
+    int64 aligned_size = 0;
+    CalculateVMAlignedBoundaries(region.offset,
+                                 region.size,
+                                 &aligned_start,
+                                 &aligned_size,
+                                 &data_offset);
+
+    // Ensure that the casts in the mmap call below are sane.
+    if (aligned_start < 0 || aligned_size < 0 ||
+        aligned_start > std::numeric_limits<off_t>::max() ||
+        static_cast<uint64>(aligned_size) >
+            std::numeric_limits<size_t>::max() ||
+        static_cast<uint64>(region.size) > std::numeric_limits<size_t>::max()) {
+      DLOG(ERROR) << "Region bounds are not valid for mmap";
+      return false;
+    }
+
+    map_start = static_cast<off_t>(aligned_start);
+    map_size = static_cast<size_t>(aligned_size);
+    length_ = static_cast<size_t>(region.size);
+  }
+
+  data_ = static_cast<uint8*>(mmap(NULL,
+                                   map_size,
+                                   PROT_READ,
+                                   MAP_SHARED,
+                                   file_.GetPlatformFile(),
+                                   map_start));
+  if (data_ == MAP_FAILED) {
+    DPLOG(ERROR) << "mmap " << file_.GetPlatformFile();
+    return false;
+  }
+
+  data_ += data_offset;
+  return true;
+}
+#endif
+
+void MemoryMappedFile::CloseHandles() {
+  ThreadRestrictions::AssertIOAllowed();
+
+  if (data_ != NULL)
+    munmap(data_, length_);
+  file_.Close();
+
+  data_ = NULL;
+  length_ = 0;
+}
+
+}  // namespace base
diff --git a/base/files/memory_mapped_file_unittest.cc b/base/files/memory_mapped_file_unittest.cc
new file mode 100644
index 0000000..d0833b5
--- /dev/null
+++ b/base/files/memory_mapped_file_unittest.cc
@@ -0,0 +1,166 @@
+// 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.
+
+#include "base/files/memory_mapped_file.h"
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace base {
+
+namespace {
+
+// Create a temporary buffer and fill it with a watermark sequence.
+scoped_ptr<uint8[]> CreateTestBuffer(size_t size, size_t offset) {
+  scoped_ptr<uint8[]> buf(new uint8[size]);
+  for (size_t i = 0; i < size; ++i)
+    buf.get()[i] = static_cast<uint8>((offset + i) % 253);
+  return buf.Pass();
+}
+
+// Check that the watermark sequence is consistent with the |offset| provided.
+bool CheckBufferContents(const uint8* data, size_t size, size_t offset) {
+  scoped_ptr<uint8[]> test_data(CreateTestBuffer(size, offset));
+  return memcmp(test_data.get(), data, size) == 0;
+}
+
+class MemoryMappedFileTest : public PlatformTest {
+ protected:
+  void SetUp() override {
+    PlatformTest::SetUp();
+    CreateTemporaryFile(&temp_file_path_);
+  }
+
+  void TearDown() override { EXPECT_TRUE(DeleteFile(temp_file_path_, false)); }
+
+  void CreateTemporaryTestFile(size_t size) {
+    File file(temp_file_path_,
+              File::FLAG_CREATE_ALWAYS | File::FLAG_READ | File::FLAG_WRITE);
+    EXPECT_TRUE(file.IsValid());
+
+    scoped_ptr<uint8[]> test_data(CreateTestBuffer(size, 0));
+    size_t bytes_written =
+        file.Write(0, reinterpret_cast<char*>(test_data.get()), size);
+    EXPECT_EQ(size, bytes_written);
+    file.Close();
+  }
+
+  const FilePath temp_file_path() const { return temp_file_path_; }
+
+ private:
+  FilePath temp_file_path_;
+};
+
+TEST_F(MemoryMappedFileTest, MapWholeFileByPath) {
+  const size_t kFileSize = 68 * 1024;
+  CreateTemporaryTestFile(kFileSize);
+  MemoryMappedFile map;
+  map.Initialize(temp_file_path());
+  ASSERT_EQ(kFileSize, map.length());
+  ASSERT_TRUE(map.data() != NULL);
+  EXPECT_TRUE(map.IsValid());
+  ASSERT_TRUE(CheckBufferContents(map.data(), kFileSize, 0));
+}
+
+TEST_F(MemoryMappedFileTest, MapWholeFileByFD) {
+  const size_t kFileSize = 68 * 1024;
+  CreateTemporaryTestFile(kFileSize);
+  MemoryMappedFile map;
+  map.Initialize(File(temp_file_path(), File::FLAG_OPEN | File::FLAG_READ));
+  ASSERT_EQ(kFileSize, map.length());
+  ASSERT_TRUE(map.data() != NULL);
+  EXPECT_TRUE(map.IsValid());
+  ASSERT_TRUE(CheckBufferContents(map.data(), kFileSize, 0));
+}
+
+TEST_F(MemoryMappedFileTest, MapSmallFile) {
+  const size_t kFileSize = 127;
+  CreateTemporaryTestFile(kFileSize);
+  MemoryMappedFile map;
+  map.Initialize(temp_file_path());
+  ASSERT_EQ(kFileSize, map.length());
+  ASSERT_TRUE(map.data() != NULL);
+  EXPECT_TRUE(map.IsValid());
+  ASSERT_TRUE(CheckBufferContents(map.data(), kFileSize, 0));
+}
+
+TEST_F(MemoryMappedFileTest, MapWholeFileUsingRegion) {
+  const size_t kFileSize = 157 * 1024;
+  CreateTemporaryTestFile(kFileSize);
+  MemoryMappedFile map;
+
+  File file(temp_file_path(), File::FLAG_OPEN | File::FLAG_READ);
+  map.Initialize(file.Pass(), MemoryMappedFile::Region::kWholeFile);
+  ASSERT_EQ(kFileSize, map.length());
+  ASSERT_TRUE(map.data() != NULL);
+  EXPECT_TRUE(map.IsValid());
+  ASSERT_TRUE(CheckBufferContents(map.data(), kFileSize, 0));
+}
+
+TEST_F(MemoryMappedFileTest, MapPartialRegionAtBeginning) {
+  const size_t kFileSize = 157 * 1024;
+  const size_t kPartialSize = 4 * 1024 + 32;
+  CreateTemporaryTestFile(kFileSize);
+  MemoryMappedFile map;
+
+  File file(temp_file_path(), File::FLAG_OPEN | File::FLAG_READ);
+  map.Initialize(file.Pass(), MemoryMappedFile::Region(0, kPartialSize));
+  ASSERT_EQ(kPartialSize, map.length());
+  ASSERT_TRUE(map.data() != NULL);
+  EXPECT_TRUE(map.IsValid());
+  ASSERT_TRUE(CheckBufferContents(map.data(), kPartialSize, 0));
+}
+
+TEST_F(MemoryMappedFileTest, MapPartialRegionAtEnd) {
+  const size_t kFileSize = 157 * 1024;
+  const size_t kPartialSize = 5 * 1024 - 32;
+  const size_t kOffset = kFileSize - kPartialSize;
+  CreateTemporaryTestFile(kFileSize);
+  MemoryMappedFile map;
+
+  File file(temp_file_path(), File::FLAG_OPEN | File::FLAG_READ);
+  map.Initialize(file.Pass(), MemoryMappedFile::Region(kOffset, kPartialSize));
+  ASSERT_EQ(kPartialSize, map.length());
+  ASSERT_TRUE(map.data() != NULL);
+  EXPECT_TRUE(map.IsValid());
+  ASSERT_TRUE(CheckBufferContents(map.data(), kPartialSize, kOffset));
+}
+
+TEST_F(MemoryMappedFileTest, MapSmallPartialRegionInTheMiddle) {
+  const size_t kFileSize = 157 * 1024;
+  const size_t kOffset = 1024 * 5 + 32;
+  const size_t kPartialSize = 8;
+
+  CreateTemporaryTestFile(kFileSize);
+  MemoryMappedFile map;
+
+  File file(temp_file_path(), File::FLAG_OPEN | File::FLAG_READ);
+  map.Initialize(file.Pass(), MemoryMappedFile::Region(kOffset, kPartialSize));
+  ASSERT_EQ(kPartialSize, map.length());
+  ASSERT_TRUE(map.data() != NULL);
+  EXPECT_TRUE(map.IsValid());
+  ASSERT_TRUE(CheckBufferContents(map.data(), kPartialSize, kOffset));
+}
+
+TEST_F(MemoryMappedFileTest, MapLargePartialRegionInTheMiddle) {
+  const size_t kFileSize = 157 * 1024;
+  const size_t kOffset = 1024 * 5 + 32;
+  const size_t kPartialSize = 16 * 1024 - 32;
+
+  CreateTemporaryTestFile(kFileSize);
+  MemoryMappedFile map;
+
+  File file(temp_file_path(), File::FLAG_OPEN | File::FLAG_READ);
+  map.Initialize(file.Pass(), MemoryMappedFile::Region(kOffset, kPartialSize));
+  ASSERT_EQ(kPartialSize, map.length());
+  ASSERT_TRUE(map.data() != NULL);
+  EXPECT_TRUE(map.IsValid());
+  ASSERT_TRUE(CheckBufferContents(map.data(), kPartialSize, kOffset));
+}
+
+}  // namespace
+
+}  // namespace base
diff --git a/base/files/memory_mapped_file_win.cc b/base/files/memory_mapped_file_win.cc
new file mode 100644
index 0000000..4e7e934
--- /dev/null
+++ b/base/files/memory_mapped_file_win.cc
@@ -0,0 +1,92 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/memory_mapped_file.h"
+
+#include "base/files/file_path.h"
+#include "base/strings/string16.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace base {
+
+MemoryMappedFile::MemoryMappedFile() : data_(NULL), length_(0), image_(false) {
+}
+
+bool MemoryMappedFile::InitializeAsImageSection(const FilePath& file_name) {
+  image_ = true;
+  return Initialize(file_name);
+}
+
+bool MemoryMappedFile::MapFileRegionToMemory(
+    const MemoryMappedFile::Region& region) {
+  ThreadRestrictions::AssertIOAllowed();
+
+  if (!file_.IsValid())
+    return false;
+
+  int flags = image_ ? SEC_IMAGE | PAGE_READONLY : PAGE_READONLY;
+
+  file_mapping_.Set(::CreateFileMapping(file_.GetPlatformFile(), NULL,
+                                        flags, 0, 0, NULL));
+  if (!file_mapping_.IsValid())
+    return false;
+
+  LARGE_INTEGER map_start = {0};
+  SIZE_T map_size = 0;
+  int32 data_offset = 0;
+
+  if (region == MemoryMappedFile::Region::kWholeFile) {
+    int64 file_len = file_.GetLength();
+    if (file_len <= 0 || file_len > kint32max)
+      return false;
+    length_ = static_cast<size_t>(file_len);
+  } else {
+    // The region can be arbitrarily aligned. MapViewOfFile, instead, requires
+    // that the start address is aligned to the VM granularity (which is
+    // typically larger than a page size, for instance 32k).
+    // Also, conversely to POSIX's mmap, the |map_size| doesn't have to be
+    // aligned and must be less than or equal the mapped file size.
+    // We map here the outer region [|aligned_start|, |aligned_start+size|]
+    // which contains |region| and then add up the |data_offset| displacement.
+    int64 aligned_start = 0;
+    int64 ignored = 0;
+    CalculateVMAlignedBoundaries(
+        region.offset, region.size, &aligned_start, &ignored, &data_offset);
+    int64 size = region.size + data_offset;
+
+    // Ensure that the casts below in the MapViewOfFile call are sane.
+    if (aligned_start < 0 || size < 0 ||
+        static_cast<uint64>(size) > std::numeric_limits<SIZE_T>::max()) {
+      DLOG(ERROR) << "Region bounds are not valid for MapViewOfFile";
+      return false;
+    }
+    map_start.QuadPart = aligned_start;
+    map_size = static_cast<SIZE_T>(size);
+    length_ = static_cast<size_t>(region.size);
+  }
+
+  data_ = static_cast<uint8*>(::MapViewOfFile(file_mapping_.Get(),
+                                              FILE_MAP_READ,
+                                              map_start.HighPart,
+                                              map_start.LowPart,
+                                              map_size));
+  if (data_ == NULL)
+    return false;
+  data_ += data_offset;
+  return true;
+}
+
+void MemoryMappedFile::CloseHandles() {
+  if (data_)
+    ::UnmapViewOfFile(data_);
+  if (file_mapping_.IsValid())
+    file_mapping_.Close();
+  if (file_.IsValid())
+    file_.Close();
+
+  data_ = NULL;
+  length_ = 0;
+}
+
+}  // namespace base
diff --git a/base/files/scoped_file.cc b/base/files/scoped_file.cc
new file mode 100644
index 0000000..39f064d
--- /dev/null
+++ b/base/files/scoped_file.cc
@@ -0,0 +1,35 @@
+// 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.
+
+#include "base/files/scoped_file.h"
+
+#include "base/logging.h"
+
+#if defined(OS_POSIX)
+#include <unistd.h>
+
+#include "base/posix/eintr_wrapper.h"
+#endif
+
+namespace base {
+namespace internal {
+
+#if defined(OS_POSIX)
+
+// static
+void ScopedFDCloseTraits::Free(int fd) {
+  // It's important to crash here.
+  // There are security implications to not closing a file descriptor
+  // properly. As file descriptors are "capabilities", keeping them open
+  // would make the current process keep access to a resource. Much of
+  // Chrome relies on being able to "drop" such access.
+  // It's especially problematic on Linux with the setuid sandbox, where
+  // a single open directory would bypass the entire security model.
+  PCHECK(0 == IGNORE_EINTR(close(fd)));
+}
+
+#endif  // OS_POSIX
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/files/scoped_file.h b/base/files/scoped_file.h
new file mode 100644
index 0000000..106f6ad
--- /dev/null
+++ b/base/files/scoped_file.h
@@ -0,0 +1,61 @@
+// 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.
+
+#ifndef BASE_FILES_SCOPED_FILE_H_
+#define BASE_FILES_SCOPED_FILE_H_
+
+#include <stdio.h>
+
+#include "base/base_export.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/scoped_generic.h"
+#include "build/build_config.h"
+
+namespace base {
+
+namespace internal {
+
+#if defined(OS_POSIX)
+struct BASE_EXPORT ScopedFDCloseTraits {
+  static int InvalidValue() {
+    return -1;
+  }
+  static void Free(int fd);
+};
+#endif
+
+// Functor for |ScopedFILE| (below).
+struct ScopedFILECloser {
+  inline void operator()(FILE* x) const {
+    if (x)
+      fclose(x);
+  }
+};
+
+}  // namespace internal
+
+// -----------------------------------------------------------------------------
+
+#if defined(OS_POSIX)
+// A low-level Posix file descriptor closer class. Use this when writing
+// platform-specific code, especially that does non-file-like things with the
+// FD (like sockets).
+//
+// If you're writing low-level Windows code, see base/win/scoped_handle.h
+// which provides some additional functionality.
+//
+// If you're writing cross-platform code that deals with actual files, you
+// should generally use base::File instead which can be constructed with a
+// handle, and in addition to handling ownership, has convenient cross-platform
+// file manipulation functions on it.
+typedef ScopedGeneric<int, internal::ScopedFDCloseTraits> ScopedFD;
+#endif
+
+// Automatically closes |FILE*|s.
+typedef scoped_ptr<FILE, internal::ScopedFILECloser> ScopedFILE;
+
+}  // namespace base
+
+#endif  // BASE_FILES_SCOPED_FILE_H_
diff --git a/base/files/scoped_temp_dir.cc b/base/files/scoped_temp_dir.cc
new file mode 100644
index 0000000..27b758e
--- /dev/null
+++ b/base/files/scoped_temp_dir.cc
@@ -0,0 +1,83 @@
+// Copyright (c) 2011 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/files/scoped_temp_dir.h"
+
+#include "base/files/file_util.h"
+#include "base/logging.h"
+
+namespace base {
+
+ScopedTempDir::ScopedTempDir() {
+}
+
+ScopedTempDir::~ScopedTempDir() {
+  if (!path_.empty() && !Delete())
+    DLOG(WARNING) << "Could not delete temp dir in dtor.";
+}
+
+bool ScopedTempDir::CreateUniqueTempDir() {
+  if (!path_.empty())
+    return false;
+
+  // This "scoped_dir" prefix is only used on Windows and serves as a template
+  // for the unique name.
+  if (!base::CreateNewTempDirectory(FILE_PATH_LITERAL("scoped_dir"), &path_))
+    return false;
+
+  return true;
+}
+
+bool ScopedTempDir::CreateUniqueTempDirUnderPath(const FilePath& base_path) {
+  if (!path_.empty())
+    return false;
+
+  // If |base_path| does not exist, create it.
+  if (!base::CreateDirectory(base_path))
+    return false;
+
+  // Create a new, uniquely named directory under |base_path|.
+  if (!base::CreateTemporaryDirInDir(base_path,
+                                     FILE_PATH_LITERAL("scoped_dir_"),
+                                     &path_))
+    return false;
+
+  return true;
+}
+
+bool ScopedTempDir::Set(const FilePath& path) {
+  if (!path_.empty())
+    return false;
+
+  if (!DirectoryExists(path) && !base::CreateDirectory(path))
+    return false;
+
+  path_ = path;
+  return true;
+}
+
+bool ScopedTempDir::Delete() {
+  if (path_.empty())
+    return false;
+
+  bool ret = base::DeleteFile(path_, true);
+  if (ret) {
+    // We only clear the path if deleted the directory.
+    path_.clear();
+  }
+
+  return ret;
+}
+
+FilePath ScopedTempDir::Take() {
+  FilePath ret = path_;
+  path_ = FilePath();
+  return ret;
+}
+
+bool ScopedTempDir::IsValid() const {
+  return !path_.empty() && DirectoryExists(path_);
+}
+
+}  // namespace base
diff --git a/base/files/scoped_temp_dir.h b/base/files/scoped_temp_dir.h
new file mode 100644
index 0000000..5f63e09
--- /dev/null
+++ b/base/files/scoped_temp_dir.h
@@ -0,0 +1,62 @@
+// Copyright (c) 2011 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_FILES_SCOPED_TEMP_DIR_H_
+#define BASE_FILES_SCOPED_TEMP_DIR_H_
+
+// An object representing a temporary / scratch directory that should be cleaned
+// up (recursively) when this object goes out of scope.  Note that since
+// deletion occurs during the destructor, no further error handling is possible
+// if the directory fails to be deleted.  As a result, deletion is not
+// guaranteed by this class.
+//
+// Multiple calls to the methods which establish a temporary directory
+// (CreateUniqueTempDir, CreateUniqueTempDirUnderPath, and Set) must have
+// intervening calls to Delete or Take, or the calls will fail.
+
+#include "base/base_export.h"
+#include "base/files/file_path.h"
+
+namespace base {
+
+class BASE_EXPORT ScopedTempDir {
+ public:
+  // No directory is owned/created initially.
+  ScopedTempDir();
+
+  // Recursively delete path.
+  ~ScopedTempDir();
+
+  // Creates a unique directory in TempPath, and takes ownership of it.
+  // See file_util::CreateNewTemporaryDirectory.
+  bool CreateUniqueTempDir() WARN_UNUSED_RESULT;
+
+  // Creates a unique directory under a given path, and takes ownership of it.
+  bool CreateUniqueTempDirUnderPath(const FilePath& path) WARN_UNUSED_RESULT;
+
+  // Takes ownership of directory at |path|, creating it if necessary.
+  // Don't call multiple times unless Take() has been called first.
+  bool Set(const FilePath& path) WARN_UNUSED_RESULT;
+
+  // Deletes the temporary directory wrapped by this object.
+  bool Delete() WARN_UNUSED_RESULT;
+
+  // Caller takes ownership of the temporary directory so it won't be destroyed
+  // when this object goes out of scope.
+  FilePath Take();
+
+  const FilePath& path() const { return path_; }
+
+  // Returns true if path_ is non-empty and exists.
+  bool IsValid() const;
+
+ private:
+  FilePath path_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedTempDir);
+};
+
+}  // namespace base
+
+#endif  // BASE_FILES_SCOPED_TEMP_DIR_H_
diff --git a/base/files/scoped_temp_dir_unittest.cc b/base/files/scoped_temp_dir_unittest.cc
new file mode 100644
index 0000000..a19f34d
--- /dev/null
+++ b/base/files/scoped_temp_dir_unittest.cc
@@ -0,0 +1,113 @@
+// Copyright (c) 2011 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 <string>
+
+#include "base/files/file.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(ScopedTempDir, FullPath) {
+  FilePath test_path;
+  base::CreateNewTempDirectory(FILE_PATH_LITERAL("scoped_temp_dir"),
+                               &test_path);
+
+  // Against an existing dir, it should get destroyed when leaving scope.
+  EXPECT_TRUE(DirectoryExists(test_path));
+  {
+    ScopedTempDir dir;
+    EXPECT_TRUE(dir.Set(test_path));
+    EXPECT_TRUE(dir.IsValid());
+  }
+  EXPECT_FALSE(DirectoryExists(test_path));
+
+  {
+    ScopedTempDir dir;
+    EXPECT_TRUE(dir.Set(test_path));
+    // Now the dir doesn't exist, so ensure that it gets created.
+    EXPECT_TRUE(DirectoryExists(test_path));
+    // When we call Release(), it shouldn't get destroyed when leaving scope.
+    FilePath path = dir.Take();
+    EXPECT_EQ(path.value(), test_path.value());
+    EXPECT_FALSE(dir.IsValid());
+  }
+  EXPECT_TRUE(DirectoryExists(test_path));
+
+  // Clean up.
+  {
+    ScopedTempDir dir;
+    EXPECT_TRUE(dir.Set(test_path));
+  }
+  EXPECT_FALSE(DirectoryExists(test_path));
+}
+
+TEST(ScopedTempDir, TempDir) {
+  // In this case, just verify that a directory was created and that it's a
+  // child of TempDir.
+  FilePath test_path;
+  {
+    ScopedTempDir dir;
+    EXPECT_TRUE(dir.CreateUniqueTempDir());
+    test_path = dir.path();
+    EXPECT_TRUE(DirectoryExists(test_path));
+    FilePath tmp_dir;
+    EXPECT_TRUE(base::GetTempDir(&tmp_dir));
+    EXPECT_TRUE(test_path.value().find(tmp_dir.value()) != std::string::npos);
+  }
+  EXPECT_FALSE(DirectoryExists(test_path));
+}
+
+TEST(ScopedTempDir, UniqueTempDirUnderPath) {
+  // Create a path which will contain a unique temp path.
+  FilePath base_path;
+  ASSERT_TRUE(base::CreateNewTempDirectory(FILE_PATH_LITERAL("base_dir"),
+                                           &base_path));
+
+  FilePath test_path;
+  {
+    ScopedTempDir dir;
+    EXPECT_TRUE(dir.CreateUniqueTempDirUnderPath(base_path));
+    test_path = dir.path();
+    EXPECT_TRUE(DirectoryExists(test_path));
+    EXPECT_TRUE(base_path.IsParent(test_path));
+    EXPECT_TRUE(test_path.value().find(base_path.value()) != std::string::npos);
+  }
+  EXPECT_FALSE(DirectoryExists(test_path));
+  base::DeleteFile(base_path, true);
+}
+
+TEST(ScopedTempDir, MultipleInvocations) {
+  ScopedTempDir dir;
+  EXPECT_TRUE(dir.CreateUniqueTempDir());
+  EXPECT_FALSE(dir.CreateUniqueTempDir());
+  EXPECT_TRUE(dir.Delete());
+  EXPECT_TRUE(dir.CreateUniqueTempDir());
+  EXPECT_FALSE(dir.CreateUniqueTempDir());
+  ScopedTempDir other_dir;
+  EXPECT_TRUE(other_dir.Set(dir.Take()));
+  EXPECT_TRUE(dir.CreateUniqueTempDir());
+  EXPECT_FALSE(dir.CreateUniqueTempDir());
+  EXPECT_FALSE(other_dir.CreateUniqueTempDir());
+}
+
+#if defined(OS_WIN)
+TEST(ScopedTempDir, LockedTempDir) {
+  ScopedTempDir dir;
+  EXPECT_TRUE(dir.CreateUniqueTempDir());
+  base::File file(dir.path().Append(FILE_PATH_LITERAL("temp")),
+                  base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
+  EXPECT_TRUE(file.IsValid());
+  EXPECT_EQ(base::File::FILE_OK, file.error_details());
+  EXPECT_FALSE(dir.Delete());  // We should not be able to delete.
+  EXPECT_FALSE(dir.path().empty());  // We should still have a valid path.
+  file.Close();
+  // Now, we should be able to delete.
+  EXPECT_TRUE(dir.Delete());
+}
+#endif  // defined(OS_WIN)
+
+}  // namespace base
diff --git a/base/format_macros.h b/base/format_macros.h
new file mode 100644
index 0000000..d58658d
--- /dev/null
+++ b/base/format_macros.h
@@ -0,0 +1,94 @@
+// Copyright (c) 2009 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_FORMAT_MACROS_H_
+#define BASE_FORMAT_MACROS_H_
+
+// This file defines the format macros for some integer types.
+
+// To print a 64-bit value in a portable way:
+//   int64_t value;
+//   printf("xyz:%" PRId64, value);
+// The "d" in the macro corresponds to %d; you can also use PRIu64 etc.
+//
+// For wide strings, prepend "Wide" to the macro:
+//   int64_t value;
+//   StringPrintf(L"xyz: %" WidePRId64, value);
+//
+// To print a size_t value in a portable way:
+//   size_t size;
+//   printf("xyz: %" PRIuS, size);
+// The "u" in the macro corresponds to %u, and S is for "size".
+
+#include "build/build_config.h"
+
+#if defined(OS_POSIX) && (defined(_INTTYPES_H) || defined(_INTTYPES_H_)) && \
+    !defined(PRId64)
+#error "inttypes.h has already been included before this header file, but "
+#error "without __STDC_FORMAT_MACROS defined."
+#endif
+
+#if defined(OS_POSIX) && !defined(__STDC_FORMAT_MACROS)
+#define __STDC_FORMAT_MACROS
+#endif
+
+#include <inttypes.h>
+
+#if defined(OS_POSIX)
+
+// GCC will concatenate wide and narrow strings correctly, so nothing needs to
+// be done here.
+#define WidePRId64 PRId64
+#define WidePRIu64 PRIu64
+#define WidePRIx64 PRIx64
+
+#if !defined(PRIuS)
+#define PRIuS "zu"
+#endif
+
+// The size of NSInteger and NSUInteger varies between 32-bit and 64-bit
+// architectures and Apple does not provides standard format macros and
+// recommends casting. This has many drawbacks, so instead define macros
+// for formatting those types.
+#if defined(OS_MACOSX)
+#if defined(ARCH_CPU_64_BITS)
+#if !defined(PRIdNS)
+#define PRIdNS "ld"
+#endif
+#if !defined(PRIuNS)
+#define PRIuNS "lu"
+#endif
+#if !defined(PRIxNS)
+#define PRIxNS "lx"
+#endif
+#else  // defined(ARCH_CPU_64_BITS)
+#if !defined(PRIdNS)
+#define PRIdNS "d"
+#endif
+#if !defined(PRIuNS)
+#define PRIuNS "u"
+#endif
+#if !defined(PRIxNS)
+#define PRIxNS "x"
+#endif
+#endif
+#endif  // defined(OS_MACOSX)
+
+#else  // OS_WIN
+
+#if !defined(PRId64) || !defined(PRIu64) || !defined(PRIx64)
+#error "inttypes.h provided by win toolchain should define these."
+#endif
+
+#define WidePRId64 L"I64d"
+#define WidePRIu64 L"I64u"
+#define WidePRIx64 L"I64x"
+
+#if !defined(PRIuS)
+#define PRIuS "Iu"
+#endif
+
+#endif
+
+#endif  // BASE_FORMAT_MACROS_H_
diff --git a/base/gmock_unittest.cc b/base/gmock_unittest.cc
new file mode 100644
index 0000000..855380a
--- /dev/null
+++ b/base/gmock_unittest.cc
@@ -0,0 +1,137 @@
+// Copyright (c) 2009 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 test is a simple sanity check to make sure gmock is able to build/link
+// correctly.  It just instantiates a mock object and runs through a couple of
+// the basic mock features.
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Gmock matchers and actions that we use below.
+using testing::AnyOf;
+using testing::Eq;
+using testing::Return;
+using testing::SetArgumentPointee;
+using testing::WithArg;
+using testing::_;
+
+namespace {
+
+// Simple class that we can mock out the behavior for.  Everything is virtual
+// for easy mocking.
+class SampleClass {
+ public:
+  SampleClass() {}
+  virtual ~SampleClass() {}
+
+  virtual int ReturnSomething() {
+    return -1;
+  }
+
+  virtual void ReturnNothingConstly() const {
+  }
+
+  virtual void OutputParam(int* a) {
+  }
+
+  virtual int ReturnSecond(int a, int b) {
+    return b;
+  }
+};
+
+// Declare a mock for the class.
+class MockSampleClass : public SampleClass {
+ public:
+  MOCK_METHOD0(ReturnSomething, int());
+  MOCK_CONST_METHOD0(ReturnNothingConstly, void());
+  MOCK_METHOD1(OutputParam, void(int* a));
+  MOCK_METHOD2(ReturnSecond, int(int a, int b));
+};
+
+// Create a couple of custom actions.  Custom actions can be used for adding
+// more complex behavior into your mock...though if you start needing these, ask
+// if you're asking your mock to do too much.
+ACTION(ReturnVal) {
+  // Return the first argument received.
+  return arg0;
+}
+ACTION(ReturnSecond) {
+  // Returns the second argument.  This basically implemetns ReturnSecond.
+  return arg1;
+}
+
+TEST(GmockTest, SimpleMatchAndActions) {
+  // Basic test of some simple gmock matchers, actions, and cardinality
+  // expectations.
+  MockSampleClass mock;
+
+  EXPECT_CALL(mock, ReturnSomething())
+      .WillOnce(Return(1))
+      .WillOnce(Return(2))
+      .WillOnce(Return(3));
+  EXPECT_EQ(1, mock.ReturnSomething());
+  EXPECT_EQ(2, mock.ReturnSomething());
+  EXPECT_EQ(3, mock.ReturnSomething());
+
+  EXPECT_CALL(mock, ReturnNothingConstly()).Times(2);
+  mock.ReturnNothingConstly();
+  mock.ReturnNothingConstly();
+}
+
+TEST(GmockTest, AssignArgument) {
+  // Capture an argument for examination.
+  MockSampleClass mock;
+
+  EXPECT_CALL(mock, OutputParam(_))
+      .WillRepeatedly(SetArgumentPointee<0>(5));
+
+  int arg = 0;
+  mock.OutputParam(&arg);
+  EXPECT_EQ(5, arg);
+}
+
+TEST(GmockTest, SideEffects) {
+  // Capture an argument for examination.
+  MockSampleClass mock;
+
+  EXPECT_CALL(mock, OutputParam(_))
+      .WillRepeatedly(SetArgumentPointee<0>(5));
+
+  int arg = 0;
+  mock.OutputParam(&arg);
+  EXPECT_EQ(5, arg);
+}
+
+TEST(GmockTest, CustomAction_ReturnSecond) {
+  // Test a mock of the ReturnSecond behavior using an action that provides an
+  // alternate implementation of the function.  Danger here though, this is
+  // starting to add too much behavior of the mock, which means the mock
+  // implementation might start to have bugs itself.
+  MockSampleClass mock;
+
+  EXPECT_CALL(mock, ReturnSecond(_, AnyOf(Eq(4), Eq(5))))
+      .WillRepeatedly(ReturnSecond());
+  EXPECT_EQ(4, mock.ReturnSecond(-1, 4));
+  EXPECT_EQ(5, mock.ReturnSecond(0, 5));
+  EXPECT_EQ(4, mock.ReturnSecond(0xdeadbeef, 4));
+  EXPECT_EQ(4, mock.ReturnSecond(112358, 4));
+  EXPECT_EQ(5, mock.ReturnSecond(1337, 5));
+}
+
+TEST(GmockTest, CustomAction_ReturnVal) {
+  // Alternate implemention of ReturnSecond using a more general custom action,
+  // and a WithArg adapter to bridge the interfaces.
+  MockSampleClass mock;
+
+  EXPECT_CALL(mock, ReturnSecond(_, AnyOf(Eq(4), Eq(5))))
+      .WillRepeatedly(WithArg<1>(ReturnVal()));
+  EXPECT_EQ(4, mock.ReturnSecond(-1, 4));
+  EXPECT_EQ(5, mock.ReturnSecond(0, 5));
+  EXPECT_EQ(4, mock.ReturnSecond(0xdeadbeef, 4));
+  EXPECT_EQ(4, mock.ReturnSecond(112358, 4));
+  EXPECT_EQ(5, mock.ReturnSecond(1337, 5));
+}
+
+}  // namespace
diff --git a/base/gtest_prod_util.h b/base/gtest_prod_util.h
new file mode 100644
index 0000000..3289e63
--- /dev/null
+++ b/base/gtest_prod_util.h
@@ -0,0 +1,66 @@
+// Copyright (c) 2012 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_GTEST_PROD_UTIL_H_
+#define BASE_GTEST_PROD_UTIL_H_
+
+#include "testing/gtest/include/gtest/gtest_prod.h"
+
+// This is a wrapper for gtest's FRIEND_TEST macro that friends
+// test with all possible prefixes. This is very helpful when changing the test
+// prefix, because the friend declarations don't need to be updated.
+//
+// Example usage:
+//
+// class MyClass {
+//  private:
+//   void MyMethod();
+//   FRIEND_TEST_ALL_PREFIXES(MyClassTest, MyMethod);
+// };
+#define FRIEND_TEST_ALL_PREFIXES(test_case_name, test_name) \
+  FRIEND_TEST(test_case_name, test_name); \
+  FRIEND_TEST(test_case_name, DISABLED_##test_name); \
+  FRIEND_TEST(test_case_name, FLAKY_##test_name)
+
+// C++ compilers will refuse to compile the following code:
+//
+// namespace foo {
+// class MyClass {
+//  private:
+//   FRIEND_TEST_ALL_PREFIXES(MyClassTest, TestMethod);
+//   bool private_var;
+// };
+// }  // namespace foo
+//
+// class MyClassTest::TestMethod() {
+//   foo::MyClass foo_class;
+//   foo_class.private_var = true;
+// }
+//
+// Unless you forward declare MyClassTest::TestMethod outside of namespace foo.
+// Use FORWARD_DECLARE_TEST to do so for all possible prefixes.
+//
+// Example usage:
+//
+// FORWARD_DECLARE_TEST(MyClassTest, TestMethod);
+//
+// namespace foo {
+// class MyClass {
+//  private:
+//   FRIEND_TEST_ALL_PREFIXES(::MyClassTest, TestMethod);  // NOTE use of ::
+//   bool private_var;
+// };
+// }  // namespace foo
+//
+// class MyClassTest::TestMethod() {
+//   foo::MyClass foo_class;
+//   foo_class.private_var = true;
+// }
+
+#define FORWARD_DECLARE_TEST(test_case_name, test_name) \
+  class test_case_name##_##test_name##_Test; \
+  class test_case_name##_##DISABLED_##test_name##_Test; \
+  class test_case_name##_##FLAKY_##test_name##_Test
+
+#endif  // BASE_GTEST_PROD_UTIL_H_
diff --git a/base/guid.cc b/base/guid.cc
new file mode 100644
index 0000000..be5c58b
--- /dev/null
+++ b/base/guid.cc
@@ -0,0 +1,30 @@
+// Copyright (c) 2012 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/guid.h"
+
+#include "base/strings/string_util.h"
+
+namespace base {
+
+bool IsValidGUID(const std::string& guid) {
+  const size_t kGUIDLength = 36U;
+  if (guid.length() != kGUIDLength)
+    return false;
+
+  for (size_t i = 0; i < guid.length(); ++i) {
+    char current = guid[i];
+    if (i == 8 || i == 13 || i == 18 || i == 23) {
+      if (current != '-')
+        return false;
+    } else {
+      if (!IsHexDigit(current))
+        return false;
+    }
+  }
+
+  return true;
+}
+
+}  // namespace base
diff --git a/base/guid.h b/base/guid.h
new file mode 100644
index 0000000..abcc589
--- /dev/null
+++ b/base/guid.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2012 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_GUID_H_
+#define BASE_GUID_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "build/build_config.h"
+
+namespace base {
+
+// Generate a 128-bit random GUID of the form: "%08X-%04X-%04X-%04X-%012llX".
+// If GUID generation fails an empty string is returned.
+// The POSIX implementation uses pseudo random number generation to create
+// the GUID.  The Windows implementation uses system services.
+BASE_EXPORT std::string GenerateGUID();
+
+// Returns true if the input string conforms to the GUID format.
+BASE_EXPORT bool IsValidGUID(const std::string& guid);
+
+#if defined(OS_POSIX)
+// For unit testing purposes only.  Do not use outside of tests.
+BASE_EXPORT std::string RandomDataToGUIDString(const uint64 bytes[2]);
+#endif
+
+}  // namespace base
+
+#endif  // BASE_GUID_H_
diff --git a/base/guid_posix.cc b/base/guid_posix.cc
new file mode 100644
index 0000000..f0fedc2
--- /dev/null
+++ b/base/guid_posix.cc
@@ -0,0 +1,42 @@
+// Copyright (c) 2012 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/guid.h"
+
+#include "base/rand_util.h"
+#include "base/strings/stringprintf.h"
+
+namespace base {
+
+std::string GenerateGUID() {
+  uint64 sixteen_bytes[2] = { base::RandUint64(), base::RandUint64() };
+
+  // Set the GUID to version 4 as described in RFC 4122, section 4.4.
+  // The format of GUID version 4 must be xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx,
+  // where y is one of [8, 9, A, B].
+
+  // Clear the version bits and set the version to 4:
+  sixteen_bytes[0] &= 0xffffffffffff0fffULL;
+  sixteen_bytes[0] |= 0x0000000000004000ULL;
+
+  // Set the two most significant bits (bits 6 and 7) of the
+  // clock_seq_hi_and_reserved to zero and one, respectively:
+  sixteen_bytes[1] &= 0x3fffffffffffffffULL;
+  sixteen_bytes[1] |= 0x8000000000000000ULL;
+
+  return RandomDataToGUIDString(sixteen_bytes);
+}
+
+// TODO(cmasone): Once we're comfortable this works, migrate Windows code to
+// use this as well.
+std::string RandomDataToGUIDString(const uint64 bytes[2]) {
+  return StringPrintf("%08X-%04X-%04X-%04X-%012llX",
+                      static_cast<unsigned int>(bytes[0] >> 32),
+                      static_cast<unsigned int>((bytes[0] >> 16) & 0x0000ffff),
+                      static_cast<unsigned int>(bytes[0] & 0x0000ffff),
+                      static_cast<unsigned int>(bytes[1] >> 48),
+                      bytes[1] & 0x0000ffffffffffffULL);
+}
+
+}  // namespace base
diff --git a/base/guid_unittest.cc b/base/guid_unittest.cc
new file mode 100644
index 0000000..1485497
--- /dev/null
+++ b/base/guid_unittest.cc
@@ -0,0 +1,66 @@
+// Copyright (c) 2012 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/guid.h"
+
+#include <limits>
+
+#include "base/strings/string_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+#if defined(OS_POSIX)
+
+namespace {
+
+bool IsGUIDv4(const std::string& guid) {
+  // The format of GUID version 4 must be xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx,
+  // where y is one of [8, 9, A, B].
+  return IsValidGUID(guid) && guid[14] == '4' &&
+         (guid[19] == '8' || guid[19] == '9' || guid[19] == 'A' ||
+          guid[19] == 'a' || guid[19] == 'B' || guid[19] == 'b');
+}
+
+}  // namespace
+
+TEST(GUIDTest, GUIDGeneratesAllZeroes) {
+  uint64 bytes[] = { 0, 0 };
+  std::string clientid = RandomDataToGUIDString(bytes);
+  EXPECT_EQ("00000000-0000-0000-0000-000000000000", clientid);
+}
+
+TEST(GUIDTest, GUIDGeneratesCorrectly) {
+  uint64 bytes[] = { 0x0123456789ABCDEFULL, 0xFEDCBA9876543210ULL };
+  std::string clientid = RandomDataToGUIDString(bytes);
+  EXPECT_EQ("01234567-89AB-CDEF-FEDC-BA9876543210", clientid);
+}
+#endif
+
+TEST(GUIDTest, GUIDCorrectlyFormatted) {
+  const int kIterations = 10;
+  for (int it = 0; it < kIterations; ++it) {
+    std::string guid = GenerateGUID();
+    EXPECT_TRUE(IsValidGUID(guid));
+    EXPECT_TRUE(IsValidGUID(StringToLowerASCII(guid)));
+    EXPECT_TRUE(IsValidGUID(StringToUpperASCII(guid)));
+  }
+}
+
+TEST(GUIDTest, GUIDBasicUniqueness) {
+  const int kIterations = 10;
+  for (int it = 0; it < kIterations; ++it) {
+    std::string guid1 = GenerateGUID();
+    std::string guid2 = GenerateGUID();
+    EXPECT_EQ(36U, guid1.length());
+    EXPECT_EQ(36U, guid2.length());
+    EXPECT_NE(guid1, guid2);
+#if defined(OS_POSIX)
+    EXPECT_TRUE(IsGUIDv4(guid1));
+    EXPECT_TRUE(IsGUIDv4(guid2));
+#endif
+  }
+}
+
+}  // namespace base
diff --git a/base/guid_win.cc b/base/guid_win.cc
new file mode 100644
index 0000000..da3453d
--- /dev/null
+++ b/base/guid_win.cc
@@ -0,0 +1,38 @@
+// Copyright (c) 2012 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/guid.h"
+
+#include <stdlib.h>
+
+#include <objbase.h>
+#include <windows.h>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+
+namespace base {
+
+std::string GenerateGUID() {
+  const int kGUIDSize = 39;
+
+  GUID guid;
+  HRESULT guid_result = CoCreateGuid(&guid);
+  DCHECK(SUCCEEDED(guid_result));
+  if (!SUCCEEDED(guid_result))
+    return std::string();
+
+  std::wstring guid_string;
+  int result = StringFromGUID2(guid,
+                               WriteInto(&guid_string, kGUIDSize), kGUIDSize);
+  DCHECK(result == kGUIDSize);
+  if (result != kGUIDSize)
+    return std::string();
+
+  return WideToUTF8(guid_string.substr(1, guid_string.length() - 2));
+}
+
+}  // namespace base
diff --git a/base/hash.cc b/base/hash.cc
new file mode 100644
index 0000000..a7db64a
--- /dev/null
+++ b/base/hash.cc
@@ -0,0 +1,18 @@
+// 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.
+
+#include "base/hash.h"
+
+// Definition in base/third_party/superfasthash/superfasthash.c. (Third-party
+// code did not come with its own header file, so declaring the function here.)
+// Note: This algorithm is also in Blink under Source/wtf/StringHasher.h.
+extern "C" uint32_t SuperFastHash(const char* data, int len);
+
+namespace base {
+
+uint32 SuperFastHash(const char* data, int len) {
+  return ::SuperFastHash(data, len);
+}
+
+}  // namespace base
diff --git a/base/hash.h b/base/hash.h
new file mode 100644
index 0000000..e46f6ac
--- /dev/null
+++ b/base/hash.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2011 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_HASH_H_
+#define BASE_HASH_H_
+
+#include <limits>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+namespace base {
+
+// WARNING: This hash function should not be used for any cryptographic purpose.
+BASE_EXPORT uint32 SuperFastHash(const char* data, int len);
+
+// Computes a hash of a memory buffer |data| of a given |length|.
+// WARNING: This hash function should not be used for any cryptographic purpose.
+inline uint32 Hash(const char* data, size_t length) {
+  if (length > static_cast<size_t>(std::numeric_limits<int>::max())) {
+    NOTREACHED();
+    return 0;
+  }
+  return SuperFastHash(data, static_cast<int>(length));
+}
+
+// Computes a hash of a string |str|.
+// WARNING: This hash function should not be used for any cryptographic purpose.
+inline uint32 Hash(const std::string& str) {
+  return Hash(str.data(), str.size());
+}
+
+}  // namespace base
+
+#endif  // BASE_HASH_H_
diff --git a/base/hash_unittest.cc b/base/hash_unittest.cc
new file mode 100644
index 0000000..fc8a751
--- /dev/null
+++ b/base/hash_unittest.cc
@@ -0,0 +1,82 @@
+// 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.
+
+#include "base/hash.h"
+
+#include <string>
+#include <vector>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(HashTest, String) {
+  std::string str;
+  // Empty string (should hash to 0).
+  str = "";
+  EXPECT_EQ(0u, Hash(str));
+
+  // Simple test.
+  str = "hello world";
+  EXPECT_EQ(2794219650u, Hash(str));
+
+  // Change one bit.
+  str = "helmo world";
+  EXPECT_EQ(1006697176u, Hash(str));
+
+  // Insert a null byte.
+  str = "hello  world";
+  str[5] = '\0';
+  EXPECT_EQ(2319902537u, Hash(str));
+
+  // Test that the bytes after the null contribute to the hash.
+  str = "hello  worle";
+  str[5] = '\0';
+  EXPECT_EQ(553904462u, Hash(str));
+
+  // Extremely long string.
+  // Also tests strings with high bit set, and null byte.
+  std::vector<char> long_string_buffer;
+  for (int i = 0; i < 4096; ++i)
+    long_string_buffer.push_back((i % 256) - 128);
+  str.assign(&long_string_buffer.front(), long_string_buffer.size());
+  EXPECT_EQ(2797962408u, Hash(str));
+
+  // All possible lengths (mod 4). Tests separate code paths. Also test with
+  // final byte high bit set (regression test for http://crbug.com/90659).
+  // Note that the 1 and 3 cases have a weird bug where the final byte is
+  // treated as a signed char. It was decided on the above bug discussion to
+  // enshrine that behaviour as "correct" to avoid invalidating existing hashes.
+
+  // Length mod 4 == 0.
+  str = "hello w\xab";
+  EXPECT_EQ(615571198u, Hash(str));
+  // Length mod 4 == 1.
+  str = "hello wo\xab";
+  EXPECT_EQ(623474296u, Hash(str));
+  // Length mod 4 == 2.
+  str = "hello wor\xab";
+  EXPECT_EQ(4278562408u, Hash(str));
+  // Length mod 4 == 3.
+  str = "hello worl\xab";
+  EXPECT_EQ(3224633008u, Hash(str));
+}
+
+TEST(HashTest, CString) {
+  const char* str;
+  // Empty string (should hash to 0).
+  str = "";
+  EXPECT_EQ(0u, Hash(str, strlen(str)));
+
+  // Simple test.
+  str = "hello world";
+  EXPECT_EQ(2794219650u, Hash(str, strlen(str)));
+
+  // Ensure that it stops reading after the given length, and does not expect a
+  // null byte.
+  str = "hello world; don't read this part";
+  EXPECT_EQ(2794219650u, Hash(str, strlen("hello world")));
+}
+
+}  // namespace base
diff --git a/base/i18n/OWNERS b/base/i18n/OWNERS
new file mode 100644
index 0000000..d717b8d
--- /dev/null
+++ b/base/i18n/OWNERS
@@ -0,0 +1 @@
+jshin@chromium.org
diff --git a/base/i18n/base_i18n_export.h b/base/i18n/base_i18n_export.h
new file mode 100644
index 0000000..e8a2add
--- /dev/null
+++ b/base/i18n/base_i18n_export.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2011 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_I18N_BASE_I18N_EXPORT_H_
+#define BASE_I18N_BASE_I18N_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(BASE_I18N_IMPLEMENTATION)
+#define BASE_I18N_EXPORT __declspec(dllexport)
+#else
+#define BASE_I18N_EXPORT __declspec(dllimport)
+#endif  // defined(BASE_I18N_IMPLEMENTATION)
+
+#else  // defined(WIN32)
+#if defined(BASE_I18N_IMPLEMENTATION)
+#define BASE_I18N_EXPORT __attribute__((visibility("default")))
+#else
+#define BASE_I18N_EXPORT
+#endif
+#endif
+
+#else  // defined(COMPONENT_BUILD)
+#define BASE_I18N_EXPORT
+#endif
+
+#endif  // BASE_I18N_BASE_I18N_EXPORT_H_
diff --git a/base/i18n/bidi_line_iterator.cc b/base/i18n/bidi_line_iterator.cc
new file mode 100644
index 0000000..216129e
--- /dev/null
+++ b/base/i18n/bidi_line_iterator.cc
@@ -0,0 +1,74 @@
+// Copyright (c) 2011 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/i18n/bidi_line_iterator.h"
+
+#include "base/logging.h"
+
+namespace base {
+namespace i18n {
+
+namespace {
+  UBiDiLevel GetParagraphLevelForDirection(TextDirection direction) {
+    switch (direction) {
+      case UNKNOWN_DIRECTION:
+        return UBIDI_DEFAULT_LTR;
+        break;
+      case RIGHT_TO_LEFT:
+        return 1;  // Highest RTL level.
+        break;
+      case LEFT_TO_RIGHT:
+        return 0;  // Highest LTR level.
+        break;
+      default:
+        NOTREACHED();
+        return 0;
+    }
+  }
+}  // namespace
+
+BiDiLineIterator::BiDiLineIterator() : bidi_(NULL) {
+}
+
+BiDiLineIterator::~BiDiLineIterator() {
+  if (bidi_) {
+    ubidi_close(bidi_);
+    bidi_ = NULL;
+  }
+}
+
+bool BiDiLineIterator::Open(const string16& text, TextDirection direction) {
+  DCHECK(!bidi_);
+  UErrorCode error = U_ZERO_ERROR;
+  bidi_ = ubidi_openSized(static_cast<int>(text.length()), 0, &error);
+  if (U_FAILURE(error))
+    return false;
+  ubidi_setPara(bidi_, text.data(), static_cast<int>(text.length()),
+                GetParagraphLevelForDirection(direction), NULL, &error);
+  return (U_SUCCESS(error) == TRUE);
+}
+
+int BiDiLineIterator::CountRuns() {
+  DCHECK(bidi_ != NULL);
+  UErrorCode error = U_ZERO_ERROR;
+  const int runs = ubidi_countRuns(bidi_, &error);
+  return U_SUCCESS(error) ? runs : 0;
+}
+
+UBiDiDirection BiDiLineIterator::GetVisualRun(int index,
+                                              int* start,
+                                              int* length) {
+  DCHECK(bidi_ != NULL);
+  return ubidi_getVisualRun(bidi_, index, start, length);
+}
+
+void BiDiLineIterator::GetLogicalRun(int start,
+                                     int* end,
+                                     UBiDiLevel* level) {
+  DCHECK(bidi_ != NULL);
+  ubidi_getLogicalRun(bidi_, start, end, level);
+}
+
+}  // namespace i18n
+}  // namespace base
diff --git a/base/i18n/bidi_line_iterator.h b/base/i18n/bidi_line_iterator.h
new file mode 100644
index 0000000..0bf1ec6
--- /dev/null
+++ b/base/i18n/bidi_line_iterator.h
@@ -0,0 +1,47 @@
+// Copyright (c) 2011 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_I18N_BIDI_LINE_ITERATOR_H_
+#define BASE_I18N_BIDI_LINE_ITERATOR_H_
+
+#include "base/basictypes.h"
+#include "base/i18n/base_i18n_export.h"
+#include "base/i18n/rtl.h"
+#include "base/strings/string16.h"
+#include "third_party/icu/source/common/unicode/ubidi.h"
+
+namespace base {
+namespace i18n {
+
+// A simple wrapper class for the bidirectional iterator of ICU.
+// This class uses the bidirectional iterator of ICU to split a line of
+// bidirectional texts into visual runs in its display order.
+class BASE_I18N_EXPORT BiDiLineIterator {
+ public:
+  BiDiLineIterator();
+  ~BiDiLineIterator();
+
+  // Initializes the bidirectional iterator with the specified text.  Returns
+  // whether initialization succeeded.
+  bool Open(const string16& text, TextDirection direction);
+
+  // Returns the number of visual runs in the text, or zero on error.
+  int CountRuns();
+
+  // Gets the logical offset, length, and direction of the specified visual run.
+  UBiDiDirection GetVisualRun(int index, int* start, int* length);
+
+  // Given a start position, figure out where the run ends (and the BiDiLevel).
+  void GetLogicalRun(int start, int* end, UBiDiLevel* level);
+
+ private:
+  UBiDi* bidi_;
+
+  DISALLOW_COPY_AND_ASSIGN(BiDiLineIterator);
+};
+
+}  // namespace i18n
+}  // namespace base
+
+#endif  // BASE_I18N_BIDI_LINE_ITERATOR_H_
diff --git a/base/i18n/break_iterator.cc b/base/i18n/break_iterator.cc
new file mode 100644
index 0000000..e2ed667
--- /dev/null
+++ b/base/i18n/break_iterator.cc
@@ -0,0 +1,186 @@
+// Copyright (c) 2011 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/i18n/break_iterator.h"
+
+#include "base/logging.h"
+#include "third_party/icu/source/common/unicode/ubrk.h"
+#include "third_party/icu/source/common/unicode/uchar.h"
+#include "third_party/icu/source/common/unicode/ustring.h"
+
+namespace base {
+namespace i18n {
+
+const size_t npos = static_cast<size_t>(-1);
+
+BreakIterator::BreakIterator(const StringPiece16& str, BreakType break_type)
+    : iter_(NULL),
+      string_(str),
+      break_type_(break_type),
+      prev_(npos),
+      pos_(0) {
+}
+
+BreakIterator::BreakIterator(const StringPiece16& str, const string16& rules)
+    : iter_(NULL),
+      string_(str),
+      rules_(rules),
+      break_type_(RULE_BASED),
+      prev_(npos),
+      pos_(0) {
+}
+
+BreakIterator::~BreakIterator() {
+  if (iter_)
+    ubrk_close(static_cast<UBreakIterator*>(iter_));
+}
+
+bool BreakIterator::Init() {
+  UErrorCode status = U_ZERO_ERROR;
+  UParseError parse_error;
+  UBreakIteratorType break_type;
+  switch (break_type_) {
+    case BREAK_CHARACTER:
+      break_type = UBRK_CHARACTER;
+      break;
+    case BREAK_WORD:
+      break_type = UBRK_WORD;
+      break;
+    case BREAK_LINE:
+    case BREAK_NEWLINE:
+    case RULE_BASED: // (Keep compiler happy, break_type not used in this case)
+      break_type = UBRK_LINE;
+      break;
+    default:
+      NOTREACHED() << "invalid break_type_";
+      return false;
+  }
+  if (break_type_ == RULE_BASED) {
+    iter_ = ubrk_openRules(rules_.c_str(),
+                           static_cast<int32_t>(rules_.length()),
+                           string_.data(),
+                           static_cast<int32_t>(string_.size()),
+                           &parse_error,
+                           &status);
+    if (U_FAILURE(status)) {
+      NOTREACHED() << "ubrk_openRules failed to parse rule string at line "
+          << parse_error.line << ", offset " << parse_error.offset;
+    }
+  } else {
+    iter_ = ubrk_open(break_type,
+                      NULL,
+                      string_.data(),
+                      static_cast<int32_t>(string_.size()),
+                      &status);
+    if (U_FAILURE(status)) {
+      NOTREACHED() << "ubrk_open failed for type " << break_type
+          << " with error " << status;
+    }
+  }
+
+  if (U_FAILURE(status)) {
+    return false;
+  }
+
+  // Move the iterator to the beginning of the string.
+  ubrk_first(static_cast<UBreakIterator*>(iter_));
+  return true;
+}
+
+bool BreakIterator::Advance() {
+  int32_t pos;
+  int32_t status;
+  prev_ = pos_;
+  switch (break_type_) {
+    case BREAK_CHARACTER:
+    case BREAK_WORD:
+    case BREAK_LINE:
+    case RULE_BASED:
+      pos = ubrk_next(static_cast<UBreakIterator*>(iter_));
+      if (pos == UBRK_DONE) {
+        pos_ = npos;
+        return false;
+      }
+      pos_ = static_cast<size_t>(pos);
+      return true;
+    case BREAK_NEWLINE:
+      do {
+        pos = ubrk_next(static_cast<UBreakIterator*>(iter_));
+        if (pos == UBRK_DONE)
+          break;
+        pos_ = static_cast<size_t>(pos);
+        status = ubrk_getRuleStatus(static_cast<UBreakIterator*>(iter_));
+      } while (status >= UBRK_LINE_SOFT && status < UBRK_LINE_SOFT_LIMIT);
+      if (pos == UBRK_DONE && prev_ == pos_) {
+        pos_ = npos;
+        return false;
+      }
+      return true;
+    default:
+      NOTREACHED() << "invalid break_type_";
+      return false;
+  }
+}
+
+bool BreakIterator::SetText(const base::char16* text, const size_t length) {
+  UErrorCode status = U_ZERO_ERROR;
+  ubrk_setText(static_cast<UBreakIterator*>(iter_),
+               text, length, &status);
+  pos_ = 0;  // implicit when ubrk_setText is done
+  prev_ = npos;
+  if (U_FAILURE(status)) {
+    NOTREACHED() << "ubrk_setText failed";
+    return false;
+  }
+  string_ = StringPiece16(text, length);
+  return true;
+}
+
+bool BreakIterator::IsWord() const {
+  int32_t status = ubrk_getRuleStatus(static_cast<UBreakIterator*>(iter_));
+  if (break_type_ != BREAK_WORD && break_type_ != RULE_BASED)
+    return false;
+  return status != UBRK_WORD_NONE;
+}
+
+bool BreakIterator::IsEndOfWord(size_t position) const {
+  if (break_type_ != BREAK_WORD && break_type_ != RULE_BASED)
+    return false;
+
+  UBreakIterator* iter = static_cast<UBreakIterator*>(iter_);
+  UBool boundary = ubrk_isBoundary(iter, static_cast<int32_t>(position));
+  int32_t status = ubrk_getRuleStatus(iter);
+  return (!!boundary && status != UBRK_WORD_NONE);
+}
+
+bool BreakIterator::IsStartOfWord(size_t position) const {
+  if (break_type_ != BREAK_WORD && break_type_ != RULE_BASED)
+    return false;
+
+  UBreakIterator* iter = static_cast<UBreakIterator*>(iter_);
+  UBool boundary = ubrk_isBoundary(iter, static_cast<int32_t>(position));
+  ubrk_next(iter);
+  int32_t next_status = ubrk_getRuleStatus(iter);
+  return (!!boundary && next_status != UBRK_WORD_NONE);
+}
+
+bool BreakIterator::IsGraphemeBoundary(size_t position) const {
+  if (break_type_ != BREAK_CHARACTER)
+    return false;
+
+  UBreakIterator* iter = static_cast<UBreakIterator*>(iter_);
+  return !!ubrk_isBoundary(iter, static_cast<int32_t>(position));
+}
+
+string16 BreakIterator::GetString() const {
+  return GetStringPiece().as_string();
+}
+
+StringPiece16 BreakIterator::GetStringPiece() const {
+  DCHECK(prev_ != npos && pos_ != npos);
+  return string_.substr(prev_, pos_ - prev_);
+}
+
+}  // namespace i18n
+}  // namespace base
diff --git a/base/i18n/break_iterator.h b/base/i18n/break_iterator.h
new file mode 100644
index 0000000..19fdbe0
--- /dev/null
+++ b/base/i18n/break_iterator.h
@@ -0,0 +1,153 @@
+// Copyright (c) 2011 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_I18N_BREAK_ITERATOR_H_
+#define BASE_I18N_BREAK_ITERATOR_H_
+
+#include "base/basictypes.h"
+#include "base/i18n/base_i18n_export.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
+
+// The BreakIterator class iterates through the words, word breaks, and
+// line breaks in a UTF-16 string.
+//
+// It provides several modes, BREAK_WORD, BREAK_LINE, and BREAK_NEWLINE,
+// which modify how characters are aggregated into the returned string.
+//
+// Under BREAK_WORD mode, once a word is encountered any non-word
+// characters are not included in the returned string (e.g. in the
+// UTF-16 equivalent of the string " foo bar! ", the word breaks are at
+// the periods in ". .foo. .bar.!. .").
+// Note that Chinese/Japanese/Thai do not use spaces between words so that
+// boundaries can fall in the middle of a continuous run of non-space /
+// non-punctuation characters.
+//
+// Under BREAK_LINE mode, once a line breaking opportunity is encountered,
+// any non-word  characters are included in the returned string, breaking
+// only when a space-equivalent character or a line breaking opportunity
+// is encountered (e.g. in the UTF16-equivalent of the string " foo bar! ",
+// the breaks are at the periods in ". .foo .bar! .").
+//
+// Note that lines can be broken at any character/syllable/grapheme cluster
+// boundary in Chinese/Japanese/Korean and at word boundaries in Thai
+// (Thai does not use spaces between words). Therefore, this is NOT the same
+// as breaking only at space-equivalent characters where its former
+// name (BREAK_SPACE) implied.
+//
+// Under BREAK_NEWLINE mode, all characters are included in the returned
+// string, breaking only when a newline-equivalent character is encountered
+// (eg. in the UTF-16 equivalent of the string "foo\nbar!\n\n", the line
+// breaks are at the periods in ".foo\n.bar\n.\n.").
+//
+// To extract the words from a string, move a BREAK_WORD BreakIterator
+// through the string and test whether IsWord() is true. E.g.,
+//   BreakIterator iter(str, BreakIterator::BREAK_WORD);
+//   if (!iter.Init())
+//     return false;
+//   while (iter.Advance()) {
+//     if (iter.IsWord()) {
+//       // Region [iter.prev(), iter.pos()) contains a word.
+//       VLOG(1) << "word: " << iter.GetString();
+//     }
+//   }
+
+namespace base {
+namespace i18n {
+
+class BASE_I18N_EXPORT BreakIterator {
+ public:
+  enum BreakType {
+    BREAK_WORD,
+    BREAK_LINE,
+    // TODO(jshin): Remove this after reviewing call sites.
+    // If call sites really need break only on space-like characters
+    // implement it separately.
+    BREAK_SPACE = BREAK_LINE,
+    BREAK_NEWLINE,
+    BREAK_CHARACTER,
+    // But don't remove this one!
+    RULE_BASED,
+  };
+
+  // Requires |str| to live as long as the BreakIterator does.
+  BreakIterator(const StringPiece16& str, BreakType break_type);
+  // Make a rule-based iterator. BreakType == RULE_BASED is implied.
+  // TODO(andrewhayden): This signature could easily be misinterpreted as
+  // "(const string16& str, const string16& locale)". We should do something
+  // better.
+  BreakIterator(const StringPiece16& str, const string16& rules);
+  ~BreakIterator();
+
+  // Init() must be called before any of the iterators are valid.
+  // Returns false if ICU failed to initialize.
+  bool Init();
+
+  // Advance to the next break.  Returns false if we've run past the end of
+  // the string.  (Note that the very last "break" is after the final
+  // character in the string, and when we advance to that position it's the
+  // last time Advance() returns true.)
+  bool Advance();
+
+  // Updates the text used by the iterator, resetting the iterator as if
+  // if Init() had been called again. Any old state is lost. Returns true
+  // unless there is an error setting the text.
+  bool SetText(const base::char16* text, const size_t length);
+
+  // Under BREAK_WORD mode, returns true if the break we just hit is the
+  // end of a word. (Otherwise, the break iterator just skipped over e.g.
+  // whitespace or punctuation.)  Under BREAK_LINE and BREAK_NEWLINE modes,
+  // this distinction doesn't apply and it always returns false.
+  bool IsWord() const;
+
+  // Under BREAK_WORD mode, returns true if |position| is at the end of word or
+  // at the start of word. It always returns false under BREAK_LINE and
+  // BREAK_NEWLINE modes.
+  bool IsEndOfWord(size_t position) const;
+  bool IsStartOfWord(size_t position) const;
+
+  // Under BREAK_CHARACTER mode, returns whether |position| is a Unicode
+  // grapheme boundary.
+  bool IsGraphemeBoundary(size_t position) const;
+
+  // Returns the string between prev() and pos().
+  // Advance() must have been called successfully at least once for pos() to
+  // have advanced to somewhere useful.
+  string16 GetString() const;
+
+  StringPiece16 GetStringPiece() const;
+
+  // Returns the value of pos() returned before Advance() was last called.
+  size_t prev() const { return prev_; }
+
+  // Returns the current break position within the string,
+  // or BreakIterator::npos when done.
+  size_t pos() const { return pos_; }
+
+ private:
+  // ICU iterator, avoiding ICU ubrk.h dependence.
+  // This is actually an ICU UBreakiterator* type, which turns out to be
+  // a typedef for a void* in the ICU headers. Using void* directly prevents
+  // callers from needing access to the ICU public headers directory.
+  void* iter_;
+
+  // The string we're iterating over. Can be changed with SetText(...)
+  StringPiece16 string_;
+
+  // Rules for our iterator. Mutually exclusive with break_type_.
+  const string16 rules_;
+
+  // The breaking style (word/space/newline). Mutually exclusive with rules_
+  BreakType break_type_;
+
+  // Previous and current iterator positions.
+  size_t prev_, pos_;
+
+  DISALLOW_COPY_AND_ASSIGN(BreakIterator);
+};
+
+}  // namespace i18n
+}  // namespace base
+
+#endif  // BASE_I18N_BREAK_ITERATOR_H_
diff --git a/base/i18n/break_iterator_unittest.cc b/base/i18n/break_iterator_unittest.cc
new file mode 100644
index 0000000..220a996
--- /dev/null
+++ b/base/i18n/break_iterator_unittest.cc
@@ -0,0 +1,373 @@
+// Copyright (c) 2011 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/i18n/break_iterator.h"
+
+#include "base/strings/string_piece.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace i18n {
+
+TEST(BreakIteratorTest, BreakWordEmpty) {
+  string16 empty;
+  BreakIterator iter(empty, BreakIterator::BREAK_WORD);
+  ASSERT_TRUE(iter.Init());
+  EXPECT_FALSE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_FALSE(iter.Advance());  // Test unexpected advance after end.
+  EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakWord) {
+  string16 space(UTF8ToUTF16(" "));
+  string16 str(UTF8ToUTF16(" foo bar! \npouet boom"));
+  BreakIterator iter(str, BreakIterator::BREAK_WORD);
+  ASSERT_TRUE(iter.Init());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(space, iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_TRUE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("foo"), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(space, iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_TRUE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("bar"), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("!"), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(space, iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("\n"), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_TRUE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("pouet"), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(space, iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_TRUE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("boom"), iter.GetString());
+  EXPECT_FALSE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_FALSE(iter.Advance());  // Test unexpected advance after end.
+  EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakWide16) {
+  // Two greek words separated by space.
+  const string16 str(WideToUTF16(
+      L"\x03a0\x03b1\x03b3\x03ba\x03cc\x03c3\x03bc\x03b9"
+      L"\x03bf\x03c2\x0020\x0399\x03c3\x03c4\x03cc\x03c2"));
+  const string16 word1(str.substr(0, 10));
+  const string16 word2(str.substr(11, 5));
+  BreakIterator iter(str, BreakIterator::BREAK_WORD);
+  ASSERT_TRUE(iter.Init());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_TRUE(iter.IsWord());
+  EXPECT_EQ(word1, iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16(" "), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_TRUE(iter.IsWord());
+  EXPECT_EQ(word2, iter.GetString());
+  EXPECT_FALSE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_FALSE(iter.Advance());  // Test unexpected advance after end.
+  EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakWide32) {
+  // U+1D49C MATHEMATICAL SCRIPT CAPITAL A
+  const char very_wide_char[] = "\xF0\x9D\x92\x9C";
+  const string16 str(
+      UTF8ToUTF16(base::StringPrintf("%s a", very_wide_char)));
+  const string16 very_wide_word(str.substr(0, 2));
+
+  BreakIterator iter(str, BreakIterator::BREAK_WORD);
+  ASSERT_TRUE(iter.Init());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_TRUE(iter.IsWord());
+  EXPECT_EQ(very_wide_word, iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16(" "), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_TRUE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("a"), iter.GetString());
+  EXPECT_FALSE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_FALSE(iter.Advance());  // Test unexpected advance after end.
+  EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakSpaceEmpty) {
+  string16 empty;
+  BreakIterator iter(empty, BreakIterator::BREAK_SPACE);
+  ASSERT_TRUE(iter.Init());
+  EXPECT_FALSE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_FALSE(iter.Advance());  // Test unexpected advance after end.
+  EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakSpace) {
+  string16 str(UTF8ToUTF16(" foo bar! \npouet boom"));
+  BreakIterator iter(str, BreakIterator::BREAK_SPACE);
+  ASSERT_TRUE(iter.Init());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16(" "), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("foo "), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("bar! \n"), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("pouet "), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("boom"), iter.GetString());
+  EXPECT_FALSE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_FALSE(iter.Advance());  // Test unexpected advance after end.
+  EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakSpaceSP) {
+  string16 str(UTF8ToUTF16(" foo bar! \npouet boom "));
+  BreakIterator iter(str, BreakIterator::BREAK_SPACE);
+  ASSERT_TRUE(iter.Init());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16(" "), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("foo "), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("bar! \n"), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("pouet "), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("boom "), iter.GetString());
+  EXPECT_FALSE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_FALSE(iter.Advance());  // Test unexpected advance after end.
+  EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakSpacekWide16) {
+  // Two Greek words.
+  const string16 str(WideToUTF16(
+      L"\x03a0\x03b1\x03b3\x03ba\x03cc\x03c3\x03bc\x03b9"
+      L"\x03bf\x03c2\x0020\x0399\x03c3\x03c4\x03cc\x03c2"));
+  const string16 word1(str.substr(0, 11));
+  const string16 word2(str.substr(11, 5));
+  BreakIterator iter(str, BreakIterator::BREAK_SPACE);
+  ASSERT_TRUE(iter.Init());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(word1, iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(word2, iter.GetString());
+  EXPECT_FALSE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_FALSE(iter.Advance());  // Test unexpected advance after end.
+  EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakSpaceWide32) {
+  // U+1D49C MATHEMATICAL SCRIPT CAPITAL A
+  const char very_wide_char[] = "\xF0\x9D\x92\x9C";
+  const string16 str(
+      UTF8ToUTF16(base::StringPrintf("%s a", very_wide_char)));
+  const string16 very_wide_word(str.substr(0, 3));
+
+  BreakIterator iter(str, BreakIterator::BREAK_SPACE);
+  ASSERT_TRUE(iter.Init());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(very_wide_word, iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("a"), iter.GetString());
+  EXPECT_FALSE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_FALSE(iter.Advance());  // Test unexpected advance after end.
+  EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakLineEmpty) {
+  string16 empty;
+  BreakIterator iter(empty, BreakIterator::BREAK_NEWLINE);
+  ASSERT_TRUE(iter.Init());
+  EXPECT_FALSE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_FALSE(iter.Advance());   // Test unexpected advance after end.
+  EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakLine) {
+  string16 nl(UTF8ToUTF16("\n"));
+  string16 str(UTF8ToUTF16("\nfoo bar!\n\npouet boom"));
+  BreakIterator iter(str, BreakIterator::BREAK_NEWLINE);
+  ASSERT_TRUE(iter.Init());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(nl, iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("foo bar!\n"), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(nl, iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("pouet boom"), iter.GetString());
+  EXPECT_FALSE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_FALSE(iter.Advance());   // Test unexpected advance after end.
+  EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakLineNL) {
+  string16 nl(UTF8ToUTF16("\n"));
+  string16 str(UTF8ToUTF16("\nfoo bar!\n\npouet boom\n"));
+  BreakIterator iter(str, BreakIterator::BREAK_NEWLINE);
+  ASSERT_TRUE(iter.Init());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(nl, iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("foo bar!\n"), iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(nl, iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("pouet boom\n"), iter.GetString());
+  EXPECT_FALSE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_FALSE(iter.Advance());   // Test unexpected advance after end.
+  EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakLineWide16) {
+  // Two Greek words separated by newline.
+  const string16 str(WideToUTF16(
+      L"\x03a0\x03b1\x03b3\x03ba\x03cc\x03c3\x03bc\x03b9"
+      L"\x03bf\x03c2\x000a\x0399\x03c3\x03c4\x03cc\x03c2"));
+  const string16 line1(str.substr(0, 11));
+  const string16 line2(str.substr(11, 5));
+  BreakIterator iter(str, BreakIterator::BREAK_NEWLINE);
+  ASSERT_TRUE(iter.Init());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(line1, iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(line2, iter.GetString());
+  EXPECT_FALSE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_FALSE(iter.Advance());   // Test unexpected advance after end.
+  EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakLineWide32) {
+  // U+1D49C MATHEMATICAL SCRIPT CAPITAL A
+  const char very_wide_char[] = "\xF0\x9D\x92\x9C";
+  const string16 str(
+      UTF8ToUTF16(base::StringPrintf("%s\na", very_wide_char)));
+  const string16 very_wide_line(str.substr(0, 3));
+  BreakIterator iter(str, BreakIterator::BREAK_NEWLINE);
+  ASSERT_TRUE(iter.Init());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(very_wide_line, iter.GetString());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_EQ(UTF8ToUTF16("a"), iter.GetString());
+  EXPECT_FALSE(iter.Advance());
+  EXPECT_FALSE(iter.IsWord());
+  EXPECT_FALSE(iter.Advance());   // Test unexpected advance after end.
+  EXPECT_FALSE(iter.IsWord());
+}
+
+TEST(BreakIteratorTest, BreakCharacter) {
+  static const wchar_t* kCharacters[] = {
+    // An English word consisting of four ASCII characters.
+    L"w", L"o", L"r", L"d", L" ",
+    // A Hindi word (which means "Hindi") consisting of three Devanagari
+    // characters.
+    L"\x0939\x093F", L"\x0928\x094D", L"\x0926\x0940", L" ",
+    // A Thai word (which means "feel") consisting of three Thai characters.
+    L"\x0E23\x0E39\x0E49", L"\x0E2A\x0E36", L"\x0E01", L" ",
+  };
+  std::vector<string16> characters;
+  string16 text;
+  for (size_t i = 0; i < arraysize(kCharacters); ++i) {
+    characters.push_back(WideToUTF16(kCharacters[i]));
+    text.append(characters.back());
+  }
+  BreakIterator iter(text, BreakIterator::BREAK_CHARACTER);
+  ASSERT_TRUE(iter.Init());
+  for (size_t i = 0; i < arraysize(kCharacters); ++i) {
+    EXPECT_TRUE(iter.Advance());
+    EXPECT_EQ(characters[i], iter.GetString());
+  }
+}
+
+// Test for https://code.google.com/p/chromium/issues/detail?id=411213
+// We should be able to get valid substrings with GetString() function
+// after setting new content by calling SetText().
+TEST(BreakIteratorTest, GetStringAfterSetText) {
+  const string16 initial_string(ASCIIToUTF16("str"));
+  BreakIterator iter(initial_string, BreakIterator::BREAK_WORD);
+  ASSERT_TRUE(iter.Init());
+
+  const string16 long_string(ASCIIToUTF16("another,string"));
+  EXPECT_TRUE(iter.SetText(long_string.c_str(), long_string.size()));
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_TRUE(iter.Advance());  // Advance to ',' in |long_string|
+
+  // Check that the current position is out of bounds of the |initial_string|.
+  EXPECT_LT(initial_string.size(), iter.pos());
+
+  // Check that we can get a valid substring of |long_string|.
+  EXPECT_EQ(ASCIIToUTF16(","), iter.GetString());
+}
+
+TEST(BreakIteratorTest, GetStringPiece) {
+  const string16 initial_string(ASCIIToUTF16("some string"));
+  BreakIterator iter(initial_string, BreakIterator::BREAK_WORD);
+  ASSERT_TRUE(iter.Init());
+
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_EQ(iter.GetString(), iter.GetStringPiece().as_string());
+  EXPECT_EQ(StringPiece16(ASCIIToUTF16("some")), iter.GetStringPiece());
+
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_TRUE(iter.Advance());
+  EXPECT_EQ(iter.GetString(), iter.GetStringPiece().as_string());
+  EXPECT_EQ(StringPiece16(ASCIIToUTF16("string")), iter.GetStringPiece());
+}
+
+}  // namespace i18n
+}  // namespace base
diff --git a/base/i18n/build_utf8_validator_tables.cc b/base/i18n/build_utf8_validator_tables.cc
new file mode 100644
index 0000000..ae5b1a7
--- /dev/null
+++ b/base/i18n/build_utf8_validator_tables.cc
@@ -0,0 +1,466 @@
+// 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.
+
+// Create a state machine for validating UTF-8. The algorithm in brief:
+// 1. Convert the complete unicode range of code points, except for the
+//    surrogate code points, to an ordered array of sequences of bytes in
+//    UTF-8.
+// 2. Convert individual bytes to ranges, starting from the right of each byte
+//    sequence. For each range, ensure the bytes on the left and the ranges
+//    on the right are the identical.
+// 3. Convert the resulting list of ranges into a state machine, collapsing
+//    identical states.
+// 4. Convert the state machine to an array of bytes.
+// 5. Output as a C++ file.
+//
+// To use:
+//  $ ninja -C out/Release build_utf8_validator_tables
+//  $ out/Release/build_utf8_validator_tables
+//                                   --output=base/i18n/utf8_validator_tables.cc
+//  $ git add base/i18n/utf8_validator_tables.cc
+//
+// Because the table is not expected to ever change, it is checked into the
+// repository rather than being regenerated at build time.
+//
+// This code uses type uint8 throughout to represent bytes, to avoid
+// signed/unsigned char confusion.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <algorithm>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "third_party/icu/source/common/unicode/utf8.h"
+
+namespace {
+
+const char kHelpText[] =
+    "Usage: build_utf8_validator_tables [ --help ] [ --output=<file> ]\n";
+
+const char kProlog[] =
+    "// Copyright 2013 The Chromium Authors. All rights reserved.\n"
+    "// Use of this source code is governed by a BSD-style license that can "
+    "be\n"
+    "// found in the LICENSE file.\n"
+    "\n"
+    "// This file is auto-generated by build_utf8_validator_tables.\n"
+    "// DO NOT EDIT.\n"
+    "\n"
+    "#include \"base/i18n/utf8_validator_tables.h\"\n"
+    "\n"
+    "namespace base {\n"
+    "namespace internal {\n"
+    "\n"
+    "const uint8 kUtf8ValidatorTables[] = {\n";
+
+const char kEpilog[] =
+    "};\n"
+    "\n"
+    "const size_t kUtf8ValidatorTablesSize = arraysize(kUtf8ValidatorTables);\n"
+    "\n"
+    "}  // namespace internal\n"
+    "}  // namespace base\n";
+
+// Ranges are inclusive at both ends--they represent [from, to]
+class Range {
+ public:
+  // Ranges always start with just one byte.
+  explicit Range(uint8 value) : from_(value), to_(value) {}
+
+  // Range objects are copyable and assignable to be used in STL
+  // containers. Since they only contain non-pointer POD types, the default copy
+  // constructor, assignment operator and destructor will work.
+
+  // Add a byte to the range. We intentionally only support adding a byte at the
+  // end, since that is the only operation the code needs.
+  void AddByte(uint8 to) {
+    CHECK(to == to_ + 1);
+    to_ = to;
+  }
+
+  uint8 from() const { return from_; }
+  uint8 to() const { return to_; }
+
+  bool operator<(const Range& rhs) const {
+    return (from() < rhs.from() || (from() == rhs.from() && to() < rhs.to()));
+  }
+
+  bool operator==(const Range& rhs) const {
+    return from() == rhs.from() && to() == rhs.to();
+  }
+
+ private:
+  uint8 from_;
+  uint8 to_;
+};
+
+// A vector of Ranges is like a simple regular expression--it corresponds to
+// a set of strings of the same length that have bytes in each position in
+// the appropriate range.
+typedef std::vector<Range> StringSet;
+
+// A UTF-8 "character" is represented by a sequence of bytes.
+typedef std::vector<uint8> Character;
+
+// In the second stage of the algorithm, we want to convert a large list of
+// Characters into a small list of StringSets.
+struct Pair {
+  Character character;
+  StringSet set;
+};
+
+typedef std::vector<Pair> PairVector;
+
+// A class to print a table of numbers in the same style as clang-format.
+class TablePrinter {
+ public:
+  explicit TablePrinter(FILE* stream)
+      : stream_(stream), values_on_this_line_(0), current_offset_(0) {}
+
+  void PrintValue(uint8 value) {
+    if (values_on_this_line_ == 0) {
+      fputs("   ", stream_);
+    } else if (values_on_this_line_ == kMaxValuesPerLine) {
+      fprintf(stream_, "  // 0x%02x\n   ", current_offset_);
+      values_on_this_line_ = 0;
+    }
+    fprintf(stream_, " 0x%02x,", static_cast<int>(value));
+    ++values_on_this_line_;
+    ++current_offset_;
+  }
+
+  void NewLine() {
+    while (values_on_this_line_ < kMaxValuesPerLine) {
+      fputs("      ", stream_);
+      ++values_on_this_line_;
+    }
+    fprintf(stream_, "  // 0x%02x\n", current_offset_);
+    values_on_this_line_ = 0;
+  }
+
+ private:
+  // stdio stream. Not owned.
+  FILE* stream_;
+
+  // Number of values so far printed on this line.
+  int values_on_this_line_;
+
+  // Total values printed so far.
+  int current_offset_;
+
+  static const int kMaxValuesPerLine = 8;
+
+  DISALLOW_COPY_AND_ASSIGN(TablePrinter);
+};
+
+// Start by filling a PairVector with characters. The resulting vector goes from
+// "\x00" to "\xf4\x8f\xbf\xbf".
+PairVector InitializeCharacters() {
+  PairVector vector;
+  for (int i = 0; i <= 0x10FFFF; ++i) {
+    if (i >= 0xD800 && i < 0xE000) {
+      // Surrogate codepoints are not permitted. Non-character code points are
+      // explicitly permitted.
+      continue;
+    }
+    uint8 bytes[4];
+    unsigned int offset = 0;
+    UBool is_error = false;
+    U8_APPEND(bytes, offset, arraysize(bytes), i, is_error);
+    DCHECK(!is_error);
+    DCHECK_GT(offset, 0u);
+    DCHECK_LE(offset, arraysize(bytes));
+    Pair pair = {Character(bytes, bytes + offset), StringSet()};
+    vector.push_back(pair);
+  }
+  return vector;
+}
+
+// Construct a new Pair from |character| and the concatenation of |new_range|
+// and |existing_set|, and append it to |pairs|.
+void ConstructPairAndAppend(const Character& character,
+                            const Range& new_range,
+                            const StringSet& existing_set,
+                            PairVector* pairs) {
+  Pair new_pair = {character, StringSet(1, new_range)};
+  new_pair.set.insert(
+      new_pair.set.end(), existing_set.begin(), existing_set.end());
+  pairs->push_back(new_pair);
+}
+
+// Each pass over the PairVector strips one byte off the right-hand-side of the
+// characters and adds a range to the set on the right. For example, the first
+// pass converts the range from "\xe0\xa0\x80" to "\xe0\xa0\xbf" to ("\xe0\xa0",
+// [\x80-\xbf]), then the second pass converts the range from ("\xe0\xa0",
+// [\x80-\xbf]) to ("\xe0\xbf", [\x80-\xbf]) to ("\xe0",
+// [\xa0-\xbf][\x80-\xbf]).
+void MoveRightMostCharToSet(PairVector* pairs) {
+  PairVector new_pairs;
+  PairVector::const_iterator it = pairs->begin();
+  while (it != pairs->end() && it->character.empty()) {
+    new_pairs.push_back(*it);
+    ++it;
+  }
+  CHECK(it != pairs->end());
+  Character unconverted_bytes(it->character.begin(), it->character.end() - 1);
+  Range new_range(it->character.back());
+  StringSet converted = it->set;
+  ++it;
+  while (it != pairs->end()) {
+    const Pair& current_pair = *it++;
+    if (current_pair.character.size() == unconverted_bytes.size() + 1 &&
+        std::equal(unconverted_bytes.begin(),
+                   unconverted_bytes.end(),
+                   current_pair.character.begin()) &&
+        converted == current_pair.set) {
+      // The particular set of UTF-8 codepoints we are validating guarantees
+      // that each byte range will be contiguous. This would not necessarily be
+      // true for an arbitrary set of UTF-8 codepoints.
+      DCHECK_EQ(new_range.to() + 1, current_pair.character.back());
+      new_range.AddByte(current_pair.character.back());
+      continue;
+    }
+    ConstructPairAndAppend(unconverted_bytes, new_range, converted, &new_pairs);
+    unconverted_bytes = Character(current_pair.character.begin(),
+                                  current_pair.character.end() - 1);
+    new_range = Range(current_pair.character.back());
+    converted = current_pair.set;
+  }
+  ConstructPairAndAppend(unconverted_bytes, new_range, converted, &new_pairs);
+  new_pairs.swap(*pairs);
+}
+
+void MoveAllCharsToSets(PairVector* pairs) {
+  // Since each pass of the function moves one character, and UTF-8 sequences
+  // are at most 4 characters long, this simply runs the algorithm four times.
+  for (int i = 0; i < 4; ++i) {
+    MoveRightMostCharToSet(pairs);
+  }
+#if DCHECK_IS_ON()
+  for (PairVector::const_iterator it = pairs->begin(); it != pairs->end();
+       ++it) {
+    DCHECK(it->character.empty());
+  }
+#endif
+}
+
+// Logs the generated string sets in regular-expression style, ie. [\x00-\x7f],
+// [\xc2-\xdf][\x80-\xbf], etc. This can be a useful sanity-check that the
+// algorithm is working. Use the command-line option
+// --vmodule=build_utf8_validator_tables=1 to see this output.
+void LogStringSets(const PairVector& pairs) {
+  for (PairVector::const_iterator pair_it = pairs.begin();
+       pair_it != pairs.end();
+       ++pair_it) {
+    std::string set_as_string;
+    for (StringSet::const_iterator set_it = pair_it->set.begin();
+         set_it != pair_it->set.end();
+         ++set_it) {
+      set_as_string += base::StringPrintf("[\\x%02x-\\x%02x]",
+                                          static_cast<int>(set_it->from()),
+                                          static_cast<int>(set_it->to()));
+    }
+    VLOG(1) << set_as_string;
+  }
+}
+
+// A single state in the state machine is represented by a sorted vector of
+// start bytes and target states. All input bytes in the range between the start
+// byte and the next entry in the vector (or 0xFF) result in a transition to the
+// target state.
+struct StateRange {
+  uint8 from;
+  uint8 target_state;
+};
+
+typedef std::vector<StateRange> State;
+
+// Generates a state where all bytes go to state 1 (invalid). This is also used
+// as an initialiser for other states (since bytes from outside the desired
+// range are invalid).
+State GenerateInvalidState() {
+  const StateRange range = {0, 1};
+  return State(1, range);
+}
+
+// A map from a state (ie. a set of strings which will match from this state) to
+// a number (which is an index into the array of states).
+typedef std::map<StringSet, uint8> StateMap;
+
+// Create a new state corresponding to |set|, add it |states| and |state_map|
+// and return the index it was given in |states|.
+uint8 MakeState(const StringSet& set,
+                std::vector<State>* states,
+                StateMap* state_map) {
+  DCHECK(!set.empty());
+  const Range& range = set.front();
+  const StringSet rest(set.begin() + 1, set.end());
+  const StateMap::const_iterator where = state_map->find(rest);
+  const uint8 target_state = where == state_map->end()
+                                 ? MakeState(rest, states, state_map)
+                                 : where->second;
+  DCHECK_LT(0, range.from());
+  DCHECK_LT(range.to(), 0xFF);
+  const StateRange new_state_initializer[] = {
+      {0, 1}, {range.from(), target_state},
+      {static_cast<uint8>(range.to() + 1), 1}};
+  states->push_back(
+      State(new_state_initializer,
+            new_state_initializer + arraysize(new_state_initializer)));
+  const uint8 new_state_number =
+      base::checked_cast<uint8>(states->size() - 1);
+  CHECK(state_map->insert(std::make_pair(set, new_state_number)).second);
+  return new_state_number;
+}
+
+std::vector<State> GenerateStates(const PairVector& pairs) {
+  // States 0 and 1 are the initial/valid state and invalid state, respectively.
+  std::vector<State> states(2, GenerateInvalidState());
+  StateMap state_map;
+  state_map.insert(std::make_pair(StringSet(), 0));
+  for (PairVector::const_iterator it = pairs.begin(); it != pairs.end(); ++it) {
+    DCHECK(it->character.empty());
+    DCHECK(!it->set.empty());
+    const Range& range = it->set.front();
+    const StringSet rest(it->set.begin() + 1, it->set.end());
+    const StateMap::const_iterator where = state_map.find(rest);
+    const uint8 target_state = where == state_map.end()
+                                   ? MakeState(rest, &states, &state_map)
+                                   : where->second;
+    if (states[0].back().from == range.from()) {
+      DCHECK_EQ(1, states[0].back().target_state);
+      states[0].back().target_state = target_state;
+      DCHECK_LT(range.to(), 0xFF);
+      const StateRange new_range = {static_cast<uint8>(range.to() + 1), 1};
+      states[0].push_back(new_range);
+    } else {
+      DCHECK_LT(range.to(), 0xFF);
+      const StateRange new_range_initializer[] = {{range.from(), target_state},
+           {static_cast<uint8>(range.to() + 1), 1}};
+      states[0]
+          .insert(states[0].end(),
+                  new_range_initializer,
+                  new_range_initializer + arraysize(new_range_initializer));
+    }
+  }
+  return states;
+}
+
+// Output the generated states as a C++ table. Two tricks are used to compact
+// the table: each state in the table starts with a shift value which indicates
+// how many bits we can discard from the right-hand-side of the byte before
+// doing the table lookup. Secondly, only the state-transitions for bytes
+// with the top-bit set are included in the table; bytes without the top-bit set
+// are just ASCII and are handled directly by the code.
+void PrintStates(const std::vector<State>& states, FILE* stream) {
+  // First calculate the start-offset of each state. This allows the state
+  // machine to jump directly to the correct offset, avoiding an extra
+  // indirection. State 0 starts at offset 0.
+  std::vector<uint8> state_offset(1, 0);
+  std::vector<uint8> shifts;
+  uint8 pos = 0;
+
+  for (std::vector<State>::const_iterator state_it = states.begin();
+       state_it != states.end();
+       ++state_it) {
+    // We want to set |shift| to the (0-based) index of the least-significant
+    // set bit in any of the ranges for this state, since this tells us how many
+    // bits we can discard and still determine what range a byte lies in. Sadly
+    // it appears that ffs() is not portable, so we do it clumsily.
+    uint8 shift = 7;
+    for (State::const_iterator range_it = state_it->begin();
+         range_it != state_it->end();
+         ++range_it) {
+      while (shift > 0 && range_it->from % (1 << shift) != 0) {
+        --shift;
+      }
+    }
+    shifts.push_back(shift);
+    pos += 1 + (1 << (7 - shift));
+    state_offset.push_back(pos);
+  }
+
+  DCHECK_EQ(129, state_offset[1]);
+
+  fputs(kProlog, stream);
+  TablePrinter table_printer(stream);
+
+  for (uint8 state_index = 0; state_index < states.size(); ++state_index) {
+    const uint8 shift = shifts[state_index];
+    uint8 next_range = 0;
+    uint8 target_state = 1;
+    fprintf(stream,
+            "    // State %d, offset 0x%02x\n",
+            static_cast<int>(state_index),
+            static_cast<int>(state_offset[state_index]));
+    table_printer.PrintValue(shift);
+    for (int i = 0; i < 0x100; i += (1 << shift)) {
+      if (next_range < states[state_index].size() &&
+          states[state_index][next_range].from == i) {
+        target_state = states[state_index][next_range].target_state;
+        ++next_range;
+      }
+      if (i >= 0x80) {
+        table_printer.PrintValue(state_offset[target_state]);
+      }
+    }
+    table_printer.NewLine();
+  }
+
+  fputs(kEpilog, stream);
+}
+
+}  // namespace
+
+int main(int argc, char* argv[]) {
+  base::CommandLine::Init(argc, argv);
+  logging::LoggingSettings settings;
+  settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
+  logging::InitLogging(settings);
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch("help")) {
+    fwrite(kHelpText, 1, arraysize(kHelpText), stdout);
+    exit(EXIT_SUCCESS);
+  }
+  base::FilePath filename =
+      base::CommandLine::ForCurrentProcess()->GetSwitchValuePath("output");
+
+  FILE* output = stdout;
+  if (!filename.empty()) {
+    output = base::OpenFile(filename, "wb");
+    if (!output)
+      PLOG(FATAL) << "Couldn't open '" << filename.AsUTF8Unsafe()
+                  << "' for writing";
+  }
+
+  // Step 1: Enumerate the characters
+  PairVector pairs = InitializeCharacters();
+  // Step 2: Convert to sets.
+  MoveAllCharsToSets(&pairs);
+  if (VLOG_IS_ON(1)) {
+    LogStringSets(pairs);
+  }
+  // Step 3: Generate states.
+  std::vector<State> states = GenerateStates(pairs);
+  // Step 4/5: Print output
+  PrintStates(states, output);
+
+  if (!filename.empty()) {
+    if (!base::CloseFile(output))
+      PLOG(FATAL) << "Couldn't finish writing '" << filename.AsUTF8Unsafe()
+                  << "'";
+  }
+
+  return EXIT_SUCCESS;
+}
diff --git a/base/i18n/case_conversion.cc b/base/i18n/case_conversion.cc
new file mode 100644
index 0000000..5debc2e
--- /dev/null
+++ b/base/i18n/case_conversion.cc
@@ -0,0 +1,26 @@
+// Copyright (c) 2011 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/i18n/case_conversion.h"
+
+#include "base/strings/string16.h"
+#include "third_party/icu/source/common/unicode/unistr.h"
+
+namespace base {
+namespace i18n {
+
+string16 ToLower(const StringPiece16& string) {
+  icu::UnicodeString unicode_string(string.data(), string.size());
+  unicode_string.toLower();
+  return string16(unicode_string.getBuffer(), unicode_string.length());
+}
+
+string16 ToUpper(const StringPiece16& string) {
+  icu::UnicodeString unicode_string(string.data(), string.size());
+  unicode_string.toUpper();
+  return string16(unicode_string.getBuffer(), unicode_string.length());
+}
+
+}  // namespace i18n
+}  // namespace base
diff --git a/base/i18n/case_conversion.h b/base/i18n/case_conversion.h
new file mode 100644
index 0000000..5d538cc
--- /dev/null
+++ b/base/i18n/case_conversion.h
@@ -0,0 +1,24 @@
+// Copyright (c) 2011 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_I18N_CASE_CONVERSION_H_
+#define BASE_I18N_CASE_CONVERSION_H_
+
+#include "base/i18n/base_i18n_export.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+namespace i18n {
+
+// Returns the lower case equivalent of string. Uses ICU's default locale.
+BASE_I18N_EXPORT string16 ToLower(const StringPiece16& string);
+
+// Returns the upper case equivalent of string. Uses ICU's default locale.
+BASE_I18N_EXPORT string16 ToUpper(const StringPiece16& string);
+
+}  // namespace i18n
+}  // namespace base
+
+#endif  // BASE_I18N_CASE_CONVERSION_H_
diff --git a/base/i18n/case_conversion_unittest.cc b/base/i18n/case_conversion_unittest.cc
new file mode 100644
index 0000000..75e5ad2
--- /dev/null
+++ b/base/i18n/case_conversion_unittest.cc
@@ -0,0 +1,80 @@
+// Copyright (c) 2011 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/i18n/case_conversion.h"
+#include "base/i18n/rtl.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/icu/source/i18n/unicode/usearch.h"
+
+namespace base {
+namespace {
+
+// Test upper and lower case string conversion.
+TEST(CaseConversionTest, UpperLower) {
+  const string16 mixed(ASCIIToUTF16("Text with UPPer & lowER casE."));
+  const string16 expected_lower(ASCIIToUTF16("text with upper & lower case."));
+  const string16 expected_upper(ASCIIToUTF16("TEXT WITH UPPER & LOWER CASE."));
+
+  string16 result = base::i18n::ToLower(mixed);
+  EXPECT_EQ(expected_lower, result);
+
+  result = base::i18n::ToUpper(mixed);
+  EXPECT_EQ(expected_upper, result);
+}
+
+TEST(CaseConversionTest, NonASCII) {
+  const string16 mixed(WideToUTF16(
+      L"\xC4\xD6\xE4\xF6\x20\xCF\xEF\x20\xF7\x25"
+      L"\xA4\x23\x2A\x5E\x60\x40\xA3\x24\x2030\x201A\x7E\x20\x1F07\x1F0F"
+      L"\x20\x1E00\x1E01"));
+  const string16 expected_lower(WideToUTF16(
+      L"\xE4\xF6\xE4\xF6\x20\xEF\xEF"
+      L"\x20\xF7\x25\xA4\x23\x2A\x5E\x60\x40\xA3\x24\x2030\x201A\x7E\x20\x1F07"
+      L"\x1F07\x20\x1E01\x1E01"));
+  const string16 expected_upper(WideToUTF16(
+      L"\xC4\xD6\xC4\xD6\x20\xCF\xCF"
+      L"\x20\xF7\x25\xA4\x23\x2A\x5E\x60\x40\xA3\x24\x2030\x201A\x7E\x20\x1F0F"
+      L"\x1F0F\x20\x1E00\x1E00"));
+
+  string16 result = base::i18n::ToLower(mixed);
+  EXPECT_EQ(expected_lower, result);
+
+  result = base::i18n::ToUpper(mixed);
+  EXPECT_EQ(expected_upper, result);
+}
+
+TEST(CaseConversionTest, TurkishLocaleConversion) {
+  const string16 mixed(WideToUTF16(L"\x49\x131"));
+  const string16 expected_lower(WideToUTF16(L"\x69\x131"));
+  const string16 expected_upper(WideToUTF16(L"\x49\x49"));
+
+  std::string default_locale(uloc_getDefault());
+  i18n::SetICUDefaultLocale("en_US");
+
+  string16 result = base::i18n::ToLower(mixed);
+  EXPECT_EQ(expected_lower, result);
+
+  result = base::i18n::ToUpper(mixed);
+  EXPECT_EQ(expected_upper, result);
+
+  i18n::SetICUDefaultLocale("tr");
+
+  const string16 expected_lower_turkish(WideToUTF16(L"\x131\x131"));
+  const string16 expected_upper_turkish(WideToUTF16(L"\x49\x49"));
+
+  result = base::i18n::ToLower(mixed);
+  EXPECT_EQ(expected_lower_turkish, result);
+
+  result = base::i18n::ToUpper(mixed);
+  EXPECT_EQ(expected_upper_turkish, result);
+
+  base::i18n::SetICUDefaultLocale(default_locale.data());
+}
+
+}  // namespace
+}  // namespace base
+
+
+
diff --git a/base/i18n/char_iterator.cc b/base/i18n/char_iterator.cc
new file mode 100644
index 0000000..25efc51
--- /dev/null
+++ b/base/i18n/char_iterator.cc
@@ -0,0 +1,82 @@
+// Copyright (c) 2011 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/i18n/char_iterator.h"
+
+#include "third_party/icu/source/common/unicode/utf8.h"
+#include "third_party/icu/source/common/unicode/utf16.h"
+
+namespace base {
+namespace i18n {
+
+UTF8CharIterator::UTF8CharIterator(const std::string* str)
+    : str_(reinterpret_cast<const uint8_t*>(str->data())),
+      len_(str->size()),
+      array_pos_(0),
+      next_pos_(0),
+      char_pos_(0),
+      char_(0) {
+  if (len_)
+    U8_NEXT(str_, next_pos_, len_, char_);
+}
+
+UTF8CharIterator::~UTF8CharIterator() {
+}
+
+bool UTF8CharIterator::Advance() {
+  if (array_pos_ >= len_)
+    return false;
+
+  array_pos_ = next_pos_;
+  char_pos_++;
+  if (next_pos_ < len_)
+    U8_NEXT(str_, next_pos_, len_, char_);
+
+  return true;
+}
+
+UTF16CharIterator::UTF16CharIterator(const string16* str)
+    : str_(reinterpret_cast<const char16*>(str->data())),
+      len_(str->size()),
+      array_pos_(0),
+      next_pos_(0),
+      char_pos_(0),
+      char_(0) {
+  if (len_)
+    ReadChar();
+}
+
+UTF16CharIterator::UTF16CharIterator(const char16* str, size_t str_len)
+    : str_(str),
+      len_(str_len),
+      array_pos_(0),
+      next_pos_(0),
+      char_pos_(0),
+      char_(0) {
+  if (len_)
+    ReadChar();
+}
+
+UTF16CharIterator::~UTF16CharIterator() {
+}
+
+bool UTF16CharIterator::Advance() {
+  if (array_pos_ >= len_)
+    return false;
+
+  array_pos_ = next_pos_;
+  char_pos_++;
+  if (next_pos_ < len_)
+    ReadChar();
+
+  return true;
+}
+
+void UTF16CharIterator::ReadChar() {
+  // This is actually a huge macro, so is worth having in a separate function.
+  U16_NEXT(str_, next_pos_, len_, char_);
+}
+
+}  // namespace i18n
+}  // namespace base
diff --git a/base/i18n/char_iterator.h b/base/i18n/char_iterator.h
new file mode 100644
index 0000000..8174ef4
--- /dev/null
+++ b/base/i18n/char_iterator.h
@@ -0,0 +1,130 @@
+// Copyright (c) 2011 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_I18N_CHAR_ITERATOR_H_
+#define BASE_I18N_CHAR_ITERATOR_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/i18n/base_i18n_export.h"
+#include "base/strings/string16.h"
+
+// The CharIterator classes iterate through the characters in UTF8 and
+// UTF16 strings.  Example usage:
+//
+//   UTF8CharIterator iter(&str);
+//   while (!iter.end()) {
+//     VLOG(1) << iter.get();
+//     iter.Advance();
+//   }
+
+#if defined(OS_WIN)
+typedef unsigned char uint8_t;
+#endif
+
+namespace base {
+namespace i18n {
+
+class BASE_I18N_EXPORT UTF8CharIterator {
+ public:
+  // Requires |str| to live as long as the UTF8CharIterator does.
+  explicit UTF8CharIterator(const std::string* str);
+  ~UTF8CharIterator();
+
+  // Return the starting array index of the current character within the
+  // string.
+  int32 array_pos() const { return array_pos_; }
+
+  // Return the logical index of the current character, independent of the
+  // number of bytes each character takes.
+  int32 char_pos() const { return char_pos_; }
+
+  // Return the current char.
+  int32 get() const { return char_; }
+
+  // Returns true if we're at the end of the string.
+  bool end() const { return array_pos_ == len_; }
+
+  // Advance to the next actual character.  Returns false if we're at the
+  // end of the string.
+  bool Advance();
+
+ private:
+  // The string we're iterating over.
+  const uint8_t* str_;
+
+  // The length of the encoded string.
+  int32 len_;
+
+  // Array index.
+  int32 array_pos_;
+
+  // The next array index.
+  int32 next_pos_;
+
+  // Character index.
+  int32 char_pos_;
+
+  // The current character.
+  int32 char_;
+
+  DISALLOW_COPY_AND_ASSIGN(UTF8CharIterator);
+};
+
+class BASE_I18N_EXPORT UTF16CharIterator {
+ public:
+  // Requires |str| to live as long as the UTF16CharIterator does.
+  explicit UTF16CharIterator(const string16* str);
+  UTF16CharIterator(const char16* str, size_t str_len);
+  ~UTF16CharIterator();
+
+  // Return the starting array index of the current character within the
+  // string.
+  int32 array_pos() const { return array_pos_; }
+
+  // Return the logical index of the current character, independent of the
+  // number of codewords each character takes.
+  int32 char_pos() const { return char_pos_; }
+
+  // Return the current char.
+  int32 get() const { return char_; }
+
+  // Returns true if we're at the end of the string.
+  bool end() const { return array_pos_ == len_; }
+
+  // Advance to the next actual character.  Returns false if we're at the
+  // end of the string.
+  bool Advance();
+
+ private:
+  // Fills in the current character we found and advances to the next
+  // character, updating all flags as necessary.
+  void ReadChar();
+
+  // The string we're iterating over.
+  const char16* str_;
+
+  // The length of the encoded string.
+  int32 len_;
+
+  // Array index.
+  int32 array_pos_;
+
+  // The next array index.
+  int32 next_pos_;
+
+  // Character index.
+  int32 char_pos_;
+
+  // The current character.
+  int32 char_;
+
+  DISALLOW_COPY_AND_ASSIGN(UTF16CharIterator);
+};
+
+}  // namespace i18n
+}  // namespace base
+
+#endif  // BASE_I18N_CHAR_ITERATOR_H_
diff --git a/base/i18n/char_iterator_unittest.cc b/base/i18n/char_iterator_unittest.cc
new file mode 100644
index 0000000..0cf8e6c
--- /dev/null
+++ b/base/i18n/char_iterator_unittest.cc
@@ -0,0 +1,101 @@
+// Copyright (c) 2011 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/i18n/char_iterator.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace i18n {
+
+TEST(CharIteratorsTest, TestUTF8) {
+  std::string empty;
+  UTF8CharIterator empty_iter(&empty);
+  ASSERT_TRUE(empty_iter.end());
+  ASSERT_EQ(0, empty_iter.array_pos());
+  ASSERT_EQ(0, empty_iter.char_pos());
+  ASSERT_FALSE(empty_iter.Advance());
+
+  std::string str("s\303\273r");  // [u with circumflex]
+  UTF8CharIterator iter(&str);
+  ASSERT_FALSE(iter.end());
+  ASSERT_EQ(0, iter.array_pos());
+  ASSERT_EQ(0, iter.char_pos());
+  ASSERT_EQ('s', iter.get());
+  ASSERT_TRUE(iter.Advance());
+
+  ASSERT_FALSE(iter.end());
+  ASSERT_EQ(1, iter.array_pos());
+  ASSERT_EQ(1, iter.char_pos());
+  ASSERT_EQ(251, iter.get());
+  ASSERT_TRUE(iter.Advance());
+
+  ASSERT_FALSE(iter.end());
+  ASSERT_EQ(3, iter.array_pos());
+  ASSERT_EQ(2, iter.char_pos());
+  ASSERT_EQ('r', iter.get());
+  ASSERT_TRUE(iter.Advance());
+
+  ASSERT_TRUE(iter.end());
+  ASSERT_EQ(4, iter.array_pos());
+  ASSERT_EQ(3, iter.char_pos());
+
+  // Don't care what it returns, but this shouldn't crash
+  iter.get();
+
+  ASSERT_FALSE(iter.Advance());
+}
+
+TEST(CharIteratorsTest, TestUTF16) {
+  string16 empty = UTF8ToUTF16("");
+  UTF16CharIterator empty_iter(&empty);
+  ASSERT_TRUE(empty_iter.end());
+  ASSERT_EQ(0, empty_iter.array_pos());
+  ASSERT_EQ(0, empty_iter.char_pos());
+  ASSERT_FALSE(empty_iter.Advance());
+
+  // This test string contains 4 characters:
+  //   x
+  //   u with circumflex - 2 bytes in UTF8, 1 codeword in UTF16
+  //   math double-struck A - 4 bytes in UTF8, 2 codewords in UTF16
+  //   z
+  string16 str = UTF8ToUTF16("x\303\273\360\235\224\270z");
+  UTF16CharIterator iter(&str);
+  ASSERT_FALSE(iter.end());
+  ASSERT_EQ(0, iter.array_pos());
+  ASSERT_EQ(0, iter.char_pos());
+  ASSERT_EQ('x', iter.get());
+  ASSERT_TRUE(iter.Advance());
+
+  ASSERT_FALSE(iter.end());
+  ASSERT_EQ(1, iter.array_pos());
+  ASSERT_EQ(1, iter.char_pos());
+  ASSERT_EQ(251, iter.get());
+  ASSERT_TRUE(iter.Advance());
+
+  ASSERT_FALSE(iter.end());
+  ASSERT_EQ(2, iter.array_pos());
+  ASSERT_EQ(2, iter.char_pos());
+  ASSERT_EQ(120120, iter.get());
+  ASSERT_TRUE(iter.Advance());
+
+  ASSERT_FALSE(iter.end());
+  ASSERT_EQ(4, iter.array_pos());
+  ASSERT_EQ(3, iter.char_pos());
+  ASSERT_EQ('z', iter.get());
+  ASSERT_TRUE(iter.Advance());
+
+  ASSERT_TRUE(iter.end());
+  ASSERT_EQ(5, iter.array_pos());
+  ASSERT_EQ(4, iter.char_pos());
+
+  // Don't care what it returns, but this shouldn't crash
+  iter.get();
+
+  ASSERT_FALSE(iter.Advance());
+}
+
+}  // namespace i18n
+}  // namespace base
diff --git a/base/i18n/file_util_icu.cc b/base/i18n/file_util_icu.cc
new file mode 100644
index 0000000..f6e2c29
--- /dev/null
+++ b/base/i18n/file_util_icu.cc
@@ -0,0 +1,181 @@
+// Copyright (c) 2012 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.
+
+// File utilities that use the ICU library go in this file.
+
+#include "base/i18n/file_util_icu.h"
+
+#include "base/files/file_path.h"
+#include "base/i18n/icu_string_conversions.h"
+#include "base/i18n/string_compare.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/singleton.h"
+#include "base/strings/string_util.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
+#include "third_party/icu/source/common/unicode/uniset.h"
+#include "third_party/icu/source/i18n/unicode/coll.h"
+
+namespace base {
+namespace i18n {
+
+namespace {
+
+class IllegalCharacters {
+ public:
+  static IllegalCharacters* GetInstance() {
+    return Singleton<IllegalCharacters>::get();
+  }
+
+  bool DisallowedEverywhere(UChar32 ucs4) {
+    return !!illegal_anywhere_->contains(ucs4);
+  }
+
+  bool DisallowedLeadingOrTrailing(UChar32 ucs4) {
+    return !!illegal_at_ends_->contains(ucs4);
+  }
+
+  bool IsAllowedName(const string16& s) {
+    return s.empty() || (!!illegal_anywhere_->containsNone(
+                             icu::UnicodeString(s.c_str(), s.size())) &&
+                         !illegal_at_ends_->contains(*s.begin()) &&
+                         !illegal_at_ends_->contains(*s.rbegin()));
+  }
+
+ private:
+  friend class Singleton<IllegalCharacters>;
+  friend struct DefaultSingletonTraits<IllegalCharacters>;
+
+  IllegalCharacters();
+  ~IllegalCharacters() { }
+
+  // set of characters considered invalid anywhere inside a filename.
+  scoped_ptr<icu::UnicodeSet> illegal_anywhere_;
+
+  // set of characters considered invalid at either end of a filename.
+  scoped_ptr<icu::UnicodeSet> illegal_at_ends_;
+
+  DISALLOW_COPY_AND_ASSIGN(IllegalCharacters);
+};
+
+IllegalCharacters::IllegalCharacters() {
+  UErrorCode everywhere_status = U_ZERO_ERROR;
+  UErrorCode ends_status = U_ZERO_ERROR;
+  // Control characters, formatting characters, non-characters, path separators,
+  // and some printable ASCII characters regarded as dangerous ('"*/:<>?\\').
+  // See  http://blogs.msdn.com/michkap/archive/2006/11/03/941420.aspx
+  // and http://msdn2.microsoft.com/en-us/library/Aa365247.aspx
+  // Note that code points in the "Other, Format" (Cf) category are ignored on
+  // HFS+ despite the ZERO_WIDTH_JOINER and ZERO_WIDTH_NON-JOINER being
+  // legitimate in Arabic and some S/SE Asian scripts. In addition tilde (~) is
+  // also excluded due to the possibility of interacting poorly with short
+  // filenames on VFAT. (Related to CVE-2014-9390)
+  illegal_anywhere_.reset(new icu::UnicodeSet(
+      UNICODE_STRING_SIMPLE("[[\"~*/:<>?\\\\|][:Cc:][:Cf:]]"),
+      everywhere_status));
+  illegal_at_ends_.reset(new icu::UnicodeSet(
+      UNICODE_STRING_SIMPLE("[[:WSpace:][.]]"), ends_status));
+  DCHECK(U_SUCCESS(everywhere_status));
+  DCHECK(U_SUCCESS(ends_status));
+
+  // Add non-characters. If this becomes a performance bottleneck by
+  // any chance, do not add these to |set| and change IsFilenameLegal()
+  // to check |ucs4 & 0xFFFEu == 0xFFFEu|, in addiition to calling
+  // IsAllowedName().
+  illegal_anywhere_->add(0xFDD0, 0xFDEF);
+  for (int i = 0; i <= 0x10; ++i) {
+    int plane_base = 0x10000 * i;
+    illegal_anywhere_->add(plane_base + 0xFFFE, plane_base + 0xFFFF);
+  }
+  illegal_anywhere_->freeze();
+  illegal_at_ends_->freeze();
+}
+
+}  // namespace
+
+bool IsFilenameLegal(const string16& file_name) {
+  return IllegalCharacters::GetInstance()->IsAllowedName(file_name);
+}
+
+void ReplaceIllegalCharactersInPath(FilePath::StringType* file_name,
+                                    char replace_char) {
+  IllegalCharacters* illegal = IllegalCharacters::GetInstance();
+
+  DCHECK(!(illegal->DisallowedEverywhere(replace_char)));
+  DCHECK(!(illegal->DisallowedLeadingOrTrailing(replace_char)));
+
+  int cursor = 0;  // The ICU macros expect an int.
+  while (cursor < static_cast<int>(file_name->size())) {
+    int char_begin = cursor;
+    uint32 code_point;
+#if defined(OS_MACOSX)
+    // Mac uses UTF-8 encoding for filenames.
+    U8_NEXT(file_name->data(), cursor, static_cast<int>(file_name->length()),
+            code_point);
+#elif defined(OS_WIN)
+    // Windows uses UTF-16 encoding for filenames.
+    U16_NEXT(file_name->data(), cursor, static_cast<int>(file_name->length()),
+             code_point);
+#elif defined(OS_POSIX)
+    // Linux doesn't actually define an encoding. It basically allows anything
+    // except for a few special ASCII characters.
+    unsigned char cur_char = static_cast<unsigned char>((*file_name)[cursor++]);
+    if (cur_char >= 0x80)
+      continue;
+    code_point = cur_char;
+#else
+    NOTREACHED();
+#endif
+
+    if (illegal->DisallowedEverywhere(code_point) ||
+        ((char_begin == 0 || cursor == static_cast<int>(file_name->length())) &&
+         illegal->DisallowedLeadingOrTrailing(code_point))) {
+      file_name->replace(char_begin, cursor - char_begin, 1, replace_char);
+      // We just made the potentially multi-byte/word char into one that only
+      // takes one byte/word, so need to adjust the cursor to point to the next
+      // character again.
+      cursor = char_begin + 1;
+    }
+  }
+}
+
+bool LocaleAwareCompareFilenames(const FilePath& a, const FilePath& b) {
+  UErrorCode error_code = U_ZERO_ERROR;
+  // Use the default collator. The default locale should have been properly
+  // set by the time this constructor is called.
+  scoped_ptr<icu::Collator> collator(icu::Collator::createInstance(error_code));
+  DCHECK(U_SUCCESS(error_code));
+  // Make it case-sensitive.
+  collator->setStrength(icu::Collator::TERTIARY);
+
+#if defined(OS_WIN)
+  return CompareString16WithCollator(*collator, WideToUTF16(a.value()),
+                                     WideToUTF16(b.value())) == UCOL_LESS;
+
+#elif defined(OS_POSIX)
+  // On linux, the file system encoding is not defined. We assume
+  // SysNativeMBToWide takes care of it.
+  return CompareString16WithCollator(
+             *collator, WideToUTF16(SysNativeMBToWide(a.value().c_str())),
+             WideToUTF16(SysNativeMBToWide(b.value().c_str()))) == UCOL_LESS;
+#else
+  #error Not implemented on your system
+#endif
+}
+
+void NormalizeFileNameEncoding(FilePath* file_name) {
+#if defined(OS_CHROMEOS)
+  std::string normalized_str;
+  if (ConvertToUtf8AndNormalize(file_name->BaseName().value(),
+                                kCodepageUTF8,
+                                &normalized_str)) {
+    *file_name = file_name->DirName().Append(FilePath(normalized_str));
+  }
+#endif
+}
+
+}  // namespace i18n
+}  // namespace base
diff --git a/base/i18n/file_util_icu.h b/base/i18n/file_util_icu.h
new file mode 100644
index 0000000..6d7f2ec
--- /dev/null
+++ b/base/i18n/file_util_icu.h
@@ -0,0 +1,55 @@
+// Copyright (c) 2012 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_I18N_FILE_UTIL_ICU_H_
+#define BASE_I18N_FILE_UTIL_ICU_H_
+
+// File utilities that use the ICU library go in this file.
+
+#include "base/files/file_path.h"
+#include "base/i18n/base_i18n_export.h"
+#include "base/strings/string16.h"
+
+namespace base {
+namespace i18n {
+
+// Returns true if file_name does not have any illegal character. The input
+// param has the same restriction as that for ReplaceIllegalCharacters.
+BASE_I18N_EXPORT bool IsFilenameLegal(const string16& file_name);
+
+// Replaces characters in |file_name| that are illegal for file names with
+// |replace_char|. |file_name| must not be a full or relative path, but just the
+// file name component (since slashes are considered illegal). Any leading or
+// trailing whitespace or periods in |file_name| is also replaced with the
+// |replace_char|.
+//
+// Example:
+//   "bad:file*name?.txt" will be turned into "bad_file_name_.txt" when
+//   |replace_char| is '_'.
+//
+// Warning: Do not use this function as the sole means of sanitizing a filename.
+//   While the resulting filename itself would be legal, it doesn't necessarily
+//   mean that the file will behave safely. On Windows, certain reserved names
+//   refer to devices rather than files (E.g. LPT1), and some filenames could be
+//   interpreted as shell namespace extensions (E.g. Foo.{<GUID>}).
+//
+// TODO(asanka): Move full filename sanitization logic here.
+BASE_I18N_EXPORT void ReplaceIllegalCharactersInPath(
+    FilePath::StringType* file_name,
+    char replace_char);
+
+// Compares two filenames using the current locale information. This can be
+// used to sort directory listings. It behaves like "operator<" for use in
+// std::sort.
+BASE_I18N_EXPORT bool LocaleAwareCompareFilenames(const FilePath& a,
+                                                  const FilePath& b);
+
+// Calculates the canonical file-system representation of |file_name| base name.
+// Modifies |file_name| in place. No-op if not on ChromeOS.
+BASE_I18N_EXPORT void NormalizeFileNameEncoding(FilePath* file_name);
+
+}  // namespace i18n
+}  // namespace base
+
+#endif  // BASE_I18N_FILE_UTIL_ICU_H_
diff --git a/base/i18n/file_util_icu_unittest.cc b/base/i18n/file_util_icu_unittest.cc
new file mode 100644
index 0000000..8fa7f6a
--- /dev/null
+++ b/base/i18n/file_util_icu_unittest.cc
@@ -0,0 +1,136 @@
+// Copyright (c) 2012 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/i18n/file_util_icu.h"
+
+#include "base/files/file_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace base {
+namespace i18n {
+
+// file_util winds up using autoreleased objects on the Mac, so this needs
+// to be a PlatformTest
+class FileUtilICUTest : public PlatformTest {
+};
+
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
+
+// Linux disallows some evil ASCII characters, but passes all non-ASCII.
+static const struct GoodBadPairLinux {
+  const char* bad_name;
+  const char* good_name;
+} kLinuxIllegalCharacterCases[] = {
+  {"bad*\\/file:name?.jpg", "bad---file-name-.jpg"},
+  {"**********::::.txt", "--------------.txt"},
+  {"\xe9\xf0zzzz.\xff", "\xe9\xf0zzzz.\xff"},
+  {" _ ", "-_-"},
+  {".", "-"},
+  {" .( ). ", "-.( ).-"},
+  {"     ", "-   -"},
+};
+
+TEST_F(FileUtilICUTest, ReplaceIllegalCharacersInPathLinuxTest) {
+  for (size_t i = 0; i < arraysize(kLinuxIllegalCharacterCases); ++i) {
+    std::string bad_name(kLinuxIllegalCharacterCases[i].bad_name);
+    ReplaceIllegalCharactersInPath(&bad_name, '-');
+    EXPECT_EQ(kLinuxIllegalCharacterCases[i].good_name, bad_name);
+  }
+}
+
+#endif
+
+// For Mac & Windows, which both do Unicode validation on filenames. These
+// characters are given as wide strings since its more convenient to specify
+// unicode characters. For Mac they should be converted to UTF-8.
+static const struct goodbad_pair {
+  const wchar_t* bad_name;
+  const wchar_t* good_name;
+} kIllegalCharacterCases[] = {
+    {L"bad*file:name?.jpg", L"bad-file-name-.jpg"},
+    {L"**********::::.txt", L"--------------.txt"},
+    // We can't use UCNs (universal character names) for C0/C1 characters and
+    // U+007F, but \x escape is interpreted by MSVC and gcc as we intend.
+    {L"bad\x0003\x0091 file\u200E\u200Fname.png", L"bad-- file--name.png"},
+    {L"bad*file\\?name.jpg", L"bad-file--name.jpg"},
+    {L"\t  bad*file\\name/.jpg", L"-  bad-file-name-.jpg"},
+    {L"this_file_name is okay!.mp3", L"this_file_name is okay!.mp3"},
+    {L"\u4E00\uAC00.mp3", L"\u4E00\uAC00.mp3"},
+    {L"\u0635\u200C\u0644.mp3", L"\u0635-\u0644.mp3"},
+    {L"\U00010330\U00010331.mp3", L"\U00010330\U00010331.mp3"},
+    // Unassigned codepoints are ok.
+    {L"\u0378\U00040001.mp3", L"\u0378\U00040001.mp3"},
+    // Non-characters are not allowed.
+    {L"bad\uFFFFfile\U0010FFFEname.jpg", L"bad-file-name.jpg"},
+    {L"bad\uFDD0file\uFDEFname.jpg", L"bad-file-name.jpg"},
+    // CVE-2014-9390
+    {L"(\u200C.\u200D.\u200E.\u200F.\u202A.\u202B.\u202C.\u202D.\u202E.\u206A."
+     L"\u206B.\u206C.\u206D.\u206F.\uFEFF)",
+     L"(-.-.-.-.-.-.-.-.-.-.-.-.-.-.-)"},
+    {L"config~1", L"config-1"},
+    {L" _ ", L"-_-"},
+    {L" ", L"-"},
+    {L"\u2008.(\u2007).\u3000", L"-.(\u2007).-"},
+    {L"     ", L"-   -"},
+    {L".    ", L"-   -"}
+};
+
+#if defined(OS_WIN) || defined(OS_MACOSX)
+
+TEST_F(FileUtilICUTest, ReplaceIllegalCharactersInPathTest) {
+  for (size_t i = 0; i < arraysize(kIllegalCharacterCases); ++i) {
+#if defined(OS_WIN)
+    std::wstring bad_name(kIllegalCharacterCases[i].bad_name);
+    ReplaceIllegalCharactersInPath(&bad_name, '-');
+    EXPECT_EQ(kIllegalCharacterCases[i].good_name, bad_name);
+#elif defined(OS_MACOSX)
+    std::string bad_name(WideToUTF8(kIllegalCharacterCases[i].bad_name));
+    ReplaceIllegalCharactersInPath(&bad_name, '-');
+    EXPECT_EQ(WideToUTF8(kIllegalCharacterCases[i].good_name), bad_name);
+#endif
+  }
+}
+
+#endif
+
+TEST_F(FileUtilICUTest, IsFilenameLegalTest) {
+  EXPECT_TRUE(IsFilenameLegal(string16()));
+
+  for (const auto& test_case : kIllegalCharacterCases) {
+    string16 bad_name = WideToUTF16(test_case.bad_name);
+    string16 good_name = WideToUTF16(test_case.good_name);
+
+    EXPECT_TRUE(IsFilenameLegal(good_name)) << good_name;
+    if (good_name != bad_name)
+      EXPECT_FALSE(IsFilenameLegal(bad_name)) << bad_name;
+  }
+}
+
+#if defined(OS_CHROMEOS)
+static const struct normalize_name_encoding_test_cases {
+  const char* original_path;
+  const char* normalized_path;
+} kNormalizeFileNameEncodingTestCases[] = {
+  { "foo_na\xcc\x88me.foo", "foo_n\xc3\xa4me.foo"},
+  { "foo_dir_na\xcc\x88me/foo_na\xcc\x88me.foo",
+    "foo_dir_na\xcc\x88me/foo_n\xc3\xa4me.foo"},
+  { "", ""},
+  { "foo_dir_na\xcc\x88me/", "foo_dir_n\xc3\xa4me"}
+};
+
+TEST_F(FileUtilICUTest, NormalizeFileNameEncoding) {
+  for (size_t i = 0; i < arraysize(kNormalizeFileNameEncodingTestCases); i++) {
+    FilePath path(kNormalizeFileNameEncodingTestCases[i].original_path);
+    NormalizeFileNameEncoding(&path);
+    EXPECT_EQ(FilePath(kNormalizeFileNameEncodingTestCases[i].normalized_path),
+              path);
+  }
+}
+
+#endif
+
+}  // namespace i18n
+}  // namespace base
diff --git a/base/i18n/i18n_constants.cc b/base/i18n/i18n_constants.cc
new file mode 100644
index 0000000..7d2f5fc
--- /dev/null
+++ b/base/i18n/i18n_constants.cc
@@ -0,0 +1,13 @@
+// Copyright (c) 2011 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/i18n/i18n_constants.h"
+
+namespace base {
+
+const char kCodepageLatin1[] = "ISO-8859-1";
+const char kCodepageUTF8[] = "UTF-8";
+
+}  // namespace base
+
diff --git a/base/i18n/i18n_constants.h b/base/i18n/i18n_constants.h
new file mode 100644
index 0000000..c1bd87d
--- /dev/null
+++ b/base/i18n/i18n_constants.h
@@ -0,0 +1,21 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_I18N_I18N_CONSTANTS_H_
+#define BASE_I18N_I18N_CONSTANTS_H_
+
+#include "base/i18n/base_i18n_export.h"
+
+namespace base {
+
+// Names of codepages (charsets) understood by icu.
+BASE_I18N_EXPORT extern const char kCodepageLatin1[];  // a.k.a. ISO 8859-1
+BASE_I18N_EXPORT extern const char kCodepageUTF8[];
+
+// The other possible options are UTF-16BE and UTF-16LE, but they are unused in
+// Chromium as of this writing.
+
+}  // namespace base
+
+#endif  // BASE_I18N_I18N_CONSTANTS_H_
diff --git a/base/i18n/icu_encoding_detection.cc b/base/i18n/icu_encoding_detection.cc
new file mode 100644
index 0000000..ccd5cde
--- /dev/null
+++ b/base/i18n/icu_encoding_detection.cc
@@ -0,0 +1,104 @@
+// Copyright (c) 2011 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/i18n/icu_encoding_detection.h"
+
+#include <set>
+
+#include "base/strings/string_util.h"
+#include "third_party/icu/source/i18n/unicode/ucsdet.h"
+
+namespace base {
+
+bool DetectEncoding(const std::string& text, std::string* encoding) {
+  if (IsStringASCII(text)) {
+    *encoding = std::string();
+    return true;
+  }
+
+  UErrorCode status = U_ZERO_ERROR;
+  UCharsetDetector* detector = ucsdet_open(&status);
+  ucsdet_setText(detector, text.data(), static_cast<int32_t>(text.length()),
+                 &status);
+  const UCharsetMatch* match = ucsdet_detect(detector, &status);
+  if (match == NULL)
+    return false;
+  const char* detected_encoding = ucsdet_getName(match, &status);
+  ucsdet_close(detector);
+
+  if (U_FAILURE(status))
+    return false;
+
+  *encoding = detected_encoding;
+  return true;
+}
+
+bool DetectAllEncodings(const std::string& text,
+                        std::vector<std::string>* encodings) {
+  UErrorCode status = U_ZERO_ERROR;
+  UCharsetDetector* detector = ucsdet_open(&status);
+  ucsdet_setText(detector, text.data(), static_cast<int32_t>(text.length()),
+                 &status);
+  int matches_count = 0;
+  const UCharsetMatch** matches = ucsdet_detectAll(detector,
+                                                   &matches_count,
+                                                   &status);
+  if (U_FAILURE(status)) {
+    ucsdet_close(detector);
+    return false;
+  }
+
+  // ICU has some heuristics for encoding detection, such that the more likely
+  // encodings should be returned first. However, it doesn't always return
+  // all encodings that properly decode |text|, so we'll append more encodings
+  // later. To make that efficient, keep track of encodings sniffed in this
+  // first phase.
+  std::set<std::string> sniffed_encodings;
+
+  encodings->clear();
+  for (int i = 0; i < matches_count; i++) {
+    UErrorCode get_name_status = U_ZERO_ERROR;
+    const char* encoding_name = ucsdet_getName(matches[i], &get_name_status);
+
+    // If we failed to get the encoding's name, ignore the error.
+    if (U_FAILURE(get_name_status))
+      continue;
+
+    int32_t confidence = ucsdet_getConfidence(matches[i], &get_name_status);
+
+    // We also treat this error as non-fatal.
+    if (U_FAILURE(get_name_status))
+      continue;
+
+    // A confidence level >= 10 means that the encoding is expected to properly
+    // decode the text. Drop all encodings with lower confidence level.
+    if (confidence < 10)
+      continue;
+
+    encodings->push_back(encoding_name);
+    sniffed_encodings.insert(encoding_name);
+  }
+
+  // Append all encodings not included earlier, in arbitrary order.
+  // TODO(jshin): This shouldn't be necessary, possible ICU bug.
+  // See also http://crbug.com/65917.
+  UEnumeration* detectable_encodings = ucsdet_getAllDetectableCharsets(detector,
+                                                                       &status);
+  int detectable_count = uenum_count(detectable_encodings, &status);
+  for (int i = 0; i < detectable_count; i++) {
+    int name_length;
+    const char* name_raw = uenum_next(detectable_encodings,
+                                      &name_length,
+                                      &status);
+    std::string name(name_raw, name_length);
+    if (sniffed_encodings.find(name) == sniffed_encodings.end())
+      encodings->push_back(name);
+  }
+  uenum_close(detectable_encodings);
+
+  ucsdet_close(detector);
+  return !encodings->empty();
+}
+
+}  // namespace base
diff --git a/base/i18n/icu_encoding_detection.h b/base/i18n/icu_encoding_detection.h
new file mode 100644
index 0000000..6d1e71c
--- /dev/null
+++ b/base/i18n/icu_encoding_detection.h
@@ -0,0 +1,30 @@
+// Copyright (c) 2011 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_I18N_ICU_ENCODING_DETECTION_H_
+#define BASE_I18N_ICU_ENCODING_DETECTION_H_
+
+#include <string>
+#include <vector>
+
+#include "base/i18n/base_i18n_export.h"
+
+namespace base {
+
+// Detect encoding of |text| and put the name of encoding (as returned by ICU)
+// in |encoding|. For ASCII texts |encoding| will be set to an empty string.
+// Returns true on success.
+BASE_I18N_EXPORT bool DetectEncoding(const std::string& text,
+                                     std::string* encoding);
+
+// Detect all possible encodings of |text| and put their names
+// (as returned by ICU) in |encodings|. Returns true on success.
+// Note: this function may return encodings that may fail to decode |text|,
+// the caller is responsible for handling that.
+BASE_I18N_EXPORT bool DetectAllEncodings(const std::string& text,
+                                         std::vector<std::string>* encodings);
+
+}  // namespace base
+
+#endif  // BASE_I18N_ICU_ENCODING_DETECTION_H_
diff --git a/base/i18n/icu_string_conversions.cc b/base/i18n/icu_string_conversions.cc
new file mode 100644
index 0000000..edb31c3
--- /dev/null
+++ b/base/i18n/icu_string_conversions.cc
@@ -0,0 +1,216 @@
+// Copyright (c) 2012 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/i18n/icu_string_conversions.h"
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "third_party/icu/source/common/unicode/ucnv.h"
+#include "third_party/icu/source/common/unicode/ucnv_cb.h"
+#include "third_party/icu/source/common/unicode/ucnv_err.h"
+#include "third_party/icu/source/common/unicode/unorm.h"
+#include "third_party/icu/source/common/unicode/ustring.h"
+
+namespace base {
+
+namespace {
+// ToUnicodeCallbackSubstitute() is based on UCNV_TO_U_CALLBACK_SUBSTITUTE
+// in source/common/ucnv_err.c.
+
+// Copyright (c) 1995-2006 International Business Machines Corporation
+// and others
+//
+// All rights reserved.
+//
+
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, and/or
+// sell copies of the Software, and to permit persons to whom the Software
+// is furnished to do so, provided that the above copyright notice(s) and
+// this permission notice appear in all copies of the Software and that
+// both the above copyright notice(s) and this permission notice appear in
+// supporting documentation.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+// OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
+// INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
+// OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+// OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
+// OR PERFORMANCE OF THIS SOFTWARE.
+//
+// Except as contained in this notice, the name of a copyright holder
+// shall not be used in advertising or otherwise to promote the sale, use
+// or other dealings in this Software without prior written authorization
+// of the copyright holder.
+
+//  ___________________________________________________________________________
+//
+// All trademarks and registered trademarks mentioned herein are the property
+// of their respective owners.
+
+void ToUnicodeCallbackSubstitute(const void* context,
+                                 UConverterToUnicodeArgs *to_args,
+                                 const char* code_units,
+                                 int32_t length,
+                                 UConverterCallbackReason reason,
+                                 UErrorCode * err) {
+  static const UChar kReplacementChar = 0xFFFD;
+  if (reason <= UCNV_IRREGULAR) {
+      if (context == NULL ||
+          (*(reinterpret_cast<const char*>(context)) == 'i' &&
+           reason == UCNV_UNASSIGNED)) {
+        *err = U_ZERO_ERROR;
+        ucnv_cbToUWriteUChars(to_args, &kReplacementChar, 1, 0, err);
+      }
+      // else the caller must have set the error code accordingly.
+  }
+  // else ignore the reset, close and clone calls.
+}
+
+bool ConvertFromUTF16(UConverter* converter, const UChar* uchar_src,
+                      int uchar_len, OnStringConversionError::Type on_error,
+                      std::string* encoded) {
+  int encoded_max_length = UCNV_GET_MAX_BYTES_FOR_STRING(uchar_len,
+      ucnv_getMaxCharSize(converter));
+  encoded->resize(encoded_max_length);
+
+  UErrorCode status = U_ZERO_ERROR;
+
+  // Setup our error handler.
+  switch (on_error) {
+    case OnStringConversionError::FAIL:
+      ucnv_setFromUCallBack(converter, UCNV_FROM_U_CALLBACK_STOP, 0,
+                            NULL, NULL, &status);
+      break;
+    case OnStringConversionError::SKIP:
+    case OnStringConversionError::SUBSTITUTE:
+      ucnv_setFromUCallBack(converter, UCNV_FROM_U_CALLBACK_SKIP, 0,
+                            NULL, NULL, &status);
+      break;
+    default:
+      NOTREACHED();
+  }
+
+  // ucnv_fromUChars returns size not including terminating null
+  int actual_size = ucnv_fromUChars(converter, &(*encoded)[0],
+      encoded_max_length, uchar_src, uchar_len, &status);
+  encoded->resize(actual_size);
+  ucnv_close(converter);
+  if (U_SUCCESS(status))
+    return true;
+  encoded->clear();  // Make sure the output is empty on error.
+  return false;
+}
+
+// Set up our error handler for ToUTF-16 converters
+void SetUpErrorHandlerForToUChars(OnStringConversionError::Type on_error,
+                                  UConverter* converter, UErrorCode* status) {
+  switch (on_error) {
+    case OnStringConversionError::FAIL:
+      ucnv_setToUCallBack(converter, UCNV_TO_U_CALLBACK_STOP, 0,
+                          NULL, NULL, status);
+      break;
+    case OnStringConversionError::SKIP:
+      ucnv_setToUCallBack(converter, UCNV_TO_U_CALLBACK_SKIP, 0,
+                          NULL, NULL, status);
+      break;
+    case OnStringConversionError::SUBSTITUTE:
+      ucnv_setToUCallBack(converter, ToUnicodeCallbackSubstitute, 0,
+                          NULL, NULL, status);
+      break;
+    default:
+      NOTREACHED();
+  }
+}
+
+}  // namespace
+
+// Codepage <-> Wide/UTF-16  ---------------------------------------------------
+
+bool UTF16ToCodepage(const string16& utf16,
+                     const char* codepage_name,
+                     OnStringConversionError::Type on_error,
+                     std::string* encoded) {
+  encoded->clear();
+
+  UErrorCode status = U_ZERO_ERROR;
+  UConverter* converter = ucnv_open(codepage_name, &status);
+  if (!U_SUCCESS(status))
+    return false;
+
+  return ConvertFromUTF16(converter, utf16.c_str(),
+                          static_cast<int>(utf16.length()), on_error, encoded);
+}
+
+bool CodepageToUTF16(const std::string& encoded,
+                     const char* codepage_name,
+                     OnStringConversionError::Type on_error,
+                     string16* utf16) {
+  utf16->clear();
+
+  UErrorCode status = U_ZERO_ERROR;
+  UConverter* converter = ucnv_open(codepage_name, &status);
+  if (!U_SUCCESS(status))
+    return false;
+
+  // Even in the worst case, the maximum length in 2-byte units of UTF-16
+  // output would be at most the same as the number of bytes in input. There
+  // is no single-byte encoding in which a character is mapped to a
+  // non-BMP character requiring two 2-byte units.
+  //
+  // Moreover, non-BMP characters in legacy multibyte encodings
+  // (e.g. EUC-JP, GB18030) take at least 2 bytes. The only exceptions are
+  // BOCU and SCSU, but we don't care about them.
+  size_t uchar_max_length = encoded.length() + 1;
+
+  SetUpErrorHandlerForToUChars(on_error, converter, &status);
+  scoped_ptr<char16[]> buffer(new char16[uchar_max_length]);
+  int actual_size = ucnv_toUChars(converter, buffer.get(),
+      static_cast<int>(uchar_max_length), encoded.data(),
+      static_cast<int>(encoded.length()), &status);
+  ucnv_close(converter);
+  if (!U_SUCCESS(status)) {
+    utf16->clear();  // Make sure the output is empty on error.
+    return false;
+  }
+
+  utf16->assign(buffer.get(), actual_size);
+  return true;
+}
+
+bool ConvertToUtf8AndNormalize(const std::string& text,
+                               const std::string& charset,
+                               std::string* result) {
+  result->clear();
+  string16 utf16;
+  if (!CodepageToUTF16(
+      text, charset.c_str(), OnStringConversionError::FAIL, &utf16))
+    return false;
+
+  UErrorCode status = U_ZERO_ERROR;
+  size_t max_length = utf16.length() + 1;
+  string16 normalized_utf16;
+  scoped_ptr<char16[]> buffer(new char16[max_length]);
+  int actual_length = unorm_normalize(
+      utf16.c_str(), utf16.length(), UNORM_NFC, 0,
+      buffer.get(), static_cast<int>(max_length), &status);
+  if (!U_SUCCESS(status))
+    return false;
+  normalized_utf16.assign(buffer.get(), actual_length);
+
+  return UTF16ToUTF8(normalized_utf16.data(),
+                     normalized_utf16.length(), result);
+}
+
+}  // namespace base
diff --git a/base/i18n/icu_string_conversions.h b/base/i18n/icu_string_conversions.h
new file mode 100644
index 0000000..9135da8
--- /dev/null
+++ b/base/i18n/icu_string_conversions.h
@@ -0,0 +1,57 @@
+// Copyright (c) 2011 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_I18N_ICU_STRING_CONVERSIONS_H_
+#define BASE_I18N_ICU_STRING_CONVERSIONS_H_
+
+#include <string>
+
+#include "base/i18n/base_i18n_export.h"
+#include "base/i18n/i18n_constants.h"
+#include "base/strings/string16.h"
+
+namespace base {
+
+// Defines the error handling modes of UTF16ToCodepage and CodepageToUTF16.
+class OnStringConversionError {
+ public:
+  enum Type {
+    // The function will return failure. The output buffer will be empty.
+    FAIL,
+
+    // The offending characters are skipped and the conversion will proceed as
+    // if they did not exist.
+    SKIP,
+
+    // When converting to Unicode, the offending byte sequences are substituted
+    // by Unicode replacement character (U+FFFD). When converting from Unicode,
+    // this is the same as SKIP.
+    SUBSTITUTE,
+  };
+
+ private:
+  OnStringConversionError();
+};
+
+// Converts between UTF-16 strings and the encoding specified.  If the
+// encoding doesn't exist or the encoding fails (when on_error is FAIL),
+// returns false.
+BASE_I18N_EXPORT bool UTF16ToCodepage(const string16& utf16,
+                                      const char* codepage_name,
+                                      OnStringConversionError::Type on_error,
+                                      std::string* encoded);
+BASE_I18N_EXPORT bool CodepageToUTF16(const std::string& encoded,
+                                      const char* codepage_name,
+                                      OnStringConversionError::Type on_error,
+                                      string16* utf16);
+
+// Converts from any codepage to UTF-8 and ensures the resulting UTF-8 is
+// normalized.
+BASE_I18N_EXPORT bool ConvertToUtf8AndNormalize(const std::string& text,
+                                                const std::string& charset,
+                                                std::string* result);
+
+}  // namespace base
+
+#endif  // BASE_I18N_ICU_STRING_CONVERSIONS_H_
diff --git a/base/i18n/icu_string_conversions_unittest.cc b/base/i18n/icu_string_conversions_unittest.cc
new file mode 100644
index 0000000..821529d
--- /dev/null
+++ b/base/i18n/icu_string_conversions_unittest.cc
@@ -0,0 +1,265 @@
+// Copyright (c) 2011 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 <math.h>
+#include <stdarg.h>
+
+#include <limits>
+#include <sstream>
+
+#include "base/basictypes.h"
+#include "base/format_macros.h"
+#include "base/i18n/icu_string_conversions.h"
+#include "base/logging.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+// Given a null-terminated string of wchar_t with each wchar_t representing
+// a UTF-16 code unit, returns a string16 made up of wchar_t's in the input.
+// Each wchar_t should be <= 0xFFFF and a non-BMP character (> U+FFFF)
+// should be represented as a surrogate pair (two UTF-16 units)
+// *even* where wchar_t is 32-bit (Linux and Mac).
+//
+// This is to help write tests for functions with string16 params until
+// the C++ 0x UTF-16 literal is well-supported by compilers.
+string16 BuildString16(const wchar_t* s) {
+#if defined(WCHAR_T_IS_UTF16)
+  return string16(s);
+#elif defined(WCHAR_T_IS_UTF32)
+  string16 u16;
+  while (*s != 0) {
+    DCHECK_LE(static_cast<unsigned int>(*s), 0xFFFFu);
+    u16.push_back(*s++);
+  }
+  return u16;
+#endif
+}
+
+}  // namespace
+
+// kConverterCodepageCases is not comprehensive. There are a number of cases
+// to add if we really want to have a comprehensive coverage of various
+// codepages and their 'idiosyncrasies'. Currently, the only implementation
+// for CodepageTo* and *ToCodepage uses ICU, which has a very extensive
+// set of tests for the charset conversion. So, we can get away with a
+// relatively small number of cases listed below.
+//
+// Note about |u16_wide| in the following struct.
+// On Windows, the field is always identical to |wide|. On Mac and Linux,
+// it's identical as long as there's no character outside the
+// BMP (<= U+FFFF). When there is, it is different from |wide| and
+// is not a real wide string (UTF-32 string) in that each wchar_t in
+// the string is a UTF-16 code unit zero-extended to be 32-bit
+// even when the code unit belongs to a surrogate pair.
+// For instance, a Unicode string (U+0041 U+010000) is represented as
+// L"\x0041\xD800\xDC00" instead of L"\x0041\x10000".
+// To avoid the clutter, |u16_wide| will be set to NULL
+// if it's identical to |wide| on *all* platforms.
+
+static const struct {
+  const char* codepage_name;
+  const char* encoded;
+  OnStringConversionError::Type on_error;
+  bool success;
+  const wchar_t* wide;
+  const wchar_t* u16_wide;
+} kConvertCodepageCases[] = {
+  // Test a case where the input cannot be decoded, using SKIP, FAIL
+  // and SUBSTITUTE error handling rules. "A7 41" is valid, but "A6" isn't.
+  {"big5",
+   "\xA7\x41\xA6",
+   OnStringConversionError::FAIL,
+   false,
+   L"",
+   NULL},
+  {"big5",
+   "\xA7\x41\xA6",
+   OnStringConversionError::SKIP,
+   true,
+   L"\x4F60",
+   NULL},
+  {"big5",
+   "\xA7\x41\xA6",
+   OnStringConversionError::SUBSTITUTE,
+   true,
+   L"\x4F60\xFFFD",
+   NULL},
+  // Arabic (ISO-8859)
+  {"iso-8859-6",
+   "\xC7\xEE\xE4\xD3\xF1\xEE\xE4\xC7\xE5\xEF" " "
+   "\xD9\xEE\xE4\xEE\xEA\xF2\xE3\xEF\xE5\xF2",
+   OnStringConversionError::FAIL,
+   true,
+   L"\x0627\x064E\x0644\x0633\x0651\x064E\x0644\x0627\x0645\x064F" L" "
+   L"\x0639\x064E\x0644\x064E\x064A\x0652\x0643\x064F\x0645\x0652",
+   NULL},
+  // Chinese Simplified (GB2312)
+  {"gb2312",
+   "\xC4\xE3\xBA\xC3",
+   OnStringConversionError::FAIL,
+   true,
+   L"\x4F60\x597D",
+   NULL},
+  // Chinese (GB18030) : 4 byte sequences mapped to BMP characters
+  {"gb18030",
+   "\x81\x30\x84\x36\xA1\xA7",
+   OnStringConversionError::FAIL,
+   true,
+   L"\x00A5\x00A8",
+   NULL},
+  // Chinese (GB18030) : A 4 byte sequence mapped to plane 2 (U+20000)
+  {"gb18030",
+   "\x95\x32\x82\x36\xD2\xBB",
+   OnStringConversionError::FAIL,
+   true,
+#if defined(WCHAR_T_IS_UTF16)
+   L"\xD840\xDC00\x4E00",
+#elif defined(WCHAR_T_IS_UTF32)
+   L"\x20000\x4E00",
+#endif
+   L"\xD840\xDC00\x4E00"},
+  {"big5",
+   "\xA7\x41\xA6\x6E",
+   OnStringConversionError::FAIL,
+   true,
+   L"\x4F60\x597D",
+   NULL},
+  // Greek (ISO-8859)
+  {"iso-8859-7",
+   "\xE3\xE5\xE9\xDC" " " "\xF3\xEF\xF5",
+   OnStringConversionError::FAIL,
+   true,
+   L"\x03B3\x03B5\x03B9\x03AC" L" " L"\x03C3\x03BF\x03C5",
+   NULL},
+  // Hebrew (Windows)
+  {"windows-1255",
+   "\xF9\xD1\xC8\xEC\xE5\xC9\xED",
+   OnStringConversionError::FAIL,
+   true,
+   L"\x05E9\x05C1\x05B8\x05DC\x05D5\x05B9\x05DD",
+   NULL},
+  // Korean (EUC)
+  {"euc-kr",
+   "\xBE\xC8\xB3\xE7\xC7\xCF\xBC\xBC\xBF\xE4",
+   OnStringConversionError::FAIL,
+   true,
+   L"\xC548\xB155\xD558\xC138\xC694",
+   NULL},
+  // Japanese (EUC)
+  {"euc-jp",
+   "\xA4\xB3\xA4\xF3\xA4\xCB\xA4\xC1\xA4\xCF\xB0\xEC\x8E\xA6",
+   OnStringConversionError::FAIL,
+   true,
+   L"\x3053\x3093\x306B\x3061\x306F\x4E00\xFF66",
+   NULL},
+  // Japanese (ISO-2022)
+  {"iso-2022-jp",
+   "\x1B$B" "\x24\x33\x24\x73\x24\x4B\x24\x41\x24\x4F\x30\x6C" "\x1B(B"
+   "ab" "\x1B(J" "\x5C\x7E#$" "\x1B(B",
+   OnStringConversionError::FAIL,
+   true,
+   L"\x3053\x3093\x306B\x3061\x306F\x4E00" L"ab\x00A5\x203E#$",
+   NULL},
+  // Japanese (Shift-JIS)
+  {"sjis",
+   "\x82\xB1\x82\xF1\x82\xC9\x82\xBF\x82\xCD\x88\xEA\xA6",
+   OnStringConversionError::FAIL,
+   true,
+   L"\x3053\x3093\x306B\x3061\x306F\x4E00\xFF66",
+   NULL},
+  // Russian (KOI8)
+  {"koi8-r",
+   "\xDA\xC4\xD2\xC1\xD7\xD3\xD4\xD7\xD5\xCA\xD4\xC5",
+   OnStringConversionError::FAIL,
+   true,
+   L"\x0437\x0434\x0440\x0430\x0432\x0441\x0442\x0432"
+   L"\x0443\x0439\x0442\x0435",
+   NULL},
+  // Thai (windows-874)
+  {"windows-874",
+   "\xCA\xC7\xD1\xCA\xB4\xD5" "\xA4\xC3\xD1\xBA",
+   OnStringConversionError::FAIL,
+   true,
+   L"\x0E2A\x0E27\x0E31\x0E2A\x0E14\x0E35"
+   L"\x0E04\x0E23\x0e31\x0E1A",
+   NULL},
+};
+
+TEST(ICUStringConversionsTest, ConvertBetweenCodepageAndUTF16) {
+  for (size_t i = 0; i < arraysize(kConvertCodepageCases); ++i) {
+    SCOPED_TRACE(base::StringPrintf(
+                     "Test[%" PRIuS "]: <encoded: %s> <codepage: %s>", i,
+                     kConvertCodepageCases[i].encoded,
+                     kConvertCodepageCases[i].codepage_name));
+
+    string16 utf16;
+    bool success = CodepageToUTF16(kConvertCodepageCases[i].encoded,
+                                   kConvertCodepageCases[i].codepage_name,
+                                   kConvertCodepageCases[i].on_error,
+                                   &utf16);
+    string16 utf16_expected;
+    if (kConvertCodepageCases[i].u16_wide == NULL)
+      utf16_expected = BuildString16(kConvertCodepageCases[i].wide);
+    else
+      utf16_expected = BuildString16(kConvertCodepageCases[i].u16_wide);
+    EXPECT_EQ(kConvertCodepageCases[i].success, success);
+    EXPECT_EQ(utf16_expected, utf16);
+
+    // When decoding was successful and nothing was skipped, we also check the
+    // reverse conversion. See also the corresponding comment in
+    // ConvertBetweenCodepageAndWide.
+    if (success &&
+        kConvertCodepageCases[i].on_error == OnStringConversionError::FAIL) {
+      std::string encoded;
+      success = UTF16ToCodepage(utf16, kConvertCodepageCases[i].codepage_name,
+                                kConvertCodepageCases[i].on_error, &encoded);
+      EXPECT_EQ(kConvertCodepageCases[i].success, success);
+      EXPECT_EQ(kConvertCodepageCases[i].encoded, encoded);
+    }
+  }
+}
+
+static const struct {
+  const char* encoded;
+  const char* codepage_name;
+  bool expected_success;
+  const char* expected_value;
+} kConvertAndNormalizeCases[] = {
+  {"foo-\xe4.html", "iso-8859-1", true, "foo-\xc3\xa4.html"},
+  {"foo-\xe4.html", "iso-8859-7", true, "foo-\xce\xb4.html"},
+  {"foo-\xe4.html", "foo-bar", false, ""},
+  // HTML Encoding spec treats US-ASCII as synonymous with windows-1252
+  {"foo-\xff.html", "ascii", true, "foo-\xc3\xbf.html"},
+  {"foo.html", "ascii", true, "foo.html"},
+  {"foo-a\xcc\x88.html", "utf-8", true, "foo-\xc3\xa4.html"},
+  {"\x95\x32\x82\x36\xD2\xBB", "gb18030", true, "\xF0\xA0\x80\x80\xE4\xB8\x80"},
+  {"\xA7\x41\xA6\x6E", "big5", true, "\xE4\xBD\xA0\xE5\xA5\xBD"},
+  // Windows-1258 does have a combining character at xD2 (which is U+0309).
+  // The sequence of (U+00E2, U+0309) is also encoded as U+1EA9.
+  {"foo\xE2\xD2", "windows-1258", true, "foo\xE1\xBA\xA9"},
+  {"", "iso-8859-1", true, ""},
+};
+TEST(ICUStringConversionsTest, ConvertToUtf8AndNormalize) {
+  std::string result;
+  for (size_t i = 0; i < arraysize(kConvertAndNormalizeCases); ++i) {
+    SCOPED_TRACE(base::StringPrintf(
+                     "Test[%" PRIuS "]: <encoded: %s> <codepage: %s>", i,
+                     kConvertAndNormalizeCases[i].encoded,
+                     kConvertAndNormalizeCases[i].codepage_name));
+
+    bool success = ConvertToUtf8AndNormalize(
+        kConvertAndNormalizeCases[i].encoded,
+        kConvertAndNormalizeCases[i].codepage_name, &result);
+    EXPECT_EQ(kConvertAndNormalizeCases[i].expected_success, success);
+    EXPECT_EQ(kConvertAndNormalizeCases[i].expected_value, result);
+  }
+}
+
+}  // namespace base
diff --git a/base/i18n/icu_util.cc b/base/i18n/icu_util.cc
new file mode 100644
index 0000000..a9f0b12
--- /dev/null
+++ b/base/i18n/icu_util.cc
@@ -0,0 +1,205 @@
+// Copyright (c) 2012 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/i18n/icu_util.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
+#include <string>
+
+#include "base/debug/alias.h"
+#include "base/files/file_path.h"
+#include "base/files/memory_mapped_file.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "base/strings/string_util.h"
+#include "base/strings/sys_string_conversions.h"
+#include "third_party/icu/source/common/unicode/putil.h"
+#include "third_party/icu/source/common/unicode/udata.h"
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+#include "third_party/icu/source/i18n/unicode/timezone.h"
+#endif
+
+#if defined(OS_MACOSX)
+#include "base/mac/foundation_util.h"
+#endif
+
+#define ICU_UTIL_DATA_FILE   0
+#define ICU_UTIL_DATA_SHARED 1
+#define ICU_UTIL_DATA_STATIC 2
+
+namespace base {
+namespace i18n {
+
+// Use an unversioned file name to simplify a icu version update down the road.
+// No need to change the filename in multiple places (gyp files, windows
+// build pkg configurations, etc). 'l' stands for Little Endian.
+// This variable is exported through the header file.
+const char kIcuDataFileName[] = "icudtl.dat";
+#if ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_SHARED
+#define ICU_UTIL_DATA_SYMBOL "icudt" U_ICU_VERSION_SHORT "_dat"
+#if defined(OS_WIN)
+#define ICU_UTIL_DATA_SHARED_MODULE_NAME "icudt.dll"
+#endif
+#endif
+
+namespace {
+
+#if !defined(NDEBUG)
+// Assert that we are not called more than once.  Even though calling this
+// function isn't harmful (ICU can handle it), being called twice probably
+// indicates a programming error.
+#if !defined(OS_NACL)
+bool g_called_once = false;
+#endif
+bool g_check_called_once = true;
+#endif
+}
+
+#if !defined(OS_NACL)
+bool InitializeICUWithFileDescriptor(
+    PlatformFile data_fd,
+    MemoryMappedFile::Region data_region) {
+#if !defined(NDEBUG)
+  DCHECK(!g_check_called_once || !g_called_once);
+  g_called_once = true;
+#endif
+
+#if (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_STATIC)
+  // The ICU data is statically linked.
+  return true;
+#elif (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE)
+  CR_DEFINE_STATIC_LOCAL(MemoryMappedFile, mapped_file, ());
+  if (!mapped_file.IsValid()) {
+    if (!mapped_file.Initialize(File(data_fd), data_region)) {
+      LOG(ERROR) << "Couldn't mmap icu data file";
+      return false;
+    }
+  }
+  UErrorCode err = U_ZERO_ERROR;
+  udata_setCommonData(const_cast<uint8*>(mapped_file.data()), &err);
+  return err == U_ZERO_ERROR;
+#endif // ICU_UTIL_DATA_FILE
+}
+
+
+bool InitializeICU() {
+#if !defined(NDEBUG)
+  DCHECK(!g_check_called_once || !g_called_once);
+  g_called_once = true;
+#endif
+
+  bool result;
+#if (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_SHARED)
+  // We expect to find the ICU data module alongside the current module.
+  FilePath data_path;
+  PathService::Get(DIR_MODULE, &data_path);
+  data_path = data_path.AppendASCII(ICU_UTIL_DATA_SHARED_MODULE_NAME);
+
+  HMODULE module = LoadLibrary(data_path.value().c_str());
+  if (!module) {
+    LOG(ERROR) << "Failed to load " << ICU_UTIL_DATA_SHARED_MODULE_NAME;
+    return false;
+  }
+
+  FARPROC addr = GetProcAddress(module, ICU_UTIL_DATA_SYMBOL);
+  if (!addr) {
+    LOG(ERROR) << ICU_UTIL_DATA_SYMBOL << ": not found in "
+               << ICU_UTIL_DATA_SHARED_MODULE_NAME;
+    return false;
+  }
+
+  UErrorCode err = U_ZERO_ERROR;
+  udata_setCommonData(reinterpret_cast<void*>(addr), &err);
+  result = (err == U_ZERO_ERROR);
+#elif (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_STATIC)
+  // The ICU data is statically linked.
+  result = true;
+#elif (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE)
+  // If the ICU data directory is set, ICU won't actually load the data until
+  // it is needed.  This can fail if the process is sandboxed at that time.
+  // Instead, we map the file in and hand off the data so the sandbox won't
+  // cause any problems.
+
+  // Chrome doesn't normally shut down ICU, so the mapped data shouldn't ever
+  // be released.
+  CR_DEFINE_STATIC_LOCAL(MemoryMappedFile, mapped_file, ());
+  if (!mapped_file.IsValid()) {
+#if !defined(OS_MACOSX)
+    FilePath data_path;
+#if defined(OS_WIN)
+    // The data file will be in the same directory as the current module.
+    bool path_ok = PathService::Get(DIR_MODULE, &data_path);
+    wchar_t tmp_buffer[_MAX_PATH] = {0};
+    wcscpy_s(tmp_buffer, data_path.value().c_str());
+    debug::Alias(tmp_buffer);
+    CHECK(path_ok);  // TODO(scottmg): http://crbug.com/445616
+#elif defined(OS_ANDROID)
+    bool path_ok = PathService::Get(DIR_ANDROID_APP_DATA, &data_path);
+#else
+    // For now, expect the data file to be alongside the executable.
+    // This is sufficient while we work on unit tests, but will eventually
+    // likely live in a data directory.
+    bool path_ok = PathService::Get(DIR_EXE, &data_path);
+#endif
+    DCHECK(path_ok);
+    data_path = data_path.AppendASCII(kIcuDataFileName);
+
+#if defined(OS_WIN)
+    // TODO(scottmg): http://crbug.com/445616
+    wchar_t tmp_buffer2[_MAX_PATH] = {0};
+    wcscpy_s(tmp_buffer2, data_path.value().c_str());
+    debug::Alias(tmp_buffer2);
+#endif
+
+#else
+    // Assume it is in the framework bundle's Resources directory.
+    ScopedCFTypeRef<CFStringRef> data_file_name(
+        SysUTF8ToCFStringRef(kIcuDataFileName));
+    FilePath data_path =
+      mac::PathForFrameworkBundleResource(data_file_name);
+    if (data_path.empty()) {
+      LOG(ERROR) << kIcuDataFileName << " not found in bundle";
+      return false;
+    }
+#endif  // OS check
+    if (!mapped_file.Initialize(data_path)) {
+#if defined(OS_WIN)
+      CHECK(false);  // TODO(scottmg): http://crbug.com/445616
+#endif
+      LOG(ERROR) << "Couldn't mmap " << data_path.AsUTF8Unsafe();
+      return false;
+    }
+  }
+  UErrorCode err = U_ZERO_ERROR;
+  udata_setCommonData(const_cast<uint8*>(mapped_file.data()), &err);
+  result = (err == U_ZERO_ERROR);
+#if defined(OS_WIN)
+  CHECK(result);  // TODO(scottmg): http://crbug.com/445616
+#endif
+#endif
+
+// To respond to the timezone change properly, the default timezone
+// cache in ICU has to be populated on starting up.
+// TODO(jungshik): Some callers do not care about tz at all. If necessary,
+// add a boolean argument to this function to init'd the default tz only
+// when requested.
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+  if (result)
+    scoped_ptr<icu::TimeZone> zone(icu::TimeZone::createDefault());
+#endif
+  return result;
+}
+#endif
+
+void AllowMultipleInitializeCallsForTesting() {
+#if !defined(NDEBUG)
+  g_check_called_once = false;
+#endif
+}
+
+}  // namespace i18n
+}  // namespace base
diff --git a/base/i18n/icu_util.h b/base/i18n/icu_util.h
new file mode 100644
index 0000000..65de0ad
--- /dev/null
+++ b/base/i18n/icu_util.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2011 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_I18N_ICU_UTIL_H_
+#define BASE_I18N_ICU_UTIL_H_
+
+#include "base/files/memory_mapped_file.h"
+#include "base/i18n/base_i18n_export.h"
+#include "build/build_config.h"
+
+namespace base {
+namespace i18n {
+
+BASE_I18N_EXPORT extern const char kIcuDataFileName[];
+
+#if !defined(OS_NACL)
+// Call this function to load ICU's data tables for the current process.  This
+// function should be called before ICU is used.
+BASE_I18N_EXPORT bool InitializeICU();
+
+// Android and html_viewer use a file descriptor passed by browser process to
+// initialize ICU in render processes.
+BASE_I18N_EXPORT bool InitializeICUWithFileDescriptor(
+    PlatformFile data_fd,
+    MemoryMappedFile::Region data_region);
+#endif
+
+// In a test binary, the call above might occur twice.
+BASE_I18N_EXPORT void AllowMultipleInitializeCallsForTesting();
+
+}  // namespace i18n
+}  // namespace base
+
+#endif  // BASE_I18N_ICU_UTIL_H_
diff --git a/base/i18n/icu_util_nacl_win64.cc b/base/i18n/icu_util_nacl_win64.cc
new file mode 100644
index 0000000..9ba8640
--- /dev/null
+++ b/base/i18n/icu_util_nacl_win64.cc
@@ -0,0 +1,15 @@
+// Copyright (c) 2009 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/i18n/icu_util.h"
+
+namespace base {
+namespace i18n {
+
+BASE_I18N_EXPORT bool InitializeICU() {
+  return true;
+}
+
+}  // namespace i18n
+}  // namespace base
diff --git a/base/i18n/number_formatting.cc b/base/i18n/number_formatting.cc
new file mode 100644
index 0000000..47aa14c
--- /dev/null
+++ b/base/i18n/number_formatting.cc
@@ -0,0 +1,87 @@
+// Copyright (c) 2012 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/i18n/number_formatting.h"
+
+#include "base/format_macros.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "third_party/icu/source/common/unicode/ustring.h"
+#include "third_party/icu/source/i18n/unicode/numfmt.h"
+
+namespace base {
+
+namespace {
+
+// A simple wrapper around icu::NumberFormat that allows for resetting it
+// (as LazyInstance does not).
+struct NumberFormatWrapper {
+  NumberFormatWrapper() {
+    Reset();
+  }
+
+  void Reset() {
+    // There's no ICU call to destroy a NumberFormat object other than
+    // operator delete, so use the default Delete, which calls operator delete.
+    // This can cause problems if a different allocator is used by this file
+    // than by ICU.
+    UErrorCode status = U_ZERO_ERROR;
+    number_format.reset(icu::NumberFormat::createInstance(status));
+    DCHECK(U_SUCCESS(status));
+  }
+
+  scoped_ptr<icu::NumberFormat> number_format;
+};
+
+LazyInstance<NumberFormatWrapper> g_number_format_int =
+    LAZY_INSTANCE_INITIALIZER;
+LazyInstance<NumberFormatWrapper> g_number_format_float =
+    LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+string16 FormatNumber(int64 number) {
+  icu::NumberFormat* number_format =
+      g_number_format_int.Get().number_format.get();
+
+  if (!number_format) {
+    // As a fallback, just return the raw number in a string.
+    return UTF8ToUTF16(StringPrintf("%" PRId64, number));
+  }
+  icu::UnicodeString ustr;
+  number_format->format(number, ustr);
+
+  return string16(ustr.getBuffer(), static_cast<size_t>(ustr.length()));
+}
+
+string16 FormatDouble(double number, int fractional_digits) {
+  icu::NumberFormat* number_format =
+      g_number_format_float.Get().number_format.get();
+
+  if (!number_format) {
+    // As a fallback, just return the raw number in a string.
+    return UTF8ToUTF16(StringPrintf("%f", number));
+  }
+  number_format->setMaximumFractionDigits(fractional_digits);
+  number_format->setMinimumFractionDigits(fractional_digits);
+  icu::UnicodeString ustr;
+  number_format->format(number, ustr);
+
+  return string16(ustr.getBuffer(), static_cast<size_t>(ustr.length()));
+}
+
+namespace testing {
+
+void ResetFormatters() {
+  g_number_format_int.Get().Reset();
+  g_number_format_float.Get().Reset();
+}
+
+}  // namespace testing
+
+}  // namespace base
diff --git a/base/i18n/number_formatting.h b/base/i18n/number_formatting.h
new file mode 100644
index 0000000..556f9c2
--- /dev/null
+++ b/base/i18n/number_formatting.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2011 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_I18N_NUMBER_FORMATTING_H_
+#define BASE_I18N_NUMBER_FORMATTING_H_
+
+#include "base/basictypes.h"
+#include "base/i18n/base_i18n_export.h"
+#include "base/strings/string16.h"
+
+namespace base {
+
+// Return a number formatted with separators in the user's locale.
+// Ex: FormatNumber(1234567)
+//         => "1,234,567" in English, "1.234.567" in German
+BASE_I18N_EXPORT string16 FormatNumber(int64 number);
+
+// Return a number formatted with separators in the user's locale.
+// Ex: FormatDouble(1234567.8, 1)
+//         => "1,234,567.8" in English, "1.234.567,8" in German
+BASE_I18N_EXPORT string16 FormatDouble(double number, int fractional_digits);
+
+namespace testing {
+
+// Causes cached formatters to be discarded and recreated. Only useful for
+// testing.
+BASE_I18N_EXPORT void ResetFormatters();
+
+}  // namespace testing
+
+}  // namespace base
+
+#endif  // BASE_I18N_NUMBER_FORMATTING_H_
diff --git a/base/i18n/number_formatting_unittest.cc b/base/i18n/number_formatting_unittest.cc
new file mode 100644
index 0000000..3b0718d
--- /dev/null
+++ b/base/i18n/number_formatting_unittest.cc
@@ -0,0 +1,88 @@
+// Copyright (c) 2011 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 <limits>
+
+#include "base/i18n/number_formatting.h"
+#include "base/i18n/rtl.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+TEST(NumberFormattingTest, FormatNumber) {
+  static const struct {
+    int64 number;
+    const char* expected_english;
+    const char* expected_german;
+  } cases[] = {
+    {0, "0", "0"},
+    {1024, "1,024", "1.024"},
+    {std::numeric_limits<int64>::max(),
+        "9,223,372,036,854,775,807", "9.223.372.036.854.775.807"},
+    {std::numeric_limits<int64>::min(),
+        "-9,223,372,036,854,775,808", "-9.223.372.036.854.775.808"},
+    {-42, "-42", "-42"},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    i18n::SetICUDefaultLocale("en");
+    testing::ResetFormatters();
+    EXPECT_EQ(cases[i].expected_english,
+              UTF16ToUTF8(FormatNumber(cases[i].number)));
+    i18n::SetICUDefaultLocale("de");
+    testing::ResetFormatters();
+    EXPECT_EQ(cases[i].expected_german,
+              UTF16ToUTF8(FormatNumber(cases[i].number)));
+  }
+}
+
+TEST(NumberFormattingTest, FormatDouble) {
+  static const struct {
+    double number;
+    int frac_digits;
+    const char* expected_english;
+    const char* expected_german;
+  } cases[] = {
+    {0.0, 0, "0", "0"},
+#if !defined(OS_ANDROID)
+    // Bionic can't printf negative zero correctly.
+    {-0.0, 4, "-0.0000", "-0,0000"},
+#endif
+    {1024.2, 0, "1,024", "1.024"},
+    {-1024.223, 2, "-1,024.22", "-1.024,22"},
+    {std::numeric_limits<double>::max(), 6,
+        "179,769,313,486,232,000,000,000,000,000,000,000,000,000,000,000,000,"
+        "000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,"
+        "000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,"
+        "000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,"
+        "000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,"
+        "000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,"
+        "000.000000",
+        "179.769.313.486.232.000.000.000.000.000.000.000.000.000.000.000.000."
+        "000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000."
+        "000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000."
+        "000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000."
+        "000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000."
+        "000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000."
+        "000,000000"},
+    {std::numeric_limits<double>::min(), 2, "0.00", "0,00"},
+    {-42.7, 3, "-42.700", "-42,700"},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    i18n::SetICUDefaultLocale("en");
+    testing::ResetFormatters();
+    EXPECT_EQ(cases[i].expected_english,
+              UTF16ToUTF8(FormatDouble(cases[i].number, cases[i].frac_digits)));
+    i18n::SetICUDefaultLocale("de");
+    testing::ResetFormatters();
+    EXPECT_EQ(cases[i].expected_german,
+              UTF16ToUTF8(FormatDouble(cases[i].number, cases[i].frac_digits)));
+  }
+}
+
+}  // namespace
+}  // namespace base
diff --git a/base/i18n/rtl.cc b/base/i18n/rtl.cc
new file mode 100644
index 0000000..1cccae2
--- /dev/null
+++ b/base/i18n/rtl.cc
@@ -0,0 +1,394 @@
+// Copyright (c) 2011 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/i18n/rtl.h"
+
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "third_party/icu/source/common/unicode/locid.h"
+#include "third_party/icu/source/common/unicode/uchar.h"
+#include "third_party/icu/source/common/unicode/uscript.h"
+#include "third_party/icu/source/i18n/unicode/coll.h"
+
+namespace {
+
+// Extract language, country and variant, but ignore keywords.  For example,
+// en-US, ca@valencia, ca-ES@valencia.
+std::string GetLocaleString(const icu::Locale& locale) {
+  const char* language = locale.getLanguage();
+  const char* country = locale.getCountry();
+  const char* variant = locale.getVariant();
+
+  std::string result =
+      (language != NULL && *language != '\0') ? language : "und";
+
+  if (country != NULL && *country != '\0') {
+    result += '-';
+    result += country;
+  }
+
+  if (variant != NULL && *variant != '\0') {
+    std::string variant_str(variant);
+    base::StringToLowerASCII(&variant_str);
+    result += '@' + variant_str;
+  }
+
+  return result;
+}
+
+// Returns LEFT_TO_RIGHT or RIGHT_TO_LEFT if |character| has strong
+// directionality, returns UNKNOWN_DIRECTION if it doesn't. Please refer to
+// http://unicode.org/reports/tr9/ for more information.
+base::i18n::TextDirection GetCharacterDirection(UChar32 character) {
+  // Now that we have the character, we use ICU in order to query for the
+  // appropriate Unicode BiDi character type.
+  int32_t property = u_getIntPropertyValue(character, UCHAR_BIDI_CLASS);
+  if ((property == U_RIGHT_TO_LEFT) ||
+      (property == U_RIGHT_TO_LEFT_ARABIC) ||
+      (property == U_RIGHT_TO_LEFT_EMBEDDING) ||
+      (property == U_RIGHT_TO_LEFT_OVERRIDE)) {
+    return base::i18n::RIGHT_TO_LEFT;
+  } else if ((property == U_LEFT_TO_RIGHT) ||
+             (property == U_LEFT_TO_RIGHT_EMBEDDING) ||
+             (property == U_LEFT_TO_RIGHT_OVERRIDE)) {
+    return base::i18n::LEFT_TO_RIGHT;
+  }
+  return base::i18n::UNKNOWN_DIRECTION;
+}
+
+}  // namespace
+
+namespace base {
+namespace i18n {
+
+// Represents the locale-specific ICU text direction.
+static TextDirection g_icu_text_direction = UNKNOWN_DIRECTION;
+
+// Convert the ICU default locale to a string.
+std::string GetConfiguredLocale() {
+  return GetLocaleString(icu::Locale::getDefault());
+}
+
+// Convert the ICU canonicalized locale to a string.
+std::string GetCanonicalLocale(const std::string& locale) {
+  return GetLocaleString(icu::Locale::createCanonical(locale.c_str()));
+}
+
+// Convert Chrome locale name to ICU locale name
+std::string ICULocaleName(const std::string& locale_string) {
+  // If not Spanish, just return it.
+  if (locale_string.substr(0, 2) != "es")
+    return locale_string;
+  // Expand es to es-ES.
+  if (LowerCaseEqualsASCII(locale_string, "es"))
+    return "es-ES";
+  // Map es-419 (Latin American Spanish) to es-FOO depending on the system
+  // locale.  If it's es-RR other than es-ES, map to es-RR. Otherwise, map
+  // to es-MX (the most populous in Spanish-speaking Latin America).
+  if (LowerCaseEqualsASCII(locale_string, "es-419")) {
+    const icu::Locale& locale = icu::Locale::getDefault();
+    std::string language = locale.getLanguage();
+    const char* country = locale.getCountry();
+    if (LowerCaseEqualsASCII(language, "es") &&
+      !LowerCaseEqualsASCII(country, "es")) {
+        language += '-';
+        language += country;
+        return language;
+    }
+    return "es-MX";
+  }
+  // Currently, Chrome has only "es" and "es-419", but later we may have
+  // more specific "es-RR".
+  return locale_string;
+}
+
+void SetICUDefaultLocale(const std::string& locale_string) {
+  icu::Locale locale(ICULocaleName(locale_string).c_str());
+  UErrorCode error_code = U_ZERO_ERROR;
+  icu::Locale::setDefault(locale, error_code);
+  // This return value is actually bogus because Locale object is
+  // an ID and setDefault seems to always succeed (regardless of the
+  // presence of actual locale data). However,
+  // it does not hurt to have it as a sanity check.
+  DCHECK(U_SUCCESS(error_code));
+  g_icu_text_direction = UNKNOWN_DIRECTION;
+}
+
+bool IsRTL() {
+  return ICUIsRTL();
+}
+
+bool ICUIsRTL() {
+  if (g_icu_text_direction == UNKNOWN_DIRECTION) {
+    const icu::Locale& locale = icu::Locale::getDefault();
+    g_icu_text_direction = GetTextDirectionForLocale(locale.getName());
+  }
+  return g_icu_text_direction == RIGHT_TO_LEFT;
+}
+
+TextDirection GetTextDirectionForLocale(const char* locale_name) {
+  UErrorCode status = U_ZERO_ERROR;
+  ULayoutType layout_dir = uloc_getCharacterOrientation(locale_name, &status);
+  DCHECK(U_SUCCESS(status));
+  // Treat anything other than RTL as LTR.
+  return (layout_dir != ULOC_LAYOUT_RTL) ? LEFT_TO_RIGHT : RIGHT_TO_LEFT;
+}
+
+TextDirection GetFirstStrongCharacterDirection(const string16& text) {
+  const UChar* string = text.c_str();
+  size_t length = text.length();
+  size_t position = 0;
+  while (position < length) {
+    UChar32 character;
+    size_t next_position = position;
+    U16_NEXT(string, next_position, length, character);
+    TextDirection direction = GetCharacterDirection(character);
+    if (direction != UNKNOWN_DIRECTION)
+      return direction;
+    position = next_position;
+  }
+  return LEFT_TO_RIGHT;
+}
+
+TextDirection GetLastStrongCharacterDirection(const string16& text) {
+  const UChar* string = text.c_str();
+  size_t position = text.length();
+  while (position > 0) {
+    UChar32 character;
+    size_t prev_position = position;
+    U16_PREV(string, 0, prev_position, character);
+    TextDirection direction = GetCharacterDirection(character);
+    if (direction != UNKNOWN_DIRECTION)
+      return direction;
+    position = prev_position;
+  }
+  return LEFT_TO_RIGHT;
+}
+
+TextDirection GetStringDirection(const string16& text) {
+  const UChar* string = text.c_str();
+  size_t length = text.length();
+  size_t position = 0;
+
+  TextDirection result(UNKNOWN_DIRECTION);
+  while (position < length) {
+    UChar32 character;
+    size_t next_position = position;
+    U16_NEXT(string, next_position, length, character);
+    TextDirection direction = GetCharacterDirection(character);
+    if (direction != UNKNOWN_DIRECTION) {
+      if (result != UNKNOWN_DIRECTION && result != direction)
+        return UNKNOWN_DIRECTION;
+      result = direction;
+    }
+    position = next_position;
+  }
+
+  // Handle the case of a string not containing any strong directionality
+  // characters defaulting to LEFT_TO_RIGHT.
+  if (result == UNKNOWN_DIRECTION)
+    return LEFT_TO_RIGHT;
+
+  return result;
+}
+
+#if defined(OS_WIN)
+bool AdjustStringForLocaleDirection(string16* text) {
+  if (!IsRTL() || text->empty())
+    return false;
+
+  // Marking the string as LTR if the locale is RTL and the string does not
+  // contain strong RTL characters. Otherwise, mark the string as RTL.
+  bool has_rtl_chars = StringContainsStrongRTLChars(*text);
+  if (!has_rtl_chars)
+    WrapStringWithLTRFormatting(text);
+  else
+    WrapStringWithRTLFormatting(text);
+
+  return true;
+}
+
+bool UnadjustStringForLocaleDirection(string16* text) {
+  if (!IsRTL() || text->empty())
+    return false;
+
+  *text = StripWrappingBidiControlCharacters(*text);
+  return true;
+}
+#else
+bool AdjustStringForLocaleDirection(string16* text) {
+  // On OS X & GTK the directionality of a label is determined by the first
+  // strongly directional character.
+  // However, we want to make sure that in an LTR-language-UI all strings are
+  // left aligned and vice versa.
+  // A problem can arise if we display a string which starts with user input.
+  // User input may be of the opposite directionality to the UI. So the whole
+  // string will be displayed in the opposite directionality, e.g. if we want to
+  // display in an LTR UI [such as US English]:
+  //
+  // EMAN_NOISNETXE is now installed.
+  //
+  // Since EXTENSION_NAME begins with a strong RTL char, the label's
+  // directionality will be set to RTL and the string will be displayed visually
+  // as:
+  //
+  // .is now installed EMAN_NOISNETXE
+  //
+  // In order to solve this issue, we prepend an LRM to the string. An LRM is a
+  // strongly directional LTR char.
+  // We also append an LRM at the end, which ensures that we're in an LTR
+  // context.
+
+  // Unlike Windows, Linux and OS X can correctly display RTL glyphs out of the
+  // box so there is no issue with displaying zero-width bidi control characters
+  // on any system.  Thus no need for the !IsRTL() check here.
+  if (text->empty())
+    return false;
+
+  bool ui_direction_is_rtl = IsRTL();
+
+  bool has_rtl_chars = StringContainsStrongRTLChars(*text);
+  if (!ui_direction_is_rtl && has_rtl_chars) {
+    WrapStringWithRTLFormatting(text);
+    text->insert(static_cast<size_t>(0), static_cast<size_t>(1),
+                 kLeftToRightMark);
+    text->push_back(kLeftToRightMark);
+  } else if (ui_direction_is_rtl && has_rtl_chars) {
+    WrapStringWithRTLFormatting(text);
+    text->insert(static_cast<size_t>(0), static_cast<size_t>(1),
+                 kRightToLeftMark);
+    text->push_back(kRightToLeftMark);
+  } else if (ui_direction_is_rtl) {
+    WrapStringWithLTRFormatting(text);
+    text->insert(static_cast<size_t>(0), static_cast<size_t>(1),
+                 kRightToLeftMark);
+    text->push_back(kRightToLeftMark);
+  } else {
+    return false;
+  }
+
+  return true;
+}
+
+bool UnadjustStringForLocaleDirection(string16* text) {
+  if (text->empty())
+    return false;
+
+  size_t begin_index = 0;
+  char16 begin = text->at(begin_index);
+  if (begin == kLeftToRightMark ||
+      begin == kRightToLeftMark) {
+    ++begin_index;
+  }
+
+  size_t end_index = text->length() - 1;
+  char16 end = text->at(end_index);
+  if (end == kLeftToRightMark ||
+      end == kRightToLeftMark) {
+    --end_index;
+  }
+
+  string16 unmarked_text =
+      text->substr(begin_index, end_index - begin_index + 1);
+  *text = StripWrappingBidiControlCharacters(unmarked_text);
+  return true;
+}
+
+#endif  // !OS_WIN
+
+bool StringContainsStrongRTLChars(const string16& text) {
+  const UChar* string = text.c_str();
+  size_t length = text.length();
+  size_t position = 0;
+  while (position < length) {
+    UChar32 character;
+    size_t next_position = position;
+    U16_NEXT(string, next_position, length, character);
+
+    // Now that we have the character, we use ICU in order to query for the
+    // appropriate Unicode BiDi character type.
+    int32_t property = u_getIntPropertyValue(character, UCHAR_BIDI_CLASS);
+    if ((property == U_RIGHT_TO_LEFT) || (property == U_RIGHT_TO_LEFT_ARABIC))
+      return true;
+
+    position = next_position;
+  }
+
+  return false;
+}
+
+void WrapStringWithLTRFormatting(string16* text) {
+  if (text->empty())
+    return;
+
+  // Inserting an LRE (Left-To-Right Embedding) mark as the first character.
+  text->insert(static_cast<size_t>(0), static_cast<size_t>(1),
+               kLeftToRightEmbeddingMark);
+
+  // Inserting a PDF (Pop Directional Formatting) mark as the last character.
+  text->push_back(kPopDirectionalFormatting);
+}
+
+void WrapStringWithRTLFormatting(string16* text) {
+  if (text->empty())
+    return;
+
+  // Inserting an RLE (Right-To-Left Embedding) mark as the first character.
+  text->insert(static_cast<size_t>(0), static_cast<size_t>(1),
+               kRightToLeftEmbeddingMark);
+
+  // Inserting a PDF (Pop Directional Formatting) mark as the last character.
+  text->push_back(kPopDirectionalFormatting);
+}
+
+void WrapPathWithLTRFormatting(const FilePath& path,
+                               string16* rtl_safe_path) {
+  // Wrap the overall path with LRE-PDF pair which essentialy marks the
+  // string as a Left-To-Right string.
+  // Inserting an LRE (Left-To-Right Embedding) mark as the first character.
+  rtl_safe_path->push_back(kLeftToRightEmbeddingMark);
+#if defined(OS_MACOSX)
+    rtl_safe_path->append(UTF8ToUTF16(path.value()));
+#elif defined(OS_WIN)
+    rtl_safe_path->append(path.value());
+#else  // defined(OS_POSIX) && !defined(OS_MACOSX)
+    std::wstring wide_path = base::SysNativeMBToWide(path.value());
+    rtl_safe_path->append(WideToUTF16(wide_path));
+#endif
+  // Inserting a PDF (Pop Directional Formatting) mark as the last character.
+  rtl_safe_path->push_back(kPopDirectionalFormatting);
+}
+
+string16 GetDisplayStringInLTRDirectionality(const string16& text) {
+  // Always wrap the string in RTL UI (it may be appended to RTL string).
+  // Also wrap strings with an RTL first strong character direction in LTR UI.
+  if (IsRTL() || GetFirstStrongCharacterDirection(text) == RIGHT_TO_LEFT) {
+    string16 text_mutable(text);
+    WrapStringWithLTRFormatting(&text_mutable);
+    return text_mutable;
+  }
+  return text;
+}
+
+string16 StripWrappingBidiControlCharacters(const string16& text) {
+  if (text.empty())
+    return text;
+  size_t begin_index = 0;
+  char16 begin = text[begin_index];
+  if (begin == kLeftToRightEmbeddingMark ||
+      begin == kRightToLeftEmbeddingMark ||
+      begin == kLeftToRightOverride ||
+      begin == kRightToLeftOverride)
+    ++begin_index;
+  size_t end_index = text.length() - 1;
+  if (text[end_index] == kPopDirectionalFormatting)
+    --end_index;
+  return text.substr(begin_index, end_index - begin_index + 1);
+}
+
+}  // namespace i18n
+}  // namespace base
diff --git a/base/i18n/rtl.h b/base/i18n/rtl.h
new file mode 100644
index 0000000..9b9a0dc
--- /dev/null
+++ b/base/i18n/rtl.h
@@ -0,0 +1,149 @@
+// Copyright (c) 2011 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_I18N_RTL_H_
+#define BASE_I18N_RTL_H_
+
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "base/i18n/base_i18n_export.h"
+#include "base/strings/string16.h"
+#include "build/build_config.h"
+
+namespace base {
+
+class FilePath;
+
+namespace i18n {
+
+const char16 kRightToLeftMark = 0x200F;
+const char16 kLeftToRightMark = 0x200E;
+const char16 kLeftToRightEmbeddingMark = 0x202A;
+const char16 kRightToLeftEmbeddingMark = 0x202B;
+const char16 kPopDirectionalFormatting = 0x202C;
+const char16 kLeftToRightOverride = 0x202D;
+const char16 kRightToLeftOverride = 0x202E;
+
+// Locale.java mirrored this enum TextDirection. Please keep in sync.
+enum TextDirection {
+  UNKNOWN_DIRECTION = 0,
+  RIGHT_TO_LEFT = 1,
+  LEFT_TO_RIGHT = 2,
+  TEXT_DIRECTION_NUM_DIRECTIONS = 3,
+};
+
+// Get the locale that the currently running process has been configured to use.
+// The return value is of the form language[-country] (e.g., en-US) where the
+// language is the 2 or 3 letter code from ISO-639.
+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 std::string& locale);
+
+// Sets the default locale of ICU.
+// Once the application locale of Chrome in GetApplicationLocale is determined,
+// the default locale of ICU need to be changed to match the application locale
+// so that ICU functions work correctly in a locale-dependent manner.
+// This is handy in that we don't have to call GetApplicationLocale()
+// everytime we call locale-dependent ICU APIs as long as we make sure
+// that this is called before any locale-dependent API is called.
+BASE_I18N_EXPORT void SetICUDefaultLocale(const std::string& locale_string);
+
+// Returns true if the application text direction is right-to-left.
+BASE_I18N_EXPORT bool IsRTL();
+
+// Returns whether the text direction for the default ICU locale is RTL.  This
+// assumes that SetICUDefaultLocale has been called to set the default locale to
+// the UI locale of Chrome.
+// NOTE: Generally, you should call IsRTL() instead of this.
+BASE_I18N_EXPORT bool ICUIsRTL();
+
+// Returns the text direction for |locale_name|.
+BASE_I18N_EXPORT TextDirection GetTextDirectionForLocale(
+    const char* locale_name);
+
+// Given the string in |text|, returns the directionality of the first or last
+// character with strong directionality in the string. If no character in the
+// text has strong directionality, LEFT_TO_RIGHT is returned. The Bidi
+// character types L, LRE, LRO, R, AL, RLE, and RLO are considered as strong
+// directionality characters. Please refer to http://unicode.org/reports/tr9/
+// for more information.
+BASE_I18N_EXPORT TextDirection GetFirstStrongCharacterDirection(
+    const string16& text);
+BASE_I18N_EXPORT TextDirection GetLastStrongCharacterDirection(
+    const string16& text);
+
+// Given the string in |text|, returns LEFT_TO_RIGHT or RIGHT_TO_LEFT if all the
+// strong directionality characters in the string are of the same
+// directionality. It returns UNKNOWN_DIRECTION if the string contains a mix of
+// LTR and RTL strong directionality characters. Defaults to LEFT_TO_RIGHT if
+// the string does not contain directionality characters. Please refer to
+// http://unicode.org/reports/tr9/ for more information.
+BASE_I18N_EXPORT TextDirection GetStringDirection(const string16& text);
+
+// Given the string in |text|, this function modifies the string in place with
+// the appropriate Unicode formatting marks that mark the string direction
+// (either left-to-right or right-to-left). The function checks both the current
+// locale and the contents of the string in order to determine the direction of
+// the returned string. The function returns true if the string in |text| was
+// properly adjusted.
+//
+// Certain LTR strings are not rendered correctly when the context is RTL. For
+// example, the string "Foo!" will appear as "!Foo" if it is rendered as is in
+// an RTL context. Calling this function will make sure the returned localized
+// string is always treated as a right-to-left string. This is done by
+// inserting certain Unicode formatting marks into the returned string.
+//
+// ** Notes about the Windows version of this function:
+// TODO(idana) bug 6806: this function adjusts the string in question only
+// if the current locale is right-to-left. The function does not take care of
+// the opposite case (an RTL string displayed in an LTR context) since
+// adjusting the string involves inserting Unicode formatting characters that
+// Windows does not handle well unless right-to-left language support is
+// installed. Since the English version of Windows doesn't have right-to-left
+// language support installed by default, inserting the direction Unicode mark
+// results in Windows displaying squares.
+BASE_I18N_EXPORT bool AdjustStringForLocaleDirection(string16* text);
+
+// Undoes the actions of the above function (AdjustStringForLocaleDirection).
+BASE_I18N_EXPORT bool UnadjustStringForLocaleDirection(string16* text);
+
+// Returns true if the string contains at least one character with strong right
+// to left directionality; that is, a character with either R or AL Unicode
+// BiDi character type.
+BASE_I18N_EXPORT bool StringContainsStrongRTLChars(const string16& text);
+
+// Wraps a string with an LRE-PDF pair which essentialy marks the string as a
+// Left-To-Right string. Doing this is useful in order to make sure LTR
+// strings are rendered properly in an RTL context.
+BASE_I18N_EXPORT void WrapStringWithLTRFormatting(string16* text);
+
+// Wraps a string with an RLE-PDF pair which essentialy marks the string as a
+// Right-To-Left string. Doing this is useful in order to make sure RTL
+// strings are rendered properly in an LTR context.
+BASE_I18N_EXPORT void WrapStringWithRTLFormatting(string16* text);
+
+// Wraps file path to get it to display correctly in RTL UI. All filepaths
+// should be passed through this function before display in UI for RTL locales.
+BASE_I18N_EXPORT void WrapPathWithLTRFormatting(const FilePath& path,
+                                                string16* rtl_safe_path);
+
+// Return the string in |text| wrapped with LRE (Left-To-Right Embedding) and
+// PDF (Pop Directional Formatting) marks, if needed for UI display purposes.
+BASE_I18N_EXPORT string16 GetDisplayStringInLTRDirectionality(
+    const string16& text) WARN_UNUSED_RESULT;
+
+// Strip the beginning (U+202A..U+202B, U+202D..U+202E) and/or ending (U+202C)
+// explicit bidi control characters from |text|, if there are any. Otherwise,
+// return the text itself. Explicit bidi control characters display and have
+// semantic effect. They can be deleted so they might not always appear in a
+// pair.
+BASE_I18N_EXPORT string16 StripWrappingBidiControlCharacters(
+    const string16& text) WARN_UNUSED_RESULT;
+
+}  // namespace i18n
+}  // namespace base
+
+#endif  // BASE_I18N_RTL_H_
diff --git a/base/i18n/rtl_unittest.cc b/base/i18n/rtl_unittest.cc
new file mode 100644
index 0000000..87ac87d
--- /dev/null
+++ b/base/i18n/rtl_unittest.cc
@@ -0,0 +1,441 @@
+// Copyright (c) 2011 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/i18n/rtl.h"
+
+#include <algorithm>
+
+#include "base/files/file_path.h"
+#include "base/strings/string_util.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+#include "third_party/icu/source/i18n/unicode/usearch.h"
+
+namespace base {
+namespace i18n {
+
+namespace {
+
+// A test utility function to set the application default text direction.
+void SetRTL(bool rtl) {
+  // Override the current locale/direction.
+  SetICUDefaultLocale(rtl ? "he" : "en");
+  EXPECT_EQ(rtl, IsRTL());
+}
+
+}  // namespace
+
+class RTLTest : public PlatformTest {
+};
+
+TEST_F(RTLTest, GetFirstStrongCharacterDirection) {
+  struct {
+    const wchar_t* text;
+    TextDirection direction;
+  } cases[] = {
+    // Test pure LTR string.
+    { L"foo bar", LEFT_TO_RIGHT },
+    // Test pure RTL string.
+    { L"\x05d0\x05d1\x05d2 \x05d3\x0d4\x05d5", RIGHT_TO_LEFT},
+    // Test bidi string in which the first character with strong directionality
+    // is a character with type L.
+    { L"foo \x05d0 bar", LEFT_TO_RIGHT },
+    // Test bidi string in which the first character with strong directionality
+    // is a character with type R.
+    { L"\x05d0 foo bar", RIGHT_TO_LEFT },
+    // Test bidi string which starts with a character with weak directionality
+    // and in which the first character with strong directionality is a
+    // character with type L.
+    { L"!foo \x05d0 bar", LEFT_TO_RIGHT },
+    // Test bidi string which starts with a character with weak directionality
+    // and in which the first character with strong directionality is a
+    // character with type R.
+    { L",\x05d0 foo bar", RIGHT_TO_LEFT },
+    // Test bidi string in which the first character with strong directionality
+    // is a character with type LRE.
+    { L"\x202a \x05d0 foo  bar", LEFT_TO_RIGHT },
+    // Test bidi string in which the first character with strong directionality
+    // is a character with type LRO.
+    { L"\x202d \x05d0 foo  bar", LEFT_TO_RIGHT },
+    // Test bidi string in which the first character with strong directionality
+    // is a character with type RLE.
+    { L"\x202b foo \x05d0 bar", RIGHT_TO_LEFT },
+    // Test bidi string in which the first character with strong directionality
+    // is a character with type RLO.
+    { L"\x202e foo \x05d0 bar", RIGHT_TO_LEFT },
+    // Test bidi string in which the first character with strong directionality
+    // is a character with type AL.
+    { L"\x0622 foo \x05d0 bar", RIGHT_TO_LEFT },
+    // Test a string without strong directionality characters.
+    { L",!.{}", LEFT_TO_RIGHT },
+    // Test empty string.
+    { L"", LEFT_TO_RIGHT },
+    // Test characters in non-BMP (e.g. Phoenician letters. Please refer to
+    // http://demo.icu-project.org/icu-bin/ubrowse?scr=151&b=10910 for more
+    // information).
+    {
+#if defined(WCHAR_T_IS_UTF32)
+      L" ! \x10910" L"abc 123",
+#elif defined(WCHAR_T_IS_UTF16)
+      L" ! \xd802\xdd10" L"abc 123",
+#else
+#error wchar_t should be either UTF-16 or UTF-32
+#endif
+      RIGHT_TO_LEFT },
+    {
+#if defined(WCHAR_T_IS_UTF32)
+      L" ! \x10401" L"abc 123",
+#elif defined(WCHAR_T_IS_UTF16)
+      L" ! \xd801\xdc01" L"abc 123",
+#else
+#error wchar_t should be either UTF-16 or UTF-32
+#endif
+      LEFT_TO_RIGHT },
+   };
+
+  for (size_t i = 0; i < arraysize(cases); ++i)
+    EXPECT_EQ(cases[i].direction,
+              GetFirstStrongCharacterDirection(WideToUTF16(cases[i].text)));
+}
+
+
+// Note that the cases with LRE, LRO, RLE and RLO are invalid for
+// GetLastStrongCharacterDirection because they should be followed by PDF
+// character.
+TEST_F(RTLTest, GetLastStrongCharacterDirection) {
+  struct {
+    const wchar_t* text;
+    TextDirection direction;
+  } cases[] = {
+    // Test pure LTR string.
+    { L"foo bar", LEFT_TO_RIGHT },
+    // Test pure RTL string.
+    { L"\x05d0\x05d1\x05d2 \x05d3\x0d4\x05d5", RIGHT_TO_LEFT},
+    // Test bidi string in which the last character with strong directionality
+    // is a character with type L.
+    { L"foo \x05d0 bar", LEFT_TO_RIGHT },
+    // Test bidi string in which the last character with strong directionality
+    // is a character with type R.
+    { L"\x05d0 foo bar \x05d3", RIGHT_TO_LEFT },
+    // Test bidi string which ends with a character with weak directionality
+    // and in which the last character with strong directionality is a
+    // character with type L.
+    { L"!foo \x05d0 bar!", LEFT_TO_RIGHT },
+    // Test bidi string which ends with a character with weak directionality
+    // and in which the last character with strong directionality is a
+    // character with type R.
+    { L",\x05d0 foo bar \x05d1,", RIGHT_TO_LEFT },
+    // Test bidi string in which the last character with strong directionality
+    // is a character with type AL.
+    { L"\x0622 foo \x05d0 bar \x0622", RIGHT_TO_LEFT },
+    // Test a string without strong directionality characters.
+    { L",!.{}", LEFT_TO_RIGHT },
+    // Test empty string.
+    { L"", LEFT_TO_RIGHT },
+    // Test characters in non-BMP (e.g. Phoenician letters. Please refer to
+    // http://demo.icu-project.org/icu-bin/ubrowse?scr=151&b=10910 for more
+    // information).
+    {
+#if defined(WCHAR_T_IS_UTF32)
+       L"abc 123" L" ! \x10910 !",
+#elif defined(WCHAR_T_IS_UTF16)
+       L"abc 123" L" ! \xd802\xdd10 !",
+#else
+#error wchar_t should be either UTF-16 or UTF-32
+#endif
+      RIGHT_TO_LEFT },
+    {
+#if defined(WCHAR_T_IS_UTF32)
+       L"abc 123" L" ! \x10401 !",
+#elif defined(WCHAR_T_IS_UTF16)
+       L"abc 123" L" ! \xd801\xdc01 !",
+#else
+#error wchar_t should be either UTF-16 or UTF-32
+#endif
+      LEFT_TO_RIGHT },
+   };
+
+  for (size_t i = 0; i < arraysize(cases); ++i)
+    EXPECT_EQ(cases[i].direction,
+              GetLastStrongCharacterDirection(WideToUTF16(cases[i].text)));
+}
+
+TEST_F(RTLTest, GetStringDirection) {
+  struct {
+    const wchar_t* text;
+    TextDirection direction;
+  } cases[] = {
+    // Test pure LTR string.
+    { L"foobar", LEFT_TO_RIGHT },
+    { L".foobar", LEFT_TO_RIGHT },
+    { L"foo, bar", LEFT_TO_RIGHT },
+    // Test pure LTR with strong directionality characters of type LRE.
+    { L"\x202a\x202a", LEFT_TO_RIGHT },
+    { L".\x202a\x202a", LEFT_TO_RIGHT },
+    { L"\x202a, \x202a", LEFT_TO_RIGHT },
+    // Test pure LTR with strong directionality characters of type LRO.
+    { L"\x202d\x202d", LEFT_TO_RIGHT },
+    { L".\x202d\x202d", LEFT_TO_RIGHT },
+    { L"\x202d, \x202d", LEFT_TO_RIGHT },
+    // Test pure LTR with various types of strong directionality characters.
+    { L"foo \x202a\x202d", LEFT_TO_RIGHT },
+    { L".\x202d foo \x202a", LEFT_TO_RIGHT },
+    { L"\x202a, \x202d foo", LEFT_TO_RIGHT },
+    // Test pure RTL with strong directionality characters of type R.
+    { L"\x05d0\x05d0", RIGHT_TO_LEFT },
+    { L".\x05d0\x05d0", RIGHT_TO_LEFT },
+    { L"\x05d0, \x05d0", RIGHT_TO_LEFT },
+    // Test pure RTL with strong directionality characters of type RLE.
+    { L"\x202b\x202b", RIGHT_TO_LEFT },
+    { L".\x202b\x202b", RIGHT_TO_LEFT },
+    { L"\x202b, \x202b", RIGHT_TO_LEFT },
+    // Test pure RTL with strong directionality characters of type RLO.
+    { L"\x202e\x202e", RIGHT_TO_LEFT },
+    { L".\x202e\x202e", RIGHT_TO_LEFT },
+    { L"\x202e, \x202e", RIGHT_TO_LEFT },
+    // Test pure RTL with strong directionality characters of type AL.
+    { L"\x0622\x0622", RIGHT_TO_LEFT },
+    { L".\x0622\x0622", RIGHT_TO_LEFT },
+    { L"\x0622, \x0622", RIGHT_TO_LEFT },
+    // Test pure RTL with various types of strong directionality characters.
+    { L"\x05d0\x202b\x202e\x0622", RIGHT_TO_LEFT },
+    { L".\x202b\x202e\x0622\x05d0", RIGHT_TO_LEFT },
+    { L"\x0622\x202e, \x202b\x05d0", RIGHT_TO_LEFT },
+    // Test bidi strings.
+    { L"foo \x05d0 bar", UNKNOWN_DIRECTION },
+    { L"\x202b foo bar", UNKNOWN_DIRECTION },
+    { L"!foo \x0622 bar", UNKNOWN_DIRECTION },
+    { L"\x202a\x202b", UNKNOWN_DIRECTION },
+    { L"\x202e\x202d", UNKNOWN_DIRECTION },
+    { L"\x0622\x202a", UNKNOWN_DIRECTION },
+    { L"\x202d\x05d0", UNKNOWN_DIRECTION },
+    // Test a string without strong directionality characters.
+    { L",!.{}", LEFT_TO_RIGHT },
+    // Test empty string.
+    { L"", LEFT_TO_RIGHT },
+    {
+#if defined(WCHAR_T_IS_UTF32)
+      L" ! \x10910" L"abc 123",
+#elif defined(WCHAR_T_IS_UTF16)
+      L" ! \xd802\xdd10" L"abc 123",
+#else
+#error wchar_t should be either UTF-16 or UTF-32
+#endif
+      UNKNOWN_DIRECTION },
+    {
+#if defined(WCHAR_T_IS_UTF32)
+      L" ! \x10401" L"abc 123",
+#elif defined(WCHAR_T_IS_UTF16)
+      L" ! \xd801\xdc01" L"abc 123",
+#else
+#error wchar_t should be either UTF-16 or UTF-32
+#endif
+      LEFT_TO_RIGHT },
+   };
+
+  for (size_t i = 0; i < arraysize(cases); ++i)
+    EXPECT_EQ(cases[i].direction,
+              GetStringDirection(WideToUTF16(cases[i].text)));
+}
+
+TEST_F(RTLTest, WrapPathWithLTRFormatting) {
+  const wchar_t* cases[] = {
+    // Test common path, such as "c:\foo\bar".
+    L"c:/foo/bar",
+    // Test path with file name, such as "c:\foo\bar\test.jpg".
+    L"c:/foo/bar/test.jpg",
+    // Test path ending with punctuation, such as "c:\(foo)\bar.".
+    L"c:/(foo)/bar.",
+    // Test path ending with separator, such as "c:\foo\bar\".
+    L"c:/foo/bar/",
+    // Test path with RTL character.
+    L"c:/\x05d0",
+    // Test path with 2 level RTL directory names.
+    L"c:/\x05d0/\x0622",
+    // Test path with mixed RTL/LTR directory names and ending with punctuation.
+    L"c:/\x05d0/\x0622/(foo)/b.a.r.",
+    // Test path without driver name, such as "/foo/bar/test/jpg".
+    L"/foo/bar/test.jpg",
+    // Test path start with current directory, such as "./foo".
+    L"./foo",
+    // Test path start with parent directory, such as "../foo/bar.jpg".
+    L"../foo/bar.jpg",
+    // Test absolute path, such as "//foo/bar.jpg".
+    L"//foo/bar.jpg",
+    // Test path with mixed RTL/LTR directory names.
+    L"c:/foo/\x05d0/\x0622/\x05d1.jpg",
+    // Test empty path.
+    L""
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    FilePath path;
+#if defined(OS_WIN)
+    std::wstring win_path(cases[i]);
+    std::replace(win_path.begin(), win_path.end(), '/', '\\');
+    path = FilePath(win_path);
+    std::wstring wrapped_expected =
+        std::wstring(L"\x202a") + win_path + L"\x202c";
+#else
+    path = FilePath(base::SysWideToNativeMB(cases[i]));
+    std::wstring wrapped_expected =
+        std::wstring(L"\x202a") + cases[i] + L"\x202c";
+#endif
+    string16 localized_file_path_string;
+    WrapPathWithLTRFormatting(path, &localized_file_path_string);
+
+    std::wstring wrapped_actual = UTF16ToWide(localized_file_path_string);
+    EXPECT_EQ(wrapped_expected, wrapped_actual);
+  }
+}
+
+TEST_F(RTLTest, WrapString) {
+  const wchar_t* cases[] = {
+    L" . ",
+    L"abc",
+    L"a" L"\x5d0\x5d1",
+    L"a" L"\x5d1" L"b",
+    L"\x5d0\x5d1\x5d2",
+    L"\x5d0\x5d1" L"a",
+    L"\x5d0" L"a" L"\x5d1",
+  };
+
+  const bool was_rtl = IsRTL();
+
+  for (size_t i = 0; i < 2; ++i) {
+    // Toggle the application default text direction (to try each direction).
+    SetRTL(!IsRTL());
+
+    string16 empty;
+    WrapStringWithLTRFormatting(&empty);
+    EXPECT_TRUE(empty.empty());
+    WrapStringWithRTLFormatting(&empty);
+    EXPECT_TRUE(empty.empty());
+
+    for (size_t i = 0; i < arraysize(cases); ++i) {
+      string16 input = WideToUTF16(cases[i]);
+      string16 ltr_wrap = input;
+      WrapStringWithLTRFormatting(&ltr_wrap);
+      EXPECT_EQ(ltr_wrap[0], kLeftToRightEmbeddingMark);
+      EXPECT_EQ(ltr_wrap.substr(1, ltr_wrap.length() - 2), input);
+      EXPECT_EQ(ltr_wrap[ltr_wrap.length() -1], kPopDirectionalFormatting);
+
+      string16 rtl_wrap = input;
+      WrapStringWithRTLFormatting(&rtl_wrap);
+      EXPECT_EQ(rtl_wrap[0], kRightToLeftEmbeddingMark);
+      EXPECT_EQ(rtl_wrap.substr(1, rtl_wrap.length() - 2), input);
+      EXPECT_EQ(rtl_wrap[rtl_wrap.length() -1], kPopDirectionalFormatting);
+    }
+  }
+
+  EXPECT_EQ(was_rtl, IsRTL());
+}
+
+TEST_F(RTLTest, GetDisplayStringInLTRDirectionality) {
+  struct {
+    const wchar_t* path;
+    bool wrap_ltr;
+    bool wrap_rtl;
+  } cases[] = {
+    { L"test",                   false, true },
+    { L"test.html",              false, true },
+    { L"\x05d0\x05d1\x05d2",     true,  true },
+    { L"\x05d0\x05d1\x05d2.txt", true,  true },
+    { L"\x05d0" L"abc",          true,  true },
+    { L"\x05d0" L"abc.txt",      true,  true },
+    { L"abc\x05d0\x05d1",        false, true },
+    { L"abc\x05d0\x05d1.jpg",    false, true },
+  };
+
+  const bool was_rtl = IsRTL();
+
+  for (size_t i = 0; i < 2; ++i) {
+    // Toggle the application default text direction (to try each direction).
+    SetRTL(!IsRTL());
+    for (size_t i = 0; i < arraysize(cases); ++i) {
+      string16 input = WideToUTF16(cases[i].path);
+      string16 output = GetDisplayStringInLTRDirectionality(input);
+      // Test the expected wrapping behavior for the current UI directionality.
+      if (IsRTL() ? cases[i].wrap_rtl : cases[i].wrap_ltr)
+        EXPECT_NE(output, input);
+      else
+        EXPECT_EQ(output, input);
+    }
+  }
+
+  EXPECT_EQ(was_rtl, IsRTL());
+}
+
+TEST_F(RTLTest, GetTextDirection) {
+  EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("ar"));
+  EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("ar_EG"));
+  EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("he"));
+  EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("he_IL"));
+  // iw is an obsolete code for Hebrew.
+  EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("iw"));
+  // Although we're not yet localized to Farsi and Urdu, we
+  // do have the text layout direction information for them.
+  EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("fa"));
+  EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("ur"));
+#if 0
+  // Enable these when we include the minimal locale data for Azerbaijani
+  // written in Arabic and Dhivehi. At the moment, our copy of
+  // ICU data does not have entries for them.
+  EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("az_Arab"));
+  // Dhivehi that uses Thaana script.
+  EXPECT_EQ(RIGHT_TO_LEFT, GetTextDirectionForLocale("dv"));
+#endif
+  EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocale("en"));
+  // Chinese in China with '-'.
+  EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocale("zh-CN"));
+  // Filipino : 3-letter code
+  EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocale("fil"));
+  // Russian
+  EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocale("ru"));
+  // Japanese that uses multiple scripts
+  EXPECT_EQ(LEFT_TO_RIGHT, GetTextDirectionForLocale("ja"));
+}
+
+TEST_F(RTLTest, UnadjustStringForLocaleDirection) {
+  // These test strings are borrowed from WrapPathWithLTRFormatting
+  const wchar_t* cases[] = {
+    L"foo bar",
+    L"foo \x05d0 bar",
+    L"\x05d0 foo bar",
+    L"!foo \x05d0 bar",
+    L",\x05d0 foo bar",
+    L"\x202a \x05d0 foo  bar",
+    L"\x202d \x05d0 foo  bar",
+    L"\x202b foo \x05d0 bar",
+    L"\x202e foo \x05d0 bar",
+    L"\x0622 foo \x05d0 bar",
+  };
+
+  const bool was_rtl = IsRTL();
+
+  for (size_t i = 0; i < 2; ++i) {
+    // Toggle the application default text direction (to try each direction).
+    SetRTL(!IsRTL());
+
+    for (size_t i = 0; i < arraysize(cases); ++i) {
+      string16 test_case = WideToUTF16(cases[i]);
+      string16 adjusted_string = test_case;
+
+      if (!AdjustStringForLocaleDirection(&adjusted_string))
+        continue;
+
+      EXPECT_NE(test_case, adjusted_string);
+      EXPECT_TRUE(UnadjustStringForLocaleDirection(&adjusted_string));
+      EXPECT_EQ(test_case, adjusted_string) << " for test case [" << test_case
+                                            << "] with IsRTL() == " << IsRTL();
+    }
+  }
+
+  EXPECT_EQ(was_rtl, IsRTL());
+}
+
+}  // namespace i18n
+}  // namespace base
diff --git a/base/i18n/streaming_utf8_validator.cc b/base/i18n/streaming_utf8_validator.cc
new file mode 100644
index 0000000..c809985
--- /dev/null
+++ b/base/i18n/streaming_utf8_validator.cc
@@ -0,0 +1,59 @@
+// 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 implementation doesn't use ICU. The ICU macros are oriented towards
+// character-at-a-time processing, whereas byte-at-a-time processing is easier
+// with streaming input.
+
+#include "base/i18n/streaming_utf8_validator.h"
+
+#include "base/i18n/utf8_validator_tables.h"
+#include "base/logging.h"
+
+namespace base {
+namespace {
+
+uint8 StateTableLookup(uint8 offset) {
+  DCHECK_LT(offset, internal::kUtf8ValidatorTablesSize);
+  return internal::kUtf8ValidatorTables[offset];
+}
+
+}  // namespace
+
+StreamingUtf8Validator::State StreamingUtf8Validator::AddBytes(const char* data,
+                                                               size_t size) {
+  // Copy |state_| into a local variable so that the compiler doesn't have to be
+  // careful of aliasing.
+  uint8 state = state_;
+  for (const char* p = data; p != data + size; ++p) {
+    if ((*p & 0x80) == 0) {
+      if (state == 0)
+        continue;
+      state = internal::I18N_UTF8_VALIDATOR_INVALID_INDEX;
+      break;
+    }
+    const uint8 shift_amount = StateTableLookup(state);
+    const uint8 shifted_char = (*p & 0x7F) >> shift_amount;
+    state = StateTableLookup(state + shifted_char + 1);
+    // State may be INVALID here, but this code is optimised for the case of
+    // valid UTF-8 and it is more efficient (by about 2%) to not attempt an
+    // early loop exit unless we hit an ASCII character.
+  }
+  state_ = state;
+  return state == 0 ? VALID_ENDPOINT
+      : state == internal::I18N_UTF8_VALIDATOR_INVALID_INDEX
+      ? INVALID
+      : VALID_MIDPOINT;
+}
+
+void StreamingUtf8Validator::Reset() {
+  state_ = 0u;
+}
+
+bool StreamingUtf8Validator::Validate(const std::string& string) {
+  return StreamingUtf8Validator().AddBytes(string.data(), string.size()) ==
+         VALID_ENDPOINT;
+}
+
+}  // namespace base
diff --git a/base/i18n/streaming_utf8_validator.h b/base/i18n/streaming_utf8_validator.h
new file mode 100644
index 0000000..f10ac72
--- /dev/null
+++ b/base/i18n/streaming_utf8_validator.h
@@ -0,0 +1,63 @@
+// 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.
+
+// A streaming validator for UTF-8. Validation is based on the definition in
+// RFC-3629. In particular, it does not reject the invalid characters rejected
+// by base::IsStringUTF8().
+//
+// The implementation detects errors on the first possible byte.
+
+#ifndef BASE_I18N_STREAMING_UTF8_VALIDATOR_H_
+#define BASE_I18N_STREAMING_UTF8_VALIDATOR_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/i18n/base_i18n_export.h"
+
+namespace base {
+
+class BASE_I18N_EXPORT StreamingUtf8Validator {
+ public:
+  // The validator exposes 3 states. It starts in state VALID_ENDPOINT. As it
+  // processes characters it alternates between VALID_ENDPOINT and
+  // VALID_MIDPOINT. If it encounters an invalid byte or UTF-8 sequence the
+  // state changes permanently to INVALID.
+  enum State {
+    VALID_ENDPOINT,
+    VALID_MIDPOINT,
+    INVALID
+  };
+
+  StreamingUtf8Validator() : state_(0u) {}
+  // Trivial destructor intentionally omitted.
+
+  // Validate |size| bytes starting at |data|. If the concatenation of all calls
+  // to AddBytes() since this object was constructed or reset is a valid UTF-8
+  // string, returns VALID_ENDPOINT. If it could be the prefix of a valid UTF-8
+  // string, returns VALID_MIDPOINT. If an invalid byte or UTF-8 sequence was
+  // present, returns INVALID.
+  State AddBytes(const char* data, size_t size);
+
+  // Return the object to a freshly-constructed state so that it can be re-used.
+  void Reset();
+
+  // Validate a complete string using the same criteria. Returns true if the
+  // string only contains complete, valid UTF-8 codepoints.
+  static bool Validate(const std::string& string);
+
+ private:
+  // The current state of the validator. Value 0 is the initial/valid state.
+  // The state is stored as an offset into |kUtf8ValidatorTables|. The special
+  // state |kUtf8InvalidState| is invalid.
+  uint8 state_;
+
+  // This type could be made copyable but there is currently no use-case for
+  // it.
+  DISALLOW_COPY_AND_ASSIGN(StreamingUtf8Validator);
+};
+
+}  // namespace base
+
+#endif  // BASE_I18N_STREAMING_UTF8_VALIDATOR_H_
diff --git a/base/i18n/streaming_utf8_validator_perftest.cc b/base/i18n/streaming_utf8_validator_perftest.cc
new file mode 100644
index 0000000..6b8c17b
--- /dev/null
+++ b/base/i18n/streaming_utf8_validator_perftest.cc
@@ -0,0 +1,238 @@
+// 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.
+
+// All data that is passed through a WebSocket with type "Text" needs to be
+// validated as UTF8. Since this is done on the IO thread, it needs to be
+// reasonably fast.
+
+// We are only interested in the performance on valid UTF8. Invalid UTF8 will
+// result in a connection failure, so is unlikely to become a source of
+// performance issues.
+
+#include "base/i18n/streaming_utf8_validator.h"
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/perf_time_logger.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+// We want to test ranges of valid UTF-8 sequences. These ranges are inclusive.
+// They are intended to be large enough that the validator needs to do
+// meaningful work while being in some sense "realistic" (eg. control characters
+// are not included).
+const char kOneByteSeqRangeStart[] = " ";  // U+0020
+const char kOneByteSeqRangeEnd[] = "~";    // U+007E
+
+const char kTwoByteSeqRangeStart[] = "\xc2\xa0";  // U+00A0 non-breaking space
+const char kTwoByteSeqRangeEnd[] = "\xc9\x8f";    // U+024F small y with stroke
+
+const char kThreeByteSeqRangeStart[] = "\xe3\x81\x82";  // U+3042 Hiragana "a"
+const char kThreeByteSeqRangeEnd[] = "\xe9\xbf\x83";    // U+9FC3 "to blink"
+
+const char kFourByteSeqRangeStart[] = "\xf0\xa0\x80\x8b";  // U+2000B
+const char kFourByteSeqRangeEnd[] = "\xf0\xaa\x9a\xb2";    // U+2A6B2
+
+// The different lengths of strings to test.
+const size_t kTestLengths[] = {1, 32, 256, 32768, 1 << 20};
+
+// Simplest possible byte-at-a-time validator, to provide a baseline
+// for comparison. This is only tried on 1-byte UTF-8 sequences, as
+// the results will not be meaningful with sequences containing
+// top-bit-set bytes.
+bool IsString7Bit(const std::string& s) {
+  for (std::string::const_iterator it = s.begin(); it != s.end(); ++it) {
+    if (*it & 0x80)
+      return false;
+  }
+  return true;
+}
+
+// Assumes that |previous| is a valid UTF-8 sequence, and attempts to return
+// the next one. Is just barely smart enough to iterate through the ranges
+// defined about.
+std::string NextUtf8Sequence(const std::string& previous) {
+  DCHECK(StreamingUtf8Validator::Validate(previous));
+  std::string next = previous;
+  for (int i = static_cast<int>(previous.length() - 1); i >= 0; --i) {
+    // All bytes in a UTF-8 sequence except the first one are
+    // constrained to the range 0x80 to 0xbf, inclusive. When we
+    // increment past 0xbf, we carry into the previous byte.
+    if (i > 0 && next[i] == '\xbf') {
+      next[i] = '\x80';
+      continue;  // carry
+    }
+    ++next[i];
+    break;  // no carry
+  }
+  DCHECK(StreamingUtf8Validator::Validate(next))
+      << "Result \"" << next << "\" failed validation";
+  return next;
+}
+
+typedef bool (*TestTargetType)(const std::string&);
+
+// Run fuction |target| over |test_string| |times| times, and report the results
+// using |description|.
+bool RunTest(const std::string& description,
+             TestTargetType target,
+             const std::string& test_string,
+             int times) {
+  base::PerfTimeLogger timer(description.c_str());
+  bool result = true;
+  for (int i = 0; i < times; ++i) {
+    result = target(test_string) && result;
+  }
+  timer.Done();
+  return result;
+}
+
+// Construct a string by repeating |input| enough times to equal or exceed
+// |length|.
+std::string ConstructRepeatedTestString(const std::string& input,
+                                        size_t length) {
+  std::string output = input;
+  while (output.length() * 2 < length) {
+    output += output;
+  }
+  if (output.length() < length) {
+    output += ConstructRepeatedTestString(input, length - output.length());
+  }
+  return output;
+}
+
+// Construct a string by expanding the range of UTF-8 sequences
+// between |input_start| and |input_end|, inclusive, and then
+// repeating the resulting string until it equals or exceeds |length|
+// bytes. |input_start| and |input_end| must be valid UTF-8
+// sequences.
+std::string ConstructRangedTestString(const std::string& input_start,
+                                      const std::string& input_end,
+                                      size_t length) {
+  std::string output = input_start;
+  std::string input = input_start;
+  while (output.length() < length && input != input_end) {
+    input = NextUtf8Sequence(input);
+    output += input;
+  }
+  if (output.length() < length) {
+    output = ConstructRepeatedTestString(output, length);
+  }
+  return output;
+}
+
+struct TestFunctionDescription {
+  TestTargetType function;
+  const char* function_name;
+};
+
+bool IsStringUTF8(const std::string& str) {
+  return base::IsStringUTF8(base::StringPiece(str));
+}
+
+// IsString7Bit is intentionally placed last so it can be excluded easily.
+const TestFunctionDescription kTestFunctions[] = {
+    {&StreamingUtf8Validator::Validate, "StreamingUtf8Validator"},
+    {&IsStringUTF8, "IsStringUTF8"}, {&IsString7Bit, "IsString7Bit"}};
+
+// Construct a test string from |construct_test_string| for each of the lengths
+// in |kTestLengths| in turn. For each string, run each test in |test_functions|
+// for a number of iterations such that the total number of bytes validated
+// is around 16MB.
+void RunSomeTests(
+    const char format[],
+    base::Callback<std::string(size_t length)> construct_test_string,
+    const TestFunctionDescription* test_functions,
+    size_t test_count) {
+  for (size_t i = 0; i < arraysize(kTestLengths); ++i) {
+    const size_t length = kTestLengths[i];
+    const std::string test_string = construct_test_string.Run(length);
+    const int real_length = static_cast<int>(test_string.length());
+    const int times = (1 << 24) / real_length;
+    for (size_t test_index = 0; test_index < test_count; ++test_index) {
+      EXPECT_TRUE(RunTest(StringPrintf(format,
+                                       test_functions[test_index].function_name,
+                                       real_length,
+                                       times),
+                          test_functions[test_index].function,
+                          test_string,
+                          times));
+    }
+  }
+}
+
+TEST(StreamingUtf8ValidatorPerfTest, OneByteRepeated) {
+  RunSomeTests("%s: bytes=1 repeated length=%d repeat=%d",
+               base::Bind(ConstructRepeatedTestString, kOneByteSeqRangeStart),
+               kTestFunctions,
+               3);
+}
+
+TEST(StreamingUtf8ValidatorPerfTest, OneByteRange) {
+  RunSomeTests("%s: bytes=1 ranged length=%d repeat=%d",
+               base::Bind(ConstructRangedTestString,
+                          kOneByteSeqRangeStart,
+                          kOneByteSeqRangeEnd),
+               kTestFunctions,
+               3);
+}
+
+TEST(StreamingUtf8ValidatorPerfTest, TwoByteRepeated) {
+  RunSomeTests("%s: bytes=2 repeated length=%d repeat=%d",
+               base::Bind(ConstructRepeatedTestString, kTwoByteSeqRangeStart),
+               kTestFunctions,
+               2);
+}
+
+TEST(StreamingUtf8ValidatorPerfTest, TwoByteRange) {
+  RunSomeTests("%s: bytes=2 ranged length=%d repeat=%d",
+               base::Bind(ConstructRangedTestString,
+                          kTwoByteSeqRangeStart,
+                          kTwoByteSeqRangeEnd),
+               kTestFunctions,
+               2);
+}
+
+TEST(StreamingUtf8ValidatorPerfTest, ThreeByteRepeated) {
+  RunSomeTests(
+      "%s: bytes=3 repeated length=%d repeat=%d",
+      base::Bind(ConstructRepeatedTestString, kThreeByteSeqRangeStart),
+      kTestFunctions,
+      2);
+}
+
+TEST(StreamingUtf8ValidatorPerfTest, ThreeByteRange) {
+  RunSomeTests("%s: bytes=3 ranged length=%d repeat=%d",
+               base::Bind(ConstructRangedTestString,
+                          kThreeByteSeqRangeStart,
+                          kThreeByteSeqRangeEnd),
+               kTestFunctions,
+               2);
+}
+
+TEST(StreamingUtf8ValidatorPerfTest, FourByteRepeated) {
+  RunSomeTests("%s: bytes=4 repeated length=%d repeat=%d",
+               base::Bind(ConstructRepeatedTestString, kFourByteSeqRangeStart),
+               kTestFunctions,
+               2);
+}
+
+TEST(StreamingUtf8ValidatorPerfTest, FourByteRange) {
+  RunSomeTests("%s: bytes=4 ranged length=%d repeat=%d",
+               base::Bind(ConstructRangedTestString,
+                          kFourByteSeqRangeStart,
+                          kFourByteSeqRangeEnd),
+               kTestFunctions,
+               2);
+}
+
+}  // namespace
+}  // namespace base
diff --git a/base/i18n/streaming_utf8_validator_unittest.cc b/base/i18n/streaming_utf8_validator_unittest.cc
new file mode 100644
index 0000000..20ea564
--- /dev/null
+++ b/base/i18n/streaming_utf8_validator_unittest.cc
@@ -0,0 +1,412 @@
+// 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.
+
+#include "base/i18n/streaming_utf8_validator.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <string>
+
+#include "base/strings/string_piece.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Define BASE_I18N_UTF8_VALIDATOR_THOROUGH_TEST to verify that this class
+// accepts exactly the same set of 4-byte strings as ICU-based validation. This
+// tests every possible 4-byte string, so it is too slow to run routinely on
+// low-powered machines.
+//
+// #define BASE_I18N_UTF8_VALIDATOR_THOROUGH_TEST
+
+#ifdef BASE_I18N_UTF8_VALIDATOR_THOROUGH_TEST
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversion_utils.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "third_party/icu/source/common/unicode/utf8.h"
+
+#endif  // BASE_I18N_UTF8_VALIDATOR_THOROUGH_TEST
+
+namespace base {
+namespace {
+
+// Avoid having to qualify the enum values in the tests.
+const StreamingUtf8Validator::State VALID_ENDPOINT =
+    StreamingUtf8Validator::VALID_ENDPOINT;
+const StreamingUtf8Validator::State VALID_MIDPOINT =
+    StreamingUtf8Validator::VALID_MIDPOINT;
+const StreamingUtf8Validator::State INVALID = StreamingUtf8Validator::INVALID;
+
+#ifdef BASE_I18N_UTF8_VALIDATOR_THOROUGH_TEST
+
+const uint32 kThoroughTestChunkSize = 1 << 24;
+
+class StreamingUtf8ValidatorThoroughTest : public ::testing::Test {
+ protected:
+  StreamingUtf8ValidatorThoroughTest()
+      : all_done_(&lock_), tasks_dispatched_(0), tasks_finished_(0) {}
+
+  // This uses the same logic as base::IsStringUTF8 except it considers
+  // non-characters valid (and doesn't require a string as input).
+  static bool IsStringUtf8(const char* src, int32 src_len) {
+    int32 char_index = 0;
+
+    while (char_index < src_len) {
+      int32 code_point;
+      U8_NEXT(src, char_index, src_len, code_point);
+      if (!base::IsValidCodepoint(code_point))
+        return false;
+    }
+    return true;
+  }
+
+  // Converts the passed-in integer to a 4 byte string and then
+  // verifies that IsStringUtf8 and StreamingUtf8Validator agree on
+  // whether it is valid UTF-8 or not.
+  void TestNumber(uint32 n) const {
+    char test[sizeof n];
+    memcpy(test, &n, sizeof n);
+    StreamingUtf8Validator validator;
+    EXPECT_EQ(IsStringUtf8(test, sizeof n),
+              validator.AddBytes(test, sizeof n) == VALID_ENDPOINT)
+        << "Difference of opinion for \""
+        << base::StringPrintf("\\x%02X\\x%02X\\x%02X\\x%02X",
+                              test[0] & 0xFF,
+                              test[1] & 0xFF,
+                              test[2] & 0xFF,
+                              test[3] & 0xFF) << "\"";
+  }
+
+ public:
+  // Tests the 4-byte sequences corresponding to the |size| integers
+  // starting at |begin|. This is intended to be run from a worker
+  // pool. Signals |all_done_| at the end if it thinks all tasks are
+  // finished.
+  void TestRange(uint32 begin, uint32 size) {
+    for (uint32 i = 0; i < size; ++i) {
+      TestNumber(begin + i);
+    }
+    base::AutoLock al(lock_);
+    ++tasks_finished_;
+    LOG(INFO) << tasks_finished_ << " / " << tasks_dispatched_
+              << " tasks done\n";
+    if (tasks_finished_ >= tasks_dispatched_) {
+      all_done_.Signal();
+    }
+  }
+
+ protected:
+  base::Lock lock_;
+  base::ConditionVariable all_done_;
+  int tasks_dispatched_;
+  int tasks_finished_;
+};
+
+TEST_F(StreamingUtf8ValidatorThoroughTest, TestEverything) {
+  scoped_refptr<base::SequencedWorkerPool> pool =
+      new base::SequencedWorkerPool(32, "TestEverything");
+  base::AutoLock al(lock_);
+  uint32 begin = 0;
+  do {
+    pool->PostWorkerTask(
+        FROM_HERE,
+        base::Bind(&StreamingUtf8ValidatorThoroughTest::TestRange,
+                   base::Unretained(this),
+                   begin,
+                   kThoroughTestChunkSize));
+    ++tasks_dispatched_;
+    begin += kThoroughTestChunkSize;
+  } while (begin != 0);
+  while (tasks_finished_ < tasks_dispatched_)
+    all_done_.Wait();
+}
+
+#endif  // BASE_I18N_UTF8_VALIDATOR_THOROUGH_TEST
+
+// These valid and invalid UTF-8 sequences are based on the tests from
+// base/strings/string_util_unittest.cc
+
+// All of the strings in |valid| must represent a single codepoint, because
+// partial sequences are constructed by taking non-empty prefixes of these
+// strings.
+const char* const valid[] = {"\r",           "\n",           "a",
+                             "\xc2\x81",     "\xe1\x80\xbf", "\xf1\x80\xa0\xbf",
+                             "\xef\xbb\xbf",  // UTF-8 BOM
+};
+
+const char* const* const valid_end = valid + arraysize(valid);
+
+const char* const invalid[] = {
+    // always invalid bytes
+    "\xc0", "\xc1",
+    "\xf5", "\xf6", "\xf7",
+    "\xf8", "\xf9", "\xfa", "\xfb", "\xfc", "\xfd", "\xfe", "\xff",
+    // surrogate code points
+    "\xed\xa0\x80", "\xed\x0a\x8f", "\xed\xbf\xbf",
+    //
+    // overlong sequences
+    "\xc0\x80"               // U+0000
+    "\xc1\x80",              // "A"
+    "\xc1\x81",              // "B"
+    "\xe0\x80\x80",          // U+0000
+    "\xe0\x82\x80",          // U+0080
+    "\xe0\x9f\xbf",          // U+07ff
+    "\xf0\x80\x80\x8D",      // U+000D
+    "\xf0\x80\x82\x91",      // U+0091
+    "\xf0\x80\xa0\x80",      // U+0800
+    "\xf0\x8f\xbb\xbf",      // U+FEFF (BOM)
+    "\xf8\x80\x80\x80\xbf",  // U+003F
+    "\xfc\x80\x80\x80\xa0\xa5",
+    //
+    // Beyond U+10FFFF
+    "\xf4\x90\x80\x80",          // U+110000
+    "\xf8\xa0\xbf\x80\xbf",      // 5 bytes
+    "\xfc\x9c\xbf\x80\xbf\x80",  // 6 bytes
+    //
+    // BOMs in UTF-16(BE|LE)
+    "\xfe\xff", "\xff\xfe",
+};
+
+const char* const* const invalid_end = invalid + arraysize(invalid);
+
+// A ForwardIterator which returns all the non-empty prefixes of the elements of
+// "valid".
+class PartialIterator {
+ public:
+  // The constructor returns the first iterator, ie. it is equivalent to
+  // begin().
+  PartialIterator() : index_(0), prefix_length_(0) { Advance(); }
+  // The trivial destructor left intentionally undefined.
+  // This is a value type; the default copy constructor and assignment operator
+  // generated by the compiler are used.
+
+  static PartialIterator end() { return PartialIterator(arraysize(valid), 1); }
+
+  PartialIterator& operator++() {
+    Advance();
+    return *this;
+  }
+
+  base::StringPiece operator*() const {
+    return base::StringPiece(valid[index_], prefix_length_);
+  }
+
+  bool operator==(const PartialIterator& rhs) const {
+    return index_ == rhs.index_ && prefix_length_ == rhs.prefix_length_;
+  }
+
+  bool operator!=(const PartialIterator& rhs) const { return !(rhs == *this); }
+
+ private:
+  // This constructor is used by the end() method.
+  PartialIterator(size_t index, size_t prefix_length)
+      : index_(index), prefix_length_(prefix_length) {}
+
+  void Advance() {
+    if (index_ < arraysize(valid) && prefix_length_ < strlen(valid[index_]))
+      ++prefix_length_;
+    while (index_ < arraysize(valid) &&
+           prefix_length_ == strlen(valid[index_])) {
+      ++index_;
+      prefix_length_ = 1;
+    }
+  }
+
+  // The UTF-8 sequence, as an offset into the |valid| array.
+  size_t index_;
+  size_t prefix_length_;
+};
+
+// A test fixture for tests which test one UTF-8 sequence (or invalid
+// byte sequence) at a time.
+class StreamingUtf8ValidatorSingleSequenceTest : public ::testing::Test {
+ protected:
+  // Iterator must be convertible when de-referenced to StringPiece.
+  template <typename Iterator>
+  void CheckRange(Iterator begin,
+                  Iterator end,
+                  StreamingUtf8Validator::State expected) {
+    for (Iterator it = begin; it != end; ++it) {
+      StreamingUtf8Validator validator;
+      base::StringPiece sequence = *it;
+      EXPECT_EQ(expected,
+                validator.AddBytes(sequence.data(), sequence.size()))
+          << "Failed for \"" << sequence << "\"";
+    }
+  }
+
+  // Adding input a byte at a time should make absolutely no difference.
+  template <typename Iterator>
+  void CheckRangeByteAtATime(Iterator begin,
+                             Iterator end,
+                             StreamingUtf8Validator::State expected) {
+    for (Iterator it = begin; it != end; ++it) {
+      StreamingUtf8Validator validator;
+      base::StringPiece sequence = *it;
+      StreamingUtf8Validator::State state = VALID_ENDPOINT;
+      for (base::StringPiece::const_iterator cit = sequence.begin();
+           cit != sequence.end();
+           ++cit) {
+        state = validator.AddBytes(&*cit, 1);
+      }
+      EXPECT_EQ(expected, state) << "Failed for \"" << sequence << "\"";
+    }
+  }
+};
+
+// A test fixture for tests which test the concatenation of byte sequences.
+class StreamingUtf8ValidatorDoubleSequenceTest : public ::testing::Test {
+ protected:
+  // Check every possible concatenation of byte sequences from two
+  // ranges, and verify that the combination matches the expected
+  // state.
+  template <typename Iterator1, typename Iterator2>
+  void CheckCombinations(Iterator1 begin1,
+                         Iterator1 end1,
+                         Iterator2 begin2,
+                         Iterator2 end2,
+                         StreamingUtf8Validator::State expected) {
+    StreamingUtf8Validator validator;
+    for (Iterator1 it1 = begin1; it1 != end1; ++it1) {
+      base::StringPiece c1 = *it1;
+      for (Iterator2 it2 = begin2; it2 != end2; ++it2) {
+        base::StringPiece c2 = *it2;
+        validator.AddBytes(c1.data(), c1.size());
+        EXPECT_EQ(expected, validator.AddBytes(c2.data(), c2.size()))
+            << "Failed for \"" << c1 << c2 << "\"";
+        validator.Reset();
+      }
+    }
+  }
+};
+
+TEST(StreamingUtf8ValidatorTest, NothingIsValid) {
+  static const char kNothing[] = "";
+  EXPECT_EQ(VALID_ENDPOINT, StreamingUtf8Validator().AddBytes(kNothing, 0));
+}
+
+// Because the members of the |valid| array need to be non-zero length
+// sequences and are measured with strlen(), |valid| cannot be used it
+// to test the NUL character '\0', so the NUL character gets its own
+// test.
+TEST(StreamingUtf8ValidatorTest, NulIsValid) {
+  static const char kNul[] = "\x00";
+  EXPECT_EQ(VALID_ENDPOINT, StreamingUtf8Validator().AddBytes(kNul, 1));
+}
+
+// Just a basic sanity test before we start getting fancy.
+TEST(StreamingUtf8ValidatorTest, HelloWorld) {
+  static const char kHelloWorld[] = "Hello, World!";
+  EXPECT_EQ(
+      VALID_ENDPOINT,
+      StreamingUtf8Validator().AddBytes(kHelloWorld, strlen(kHelloWorld)));
+}
+
+// Check that the Reset() method works.
+TEST(StreamingUtf8ValidatorTest, ResetWorks) {
+  StreamingUtf8Validator validator;
+  EXPECT_EQ(INVALID, validator.AddBytes("\xC0", 1));
+  EXPECT_EQ(INVALID, validator.AddBytes("a", 1));
+  validator.Reset();
+  EXPECT_EQ(VALID_ENDPOINT, validator.AddBytes("a", 1));
+}
+
+TEST_F(StreamingUtf8ValidatorSingleSequenceTest, Valid) {
+  CheckRange(valid, valid_end, VALID_ENDPOINT);
+}
+
+TEST_F(StreamingUtf8ValidatorSingleSequenceTest, Partial) {
+  CheckRange(PartialIterator(), PartialIterator::end(), VALID_MIDPOINT);
+}
+
+TEST_F(StreamingUtf8ValidatorSingleSequenceTest, Invalid) {
+  CheckRange(invalid, invalid_end, INVALID);
+}
+
+TEST_F(StreamingUtf8ValidatorSingleSequenceTest, ValidByByte) {
+  CheckRangeByteAtATime(valid, valid_end, VALID_ENDPOINT);
+}
+
+TEST_F(StreamingUtf8ValidatorSingleSequenceTest, PartialByByte) {
+  CheckRangeByteAtATime(
+      PartialIterator(), PartialIterator::end(), VALID_MIDPOINT);
+}
+
+TEST_F(StreamingUtf8ValidatorSingleSequenceTest, InvalidByByte) {
+  CheckRangeByteAtATime(invalid, invalid_end, INVALID);
+}
+
+TEST_F(StreamingUtf8ValidatorDoubleSequenceTest, ValidPlusValidIsValid) {
+  CheckCombinations(valid, valid_end, valid, valid_end, VALID_ENDPOINT);
+}
+
+TEST_F(StreamingUtf8ValidatorDoubleSequenceTest, ValidPlusPartialIsPartial) {
+  CheckCombinations(valid,
+                    valid_end,
+                    PartialIterator(),
+                    PartialIterator::end(),
+                    VALID_MIDPOINT);
+}
+
+TEST_F(StreamingUtf8ValidatorDoubleSequenceTest, PartialPlusValidIsInvalid) {
+  CheckCombinations(
+      PartialIterator(), PartialIterator::end(), valid, valid_end, INVALID);
+}
+
+TEST_F(StreamingUtf8ValidatorDoubleSequenceTest, PartialPlusPartialIsInvalid) {
+  CheckCombinations(PartialIterator(),
+                    PartialIterator::end(),
+                    PartialIterator(),
+                    PartialIterator::end(),
+                    INVALID);
+}
+
+TEST_F(StreamingUtf8ValidatorDoubleSequenceTest, ValidPlusInvalidIsInvalid) {
+  CheckCombinations(valid, valid_end, invalid, invalid_end, INVALID);
+}
+
+TEST_F(StreamingUtf8ValidatorDoubleSequenceTest, InvalidPlusValidIsInvalid) {
+  CheckCombinations(invalid, invalid_end, valid, valid_end, INVALID);
+}
+
+TEST_F(StreamingUtf8ValidatorDoubleSequenceTest, InvalidPlusInvalidIsInvalid) {
+  CheckCombinations(invalid, invalid_end, invalid, invalid_end, INVALID);
+}
+
+TEST_F(StreamingUtf8ValidatorDoubleSequenceTest, InvalidPlusPartialIsInvalid) {
+  CheckCombinations(
+      invalid, invalid_end, PartialIterator(), PartialIterator::end(), INVALID);
+}
+
+TEST_F(StreamingUtf8ValidatorDoubleSequenceTest, PartialPlusInvalidIsInvalid) {
+  CheckCombinations(
+      PartialIterator(), PartialIterator::end(), invalid, invalid_end, INVALID);
+}
+
+TEST(StreamingUtf8ValidatorValidateTest, EmptyIsValid) {
+  EXPECT_TRUE(StreamingUtf8Validator::Validate(std::string()));
+}
+
+TEST(StreamingUtf8ValidatorValidateTest, SimpleValidCase) {
+  EXPECT_TRUE(StreamingUtf8Validator::Validate("\xc2\x81"));
+}
+
+TEST(StreamingUtf8ValidatorValidateTest, SimpleInvalidCase) {
+  EXPECT_FALSE(StreamingUtf8Validator::Validate("\xc0\x80"));
+}
+
+TEST(StreamingUtf8ValidatorValidateTest, TruncatedIsInvalid) {
+  EXPECT_FALSE(StreamingUtf8Validator::Validate("\xc2"));
+}
+
+}  // namespace
+}  // namespace base
diff --git a/base/i18n/string_compare.cc b/base/i18n/string_compare.cc
new file mode 100644
index 0000000..2851e7d
--- /dev/null
+++ b/base/i18n/string_compare.cc
@@ -0,0 +1,28 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/i18n/string_compare.h"
+
+#include "base/logging.h"
+#include "base/strings/utf_string_conversions.h"
+
+namespace base {
+namespace i18n {
+
+// Compares the character data stored in two different string16 strings by
+// specified Collator instance.
+UCollationResult CompareString16WithCollator(const icu::Collator& collator,
+                                             const string16& lhs,
+                                             const string16& rhs) {
+  UErrorCode error = U_ZERO_ERROR;
+  UCollationResult result = collator.compare(
+      static_cast<const UChar*>(lhs.c_str()), static_cast<int>(lhs.length()),
+      static_cast<const UChar*>(rhs.c_str()), static_cast<int>(rhs.length()),
+      error);
+  DCHECK(U_SUCCESS(error));
+  return result;
+}
+
+}  // namespace i18n
+}  // namespace base
diff --git a/base/i18n/string_compare.h b/base/i18n/string_compare.h
new file mode 100644
index 0000000..5fcc5fe
--- /dev/null
+++ b/base/i18n/string_compare.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_I18N_STRING_COMPARE_H_
+#define BASE_I18N_STRING_COMPARE_H_
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+#include "base/i18n/base_i18n_export.h"
+#include "base/strings/string16.h"
+#include "third_party/icu/source/i18n/unicode/coll.h"
+
+namespace base {
+namespace i18n {
+
+// Compares the two strings using the specified collator.
+BASE_I18N_EXPORT UCollationResult
+CompareString16WithCollator(const icu::Collator& collator,
+                            const string16& lhs,
+                            const string16& rhs);
+
+}  // namespace i18n
+}  // namespace base
+
+#endif  // BASE_I18N_STRING_COMPARE_H_
diff --git a/base/i18n/string_search.cc b/base/i18n/string_search.cc
new file mode 100644
index 0000000..121dfce
--- /dev/null
+++ b/base/i18n/string_search.cc
@@ -0,0 +1,80 @@
+// Copyright (c) 2011 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/i18n/string_search.h"
+#include "base/logging.h"
+
+#include "third_party/icu/source/i18n/unicode/usearch.h"
+
+namespace base {
+namespace i18n {
+
+FixedPatternStringSearchIgnoringCaseAndAccents::
+FixedPatternStringSearchIgnoringCaseAndAccents(const string16& find_this)
+    : find_this_(find_this) {
+  // usearch_open requires a valid string argument to be searched, even if we
+  // want to set it by usearch_setText afterwards. So, supplying a dummy text.
+  const string16& dummy = find_this_;
+
+  UErrorCode status = U_ZERO_ERROR;
+  search_ = usearch_open(find_this_.data(), find_this_.size(),
+                         dummy.data(), dummy.size(),
+                         uloc_getDefault(),
+                         NULL,  // breakiter
+                         &status);
+  if (U_SUCCESS(status)) {
+    UCollator* collator = usearch_getCollator(search_);
+    ucol_setStrength(collator, UCOL_PRIMARY);
+    usearch_reset(search_);
+  }
+}
+
+FixedPatternStringSearchIgnoringCaseAndAccents::
+~FixedPatternStringSearchIgnoringCaseAndAccents() {
+  if (search_)
+    usearch_close(search_);
+}
+
+bool FixedPatternStringSearchIgnoringCaseAndAccents::Search(
+    const string16& in_this, size_t* match_index, size_t* match_length) {
+  UErrorCode status = U_ZERO_ERROR;
+  usearch_setText(search_, in_this.data(), in_this.size(), &status);
+
+  // Default to basic substring search if usearch fails. According to
+  // http://icu-project.org/apiref/icu4c/usearch_8h.html, usearch_open will fail
+  // if either |find_this| or |in_this| are empty. In either case basic
+  // substring search will give the correct return value.
+  if (!U_SUCCESS(status)) {
+    size_t index = in_this.find(find_this_);
+    if (index == string16::npos) {
+      return false;
+    } else {
+      if (match_index)
+        *match_index = index;
+      if (match_length)
+        *match_length = find_this_.size();
+      return true;
+    }
+  }
+
+  int32_t index = usearch_first(search_, &status);
+  if (!U_SUCCESS(status) || index == USEARCH_DONE)
+    return false;
+  if (match_index)
+    *match_index = static_cast<size_t>(index);
+  if (match_length)
+    *match_length = static_cast<size_t>(usearch_getMatchedLength(search_));
+  return true;
+}
+
+bool StringSearchIgnoringCaseAndAccents(const string16& find_this,
+                                        const string16& in_this,
+                                        size_t* match_index,
+                                        size_t* match_length) {
+  return FixedPatternStringSearchIgnoringCaseAndAccents(find_this).Search(
+      in_this, match_index, match_length);
+}
+
+}  // namespace i18n
+}  // namespace base
diff --git a/base/i18n/string_search.h b/base/i18n/string_search.h
new file mode 100644
index 0000000..138606f
--- /dev/null
+++ b/base/i18n/string_search.h
@@ -0,0 +1,53 @@
+// Copyright (c) 2011 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_I18N_STRING_SEARCH_H_
+#define BASE_I18N_STRING_SEARCH_H_
+
+#include "base/i18n/base_i18n_export.h"
+#include "base/strings/string16.h"
+
+struct UStringSearch;
+
+namespace base {
+namespace i18n {
+
+// Returns true if |in_this| contains |find_this|. If |match_index| or
+// |match_length| are non-NULL, they are assigned the start position and total
+// length of the match.
+//
+// Only differences between base letters are taken into consideration. Case and
+// accent differences are ignored. Please refer to 'primary level' in
+// http://userguide.icu-project.org/collation/concepts for additional details.
+BASE_I18N_EXPORT
+    bool StringSearchIgnoringCaseAndAccents(const string16& find_this,
+                                            const string16& in_this,
+                                            size_t* match_index,
+                                            size_t* match_length);
+
+// This class is for speeding up multiple StringSearchIgnoringCaseAndAccents()
+// with the same |find_this| argument. |find_this| is passed as the constructor
+// argument, and precomputation for searching is done only at that timing.
+class BASE_I18N_EXPORT FixedPatternStringSearchIgnoringCaseAndAccents {
+ public:
+  explicit FixedPatternStringSearchIgnoringCaseAndAccents(
+      const string16& find_this);
+  ~FixedPatternStringSearchIgnoringCaseAndAccents();
+
+  // Returns true if |in_this| contains |find_this|. If |match_index| or
+  // |match_length| are non-NULL, they are assigned the start position and total
+  // length of the match.
+  bool Search(const string16& in_this,
+              size_t* match_index,
+              size_t* match_length);
+
+ private:
+  string16 find_this_;
+  UStringSearch* search_;
+};
+
+}  // namespace i18n
+}  // namespace base
+
+#endif  // BASE_I18N_STRING_SEARCH_H_
diff --git a/base/i18n/string_search_unittest.cc b/base/i18n/string_search_unittest.cc
new file mode 100644
index 0000000..9419b26
--- /dev/null
+++ b/base/i18n/string_search_unittest.cc
@@ -0,0 +1,226 @@
+// Copyright (c) 2011 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 <string>
+
+#include "base/i18n/rtl.h"
+#include "base/i18n/string_search.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/icu/source/i18n/unicode/usearch.h"
+
+namespace base {
+namespace i18n {
+
+// Note on setting default locale for testing: The current default locale on
+// the Mac trybot is en_US_POSIX, with which primary-level collation strength
+// string search is case-sensitive, when normally it should be
+// case-insensitive. In other locales (including en_US which English speakers
+// in the U.S. use), this search would be case-insensitive as expected.
+
+TEST(StringSearchTest, ASCII) {
+  std::string default_locale(uloc_getDefault());
+  bool locale_is_posix = (default_locale == "en_US_POSIX");
+  if (locale_is_posix)
+    SetICUDefaultLocale("en_US");
+
+  size_t index = 0;
+  size_t length = 0;
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      ASCIIToUTF16("hello"), ASCIIToUTF16("hello world"), &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(5U, length);
+
+  EXPECT_FALSE(StringSearchIgnoringCaseAndAccents(
+      ASCIIToUTF16("h    e l l o"), ASCIIToUTF16("h   e l l o"),
+      &index, &length));
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      ASCIIToUTF16("aabaaa"), ASCIIToUTF16("aaabaabaaa"), &index, &length));
+  EXPECT_EQ(4U, index);
+  EXPECT_EQ(6U, length);
+
+  EXPECT_FALSE(StringSearchIgnoringCaseAndAccents(
+      ASCIIToUTF16("searching within empty string"), string16(),
+      &index, &length));
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      string16(), ASCIIToUTF16("searching for empty string"), &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(0U, length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      ASCIIToUTF16("case insensitivity"), ASCIIToUTF16("CaSe InSeNsItIvItY"),
+      &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(18U, length);
+
+  if (locale_is_posix)
+    SetICUDefaultLocale(default_locale.data());
+}
+
+TEST(StringSearchTest, UnicodeLocaleIndependent) {
+  // Base characters
+  const string16 e_base = WideToUTF16(L"e");
+  const string16 E_base = WideToUTF16(L"E");
+  const string16 a_base = WideToUTF16(L"a");
+
+  // Composed characters
+  const string16 e_with_acute_accent = WideToUTF16(L"\u00e9");
+  const string16 E_with_acute_accent = WideToUTF16(L"\u00c9");
+  const string16 e_with_grave_accent = WideToUTF16(L"\u00e8");
+  const string16 E_with_grave_accent = WideToUTF16(L"\u00c8");
+  const string16 a_with_acute_accent = WideToUTF16(L"\u00e1");
+
+  // Decomposed characters
+  const string16 e_with_acute_combining_mark = WideToUTF16(L"e\u0301");
+  const string16 E_with_acute_combining_mark = WideToUTF16(L"E\u0301");
+  const string16 e_with_grave_combining_mark = WideToUTF16(L"e\u0300");
+  const string16 E_with_grave_combining_mark = WideToUTF16(L"E\u0300");
+  const string16 a_with_acute_combining_mark = WideToUTF16(L"a\u0301");
+
+  std::string default_locale(uloc_getDefault());
+  bool locale_is_posix = (default_locale == "en_US_POSIX");
+  if (locale_is_posix)
+    SetICUDefaultLocale("en_US");
+
+  size_t index = 0;
+  size_t length = 0;
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      e_base, e_with_acute_accent, &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_with_acute_accent.size(), length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      e_with_acute_accent, e_base, &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_base.size(), length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      e_base, e_with_acute_combining_mark, &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_with_acute_combining_mark.size(), length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      e_with_acute_combining_mark, e_base, &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_base.size(), length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      e_with_acute_combining_mark, e_with_acute_accent,
+      &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_with_acute_accent.size(), length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      e_with_acute_accent, e_with_acute_combining_mark,
+      &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_with_acute_combining_mark.size(), length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      e_with_acute_combining_mark, e_with_grave_combining_mark,
+      &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_with_grave_combining_mark.size(), length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      e_with_grave_combining_mark, e_with_acute_combining_mark,
+      &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_with_acute_combining_mark.size(), length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      e_with_acute_combining_mark, e_with_grave_accent, &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_with_grave_accent.size(), length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      e_with_grave_accent, e_with_acute_combining_mark, &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_with_acute_combining_mark.size(), length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      E_with_acute_accent, e_with_acute_accent, &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_with_acute_accent.size(), length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      E_with_grave_accent, e_with_acute_accent, &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_with_acute_accent.size(), length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      E_with_acute_combining_mark, e_with_grave_accent, &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_with_grave_accent.size(), length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      E_with_grave_combining_mark, e_with_acute_accent, &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_with_acute_accent.size(), length);
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      E_base, e_with_grave_accent, &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(e_with_grave_accent.size(), length);
+
+  EXPECT_FALSE(StringSearchIgnoringCaseAndAccents(
+      a_with_acute_accent, e_with_acute_accent, &index, &length));
+
+  EXPECT_FALSE(StringSearchIgnoringCaseAndAccents(
+      a_with_acute_combining_mark, e_with_acute_combining_mark,
+      &index, &length));
+
+  if (locale_is_posix)
+    SetICUDefaultLocale(default_locale.data());
+}
+
+TEST(StringSearchTest, UnicodeLocaleDependent) {
+  // Base characters
+  const string16 a_base = WideToUTF16(L"a");
+
+  // Composed characters
+  const string16 a_with_ring = WideToUTF16(L"\u00e5");
+
+  EXPECT_TRUE(StringSearchIgnoringCaseAndAccents(
+      a_base, a_with_ring, NULL, NULL));
+
+  const char* default_locale = uloc_getDefault();
+  SetICUDefaultLocale("da");
+
+  EXPECT_FALSE(StringSearchIgnoringCaseAndAccents(
+      a_base, a_with_ring, NULL, NULL));
+
+  SetICUDefaultLocale(default_locale);
+}
+
+TEST(StringSearchTest, FixedPatternMultipleSearch) {
+  std::string default_locale(uloc_getDefault());
+  bool locale_is_posix = (default_locale == "en_US_POSIX");
+  if (locale_is_posix)
+    SetICUDefaultLocale("en_US");
+
+  size_t index = 0;
+  size_t length = 0;
+
+  // Search "hello" over multiple texts.
+  FixedPatternStringSearchIgnoringCaseAndAccents query(ASCIIToUTF16("hello"));
+  EXPECT_TRUE(query.Search(ASCIIToUTF16("12hello34"), &index, &length));
+  EXPECT_EQ(2U, index);
+  EXPECT_EQ(5U, length);
+  EXPECT_FALSE(query.Search(ASCIIToUTF16("bye"), &index, &length));
+  EXPECT_TRUE(query.Search(ASCIIToUTF16("hELLo"), &index, &length));
+  EXPECT_EQ(0U, index);
+  EXPECT_EQ(5U, length);
+
+  if (locale_is_posix)
+    SetICUDefaultLocale(default_locale.data());
+}
+
+}  // namespace i18n
+}  // namespace base
diff --git a/base/i18n/time_formatting.cc b/base/i18n/time_formatting.cc
new file mode 100644
index 0000000..15b34a3
--- /dev/null
+++ b/base/i18n/time_formatting.cc
@@ -0,0 +1,167 @@
+// Copyright (c) 2011 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/i18n/time_formatting.h"
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/time/time.h"
+#include "third_party/icu/source/i18n/unicode/datefmt.h"
+#include "third_party/icu/source/i18n/unicode/dtptngen.h"
+#include "third_party/icu/source/i18n/unicode/smpdtfmt.h"
+
+namespace base {
+namespace {
+
+string16 TimeFormat(const icu::DateFormat* formatter,
+                    const Time& time) {
+  DCHECK(formatter);
+  icu::UnicodeString date_string;
+
+  formatter->format(static_cast<UDate>(time.ToDoubleT() * 1000), date_string);
+  return string16(date_string.getBuffer(),
+                  static_cast<size_t>(date_string.length()));
+}
+
+string16 TimeFormatWithoutAmPm(const icu::DateFormat* formatter,
+                               const Time& time) {
+  DCHECK(formatter);
+  icu::UnicodeString time_string;
+
+  icu::FieldPosition ampm_field(icu::DateFormat::kAmPmField);
+  formatter->format(
+      static_cast<UDate>(time.ToDoubleT() * 1000), time_string, ampm_field);
+  int ampm_length = ampm_field.getEndIndex() - ampm_field.getBeginIndex();
+  if (ampm_length) {
+    int begin = ampm_field.getBeginIndex();
+    // Doesn't include any spacing before the field.
+    if (begin)
+      begin--;
+    time_string.removeBetween(begin, ampm_field.getEndIndex());
+  }
+  return string16(time_string.getBuffer(),
+                  static_cast<size_t>(time_string.length()));
+}
+
+}  // namespace
+
+string16 TimeFormatTimeOfDay(const Time& time) {
+  // We can omit the locale parameter because the default should match
+  // Chrome's application locale.
+  scoped_ptr<icu::DateFormat> formatter(
+      icu::DateFormat::createTimeInstance(icu::DateFormat::kShort));
+  return TimeFormat(formatter.get(), time);
+}
+
+string16 TimeFormatTimeOfDayWithHourClockType(const Time& time,
+                                              HourClockType type,
+                                              AmPmClockType ampm) {
+  // Just redirect to the normal function if the default type matches the
+  // given type.
+  HourClockType default_type = GetHourClockType();
+  if (default_type == type && (type == k24HourClock || ampm == kKeepAmPm)) {
+    return TimeFormatTimeOfDay(time);
+  }
+
+  // Generate a locale-dependent format pattern. The generator will take
+  // care of locale-dependent formatting issues like which separator to
+  // use (some locales use '.' instead of ':'), and where to put the am/pm
+  // marker.
+  UErrorCode status = U_ZERO_ERROR;
+  scoped_ptr<icu::DateTimePatternGenerator> generator(
+      icu::DateTimePatternGenerator::createInstance(status));
+  DCHECK(U_SUCCESS(status));
+  const char* base_pattern = (type == k12HourClock ? "ahm" : "Hm");
+  icu::UnicodeString generated_pattern =
+      generator->getBestPattern(icu::UnicodeString(base_pattern), status);
+  DCHECK(U_SUCCESS(status));
+
+  // Then, format the time using the generated pattern.
+  icu::SimpleDateFormat formatter(generated_pattern, status);
+  DCHECK(U_SUCCESS(status));
+  if (ampm == kKeepAmPm) {
+    return TimeFormat(&formatter, time);
+  } else {
+    return TimeFormatWithoutAmPm(&formatter, time);
+  }
+}
+
+string16 TimeFormatShortDate(const Time& time) {
+  scoped_ptr<icu::DateFormat> formatter(
+      icu::DateFormat::createDateInstance(icu::DateFormat::kMedium));
+  return TimeFormat(formatter.get(), time);
+}
+
+string16 TimeFormatShortDateNumeric(const Time& time) {
+  scoped_ptr<icu::DateFormat> formatter(
+      icu::DateFormat::createDateInstance(icu::DateFormat::kShort));
+  return TimeFormat(formatter.get(), time);
+}
+
+string16 TimeFormatShortDateAndTime(const Time& time) {
+  scoped_ptr<icu::DateFormat> formatter(
+      icu::DateFormat::createDateTimeInstance(icu::DateFormat::kShort));
+  return TimeFormat(formatter.get(), time);
+}
+
+string16 TimeFormatShortDateAndTimeWithTimeZone(const Time& time) {
+  scoped_ptr<icu::DateFormat> formatter(icu::DateFormat::createDateTimeInstance(
+      icu::DateFormat::kShort, icu::DateFormat::kLong));
+  return TimeFormat(formatter.get(), time);
+}
+
+string16 TimeFormatFriendlyDateAndTime(const Time& time) {
+  scoped_ptr<icu::DateFormat> formatter(
+      icu::DateFormat::createDateTimeInstance(icu::DateFormat::kFull));
+  return TimeFormat(formatter.get(), time);
+}
+
+string16 TimeFormatFriendlyDate(const Time& time) {
+  scoped_ptr<icu::DateFormat> formatter(icu::DateFormat::createDateInstance(
+      icu::DateFormat::kFull));
+  return TimeFormat(formatter.get(), time);
+}
+
+HourClockType GetHourClockType() {
+  // TODO(satorux,jshin): Rework this with ures_getByKeyWithFallback()
+  // once it becomes public. The short time format can be found at
+  // "calendar/gregorian/DateTimePatterns/3" in the resources.
+  scoped_ptr<icu::SimpleDateFormat> formatter(
+      static_cast<icu::SimpleDateFormat*>(
+          icu::DateFormat::createTimeInstance(icu::DateFormat::kShort)));
+  // Retrieve the short time format.
+  icu::UnicodeString pattern_unicode;
+  formatter->toPattern(pattern_unicode);
+
+  // Determine what hour clock type the current locale uses, by checking
+  // "a" (am/pm marker) in the short time format. This is reliable as "a"
+  // is used by all of 12-hour clock formats, but not any of 24-hour clock
+  // formats, as shown below.
+  //
+  // % grep -A4 DateTimePatterns third_party/icu/source/data/locales/*.txt |
+  //   grep -B1 -- -- |grep -v -- '--' |
+  //   perl -nle 'print $1 if /^\S+\s+"(.*)"/' |sort -u
+  //
+  // H.mm
+  // H:mm
+  // HH.mm
+  // HH:mm
+  // a h:mm
+  // ah:mm
+  // ahh:mm
+  // h-mm a
+  // h:mm a
+  // hh:mm a
+  //
+  // See http://userguide.icu-project.org/formatparse/datetime for details
+  // about the date/time format syntax.
+  if (pattern_unicode.indexOf('a') == -1) {
+    return k24HourClock;
+  } else {
+    return k12HourClock;
+  }
+}
+
+}  // namespace base
diff --git a/base/i18n/time_formatting.h b/base/i18n/time_formatting.h
new file mode 100644
index 0000000..2053c0b
--- /dev/null
+++ b/base/i18n/time_formatting.h
@@ -0,0 +1,71 @@
+// Copyright (c) 2011 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.
+
+// Basic time formatting methods.  These methods use the current locale
+// formatting for displaying the time.
+
+#ifndef BASE_I18N_TIME_FORMATTING_H_
+#define BASE_I18N_TIME_FORMATTING_H_
+
+#include "base/i18n/base_i18n_export.h"
+#include "base/strings/string16.h"
+
+namespace base {
+
+class Time;
+
+// Argument type used to specify the hour clock type.
+enum HourClockType {
+  k12HourClock,  // Uses 1-12. e.g., "3:07 PM"
+  k24HourClock,  // Uses 0-23. e.g., "15:07"
+};
+
+// Argument type used to specify whether or not to include AM/PM sign.
+enum AmPmClockType {
+  kDropAmPm,  // Drops AM/PM sign. e.g., "3:07"
+  kKeepAmPm,  // Keeps AM/PM sign. e.g., "3:07 PM"
+};
+
+// Returns the time of day, e.g., "3:07 PM".
+BASE_I18N_EXPORT string16 TimeFormatTimeOfDay(const Time& time);
+
+// Returns the time of day in the specified hour clock type. e.g.
+// "3:07 PM" (type == k12HourClock, ampm == kKeepAmPm).
+// "3:07"    (type == k12HourClock, ampm == kDropAmPm).
+// "15:07"   (type == k24HourClock).
+BASE_I18N_EXPORT string16 TimeFormatTimeOfDayWithHourClockType(
+    const Time& time,
+    HourClockType type,
+    AmPmClockType ampm);
+
+// Returns a shortened date, e.g. "Nov 7, 2007"
+BASE_I18N_EXPORT string16 TimeFormatShortDate(const Time& time);
+
+// Returns a numeric date such as 12/13/52.
+BASE_I18N_EXPORT string16 TimeFormatShortDateNumeric(const Time& time);
+
+// Returns a numeric date and time such as "12/13/52 2:44:30 PM".
+BASE_I18N_EXPORT string16 TimeFormatShortDateAndTime(const Time& time);
+
+// Returns a numeric date and time with time zone such as
+// "12/13/52 2:44:30 PM PST".
+BASE_I18N_EXPORT string16
+TimeFormatShortDateAndTimeWithTimeZone(const Time& time);
+
+// Formats a time in a friendly sentence format, e.g.
+// "Monday, March 6, 2008 2:44:30 PM".
+BASE_I18N_EXPORT string16 TimeFormatFriendlyDateAndTime(const Time& time);
+
+// Formats a time in a friendly sentence format, e.g.
+// "Monday, March 6, 2008".
+BASE_I18N_EXPORT string16 TimeFormatFriendlyDate(const Time& time);
+
+// Gets the hour clock type of the current locale. e.g.
+// k12HourClock (en-US).
+// k24HourClock (en-GB).
+BASE_I18N_EXPORT HourClockType GetHourClockType();
+
+}  // namespace base
+
+#endif  // BASE_I18N_TIME_FORMATTING_H_
diff --git a/base/i18n/time_formatting_unittest.cc b/base/i18n/time_formatting_unittest.cc
new file mode 100644
index 0000000..df0c1ed
--- /dev/null
+++ b/base/i18n/time_formatting_unittest.cc
@@ -0,0 +1,172 @@
+// Copyright (c) 2011 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/i18n/time_formatting.h"
+
+#include "base/i18n/rtl.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/icu/source/common/unicode/uversion.h"
+#include "third_party/icu/source/i18n/unicode/calendar.h"
+#include "third_party/icu/source/i18n/unicode/timezone.h"
+
+namespace base {
+namespace {
+
+const Time::Exploded kTestDateTimeExploded = {
+  2011, 4, 6, 30, // Sat, Apr 30, 2011
+  15, 42, 7, 0    // 15:42:07.000
+};
+
+base::string16 GetShortTimeZone() {
+  scoped_ptr<icu::TimeZone> zone(icu::TimeZone::createDefault());
+  icu::UnicodeString name;
+  zone->getDisplayName(true, icu::TimeZone::SHORT, name);
+  return base::string16(name.getBuffer(), name.length());
+}
+
+TEST(TimeFormattingTest, TimeFormatTimeOfDayDefault12h) {
+  // Test for a locale defaulted to 12h clock.
+  // As an instance, we use third_party/icu/source/data/locales/en.txt.
+  i18n::SetICUDefaultLocale("en_US");
+
+  Time time(Time::FromLocalExploded(kTestDateTimeExploded));
+  string16 clock24h(ASCIIToUTF16("15:42"));
+  string16 clock12h_pm(ASCIIToUTF16("3:42 PM"));
+  string16 clock12h(ASCIIToUTF16("3:42"));
+
+  // The default is 12h clock.
+  EXPECT_EQ(clock12h_pm, TimeFormatTimeOfDay(time));
+  EXPECT_EQ(k12HourClock, GetHourClockType());
+  // k{Keep,Drop}AmPm should not affect for 24h clock.
+  EXPECT_EQ(clock24h,
+            TimeFormatTimeOfDayWithHourClockType(time,
+                                                 k24HourClock,
+                                                 kKeepAmPm));
+  EXPECT_EQ(clock24h,
+            TimeFormatTimeOfDayWithHourClockType(time,
+                                                 k24HourClock,
+                                                 kDropAmPm));
+  // k{Keep,Drop}AmPm affects for 12h clock.
+  EXPECT_EQ(clock12h_pm,
+            TimeFormatTimeOfDayWithHourClockType(time,
+                                                 k12HourClock,
+                                                 kKeepAmPm));
+  EXPECT_EQ(clock12h,
+            TimeFormatTimeOfDayWithHourClockType(time,
+                                                 k12HourClock,
+                                                 kDropAmPm));
+}
+
+TEST(TimeFormattingTest, TimeFormatTimeOfDayDefault24h) {
+  // Test for a locale defaulted to 24h clock.
+  // As an instance, we use third_party/icu/source/data/locales/en_GB.txt.
+  i18n::SetICUDefaultLocale("en_GB");
+
+  Time time(Time::FromLocalExploded(kTestDateTimeExploded));
+  string16 clock24h(ASCIIToUTF16("15:42"));
+  string16 clock12h_pm(ASCIIToUTF16("3:42 pm"));
+  string16 clock12h(ASCIIToUTF16("3:42"));
+
+  // The default is 24h clock.
+  EXPECT_EQ(clock24h, TimeFormatTimeOfDay(time));
+  EXPECT_EQ(k24HourClock, GetHourClockType());
+  // k{Keep,Drop}AmPm should not affect for 24h clock.
+  EXPECT_EQ(clock24h,
+            TimeFormatTimeOfDayWithHourClockType(time,
+                                                 k24HourClock,
+                                                 kKeepAmPm));
+  EXPECT_EQ(clock24h,
+            TimeFormatTimeOfDayWithHourClockType(time,
+                                                 k24HourClock,
+                                                 kDropAmPm));
+  // k{Keep,Drop}AmPm affects for 12h clock.
+  EXPECT_EQ(clock12h_pm,
+            TimeFormatTimeOfDayWithHourClockType(time,
+                                                 k12HourClock,
+                                                 kKeepAmPm));
+  EXPECT_EQ(clock12h,
+            TimeFormatTimeOfDayWithHourClockType(time,
+                                                 k12HourClock,
+                                                 kDropAmPm));
+}
+
+TEST(TimeFormattingTest, TimeFormatTimeOfDayJP) {
+  // Test for a locale that uses different mark than "AM" and "PM".
+  // As an instance, we use third_party/icu/source/data/locales/ja.txt.
+  i18n::SetICUDefaultLocale("ja_JP");
+
+  Time time(Time::FromLocalExploded(kTestDateTimeExploded));
+  string16 clock24h(ASCIIToUTF16("15:42"));
+  string16 clock12h_pm(WideToUTF16(L"\x5348\x5f8c" L"3:42"));
+  string16 clock12h(ASCIIToUTF16("3:42"));
+
+  // The default is 24h clock.
+  EXPECT_EQ(clock24h, TimeFormatTimeOfDay(time));
+  EXPECT_EQ(k24HourClock, GetHourClockType());
+  // k{Keep,Drop}AmPm should not affect for 24h clock.
+  EXPECT_EQ(clock24h,
+            TimeFormatTimeOfDayWithHourClockType(time,
+                                                 k24HourClock,
+                                                 kKeepAmPm));
+  EXPECT_EQ(clock24h,
+            TimeFormatTimeOfDayWithHourClockType(time,
+                                                 k24HourClock,
+                                                 kDropAmPm));
+  // k{Keep,Drop}AmPm affects for 12h clock.
+  EXPECT_EQ(clock12h_pm,
+            TimeFormatTimeOfDayWithHourClockType(time,
+                                                 k12HourClock,
+                                                 kKeepAmPm));
+  EXPECT_EQ(clock12h,
+            TimeFormatTimeOfDayWithHourClockType(time,
+                                                 k12HourClock,
+                                                 kDropAmPm));
+}
+
+TEST(TimeFormattingTest, TimeFormatDateUS) {
+  // See third_party/icu/source/data/locales/en.txt.
+  // The date patterns are "EEEE, MMMM d, y", "MMM d, y", and "M/d/yy".
+  i18n::SetICUDefaultLocale("en_US");
+
+  Time time(Time::FromLocalExploded(kTestDateTimeExploded));
+
+  EXPECT_EQ(ASCIIToUTF16("Apr 30, 2011"), TimeFormatShortDate(time));
+  EXPECT_EQ(ASCIIToUTF16("4/30/11"), TimeFormatShortDateNumeric(time));
+
+  EXPECT_EQ(ASCIIToUTF16("4/30/11, 3:42:07 PM"),
+            TimeFormatShortDateAndTime(time));
+  EXPECT_EQ(ASCIIToUTF16("4/30/11, 3:42:07 PM ") + GetShortTimeZone(),
+            TimeFormatShortDateAndTimeWithTimeZone(time));
+
+  EXPECT_EQ(ASCIIToUTF16("Saturday, April 30, 2011 at 3:42:07 PM"),
+            TimeFormatFriendlyDateAndTime(time));
+
+  EXPECT_EQ(ASCIIToUTF16("Saturday, April 30, 2011"),
+            TimeFormatFriendlyDate(time));
+}
+
+TEST(TimeFormattingTest, TimeFormatDateGB) {
+  // See third_party/icu/source/data/locales/en_GB.txt.
+  // The date patterns are "EEEE, d MMMM y", "d MMM y", and "dd/MM/yyyy".
+  i18n::SetICUDefaultLocale("en_GB");
+
+  Time time(Time::FromLocalExploded(kTestDateTimeExploded));
+
+  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"),
+            TimeFormatShortDateAndTime(time));
+  EXPECT_EQ(ASCIIToUTF16("30/04/2011, 15:42:07 ") + GetShortTimeZone(),
+            TimeFormatShortDateAndTimeWithTimeZone(time));
+  EXPECT_EQ(ASCIIToUTF16("Saturday, 30 April 2011 at 15:42:07"),
+            TimeFormatFriendlyDateAndTime(time));
+  EXPECT_EQ(ASCIIToUTF16("Saturday, 30 April 2011"),
+            TimeFormatFriendlyDate(time));
+}
+
+}  // namespace
+}  // namespace base
diff --git a/base/i18n/timezone.cc b/base/i18n/timezone.cc
new file mode 100644
index 0000000..f668543
--- /dev/null
+++ b/base/i18n/timezone.cc
@@ -0,0 +1,616 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/i18n/timezone.h"
+
+#include <string.h>
+
+#include <map>
+
+#include "base/memory/singleton.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "third_party/icu/source/i18n/unicode/timezone.h"
+
+namespace base {
+
+namespace {
+
+class TimezoneMap {
+ public:
+  static TimezoneMap* GetInstance() {
+    return Singleton<TimezoneMap>::get();
+  }
+
+  std::string CountryCodeForTimezone(const std::string& olson_code) {
+    std::map<const char*, const char*, CompareCStrings>::iterator iter =
+      map_.find(olson_code.c_str());
+    if (iter != map_.end())
+      return iter->second;
+
+    return std::string();
+  }
+
+ private:
+  TimezoneMap() {
+    // These mappings are adapted from zone.tab, which is available at
+    // <http://www.ietf.org/timezones/data/zone.tab> and is a part of public
+    // domain.
+    struct OlsonCodeData {
+      const char* country_code;
+      const char* olson_code;
+    };
+    static const OlsonCodeData olson_code_data[] = {
+        { "AD", "Europe/Andorra" },
+        { "AE", "Asia/Dubai" },
+        { "AF", "Asia/Kabul" },
+        { "AG", "America/Antigua" },
+        { "AI", "America/Anguilla" },
+        { "AL", "Europe/Tirane" },
+        { "AM", "Asia/Yerevan" },
+        { "AO", "Africa/Luanda" },
+        { "AQ", "Antarctica/McMurdo" },
+        { "AQ", "Antarctica/Rothera" },
+        { "AQ", "Antarctica/Palmer" },
+        { "AQ", "Antarctica/Mawson" },
+        { "AQ", "Antarctica/Davis" },
+        { "AQ", "Antarctica/Casey" },
+        { "AQ", "Antarctica/Vostok" },
+        { "AQ", "Antarctica/DumontDUrville" },
+        { "AQ", "Antarctica/Syowa" },
+        { "AR", "America/Argentina/Buenos_Aires" },
+        { "AR", "America/Argentina/Cordoba" },
+        { "AR", "America/Argentina/Salta" },
+        { "AR", "America/Argentina/Jujuy" },
+        { "AR", "America/Argentina/Tucuman" },
+        { "AR", "America/Argentina/Catamarca" },
+        { "AR", "America/Argentina/La_Rioja" },
+        { "AR", "America/Argentina/San_Juan" },
+        { "AR", "America/Argentina/Mendoza" },
+        { "AR", "America/Argentina/San_Luis" },
+        { "AR", "America/Argentina/Rio_Gallegos" },
+        { "AR", "America/Argentina/Ushuaia" },
+        { "AS", "Pacific/Pago_Pago" },
+        { "AT", "Europe/Vienna" },
+        { "AU", "Australia/Lord_Howe" },
+        { "AU", "Antarctica/Macquarie" },
+        { "AU", "Australia/Hobart" },
+        { "AU", "Australia/Currie" },
+        { "AU", "Australia/Melbourne" },
+        { "AU", "Australia/Sydney" },
+        { "AU", "Australia/Broken_Hill" },
+        { "AU", "Australia/Brisbane" },
+        { "AU", "Australia/Lindeman" },
+        { "AU", "Australia/Adelaide" },
+        { "AU", "Australia/Darwin" },
+        { "AU", "Australia/Perth" },
+        { "AU", "Australia/Eucla" },
+        { "AW", "America/Aruba" },
+        { "AX", "Europe/Mariehamn" },
+        { "AZ", "Asia/Baku" },
+        { "BA", "Europe/Sarajevo" },
+        { "BB", "America/Barbados" },
+        { "BD", "Asia/Dhaka" },
+        { "BE", "Europe/Brussels" },
+        { "BF", "Africa/Ouagadougou" },
+        { "BG", "Europe/Sofia" },
+        { "BH", "Asia/Bahrain" },
+        { "BI", "Africa/Bujumbura" },
+        { "BJ", "Africa/Porto-Novo" },
+        { "BL", "America/St_Barthelemy" },
+        { "BM", "Atlantic/Bermuda" },
+        { "BN", "Asia/Brunei" },
+        { "BO", "America/La_Paz" },
+        { "BQ", "America/Kralendijk" },
+        { "BR", "America/Noronha" },
+        { "BR", "America/Belem" },
+        { "BR", "America/Fortaleza" },
+        { "BR", "America/Recife" },
+        { "BR", "America/Araguaina" },
+        { "BR", "America/Maceio" },
+        { "BR", "America/Bahia" },
+        { "BR", "America/Sao_Paulo" },
+        { "BR", "America/Campo_Grande" },
+        { "BR", "America/Cuiaba" },
+        { "BR", "America/Santarem" },
+        { "BR", "America/Porto_Velho" },
+        { "BR", "America/Boa_Vista" },
+        { "BR", "America/Manaus" },
+        { "BR", "America/Eirunepe" },
+        { "BR", "America/Rio_Branco" },
+        { "BS", "America/Nassau" },
+        { "BT", "Asia/Thimphu" },
+        { "BW", "Africa/Gaborone" },
+        { "BY", "Europe/Minsk" },
+        { "BZ", "America/Belize" },
+        { "CA", "America/St_Johns" },
+        { "CA", "America/Halifax" },
+        { "CA", "America/Glace_Bay" },
+        { "CA", "America/Moncton" },
+        { "CA", "America/Goose_Bay" },
+        { "CA", "America/Blanc-Sablon" },
+        { "CA", "America/Toronto" },
+        { "CA", "America/Nipigon" },
+        { "CA", "America/Thunder_Bay" },
+        { "CA", "America/Iqaluit" },
+        { "CA", "America/Pangnirtung" },
+        { "CA", "America/Resolute" },
+        { "CA", "America/Atikokan" },
+        { "CA", "America/Rankin_Inlet" },
+        { "CA", "America/Winnipeg" },
+        { "CA", "America/Rainy_River" },
+        { "CA", "America/Regina" },
+        { "CA", "America/Swift_Current" },
+        { "CA", "America/Edmonton" },
+        { "CA", "America/Cambridge_Bay" },
+        { "CA", "America/Yellowknife" },
+        { "CA", "America/Inuvik" },
+        { "CA", "America/Creston" },
+        { "CA", "America/Dawson_Creek" },
+        { "CA", "America/Vancouver" },
+        { "CA", "America/Whitehorse" },
+        { "CA", "America/Dawson" },
+        { "CC", "Indian/Cocos" },
+        { "CD", "Africa/Kinshasa" },
+        { "CD", "Africa/Lubumbashi" },
+        { "CF", "Africa/Bangui" },
+        { "CG", "Africa/Brazzaville" },
+        { "CH", "Europe/Zurich" },
+        { "CI", "Africa/Abidjan" },
+        { "CK", "Pacific/Rarotonga" },
+        { "CL", "America/Santiago" },
+        { "CL", "Pacific/Easter" },
+        { "CM", "Africa/Douala" },
+        { "CN", "Asia/Shanghai" },
+        { "CN", "Asia/Harbin" },
+        { "CN", "Asia/Chongqing" },
+        { "CN", "Asia/Urumqi" },
+        { "CN", "Asia/Kashgar" },
+        { "CO", "America/Bogota" },
+        { "CR", "America/Costa_Rica" },
+        { "CU", "America/Havana" },
+        { "CV", "Atlantic/Cape_Verde" },
+        { "CW", "America/Curacao" },
+        { "CX", "Indian/Christmas" },
+        { "CY", "Asia/Nicosia" },
+        { "CZ", "Europe/Prague" },
+        { "DE", "Europe/Berlin" },
+        { "DE", "Europe/Busingen" },
+        { "DJ", "Africa/Djibouti" },
+        { "DK", "Europe/Copenhagen" },
+        { "DM", "America/Dominica" },
+        { "DO", "America/Santo_Domingo" },
+        { "DZ", "Africa/Algiers" },
+        { "EC", "America/Guayaquil" },
+        { "EC", "Pacific/Galapagos" },
+        { "EE", "Europe/Tallinn" },
+        { "EG", "Africa/Cairo" },
+        { "EH", "Africa/El_Aaiun" },
+        { "ER", "Africa/Asmara" },
+        { "ES", "Europe/Madrid" },
+        { "ES", "Africa/Ceuta" },
+        { "ES", "Atlantic/Canary" },
+        { "ET", "Africa/Addis_Ababa" },
+        { "FI", "Europe/Helsinki" },
+        { "FJ", "Pacific/Fiji" },
+        { "FK", "Atlantic/Stanley" },
+        { "FM", "Pacific/Chuuk" },
+        { "FM", "Pacific/Pohnpei" },
+        { "FM", "Pacific/Kosrae" },
+        { "FO", "Atlantic/Faroe" },
+        { "FR", "Europe/Paris" },
+        { "GA", "Africa/Libreville" },
+        { "GB", "Europe/London" },
+        { "GD", "America/Grenada" },
+        { "GE", "Asia/Tbilisi" },
+        { "GF", "America/Cayenne" },
+        { "GG", "Europe/Guernsey" },
+        { "GH", "Africa/Accra" },
+        { "GI", "Europe/Gibraltar" },
+        { "GL", "America/Godthab" },
+        { "GL", "America/Danmarkshavn" },
+        { "GL", "America/Scoresbysund" },
+        { "GL", "America/Thule" },
+        { "GM", "Africa/Banjul" },
+        { "GN", "Africa/Conakry" },
+        { "GP", "America/Guadeloupe" },
+        { "GQ", "Africa/Malabo" },
+        { "GR", "Europe/Athens" },
+        { "GS", "Atlantic/South_Georgia" },
+        { "GT", "America/Guatemala" },
+        { "GU", "Pacific/Guam" },
+        { "GW", "Africa/Bissau" },
+        { "GY", "America/Guyana" },
+        { "HK", "Asia/Hong_Kong" },
+        { "HN", "America/Tegucigalpa" },
+        { "HR", "Europe/Zagreb" },
+        { "HT", "America/Port-au-Prince" },
+        { "HU", "Europe/Budapest" },
+        { "ID", "Asia/Jakarta" },
+        { "ID", "Asia/Pontianak" },
+        { "ID", "Asia/Makassar" },
+        { "ID", "Asia/Jayapura" },
+        { "IE", "Europe/Dublin" },
+        { "IL", "Asia/Jerusalem" },
+        { "IM", "Europe/Isle_of_Man" },
+        { "IN", "Asia/Kolkata" },
+        { "IO", "Indian/Chagos" },
+        { "IQ", "Asia/Baghdad" },
+        { "IR", "Asia/Tehran" },
+        { "IS", "Atlantic/Reykjavik" },
+        { "IT", "Europe/Rome" },
+        { "JE", "Europe/Jersey" },
+        { "JM", "America/Jamaica" },
+        { "JO", "Asia/Amman" },
+        { "JP", "Asia/Tokyo" },
+        { "KE", "Africa/Nairobi" },
+        { "KG", "Asia/Bishkek" },
+        { "KH", "Asia/Phnom_Penh" },
+        { "KI", "Pacific/Tarawa" },
+        { "KI", "Pacific/Enderbury" },
+        { "KI", "Pacific/Kiritimati" },
+        { "KM", "Indian/Comoro" },
+        { "KN", "America/St_Kitts" },
+        { "KP", "Asia/Pyongyang" },
+        { "KR", "Asia/Seoul" },
+        { "KW", "Asia/Kuwait" },
+        { "KY", "America/Cayman" },
+        { "KZ", "Asia/Almaty" },
+        { "KZ", "Asia/Qyzylorda" },
+        { "KZ", "Asia/Aqtobe" },
+        { "KZ", "Asia/Aqtau" },
+        { "KZ", "Asia/Oral" },
+        { "LA", "Asia/Vientiane" },
+        { "LB", "Asia/Beirut" },
+        { "LC", "America/St_Lucia" },
+        { "LI", "Europe/Vaduz" },
+        { "LK", "Asia/Colombo" },
+        { "LR", "Africa/Monrovia" },
+        { "LS", "Africa/Maseru" },
+        { "LT", "Europe/Vilnius" },
+        { "LU", "Europe/Luxembourg" },
+        { "LV", "Europe/Riga" },
+        { "LY", "Africa/Tripoli" },
+        { "MA", "Africa/Casablanca" },
+        { "MC", "Europe/Monaco" },
+        { "MD", "Europe/Chisinau" },
+        { "ME", "Europe/Podgorica" },
+        { "MF", "America/Marigot" },
+        { "MG", "Indian/Antananarivo" },
+        { "MH", "Pacific/Majuro" },
+        { "MH", "Pacific/Kwajalein" },
+        { "MK", "Europe/Skopje" },
+        { "ML", "Africa/Bamako" },
+        { "MM", "Asia/Rangoon" },
+        { "MN", "Asia/Ulaanbaatar" },
+        { "MN", "Asia/Hovd" },
+        { "MN", "Asia/Choibalsan" },
+        { "MO", "Asia/Macau" },
+        { "MP", "Pacific/Saipan" },
+        { "MQ", "America/Martinique" },
+        { "MR", "Africa/Nouakchott" },
+        { "MS", "America/Montserrat" },
+        { "MT", "Europe/Malta" },
+        { "MU", "Indian/Mauritius" },
+        { "MV", "Indian/Maldives" },
+        { "MW", "Africa/Blantyre" },
+        { "MX", "America/Mexico_City" },
+        { "MX", "America/Cancun" },
+        { "MX", "America/Merida" },
+        { "MX", "America/Monterrey" },
+        { "MX", "America/Matamoros" },
+        { "MX", "America/Mazatlan" },
+        { "MX", "America/Chihuahua" },
+        { "MX", "America/Ojinaga" },
+        { "MX", "America/Hermosillo" },
+        { "MX", "America/Tijuana" },
+        { "MX", "America/Santa_Isabel" },
+        { "MX", "America/Bahia_Banderas" },
+        { "MY", "Asia/Kuala_Lumpur" },
+        { "MY", "Asia/Kuching" },
+        { "MZ", "Africa/Maputo" },
+        { "NA", "Africa/Windhoek" },
+        { "NC", "Pacific/Noumea" },
+        { "NE", "Africa/Niamey" },
+        { "NF", "Pacific/Norfolk" },
+        { "NG", "Africa/Lagos" },
+        { "NI", "America/Managua" },
+        { "NL", "Europe/Amsterdam" },
+        { "NO", "Europe/Oslo" },
+        { "NP", "Asia/Kathmandu" },
+        { "NR", "Pacific/Nauru" },
+        { "NU", "Pacific/Niue" },
+        { "NZ", "Pacific/Auckland" },
+        { "NZ", "Pacific/Chatham" },
+        { "OM", "Asia/Muscat" },
+        { "PA", "America/Panama" },
+        { "PE", "America/Lima" },
+        { "PF", "Pacific/Tahiti" },
+        { "PF", "Pacific/Marquesas" },
+        { "PF", "Pacific/Gambier" },
+        { "PG", "Pacific/Port_Moresby" },
+        { "PH", "Asia/Manila" },
+        { "PK", "Asia/Karachi" },
+        { "PL", "Europe/Warsaw" },
+        { "PM", "America/Miquelon" },
+        { "PN", "Pacific/Pitcairn" },
+        { "PR", "America/Puerto_Rico" },
+        { "PS", "Asia/Gaza" },
+        { "PS", "Asia/Hebron" },
+        { "PT", "Europe/Lisbon" },
+        { "PT", "Atlantic/Madeira" },
+        { "PT", "Atlantic/Azores" },
+        { "PW", "Pacific/Palau" },
+        { "PY", "America/Asuncion" },
+        { "QA", "Asia/Qatar" },
+        { "RE", "Indian/Reunion" },
+        { "RO", "Europe/Bucharest" },
+        { "RS", "Europe/Belgrade" },
+        { "RU", "Europe/Kaliningrad" },
+        { "RU", "Europe/Moscow" },
+        { "RU", "Europe/Volgograd" },
+        { "RU", "Europe/Samara" },
+        { "RU", "Asia/Yekaterinburg" },
+        { "RU", "Asia/Omsk" },
+        { "RU", "Asia/Novosibirsk" },
+        { "RU", "Asia/Novokuznetsk" },
+        { "RU", "Asia/Krasnoyarsk" },
+        { "RU", "Asia/Irkutsk" },
+        { "RU", "Asia/Yakutsk" },
+        { "RU", "Asia/Khandyga" },
+        { "RU", "Asia/Vladivostok" },
+        { "RU", "Asia/Sakhalin" },
+        { "RU", "Asia/Ust-Nera" },
+        { "RU", "Asia/Magadan" },
+        { "RU", "Asia/Kamchatka" },
+        { "RU", "Asia/Anadyr" },
+        { "RW", "Africa/Kigali" },
+        { "SA", "Asia/Riyadh" },
+        { "SB", "Pacific/Guadalcanal" },
+        { "SC", "Indian/Mahe" },
+        { "SD", "Africa/Khartoum" },
+        { "SE", "Europe/Stockholm" },
+        { "SG", "Asia/Singapore" },
+        { "SH", "Atlantic/St_Helena" },
+        { "SI", "Europe/Ljubljana" },
+        { "SJ", "Arctic/Longyearbyen" },
+        { "SK", "Europe/Bratislava" },
+        { "SL", "Africa/Freetown" },
+        { "SM", "Europe/San_Marino" },
+        { "SN", "Africa/Dakar" },
+        { "SO", "Africa/Mogadishu" },
+        { "SR", "America/Paramaribo" },
+        { "SS", "Africa/Juba" },
+        { "ST", "Africa/Sao_Tome" },
+        { "SV", "America/El_Salvador" },
+        { "SX", "America/Lower_Princes" },
+        { "SY", "Asia/Damascus" },
+        { "SZ", "Africa/Mbabane" },
+        { "TC", "America/Grand_Turk" },
+        { "TD", "Africa/Ndjamena" },
+        { "TF", "Indian/Kerguelen" },
+        { "TG", "Africa/Lome" },
+        { "TH", "Asia/Bangkok" },
+        { "TJ", "Asia/Dushanbe" },
+        { "TK", "Pacific/Fakaofo" },
+        { "TL", "Asia/Dili" },
+        { "TM", "Asia/Ashgabat" },
+        { "TN", "Africa/Tunis" },
+        { "TO", "Pacific/Tongatapu" },
+        { "TR", "Europe/Istanbul" },
+        { "TT", "America/Port_of_Spain" },
+        { "TV", "Pacific/Funafuti" },
+        { "TW", "Asia/Taipei" },
+        { "TZ", "Africa/Dar_es_Salaam" },
+        { "UA", "Europe/Kiev" },
+        { "UA", "Europe/Uzhgorod" },
+        { "UA", "Europe/Zaporozhye" },
+        { "UA", "Europe/Simferopol" },
+        { "UG", "Africa/Kampala" },
+        { "UM", "Pacific/Johnston" },
+        { "UM", "Pacific/Midway" },
+        { "UM", "Pacific/Wake" },
+        { "US", "America/New_York" },
+        { "US", "America/Detroit" },
+        { "US", "America/Kentucky/Louisville" },
+        { "US", "America/Kentucky/Monticello" },
+        { "US", "America/Indiana/Indianapolis" },
+        { "US", "America/Indiana/Vincennes" },
+        { "US", "America/Indiana/Winamac" },
+        { "US", "America/Indiana/Marengo" },
+        { "US", "America/Indiana/Petersburg" },
+        { "US", "America/Indiana/Vevay" },
+        { "US", "America/Chicago" },
+        { "US", "America/Indiana/Tell_City" },
+        { "US", "America/Indiana/Knox" },
+        { "US", "America/Menominee" },
+        { "US", "America/North_Dakota/Center" },
+        { "US", "America/North_Dakota/New_Salem" },
+        { "US", "America/North_Dakota/Beulah" },
+        { "US", "America/Denver" },
+        { "US", "America/Boise" },
+        { "US", "America/Phoenix" },
+        { "US", "America/Los_Angeles" },
+        { "US", "America/Anchorage" },
+        { "US", "America/Juneau" },
+        { "US", "America/Sitka" },
+        { "US", "America/Yakutat" },
+        { "US", "America/Nome" },
+        { "US", "America/Adak" },
+        { "US", "America/Metlakatla" },
+        { "US", "Pacific/Honolulu" },
+        { "UY", "America/Montevideo" },
+        { "UZ", "Asia/Samarkand" },
+        { "UZ", "Asia/Tashkent" },
+        { "VA", "Europe/Vatican" },
+        { "VC", "America/St_Vincent" },
+        { "VE", "America/Caracas" },
+        { "VG", "America/Tortola" },
+        { "VI", "America/St_Thomas" },
+        { "VN", "Asia/Ho_Chi_Minh" },
+        { "VU", "Pacific/Efate" },
+        { "WF", "Pacific/Wallis" },
+        { "WS", "Pacific/Apia" },
+        { "YE", "Asia/Aden" },
+        { "YT", "Indian/Mayotte" },
+        { "ZA", "Africa/Johannesburg" },
+        { "ZM", "Africa/Lusaka" },
+        { "ZW", "Africa/Harare" },
+        // The mappings below are custom additions to zone.tab.
+        { "GB", "Etc/GMT" },
+        { "GB", "Etc/UTC" },
+        { "GB", "Etc/UCT" },
+    };
+
+    for (size_t i = 0; i < arraysize(olson_code_data); ++i)
+      map_[olson_code_data[i].olson_code] = olson_code_data[i].country_code;
+
+    // These are mapping from old codenames to new codenames. They are also
+    // part of public domain, and available at
+    // <http://www.ietf.org/timezones/data/backward>.
+    struct LinkData {
+      const char* old_code;
+      const char* new_code;
+    };
+    static const LinkData link_data[] = {
+        { "Africa/Asmera", "Africa/Asmara" },
+        { "Africa/Timbuktu", "Africa/Bamako" },
+        { "America/Argentina/ComodRivadavia", "America/Argentina/Catamarca" },
+        { "America/Atka", "America/Adak" },
+        { "America/Buenos_Aires", "America/Argentina/Buenos_Aires" },
+        { "America/Catamarca", "America/Argentina/Catamarca" },
+        { "America/Coral_Harbour", "America/Atikokan" },
+        { "America/Cordoba", "America/Argentina/Cordoba" },
+        { "America/Ensenada", "America/Tijuana" },
+        { "America/Fort_Wayne", "America/Indiana/Indianapolis" },
+        { "America/Indianapolis", "America/Indiana/Indianapolis" },
+        { "America/Jujuy", "America/Argentina/Jujuy" },
+        { "America/Knox_IN", "America/Indiana/Knox" },
+        { "America/Louisville", "America/Kentucky/Louisville" },
+        { "America/Mendoza", "America/Argentina/Mendoza" },
+        { "America/Porto_Acre", "America/Rio_Branco" },
+        { "America/Rosario", "America/Argentina/Cordoba" },
+        { "America/Virgin", "America/St_Thomas" },
+        { "Asia/Ashkhabad", "Asia/Ashgabat" },
+        { "Asia/Chungking", "Asia/Chongqing" },
+        { "Asia/Dacca", "Asia/Dhaka" },
+        { "Asia/Katmandu", "Asia/Kathmandu" },
+        { "Asia/Calcutta", "Asia/Kolkata" },
+        { "Asia/Macao", "Asia/Macau" },
+        { "Asia/Tel_Aviv", "Asia/Jerusalem" },
+        { "Asia/Saigon", "Asia/Ho_Chi_Minh" },
+        { "Asia/Thimbu", "Asia/Thimphu" },
+        { "Asia/Ujung_Pandang", "Asia/Makassar" },
+        { "Asia/Ulan_Bator", "Asia/Ulaanbaatar" },
+        { "Atlantic/Faeroe", "Atlantic/Faroe" },
+        { "Atlantic/Jan_Mayen", "Europe/Oslo" },
+        { "Australia/ACT", "Australia/Sydney" },
+        { "Australia/Canberra", "Australia/Sydney" },
+        { "Australia/LHI", "Australia/Lord_Howe" },
+        { "Australia/NSW", "Australia/Sydney" },
+        { "Australia/North", "Australia/Darwin" },
+        { "Australia/Queensland", "Australia/Brisbane" },
+        { "Australia/South", "Australia/Adelaide" },
+        { "Australia/Tasmania", "Australia/Hobart" },
+        { "Australia/Victoria", "Australia/Melbourne" },
+        { "Australia/West", "Australia/Perth" },
+        { "Australia/Yancowinna", "Australia/Broken_Hill" },
+        { "Brazil/Acre", "America/Rio_Branco" },
+        { "Brazil/DeNoronha", "America/Noronha" },
+        { "Brazil/East", "America/Sao_Paulo" },
+        { "Brazil/West", "America/Manaus" },
+        { "Canada/Atlantic", "America/Halifax" },
+        { "Canada/Central", "America/Winnipeg" },
+        { "Canada/East-Saskatchewan", "America/Regina" },
+        { "Canada/Eastern", "America/Toronto" },
+        { "Canada/Mountain", "America/Edmonton" },
+        { "Canada/Newfoundland", "America/St_Johns" },
+        { "Canada/Pacific", "America/Vancouver" },
+        { "Canada/Saskatchewan", "America/Regina" },
+        { "Canada/Yukon", "America/Whitehorse" },
+        { "Chile/Continental", "America/Santiago" },
+        { "Chile/EasterIsland", "Pacific/Easter" },
+        { "Cuba", "America/Havana" },
+        { "Egypt", "Africa/Cairo" },
+        { "Eire", "Europe/Dublin" },
+        { "Europe/Belfast", "Europe/London" },
+        { "Europe/Tiraspol", "Europe/Chisinau" },
+        { "GB", "Europe/London" },
+        { "GB-Eire", "Europe/London" },
+        { "GMT+0", "Etc/GMT" },
+        { "GMT-0", "Etc/GMT" },
+        { "GMT0", "Etc/GMT" },
+        { "Greenwich", "Etc/GMT" },
+        { "Hongkong", "Asia/Hong_Kong" },
+        { "Iceland", "Atlantic/Reykjavik" },
+        { "Iran", "Asia/Tehran" },
+        { "Israel", "Asia/Jerusalem" },
+        { "Jamaica", "America/Jamaica" },
+        { "Japan", "Asia/Tokyo" },
+        { "Kwajalein", "Pacific/Kwajalein" },
+        { "Libya", "Africa/Tripoli" },
+        { "Mexico/BajaNorte", "America/Tijuana" },
+        { "Mexico/BajaSur", "America/Mazatlan" },
+        { "Mexico/General", "America/Mexico_City" },
+        { "NZ", "Pacific/Auckland" },
+        { "NZ-CHAT", "Pacific/Chatham" },
+        { "Navajo", "America/Denver" },
+        { "PRC", "Asia/Shanghai" },
+        { "Pacific/Samoa", "Pacific/Pago_Pago" },
+        { "Pacific/Yap", "Pacific/Chuuk" },
+        { "Pacific/Truk", "Pacific/Chuuk" },
+        { "Pacific/Ponape", "Pacific/Pohnpei" },
+        { "Poland", "Europe/Warsaw" },
+        { "Portugal", "Europe/Lisbon" },
+        { "ROC", "Asia/Taipei" },
+        { "ROK", "Asia/Seoul" },
+        { "Singapore", "Asia/Singapore" },
+        { "Turkey", "Europe/Istanbul" },
+        { "UCT", "Etc/UCT" },
+        { "US/Alaska", "America/Anchorage" },
+        { "US/Aleutian", "America/Adak" },
+        { "US/Arizona", "America/Phoenix" },
+        { "US/Central", "America/Chicago" },
+        { "US/East-Indiana", "America/Indiana/Indianapolis" },
+        { "US/Eastern", "America/New_York" },
+        { "US/Hawaii", "Pacific/Honolulu" },
+        { "US/Indiana-Starke", "America/Indiana/Knox" },
+        { "US/Michigan", "America/Detroit" },
+        { "US/Mountain", "America/Denver" },
+        { "US/Pacific", "America/Los_Angeles" },
+        { "US/Samoa", "Pacific/Pago_Pago" },
+        { "UTC", "Etc/UTC" },
+        { "Universal", "Etc/UTC" },
+        { "W-SU", "Europe/Moscow" },
+        { "Zulu", "Etc/UTC" },
+    };
+
+    for (size_t i = 0; i < arraysize(link_data); ++i)
+      map_[link_data[i].old_code] = map_[link_data[i].new_code];
+  }
+
+  friend struct DefaultSingletonTraits<TimezoneMap>;
+
+  struct CompareCStrings {
+    bool operator()(const char* str1, const char* str2) const {
+      return strcmp(str1, str2) < 0;
+    }
+  };
+  std::map<const char*, const char*, CompareCStrings> map_;
+
+  DISALLOW_COPY_AND_ASSIGN(TimezoneMap);
+};
+
+}  // namespace
+
+std::string CountryCodeForCurrentTimezone() {
+  scoped_ptr<icu::TimeZone> zone(icu::TimeZone::createDefault());
+  icu::UnicodeString id;
+  zone->getID(id);
+  string16 olson_code(id.getBuffer(), id.length());
+  return TimezoneMap::GetInstance()->CountryCodeForTimezone(
+      UTF16ToUTF8(olson_code));
+}
+
+}  // namespace base
diff --git a/base/i18n/timezone.h b/base/i18n/timezone.h
new file mode 100644
index 0000000..f7fda94
--- /dev/null
+++ b/base/i18n/timezone.h
@@ -0,0 +1,21 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_I18N_TIMEZONE_H_
+#define BASE_I18N_TIMEZONE_H_
+
+#include <string>
+
+#include "base/i18n/base_i18n_export.h"
+
+namespace base {
+
+// Checks the system timezone and turns it into a two-character ASCII country
+// code. This may fail (for example, it will always fail on Android), in which
+// case it will return an empty string.
+BASE_I18N_EXPORT std::string CountryCodeForCurrentTimezone();
+
+}  // namespace base
+
+#endif  // BASE_I18N_TIMEZONE_H_
diff --git a/base/i18n/timezone_unittest.cc b/base/i18n/timezone_unittest.cc
new file mode 100644
index 0000000..2cdcc42
--- /dev/null
+++ b/base/i18n/timezone_unittest.cc
@@ -0,0 +1,21 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/i18n/timezone.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+TEST(TimezoneTest, CountryCodeForCurrentTimezone) {
+  std::string country_code = CountryCodeForCurrentTimezone();
+  // On some systems (such as Android or some flavors of Linux), icu may come up
+  // empty.
+  if (!country_code.empty())
+    EXPECT_EQ(2U, country_code.size());
+}
+
+}  // namespace
+}  // namespace base
diff --git a/base/i18n/utf8_validator_tables.cc b/base/i18n/utf8_validator_tables.cc
new file mode 100644
index 0000000..8dfa10c
--- /dev/null
+++ b/base/i18n/utf8_validator_tables.cc
@@ -0,0 +1,55 @@
+// 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 auto-generated by build_utf8_validator_tables.
+// DO NOT EDIT.
+
+#include "base/i18n/utf8_validator_tables.h"
+
+namespace base {
+namespace internal {
+
+const uint8 kUtf8ValidatorTables[] = {
+    // State 0, offset 0x00
+    0x00, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,  // 0x08
+    0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,  // 0x10
+    0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,  // 0x18
+    0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,  // 0x20
+    0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,  // 0x28
+    0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,  // 0x30
+    0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,  // 0x38
+    0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,  // 0x40
+    0x81, 0x81, 0x81, 0x83, 0x83, 0x83, 0x83, 0x83,  // 0x48
+    0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,  // 0x50
+    0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,  // 0x58
+    0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83,  // 0x60
+    0x83, 0x86, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b,  // 0x68
+    0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8e, 0x8b,  // 0x70
+    0x8b, 0x93, 0x9c, 0x9c, 0x9c, 0x9f, 0x81, 0x81,  // 0x78
+    0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,  // 0x80
+    0x81,                                            // 0x81
+    // State 1, offset 0x81
+    0x07, 0x81,                                      // 0x83
+    // State 2, offset 0x83
+    0x06, 0x00, 0x81,                                // 0x86
+    // State 3, offset 0x86
+    0x05, 0x81, 0x83, 0x81, 0x81,                    // 0x8b
+    // State 4, offset 0x8b
+    0x06, 0x83, 0x81,                                // 0x8e
+    // State 5, offset 0x8e
+    0x05, 0x83, 0x81, 0x81, 0x81,                    // 0x93
+    // State 6, offset 0x93
+    0x04, 0x81, 0x8b, 0x8b, 0x8b, 0x81, 0x81, 0x81,  // 0x9b
+    0x81,                                            // 0x9c
+    // State 7, offset 0x9c
+    0x06, 0x8b, 0x81,                                // 0x9f
+    // State 8, offset 0x9f
+    0x04, 0x8b, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,  // 0xa7
+    0x81,                                            // 0xa8
+};
+
+const size_t kUtf8ValidatorTablesSize = arraysize(kUtf8ValidatorTables);
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/i18n/utf8_validator_tables.h b/base/i18n/utf8_validator_tables.h
new file mode 100644
index 0000000..b7db56e
--- /dev/null
+++ b/base/i18n/utf8_validator_tables.h
@@ -0,0 +1,29 @@
+// 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.
+
+#ifndef BASE_I18N_UTF8_VALIDATOR_TABLES_H_
+#define BASE_I18N_UTF8_VALIDATOR_TABLES_H_
+
+#include "base/basictypes.h"
+
+namespace base {
+namespace internal {
+
+// The tables for all states; a list of entries of the form (right_shift,
+// next_state, next_state, ....). The right_shifts are used to reduce the
+// overall size of the table. The table only covers bytes in the range
+// [0x80, 0xFF] to save space.
+extern const uint8 kUtf8ValidatorTables[];
+
+extern const size_t kUtf8ValidatorTablesSize;
+
+// The offset of the INVALID state in kUtf8ValidatorTables.
+enum {
+  I18N_UTF8_VALIDATOR_INVALID_INDEX = 129
+};
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_I18N_UTF8_VALIDATOR_TABLES_H_
diff --git a/base/id_map.h b/base/id_map.h
new file mode 100644
index 0000000..852c138
--- /dev/null
+++ b/base/id_map.h
@@ -0,0 +1,279 @@
+// Copyright (c) 2011 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_ID_MAP_H_
+#define BASE_ID_MAP_H_
+
+#include <set>
+
+#include "base/basictypes.h"
+#include "base/containers/hash_tables.h"
+#include "base/logging.h"
+#include "base/threading/non_thread_safe.h"
+
+// Ownership semantics - own pointer means the pointer is deleted in Remove()
+// & during destruction
+enum IDMapOwnershipSemantics {
+  IDMapExternalPointer,
+  IDMapOwnPointer
+};
+
+// This object maintains a list of IDs that can be quickly converted to
+// pointers to objects. It is implemented as a hash table, optimized for
+// relatively small data sets (in the common case, there will be exactly one
+// item in the list).
+//
+// Items can be inserted into the container with arbitrary ID, but the caller
+// must ensure they are unique. Inserting IDs and relying on automatically
+// generated ones is not allowed because they can collide.
+//
+// This class does not have a virtual destructor, do not inherit from it when
+// ownership semantics are set to own because pointers will leak.
+template<typename T, IDMapOwnershipSemantics OS = IDMapExternalPointer>
+class IDMap : public base::NonThreadSafe {
+ public:
+  typedef int32 KeyType;
+
+ private:
+  typedef base::hash_map<KeyType, T*> HashTable;
+
+ public:
+  IDMap() : iteration_depth_(0), next_id_(1), check_on_null_data_(false) {
+    // A number of consumers of IDMap create it on one thread but always access
+    // it from a different, but consitent, thread post-construction.
+    DetachFromThread();
+  }
+
+  ~IDMap() {
+    // Many IDMap's are static, and hence will be destroyed on the main thread.
+    // However, all the accesses may take place on another thread, such as the
+    // IO thread. Detaching again to clean this up.
+    DetachFromThread();
+    Releaser<OS, 0>::release_all(&data_);
+  }
+
+  // Sets whether Add and Replace should DCHECK if passed in NULL data.
+  // Default is false.
+  void set_check_on_null_data(bool value) { check_on_null_data_ = value; }
+
+  // Adds a view with an automatically generated unique ID. See AddWithID.
+  KeyType Add(T* data) {
+    DCHECK(CalledOnValidThread());
+    DCHECK(!check_on_null_data_ || data);
+    KeyType this_id = next_id_;
+    DCHECK(data_.find(this_id) == data_.end()) << "Inserting duplicate item";
+    data_[this_id] = data;
+    next_id_++;
+    return this_id;
+  }
+
+  // Adds a new data member with the specified ID. The ID must not be in
+  // the list. The caller either must generate all unique IDs itself and use
+  // this function, or allow this object to generate IDs and call Add. These
+  // two methods may not be mixed, or duplicate IDs may be generated
+  void AddWithID(T* data, KeyType id) {
+    DCHECK(CalledOnValidThread());
+    DCHECK(!check_on_null_data_ || data);
+    DCHECK(data_.find(id) == data_.end()) << "Inserting duplicate item";
+    data_[id] = data;
+  }
+
+  void Remove(KeyType id) {
+    DCHECK(CalledOnValidThread());
+    typename HashTable::iterator i = data_.find(id);
+    if (i == data_.end()) {
+      NOTREACHED() << "Attempting to remove an item not in the list";
+      return;
+    }
+
+    if (iteration_depth_ == 0) {
+      Releaser<OS, 0>::release(i->second);
+      data_.erase(i);
+    } else {
+      removed_ids_.insert(id);
+    }
+  }
+
+  // Replaces the value for |id| with |new_data| and returns a pointer to the
+  // existing value. If there is no entry for |id|, the map is not altered and
+  // nullptr is returned. The OwnershipSemantics of the map have no effect on
+  // how the existing value is treated, the IDMap does not delete the existing
+  // value being replaced.
+  T* Replace(KeyType id, T* new_data) {
+    DCHECK(CalledOnValidThread());
+    DCHECK(!check_on_null_data_ || new_data);
+    typename HashTable::iterator i = data_.find(id);
+    if (i == data_.end()) {
+      NOTREACHED() << "Attempting to replace an item not in the list";
+      return nullptr;
+    }
+
+    T* temp = i->second;
+    i->second = new_data;
+    return temp;
+  }
+
+  void Clear() {
+    DCHECK(CalledOnValidThread());
+    if (iteration_depth_ == 0) {
+      Releaser<OS, 0>::release_all(&data_);
+    } else {
+      for (typename HashTable::iterator i = data_.begin();
+           i != data_.end(); ++i)
+        removed_ids_.insert(i->first);
+    }
+  }
+
+  bool IsEmpty() const {
+    DCHECK(CalledOnValidThread());
+    return size() == 0u;
+  }
+
+  T* Lookup(KeyType id) const {
+    DCHECK(CalledOnValidThread());
+    typename HashTable::const_iterator i = data_.find(id);
+    if (i == data_.end())
+      return NULL;
+    return i->second;
+  }
+
+  size_t size() const {
+    DCHECK(CalledOnValidThread());
+    return data_.size() - removed_ids_.size();
+  }
+
+#if defined(UNIT_TEST)
+  int iteration_depth() const {
+    return iteration_depth_;
+  }
+#endif  // defined(UNIT_TEST)
+
+  // It is safe to remove elements from the map during iteration. All iterators
+  // will remain valid.
+  template<class ReturnType>
+  class Iterator {
+   public:
+    Iterator(IDMap<T, OS>* map)
+        : map_(map),
+          iter_(map_->data_.begin()) {
+      Init();
+    }
+
+    Iterator(const Iterator& iter)
+        : map_(iter.map_),
+          iter_(iter.iter_) {
+      Init();
+    }
+
+    const Iterator& operator=(const Iterator& iter) {
+      map_ = iter.map;
+      iter_ = iter.iter;
+      Init();
+      return *this;
+    }
+
+    ~Iterator() {
+      DCHECK(map_->CalledOnValidThread());
+
+      // We're going to decrement iteration depth. Make sure it's greater than
+      // zero so that it doesn't become negative.
+      DCHECK_LT(0, map_->iteration_depth_);
+
+      if (--map_->iteration_depth_ == 0)
+        map_->Compact();
+    }
+
+    bool IsAtEnd() const {
+      DCHECK(map_->CalledOnValidThread());
+      return iter_ == map_->data_.end();
+    }
+
+    KeyType GetCurrentKey() const {
+      DCHECK(map_->CalledOnValidThread());
+      return iter_->first;
+    }
+
+    ReturnType* GetCurrentValue() const {
+      DCHECK(map_->CalledOnValidThread());
+      return iter_->second;
+    }
+
+    void Advance() {
+      DCHECK(map_->CalledOnValidThread());
+      ++iter_;
+      SkipRemovedEntries();
+    }
+
+   private:
+    void Init() {
+      DCHECK(map_->CalledOnValidThread());
+      ++map_->iteration_depth_;
+      SkipRemovedEntries();
+    }
+
+    void SkipRemovedEntries() {
+      while (iter_ != map_->data_.end() &&
+             map_->removed_ids_.find(iter_->first) !=
+             map_->removed_ids_.end()) {
+        ++iter_;
+      }
+    }
+
+    IDMap<T, OS>* map_;
+    typename HashTable::const_iterator iter_;
+  };
+
+  typedef Iterator<T> iterator;
+  typedef Iterator<const T> const_iterator;
+
+ private:
+
+  // The dummy parameter is there because C++ standard does not allow
+  // explicitly specialized templates inside classes
+  template<IDMapOwnershipSemantics OI, int dummy> struct Releaser {
+    static inline void release(T* ptr) {}
+    static inline void release_all(HashTable* table) {}
+  };
+
+  template<int dummy> struct Releaser<IDMapOwnPointer, dummy> {
+    static inline void release(T* ptr) { delete ptr;}
+    static inline void release_all(HashTable* table) {
+      for (typename HashTable::iterator i = table->begin();
+           i != table->end(); ++i) {
+        delete i->second;
+      }
+      table->clear();
+    }
+  };
+
+  void Compact() {
+    DCHECK_EQ(0, iteration_depth_);
+    for (std::set<KeyType>::const_iterator i = removed_ids_.begin();
+         i != removed_ids_.end(); ++i) {
+      Remove(*i);
+    }
+    removed_ids_.clear();
+  }
+
+  // Keep track of how many iterators are currently iterating on us to safely
+  // handle removing items during iteration.
+  int iteration_depth_;
+
+  // Keep set of IDs that should be removed after the outermost iteration has
+  // finished. This way we manage to not invalidate the iterator when an element
+  // is removed.
+  std::set<KeyType> removed_ids_;
+
+  // The next ID that we will return from Add()
+  KeyType next_id_;
+
+  HashTable data_;
+
+  // See description above setter.
+  bool check_on_null_data_;
+
+  DISALLOW_COPY_AND_ASSIGN(IDMap);
+};
+
+#endif  // BASE_ID_MAP_H_
diff --git a/base/id_map_unittest.cc b/base/id_map_unittest.cc
new file mode 100644
index 0000000..a9fb2b9
--- /dev/null
+++ b/base/id_map_unittest.cc
@@ -0,0 +1,358 @@
+// Copyright (c) 2011 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/id_map.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class TestObject {
+};
+
+class DestructorCounter {
+ public:
+  explicit DestructorCounter(int* counter) : counter_(counter) {}
+  ~DestructorCounter() { ++(*counter_); }
+
+ private:
+  int* counter_;
+};
+
+TEST(IDMapTest, Basic) {
+  IDMap<TestObject> map;
+  EXPECT_TRUE(map.IsEmpty());
+  EXPECT_EQ(0U, map.size());
+
+  TestObject obj1;
+  TestObject obj2;
+
+  int32 id1 = map.Add(&obj1);
+  EXPECT_FALSE(map.IsEmpty());
+  EXPECT_EQ(1U, map.size());
+  EXPECT_EQ(&obj1, map.Lookup(id1));
+
+  int32 id2 = map.Add(&obj2);
+  EXPECT_FALSE(map.IsEmpty());
+  EXPECT_EQ(2U, map.size());
+
+  EXPECT_EQ(&obj1, map.Lookup(id1));
+  EXPECT_EQ(&obj2, map.Lookup(id2));
+
+  map.Remove(id1);
+  EXPECT_FALSE(map.IsEmpty());
+  EXPECT_EQ(1U, map.size());
+
+  map.Remove(id2);
+  EXPECT_TRUE(map.IsEmpty());
+  EXPECT_EQ(0U, map.size());
+
+  map.AddWithID(&obj1, 1);
+  map.AddWithID(&obj2, 2);
+  EXPECT_EQ(&obj1, map.Lookup(1));
+  EXPECT_EQ(&obj2, map.Lookup(2));
+
+  EXPECT_EQ(&obj2, map.Replace(2, &obj1));
+  EXPECT_EQ(&obj1, map.Lookup(2));
+
+  EXPECT_EQ(0, map.iteration_depth());
+}
+
+TEST(IDMapTest, IteratorRemainsValidWhenRemovingCurrentElement) {
+  IDMap<TestObject> map;
+
+  TestObject obj1;
+  TestObject obj2;
+  TestObject obj3;
+
+  map.Add(&obj1);
+  map.Add(&obj2);
+  map.Add(&obj3);
+
+  {
+    IDMap<TestObject>::const_iterator iter(&map);
+
+    EXPECT_EQ(1, map.iteration_depth());
+
+    while (!iter.IsAtEnd()) {
+      map.Remove(iter.GetCurrentKey());
+      iter.Advance();
+    }
+
+    // Test that while an iterator is still in scope, we get the map emptiness
+    // right (http://crbug.com/35571).
+    EXPECT_TRUE(map.IsEmpty());
+    EXPECT_EQ(0U, map.size());
+  }
+
+  EXPECT_TRUE(map.IsEmpty());
+  EXPECT_EQ(0U, map.size());
+
+  EXPECT_EQ(0, map.iteration_depth());
+}
+
+TEST(IDMapTest, IteratorRemainsValidWhenRemovingOtherElements) {
+  IDMap<TestObject> map;
+
+  const int kCount = 5;
+  TestObject obj[kCount];
+
+  for (int i = 0; i < kCount; i++)
+    map.Add(&obj[i]);
+
+  // IDMap uses a hash_map, which has no predictable iteration order.
+  int32 ids_in_iteration_order[kCount];
+  const TestObject* objs_in_iteration_order[kCount];
+  int counter = 0;
+  for (IDMap<TestObject>::const_iterator iter(&map);
+       !iter.IsAtEnd(); iter.Advance()) {
+    ids_in_iteration_order[counter] = iter.GetCurrentKey();
+    objs_in_iteration_order[counter] = iter.GetCurrentValue();
+    counter++;
+  }
+
+  counter = 0;
+  for (IDMap<TestObject>::const_iterator iter(&map);
+       !iter.IsAtEnd(); iter.Advance()) {
+    EXPECT_EQ(1, map.iteration_depth());
+
+    switch (counter) {
+      case 0:
+        EXPECT_EQ(ids_in_iteration_order[0], iter.GetCurrentKey());
+        EXPECT_EQ(objs_in_iteration_order[0], iter.GetCurrentValue());
+        map.Remove(ids_in_iteration_order[1]);
+        break;
+      case 1:
+        EXPECT_EQ(ids_in_iteration_order[2], iter.GetCurrentKey());
+        EXPECT_EQ(objs_in_iteration_order[2], iter.GetCurrentValue());
+        map.Remove(ids_in_iteration_order[3]);
+        break;
+      case 2:
+        EXPECT_EQ(ids_in_iteration_order[4], iter.GetCurrentKey());
+        EXPECT_EQ(objs_in_iteration_order[4], iter.GetCurrentValue());
+        map.Remove(ids_in_iteration_order[0]);
+        break;
+      default:
+        FAIL() << "should not have that many elements";
+        break;
+    }
+
+    counter++;
+  }
+
+  EXPECT_EQ(0, map.iteration_depth());
+}
+
+TEST(IDMapTest, CopyIterator) {
+  IDMap<TestObject> map;
+
+  TestObject obj1;
+  TestObject obj2;
+  TestObject obj3;
+
+  map.Add(&obj1);
+  map.Add(&obj2);
+  map.Add(&obj3);
+
+  EXPECT_EQ(0, map.iteration_depth());
+
+  {
+    IDMap<TestObject>::const_iterator iter1(&map);
+    EXPECT_EQ(1, map.iteration_depth());
+
+    // Make sure that copying the iterator correctly increments
+    // map's iteration depth.
+    IDMap<TestObject>::const_iterator iter2(iter1);
+    EXPECT_EQ(2, map.iteration_depth());
+  }
+
+  // Make sure after destroying all iterators the map's iteration depth
+  // returns to initial state.
+  EXPECT_EQ(0, map.iteration_depth());
+}
+
+TEST(IDMapTest, AssignIterator) {
+  IDMap<TestObject> map;
+
+  TestObject obj1;
+  TestObject obj2;
+  TestObject obj3;
+
+  map.Add(&obj1);
+  map.Add(&obj2);
+  map.Add(&obj3);
+
+  EXPECT_EQ(0, map.iteration_depth());
+
+  {
+    IDMap<TestObject>::const_iterator iter1(&map);
+    EXPECT_EQ(1, map.iteration_depth());
+
+    IDMap<TestObject>::const_iterator iter2(&map);
+    EXPECT_EQ(2, map.iteration_depth());
+
+    // Make sure that assigning the iterator correctly updates
+    // map's iteration depth (-1 for destruction, +1 for assignment).
+    EXPECT_EQ(2, map.iteration_depth());
+  }
+
+  // Make sure after destroying all iterators the map's iteration depth
+  // returns to initial state.
+  EXPECT_EQ(0, map.iteration_depth());
+}
+
+TEST(IDMapTest, IteratorRemainsValidWhenClearing) {
+  IDMap<TestObject> map;
+
+  const int kCount = 5;
+  TestObject obj[kCount];
+
+  for (int i = 0; i < kCount; i++)
+    map.Add(&obj[i]);
+
+  // IDMap uses a hash_map, which has no predictable iteration order.
+  int32 ids_in_iteration_order[kCount];
+  const TestObject* objs_in_iteration_order[kCount];
+  int counter = 0;
+  for (IDMap<TestObject>::const_iterator iter(&map);
+       !iter.IsAtEnd(); iter.Advance()) {
+    ids_in_iteration_order[counter] = iter.GetCurrentKey();
+    objs_in_iteration_order[counter] = iter.GetCurrentValue();
+    counter++;
+  }
+
+  counter = 0;
+  for (IDMap<TestObject>::const_iterator iter(&map);
+       !iter.IsAtEnd(); iter.Advance()) {
+    switch (counter) {
+      case 0:
+        EXPECT_EQ(ids_in_iteration_order[0], iter.GetCurrentKey());
+        EXPECT_EQ(objs_in_iteration_order[0], iter.GetCurrentValue());
+        break;
+      case 1:
+        EXPECT_EQ(ids_in_iteration_order[1], iter.GetCurrentKey());
+        EXPECT_EQ(objs_in_iteration_order[1], iter.GetCurrentValue());
+        map.Clear();
+        EXPECT_TRUE(map.IsEmpty());
+        EXPECT_EQ(0U, map.size());
+        break;
+      default:
+        FAIL() << "should not have that many elements";
+        break;
+    }
+    counter++;
+  }
+
+  EXPECT_TRUE(map.IsEmpty());
+  EXPECT_EQ(0U, map.size());
+}
+
+TEST(IDMapTest, OwningPointersDeletesThemOnRemove) {
+  const int kCount = 3;
+
+  int external_del_count = 0;
+  DestructorCounter* external_obj[kCount];
+  int map_external_ids[kCount];
+
+  int owned_del_count = 0;
+  DestructorCounter* owned_obj[kCount];
+  int map_owned_ids[kCount];
+
+  IDMap<DestructorCounter> map_external;
+  IDMap<DestructorCounter, IDMapOwnPointer> map_owned;
+
+  for (int i = 0; i < kCount; ++i) {
+    external_obj[i] = new DestructorCounter(&external_del_count);
+    map_external_ids[i] = map_external.Add(external_obj[i]);
+
+    owned_obj[i] = new DestructorCounter(&owned_del_count);
+    map_owned_ids[i] = map_owned.Add(owned_obj[i]);
+  }
+
+  for (int i = 0; i < kCount; ++i) {
+    EXPECT_EQ(external_del_count, 0);
+    EXPECT_EQ(owned_del_count, i);
+
+    map_external.Remove(map_external_ids[i]);
+    map_owned.Remove(map_owned_ids[i]);
+  }
+
+  for (int i = 0; i < kCount; ++i) {
+    delete external_obj[i];
+  }
+
+  EXPECT_EQ(external_del_count, kCount);
+  EXPECT_EQ(owned_del_count, kCount);
+}
+
+TEST(IDMapTest, OwningPointersDeletesThemOnClear) {
+  const int kCount = 3;
+
+  int external_del_count = 0;
+  DestructorCounter* external_obj[kCount];
+
+  int owned_del_count = 0;
+  DestructorCounter* owned_obj[kCount];
+
+  IDMap<DestructorCounter> map_external;
+  IDMap<DestructorCounter, IDMapOwnPointer> map_owned;
+
+  for (int i = 0; i < kCount; ++i) {
+    external_obj[i] = new DestructorCounter(&external_del_count);
+    map_external.Add(external_obj[i]);
+
+    owned_obj[i] = new DestructorCounter(&owned_del_count);
+    map_owned.Add(owned_obj[i]);
+  }
+
+  EXPECT_EQ(external_del_count, 0);
+  EXPECT_EQ(owned_del_count, 0);
+
+  map_external.Clear();
+  map_owned.Clear();
+
+  EXPECT_EQ(external_del_count, 0);
+  EXPECT_EQ(owned_del_count, kCount);
+
+  for (int i = 0; i < kCount; ++i) {
+    delete external_obj[i];
+  }
+
+  EXPECT_EQ(external_del_count, kCount);
+  EXPECT_EQ(owned_del_count, kCount);
+}
+
+TEST(IDMapTest, OwningPointersDeletesThemOnDestruct) {
+  const int kCount = 3;
+
+  int external_del_count = 0;
+  DestructorCounter* external_obj[kCount];
+
+  int owned_del_count = 0;
+  DestructorCounter* owned_obj[kCount];
+
+  {
+    IDMap<DestructorCounter> map_external;
+    IDMap<DestructorCounter, IDMapOwnPointer> map_owned;
+
+    for (int i = 0; i < kCount; ++i) {
+      external_obj[i] = new DestructorCounter(&external_del_count);
+      map_external.Add(external_obj[i]);
+
+      owned_obj[i] = new DestructorCounter(&owned_del_count);
+      map_owned.Add(owned_obj[i]);
+    }
+  }
+
+  EXPECT_EQ(external_del_count, 0);
+
+  for (int i = 0; i < kCount; ++i) {
+    delete external_obj[i];
+  }
+
+  EXPECT_EQ(external_del_count, kCount);
+  EXPECT_EQ(owned_del_count, kCount);
+}
+
+}  // namespace
diff --git a/base/ios/OWNERS b/base/ios/OWNERS
new file mode 100644
index 0000000..dc0be62
--- /dev/null
+++ b/base/ios/OWNERS
@@ -0,0 +1,4 @@
+droger@chromium.org
+qsr@chromium.org
+rohitrao@chromium.org
+stuartmorgan@chromium.org
diff --git a/base/ios/block_types.h b/base/ios/block_types.h
new file mode 100644
index 0000000..e4dde79
--- /dev/null
+++ b/base/ios/block_types.h
@@ -0,0 +1,14 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_IOS_BLOCK_TYPES_H_
+#define BASE_IOS_BLOCK_TYPES_H_
+
+// A generic procedural block type that takes no arguments and returns nothing.
+typedef void (^ProceduralBlock)(void);
+
+// A block that takes no arguments and returns a bool.
+typedef bool (^ConditionBlock)(void);
+
+#endif  // BASE_IOS_BLOCK_TYPES_H_
diff --git a/base/ios/crb_protocol_observers.h b/base/ios/crb_protocol_observers.h
new file mode 100644
index 0000000..8ff5878
--- /dev/null
+++ b/base/ios/crb_protocol_observers.h
@@ -0,0 +1,43 @@
+// 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.
+
+#ifndef BASE_IOS_CRB_PROTOCOL_OBSERVERS_H_
+#define BASE_IOS_CRB_PROTOCOL_OBSERVERS_H_
+
+#import <Foundation/Foundation.h>
+
+typedef void (^ExecutionWithObserverBlock)(id);
+
+// Implements a container for observers that implement a specific Objective-C
+// protocol. The container forwards method invocations to its contained
+// observers, so that sending a message to all the observers is as simple as
+// sending the message to the container.
+// It is safe for an observer to remove itself or another observer while being
+// notified. It is also safe to add an other observer while being notified but
+// the newly added observer will not be notified as part of the current
+// notification dispatch.
+@interface CRBProtocolObservers : NSObject
+
+// The Objective-C protocol that the observers in this container conform to.
+@property(nonatomic, readonly) Protocol* protocol;
+
+// Returns a CRBProtocolObservers container for observers that conform to
+// |protocol|.
++ (instancetype)observersWithProtocol:(Protocol*)protocol;
+
+// Adds |observer| to this container.
+- (void)addObserver:(id)observer;
+
+// Remove |observer| from this container.
+- (void)removeObserver:(id)observer;
+
+// Returns true if there are currently no observers.
+- (BOOL)empty;
+
+// Executes callback on every observer. |callback| cannot be nil.
+- (void)executeOnObservers:(ExecutionWithObserverBlock)callback;
+
+@end
+
+#endif  // BASE_IOS_CRB_PROTOCOL_OBSERVERS_H_
diff --git a/base/ios/crb_protocol_observers.mm b/base/ios/crb_protocol_observers.mm
new file mode 100644
index 0000000..90a277b
--- /dev/null
+++ b/base/ios/crb_protocol_observers.mm
@@ -0,0 +1,190 @@
+// 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.
+
+#import "base/ios/crb_protocol_observers.h"
+
+#include <objc/runtime.h>
+#include <algorithm>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/mac/scoped_nsobject.h"
+
+@interface CRBProtocolObservers () {
+  base::scoped_nsobject<Protocol> _protocol;
+  // ivars declared here are private to the implementation but must be
+  // public for allowing the C++ |Iterator| class access to those ivars.
+ @public
+  // vector of weak pointers to observers.
+  std::vector<__unsafe_unretained id> _observers;
+  // The nested level of observer iteration.
+  // A depth of 0 means nobody is currently iterating on the list of observers.
+  int _invocationDepth;
+}
+
+// Removes nil observers from the list and is called when the
+// |_invocationDepth| reaches 0.
+- (void)compact;
+
+@end
+
+namespace {
+
+class Iterator {
+ public:
+  explicit Iterator(CRBProtocolObservers* protocol_observers);
+  ~Iterator();
+  id GetNext();
+
+ private:
+  CRBProtocolObservers* protocol_observers_;
+  size_t index_;
+  size_t max_index_;
+};
+
+Iterator::Iterator(CRBProtocolObservers* protocol_observers)
+    : protocol_observers_(protocol_observers),
+      index_(0),
+      max_index_(protocol_observers->_observers.size()) {
+  DCHECK(protocol_observers_);
+  ++protocol_observers->_invocationDepth;
+}
+
+Iterator::~Iterator() {
+  if (protocol_observers_ && --protocol_observers_->_invocationDepth == 0)
+    [protocol_observers_ compact];
+}
+
+id Iterator::GetNext() {
+  if (!protocol_observers_)
+    return nil;
+  auto& observers = protocol_observers_->_observers;
+  // Skip nil elements.
+  size_t max_index = std::min(max_index_, observers.size());
+  while (index_ < max_index && !observers[index_])
+    ++index_;
+  return index_ < max_index ? observers[index_++] : nil;
+}
+}
+
+@interface CRBProtocolObservers ()
+
+// Designated initializer.
+- (id)initWithProtocol:(Protocol*)protocol;
+
+@end
+
+@implementation CRBProtocolObservers
+
++ (instancetype)observersWithProtocol:(Protocol*)protocol {
+  return [[[self alloc] initWithProtocol:protocol] autorelease];
+}
+
+- (id)init {
+  NOTREACHED();
+  return nil;
+}
+
+- (id)initWithProtocol:(Protocol*)protocol {
+  self = [super init];
+  if (self) {
+    _protocol.reset([protocol retain]);
+  }
+  return self;
+}
+
+- (Protocol*)protocol {
+  return _protocol.get();
+}
+
+- (void)addObserver:(id)observer {
+  DCHECK(observer);
+  DCHECK([observer conformsToProtocol:self.protocol]);
+
+  if (std::find(_observers.begin(), _observers.end(), observer) !=
+      _observers.end())
+    return;
+
+  _observers.push_back(observer);
+}
+
+- (void)removeObserver:(id)observer {
+  DCHECK(observer);
+  auto it = std::find(_observers.begin(), _observers.end(), observer);
+  if (it != _observers.end()) {
+    if (_invocationDepth)
+      *it = nil;
+    else
+      _observers.erase(it);
+  }
+}
+
+- (BOOL)empty {
+  int count = 0;
+  for (id observer : _observers) {
+    if (observer != nil)
+      ++count;
+  }
+  return count == 0;
+}
+
+#pragma mark - NSObject
+
+- (NSMethodSignature*)methodSignatureForSelector:(SEL)selector {
+  NSMethodSignature* signature = [super methodSignatureForSelector:selector];
+  if (signature)
+    return signature;
+
+  // Look for a required method in the protocol. protocol_getMethodDescription
+  // returns a struct whose fields are null if a method for the selector was
+  // not found.
+  struct objc_method_description description =
+      protocol_getMethodDescription(self.protocol, selector, YES, YES);
+  if (description.types)
+    return [NSMethodSignature signatureWithObjCTypes:description.types];
+
+  // Look for an optional method in the protocol.
+  description = protocol_getMethodDescription(self.protocol, selector, NO, YES);
+  if (description.types)
+    return [NSMethodSignature signatureWithObjCTypes:description.types];
+
+  // There is neither a required nor optional method with this selector in the
+  // protocol, so invoke -[NSObject doesNotRecognizeSelector:] to raise
+  // NSInvalidArgumentException.
+  [self doesNotRecognizeSelector:selector];
+  return nil;
+}
+
+- (void)forwardInvocation:(NSInvocation*)invocation {
+  DCHECK(invocation);
+  if (_observers.empty())
+    return;
+  SEL selector = [invocation selector];
+  Iterator it(self);
+  id observer;
+  while ((observer = it.GetNext()) != nil) {
+    if ([observer respondsToSelector:selector])
+      [invocation invokeWithTarget:observer];
+  }
+}
+
+- (void)executeOnObservers:(ExecutionWithObserverBlock)callback {
+  DCHECK(callback);
+  if (_observers.empty())
+    return;
+  Iterator it(self);
+  id observer;
+  while ((observer = it.GetNext()) != nil)
+    callback(observer);
+}
+
+#pragma mark - Private
+
+- (void)compact {
+  DCHECK(!_invocationDepth);
+  _observers.erase(std::remove(_observers.begin(), _observers.end(), nil),
+                   _observers.end());
+}
+
+@end
diff --git a/base/ios/crb_protocol_observers_unittest.mm b/base/ios/crb_protocol_observers_unittest.mm
new file mode 100644
index 0000000..b8cf423
--- /dev/null
+++ b/base/ios/crb_protocol_observers_unittest.mm
@@ -0,0 +1,290 @@
+// 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.
+
+#import "base/ios/crb_protocol_observers.h"
+#include "base/ios/weak_nsobject.h"
+#include "base/logging.h"
+#include "base/mac/scoped_nsautorelease_pool.h"
+#include "base/mac/scoped_nsobject.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+
+@protocol TestObserver
+
+@required
+- (void)requiredMethod;
+- (void)reset;
+
+@optional
+- (void)optionalMethod;
+- (void)mutateByAddingObserver:(id<TestObserver>)observer;
+- (void)mutateByRemovingObserver:(id<TestObserver>)observer;
+- (void)nestedMutateByAddingObserver:(id<TestObserver>)observer;
+- (void)nestedMutateByRemovingObserver:(id<TestObserver>)observer;
+
+@end
+
+// Implements only the required methods in the TestObserver protocol.
+@interface TestPartialObserver : NSObject<TestObserver>
+@property(nonatomic, readonly) BOOL requiredMethodInvoked;
+@end
+
+// Implements all the methods in the TestObserver protocol.
+@interface TestCompleteObserver : TestPartialObserver<TestObserver>
+@property(nonatomic, readonly) BOOL optionalMethodInvoked;
+@end
+
+@interface TestMutateObserver : TestCompleteObserver
+- (instancetype)initWithObserver:(CRBProtocolObservers*)observer
+    NS_DESIGNATED_INITIALIZER;
+- (instancetype)init NS_UNAVAILABLE;
+@end
+
+namespace {
+
+class CRBProtocolObserversTest : public PlatformTest {
+ public:
+  CRBProtocolObserversTest() {}
+
+ protected:
+  void SetUp() override {
+    PlatformTest::SetUp();
+
+    observers_.reset([[CRBProtocolObservers observersWithProtocol:
+        @protocol(TestObserver)] retain]);
+
+    partial_observer_.reset([[TestPartialObserver alloc] init]);
+    EXPECT_FALSE([partial_observer_ requiredMethodInvoked]);
+
+    complete_observer_.reset([[TestCompleteObserver alloc] init]);
+    EXPECT_FALSE([complete_observer_ requiredMethodInvoked]);
+    EXPECT_FALSE([complete_observer_ optionalMethodInvoked]);
+
+    mutate_observer_.reset(
+        [[TestMutateObserver alloc] initWithObserver:observers_.get()]);
+    EXPECT_FALSE([mutate_observer_ requiredMethodInvoked]);
+  }
+
+  base::scoped_nsobject<id> observers_;
+  base::scoped_nsobject<TestPartialObserver> partial_observer_;
+  base::scoped_nsobject<TestCompleteObserver> complete_observer_;
+  base::scoped_nsobject<TestMutateObserver> mutate_observer_;
+};
+
+// Verifies basic functionality of -[CRBProtocolObservers addObserver:] and
+// -[CRBProtocolObservers removeObserver:].
+TEST_F(CRBProtocolObserversTest, AddRemoveObserver) {
+  // Add an observer and verify that the CRBProtocolObservers instance forwards
+  // an invocation to it.
+  [observers_ addObserver:partial_observer_];
+  [observers_ requiredMethod];
+  EXPECT_TRUE([partial_observer_ requiredMethodInvoked]);
+
+  [partial_observer_ reset];
+  EXPECT_FALSE([partial_observer_ requiredMethodInvoked]);
+
+  // Remove the observer and verify that the CRBProtocolObservers instance no
+  // longer forwards an invocation to it.
+  [observers_ removeObserver:partial_observer_];
+  [observers_ requiredMethod];
+  EXPECT_FALSE([partial_observer_ requiredMethodInvoked]);
+}
+
+// Verifies that CRBProtocolObservers correctly forwards the invocation of a
+// required method in the protocol.
+TEST_F(CRBProtocolObserversTest, RequiredMethods) {
+  [observers_ addObserver:partial_observer_];
+  [observers_ addObserver:complete_observer_];
+  [observers_ requiredMethod];
+  EXPECT_TRUE([partial_observer_ requiredMethodInvoked]);
+  EXPECT_TRUE([complete_observer_ requiredMethodInvoked]);
+}
+
+// Verifies that CRBProtocolObservers correctly forwards the invocation of an
+// optional method in the protocol.
+TEST_F(CRBProtocolObserversTest, OptionalMethods) {
+  [observers_ addObserver:partial_observer_];
+  [observers_ addObserver:complete_observer_];
+  [observers_ optionalMethod];
+  EXPECT_FALSE([partial_observer_ requiredMethodInvoked]);
+  EXPECT_FALSE([complete_observer_ requiredMethodInvoked]);
+  EXPECT_TRUE([complete_observer_ optionalMethodInvoked]);
+}
+
+// Verifies that CRBProtocolObservers only holds a weak reference to an
+// observer.
+TEST_F(CRBProtocolObserversTest, WeakReference) {
+  base::WeakNSObject<TestPartialObserver> weak_observer(
+      partial_observer_);
+  EXPECT_TRUE(weak_observer);
+
+  [observers_ addObserver:partial_observer_];
+
+  {
+    // Need an autorelease pool here, because
+    // -[CRBProtocolObservers forwardInvocation:] creates a temporary
+    // autoreleased array that holds all the observers.
+    base::mac::ScopedNSAutoreleasePool pool;
+    [observers_ requiredMethod];
+    EXPECT_TRUE([partial_observer_ requiredMethodInvoked]);
+  }
+
+  partial_observer_.reset();
+  EXPECT_FALSE(weak_observer.get());
+}
+
+// Verifies that an observer can safely remove itself as observer while being
+// notified.
+TEST_F(CRBProtocolObserversTest, SelfMutateObservers) {
+  [observers_ addObserver:mutate_observer_];
+  EXPECT_FALSE([observers_ empty]);
+
+  [observers_ requiredMethod];
+  EXPECT_TRUE([mutate_observer_ requiredMethodInvoked]);
+
+  [mutate_observer_ reset];
+
+  [observers_ nestedMutateByRemovingObserver:mutate_observer_];
+  EXPECT_FALSE([mutate_observer_ requiredMethodInvoked]);
+
+  [observers_ addObserver:partial_observer_];
+
+  [observers_ requiredMethod];
+  EXPECT_FALSE([mutate_observer_ requiredMethodInvoked]);
+  EXPECT_TRUE([partial_observer_ requiredMethodInvoked]);
+
+  [observers_ removeObserver:partial_observer_];
+  EXPECT_TRUE([observers_ empty]);
+}
+
+// Verifies that - [CRBProtocolObservers addObserver:] and
+// - [CRBProtocolObservers removeObserver:] can be called while methods are
+// being forwarded.
+TEST_F(CRBProtocolObserversTest, MutateObservers) {
+  // Indirectly add an observer while forwarding an observer method.
+  [observers_ addObserver:mutate_observer_];
+
+  [observers_ mutateByAddingObserver:partial_observer_];
+  EXPECT_FALSE([partial_observer_ requiredMethodInvoked]);
+
+  // Check that methods are correctly forwared to the indirectly added observer.
+  [mutate_observer_ reset];
+  [observers_ requiredMethod];
+  EXPECT_TRUE([mutate_observer_ requiredMethodInvoked]);
+  EXPECT_TRUE([partial_observer_ requiredMethodInvoked]);
+
+  [mutate_observer_ reset];
+  [partial_observer_ reset];
+
+  // Indirectly remove an observer while forwarding an observer method.
+  [observers_ mutateByRemovingObserver:partial_observer_];
+
+  // Check that method is not forwared to the indirectly removed observer.
+  [observers_ requiredMethod];
+  EXPECT_TRUE([mutate_observer_ requiredMethodInvoked]);
+  EXPECT_FALSE([partial_observer_ requiredMethodInvoked]);
+}
+
+// Verifies that - [CRBProtocolObservers addObserver:] and
+// - [CRBProtocolObservers removeObserver:] can be called while methods are
+// being forwarded with a nested invocation depth > 0.
+TEST_F(CRBProtocolObserversTest, NestedMutateObservers) {
+  // Indirectly add an observer while forwarding an observer method.
+  [observers_ addObserver:mutate_observer_];
+
+  [observers_ nestedMutateByAddingObserver:partial_observer_];
+  EXPECT_FALSE([partial_observer_ requiredMethodInvoked]);
+
+  // Check that methods are correctly forwared to the indirectly added observer.
+  [mutate_observer_ reset];
+  [observers_ requiredMethod];
+  EXPECT_TRUE([mutate_observer_ requiredMethodInvoked]);
+  EXPECT_TRUE([partial_observer_ requiredMethodInvoked]);
+
+  [mutate_observer_ reset];
+  [partial_observer_ reset];
+
+  // Indirectly remove an observer while forwarding an observer method.
+  [observers_ nestedMutateByRemovingObserver:partial_observer_];
+
+  // Check that method is not forwared to the indirectly removed observer.
+  [observers_ requiredMethod];
+  EXPECT_TRUE([mutate_observer_ requiredMethodInvoked]);
+  EXPECT_FALSE([partial_observer_ requiredMethodInvoked]);
+}
+
+}  // namespace
+
+@implementation TestPartialObserver {
+  BOOL _requiredMethodInvoked;
+}
+
+- (BOOL)requiredMethodInvoked {
+  return _requiredMethodInvoked;
+}
+
+- (void)requiredMethod {
+  _requiredMethodInvoked = YES;
+}
+
+- (void)reset {
+  _requiredMethodInvoked = NO;
+}
+
+@end
+
+@implementation TestCompleteObserver {
+  BOOL _optionalMethodInvoked;
+}
+
+- (BOOL)optionalMethodInvoked {
+  return _optionalMethodInvoked;
+}
+
+- (void)optionalMethod {
+  _optionalMethodInvoked = YES;
+}
+
+- (void)reset {
+  [super reset];
+  _optionalMethodInvoked = NO;
+}
+
+@end
+
+@implementation TestMutateObserver {
+  __weak id _observers;
+}
+
+- (instancetype)initWithObserver:(CRBProtocolObservers*)observers {
+  self = [super init];
+  if (self) {
+    _observers = observers;
+  }
+  return self;
+}
+
+- (instancetype)init {
+  NOTREACHED();
+  return nil;
+}
+
+- (void)mutateByAddingObserver:(id<TestObserver>)observer {
+  [_observers addObserver:observer];
+}
+
+- (void)mutateByRemovingObserver:(id<TestObserver>)observer {
+  [_observers removeObserver:observer];
+}
+
+- (void)nestedMutateByAddingObserver:(id<TestObserver>)observer {
+  [_observers mutateByAddingObserver:observer];
+}
+
+- (void)nestedMutateByRemovingObserver:(id<TestObserver>)observer {
+  [_observers mutateByRemovingObserver:observer];
+}
+
+@end
diff --git a/base/ios/device_util.h b/base/ios/device_util.h
new file mode 100644
index 0000000..1cd9a04
--- /dev/null
+++ b/base/ios/device_util.h
@@ -0,0 +1,84 @@
+// Copyright (c) 2012 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_IOS_DEVICE_UTIL_H_
+#define BASE_IOS_DEVICE_UTIL_H_
+
+#include <string>
+
+namespace ios {
+namespace device_util {
+
+// Returns the hardware version of the device the app is running on.
+//
+// The returned string is the string returned by sysctlbyname() with name
+// "hw.machine". Possible (known) values include:
+//
+// iPhone1,1 -> iPhone 1G
+// iPhone1,2 -> iPhone 3G
+// iPhone2,1 -> iPhone 3GS
+// iPhone3,1 -> iPhone 4/AT&T
+// iPhone3,2 -> iPhone 4/Other Carrier?
+// iPhone3,3 -> iPhone 4/Other Carrier?
+// iPhone4,1 -> iPhone 4S
+//
+// iPod1,1   -> iPod touch 1G
+// iPod2,1   -> iPod touch 2G
+// iPod2,2   -> ?
+// iPod3,1   -> iPod touch 3G
+// iPod4,1   -> iPod touch 4G
+// iPod5,1   -> ?
+//
+// iPad1,1   -> iPad 1G, WiFi
+// iPad1,?   -> iPad 1G, 3G <- needs 3G owner to test
+// iPad2,1   -> iPad 2G, WiFi
+//
+// AppleTV2,1 -> AppleTV 2
+//
+// i386       -> Simulator
+// x86_64     -> Simulator
+std::string GetPlatform();
+
+// Returns true if the application is running on a device with 512MB or more
+// RAM.
+bool RamIsAtLeast512Mb();
+
+// Returns true if the application is running on a device with 1024MB or more
+// RAM.
+bool RamIsAtLeast1024Mb();
+
+// Returns true if the application is running on a device with |ram_in_mb| MB or
+// more RAM.
+// Use with caution! Actual RAM reported by devices is less than the commonly
+// used powers-of-two values. For example, a 512MB device may report only 502MB
+// RAM. The convenience methods above should be used in most cases because they
+// correctly handle this issue.
+bool RamIsAtLeast(uint64_t ram_in_mb);
+
+// Returns true if the device has only one core.
+bool IsSingleCoreDevice();
+
+// Returns the MAC address of the interface with name |interface_name|.
+std::string GetMacAddress(const std::string& interface_name);
+
+// Returns a random UUID.
+std::string GetRandomId();
+
+// Returns an identifier for the device, using the given |salt|. A global
+// identifier is generated the first time this method is called, and the salt
+// is used to be able to generate distinct identifiers for the same device. If
+// |salt| is NULL, a default value is used. Unless you are using this value for
+// something that should be anonymous, you should probably pass NULL.
+std::string GetDeviceIdentifier(const char* salt);
+
+// Returns a hashed version of |in_string| using |salt| (which must not be
+// zero-length). Different salt values should result in differently hashed
+// strings.
+std::string GetSaltedString(const std::string& in_string,
+                            const std::string& salt);
+
+}  // namespace device_util
+}  // namespace ios
+
+#endif  // BASE_IOS_DEVICE_UTIL_H_
diff --git a/base/ios/device_util.mm b/base/ios/device_util.mm
new file mode 100644
index 0000000..1234562
--- /dev/null
+++ b/base/ios/device_util.mm
@@ -0,0 +1,177 @@
+// Copyright (c) 2012 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/ios/device_util.h"
+
+#include <CommonCrypto/CommonDigest.h>
+#import <UIKit/UIKit.h>
+
+#include <ifaddrs.h>
+#include <net/if_dl.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include "base/logging.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/sys_string_conversions.h"
+
+namespace {
+
+// Client ID key in the user preferences.
+NSString* const kLegacyClientIdPreferenceKey = @"ChromiumClientID";
+NSString* const kClientIdPreferenceKey = @"ChromeClientID";
+// Current hardware type. This is used to detect that a device has been backed
+// up and restored to another device, and allows regenerating a new device id.
+NSString* const kHardwareTypePreferenceKey = @"ClientIDGenerationHardwareType";
+// Default salt for device ids.
+const char kDefaultSalt[] = "Salt";
+// Zero UUID returned on buggy iOS devices.
+NSString* const kZeroUUID = @"00000000-0000-0000-0000-000000000000";
+
+NSString* GenerateClientId() {
+  NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+
+  // Try to migrate from legacy client id.
+  NSString* client_id = [defaults stringForKey:kLegacyClientIdPreferenceKey];
+
+  // Some iOS6 devices return a buggy identifierForVendor:
+  // http://openradar.appspot.com/12377282. If this is the case, revert to
+  // generating a new one.
+  if (!client_id || [client_id isEqualToString:kZeroUUID]) {
+    client_id = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
+    if ([client_id isEqualToString:kZeroUUID])
+      client_id = base::SysUTF8ToNSString(ios::device_util::GetRandomId());
+  }
+  return client_id;
+}
+
+}  // namespace
+
+namespace ios {
+namespace device_util {
+
+std::string GetPlatform() {
+  std::string platform;
+  size_t size = 0;
+  sysctlbyname("hw.machine", NULL, &size, NULL, 0);
+  sysctlbyname("hw.machine", WriteInto(&platform, size), &size, NULL, 0);
+  return platform;
+}
+
+bool RamIsAtLeast512Mb() {
+  // 512MB devices report anywhere from 502-504 MB, use 450 MB just to be safe.
+  return RamIsAtLeast(450);
+}
+
+bool RamIsAtLeast1024Mb() {
+  // 1GB devices report anywhere from 975-999 MB, use 900 MB just to be safe.
+  return RamIsAtLeast(900);
+}
+
+bool RamIsAtLeast(uint64_t ram_in_mb) {
+  uint64_t memory_size = 0;
+  size_t size = sizeof(memory_size);
+  if (sysctlbyname("hw.memsize", &memory_size, &size, NULL, 0) == 0) {
+    // Anything >= 500M, call high ram.
+    return memory_size >= ram_in_mb * 1024 * 1024;
+  }
+  return false;
+}
+
+bool IsSingleCoreDevice() {
+  uint64_t cpu_number = 0;
+  size_t sizes = sizeof(cpu_number);
+  sysctlbyname("hw.physicalcpu", &cpu_number, &sizes, NULL, 0);
+  return cpu_number == 1;
+}
+
+std::string GetMacAddress(const std::string& interface_name) {
+  std::string mac_string;
+  struct ifaddrs* addresses;
+  if (getifaddrs(&addresses) == 0) {
+    for (struct ifaddrs* address = addresses; address;
+         address = address->ifa_next) {
+      if ((address->ifa_addr->sa_family == AF_LINK) &&
+          strcmp(interface_name.c_str(), address->ifa_name) == 0) {
+        const struct sockaddr_dl* found_address_struct =
+            reinterpret_cast<const struct sockaddr_dl*>(address->ifa_addr);
+
+        // |found_address_struct->sdl_data| contains the interface name followed
+        // by the interface address. The address part can be accessed based on
+        // the length of the name, that is, |found_address_struct->sdl_nlen|.
+        const unsigned char* found_address =
+            reinterpret_cast<const unsigned char*>(
+                &found_address_struct->sdl_data[
+                    found_address_struct->sdl_nlen]);
+
+        int found_address_length = found_address_struct->sdl_alen;
+        for (int i = 0; i < found_address_length; ++i) {
+          if (i != 0)
+            mac_string.push_back(':');
+          base::StringAppendF(&mac_string, "%02X", found_address[i]);
+        }
+        break;
+      }
+    }
+    freeifaddrs(addresses);
+  }
+  return mac_string;
+}
+
+std::string GetRandomId() {
+  base::ScopedCFTypeRef<CFUUIDRef> uuid_object(
+      CFUUIDCreate(kCFAllocatorDefault));
+  base::ScopedCFTypeRef<CFStringRef> uuid_string(
+      CFUUIDCreateString(kCFAllocatorDefault, uuid_object));
+  return base::SysCFStringRefToUTF8(uuid_string);
+}
+
+std::string GetDeviceIdentifier(const char* salt) {
+  NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+
+  NSString* last_seen_hardware =
+      [defaults stringForKey:kHardwareTypePreferenceKey];
+  NSString* current_hardware = base::SysUTF8ToNSString(GetPlatform());
+  if (!last_seen_hardware) {
+    last_seen_hardware = current_hardware;
+    [defaults setObject:current_hardware forKey:kHardwareTypePreferenceKey];
+    [defaults synchronize];
+  }
+
+  NSString* client_id = [defaults stringForKey:kClientIdPreferenceKey];
+
+  if (!client_id || ![last_seen_hardware isEqualToString:current_hardware]) {
+    client_id = GenerateClientId();
+    [defaults setObject:client_id forKey:kClientIdPreferenceKey];
+    [defaults setObject:current_hardware forKey:kHardwareTypePreferenceKey];
+    [defaults synchronize];
+  }
+
+  return GetSaltedString(base::SysNSStringToUTF8(client_id),
+                         salt ? salt : kDefaultSalt);
+}
+
+std::string GetSaltedString(const std::string& in_string,
+                            const std::string& salt) {
+  DCHECK(salt.length());
+  NSData* hash_data = [base::SysUTF8ToNSString(in_string + salt)
+      dataUsingEncoding:NSUTF8StringEncoding];
+
+  unsigned char hash[CC_SHA256_DIGEST_LENGTH];
+  CC_SHA256([hash_data bytes], [hash_data length], hash);
+  CFUUIDBytes* uuid_bytes = reinterpret_cast<CFUUIDBytes*>(hash);
+
+  base::ScopedCFTypeRef<CFUUIDRef> uuid_object(
+      CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault, *uuid_bytes));
+  base::ScopedCFTypeRef<CFStringRef> device_id(
+      CFUUIDCreateString(kCFAllocatorDefault, uuid_object));
+  return base::SysCFStringRefToUTF8(device_id);
+}
+
+}  // namespace device_util
+}  // namespace ios
diff --git a/base/ios/device_util_unittest.mm b/base/ios/device_util_unittest.mm
new file mode 100644
index 0000000..82d4217
--- /dev/null
+++ b/base/ios/device_util_unittest.mm
@@ -0,0 +1,143 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <UIKit/UIKit.h>
+
+#include "base/ios/device_util.h"
+#include "base/strings/sys_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/gtest_mac.h"
+#include "testing/platform_test.h"
+
+namespace {
+// The behavior of most of these utility functions depends on what they are run
+// on, so there is not much to unittest them. The APIs are run to make sure they
+// don't choke. Additional checks are added for particular APIs when needed.
+
+typedef PlatformTest DeviceUtilTest;
+
+void CleanNSUserDefaultsForDeviceId() {
+  NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+  [defaults removeObjectForKey:@"ChromeClientID"];
+  [defaults removeObjectForKey:@"ChromiumClientID"];
+  [defaults removeObjectForKey:@"ClientIDGenerationHardwareType"];
+  [defaults synchronize];
+}
+
+TEST_F(DeviceUtilTest, GetPlatform) {
+  GTEST_ASSERT_GT(ios::device_util::GetPlatform().length(), 0U);
+}
+
+TEST_F(DeviceUtilTest, IsSingleCoreDevice) {
+  ios::device_util::IsSingleCoreDevice();
+}
+
+TEST_F(DeviceUtilTest, GetMacAddress) {
+  GTEST_ASSERT_GT(ios::device_util::GetMacAddress("en0").length(), 0U);
+}
+
+TEST_F(DeviceUtilTest, GetRandomId) {
+  GTEST_ASSERT_GT(ios::device_util::GetRandomId().length(), 0U);
+}
+
+TEST_F(DeviceUtilTest, GetDeviceIdentifier) {
+  CleanNSUserDefaultsForDeviceId();
+
+  std::string default_id = ios::device_util::GetDeviceIdentifier(NULL);
+  std::string other_id = ios::device_util::GetDeviceIdentifier("ForTest");
+  EXPECT_NE(default_id, other_id);
+
+  CleanNSUserDefaultsForDeviceId();
+
+  std::string new_default_id = ios::device_util::GetDeviceIdentifier(NULL);
+  if (![[[[UIDevice currentDevice] identifierForVendor] UUIDString]
+          isEqualToString:@"00000000-0000-0000-0000-000000000000"]) {
+    EXPECT_EQ(default_id, new_default_id);
+  } else {
+    EXPECT_NE(default_id, new_default_id);
+  }
+
+  CleanNSUserDefaultsForDeviceId();
+}
+
+TEST_F(DeviceUtilTest, CheckMigration) {
+  CleanNSUserDefaultsForDeviceId();
+
+  NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+  [defaults setObject:@"10000000-0000-0000-0000-000000000000"
+               forKey:@"ChromeClientID"];
+  [defaults synchronize];
+  std::string expected_id = ios::device_util::GetDeviceIdentifier(NULL);
+  [defaults removeObjectForKey:@"ChromeClientID"];
+  [defaults setObject:@"10000000-0000-0000-0000-000000000000"
+               forKey:@"ChromiumClientID"];
+  [defaults synchronize];
+  std::string new_id = ios::device_util::GetDeviceIdentifier(NULL);
+  EXPECT_EQ(expected_id, new_id);
+
+  CleanNSUserDefaultsForDeviceId();
+}
+
+TEST_F(DeviceUtilTest, CheckMigrationFromZero) {
+  CleanNSUserDefaultsForDeviceId();
+
+  NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+  [defaults setObject:@"00000000-0000-0000-0000-000000000000"
+               forKey:@"ChromeClientID"];
+  [defaults synchronize];
+  std::string zero_id = ios::device_util::GetDeviceIdentifier(NULL);
+  [defaults removeObjectForKey:@"ChromeClientID"];
+  [defaults setObject:@"00000000-0000-0000-0000-000000000000"
+               forKey:@"ChromiumClientID"];
+  [defaults synchronize];
+  std::string new_id = ios::device_util::GetDeviceIdentifier(NULL);
+  EXPECT_NE(zero_id, new_id);
+
+  CleanNSUserDefaultsForDeviceId();
+}
+
+TEST_F(DeviceUtilTest, GetSaltedStringEquals) {
+  std::string string1("The quick brown fox jumps over the lazy dog");
+  std::string string2("The quick brown fox jumps over the lazy dog");
+  std::string salt("salt");
+  // Same string and same salt should result in the same salted string.
+  EXPECT_EQ(ios::device_util::GetSaltedString(string1, salt),
+            ios::device_util::GetSaltedString(string2, salt));
+}
+
+TEST_F(DeviceUtilTest, GetSaltedStringNotEquals) {
+  std::string string1("The quick brown fox jumps over the lazy dog");
+  std::string string2("The lazy brown fox jumps over the quick dog");
+  std::string salt("salt");
+  // Different string and same salt should result in different salted strings.
+  EXPECT_NE(ios::device_util::GetSaltedString(string1, salt),
+            ios::device_util::GetSaltedString(string2, salt));
+}
+
+TEST_F(DeviceUtilTest, GetSaltedStringDifferentSalt) {
+  std::string string1("The quick brown fox jumps over the lazy dog");
+  std::string salt1("salt");
+  std::string salt2("pepper");
+  // Same string with different salt should result in different salted strings.
+  EXPECT_NE(ios::device_util::GetSaltedString(string1, salt1),
+            ios::device_util::GetSaltedString(string1, salt2));
+}
+
+TEST_F(DeviceUtilTest, CheckDeviceMigration) {
+  CleanNSUserDefaultsForDeviceId();
+
+  NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
+  [defaults setObject:@"10000000-0000-0000-0000-000000000000"
+               forKey:@"ChromeClientID"];
+  [defaults synchronize];
+  std::string base_id = ios::device_util::GetDeviceIdentifier(NULL);
+  [defaults setObject:@"Foo" forKey:@"ClientIDGenerationHardwareType"];
+  [defaults synchronize];
+  std::string new_id = ios::device_util::GetDeviceIdentifier(NULL);
+  EXPECT_NE(new_id, base_id);
+
+  CleanNSUserDefaultsForDeviceId();
+}
+
+}  // namespace
diff --git a/base/ios/ios_util.h b/base/ios/ios_util.h
new file mode 100644
index 0000000..d9d7e19
--- /dev/null
+++ b/base/ios/ios_util.h
@@ -0,0 +1,23 @@
+// Copyright 2012 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_IOS_IOS_UTIL_H_
+#define BASE_IOS_IOS_UTIL_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace ios {
+
+// Returns whether the operating system is iOS 8 or later.
+BASE_EXPORT bool IsRunningOnIOS8OrLater();
+
+// Returns whether the operating system is at the given version or later.
+BASE_EXPORT bool IsRunningOnOrLater(int32 major, int32 minor, int32 bug_fix);
+
+}  // namespace ios
+}  // namespace base
+
+#endif  // BASE_IOS_IOS_UTIL_H_
diff --git a/base/ios/ios_util.mm b/base/ios/ios_util.mm
new file mode 100644
index 0000000..ca0a24d
--- /dev/null
+++ b/base/ios/ios_util.mm
@@ -0,0 +1,38 @@
+// Copyright 2012 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/ios/ios_util.h"
+
+#include "base/sys_info.h"
+
+namespace {
+// Return a 3 elements array containing the major, minor and bug fix version of
+// the OS.
+const int32* OSVersionAsArray() {
+  int32* digits = new int32[3];
+  base::SysInfo::OperatingSystemVersionNumbers(
+      &digits[0], &digits[1], &digits[2]);
+  return digits;
+}
+}  // namespace
+
+namespace base {
+namespace ios {
+
+bool IsRunningOnIOS8OrLater() {
+  return IsRunningOnOrLater(8, 0, 0);
+}
+
+bool IsRunningOnOrLater(int32 major, int32 minor, int32 bug_fix) {
+  static const int32* current_version = OSVersionAsArray();
+  int32 version[] = { major, minor, bug_fix };
+  for (size_t i = 0; i < arraysize(version); i++) {
+    if (current_version[i] != version[i])
+      return current_version[i] > version[i];
+  }
+  return true;
+}
+
+}  // namespace ios
+}  // namespace base
diff --git a/base/ios/scoped_critical_action.h b/base/ios/scoped_critical_action.h
new file mode 100644
index 0000000..803d587
--- /dev/null
+++ b/base/ios/scoped_critical_action.h
@@ -0,0 +1,68 @@
+// Copyright (c) 2012 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_IOS_SCOPED_CRITICAL_ACTION_H_
+#define BASE_IOS_SCOPED_CRITICAL_ACTION_H_
+
+#include "base/memory/ref_counted.h"
+#include "base/synchronization/lock.h"
+
+namespace base {
+namespace ios {
+
+// This class attempts to allow the application to continue to run for a period
+// of time after it transitions to the background. The construction of an
+// instance of this class marks the beginning of a task that needs background
+// running time when the application is moved to the background and the
+// destruction marks the end of such a task.
+//
+// Note there is no guarantee that the task will continue to finish when the
+// application is moved to the background.
+//
+// This class should be used at times where leaving a task unfinished might be
+// detrimental to user experience. For example, it should be used to ensure that
+// the application has enough time to save important data or at least attempt to
+// save such data.
+class ScopedCriticalAction {
+ public:
+  ScopedCriticalAction();
+  ~ScopedCriticalAction();
+
+ private:
+  // Core logic; ScopedCriticalAction should not be reference counted so
+  // that it follows the normal pattern of stack-allocating ScopedFoo objects,
+  // but the expiration handler needs to have a reference counted object to
+  // refer to.
+  class Core : public base::RefCountedThreadSafe<Core> {
+   public:
+    Core();
+
+    // Informs the OS that the background task has completed.
+    void EndBackgroundTask();
+
+   private:
+    friend base::RefCountedThreadSafe<Core>;
+    ~Core();
+
+    // |UIBackgroundTaskIdentifier| returned by
+    // |beginBackgroundTaskWithExpirationHandler:| when marking the beginning of
+    // a long-running background task. It is defined as an |unsigned int|
+    // instead of a |UIBackgroundTaskIdentifier| so this class can be used in
+    // .cc files.
+    unsigned int background_task_id_;
+    Lock background_task_id_lock_;
+
+    DISALLOW_COPY_AND_ASSIGN(Core);
+  };
+
+  // The instance of the core that drives the background task.
+  scoped_refptr<Core> core_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedCriticalAction);
+};
+
+}  // namespace ios
+}  // namespace base
+
+#endif  // BASE_IOS_SCOPED_CRITICAL_ACTION_H_
diff --git a/base/ios/scoped_critical_action.mm b/base/ios/scoped_critical_action.mm
new file mode 100644
index 0000000..9dad70e
--- /dev/null
+++ b/base/ios/scoped_critical_action.mm
@@ -0,0 +1,64 @@
+// Copyright (c) 2012 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/ios/scoped_critical_action.h"
+
+#import <UIKit/UIKit.h>
+
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/synchronization/lock.h"
+
+namespace base {
+namespace ios {
+
+ScopedCriticalAction::ScopedCriticalAction()
+    : core_(new ScopedCriticalAction::Core()) {
+}
+
+ScopedCriticalAction::~ScopedCriticalAction() {
+  core_->EndBackgroundTask();
+}
+
+// This implementation calls |beginBackgroundTaskWithExpirationHandler:| when
+// instantiated and |endBackgroundTask:| when destroyed, creating a scope whose
+// execution will continue (temporarily) even after the app is backgrounded.
+ScopedCriticalAction::Core::Core() {
+  scoped_refptr<ScopedCriticalAction::Core> core = this;
+  background_task_id_ = [[UIApplication sharedApplication]
+      beginBackgroundTaskWithExpirationHandler:^{
+        DLOG(WARNING) << "Background task with id " << background_task_id_
+                      << " expired.";
+        // Note if |endBackgroundTask:| is not called for each task before time
+        // expires, the system kills the application.
+        core->EndBackgroundTask();
+      }];
+  if (background_task_id_ == UIBackgroundTaskInvalid) {
+    DLOG(WARNING) <<
+        "beginBackgroundTaskWithExpirationHandler: returned an invalid ID";
+  } else {
+    VLOG(3) << "Beginning background task with id " << background_task_id_;
+  }
+}
+
+ScopedCriticalAction::Core::~Core() {
+  DCHECK_EQ(background_task_id_, UIBackgroundTaskInvalid);
+}
+
+void ScopedCriticalAction::Core::EndBackgroundTask() {
+  UIBackgroundTaskIdentifier task_id;
+  {
+    AutoLock lock_scope(background_task_id_lock_);
+    if (background_task_id_ == UIBackgroundTaskInvalid)
+      return;
+    task_id = background_task_id_;
+    background_task_id_ = UIBackgroundTaskInvalid;
+  }
+
+  VLOG(3) << "Ending background task with id " << task_id;
+  [[UIApplication sharedApplication] endBackgroundTask:task_id];
+}
+
+}  // namespace ios
+}  // namespace base
diff --git a/base/ios/weak_nsobject.h b/base/ios/weak_nsobject.h
new file mode 100644
index 0000000..fc3a7c3
--- /dev/null
+++ b/base/ios/weak_nsobject.h
@@ -0,0 +1,189 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_IOS_WEAK_NSOBJECT_H_
+#define BASE_IOS_WEAK_NSOBJECT_H_
+
+#import <Foundation/Foundation.h>
+#import <objc/runtime.h>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/threading/non_thread_safe.h"
+#include "base/threading/thread_checker.h"
+
+// WeakNSObject<> is patterned after scoped_nsobject<>, but instead of
+// maintaining ownership of an NSObject subclass object, it will nil itself out
+// when the object is deallocated.
+//
+// WeakNSProtocol<> has the same behavior as WeakNSObject, but can be used
+// with protocols.
+//
+// Example usage (base::WeakNSObject<T>):
+//   scoped_nsobject<Foo> foo([[Foo alloc] init]);
+//   WeakNSObject<Foo> weak_foo;  // No pointer
+//   weak_foo.reset(foo)  // Now a weak reference is kept.
+//   [weak_foo description];  // Returns [foo description].
+//   foo.reset();  // The reference is released.
+//   [weak_foo description];  // Returns nil, as weak_foo is pointing to nil.
+//
+//
+// Implementation wise a WeakNSObject keeps a reference to a refcounted
+// WeakContainer. There is one unique instance of a WeakContainer per watched
+// NSObject, this relationship is maintained via the ObjectiveC associated
+// object API, indirectly via an ObjectiveC CRBWeakNSProtocolSentinel class.
+//
+// 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:
+  explicit WeakContainer(id object) : object_(object) {}
+
+  id object() {
+    DCHECK(checker_.CalledOnValidThread());
+    return object_;
+  }
+
+  void nullify() {
+    DCHECK(checker_.CalledOnValidThread());
+    object_ = nil;
+  }
+
+ private:
+  friend base::RefCountedThreadSafe<WeakContainer>;
+  ~WeakContainer() {}
+  base::ThreadChecker checker_;
+  id object_;
+};
+
+}  // namespace base
+
+// Sentinel for observing the object contained in the weak pointer. The object
+// will be deleted when the weak object is deleted and will notify its
+// container.
+@interface CRBWeakNSProtocolSentinel : NSObject
+// Return the only associated container for this object. There can be only one.
+// Will return null if object is nil .
++ (scoped_refptr<base::WeakContainer>)containerForObject:(id)object;
+@end
+
+namespace base {
+
+// Base class for all WeakNSObject derivatives.
+template <typename NST>
+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 used on one thread and released on
+    // another. This is not the case for the contained object.
+    checker_.DetachFromThread();
+  }
+
+  void reset(NST object = nil) {
+    DCHECK(checker_.CalledOnValidThread());
+    container_ = [CRBWeakNSProtocolSentinel containerForObject:object];
+  }
+
+  NST get() const {
+    DCHECK(checker_.CalledOnValidThread());
+    if (!container_.get())
+      return nil;
+    return container_->object();
+  }
+
+  WeakNSProtocol& operator=(const WeakNSProtocol<NST>& that) {
+    // A WeakNSProtocol object can be copied on one thread and used on
+    // another.
+    checker_.DetachFromThread();
+    container_ = that.container_;
+    return *this;
+  }
+
+  bool operator==(NST that) const {
+    DCHECK(checker_.CalledOnValidThread());
+    return get() == that;
+  }
+
+  bool operator!=(NST that) const {
+    DCHECK(checker_.CalledOnValidThread());
+    return get() != that;
+  }
+
+  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
+template <class NST>
+bool operator==(NST p1, const WeakNSProtocol<NST>& p2) {
+  return p1 == p2.get();
+}
+
+template <class NST>
+bool operator!=(NST p1, const WeakNSProtocol<NST>& p2) {
+  return p1 != p2.get();
+}
+
+template <typename NST>
+class WeakNSObject : public WeakNSProtocol<NST*> {
+ public:
+  explicit WeakNSObject(NST* object = nil) : WeakNSProtocol<NST*>(object) {}
+
+  WeakNSObject(const WeakNSObject<NST>& that) : WeakNSProtocol<NST*>(that) {}
+
+  WeakNSObject& operator=(const WeakNSObject<NST>& that) {
+    WeakNSProtocol<NST*>::operator=(that);
+    return *this;
+  }
+};
+
+// Specialization to make WeakNSObject<id> work.
+template <>
+class WeakNSObject<id> : public WeakNSProtocol<id> {
+ public:
+  explicit WeakNSObject(id object = nil) : WeakNSProtocol<id>(object) {}
+
+  WeakNSObject(const WeakNSObject<id>& that) : WeakNSProtocol<id>(that) {}
+
+  WeakNSObject& operator=(const WeakNSObject<id>& that) {
+    WeakNSProtocol<id>::operator=(that);
+    return *this;
+  }
+};
+
+}  // namespace base
+
+#endif  // BASE_IOS_WEAK_NSOBJECT_H_
diff --git a/base/ios/weak_nsobject.mm b/base/ios/weak_nsobject.mm
new file mode 100644
index 0000000..36f9d3e
--- /dev/null
+++ b/base/ios/weak_nsobject.mm
@@ -0,0 +1,61 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/ios/weak_nsobject.h"
+
+#include "base/mac/scoped_nsautorelease_pool.h"
+#include "base/mac/scoped_nsobject.h"
+
+namespace {
+// The key needed by objc_setAssociatedObject.
+char sentinelObserverKey_;
+}
+
+@interface CRBWeakNSProtocolSentinel ()
+// Container to notify on dealloc.
+@property(readonly, assign) scoped_refptr<base::WeakContainer> container;
+// Designed initializer.
+- (id)initWithContainer:(scoped_refptr<base::WeakContainer>)container;
+@end
+
+@implementation CRBWeakNSProtocolSentinel
+
+@synthesize container = container_;
+
++ (scoped_refptr<base::WeakContainer>)containerForObject:(id)object {
+  if (object == nil)
+    return nullptr;
+  // The autoreleasePool is needed here as the call to objc_getAssociatedObject
+  // returns an autoreleased object which is better released sooner than later.
+  base::mac::ScopedNSAutoreleasePool pool;
+  CRBWeakNSProtocolSentinel* sentinel =
+      objc_getAssociatedObject(object, &sentinelObserverKey_);
+  if (!sentinel) {
+    base::scoped_nsobject<CRBWeakNSProtocolSentinel> newSentinel(
+        [[CRBWeakNSProtocolSentinel alloc]
+            initWithContainer:new base::WeakContainer(object)]);
+    sentinel = newSentinel;
+    objc_setAssociatedObject(object, &sentinelObserverKey_, sentinel,
+                             OBJC_ASSOCIATION_RETAIN);
+    // The retain count is 2. One retain is due to the alloc, the other to the
+    // association with the weak object.
+    DCHECK_EQ(2u, [sentinel retainCount]);
+  }
+  return [sentinel container];
+}
+
+- (id)initWithContainer:(scoped_refptr<base::WeakContainer>)container {
+  DCHECK(container.get());
+  self = [super init];
+  if (self)
+    container_ = container;
+  return self;
+}
+
+- (void)dealloc {
+  self.container->nullify();
+  [super dealloc];
+}
+
+@end
diff --git a/base/ios/weak_nsobject_unittest.mm b/base/ios/weak_nsobject_unittest.mm
new file mode 100644
index 0000000..81de993
--- /dev/null
+++ b/base/ios/weak_nsobject_unittest.mm
@@ -0,0 +1,140 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#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"
+
+namespace base {
+namespace {
+
+TEST(WeakNSObjectTest, WeakNSObject) {
+  scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
+  WeakNSObject<NSObject> w1(p1);
+  EXPECT_TRUE(w1);
+  p1.reset();
+  EXPECT_FALSE(w1);
+}
+
+TEST(WeakNSObjectTest, MultipleWeakNSObject) {
+  scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
+  WeakNSObject<NSObject> w1(p1);
+  WeakNSObject<NSObject> w2(w1);
+  EXPECT_TRUE(w1);
+  EXPECT_TRUE(w2);
+  EXPECT_TRUE(w1.get() == w2.get());
+  p1.reset();
+  EXPECT_FALSE(w1);
+  EXPECT_FALSE(w2);
+}
+
+TEST(WeakNSObjectTest, WeakNSObjectDies) {
+  scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
+  {
+    WeakNSObject<NSObject> w1(p1);
+    EXPECT_TRUE(w1);
+  }
+}
+
+TEST(WeakNSObjectTest, WeakNSObjectReset) {
+  scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
+  WeakNSObject<NSObject> w1(p1);
+  EXPECT_TRUE(w1);
+  w1.reset();
+  EXPECT_FALSE(w1);
+  EXPECT_TRUE(p1);
+  EXPECT_TRUE([p1 description]);
+}
+
+TEST(WeakNSObjectTest, WeakNSObjectResetWithObject) {
+  scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
+  scoped_nsobject<NSObject> p2([[NSObject alloc] init]);
+  WeakNSObject<NSObject> w1(p1);
+  EXPECT_TRUE(w1);
+  w1.reset(p2);
+  EXPECT_TRUE(w1);
+  EXPECT_TRUE([p1 description]);
+  EXPECT_TRUE([p2 description]);
+}
+
+TEST(WeakNSObjectTest, WeakNSObjectEmpty) {
+  scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
+  WeakNSObject<NSObject> w1;
+  EXPECT_FALSE(w1);
+  w1.reset(p1);
+  EXPECT_TRUE(w1);
+  p1.reset();
+  EXPECT_FALSE(w1);
+}
+
+TEST(WeakNSObjectTest, WeakNSObjectCopy) {
+  scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
+  WeakNSObject<NSObject> w1(p1);
+  WeakNSObject<NSObject> w2(w1);
+  EXPECT_TRUE(w1);
+  EXPECT_TRUE(w2);
+  p1.reset();
+  EXPECT_FALSE(w1);
+  EXPECT_FALSE(w2);
+}
+
+TEST(WeakNSObjectTest, WeakNSObjectAssignment) {
+  scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
+  WeakNSObject<NSObject> w1(p1);
+  WeakNSObject<NSObject> w2;
+  EXPECT_FALSE(w2);
+  w2 = w1;
+  EXPECT_TRUE(w1);
+  EXPECT_TRUE(w2);
+  p1.reset();
+  EXPECT_FALSE(w1);
+  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) {
+  // Copy using constructor.
+  WeakNSObject<NSMutableData> weak_copy1(weak_object);
+  runner->PostTask(FROM_HERE, Bind(&TouchWeakData, weak_copy1));
+  // Copy using assignment operator.
+  WeakNSObject<NSMutableData> weak_copy2 = weak_object;
+  runner->PostTask(FROM_HERE, Bind(&TouchWeakData, weak_copy2));
+}
+
+// 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 and the object touched twice.
+  EXPECT_EQ(2u, [data length]);
+}
+
+}  // namespace
+}  // namespace base
diff --git a/base/json/BUILD.gn b/base/json/BUILD.gn
new file mode 100644
index 0000000..70830c1
--- /dev/null
+++ b/base/json/BUILD.gn
@@ -0,0 +1,37 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("json") {
+  sources = [
+    "json_file_value_serializer.cc",
+    "json_file_value_serializer.h",
+    "json_parser.cc",
+    "json_parser.h",
+    "json_reader.cc",
+    "json_reader.h",
+    "json_string_value_serializer.cc",
+    "json_string_value_serializer.h",
+    "json_value_converter.cc",
+    "json_value_converter.h",
+    "json_writer.cc",
+    "json_writer.h",
+    "string_escape.cc",
+    "string_escape.h",
+  ]
+
+  if (is_nacl) {
+    sources -= [
+      "json_file_value_serializer.cc",
+      "json_file_value_serializer.h",
+    ]
+  }
+
+  configs += [ "//base:base_implementation" ]
+
+  deps = [
+    "//base/memory",
+  ]
+
+  visibility = [ "//base/*" ]
+}
diff --git a/base/json/json_file_value_serializer.cc b/base/json/json_file_value_serializer.cc
new file mode 100644
index 0000000..72a0970
--- /dev/null
+++ b/base/json/json_file_value_serializer.cc
@@ -0,0 +1,118 @@
+// Copyright (c) 2012 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/json/json_file_value_serializer.h"
+
+#include "base/files/file_util.h"
+#include "base/json/json_string_value_serializer.h"
+#include "base/logging.h"
+
+using base::FilePath;
+
+const char JSONFileValueDeserializer::kAccessDenied[] = "Access denied.";
+const char JSONFileValueDeserializer::kCannotReadFile[] = "Can't read file.";
+const char JSONFileValueDeserializer::kFileLocked[] = "File locked.";
+const char JSONFileValueDeserializer::kNoSuchFile[] = "File doesn't exist.";
+
+JSONFileValueSerializer::JSONFileValueSerializer(
+    const base::FilePath& json_file_path)
+    : json_file_path_(json_file_path) {
+}
+
+JSONFileValueSerializer::~JSONFileValueSerializer() {
+}
+
+bool JSONFileValueSerializer::Serialize(const base::Value& root) {
+  return SerializeInternal(root, false);
+}
+
+bool JSONFileValueSerializer::SerializeAndOmitBinaryValues(
+    const base::Value& root) {
+  return SerializeInternal(root, true);
+}
+
+bool JSONFileValueSerializer::SerializeInternal(const base::Value& root,
+                                                bool omit_binary_values) {
+  std::string json_string;
+  JSONStringValueSerializer serializer(&json_string);
+  serializer.set_pretty_print(true);
+  bool result = omit_binary_values ?
+      serializer.SerializeAndOmitBinaryValues(root) :
+      serializer.Serialize(root);
+  if (!result)
+    return false;
+
+  int data_size = static_cast<int>(json_string.size());
+  if (base::WriteFile(json_file_path_, json_string.data(), data_size) !=
+      data_size)
+    return false;
+
+  return true;
+}
+
+JSONFileValueDeserializer::JSONFileValueDeserializer(
+    const base::FilePath& json_file_path)
+    : json_file_path_(json_file_path),
+      allow_trailing_comma_(false),
+      last_read_size_(0U) {
+}
+
+JSONFileValueDeserializer::~JSONFileValueDeserializer() {
+}
+
+int JSONFileValueDeserializer::ReadFileToString(std::string* json_string) {
+  DCHECK(json_string);
+  if (!base::ReadFileToString(json_file_path_, json_string)) {
+#if defined(OS_WIN)
+    int error = ::GetLastError();
+    if (error == ERROR_SHARING_VIOLATION || error == ERROR_LOCK_VIOLATION) {
+      return JSON_FILE_LOCKED;
+    } else if (error == ERROR_ACCESS_DENIED) {
+      return JSON_ACCESS_DENIED;
+    }
+#endif
+    if (!base::PathExists(json_file_path_))
+      return JSON_NO_SUCH_FILE;
+    else
+      return JSON_CANNOT_READ_FILE;
+  }
+
+  last_read_size_ = json_string->size();
+  return JSON_NO_ERROR;
+}
+
+const char* JSONFileValueDeserializer::GetErrorMessageForCode(int error_code) {
+  switch (error_code) {
+    case JSON_NO_ERROR:
+      return "";
+    case JSON_ACCESS_DENIED:
+      return kAccessDenied;
+    case JSON_CANNOT_READ_FILE:
+      return kCannotReadFile;
+    case JSON_FILE_LOCKED:
+      return kFileLocked;
+    case JSON_NO_SUCH_FILE:
+      return kNoSuchFile;
+    default:
+      NOTREACHED();
+      return "";
+  }
+}
+
+base::Value* JSONFileValueDeserializer::Deserialize(int* error_code,
+                                                    std::string* error_str) {
+  std::string json_string;
+  int error = ReadFileToString(&json_string);
+  if (error != JSON_NO_ERROR) {
+    if (error_code)
+      *error_code = error;
+    if (error_str)
+      *error_str = GetErrorMessageForCode(error);
+    return NULL;
+  }
+
+  JSONStringValueDeserializer deserializer(json_string);
+  deserializer.set_allow_trailing_comma(allow_trailing_comma_);
+  return deserializer.Deserialize(error_code, error_str);
+}
diff --git a/base/json/json_file_value_serializer.h b/base/json/json_file_value_serializer.h
new file mode 100644
index 0000000..aab47ee
--- /dev/null
+++ b/base/json/json_file_value_serializer.h
@@ -0,0 +1,104 @@
+// Copyright (c) 2012 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_JSON_JSON_FILE_VALUE_SERIALIZER_H_
+#define BASE_JSON_JSON_FILE_VALUE_SERIALIZER_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/files/file_path.h"
+#include "base/values.h"
+
+class BASE_EXPORT JSONFileValueSerializer : public base::ValueSerializer {
+ public:
+  // |json_file_path_| is the path of a file that will be destination of the
+  // serialization. The serializer will attempt to create the file at the
+  // specified location.
+  explicit JSONFileValueSerializer(const base::FilePath& json_file_path);
+
+  ~JSONFileValueSerializer() override;
+
+  // DO NOT USE except in unit tests to verify the file was written properly.
+  // We should never serialize directly to a file since this will block the
+  // thread. Instead, serialize to a string and write to the file you want on
+  // the file thread.
+  //
+  // Attempt to serialize the data structure represented by Value into
+  // JSON.  If the return value is true, the result will have been written
+  // into the file whose name was passed into the constructor.
+  bool Serialize(const base::Value& root) override;
+
+  // Equivalent to Serialize(root) except binary values are omitted from the
+  // output.
+  bool SerializeAndOmitBinaryValues(const base::Value& root);
+
+ private:
+  bool SerializeInternal(const base::Value& root, bool omit_binary_values);
+
+  const base::FilePath json_file_path_;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(JSONFileValueSerializer);
+};
+
+class BASE_EXPORT JSONFileValueDeserializer : public base::ValueDeserializer {
+ public:
+  // |json_file_path_| is the path of a file that will be source of the
+  // deserialization.
+  explicit JSONFileValueDeserializer(const base::FilePath& json_file_path);
+
+  ~JSONFileValueDeserializer() override;
+
+  // Attempt to deserialize the data structure encoded in the file passed
+  // in to the constructor into a structure of Value objects.  If the return
+  // value is NULL, and if |error_code| is non-null, |error_code| will
+  // contain an integer error code (either JsonFileError or JsonParseError).
+  // If |error_message| is non-null, it will be filled in with a formatted
+  // error message including the location of the error if appropriate.
+  // The caller takes ownership of the returned value.
+  base::Value* Deserialize(int* error_code,
+                           std::string* error_message) override;
+
+  // This enum is designed to safely overlap with JSONReader::JsonParseError.
+  enum JsonFileError {
+    JSON_NO_ERROR = 0,
+    JSON_ACCESS_DENIED = 1000,
+    JSON_CANNOT_READ_FILE,
+    JSON_FILE_LOCKED,
+    JSON_NO_SUCH_FILE
+  };
+
+  // File-specific error messages that can be returned.
+  static const char kAccessDenied[];
+  static const char kCannotReadFile[];
+  static const char kFileLocked[];
+  static const char kNoSuchFile[];
+
+  // Convert an error code into an error message.  |error_code| is assumed to
+  // be a JsonFileError.
+  static const char* GetErrorMessageForCode(int error_code);
+
+  void set_allow_trailing_comma(bool new_value) {
+    allow_trailing_comma_ = new_value;
+  }
+
+  // Returns the size (in bytes) of JSON string read from disk in the last
+  // successful |Deserialize()| call.
+  size_t get_last_read_size() const { return last_read_size_; }
+
+ private:
+  // A wrapper for ReadFileToString which returns a non-zero JsonFileError if
+  // there were file errors.
+  int ReadFileToString(std::string* json_string);
+
+  const base::FilePath json_file_path_;
+  bool allow_trailing_comma_;
+  size_t last_read_size_;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(JSONFileValueDeserializer);
+};
+
+#endif  // BASE_JSON_JSON_FILE_VALUE_SERIALIZER_H_
+
diff --git a/base/json/json_parser.cc b/base/json/json_parser.cc
new file mode 100644
index 0000000..4d79be3
--- /dev/null
+++ b/base/json/json_parser.cc
@@ -0,0 +1,966 @@
+// Copyright (c) 2012 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/json/json_parser.h"
+
+#include <cmath>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversion_utils.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/third_party/icu/icu_utf.h"
+#include "base/values.h"
+
+namespace base {
+namespace internal {
+
+namespace {
+
+const int kStackMaxDepth = 100;
+
+const int32 kExtendedASCIIStart = 0x80;
+
+// This and the class below are used to own the JSON input string for when
+// string tokens are stored as StringPiece instead of std::string. This
+// optimization avoids about 2/3rds of string memory copies. The constructor
+// takes ownership of the input string. The real root value is Swap()ed into
+// the new instance.
+class DictionaryHiddenRootValue : public base::DictionaryValue {
+ public:
+  DictionaryHiddenRootValue(std::string* json, Value* root) : json_(json) {
+    DCHECK(root->IsType(Value::TYPE_DICTIONARY));
+    DictionaryValue::Swap(static_cast<DictionaryValue*>(root));
+  }
+
+  void Swap(DictionaryValue* other) override {
+    DVLOG(1) << "Swap()ing a DictionaryValue inefficiently.";
+
+    // First deep copy to convert JSONStringValue to std::string and swap that
+    // copy with |other|, which contains the new contents of |this|.
+    scoped_ptr<base::DictionaryValue> copy(DeepCopy());
+    copy->Swap(other);
+
+    // Then erase the contents of the current dictionary and swap in the
+    // new contents, originally from |other|.
+    Clear();
+    json_.reset();
+    DictionaryValue::Swap(copy.get());
+  }
+
+  // Not overriding DictionaryValue::Remove because it just calls through to
+  // the method below.
+
+  bool RemoveWithoutPathExpansion(const std::string& key,
+                                  scoped_ptr<Value>* out) override {
+    // If the caller won't take ownership of the removed value, just call up.
+    if (!out)
+      return DictionaryValue::RemoveWithoutPathExpansion(key, out);
+
+    DVLOG(1) << "Remove()ing from a DictionaryValue inefficiently.";
+
+    // Otherwise, remove the value while its still "owned" by this and copy it
+    // to convert any JSONStringValues to std::string.
+    scoped_ptr<Value> out_owned;
+    if (!DictionaryValue::RemoveWithoutPathExpansion(key, &out_owned))
+      return false;
+
+    out->reset(out_owned->DeepCopy());
+
+    return true;
+  }
+
+ private:
+  scoped_ptr<std::string> json_;
+
+  DISALLOW_COPY_AND_ASSIGN(DictionaryHiddenRootValue);
+};
+
+class ListHiddenRootValue : public base::ListValue {
+ public:
+  ListHiddenRootValue(std::string* json, Value* root) : json_(json) {
+    DCHECK(root->IsType(Value::TYPE_LIST));
+    ListValue::Swap(static_cast<ListValue*>(root));
+  }
+
+  void Swap(ListValue* other) override {
+    DVLOG(1) << "Swap()ing a ListValue inefficiently.";
+
+    // First deep copy to convert JSONStringValue to std::string and swap that
+    // copy with |other|, which contains the new contents of |this|.
+    scoped_ptr<base::ListValue> copy(DeepCopy());
+    copy->Swap(other);
+
+    // Then erase the contents of the current list and swap in the new contents,
+    // originally from |other|.
+    Clear();
+    json_.reset();
+    ListValue::Swap(copy.get());
+  }
+
+  bool Remove(size_t index, scoped_ptr<Value>* out) override {
+    // If the caller won't take ownership of the removed value, just call up.
+    if (!out)
+      return ListValue::Remove(index, out);
+
+    DVLOG(1) << "Remove()ing from a ListValue inefficiently.";
+
+    // Otherwise, remove the value while its still "owned" by this and copy it
+    // to convert any JSONStringValues to std::string.
+    scoped_ptr<Value> out_owned;
+    if (!ListValue::Remove(index, &out_owned))
+      return false;
+
+    out->reset(out_owned->DeepCopy());
+
+    return true;
+  }
+
+ private:
+  scoped_ptr<std::string> json_;
+
+  DISALLOW_COPY_AND_ASSIGN(ListHiddenRootValue);
+};
+
+// A variant on StringValue that uses StringPiece instead of copying the string
+// into the Value. This can only be stored in a child of hidden root (above),
+// otherwise the referenced string will not be guaranteed to outlive it.
+class JSONStringValue : public base::Value {
+ public:
+  explicit JSONStringValue(const base::StringPiece& piece)
+      : Value(TYPE_STRING),
+        string_piece_(piece) {
+  }
+
+  // Overridden from base::Value:
+  bool GetAsString(std::string* out_value) const override {
+    string_piece_.CopyToString(out_value);
+    return true;
+  }
+  bool GetAsString(string16* out_value) const override {
+    *out_value = UTF8ToUTF16(string_piece_);
+    return true;
+  }
+  Value* DeepCopy() const override {
+    return new StringValue(string_piece_.as_string());
+  }
+  bool Equals(const Value* other) const override {
+    std::string other_string;
+    return other->IsType(TYPE_STRING) && other->GetAsString(&other_string) &&
+        StringPiece(other_string) == string_piece_;
+  }
+
+ private:
+  // The location in the original input stream.
+  base::StringPiece string_piece_;
+
+  DISALLOW_COPY_AND_ASSIGN(JSONStringValue);
+};
+
+// Simple class that checks for maximum recursion/"stack overflow."
+class StackMarker {
+ public:
+  explicit StackMarker(int* depth) : depth_(depth) {
+    ++(*depth_);
+    DCHECK_LE(*depth_, kStackMaxDepth);
+  }
+  ~StackMarker() {
+    --(*depth_);
+  }
+
+  bool IsTooDeep() const {
+    return *depth_ >= kStackMaxDepth;
+  }
+
+ private:
+  int* const depth_;
+
+  DISALLOW_COPY_AND_ASSIGN(StackMarker);
+};
+
+}  // namespace
+
+JSONParser::JSONParser(int options)
+    : options_(options),
+      start_pos_(NULL),
+      pos_(NULL),
+      end_pos_(NULL),
+      index_(0),
+      stack_depth_(0),
+      line_number_(0),
+      index_last_line_(0),
+      error_code_(JSONReader::JSON_NO_ERROR),
+      error_line_(0),
+      error_column_(0) {
+}
+
+JSONParser::~JSONParser() {
+}
+
+Value* JSONParser::Parse(const StringPiece& input) {
+  scoped_ptr<std::string> input_copy;
+  // If the children of a JSON root can be detached, then hidden roots cannot
+  // be used, so do not bother copying the input because StringPiece will not
+  // be used anywhere.
+  if (!(options_ & JSON_DETACHABLE_CHILDREN)) {
+    input_copy.reset(new std::string(input.as_string()));
+    start_pos_ = input_copy->data();
+  } else {
+    start_pos_ = input.data();
+  }
+  pos_ = start_pos_;
+  end_pos_ = start_pos_ + input.length();
+  index_ = 0;
+  line_number_ = 1;
+  index_last_line_ = 0;
+
+  error_code_ = JSONReader::JSON_NO_ERROR;
+  error_line_ = 0;
+  error_column_ = 0;
+
+  // When the input JSON string starts with a UTF-8 Byte-Order-Mark
+  // <0xEF 0xBB 0xBF>, advance the start position to avoid the
+  // ParseNextToken function mis-treating a Unicode BOM as an invalid
+  // character and returning NULL.
+  if (CanConsume(3) && static_cast<uint8>(*pos_) == 0xEF &&
+      static_cast<uint8>(*(pos_ + 1)) == 0xBB &&
+      static_cast<uint8>(*(pos_ + 2)) == 0xBF) {
+    NextNChars(3);
+  }
+
+  // Parse the first and any nested tokens.
+  scoped_ptr<Value> root(ParseNextToken());
+  if (!root.get())
+    return NULL;
+
+  // Make sure the input stream is at an end.
+  if (GetNextToken() != T_END_OF_INPUT) {
+    if (!CanConsume(1) || (NextChar() && GetNextToken() != T_END_OF_INPUT)) {
+      ReportError(JSONReader::JSON_UNEXPECTED_DATA_AFTER_ROOT, 1);
+      return NULL;
+    }
+  }
+
+  // Dictionaries and lists can contain JSONStringValues, so wrap them in a
+  // hidden root.
+  if (!(options_ & JSON_DETACHABLE_CHILDREN)) {
+    if (root->IsType(Value::TYPE_DICTIONARY)) {
+      return new DictionaryHiddenRootValue(input_copy.release(), root.get());
+    } else if (root->IsType(Value::TYPE_LIST)) {
+      return new ListHiddenRootValue(input_copy.release(), root.get());
+    } else if (root->IsType(Value::TYPE_STRING)) {
+      // A string type could be a JSONStringValue, but because there's no
+      // corresponding HiddenRootValue, the memory will be lost. Deep copy to
+      // preserve it.
+      return root->DeepCopy();
+    }
+  }
+
+  // All other values can be returned directly.
+  return root.release();
+}
+
+JSONReader::JsonParseError JSONParser::error_code() const {
+  return error_code_;
+}
+
+std::string JSONParser::GetErrorMessage() const {
+  return FormatErrorMessage(error_line_, error_column_,
+      JSONReader::ErrorCodeToString(error_code_));
+}
+
+// StringBuilder ///////////////////////////////////////////////////////////////
+
+JSONParser::StringBuilder::StringBuilder()
+    : pos_(NULL),
+      length_(0),
+      string_(NULL) {
+}
+
+JSONParser::StringBuilder::StringBuilder(const char* pos)
+    : pos_(pos),
+      length_(0),
+      string_(NULL) {
+}
+
+void JSONParser::StringBuilder::Swap(StringBuilder* other) {
+  std::swap(other->string_, string_);
+  std::swap(other->pos_, pos_);
+  std::swap(other->length_, length_);
+}
+
+JSONParser::StringBuilder::~StringBuilder() {
+  delete string_;
+}
+
+void JSONParser::StringBuilder::Append(const char& c) {
+  DCHECK_GE(c, 0);
+  DCHECK_LT(c, 128);
+
+  if (string_)
+    string_->push_back(c);
+  else
+    ++length_;
+}
+
+void JSONParser::StringBuilder::AppendString(const std::string& str) {
+  DCHECK(string_);
+  string_->append(str);
+}
+
+void JSONParser::StringBuilder::Convert() {
+  if (string_)
+    return;
+  string_  = new std::string(pos_, length_);
+}
+
+bool JSONParser::StringBuilder::CanBeStringPiece() const {
+  return !string_;
+}
+
+StringPiece JSONParser::StringBuilder::AsStringPiece() {
+  if (string_)
+    return StringPiece();
+  return StringPiece(pos_, length_);
+}
+
+const std::string& JSONParser::StringBuilder::AsString() {
+  if (!string_)
+    Convert();
+  return *string_;
+}
+
+// JSONParser private //////////////////////////////////////////////////////////
+
+inline bool JSONParser::CanConsume(int length) {
+  return pos_ + length <= end_pos_;
+}
+
+const char* JSONParser::NextChar() {
+  DCHECK(CanConsume(1));
+  ++index_;
+  ++pos_;
+  return pos_;
+}
+
+void JSONParser::NextNChars(int n) {
+  DCHECK(CanConsume(n));
+  index_ += n;
+  pos_ += n;
+}
+
+JSONParser::Token JSONParser::GetNextToken() {
+  EatWhitespaceAndComments();
+  if (!CanConsume(1))
+    return T_END_OF_INPUT;
+
+  switch (*pos_) {
+    case '{':
+      return T_OBJECT_BEGIN;
+    case '}':
+      return T_OBJECT_END;
+    case '[':
+      return T_ARRAY_BEGIN;
+    case ']':
+      return T_ARRAY_END;
+    case '"':
+      return T_STRING;
+    case '0':
+    case '1':
+    case '2':
+    case '3':
+    case '4':
+    case '5':
+    case '6':
+    case '7':
+    case '8':
+    case '9':
+    case '-':
+      return T_NUMBER;
+    case 't':
+      return T_BOOL_TRUE;
+    case 'f':
+      return T_BOOL_FALSE;
+    case 'n':
+      return T_NULL;
+    case ',':
+      return T_LIST_SEPARATOR;
+    case ':':
+      return T_OBJECT_PAIR_SEPARATOR;
+    default:
+      return T_INVALID_TOKEN;
+  }
+}
+
+void JSONParser::EatWhitespaceAndComments() {
+  while (pos_ < end_pos_) {
+    switch (*pos_) {
+      case '\r':
+      case '\n':
+        index_last_line_ = index_;
+        // Don't increment line_number_ twice for "\r\n".
+        if (!(*pos_ == '\n' && pos_ > start_pos_ && *(pos_ - 1) == '\r'))
+          ++line_number_;
+        // Fall through.
+      case ' ':
+      case '\t':
+        NextChar();
+        break;
+      case '/':
+        if (!EatComment())
+          return;
+        break;
+      default:
+        return;
+    }
+  }
+}
+
+bool JSONParser::EatComment() {
+  if (*pos_ != '/' || !CanConsume(1))
+    return false;
+
+  char next_char = *NextChar();
+  if (next_char == '/') {
+    // Single line comment, read to newline.
+    while (CanConsume(1)) {
+      next_char = *NextChar();
+      if (next_char == '\n' || next_char == '\r')
+        return true;
+    }
+  } else if (next_char == '*') {
+    char previous_char = '\0';
+    // Block comment, read until end marker.
+    while (CanConsume(1)) {
+      next_char = *NextChar();
+      if (previous_char == '*' && next_char == '/') {
+        // EatWhitespaceAndComments will inspect pos_, which will still be on
+        // the last / of the comment, so advance once more (which may also be
+        // end of input).
+        NextChar();
+        return true;
+      }
+      previous_char = next_char;
+    }
+
+    // If the comment is unterminated, GetNextToken will report T_END_OF_INPUT.
+  }
+
+  return false;
+}
+
+Value* JSONParser::ParseNextToken() {
+  return ParseToken(GetNextToken());
+}
+
+Value* JSONParser::ParseToken(Token token) {
+  switch (token) {
+    case T_OBJECT_BEGIN:
+      return ConsumeDictionary();
+    case T_ARRAY_BEGIN:
+      return ConsumeList();
+    case T_STRING:
+      return ConsumeString();
+    case T_NUMBER:
+      return ConsumeNumber();
+    case T_BOOL_TRUE:
+    case T_BOOL_FALSE:
+    case T_NULL:
+      return ConsumeLiteral();
+    default:
+      ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 1);
+      return NULL;
+  }
+}
+
+Value* JSONParser::ConsumeDictionary() {
+  if (*pos_ != '{') {
+    ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 1);
+    return NULL;
+  }
+
+  StackMarker depth_check(&stack_depth_);
+  if (depth_check.IsTooDeep()) {
+    ReportError(JSONReader::JSON_TOO_MUCH_NESTING, 1);
+    return NULL;
+  }
+
+  scoped_ptr<DictionaryValue> dict(new DictionaryValue);
+
+  NextChar();
+  Token token = GetNextToken();
+  while (token != T_OBJECT_END) {
+    if (token != T_STRING) {
+      ReportError(JSONReader::JSON_UNQUOTED_DICTIONARY_KEY, 1);
+      return NULL;
+    }
+
+    // First consume the key.
+    StringBuilder key;
+    if (!ConsumeStringRaw(&key)) {
+      return NULL;
+    }
+
+    // Read the separator.
+    NextChar();
+    token = GetNextToken();
+    if (token != T_OBJECT_PAIR_SEPARATOR) {
+      ReportError(JSONReader::JSON_SYNTAX_ERROR, 1);
+      return NULL;
+    }
+
+    // The next token is the value. Ownership transfers to |dict|.
+    NextChar();
+    Value* value = ParseNextToken();
+    if (!value) {
+      // ReportError from deeper level.
+      return NULL;
+    }
+
+    dict->SetWithoutPathExpansion(key.AsString(), value);
+
+    NextChar();
+    token = GetNextToken();
+    if (token == T_LIST_SEPARATOR) {
+      NextChar();
+      token = GetNextToken();
+      if (token == T_OBJECT_END && !(options_ & JSON_ALLOW_TRAILING_COMMAS)) {
+        ReportError(JSONReader::JSON_TRAILING_COMMA, 1);
+        return NULL;
+      }
+    } else if (token != T_OBJECT_END) {
+      ReportError(JSONReader::JSON_SYNTAX_ERROR, 0);
+      return NULL;
+    }
+  }
+
+  return dict.release();
+}
+
+Value* JSONParser::ConsumeList() {
+  if (*pos_ != '[') {
+    ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 1);
+    return NULL;
+  }
+
+  StackMarker depth_check(&stack_depth_);
+  if (depth_check.IsTooDeep()) {
+    ReportError(JSONReader::JSON_TOO_MUCH_NESTING, 1);
+    return NULL;
+  }
+
+  scoped_ptr<ListValue> list(new ListValue);
+
+  NextChar();
+  Token token = GetNextToken();
+  while (token != T_ARRAY_END) {
+    Value* item = ParseToken(token);
+    if (!item) {
+      // ReportError from deeper level.
+      return NULL;
+    }
+
+    list->Append(item);
+
+    NextChar();
+    token = GetNextToken();
+    if (token == T_LIST_SEPARATOR) {
+      NextChar();
+      token = GetNextToken();
+      if (token == T_ARRAY_END && !(options_ & JSON_ALLOW_TRAILING_COMMAS)) {
+        ReportError(JSONReader::JSON_TRAILING_COMMA, 1);
+        return NULL;
+      }
+    } else if (token != T_ARRAY_END) {
+      ReportError(JSONReader::JSON_SYNTAX_ERROR, 1);
+      return NULL;
+    }
+  }
+
+  return list.release();
+}
+
+Value* JSONParser::ConsumeString() {
+  StringBuilder string;
+  if (!ConsumeStringRaw(&string))
+    return NULL;
+
+  // Create the Value representation, using a hidden root, if configured
+  // to do so, and if the string can be represented by StringPiece.
+  if (string.CanBeStringPiece() && !(options_ & JSON_DETACHABLE_CHILDREN)) {
+    return new JSONStringValue(string.AsStringPiece());
+  } else {
+    if (string.CanBeStringPiece())
+      string.Convert();
+    return new StringValue(string.AsString());
+  }
+}
+
+bool JSONParser::ConsumeStringRaw(StringBuilder* out) {
+  if (*pos_ != '"') {
+    ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 1);
+    return false;
+  }
+
+  // StringBuilder will internally build a StringPiece unless a UTF-16
+  // conversion occurs, at which point it will perform a copy into a
+  // std::string.
+  StringBuilder string(NextChar());
+
+  int length = end_pos_ - start_pos_;
+  int32 next_char = 0;
+
+  while (CanConsume(1)) {
+    pos_ = start_pos_ + index_;  // CBU8_NEXT is postcrement.
+    CBU8_NEXT(start_pos_, index_, length, next_char);
+    if (next_char < 0 || !IsValidCharacter(next_char)) {
+      ReportError(JSONReader::JSON_UNSUPPORTED_ENCODING, 1);
+      return false;
+    }
+
+    // If this character is an escape sequence...
+    if (next_char == '\\') {
+      // The input string will be adjusted (either by combining the two
+      // characters of an encoded escape sequence, or with a UTF conversion),
+      // so using StringPiece isn't possible -- force a conversion.
+      string.Convert();
+
+      if (!CanConsume(1)) {
+        ReportError(JSONReader::JSON_INVALID_ESCAPE, 0);
+        return false;
+      }
+
+      switch (*NextChar()) {
+        // Allowed esape sequences:
+        case 'x': {  // UTF-8 sequence.
+          // UTF-8 \x escape sequences are not allowed in the spec, but they
+          // are supported here for backwards-compatiblity with the old parser.
+          if (!CanConsume(2)) {
+            ReportError(JSONReader::JSON_INVALID_ESCAPE, 1);
+            return false;
+          }
+
+          int hex_digit = 0;
+          if (!HexStringToInt(StringPiece(NextChar(), 2), &hex_digit)) {
+            ReportError(JSONReader::JSON_INVALID_ESCAPE, -1);
+            return false;
+          }
+          NextChar();
+
+          if (hex_digit < kExtendedASCIIStart)
+            string.Append(static_cast<char>(hex_digit));
+          else
+            DecodeUTF8(hex_digit, &string);
+          break;
+        }
+        case 'u': {  // UTF-16 sequence.
+          // UTF units are of the form \uXXXX.
+          if (!CanConsume(5)) {  // 5 being 'u' and four HEX digits.
+            ReportError(JSONReader::JSON_INVALID_ESCAPE, 0);
+            return false;
+          }
+
+          // Skip the 'u'.
+          NextChar();
+
+          std::string utf8_units;
+          if (!DecodeUTF16(&utf8_units)) {
+            ReportError(JSONReader::JSON_INVALID_ESCAPE, -1);
+            return false;
+          }
+
+          string.AppendString(utf8_units);
+          break;
+        }
+        case '"':
+          string.Append('"');
+          break;
+        case '\\':
+          string.Append('\\');
+          break;
+        case '/':
+          string.Append('/');
+          break;
+        case 'b':
+          string.Append('\b');
+          break;
+        case 'f':
+          string.Append('\f');
+          break;
+        case 'n':
+          string.Append('\n');
+          break;
+        case 'r':
+          string.Append('\r');
+          break;
+        case 't':
+          string.Append('\t');
+          break;
+        case 'v':  // Not listed as valid escape sequence in the RFC.
+          string.Append('\v');
+          break;
+        // All other escape squences are illegal.
+        default:
+          ReportError(JSONReader::JSON_INVALID_ESCAPE, 0);
+          return false;
+      }
+    } else if (next_char == '"') {
+      --index_;  // Rewind by one because of CBU8_NEXT.
+      out->Swap(&string);
+      return true;
+    } else {
+      if (next_char < kExtendedASCIIStart)
+        string.Append(static_cast<char>(next_char));
+      else
+        DecodeUTF8(next_char, &string);
+    }
+  }
+
+  ReportError(JSONReader::JSON_SYNTAX_ERROR, 0);
+  return false;
+}
+
+// Entry is at the first X in \uXXXX.
+bool JSONParser::DecodeUTF16(std::string* dest_string) {
+  if (!CanConsume(4))
+    return false;
+
+  // This is a 32-bit field because the shift operations in the
+  // conversion process below cause MSVC to error about "data loss."
+  // This only stores UTF-16 code units, though.
+  // Consume the UTF-16 code unit, which may be a high surrogate.
+  int code_unit16_high = 0;
+  if (!HexStringToInt(StringPiece(pos_, 4), &code_unit16_high))
+    return false;
+
+  // Only add 3, not 4, because at the end of this iteration, the parser has
+  // finished working with the last digit of the UTF sequence, meaning that
+  // the next iteration will advance to the next byte.
+  NextNChars(3);
+
+  // Used to convert the UTF-16 code units to a code point and then to a UTF-8
+  // code unit sequence.
+  char code_unit8[8] = { 0 };
+  size_t offset = 0;
+
+  // If this is a high surrogate, consume the next code unit to get the
+  // low surrogate.
+  if (CBU16_IS_SURROGATE(code_unit16_high)) {
+    // Make sure this is the high surrogate. If not, it's an encoding
+    // error.
+    if (!CBU16_IS_SURROGATE_LEAD(code_unit16_high))
+      return false;
+
+    // Make sure that the token has more characters to consume the
+    // lower surrogate.
+    if (!CanConsume(6))  // 6 being '\' 'u' and four HEX digits.
+      return false;
+    if (*NextChar() != '\\' || *NextChar() != 'u')
+      return false;
+
+    NextChar();  // Read past 'u'.
+    int code_unit16_low = 0;
+    if (!HexStringToInt(StringPiece(pos_, 4), &code_unit16_low))
+      return false;
+
+    NextNChars(3);
+
+    if (!CBU16_IS_TRAIL(code_unit16_low)) {
+      return false;
+    }
+
+    uint32 code_point = CBU16_GET_SUPPLEMENTARY(code_unit16_high,
+                                                code_unit16_low);
+    offset = 0;
+    CBU8_APPEND_UNSAFE(code_unit8, offset, code_point);
+  } else {
+    // Not a surrogate.
+    DCHECK(CBU16_IS_SINGLE(code_unit16_high));
+    CBU8_APPEND_UNSAFE(code_unit8, offset, code_unit16_high);
+  }
+
+  dest_string->append(code_unit8);
+  return true;
+}
+
+void JSONParser::DecodeUTF8(const int32& point, StringBuilder* dest) {
+  // Anything outside of the basic ASCII plane will need to be decoded from
+  // int32 to a multi-byte sequence.
+  if (point < kExtendedASCIIStart) {
+    dest->Append(static_cast<char>(point));
+  } else {
+    char utf8_units[4] = { 0 };
+    int offset = 0;
+    CBU8_APPEND_UNSAFE(utf8_units, offset, point);
+    dest->Convert();
+    // CBU8_APPEND_UNSAFE can overwrite up to 4 bytes, so utf8_units may not be
+    // zero terminated at this point.  |offset| contains the correct length.
+    dest->AppendString(std::string(utf8_units, offset));
+  }
+}
+
+Value* JSONParser::ConsumeNumber() {
+  const char* num_start = pos_;
+  const int start_index = index_;
+  int end_index = start_index;
+
+  if (*pos_ == '-')
+    NextChar();
+
+  if (!ReadInt(false)) {
+    ReportError(JSONReader::JSON_SYNTAX_ERROR, 1);
+    return NULL;
+  }
+  end_index = index_;
+
+  // The optional fraction part.
+  if (*pos_ == '.') {
+    if (!CanConsume(1)) {
+      ReportError(JSONReader::JSON_SYNTAX_ERROR, 1);
+      return NULL;
+    }
+    NextChar();
+    if (!ReadInt(true)) {
+      ReportError(JSONReader::JSON_SYNTAX_ERROR, 1);
+      return NULL;
+    }
+    end_index = index_;
+  }
+
+  // Optional exponent part.
+  if (*pos_ == 'e' || *pos_ == 'E') {
+    NextChar();
+    if (*pos_ == '-' || *pos_ == '+')
+      NextChar();
+    if (!ReadInt(true)) {
+      ReportError(JSONReader::JSON_SYNTAX_ERROR, 1);
+      return NULL;
+    }
+    end_index = index_;
+  }
+
+  // ReadInt is greedy because numbers have no easily detectable sentinel,
+  // so save off where the parser should be on exit (see Consume invariant at
+  // the top of the header), then make sure the next token is one which is
+  // valid.
+  const char* exit_pos = pos_ - 1;
+  int exit_index = index_ - 1;
+
+  switch (GetNextToken()) {
+    case T_OBJECT_END:
+    case T_ARRAY_END:
+    case T_LIST_SEPARATOR:
+    case T_END_OF_INPUT:
+      break;
+    default:
+      ReportError(JSONReader::JSON_SYNTAX_ERROR, 1);
+      return NULL;
+  }
+
+  pos_ = exit_pos;
+  index_ = exit_index;
+
+  StringPiece num_string(num_start, end_index - start_index);
+
+  int num_int;
+  if (StringToInt(num_string, &num_int))
+    return new FundamentalValue(num_int);
+
+  double num_double;
+  if (base::StringToDouble(num_string.as_string(), &num_double) &&
+      std::isfinite(num_double)) {
+    return new FundamentalValue(num_double);
+  }
+
+  return NULL;
+}
+
+bool JSONParser::ReadInt(bool allow_leading_zeros) {
+  char first = *pos_;
+  int len = 0;
+
+  char c = first;
+  while (CanConsume(1) && IsAsciiDigit(c)) {
+    c = *NextChar();
+    ++len;
+  }
+
+  if (len == 0)
+    return false;
+
+  if (!allow_leading_zeros && len > 1 && first == '0')
+    return false;
+
+  return true;
+}
+
+Value* JSONParser::ConsumeLiteral() {
+  switch (*pos_) {
+    case 't': {
+      const char kTrueLiteral[] = "true";
+      const int kTrueLen = static_cast<int>(strlen(kTrueLiteral));
+      if (!CanConsume(kTrueLen - 1) ||
+          !StringsAreEqual(pos_, kTrueLiteral, kTrueLen)) {
+        ReportError(JSONReader::JSON_SYNTAX_ERROR, 1);
+        return NULL;
+      }
+      NextNChars(kTrueLen - 1);
+      return new FundamentalValue(true);
+    }
+    case 'f': {
+      const char kFalseLiteral[] = "false";
+      const int kFalseLen = static_cast<int>(strlen(kFalseLiteral));
+      if (!CanConsume(kFalseLen - 1) ||
+          !StringsAreEqual(pos_, kFalseLiteral, kFalseLen)) {
+        ReportError(JSONReader::JSON_SYNTAX_ERROR, 1);
+        return NULL;
+      }
+      NextNChars(kFalseLen - 1);
+      return new FundamentalValue(false);
+    }
+    case 'n': {
+      const char kNullLiteral[] = "null";
+      const int kNullLen = static_cast<int>(strlen(kNullLiteral));
+      if (!CanConsume(kNullLen - 1) ||
+          !StringsAreEqual(pos_, kNullLiteral, kNullLen)) {
+        ReportError(JSONReader::JSON_SYNTAX_ERROR, 1);
+        return NULL;
+      }
+      NextNChars(kNullLen - 1);
+      return Value::CreateNullValue().release();
+    }
+    default:
+      ReportError(JSONReader::JSON_UNEXPECTED_TOKEN, 1);
+      return NULL;
+  }
+}
+
+// static
+bool JSONParser::StringsAreEqual(const char* one, const char* two, size_t len) {
+  return strncmp(one, two, len) == 0;
+}
+
+void JSONParser::ReportError(JSONReader::JsonParseError code,
+                             int column_adjust) {
+  error_code_ = code;
+  error_line_ = line_number_;
+  error_column_ = index_ - index_last_line_ + column_adjust;
+}
+
+// static
+std::string JSONParser::FormatErrorMessage(int line, int column,
+                                           const std::string& description) {
+  if (line || column) {
+    return StringPrintf("Line: %i, column: %i, %s",
+        line, column, description.c_str());
+  }
+  return description;
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/json/json_parser.h b/base/json/json_parser.h
new file mode 100644
index 0000000..b4d0b1b
--- /dev/null
+++ b/base/json/json_parser.h
@@ -0,0 +1,271 @@
+// Copyright (c) 2012 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_JSON_JSON_PARSER_H_
+#define BASE_JSON_JSON_PARSER_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/json/json_reader.h"
+#include "base/strings/string_piece.h"
+
+#if !defined(OS_CHROMEOS)
+#include "base/gtest_prod_util.h"
+#endif
+
+namespace base {
+class Value;
+}
+
+#if defined(OS_CHROMEOS)
+// Chromium and Chromium OS check out gtest to different places, so this is
+// unable to compile on both if gtest_prod.h is included here. Instead, include
+// its only contents -- this will need to be updated if the macro ever changes.
+#define FRIEND_TEST(test_case_name, test_name)\
+friend class test_case_name##_##test_name##_Test
+
+#define FRIEND_TEST_ALL_PREFIXES(test_case_name, test_name) \
+  FRIEND_TEST(test_case_name, test_name); \
+  FRIEND_TEST(test_case_name, DISABLED_##test_name); \
+  FRIEND_TEST(test_case_name, FLAKY_##test_name)
+#endif  // OS_CHROMEOS
+
+namespace base {
+namespace internal {
+
+class JSONParserTest;
+
+// The implementation behind the JSONReader interface. This class is not meant
+// to be used directly; it encapsulates logic that need not be exposed publicly.
+//
+// This parser guarantees O(n) time through the input string. It also optimizes
+// base::StringValue by using StringPiece where possible when returning Value
+// objects by using "hidden roots," discussed in the implementation.
+//
+// Iteration happens on the byte level, with the functions CanConsume and
+// NextChar. The conversion from byte to JSON token happens without advancing
+// the parser in GetNextToken/ParseToken, that is tokenization operates on
+// the current parser position without advancing.
+//
+// Built on top of these are a family of Consume functions that iterate
+// internally. Invariant: on entry of a Consume function, the parser is wound
+// to the first byte of a valid JSON token. On exit, it is on the last byte
+// of a token, such that the next iteration of the parser will be at the byte
+// immediately following the token, which would likely be the first byte of the
+// next token.
+class BASE_EXPORT_PRIVATE JSONParser {
+ public:
+  explicit JSONParser(int options);
+  ~JSONParser();
+
+  // Parses the input string according to the set options and returns the
+  // result as a Value owned by the caller.
+  Value* Parse(const StringPiece& input);
+
+  // Returns the error code.
+  JSONReader::JsonParseError error_code() const;
+
+  // Returns the human-friendly error message.
+  std::string GetErrorMessage() const;
+
+ private:
+  enum Token {
+    T_OBJECT_BEGIN,           // {
+    T_OBJECT_END,             // }
+    T_ARRAY_BEGIN,            // [
+    T_ARRAY_END,              // ]
+    T_STRING,
+    T_NUMBER,
+    T_BOOL_TRUE,              // true
+    T_BOOL_FALSE,             // false
+    T_NULL,                   // null
+    T_LIST_SEPARATOR,         // ,
+    T_OBJECT_PAIR_SEPARATOR,  // :
+    T_END_OF_INPUT,
+    T_INVALID_TOKEN,
+  };
+
+  // A helper class used for parsing strings. One optimization performed is to
+  // create base::Value with a StringPiece to avoid unnecessary std::string
+  // copies. This is not possible if the input string needs to be decoded from
+  // UTF-16 to UTF-8, or if an escape sequence causes characters to be skipped.
+  // This class centralizes that logic.
+  class StringBuilder {
+   public:
+    // Empty constructor. Used for creating a builder with which to Swap().
+    StringBuilder();
+
+    // |pos| is the beginning of an input string, excluding the |"|.
+    explicit StringBuilder(const char* pos);
+
+    ~StringBuilder();
+
+    // Swaps the contents of |other| with this.
+    void Swap(StringBuilder* other);
+
+    // Either increases the |length_| of the string or copies the character if
+    // the StringBuilder has been converted. |c| must be in the basic ASCII
+    // plane; all other characters need to be in UTF-8 units, appended with
+    // AppendString below.
+    void Append(const char& c);
+
+    // Appends a string to the std::string. Must be Convert()ed to use.
+    void AppendString(const std::string& str);
+
+    // Converts the builder from its default StringPiece to a full std::string,
+    // performing a copy. Once a builder is converted, it cannot be made a
+    // StringPiece again.
+    void Convert();
+
+    // Returns whether the builder can be converted to a StringPiece.
+    bool CanBeStringPiece() const;
+
+    // Returns the StringPiece representation. Returns an empty piece if it
+    // cannot be converted.
+    StringPiece AsStringPiece();
+
+    // Returns the builder as a std::string.
+    const std::string& AsString();
+
+   private:
+    // The beginning of the input string.
+    const char* pos_;
+
+    // Number of bytes in |pos_| that make up the string being built.
+    size_t length_;
+
+    // The copied string representation. NULL until Convert() is called.
+    // Strong. scoped_ptr<T> has too much of an overhead here.
+    std::string* string_;
+  };
+
+  // Quick check that the stream has capacity to consume |length| more bytes.
+  bool CanConsume(int length);
+
+  // The basic way to consume a single character in the stream. Consumes one
+  // byte of the input stream and returns a pointer to the rest of it.
+  const char* NextChar();
+
+  // Performs the equivalent of NextChar N times.
+  void NextNChars(int n);
+
+  // Skips over whitespace and comments to find the next token in the stream.
+  // This does not advance the parser for non-whitespace or comment chars.
+  Token GetNextToken();
+
+  // Consumes whitespace characters and comments until the next non-that is
+  // encountered.
+  void EatWhitespaceAndComments();
+  // Helper function that consumes a comment, assuming that the parser is
+  // currently wound to a '/'.
+  bool EatComment();
+
+  // Calls GetNextToken() and then ParseToken(). Caller owns the result.
+  Value* ParseNextToken();
+
+  // Takes a token that represents the start of a Value ("a structural token"
+  // in RFC terms) and consumes it, returning the result as an object the
+  // caller owns.
+  Value* ParseToken(Token token);
+
+  // Assuming that the parser is currently wound to '{', this parses a JSON
+  // object into a DictionaryValue.
+  Value* ConsumeDictionary();
+
+  // Assuming that the parser is wound to '[', this parses a JSON list into a
+  // ListValue.
+  Value* ConsumeList();
+
+  // Calls through ConsumeStringRaw and wraps it in a value.
+  Value* ConsumeString();
+
+  // Assuming that the parser is wound to a double quote, this parses a string,
+  // decoding any escape sequences and converts UTF-16 to UTF-8. Returns true on
+  // success and Swap()s the result into |out|. Returns false on failure with
+  // error information set.
+  bool ConsumeStringRaw(StringBuilder* out);
+  // Helper function for ConsumeStringRaw() that consumes the next four or 10
+  // bytes (parser is wound to the first character of a HEX sequence, with the
+  // potential for consuming another \uXXXX for a surrogate). Returns true on
+  // success and places the UTF8 code units in |dest_string|, and false on
+  // failure.
+  bool DecodeUTF16(std::string* dest_string);
+  // Helper function for ConsumeStringRaw() that takes a single code point,
+  // decodes it into UTF-8 units, and appends it to the given builder. The
+  // point must be valid.
+  void DecodeUTF8(const int32& point, StringBuilder* dest);
+
+  // Assuming that the parser is wound to the start of a valid JSON number,
+  // this parses and converts it to either an int or double value.
+  Value* ConsumeNumber();
+  // Helper that reads characters that are ints. Returns true if a number was
+  // read and false on error.
+  bool ReadInt(bool allow_leading_zeros);
+
+  // Consumes the literal values of |true|, |false|, and |null|, assuming the
+  // parser is wound to the first character of any of those.
+  Value* ConsumeLiteral();
+
+  // Compares two string buffers of a given length.
+  static bool StringsAreEqual(const char* left, const char* right, size_t len);
+
+  // Sets the error information to |code| at the current column, based on
+  // |index_| and |index_last_line_|, with an optional positive/negative
+  // adjustment by |column_adjust|.
+  void ReportError(JSONReader::JsonParseError code, int column_adjust);
+
+  // Given the line and column number of an error, formats one of the error
+  // message contants from json_reader.h for human display.
+  static std::string FormatErrorMessage(int line, int column,
+                                        const std::string& description);
+
+  // base::JSONParserOptions that control parsing.
+  int options_;
+
+  // Pointer to the start of the input data.
+  const char* start_pos_;
+
+  // Pointer to the current position in the input data. Equivalent to
+  // |start_pos_ + index_|.
+  const char* pos_;
+
+  // Pointer to the last character of the input data.
+  const char* end_pos_;
+
+  // The index in the input stream to which the parser is wound.
+  int index_;
+
+  // The number of times the parser has recursed (current stack depth).
+  int stack_depth_;
+
+  // The line number that the parser is at currently.
+  int line_number_;
+
+  // The last value of |index_| on the previous line.
+  int index_last_line_;
+
+  // Error information.
+  JSONReader::JsonParseError error_code_;
+  int error_line_;
+  int error_column_;
+
+  friend class JSONParserTest;
+  FRIEND_TEST_ALL_PREFIXES(JSONParserTest, NextChar);
+  FRIEND_TEST_ALL_PREFIXES(JSONParserTest, ConsumeDictionary);
+  FRIEND_TEST_ALL_PREFIXES(JSONParserTest, ConsumeList);
+  FRIEND_TEST_ALL_PREFIXES(JSONParserTest, ConsumeString);
+  FRIEND_TEST_ALL_PREFIXES(JSONParserTest, ConsumeLiterals);
+  FRIEND_TEST_ALL_PREFIXES(JSONParserTest, ConsumeNumbers);
+  FRIEND_TEST_ALL_PREFIXES(JSONParserTest, ErrorMessages);
+
+  DISALLOW_COPY_AND_ASSIGN(JSONParser);
+};
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_JSON_JSON_PARSER_H_
diff --git a/base/json/json_parser_unittest.cc b/base/json/json_parser_unittest.cc
new file mode 100644
index 0000000..f776ddf
--- /dev/null
+++ b/base/json/json_parser_unittest.cc
@@ -0,0 +1,317 @@
+// Copyright (c) 2012 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/json/json_parser.h"
+
+#include "base/json/json_reader.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace internal {
+
+class JSONParserTest : public testing::Test {
+ public:
+  JSONParser* NewTestParser(const std::string& input) {
+    JSONParser* parser = new JSONParser(JSON_PARSE_RFC);
+    parser->start_pos_ = input.data();
+    parser->pos_ = parser->start_pos_;
+    parser->end_pos_ = parser->start_pos_ + input.length();
+    return parser;
+  }
+
+  void TestLastThree(JSONParser* parser) {
+    EXPECT_EQ(',', *parser->NextChar());
+    EXPECT_EQ('|', *parser->NextChar());
+    EXPECT_EQ('\0', *parser->NextChar());
+    EXPECT_EQ(parser->end_pos_, parser->pos_);
+  }
+};
+
+TEST_F(JSONParserTest, NextChar) {
+  std::string input("Hello world");
+  scoped_ptr<JSONParser> parser(NewTestParser(input));
+
+  EXPECT_EQ('H', *parser->pos_);
+  for (size_t i = 1; i < input.length(); ++i) {
+    EXPECT_EQ(input[i], *parser->NextChar());
+  }
+  EXPECT_EQ(parser->end_pos_, parser->NextChar());
+}
+
+TEST_F(JSONParserTest, ConsumeString) {
+  std::string input("\"test\",|");
+  scoped_ptr<JSONParser> parser(NewTestParser(input));
+  scoped_ptr<Value> value(parser->ConsumeString());
+  EXPECT_EQ('"', *parser->pos_);
+
+  TestLastThree(parser.get());
+
+  ASSERT_TRUE(value.get());
+  std::string str;
+  EXPECT_TRUE(value->GetAsString(&str));
+  EXPECT_EQ("test", str);
+}
+
+TEST_F(JSONParserTest, ConsumeList) {
+  std::string input("[true, false],|");
+  scoped_ptr<JSONParser> parser(NewTestParser(input));
+  scoped_ptr<Value> value(parser->ConsumeList());
+  EXPECT_EQ(']', *parser->pos_);
+
+  TestLastThree(parser.get());
+
+  ASSERT_TRUE(value.get());
+  base::ListValue* list;
+  EXPECT_TRUE(value->GetAsList(&list));
+  EXPECT_EQ(2u, list->GetSize());
+}
+
+TEST_F(JSONParserTest, ConsumeDictionary) {
+  std::string input("{\"abc\":\"def\"},|");
+  scoped_ptr<JSONParser> parser(NewTestParser(input));
+  scoped_ptr<Value> value(parser->ConsumeDictionary());
+  EXPECT_EQ('}', *parser->pos_);
+
+  TestLastThree(parser.get());
+
+  ASSERT_TRUE(value.get());
+  base::DictionaryValue* dict;
+  EXPECT_TRUE(value->GetAsDictionary(&dict));
+  std::string str;
+  EXPECT_TRUE(dict->GetString("abc", &str));
+  EXPECT_EQ("def", str);
+}
+
+TEST_F(JSONParserTest, ConsumeLiterals) {
+  // Literal |true|.
+  std::string input("true,|");
+  scoped_ptr<JSONParser> parser(NewTestParser(input));
+  scoped_ptr<Value> value(parser->ConsumeLiteral());
+  EXPECT_EQ('e', *parser->pos_);
+
+  TestLastThree(parser.get());
+
+  ASSERT_TRUE(value.get());
+  bool bool_value = false;
+  EXPECT_TRUE(value->GetAsBoolean(&bool_value));
+  EXPECT_TRUE(bool_value);
+
+  // Literal |false|.
+  input = "false,|";
+  parser.reset(NewTestParser(input));
+  value.reset(parser->ConsumeLiteral());
+  EXPECT_EQ('e', *parser->pos_);
+
+  TestLastThree(parser.get());
+
+  ASSERT_TRUE(value.get());
+  EXPECT_TRUE(value->GetAsBoolean(&bool_value));
+  EXPECT_FALSE(bool_value);
+
+  // Literal |null|.
+  input = "null,|";
+  parser.reset(NewTestParser(input));
+  value.reset(parser->ConsumeLiteral());
+  EXPECT_EQ('l', *parser->pos_);
+
+  TestLastThree(parser.get());
+
+  ASSERT_TRUE(value.get());
+  EXPECT_TRUE(value->IsType(Value::TYPE_NULL));
+}
+
+TEST_F(JSONParserTest, ConsumeNumbers) {
+  // Integer.
+  std::string input("1234,|");
+  scoped_ptr<JSONParser> parser(NewTestParser(input));
+  scoped_ptr<Value> value(parser->ConsumeNumber());
+  EXPECT_EQ('4', *parser->pos_);
+
+  TestLastThree(parser.get());
+
+  ASSERT_TRUE(value.get());
+  int number_i;
+  EXPECT_TRUE(value->GetAsInteger(&number_i));
+  EXPECT_EQ(1234, number_i);
+
+  // Negative integer.
+  input = "-1234,|";
+  parser.reset(NewTestParser(input));
+  value.reset(parser->ConsumeNumber());
+  EXPECT_EQ('4', *parser->pos_);
+
+  TestLastThree(parser.get());
+
+  ASSERT_TRUE(value.get());
+  EXPECT_TRUE(value->GetAsInteger(&number_i));
+  EXPECT_EQ(-1234, number_i);
+
+  // Double.
+  input = "12.34,|";
+  parser.reset(NewTestParser(input));
+  value.reset(parser->ConsumeNumber());
+  EXPECT_EQ('4', *parser->pos_);
+
+  TestLastThree(parser.get());
+
+  ASSERT_TRUE(value.get());
+  double number_d;
+  EXPECT_TRUE(value->GetAsDouble(&number_d));
+  EXPECT_EQ(12.34, number_d);
+
+  // Scientific.
+  input = "42e3,|";
+  parser.reset(NewTestParser(input));
+  value.reset(parser->ConsumeNumber());
+  EXPECT_EQ('3', *parser->pos_);
+
+  TestLastThree(parser.get());
+
+  ASSERT_TRUE(value.get());
+  EXPECT_TRUE(value->GetAsDouble(&number_d));
+  EXPECT_EQ(42000, number_d);
+
+  // Negative scientific.
+  input = "314159e-5,|";
+  parser.reset(NewTestParser(input));
+  value.reset(parser->ConsumeNumber());
+  EXPECT_EQ('5', *parser->pos_);
+
+  TestLastThree(parser.get());
+
+  ASSERT_TRUE(value.get());
+  EXPECT_TRUE(value->GetAsDouble(&number_d));
+  EXPECT_EQ(3.14159, number_d);
+
+  // Positive scientific.
+  input = "0.42e+3,|";
+  parser.reset(NewTestParser(input));
+  value.reset(parser->ConsumeNumber());
+  EXPECT_EQ('3', *parser->pos_);
+
+  TestLastThree(parser.get());
+
+  ASSERT_TRUE(value.get());
+  EXPECT_TRUE(value->GetAsDouble(&number_d));
+  EXPECT_EQ(420, number_d);
+}
+
+TEST_F(JSONParserTest, ErrorMessages) {
+  // Error strings should not be modified in case of success.
+  std::string error_message;
+  int error_code = 0;
+  scoped_ptr<Value> root;
+  root.reset(JSONReader::DeprecatedReadAndReturnError(
+      "[42]", JSON_PARSE_RFC, &error_code, &error_message));
+  EXPECT_TRUE(error_message.empty());
+  EXPECT_EQ(0, error_code);
+
+  // Test line and column counting
+  const char big_json[] = "[\n0,\n1,\n2,\n3,4,5,6 7,\n8,\n9\n]";
+  // error here ----------------------------------^
+  root.reset(JSONReader::DeprecatedReadAndReturnError(
+      big_json, JSON_PARSE_RFC, &error_code, &error_message));
+  EXPECT_FALSE(root.get());
+  EXPECT_EQ(JSONParser::FormatErrorMessage(5, 10, JSONReader::kSyntaxError),
+            error_message);
+  EXPECT_EQ(JSONReader::JSON_SYNTAX_ERROR, error_code);
+
+  error_code = 0;
+  error_message = "";
+  // Test line and column counting with "\r\n" line ending
+  const char big_json_crlf[] =
+      "[\r\n0,\r\n1,\r\n2,\r\n3,4,5,6 7,\r\n8,\r\n9\r\n]";
+  // error here ----------------------^
+  root.reset(JSONReader::DeprecatedReadAndReturnError(
+      big_json_crlf, JSON_PARSE_RFC, &error_code, &error_message));
+  EXPECT_FALSE(root.get());
+  EXPECT_EQ(JSONParser::FormatErrorMessage(5, 10, JSONReader::kSyntaxError),
+            error_message);
+  EXPECT_EQ(JSONReader::JSON_SYNTAX_ERROR, error_code);
+
+  // Test each of the error conditions
+  root.reset(JSONReader::DeprecatedReadAndReturnError(
+      "{},{}", JSON_PARSE_RFC, &error_code, &error_message));
+  EXPECT_FALSE(root.get());
+  EXPECT_EQ(JSONParser::FormatErrorMessage(1, 3,
+      JSONReader::kUnexpectedDataAfterRoot), error_message);
+  EXPECT_EQ(JSONReader::JSON_UNEXPECTED_DATA_AFTER_ROOT, error_code);
+
+  std::string nested_json;
+  for (int i = 0; i < 101; ++i) {
+    nested_json.insert(nested_json.begin(), '[');
+    nested_json.append(1, ']');
+  }
+  root.reset(JSONReader::DeprecatedReadAndReturnError(
+      nested_json, JSON_PARSE_RFC, &error_code, &error_message));
+  EXPECT_FALSE(root.get());
+  EXPECT_EQ(JSONParser::FormatErrorMessage(1, 100, JSONReader::kTooMuchNesting),
+            error_message);
+  EXPECT_EQ(JSONReader::JSON_TOO_MUCH_NESTING, error_code);
+
+  root.reset(JSONReader::DeprecatedReadAndReturnError(
+      "[1,]", JSON_PARSE_RFC, &error_code, &error_message));
+  EXPECT_FALSE(root.get());
+  EXPECT_EQ(JSONParser::FormatErrorMessage(1, 4, JSONReader::kTrailingComma),
+            error_message);
+  EXPECT_EQ(JSONReader::JSON_TRAILING_COMMA, error_code);
+
+  root.reset(JSONReader::DeprecatedReadAndReturnError(
+      "{foo:\"bar\"}", JSON_PARSE_RFC, &error_code, &error_message));
+  EXPECT_FALSE(root.get());
+  EXPECT_EQ(JSONParser::FormatErrorMessage(1, 2,
+      JSONReader::kUnquotedDictionaryKey), error_message);
+  EXPECT_EQ(JSONReader::JSON_UNQUOTED_DICTIONARY_KEY, error_code);
+
+  root.reset(JSONReader::DeprecatedReadAndReturnError(
+      "{\"foo\":\"bar\",}", JSON_PARSE_RFC, &error_code, &error_message));
+  EXPECT_FALSE(root.get());
+  EXPECT_EQ(JSONParser::FormatErrorMessage(1, 14, JSONReader::kTrailingComma),
+            error_message);
+
+  root.reset(JSONReader::DeprecatedReadAndReturnError(
+      "[nu]", JSON_PARSE_RFC, &error_code, &error_message));
+  EXPECT_FALSE(root.get());
+  EXPECT_EQ(JSONParser::FormatErrorMessage(1, 2, JSONReader::kSyntaxError),
+            error_message);
+  EXPECT_EQ(JSONReader::JSON_SYNTAX_ERROR, error_code);
+
+  root.reset(JSONReader::DeprecatedReadAndReturnError(
+      "[\"xxx\\xq\"]", JSON_PARSE_RFC, &error_code, &error_message));
+  EXPECT_FALSE(root.get());
+  EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONReader::kInvalidEscape),
+            error_message);
+  EXPECT_EQ(JSONReader::JSON_INVALID_ESCAPE, error_code);
+
+  root.reset(JSONReader::DeprecatedReadAndReturnError(
+      "[\"xxx\\uq\"]", JSON_PARSE_RFC, &error_code, &error_message));
+  EXPECT_FALSE(root.get());
+  EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONReader::kInvalidEscape),
+            error_message);
+  EXPECT_EQ(JSONReader::JSON_INVALID_ESCAPE, error_code);
+
+  root.reset(JSONReader::DeprecatedReadAndReturnError(
+      "[\"xxx\\q\"]", JSON_PARSE_RFC, &error_code, &error_message));
+  EXPECT_FALSE(root.get());
+  EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONReader::kInvalidEscape),
+            error_message);
+  EXPECT_EQ(JSONReader::JSON_INVALID_ESCAPE, error_code);
+}
+
+TEST_F(JSONParserTest, Decode4ByteUtf8Char) {
+  // This test strings contains a 4 byte unicode character (a smiley!) that the
+  // reader should be able to handle (the character is \xf0\x9f\x98\x87).
+  const char kUtf8Data[] =
+      "[\"😇\",[],[],[],{\"google:suggesttype\":[]}]";
+  std::string error_message;
+  int error_code = 0;
+  scoped_ptr<Value> root(JSONReader::DeprecatedReadAndReturnError(
+      kUtf8Data, JSON_PARSE_RFC, &error_code, &error_message));
+  EXPECT_TRUE(root.get()) << error_message;
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/json/json_reader.cc b/base/json/json_reader.cc
new file mode 100644
index 0000000..ad3ea98
--- /dev/null
+++ b/base/json/json_reader.cc
@@ -0,0 +1,132 @@
+// Copyright (c) 2012 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/json/json_reader.h"
+
+#include "base/json/json_parser.h"
+#include "base/logging.h"
+#include "base/values.h"
+
+namespace base {
+
+// Values 1000 and above are used by JSONFileValueSerializer::JsonFileError.
+COMPILE_ASSERT(JSONReader::JSON_PARSE_ERROR_COUNT < 1000,
+               json_reader_error_out_of_bounds);
+
+const char JSONReader::kInvalidEscape[] =
+    "Invalid escape sequence.";
+const char JSONReader::kSyntaxError[] =
+    "Syntax error.";
+const char JSONReader::kUnexpectedToken[] =
+    "Unexpected token.";
+const char JSONReader::kTrailingComma[] =
+    "Trailing comma not allowed.";
+const char JSONReader::kTooMuchNesting[] =
+    "Too much nesting.";
+const char JSONReader::kUnexpectedDataAfterRoot[] =
+    "Unexpected data after root element.";
+const char JSONReader::kUnsupportedEncoding[] =
+    "Unsupported encoding. JSON must be UTF-8.";
+const char JSONReader::kUnquotedDictionaryKey[] =
+    "Dictionary keys must be quoted.";
+
+JSONReader::JSONReader()
+    : JSONReader(JSON_PARSE_RFC) {
+}
+
+JSONReader::JSONReader(int options)
+    : parser_(new internal::JSONParser(options)) {
+}
+
+JSONReader::~JSONReader() {
+}
+
+// static
+Value* JSONReader::DeprecatedRead(const StringPiece& json) {
+  return Read(json).release();
+}
+
+// static
+scoped_ptr<Value> JSONReader::Read(const StringPiece& json) {
+  internal::JSONParser parser(JSON_PARSE_RFC);
+  return make_scoped_ptr(parser.Parse(json));
+}
+
+// static
+Value* JSONReader::DeprecatedRead(const StringPiece& json, int options) {
+  return Read(json, options).release();
+}
+
+// static
+scoped_ptr<Value> JSONReader::Read(const StringPiece& json, int options) {
+  internal::JSONParser parser(options);
+  return make_scoped_ptr(parser.Parse(json));
+}
+
+// static
+Value* JSONReader::DeprecatedReadAndReturnError(const StringPiece& json,
+                                                int options,
+                                                int* error_code_out,
+                                                std::string* error_msg_out) {
+  return ReadAndReturnError(json, options, error_code_out, error_msg_out)
+      .release();
+}
+
+// static
+scoped_ptr<Value> JSONReader::ReadAndReturnError(const StringPiece& json,
+                                                 int options,
+                                                 int* error_code_out,
+                                                 std::string* error_msg_out) {
+  internal::JSONParser parser(options);
+  scoped_ptr<Value> root(parser.Parse(json));
+  if (!root) {
+    if (error_code_out)
+      *error_code_out = parser.error_code();
+    if (error_msg_out)
+      *error_msg_out = parser.GetErrorMessage();
+  }
+
+  return root;
+}
+
+// static
+std::string JSONReader::ErrorCodeToString(JsonParseError error_code) {
+  switch (error_code) {
+    case JSON_NO_ERROR:
+      return std::string();
+    case JSON_INVALID_ESCAPE:
+      return kInvalidEscape;
+    case JSON_SYNTAX_ERROR:
+      return kSyntaxError;
+    case JSON_UNEXPECTED_TOKEN:
+      return kUnexpectedToken;
+    case JSON_TRAILING_COMMA:
+      return kTrailingComma;
+    case JSON_TOO_MUCH_NESTING:
+      return kTooMuchNesting;
+    case JSON_UNEXPECTED_DATA_AFTER_ROOT:
+      return kUnexpectedDataAfterRoot;
+    case JSON_UNSUPPORTED_ENCODING:
+      return kUnsupportedEncoding;
+    case JSON_UNQUOTED_DICTIONARY_KEY:
+      return kUnquotedDictionaryKey;
+    default:
+      NOTREACHED();
+      return std::string();
+  }
+}
+
+scoped_ptr<Value> JSONReader::ReadToValue(const std::string& json) {
+  return make_scoped_ptr(parser_->Parse(json));
+}
+
+JSONReader::JsonParseError JSONReader::error_code() const {
+  return parser_->error_code();
+}
+
+std::string JSONReader::GetErrorMessage() const {
+  return parser_->GetErrorMessage();
+}
+
+}  // namespace base
diff --git a/base/json/json_reader.h b/base/json/json_reader.h
new file mode 100644
index 0000000..378935a
--- /dev/null
+++ b/base/json/json_reader.h
@@ -0,0 +1,143 @@
+// Copyright (c) 2012 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.
+//
+// A JSON parser.  Converts strings of JSON into a Value object (see
+// base/values.h).
+// http://www.ietf.org/rfc/rfc4627.txt?number=4627
+//
+// Known limitations/deviations from the RFC:
+// - Only knows how to parse ints within the range of a signed 32 bit int and
+//   decimal numbers within a double.
+// - Assumes input is encoded as UTF8.  The spec says we should allow UTF-16
+//   (BE or LE) and UTF-32 (BE or LE) as well.
+// - We limit nesting to 100 levels to prevent stack overflow (this is allowed
+//   by the RFC).
+// - A Unicode FAQ ("http://unicode.org/faq/utf_bom.html") writes a data
+//   stream may start with a Unicode Byte-Order-Mark (U+FEFF), i.e. the input
+//   UTF-8 string for the JSONReader::JsonToValue() function may start with a
+//   UTF-8 BOM (0xEF, 0xBB, 0xBF).
+//   To avoid the function from mis-treating a UTF-8 BOM as an invalid
+//   character, the function skips a Unicode BOM at the beginning of the
+//   Unicode string (converted from the input UTF-8 string) before parsing it.
+//
+// TODO(tc): Add a parsing option to to relax object keys being wrapped in
+//   double quotes
+// TODO(tc): Add an option to disable comment stripping
+
+#ifndef BASE_JSON_JSON_READER_H_
+#define BASE_JSON_JSON_READER_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+class Value;
+
+namespace internal {
+class JSONParser;
+}
+
+enum JSONParserOptions {
+  // Parses the input strictly according to RFC 4627, except for where noted
+  // above.
+  JSON_PARSE_RFC = 0,
+
+  // Allows commas to exist after the last element in structures.
+  JSON_ALLOW_TRAILING_COMMAS = 1 << 0,
+
+  // The parser can perform optimizations by placing hidden data in the root of
+  // the JSON object, which speeds up certain operations on children. However,
+  // if the child is Remove()d from root, it would result in use-after-free
+  // unless it is DeepCopy()ed or this option is used.
+  JSON_DETACHABLE_CHILDREN = 1 << 1,
+};
+
+class BASE_EXPORT JSONReader {
+ public:
+  // Error codes during parsing.
+  enum JsonParseError {
+    JSON_NO_ERROR = 0,
+    JSON_INVALID_ESCAPE,
+    JSON_SYNTAX_ERROR,
+    JSON_UNEXPECTED_TOKEN,
+    JSON_TRAILING_COMMA,
+    JSON_TOO_MUCH_NESTING,
+    JSON_UNEXPECTED_DATA_AFTER_ROOT,
+    JSON_UNSUPPORTED_ENCODING,
+    JSON_UNQUOTED_DICTIONARY_KEY,
+    JSON_PARSE_ERROR_COUNT
+  };
+
+  // String versions of parse error codes.
+  static const char kInvalidEscape[];
+  static const char kSyntaxError[];
+  static const char kUnexpectedToken[];
+  static const char kTrailingComma[];
+  static const char kTooMuchNesting[];
+  static const char kUnexpectedDataAfterRoot[];
+  static const char kUnsupportedEncoding[];
+  static const char kUnquotedDictionaryKey[];
+
+  // Constructs a reader with the default options, JSON_PARSE_RFC.
+  JSONReader();
+
+  // Constructs a reader with custom options.
+  explicit JSONReader(int options);
+
+  ~JSONReader();
+
+  // Reads and parses |json|, returning a Value. The caller owns the returned
+  // instance. If |json| is not a properly formed JSON string, returns NULL.
+  static scoped_ptr<Value> Read(const StringPiece& json);
+  // TODO(estade): remove this bare pointer version.
+  static Value* DeprecatedRead(const StringPiece& json);
+
+  // Reads and parses |json|, returning a Value owned by the caller. The
+  // parser respects the given |options|. If the input is not properly formed,
+  // returns NULL.
+  static scoped_ptr<Value> Read(const StringPiece& json, int options);
+  // TODO(estade): remove this bare pointer version.
+  static Value* DeprecatedRead(const StringPiece& json, int options);
+
+  // Reads and parses |json| like Read(). |error_code_out| and |error_msg_out|
+  // are optional. If specified and NULL is returned, they will be populated
+  // an error code and a formatted error message (including error location if
+  // appropriate). Otherwise, they will be unmodified.
+  static scoped_ptr<Value> ReadAndReturnError(const StringPiece& json,
+                                              int options,  // JSONParserOptions
+                                              int* error_code_out,
+                                              std::string* error_msg_out);
+  // TODO(estade): remove this bare pointer version.
+  static Value* DeprecatedReadAndReturnError(const StringPiece& json,
+                                             int options,  // JSONParserOptions
+                                             int* error_code_out,
+                                             std::string* error_msg_out);
+
+  // Converts a JSON parse error code into a human readable message.
+  // Returns an empty string if error_code is JSON_NO_ERROR.
+  static std::string ErrorCodeToString(JsonParseError error_code);
+
+  // Parses an input string into a Value that is owned by the caller.
+  scoped_ptr<Value> ReadToValue(const std::string& json);
+
+  // Returns the error code if the last call to ReadToValue() failed.
+  // Returns JSON_NO_ERROR otherwise.
+  JsonParseError error_code() const;
+
+  // Converts error_code_ to a human-readable string, including line and column
+  // numbers if appropriate.
+  std::string GetErrorMessage() const;
+
+ private:
+  scoped_ptr<internal::JSONParser> parser_;
+};
+
+}  // namespace base
+
+#endif  // BASE_JSON_JSON_READER_H_
diff --git a/base/json/json_reader_unittest.cc b/base/json/json_reader_unittest.cc
new file mode 100644
index 0000000..7d3a6d9
--- /dev/null
+++ b/base/json/json_reader_unittest.cc
@@ -0,0 +1,668 @@
+// Copyright (c) 2012 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/json/json_reader.h"
+
+#include "base/base_paths.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/path_service.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(JSONReaderTest, Reading) {
+  // some whitespace checking
+  scoped_ptr<Value> root;
+  root = JSONReader().ReadToValue("   null   ");
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_NULL));
+
+  // Invalid JSON string
+  root = JSONReader().ReadToValue("nu");
+  EXPECT_FALSE(root.get());
+
+  // Simple bool
+  root = JSONReader().ReadToValue("true  ");
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_BOOLEAN));
+
+  // Embedded comment
+  root = JSONReader().ReadToValue("/* comment */null");
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_NULL));
+  root = JSONReader().ReadToValue("40 /* comment */");
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_INTEGER));
+  root = JSONReader().ReadToValue("true // comment");
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_BOOLEAN));
+  root = JSONReader().ReadToValue("/* comment */\"sample string\"");
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_STRING));
+  std::string value;
+  EXPECT_TRUE(root->GetAsString(&value));
+  EXPECT_EQ("sample string", value);
+  root = JSONReader().ReadToValue("[1, /* comment, 2 ] */ \n 3]");
+  ASSERT_TRUE(root.get());
+  ListValue* list = static_cast<ListValue*>(root.get());
+  EXPECT_EQ(2u, list->GetSize());
+  int int_val = 0;
+  EXPECT_TRUE(list->GetInteger(0, &int_val));
+  EXPECT_EQ(1, int_val);
+  EXPECT_TRUE(list->GetInteger(1, &int_val));
+  EXPECT_EQ(3, int_val);
+  root = JSONReader().ReadToValue("[1, /*a*/2, 3]");
+  ASSERT_TRUE(root.get());
+  list = static_cast<ListValue*>(root.get());
+  EXPECT_EQ(3u, list->GetSize());
+  root = JSONReader().ReadToValue("/* comment **/42");
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_INTEGER));
+  EXPECT_TRUE(root->GetAsInteger(&int_val));
+  EXPECT_EQ(42, int_val);
+  root = JSONReader().ReadToValue(
+      "/* comment **/\n"
+      "// */ 43\n"
+      "44");
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_INTEGER));
+  EXPECT_TRUE(root->GetAsInteger(&int_val));
+  EXPECT_EQ(44, int_val);
+
+  // Test number formats
+  root = JSONReader().ReadToValue("43");
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_INTEGER));
+  EXPECT_TRUE(root->GetAsInteger(&int_val));
+  EXPECT_EQ(43, int_val);
+
+  // According to RFC4627, oct, hex, and leading zeros are invalid JSON.
+  root = JSONReader().ReadToValue("043");
+  EXPECT_FALSE(root.get());
+  root = JSONReader().ReadToValue("0x43");
+  EXPECT_FALSE(root.get());
+  root = JSONReader().ReadToValue("00");
+  EXPECT_FALSE(root.get());
+
+  // Test 0 (which needs to be special cased because of the leading zero
+  // clause).
+  root = JSONReader().ReadToValue("0");
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_INTEGER));
+  int_val = 1;
+  EXPECT_TRUE(root->GetAsInteger(&int_val));
+  EXPECT_EQ(0, int_val);
+
+  // Numbers that overflow ints should succeed, being internally promoted to
+  // storage as doubles
+  root = JSONReader().ReadToValue("2147483648");
+  ASSERT_TRUE(root.get());
+  double double_val;
+  EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE));
+  double_val = 0.0;
+  EXPECT_TRUE(root->GetAsDouble(&double_val));
+  EXPECT_DOUBLE_EQ(2147483648.0, double_val);
+  root = JSONReader().ReadToValue("-2147483649");
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE));
+  double_val = 0.0;
+  EXPECT_TRUE(root->GetAsDouble(&double_val));
+  EXPECT_DOUBLE_EQ(-2147483649.0, double_val);
+
+  // Parse a double
+  root = JSONReader().ReadToValue("43.1");
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE));
+  double_val = 0.0;
+  EXPECT_TRUE(root->GetAsDouble(&double_val));
+  EXPECT_DOUBLE_EQ(43.1, double_val);
+
+  root = JSONReader().ReadToValue("4.3e-1");
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE));
+  double_val = 0.0;
+  EXPECT_TRUE(root->GetAsDouble(&double_val));
+  EXPECT_DOUBLE_EQ(.43, double_val);
+
+  root = JSONReader().ReadToValue("2.1e0");
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE));
+  double_val = 0.0;
+  EXPECT_TRUE(root->GetAsDouble(&double_val));
+  EXPECT_DOUBLE_EQ(2.1, double_val);
+
+  root = JSONReader().ReadToValue("2.1e+0001");
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE));
+  double_val = 0.0;
+  EXPECT_TRUE(root->GetAsDouble(&double_val));
+  EXPECT_DOUBLE_EQ(21.0, double_val);
+
+  root = JSONReader().ReadToValue("0.01");
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE));
+  double_val = 0.0;
+  EXPECT_TRUE(root->GetAsDouble(&double_val));
+  EXPECT_DOUBLE_EQ(0.01, double_val);
+
+  root = JSONReader().ReadToValue("1.00");
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_DOUBLE));
+  double_val = 0.0;
+  EXPECT_TRUE(root->GetAsDouble(&double_val));
+  EXPECT_DOUBLE_EQ(1.0, double_val);
+
+  // Fractional parts must have a digit before and after the decimal point.
+  root = JSONReader().ReadToValue("1.");
+  EXPECT_FALSE(root.get());
+  root = JSONReader().ReadToValue(".1");
+  EXPECT_FALSE(root.get());
+  root = JSONReader().ReadToValue("1.e10");
+  EXPECT_FALSE(root.get());
+
+  // Exponent must have a digit following the 'e'.
+  root = JSONReader().ReadToValue("1e");
+  EXPECT_FALSE(root.get());
+  root = JSONReader().ReadToValue("1E");
+  EXPECT_FALSE(root.get());
+  root = JSONReader().ReadToValue("1e1.");
+  EXPECT_FALSE(root.get());
+  root = JSONReader().ReadToValue("1e1.0");
+  EXPECT_FALSE(root.get());
+
+  // INF/-INF/NaN are not valid
+  root = JSONReader().ReadToValue("1e1000");
+  EXPECT_FALSE(root.get());
+  root = JSONReader().ReadToValue("-1e1000");
+  EXPECT_FALSE(root.get());
+  root = JSONReader().ReadToValue("NaN");
+  EXPECT_FALSE(root.get());
+  root = JSONReader().ReadToValue("nan");
+  EXPECT_FALSE(root.get());
+  root = JSONReader().ReadToValue("inf");
+  EXPECT_FALSE(root.get());
+
+  // Invalid number formats
+  root = JSONReader().ReadToValue("4.3.1");
+  EXPECT_FALSE(root.get());
+  root = JSONReader().ReadToValue("4e3.1");
+  EXPECT_FALSE(root.get());
+
+  // Test string parser
+  root = JSONReader().ReadToValue("\"hello world\"");
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_STRING));
+  std::string str_val;
+  EXPECT_TRUE(root->GetAsString(&str_val));
+  EXPECT_EQ("hello world", str_val);
+
+  // Empty string
+  root = JSONReader().ReadToValue("\"\"");
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_STRING));
+  str_val.clear();
+  EXPECT_TRUE(root->GetAsString(&str_val));
+  EXPECT_EQ("", str_val);
+
+  // Test basic string escapes
+  root = JSONReader().ReadToValue("\" \\\"\\\\\\/\\b\\f\\n\\r\\t\\v\"");
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_STRING));
+  str_val.clear();
+  EXPECT_TRUE(root->GetAsString(&str_val));
+  EXPECT_EQ(" \"\\/\b\f\n\r\t\v", str_val);
+
+  // Test hex and unicode escapes including the null character.
+  root = JSONReader().ReadToValue("\"\\x41\\x00\\u1234\"");
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_STRING));
+  str_val.clear();
+  EXPECT_TRUE(root->GetAsString(&str_val));
+  EXPECT_EQ(std::wstring(L"A\0\x1234", 3), UTF8ToWide(str_val));
+
+  // Test invalid strings
+  root = JSONReader().ReadToValue("\"no closing quote");
+  EXPECT_FALSE(root.get());
+  root = JSONReader().ReadToValue("\"\\z invalid escape char\"");
+  EXPECT_FALSE(root.get());
+  root = JSONReader().ReadToValue("\"\\xAQ invalid hex code\"");
+  EXPECT_FALSE(root.get());
+  root = JSONReader().ReadToValue("not enough hex chars\\x1\"");
+  EXPECT_FALSE(root.get());
+  root = JSONReader().ReadToValue("\"not enough escape chars\\u123\"");
+  EXPECT_FALSE(root.get());
+  root = JSONReader().ReadToValue("\"extra backslash at end of input\\\"");
+  EXPECT_FALSE(root.get());
+
+  // Basic array
+  root.reset(JSONReader::DeprecatedRead("[true, false, null]"));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_LIST));
+  list = static_cast<ListValue*>(root.get());
+  EXPECT_EQ(3U, list->GetSize());
+
+  // Test with trailing comma.  Should be parsed the same as above.
+  scoped_ptr<Value> root2;
+  root2.reset(JSONReader::DeprecatedRead("[true, false, null, ]",
+                                         JSON_ALLOW_TRAILING_COMMAS));
+  EXPECT_TRUE(root->Equals(root2.get()));
+
+  // Empty array
+  root.reset(JSONReader::DeprecatedRead("[]"));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_LIST));
+  list = static_cast<ListValue*>(root.get());
+  EXPECT_EQ(0U, list->GetSize());
+
+  // Nested arrays
+  root.reset(
+      JSONReader::DeprecatedRead("[[true], [], [false, [], [null]], null]"));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_LIST));
+  list = static_cast<ListValue*>(root.get());
+  EXPECT_EQ(4U, list->GetSize());
+
+  // Lots of trailing commas.
+  root2.reset(JSONReader::DeprecatedRead(
+      "[[true], [], [false, [], [null, ]  , ], null,]",
+      JSON_ALLOW_TRAILING_COMMAS));
+  EXPECT_TRUE(root->Equals(root2.get()));
+
+  // Invalid, missing close brace.
+  root.reset(
+      JSONReader::DeprecatedRead("[[true], [], [false, [], [null]], null"));
+  EXPECT_FALSE(root.get());
+
+  // Invalid, too many commas
+  root.reset(JSONReader::DeprecatedRead("[true,, null]"));
+  EXPECT_FALSE(root.get());
+  root.reset(
+      JSONReader::DeprecatedRead("[true,, null]", JSON_ALLOW_TRAILING_COMMAS));
+  EXPECT_FALSE(root.get());
+
+  // Invalid, no commas
+  root.reset(JSONReader::DeprecatedRead("[true null]"));
+  EXPECT_FALSE(root.get());
+
+  // Invalid, trailing comma
+  root.reset(JSONReader::DeprecatedRead("[true,]"));
+  EXPECT_FALSE(root.get());
+
+  // Valid if we set |allow_trailing_comma| to true.
+  root.reset(JSONReader::DeprecatedRead("[true,]", JSON_ALLOW_TRAILING_COMMAS));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_LIST));
+  list = static_cast<ListValue*>(root.get());
+  EXPECT_EQ(1U, list->GetSize());
+  Value* tmp_value = NULL;
+  ASSERT_TRUE(list->Get(0, &tmp_value));
+  EXPECT_TRUE(tmp_value->IsType(Value::TYPE_BOOLEAN));
+  bool bool_value = false;
+  EXPECT_TRUE(tmp_value->GetAsBoolean(&bool_value));
+  EXPECT_TRUE(bool_value);
+
+  // Don't allow empty elements, even if |allow_trailing_comma| is
+  // true.
+  root.reset(JSONReader::DeprecatedRead("[,]", JSON_ALLOW_TRAILING_COMMAS));
+  EXPECT_FALSE(root.get());
+  root.reset(
+      JSONReader::DeprecatedRead("[true,,]", JSON_ALLOW_TRAILING_COMMAS));
+  EXPECT_FALSE(root.get());
+  root.reset(
+      JSONReader::DeprecatedRead("[,true,]", JSON_ALLOW_TRAILING_COMMAS));
+  EXPECT_FALSE(root.get());
+  root.reset(
+      JSONReader::DeprecatedRead("[true,,false]", JSON_ALLOW_TRAILING_COMMAS));
+  EXPECT_FALSE(root.get());
+
+  // Test objects
+  root.reset(JSONReader::DeprecatedRead("{}"));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
+
+  root.reset(JSONReader::DeprecatedRead(
+      "{\"number\":9.87654321, \"null\":null , \"\\x53\" : \"str\" }"));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
+  DictionaryValue* dict_val = static_cast<DictionaryValue*>(root.get());
+  double_val = 0.0;
+  EXPECT_TRUE(dict_val->GetDouble("number", &double_val));
+  EXPECT_DOUBLE_EQ(9.87654321, double_val);
+  Value* null_val = NULL;
+  ASSERT_TRUE(dict_val->Get("null", &null_val));
+  EXPECT_TRUE(null_val->IsType(Value::TYPE_NULL));
+  str_val.clear();
+  EXPECT_TRUE(dict_val->GetString("S", &str_val));
+  EXPECT_EQ("str", str_val);
+
+  root2.reset(JSONReader::DeprecatedRead(
+      "{\"number\":9.87654321, \"null\":null , \"\\x53\" : \"str\", }",
+      JSON_ALLOW_TRAILING_COMMAS));
+  ASSERT_TRUE(root2.get());
+  EXPECT_TRUE(root->Equals(root2.get()));
+
+  // Test newline equivalence.
+  root2.reset(JSONReader::DeprecatedRead(
+      "{\n"
+      "  \"number\":9.87654321,\n"
+      "  \"null\":null,\n"
+      "  \"\\x53\":\"str\",\n"
+      "}\n",
+      JSON_ALLOW_TRAILING_COMMAS));
+  ASSERT_TRUE(root2.get());
+  EXPECT_TRUE(root->Equals(root2.get()));
+
+  root2.reset(JSONReader::DeprecatedRead(
+      "{\r\n"
+      "  \"number\":9.87654321,\r\n"
+      "  \"null\":null,\r\n"
+      "  \"\\x53\":\"str\",\r\n"
+      "}\r\n",
+      JSON_ALLOW_TRAILING_COMMAS));
+  ASSERT_TRUE(root2.get());
+  EXPECT_TRUE(root->Equals(root2.get()));
+
+  // Test nesting
+  root.reset(JSONReader::DeprecatedRead(
+      "{\"inner\":{\"array\":[true]},\"false\":false,\"d\":{}}"));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
+  dict_val = static_cast<DictionaryValue*>(root.get());
+  DictionaryValue* inner_dict = NULL;
+  ASSERT_TRUE(dict_val->GetDictionary("inner", &inner_dict));
+  ListValue* inner_array = NULL;
+  ASSERT_TRUE(inner_dict->GetList("array", &inner_array));
+  EXPECT_EQ(1U, inner_array->GetSize());
+  bool_value = true;
+  EXPECT_TRUE(dict_val->GetBoolean("false", &bool_value));
+  EXPECT_FALSE(bool_value);
+  inner_dict = NULL;
+  EXPECT_TRUE(dict_val->GetDictionary("d", &inner_dict));
+
+  root2.reset(JSONReader::DeprecatedRead(
+      "{\"inner\": {\"array\":[true] , },\"false\":false,\"d\":{},}",
+      JSON_ALLOW_TRAILING_COMMAS));
+  EXPECT_TRUE(root->Equals(root2.get()));
+
+  // Test keys with periods
+  root.reset(JSONReader::DeprecatedRead(
+      "{\"a.b\":3,\"c\":2,\"d.e.f\":{\"g.h.i.j\":1}}"));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
+  dict_val = static_cast<DictionaryValue*>(root.get());
+  int integer_value = 0;
+  EXPECT_TRUE(dict_val->GetIntegerWithoutPathExpansion("a.b", &integer_value));
+  EXPECT_EQ(3, integer_value);
+  EXPECT_TRUE(dict_val->GetIntegerWithoutPathExpansion("c", &integer_value));
+  EXPECT_EQ(2, integer_value);
+  inner_dict = NULL;
+  ASSERT_TRUE(dict_val->GetDictionaryWithoutPathExpansion("d.e.f",
+                                                          &inner_dict));
+  EXPECT_EQ(1U, inner_dict->size());
+  EXPECT_TRUE(inner_dict->GetIntegerWithoutPathExpansion("g.h.i.j",
+                                                         &integer_value));
+  EXPECT_EQ(1, integer_value);
+
+  root.reset(JSONReader::DeprecatedRead("{\"a\":{\"b\":2},\"a.b\":1}"));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
+  dict_val = static_cast<DictionaryValue*>(root.get());
+  EXPECT_TRUE(dict_val->GetInteger("a.b", &integer_value));
+  EXPECT_EQ(2, integer_value);
+  EXPECT_TRUE(dict_val->GetIntegerWithoutPathExpansion("a.b", &integer_value));
+  EXPECT_EQ(1, integer_value);
+
+  // Invalid, no closing brace
+  root.reset(JSONReader::DeprecatedRead("{\"a\": true"));
+  EXPECT_FALSE(root.get());
+
+  // Invalid, keys must be quoted
+  root.reset(JSONReader::DeprecatedRead("{foo:true}"));
+  EXPECT_FALSE(root.get());
+
+  // Invalid, trailing comma
+  root.reset(JSONReader::DeprecatedRead("{\"a\":true,}"));
+  EXPECT_FALSE(root.get());
+
+  // Invalid, too many commas
+  root.reset(JSONReader::DeprecatedRead("{\"a\":true,,\"b\":false}"));
+  EXPECT_FALSE(root.get());
+  root.reset(JSONReader::DeprecatedRead("{\"a\":true,,\"b\":false}",
+                                        JSON_ALLOW_TRAILING_COMMAS));
+  EXPECT_FALSE(root.get());
+
+  // Invalid, no separator
+  root.reset(JSONReader::DeprecatedRead("{\"a\" \"b\"}"));
+  EXPECT_FALSE(root.get());
+
+  // Invalid, lone comma.
+  root.reset(JSONReader::DeprecatedRead("{,}"));
+  EXPECT_FALSE(root.get());
+  root.reset(JSONReader::DeprecatedRead("{,}", JSON_ALLOW_TRAILING_COMMAS));
+  EXPECT_FALSE(root.get());
+  root.reset(
+      JSONReader::DeprecatedRead("{\"a\":true,,}", JSON_ALLOW_TRAILING_COMMAS));
+  EXPECT_FALSE(root.get());
+  root.reset(
+      JSONReader::DeprecatedRead("{,\"a\":true}", JSON_ALLOW_TRAILING_COMMAS));
+  EXPECT_FALSE(root.get());
+  root.reset(JSONReader::DeprecatedRead("{\"a\":true,,\"b\":false}",
+                                        JSON_ALLOW_TRAILING_COMMAS));
+  EXPECT_FALSE(root.get());
+
+  // Test stack overflow
+  std::string evil(1000000, '[');
+  evil.append(std::string(1000000, ']'));
+  root.reset(JSONReader::DeprecatedRead(evil));
+  EXPECT_FALSE(root.get());
+
+  // A few thousand adjacent lists is fine.
+  std::string not_evil("[");
+  not_evil.reserve(15010);
+  for (int i = 0; i < 5000; ++i) {
+    not_evil.append("[],");
+  }
+  not_evil.append("[]]");
+  root.reset(JSONReader::DeprecatedRead(not_evil));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_LIST));
+  list = static_cast<ListValue*>(root.get());
+  EXPECT_EQ(5001U, list->GetSize());
+
+  // Test utf8 encoded input
+  root = JSONReader().ReadToValue("\"\xe7\xbd\x91\xe9\xa1\xb5\"");
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_STRING));
+  str_val.clear();
+  EXPECT_TRUE(root->GetAsString(&str_val));
+  EXPECT_EQ(L"\x7f51\x9875", UTF8ToWide(str_val));
+
+  root = JSONReader().ReadToValue(
+      "{\"path\": \"/tmp/\xc3\xa0\xc3\xa8\xc3\xb2.png\"}");
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
+  EXPECT_TRUE(root->GetAsDictionary(&dict_val));
+  EXPECT_TRUE(dict_val->GetString("path", &str_val));
+  EXPECT_EQ("/tmp/\xC3\xA0\xC3\xA8\xC3\xB2.png", str_val);
+
+  // Test invalid utf8 encoded input
+  root = JSONReader().ReadToValue("\"345\xb0\xa1\xb0\xa2\"");
+  EXPECT_FALSE(root.get());
+  root = JSONReader().ReadToValue("\"123\xc0\x81\"");
+  EXPECT_FALSE(root.get());
+  root = JSONReader().ReadToValue("\"abc\xc0\xae\"");
+  EXPECT_FALSE(root.get());
+
+  // Test utf16 encoded strings.
+  root = JSONReader().ReadToValue("\"\\u20ac3,14\"");
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_STRING));
+  str_val.clear();
+  EXPECT_TRUE(root->GetAsString(&str_val));
+  EXPECT_EQ("\xe2\x82\xac""3,14", str_val);
+
+  root = JSONReader().ReadToValue("\"\\ud83d\\udca9\\ud83d\\udc6c\"");
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->IsType(Value::TYPE_STRING));
+  str_val.clear();
+  EXPECT_TRUE(root->GetAsString(&str_val));
+  EXPECT_EQ("\xf0\x9f\x92\xa9\xf0\x9f\x91\xac", str_val);
+
+  // Test invalid utf16 strings.
+  const char* const cases[] = {
+    "\"\\u123\"",  // Invalid scalar.
+    "\"\\ud83d\"",  // Invalid scalar.
+    "\"\\u$%@!\"",  // Invalid scalar.
+    "\"\\uzz89\"",  // Invalid scalar.
+    "\"\\ud83d\\udca\"",  // Invalid lower surrogate.
+    "\"\\ud83d\\ud83d\"",  // Invalid lower surrogate.
+    "\"\\ud83foo\"",  // No lower surrogate.
+    "\"\\ud83\\foo\""  // No lower surrogate.
+  };
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    root = JSONReader().ReadToValue(cases[i]);
+    EXPECT_FALSE(root.get()) << cases[i];
+  }
+
+  // Test literal root objects.
+  root.reset(JSONReader::DeprecatedRead("null"));
+  EXPECT_TRUE(root->IsType(Value::TYPE_NULL));
+
+  root.reset(JSONReader::DeprecatedRead("true"));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->GetAsBoolean(&bool_value));
+  EXPECT_TRUE(bool_value);
+
+  root.reset(JSONReader::DeprecatedRead("10"));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->GetAsInteger(&integer_value));
+  EXPECT_EQ(10, integer_value);
+
+  root.reset(JSONReader::DeprecatedRead("\"root\""));
+  ASSERT_TRUE(root.get());
+  EXPECT_TRUE(root->GetAsString(&str_val));
+  EXPECT_EQ("root", str_val);
+}
+
+TEST(JSONReaderTest, ReadFromFile) {
+  FilePath path;
+  ASSERT_TRUE(PathService::Get(base::DIR_TEST_DATA, &path));
+  path = path.AppendASCII("json");
+  ASSERT_TRUE(base::PathExists(path));
+
+  std::string input;
+  ASSERT_TRUE(ReadFileToString(
+      path.Append(FILE_PATH_LITERAL("bom_feff.json")), &input));
+
+  JSONReader reader;
+  scoped_ptr<Value> root(reader.ReadToValue(input));
+  ASSERT_TRUE(root.get()) << reader.GetErrorMessage();
+  EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
+}
+
+// Tests that the root of a JSON object can be deleted safely while its
+// children outlive it.
+TEST(JSONReaderTest, StringOptimizations) {
+  scoped_ptr<Value> dict_literal_0;
+  scoped_ptr<Value> dict_literal_1;
+  scoped_ptr<Value> dict_string_0;
+  scoped_ptr<Value> dict_string_1;
+  scoped_ptr<Value> list_value_0;
+  scoped_ptr<Value> list_value_1;
+
+  {
+    scoped_ptr<Value> root = JSONReader::Read(
+        "{"
+        "  \"test\": {"
+        "    \"foo\": true,"
+        "    \"bar\": 3.14,"
+        "    \"baz\": \"bat\","
+        "    \"moo\": \"cow\""
+        "  },"
+        "  \"list\": ["
+        "    \"a\","
+        "    \"b\""
+        "  ]"
+        "}",
+        JSON_DETACHABLE_CHILDREN);
+    ASSERT_TRUE(root.get());
+
+    DictionaryValue* root_dict = NULL;
+    ASSERT_TRUE(root->GetAsDictionary(&root_dict));
+
+    DictionaryValue* dict = NULL;
+    ListValue* list = NULL;
+
+    ASSERT_TRUE(root_dict->GetDictionary("test", &dict));
+    ASSERT_TRUE(root_dict->GetList("list", &list));
+
+    EXPECT_TRUE(dict->Remove("foo", &dict_literal_0));
+    EXPECT_TRUE(dict->Remove("bar", &dict_literal_1));
+    EXPECT_TRUE(dict->Remove("baz", &dict_string_0));
+    EXPECT_TRUE(dict->Remove("moo", &dict_string_1));
+
+    ASSERT_EQ(2u, list->GetSize());
+    EXPECT_TRUE(list->Remove(0, &list_value_0));
+    EXPECT_TRUE(list->Remove(0, &list_value_1));
+  }
+
+  bool b = false;
+  double d = 0;
+  std::string s;
+
+  EXPECT_TRUE(dict_literal_0->GetAsBoolean(&b));
+  EXPECT_TRUE(b);
+
+  EXPECT_TRUE(dict_literal_1->GetAsDouble(&d));
+  EXPECT_EQ(3.14, d);
+
+  EXPECT_TRUE(dict_string_0->GetAsString(&s));
+  EXPECT_EQ("bat", s);
+
+  EXPECT_TRUE(dict_string_1->GetAsString(&s));
+  EXPECT_EQ("cow", s);
+
+  EXPECT_TRUE(list_value_0->GetAsString(&s));
+  EXPECT_EQ("a", s);
+  EXPECT_TRUE(list_value_1->GetAsString(&s));
+  EXPECT_EQ("b", s);
+}
+
+// A smattering of invalid JSON designed to test specific portions of the
+// parser implementation against buffer overflow. Best run with DCHECKs so
+// that the one in NextChar fires.
+TEST(JSONReaderTest, InvalidSanity) {
+  const char* const invalid_json[] = {
+      "/* test *",
+      "{\"foo\"",
+      "{\"foo\":",
+      "  [",
+      "\"\\u123g\"",
+      "{\n\"eh:\n}",
+  };
+
+  for (size_t i = 0; i < arraysize(invalid_json); ++i) {
+    JSONReader reader;
+    LOG(INFO) << "Sanity test " << i << ": <" << invalid_json[i] << ">";
+    EXPECT_FALSE(reader.ReadToValue(invalid_json[i]));
+    EXPECT_NE(JSONReader::JSON_NO_ERROR, reader.error_code());
+    EXPECT_NE("", reader.GetErrorMessage());
+  }
+}
+
+TEST(JSONReaderTest, IllegalTrailingNull) {
+  const char json[] = { '"', 'n', 'u', 'l', 'l', '"', '\0' };
+  std::string json_string(json, sizeof(json));
+  JSONReader reader;
+  EXPECT_FALSE(reader.ReadToValue(json_string));
+  EXPECT_EQ(JSONReader::JSON_UNEXPECTED_DATA_AFTER_ROOT, reader.error_code());
+}
+
+}  // namespace base
diff --git a/base/json/json_string_value_serializer.cc b/base/json/json_string_value_serializer.cc
new file mode 100644
index 0000000..5425c7e
--- /dev/null
+++ b/base/json/json_string_value_serializer.cc
@@ -0,0 +1,57 @@
+// Copyright (c) 2012 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/json/json_string_value_serializer.h"
+
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+#include "base/logging.h"
+
+using base::Value;
+
+JSONStringValueSerializer::JSONStringValueSerializer(std::string* json_string)
+    : json_string_(json_string),
+      pretty_print_(false) {
+}
+
+JSONStringValueSerializer::~JSONStringValueSerializer() {}
+
+bool JSONStringValueSerializer::Serialize(const Value& root) {
+  return SerializeInternal(root, false);
+}
+
+bool JSONStringValueSerializer::SerializeAndOmitBinaryValues(
+    const Value& root) {
+  return SerializeInternal(root, true);
+}
+
+bool JSONStringValueSerializer::SerializeInternal(const Value& root,
+                                                  bool omit_binary_values) {
+  if (!json_string_)
+    return false;
+
+  int options = 0;
+  if (omit_binary_values)
+    options |= base::JSONWriter::OPTIONS_OMIT_BINARY_VALUES;
+  if (pretty_print_)
+    options |= base::JSONWriter::OPTIONS_PRETTY_PRINT;
+
+  return base::JSONWriter::WriteWithOptions(root, options, json_string_);
+}
+
+JSONStringValueDeserializer::JSONStringValueDeserializer(
+    const base::StringPiece& json_string)
+    : json_string_(json_string),
+      allow_trailing_comma_(false) {
+}
+
+JSONStringValueDeserializer::~JSONStringValueDeserializer() {}
+
+Value* JSONStringValueDeserializer::Deserialize(int* error_code,
+                                                std::string* error_str) {
+  return base::JSONReader::DeprecatedReadAndReturnError(
+      json_string_, allow_trailing_comma_ ? base::JSON_ALLOW_TRAILING_COMMAS
+                                          : base::JSON_PARSE_RFC,
+      error_code, error_str);
+}
diff --git a/base/json/json_string_value_serializer.h b/base/json/json_string_value_serializer.h
new file mode 100644
index 0000000..bc0e66d
--- /dev/null
+++ b/base/json/json_string_value_serializer.h
@@ -0,0 +1,78 @@
+// Copyright (c) 2012 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_JSON_JSON_STRING_VALUE_SERIALIZER_H_
+#define BASE_JSON_JSON_STRING_VALUE_SERIALIZER_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/files/file_path.h"
+#include "base/strings/string_piece.h"
+#include "base/values.h"
+
+class BASE_EXPORT JSONStringValueSerializer : public base::ValueSerializer {
+ public:
+  // |json_string| is the string that will be the destination of the
+  // serialization.  The caller of the constructor retains ownership of the
+  // string. |json_string| must not be null.
+  explicit JSONStringValueSerializer(std::string* json_string);
+
+  ~JSONStringValueSerializer() override;
+
+  // Attempt to serialize the data structure represented by Value into
+  // JSON.  If the return value is true, the result will have been written
+  // into the string passed into the constructor.
+  bool Serialize(const base::Value& root) override;
+
+  // Equivalent to Serialize(root) except binary values are omitted from the
+  // output.
+  bool SerializeAndOmitBinaryValues(const base::Value& root);
+
+  void set_pretty_print(bool new_value) { pretty_print_ = new_value; }
+  bool pretty_print() { return pretty_print_; }
+
+ private:
+  bool SerializeInternal(const base::Value& root, bool omit_binary_values);
+
+  // Owned by the caller of the constructor.
+  std::string* json_string_;
+  bool pretty_print_;  // If true, serialization will span multiple lines.
+
+  DISALLOW_COPY_AND_ASSIGN(JSONStringValueSerializer);
+};
+
+class BASE_EXPORT JSONStringValueDeserializer : public base::ValueDeserializer {
+ public:
+  // This retains a reference to the contents of |json_string|, so the data
+  // must outlive the JSONStringValueDeserializer.
+  explicit JSONStringValueDeserializer(const base::StringPiece& json_string);
+
+  ~JSONStringValueDeserializer() override;
+
+  // Attempt to deserialize the data structure encoded in the string passed
+  // in to the constructor into a structure of Value objects.  If the return
+  // value is null, and if |error_code| is non-null, |error_code| will
+  // contain an integer error code (a JsonParseError in this case).
+  // If |error_message| is non-null, it will be filled in with a formatted
+  // error message including the location of the error if appropriate.
+  // The caller takes ownership of the returned value.
+  base::Value* Deserialize(int* error_code,
+                           std::string* error_message) override;
+
+  void set_allow_trailing_comma(bool new_value) {
+    allow_trailing_comma_ = new_value;
+  }
+
+ private:
+  // Data is owned by the caller of the constructor.
+  base::StringPiece json_string_;
+  // If true, deserialization will allow trailing commas.
+  bool allow_trailing_comma_;
+
+  DISALLOW_COPY_AND_ASSIGN(JSONStringValueDeserializer);
+};
+
+#endif  // BASE_JSON_JSON_STRING_VALUE_SERIALIZER_H_
diff --git a/base/json/json_value_converter.cc b/base/json/json_value_converter.cc
new file mode 100644
index 0000000..6f772f3
--- /dev/null
+++ b/base/json/json_value_converter.cc
@@ -0,0 +1,37 @@
+// 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.
+
+#include "base/json/json_value_converter.h"
+
+namespace base {
+namespace internal {
+
+bool BasicValueConverter<int>::Convert(
+    const base::Value& value, int* field) const {
+  return value.GetAsInteger(field);
+}
+
+bool BasicValueConverter<std::string>::Convert(
+    const base::Value& value, std::string* field) const {
+  return value.GetAsString(field);
+}
+
+bool BasicValueConverter<string16>::Convert(
+    const base::Value& value, string16* field) const {
+  return value.GetAsString(field);
+}
+
+bool BasicValueConverter<double>::Convert(
+    const base::Value& value, double* field) const {
+  return value.GetAsDouble(field);
+}
+
+bool BasicValueConverter<bool>::Convert(
+    const base::Value& value, bool* field) const {
+  return value.GetAsBoolean(field);
+}
+
+}  // namespace internal
+}  // namespace base
+
diff --git a/base/json/json_value_converter.h b/base/json/json_value_converter.h
new file mode 100644
index 0000000..f94d46e
--- /dev/null
+++ b/base/json/json_value_converter.h
@@ -0,0 +1,514 @@
+// Copyright (c) 2012 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_JSON_JSON_VALUE_CONVERTER_H_
+#define BASE_JSON_JSON_VALUE_CONVERTER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "base/stl_util.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
+#include "base/values.h"
+
+// JSONValueConverter converts a JSON value into a C++ struct in a
+// lightweight way.
+//
+// Usage:
+// For real examples, you may want to refer to _unittest.cc file.
+//
+// Assume that you have a struct like this:
+//   struct Message {
+//     int foo;
+//     std::string bar;
+//     static void RegisterJSONConverter(
+//         JSONValueConverter<Message>* converter);
+//   };
+//
+// And you want to parse a json data into this struct.  First, you
+// need to declare RegisterJSONConverter() method in your struct.
+//   // static
+//   void Message::RegisterJSONConverter(
+//       JSONValueConverter<Message>* converter) {
+//     converter->RegisterIntField("foo", &Message::foo);
+//     converter->RegisterStringField("bar", &Message::bar);
+//   }
+//
+// Then, you just instantiate your JSONValueConverter of your type and call
+// Convert() method.
+//   Message message;
+//   JSONValueConverter<Message> converter;
+//   converter.Convert(json, &message);
+//
+// Convert() returns false when it fails.  Here "fail" means that the value is
+// structurally different from expected, such like a string value appears
+// for an int field.  Do not report failures for missing fields.
+// Also note that Convert() will modify the passed |message| even when it
+// fails for performance reason.
+//
+// For nested field, the internal message also has to implement the registration
+// method.  Then, just use RegisterNestedField() from the containing struct's
+// RegisterJSONConverter method.
+//   struct Nested {
+//     Message foo;
+//     static void RegisterJSONConverter(...) {
+//       ...
+//       converter->RegisterNestedField("foo", &Nested::foo);
+//     }
+//   };
+//
+// For repeated field, we just assume ScopedVector for its container
+// and you can put RegisterRepeatedInt or some other types.  Use
+// RegisterRepeatedMessage for nested repeated fields.
+//
+// Sometimes JSON format uses string representations for other types such
+// like enum, timestamp, or URL.  You can use RegisterCustomField method
+// and specify a function to convert a StringPiece to your type.
+//   bool ConvertFunc(const StringPiece& s, YourEnum* result) {
+//     // do something and return true if succeed...
+//   }
+//   struct Message {
+//     YourEnum ye;
+//     ...
+//     static void RegisterJSONConverter(...) {
+//       ...
+//       converter->RegsiterCustomField<YourEnum>(
+//           "your_enum", &Message::ye, &ConvertFunc);
+//     }
+//   };
+
+namespace base {
+
+template <typename StructType>
+class JSONValueConverter;
+
+namespace internal {
+
+template<typename StructType>
+class FieldConverterBase {
+ public:
+  explicit FieldConverterBase(const std::string& path) : field_path_(path) {}
+  virtual ~FieldConverterBase() {}
+  virtual bool ConvertField(const base::Value& value, StructType* obj)
+      const = 0;
+  const std::string& field_path() const { return field_path_; }
+
+ private:
+  std::string field_path_;
+  DISALLOW_COPY_AND_ASSIGN(FieldConverterBase);
+};
+
+template <typename FieldType>
+class ValueConverter {
+ public:
+  virtual ~ValueConverter() {}
+  virtual bool Convert(const base::Value& value, FieldType* field) const = 0;
+};
+
+template <typename StructType, typename FieldType>
+class FieldConverter : public FieldConverterBase<StructType> {
+ public:
+  explicit FieldConverter(const std::string& path,
+                          FieldType StructType::* field,
+                          ValueConverter<FieldType>* converter)
+      : FieldConverterBase<StructType>(path),
+        field_pointer_(field),
+        value_converter_(converter) {
+  }
+
+  bool ConvertField(const base::Value& value, StructType* dst) const override {
+    return value_converter_->Convert(value, &(dst->*field_pointer_));
+  }
+
+ private:
+  FieldType StructType::* field_pointer_;
+  scoped_ptr<ValueConverter<FieldType> > value_converter_;
+  DISALLOW_COPY_AND_ASSIGN(FieldConverter);
+};
+
+template <typename FieldType>
+class BasicValueConverter;
+
+template <>
+class BASE_EXPORT BasicValueConverter<int> : public ValueConverter<int> {
+ public:
+  BasicValueConverter() {}
+
+  bool Convert(const base::Value& value, int* field) const override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
+};
+
+template <>
+class BASE_EXPORT BasicValueConverter<std::string>
+    : public ValueConverter<std::string> {
+ public:
+  BasicValueConverter() {}
+
+  bool Convert(const base::Value& value, std::string* field) const override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
+};
+
+template <>
+class BASE_EXPORT BasicValueConverter<string16>
+    : public ValueConverter<string16> {
+ public:
+  BasicValueConverter() {}
+
+  bool Convert(const base::Value& value, string16* field) const override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
+};
+
+template <>
+class BASE_EXPORT BasicValueConverter<double> : public ValueConverter<double> {
+ public:
+  BasicValueConverter() {}
+
+  bool Convert(const base::Value& value, double* field) const override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
+};
+
+template <>
+class BASE_EXPORT BasicValueConverter<bool> : public ValueConverter<bool> {
+ public:
+  BasicValueConverter() {}
+
+  bool Convert(const base::Value& value, bool* field) const override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
+};
+
+template <typename FieldType>
+class ValueFieldConverter : public ValueConverter<FieldType> {
+ public:
+  typedef bool(*ConvertFunc)(const base::Value* value, FieldType* field);
+
+  ValueFieldConverter(ConvertFunc convert_func)
+      : convert_func_(convert_func) {}
+
+  bool Convert(const base::Value& value, FieldType* field) const override {
+    return convert_func_(&value, field);
+  }
+
+ private:
+  ConvertFunc convert_func_;
+
+  DISALLOW_COPY_AND_ASSIGN(ValueFieldConverter);
+};
+
+template <typename FieldType>
+class CustomFieldConverter : public ValueConverter<FieldType> {
+ public:
+  typedef bool(*ConvertFunc)(const StringPiece& value, FieldType* field);
+
+  CustomFieldConverter(ConvertFunc convert_func)
+      : convert_func_(convert_func) {}
+
+  bool Convert(const base::Value& value, FieldType* field) const override {
+    std::string string_value;
+    return value.GetAsString(&string_value) &&
+        convert_func_(string_value, field);
+  }
+
+ private:
+  ConvertFunc convert_func_;
+
+  DISALLOW_COPY_AND_ASSIGN(CustomFieldConverter);
+};
+
+template <typename NestedType>
+class NestedValueConverter : public ValueConverter<NestedType> {
+ public:
+  NestedValueConverter() {}
+
+  bool Convert(const base::Value& value, NestedType* field) const override {
+    return converter_.Convert(value, field);
+  }
+
+ private:
+  JSONValueConverter<NestedType> converter_;
+  DISALLOW_COPY_AND_ASSIGN(NestedValueConverter);
+};
+
+template <typename Element>
+class RepeatedValueConverter : public ValueConverter<ScopedVector<Element> > {
+ public:
+  RepeatedValueConverter() {}
+
+  bool Convert(const base::Value& value,
+               ScopedVector<Element>* field) const override {
+    const base::ListValue* list = NULL;
+    if (!value.GetAsList(&list)) {
+      // The field is not a list.
+      return false;
+    }
+
+    field->reserve(list->GetSize());
+    for (size_t i = 0; i < list->GetSize(); ++i) {
+      const base::Value* element = NULL;
+      if (!list->Get(i, &element))
+        continue;
+
+      scoped_ptr<Element> e(new Element);
+      if (basic_converter_.Convert(*element, e.get())) {
+        field->push_back(e.release());
+      } else {
+        DVLOG(1) << "failure at " << i << "-th element";
+        return false;
+      }
+    }
+    return true;
+  }
+
+ private:
+  BasicValueConverter<Element> basic_converter_;
+  DISALLOW_COPY_AND_ASSIGN(RepeatedValueConverter);
+};
+
+template <typename NestedType>
+class RepeatedMessageConverter
+    : public ValueConverter<ScopedVector<NestedType> > {
+ public:
+  RepeatedMessageConverter() {}
+
+  bool Convert(const base::Value& value,
+               ScopedVector<NestedType>* field) const override {
+    const base::ListValue* list = NULL;
+    if (!value.GetAsList(&list))
+      return false;
+
+    field->reserve(list->GetSize());
+    for (size_t i = 0; i < list->GetSize(); ++i) {
+      const base::Value* element = NULL;
+      if (!list->Get(i, &element))
+        continue;
+
+      scoped_ptr<NestedType> nested(new NestedType);
+      if (converter_.Convert(*element, nested.get())) {
+        field->push_back(nested.release());
+      } else {
+        DVLOG(1) << "failure at " << i << "-th element";
+        return false;
+      }
+    }
+    return true;
+  }
+
+ private:
+  JSONValueConverter<NestedType> converter_;
+  DISALLOW_COPY_AND_ASSIGN(RepeatedMessageConverter);
+};
+
+template <typename NestedType>
+class RepeatedCustomValueConverter
+    : public ValueConverter<ScopedVector<NestedType> > {
+ public:
+  typedef bool(*ConvertFunc)(const base::Value* value, NestedType* field);
+
+  RepeatedCustomValueConverter(ConvertFunc convert_func)
+      : convert_func_(convert_func) {}
+
+  bool Convert(const base::Value& value,
+               ScopedVector<NestedType>* field) const override {
+    const base::ListValue* list = NULL;
+    if (!value.GetAsList(&list))
+      return false;
+
+    field->reserve(list->GetSize());
+    for (size_t i = 0; i < list->GetSize(); ++i) {
+      const base::Value* element = NULL;
+      if (!list->Get(i, &element))
+        continue;
+
+      scoped_ptr<NestedType> nested(new NestedType);
+      if ((*convert_func_)(element, nested.get())) {
+        field->push_back(nested.release());
+      } else {
+        DVLOG(1) << "failure at " << i << "-th element";
+        return false;
+      }
+    }
+    return true;
+  }
+
+ private:
+  ConvertFunc convert_func_;
+  DISALLOW_COPY_AND_ASSIGN(RepeatedCustomValueConverter);
+};
+
+
+}  // namespace internal
+
+template <class StructType>
+class JSONValueConverter {
+ public:
+  JSONValueConverter() {
+    StructType::RegisterJSONConverter(this);
+  }
+
+  void RegisterIntField(const std::string& field_name,
+                        int StructType::* field) {
+    fields_.push_back(new internal::FieldConverter<StructType, int>(
+        field_name, field, new internal::BasicValueConverter<int>));
+  }
+
+  void RegisterStringField(const std::string& field_name,
+                           std::string StructType::* field) {
+    fields_.push_back(new internal::FieldConverter<StructType, std::string>(
+        field_name, field, new internal::BasicValueConverter<std::string>));
+  }
+
+  void RegisterStringField(const std::string& field_name,
+                           string16 StructType::* field) {
+    fields_.push_back(new internal::FieldConverter<StructType, string16>(
+        field_name, field, new internal::BasicValueConverter<string16>));
+  }
+
+  void RegisterBoolField(const std::string& field_name,
+                         bool StructType::* field) {
+    fields_.push_back(new internal::FieldConverter<StructType, bool>(
+        field_name, field, new internal::BasicValueConverter<bool>));
+  }
+
+  void RegisterDoubleField(const std::string& field_name,
+                           double StructType::* field) {
+    fields_.push_back(new internal::FieldConverter<StructType, double>(
+        field_name, field, new internal::BasicValueConverter<double>));
+  }
+
+  template <class NestedType>
+  void RegisterNestedField(
+      const std::string& field_name, NestedType StructType::* field) {
+    fields_.push_back(new internal::FieldConverter<StructType, NestedType>(
+            field_name,
+            field,
+            new internal::NestedValueConverter<NestedType>));
+  }
+
+  template <typename FieldType>
+  void RegisterCustomField(
+      const std::string& field_name,
+      FieldType StructType::* field,
+      bool (*convert_func)(const StringPiece&, FieldType*)) {
+    fields_.push_back(new internal::FieldConverter<StructType, FieldType>(
+        field_name,
+        field,
+        new internal::CustomFieldConverter<FieldType>(convert_func)));
+  }
+
+  template <typename FieldType>
+  void RegisterCustomValueField(
+      const std::string& field_name,
+      FieldType StructType::* field,
+      bool (*convert_func)(const base::Value*, FieldType*)) {
+    fields_.push_back(new internal::FieldConverter<StructType, FieldType>(
+        field_name,
+        field,
+        new internal::ValueFieldConverter<FieldType>(convert_func)));
+  }
+
+  void RegisterRepeatedInt(const std::string& field_name,
+                           ScopedVector<int> StructType::* field) {
+    fields_.push_back(
+        new internal::FieldConverter<StructType, ScopedVector<int> >(
+            field_name, field, new internal::RepeatedValueConverter<int>));
+  }
+
+  void RegisterRepeatedString(const std::string& field_name,
+                              ScopedVector<std::string> StructType::* field) {
+    fields_.push_back(
+        new internal::FieldConverter<StructType, ScopedVector<std::string> >(
+            field_name,
+            field,
+            new internal::RepeatedValueConverter<std::string>));
+  }
+
+  void RegisterRepeatedString(const std::string& field_name,
+                              ScopedVector<string16> StructType::* field) {
+    fields_.push_back(
+        new internal::FieldConverter<StructType, ScopedVector<string16> >(
+            field_name,
+            field,
+            new internal::RepeatedValueConverter<string16>));
+  }
+
+  void RegisterRepeatedDouble(const std::string& field_name,
+                              ScopedVector<double> StructType::* field) {
+    fields_.push_back(
+        new internal::FieldConverter<StructType, ScopedVector<double> >(
+            field_name, field, new internal::RepeatedValueConverter<double>));
+  }
+
+  void RegisterRepeatedBool(const std::string& field_name,
+                            ScopedVector<bool> StructType::* field) {
+    fields_.push_back(
+        new internal::FieldConverter<StructType, ScopedVector<bool> >(
+            field_name, field, new internal::RepeatedValueConverter<bool>));
+  }
+
+  template <class NestedType>
+  void RegisterRepeatedCustomValue(
+      const std::string& field_name,
+      ScopedVector<NestedType> StructType::* field,
+      bool (*convert_func)(const base::Value*, NestedType*)) {
+    fields_.push_back(
+        new internal::FieldConverter<StructType, ScopedVector<NestedType> >(
+            field_name,
+            field,
+            new internal::RepeatedCustomValueConverter<NestedType>(
+                convert_func)));
+  }
+
+  template <class NestedType>
+  void RegisterRepeatedMessage(const std::string& field_name,
+                               ScopedVector<NestedType> StructType::* field) {
+    fields_.push_back(
+        new internal::FieldConverter<StructType, ScopedVector<NestedType> >(
+            field_name,
+            field,
+            new internal::RepeatedMessageConverter<NestedType>));
+  }
+
+  bool Convert(const base::Value& value, StructType* output) const {
+    const DictionaryValue* dictionary_value = NULL;
+    if (!value.GetAsDictionary(&dictionary_value))
+      return false;
+
+    for(size_t i = 0; i < fields_.size(); ++i) {
+      const internal::FieldConverterBase<StructType>* field_converter =
+          fields_[i];
+      const base::Value* field = NULL;
+      if (dictionary_value->Get(field_converter->field_path(), &field)) {
+        if (!field_converter->ConvertField(*field, output)) {
+          DVLOG(1) << "failure at field " << field_converter->field_path();
+          return false;
+        }
+      }
+    }
+    return true;
+  }
+
+ private:
+  ScopedVector<internal::FieldConverterBase<StructType> > fields_;
+
+  DISALLOW_COPY_AND_ASSIGN(JSONValueConverter);
+};
+
+}  // namespace base
+
+#endif  // BASE_JSON_JSON_VALUE_CONVERTER_H_
diff --git a/base/json/json_value_converter_unittest.cc b/base/json/json_value_converter_unittest.cc
new file mode 100644
index 0000000..9038610
--- /dev/null
+++ b/base/json/json_value_converter_unittest.cc
@@ -0,0 +1,256 @@
+// Copyright (c) 2012 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/json/json_value_converter.h"
+
+#include <string>
+#include <vector>
+
+#include "base/json/json_reader.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "base/strings/string_piece.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+// Very simple messages.
+struct SimpleMessage {
+  enum SimpleEnum {
+    FOO, BAR,
+  };
+  int foo;
+  std::string bar;
+  bool baz;
+  bool bstruct;
+  SimpleEnum simple_enum;
+  ScopedVector<int> ints;
+  ScopedVector<std::string> string_values;
+  SimpleMessage() : foo(0), baz(false), bstruct(false), simple_enum(FOO) {}
+
+  static bool ParseSimpleEnum(const StringPiece& value, SimpleEnum* field) {
+    if (value == "foo") {
+      *field = FOO;
+      return true;
+    } else if (value == "bar") {
+      *field = BAR;
+      return true;
+    }
+    return false;
+  }
+
+  static bool HasFieldPresent(const base::Value* value, bool* result) {
+    *result = value != NULL;
+    return true;
+  }
+
+  static bool GetValueString(const base::Value* value, std::string* result) {
+    const base::DictionaryValue* dict = NULL;
+    if (!value->GetAsDictionary(&dict))
+      return false;
+
+    if (!dict->GetString("val", result))
+      return false;
+
+    return true;
+  }
+
+  static void RegisterJSONConverter(
+      base::JSONValueConverter<SimpleMessage>* converter) {
+    converter->RegisterIntField("foo", &SimpleMessage::foo);
+    converter->RegisterStringField("bar", &SimpleMessage::bar);
+    converter->RegisterBoolField("baz", &SimpleMessage::baz);
+    converter->RegisterCustomField<SimpleEnum>(
+        "simple_enum", &SimpleMessage::simple_enum, &ParseSimpleEnum);
+    converter->RegisterRepeatedInt("ints", &SimpleMessage::ints);
+    converter->RegisterCustomValueField<bool>("bstruct",
+                                              &SimpleMessage::bstruct,
+                                              &HasFieldPresent);
+    converter->RegisterRepeatedCustomValue<std::string>(
+        "string_values",
+        &SimpleMessage::string_values,
+        &GetValueString);
+  }
+};
+
+// For nested messages.
+struct NestedMessage {
+  double foo;
+  SimpleMessage child;
+  ScopedVector<SimpleMessage> children;
+
+  NestedMessage() : foo(0) {}
+
+  static void RegisterJSONConverter(
+      base::JSONValueConverter<NestedMessage>* converter) {
+    converter->RegisterDoubleField("foo", &NestedMessage::foo);
+    converter->RegisterNestedField("child", &NestedMessage::child);
+    converter->RegisterRepeatedMessage("children", &NestedMessage::children);
+  }
+};
+
+}  // namespace
+
+TEST(JSONValueConverterTest, ParseSimpleMessage) {
+  const char normal_data[] =
+      "{\n"
+      "  \"foo\": 1,\n"
+      "  \"bar\": \"bar\",\n"
+      "  \"baz\": true,\n"
+      "  \"bstruct\": {},\n"
+      "  \"string_values\": [{\"val\": \"value_1\"}, {\"val\": \"value_2\"}],"
+      "  \"simple_enum\": \"foo\","
+      "  \"ints\": [1, 2]"
+      "}\n";
+
+  scoped_ptr<Value> value = base::JSONReader::Read(normal_data);
+  SimpleMessage message;
+  base::JSONValueConverter<SimpleMessage> converter;
+  EXPECT_TRUE(converter.Convert(*value.get(), &message));
+
+  EXPECT_EQ(1, message.foo);
+  EXPECT_EQ("bar", message.bar);
+  EXPECT_TRUE(message.baz);
+  EXPECT_EQ(SimpleMessage::FOO, message.simple_enum);
+  EXPECT_EQ(2, static_cast<int>(message.ints.size()));
+  ASSERT_EQ(2U, message.string_values.size());
+  EXPECT_EQ("value_1", *message.string_values[0]);
+  EXPECT_EQ("value_2", *message.string_values[1]);
+  EXPECT_EQ(1, *(message.ints[0]));
+  EXPECT_EQ(2, *(message.ints[1]));
+}
+
+TEST(JSONValueConverterTest, ParseNestedMessage) {
+  const char normal_data[] =
+      "{\n"
+      "  \"foo\": 1.0,\n"
+      "  \"child\": {\n"
+      "    \"foo\": 1,\n"
+      "    \"bar\": \"bar\",\n"
+      "    \"bstruct\": {},\n"
+      "    \"string_values\": [{\"val\": \"value_1\"}, {\"val\": \"value_2\"}],"
+      "    \"baz\": true\n"
+      "  },\n"
+      "  \"children\": [{\n"
+      "    \"foo\": 2,\n"
+      "    \"bar\": \"foobar\",\n"
+      "    \"bstruct\": \"\",\n"
+      "    \"string_values\": [{\"val\": \"value_1\"}],"
+      "    \"baz\": true\n"
+      "  },\n"
+      "  {\n"
+      "    \"foo\": 3,\n"
+      "    \"bar\": \"barbaz\",\n"
+      "    \"baz\": false\n"
+      "  }]\n"
+      "}\n";
+
+  scoped_ptr<Value> value = base::JSONReader::Read(normal_data);
+  NestedMessage message;
+  base::JSONValueConverter<NestedMessage> converter;
+  EXPECT_TRUE(converter.Convert(*value.get(), &message));
+
+  EXPECT_EQ(1.0, message.foo);
+  EXPECT_EQ(1, message.child.foo);
+  EXPECT_EQ("bar", message.child.bar);
+  EXPECT_TRUE(message.child.baz);
+  EXPECT_TRUE(message.child.bstruct);
+  ASSERT_EQ(2U, message.child.string_values.size());
+  EXPECT_EQ("value_1", *message.child.string_values[0]);
+  EXPECT_EQ("value_2", *message.child.string_values[1]);
+
+  EXPECT_EQ(2, static_cast<int>(message.children.size()));
+  const SimpleMessage* first_child = message.children[0];
+  ASSERT_TRUE(first_child);
+  EXPECT_EQ(2, first_child->foo);
+  EXPECT_EQ("foobar", first_child->bar);
+  EXPECT_TRUE(first_child->baz);
+  EXPECT_TRUE(first_child->bstruct);
+  ASSERT_EQ(1U, first_child->string_values.size());
+  EXPECT_EQ("value_1", *first_child->string_values[0]);
+
+  const SimpleMessage* second_child = message.children[1];
+  ASSERT_TRUE(second_child);
+  EXPECT_EQ(3, second_child->foo);
+  EXPECT_EQ("barbaz", second_child->bar);
+  EXPECT_FALSE(second_child->baz);
+  EXPECT_FALSE(second_child->bstruct);
+  EXPECT_EQ(0U, second_child->string_values.size());
+}
+
+TEST(JSONValueConverterTest, ParseFailures) {
+  const char normal_data[] =
+      "{\n"
+      "  \"foo\": 1,\n"
+      "  \"bar\": 2,\n" // "bar" is an integer here.
+      "  \"baz\": true,\n"
+      "  \"ints\": [1, 2]"
+      "}\n";
+
+  scoped_ptr<Value> value = base::JSONReader::Read(normal_data);
+  SimpleMessage message;
+  base::JSONValueConverter<SimpleMessage> converter;
+  EXPECT_FALSE(converter.Convert(*value.get(), &message));
+  // Do not check the values below.  |message| may be modified during
+  // Convert() even it fails.
+}
+
+TEST(JSONValueConverterTest, ParseWithMissingFields) {
+  const char normal_data[] =
+      "{\n"
+      "  \"foo\": 1,\n"
+      "  \"baz\": true,\n"
+      "  \"ints\": [1, 2]"
+      "}\n";
+
+  scoped_ptr<Value> value = base::JSONReader::Read(normal_data);
+  SimpleMessage message;
+  base::JSONValueConverter<SimpleMessage> converter;
+  // Convert() still succeeds even if the input doesn't have "bar" field.
+  EXPECT_TRUE(converter.Convert(*value.get(), &message));
+
+  EXPECT_EQ(1, message.foo);
+  EXPECT_TRUE(message.baz);
+  EXPECT_EQ(2, static_cast<int>(message.ints.size()));
+  EXPECT_EQ(1, *(message.ints[0]));
+  EXPECT_EQ(2, *(message.ints[1]));
+}
+
+TEST(JSONValueConverterTest, EnumParserFails) {
+  const char normal_data[] =
+      "{\n"
+      "  \"foo\": 1,\n"
+      "  \"bar\": \"bar\",\n"
+      "  \"baz\": true,\n"
+      "  \"simple_enum\": \"baz\","
+      "  \"ints\": [1, 2]"
+      "}\n";
+
+  scoped_ptr<Value> value = base::JSONReader::Read(normal_data);
+  SimpleMessage message;
+  base::JSONValueConverter<SimpleMessage> converter;
+  EXPECT_FALSE(converter.Convert(*value.get(), &message));
+  // No check the values as mentioned above.
+}
+
+TEST(JSONValueConverterTest, RepeatedValueErrorInTheMiddle) {
+  const char normal_data[] =
+      "{\n"
+      "  \"foo\": 1,\n"
+      "  \"bar\": \"bar\",\n"
+      "  \"baz\": true,\n"
+      "  \"simple_enum\": \"baz\","
+      "  \"ints\": [1, false]"
+      "}\n";
+
+  scoped_ptr<Value> value = base::JSONReader::Read(normal_data);
+  SimpleMessage message;
+  base::JSONValueConverter<SimpleMessage> converter;
+  EXPECT_FALSE(converter.Convert(*value.get(), &message));
+  // No check the values as mentioned above.
+}
+
+}  // namespace base
diff --git a/base/json/json_value_serializer_unittest.cc b/base/json/json_value_serializer_unittest.cc
new file mode 100644
index 0000000..a4d7cdc
--- /dev/null
+++ b/base/json/json_value_serializer_unittest.cc
@@ -0,0 +1,497 @@
+// Copyright (c) 2012 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 <string>
+
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/json/json_file_value_serializer.h"
+#include "base/json/json_reader.h"
+#include "base/json/json_string_value_serializer.h"
+#include "base/json/json_writer.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/path_service.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+// Some proper JSON to test with:
+const char kProperJSON[] =
+    "{\n"
+    "   \"compound\": {\n"
+    "      \"a\": 1,\n"
+    "      \"b\": 2\n"
+    "   },\n"
+    "   \"some_String\": \"1337\",\n"
+    "   \"some_int\": 42,\n"
+    "   \"the_list\": [ \"val1\", \"val2\" ]\n"
+    "}\n";
+
+// Some proper JSON with trailing commas:
+const char kProperJSONWithCommas[] =
+    "{\n"
+    "\t\"some_int\": 42,\n"
+    "\t\"some_String\": \"1337\",\n"
+    "\t\"the_list\": [\"val1\", \"val2\", ],\n"
+    "\t\"compound\": { \"a\": 1, \"b\": 2, },\n"
+    "}\n";
+
+// kProperJSON with a few misc characters at the begin and end.
+const char kProperJSONPadded[] =
+    ")]}'\n"
+    "{\n"
+    "   \"compound\": {\n"
+    "      \"a\": 1,\n"
+    "      \"b\": 2\n"
+    "   },\n"
+    "   \"some_String\": \"1337\",\n"
+    "   \"some_int\": 42,\n"
+    "   \"the_list\": [ \"val1\", \"val2\" ]\n"
+    "}\n"
+    "?!ab\n";
+
+const char kWinLineEnds[] = "\r\n";
+const char kLinuxLineEnds[] = "\n";
+
+// Verifies the generated JSON against the expected output.
+void CheckJSONIsStillTheSame(const Value& value) {
+  // Serialize back the output.
+  std::string serialized_json;
+  JSONStringValueSerializer str_serializer(&serialized_json);
+  str_serializer.set_pretty_print(true);
+  ASSERT_TRUE(str_serializer.Serialize(value));
+  // Unify line endings between platforms.
+  ReplaceSubstringsAfterOffset(&serialized_json, 0,
+                               kWinLineEnds, kLinuxLineEnds);
+  // Now compare the input with the output.
+  ASSERT_EQ(kProperJSON, serialized_json);
+}
+
+void ValidateJsonList(const std::string& json) {
+  scoped_ptr<Value> root = JSONReader::Read(json);
+  ASSERT_TRUE(root.get() && root->IsType(Value::TYPE_LIST));
+  ListValue* list = static_cast<ListValue*>(root.get());
+  ASSERT_EQ(1U, list->GetSize());
+  Value* elt = NULL;
+  ASSERT_TRUE(list->Get(0, &elt));
+  int value = 0;
+  ASSERT_TRUE(elt && elt->GetAsInteger(&value));
+  ASSERT_EQ(1, value);
+}
+
+// Test proper JSON deserialization from string is working.
+TEST(JSONValueDeserializerTest, ReadProperJSONFromString) {
+  // Try to deserialize it through the serializer.
+  JSONStringValueDeserializer str_deserializer(kProperJSON);
+
+  int error_code = 0;
+  std::string error_message;
+  scoped_ptr<Value> value(
+      str_deserializer.Deserialize(&error_code, &error_message));
+  ASSERT_TRUE(value.get());
+  ASSERT_EQ(0, error_code);
+  ASSERT_TRUE(error_message.empty());
+  // Verify if the same JSON is still there.
+  CheckJSONIsStillTheSame(*value);
+}
+
+// Test proper JSON deserialization from a StringPiece substring.
+TEST(JSONValueDeserializerTest, ReadProperJSONFromStringPiece) {
+  // Create a StringPiece for the substring of kProperJSONPadded that matches
+  // kProperJSON.
+  base::StringPiece proper_json(kProperJSONPadded);
+  proper_json = proper_json.substr(5, proper_json.length() - 10);
+  JSONStringValueDeserializer str_deserializer(proper_json);
+
+  int error_code = 0;
+  std::string error_message;
+  scoped_ptr<Value> value(
+      str_deserializer.Deserialize(&error_code, &error_message));
+  ASSERT_TRUE(value.get());
+  ASSERT_EQ(0, error_code);
+  ASSERT_TRUE(error_message.empty());
+  // Verify if the same JSON is still there.
+  CheckJSONIsStillTheSame(*value);
+}
+
+// Test that trialing commas are only properly deserialized from string when
+// the proper flag for that is set.
+TEST(JSONValueDeserializerTest, ReadJSONWithTrailingCommasFromString) {
+  // Try to deserialize it through the serializer.
+  JSONStringValueDeserializer str_deserializer(kProperJSONWithCommas);
+
+  int error_code = 0;
+  std::string error_message;
+  scoped_ptr<Value> value(
+      str_deserializer.Deserialize(&error_code, &error_message));
+  ASSERT_FALSE(value.get());
+  ASSERT_NE(0, error_code);
+  ASSERT_FALSE(error_message.empty());
+  // Now the flag is set and it must pass.
+  str_deserializer.set_allow_trailing_comma(true);
+  value.reset(str_deserializer.Deserialize(&error_code, &error_message));
+  ASSERT_TRUE(value.get());
+  ASSERT_EQ(JSONReader::JSON_TRAILING_COMMA, error_code);
+  // Verify if the same JSON is still there.
+  CheckJSONIsStillTheSame(*value);
+}
+
+// Test proper JSON deserialization from file is working.
+TEST(JSONValueDeserializerTest, ReadProperJSONFromFile) {
+  ScopedTempDir tempdir;
+  ASSERT_TRUE(tempdir.CreateUniqueTempDir());
+  // Write it down in the file.
+  FilePath temp_file(tempdir.path().AppendASCII("test.json"));
+  ASSERT_EQ(static_cast<int>(strlen(kProperJSON)),
+            WriteFile(temp_file, kProperJSON, strlen(kProperJSON)));
+
+  // Try to deserialize it through the serializer.
+  JSONFileValueDeserializer file_deserializer(temp_file);
+
+  int error_code = 0;
+  std::string error_message;
+  scoped_ptr<Value> value(
+      file_deserializer.Deserialize(&error_code, &error_message));
+  ASSERT_TRUE(value.get());
+  ASSERT_EQ(0, error_code);
+  ASSERT_TRUE(error_message.empty());
+  // Verify if the same JSON is still there.
+  CheckJSONIsStillTheSame(*value);
+}
+
+// Test that trialing commas are only properly deserialized from file when
+// the proper flag for that is set.
+TEST(JSONValueDeserializerTest, ReadJSONWithCommasFromFile) {
+  ScopedTempDir tempdir;
+  ASSERT_TRUE(tempdir.CreateUniqueTempDir());
+  // Write it down in the file.
+  FilePath temp_file(tempdir.path().AppendASCII("test.json"));
+  ASSERT_EQ(static_cast<int>(strlen(kProperJSONWithCommas)),
+            WriteFile(temp_file, kProperJSONWithCommas,
+                      strlen(kProperJSONWithCommas)));
+
+  // Try to deserialize it through the serializer.
+  JSONFileValueDeserializer file_deserializer(temp_file);
+  // This must fail without the proper flag.
+  int error_code = 0;
+  std::string error_message;
+  scoped_ptr<Value> value(
+      file_deserializer.Deserialize(&error_code, &error_message));
+  ASSERT_FALSE(value.get());
+  ASSERT_NE(0, error_code);
+  ASSERT_FALSE(error_message.empty());
+  // Now the flag is set and it must pass.
+  file_deserializer.set_allow_trailing_comma(true);
+  value.reset(file_deserializer.Deserialize(&error_code, &error_message));
+  ASSERT_TRUE(value.get());
+  ASSERT_EQ(JSONReader::JSON_TRAILING_COMMA, error_code);
+  // Verify if the same JSON is still there.
+  CheckJSONIsStillTheSame(*value);
+}
+
+TEST(JSONValueDeserializerTest, AllowTrailingComma) {
+  scoped_ptr<Value> root;
+  scoped_ptr<Value> root_expected;
+  static const char kTestWithCommas[] = "{\"key\": [true,],}";
+  static const char kTestNoCommas[] = "{\"key\": [true]}";
+
+  JSONStringValueDeserializer deserializer(kTestWithCommas);
+  deserializer.set_allow_trailing_comma(true);
+  JSONStringValueDeserializer deserializer_expected(kTestNoCommas);
+  root.reset(deserializer.Deserialize(NULL, NULL));
+  ASSERT_TRUE(root.get());
+  root_expected.reset(deserializer_expected.Deserialize(NULL, NULL));
+  ASSERT_TRUE(root_expected.get());
+  ASSERT_TRUE(root->Equals(root_expected.get()));
+}
+
+TEST(JSONValueSerializerTest, Roundtrip) {
+  static const char kOriginalSerialization[] =
+    "{\"bool\":true,\"double\":3.14,\"int\":42,\"list\":[1,2],\"null\":null}";
+  JSONStringValueDeserializer deserializer(kOriginalSerialization);
+  scoped_ptr<Value> root(deserializer.Deserialize(NULL, NULL));
+  ASSERT_TRUE(root.get());
+  ASSERT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
+
+  DictionaryValue* root_dict = static_cast<DictionaryValue*>(root.get());
+
+  Value* null_value = NULL;
+  ASSERT_TRUE(root_dict->Get("null", &null_value));
+  ASSERT_TRUE(null_value);
+  ASSERT_TRUE(null_value->IsType(Value::TYPE_NULL));
+
+  bool bool_value = false;
+  ASSERT_TRUE(root_dict->GetBoolean("bool", &bool_value));
+  ASSERT_TRUE(bool_value);
+
+  int int_value = 0;
+  ASSERT_TRUE(root_dict->GetInteger("int", &int_value));
+  ASSERT_EQ(42, int_value);
+
+  double double_value = 0.0;
+  ASSERT_TRUE(root_dict->GetDouble("double", &double_value));
+  ASSERT_DOUBLE_EQ(3.14, double_value);
+
+  std::string test_serialization;
+  JSONStringValueSerializer mutable_serializer(&test_serialization);
+  ASSERT_TRUE(mutable_serializer.Serialize(*root_dict));
+  ASSERT_EQ(kOriginalSerialization, test_serialization);
+
+  mutable_serializer.set_pretty_print(true);
+  ASSERT_TRUE(mutable_serializer.Serialize(*root_dict));
+  // JSON output uses a different newline style on Windows than on other
+  // platforms.
+#if defined(OS_WIN)
+#define JSON_NEWLINE "\r\n"
+#else
+#define JSON_NEWLINE "\n"
+#endif
+  const std::string pretty_serialization =
+    "{" JSON_NEWLINE
+    "   \"bool\": true," JSON_NEWLINE
+    "   \"double\": 3.14," JSON_NEWLINE
+    "   \"int\": 42," JSON_NEWLINE
+    "   \"list\": [ 1, 2 ]," JSON_NEWLINE
+    "   \"null\": null" JSON_NEWLINE
+    "}" JSON_NEWLINE;
+#undef JSON_NEWLINE
+  ASSERT_EQ(pretty_serialization, test_serialization);
+}
+
+TEST(JSONValueSerializerTest, StringEscape) {
+  string16 all_chars;
+  for (int i = 1; i < 256; ++i) {
+    all_chars += static_cast<char16>(i);
+  }
+  // Generated in in Firefox using the following js (with an extra backslash for
+  // double quote):
+  // var s = '';
+  // for (var i = 1; i < 256; ++i) { s += String.fromCharCode(i); }
+  // uneval(s).replace(/\\/g, "\\\\");
+  std::string all_chars_expected =
+      "\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\b\\t\\n\\u000B\\f\\r"
+      "\\u000E\\u000F\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017"
+      "\\u0018\\u0019\\u001A\\u001B\\u001C\\u001D\\u001E\\u001F !\\\"#$%&'()*+,"
+      "-./0123456789:;\\u003C=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcde"
+      "fghijklmnopqrstuvwxyz{|}~\x7F\xC2\x80\xC2\x81\xC2\x82\xC2\x83\xC2\x84"
+      "\xC2\x85\xC2\x86\xC2\x87\xC2\x88\xC2\x89\xC2\x8A\xC2\x8B\xC2\x8C\xC2\x8D"
+      "\xC2\x8E\xC2\x8F\xC2\x90\xC2\x91\xC2\x92\xC2\x93\xC2\x94\xC2\x95\xC2\x96"
+      "\xC2\x97\xC2\x98\xC2\x99\xC2\x9A\xC2\x9B\xC2\x9C\xC2\x9D\xC2\x9E\xC2\x9F"
+      "\xC2\xA0\xC2\xA1\xC2\xA2\xC2\xA3\xC2\xA4\xC2\xA5\xC2\xA6\xC2\xA7\xC2\xA8"
+      "\xC2\xA9\xC2\xAA\xC2\xAB\xC2\xAC\xC2\xAD\xC2\xAE\xC2\xAF\xC2\xB0\xC2\xB1"
+      "\xC2\xB2\xC2\xB3\xC2\xB4\xC2\xB5\xC2\xB6\xC2\xB7\xC2\xB8\xC2\xB9\xC2\xBA"
+      "\xC2\xBB\xC2\xBC\xC2\xBD\xC2\xBE\xC2\xBF\xC3\x80\xC3\x81\xC3\x82\xC3\x83"
+      "\xC3\x84\xC3\x85\xC3\x86\xC3\x87\xC3\x88\xC3\x89\xC3\x8A\xC3\x8B\xC3\x8C"
+      "\xC3\x8D\xC3\x8E\xC3\x8F\xC3\x90\xC3\x91\xC3\x92\xC3\x93\xC3\x94\xC3\x95"
+      "\xC3\x96\xC3\x97\xC3\x98\xC3\x99\xC3\x9A\xC3\x9B\xC3\x9C\xC3\x9D\xC3\x9E"
+      "\xC3\x9F\xC3\xA0\xC3\xA1\xC3\xA2\xC3\xA3\xC3\xA4\xC3\xA5\xC3\xA6\xC3\xA7"
+      "\xC3\xA8\xC3\xA9\xC3\xAA\xC3\xAB\xC3\xAC\xC3\xAD\xC3\xAE\xC3\xAF\xC3\xB0"
+      "\xC3\xB1\xC3\xB2\xC3\xB3\xC3\xB4\xC3\xB5\xC3\xB6\xC3\xB7\xC3\xB8\xC3\xB9"
+      "\xC3\xBA\xC3\xBB\xC3\xBC\xC3\xBD\xC3\xBE\xC3\xBF";
+
+  std::string expected_output = "{\"all_chars\":\"" + all_chars_expected +
+                                 "\"}";
+  // Test JSONWriter interface
+  std::string output_js;
+  DictionaryValue valueRoot;
+  valueRoot.SetString("all_chars", all_chars);
+  JSONWriter::Write(valueRoot, &output_js);
+  ASSERT_EQ(expected_output, output_js);
+
+  // Test JSONValueSerializer interface (uses JSONWriter).
+  JSONStringValueSerializer serializer(&output_js);
+  ASSERT_TRUE(serializer.Serialize(valueRoot));
+  ASSERT_EQ(expected_output, output_js);
+}
+
+TEST(JSONValueSerializerTest, UnicodeStrings) {
+  // unicode string json -> escaped ascii text
+  DictionaryValue root;
+  string16 test(WideToUTF16(L"\x7F51\x9875"));
+  root.SetString("web", test);
+
+  static const char kExpected[] = "{\"web\":\"\xE7\xBD\x91\xE9\xA1\xB5\"}";
+
+  std::string actual;
+  JSONStringValueSerializer serializer(&actual);
+  ASSERT_TRUE(serializer.Serialize(root));
+  ASSERT_EQ(kExpected, actual);
+
+  // escaped ascii text -> json
+  JSONStringValueDeserializer deserializer(kExpected);
+  scoped_ptr<Value> deserial_root(deserializer.Deserialize(NULL, NULL));
+  ASSERT_TRUE(deserial_root.get());
+  DictionaryValue* dict_root =
+      static_cast<DictionaryValue*>(deserial_root.get());
+  string16 web_value;
+  ASSERT_TRUE(dict_root->GetString("web", &web_value));
+  ASSERT_EQ(test, web_value);
+}
+
+TEST(JSONValueSerializerTest, HexStrings) {
+  // hex string json -> escaped ascii text
+  DictionaryValue root;
+  string16 test(WideToUTF16(L"\x01\x02"));
+  root.SetString("test", test);
+
+  static const char kExpected[] = "{\"test\":\"\\u0001\\u0002\"}";
+
+  std::string actual;
+  JSONStringValueSerializer serializer(&actual);
+  ASSERT_TRUE(serializer.Serialize(root));
+  ASSERT_EQ(kExpected, actual);
+
+  // escaped ascii text -> json
+  JSONStringValueDeserializer deserializer(kExpected);
+  scoped_ptr<Value> deserial_root(deserializer.Deserialize(NULL, NULL));
+  ASSERT_TRUE(deserial_root.get());
+  DictionaryValue* dict_root =
+      static_cast<DictionaryValue*>(deserial_root.get());
+  string16 test_value;
+  ASSERT_TRUE(dict_root->GetString("test", &test_value));
+  ASSERT_EQ(test, test_value);
+
+  // Test converting escaped regular chars
+  static const char kEscapedChars[] = "{\"test\":\"\\u0067\\u006f\"}";
+  JSONStringValueDeserializer deserializer2(kEscapedChars);
+  deserial_root.reset(deserializer2.Deserialize(NULL, NULL));
+  ASSERT_TRUE(deserial_root.get());
+  dict_root = static_cast<DictionaryValue*>(deserial_root.get());
+  ASSERT_TRUE(dict_root->GetString("test", &test_value));
+  ASSERT_EQ(ASCIIToUTF16("go"), test_value);
+}
+
+TEST(JSONValueSerializerTest, JSONReaderComments) {
+  ValidateJsonList("[ // 2, 3, ignore me ] \n1 ]");
+  ValidateJsonList("[ /* 2, \n3, ignore me ]*/ \n1 ]");
+  ValidateJsonList("//header\n[ // 2, \n// 3, \n1 ]// footer");
+  ValidateJsonList("/*\n[ // 2, \n// 3, \n1 ]*/[1]");
+  ValidateJsonList("[ 1 /* one */ ] /* end */");
+  ValidateJsonList("[ 1 //// ,2\r\n ]");
+
+  scoped_ptr<Value> root;
+
+  // It's ok to have a comment in a string.
+  root.reset(JSONReader::DeprecatedRead("[\"// ok\\n /* foo */ \"]"));
+  ASSERT_TRUE(root.get() && root->IsType(Value::TYPE_LIST));
+  ListValue* list = static_cast<ListValue*>(root.get());
+  ASSERT_EQ(1U, list->GetSize());
+  Value* elt = NULL;
+  ASSERT_TRUE(list->Get(0, &elt));
+  std::string value;
+  ASSERT_TRUE(elt && elt->GetAsString(&value));
+  ASSERT_EQ("// ok\n /* foo */ ", value);
+
+  // You can't nest comments.
+  root.reset(JSONReader::DeprecatedRead("/* /* inner */ outer */ [ 1 ]"));
+  ASSERT_FALSE(root.get());
+
+  // Not a open comment token.
+  root.reset(JSONReader::DeprecatedRead("/ * * / [1]"));
+  ASSERT_FALSE(root.get());
+}
+
+class JSONFileValueSerializerTest : public testing::Test {
+ protected:
+  void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); }
+
+  base::ScopedTempDir temp_dir_;
+};
+
+TEST_F(JSONFileValueSerializerTest, Roundtrip) {
+  base::FilePath original_file_path;
+  ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &original_file_path));
+  original_file_path =
+      original_file_path.Append(FILE_PATH_LITERAL("serializer_test.json"));
+
+  ASSERT_TRUE(PathExists(original_file_path));
+
+  JSONFileValueDeserializer deserializer(original_file_path);
+  scoped_ptr<Value> root;
+  root.reset(deserializer.Deserialize(NULL, NULL));
+
+  ASSERT_TRUE(root.get());
+  ASSERT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
+
+  DictionaryValue* root_dict = static_cast<DictionaryValue*>(root.get());
+
+  Value* null_value = NULL;
+  ASSERT_TRUE(root_dict->Get("null", &null_value));
+  ASSERT_TRUE(null_value);
+  ASSERT_TRUE(null_value->IsType(Value::TYPE_NULL));
+
+  bool bool_value = false;
+  ASSERT_TRUE(root_dict->GetBoolean("bool", &bool_value));
+  ASSERT_TRUE(bool_value);
+
+  int int_value = 0;
+  ASSERT_TRUE(root_dict->GetInteger("int", &int_value));
+  ASSERT_EQ(42, int_value);
+
+  std::string string_value;
+  ASSERT_TRUE(root_dict->GetString("string", &string_value));
+  ASSERT_EQ("hello", string_value);
+
+  // Now try writing.
+  const base::FilePath written_file_path =
+      temp_dir_.path().Append(FILE_PATH_LITERAL("test_output.js"));
+
+  ASSERT_FALSE(PathExists(written_file_path));
+  JSONFileValueSerializer serializer(written_file_path);
+  ASSERT_TRUE(serializer.Serialize(*root));
+  ASSERT_TRUE(PathExists(written_file_path));
+
+  // Now compare file contents.
+  EXPECT_TRUE(TextContentsEqual(original_file_path, written_file_path));
+  EXPECT_TRUE(base::DeleteFile(written_file_path, false));
+}
+
+TEST_F(JSONFileValueSerializerTest, RoundtripNested) {
+  base::FilePath original_file_path;
+  ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &original_file_path));
+  original_file_path = original_file_path.Append(
+      FILE_PATH_LITERAL("serializer_nested_test.json"));
+
+  ASSERT_TRUE(PathExists(original_file_path));
+
+  JSONFileValueDeserializer deserializer(original_file_path);
+  scoped_ptr<Value> root;
+  root.reset(deserializer.Deserialize(NULL, NULL));
+  ASSERT_TRUE(root.get());
+
+  // Now try writing.
+  base::FilePath written_file_path = temp_dir_.path().Append(
+      FILE_PATH_LITERAL("test_output.json"));
+
+  ASSERT_FALSE(PathExists(written_file_path));
+  JSONFileValueSerializer serializer(written_file_path);
+  ASSERT_TRUE(serializer.Serialize(*root));
+  ASSERT_TRUE(PathExists(written_file_path));
+
+  // Now compare file contents.
+  EXPECT_TRUE(TextContentsEqual(original_file_path, written_file_path));
+  EXPECT_TRUE(base::DeleteFile(written_file_path, false));
+}
+
+TEST_F(JSONFileValueSerializerTest, NoWhitespace) {
+  base::FilePath source_file_path;
+  ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &source_file_path));
+  source_file_path = source_file_path.Append(
+      FILE_PATH_LITERAL("serializer_test_nowhitespace.json"));
+  ASSERT_TRUE(PathExists(source_file_path));
+  JSONFileValueDeserializer deserializer(source_file_path);
+  scoped_ptr<Value> root;
+  root.reset(deserializer.Deserialize(NULL, NULL));
+  ASSERT_TRUE(root.get());
+}
+
+}  // namespace
+
+}  // namespace base
diff --git a/base/json/json_writer.cc b/base/json/json_writer.cc
new file mode 100644
index 0000000..abfead8
--- /dev/null
+++ b/base/json/json_writer.cc
@@ -0,0 +1,208 @@
+// Copyright (c) 2012 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/json/json_writer.h"
+
+#include <cmath>
+
+#include "base/json/string_escape.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+
+namespace base {
+
+#if defined(OS_WIN)
+const char kPrettyPrintLineEnding[] = "\r\n";
+#else
+const char kPrettyPrintLineEnding[] = "\n";
+#endif
+
+// static
+bool JSONWriter::Write(const Value& node, std::string* json) {
+  return WriteWithOptions(node, 0, json);
+}
+
+// static
+bool JSONWriter::WriteWithOptions(const Value& node,
+                                  int options,
+                                  std::string* json) {
+  json->clear();
+  // Is there a better way to estimate the size of the output?
+  json->reserve(1024);
+
+  JSONWriter writer(options, json);
+  bool result = writer.BuildJSONString(node, 0U);
+
+  if (options & OPTIONS_PRETTY_PRINT)
+    json->append(kPrettyPrintLineEnding);
+
+  return result;
+}
+
+JSONWriter::JSONWriter(int options, std::string* json)
+    : omit_binary_values_((options & OPTIONS_OMIT_BINARY_VALUES) != 0),
+      omit_double_type_preservation_(
+          (options & OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION) != 0),
+      pretty_print_((options & OPTIONS_PRETTY_PRINT) != 0),
+      json_string_(json) {
+  DCHECK(json);
+}
+
+bool JSONWriter::BuildJSONString(const Value& node, size_t depth) {
+  switch (node.GetType()) {
+    case Value::TYPE_NULL: {
+      json_string_->append("null");
+      return true;
+    }
+
+    case Value::TYPE_BOOLEAN: {
+      bool value;
+      bool result = node.GetAsBoolean(&value);
+      DCHECK(result);
+      json_string_->append(value ? "true" : "false");
+      return result;
+    }
+
+    case Value::TYPE_INTEGER: {
+      int value;
+      bool result = node.GetAsInteger(&value);
+      DCHECK(result);
+      json_string_->append(IntToString(value));
+      return result;
+    }
+
+    case Value::TYPE_DOUBLE: {
+      double value;
+      bool result = node.GetAsDouble(&value);
+      DCHECK(result);
+      if (omit_double_type_preservation_ &&
+          value <= kint64max &&
+          value >= kint64min &&
+          std::floor(value) == value) {
+        json_string_->append(Int64ToString(static_cast<int64>(value)));
+        return result;
+      }
+      std::string real = DoubleToString(value);
+      // Ensure that the number has a .0 if there's no decimal or 'e'.  This
+      // makes sure that when we read the JSON back, it's interpreted as a
+      // real rather than an int.
+      if (real.find('.') == std::string::npos &&
+          real.find('e') == std::string::npos &&
+          real.find('E') == std::string::npos) {
+        real.append(".0");
+      }
+      // The JSON spec requires that non-integer values in the range (-1,1)
+      // have a zero before the decimal point - ".52" is not valid, "0.52" is.
+      if (real[0] == '.') {
+        real.insert(static_cast<size_t>(0), static_cast<size_t>(1), '0');
+      } else if (real.length() > 1 && real[0] == '-' && real[1] == '.') {
+        // "-.1" bad "-0.1" good
+        real.insert(static_cast<size_t>(1), static_cast<size_t>(1), '0');
+      }
+      json_string_->append(real);
+      return result;
+    }
+
+    case Value::TYPE_STRING: {
+      std::string value;
+      bool result = node.GetAsString(&value);
+      DCHECK(result);
+      EscapeJSONString(value, true, json_string_);
+      return result;
+    }
+
+    case Value::TYPE_LIST: {
+      json_string_->push_back('[');
+      if (pretty_print_)
+        json_string_->push_back(' ');
+
+      const ListValue* list = NULL;
+      bool first_value_has_been_output = false;
+      bool result = node.GetAsList(&list);
+      DCHECK(result);
+      for (ListValue::const_iterator it = list->begin(); it != list->end();
+           ++it) {
+        const Value* value = *it;
+        if (omit_binary_values_ && value->GetType() == Value::TYPE_BINARY)
+          continue;
+
+        if (first_value_has_been_output) {
+          json_string_->push_back(',');
+          if (pretty_print_)
+            json_string_->push_back(' ');
+        }
+
+        if (!BuildJSONString(*value, depth))
+          result = false;
+
+        first_value_has_been_output = true;
+      }
+
+      if (pretty_print_)
+        json_string_->push_back(' ');
+      json_string_->push_back(']');
+      return result;
+    }
+
+    case Value::TYPE_DICTIONARY: {
+      json_string_->push_back('{');
+      if (pretty_print_)
+        json_string_->append(kPrettyPrintLineEnding);
+
+      const DictionaryValue* dict = NULL;
+      bool first_value_has_been_output = false;
+      bool result = node.GetAsDictionary(&dict);
+      DCHECK(result);
+      for (DictionaryValue::Iterator itr(*dict); !itr.IsAtEnd();
+           itr.Advance()) {
+        if (omit_binary_values_ &&
+            itr.value().GetType() == Value::TYPE_BINARY) {
+          continue;
+        }
+
+        if (first_value_has_been_output) {
+          json_string_->push_back(',');
+          if (pretty_print_)
+            json_string_->append(kPrettyPrintLineEnding);
+        }
+
+        if (pretty_print_)
+          IndentLine(depth + 1U);
+
+        EscapeJSONString(itr.key(), true, json_string_);
+        json_string_->push_back(':');
+        if (pretty_print_)
+          json_string_->push_back(' ');
+
+        if (!BuildJSONString(itr.value(), depth + 1U))
+          result = false;
+
+        first_value_has_been_output = true;
+      }
+
+      if (pretty_print_) {
+        json_string_->append(kPrettyPrintLineEnding);
+        IndentLine(depth);
+      }
+
+      json_string_->push_back('}');
+      return result;
+    }
+
+    case Value::TYPE_BINARY:
+      // Successful only if we're allowed to omit it.
+      DLOG_IF(ERROR, !omit_binary_values_) << "Cannot serialize binary value.";
+      return omit_binary_values_;
+  }
+  NOTREACHED();
+  return false;
+}
+
+void JSONWriter::IndentLine(size_t depth) {
+  json_string_->append(depth * 3U, ' ');
+}
+
+}  // namespace base
diff --git a/base/json/json_writer.h b/base/json/json_writer.h
new file mode 100644
index 0000000..5711665
--- /dev/null
+++ b/base/json/json_writer.h
@@ -0,0 +1,71 @@
+// Copyright (c) 2012 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_JSON_JSON_WRITER_H_
+#define BASE_JSON_JSON_WRITER_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+
+class Value;
+
+class BASE_EXPORT JSONWriter {
+ public:
+  enum Options {
+    // This option instructs the writer that if a Binary value is encountered,
+    // the value (and key if within a dictionary) will be omitted from the
+    // output, and success will be returned. Otherwise, if a binary value is
+    // encountered, failure will be returned.
+    OPTIONS_OMIT_BINARY_VALUES = 1 << 0,
+
+    // This option instructs the writer to write doubles that have no fractional
+    // part as a normal integer (i.e., without using exponential notation
+    // or appending a '.0') as long as the value is within the range of a
+    // 64-bit int.
+    OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION = 1 << 1,
+
+    // Return a slightly nicer formatted json string (pads with whitespace to
+    // help with readability).
+    OPTIONS_PRETTY_PRINT = 1 << 2,
+  };
+
+  // Given a root node, generates a JSON string and puts it into |json|.
+  // TODO(tc): Should we generate json if it would be invalid json (e.g.,
+  // |node| is not a DictionaryValue/ListValue or if there are inf/-inf float
+  // values)? Return true on success and false on failure.
+  static bool Write(const Value& node, std::string* json);
+
+  // Same as above but with |options| which is a bunch of JSONWriter::Options
+  // bitwise ORed together. Return true on success and false on failure.
+  static bool WriteWithOptions(const Value& node,
+                               int options,
+                               std::string* json);
+
+ private:
+  JSONWriter(int options, std::string* json);
+
+  // Called recursively to build the JSON string. When completed,
+  // |json_string_| will contain the JSON.
+  bool BuildJSONString(const Value& node, size_t depth);
+
+  // Adds space to json_string_ for the indent level.
+  void IndentLine(size_t depth);
+
+  bool omit_binary_values_;
+  bool omit_double_type_preservation_;
+  bool pretty_print_;
+
+  // Where we write JSON data as we generate it.
+  std::string* json_string_;
+
+  DISALLOW_COPY_AND_ASSIGN(JSONWriter);
+};
+
+}  // namespace base
+
+#endif  // BASE_JSON_JSON_WRITER_H_
diff --git a/base/json/json_writer_unittest.cc b/base/json/json_writer_unittest.cc
new file mode 100644
index 0000000..0daeafc
--- /dev/null
+++ b/base/json/json_writer_unittest.cc
@@ -0,0 +1,154 @@
+// Copyright (c) 2012 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/json/json_writer.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(JSONWriterTest, BasicTypes) {
+  std::string output_js;
+
+  // Test null.
+  EXPECT_TRUE(JSONWriter::Write(*Value::CreateNullValue(), &output_js));
+  EXPECT_EQ("null", output_js);
+
+  // Test empty dict.
+  EXPECT_TRUE(JSONWriter::Write(DictionaryValue(), &output_js));
+  EXPECT_EQ("{}", output_js);
+
+  // Test empty list.
+  EXPECT_TRUE(JSONWriter::Write(ListValue(), &output_js));
+  EXPECT_EQ("[]", output_js);
+
+  // Test integer values.
+  EXPECT_TRUE(JSONWriter::Write(FundamentalValue(42), &output_js));
+  EXPECT_EQ("42", output_js);
+
+  // Test boolean values.
+  EXPECT_TRUE(JSONWriter::Write(FundamentalValue(true), &output_js));
+  EXPECT_EQ("true", output_js);
+
+  // Test Real values should always have a decimal or an 'e'.
+  EXPECT_TRUE(JSONWriter::Write(FundamentalValue(1.0), &output_js));
+  EXPECT_EQ("1.0", output_js);
+
+  // Test Real values in the the range (-1, 1) must have leading zeros
+  EXPECT_TRUE(JSONWriter::Write(FundamentalValue(0.2), &output_js));
+  EXPECT_EQ("0.2", output_js);
+
+  // Test Real values in the the range (-1, 1) must have leading zeros
+  EXPECT_TRUE(JSONWriter::Write(FundamentalValue(-0.8), &output_js));
+  EXPECT_EQ("-0.8", output_js);
+
+  // Test String values.
+  EXPECT_TRUE(JSONWriter::Write(StringValue("foo"), &output_js));
+  EXPECT_EQ("\"foo\"", output_js);
+}
+
+TEST(JSONWriterTest, NestedTypes) {
+  std::string output_js;
+
+  // Writer unittests like empty list/dict nesting,
+  // list list nesting, etc.
+  DictionaryValue root_dict;
+  scoped_ptr<ListValue> list(new ListValue());
+  scoped_ptr<DictionaryValue> inner_dict(new DictionaryValue());
+  inner_dict->SetInteger("inner int", 10);
+  list->Append(inner_dict.Pass());
+  list->Append(make_scoped_ptr(new ListValue()));
+  list->AppendBoolean(true);
+  root_dict.Set("list", list.Pass());
+
+  // Test the pretty-printer.
+  EXPECT_TRUE(JSONWriter::Write(root_dict, &output_js));
+  EXPECT_EQ("{\"list\":[{\"inner int\":10},[],true]}", output_js);
+  EXPECT_TRUE(JSONWriter::WriteWithOptions(
+      root_dict, JSONWriter::OPTIONS_PRETTY_PRINT, &output_js));
+
+  // The pretty-printer uses a different newline style on Windows than on
+  // other platforms.
+#if defined(OS_WIN)
+#define JSON_NEWLINE "\r\n"
+#else
+#define JSON_NEWLINE "\n"
+#endif
+  EXPECT_EQ("{" JSON_NEWLINE
+            "   \"list\": [ {" JSON_NEWLINE
+            "      \"inner int\": 10" JSON_NEWLINE
+            "   }, [  ], true ]" JSON_NEWLINE
+            "}" JSON_NEWLINE,
+            output_js);
+#undef JSON_NEWLINE
+}
+
+TEST(JSONWriterTest, KeysWithPeriods) {
+  std::string output_js;
+
+  DictionaryValue period_dict;
+  period_dict.SetIntegerWithoutPathExpansion("a.b", 3);
+  period_dict.SetIntegerWithoutPathExpansion("c", 2);
+  scoped_ptr<DictionaryValue> period_dict2(new DictionaryValue());
+  period_dict2->SetIntegerWithoutPathExpansion("g.h.i.j", 1);
+  period_dict.SetWithoutPathExpansion("d.e.f", period_dict2.Pass());
+  EXPECT_TRUE(JSONWriter::Write(period_dict, &output_js));
+  EXPECT_EQ("{\"a.b\":3,\"c\":2,\"d.e.f\":{\"g.h.i.j\":1}}", output_js);
+
+  DictionaryValue period_dict3;
+  period_dict3.SetInteger("a.b", 2);
+  period_dict3.SetIntegerWithoutPathExpansion("a.b", 1);
+  EXPECT_TRUE(JSONWriter::Write(period_dict3, &output_js));
+  EXPECT_EQ("{\"a\":{\"b\":2},\"a.b\":1}", output_js);
+}
+
+TEST(JSONWriterTest, BinaryValues) {
+  std::string output_js;
+
+  // Binary values should return errors unless suppressed via the
+  // OPTIONS_OMIT_BINARY_VALUES flag.
+  scoped_ptr<Value> root(BinaryValue::CreateWithCopiedBuffer("asdf", 4));
+  EXPECT_FALSE(JSONWriter::Write(*root, &output_js));
+  EXPECT_TRUE(JSONWriter::WriteWithOptions(
+      *root, JSONWriter::OPTIONS_OMIT_BINARY_VALUES, &output_js));
+  EXPECT_TRUE(output_js.empty());
+
+  ListValue binary_list;
+  binary_list.Append(BinaryValue::CreateWithCopiedBuffer("asdf", 4));
+  binary_list.Append(make_scoped_ptr(new FundamentalValue(5)));
+  binary_list.Append(BinaryValue::CreateWithCopiedBuffer("asdf", 4));
+  binary_list.Append(make_scoped_ptr(new FundamentalValue(2)));
+  binary_list.Append(BinaryValue::CreateWithCopiedBuffer("asdf", 4));
+  EXPECT_FALSE(JSONWriter::Write(binary_list, &output_js));
+  EXPECT_TRUE(JSONWriter::WriteWithOptions(
+      binary_list, JSONWriter::OPTIONS_OMIT_BINARY_VALUES, &output_js));
+  EXPECT_EQ("[5,2]", output_js);
+
+  DictionaryValue binary_dict;
+  binary_dict.Set(
+      "a", make_scoped_ptr(BinaryValue::CreateWithCopiedBuffer("asdf", 4)));
+  binary_dict.SetInteger("b", 5);
+  binary_dict.Set(
+      "c", make_scoped_ptr(BinaryValue::CreateWithCopiedBuffer("asdf", 4)));
+  binary_dict.SetInteger("d", 2);
+  binary_dict.Set(
+      "e", make_scoped_ptr(BinaryValue::CreateWithCopiedBuffer("asdf", 4)));
+  EXPECT_FALSE(JSONWriter::Write(binary_dict, &output_js));
+  EXPECT_TRUE(JSONWriter::WriteWithOptions(
+      binary_dict, JSONWriter::OPTIONS_OMIT_BINARY_VALUES, &output_js));
+  EXPECT_EQ("{\"b\":5,\"d\":2}", output_js);
+}
+
+TEST(JSONWriterTest, DoublesAsInts) {
+  std::string output_js;
+
+  // Test allowing a double with no fractional part to be written as an integer.
+  FundamentalValue double_value(1e10);
+  EXPECT_TRUE(JSONWriter::WriteWithOptions(
+      double_value, JSONWriter::OPTIONS_OMIT_DOUBLE_TYPE_PRESERVATION,
+      &output_js));
+  EXPECT_EQ("10000000000", output_js);
+}
+
+}  // namespace base
diff --git a/base/json/string_escape.cc b/base/json/string_escape.cc
new file mode 100644
index 0000000..469f9f9
--- /dev/null
+++ b/base/json/string_escape.cc
@@ -0,0 +1,154 @@
+// Copyright (c) 2006-2008 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/json/string_escape.h"
+
+#include <string>
+
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversion_utils.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/third_party/icu/icu_utf.h"
+
+namespace base {
+
+namespace {
+
+// Format string for printing a \uXXXX escape sequence.
+const char kU16EscapeFormat[] = "\\u%04X";
+
+// The code point to output for an invalid input code unit.
+const uint32 kReplacementCodePoint = 0xFFFD;
+
+// Used below in EscapeSpecialCodePoint().
+COMPILE_ASSERT('<' == 0x3C, less_than_sign_is_0x3c);
+
+// Try to escape the |code_point| if it is a known special character. If
+// successful, returns true and appends the escape sequence to |dest|. This
+// isn't required by the spec, but it's more readable by humans.
+bool EscapeSpecialCodePoint(uint32 code_point, std::string* dest) {
+  // WARNING: if you add a new case here, you need to update the reader as well.
+  // Note: \v is in the reader, but not here since the JSON spec doesn't
+  // allow it.
+  switch (code_point) {
+    case '\b':
+      dest->append("\\b");
+      break;
+    case '\f':
+      dest->append("\\f");
+      break;
+    case '\n':
+      dest->append("\\n");
+      break;
+    case '\r':
+      dest->append("\\r");
+      break;
+    case '\t':
+      dest->append("\\t");
+      break;
+    case '\\':
+      dest->append("\\\\");
+      break;
+    case '"':
+      dest->append("\\\"");
+      break;
+    // Escape < to prevent script execution; escaping > is not necessary and
+    // not doing so save a few bytes.
+    case '<':
+      dest->append("\\u003C");
+      break;
+    default:
+      return false;
+  }
+  return true;
+}
+
+template <typename S>
+bool EscapeJSONStringImpl(const S& str, bool put_in_quotes, std::string* dest) {
+  bool did_replacement = false;
+
+  if (put_in_quotes)
+    dest->push_back('"');
+
+  // Casting is necessary because ICU uses int32. Try and do so safely.
+  CHECK_LE(str.length(), static_cast<size_t>(kint32max));
+  const int32 length = static_cast<int32>(str.length());
+
+  for (int32 i = 0; i < length; ++i) {
+    uint32 code_point;
+    if (!ReadUnicodeCharacter(str.data(), length, &i, &code_point)) {
+      code_point = kReplacementCodePoint;
+      did_replacement = true;
+    }
+
+    if (EscapeSpecialCodePoint(code_point, dest))
+      continue;
+
+    // Escape non-printing characters.
+    if (code_point < 32)
+      base::StringAppendF(dest, kU16EscapeFormat, code_point);
+    else
+      WriteUnicodeCharacter(code_point, dest);
+  }
+
+  if (put_in_quotes)
+    dest->push_back('"');
+
+  return !did_replacement;
+}
+
+}  // namespace
+
+bool EscapeJSONString(const StringPiece& str,
+                      bool put_in_quotes,
+                      std::string* dest) {
+  return EscapeJSONStringImpl(str, put_in_quotes, dest);
+}
+
+bool EscapeJSONString(const StringPiece16& str,
+                      bool put_in_quotes,
+                      std::string* dest) {
+  return EscapeJSONStringImpl(str, put_in_quotes, dest);
+}
+
+std::string GetQuotedJSONString(const StringPiece& str) {
+  std::string dest;
+  bool ok = EscapeJSONStringImpl(str, true, &dest);
+  DCHECK(ok);
+  return dest;
+}
+
+std::string GetQuotedJSONString(const StringPiece16& str) {
+  std::string dest;
+  bool ok = EscapeJSONStringImpl(str, true, &dest);
+  DCHECK(ok);
+  return dest;
+}
+
+std::string EscapeBytesAsInvalidJSONString(const StringPiece& str,
+                                           bool put_in_quotes) {
+  std::string dest;
+
+  if (put_in_quotes)
+    dest.push_back('"');
+
+  for (StringPiece::const_iterator it = str.begin(); it != str.end(); ++it) {
+    unsigned char c = *it;
+    if (EscapeSpecialCodePoint(c, &dest))
+      continue;
+
+    if (c < 32 || c > 126)
+      base::StringAppendF(&dest, kU16EscapeFormat, c);
+    else
+      dest.push_back(*it);
+  }
+
+  if (put_in_quotes)
+    dest.push_back('"');
+
+  return dest;
+}
+
+}  // namespace base
diff --git a/base/json/string_escape.h b/base/json/string_escape.h
new file mode 100644
index 0000000..b66b7e5
--- /dev/null
+++ b/base/json/string_escape.h
@@ -0,0 +1,60 @@
+// Copyright (c) 2011 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 defines utility functions for escaping strings suitable for JSON.
+
+#ifndef BASE_JSON_STRING_ESCAPE_H_
+#define BASE_JSON_STRING_ESCAPE_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+// Appends to |dest| an escaped version of |str|. Valid UTF-8 code units will
+// pass through from the input to the output. Invalid code units will be
+// replaced with the U+FFFD replacement character. This function returns true
+// if no replacement was necessary and false if there was a lossy replacement.
+// On return, |dest| will contain a valid UTF-8 JSON string.
+//
+// Non-printing control characters will be escaped as \uXXXX sequences for
+// readability.
+//
+// If |put_in_quotes| is true, then a leading and trailing double-quote mark
+// will be appended to |dest| as well.
+BASE_EXPORT bool EscapeJSONString(const StringPiece& str,
+                                  bool put_in_quotes,
+                                  std::string* dest);
+
+// Performs a similar function to the UTF-8 StringPiece version above,
+// converting UTF-16 code units to UTF-8 code units and escaping non-printing
+// control characters. On return, |dest| will contain a valid UTF-8 JSON string.
+BASE_EXPORT bool EscapeJSONString(const StringPiece16& str,
+                                  bool put_in_quotes,
+                                  std::string* dest);
+
+// Helper functions that wrap the above two functions but return the value
+// instead of appending. |put_in_quotes| is always true.
+BASE_EXPORT std::string GetQuotedJSONString(const StringPiece& str);
+BASE_EXPORT std::string GetQuotedJSONString(const StringPiece16& str);
+
+// Given an arbitrary byte string |str|, this will escape all non-ASCII bytes
+// as \uXXXX escape sequences. This function is *NOT* meant to be used with
+// Unicode strings and does not validate |str| as one.
+//
+// CAVEAT CALLER: The output of this function may not be valid JSON, since
+// JSON requires escape sequences to be valid UTF-16 code units. This output
+// will be mangled if passed to to the base::JSONReader, since the reader will
+// interpret it as UTF-16 and convert it to UTF-8.
+//
+// The output of this function takes the *appearance* of JSON but is not in
+// fact valid according to RFC 4627.
+BASE_EXPORT std::string EscapeBytesAsInvalidJSONString(const StringPiece& str,
+                                                       bool put_in_quotes);
+
+}  // namespace base
+
+#endif  // BASE_JSON_STRING_ESCAPE_H_
diff --git a/base/json/string_escape_unittest.cc b/base/json/string_escape_unittest.cc
new file mode 100644
index 0000000..100373f
--- /dev/null
+++ b/base/json/string_escape_unittest.cc
@@ -0,0 +1,182 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/json/string_escape.h"
+
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(JSONStringEscapeTest, EscapeUTF8) {
+  const struct {
+    const char* to_escape;
+    const char* escaped;
+  } cases[] = {
+    {"\b\001aZ\"\\wee", "\\b\\u0001aZ\\\"\\\\wee"},
+    {"a\b\f\n\r\t\v\1\\.\"z",
+        "a\\b\\f\\n\\r\\t\\u000B\\u0001\\\\.\\\"z"},
+    {"b\x0f\x7f\xf0\xff!",  // \xf0\xff is not a valid UTF-8 unit.
+        "b\\u000F\x7F\xEF\xBF\xBD\xEF\xBF\xBD!"},
+    {"c<>d", "c\\u003C>d"},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    const char* in_ptr = cases[i].to_escape;
+    std::string in_str = in_ptr;
+
+    std::string out;
+    EscapeJSONString(in_ptr, false, &out);
+    EXPECT_EQ(std::string(cases[i].escaped), out);
+    EXPECT_TRUE(IsStringUTF8(out));
+
+    out.erase();
+    bool convert_ok = EscapeJSONString(in_str, false, &out);
+    EXPECT_EQ(std::string(cases[i].escaped), out);
+    EXPECT_TRUE(IsStringUTF8(out));
+
+    if (convert_ok) {
+      std::string fooout = GetQuotedJSONString(in_str);
+      EXPECT_EQ("\"" + std::string(cases[i].escaped) + "\"", fooout);
+      EXPECT_TRUE(IsStringUTF8(out));
+    }
+  }
+
+  std::string in = cases[0].to_escape;
+  std::string out;
+  EscapeJSONString(in, false, &out);
+  EXPECT_TRUE(IsStringUTF8(out));
+
+  // test quoting
+  std::string out_quoted;
+  EscapeJSONString(in, true, &out_quoted);
+  EXPECT_EQ(out.length() + 2, out_quoted.length());
+  EXPECT_EQ(out_quoted.find(out), 1U);
+  EXPECT_TRUE(IsStringUTF8(out_quoted));
+
+  // now try with a NULL in the string
+  std::string null_prepend = "test";
+  null_prepend.push_back(0);
+  in = null_prepend + in;
+  std::string expected = "test\\u0000";
+  expected += cases[0].escaped;
+  out.clear();
+  EscapeJSONString(in, false, &out);
+  EXPECT_EQ(expected, out);
+  EXPECT_TRUE(IsStringUTF8(out));
+}
+
+TEST(JSONStringEscapeTest, EscapeUTF16) {
+  const struct {
+    const wchar_t* to_escape;
+    const char* escaped;
+  } cases[] = {
+    {L"b\uffb1\u00ff", "b\xEF\xBE\xB1\xC3\xBF"},
+    {L"\b\001aZ\"\\wee", "\\b\\u0001aZ\\\"\\\\wee"},
+    {L"a\b\f\n\r\t\v\1\\.\"z",
+        "a\\b\\f\\n\\r\\t\\u000B\\u0001\\\\.\\\"z"},
+    {L"b\x0f\x7f\xf0\xff!", "b\\u000F\x7F\xC3\xB0\xC3\xBF!"},
+    {L"c<>d", "c\\u003C>d"},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    string16 in = WideToUTF16(cases[i].to_escape);
+
+    std::string out;
+    EscapeJSONString(in, false, &out);
+    EXPECT_EQ(std::string(cases[i].escaped), out);
+    EXPECT_TRUE(IsStringUTF8(out));
+
+    out = GetQuotedJSONString(in);
+    EXPECT_EQ("\"" + std::string(cases[i].escaped) + "\"", out);
+    EXPECT_TRUE(IsStringUTF8(out));
+  }
+
+  string16 in = WideToUTF16(cases[0].to_escape);
+  std::string out;
+  EscapeJSONString(in, false, &out);
+  EXPECT_TRUE(IsStringUTF8(out));
+
+  // test quoting
+  std::string out_quoted;
+  EscapeJSONString(in, true, &out_quoted);
+  EXPECT_EQ(out.length() + 2, out_quoted.length());
+  EXPECT_EQ(out_quoted.find(out), 1U);
+  EXPECT_TRUE(IsStringUTF8(out));
+
+  // now try with a NULL in the string
+  string16 null_prepend = WideToUTF16(L"test");
+  null_prepend.push_back(0);
+  in = null_prepend + in;
+  std::string expected = "test\\u0000";
+  expected += cases[0].escaped;
+  out.clear();
+  EscapeJSONString(in, false, &out);
+  EXPECT_EQ(expected, out);
+  EXPECT_TRUE(IsStringUTF8(out));
+}
+
+TEST(JSONStringEscapeTest, EscapeUTF16OutsideBMP) {
+  {
+    // {a, U+10300, !}, SMP.
+    string16 test;
+    test.push_back('a');
+    test.push_back(0xD800);
+    test.push_back(0xDF00);
+    test.push_back('!');
+    std::string actual;
+    EXPECT_TRUE(EscapeJSONString(test, false, &actual));
+    EXPECT_EQ("a\xF0\x90\x8C\x80!", actual);
+  }
+  {
+    // {U+20021, U+2002B}, SIP.
+    string16 test;
+    test.push_back(0xD840);
+    test.push_back(0xDC21);
+    test.push_back(0xD840);
+    test.push_back(0xDC2B);
+    std::string actual;
+    EXPECT_TRUE(EscapeJSONString(test, false, &actual));
+    EXPECT_EQ("\xF0\xA0\x80\xA1\xF0\xA0\x80\xAB", actual);
+  }
+  {
+    // {?, U+D800, @}, lone surrogate.
+    string16 test;
+    test.push_back('?');
+    test.push_back(0xD800);
+    test.push_back('@');
+    std::string actual;
+    EXPECT_FALSE(EscapeJSONString(test, false, &actual));
+    EXPECT_EQ("?\xEF\xBF\xBD@", actual);
+  }
+}
+
+TEST(JSONStringEscapeTest, EscapeBytes) {
+  const struct {
+    const char* to_escape;
+    const char* escaped;
+  } cases[] = {
+    {"b\x0f\x7f\xf0\xff!", "b\\u000F\\u007F\\u00F0\\u00FF!"},
+    {"\xe5\xc4\x4f\x05\xb6\xfd", "\\u00E5\\u00C4O\\u0005\\u00B6\\u00FD"},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    std::string in = std::string(cases[i].to_escape);
+    EXPECT_FALSE(IsStringUTF8(in));
+
+    EXPECT_EQ(std::string(cases[i].escaped),
+        EscapeBytesAsInvalidJSONString(in, false));
+    EXPECT_EQ("\"" + std::string(cases[i].escaped) + "\"",
+        EscapeBytesAsInvalidJSONString(in, true));
+  }
+
+  const char kEmbedNull[] = { '\xab', '\x39', '\0', '\x9f', '\xab' };
+  std::string in(kEmbedNull, arraysize(kEmbedNull));
+  EXPECT_FALSE(IsStringUTF8(in));
+  EXPECT_EQ(std::string("\\u00AB9\\u0000\\u009F\\u00AB"),
+            EscapeBytesAsInvalidJSONString(in, false));
+}
+
+}  // namespace base
diff --git a/base/lazy_instance.cc b/base/lazy_instance.cc
new file mode 100644
index 0000000..594c1fe
--- /dev/null
+++ b/base/lazy_instance.cc
@@ -0,0 +1,55 @@
+// Copyright (c) 2011 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/lazy_instance.h"
+
+#include "base/at_exit.h"
+#include "base/atomicops.h"
+#include "base/basictypes.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+namespace internal {
+
+// TODO(joth): This function could be shared with Singleton, in place of its
+// WaitForInstance() call.
+bool NeedsLazyInstance(subtle::AtomicWord* state) {
+  // Try to create the instance, if we're the first, will go from 0 to
+  // kLazyInstanceStateCreating, otherwise we've already been beaten here.
+  // The memory access has no memory ordering as state 0 and
+  // kLazyInstanceStateCreating have no associated data (memory barriers are
+  // all about ordering of memory accesses to *associated* data).
+  if (subtle::NoBarrier_CompareAndSwap(state, 0,
+                                       kLazyInstanceStateCreating) == 0)
+    // Caller must create instance
+    return true;
+
+  // It's either in the process of being created, or already created. Spin.
+  // The load has acquire memory ordering as a thread which sees
+  // state_ == STATE_CREATED needs to acquire visibility over
+  // the associated data (buf_). Pairing Release_Store is in
+  // CompleteLazyInstance().
+  while (subtle::Acquire_Load(state) == kLazyInstanceStateCreating) {
+    PlatformThread::YieldCurrentThread();
+  }
+  // Someone else created the instance.
+  return false;
+}
+
+void CompleteLazyInstance(subtle::AtomicWord* state,
+                          subtle::AtomicWord new_instance,
+                          void* lazy_instance,
+                          void (*dtor)(void*)) {
+  // Instance is created, go from CREATING to CREATED.
+  // Releases visibility over private_buf_ to readers. Pairing Acquire_Load's
+  // are in NeedsInstance() and Pointer().
+  subtle::Release_Store(state, new_instance);
+
+  // Make sure that the lazily instantiated object will get destroyed at exit.
+  if (dtor)
+    AtExitManager::RegisterCallback(dtor, lazy_instance);
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/lazy_instance.h b/base/lazy_instance.h
new file mode 100644
index 0000000..d52b543
--- /dev/null
+++ b/base/lazy_instance.h
@@ -0,0 +1,208 @@
+// Copyright (c) 2012 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.
+
+// The LazyInstance<Type, Traits> class manages a single instance of Type,
+// which will be lazily created on the first time it's accessed.  This class is
+// useful for places you would normally use a function-level static, but you
+// need to have guaranteed thread-safety.  The Type constructor will only ever
+// be called once, even if two threads are racing to create the object.  Get()
+// and Pointer() will always return the same, completely initialized instance.
+// When the instance is constructed it is registered with AtExitManager.  The
+// destructor will be called on program exit.
+//
+// LazyInstance is completely thread safe, assuming that you create it safely.
+// The class was designed to be POD initialized, so it shouldn't require a
+// static constructor.  It really only makes sense to declare a LazyInstance as
+// a global variable using the LAZY_INSTANCE_INITIALIZER initializer.
+//
+// LazyInstance is similar to Singleton, except it does not have the singleton
+// property.  You can have multiple LazyInstance's of the same type, and each
+// will manage a unique instance.  It also preallocates the space for Type, as
+// to avoid allocating the Type instance on the heap.  This may help with the
+// performance of creating the instance, and reducing heap fragmentation.  This
+// requires that Type be a complete type so we can determine the size.
+//
+// Example usage:
+//   static LazyInstance<MyClass> my_instance = LAZY_INSTANCE_INITIALIZER;
+//   void SomeMethod() {
+//     my_instance.Get().SomeMethod();  // MyClass::SomeMethod()
+//
+//     MyClass* ptr = my_instance.Pointer();
+//     ptr->DoDoDo();  // MyClass::DoDoDo
+//   }
+
+#ifndef BASE_LAZY_INSTANCE_H_
+#define BASE_LAZY_INSTANCE_H_
+
+#include <new>  // For placement new.
+
+#include "base/atomicops.h"
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/debug/leak_annotations.h"
+#include "base/logging.h"
+#include "base/memory/aligned_memory.h"
+#include "base/threading/thread_restrictions.h"
+
+// LazyInstance uses its own struct initializer-list style static
+// initialization, as base's LINKER_INITIALIZED requires a constructor and on
+// some compilers (notably gcc 4.4) this still ends up needing runtime
+// initialization.
+#define LAZY_INSTANCE_INITIALIZER {0}
+
+namespace base {
+
+template <typename Type>
+struct DefaultLazyInstanceTraits {
+  static const bool kRegisterOnExit = true;
+#ifndef NDEBUG
+  static const bool kAllowedToAccessOnNonjoinableThread = false;
+#endif
+
+  static Type* New(void* instance) {
+    DCHECK_EQ(reinterpret_cast<uintptr_t>(instance) & (ALIGNOF(Type) - 1), 0u)
+        << ": Bad boy, the buffer passed to placement new is not aligned!\n"
+        "This may break some stuff like SSE-based optimizations assuming the "
+        "<Type> objects are word aligned.";
+    // Use placement new to initialize our instance in our preallocated space.
+    // The parenthesis is very important here to force POD type initialization.
+    return new (instance) Type();
+  }
+  static void Delete(Type* instance) {
+    // Explicitly call the destructor.
+    instance->~Type();
+  }
+};
+
+// We pull out some of the functionality into non-templated functions, so we
+// can implement the more complicated pieces out of line in the .cc file.
+namespace internal {
+
+// Use LazyInstance<T>::Leaky for a less-verbose call-site typedef; e.g.:
+// base::LazyInstance<T>::Leaky my_leaky_lazy_instance;
+// instead of:
+// base::LazyInstance<T, base::internal::LeakyLazyInstanceTraits<T> >
+// my_leaky_lazy_instance;
+// (especially when T is MyLongTypeNameImplClientHolderFactory).
+// Only use this internal::-qualified verbose form to extend this traits class
+// (depending on its implementation details).
+template <typename Type>
+struct LeakyLazyInstanceTraits {
+  static const bool kRegisterOnExit = false;
+#ifndef NDEBUG
+  static const bool kAllowedToAccessOnNonjoinableThread = true;
+#endif
+
+  static Type* New(void* instance) {
+    ANNOTATE_SCOPED_MEMORY_LEAK;
+    return DefaultLazyInstanceTraits<Type>::New(instance);
+  }
+  static void Delete(Type* instance) {
+  }
+};
+
+// Our AtomicWord doubles as a spinlock, where a value of
+// kBeingCreatedMarker means the spinlock is being held for creation.
+static const subtle::AtomicWord kLazyInstanceStateCreating = 1;
+
+// Check if instance needs to be created. If so return true otherwise
+// if another thread has beat us, wait for instance to be created and
+// return false.
+BASE_EXPORT bool NeedsLazyInstance(subtle::AtomicWord* state);
+
+// After creating an instance, call this to register the dtor to be called
+// at program exit and to update the atomic state to hold the |new_instance|
+BASE_EXPORT void CompleteLazyInstance(subtle::AtomicWord* state,
+                                      subtle::AtomicWord new_instance,
+                                      void* lazy_instance,
+                                      void (*dtor)(void*));
+
+}  // namespace internal
+
+template <typename Type, typename Traits = DefaultLazyInstanceTraits<Type> >
+class LazyInstance {
+ public:
+  // Do not define a destructor, as doing so makes LazyInstance a
+  // non-POD-struct. We don't want that because then a static initializer will
+  // be created to register the (empty) destructor with atexit() under MSVC, for
+  // example. We handle destruction of the contained Type class explicitly via
+  // the OnExit member function, where needed.
+  // ~LazyInstance() {}
+
+  // Convenience typedef to avoid having to repeat Type for leaky lazy
+  // instances.
+  typedef LazyInstance<Type, internal::LeakyLazyInstanceTraits<Type> > Leaky;
+
+  Type& Get() {
+    return *Pointer();
+  }
+
+  Type* Pointer() {
+#ifndef NDEBUG
+    // Avoid making TLS lookup on release builds.
+    if (!Traits::kAllowedToAccessOnNonjoinableThread)
+      ThreadRestrictions::AssertSingletonAllowed();
+#endif
+    // If any bit in the created mask is true, the instance has already been
+    // fully constructed.
+    static const subtle::AtomicWord kLazyInstanceCreatedMask =
+        ~internal::kLazyInstanceStateCreating;
+
+    // We will hopefully have fast access when the instance is already created.
+    // Since a thread sees private_instance_ == 0 or kLazyInstanceStateCreating
+    // at most once, the load is taken out of NeedsInstance() as a fast-path.
+    // The load has acquire memory ordering as a thread which sees
+    // private_instance_ > creating needs to acquire visibility over
+    // the associated data (private_buf_). Pairing Release_Store is in
+    // CompleteLazyInstance().
+    subtle::AtomicWord value = subtle::Acquire_Load(&private_instance_);
+    if (!(value & kLazyInstanceCreatedMask) &&
+        internal::NeedsLazyInstance(&private_instance_)) {
+      // Create the instance in the space provided by |private_buf_|.
+      value = reinterpret_cast<subtle::AtomicWord>(
+          Traits::New(private_buf_.void_data()));
+      internal::CompleteLazyInstance(&private_instance_, value, this,
+                                     Traits::kRegisterOnExit ? OnExit : NULL);
+    }
+    return instance();
+  }
+
+  bool operator==(Type* p) {
+    switch (subtle::NoBarrier_Load(&private_instance_)) {
+      case 0:
+        return p == NULL;
+      case internal::kLazyInstanceStateCreating:
+        return static_cast<void*>(p) == private_buf_.void_data();
+      default:
+        return p == instance();
+    }
+  }
+
+  // Effectively private: member data is only public to allow the linker to
+  // statically initialize it and to maintain a POD class. DO NOT USE FROM
+  // OUTSIDE THIS CLASS.
+
+  subtle::AtomicWord private_instance_;
+  // Preallocated space for the Type instance.
+  base::AlignedMemory<sizeof(Type), ALIGNOF(Type)> private_buf_;
+
+ private:
+  Type* instance() {
+    return reinterpret_cast<Type*>(subtle::NoBarrier_Load(&private_instance_));
+  }
+
+  // Adapter function for use with AtExit.  This should be called single
+  // threaded, so don't synchronize across threads.
+  // Calling OnExit while the instance is in use by other threads is a mistake.
+  static void OnExit(void* lazy_instance) {
+    LazyInstance<Type, Traits>* me =
+        reinterpret_cast<LazyInstance<Type, Traits>*>(lazy_instance);
+    Traits::Delete(me->instance());
+    subtle::NoBarrier_Store(&me->private_instance_, 0);
+  }
+};
+
+}  // namespace base
+
+#endif  // BASE_LAZY_INSTANCE_H_
diff --git a/base/lazy_instance_unittest.cc b/base/lazy_instance_unittest.cc
new file mode 100644
index 0000000..ec9ef26
--- /dev/null
+++ b/base/lazy_instance_unittest.cc
@@ -0,0 +1,172 @@
+// Copyright (c) 2012 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/at_exit.h"
+#include "base/atomic_sequence_num.h"
+#include "base/lazy_instance.h"
+#include "base/memory/aligned_memory.h"
+#include "base/threading/simple_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+base::StaticAtomicSequenceNumber constructed_seq_;
+base::StaticAtomicSequenceNumber destructed_seq_;
+
+class ConstructAndDestructLogger {
+ public:
+  ConstructAndDestructLogger() {
+    constructed_seq_.GetNext();
+  }
+  ~ConstructAndDestructLogger() {
+    destructed_seq_.GetNext();
+  }
+};
+
+class SlowConstructor {
+ public:
+  SlowConstructor() : some_int_(0) {
+    // Sleep for 1 second to try to cause a race.
+    base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
+    ++constructed;
+    some_int_ = 12;
+  }
+  int some_int() const { return some_int_; }
+
+  static int constructed;
+ private:
+  int some_int_;
+};
+
+int SlowConstructor::constructed = 0;
+
+class SlowDelegate : public base::DelegateSimpleThread::Delegate {
+ public:
+  explicit SlowDelegate(base::LazyInstance<SlowConstructor>* lazy)
+      : lazy_(lazy) {}
+
+  void Run() override {
+    EXPECT_EQ(12, lazy_->Get().some_int());
+    EXPECT_EQ(12, lazy_->Pointer()->some_int());
+  }
+
+ private:
+  base::LazyInstance<SlowConstructor>* lazy_;
+};
+
+}  // namespace
+
+static base::LazyInstance<ConstructAndDestructLogger> lazy_logger =
+    LAZY_INSTANCE_INITIALIZER;
+
+TEST(LazyInstanceTest, Basic) {
+  {
+    base::ShadowingAtExitManager shadow;
+
+    EXPECT_EQ(0, constructed_seq_.GetNext());
+    EXPECT_EQ(0, destructed_seq_.GetNext());
+
+    lazy_logger.Get();
+    EXPECT_EQ(2, constructed_seq_.GetNext());
+    EXPECT_EQ(1, destructed_seq_.GetNext());
+
+    lazy_logger.Pointer();
+    EXPECT_EQ(3, constructed_seq_.GetNext());
+    EXPECT_EQ(2, destructed_seq_.GetNext());
+  }
+  EXPECT_EQ(4, constructed_seq_.GetNext());
+  EXPECT_EQ(4, destructed_seq_.GetNext());
+}
+
+static base::LazyInstance<SlowConstructor> lazy_slow =
+    LAZY_INSTANCE_INITIALIZER;
+
+TEST(LazyInstanceTest, ConstructorThreadSafety) {
+  {
+    base::ShadowingAtExitManager shadow;
+
+    SlowDelegate delegate(&lazy_slow);
+    EXPECT_EQ(0, SlowConstructor::constructed);
+
+    base::DelegateSimpleThreadPool pool("lazy_instance_cons", 5);
+    pool.AddWork(&delegate, 20);
+    EXPECT_EQ(0, SlowConstructor::constructed);
+
+    pool.Start();
+    pool.JoinAll();
+    EXPECT_EQ(1, SlowConstructor::constructed);
+  }
+}
+
+namespace {
+
+// DeleteLogger is an object which sets a flag when it's destroyed.
+// It accepts a bool* and sets the bool to true when the dtor runs.
+class DeleteLogger {
+ public:
+  DeleteLogger() : deleted_(NULL) {}
+  ~DeleteLogger() { *deleted_ = true; }
+
+  void SetDeletedPtr(bool* deleted) {
+    deleted_ = deleted;
+  }
+
+ private:
+  bool* deleted_;
+};
+
+}  // anonymous namespace
+
+TEST(LazyInstanceTest, LeakyLazyInstance) {
+  // Check that using a plain LazyInstance causes the dtor to run
+  // when the AtExitManager finishes.
+  bool deleted1 = false;
+  {
+    base::ShadowingAtExitManager shadow;
+    static base::LazyInstance<DeleteLogger> test = LAZY_INSTANCE_INITIALIZER;
+    test.Get().SetDeletedPtr(&deleted1);
+  }
+  EXPECT_TRUE(deleted1);
+
+  // Check that using a *leaky* LazyInstance makes the dtor not run
+  // when the AtExitManager finishes.
+  bool deleted2 = false;
+  {
+    base::ShadowingAtExitManager shadow;
+    static base::LazyInstance<DeleteLogger>::Leaky
+        test = LAZY_INSTANCE_INITIALIZER;
+    test.Get().SetDeletedPtr(&deleted2);
+  }
+  EXPECT_FALSE(deleted2);
+}
+
+namespace {
+
+template <size_t alignment>
+class AlignedData {
+ public:
+  AlignedData() {}
+  ~AlignedData() {}
+  base::AlignedMemory<alignment, alignment> data_;
+};
+
+}  // anonymous namespace
+
+#define EXPECT_ALIGNED(ptr, align) \
+    EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(ptr) & (align - 1))
+
+TEST(LazyInstanceTest, Alignment) {
+  using base::LazyInstance;
+
+  // Create some static instances with increasing sizes and alignment
+  // requirements. By ordering this way, the linker will need to do some work to
+  // ensure proper alignment of the static data.
+  static LazyInstance<AlignedData<4> > align4 = LAZY_INSTANCE_INITIALIZER;
+  static LazyInstance<AlignedData<32> > align32 = LAZY_INSTANCE_INITIALIZER;
+  static LazyInstance<AlignedData<4096> > align4096 = LAZY_INSTANCE_INITIALIZER;
+
+  EXPECT_ALIGNED(align4.Pointer(), 4);
+  EXPECT_ALIGNED(align32.Pointer(), 32);
+  EXPECT_ALIGNED(align4096.Pointer(), 4096);
+}
diff --git a/base/linux_util.cc b/base/linux_util.cc
new file mode 100644
index 0000000..d6cd504
--- /dev/null
+++ b/base/linux_util.cc
@@ -0,0 +1,179 @@
+// Copyright (c) 2012 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/linux_util.h"
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/files/file_util.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/singleton.h"
+#include "base/process/launch.h"
+#include "base/strings/string_util.h"
+#include "base/synchronization/lock.h"
+
+namespace {
+
+// Not needed for OS_CHROMEOS.
+#if defined(OS_LINUX)
+enum LinuxDistroState {
+  STATE_DID_NOT_CHECK  = 0,
+  STATE_CHECK_STARTED  = 1,
+  STATE_CHECK_FINISHED = 2,
+};
+
+// Helper class for GetLinuxDistro().
+class LinuxDistroHelper {
+ public:
+  // Retrieves the Singleton.
+  static LinuxDistroHelper* GetInstance() {
+    return Singleton<LinuxDistroHelper>::get();
+  }
+
+  // The simple state machine goes from:
+  // STATE_DID_NOT_CHECK -> STATE_CHECK_STARTED -> STATE_CHECK_FINISHED.
+  LinuxDistroHelper() : state_(STATE_DID_NOT_CHECK) {}
+  ~LinuxDistroHelper() {}
+
+  // Retrieve the current state, if we're in STATE_DID_NOT_CHECK,
+  // we automatically move to STATE_CHECK_STARTED so nobody else will
+  // do the check.
+  LinuxDistroState State() {
+    base::AutoLock scoped_lock(lock_);
+    if (STATE_DID_NOT_CHECK == state_) {
+      state_ = STATE_CHECK_STARTED;
+      return STATE_DID_NOT_CHECK;
+    }
+    return state_;
+  }
+
+  // Indicate the check finished, move to STATE_CHECK_FINISHED.
+  void CheckFinished() {
+    base::AutoLock scoped_lock(lock_);
+    DCHECK_EQ(STATE_CHECK_STARTED, state_);
+    state_ = STATE_CHECK_FINISHED;
+  }
+
+ private:
+  base::Lock lock_;
+  LinuxDistroState state_;
+};
+#endif  // if defined(OS_LINUX)
+
+}  // namespace
+
+namespace base {
+
+// Account for the terminating null character.
+static const int kDistroSize = 128 + 1;
+
+// We use this static string to hold the Linux distro info. If we
+// crash, the crash handler code will send this in the crash dump.
+char g_linux_distro[kDistroSize] =
+#if defined(OS_CHROMEOS)
+    "CrOS";
+#elif defined(OS_ANDROID)
+    "Android";
+#else  // if defined(OS_LINUX)
+    "Unknown";
+#endif
+
+std::string GetLinuxDistro() {
+#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
+  return g_linux_distro;
+#elif defined(OS_LINUX)
+  LinuxDistroHelper* distro_state_singleton = LinuxDistroHelper::GetInstance();
+  LinuxDistroState state = distro_state_singleton->State();
+  if (STATE_CHECK_FINISHED == state)
+    return g_linux_distro;
+  if (STATE_CHECK_STARTED == state)
+    return "Unknown"; // Don't wait for other thread to finish.
+  DCHECK_EQ(state, STATE_DID_NOT_CHECK);
+  // We do this check only once per process. If it fails, there's
+  // little reason to believe it will work if we attempt to run
+  // lsb_release again.
+  std::vector<std::string> argv;
+  argv.push_back("lsb_release");
+  argv.push_back("-d");
+  std::string output;
+  base::GetAppOutput(CommandLine(argv), &output);
+  if (output.length() > 0) {
+    // lsb_release -d should return: Description:<tab>Distro Info
+    const char field[] = "Description:\t";
+    if (output.compare(0, strlen(field), field) == 0) {
+      SetLinuxDistro(output.substr(strlen(field)));
+    }
+  }
+  distro_state_singleton->CheckFinished();
+  return g_linux_distro;
+#else
+  NOTIMPLEMENTED();
+  return "Unknown";
+#endif
+}
+
+void SetLinuxDistro(const std::string& distro) {
+  std::string trimmed_distro;
+  base::TrimWhitespaceASCII(distro, base::TRIM_ALL, &trimmed_distro);
+  base::strlcpy(g_linux_distro, trimmed_distro.c_str(), kDistroSize);
+}
+
+pid_t FindThreadIDWithSyscall(pid_t pid, const std::string& expected_data,
+                              bool* syscall_supported) {
+  char buf[256];
+  snprintf(buf, sizeof(buf), "/proc/%d/task", pid);
+
+  if (syscall_supported != NULL)
+    *syscall_supported = false;
+
+  DIR* task = opendir(buf);
+  if (!task) {
+    DLOG(WARNING) << "Cannot open " << buf;
+    return -1;
+  }
+
+  std::vector<pid_t> tids;
+  struct dirent* dent;
+  while ((dent = readdir(task))) {
+    char* endptr;
+    const unsigned long int tid_ul = strtoul(dent->d_name, &endptr, 10);
+    if (tid_ul == ULONG_MAX || *endptr)
+      continue;
+    tids.push_back(tid_ul);
+  }
+  closedir(task);
+
+  scoped_ptr<char[]> syscall_data(new char[expected_data.length()]);
+  for (std::vector<pid_t>::const_iterator
+       i = tids.begin(); i != tids.end(); ++i) {
+    const pid_t current_tid = *i;
+    snprintf(buf, sizeof(buf), "/proc/%d/task/%d/syscall", pid, current_tid);
+    int fd = open(buf, O_RDONLY);
+    if (fd < 0)
+      continue;
+    if (syscall_supported != NULL)
+      *syscall_supported = true;
+    bool read_ret = ReadFromFD(fd, syscall_data.get(), expected_data.length());
+    close(fd);
+    if (!read_ret)
+      continue;
+
+    if (0 == strncmp(expected_data.c_str(), syscall_data.get(),
+                     expected_data.length())) {
+      return current_tid;
+    }
+  }
+  return -1;
+}
+
+}  // namespace base
diff --git a/base/linux_util.h b/base/linux_util.h
new file mode 100644
index 0000000..83523df
--- /dev/null
+++ b/base/linux_util.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2012 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_LINUX_UTIL_H_
+#define BASE_LINUX_UTIL_H_
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <string>
+
+#include "base/base_export.h"
+
+namespace base {
+
+// This is declared here so the crash reporter can access the memory directly
+// in compromised context without going through the standard library.
+BASE_EXPORT extern char g_linux_distro[];
+
+// Get the Linux Distro if we can, or return "Unknown".
+BASE_EXPORT std::string GetLinuxDistro();
+
+// Set the Linux Distro string.
+BASE_EXPORT void SetLinuxDistro(const std::string& distro);
+
+// For a given process |pid|, look through all its threads and find the first
+// thread with /proc/[pid]/task/[thread_id]/syscall whose first N bytes matches
+// |expected_data|, where N is the length of |expected_data|.
+// Returns the thread id or -1 on error.  If |syscall_supported| is
+// set to false the kernel does not support syscall in procfs.
+BASE_EXPORT pid_t FindThreadIDWithSyscall(pid_t pid,
+                                          const std::string& expected_data,
+                                          bool* syscall_supported);
+
+}  // namespace base
+
+#endif  // BASE_LINUX_UTIL_H_
diff --git a/base/location.cc b/base/location.cc
new file mode 100644
index 0000000..1333e6e
--- /dev/null
+++ b/base/location.cc
@@ -0,0 +1,106 @@
+// Copyright (c) 2012 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 "build/build_config.h"
+
+#if defined(COMPILER_MSVC)
+#include <intrin.h>
+#endif
+
+#include "base/location.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+
+namespace tracked_objects {
+
+Location::Location(const char* function_name,
+                   const char* file_name,
+                   int line_number,
+                   const void* program_counter)
+    : function_name_(function_name),
+      file_name_(file_name),
+      line_number_(line_number),
+      program_counter_(program_counter) {
+}
+
+Location::Location()
+    : function_name_("Unknown"),
+      file_name_("Unknown"),
+      line_number_(-1),
+      program_counter_(NULL) {
+}
+
+Location::Location(const Location& other)
+    : function_name_(other.function_name_),
+      file_name_(other.file_name_),
+      line_number_(other.line_number_),
+      program_counter_(other.program_counter_) {
+}
+
+std::string Location::ToString() const {
+  return std::string(function_name_) + "@" + file_name_ + ":" +
+      base::IntToString(line_number_);
+}
+
+void Location::Write(bool display_filename, bool display_function_name,
+                     std::string* output) const {
+  base::StringAppendF(output, "%s[%d] ",
+      display_filename ? file_name_ : "line",
+      line_number_);
+
+  if (display_function_name) {
+    WriteFunctionName(output);
+    output->push_back(' ');
+  }
+}
+
+void Location::WriteFunctionName(std::string* output) const {
+  // Translate "<" to "&lt;" for HTML safety.
+  // TODO(jar): Support ASCII or html for logging in ASCII.
+  for (const char *p = function_name_; *p; p++) {
+    switch (*p) {
+      case '<':
+        output->append("&lt;");
+        break;
+
+      case '>':
+        output->append("&gt;");
+        break;
+
+      default:
+        output->push_back(*p);
+        break;
+    }
+  }
+}
+
+//------------------------------------------------------------------------------
+LocationSnapshot::LocationSnapshot() : line_number(-1) {
+}
+
+LocationSnapshot::LocationSnapshot(
+    const tracked_objects::Location& location)
+    : file_name(location.file_name()),
+      function_name(location.function_name()),
+      line_number(location.line_number()) {
+}
+
+LocationSnapshot::~LocationSnapshot() {
+}
+
+//------------------------------------------------------------------------------
+#if defined(COMPILER_MSVC)
+__declspec(noinline)
+#endif
+BASE_EXPORT const void* GetProgramCounter() {
+#if defined(COMPILER_MSVC)
+  return _ReturnAddress();
+#elif defined(COMPILER_GCC) && !defined(OS_NACL)
+  return __builtin_extract_return_addr(__builtin_return_address(0));
+#else
+  return NULL;
+#endif
+}
+
+}  // namespace tracked_objects
diff --git a/base/location.h b/base/location.h
new file mode 100644
index 0000000..477dc02
--- /dev/null
+++ b/base/location.h
@@ -0,0 +1,113 @@
+// Copyright (c) 2012 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_LOCATION_H_
+#define BASE_LOCATION_H_
+
+#include <cassert>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/containers/hash_tables.h"
+
+namespace tracked_objects {
+
+// Location provides basic info where of an object was constructed, or was
+// significantly brought to life.
+class BASE_EXPORT Location {
+ public:
+  // Constructor should be called with a long-lived char*, such as __FILE__.
+  // It assumes the provided value will persist as a global constant, and it
+  // will not make a copy of it.
+  Location(const char* function_name,
+           const char* file_name,
+           int line_number,
+           const void* program_counter);
+
+  // Provide a default constructor for easy of debugging.
+  Location();
+
+  // Copy constructor.
+  Location(const Location& other);
+
+  // Comparator for hash map insertion.
+  // No need to use |function_name_| since the other two fields uniquely
+  // identify this location.
+  bool operator==(const Location& other) const {
+    return line_number_ == other.line_number_ &&
+           file_name_ == other.file_name_;
+  }
+
+  const char* function_name()   const { return function_name_; }
+  const char* file_name()       const { return file_name_; }
+  int line_number()             const { return line_number_; }
+  const void* program_counter() const { return program_counter_; }
+
+  std::string ToString() const;
+
+  // Hash operator for hash maps.
+  struct Hash {
+    size_t operator()(const Location& location) const {
+      // Compute the hash value using file name pointer and line number.
+      // No need to use |function_name_| since the other two fields uniquely
+      // identify this location.
+
+      // The file name will always be uniquely identified by its pointer since
+      // it comes from __FILE__, so no need to check the contents of the string.
+      // See the definition of FROM_HERE in location.h, and how it is used
+      // elsewhere.
+
+      // Due to inconsistent definitions of uint64_t and uintptr_t, casting the
+      // file name pointer to a uintptr_t causes a compiler error for some
+      // platforms. The solution is to explicitly cast it to a uint64_t.
+      return base::HashPair(reinterpret_cast<uint64_t>(location.file_name()),
+                            location.line_number());
+    }
+  };
+
+  // Translate the some of the state in this instance into a human readable
+  // string with HTML characters in the function names escaped, and append that
+  // string to |output|.  Inclusion of the file_name_ and function_name_ are
+  // optional, and controlled by the boolean arguments.
+  void Write(bool display_filename, bool display_function_name,
+             std::string* output) const;
+
+  // Write function_name_ in HTML with '<' and '>' properly encoded.
+  void WriteFunctionName(std::string* output) const;
+
+ private:
+  const char* function_name_;
+  const char* file_name_;
+  int line_number_;
+  const void* program_counter_;
+};
+
+// A "snapshotted" representation of the Location class that can safely be
+// passed across process boundaries.
+struct BASE_EXPORT LocationSnapshot {
+  // The default constructor is exposed to support the IPC serialization macros.
+  LocationSnapshot();
+  explicit LocationSnapshot(const tracked_objects::Location& location);
+  ~LocationSnapshot();
+
+  std::string file_name;
+  std::string function_name;
+  int line_number;
+};
+
+BASE_EXPORT const void* GetProgramCounter();
+
+// Define a macro to record the current source location.
+#define FROM_HERE FROM_HERE_WITH_EXPLICIT_FUNCTION(__FUNCTION__)
+
+#define FROM_HERE_WITH_EXPLICIT_FUNCTION(function_name)                        \
+    ::tracked_objects::Location(function_name,                                 \
+                                __FILE__,                                      \
+                                __LINE__,                                      \
+                                ::tracked_objects::GetProgramCounter())
+
+}  // namespace tracked_objects
+
+#endif  // BASE_LOCATION_H_
diff --git a/base/logging.cc b/base/logging.cc
new file mode 100644
index 0000000..71528ad
--- /dev/null
+++ b/base/logging.cc
@@ -0,0 +1,815 @@
+// Copyright (c) 2012 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/logging.h"
+
+#if defined(OS_WIN)
+#include <io.h>
+#include <windows.h>
+typedef HANDLE FileHandle;
+typedef HANDLE MutexHandle;
+// Windows warns on using write().  It prefers _write().
+#define write(fd, buf, count) _write(fd, buf, static_cast<unsigned int>(count))
+// Windows doesn't define STDERR_FILENO.  Define it here.
+#define STDERR_FILENO 2
+#elif defined(OS_MACOSX)
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+#include <mach-o/dyld.h>
+#elif defined(OS_POSIX)
+#if defined(OS_NACL)
+#include <sys/time.h>  // timespec doesn't seem to be in <time.h>
+#else
+#include <sys/syscall.h>
+#endif
+#include <time.h>
+#endif
+
+#if defined(OS_POSIX)
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#define MAX_PATH PATH_MAX
+typedef FILE* FileHandle;
+typedef pthread_mutex_t* MutexHandle;
+#endif
+
+#include <algorithm>
+#include <cstring>
+#include <ctime>
+#include <iomanip>
+#include <ostream>
+#include <string>
+
+#include "base/base_switches.h"
+#include "base/command_line.h"
+#include "base/debug/alias.h"
+#include "base/debug/debugger.h"
+#include "base/debug/stack_trace.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/synchronization/lock_impl.h"
+#include "base/threading/platform_thread.h"
+#include "base/vlog.h"
+#if defined(OS_POSIX)
+#include "base/posix/safe_strerror.h"
+#endif
+
+#if defined(OS_ANDROID)
+#include <android/log.h>
+#endif
+
+namespace logging {
+
+namespace {
+
+VlogInfo* g_vlog_info = nullptr;
+VlogInfo* g_vlog_info_prev = nullptr;
+
+const char* const log_severity_names[LOG_NUM_SEVERITIES] = {
+  "INFO", "WARNING", "ERROR", "FATAL" };
+
+const char* log_severity_name(int severity) {
+  if (severity >= 0 && severity < LOG_NUM_SEVERITIES)
+    return log_severity_names[severity];
+  return "UNKNOWN";
+}
+
+int g_min_log_level = 0;
+
+LoggingDestination g_logging_destination = LOG_DEFAULT;
+
+// For LOG_ERROR and above, always print to stderr.
+const int kAlwaysPrintErrorLevel = LOG_ERROR;
+
+// Which log file to use? This is initialized by InitLogging or
+// will be lazily initialized to the default value when it is
+// first needed.
+#if defined(OS_WIN)
+typedef std::wstring PathString;
+#else
+typedef std::string PathString;
+#endif
+PathString* g_log_file_name = nullptr;
+
+// This file is lazily opened and the handle may be nullptr
+FileHandle g_log_file = nullptr;
+
+// What should be prepended to each message?
+bool g_log_process_id = false;
+bool g_log_thread_id = false;
+bool g_log_timestamp = true;
+bool g_log_tickcount = false;
+
+// Should we pop up fatal debug messages in a dialog?
+bool show_error_dialogs = false;
+
+// An assert handler override specified by the client to be called instead of
+// the debug message dialog and process termination.
+LogAssertHandlerFunction log_assert_handler = nullptr;
+// A log message handler that gets notified of every log message we process.
+LogMessageHandlerFunction log_message_handler = nullptr;
+
+// Helper functions to wrap platform differences.
+
+int32 CurrentProcessId() {
+#if defined(OS_WIN)
+  return GetCurrentProcessId();
+#elif defined(OS_POSIX)
+  return getpid();
+#endif
+}
+
+uint64 TickCount() {
+#if defined(OS_WIN)
+  return GetTickCount();
+#elif defined(OS_MACOSX)
+  return mach_absolute_time();
+#elif defined(OS_NACL)
+  // NaCl sadly does not have _POSIX_TIMERS enabled in sys/features.h
+  // So we have to use clock() for now.
+  return clock();
+#elif defined(OS_POSIX)
+  struct timespec ts;
+  clock_gettime(CLOCK_MONOTONIC, &ts);
+
+  uint64 absolute_micro =
+    static_cast<int64>(ts.tv_sec) * 1000000 +
+    static_cast<int64>(ts.tv_nsec) / 1000;
+
+  return absolute_micro;
+#endif
+}
+
+void DeleteFilePath(const PathString& log_name) {
+#if defined(OS_WIN)
+  DeleteFile(log_name.c_str());
+#elif defined(OS_NACL)
+  // Do nothing; unlink() isn't supported on NaCl.
+#else
+  unlink(log_name.c_str());
+#endif
+}
+
+PathString GetDefaultLogFile() {
+#if defined(OS_WIN)
+  // On Windows we use the same path as the exe.
+  wchar_t module_name[MAX_PATH];
+  GetModuleFileName(nullptr, module_name, MAX_PATH);
+
+  PathString log_name = module_name;
+  PathString::size_type last_backslash = log_name.rfind('\\', log_name.size());
+  if (last_backslash != PathString::npos)
+    log_name.erase(last_backslash + 1);
+  log_name += L"debug.log";
+  return log_name;
+#elif defined(OS_POSIX)
+  // On other platforms we just use the current directory.
+  return PathString("debug.log");
+#endif
+}
+
+// This class acts as a wrapper for locking the logging files.
+// LoggingLock::Init() should be called from the main thread before any logging
+// is done. Then whenever logging, be sure to have a local LoggingLock
+// instance on the stack. This will ensure that the lock is unlocked upon
+// exiting the frame.
+// LoggingLocks can not be nested.
+class LoggingLock {
+ public:
+  LoggingLock() {
+    LockLogging();
+  }
+
+  ~LoggingLock() {
+    UnlockLogging();
+  }
+
+  static void Init(LogLockingState lock_log, const PathChar* new_log_file) {
+    if (initialized)
+      return;
+    lock_log_file = lock_log;
+    if (lock_log_file == LOCK_LOG_FILE) {
+#if defined(OS_WIN)
+      if (!log_mutex) {
+        std::wstring safe_name;
+        if (new_log_file)
+          safe_name = new_log_file;
+        else
+          safe_name = GetDefaultLogFile();
+        // \ is not a legal character in mutex names so we replace \ with /
+        std::replace(safe_name.begin(), safe_name.end(), '\\', '/');
+        std::wstring t(L"Global\\");
+        t.append(safe_name);
+        log_mutex = ::CreateMutex(nullptr, FALSE, t.c_str());
+
+        if (log_mutex == nullptr) {
+#if DEBUG
+          // Keep the error code for debugging
+          int error = GetLastError();  // NOLINT
+          base::debug::BreakDebugger();
+#endif
+          // Return nicely without putting initialized to true.
+          return;
+        }
+      }
+#endif
+    } else {
+      log_lock = new base::internal::LockImpl();
+    }
+    initialized = true;
+  }
+
+ private:
+  static void LockLogging() {
+    if (lock_log_file == LOCK_LOG_FILE) {
+#if defined(OS_WIN)
+      ::WaitForSingleObject(log_mutex, INFINITE);
+      // WaitForSingleObject could have returned WAIT_ABANDONED. We don't
+      // abort the process here. UI tests might be crashy sometimes,
+      // and aborting the test binary only makes the problem worse.
+      // We also don't use LOG macros because that might lead to an infinite
+      // loop. For more info see http://crbug.com/18028.
+#elif defined(OS_POSIX)
+      pthread_mutex_lock(&log_mutex);
+#endif
+    } else {
+      // use the lock
+      log_lock->Lock();
+    }
+  }
+
+  static void UnlockLogging() {
+    if (lock_log_file == LOCK_LOG_FILE) {
+#if defined(OS_WIN)
+      ReleaseMutex(log_mutex);
+#elif defined(OS_POSIX)
+      pthread_mutex_unlock(&log_mutex);
+#endif
+    } else {
+      log_lock->Unlock();
+    }
+  }
+
+  // The lock is used if log file locking is false. It helps us avoid problems
+  // with multiple threads writing to the log file at the same time.  Use
+  // LockImpl directly instead of using Lock, because Lock makes logging calls.
+  static base::internal::LockImpl* log_lock;
+
+  // When we don't use a lock, we are using a global mutex. We need to do this
+  // because LockFileEx is not thread safe.
+#if defined(OS_WIN)
+  static MutexHandle log_mutex;
+#elif defined(OS_POSIX)
+  static pthread_mutex_t log_mutex;
+#endif
+
+  static bool initialized;
+  static LogLockingState lock_log_file;
+};
+
+// static
+bool LoggingLock::initialized = false;
+// static
+base::internal::LockImpl* LoggingLock::log_lock = nullptr;
+// static
+LogLockingState LoggingLock::lock_log_file = LOCK_LOG_FILE;
+
+#if defined(OS_WIN)
+// static
+MutexHandle LoggingLock::log_mutex = nullptr;
+#elif defined(OS_POSIX)
+pthread_mutex_t LoggingLock::log_mutex = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
+// Called by logging functions to ensure that |g_log_file| is initialized
+// and can be used for writing. Returns false if the file could not be
+// initialized. |g_log_file| will be nullptr in this case.
+bool InitializeLogFileHandle() {
+  if (g_log_file)
+    return true;
+
+  if (!g_log_file_name) {
+    // Nobody has called InitLogging to specify a debug log file, so here we
+    // initialize the log file name to a default.
+    g_log_file_name = new PathString(GetDefaultLogFile());
+  }
+
+  if ((g_logging_destination & LOG_TO_FILE) != 0) {
+#if defined(OS_WIN)
+    g_log_file = CreateFile(g_log_file_name->c_str(), GENERIC_WRITE,
+                            FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
+                            OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
+    if (g_log_file == INVALID_HANDLE_VALUE || g_log_file == nullptr) {
+      // try the current directory
+      g_log_file = CreateFile(L".\\debug.log", GENERIC_WRITE,
+                              FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
+                              OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
+      if (g_log_file == INVALID_HANDLE_VALUE || g_log_file == nullptr) {
+        g_log_file = nullptr;
+        return false;
+      }
+    }
+    SetFilePointer(g_log_file, 0, 0, FILE_END);
+#elif defined(OS_POSIX)
+    g_log_file = fopen(g_log_file_name->c_str(), "a");
+    if (g_log_file == nullptr)
+      return false;
+#endif
+  }
+
+  return true;
+}
+
+void CloseFile(FileHandle log) {
+#if defined(OS_WIN)
+  CloseHandle(log);
+#else
+  fclose(log);
+#endif
+}
+
+void CloseLogFileUnlocked() {
+  if (!g_log_file)
+    return;
+
+  CloseFile(g_log_file);
+  g_log_file = nullptr;
+}
+
+}  // namespace
+
+LoggingSettings::LoggingSettings()
+    : logging_dest(LOG_DEFAULT),
+      log_file(nullptr),
+      lock_log(LOCK_LOG_FILE),
+      delete_old(APPEND_TO_OLD_LOG_FILE) {}
+
+bool BaseInitLoggingImpl(const LoggingSettings& settings) {
+#if defined(OS_NACL)
+  // Can log only to the system debug log.
+  CHECK_EQ(settings.logging_dest & ~LOG_TO_SYSTEM_DEBUG_LOG, 0);
+#endif
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  // Don't bother initializing |g_vlog_info| unless we use one of the
+  // vlog switches.
+  if (command_line->HasSwitch(switches::kV) ||
+      command_line->HasSwitch(switches::kVModule)) {
+    // NOTE: If |g_vlog_info| has already been initialized, it might be in use
+    // by another thread. Don't delete the old VLogInfo, just create a second
+    // one. We keep track of both to avoid memory leak warnings.
+    CHECK(!g_vlog_info_prev);
+    g_vlog_info_prev = g_vlog_info;
+
+    g_vlog_info =
+        new VlogInfo(command_line->GetSwitchValueASCII(switches::kV),
+                     command_line->GetSwitchValueASCII(switches::kVModule),
+                     &g_min_log_level);
+  }
+
+  g_logging_destination = settings.logging_dest;
+
+  // ignore file options unless logging to file is set.
+  if ((g_logging_destination & LOG_TO_FILE) == 0)
+    return true;
+
+  LoggingLock::Init(settings.lock_log, settings.log_file);
+  LoggingLock logging_lock;
+
+  // Calling InitLogging twice or after some log call has already opened the
+  // default log file will re-initialize to the new options.
+  CloseLogFileUnlocked();
+
+  if (!g_log_file_name)
+    g_log_file_name = new PathString();
+  *g_log_file_name = settings.log_file;
+  if (settings.delete_old == DELETE_OLD_LOG_FILE)
+    DeleteFilePath(*g_log_file_name);
+
+  return InitializeLogFileHandle();
+}
+
+void SetMinLogLevel(int level) {
+  g_min_log_level = std::min(LOG_FATAL, level);
+}
+
+int GetMinLogLevel() {
+  return g_min_log_level;
+}
+
+int GetVlogVerbosity() {
+  return std::max(-1, LOG_INFO - GetMinLogLevel());
+}
+
+int GetVlogLevelHelper(const char* file, size_t N) {
+  DCHECK_GT(N, 0U);
+  // Note: |g_vlog_info| may change on a different thread during startup
+  // (but will always be valid or nullptr).
+  VlogInfo* vlog_info = g_vlog_info;
+  return vlog_info ?
+      vlog_info->GetVlogLevel(base::StringPiece(file, N - 1)) :
+      GetVlogVerbosity();
+}
+
+void SetLogItems(bool enable_process_id, bool enable_thread_id,
+                 bool enable_timestamp, bool enable_tickcount) {
+  g_log_process_id = enable_process_id;
+  g_log_thread_id = enable_thread_id;
+  g_log_timestamp = enable_timestamp;
+  g_log_tickcount = enable_tickcount;
+}
+
+void SetShowErrorDialogs(bool enable_dialogs) {
+  show_error_dialogs = enable_dialogs;
+}
+
+void SetLogAssertHandler(LogAssertHandlerFunction handler) {
+  log_assert_handler = handler;
+}
+
+void SetLogMessageHandler(LogMessageHandlerFunction handler) {
+  log_message_handler = handler;
+}
+
+LogMessageHandlerFunction GetLogMessageHandler() {
+  return log_message_handler;
+}
+
+// Explicit instantiations for commonly used comparisons.
+template std::string* MakeCheckOpString<int, int>(
+    const int&, const int&, const char* names);
+template std::string* MakeCheckOpString<unsigned long, unsigned long>(
+    const unsigned long&, const unsigned long&, const char* names);
+template std::string* MakeCheckOpString<unsigned long, unsigned int>(
+    const unsigned long&, const unsigned int&, const char* names);
+template std::string* MakeCheckOpString<unsigned int, unsigned long>(
+    const unsigned int&, const unsigned long&, const char* names);
+template std::string* MakeCheckOpString<std::string, std::string>(
+    const std::string&, const std::string&, const char* name);
+
+#if !defined(NDEBUG)
+// Displays a message box to the user with the error message in it.
+// Used for fatal messages, where we close the app simultaneously.
+// This is for developers only; we don't use this in circumstances
+// (like release builds) where users could see it, since users don't
+// understand these messages anyway.
+void DisplayDebugMessageInDialog(const std::string& str) {
+  if (str.empty())
+    return;
+
+  if (!show_error_dialogs)
+    return;
+
+#if defined(OS_WIN)
+  // For Windows programs, it's possible that the message loop is
+  // messed up on a fatal error, and creating a MessageBox will cause
+  // that message loop to be run. Instead, we try to spawn another
+  // process that displays its command line. We look for "Debug
+  // Message.exe" in the same directory as the application. If it
+  // exists, we use it, otherwise, we use a regular message box.
+  wchar_t prog_name[MAX_PATH];
+  GetModuleFileNameW(nullptr, prog_name, MAX_PATH);
+  wchar_t* backslash = wcsrchr(prog_name, '\\');
+  if (backslash)
+    backslash[1] = 0;
+  wcscat_s(prog_name, MAX_PATH, L"debug_message.exe");
+
+  std::wstring cmdline = base::UTF8ToWide(str);
+  if (cmdline.empty())
+    return;
+
+  STARTUPINFO startup_info;
+  memset(&startup_info, 0, sizeof(startup_info));
+  startup_info.cb = sizeof(startup_info);
+
+  PROCESS_INFORMATION process_info;
+  if (CreateProcessW(prog_name, &cmdline[0], nullptr, nullptr, false, 0,
+                     nullptr, nullptr, &startup_info, &process_info)) {
+    WaitForSingleObject(process_info.hProcess, INFINITE);
+    CloseHandle(process_info.hThread);
+    CloseHandle(process_info.hProcess);
+  } else {
+    // debug process broken, let's just do a message box
+    MessageBoxW(nullptr, &cmdline[0], L"Fatal error",
+                MB_OK | MB_ICONHAND | MB_TOPMOST);
+  }
+#else
+  // We intentionally don't implement a dialog on other platforms.
+  // You can just look at stderr.
+#endif  // defined(OS_WIN)
+}
+#endif  // !defined(NDEBUG)
+
+#if defined(OS_WIN)
+LogMessage::SaveLastError::SaveLastError() : last_error_(::GetLastError()) {
+}
+
+LogMessage::SaveLastError::~SaveLastError() {
+  ::SetLastError(last_error_);
+}
+#endif  // defined(OS_WIN)
+
+LogMessage::LogMessage(const char* file, int line, LogSeverity severity)
+    : severity_(severity), file_(file), line_(line) {
+  Init(file, line);
+}
+
+LogMessage::LogMessage(const char* file, int line, std::string* result)
+    : severity_(LOG_FATAL), file_(file), line_(line) {
+  Init(file, line);
+  stream_ << "Check failed: " << *result;
+  delete result;
+}
+
+LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
+                       std::string* result)
+    : severity_(severity), file_(file), line_(line) {
+  Init(file, line);
+  stream_ << "Check failed: " << *result;
+  delete result;
+}
+
+LogMessage::~LogMessage() {
+#if !defined(NDEBUG) && !defined(OS_NACL) && !defined(__UCLIBC__)
+  if (severity_ == LOG_FATAL) {
+    // Include a stack trace on a fatal.
+    base::debug::StackTrace trace;
+    stream_ << std::endl;  // Newline to separate from log message.
+    trace.OutputToStream(&stream_);
+  }
+#endif
+  stream_ << std::endl;
+  std::string str_newline(stream_.str());
+
+  // Give any log message handler first dibs on the message.
+  if (log_message_handler &&
+      log_message_handler(severity_, file_, line_,
+                          message_start_, str_newline)) {
+    // The handler took care of it, no further processing.
+    return;
+  }
+
+  if ((g_logging_destination & LOG_TO_SYSTEM_DEBUG_LOG) != 0) {
+#if defined(OS_WIN)
+    OutputDebugStringA(str_newline.c_str());
+#elif defined(OS_ANDROID)
+    android_LogPriority priority =
+        (severity_ < 0) ? ANDROID_LOG_VERBOSE : ANDROID_LOG_UNKNOWN;
+    switch (severity_) {
+      case LOG_INFO:
+        priority = ANDROID_LOG_INFO;
+        break;
+      case LOG_WARNING:
+        priority = ANDROID_LOG_WARN;
+        break;
+      case LOG_ERROR:
+        priority = ANDROID_LOG_ERROR;
+        break;
+      case LOG_FATAL:
+        priority = ANDROID_LOG_FATAL;
+        break;
+    }
+    __android_log_write(priority, "chromium", str_newline.c_str());
+#endif
+    ignore_result(fwrite(str_newline.data(), str_newline.size(), 1, stderr));
+    fflush(stderr);
+  } else if (severity_ >= kAlwaysPrintErrorLevel) {
+    // When we're only outputting to a log file, above a certain log level, we
+    // should still output to stderr so that we can better detect and diagnose
+    // problems with unit tests, especially on the buildbots.
+    ignore_result(fwrite(str_newline.data(), str_newline.size(), 1, stderr));
+    fflush(stderr);
+  }
+
+  // write to log file
+  if ((g_logging_destination & LOG_TO_FILE) != 0) {
+    // We can have multiple threads and/or processes, so try to prevent them
+    // from clobbering each other's writes.
+    // If the client app did not call InitLogging, and the lock has not
+    // been created do it now. We do this on demand, but if two threads try
+    // to do this at the same time, there will be a race condition to create
+    // the lock. This is why InitLogging should be called from the main
+    // thread at the beginning of execution.
+    LoggingLock::Init(LOCK_LOG_FILE, nullptr);
+    LoggingLock logging_lock;
+    if (InitializeLogFileHandle()) {
+#if defined(OS_WIN)
+      SetFilePointer(g_log_file, 0, 0, SEEK_END);
+      DWORD num_written;
+      WriteFile(g_log_file,
+                static_cast<const void*>(str_newline.c_str()),
+                static_cast<DWORD>(str_newline.length()),
+                &num_written,
+                nullptr);
+#else
+      ignore_result(fwrite(
+          str_newline.data(), str_newline.size(), 1, g_log_file));
+      fflush(g_log_file);
+#endif
+    }
+  }
+
+  if (severity_ == LOG_FATAL) {
+    // Ensure the first characters of the string are on the stack so they
+    // are contained in minidumps for diagnostic purposes.
+    char str_stack[1024];
+    str_newline.copy(str_stack, arraysize(str_stack));
+    base::debug::Alias(str_stack);
+
+    if (log_assert_handler) {
+      // Make a copy of the string for the handler out of paranoia.
+      log_assert_handler(std::string(stream_.str()));
+    } else {
+      // Don't use the string with the newline, get a fresh version to send to
+      // the debug message process. We also don't display assertions to the
+      // user in release mode. The enduser can't do anything with this
+      // information, and displaying message boxes when the application is
+      // hosed can cause additional problems.
+#ifndef NDEBUG
+      DisplayDebugMessageInDialog(stream_.str());
+#endif
+      // Crash the process to generate a dump.
+      base::debug::BreakDebugger();
+    }
+  }
+}
+
+// writes the common header info to the stream
+void LogMessage::Init(const char* file, int line) {
+  base::StringPiece filename(file);
+  size_t last_slash_pos = filename.find_last_of("\\/");
+  if (last_slash_pos != base::StringPiece::npos)
+    filename.remove_prefix(last_slash_pos + 1);
+
+  // TODO(darin): It might be nice if the columns were fixed width.
+
+  stream_ <<  '[';
+  if (g_log_process_id)
+    stream_ << CurrentProcessId() << ':';
+  if (g_log_thread_id)
+    stream_ << base::PlatformThread::CurrentId() << ':';
+  if (g_log_timestamp) {
+    time_t t = time(nullptr);
+    struct tm local_time = {0};
+#ifdef _MSC_VER
+    localtime_s(&local_time, &t);
+#else
+    localtime_r(&t, &local_time);
+#endif
+    struct tm* tm_time = &local_time;
+    stream_ << std::setfill('0')
+            << std::setw(2) << 1 + tm_time->tm_mon
+            << std::setw(2) << tm_time->tm_mday
+            << '/'
+            << std::setw(2) << tm_time->tm_hour
+            << std::setw(2) << tm_time->tm_min
+            << std::setw(2) << tm_time->tm_sec
+            << ':';
+  }
+  if (g_log_tickcount)
+    stream_ << TickCount() << ':';
+  if (severity_ >= 0)
+    stream_ << log_severity_name(severity_);
+  else
+    stream_ << "VERBOSE" << -severity_;
+
+  stream_ << ":" << filename << "(" << line << ")] ";
+
+  message_start_ = stream_.str().length();
+}
+
+#if defined(OS_WIN)
+// This has already been defined in the header, but defining it again as DWORD
+// ensures that the type used in the header is equivalent to DWORD. If not,
+// the redefinition is a compile error.
+typedef DWORD SystemErrorCode;
+#endif
+
+SystemErrorCode GetLastSystemErrorCode() {
+#if defined(OS_WIN)
+  return ::GetLastError();
+#elif defined(OS_POSIX)
+  return errno;
+#else
+#error Not implemented
+#endif
+}
+
+#if defined(OS_WIN)
+BASE_EXPORT std::string SystemErrorCodeToString(SystemErrorCode error_code) {
+  const int kErrorMessageBufferSize = 256;
+  char msgbuf[kErrorMessageBufferSize];
+  DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
+  DWORD len = FormatMessageA(flags, nullptr, error_code, 0, msgbuf,
+                             arraysize(msgbuf), nullptr);
+  if (len) {
+    // Messages returned by system end with line breaks.
+    return base::CollapseWhitespaceASCII(msgbuf, true) +
+        base::StringPrintf(" (0x%X)", error_code);
+  }
+  return base::StringPrintf("Error (0x%X) while retrieving error. (0x%X)",
+                            GetLastError(), error_code);
+}
+#elif defined(OS_POSIX)
+BASE_EXPORT std::string SystemErrorCodeToString(SystemErrorCode error_code) {
+  return base::safe_strerror(error_code);
+}
+#else
+#error Not implemented
+#endif  // defined(OS_WIN)
+
+
+#if defined(OS_WIN)
+Win32ErrorLogMessage::Win32ErrorLogMessage(const char* file,
+                                           int line,
+                                           LogSeverity severity,
+                                           SystemErrorCode err)
+    : err_(err),
+      log_message_(file, line, severity) {
+}
+
+Win32ErrorLogMessage::~Win32ErrorLogMessage() {
+  stream() << ": " << SystemErrorCodeToString(err_);
+  // We're about to crash (CHECK). Put |err_| on the stack (by placing it in a
+  // field) and use Alias in hopes that it makes it into crash dumps.
+  DWORD last_error = err_;
+  base::debug::Alias(&last_error);
+}
+#elif defined(OS_POSIX)
+ErrnoLogMessage::ErrnoLogMessage(const char* file,
+                                 int line,
+                                 LogSeverity severity,
+                                 SystemErrorCode err)
+    : err_(err),
+      log_message_(file, line, severity) {
+}
+
+ErrnoLogMessage::~ErrnoLogMessage() {
+  stream() << ": " << SystemErrorCodeToString(err_);
+}
+#endif  // defined(OS_WIN)
+
+void CloseLogFile() {
+  LoggingLock logging_lock;
+  CloseLogFileUnlocked();
+}
+
+void RawLog(int level, const char* message) {
+  if (level >= g_min_log_level) {
+    size_t bytes_written = 0;
+    const size_t message_len = strlen(message);
+    int rv;
+    while (bytes_written < message_len) {
+      rv = HANDLE_EINTR(
+          write(STDERR_FILENO, message + bytes_written,
+                message_len - bytes_written));
+      if (rv < 0) {
+        // Give up, nothing we can do now.
+        break;
+      }
+      bytes_written += rv;
+    }
+
+    if (message_len > 0 && message[message_len - 1] != '\n') {
+      do {
+        rv = HANDLE_EINTR(write(STDERR_FILENO, "\n", 1));
+        if (rv < 0) {
+          // Give up, nothing we can do now.
+          break;
+        }
+      } while (rv != 1);
+    }
+  }
+
+  if (level == LOG_FATAL)
+    base::debug::BreakDebugger();
+}
+
+// This was defined at the beginning of this file.
+#undef write
+
+#if defined(OS_WIN)
+std::wstring GetLogFileFullPath() {
+  if (g_log_file_name)
+    return *g_log_file_name;
+  return std::wstring();
+}
+#endif
+
+BASE_EXPORT void LogErrorNotReached(const char* file, int line) {
+  LogMessage(file, line, LOG_ERROR).stream()
+      << "NOTREACHED() hit.";
+}
+
+}  // namespace logging
+
+std::ostream& std::operator<<(std::ostream& out, const wchar_t* wstr) {
+  return out << base::WideToUTF8(wstr);
+}
diff --git a/base/logging.h b/base/logging.h
new file mode 100644
index 0000000..ea096d1
--- /dev/null
+++ b/base/logging.h
@@ -0,0 +1,939 @@
+// Copyright (c) 2012 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_LOGGING_H_
+#define BASE_LOGGING_H_
+
+#include <cassert>
+#include <string>
+#include <cstring>
+#include <sstream>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/debug/debugger.h"
+#include "build/build_config.h"
+
+//
+// Optional message capabilities
+// -----------------------------
+// Assertion failed messages and fatal errors are displayed in a dialog box
+// before the application exits. However, running this UI creates a message
+// loop, which causes application messages to be processed and potentially
+// dispatched to existing application windows. Since the application is in a
+// bad state when this assertion dialog is displayed, these messages may not
+// get processed and hang the dialog, or the application might go crazy.
+//
+// Therefore, it can be beneficial to display the error dialog in a separate
+// process from the main application. When the logging system needs to display
+// a fatal error dialog box, it will look for a program called
+// "DebugMessage.exe" in the same directory as the application executable. It
+// will run this application with the message as the command line, and will
+// not include the name of the application as is traditional for easier
+// parsing.
+//
+// The code for DebugMessage.exe is only one line. In WinMain, do:
+//   MessageBox(NULL, GetCommandLineW(), L"Fatal Error", 0);
+//
+// If DebugMessage.exe is not found, the logging code will use a normal
+// MessageBox, potentially causing the problems discussed above.
+
+
+// Instructions
+// ------------
+//
+// Make a bunch of macros for logging.  The way to log things is to stream
+// things to LOG(<a particular severity level>).  E.g.,
+//
+//   LOG(INFO) << "Found " << num_cookies << " cookies";
+//
+// You can also do conditional logging:
+//
+//   LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
+//
+// The CHECK(condition) macro is active in both debug and release builds and
+// effectively performs a LOG(FATAL) which terminates the process and
+// generates a crashdump unless a debugger is attached.
+//
+// There are also "debug mode" logging macros like the ones above:
+//
+//   DLOG(INFO) << "Found cookies";
+//
+//   DLOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
+//
+// All "debug mode" logging is compiled away to nothing for non-debug mode
+// compiles.  LOG_IF and development flags also work well together
+// because the code can be compiled away sometimes.
+//
+// We also have
+//
+//   LOG_ASSERT(assertion);
+//   DLOG_ASSERT(assertion);
+//
+// which is syntactic sugar for {,D}LOG_IF(FATAL, assert fails) << assertion;
+//
+// There are "verbose level" logging macros.  They look like
+//
+//   VLOG(1) << "I'm printed when you run the program with --v=1 or more";
+//   VLOG(2) << "I'm printed when you run the program with --v=2 or more";
+//
+// These always log at the INFO log level (when they log at all).
+// The verbose logging can also be turned on module-by-module.  For instance,
+//    --vmodule=profile=2,icon_loader=1,browser_*=3,*/chromeos/*=4 --v=0
+// will cause:
+//   a. VLOG(2) and lower messages to be printed from profile.{h,cc}
+//   b. VLOG(1) and lower messages to be printed from icon_loader.{h,cc}
+//   c. VLOG(3) and lower messages to be printed from files prefixed with
+//      "browser"
+//   d. VLOG(4) and lower messages to be printed from files under a
+//     "chromeos" directory.
+//   e. VLOG(0) and lower messages to be printed from elsewhere
+//
+// The wildcarding functionality shown by (c) supports both '*' (match
+// 0 or more characters) and '?' (match any single character)
+// wildcards.  Any pattern containing a forward or backward slash will
+// be tested against the whole pathname and not just the module.
+// E.g., "*/foo/bar/*=2" would change the logging level for all code
+// in source files under a "foo/bar" directory.
+//
+// There's also VLOG_IS_ON(n) "verbose level" condition macro. To be used as
+//
+//   if (VLOG_IS_ON(2)) {
+//     // do some logging preparation and logging
+//     // that can't be accomplished with just VLOG(2) << ...;
+//   }
+//
+// There is also a VLOG_IF "verbose level" condition macro for sample
+// cases, when some extra computation and preparation for logs is not
+// needed.
+//
+//   VLOG_IF(1, (size > 1024))
+//      << "I'm printed when size is more than 1024 and when you run the "
+//         "program with --v=1 or more";
+//
+// We also override the standard 'assert' to use 'DLOG_ASSERT'.
+//
+// Lastly, there is:
+//
+//   PLOG(ERROR) << "Couldn't do foo";
+//   DPLOG(ERROR) << "Couldn't do foo";
+//   PLOG_IF(ERROR, cond) << "Couldn't do foo";
+//   DPLOG_IF(ERROR, cond) << "Couldn't do foo";
+//   PCHECK(condition) << "Couldn't do foo";
+//   DPCHECK(condition) << "Couldn't do foo";
+//
+// which append the last system error to the message in string form (taken from
+// GetLastError() on Windows and errno on POSIX).
+//
+// The supported severity levels for macros that allow you to specify one
+// are (in increasing order of severity) INFO, WARNING, ERROR, and FATAL.
+//
+// Very important: logging a message at the FATAL severity level causes
+// the program to terminate (after the message is logged).
+//
+// There is the special severity of DFATAL, which logs FATAL in debug mode,
+// ERROR in normal mode.
+
+namespace logging {
+
+// TODO(avi): do we want to do a unification of character types here?
+#if defined(OS_WIN)
+typedef wchar_t PathChar;
+#else
+typedef char PathChar;
+#endif
+
+// Where to record logging output? A flat file and/or system debug log
+// via OutputDebugString.
+enum LoggingDestination {
+  LOG_NONE                = 0,
+  LOG_TO_FILE             = 1 << 0,
+  LOG_TO_SYSTEM_DEBUG_LOG = 1 << 1,
+
+  LOG_TO_ALL = LOG_TO_FILE | LOG_TO_SYSTEM_DEBUG_LOG,
+
+  // On Windows, use a file next to the exe; on POSIX platforms, where
+  // it may not even be possible to locate the executable on disk, use
+  // stderr.
+#if defined(OS_WIN)
+  LOG_DEFAULT = LOG_TO_FILE,
+#elif defined(OS_POSIX)
+  LOG_DEFAULT = LOG_TO_SYSTEM_DEBUG_LOG,
+#endif
+};
+
+// Indicates that the log file should be locked when being written to.
+// Unless there is only one single-threaded process that is logging to
+// the log file, the file should be locked during writes to make each
+// log output atomic. Other writers will block.
+//
+// All processes writing to the log file must have their locking set for it to
+// work properly. Defaults to LOCK_LOG_FILE.
+enum LogLockingState { LOCK_LOG_FILE, DONT_LOCK_LOG_FILE };
+
+// On startup, should we delete or append to an existing log file (if any)?
+// Defaults to APPEND_TO_OLD_LOG_FILE.
+enum OldFileDeletionState { DELETE_OLD_LOG_FILE, APPEND_TO_OLD_LOG_FILE };
+
+struct BASE_EXPORT LoggingSettings {
+  // The defaults values are:
+  //
+  //  logging_dest: LOG_DEFAULT
+  //  log_file:     NULL
+  //  lock_log:     LOCK_LOG_FILE
+  //  delete_old:   APPEND_TO_OLD_LOG_FILE
+  LoggingSettings();
+
+  LoggingDestination logging_dest;
+
+  // The three settings below have an effect only when LOG_TO_FILE is
+  // set in |logging_dest|.
+  const PathChar* log_file;
+  LogLockingState lock_log;
+  OldFileDeletionState delete_old;
+};
+
+// Define different names for the BaseInitLoggingImpl() function depending on
+// whether NDEBUG is defined or not so that we'll fail to link if someone tries
+// to compile logging.cc with NDEBUG but includes logging.h without defining it,
+// or vice versa.
+#if NDEBUG
+#define BaseInitLoggingImpl BaseInitLoggingImpl_built_with_NDEBUG
+#else
+#define BaseInitLoggingImpl BaseInitLoggingImpl_built_without_NDEBUG
+#endif
+
+// Implementation of the InitLogging() method declared below.  We use a
+// more-specific name so we can #define it above without affecting other code
+// that has named stuff "InitLogging".
+BASE_EXPORT bool BaseInitLoggingImpl(const LoggingSettings& settings);
+
+// Sets the log file name and other global logging state. Calling this function
+// is recommended, and is normally done at the beginning of application init.
+// If you don't call it, all the flags will be initialized to their default
+// values, and there is a race condition that may leak a critical section
+// object if two threads try to do the first log at the same time.
+// See the definition of the enums above for descriptions and default values.
+//
+// The default log file is initialized to "debug.log" in the application
+// directory. You probably don't want this, especially since the program
+// directory may not be writable on an enduser's system.
+//
+// This function may be called a second time to re-direct logging (e.g after
+// loging in to a user partition), however it should never be called more than
+// twice.
+inline bool InitLogging(const LoggingSettings& settings) {
+  return BaseInitLoggingImpl(settings);
+}
+
+// Sets the log level. Anything at or above this level will be written to the
+// log file/displayed to the user (if applicable). Anything below this level
+// will be silently ignored. The log level defaults to 0 (everything is logged
+// up to level INFO) if this function is not called.
+// Note that log messages for VLOG(x) are logged at level -x, so setting
+// the min log level to negative values enables verbose logging.
+BASE_EXPORT void SetMinLogLevel(int level);
+
+// Gets the current log level.
+BASE_EXPORT int GetMinLogLevel();
+
+// Gets the VLOG default verbosity level.
+BASE_EXPORT int GetVlogVerbosity();
+
+// Gets the current vlog level for the given file (usually taken from
+// __FILE__).
+
+// Note that |N| is the size *with* the null terminator.
+BASE_EXPORT int GetVlogLevelHelper(const char* file_start, size_t N);
+
+template <size_t N>
+int GetVlogLevel(const char (&file)[N]) {
+  return GetVlogLevelHelper(file, N);
+}
+
+// Sets the common items you want to be prepended to each log message.
+// process and thread IDs default to off, the timestamp defaults to on.
+// If this function is not called, logging defaults to writing the timestamp
+// only.
+BASE_EXPORT void SetLogItems(bool enable_process_id, bool enable_thread_id,
+                             bool enable_timestamp, bool enable_tickcount);
+
+// Sets whether or not you'd like to see fatal debug messages popped up in
+// a dialog box or not.
+// Dialogs are not shown by default.
+BASE_EXPORT void SetShowErrorDialogs(bool enable_dialogs);
+
+// Sets the Log Assert Handler that will be used to notify of check failures.
+// The default handler shows a dialog box and then terminate the process,
+// however clients can use this function to override with their own handling
+// (e.g. a silent one for Unit Tests)
+typedef void (*LogAssertHandlerFunction)(const std::string& str);
+BASE_EXPORT void SetLogAssertHandler(LogAssertHandlerFunction handler);
+
+// Sets the Log Message Handler that gets passed every log message before
+// it's sent to other log destinations (if any).
+// Returns true to signal that it handled the message and the message
+// should not be sent to other log destinations.
+typedef bool (*LogMessageHandlerFunction)(int severity,
+    const char* file, int line, size_t message_start, const std::string& str);
+BASE_EXPORT void SetLogMessageHandler(LogMessageHandlerFunction handler);
+BASE_EXPORT LogMessageHandlerFunction GetLogMessageHandler();
+
+typedef int LogSeverity;
+const LogSeverity LOG_VERBOSE = -1;  // This is level 1 verbosity
+// Note: the log severities are used to index into the array of names,
+// see log_severity_names.
+const LogSeverity LOG_INFO = 0;
+const LogSeverity LOG_WARNING = 1;
+const LogSeverity LOG_ERROR = 2;
+const LogSeverity LOG_FATAL = 3;
+const LogSeverity LOG_NUM_SEVERITIES = 4;
+
+// LOG_DFATAL is LOG_FATAL in debug mode, ERROR in normal mode
+#ifdef NDEBUG
+const LogSeverity LOG_DFATAL = LOG_ERROR;
+#else
+const LogSeverity LOG_DFATAL = LOG_FATAL;
+#endif
+
+// A few definitions of macros that don't generate much code. These are used
+// by LOG() and LOG_IF, etc. Since these are used all over our code, it's
+// better to have compact code for these operations.
+#define COMPACT_GOOGLE_LOG_EX_INFO(ClassName, ...) \
+  logging::ClassName(__FILE__, __LINE__, logging::LOG_INFO , ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_EX_WARNING(ClassName, ...) \
+  logging::ClassName(__FILE__, __LINE__, logging::LOG_WARNING , ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_EX_ERROR(ClassName, ...) \
+  logging::ClassName(__FILE__, __LINE__, logging::LOG_ERROR , ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_EX_FATAL(ClassName, ...) \
+  logging::ClassName(__FILE__, __LINE__, logging::LOG_FATAL , ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_EX_DFATAL(ClassName, ...) \
+  logging::ClassName(__FILE__, __LINE__, logging::LOG_DFATAL , ##__VA_ARGS__)
+
+#define COMPACT_GOOGLE_LOG_INFO \
+  COMPACT_GOOGLE_LOG_EX_INFO(LogMessage)
+#define COMPACT_GOOGLE_LOG_WARNING \
+  COMPACT_GOOGLE_LOG_EX_WARNING(LogMessage)
+#define COMPACT_GOOGLE_LOG_ERROR \
+  COMPACT_GOOGLE_LOG_EX_ERROR(LogMessage)
+#define COMPACT_GOOGLE_LOG_FATAL \
+  COMPACT_GOOGLE_LOG_EX_FATAL(LogMessage)
+#define COMPACT_GOOGLE_LOG_DFATAL \
+  COMPACT_GOOGLE_LOG_EX_DFATAL(LogMessage)
+
+#if defined(OS_WIN)
+// wingdi.h defines ERROR to be 0. When we call LOG(ERROR), it gets
+// substituted with 0, and it expands to COMPACT_GOOGLE_LOG_0. To allow us
+// to keep using this syntax, we define this macro to do the same thing
+// as COMPACT_GOOGLE_LOG_ERROR, and also define ERROR the same way that
+// the Windows SDK does for consistency.
+#define ERROR 0
+#define COMPACT_GOOGLE_LOG_EX_0(ClassName, ...) \
+  COMPACT_GOOGLE_LOG_EX_ERROR(ClassName , ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_0 COMPACT_GOOGLE_LOG_ERROR
+// Needed for LOG_IS_ON(ERROR).
+const LogSeverity LOG_0 = LOG_ERROR;
+#endif
+
+// As special cases, we can assume that LOG_IS_ON(FATAL) always holds. Also,
+// LOG_IS_ON(DFATAL) always holds in debug mode. In particular, CHECK()s will
+// always fire if they fail.
+#define LOG_IS_ON(severity) \
+  ((::logging::LOG_ ## severity) >= ::logging::GetMinLogLevel())
+
+// We can't do any caching tricks with VLOG_IS_ON() like the
+// google-glog version since it requires GCC extensions.  This means
+// that using the v-logging functions in conjunction with --vmodule
+// may be slow.
+#define VLOG_IS_ON(verboselevel) \
+  ((verboselevel) <= ::logging::GetVlogLevel(__FILE__))
+
+// Helper macro which avoids evaluating the arguments to a stream if
+// the condition doesn't hold. Condition is evaluated once and only once.
+#define LAZY_STREAM(stream, condition)                                  \
+  !(condition) ? (void) 0 : ::logging::LogMessageVoidify() & (stream)
+
+// We use the preprocessor's merging operator, "##", so that, e.g.,
+// LOG(INFO) becomes the token COMPACT_GOOGLE_LOG_INFO.  There's some funny
+// subtle difference between ostream member streaming functions (e.g.,
+// ostream::operator<<(int) and ostream non-member streaming functions
+// (e.g., ::operator<<(ostream&, string&): it turns out that it's
+// impossible to stream something like a string directly to an unnamed
+// ostream. We employ a neat hack by calling the stream() member
+// function of LogMessage which seems to avoid the problem.
+#define LOG_STREAM(severity) COMPACT_GOOGLE_LOG_ ## severity.stream()
+
+#define LOG(severity) LAZY_STREAM(LOG_STREAM(severity), LOG_IS_ON(severity))
+#define LOG_IF(severity, condition) \
+  LAZY_STREAM(LOG_STREAM(severity), LOG_IS_ON(severity) && (condition))
+
+#define SYSLOG(severity) LOG(severity)
+#define SYSLOG_IF(severity, condition) LOG_IF(severity, condition)
+
+// The VLOG macros log with negative verbosities.
+#define VLOG_STREAM(verbose_level) \
+  logging::LogMessage(__FILE__, __LINE__, -verbose_level).stream()
+
+#define VLOG(verbose_level) \
+  LAZY_STREAM(VLOG_STREAM(verbose_level), VLOG_IS_ON(verbose_level))
+
+#define VLOG_IF(verbose_level, condition) \
+  LAZY_STREAM(VLOG_STREAM(verbose_level), \
+      VLOG_IS_ON(verbose_level) && (condition))
+
+#if defined (OS_WIN)
+#define VPLOG_STREAM(verbose_level) \
+  logging::Win32ErrorLogMessage(__FILE__, __LINE__, -verbose_level, \
+    ::logging::GetLastSystemErrorCode()).stream()
+#elif defined(OS_POSIX)
+#define VPLOG_STREAM(verbose_level) \
+  logging::ErrnoLogMessage(__FILE__, __LINE__, -verbose_level, \
+    ::logging::GetLastSystemErrorCode()).stream()
+#endif
+
+#define VPLOG(verbose_level) \
+  LAZY_STREAM(VPLOG_STREAM(verbose_level), VLOG_IS_ON(verbose_level))
+
+#define VPLOG_IF(verbose_level, condition) \
+  LAZY_STREAM(VPLOG_STREAM(verbose_level), \
+    VLOG_IS_ON(verbose_level) && (condition))
+
+// TODO(akalin): Add more VLOG variants, e.g. VPLOG.
+
+#define LOG_ASSERT(condition)  \
+  LOG_IF(FATAL, !(condition)) << "Assert failed: " #condition ". "
+#define SYSLOG_ASSERT(condition) \
+  SYSLOG_IF(FATAL, !(condition)) << "Assert failed: " #condition ". "
+
+#if defined(OS_WIN)
+#define PLOG_STREAM(severity) \
+  COMPACT_GOOGLE_LOG_EX_ ## severity(Win32ErrorLogMessage, \
+      ::logging::GetLastSystemErrorCode()).stream()
+#elif defined(OS_POSIX)
+#define PLOG_STREAM(severity) \
+  COMPACT_GOOGLE_LOG_EX_ ## severity(ErrnoLogMessage, \
+      ::logging::GetLastSystemErrorCode()).stream()
+#endif
+
+#define PLOG(severity)                                          \
+  LAZY_STREAM(PLOG_STREAM(severity), LOG_IS_ON(severity))
+
+#define PLOG_IF(severity, condition) \
+  LAZY_STREAM(PLOG_STREAM(severity), LOG_IS_ON(severity) && (condition))
+
+// The actual stream used isn't important.
+#define EAT_STREAM_PARAMETERS                                           \
+  true ? (void) 0 : ::logging::LogMessageVoidify() & LOG_STREAM(FATAL)
+
+// CHECK dies with a fatal error if condition is not true.  It is *not*
+// controlled by NDEBUG, so the check will be executed regardless of
+// compilation mode.
+//
+// We make sure CHECK et al. always evaluates their arguments, as
+// doing CHECK(FunctionWithSideEffect()) is a common idiom.
+
+#if defined(OFFICIAL_BUILD) && defined(NDEBUG) && !defined(OS_ANDROID)
+
+// Make all CHECK functions discard their log strings to reduce code
+// bloat for official release builds.
+
+// TODO(akalin): This would be more valuable if there were some way to
+// remove BreakDebugger() from the backtrace, perhaps by turning it
+// into a macro (like __debugbreak() on Windows).
+#define CHECK(condition)                                                \
+  !(condition) ? ::base::debug::BreakDebugger() : EAT_STREAM_PARAMETERS
+
+#define PCHECK(condition) CHECK(condition)
+
+#define CHECK_OP(name, op, val1, val2) CHECK((val1) op (val2))
+
+#else
+
+#if defined(_PREFAST_) && defined(OS_WIN)
+// Use __analysis_assume to tell the VC++ static analysis engine that
+// assert conditions are true, to suppress warnings.  The LAZY_STREAM
+// parameter doesn't reference 'condition' in /analyze builds because
+// this evaluation confuses /analyze. The !! before condition is because
+// __analysis_assume gets confused on some conditions:
+// http://randomascii.wordpress.com/2011/09/13/analyze-for-visual-studio-the-ugly-part-5/
+
+#define CHECK(condition)                \
+  __analysis_assume(!!(condition)),     \
+  LAZY_STREAM(LOG_STREAM(FATAL), false) \
+  << "Check failed: " #condition ". "
+
+#define PCHECK(condition)                \
+  __analysis_assume(!!(condition)),      \
+  LAZY_STREAM(PLOG_STREAM(FATAL), false) \
+  << "Check failed: " #condition ". "
+
+#else  // _PREFAST_
+
+#define CHECK(condition)                       \
+  LAZY_STREAM(LOG_STREAM(FATAL), !(condition)) \
+  << "Check failed: " #condition ". "
+
+#define PCHECK(condition)                       \
+  LAZY_STREAM(PLOG_STREAM(FATAL), !(condition)) \
+  << "Check failed: " #condition ". "
+
+#endif  // _PREFAST_
+
+// Helper macro for binary operators.
+// Don't use this macro directly in your code, use CHECK_EQ et al below.
+//
+// TODO(akalin): Rewrite this so that constructs like if (...)
+// CHECK_EQ(...) else { ... } work properly.
+#define CHECK_OP(name, op, val1, val2)                          \
+  if (std::string* _result =                                    \
+      logging::Check##name##Impl((val1), (val2),                \
+                                 #val1 " " #op " " #val2))      \
+    logging::LogMessage(__FILE__, __LINE__, _result).stream()
+
+#endif
+
+// Build the error message string.  This is separate from the "Impl"
+// function template because it is not performance critical and so can
+// be out of line, while the "Impl" code should be inline.  Caller
+// takes ownership of the returned string.
+template<class t1, class t2>
+std::string* MakeCheckOpString(const t1& v1, const t2& v2, const char* names) {
+  std::ostringstream ss;
+  ss << names << " (" << v1 << " vs. " << v2 << ")";
+  std::string* msg = new std::string(ss.str());
+  return msg;
+}
+
+// Commonly used instantiations of MakeCheckOpString<>. Explicitly instantiated
+// in logging.cc.
+extern template BASE_EXPORT std::string* MakeCheckOpString<int, int>(
+    const int&, const int&, const char* names);
+extern template BASE_EXPORT
+std::string* MakeCheckOpString<unsigned long, unsigned long>(
+    const unsigned long&, const unsigned long&, const char* names);
+extern template BASE_EXPORT
+std::string* MakeCheckOpString<unsigned long, unsigned int>(
+    const unsigned long&, const unsigned int&, const char* names);
+extern template BASE_EXPORT
+std::string* MakeCheckOpString<unsigned int, unsigned long>(
+    const unsigned int&, const unsigned long&, const char* names);
+extern template BASE_EXPORT
+std::string* MakeCheckOpString<std::string, std::string>(
+    const std::string&, const std::string&, const char* name);
+
+// Helper functions for CHECK_OP macro.
+// The (int, int) specialization works around the issue that the compiler
+// will not instantiate the template version of the function on values of
+// unnamed enum type - see comment below.
+#define DEFINE_CHECK_OP_IMPL(name, op) \
+  template <class t1, class t2> \
+  inline std::string* Check##name##Impl(const t1& v1, const t2& v2, \
+                                        const char* names) { \
+    if (v1 op v2) return NULL; \
+    else return MakeCheckOpString(v1, v2, names); \
+  } \
+  inline std::string* Check##name##Impl(int v1, int v2, const char* names) { \
+    if (v1 op v2) return NULL; \
+    else return MakeCheckOpString(v1, v2, names); \
+  }
+DEFINE_CHECK_OP_IMPL(EQ, ==)
+DEFINE_CHECK_OP_IMPL(NE, !=)
+DEFINE_CHECK_OP_IMPL(LE, <=)
+DEFINE_CHECK_OP_IMPL(LT, < )
+DEFINE_CHECK_OP_IMPL(GE, >=)
+DEFINE_CHECK_OP_IMPL(GT, > )
+#undef DEFINE_CHECK_OP_IMPL
+
+#define CHECK_EQ(val1, val2) CHECK_OP(EQ, ==, val1, val2)
+#define CHECK_NE(val1, val2) CHECK_OP(NE, !=, val1, val2)
+#define CHECK_LE(val1, val2) CHECK_OP(LE, <=, val1, val2)
+#define CHECK_LT(val1, val2) CHECK_OP(LT, < , val1, val2)
+#define CHECK_GE(val1, val2) CHECK_OP(GE, >=, val1, val2)
+#define CHECK_GT(val1, val2) CHECK_OP(GT, > , val1, val2)
+#define CHECK_IMPLIES(val1, val2) CHECK(!(val1) || (val2))
+
+#if defined(NDEBUG)
+#define ENABLE_DLOG 0
+#else
+#define ENABLE_DLOG 1
+#endif
+
+#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
+#define DCHECK_IS_ON() 0
+#else
+#define DCHECK_IS_ON() 1
+#endif
+
+// Definitions for DLOG et al.
+
+#if ENABLE_DLOG
+
+#define DLOG_IS_ON(severity) LOG_IS_ON(severity)
+#define DLOG_IF(severity, condition) LOG_IF(severity, condition)
+#define DLOG_ASSERT(condition) LOG_ASSERT(condition)
+#define DPLOG_IF(severity, condition) PLOG_IF(severity, condition)
+#define DVLOG_IF(verboselevel, condition) VLOG_IF(verboselevel, condition)
+#define DVPLOG_IF(verboselevel, condition) VPLOG_IF(verboselevel, condition)
+
+#else  // ENABLE_DLOG
+
+// If ENABLE_DLOG is off, we want to avoid emitting any references to
+// |condition| (which may reference a variable defined only if NDEBUG
+// is not defined).  Contrast this with DCHECK et al., which has
+// different behavior.
+
+#define DLOG_IS_ON(severity) false
+#define DLOG_IF(severity, condition) EAT_STREAM_PARAMETERS
+#define DLOG_ASSERT(condition) EAT_STREAM_PARAMETERS
+#define DPLOG_IF(severity, condition) EAT_STREAM_PARAMETERS
+#define DVLOG_IF(verboselevel, condition) EAT_STREAM_PARAMETERS
+#define DVPLOG_IF(verboselevel, condition) EAT_STREAM_PARAMETERS
+
+#endif  // ENABLE_DLOG
+
+// DEBUG_MODE is for uses like
+//   if (DEBUG_MODE) foo.CheckThatFoo();
+// instead of
+//   #ifndef NDEBUG
+//     foo.CheckThatFoo();
+//   #endif
+//
+// We tie its state to ENABLE_DLOG.
+enum { DEBUG_MODE = ENABLE_DLOG };
+
+#undef ENABLE_DLOG
+
+#define DLOG(severity)                                          \
+  LAZY_STREAM(LOG_STREAM(severity), DLOG_IS_ON(severity))
+
+#define DPLOG(severity)                                         \
+  LAZY_STREAM(PLOG_STREAM(severity), DLOG_IS_ON(severity))
+
+#define DVLOG(verboselevel) DVLOG_IF(verboselevel, VLOG_IS_ON(verboselevel))
+
+#define DVPLOG(verboselevel) DVPLOG_IF(verboselevel, VLOG_IS_ON(verboselevel))
+
+// Definitions for DCHECK et al.
+
+#if DCHECK_IS_ON()
+
+#define COMPACT_GOOGLE_LOG_EX_DCHECK(ClassName, ...) \
+  COMPACT_GOOGLE_LOG_EX_FATAL(ClassName , ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_DCHECK COMPACT_GOOGLE_LOG_FATAL
+const LogSeverity LOG_DCHECK = LOG_FATAL;
+
+#else  // DCHECK_IS_ON()
+
+// These are just dummy values.
+#define COMPACT_GOOGLE_LOG_EX_DCHECK(ClassName, ...) \
+  COMPACT_GOOGLE_LOG_EX_INFO(ClassName , ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_DCHECK COMPACT_GOOGLE_LOG_INFO
+const LogSeverity LOG_DCHECK = LOG_INFO;
+
+#endif  // DCHECK_IS_ON()
+
+// DCHECK et al. make sure to reference |condition| regardless of
+// whether DCHECKs are enabled; this is so that we don't get unused
+// variable warnings if the only use of a variable is in a DCHECK.
+// This behavior is different from DLOG_IF et al.
+
+#if defined(_PREFAST_) && defined(OS_WIN)
+// See comments on the previous use of __analysis_assume.
+
+#define DCHECK(condition)                                               \
+  __analysis_assume(!!(condition)),                                     \
+  LAZY_STREAM(LOG_STREAM(DCHECK), false)                                \
+  << "Check failed: " #condition ". "
+
+#define DPCHECK(condition)                                              \
+  __analysis_assume(!!(condition)),                                     \
+  LAZY_STREAM(PLOG_STREAM(DCHECK), false)                               \
+  << "Check failed: " #condition ". "
+
+#else  // _PREFAST_
+
+#define DCHECK(condition)                                                \
+  LAZY_STREAM(LOG_STREAM(DCHECK), DCHECK_IS_ON() ? !(condition) : false) \
+      << "Check failed: " #condition ". "
+
+#define DPCHECK(condition)                                                \
+  LAZY_STREAM(PLOG_STREAM(DCHECK), DCHECK_IS_ON() ? !(condition) : false) \
+      << "Check failed: " #condition ". "
+
+#endif  // _PREFAST_
+
+// Helper macro for binary operators.
+// Don't use this macro directly in your code, use DCHECK_EQ et al below.
+#define DCHECK_OP(name, op, val1, val2)                                   \
+  if (DCHECK_IS_ON())                                                     \
+    if (std::string* _result = logging::Check##name##Impl(                \
+            (val1), (val2), #val1 " " #op " " #val2))                     \
+  logging::LogMessage(__FILE__, __LINE__, ::logging::LOG_DCHECK, _result) \
+      .stream()
+
+// Equality/Inequality checks - compare two values, and log a
+// LOG_DCHECK message including the two values when the result is not
+// as expected.  The values must have operator<<(ostream, ...)
+// defined.
+//
+// You may append to the error message like so:
+//   DCHECK_NE(1, 2) << ": The world must be ending!";
+//
+// We are very careful to ensure that each argument is evaluated exactly
+// once, and that anything which is legal to pass as a function argument is
+// legal here.  In particular, the arguments may be temporary expressions
+// which will end up being destroyed at the end of the apparent statement,
+// for example:
+//   DCHECK_EQ(string("abc")[1], 'b');
+//
+// WARNING: These may not compile correctly if one of the arguments is a pointer
+// and the other is NULL. To work around this, simply static_cast NULL to the
+// type of the desired pointer.
+
+#define DCHECK_EQ(val1, val2) DCHECK_OP(EQ, ==, val1, val2)
+#define DCHECK_NE(val1, val2) DCHECK_OP(NE, !=, val1, val2)
+#define DCHECK_LE(val1, val2) DCHECK_OP(LE, <=, val1, val2)
+#define DCHECK_LT(val1, val2) DCHECK_OP(LT, < , val1, val2)
+#define DCHECK_GE(val1, val2) DCHECK_OP(GE, >=, val1, val2)
+#define DCHECK_GT(val1, val2) DCHECK_OP(GT, > , val1, val2)
+#define DCHECK_IMPLIES(val1, val2) DCHECK(!(val1) || (val2))
+
+#if !DCHECK_IS_ON() && defined(OS_CHROMEOS)
+// Implement logging of NOTREACHED() as a dedicated function to get function
+// call overhead down to a minimum.
+void LogErrorNotReached(const char* file, int line);
+#define NOTREACHED()                                       \
+  true ? ::logging::LogErrorNotReached(__FILE__, __LINE__) \
+       : EAT_STREAM_PARAMETERS
+#else
+#define NOTREACHED() DCHECK(false)
+#endif
+
+// Redefine the standard assert to use our nice log files
+#undef assert
+#define assert(x) DLOG_ASSERT(x)
+
+// This class more or less represents a particular log message.  You
+// create an instance of LogMessage and then stream stuff to it.
+// When you finish streaming to it, ~LogMessage is called and the
+// full message gets streamed to the appropriate destination.
+//
+// You shouldn't actually use LogMessage's constructor to log things,
+// though.  You should use the LOG() macro (and variants thereof)
+// above.
+class BASE_EXPORT LogMessage {
+ public:
+  // Used for LOG(severity).
+  LogMessage(const char* file, int line, LogSeverity severity);
+
+  // Used for CHECK_EQ(), etc. Takes ownership of the given string.
+  // Implied severity = LOG_FATAL.
+  LogMessage(const char* file, int line, std::string* result);
+
+  // Used for DCHECK_EQ(), etc. Takes ownership of the given string.
+  LogMessage(const char* file, int line, LogSeverity severity,
+             std::string* result);
+
+  ~LogMessage();
+
+  std::ostream& stream() { return stream_; }
+
+ private:
+  void Init(const char* file, int line);
+
+  LogSeverity severity_;
+  std::ostringstream stream_;
+  size_t message_start_;  // Offset of the start of the message (past prefix
+                          // info).
+  // The file and line information passed in to the constructor.
+  const char* file_;
+  const int line_;
+
+#if defined(OS_WIN)
+  // Stores the current value of GetLastError in the constructor and restores
+  // it in the destructor by calling SetLastError.
+  // This is useful since the LogMessage class uses a lot of Win32 calls
+  // that will lose the value of GLE and the code that called the log function
+  // will have lost the thread error value when the log call returns.
+  class SaveLastError {
+   public:
+    SaveLastError();
+    ~SaveLastError();
+
+    unsigned long get_error() const { return last_error_; }
+
+   protected:
+    unsigned long last_error_;
+  };
+
+  SaveLastError last_error_;
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(LogMessage);
+};
+
+// A non-macro interface to the log facility; (useful
+// when the logging level is not a compile-time constant).
+inline void LogAtLevel(int const log_level, std::string const &msg) {
+  LogMessage(__FILE__, __LINE__, log_level).stream() << msg;
+}
+
+// This class is used to explicitly ignore values in the conditional
+// logging macros.  This avoids compiler warnings like "value computed
+// is not used" and "statement has no effect".
+class LogMessageVoidify {
+ public:
+  LogMessageVoidify() { }
+  // This has to be an operator with a precedence lower than << but
+  // higher than ?:
+  void operator&(std::ostream&) { }
+};
+
+#if defined(OS_WIN)
+typedef unsigned long SystemErrorCode;
+#elif defined(OS_POSIX)
+typedef int SystemErrorCode;
+#endif
+
+// Alias for ::GetLastError() on Windows and errno on POSIX. Avoids having to
+// pull in windows.h just for GetLastError() and DWORD.
+BASE_EXPORT SystemErrorCode GetLastSystemErrorCode();
+BASE_EXPORT std::string SystemErrorCodeToString(SystemErrorCode error_code);
+
+#if defined(OS_WIN)
+// Appends a formatted system message of the GetLastError() type.
+class BASE_EXPORT Win32ErrorLogMessage {
+ public:
+  Win32ErrorLogMessage(const char* file,
+                       int line,
+                       LogSeverity severity,
+                       SystemErrorCode err);
+
+  // Appends the error message before destructing the encapsulated class.
+  ~Win32ErrorLogMessage();
+
+  std::ostream& stream() { return log_message_.stream(); }
+
+ private:
+  SystemErrorCode err_;
+  LogMessage log_message_;
+
+  DISALLOW_COPY_AND_ASSIGN(Win32ErrorLogMessage);
+};
+#elif defined(OS_POSIX)
+// Appends a formatted system message of the errno type
+class BASE_EXPORT ErrnoLogMessage {
+ public:
+  ErrnoLogMessage(const char* file,
+                  int line,
+                  LogSeverity severity,
+                  SystemErrorCode err);
+
+  // Appends the error message before destructing the encapsulated class.
+  ~ErrnoLogMessage();
+
+  std::ostream& stream() { return log_message_.stream(); }
+
+ private:
+  SystemErrorCode err_;
+  LogMessage log_message_;
+
+  DISALLOW_COPY_AND_ASSIGN(ErrnoLogMessage);
+};
+#endif  // OS_WIN
+
+// Closes the log file explicitly if open.
+// NOTE: Since the log file is opened as necessary by the action of logging
+//       statements, there's no guarantee that it will stay closed
+//       after this call.
+BASE_EXPORT void CloseLogFile();
+
+// Async signal safe logging mechanism.
+BASE_EXPORT void RawLog(int level, const char* message);
+
+#define RAW_LOG(level, message) logging::RawLog(logging::LOG_ ## level, message)
+
+#define RAW_CHECK(condition)                                                   \
+  do {                                                                         \
+    if (!(condition))                                                          \
+      logging::RawLog(logging::LOG_FATAL, "Check failed: " #condition "\n");   \
+  } while (0)
+
+#if defined(OS_WIN)
+// Returns the default log file path.
+BASE_EXPORT std::wstring GetLogFileFullPath();
+#endif
+
+}  // namespace logging
+
+// Note that "The behavior of a C++ program is undefined if it adds declarations
+// or definitions to namespace std or to a namespace within namespace std unless
+// otherwise specified." --C++11[namespace.std]
+//
+// We've checked that this particular definition has the intended behavior on
+// our implementations, but it's prone to breaking in the future, and please
+// don't imitate this in your own definitions without checking with some
+// standard library experts.
+namespace std {
+// These functions are provided as a convenience for logging, which is where we
+// use streams (it is against Google style to use streams in other places). It
+// is designed to allow you to emit non-ASCII Unicode strings to the log file,
+// which is normally ASCII. It is relatively slow, so try not to use it for
+// common cases. Non-ASCII characters will be converted to UTF-8 by these
+// operators.
+BASE_EXPORT std::ostream& operator<<(std::ostream& out, const wchar_t* wstr);
+inline std::ostream& operator<<(std::ostream& out, const std::wstring& wstr) {
+  return out << wstr.c_str();
+}
+}  // namespace std
+
+// The NOTIMPLEMENTED() macro annotates codepaths which have
+// not been implemented yet.
+//
+// The implementation of this macro is controlled by NOTIMPLEMENTED_POLICY:
+//   0 -- Do nothing (stripped by compiler)
+//   1 -- Warn at compile time
+//   2 -- Fail at compile time
+//   3 -- Fail at runtime (DCHECK)
+//   4 -- [default] LOG(ERROR) at runtime
+//   5 -- LOG(ERROR) at runtime, only once per call-site
+
+#ifndef NOTIMPLEMENTED_POLICY
+#if defined(OS_ANDROID) && defined(OFFICIAL_BUILD)
+#define NOTIMPLEMENTED_POLICY 0
+#else
+// Select default policy: LOG(ERROR)
+#define NOTIMPLEMENTED_POLICY 4
+#endif
+#endif
+
+#if defined(COMPILER_GCC)
+// On Linux, with GCC, we can use __PRETTY_FUNCTION__ to get the demangled name
+// of the current function in the NOTIMPLEMENTED message.
+#define NOTIMPLEMENTED_MSG "Not implemented reached in " << __PRETTY_FUNCTION__
+#else
+#define NOTIMPLEMENTED_MSG "NOT IMPLEMENTED"
+#endif
+
+#if NOTIMPLEMENTED_POLICY == 0
+#define NOTIMPLEMENTED() EAT_STREAM_PARAMETERS
+#elif NOTIMPLEMENTED_POLICY == 1
+// TODO, figure out how to generate a warning
+#define NOTIMPLEMENTED() COMPILE_ASSERT(false, NOT_IMPLEMENTED)
+#elif NOTIMPLEMENTED_POLICY == 2
+#define NOTIMPLEMENTED() COMPILE_ASSERT(false, NOT_IMPLEMENTED)
+#elif NOTIMPLEMENTED_POLICY == 3
+#define NOTIMPLEMENTED() NOTREACHED()
+#elif NOTIMPLEMENTED_POLICY == 4
+#define NOTIMPLEMENTED() LOG(ERROR) << NOTIMPLEMENTED_MSG
+#elif NOTIMPLEMENTED_POLICY == 5
+#define NOTIMPLEMENTED() do {\
+  static bool logged_once = false;\
+  LOG_IF(ERROR, !logged_once) << NOTIMPLEMENTED_MSG;\
+  logged_once = true;\
+} while(0);\
+EAT_STREAM_PARAMETERS
+#endif
+
+#endif  // BASE_LOGGING_H_
diff --git a/base/logging_unittest.cc b/base/logging_unittest.cc
new file mode 100644
index 0000000..8b9701a
--- /dev/null
+++ b/base/logging_unittest.cc
@@ -0,0 +1,258 @@
+// Copyright (c) 2011 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/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace logging {
+
+namespace {
+
+using ::testing::Return;
+
+// Needs to be global since log assert handlers can't maintain state.
+int log_sink_call_count = 0;
+
+#if !defined(OFFICIAL_BUILD) || defined(DCHECK_ALWAYS_ON) || !defined(NDEBUG)
+void LogSink(const std::string& str) {
+  ++log_sink_call_count;
+}
+#endif
+
+// Class to make sure any manipulations we do to the min log level are
+// contained (i.e., do not affect other unit tests).
+class LogStateSaver {
+ public:
+  LogStateSaver() : old_min_log_level_(GetMinLogLevel()) {}
+
+  ~LogStateSaver() {
+    SetMinLogLevel(old_min_log_level_);
+    SetLogAssertHandler(NULL);
+    log_sink_call_count = 0;
+  }
+
+ private:
+  int old_min_log_level_;
+
+  DISALLOW_COPY_AND_ASSIGN(LogStateSaver);
+};
+
+class LoggingTest : public testing::Test {
+ private:
+  LogStateSaver log_state_saver_;
+};
+
+class MockLogSource {
+ public:
+  MOCK_METHOD0(Log, const char*());
+};
+
+TEST_F(LoggingTest, BasicLogging) {
+  MockLogSource mock_log_source;
+  EXPECT_CALL(mock_log_source, Log()).Times(DEBUG_MODE ? 16 : 8).
+      WillRepeatedly(Return("log message"));
+
+  SetMinLogLevel(LOG_INFO);
+
+  EXPECT_TRUE(LOG_IS_ON(INFO));
+  // As of g++-4.5, the first argument to EXPECT_EQ cannot be a
+  // constant expression.
+  const bool kIsDebugMode = (DEBUG_MODE != 0);
+  EXPECT_TRUE(kIsDebugMode == DLOG_IS_ON(INFO));
+  EXPECT_TRUE(VLOG_IS_ON(0));
+
+  LOG(INFO) << mock_log_source.Log();
+  LOG_IF(INFO, true) << mock_log_source.Log();
+  PLOG(INFO) << mock_log_source.Log();
+  PLOG_IF(INFO, true) << mock_log_source.Log();
+  VLOG(0) << mock_log_source.Log();
+  VLOG_IF(0, true) << mock_log_source.Log();
+  VPLOG(0) << mock_log_source.Log();
+  VPLOG_IF(0, true) << mock_log_source.Log();
+
+  DLOG(INFO) << mock_log_source.Log();
+  DLOG_IF(INFO, true) << mock_log_source.Log();
+  DPLOG(INFO) << mock_log_source.Log();
+  DPLOG_IF(INFO, true) << mock_log_source.Log();
+  DVLOG(0) << mock_log_source.Log();
+  DVLOG_IF(0, true) << mock_log_source.Log();
+  DVPLOG(0) << mock_log_source.Log();
+  DVPLOG_IF(0, true) << mock_log_source.Log();
+}
+
+TEST_F(LoggingTest, LogIsOn) {
+#if defined(NDEBUG)
+  const bool kDfatalIsFatal = false;
+#else  // defined(NDEBUG)
+  const bool kDfatalIsFatal = true;
+#endif  // defined(NDEBUG)
+
+  SetMinLogLevel(LOG_INFO);
+  EXPECT_TRUE(LOG_IS_ON(INFO));
+  EXPECT_TRUE(LOG_IS_ON(WARNING));
+  EXPECT_TRUE(LOG_IS_ON(ERROR));
+  EXPECT_TRUE(LOG_IS_ON(FATAL));
+  EXPECT_TRUE(LOG_IS_ON(DFATAL));
+
+  SetMinLogLevel(LOG_WARNING);
+  EXPECT_FALSE(LOG_IS_ON(INFO));
+  EXPECT_TRUE(LOG_IS_ON(WARNING));
+  EXPECT_TRUE(LOG_IS_ON(ERROR));
+  EXPECT_TRUE(LOG_IS_ON(FATAL));
+  EXPECT_TRUE(LOG_IS_ON(DFATAL));
+
+  SetMinLogLevel(LOG_ERROR);
+  EXPECT_FALSE(LOG_IS_ON(INFO));
+  EXPECT_FALSE(LOG_IS_ON(WARNING));
+  EXPECT_TRUE(LOG_IS_ON(ERROR));
+  EXPECT_TRUE(LOG_IS_ON(FATAL));
+  EXPECT_TRUE(LOG_IS_ON(DFATAL));
+
+  // LOG_IS_ON(FATAL) should always be true.
+  SetMinLogLevel(LOG_FATAL + 1);
+  EXPECT_FALSE(LOG_IS_ON(INFO));
+  EXPECT_FALSE(LOG_IS_ON(WARNING));
+  EXPECT_FALSE(LOG_IS_ON(ERROR));
+  EXPECT_TRUE(LOG_IS_ON(FATAL));
+  EXPECT_TRUE(kDfatalIsFatal == LOG_IS_ON(DFATAL));
+}
+
+TEST_F(LoggingTest, LoggingIsLazy) {
+  MockLogSource mock_log_source;
+  EXPECT_CALL(mock_log_source, Log()).Times(0);
+
+  SetMinLogLevel(LOG_WARNING);
+
+  EXPECT_FALSE(LOG_IS_ON(INFO));
+  EXPECT_FALSE(DLOG_IS_ON(INFO));
+  EXPECT_FALSE(VLOG_IS_ON(1));
+
+  LOG(INFO) << mock_log_source.Log();
+  LOG_IF(INFO, false) << mock_log_source.Log();
+  PLOG(INFO) << mock_log_source.Log();
+  PLOG_IF(INFO, false) << mock_log_source.Log();
+  VLOG(1) << mock_log_source.Log();
+  VLOG_IF(1, true) << mock_log_source.Log();
+  VPLOG(1) << mock_log_source.Log();
+  VPLOG_IF(1, true) << mock_log_source.Log();
+
+  DLOG(INFO) << mock_log_source.Log();
+  DLOG_IF(INFO, true) << mock_log_source.Log();
+  DPLOG(INFO) << mock_log_source.Log();
+  DPLOG_IF(INFO, true) << mock_log_source.Log();
+  DVLOG(1) << mock_log_source.Log();
+  DVLOG_IF(1, true) << mock_log_source.Log();
+  DVPLOG(1) << mock_log_source.Log();
+  DVPLOG_IF(1, true) << mock_log_source.Log();
+}
+
+// Official builds have CHECKs directly call BreakDebugger.
+#if !defined(OFFICIAL_BUILD)
+
+TEST_F(LoggingTest, CheckStreamsAreLazy) {
+  MockLogSource mock_log_source, uncalled_mock_log_source;
+  EXPECT_CALL(mock_log_source, Log()).Times(8).
+      WillRepeatedly(Return("check message"));
+  EXPECT_CALL(uncalled_mock_log_source, Log()).Times(0);
+
+  SetLogAssertHandler(&LogSink);
+
+  CHECK(mock_log_source.Log()) << uncalled_mock_log_source.Log();
+  PCHECK(!mock_log_source.Log()) << mock_log_source.Log();
+  CHECK_EQ(mock_log_source.Log(), mock_log_source.Log())
+      << uncalled_mock_log_source.Log();
+  CHECK_NE(mock_log_source.Log(), mock_log_source.Log())
+      << mock_log_source.Log();
+}
+
+#endif
+
+TEST_F(LoggingTest, DebugLoggingReleaseBehavior) {
+#if !defined(NDEBUG)
+  int debug_only_variable = 1;
+#endif
+  // These should avoid emitting references to |debug_only_variable|
+  // in release mode.
+  DLOG_IF(INFO, debug_only_variable) << "test";
+  DLOG_ASSERT(debug_only_variable) << "test";
+  DPLOG_IF(INFO, debug_only_variable) << "test";
+  DVLOG_IF(1, debug_only_variable) << "test";
+}
+
+TEST_F(LoggingTest, DcheckStreamsAreLazy) {
+  MockLogSource mock_log_source;
+  EXPECT_CALL(mock_log_source, Log()).Times(0);
+#if DCHECK_IS_ON()
+  DCHECK(true) << mock_log_source.Log();
+  DCHECK_EQ(0, 0) << mock_log_source.Log();
+#else
+  DCHECK(mock_log_source.Log()) << mock_log_source.Log();
+  DPCHECK(mock_log_source.Log()) << mock_log_source.Log();
+  DCHECK_EQ(0, 0) << mock_log_source.Log();
+  DCHECK_EQ(mock_log_source.Log(), static_cast<const char*>(NULL))
+      << mock_log_source.Log();
+#endif
+}
+
+TEST_F(LoggingTest, Dcheck) {
+#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
+  // Release build.
+  EXPECT_FALSE(DCHECK_IS_ON());
+  EXPECT_FALSE(DLOG_IS_ON(DCHECK));
+#elif defined(NDEBUG) && defined(DCHECK_ALWAYS_ON)
+  // Release build with real DCHECKS.
+  SetLogAssertHandler(&LogSink);
+  EXPECT_TRUE(DCHECK_IS_ON());
+  EXPECT_FALSE(DLOG_IS_ON(DCHECK));
+#else
+  // Debug build.
+  SetLogAssertHandler(&LogSink);
+  EXPECT_TRUE(DCHECK_IS_ON());
+  EXPECT_TRUE(DLOG_IS_ON(DCHECK));
+#endif
+
+  EXPECT_EQ(0, log_sink_call_count);
+  DCHECK(false);
+  EXPECT_EQ(DCHECK_IS_ON() ? 1 : 0, log_sink_call_count);
+  DPCHECK(false);
+  EXPECT_EQ(DCHECK_IS_ON() ? 2 : 0, log_sink_call_count);
+  DCHECK_EQ(0, 1);
+  EXPECT_EQ(DCHECK_IS_ON() ? 3 : 0, log_sink_call_count);
+}
+
+TEST_F(LoggingTest, DcheckReleaseBehavior) {
+  int some_variable = 1;
+  // These should still reference |some_variable| so we don't get
+  // unused variable warnings.
+  DCHECK(some_variable) << "test";
+  DPCHECK(some_variable) << "test";
+  DCHECK_EQ(some_variable, 1) << "test";
+}
+
+// Test that defining an operator<< for a type in a namespace doesn't prevent
+// other code in that namespace from calling the operator<<(ostream, wstring)
+// defined by logging.h. This can fail if operator<<(ostream, wstring) can't be
+// found by ADL, since defining another operator<< prevents name lookup from
+// looking in the global namespace.
+namespace nested_test {
+  class Streamable {};
+  ALLOW_UNUSED_TYPE std::ostream& operator<<(std::ostream& out,
+                                             const Streamable&) {
+    return out << "Streamable";
+  }
+  TEST_F(LoggingTest, StreamingWstringFindsCorrectOperator) {
+    std::wstring wstr = L"Hello World";
+    std::ostringstream ostr;
+    ostr << wstr;
+    EXPECT_EQ("Hello World", ostr.str());
+  }
+}  // namespace nested_test
+
+}  // namespace
+
+}  // namespace logging
diff --git a/base/logging_win.cc b/base/logging_win.cc
new file mode 100644
index 0000000..53cc37c
--- /dev/null
+++ b/base/logging_win.cc
@@ -0,0 +1,138 @@
+// Copyright (c) 2011 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/logging_win.h"
+#include "base/memory/singleton.h"
+#include <initguid.h>  // NOLINT
+
+namespace logging {
+
+using base::win::EtwEventLevel;
+using base::win::EtwMofEvent;
+
+DEFINE_GUID(kLogEventId,
+    0x7fe69228, 0x633e, 0x4f06, 0x80, 0xc1, 0x52, 0x7f, 0xea, 0x23, 0xe3, 0xa7);
+
+LogEventProvider::LogEventProvider() : old_log_level_(LOG_NONE) {
+}
+
+LogEventProvider* LogEventProvider::GetInstance() {
+  return Singleton<LogEventProvider,
+                   StaticMemorySingletonTraits<LogEventProvider> >::get();
+}
+
+bool LogEventProvider::LogMessage(logging::LogSeverity severity,
+    const char* file, int line, size_t message_start,
+    const std::string& message) {
+  EtwEventLevel level = TRACE_LEVEL_NONE;
+
+  // Convert the log severity to the most appropriate ETW trace level.
+  if (severity >= 0) {
+    switch (severity) {
+      case LOG_INFO:
+        level = TRACE_LEVEL_INFORMATION;
+        break;
+      case LOG_WARNING:
+        level = TRACE_LEVEL_WARNING;
+        break;
+      case LOG_ERROR:
+        level = TRACE_LEVEL_ERROR;
+        break;
+      case LOG_FATAL:
+        level = TRACE_LEVEL_FATAL;
+        break;
+    }
+  } else {  // severity < 0 is VLOG verbosity levels.
+    level = static_cast<EtwEventLevel>(TRACE_LEVEL_INFORMATION - severity);
+  }
+
+  // Bail if we're not logging, not at that level,
+  // or if we're post-atexit handling.
+  LogEventProvider* provider = LogEventProvider::GetInstance();
+  if (provider == NULL || level > provider->enable_level())
+    return false;
+
+  // And now log the event.
+  if (provider->enable_flags() & ENABLE_LOG_MESSAGE_ONLY) {
+    EtwMofEvent<1> event(kLogEventId, LOG_MESSAGE, level);
+    event.SetField(0, message.length() + 1 - message_start,
+        message.c_str() + message_start);
+
+    provider->Log(event.get());
+  } else {
+    const size_t kMaxBacktraceDepth = 32;
+    void* backtrace[kMaxBacktraceDepth];
+    DWORD depth = 0;
+
+    // Capture a stack trace if one is requested.
+    // requested per our enable flags.
+    if (provider->enable_flags() & ENABLE_STACK_TRACE_CAPTURE)
+      depth = CaptureStackBackTrace(2, kMaxBacktraceDepth, backtrace, NULL);
+
+    EtwMofEvent<5> event(kLogEventId, LOG_MESSAGE_FULL, level);
+    if (file == NULL)
+      file = "";
+
+    // Add the stack trace.
+    event.SetField(0, sizeof(depth), &depth);
+    event.SetField(1, sizeof(backtrace[0]) * depth, &backtrace);
+    // The line.
+    event.SetField(2, sizeof(line), &line);
+    // The file.
+    event.SetField(3, strlen(file) + 1, file);
+    // And finally the message.
+    event.SetField(4, message.length() + 1 - message_start,
+        message.c_str() + message_start);
+
+    provider->Log(event.get());
+  }
+
+  // Don't increase verbosity in other log destinations.
+  if (severity < provider->old_log_level_)
+    return true;
+
+  return false;
+}
+
+void LogEventProvider::Initialize(const GUID& provider_name) {
+  LogEventProvider* provider = LogEventProvider::GetInstance();
+
+  provider->set_provider_name(provider_name);
+  provider->Register();
+
+  // Register our message handler with logging.
+  SetLogMessageHandler(LogMessage);
+}
+
+void LogEventProvider::Uninitialize() {
+  LogEventProvider::GetInstance()->Unregister();
+}
+
+void LogEventProvider::OnEventsEnabled() {
+  // Grab the old log level so we can restore it later.
+  old_log_level_ = GetMinLogLevel();
+
+  // Convert the new trace level to a logging severity
+  // and enable logging at that level.
+  EtwEventLevel level = enable_level();
+  if (level == TRACE_LEVEL_NONE || level == TRACE_LEVEL_FATAL) {
+    SetMinLogLevel(LOG_FATAL);
+  } else if (level == TRACE_LEVEL_ERROR) {
+    SetMinLogLevel(LOG_ERROR);
+  } else if (level == TRACE_LEVEL_WARNING) {
+    SetMinLogLevel(LOG_WARNING);
+  } else if (level == TRACE_LEVEL_INFORMATION) {
+    SetMinLogLevel(LOG_INFO);
+  } else if (level >= TRACE_LEVEL_VERBOSE) {
+    // Above INFO, we enable verbose levels with negative severities.
+    SetMinLogLevel(TRACE_LEVEL_INFORMATION - level);
+  }
+}
+
+void LogEventProvider::OnEventsDisabled() {
+  // Restore the old log level.
+  SetMinLogLevel(old_log_level_);
+}
+
+}  // namespace logging
diff --git a/base/logging_win.h b/base/logging_win.h
new file mode 100644
index 0000000..aa48e22
--- /dev/null
+++ b/base/logging_win.h
@@ -0,0 +1,80 @@
+// Copyright (c) 2012 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_LOGGING_WIN_H_
+#define BASE_LOGGING_WIN_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/win/event_trace_provider.h"
+#include "base/logging.h"
+
+template <typename Type>
+struct StaticMemorySingletonTraits;
+
+namespace logging {
+
+// Event ID for the log messages we generate.
+EXTERN_C BASE_EXPORT const GUID kLogEventId;
+
+// Feature enable mask for LogEventProvider.
+enum LogEnableMask {
+  // If this bit is set in our provider enable mask, we will include
+  // a stack trace with every log message.
+  ENABLE_STACK_TRACE_CAPTURE = 0x0001,
+  // If this bit is set in our provider enable mask, the provider will log
+  // a LOG message with only the textual content of the message, and no
+  // stack trace.
+  ENABLE_LOG_MESSAGE_ONLY = 0x0002,
+};
+
+// The message types our log event provider generates.
+// ETW likes user message types to start at 10.
+enum LogMessageTypes {
+  // A textual only log message, contains a zero-terminated string.
+  LOG_MESSAGE = 10,
+  // A message with a stack trace, followed by the zero-terminated
+  // message text.
+  LOG_MESSAGE_WITH_STACKTRACE = 11,
+  // A message with:
+  //  a stack trace,
+  //  the line number as a four byte integer,
+  //  the file as a zero terminated UTF8 string,
+  //  the zero-terminated UTF8 message text.
+  LOG_MESSAGE_FULL = 12,
+};
+
+// Trace provider class to drive log control and transport
+// with Event Tracing for Windows.
+class BASE_EXPORT LogEventProvider : public base::win::EtwTraceProvider {
+ public:
+  static LogEventProvider* GetInstance();
+
+  static bool LogMessage(logging::LogSeverity severity, const char* file,
+      int line, size_t message_start, const std::string& str);
+
+  static void Initialize(const GUID& provider_name);
+  static void Uninitialize();
+
+ protected:
+  // Overridden to manipulate the log level on ETW control callbacks.
+  void OnEventsEnabled() override;
+  void OnEventsDisabled() override;
+
+ private:
+  LogEventProvider();
+
+  // The log severity prior to OnEventsEnabled,
+  // restored in OnEventsDisabled.
+  logging::LogSeverity old_log_level_;
+
+  friend struct StaticMemorySingletonTraits<LogEventProvider>;
+  DISALLOW_COPY_AND_ASSIGN(LogEventProvider);
+};
+
+}  // namespace logging
+
+#endif  // BASE_LOGGING_WIN_H_
diff --git a/base/mac/OWNERS b/base/mac/OWNERS
new file mode 100644
index 0000000..b092e06
--- /dev/null
+++ b/base/mac/OWNERS
@@ -0,0 +1,15 @@
+mark@chromium.org
+thakis@chromium.org
+
+# sdk_forward_declarations.[h|mm] will likely need to be modified by Cocoa
+# developers in general; keep in sync with OWNERS of //chrome/browser/ui/cocoa.
+per-file sdk_forward_declarations.*=asvitkine@chromium.org
+per-file sdk_forward_declarations.*=avi@chromium.org
+per-file sdk_forward_declarations.*=groby@chromium.org
+per-file sdk_forward_declarations.*=jeremy@chromium.org
+per-file sdk_forward_declarations.*=mark@chromium.org
+per-file sdk_forward_declarations.*=rohitrao@chromium.org
+per-file sdk_forward_declarations.*=rsesek@chromium.org
+per-file sdk_forward_declarations.*=shess@chromium.org
+per-file sdk_forward_declarations.*=tapted@chromium.org
+per-file sdk_forward_declarations.*=thakis@chromium.org
diff --git a/base/mac/authorization_util.h b/base/mac/authorization_util.h
new file mode 100644
index 0000000..4629039
--- /dev/null
+++ b/base/mac/authorization_util.h
@@ -0,0 +1,82 @@
+// Copyright (c) 2012 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_MAC_AUTHORIZATION_UTIL_H_
+#define BASE_MAC_AUTHORIZATION_UTIL_H_
+
+// AuthorizationExecuteWithPrivileges fork()s and exec()s the tool, but it
+// does not wait() for it.  It also doesn't provide the caller with access to
+// the forked pid.  If used irresponsibly, zombie processes will accumulate.
+//
+// Apple's really gotten us between a rock and a hard place, here.
+//
+// Fortunately, AuthorizationExecuteWithPrivileges does give access to the
+// tool's stdout (and stdin) via a FILE* pipe.  The tool can output its pid
+// to this pipe, and the main program can read it, and then have something
+// that it can wait() for.
+//
+// The contract is that any tool executed by the wrappers declared in this
+// file must print its pid to stdout on a line by itself before doing anything
+// else.
+//
+// http://developer.apple.com/library/mac/#samplecode/BetterAuthorizationSample/Listings/BetterAuthorizationSampleLib_c.html
+// (Look for "What's This About Zombies?")
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <Security/Authorization.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "base/base_export.h"
+
+namespace base {
+namespace mac {
+
+// Obtains an AuthorizationRef for the rights indicated by |rights|.  If
+// necessary, prompts the user for authentication. If the user is prompted,
+// |prompt| will be used as the prompt string and an icon appropriate for the
+// application will be displayed in a prompt dialog. Note that the system
+// appends its own text to the prompt string. |extraFlags| will be ORed
+// together with the default flags. Returns NULL on failure.
+BASE_EXPORT
+AuthorizationRef GetAuthorizationRightsWithPrompt(
+    AuthorizationRights* rights,
+    CFStringRef prompt,
+    AuthorizationFlags extraFlags);
+
+// Obtains an AuthorizationRef (using |GetAuthorizationRightsWithPrompt|) that
+// can be used to run commands as root.
+BASE_EXPORT
+AuthorizationRef AuthorizationCreateToRunAsRoot(CFStringRef prompt);
+
+// Calls straight through to AuthorizationExecuteWithPrivileges.  If that
+// call succeeds, |pid| will be set to the pid of the executed tool.  If the
+// pid can't be determined, |pid| will be set to -1.  |pid| must not be NULL.
+// |pipe| may be NULL, but the tool will always be executed with a pipe in
+// order to read the pid from its stdout.
+BASE_EXPORT
+OSStatus ExecuteWithPrivilegesAndGetPID(AuthorizationRef authorization,
+                                        const char* tool_path,
+                                        AuthorizationFlags options,
+                                        const char** arguments,
+                                        FILE** pipe,
+                                        pid_t* pid);
+
+// Calls ExecuteWithPrivilegesAndGetPID, and if that call succeeds, calls
+// waitpid() to wait for the process to exit.  If waitpid() succeeds, the
+// exit status is placed in |exit_status|, otherwise, -1 is stored.
+// |exit_status| may be NULL and this function will still wait for the process
+// to exit.
+BASE_EXPORT
+OSStatus ExecuteWithPrivilegesAndWait(AuthorizationRef authorization,
+                                      const char* tool_path,
+                                      AuthorizationFlags options,
+                                      const char** arguments,
+                                      FILE** pipe,
+                                      int* exit_status);
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_AUTHORIZATION_UTIL_H_
diff --git a/base/mac/authorization_util.mm b/base/mac/authorization_util.mm
new file mode 100644
index 0000000..1dfd5a0
--- /dev/null
+++ b/base/mac/authorization_util.mm
@@ -0,0 +1,195 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/authorization_util.h"
+
+#import <Foundation/Foundation.h>
+#include <sys/wait.h>
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/mac/bundle_locations.h"
+#include "base/mac/foundation_util.h"
+#include "base/mac/mac_logging.h"
+#include "base/mac/scoped_authorizationref.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+
+namespace base {
+namespace mac {
+
+AuthorizationRef GetAuthorizationRightsWithPrompt(
+    AuthorizationRights* rights,
+    CFStringRef prompt,
+    AuthorizationFlags extraFlags) {
+  // Create an empty AuthorizationRef.
+  ScopedAuthorizationRef authorization;
+  OSStatus status = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment,
+                                        kAuthorizationFlagDefaults,
+                                        authorization.get_pointer());
+  if (status != errAuthorizationSuccess) {
+    OSSTATUS_LOG(ERROR, status) << "AuthorizationCreate";
+    return NULL;
+  }
+
+  AuthorizationFlags flags = kAuthorizationFlagDefaults |
+                             kAuthorizationFlagInteractionAllowed |
+                             kAuthorizationFlagExtendRights |
+                             kAuthorizationFlagPreAuthorize |
+                             extraFlags;
+
+  // product_logo_32.png is used instead of app.icns because Authorization
+  // Services can't deal with .icns files.
+  NSString* icon_path =
+      [base::mac::FrameworkBundle() pathForResource:@"product_logo_32"
+                                             ofType:@"png"];
+  const char* icon_path_c = [icon_path fileSystemRepresentation];
+  size_t icon_path_length = icon_path_c ? strlen(icon_path_c) : 0;
+
+  // The OS will append " Type an administrator's name and password to allow
+  // <CFBundleDisplayName> to make changes."
+  NSString* prompt_ns = base::mac::CFToNSCast(prompt);
+  const char* prompt_c = [prompt_ns UTF8String];
+  size_t prompt_length = prompt_c ? strlen(prompt_c) : 0;
+
+  AuthorizationItem environment_items[] = {
+    {kAuthorizationEnvironmentIcon, icon_path_length, (void*)icon_path_c, 0},
+    {kAuthorizationEnvironmentPrompt, prompt_length, (void*)prompt_c, 0}
+  };
+
+  AuthorizationEnvironment environment = {arraysize(environment_items),
+                                          environment_items};
+
+  status = AuthorizationCopyRights(authorization,
+                                   rights,
+                                   &environment,
+                                   flags,
+                                   NULL);
+
+  if (status != errAuthorizationSuccess) {
+    if (status != errAuthorizationCanceled) {
+      OSSTATUS_LOG(ERROR, status) << "AuthorizationCopyRights";
+    }
+    return NULL;
+  }
+
+  return authorization.release();
+}
+
+AuthorizationRef AuthorizationCreateToRunAsRoot(CFStringRef prompt) {
+  // Specify the "system.privilege.admin" right, which allows
+  // AuthorizationExecuteWithPrivileges to run commands as root.
+  AuthorizationItem right_items[] = {
+    {kAuthorizationRightExecute, 0, NULL, 0}
+  };
+  AuthorizationRights rights = {arraysize(right_items), right_items};
+
+  return GetAuthorizationRightsWithPrompt(&rights, prompt, 0);
+}
+
+OSStatus ExecuteWithPrivilegesAndGetPID(AuthorizationRef authorization,
+                                        const char* tool_path,
+                                        AuthorizationFlags options,
+                                        const char** arguments,
+                                        FILE** pipe,
+                                        pid_t* pid) {
+  // pipe may be NULL, but this function needs one.  In that case, use a local
+  // pipe.
+  FILE* local_pipe;
+  FILE** pipe_pointer;
+  if (pipe) {
+    pipe_pointer = pipe;
+  } else {
+    pipe_pointer = &local_pipe;
+  }
+
+  // AuthorizationExecuteWithPrivileges wants |char* const*| for |arguments|,
+  // but it doesn't actually modify the arguments, and that type is kind of
+  // silly and callers probably aren't dealing with that.  Put the cast here
+  // to make things a little easier on callers.
+  OSStatus status = AuthorizationExecuteWithPrivileges(authorization,
+                                                       tool_path,
+                                                       options,
+                                                       (char* const*)arguments,
+                                                       pipe_pointer);
+  if (status != errAuthorizationSuccess) {
+    return status;
+  }
+
+  int line_pid = -1;
+  size_t line_length = 0;
+  char* line_c = fgetln(*pipe_pointer, &line_length);
+  if (line_c) {
+    if (line_length > 0 && line_c[line_length - 1] == '\n') {
+      // line_c + line_length is the start of the next line if there is one.
+      // Back up one character.
+      --line_length;
+    }
+    std::string line(line_c, line_length);
+    if (!base::StringToInt(line, &line_pid)) {
+      // StringToInt may have set line_pid to something, but if the conversion
+      // was imperfect, use -1.
+      LOG(ERROR) << "ExecuteWithPrivilegesAndGetPid: funny line: " << line;
+      line_pid = -1;
+    }
+  } else {
+    LOG(ERROR) << "ExecuteWithPrivilegesAndGetPid: no line";
+  }
+
+  if (!pipe) {
+    fclose(*pipe_pointer);
+  }
+
+  if (pid) {
+    *pid = line_pid;
+  }
+
+  return status;
+}
+
+OSStatus ExecuteWithPrivilegesAndWait(AuthorizationRef authorization,
+                                      const char* tool_path,
+                                      AuthorizationFlags options,
+                                      const char** arguments,
+                                      FILE** pipe,
+                                      int* exit_status) {
+  pid_t pid;
+  OSStatus status = ExecuteWithPrivilegesAndGetPID(authorization,
+                                                   tool_path,
+                                                   options,
+                                                   arguments,
+                                                   pipe,
+                                                   &pid);
+  if (status != errAuthorizationSuccess) {
+    return status;
+  }
+
+  // exit_status may be NULL, but this function needs it.  In that case, use a
+  // local version.
+  int local_exit_status;
+  int* exit_status_pointer;
+  if (exit_status) {
+    exit_status_pointer = exit_status;
+  } else {
+    exit_status_pointer = &local_exit_status;
+  }
+
+  if (pid != -1) {
+    pid_t wait_result = HANDLE_EINTR(waitpid(pid, exit_status_pointer, 0));
+    if (wait_result != pid) {
+      PLOG(ERROR) << "waitpid";
+      *exit_status_pointer = -1;
+    }
+  } else {
+    *exit_status_pointer = -1;
+  }
+
+  return status;
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/bind_objc_block.h b/base/mac/bind_objc_block.h
new file mode 100644
index 0000000..c31f26e
--- /dev/null
+++ b/base/mac/bind_objc_block.h
@@ -0,0 +1,54 @@
+// Copyright (c) 2012 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_MAC_BIND_OBJC_BLOCK_H_
+#define BASE_MAC_BIND_OBJC_BLOCK_H_
+
+#include <Block.h>
+
+#include "base/bind.h"
+#include "base/callback_forward.h"
+#include "base/mac/scoped_block.h"
+
+// BindBlock builds a callback from an Objective-C block. Example usages:
+//
+// Closure closure = BindBlock(^{DoSomething();});
+//
+// Callback<int(void)> callback = BindBlock(^{return 42;});
+//
+// Callback<void(const std::string&, const std::string&)> callback =
+//     BindBlock(^(const std::string& arg0, const std::string& arg1) {
+//         ...
+//     });
+//
+// These variadic templates will accommodate any number of arguments, however
+// the underlying templates in bind_internal.h and callback.h are limited to
+// seven total arguments, and the bound block itself is used as one of these
+// arguments, so functionally the templates are limited to binding blocks with
+// zero through six arguments.
+
+namespace base {
+
+namespace internal {
+
+// Helper function to run the block contained in the parameter.
+template<typename R, typename... Args>
+R RunBlock(base::mac::ScopedBlock<R(^)(Args...)> block, Args... args) {
+  R(^extracted_block)(Args...) = block.get();
+  return extracted_block(args...);
+}
+
+}  // namespace internal
+
+// Construct a callback from an objective-C block with up to six arguments (see
+// note above).
+template<typename R, typename... Args>
+base::Callback<R(Args...)> BindBlock(R(^block)(Args...)) {
+  return base::Bind(&base::internal::RunBlock<R, Args...>,
+                    base::mac::ScopedBlock<R(^)(Args...)>(Block_copy(block)));
+}
+
+}  // namespace base
+
+#endif  // BASE_MAC_BIND_OBJC_BLOCK_H_
diff --git a/base/mac/bind_objc_block_unittest.mm b/base/mac/bind_objc_block_unittest.mm
new file mode 100644
index 0000000..c0e690c
--- /dev/null
+++ b/base/mac/bind_objc_block_unittest.mm
@@ -0,0 +1,99 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "base/mac/bind_objc_block.h"
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/callback_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+TEST(BindObjcBlockTest, TestScopedClosureRunnerExitScope) {
+  int run_count = 0;
+  int* ptr = &run_count;
+  {
+    base::ScopedClosureRunner runner(base::BindBlock(^{
+        (*ptr)++;
+    }));
+    EXPECT_EQ(0, run_count);
+  }
+  EXPECT_EQ(1, run_count);
+}
+
+TEST(BindObjcBlockTest, TestScopedClosureRunnerRelease) {
+  int run_count = 0;
+  int* ptr = &run_count;
+  base::Closure c;
+  {
+    base::ScopedClosureRunner runner(base::BindBlock(^{
+        (*ptr)++;
+    }));
+    c = runner.Release();
+    EXPECT_EQ(0, run_count);
+  }
+  EXPECT_EQ(0, run_count);
+  c.Run();
+  EXPECT_EQ(1, run_count);
+}
+
+TEST(BindObjcBlockTest, TestReturnValue) {
+  const int kReturnValue = 42;
+  base::Callback<int(void)> c = base::BindBlock(^{return kReturnValue;});
+  EXPECT_EQ(kReturnValue, c.Run());
+}
+
+TEST(BindObjcBlockTest, TestArgument) {
+  const int kArgument = 42;
+  base::Callback<int(int)> c = base::BindBlock(^(int a){return a + 1;});
+  EXPECT_EQ(kArgument + 1, c.Run(kArgument));
+}
+
+TEST(BindObjcBlockTest, TestTwoArguments) {
+  std::string result;
+  std::string* ptr = &result;
+  base::Callback<void(const std::string&, const std::string&)> c =
+      base::BindBlock(^(const std::string& a, const std::string& b) {
+          *ptr = a + b;
+      });
+  c.Run("forty", "two");
+  EXPECT_EQ(result, "fortytwo");
+}
+
+TEST(BindObjcBlockTest, TestThreeArguments) {
+  std::string result;
+  std::string* ptr = &result;
+  base::Callback<void(const std::string&,
+                      const std::string&,
+                      const std::string&)> c =
+      base::BindBlock(^(const std::string& a,
+                        const std::string& b,
+                        const std::string& c) {
+          *ptr = a + b + c;
+      });
+  c.Run("six", "times", "nine");
+  EXPECT_EQ(result, "sixtimesnine");
+}
+
+TEST(BindObjcBlockTest, TestSixArguments) {
+  std::string result1;
+  std::string* ptr = &result1;
+  int result2;
+  int* ptr2 = &result2;
+  base::Callback<void(int, int, const std::string&, const std::string&,
+                      int, const std::string&)> c =
+      base::BindBlock(^(int a, int b, const std::string& c,
+                        const std::string& d, int e, const std::string& f) {
+          *ptr = c + d + f;
+          *ptr2 = a + b + e;
+      });
+  c.Run(1, 2, "infinite", "improbability", 3, "drive");
+  EXPECT_EQ(result1, "infiniteimprobabilitydrive");
+  EXPECT_EQ(result2, 6);
+}
+
+}  // namespace
diff --git a/base/mac/bundle_locations.h b/base/mac/bundle_locations.h
new file mode 100644
index 0000000..276290b
--- /dev/null
+++ b/base/mac/bundle_locations.h
@@ -0,0 +1,67 @@
+// Copyright (c) 2012 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_MAC_BUNDLE_LOCATIONS_H_
+#define BASE_MAC_BUNDLE_LOCATIONS_H_
+
+#include "base/base_export.h"
+#include "base/files/file_path.h"
+
+#if defined(__OBJC__)
+#import <Foundation/Foundation.h>
+#else  // __OBJC__
+class NSBundle;
+class NSString;
+#endif  // __OBJC__
+
+namespace base {
+
+class FilePath;
+
+namespace mac {
+
+// This file provides several functions to explicitly request the various
+// component bundles of Chrome.  Please use these methods rather than calling
+// +[NSBundle mainBundle] or CFBundleGetMainBundle().
+//
+// Terminology
+//  - "Outer Bundle" - This is the main bundle for Chrome; it's what
+//  +[NSBundle mainBundle] returns when Chrome is launched normally.
+//
+//  - "Main Bundle" - This is the bundle from which Chrome was launched.
+//  This will be the same as the outer bundle except when Chrome is launched
+//  via an app shortcut, in which case this will return the app shortcut's
+//  bundle rather than the main Chrome bundle.
+//
+//  - "Framework Bundle" - This is the bundle corresponding to the Chrome
+//  framework.
+//
+// Guidelines for use:
+//  - To access a resource, the Framework bundle should be used.
+//  - If the choice is between the Outer or Main bundles then please choose
+//  carefully.  Most often the Outer bundle will be the right choice, but for
+//  cases such as adding an app to the "launch on startup" list, the Main
+//  bundle is probably the one to use.
+
+// Methods for retrieving the various bundles.
+BASE_EXPORT NSBundle* MainBundle();
+BASE_EXPORT FilePath MainBundlePath();
+BASE_EXPORT NSBundle* OuterBundle();
+BASE_EXPORT FilePath OuterBundlePath();
+BASE_EXPORT NSBundle* FrameworkBundle();
+BASE_EXPORT FilePath FrameworkBundlePath();
+
+// Set the bundle that the preceding functions will return, overriding the
+// default values. Restore the default by passing in |nil|.
+BASE_EXPORT void SetOverrideOuterBundle(NSBundle* bundle);
+BASE_EXPORT void SetOverrideFrameworkBundle(NSBundle* bundle);
+
+// Same as above but accepting a FilePath argument.
+BASE_EXPORT void SetOverrideOuterBundlePath(const FilePath& file_path);
+BASE_EXPORT void SetOverrideFrameworkBundlePath(const FilePath& file_path);
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_BUNDLE_LOCATIONS_H_
diff --git a/base/mac/bundle_locations.mm b/base/mac/bundle_locations.mm
new file mode 100644
index 0000000..54021b8
--- /dev/null
+++ b/base/mac/bundle_locations.mm
@@ -0,0 +1,83 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/bundle_locations.h"
+
+#include "base/logging.h"
+#include "base/mac/foundation_util.h"
+#include "base/strings/sys_string_conversions.h"
+
+namespace base {
+namespace mac {
+
+// NSBundle isn't threadsafe, all functions in this file must be called on the
+// main thread.
+static NSBundle* g_override_framework_bundle = nil;
+static NSBundle* g_override_outer_bundle = nil;
+
+NSBundle* MainBundle() {
+  return [NSBundle mainBundle];
+}
+
+FilePath MainBundlePath() {
+  NSBundle* bundle = MainBundle();
+  return NSStringToFilePath([bundle bundlePath]);
+}
+
+NSBundle* OuterBundle() {
+  if (g_override_outer_bundle)
+    return g_override_outer_bundle;
+  return [NSBundle mainBundle];
+}
+
+FilePath OuterBundlePath() {
+  NSBundle* bundle = OuterBundle();
+  return NSStringToFilePath([bundle bundlePath]);
+}
+
+NSBundle* FrameworkBundle() {
+  if (g_override_framework_bundle)
+    return g_override_framework_bundle;
+  return [NSBundle mainBundle];
+}
+
+FilePath FrameworkBundlePath() {
+  NSBundle* bundle = FrameworkBundle();
+  return NSStringToFilePath([bundle bundlePath]);
+}
+
+static void AssignOverrideBundle(NSBundle* new_bundle,
+                                 NSBundle** override_bundle) {
+  if (new_bundle != *override_bundle) {
+    [*override_bundle release];
+    *override_bundle = [new_bundle retain];
+  }
+}
+
+static void AssignOverridePath(const FilePath& file_path,
+                               NSBundle** override_bundle) {
+  NSString* path = base::SysUTF8ToNSString(file_path.value());
+  NSBundle* new_bundle = [NSBundle bundleWithPath:path];
+  DCHECK(new_bundle) << "Failed to load the bundle at " << file_path.value();
+  AssignOverrideBundle(new_bundle, override_bundle);
+}
+
+void SetOverrideOuterBundle(NSBundle* bundle) {
+  AssignOverrideBundle(bundle, &g_override_outer_bundle);
+}
+
+void SetOverrideFrameworkBundle(NSBundle* bundle) {
+  AssignOverrideBundle(bundle, &g_override_framework_bundle);
+}
+
+void SetOverrideOuterBundlePath(const FilePath& file_path) {
+  AssignOverridePath(file_path, &g_override_outer_bundle);
+}
+
+void SetOverrideFrameworkBundlePath(const FilePath& file_path) {
+  AssignOverridePath(file_path, &g_override_framework_bundle);
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/close_nocancel.cc b/base/mac/close_nocancel.cc
new file mode 100644
index 0000000..8971e73
--- /dev/null
+++ b/base/mac/close_nocancel.cc
@@ -0,0 +1,70 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// http://crbug.com/269623
+// http://openradar.appspot.com/14999594
+//
+// When the default version of close used on Mac OS X fails with EINTR, the
+// file descriptor is not in a deterministic state. It may have been closed,
+// or it may not have been. This makes it impossible to gracefully recover
+// from the error. If the close is retried after the FD has been closed, the
+// subsequent close can report EBADF, or worse, it can close an unrelated FD
+// opened by another thread. If the close is not retried after the FD has been
+// left open, the FD is leaked. Neither of these are good options.
+//
+// Mac OS X provides an alternate version of close, close$NOCANCEL. This
+// version will never fail with EINTR before the FD is actually closed. With
+// this version, it is thus safe to call close without checking for EINTR (as
+// the HANDLE_EINTR macro does) and not risk leaking the FD. In fact, mixing
+// this verison of close with HANDLE_EINTR is hazardous.
+//
+// The $NOCANCEL variants of various system calls are activated by compiling
+// with __DARWIN_NON_CANCELABLE, which prevents them from being pthread
+// cancellation points. Rather than taking such a heavy-handed approach, this
+// file implements an alternative: to use the $NOCANCEL variant of close (thus
+// preventing it from being a pthread cancellation point) without affecting
+// any other system calls.
+//
+// This file operates by providing a close function with the non-$NOCANCEL
+// symbol name expected for the compilation environment as set by <unistd.h>
+// and <sys/cdefs.h> (the DARWIN_ALIAS_C macro). That name is set by an asm
+// label on the declaration of the close function, so the definition of that
+// function receives that name. The function calls the $NOCANCEL variant, which
+// is resolved from libsyscall. By linking with this version of close prior to
+// the libsyscall version, close's implementation is overridden.
+
+#include <sys/cdefs.h>
+#include <unistd.h>
+
+// If the non-cancelable variants of all system calls have already been
+// chosen, do nothing.
+#if !__DARWIN_NON_CANCELABLE
+
+extern "C" {
+
+#if !__DARWIN_ONLY_UNIX_CONFORMANCE
+
+// When there's a choice between UNIX2003 and pre-UNIX2003. There's no
+// close$NOCANCEL symbol in this case, so use close$NOCANCEL$UNIX2003 as the
+// implementation. It does the same thing that close$NOCANCEL would do.
+#define close_implementation close$NOCANCEL$UNIX2003
+
+#else  // __DARWIN_ONLY_UNIX_CONFORMANCE
+
+// When only UNIX2003 is supported:
+#define close_implementation close$NOCANCEL
+
+#endif
+
+int close_implementation(int fd);
+
+int close(int fd) {
+  return close_implementation(fd);
+}
+
+#undef close_implementation
+
+}  // extern "C"
+
+#endif  // !__DARWIN_NON_CANCELABLE
diff --git a/base/mac/cocoa_protocols.h b/base/mac/cocoa_protocols.h
new file mode 100644
index 0000000..a28795c
--- /dev/null
+++ b/base/mac/cocoa_protocols.h
@@ -0,0 +1,31 @@
+// Copyright (c) 2012 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_MAC_COCOA_PROTOCOLS_H_
+#define BASE_MAC_COCOA_PROTOCOLS_H_
+
+#import <Cocoa/Cocoa.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
+// delegates to conform to these protocols, and earlier SDKs, which do not
+// define these protocols at all, this file will provide empty protocol
+// definitions when used with earlier SDK versions.
+
+#define DEFINE_EMPTY_PROTOCOL(p) \
+@protocol p \
+@end
+
+#if !defined(MAC_OS_X_VERSION_10_7) || \
+    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
+
+DEFINE_EMPTY_PROTOCOL(NSDraggingDestination)
+DEFINE_EMPTY_PROTOCOL(ICCameraDeviceDownloadDelegate)
+
+#endif  // MAC_OS_X_VERSION_10_7
+
+#undef DEFINE_EMPTY_PROTOCOL
+
+#endif  // BASE_MAC_COCOA_PROTOCOLS_H_
diff --git a/base/mac/dispatch_source_mach.cc b/base/mac/dispatch_source_mach.cc
new file mode 100644
index 0000000..745c9de
--- /dev/null
+++ b/base/mac/dispatch_source_mach.cc
@@ -0,0 +1,62 @@
+// 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.
+
+#include "base/mac/dispatch_source_mach.h"
+
+namespace base {
+
+DispatchSourceMach::DispatchSourceMach(const char* name,
+                                       mach_port_t port,
+                                       void (^event_handler)())
+    // TODO(rsesek): Specify DISPATCH_QUEUE_SERIAL, in the 10.7 SDK. NULL
+    // means the same thing but is not symbolically clear.
+    : DispatchSourceMach(dispatch_queue_create(name, NULL),
+                         port,
+                         event_handler) {
+  // Since the queue was created above in the delegated constructor, and it was
+  // subsequently retained, release it here.
+  dispatch_release(queue_);
+}
+
+DispatchSourceMach::DispatchSourceMach(dispatch_queue_t queue,
+                                       mach_port_t port,
+                                       void (^event_handler)())
+    : queue_(queue),
+      source_(dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV,
+          port, 0, queue_)),
+      source_canceled_(dispatch_semaphore_create(0)) {
+  dispatch_retain(queue);
+
+  dispatch_source_set_event_handler(source_, event_handler);
+  dispatch_source_set_cancel_handler(source_, ^{
+      dispatch_semaphore_signal(source_canceled_);
+  });
+}
+
+DispatchSourceMach::~DispatchSourceMach() {
+  Cancel();
+}
+
+void DispatchSourceMach::Resume() {
+  dispatch_resume(source_);
+}
+
+void DispatchSourceMach::Cancel() {
+  if (source_) {
+    dispatch_source_cancel(source_);
+    dispatch_release(source_);
+    source_ = NULL;
+
+    dispatch_semaphore_wait(source_canceled_, DISPATCH_TIME_FOREVER);
+    dispatch_release(source_canceled_);
+    source_canceled_ = NULL;
+  }
+
+  if (queue_) {
+    dispatch_release(queue_);
+    queue_ = NULL;
+  }
+}
+
+}  // namespace base
diff --git a/base/mac/dispatch_source_mach.h b/base/mac/dispatch_source_mach.h
new file mode 100644
index 0000000..e7d5cb2
--- /dev/null
+++ b/base/mac/dispatch_source_mach.h
@@ -0,0 +1,61 @@
+// 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.
+
+#ifndef BASE_MAC_DISPATCH_SOURCE_MACH_H_
+#define BASE_MAC_DISPATCH_SOURCE_MACH_H_
+
+#include <dispatch/dispatch.h>
+
+#include "base/base_export.h"
+#include "base/macros.h"
+
+namespace base {
+
+// This class encapsulates a MACH_RECV dispatch source. When this object is
+// destroyed, the source will be cancelled and it will wait for the source
+// to stop executing work. The source can run on either a user-supplied queue,
+// or it can create its own for the source.
+class BASE_EXPORT DispatchSourceMach {
+ public:
+  // Creates a new dispatch source for the |port| and schedules it on a new
+  // queue that will be created with |name|. When a Mach message is received,
+  // the |event_handler| will be called.
+  DispatchSourceMach(const char* name,
+                     mach_port_t port,
+                     void (^event_handler)());
+
+  // Creates a new dispatch source with the same semantics as above, but rather
+  // than creating a new queue, it schedules the source on |queue|.
+  DispatchSourceMach(dispatch_queue_t queue,
+                     mach_port_t port,
+                     void (^event_handler)());
+
+  // Cancels the source and waits for it to become fully cancelled before
+  // releasing the source.
+  ~DispatchSourceMach();
+
+  // Resumes the source. This must be called before any Mach messages will
+  // be received.
+  void Resume();
+
+ private:
+  // Cancels the source, after which this class will no longer receive Mach
+  // messages. Calling this more than once is a no-op.
+  void Cancel();
+
+  // The dispatch queue used to service the source_.
+  dispatch_queue_t queue_;
+
+  // A MACH_RECV dispatch source.
+  dispatch_source_t source_;
+
+  // Semaphore used to wait on the |source_|'s cancellation in the destructor.
+  dispatch_semaphore_t source_canceled_;
+
+  DISALLOW_COPY_AND_ASSIGN(DispatchSourceMach);
+};
+
+}  // namespace base
+
+#endif  // BASE_MAC_DISPATCH_SOURCE_MACH_H_
diff --git a/base/mac/dispatch_source_mach_unittest.cc b/base/mac/dispatch_source_mach_unittest.cc
new file mode 100644
index 0000000..82dc136
--- /dev/null
+++ b/base/mac/dispatch_source_mach_unittest.cc
@@ -0,0 +1,125 @@
+// 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.
+
+#include "base/mac/dispatch_source_mach.h"
+
+#include <mach/mach.h>
+
+#include "base/logging.h"
+#include "base/mac/scoped_mach_port.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/test/test_timeouts.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+class DispatchSourceMachTest : public testing::Test {
+ public:
+  void SetUp() override {
+    mach_port_t port = MACH_PORT_NULL;
+    ASSERT_EQ(KERN_SUCCESS, mach_port_allocate(mach_task_self(),
+        MACH_PORT_RIGHT_RECEIVE, &port));
+    receive_right_.reset(port);
+
+    ASSERT_EQ(KERN_SUCCESS, mach_port_insert_right(mach_task_self(), port,
+        port, MACH_MSG_TYPE_MAKE_SEND));
+    send_right_.reset(port);
+  }
+
+  mach_port_t GetPort() { return receive_right_.get(); }
+
+  void WaitForSemaphore(dispatch_semaphore_t semaphore) {
+    dispatch_semaphore_wait(semaphore, dispatch_time(
+        DISPATCH_TIME_NOW,
+        TestTimeouts::action_timeout().InSeconds() * NSEC_PER_SEC));
+  }
+
+ private:
+  base::mac::ScopedMachReceiveRight receive_right_;
+  base::mac::ScopedMachSendRight send_right_;
+};
+
+TEST_F(DispatchSourceMachTest, ReceiveAfterResume) {
+  dispatch_semaphore_t signal = dispatch_semaphore_create(0);
+  mach_port_t port = GetPort();
+
+  bool __block did_receive = false;
+  DispatchSourceMach source("org.chromium.base.test.ReceiveAfterResume",
+      port, ^{
+          mach_msg_empty_rcv_t msg = {{0}};
+          msg.header.msgh_size = sizeof(msg);
+          msg.header.msgh_local_port = port;
+          mach_msg_receive(&msg.header);
+          did_receive = true;
+
+          dispatch_semaphore_signal(signal);
+      });
+
+  mach_msg_empty_send_t msg = {{0}};
+  msg.header.msgh_size = sizeof(msg);
+  msg.header.msgh_remote_port = port;
+  msg.header.msgh_bits = MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_COPY_SEND);
+  ASSERT_EQ(KERN_SUCCESS, mach_msg_send(&msg.header));
+
+  EXPECT_FALSE(did_receive);
+
+  source.Resume();
+
+  WaitForSemaphore(signal);
+  dispatch_release(signal);
+
+  EXPECT_TRUE(did_receive);
+}
+
+TEST_F(DispatchSourceMachTest, NoMessagesAfterDestruction) {
+  mach_port_t port = GetPort();
+
+  scoped_ptr<int> count(new int(0));
+  int* __block count_ptr = count.get();
+
+  scoped_ptr<DispatchSourceMach> source(new DispatchSourceMach(
+      "org.chromium.base.test.NoMessagesAfterDestruction",
+      port, ^{
+          mach_msg_empty_rcv_t msg = {{0}};
+          msg.header.msgh_size = sizeof(msg);
+          msg.header.msgh_local_port = port;
+          mach_msg_receive(&msg.header);
+          LOG(INFO) << "Receieve " << *count_ptr;
+          ++(*count_ptr);
+      }));
+  source->Resume();
+
+  dispatch_queue_t queue =
+      dispatch_queue_create("org.chromium.base.test.MessageSend", NULL);
+  dispatch_semaphore_t signal = dispatch_semaphore_create(0);
+  for (int i = 0; i < 30; ++i) {
+    dispatch_async(queue, ^{
+        mach_msg_empty_send_t msg = {{0}};
+        msg.header.msgh_size = sizeof(msg);
+        msg.header.msgh_remote_port = port;
+        msg.header.msgh_bits =
+            MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_COPY_SEND);
+        mach_msg_send(&msg.header);
+    });
+
+    // After sending five messages, shut down the source and taint the
+    // pointer the handler dereferences. The test will crash if |count_ptr|
+    // is being used after "free".
+    if (i == 5) {
+      scoped_ptr<DispatchSourceMach>* source_ptr = &source;
+      dispatch_async(queue, ^{
+          source_ptr->reset();
+          count_ptr = reinterpret_cast<int*>(0xdeaddead);
+          dispatch_semaphore_signal(signal);
+      });
+    }
+  }
+
+  WaitForSemaphore(signal);
+  dispatch_release(signal);
+
+  dispatch_release(queue);
+}
+
+}  // namespace base
diff --git a/base/mac/foundation_util.h b/base/mac/foundation_util.h
new file mode 100644
index 0000000..353ed7c
--- /dev/null
+++ b/base/mac/foundation_util.h
@@ -0,0 +1,389 @@
+// Copyright (c) 2012 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_MAC_FOUNDATION_UTIL_H_
+#define BASE_MAC_FOUNDATION_UTIL_H_
+
+#include <CoreFoundation/CoreFoundation.h>
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/logging.h"
+#include "base/mac/scoped_cftyperef.h"
+
+#if defined(__OBJC__)
+#import <Foundation/Foundation.h>
+@class NSFont;
+@class UIFont;
+#else  // __OBJC__
+#include <CoreFoundation/CoreFoundation.h>
+class NSBundle;
+class NSFont;
+class NSString;
+class UIFont;
+#endif  // __OBJC__
+
+#if defined(OS_IOS)
+#include <CoreText/CoreText.h>
+#else
+#include <ApplicationServices/ApplicationServices.h>
+#endif
+
+// Adapted from NSObjCRuntime.h NS_ENUM definition (used in Foundation starting
+// with the OS X 10.8 SDK and the iOS 6.0 SDK).
+#if __has_extension(cxx_strong_enums) && \
+    (defined(OS_IOS) || (defined(MAC_OS_X_VERSION_10_8) && \
+                         MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8))
+#define CR_FORWARD_ENUM(_type, _name) enum _name : _type _name
+#else
+#define CR_FORWARD_ENUM(_type, _name) _type _name
+#endif
+
+// Adapted from NSPathUtilities.h and NSObjCRuntime.h.
+#if __LP64__ || NS_BUILD_32_LIKE_64
+typedef CR_FORWARD_ENUM(unsigned long, NSSearchPathDirectory);
+typedef unsigned long NSSearchPathDomainMask;
+#else
+typedef CR_FORWARD_ENUM(unsigned int, NSSearchPathDirectory);
+typedef unsigned int NSSearchPathDomainMask;
+#endif
+
+typedef struct OpaqueSecTrustRef* SecACLRef;
+typedef struct OpaqueSecTrustedApplicationRef* SecTrustedApplicationRef;
+
+namespace base {
+
+class FilePath;
+
+namespace mac {
+
+// Returns true if the application is running from a bundle
+BASE_EXPORT bool AmIBundled();
+BASE_EXPORT void SetOverrideAmIBundled(bool value);
+
+#if defined(UNIT_TEST)
+// This is required because instantiating some tests requires checking the
+// directory structure, which sets the AmIBundled cache state. Individual tests
+// may or may not be bundled, and this would trip them up if the cache weren't
+// cleared. This should not be called from individual tests, just from test
+// instantiation code that gets a path from PathService.
+BASE_EXPORT void ClearAmIBundledCache();
+#endif
+
+// Returns true if this process is marked as a "Background only process".
+BASE_EXPORT bool IsBackgroundOnlyProcess();
+
+// Returns the path to a resource within the framework bundle.
+BASE_EXPORT FilePath PathForFrameworkBundleResource(CFStringRef resourceName);
+
+// Returns the creator code associated with the CFBundleRef at bundle.
+OSType CreatorCodeForCFBundleRef(CFBundleRef bundle);
+
+// Returns the creator code associated with this application, by calling
+// CreatorCodeForCFBundleRef for the application's main bundle.  If this
+// information cannot be determined, returns kUnknownType ('????').  This
+// does not respect the override app bundle because it's based on CFBundle
+// instead of NSBundle, and because callers probably don't want the override
+// app bundle's creator code anyway.
+BASE_EXPORT OSType CreatorCodeForApplication();
+
+// Searches for directories for the given key in only the given |domain_mask|.
+// If found, fills result (which must always be non-NULL) with the
+// first found directory and returns true.  Otherwise, returns false.
+BASE_EXPORT bool GetSearchPathDirectory(NSSearchPathDirectory directory,
+                                        NSSearchPathDomainMask domain_mask,
+                                        FilePath* result);
+
+// Searches for directories for the given key in only the local domain.
+// If found, fills result (which must always be non-NULL) with the
+// first found directory and returns true.  Otherwise, returns false.
+BASE_EXPORT bool GetLocalDirectory(NSSearchPathDirectory directory,
+                                   FilePath* result);
+
+// Searches for directories for the given key in only the user domain.
+// If found, fills result (which must always be non-NULL) with the
+// first found directory and returns true.  Otherwise, returns false.
+BASE_EXPORT bool GetUserDirectory(NSSearchPathDirectory directory,
+                                  FilePath* result);
+
+// Returns the ~/Library directory.
+BASE_EXPORT FilePath GetUserLibraryPath();
+
+// Takes a path to an (executable) binary and tries to provide the path to an
+// application bundle containing it. It takes the outermost bundle that it can
+// find (so for "/Foo/Bar.app/.../Baz.app/..." it produces "/Foo/Bar.app").
+//   |exec_name| - path to the binary
+//   returns - path to the application bundle, or empty on error
+BASE_EXPORT FilePath GetAppBundlePath(const FilePath& exec_name);
+
+#define TYPE_NAME_FOR_CF_TYPE_DECL(TypeCF) \
+BASE_EXPORT std::string TypeNameForCFType(TypeCF##Ref);
+
+TYPE_NAME_FOR_CF_TYPE_DECL(CFArray);
+TYPE_NAME_FOR_CF_TYPE_DECL(CFBag);
+TYPE_NAME_FOR_CF_TYPE_DECL(CFBoolean);
+TYPE_NAME_FOR_CF_TYPE_DECL(CFData);
+TYPE_NAME_FOR_CF_TYPE_DECL(CFDate);
+TYPE_NAME_FOR_CF_TYPE_DECL(CFDictionary);
+TYPE_NAME_FOR_CF_TYPE_DECL(CFNull);
+TYPE_NAME_FOR_CF_TYPE_DECL(CFNumber);
+TYPE_NAME_FOR_CF_TYPE_DECL(CFSet);
+TYPE_NAME_FOR_CF_TYPE_DECL(CFString);
+TYPE_NAME_FOR_CF_TYPE_DECL(CFURL);
+TYPE_NAME_FOR_CF_TYPE_DECL(CFUUID);
+
+TYPE_NAME_FOR_CF_TYPE_DECL(CGColor);
+
+TYPE_NAME_FOR_CF_TYPE_DECL(CTFont);
+TYPE_NAME_FOR_CF_TYPE_DECL(CTRun);
+
+#undef TYPE_NAME_FOR_CF_TYPE_DECL
+
+// Retain/release calls for memory management in C++.
+BASE_EXPORT void NSObjectRetain(void* obj);
+BASE_EXPORT void NSObjectRelease(void* obj);
+
+// CFTypeRefToNSObjectAutorelease transfers ownership of a Core Foundation
+// object (one derived from CFTypeRef) to the Foundation memory management
+// system.  In a traditional managed-memory environment, cf_object is
+// autoreleased and returned as an NSObject.  In a garbage-collected
+// environment, cf_object is marked as eligible for garbage collection.
+//
+// This function should only be used to convert a concrete CFTypeRef type to
+// its equivalent "toll-free bridged" NSObject subclass, for example,
+// converting a CFStringRef to NSString.
+//
+// By calling this function, callers relinquish any ownership claim to
+// cf_object.  In a managed-memory environment, the object's ownership will be
+// managed by the innermost NSAutoreleasePool, so after this function returns,
+// callers should not assume that cf_object is valid any longer than the
+// returned NSObject.
+//
+// Returns an id, typed here for C++'s sake as a void*.
+BASE_EXPORT void* CFTypeRefToNSObjectAutorelease(CFTypeRef cf_object);
+
+// Returns the base bundle ID, which can be set by SetBaseBundleID but
+// defaults to a reasonable string. This never returns NULL. BaseBundleID
+// returns a pointer to static storage that must not be freed.
+BASE_EXPORT const char* BaseBundleID();
+
+// Sets the base bundle ID to override the default. The implementation will
+// make its own copy of new_base_bundle_id.
+BASE_EXPORT void SetBaseBundleID(const char* new_base_bundle_id);
+
+}  // namespace mac
+}  // namespace base
+
+#if !defined(__OBJC__)
+#define OBJC_CPP_CLASS_DECL(x) class x;
+#else  // __OBJC__
+#define OBJC_CPP_CLASS_DECL(x)
+#endif  // __OBJC__
+
+// Convert toll-free bridged CFTypes to NSTypes and vice-versa. This does not
+// autorelease |cf_val|. This is useful for the case where there is a CFType in
+// a call that expects an NSType and the compiler is complaining about const
+// casting problems.
+// The calls are used like this:
+// NSString *foo = CFToNSCast(CFSTR("Hello"));
+// CFStringRef foo2 = NSToCFCast(@"Hello");
+// The macro magic below is to enforce safe casting. It could possibly have
+// been done using template function specialization, but template function
+// specialization doesn't always work intuitively,
+// (http://www.gotw.ca/publications/mill17.htm) so the trusty combination
+// of macros and function overloading is used instead.
+
+#define CF_TO_NS_CAST_DECL(TypeCF, TypeNS) \
+OBJC_CPP_CLASS_DECL(TypeNS) \
+\
+namespace base { \
+namespace mac { \
+BASE_EXPORT TypeNS* CFToNSCast(TypeCF##Ref cf_val); \
+BASE_EXPORT TypeCF##Ref NSToCFCast(TypeNS* ns_val); \
+} \
+}
+
+#define CF_TO_NS_MUTABLE_CAST_DECL(name) \
+CF_TO_NS_CAST_DECL(CF##name, NS##name) \
+OBJC_CPP_CLASS_DECL(NSMutable##name) \
+\
+namespace base { \
+namespace mac { \
+BASE_EXPORT NSMutable##name* CFToNSCast(CFMutable##name##Ref cf_val); \
+BASE_EXPORT CFMutable##name##Ref NSToCFCast(NSMutable##name* ns_val); \
+} \
+}
+
+// List of toll-free bridged types taken from:
+// http://www.cocoadev.com/index.pl?TollFreeBridged
+
+CF_TO_NS_MUTABLE_CAST_DECL(Array);
+CF_TO_NS_MUTABLE_CAST_DECL(AttributedString);
+CF_TO_NS_CAST_DECL(CFCalendar, NSCalendar);
+CF_TO_NS_MUTABLE_CAST_DECL(CharacterSet);
+CF_TO_NS_MUTABLE_CAST_DECL(Data);
+CF_TO_NS_CAST_DECL(CFDate, NSDate);
+CF_TO_NS_MUTABLE_CAST_DECL(Dictionary);
+CF_TO_NS_CAST_DECL(CFError, NSError);
+CF_TO_NS_CAST_DECL(CFLocale, NSLocale);
+CF_TO_NS_CAST_DECL(CFNumber, NSNumber);
+CF_TO_NS_CAST_DECL(CFRunLoopTimer, NSTimer);
+CF_TO_NS_CAST_DECL(CFTimeZone, NSTimeZone);
+CF_TO_NS_MUTABLE_CAST_DECL(Set);
+CF_TO_NS_CAST_DECL(CFReadStream, NSInputStream);
+CF_TO_NS_CAST_DECL(CFWriteStream, NSOutputStream);
+CF_TO_NS_MUTABLE_CAST_DECL(String);
+CF_TO_NS_CAST_DECL(CFURL, NSURL);
+
+#if defined(OS_IOS)
+CF_TO_NS_CAST_DECL(CTFont, UIFont);
+#else
+CF_TO_NS_CAST_DECL(CTFont, NSFont);
+#endif
+
+#undef CF_TO_NS_CAST_DECL
+#undef CF_TO_NS_MUTABLE_CAST_DECL
+#undef OBJC_CPP_CLASS_DECL
+
+namespace base {
+namespace mac {
+
+// CFCast<>() and CFCastStrict<>() cast a basic CFTypeRef to a more
+// specific CoreFoundation type. The compatibility of the passed
+// object is found by comparing its opaque type against the
+// requested type identifier. If the supplied object is not
+// compatible with the requested return type, CFCast<>() returns
+// NULL and CFCastStrict<>() will DCHECK. Providing a NULL pointer
+// to either variant results in NULL being returned without
+// triggering any DCHECK.
+//
+// Example usage:
+// CFNumberRef some_number = base::mac::CFCast<CFNumberRef>(
+//     CFArrayGetValueAtIndex(array, index));
+//
+// CFTypeRef hello = CFSTR("hello world");
+// CFStringRef some_string = base::mac::CFCastStrict<CFStringRef>(hello);
+
+template<typename T>
+T CFCast(const CFTypeRef& cf_val);
+
+template<typename T>
+T CFCastStrict(const CFTypeRef& cf_val);
+
+#define CF_CAST_DECL(TypeCF) \
+template<> BASE_EXPORT TypeCF##Ref \
+CFCast<TypeCF##Ref>(const CFTypeRef& cf_val);\
+\
+template<> BASE_EXPORT TypeCF##Ref \
+CFCastStrict<TypeCF##Ref>(const CFTypeRef& cf_val);
+
+CF_CAST_DECL(CFArray);
+CF_CAST_DECL(CFBag);
+CF_CAST_DECL(CFBoolean);
+CF_CAST_DECL(CFData);
+CF_CAST_DECL(CFDate);
+CF_CAST_DECL(CFDictionary);
+CF_CAST_DECL(CFNull);
+CF_CAST_DECL(CFNumber);
+CF_CAST_DECL(CFSet);
+CF_CAST_DECL(CFString);
+CF_CAST_DECL(CFURL);
+CF_CAST_DECL(CFUUID);
+
+CF_CAST_DECL(CGColor);
+
+CF_CAST_DECL(CTFont);
+CF_CAST_DECL(CTFontDescriptor);
+CF_CAST_DECL(CTRun);
+
+CF_CAST_DECL(SecACL);
+CF_CAST_DECL(SecTrustedApplication);
+
+#undef CF_CAST_DECL
+
+#if defined(__OBJC__)
+
+// ObjCCast<>() and ObjCCastStrict<>() cast a basic id to a more
+// specific (NSObject-derived) type. The compatibility of the passed
+// object is found by checking if it's a kind of the requested type
+// identifier. If the supplied object is not compatible with the
+// requested return type, ObjCCast<>() returns nil and
+// ObjCCastStrict<>() will DCHECK. Providing a nil pointer to either
+// variant results in nil being returned without triggering any DCHECK.
+//
+// The strict variant is useful when retrieving a value from a
+// collection which only has values of a specific type, e.g. an
+// NSArray of NSStrings. The non-strict variant is useful when
+// retrieving values from data that you can't fully control. For
+// example, a plist read from disk may be beyond your exclusive
+// control, so you'd only want to check that the values you retrieve
+// from it are of the expected types, but not crash if they're not.
+//
+// Example usage:
+// NSString* version = base::mac::ObjCCast<NSString>(
+//     [bundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"]);
+//
+// NSString* str = base::mac::ObjCCastStrict<NSString>(
+//     [ns_arr_of_ns_strs objectAtIndex:0]);
+template<typename T>
+T* ObjCCast(id objc_val) {
+  if ([objc_val isKindOfClass:[T class]]) {
+    return reinterpret_cast<T*>(objc_val);
+  }
+  return nil;
+}
+
+template<typename T>
+T* ObjCCastStrict(id objc_val) {
+  T* rv = ObjCCast<T>(objc_val);
+  DCHECK(objc_val == nil || rv);
+  return rv;
+}
+
+#endif  // defined(__OBJC__)
+
+// Helper function for GetValueFromDictionary to create the error message
+// that appears when a type mismatch is encountered.
+BASE_EXPORT std::string GetValueFromDictionaryErrorMessage(
+    CFStringRef key, const std::string& expected_type, CFTypeRef value);
+
+// Utility function to pull out a value from a dictionary, check its type, and
+// return it. Returns NULL if the key is not present or of the wrong type.
+template<typename T>
+T GetValueFromDictionary(CFDictionaryRef dict, CFStringRef key) {
+  CFTypeRef value = CFDictionaryGetValue(dict, key);
+  T value_specific = CFCast<T>(value);
+
+  if (value && !value_specific) {
+    std::string expected_type = TypeNameForCFType(value_specific);
+    DLOG(WARNING) << GetValueFromDictionaryErrorMessage(key,
+                                                        expected_type,
+                                                        value);
+  }
+
+  return value_specific;
+}
+
+// Converts |path| to an autoreleased NSString. Returns nil if |path| is empty.
+BASE_EXPORT NSString* FilePathToNSString(const FilePath& path);
+
+// Converts |str| to a FilePath. Returns an empty path if |str| is nil.
+BASE_EXPORT FilePath NSStringToFilePath(NSString* str);
+
+}  // namespace mac
+}  // namespace base
+
+// Stream operations for CFTypes. They can be used with NSTypes as well
+// by using the NSToCFCast methods above.
+// e.g. LOG(INFO) << base::mac::NSToCFCast(@"foo");
+// Operator << can not be overloaded for ObjectiveC types as the compiler
+// can not distinguish between overloads for id with overloads for void*.
+BASE_EXPORT extern std::ostream& operator<<(std::ostream& o,
+                                            const CFErrorRef err);
+BASE_EXPORT extern std::ostream& operator<<(std::ostream& o,
+                                            const CFStringRef str);
+
+#endif  // BASE_MAC_FOUNDATION_UTIL_H_
diff --git a/base/mac/foundation_util.mm b/base/mac/foundation_util.mm
new file mode 100644
index 0000000..27d6e7c
--- /dev/null
+++ b/base/mac/foundation_util.mm
@@ -0,0 +1,455 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/foundation_util.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/mac/bundle_locations.h"
+#include "base/mac/mac_logging.h"
+#include "base/strings/sys_string_conversions.h"
+
+#if !defined(OS_IOS)
+extern "C" {
+CFTypeID SecACLGetTypeID();
+CFTypeID SecTrustedApplicationGetTypeID();
+Boolean _CFIsObjC(CFTypeID typeID, CFTypeRef obj);
+}  // extern "C"
+#endif
+
+namespace base {
+namespace mac {
+
+namespace {
+
+bool g_cached_am_i_bundled_called = false;
+bool g_cached_am_i_bundled_value = false;
+bool g_override_am_i_bundled = false;
+bool g_override_am_i_bundled_value = false;
+
+bool UncachedAmIBundled() {
+#if defined(OS_IOS)
+  // All apps are bundled on iOS.
+  return true;
+#else
+  if (g_override_am_i_bundled)
+    return g_override_am_i_bundled_value;
+
+  // Yes, this is cheap.
+  return [[base::mac::OuterBundle() bundlePath] hasSuffix:@".app"];
+#endif
+}
+
+}  // namespace
+
+bool AmIBundled() {
+  // If the return value is not cached, this function will return different
+  // values depending on when it's called. This confuses some client code, see
+  // http://crbug.com/63183 .
+  if (!g_cached_am_i_bundled_called) {
+    g_cached_am_i_bundled_called = true;
+    g_cached_am_i_bundled_value = UncachedAmIBundled();
+  }
+  DCHECK_EQ(g_cached_am_i_bundled_value, UncachedAmIBundled())
+      << "The return value of AmIBundled() changed. This will confuse tests. "
+      << "Call SetAmIBundled() override manually if your test binary "
+      << "delay-loads the framework.";
+  return g_cached_am_i_bundled_value;
+}
+
+void SetOverrideAmIBundled(bool value) {
+#if defined(OS_IOS)
+  // It doesn't make sense not to be bundled on iOS.
+  if (!value)
+    NOTREACHED();
+#endif
+  g_override_am_i_bundled = true;
+  g_override_am_i_bundled_value = value;
+}
+
+BASE_EXPORT void ClearAmIBundledCache() {
+  g_cached_am_i_bundled_called = false;
+}
+
+bool IsBackgroundOnlyProcess() {
+  // This function really does want to examine NSBundle's idea of the main
+  // bundle dictionary.  It needs to look at the actual running .app's
+  // Info.plist to access its LSUIElement property.
+  NSDictionary* info_dictionary = [base::mac::MainBundle() infoDictionary];
+  return [[info_dictionary objectForKey:@"LSUIElement"] boolValue] != NO;
+}
+
+FilePath PathForFrameworkBundleResource(CFStringRef resourceName) {
+  NSBundle* bundle = base::mac::FrameworkBundle();
+  NSString* resourcePath = [bundle pathForResource:(NSString*)resourceName
+                                            ofType:nil];
+  return NSStringToFilePath(resourcePath);
+}
+
+OSType CreatorCodeForCFBundleRef(CFBundleRef bundle) {
+  OSType creator = kUnknownType;
+  CFBundleGetPackageInfo(bundle, NULL, &creator);
+  return creator;
+}
+
+OSType CreatorCodeForApplication() {
+  CFBundleRef bundle = CFBundleGetMainBundle();
+  if (!bundle)
+    return kUnknownType;
+
+  return CreatorCodeForCFBundleRef(bundle);
+}
+
+bool GetSearchPathDirectory(NSSearchPathDirectory directory,
+                            NSSearchPathDomainMask domain_mask,
+                            FilePath* result) {
+  DCHECK(result);
+  NSArray* dirs =
+      NSSearchPathForDirectoriesInDomains(directory, domain_mask, YES);
+  if ([dirs count] < 1) {
+    return false;
+  }
+  *result = NSStringToFilePath([dirs objectAtIndex:0]);
+  return true;
+}
+
+bool GetLocalDirectory(NSSearchPathDirectory directory, FilePath* result) {
+  return GetSearchPathDirectory(directory, NSLocalDomainMask, result);
+}
+
+bool GetUserDirectory(NSSearchPathDirectory directory, FilePath* result) {
+  return GetSearchPathDirectory(directory, NSUserDomainMask, result);
+}
+
+FilePath GetUserLibraryPath() {
+  FilePath user_library_path;
+  if (!GetUserDirectory(NSLibraryDirectory, &user_library_path)) {
+    DLOG(WARNING) << "Could not get user library path";
+  }
+  return user_library_path;
+}
+
+// Takes a path to an (executable) binary and tries to provide the path to an
+// application bundle containing it. It takes the outermost bundle that it can
+// find (so for "/Foo/Bar.app/.../Baz.app/..." it produces "/Foo/Bar.app").
+//   |exec_name| - path to the binary
+//   returns - path to the application bundle, or empty on error
+FilePath GetAppBundlePath(const FilePath& exec_name) {
+  const char kExt[] = ".app";
+  const size_t kExtLength = arraysize(kExt) - 1;
+
+  // Split the path into components.
+  std::vector<std::string> components;
+  exec_name.GetComponents(&components);
+
+  // It's an error if we don't get any components.
+  if (!components.size())
+    return FilePath();
+
+  // Don't prepend '/' to the first component.
+  std::vector<std::string>::const_iterator it = components.begin();
+  std::string bundle_name = *it;
+  DCHECK_GT(it->length(), 0U);
+  // If the first component ends in ".app", we're already done.
+  if (it->length() > kExtLength &&
+      !it->compare(it->length() - kExtLength, kExtLength, kExt, kExtLength))
+    return FilePath(bundle_name);
+
+  // The first component may be "/" or "//", etc. Only append '/' if it doesn't
+  // already end in '/'.
+  if (bundle_name[bundle_name.length() - 1] != '/')
+    bundle_name += '/';
+
+  // Go through the remaining components.
+  for (++it; it != components.end(); ++it) {
+    DCHECK_GT(it->length(), 0U);
+
+    bundle_name += *it;
+
+    // If the current component ends in ".app", we're done.
+    if (it->length() > kExtLength &&
+        !it->compare(it->length() - kExtLength, kExtLength, kExt, kExtLength))
+      return FilePath(bundle_name);
+
+    // Separate this component from the next one.
+    bundle_name += '/';
+  }
+
+  return FilePath();
+}
+
+#define TYPE_NAME_FOR_CF_TYPE_DEFN(TypeCF) \
+std::string TypeNameForCFType(TypeCF##Ref) { \
+  return #TypeCF; \
+}
+
+TYPE_NAME_FOR_CF_TYPE_DEFN(CFArray);
+TYPE_NAME_FOR_CF_TYPE_DEFN(CFBag);
+TYPE_NAME_FOR_CF_TYPE_DEFN(CFBoolean);
+TYPE_NAME_FOR_CF_TYPE_DEFN(CFData);
+TYPE_NAME_FOR_CF_TYPE_DEFN(CFDate);
+TYPE_NAME_FOR_CF_TYPE_DEFN(CFDictionary);
+TYPE_NAME_FOR_CF_TYPE_DEFN(CFNull);
+TYPE_NAME_FOR_CF_TYPE_DEFN(CFNumber);
+TYPE_NAME_FOR_CF_TYPE_DEFN(CFSet);
+TYPE_NAME_FOR_CF_TYPE_DEFN(CFString);
+TYPE_NAME_FOR_CF_TYPE_DEFN(CFURL);
+TYPE_NAME_FOR_CF_TYPE_DEFN(CFUUID);
+
+TYPE_NAME_FOR_CF_TYPE_DEFN(CGColor);
+
+TYPE_NAME_FOR_CF_TYPE_DEFN(CTFont);
+TYPE_NAME_FOR_CF_TYPE_DEFN(CTRun);
+
+#undef TYPE_NAME_FOR_CF_TYPE_DEFN
+
+void NSObjectRetain(void* obj) {
+  id<NSObject> nsobj = static_cast<id<NSObject> >(obj);
+  [nsobj retain];
+}
+
+void NSObjectRelease(void* obj) {
+  id<NSObject> nsobj = static_cast<id<NSObject> >(obj);
+  [nsobj release];
+}
+
+void* CFTypeRefToNSObjectAutorelease(CFTypeRef cf_object) {
+  // When GC is on, NSMakeCollectable marks cf_object for GC and autorelease
+  // is a no-op.
+  //
+  // In the traditional GC-less environment, NSMakeCollectable is a no-op,
+  // and cf_object is autoreleased, balancing out the caller's ownership claim.
+  //
+  // NSMakeCollectable returns nil when used on a NULL object.
+  return [NSMakeCollectable(cf_object) autorelease];
+}
+
+static const char* base_bundle_id;
+
+const char* BaseBundleID() {
+  if (base_bundle_id) {
+    return base_bundle_id;
+  }
+
+#if defined(GOOGLE_CHROME_BUILD)
+  return "com.google.Chrome";
+#else
+  return "org.chromium.Chromium";
+#endif
+}
+
+void SetBaseBundleID(const char* new_base_bundle_id) {
+  if (new_base_bundle_id != base_bundle_id) {
+    free((void*)base_bundle_id);
+    base_bundle_id = new_base_bundle_id ? strdup(new_base_bundle_id) : NULL;
+  }
+}
+
+// Definitions for the corresponding CF_TO_NS_CAST_DECL macros in
+// foundation_util.h.
+#define CF_TO_NS_CAST_DEFN(TypeCF, TypeNS) \
+\
+TypeNS* CFToNSCast(TypeCF##Ref cf_val) { \
+  DCHECK(!cf_val || TypeCF##GetTypeID() == CFGetTypeID(cf_val)); \
+  TypeNS* ns_val = \
+      const_cast<TypeNS*>(reinterpret_cast<const TypeNS*>(cf_val)); \
+  return ns_val; \
+} \
+\
+TypeCF##Ref NSToCFCast(TypeNS* ns_val) { \
+  TypeCF##Ref cf_val = reinterpret_cast<TypeCF##Ref>(ns_val); \
+  DCHECK(!cf_val || TypeCF##GetTypeID() == CFGetTypeID(cf_val)); \
+  return cf_val; \
+}
+
+#define CF_TO_NS_MUTABLE_CAST_DEFN(name) \
+CF_TO_NS_CAST_DEFN(CF##name, NS##name) \
+\
+NSMutable##name* CFToNSCast(CFMutable##name##Ref cf_val) { \
+  DCHECK(!cf_val || CF##name##GetTypeID() == CFGetTypeID(cf_val)); \
+  NSMutable##name* ns_val = reinterpret_cast<NSMutable##name*>(cf_val); \
+  return ns_val; \
+} \
+\
+CFMutable##name##Ref NSToCFCast(NSMutable##name* ns_val) { \
+  CFMutable##name##Ref cf_val = \
+      reinterpret_cast<CFMutable##name##Ref>(ns_val); \
+  DCHECK(!cf_val || CF##name##GetTypeID() == CFGetTypeID(cf_val)); \
+  return cf_val; \
+}
+
+CF_TO_NS_MUTABLE_CAST_DEFN(Array);
+CF_TO_NS_MUTABLE_CAST_DEFN(AttributedString);
+CF_TO_NS_CAST_DEFN(CFCalendar, NSCalendar);
+CF_TO_NS_MUTABLE_CAST_DEFN(CharacterSet);
+CF_TO_NS_MUTABLE_CAST_DEFN(Data);
+CF_TO_NS_CAST_DEFN(CFDate, NSDate);
+CF_TO_NS_MUTABLE_CAST_DEFN(Dictionary);
+CF_TO_NS_CAST_DEFN(CFError, NSError);
+CF_TO_NS_CAST_DEFN(CFLocale, NSLocale);
+CF_TO_NS_CAST_DEFN(CFNumber, NSNumber);
+CF_TO_NS_CAST_DEFN(CFRunLoopTimer, NSTimer);
+CF_TO_NS_CAST_DEFN(CFTimeZone, NSTimeZone);
+CF_TO_NS_MUTABLE_CAST_DEFN(Set);
+CF_TO_NS_CAST_DEFN(CFReadStream, NSInputStream);
+CF_TO_NS_CAST_DEFN(CFWriteStream, NSOutputStream);
+CF_TO_NS_MUTABLE_CAST_DEFN(String);
+CF_TO_NS_CAST_DEFN(CFURL, NSURL);
+
+#if defined(OS_IOS)
+CF_TO_NS_CAST_DEFN(CTFont, UIFont);
+#else
+// The NSFont/CTFont toll-free bridging is broken when it comes to type
+// checking, so do some special-casing.
+// http://www.openradar.me/15341349 rdar://15341349
+NSFont* CFToNSCast(CTFontRef cf_val) {
+  NSFont* ns_val =
+      const_cast<NSFont*>(reinterpret_cast<const NSFont*>(cf_val));
+  DCHECK(!cf_val ||
+         CTFontGetTypeID() == CFGetTypeID(cf_val) ||
+         (_CFIsObjC(CTFontGetTypeID(), cf_val) &&
+          [ns_val isKindOfClass:NSClassFromString(@"NSFont")]));
+  return ns_val;
+}
+
+CTFontRef NSToCFCast(NSFont* ns_val) {
+  CTFontRef cf_val = reinterpret_cast<CTFontRef>(ns_val);
+  DCHECK(!cf_val ||
+         CTFontGetTypeID() == CFGetTypeID(cf_val) ||
+         [ns_val isKindOfClass:NSClassFromString(@"NSFont")]);
+  return cf_val;
+}
+#endif
+
+#undef CF_TO_NS_CAST_DEFN
+#undef CF_TO_NS_MUTABLE_CAST_DEFN
+
+#define CF_CAST_DEFN(TypeCF) \
+template<> TypeCF##Ref \
+CFCast<TypeCF##Ref>(const CFTypeRef& cf_val) { \
+  if (cf_val == NULL) { \
+    return NULL; \
+  } \
+  if (CFGetTypeID(cf_val) == TypeCF##GetTypeID()) { \
+    return (TypeCF##Ref)(cf_val); \
+  } \
+  return NULL; \
+} \
+\
+template<> TypeCF##Ref \
+CFCastStrict<TypeCF##Ref>(const CFTypeRef& cf_val) { \
+  TypeCF##Ref rv = CFCast<TypeCF##Ref>(cf_val); \
+  DCHECK(cf_val == NULL || rv); \
+  return rv; \
+}
+
+CF_CAST_DEFN(CFArray);
+CF_CAST_DEFN(CFBag);
+CF_CAST_DEFN(CFBoolean);
+CF_CAST_DEFN(CFData);
+CF_CAST_DEFN(CFDate);
+CF_CAST_DEFN(CFDictionary);
+CF_CAST_DEFN(CFNull);
+CF_CAST_DEFN(CFNumber);
+CF_CAST_DEFN(CFSet);
+CF_CAST_DEFN(CFString);
+CF_CAST_DEFN(CFURL);
+CF_CAST_DEFN(CFUUID);
+
+CF_CAST_DEFN(CGColor);
+
+CF_CAST_DEFN(CTFontDescriptor);
+CF_CAST_DEFN(CTRun);
+
+#if defined(OS_IOS)
+CF_CAST_DEFN(CTFont);
+#else
+// The NSFont/CTFont toll-free bridging is broken when it comes to type
+// checking, so do some special-casing.
+// http://www.openradar.me/15341349 rdar://15341349
+template<> CTFontRef
+CFCast<CTFontRef>(const CFTypeRef& cf_val) {
+  if (cf_val == NULL) {
+    return NULL;
+  }
+  if (CFGetTypeID(cf_val) == CTFontGetTypeID()) {
+    return (CTFontRef)(cf_val);
+  }
+
+  if (!_CFIsObjC(CTFontGetTypeID(), cf_val))
+    return NULL;
+
+  id<NSObject> ns_val = reinterpret_cast<id>(const_cast<void*>(cf_val));
+  if ([ns_val isKindOfClass:NSClassFromString(@"NSFont")]) {
+    return (CTFontRef)(cf_val);
+  }
+  return NULL;
+}
+
+template<> CTFontRef
+CFCastStrict<CTFontRef>(const CFTypeRef& cf_val) {
+  CTFontRef rv = CFCast<CTFontRef>(cf_val);
+  DCHECK(cf_val == NULL || rv);
+  return rv;
+}
+#endif
+
+#if !defined(OS_IOS)
+CF_CAST_DEFN(SecACL);
+CF_CAST_DEFN(SecTrustedApplication);
+#endif
+
+#undef CF_CAST_DEFN
+
+std::string GetValueFromDictionaryErrorMessage(
+    CFStringRef key, const std::string& expected_type, CFTypeRef value) {
+  ScopedCFTypeRef<CFStringRef> actual_type_ref(
+      CFCopyTypeIDDescription(CFGetTypeID(value)));
+  return "Expected value for key " +
+      base::SysCFStringRefToUTF8(key) +
+      " to be " +
+      expected_type +
+      " but it was " +
+      base::SysCFStringRefToUTF8(actual_type_ref) +
+      " instead";
+}
+
+NSString* FilePathToNSString(const FilePath& path) {
+  if (path.empty())
+    return nil;
+  return [NSString stringWithUTF8String:path.value().c_str()];
+}
+
+FilePath NSStringToFilePath(NSString* str) {
+  if (![str length])
+    return FilePath();
+  return FilePath([str fileSystemRepresentation]);
+}
+
+}  // namespace mac
+}  // namespace base
+
+std::ostream& operator<<(std::ostream& o, const CFStringRef string) {
+  return o << base::SysCFStringRefToUTF8(string);
+}
+
+std::ostream& operator<<(std::ostream& o, const CFErrorRef err) {
+  base::ScopedCFTypeRef<CFStringRef> desc(CFErrorCopyDescription(err));
+  base::ScopedCFTypeRef<CFDictionaryRef> user_info(CFErrorCopyUserInfo(err));
+  CFStringRef errorDesc = NULL;
+  if (user_info.get()) {
+    errorDesc = reinterpret_cast<CFStringRef>(
+        CFDictionaryGetValue(user_info.get(), kCFErrorDescriptionKey));
+  }
+  o << "Code: " << CFErrorGetCode(err)
+    << " Domain: " << CFErrorGetDomain(err)
+    << " Desc: " << desc.get();
+  if(errorDesc) {
+    o << "(" << errorDesc << ")";
+  }
+  return o;
+}
diff --git a/base/mac/foundation_util_unittest.mm b/base/mac/foundation_util_unittest.mm
new file mode 100644
index 0000000..e60a0f6
--- /dev/null
+++ b/base/mac/foundation_util_unittest.mm
@@ -0,0 +1,391 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/foundation_util.h"
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/files/file_path.h"
+#include "base/format_macros.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/mac/scoped_nsautorelease_pool.h"
+#include "base/strings/stringprintf.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#import "testing/gtest_mac.h"
+
+namespace base {
+namespace mac {
+
+TEST(FoundationUtilTest, CFCast) {
+  // Build out the CF types to be tested as empty containers.
+  ScopedCFTypeRef<CFTypeRef> test_array(
+      CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks));
+  ScopedCFTypeRef<CFTypeRef> test_array_mutable(
+      CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks));
+  ScopedCFTypeRef<CFTypeRef> test_bag(
+      CFBagCreate(NULL, NULL, 0, &kCFTypeBagCallBacks));
+  ScopedCFTypeRef<CFTypeRef> test_bag_mutable(
+      CFBagCreateMutable(NULL, 0, &kCFTypeBagCallBacks));
+  CFTypeRef test_bool = kCFBooleanTrue;
+  ScopedCFTypeRef<CFTypeRef> test_data(
+      CFDataCreate(NULL, NULL, 0));
+  ScopedCFTypeRef<CFTypeRef> test_data_mutable(
+      CFDataCreateMutable(NULL, 0));
+  ScopedCFTypeRef<CFTypeRef> test_date(
+      CFDateCreate(NULL, 0));
+  ScopedCFTypeRef<CFTypeRef> test_dict(
+      CFDictionaryCreate(NULL, NULL, NULL, 0,
+                         &kCFCopyStringDictionaryKeyCallBacks,
+                         &kCFTypeDictionaryValueCallBacks));
+  ScopedCFTypeRef<CFTypeRef> test_dict_mutable(
+      CFDictionaryCreateMutable(NULL, 0,
+                                &kCFCopyStringDictionaryKeyCallBacks,
+                                &kCFTypeDictionaryValueCallBacks));
+  int int_val = 256;
+  ScopedCFTypeRef<CFTypeRef> test_number(
+      CFNumberCreate(NULL, kCFNumberIntType, &int_val));
+  CFTypeRef test_null = kCFNull;
+  ScopedCFTypeRef<CFTypeRef> test_set(
+      CFSetCreate(NULL, NULL, 0, &kCFTypeSetCallBacks));
+  ScopedCFTypeRef<CFTypeRef> test_set_mutable(
+      CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks));
+  ScopedCFTypeRef<CFTypeRef> test_str(
+      CFStringCreateWithBytes(NULL, NULL, 0, kCFStringEncodingASCII, false));
+  CFTypeRef test_str_const = CFSTR("hello");
+  ScopedCFTypeRef<CFTypeRef> test_str_mutable(CFStringCreateMutable(NULL, 0));
+
+  // Make sure the allocations of CF types are good.
+  EXPECT_TRUE(test_array);
+  EXPECT_TRUE(test_array_mutable);
+  EXPECT_TRUE(test_bag);
+  EXPECT_TRUE(test_bag_mutable);
+  EXPECT_TRUE(test_bool);
+  EXPECT_TRUE(test_data);
+  EXPECT_TRUE(test_data_mutable);
+  EXPECT_TRUE(test_date);
+  EXPECT_TRUE(test_dict);
+  EXPECT_TRUE(test_dict_mutable);
+  EXPECT_TRUE(test_number);
+  EXPECT_TRUE(test_null);
+  EXPECT_TRUE(test_set);
+  EXPECT_TRUE(test_set_mutable);
+  EXPECT_TRUE(test_str);
+  EXPECT_TRUE(test_str_const);
+  EXPECT_TRUE(test_str_mutable);
+
+  // Casting the CFTypeRef objects correctly provides the same pointer.
+  EXPECT_EQ(test_array, CFCast<CFArrayRef>(test_array));
+  EXPECT_EQ(test_array_mutable, CFCast<CFArrayRef>(test_array_mutable));
+  EXPECT_EQ(test_bag, CFCast<CFBagRef>(test_bag));
+  EXPECT_EQ(test_bag_mutable, CFCast<CFBagRef>(test_bag_mutable));
+  EXPECT_EQ(test_bool, CFCast<CFBooleanRef>(test_bool));
+  EXPECT_EQ(test_data, CFCast<CFDataRef>(test_data));
+  EXPECT_EQ(test_data_mutable, CFCast<CFDataRef>(test_data_mutable));
+  EXPECT_EQ(test_date, CFCast<CFDateRef>(test_date));
+  EXPECT_EQ(test_dict, CFCast<CFDictionaryRef>(test_dict));
+  EXPECT_EQ(test_dict_mutable, CFCast<CFDictionaryRef>(test_dict_mutable));
+  EXPECT_EQ(test_number, CFCast<CFNumberRef>(test_number));
+  EXPECT_EQ(test_null, CFCast<CFNullRef>(test_null));
+  EXPECT_EQ(test_set, CFCast<CFSetRef>(test_set));
+  EXPECT_EQ(test_set_mutable, CFCast<CFSetRef>(test_set_mutable));
+  EXPECT_EQ(test_str, CFCast<CFStringRef>(test_str));
+  EXPECT_EQ(test_str_const, CFCast<CFStringRef>(test_str_const));
+  EXPECT_EQ(test_str_mutable, CFCast<CFStringRef>(test_str_mutable));
+
+  // When given an incorrect CF cast, provide NULL.
+  EXPECT_FALSE(CFCast<CFStringRef>(test_array));
+  EXPECT_FALSE(CFCast<CFStringRef>(test_array_mutable));
+  EXPECT_FALSE(CFCast<CFStringRef>(test_bag));
+  EXPECT_FALSE(CFCast<CFSetRef>(test_bag_mutable));
+  EXPECT_FALSE(CFCast<CFSetRef>(test_bool));
+  EXPECT_FALSE(CFCast<CFNullRef>(test_data));
+  EXPECT_FALSE(CFCast<CFDictionaryRef>(test_data_mutable));
+  EXPECT_FALSE(CFCast<CFDictionaryRef>(test_date));
+  EXPECT_FALSE(CFCast<CFNumberRef>(test_dict));
+  EXPECT_FALSE(CFCast<CFDateRef>(test_dict_mutable));
+  EXPECT_FALSE(CFCast<CFDataRef>(test_number));
+  EXPECT_FALSE(CFCast<CFDataRef>(test_null));
+  EXPECT_FALSE(CFCast<CFBooleanRef>(test_set));
+  EXPECT_FALSE(CFCast<CFBagRef>(test_set_mutable));
+  EXPECT_FALSE(CFCast<CFBagRef>(test_str));
+  EXPECT_FALSE(CFCast<CFArrayRef>(test_str_const));
+  EXPECT_FALSE(CFCast<CFArrayRef>(test_str_mutable));
+
+  // Giving a NULL provides a NULL.
+  EXPECT_FALSE(CFCast<CFArrayRef>(NULL));
+  EXPECT_FALSE(CFCast<CFBagRef>(NULL));
+  EXPECT_FALSE(CFCast<CFBooleanRef>(NULL));
+  EXPECT_FALSE(CFCast<CFDataRef>(NULL));
+  EXPECT_FALSE(CFCast<CFDateRef>(NULL));
+  EXPECT_FALSE(CFCast<CFDictionaryRef>(NULL));
+  EXPECT_FALSE(CFCast<CFNullRef>(NULL));
+  EXPECT_FALSE(CFCast<CFNumberRef>(NULL));
+  EXPECT_FALSE(CFCast<CFSetRef>(NULL));
+  EXPECT_FALSE(CFCast<CFStringRef>(NULL));
+
+  // CFCastStrict: correct cast results in correct pointer being returned.
+  EXPECT_EQ(test_array, CFCastStrict<CFArrayRef>(test_array));
+  EXPECT_EQ(test_array_mutable, CFCastStrict<CFArrayRef>(test_array_mutable));
+  EXPECT_EQ(test_bag, CFCastStrict<CFBagRef>(test_bag));
+  EXPECT_EQ(test_bag_mutable, CFCastStrict<CFBagRef>(test_bag_mutable));
+  EXPECT_EQ(test_bool, CFCastStrict<CFBooleanRef>(test_bool));
+  EXPECT_EQ(test_data, CFCastStrict<CFDataRef>(test_data));
+  EXPECT_EQ(test_data_mutable, CFCastStrict<CFDataRef>(test_data_mutable));
+  EXPECT_EQ(test_date, CFCastStrict<CFDateRef>(test_date));
+  EXPECT_EQ(test_dict, CFCastStrict<CFDictionaryRef>(test_dict));
+  EXPECT_EQ(test_dict_mutable,
+            CFCastStrict<CFDictionaryRef>(test_dict_mutable));
+  EXPECT_EQ(test_number, CFCastStrict<CFNumberRef>(test_number));
+  EXPECT_EQ(test_null, CFCastStrict<CFNullRef>(test_null));
+  EXPECT_EQ(test_set, CFCastStrict<CFSetRef>(test_set));
+  EXPECT_EQ(test_set_mutable, CFCastStrict<CFSetRef>(test_set_mutable));
+  EXPECT_EQ(test_str, CFCastStrict<CFStringRef>(test_str));
+  EXPECT_EQ(test_str_const, CFCastStrict<CFStringRef>(test_str_const));
+  EXPECT_EQ(test_str_mutable, CFCastStrict<CFStringRef>(test_str_mutable));
+
+  // CFCastStrict: Giving a NULL provides a NULL.
+  EXPECT_FALSE(CFCastStrict<CFArrayRef>(NULL));
+  EXPECT_FALSE(CFCastStrict<CFBagRef>(NULL));
+  EXPECT_FALSE(CFCastStrict<CFBooleanRef>(NULL));
+  EXPECT_FALSE(CFCastStrict<CFDataRef>(NULL));
+  EXPECT_FALSE(CFCastStrict<CFDateRef>(NULL));
+  EXPECT_FALSE(CFCastStrict<CFDictionaryRef>(NULL));
+  EXPECT_FALSE(CFCastStrict<CFNullRef>(NULL));
+  EXPECT_FALSE(CFCastStrict<CFNumberRef>(NULL));
+  EXPECT_FALSE(CFCastStrict<CFSetRef>(NULL));
+  EXPECT_FALSE(CFCastStrict<CFStringRef>(NULL));
+}
+
+TEST(FoundationUtilTest, ObjCCast) {
+  ScopedNSAutoreleasePool pool;
+
+  id test_array = [NSArray array];
+  id test_array_mutable = [NSMutableArray array];
+  id test_data = [NSData data];
+  id test_data_mutable = [NSMutableData dataWithCapacity:10];
+  id test_date = [NSDate date];
+  id test_dict =
+      [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:42]
+                                  forKey:@"meaning"];
+  id test_dict_mutable = [NSMutableDictionary dictionaryWithCapacity:10];
+  id test_number = [NSNumber numberWithInt:42];
+  id test_null = [NSNull null];
+  id test_set = [NSSet setWithObject:@"string object"];
+  id test_set_mutable = [NSMutableSet setWithCapacity:10];
+  id test_str = [NSString string];
+  id test_str_const = @"bonjour";
+  id test_str_mutable = [NSMutableString stringWithCapacity:10];
+
+  // Make sure the allocations of NS types are good.
+  EXPECT_TRUE(test_array);
+  EXPECT_TRUE(test_array_mutable);
+  EXPECT_TRUE(test_data);
+  EXPECT_TRUE(test_data_mutable);
+  EXPECT_TRUE(test_date);
+  EXPECT_TRUE(test_dict);
+  EXPECT_TRUE(test_dict_mutable);
+  EXPECT_TRUE(test_number);
+  EXPECT_TRUE(test_null);
+  EXPECT_TRUE(test_set);
+  EXPECT_TRUE(test_set_mutable);
+  EXPECT_TRUE(test_str);
+  EXPECT_TRUE(test_str_const);
+  EXPECT_TRUE(test_str_mutable);
+
+  // Casting the id correctly provides the same pointer.
+  EXPECT_EQ(test_array, ObjCCast<NSArray>(test_array));
+  EXPECT_EQ(test_array_mutable, ObjCCast<NSArray>(test_array_mutable));
+  EXPECT_EQ(test_data, ObjCCast<NSData>(test_data));
+  EXPECT_EQ(test_data_mutable, ObjCCast<NSData>(test_data_mutable));
+  EXPECT_EQ(test_date, ObjCCast<NSDate>(test_date));
+  EXPECT_EQ(test_dict, ObjCCast<NSDictionary>(test_dict));
+  EXPECT_EQ(test_dict_mutable, ObjCCast<NSDictionary>(test_dict_mutable));
+  EXPECT_EQ(test_number, ObjCCast<NSNumber>(test_number));
+  EXPECT_EQ(test_null, ObjCCast<NSNull>(test_null));
+  EXPECT_EQ(test_set, ObjCCast<NSSet>(test_set));
+  EXPECT_EQ(test_set_mutable, ObjCCast<NSSet>(test_set_mutable));
+  EXPECT_EQ(test_str, ObjCCast<NSString>(test_str));
+  EXPECT_EQ(test_str_const, ObjCCast<NSString>(test_str_const));
+  EXPECT_EQ(test_str_mutable, ObjCCast<NSString>(test_str_mutable));
+
+  // When given an incorrect ObjC cast, provide nil.
+  EXPECT_FALSE(ObjCCast<NSString>(test_array));
+  EXPECT_FALSE(ObjCCast<NSString>(test_array_mutable));
+  EXPECT_FALSE(ObjCCast<NSString>(test_data));
+  EXPECT_FALSE(ObjCCast<NSString>(test_data_mutable));
+  EXPECT_FALSE(ObjCCast<NSSet>(test_date));
+  EXPECT_FALSE(ObjCCast<NSSet>(test_dict));
+  EXPECT_FALSE(ObjCCast<NSNumber>(test_dict_mutable));
+  EXPECT_FALSE(ObjCCast<NSNull>(test_number));
+  EXPECT_FALSE(ObjCCast<NSDictionary>(test_null));
+  EXPECT_FALSE(ObjCCast<NSDictionary>(test_set));
+  EXPECT_FALSE(ObjCCast<NSDate>(test_set_mutable));
+  EXPECT_FALSE(ObjCCast<NSData>(test_str));
+  EXPECT_FALSE(ObjCCast<NSData>(test_str_const));
+  EXPECT_FALSE(ObjCCast<NSArray>(test_str_mutable));
+
+  // Giving a nil provides a nil.
+  EXPECT_FALSE(ObjCCast<NSArray>(nil));
+  EXPECT_FALSE(ObjCCast<NSData>(nil));
+  EXPECT_FALSE(ObjCCast<NSDate>(nil));
+  EXPECT_FALSE(ObjCCast<NSDictionary>(nil));
+  EXPECT_FALSE(ObjCCast<NSNull>(nil));
+  EXPECT_FALSE(ObjCCast<NSNumber>(nil));
+  EXPECT_FALSE(ObjCCast<NSSet>(nil));
+  EXPECT_FALSE(ObjCCast<NSString>(nil));
+
+  // ObjCCastStrict: correct cast results in correct pointer being returned.
+  EXPECT_EQ(test_array, ObjCCastStrict<NSArray>(test_array));
+  EXPECT_EQ(test_array_mutable,
+            ObjCCastStrict<NSArray>(test_array_mutable));
+  EXPECT_EQ(test_data, ObjCCastStrict<NSData>(test_data));
+  EXPECT_EQ(test_data_mutable,
+            ObjCCastStrict<NSData>(test_data_mutable));
+  EXPECT_EQ(test_date, ObjCCastStrict<NSDate>(test_date));
+  EXPECT_EQ(test_dict, ObjCCastStrict<NSDictionary>(test_dict));
+  EXPECT_EQ(test_dict_mutable,
+            ObjCCastStrict<NSDictionary>(test_dict_mutable));
+  EXPECT_EQ(test_number, ObjCCastStrict<NSNumber>(test_number));
+  EXPECT_EQ(test_null, ObjCCastStrict<NSNull>(test_null));
+  EXPECT_EQ(test_set, ObjCCastStrict<NSSet>(test_set));
+  EXPECT_EQ(test_set_mutable,
+            ObjCCastStrict<NSSet>(test_set_mutable));
+  EXPECT_EQ(test_str, ObjCCastStrict<NSString>(test_str));
+  EXPECT_EQ(test_str_const,
+            ObjCCastStrict<NSString>(test_str_const));
+  EXPECT_EQ(test_str_mutable,
+            ObjCCastStrict<NSString>(test_str_mutable));
+
+  // ObjCCastStrict: Giving a nil provides a nil.
+  EXPECT_FALSE(ObjCCastStrict<NSArray>(nil));
+  EXPECT_FALSE(ObjCCastStrict<NSData>(nil));
+  EXPECT_FALSE(ObjCCastStrict<NSDate>(nil));
+  EXPECT_FALSE(ObjCCastStrict<NSDictionary>(nil));
+  EXPECT_FALSE(ObjCCastStrict<NSNull>(nil));
+  EXPECT_FALSE(ObjCCastStrict<NSNumber>(nil));
+  EXPECT_FALSE(ObjCCastStrict<NSSet>(nil));
+  EXPECT_FALSE(ObjCCastStrict<NSString>(nil));
+}
+
+TEST(FoundationUtilTest, GetValueFromDictionary) {
+  int one = 1, two = 2, three = 3;
+
+  ScopedCFTypeRef<CFNumberRef> cf_one(
+      CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &one));
+  ScopedCFTypeRef<CFNumberRef> cf_two(
+      CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &two));
+  ScopedCFTypeRef<CFNumberRef> cf_three(
+      CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &three));
+
+  CFStringRef keys[] = { CFSTR("one"), CFSTR("two"), CFSTR("three") };
+  CFNumberRef values[] = { cf_one, cf_two, cf_three };
+
+  COMPILE_ASSERT(arraysize(keys) == arraysize(values),
+                 keys_and_values_arraysizes_are_different);
+
+  ScopedCFTypeRef<CFDictionaryRef> test_dict(
+      CFDictionaryCreate(kCFAllocatorDefault,
+                         reinterpret_cast<const void**>(keys),
+                         reinterpret_cast<const void**>(values),
+                         arraysize(values),
+                         &kCFCopyStringDictionaryKeyCallBacks,
+                         &kCFTypeDictionaryValueCallBacks));
+
+  // GetValueFromDictionary<>(_, _) should produce the correct
+  // expected output.
+  EXPECT_EQ(values[0],
+            GetValueFromDictionary<CFNumberRef>(test_dict, CFSTR("one")));
+  EXPECT_EQ(values[1],
+            GetValueFromDictionary<CFNumberRef>(test_dict, CFSTR("two")));
+  EXPECT_EQ(values[2],
+            GetValueFromDictionary<CFNumberRef>(test_dict, CFSTR("three")));
+
+  // Bad input should produce bad output.
+  EXPECT_FALSE(GetValueFromDictionary<CFNumberRef>(test_dict, CFSTR("four")));
+  EXPECT_FALSE(GetValueFromDictionary<CFStringRef>(test_dict, CFSTR("one")));
+}
+
+TEST(FoundationUtilTest, FilePathToNSString) {
+  EXPECT_NSEQ(nil, FilePathToNSString(FilePath()));
+  EXPECT_NSEQ(@"/a/b", FilePathToNSString(FilePath("/a/b")));
+}
+
+TEST(FoundationUtilTest, NSStringToFilePath) {
+  EXPECT_EQ(FilePath(), NSStringToFilePath(nil));
+  EXPECT_EQ(FilePath(), NSStringToFilePath(@""));
+  EXPECT_EQ(FilePath("/a/b"), NSStringToFilePath(@"/a/b"));
+}
+
+TEST(StringNumberConversionsTest, FormatNSInteger) {
+  // The PRI[dxu]NS macro assumes that NSInteger is a typedef to "int" on
+  // 32-bit architecture and a typedef to "long" on 64-bit architecture
+  // (respectively "unsigned int" and "unsigned long" for NSUInteger). Use
+  // pointer incompatibility to validate this at compilation.
+#if defined(ARCH_CPU_64_BITS)
+  typedef long FormatNSIntegerAsType;
+  typedef unsigned long FormatNSUIntegerAsType;
+#else
+  typedef int FormatNSIntegerAsType;
+  typedef unsigned int FormatNSUIntegerAsType;
+#endif  // defined(ARCH_CPU_64_BITS)
+
+  NSInteger some_nsinteger;
+  FormatNSIntegerAsType* pointer_to_some_nsinteger = &some_nsinteger;
+  ALLOW_UNUSED_LOCAL(pointer_to_some_nsinteger);
+
+  NSUInteger some_nsuinteger;
+  FormatNSUIntegerAsType* pointer_to_some_nsuinteger = &some_nsuinteger;
+  ALLOW_UNUSED_LOCAL(pointer_to_some_nsuinteger);
+
+  // Check that format specifier works correctly for NSInteger.
+  const struct {
+    NSInteger value;
+    const char* expected;
+    const char* expected_hex;
+  } nsinteger_cases[] = {
+#if !defined(ARCH_CPU_64_BITS)
+    {12345678, "12345678", "bc614e"},
+    {-12345678, "-12345678", "ff439eb2"},
+#else
+    {12345678, "12345678", "bc614e"},
+    {-12345678, "-12345678", "ffffffffff439eb2"},
+    {137451299150l, "137451299150", "2000bc614e"},
+    {-137451299150l, "-137451299150", "ffffffdfff439eb2"},
+#endif  // !defined(ARCH_CPU_64_BITS)
+  };
+
+  for (size_t i = 0; i < arraysize(nsinteger_cases); ++i) {
+    EXPECT_EQ(nsinteger_cases[i].expected,
+              StringPrintf("%" PRIdNS, nsinteger_cases[i].value));
+    EXPECT_EQ(nsinteger_cases[i].expected_hex,
+              StringPrintf("%" PRIxNS, nsinteger_cases[i].value));
+  }
+
+  // Check that format specifier works correctly for NSUInteger.
+  const struct {
+    NSUInteger value;
+    const char* expected;
+    const char* expected_hex;
+  } nsuinteger_cases[] = {
+#if !defined(ARCH_CPU_64_BITS)
+    {12345678u, "12345678", "bc614e"},
+    {4282621618u, "4282621618", "ff439eb2"},
+#else
+    {12345678u, "12345678", "bc614e"},
+    {4282621618u, "4282621618", "ff439eb2"},
+    {137451299150ul, "137451299150", "2000bc614e"},
+    {18446743936258252466ul, "18446743936258252466", "ffffffdfff439eb2"},
+#endif  // !defined(ARCH_CPU_64_BITS)
+  };
+
+  for (size_t i = 0; i < arraysize(nsuinteger_cases); ++i) {
+    EXPECT_EQ(nsuinteger_cases[i].expected,
+              StringPrintf("%" PRIuNS, nsuinteger_cases[i].value));
+    EXPECT_EQ(nsuinteger_cases[i].expected_hex,
+              StringPrintf("%" PRIxNS, nsuinteger_cases[i].value));
+  }
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/launch_services_util.cc b/base/mac/launch_services_util.cc
new file mode 100644
index 0000000..4c3b417
--- /dev/null
+++ b/base/mac/launch_services_util.cc
@@ -0,0 +1,66 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/launch_services_util.h"
+
+#include "base/logging.h"
+#include "base/mac/mac_logging.h"
+#include "base/mac/mac_util.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/strings/sys_string_conversions.h"
+
+namespace base {
+namespace mac {
+
+bool OpenApplicationWithPath(const base::FilePath& bundle_path,
+                             const CommandLine& command_line,
+                             LSLaunchFlags launch_flags,
+                             ProcessSerialNumber* out_psn) {
+  FSRef app_fsref;
+  if (!base::mac::FSRefFromPath(bundle_path.value(), &app_fsref)) {
+    LOG(ERROR) << "base::mac::FSRefFromPath failed for " << bundle_path.value();
+    return false;
+  }
+
+  std::vector<std::string> argv = command_line.argv();
+  int argc = argv.size();
+  base::ScopedCFTypeRef<CFMutableArrayRef> launch_args(
+      CFArrayCreateMutable(NULL, argc - 1, &kCFTypeArrayCallBacks));
+  if (!launch_args) {
+    LOG(ERROR) << "CFArrayCreateMutable failed, size was " << argc;
+    return false;
+  }
+
+  for (int i = 1; i < argc; ++i) {
+    const std::string& arg(argv[i]);
+
+    base::ScopedCFTypeRef<CFStringRef> arg_cf(base::SysUTF8ToCFStringRef(arg));
+    if (!arg_cf) {
+      LOG(ERROR) << "base::SysUTF8ToCFStringRef failed for " << arg;
+      return false;
+    }
+    CFArrayAppendValue(launch_args, arg_cf);
+  }
+
+  LSApplicationParameters ls_parameters = {
+    0,     // version
+    launch_flags,
+    &app_fsref,
+    NULL,  // asyncLaunchRefCon
+    NULL,  // environment
+    launch_args,
+    NULL   // initialEvent
+  };
+  // TODO(jeremya): this opens a new browser window if Chrome is already
+  // running without any windows open.
+  OSStatus status = LSOpenApplication(&ls_parameters, out_psn);
+  if (status != noErr) {
+    OSSTATUS_LOG(ERROR, status) << "LSOpenApplication";
+    return false;
+  }
+  return true;
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/launch_services_util.h b/base/mac/launch_services_util.h
new file mode 100644
index 0000000..0e64316
--- /dev/null
+++ b/base/mac/launch_services_util.h
@@ -0,0 +1,33 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_LAUNCH_SERVICES_UTIL_H_
+#define BASE_MAC_LAUNCH_SERVICES_UTIL_H_
+
+#include <CoreServices/CoreServices.h>
+
+#include "base/base_export.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+
+struct ProcessSerialNumber;
+
+namespace base {
+namespace mac {
+
+// Launches the application bundle at |bundle_path|, passing argv[1..] from
+// |command_line| as command line arguments if the app isn't already running.
+// |launch_flags| are passed directly to LSApplicationParameters.
+// |out_psn|, if not NULL, will be set to the process serial number of the
+// application's main process if the app was successfully launched.
+// Returns true if the app was successfully launched.
+BASE_EXPORT bool OpenApplicationWithPath(const FilePath& bundle_path,
+                                         const CommandLine& command_line,
+                                         LSLaunchFlags launch_flags,
+                                         ProcessSerialNumber* out_psn);
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_LAUNCH_SERVICES_UTIL_H_
diff --git a/base/mac/launchd.cc b/base/mac/launchd.cc
new file mode 100644
index 0000000..1d384c9
--- /dev/null
+++ b/base/mac/launchd.cc
@@ -0,0 +1,75 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/launchd.h"
+
+#include "base/logging.h"
+#include "base/mac/scoped_launch_data.h"
+
+namespace base {
+namespace mac {
+
+// MessageForJob sends a single message to launchd with a simple dictionary
+// mapping |operation| to |job_label|, and returns the result of calling
+// launch_msg to send that message. On failure, returns NULL. The caller
+// assumes ownership of the returned launch_data_t object.
+launch_data_t MessageForJob(const std::string& job_label,
+                            const char* operation) {
+  // launch_data_alloc returns something that needs to be freed.
+  ScopedLaunchData message(launch_data_alloc(LAUNCH_DATA_DICTIONARY));
+  if (!message) {
+    LOG(ERROR) << "launch_data_alloc";
+    return NULL;
+  }
+
+  // launch_data_new_string returns something that needs to be freed, but
+  // the dictionary will assume ownership when launch_data_dict_insert is
+  // called, so put it in a scoper and .release() it when given to the
+  // dictionary.
+  ScopedLaunchData job_label_launchd(launch_data_new_string(job_label.c_str()));
+  if (!job_label_launchd) {
+    LOG(ERROR) << "launch_data_new_string";
+    return NULL;
+  }
+
+  if (!launch_data_dict_insert(message,
+                               job_label_launchd.release(),
+                               operation)) {
+    return NULL;
+  }
+
+  return launch_msg(message);
+}
+
+pid_t PIDForJob(const std::string& job_label) {
+  ScopedLaunchData response(MessageForJob(job_label, LAUNCH_KEY_GETJOB));
+  if (!response) {
+    return -1;
+  }
+
+  launch_data_type_t response_type = launch_data_get_type(response);
+  if (response_type != LAUNCH_DATA_DICTIONARY) {
+    if (response_type == LAUNCH_DATA_ERRNO) {
+      LOG(ERROR) << "PIDForJob: error " << launch_data_get_errno(response);
+    } else {
+      LOG(ERROR) << "PIDForJob: expected dictionary, got " << response_type;
+    }
+    return -1;
+  }
+
+  launch_data_t pid_data = launch_data_dict_lookup(response,
+                                                   LAUNCH_JOBKEY_PID);
+  if (!pid_data)
+    return 0;
+
+  if (launch_data_get_type(pid_data) != LAUNCH_DATA_INTEGER) {
+    LOG(ERROR) << "PIDForJob: expected integer";
+    return -1;
+  }
+
+  return launch_data_get_integer(pid_data);
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/launchd.h b/base/mac/launchd.h
new file mode 100644
index 0000000..9e4514e
--- /dev/null
+++ b/base/mac/launchd.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2012 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_MAC_LAUNCHD_H_
+#define BASE_MAC_LAUNCHD_H_
+
+#include <launch.h>
+#include <sys/types.h>
+
+#include <string>
+
+#include "base/base_export.h"
+
+namespace base {
+namespace mac {
+
+// MessageForJob sends a single message to launchd with a simple dictionary
+// mapping |operation| to |job_label|, and returns the result of calling
+// launch_msg to send that message. On failure, returns NULL. The caller
+// assumes ownership of the returned launch_data_t object.
+BASE_EXPORT
+launch_data_t MessageForJob(const std::string& job_label,
+                            const char* operation);
+
+// Returns the process ID for |job_label| if the job is running, 0 if the job
+// is loaded but not running, or -1 on error.
+BASE_EXPORT
+pid_t PIDForJob(const std::string& job_label);
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_LAUNCHD_H_
diff --git a/base/mac/libdispatch_task_runner.cc b/base/mac/libdispatch_task_runner.cc
new file mode 100644
index 0000000..4b5abaf
--- /dev/null
+++ b/base/mac/libdispatch_task_runner.cc
@@ -0,0 +1,80 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/libdispatch_task_runner.h"
+
+#include "base/callback.h"
+
+namespace base {
+namespace mac {
+
+LibDispatchTaskRunner::LibDispatchTaskRunner(const char* name)
+    : queue_(dispatch_queue_create(name, NULL)),
+      queue_finalized_(false, false) {
+  dispatch_set_context(queue_, this);
+  dispatch_set_finalizer_f(queue_, &LibDispatchTaskRunner::Finalizer);
+}
+
+bool LibDispatchTaskRunner::PostDelayedTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    base::TimeDelta delay) {
+  if (!queue_)
+    return false;
+
+  // The block runtime would implicitly copy the reference, not the object
+  // it's referencing. Copy the closure into block storage so it's available
+  // to run.
+  __block const Closure task_copy = task;
+  void(^run_task)(void) = ^{
+      task_copy.Run();
+  };
+
+  int64 delay_nano =
+      delay.InMicroseconds() * base::Time::kNanosecondsPerMicrosecond;
+  if (delay_nano > 0) {
+    dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, delay_nano);
+    dispatch_after(time, queue_, run_task);
+  } else {
+    dispatch_async(queue_, run_task);
+  }
+  return true;
+}
+
+bool LibDispatchTaskRunner::RunsTasksOnCurrentThread() const {
+  return queue_ == dispatch_get_current_queue();
+}
+
+bool LibDispatchTaskRunner::PostNonNestableDelayedTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    base::TimeDelta delay) {
+  return PostDelayedTask(from_here, task, delay);
+}
+
+void LibDispatchTaskRunner::Shutdown() {
+  dispatch_release(queue_);
+  queue_ = NULL;
+  queue_finalized_.Wait();
+}
+
+dispatch_queue_t LibDispatchTaskRunner::GetDispatchQueue() const {
+  return queue_;
+}
+
+LibDispatchTaskRunner::~LibDispatchTaskRunner() {
+  if (queue_) {
+    dispatch_set_context(queue_, NULL);
+    dispatch_set_finalizer_f(queue_, NULL);
+    dispatch_release(queue_);
+  }
+}
+
+void LibDispatchTaskRunner::Finalizer(void* context) {
+  LibDispatchTaskRunner* self = static_cast<LibDispatchTaskRunner*>(context);
+  self->queue_finalized_.Signal();
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/libdispatch_task_runner.h b/base/mac/libdispatch_task_runner.h
new file mode 100644
index 0000000..b479bc7
--- /dev/null
+++ b/base/mac/libdispatch_task_runner.h
@@ -0,0 +1,80 @@
+// Copyright (c) 2012 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_MAC_LIBDISPATCH_TASK_RUNNER_H_
+#define BASE_MAC_LIBDISPATCH_TASK_RUNNER_H_
+
+#include <dispatch/dispatch.h>
+
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/waitable_event.h"
+
+namespace base {
+namespace mac {
+
+// This is an implementation of the TaskRunner interface that runs closures on
+// a thread managed by Apple's libdispatch. This has the benefit of being able
+// to PostTask() and friends to a dispatch queue, while being reusable as a
+// dispatch_queue_t.
+//
+// One would use this class if an object lives exclusively on one thread but
+// needs a dispatch_queue_t for use in a system API. This ensures all dispatch
+// callbacks happen on the same thread as Closure tasks.
+//
+// A LibDispatchTaskRunner will continue to run until all references to the
+// underlying dispatch queue are released.
+//
+// Important Notes:
+//   - There is no MessageLoop running on this thread, and ::current() returns
+//     NULL.
+//   - No nested loops can be run, and all tasks are run non-nested.
+//   - Work scheduled via libdispatch runs at the same priority as and is
+//     interleaved with posted tasks, though FIFO order is guaranteed.
+//
+class BASE_EXPORT LibDispatchTaskRunner : public base::SingleThreadTaskRunner {
+ public:
+  // Starts a new serial dispatch queue with a given name.
+  explicit LibDispatchTaskRunner(const char* name);
+
+  // base::TaskRunner:
+  bool PostDelayedTask(const tracked_objects::Location& from_here,
+                       const Closure& task,
+                       base::TimeDelta delay) override;
+  bool RunsTasksOnCurrentThread() const override;
+
+  // base::SequencedTaskRunner:
+  bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
+                                  const Closure& task,
+                                  base::TimeDelta delay) override;
+
+  // This blocks the calling thread until all work on the dispatch queue has
+  // been run and the queue has been destroyed. Destroying a queue requires
+  // ALL retained references to it to be released. Any new tasks posted to
+  // this thread after shutdown are dropped.
+  void Shutdown();
+
+  // Returns the dispatch queue associated with this task runner, for use with
+  // system APIs that take dispatch queues. The caller is responsible for
+  // retaining the result.
+  //
+  // All properties (context, finalizer, etc.) are managed by this class, and
+  // clients should only use the result of this for dispatch_async().
+  dispatch_queue_t GetDispatchQueue() const;
+
+ protected:
+  ~LibDispatchTaskRunner() override;
+
+ private:
+  static void Finalizer(void* context);
+
+  dispatch_queue_t queue_;
+
+  // The event on which Shutdown waits until Finalizer runs.
+  base::WaitableEvent queue_finalized_;
+};
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_LIBDISPATCH_TASK_RUNNER_H_
diff --git a/base/mac/libdispatch_task_runner_unittest.cc b/base/mac/libdispatch_task_runner_unittest.cc
new file mode 100644
index 0000000..49b0c9a
--- /dev/null
+++ b/base/mac/libdispatch_task_runner_unittest.cc
@@ -0,0 +1,224 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/libdispatch_task_runner.h"
+
+#include "base/bind.h"
+#include "base/mac/bind_objc_block.h"
+#include "base/message_loop/message_loop.h"
+#include "base/strings/stringprintf.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+class LibDispatchTaskRunnerTest : public testing::Test {
+ public:
+  void SetUp() override {
+    task_runner_ = new base::mac::LibDispatchTaskRunner(
+        "org.chromium.LibDispatchTaskRunnerTest");
+  }
+
+  // DispatchLastTask is used to run the main test thread's MessageLoop until
+  // all non-delayed tasks are run on the LibDispatchTaskRunner.
+  void DispatchLastTask() {
+    dispatch_async(task_runner_->GetDispatchQueue(), ^{
+        message_loop_.PostTask(FROM_HERE,
+                               base::MessageLoop::QuitWhenIdleClosure());
+    });
+    message_loop_.Run();
+    task_runner_->Shutdown();
+  }
+
+  // VerifyTaskOrder takes the expectations from TaskOrderMarkers and compares
+  // them against the recorded values.
+  void VerifyTaskOrder(const char* const expectations[],
+                       size_t num_expectations) {
+    size_t actual_size = task_order_.size();
+
+    for (size_t i = 0; i < num_expectations; ++i) {
+      if (i >= actual_size) {
+        EXPECT_LE(i, actual_size) << "Expected " << expectations[i];
+        continue;
+      }
+
+      EXPECT_EQ(expectations[i], task_order_[i]);
+    }
+
+    if (actual_size > num_expectations) {
+      EXPECT_LE(actual_size, num_expectations) << "Extra tasks were run:";
+      for (size_t i = num_expectations; i < actual_size; ++i) {
+        EXPECT_EQ("<none>", task_order_[i]) << " (i=" << i << ")";
+      }
+    }
+  }
+
+  // The message loop for the test main thread.
+  base::MessageLoop message_loop_;
+
+  // The task runner under test.
+  scoped_refptr<base::mac::LibDispatchTaskRunner> task_runner_;
+
+  // Vector that records data from TaskOrderMarker.
+  std::vector<std::string> task_order_;
+};
+
+// Scoper that records the beginning and end of a running task.
+class TaskOrderMarker {
+ public:
+  TaskOrderMarker(LibDispatchTaskRunnerTest* test, const std::string& name)
+      : test_(test),
+        name_(name) {
+    test->task_order_.push_back(std::string("BEGIN ") + name);
+  }
+  ~TaskOrderMarker() {
+    test_->task_order_.push_back(std::string("END ") + name_);
+  }
+
+ private:
+  LibDispatchTaskRunnerTest* test_;
+  std::string name_;
+};
+
+void RecordTaskOrder(LibDispatchTaskRunnerTest* test, const std::string& name) {
+  TaskOrderMarker marker(test, name);
+}
+
+// Returns a closure that records the task order.
+base::Closure BoundRecordTaskOrder(LibDispatchTaskRunnerTest* test,
+                                   const std::string& name) {
+  return base::Bind(&RecordTaskOrder, base::Unretained(test), name);
+}
+
+TEST_F(LibDispatchTaskRunnerTest, PostTask) {
+  task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "Basic Task"));
+  DispatchLastTask();
+  const char* const expectations[] = {
+    "BEGIN Basic Task",
+    "END Basic Task"
+  };
+  VerifyTaskOrder(expectations, arraysize(expectations));
+}
+
+TEST_F(LibDispatchTaskRunnerTest, PostTaskWithinTask) {
+  task_runner_->PostTask(FROM_HERE, base::BindBlock(^{
+      TaskOrderMarker marker(this, "Outer");
+      task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "Inner"));
+  }));
+  DispatchLastTask();
+
+  const char* const expectations[] = {
+    "BEGIN Outer",
+    "END Outer",
+    "BEGIN Inner",
+    "END Inner"
+  };
+  VerifyTaskOrder(expectations, arraysize(expectations));
+}
+
+TEST_F(LibDispatchTaskRunnerTest, NoMessageLoop) {
+  task_runner_->PostTask(FROM_HERE, base::BindBlock(^{
+      TaskOrderMarker marker(this,
+          base::StringPrintf("MessageLoop = %p", base::MessageLoop::current()));
+  }));
+  DispatchLastTask();
+
+  const char* const expectations[] = {
+    "BEGIN MessageLoop = 0x0",
+    "END MessageLoop = 0x0"
+  };
+  VerifyTaskOrder(expectations, arraysize(expectations));
+}
+
+TEST_F(LibDispatchTaskRunnerTest, DispatchAndPostTasks) {
+  dispatch_async(task_runner_->GetDispatchQueue(), ^{
+      TaskOrderMarker marker(this, "First Block");
+  });
+  task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "First Task"));
+  dispatch_async(task_runner_->GetDispatchQueue(), ^{
+      TaskOrderMarker marker(this, "Second Block");
+  });
+  task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "Second Task"));
+  DispatchLastTask();
+
+  const char* const expectations[] = {
+    "BEGIN First Block",
+    "END First Block",
+    "BEGIN First Task",
+    "END First Task",
+    "BEGIN Second Block",
+    "END Second Block",
+    "BEGIN Second Task",
+    "END Second Task",
+  };
+  VerifyTaskOrder(expectations, arraysize(expectations));
+}
+
+TEST_F(LibDispatchTaskRunnerTest, NonNestable) {
+  task_runner_->PostTask(FROM_HERE, base::BindBlock(^{
+      TaskOrderMarker marker(this, "First");
+      task_runner_->PostNonNestableTask(FROM_HERE, base::BindBlock(^{
+          TaskOrderMarker marker(this, "Second NonNestable");
+          message_loop_.PostTask(FROM_HERE,
+                                 base::MessageLoop::QuitWhenIdleClosure());
+      }));
+  }));
+  message_loop_.Run();
+  task_runner_->Shutdown();
+
+  const char* const expectations[] = {
+    "BEGIN First",
+    "END First",
+    "BEGIN Second NonNestable",
+    "END Second NonNestable"
+  };
+  VerifyTaskOrder(expectations, arraysize(expectations));
+}
+
+TEST_F(LibDispatchTaskRunnerTest, PostDelayed) {
+  base::TimeTicks post_time;
+  __block base::TimeTicks run_time;
+  const base::TimeDelta delta = base::TimeDelta::FromMilliseconds(50);
+
+  task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "First"));
+  post_time = base::TimeTicks::Now();
+  task_runner_->PostDelayedTask(FROM_HERE, base::BindBlock(^{
+      TaskOrderMarker marker(this, "Timed");
+      run_time = base::TimeTicks::Now();
+      message_loop_.PostTask(FROM_HERE,
+                             base::MessageLoop::QuitWhenIdleClosure());
+  }), delta);
+  task_runner_->PostTask(FROM_HERE, BoundRecordTaskOrder(this, "Second"));
+  message_loop_.Run();
+  task_runner_->Shutdown();
+
+  const char* const expectations[] = {
+    "BEGIN First",
+    "END First",
+    "BEGIN Second",
+    "END Second",
+    "BEGIN Timed",
+    "END Timed",
+  };
+  VerifyTaskOrder(expectations, arraysize(expectations));
+
+  EXPECT_GE(run_time, post_time + delta);
+}
+
+TEST_F(LibDispatchTaskRunnerTest, PostAfterShutdown) {
+  EXPECT_TRUE(task_runner_->PostTask(FROM_HERE,
+      BoundRecordTaskOrder(this, "First")));
+  EXPECT_TRUE(task_runner_->PostTask(FROM_HERE,
+      BoundRecordTaskOrder(this, "Second")));
+  task_runner_->Shutdown();
+  EXPECT_FALSE(task_runner_->PostTask(FROM_HERE, base::BindBlock(^{
+      TaskOrderMarker marker(this, "Not Run");
+      ADD_FAILURE() << "Should not run a task after Shutdown";
+  })));
+
+  const char* const expectations[] = {
+    "BEGIN First",
+    "END First",
+    "BEGIN Second",
+    "END Second"
+  };
+  VerifyTaskOrder(expectations, arraysize(expectations));
+}
diff --git a/base/mac/mac_logging.cc b/base/mac/mac_logging.cc
new file mode 100644
index 0000000..d58220f
--- /dev/null
+++ b/base/mac/mac_logging.cc
@@ -0,0 +1,37 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/mac_logging.h"
+
+#include <iomanip>
+
+#if !defined(OS_IOS)
+#include <CoreServices/CoreServices.h>
+#endif
+
+namespace logging {
+
+OSStatusLogMessage::OSStatusLogMessage(const char* file_path,
+                                       int line,
+                                       LogSeverity severity,
+                                       OSStatus status)
+    : LogMessage(file_path, line, severity),
+      status_(status) {
+}
+
+OSStatusLogMessage::~OSStatusLogMessage() {
+#if defined(OS_IOS)
+  // TODO(ios): Consider using NSError with NSOSStatusErrorDomain to try to
+  // get a description of the failure.
+  stream() << ": " << status_;
+#else
+  stream() << ": "
+           << GetMacOSStatusErrorString(status_)
+           << " ("
+           << status_
+           << ")";
+#endif
+}
+
+}  // namespace logging
diff --git a/base/mac/mac_logging.h b/base/mac/mac_logging.h
new file mode 100644
index 0000000..5192b20
--- /dev/null
+++ b/base/mac/mac_logging.h
@@ -0,0 +1,95 @@
+// Copyright (c) 2012 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_MAC_MAC_LOGGING_H_
+#define BASE_MAC_MAC_LOGGING_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "build/build_config.h"
+
+#if defined(OS_IOS)
+#include <MacTypes.h>
+#else
+#include <libkern/OSTypes.h>
+#endif
+
+// Use the OSSTATUS_LOG family to log messages related to errors in Mac OS X
+// system routines that report status via an OSStatus or OSErr value. It is
+// similar to the PLOG family which operates on errno, but because there is no
+// global (or thread-local) OSStatus or OSErr value, the specific error must
+// be supplied as an argument to the OSSTATUS_LOG macro. The message logged
+// will contain the symbolic constant name corresponding to the status value,
+// along with the value itself.
+//
+// OSErr is just an older 16-bit form of the newer 32-bit OSStatus. Despite
+// the name, OSSTATUS_LOG can be used equally well for OSStatus and OSErr.
+
+namespace logging {
+
+class BASE_EXPORT OSStatusLogMessage : public logging::LogMessage {
+ public:
+  OSStatusLogMessage(const char* file_path,
+                     int line,
+                     LogSeverity severity,
+                     OSStatus status);
+  ~OSStatusLogMessage();
+
+ private:
+  OSStatus status_;
+
+  DISALLOW_COPY_AND_ASSIGN(OSStatusLogMessage);
+};
+
+}  // namespace logging
+
+#if defined(NDEBUG)
+#define MAC_DVLOG_IS_ON(verbose_level) 0
+#else
+#define MAC_DVLOG_IS_ON(verbose_level) VLOG_IS_ON(verbose_level)
+#endif
+
+#define OSSTATUS_LOG_STREAM(severity, status) \
+    COMPACT_GOOGLE_LOG_EX_ ## severity(OSStatusLogMessage, status).stream()
+#define OSSTATUS_VLOG_STREAM(verbose_level, status) \
+    logging::OSStatusLogMessage(__FILE__, __LINE__, \
+                                -verbose_level, status).stream()
+
+#define OSSTATUS_LOG(severity, status) \
+    LAZY_STREAM(OSSTATUS_LOG_STREAM(severity, status), LOG_IS_ON(severity))
+#define OSSTATUS_LOG_IF(severity, condition, status) \
+    LAZY_STREAM(OSSTATUS_LOG_STREAM(severity, status), \
+                LOG_IS_ON(severity) && (condition))
+
+#define OSSTATUS_VLOG(verbose_level, status) \
+    LAZY_STREAM(OSSTATUS_VLOG_STREAM(verbose_level, status), \
+                VLOG_IS_ON(verbose_level))
+#define OSSTATUS_VLOG_IF(verbose_level, condition, status) \
+    LAZY_STREAM(OSSTATUS_VLOG_STREAM(verbose_level, status), \
+                VLOG_IS_ON(verbose_level) && (condition))
+
+#define OSSTATUS_CHECK(condition, status) \
+    LAZY_STREAM(OSSTATUS_LOG_STREAM(FATAL, status), !(condition)) \
+    << "Check failed: " # condition << ". "
+
+#define OSSTATUS_DLOG(severity, status) \
+    LAZY_STREAM(OSSTATUS_LOG_STREAM(severity, status), DLOG_IS_ON(severity))
+#define OSSTATUS_DLOG_IF(severity, condition, status) \
+    LAZY_STREAM(OSSTATUS_LOG_STREAM(severity, status), \
+                DLOG_IS_ON(severity) && (condition))
+
+#define OSSTATUS_DVLOG(verbose_level, status) \
+    LAZY_STREAM(OSSTATUS_VLOG_STREAM(verbose_level, status), \
+                MAC_DVLOG_IS_ON(verbose_level))
+#define OSSTATUS_DVLOG_IF(verbose_level, condition, status) \
+    LAZY_STREAM(OSSTATUS_VLOG_STREAM(verbose_level, status), \
+                MAC_DVLOG_IS_ON(verbose_level) && (condition))
+
+#define OSSTATUS_DCHECK(condition, status)        \
+  LAZY_STREAM(OSSTATUS_LOG_STREAM(FATAL, status), \
+              DCHECK_IS_ON() && !(condition))     \
+      << "Check failed: " #condition << ". "
+
+#endif  // BASE_MAC_MAC_LOGGING_H_
diff --git a/base/mac/mac_util.h b/base/mac/mac_util.h
new file mode 100644
index 0000000..f8ffa97
--- /dev/null
+++ b/base/mac/mac_util.h
@@ -0,0 +1,231 @@
+// Copyright (c) 2012 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_MAC_MAC_UTIL_H_
+#define BASE_MAC_MAC_UTIL_H_
+
+#include <AvailabilityMacros.h>
+#include <Carbon/Carbon.h>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/logging.h"
+
+#if defined(__OBJC__)
+#import <Foundation/Foundation.h>
+#else  // __OBJC__
+class NSImage;
+#endif  // __OBJC__
+
+namespace base {
+
+class FilePath;
+
+namespace mac {
+
+// Full screen modes, in increasing order of priority.  More permissive modes
+// take predecence.
+enum FullScreenMode {
+  kFullScreenModeHideAll = 0,
+  kFullScreenModeHideDock = 1,
+  kFullScreenModeAutoHideAll = 2,
+  kNumFullScreenModes = 3,
+
+  // kFullScreenModeNormal is not a valid FullScreenMode, but it is useful to
+  // other classes, so we include it here.
+  kFullScreenModeNormal = 10,
+};
+
+BASE_EXPORT std::string PathFromFSRef(const FSRef& ref);
+BASE_EXPORT bool FSRefFromPath(const std::string& path, FSRef* ref);
+
+// Returns an sRGB color space.  The return value is a static value; do not
+// release it!
+BASE_EXPORT CGColorSpaceRef GetSRGBColorSpace();
+
+// Returns the generic RGB color space. The return value is a static value; do
+// not release it!
+BASE_EXPORT CGColorSpaceRef GetGenericRGBColorSpace();
+
+// Returns the color space being used by the main display.  The return value
+// is a static value; do not release it!
+BASE_EXPORT CGColorSpaceRef GetSystemColorSpace();
+
+// Add a full screen request for the given |mode|.  Must be paired with a
+// ReleaseFullScreen() call for the same |mode|.  This does not by itself create
+// a fullscreen window; rather, it manages per-application state related to
+// hiding the dock and menubar.  Must be called on the main thread.
+BASE_EXPORT void RequestFullScreen(FullScreenMode mode);
+
+// Release a request for full screen mode.  Must be matched with a
+// RequestFullScreen() call for the same |mode|.  As with RequestFullScreen(),
+// this does not affect windows directly, but rather manages per-application
+// state.  For example, if there are no other outstanding
+// |kFullScreenModeAutoHideAll| requests, this will reshow the menu bar.  Must
+// be called on main thread.
+BASE_EXPORT void ReleaseFullScreen(FullScreenMode mode);
+
+// Convenience method to switch the current fullscreen mode.  This has the same
+// net effect as a ReleaseFullScreen(from_mode) call followed immediately by a
+// RequestFullScreen(to_mode).  Must be called on the main thread.
+BASE_EXPORT void SwitchFullScreenModes(FullScreenMode from_mode,
+                                       FullScreenMode to_mode);
+
+// Set the visibility of the cursor.
+BASE_EXPORT void SetCursorVisibility(bool visible);
+
+// Activates the process with the given PID.
+BASE_EXPORT void ActivateProcess(pid_t pid);
+
+// Returns true if this process is in the foreground, meaning that it's the
+// frontmost process, the one whose menu bar is shown at the top of the main
+// display.
+BASE_EXPORT bool AmIForeground();
+
+// Excludes the file given by |file_path| from being backed up by Time Machine.
+BASE_EXPORT bool SetFileBackupExclusion(const FilePath& file_path);
+
+// Checks if the current application is set as a Login Item, so it will launch
+// on Login. If a non-NULL pointer to is_hidden is passed, the Login Item also
+// is queried for the 'hide on launch' flag.
+BASE_EXPORT bool CheckLoginItemStatus(bool* is_hidden);
+
+// Adds current application to the set of Login Items with specified "hide"
+// flag. This has the same effect as adding/removing the application in
+// SystemPreferences->Accounts->LoginItems or marking Application in the Dock
+// as "Options->Open on Login".
+// Does nothing if the application is already set up as Login Item with
+// specified hide flag.
+BASE_EXPORT void AddToLoginItems(bool hide_on_startup);
+
+// Removes the current application from the list Of Login Items.
+BASE_EXPORT void RemoveFromLoginItems();
+
+// Returns true if the current process was automatically launched as a
+// 'Login Item' or via Lion's Resume. Used to suppress opening windows.
+BASE_EXPORT bool WasLaunchedAsLoginOrResumeItem();
+
+// Returns true if the current process was automatically launched as a
+// 'Login Item' or via Resume, and the 'Reopen windows when logging back in'
+// checkbox was selected by the user.  This indicates that the previous
+// session should be restored.
+BASE_EXPORT bool WasLaunchedAsLoginItemRestoreState();
+
+// Returns true if the current process was automatically launched as a
+// 'Login Item' with 'hide on startup' flag. Used to suppress opening windows.
+BASE_EXPORT bool WasLaunchedAsHiddenLoginItem();
+
+// Remove the quarantine xattr from the given file. Returns false if there was
+// an error, or true otherwise.
+BASE_EXPORT bool RemoveQuarantineAttribute(const FilePath& file_path);
+
+// Run-time OS version checks. Use these instead of
+// base::SysInfo::OperatingSystemVersionNumbers. Prefer the "OrEarlier" and
+// "OrLater" variants to those that check for a specific version, unless you
+// know for sure that you need to check for a specific version.
+
+// Snow Leopard is Mac OS X 10.6, Darwin 10.
+BASE_EXPORT bool IsOSSnowLeopard();
+
+// Lion is Mac OS X 10.7, Darwin 11.
+BASE_EXPORT bool IsOSLion();
+BASE_EXPORT bool IsOSLionOrEarlier();
+BASE_EXPORT bool IsOSLionOrLater();
+
+// Mountain Lion is Mac OS X 10.8, Darwin 12.
+BASE_EXPORT bool IsOSMountainLion();
+BASE_EXPORT bool IsOSMountainLionOrEarlier();
+BASE_EXPORT bool IsOSMountainLionOrLater();
+
+// Mavericks is Mac OS X 10.9, Darwin 13.
+BASE_EXPORT bool IsOSMavericks();
+BASE_EXPORT bool IsOSMavericksOrEarlier();
+BASE_EXPORT bool IsOSMavericksOrLater();
+
+// Yosemite is Mac OS X 10.10, Darwin 14.
+BASE_EXPORT bool IsOSYosemite();
+BASE_EXPORT bool IsOSYosemiteOrLater();
+
+// This should be infrequently used. It only makes sense to use this to avoid
+// codepaths that are very likely to break on future (unreleased, untested,
+// unborn) OS releases, or to log when the OS is newer than any known version.
+BASE_EXPORT bool IsOSLaterThanYosemite_DontCallThis();
+
+// Inline functions that are redundant due to version ranges being mutually-
+// exclusive.
+inline bool IsOSLionOrEarlier() { return !IsOSMountainLionOrLater(); }
+inline bool IsOSMountainLionOrEarlier() { return !IsOSMavericksOrLater(); }
+inline bool IsOSMavericksOrEarlier() { return !IsOSYosemiteOrLater(); }
+
+// When the deployment target is set, the code produced cannot run on earlier
+// OS releases. That enables some of the IsOS* family to be implemented as
+// constant-value inline functions. The MAC_OS_X_VERSION_MIN_REQUIRED macro
+// contains the value of the deployment target.
+
+#if defined(MAC_OS_X_VERSION_10_7) && \
+    MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_7
+#define BASE_MAC_MAC_UTIL_H_INLINED_GE_10_7
+inline bool IsOSSnowLeopard() { return false; }
+inline bool IsOSLionOrLater() { return true; }
+#endif
+
+#if defined(MAC_OS_X_VERSION_10_7) && \
+    MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_7
+#define BASE_MAC_MAC_UTIL_H_INLINED_GT_10_7
+inline bool IsOSLion() { return false; }
+#endif
+
+#if defined(MAC_OS_X_VERSION_10_8) && \
+    MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_8
+#define BASE_MAC_MAC_UTIL_H_INLINED_GE_10_8
+inline bool IsOSMountainLionOrLater() { return true; }
+#endif
+
+#if defined(MAC_OS_X_VERSION_10_8) && \
+    MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_8
+#define BASE_MAC_MAC_UTIL_H_INLINED_GT_10_8
+inline bool IsOSMountainLion() { return false; }
+#endif
+
+#if defined(MAC_OS_X_VERSION_10_9) && \
+    MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_9
+#define BASE_MAC_MAC_UTIL_H_INLINED_GE_10_9
+inline bool IsOSMavericksOrLater() { return true; }
+#endif
+
+#if defined(MAC_OS_X_VERSION_10_9) && \
+    MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_9
+#define BASE_MAC_MAC_UTIL_H_INLINED_GT_10_9
+inline bool IsOSMavericks() { return false; }
+#endif
+
+#if defined(MAC_OS_X_VERSION_10_10) && \
+    MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10
+#define BASE_MAC_MAC_UTIL_H_INLINED_GE_10_10
+inline bool IsOSYosemiteOrLater() { return true; }
+#endif
+
+#if defined(MAC_OS_X_VERSION_10_10) && \
+    MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_10
+#define BASE_MAC_MAC_UTIL_H_INLINED_GT_10_10
+inline bool IsOSYosemite() { return false; }
+inline bool IsOSLaterThanYosemite_DontCallThis() { return true; }
+#endif
+
+// Retrieve the system's model identifier string from the IOKit registry:
+// for example, "MacPro4,1", "MacBookPro6,1". Returns empty string upon
+// failure.
+BASE_EXPORT std::string GetModelIdentifier();
+
+// Parse a model identifier string; for example, into ("MacBookPro", 6, 1).
+// If any error occurs, none of the input pointers are touched.
+BASE_EXPORT bool ParseModelIdentifier(const std::string& ident,
+                                      std::string* type,
+                                      int32* major,
+                                      int32* minor);
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_MAC_UTIL_H_
diff --git a/base/mac/mac_util.mm b/base/mac/mac_util.mm
new file mode 100644
index 0000000..bdf45de
--- /dev/null
+++ b/base/mac/mac_util.mm
@@ -0,0 +1,594 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/mac_util.h"
+
+#import <Cocoa/Cocoa.h>
+#import <IOKit/IOKitLib.h>
+
+#include <errno.h>
+#include <string.h>
+#include <sys/utsname.h>
+#include <sys/xattr.h>
+
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/mac/bundle_locations.h"
+#include "base/mac/foundation_util.h"
+#include "base/mac/mac_logging.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/mac/scoped_ioobject.h"
+#include "base/mac/scoped_nsobject.h"
+#include "base/mac/sdk_forward_declarations.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/sys_string_conversions.h"
+
+namespace base {
+namespace mac {
+
+namespace {
+
+// The current count of outstanding requests for full screen mode from browser
+// windows, plugins, etc.
+int g_full_screen_requests[kNumFullScreenModes] = { 0 };
+
+// Sets the appropriate application presentation option based on the current
+// full screen requests.  Since only one presentation option can be active at a
+// given time, full screen requests are ordered by priority.  If there are no
+// outstanding full screen requests, reverts to normal mode.  If the correct
+// presentation option is already set, does nothing.
+void SetUIMode() {
+  NSApplicationPresentationOptions current_options =
+      [NSApp presentationOptions];
+
+  // Determine which mode should be active, based on which requests are
+  // currently outstanding.  More permissive requests take precedence.  For
+  // example, plugins request |kFullScreenModeAutoHideAll|, while browser
+  // windows request |kFullScreenModeHideDock| when the fullscreen overlay is
+  // down.  Precedence goes to plugins in this case, so AutoHideAll wins over
+  // HideDock.
+  NSApplicationPresentationOptions desired_options =
+      NSApplicationPresentationDefault;
+  if (g_full_screen_requests[kFullScreenModeAutoHideAll] > 0) {
+    desired_options = NSApplicationPresentationHideDock |
+                      NSApplicationPresentationAutoHideMenuBar;
+  } else if (g_full_screen_requests[kFullScreenModeHideDock] > 0) {
+    desired_options = NSApplicationPresentationHideDock;
+  } else if (g_full_screen_requests[kFullScreenModeHideAll] > 0) {
+    desired_options = NSApplicationPresentationHideDock |
+                      NSApplicationPresentationHideMenuBar;
+  }
+
+  // Mac OS X bug: if the window is fullscreened (Lion-style) and
+  // NSApplicationPresentationDefault is requested, the result is that the menu
+  // bar doesn't auto-hide. rdar://13576498 http://www.openradar.me/13576498
+  //
+  // As a workaround, in that case, explicitly set the presentation options to
+  // the ones that are set by the system as it fullscreens a window.
+  if (desired_options == NSApplicationPresentationDefault &&
+      current_options & NSApplicationPresentationFullScreen) {
+    desired_options |= NSApplicationPresentationFullScreen |
+                       NSApplicationPresentationAutoHideMenuBar |
+                       NSApplicationPresentationAutoHideDock;
+  }
+
+  if (current_options != desired_options)
+    [NSApp setPresentationOptions:desired_options];
+}
+
+// Looks into Shared File Lists corresponding to Login Items for the item
+// representing the current application.  If such an item is found, returns a
+// retained reference to it. Caller is responsible for releasing the reference.
+LSSharedFileListItemRef GetLoginItemForApp() {
+  ScopedCFTypeRef<LSSharedFileListRef> login_items(LSSharedFileListCreate(
+      NULL, kLSSharedFileListSessionLoginItems, NULL));
+
+  if (!login_items.get()) {
+    DLOG(ERROR) << "Couldn't get a Login Items list.";
+    return NULL;
+  }
+
+  base::scoped_nsobject<NSArray> login_items_array(
+      CFToNSCast(LSSharedFileListCopySnapshot(login_items, NULL)));
+
+  NSURL* url = [NSURL fileURLWithPath:[base::mac::MainBundle() bundlePath]];
+
+  for(NSUInteger i = 0; i < [login_items_array count]; ++i) {
+    LSSharedFileListItemRef item = reinterpret_cast<LSSharedFileListItemRef>(
+        [login_items_array objectAtIndex:i]);
+    CFURLRef item_url_ref = NULL;
+
+    if (LSSharedFileListItemResolve(item, 0, &item_url_ref, NULL) == noErr) {
+      ScopedCFTypeRef<CFURLRef> item_url(item_url_ref);
+      if (CFEqual(item_url, url)) {
+        CFRetain(item);
+        return item;
+      }
+    }
+  }
+
+  return NULL;
+}
+
+bool IsHiddenLoginItem(LSSharedFileListItemRef item) {
+  ScopedCFTypeRef<CFBooleanRef> hidden(reinterpret_cast<CFBooleanRef>(
+      LSSharedFileListItemCopyProperty(item,
+          reinterpret_cast<CFStringRef>(kLSSharedFileListLoginItemHidden))));
+
+  return hidden && hidden == kCFBooleanTrue;
+}
+
+}  // namespace
+
+std::string PathFromFSRef(const FSRef& ref) {
+  ScopedCFTypeRef<CFURLRef> url(
+      CFURLCreateFromFSRef(kCFAllocatorDefault, &ref));
+  NSString *path_string = [(NSURL *)url.get() path];
+  return [path_string fileSystemRepresentation];
+}
+
+bool FSRefFromPath(const std::string& path, FSRef* ref) {
+  OSStatus status = FSPathMakeRef((const UInt8*)path.c_str(),
+                                  ref, nil);
+  return status == noErr;
+}
+
+CGColorSpaceRef GetGenericRGBColorSpace() {
+  // Leaked. That's OK, it's scoped to the lifetime of the application.
+  static CGColorSpaceRef g_color_space_generic_rgb(
+      CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB));
+  DLOG_IF(ERROR, !g_color_space_generic_rgb) <<
+      "Couldn't get the generic RGB color space";
+  return g_color_space_generic_rgb;
+}
+
+CGColorSpaceRef GetSRGBColorSpace() {
+  // Leaked.  That's OK, it's scoped to the lifetime of the application.
+  static CGColorSpaceRef g_color_space_sRGB =
+      CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
+  DLOG_IF(ERROR, !g_color_space_sRGB) << "Couldn't get the sRGB color space";
+  return g_color_space_sRGB;
+}
+
+CGColorSpaceRef GetSystemColorSpace() {
+  // Leaked.  That's OK, it's scoped to the lifetime of the application.
+  // Try to get the main display's color space.
+  static CGColorSpaceRef g_system_color_space =
+      CGDisplayCopyColorSpace(CGMainDisplayID());
+
+  if (!g_system_color_space) {
+    // Use a generic RGB color space.  This is better than nothing.
+    g_system_color_space = CGColorSpaceCreateDeviceRGB();
+
+    if (g_system_color_space) {
+      DLOG(WARNING) <<
+          "Couldn't get the main display's color space, using generic";
+    } else {
+      DLOG(ERROR) << "Couldn't get any color space";
+    }
+  }
+
+  return g_system_color_space;
+}
+
+// Add a request for full screen mode.  Must be called on the main thread.
+void RequestFullScreen(FullScreenMode mode) {
+  DCHECK_LT(mode, kNumFullScreenModes);
+  if (mode >= kNumFullScreenModes)
+    return;
+
+  DCHECK_GE(g_full_screen_requests[mode], 0);
+  if (mode < 0)
+    return;
+
+  g_full_screen_requests[mode] = std::max(g_full_screen_requests[mode] + 1, 1);
+  SetUIMode();
+}
+
+// Release a request for full screen mode.  Must be called on the main thread.
+void ReleaseFullScreen(FullScreenMode mode) {
+  DCHECK_LT(mode, kNumFullScreenModes);
+  if (mode >= kNumFullScreenModes)
+    return;
+
+  DCHECK_GE(g_full_screen_requests[mode], 0);
+  if (mode < 0)
+    return;
+
+  g_full_screen_requests[mode] = std::max(g_full_screen_requests[mode] - 1, 0);
+  SetUIMode();
+}
+
+// Switches full screen modes.  Releases a request for |from_mode| and adds a
+// new request for |to_mode|.  Must be called on the main thread.
+void SwitchFullScreenModes(FullScreenMode from_mode, FullScreenMode to_mode) {
+  DCHECK_LT(from_mode, kNumFullScreenModes);
+  DCHECK_LT(to_mode, kNumFullScreenModes);
+  if (from_mode >= kNumFullScreenModes || to_mode >= kNumFullScreenModes)
+    return;
+
+  DCHECK_GT(g_full_screen_requests[from_mode], 0);
+  DCHECK_GE(g_full_screen_requests[to_mode], 0);
+  g_full_screen_requests[from_mode] =
+      std::max(g_full_screen_requests[from_mode] - 1, 0);
+  g_full_screen_requests[to_mode] =
+      std::max(g_full_screen_requests[to_mode] + 1, 1);
+  SetUIMode();
+}
+
+void SetCursorVisibility(bool visible) {
+  if (visible)
+    [NSCursor unhide];
+  else
+    [NSCursor hide];
+}
+
+void ActivateProcess(pid_t pid) {
+  ProcessSerialNumber process;
+  OSStatus status = GetProcessForPID(pid, &process);
+  if (status == noErr) {
+    SetFrontProcess(&process);
+  } else {
+    OSSTATUS_DLOG(WARNING, status) << "Unable to get process for pid " << pid;
+  }
+}
+
+bool AmIForeground() {
+  ProcessSerialNumber foreground_psn = { 0 };
+  OSErr err = GetFrontProcess(&foreground_psn);
+  if (err != noErr) {
+    OSSTATUS_DLOG(WARNING, err) << "GetFrontProcess";
+    return false;
+  }
+
+  ProcessSerialNumber my_psn = { 0, kCurrentProcess };
+
+  Boolean result = FALSE;
+  err = SameProcess(&foreground_psn, &my_psn, &result);
+  if (err != noErr) {
+    OSSTATUS_DLOG(WARNING, err) << "SameProcess";
+    return false;
+  }
+
+  return result;
+}
+
+bool SetFileBackupExclusion(const FilePath& file_path) {
+  NSString* file_path_ns =
+      [NSString stringWithUTF8String:file_path.value().c_str()];
+  NSURL* file_url = [NSURL fileURLWithPath:file_path_ns];
+
+  // When excludeByPath is true the application must be running with root
+  // privileges (admin for 10.6 and earlier) but the URL does not have to
+  // already exist. When excludeByPath is false the URL must already exist but
+  // can be used in non-root (or admin as above) mode. We use false so that
+  // non-root (or admin) users don't get their TimeMachine drive filled up with
+  // unnecessary backups.
+  OSStatus os_err =
+      CSBackupSetItemExcluded(base::mac::NSToCFCast(file_url), TRUE, FALSE);
+  if (os_err != noErr) {
+    OSSTATUS_DLOG(WARNING, os_err)
+        << "Failed to set backup exclusion for file '"
+        << file_path.value().c_str() << "'";
+  }
+  return os_err == noErr;
+}
+
+bool CheckLoginItemStatus(bool* is_hidden) {
+  ScopedCFTypeRef<LSSharedFileListItemRef> item(GetLoginItemForApp());
+  if (!item.get())
+    return false;
+
+  if (is_hidden)
+    *is_hidden = IsHiddenLoginItem(item);
+
+  return true;
+}
+
+void AddToLoginItems(bool hide_on_startup) {
+  ScopedCFTypeRef<LSSharedFileListItemRef> item(GetLoginItemForApp());
+  if (item.get() && (IsHiddenLoginItem(item) == hide_on_startup)) {
+    return;  // Already is a login item with required hide flag.
+  }
+
+  ScopedCFTypeRef<LSSharedFileListRef> login_items(LSSharedFileListCreate(
+      NULL, kLSSharedFileListSessionLoginItems, NULL));
+
+  if (!login_items.get()) {
+    DLOG(ERROR) << "Couldn't get a Login Items list.";
+    return;
+  }
+
+  // Remove the old item, it has wrong hide flag, we'll create a new one.
+  if (item.get()) {
+    LSSharedFileListItemRemove(login_items, item);
+  }
+
+  NSURL* url = [NSURL fileURLWithPath:[base::mac::MainBundle() bundlePath]];
+
+  BOOL hide = hide_on_startup ? YES : NO;
+  NSDictionary* properties =
+      [NSDictionary
+        dictionaryWithObject:[NSNumber numberWithBool:hide]
+                      forKey:(NSString*)kLSSharedFileListLoginItemHidden];
+
+  ScopedCFTypeRef<LSSharedFileListItemRef> new_item;
+  new_item.reset(LSSharedFileListInsertItemURL(
+      login_items, kLSSharedFileListItemLast, NULL, NULL,
+      reinterpret_cast<CFURLRef>(url),
+      reinterpret_cast<CFDictionaryRef>(properties), NULL));
+
+  if (!new_item.get()) {
+    DLOG(ERROR) << "Couldn't insert current app into Login Items list.";
+  }
+}
+
+void RemoveFromLoginItems() {
+  ScopedCFTypeRef<LSSharedFileListItemRef> item(GetLoginItemForApp());
+  if (!item.get())
+    return;
+
+  ScopedCFTypeRef<LSSharedFileListRef> login_items(LSSharedFileListCreate(
+      NULL, kLSSharedFileListSessionLoginItems, NULL));
+
+  if (!login_items.get()) {
+    DLOG(ERROR) << "Couldn't get a Login Items list.";
+    return;
+  }
+
+  LSSharedFileListItemRemove(login_items, item);
+}
+
+bool WasLaunchedAsLoginOrResumeItem() {
+  ProcessSerialNumber psn = { 0, kCurrentProcess };
+  ProcessInfoRec info = {};
+  info.processInfoLength = sizeof(info);
+
+  if (GetProcessInformation(&psn, &info) == noErr) {
+    ProcessInfoRec parent_info = {};
+    parent_info.processInfoLength = sizeof(parent_info);
+    if (GetProcessInformation(&info.processLauncher, &parent_info) == noErr)
+      return parent_info.processSignature == 'lgnw';
+  }
+  return false;
+}
+
+bool WasLaunchedAsLoginItemRestoreState() {
+  // "Reopen windows..." option was added for Lion.  Prior OS versions should
+  // not have this behavior.
+  if (IsOSSnowLeopard() || !WasLaunchedAsLoginOrResumeItem())
+    return false;
+
+  CFStringRef app = CFSTR("com.apple.loginwindow");
+  CFStringRef save_state = CFSTR("TALLogoutSavesState");
+  ScopedCFTypeRef<CFPropertyListRef> plist(
+      CFPreferencesCopyAppValue(save_state, app));
+  // According to documentation, com.apple.loginwindow.plist does not exist on a
+  // fresh installation until the user changes a login window setting.  The
+  // "reopen windows" option is checked by default, so the plist would exist had
+  // the user unchecked it.
+  // https://developer.apple.com/library/mac/documentation/macosx/conceptual/bpsystemstartup/chapters/CustomLogin.html
+  if (!plist)
+    return true;
+
+  if (CFBooleanRef restore_state = base::mac::CFCast<CFBooleanRef>(plist))
+    return CFBooleanGetValue(restore_state);
+
+  return false;
+}
+
+bool WasLaunchedAsHiddenLoginItem() {
+  if (!WasLaunchedAsLoginOrResumeItem())
+    return false;
+
+  ScopedCFTypeRef<LSSharedFileListItemRef> item(GetLoginItemForApp());
+  if (!item.get()) {
+    // Lion can launch items for the resume feature.  So log an error only for
+    // Snow Leopard or earlier.
+    if (IsOSSnowLeopard())
+      DLOG(ERROR) <<
+          "Process launched at Login but can't access Login Item List.";
+
+    return false;
+  }
+  return IsHiddenLoginItem(item);
+}
+
+bool RemoveQuarantineAttribute(const FilePath& file_path) {
+  const char kQuarantineAttrName[] = "com.apple.quarantine";
+  int status = removexattr(file_path.value().c_str(), kQuarantineAttrName, 0);
+  return status == 0 || errno == ENOATTR;
+}
+
+namespace {
+
+// Returns the running system's Darwin major version. Don't call this, it's
+// an implementation detail and its result is meant to be cached by
+// MacOSXMinorVersion.
+int DarwinMajorVersionInternal() {
+  // base::OperatingSystemVersionNumbers calls Gestalt, which is a
+  // higher-level operation than is needed. It might perform unnecessary
+  // operations. On 10.6, it was observed to be able to spawn threads (see
+  // http://crbug.com/53200). It might also read files or perform other
+  // blocking operations. Actually, nobody really knows for sure just what
+  // Gestalt might do, or what it might be taught to do in the future.
+  //
+  // uname, on the other hand, is implemented as a simple series of sysctl
+  // system calls to obtain the relevant data from the kernel. The data is
+  // compiled right into the kernel, so no threads or blocking or other
+  // funny business is necessary.
+
+  struct utsname uname_info;
+  if (uname(&uname_info) != 0) {
+    DPLOG(ERROR) << "uname";
+    return 0;
+  }
+
+  if (strcmp(uname_info.sysname, "Darwin") != 0) {
+    DLOG(ERROR) << "unexpected uname sysname " << uname_info.sysname;
+    return 0;
+  }
+
+  int darwin_major_version = 0;
+  char* dot = strchr(uname_info.release, '.');
+  if (dot) {
+    if (!base::StringToInt(base::StringPiece(uname_info.release,
+                                             dot - uname_info.release),
+                           &darwin_major_version)) {
+      dot = NULL;
+    }
+  }
+
+  if (!dot) {
+    DLOG(ERROR) << "could not parse uname release " << uname_info.release;
+    return 0;
+  }
+
+  return darwin_major_version;
+}
+
+// Returns the running system's Mac OS X minor version. This is the |y| value
+// in 10.y or 10.y.z. Don't call this, it's an implementation detail and the
+// result is meant to be cached by MacOSXMinorVersion.
+int MacOSXMinorVersionInternal() {
+  int darwin_major_version = DarwinMajorVersionInternal();
+
+  // The Darwin major version is always 4 greater than the Mac OS X minor
+  // version for Darwin versions beginning with 6, corresponding to Mac OS X
+  // 10.2. Since this correspondence may change in the future, warn when
+  // encountering a version higher than anything seen before. Older Darwin
+  // versions, or versions that can't be determined, result in
+  // immediate death.
+  CHECK(darwin_major_version >= 6);
+  int mac_os_x_minor_version = darwin_major_version - 4;
+  DLOG_IF(WARNING, darwin_major_version > 14) << "Assuming Darwin "
+      << base::IntToString(darwin_major_version) << " is Mac OS X 10."
+      << base::IntToString(mac_os_x_minor_version);
+
+  return mac_os_x_minor_version;
+}
+
+// Returns the running system's Mac OS X minor version. This is the |y| value
+// in 10.y or 10.y.z.
+int MacOSXMinorVersion() {
+  static int mac_os_x_minor_version = MacOSXMinorVersionInternal();
+  return mac_os_x_minor_version;
+}
+
+enum {
+  SNOW_LEOPARD_MINOR_VERSION = 6,
+  LION_MINOR_VERSION = 7,
+  MOUNTAIN_LION_MINOR_VERSION = 8,
+  MAVERICKS_MINOR_VERSION = 9,
+  YOSEMITE_MINOR_VERSION = 10,
+};
+
+}  // namespace
+
+#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GE_10_7)
+bool IsOSSnowLeopard() {
+  return MacOSXMinorVersion() == SNOW_LEOPARD_MINOR_VERSION;
+}
+#endif
+
+#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GT_10_7)
+bool IsOSLion() {
+  return MacOSXMinorVersion() == LION_MINOR_VERSION;
+}
+#endif
+
+#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GE_10_7)
+bool IsOSLionOrLater() {
+  return MacOSXMinorVersion() >= LION_MINOR_VERSION;
+}
+#endif
+
+#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GT_10_8)
+bool IsOSMountainLion() {
+  return MacOSXMinorVersion() == MOUNTAIN_LION_MINOR_VERSION;
+}
+#endif
+
+#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GE_10_8)
+bool IsOSMountainLionOrLater() {
+  return MacOSXMinorVersion() >= MOUNTAIN_LION_MINOR_VERSION;
+}
+#endif
+
+#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GT_10_9)
+bool IsOSMavericks() {
+  return MacOSXMinorVersion() == MAVERICKS_MINOR_VERSION;
+}
+#endif
+
+#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GE_10_9)
+bool IsOSMavericksOrLater() {
+  return MacOSXMinorVersion() >= MAVERICKS_MINOR_VERSION;
+}
+#endif
+
+#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GT_10_10)
+bool IsOSYosemite() {
+  return MacOSXMinorVersion() == YOSEMITE_MINOR_VERSION;
+}
+#endif
+
+#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GE_10_10)
+bool IsOSYosemiteOrLater() {
+  return MacOSXMinorVersion() >= YOSEMITE_MINOR_VERSION;
+}
+#endif
+
+#if !defined(BASE_MAC_MAC_UTIL_H_INLINED_GT_10_10)
+bool IsOSLaterThanYosemite_DontCallThis() {
+  return MacOSXMinorVersion() > YOSEMITE_MINOR_VERSION;
+}
+#endif
+
+std::string GetModelIdentifier() {
+  std::string return_string;
+  ScopedIOObject<io_service_t> platform_expert(
+      IOServiceGetMatchingService(kIOMasterPortDefault,
+                                  IOServiceMatching("IOPlatformExpertDevice")));
+  if (platform_expert) {
+    ScopedCFTypeRef<CFDataRef> model_data(
+        static_cast<CFDataRef>(IORegistryEntryCreateCFProperty(
+            platform_expert,
+            CFSTR("model"),
+            kCFAllocatorDefault,
+            0)));
+    if (model_data) {
+      return_string =
+          reinterpret_cast<const char*>(CFDataGetBytePtr(model_data));
+    }
+  }
+  return return_string;
+}
+
+bool ParseModelIdentifier(const std::string& ident,
+                          std::string* type,
+                          int32* major,
+                          int32* minor) {
+  size_t number_loc = ident.find_first_of("0123456789");
+  if (number_loc == std::string::npos)
+    return false;
+  size_t comma_loc = ident.find(',', number_loc);
+  if (comma_loc == std::string::npos)
+    return false;
+  int32 major_tmp, minor_tmp;
+  std::string::const_iterator begin = ident.begin();
+  if (!StringToInt(
+          StringPiece(begin + number_loc, begin + comma_loc), &major_tmp) ||
+      !StringToInt(
+          StringPiece(begin + comma_loc + 1, ident.end()), &minor_tmp))
+    return false;
+  *type = ident.substr(0, number_loc);
+  *major = major_tmp;
+  *minor = minor_tmp;
+  return true;
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/mac_util_unittest.mm b/base/mac/mac_util_unittest.mm
new file mode 100644
index 0000000..3982ab0
--- /dev/null
+++ b/base/mac/mac_util_unittest.mm
@@ -0,0 +1,289 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/mac/mac_util.h"
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/mac/foundation_util.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/mac/scoped_nsobject.h"
+#include "base/sys_info.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+#include <errno.h>
+#include <sys/xattr.h>
+
+namespace base {
+namespace mac {
+
+namespace {
+
+typedef PlatformTest MacUtilTest;
+
+TEST_F(MacUtilTest, TestFSRef) {
+  FSRef ref;
+  std::string path("/System/Library");
+
+  ASSERT_TRUE(FSRefFromPath(path, &ref));
+  EXPECT_EQ(path, PathFromFSRef(ref));
+}
+
+TEST_F(MacUtilTest, GetUserDirectoryTest) {
+  // Try a few keys, make sure they come back with non-empty paths.
+  FilePath caches_dir;
+  EXPECT_TRUE(GetUserDirectory(NSCachesDirectory, &caches_dir));
+  EXPECT_FALSE(caches_dir.empty());
+
+  FilePath application_support_dir;
+  EXPECT_TRUE(GetUserDirectory(NSApplicationSupportDirectory,
+                               &application_support_dir));
+  EXPECT_FALSE(application_support_dir.empty());
+
+  FilePath library_dir;
+  EXPECT_TRUE(GetUserDirectory(NSLibraryDirectory, &library_dir));
+  EXPECT_FALSE(library_dir.empty());
+}
+
+TEST_F(MacUtilTest, TestLibraryPath) {
+  FilePath library_dir = GetUserLibraryPath();
+  // Make sure the string isn't empty.
+  EXPECT_FALSE(library_dir.value().empty());
+}
+
+TEST_F(MacUtilTest, TestGetAppBundlePath) {
+  FilePath out;
+
+  // Make sure it doesn't crash.
+  out = GetAppBundlePath(FilePath());
+  EXPECT_TRUE(out.empty());
+
+  // Some more invalid inputs.
+  const char* const invalid_inputs[] = {
+    "/", "/foo", "foo", "/foo/bar.", "foo/bar.", "/foo/bar./bazquux",
+    "foo/bar./bazquux", "foo/.app", "//foo",
+  };
+  for (size_t i = 0; i < arraysize(invalid_inputs); i++) {
+    out = GetAppBundlePath(FilePath(invalid_inputs[i]));
+    EXPECT_TRUE(out.empty()) << "loop: " << i;
+  }
+
+  // Some valid inputs; this and |expected_outputs| should be in sync.
+  struct {
+    const char *in;
+    const char *expected_out;
+  } valid_inputs[] = {
+    { "FooBar.app/", "FooBar.app" },
+    { "/FooBar.app", "/FooBar.app" },
+    { "/FooBar.app/", "/FooBar.app" },
+    { "//FooBar.app", "//FooBar.app" },
+    { "/Foo/Bar.app", "/Foo/Bar.app" },
+    { "/Foo/Bar.app/", "/Foo/Bar.app" },
+    { "/F/B.app", "/F/B.app" },
+    { "/F/B.app/", "/F/B.app" },
+    { "/Foo/Bar.app/baz", "/Foo/Bar.app" },
+    { "/Foo/Bar.app/baz/", "/Foo/Bar.app" },
+    { "/Foo/Bar.app/baz/quux.app/quuux", "/Foo/Bar.app" },
+    { "/Applications/Google Foo.app/bar/Foo Helper.app/quux/Foo Helper",
+        "/Applications/Google Foo.app" },
+  };
+  for (size_t i = 0; i < arraysize(valid_inputs); i++) {
+    out = GetAppBundlePath(FilePath(valid_inputs[i].in));
+    EXPECT_FALSE(out.empty()) << "loop: " << i;
+    EXPECT_STREQ(valid_inputs[i].expected_out,
+        out.value().c_str()) << "loop: " << i;
+  }
+}
+
+// http://crbug.com/425745
+TEST_F(MacUtilTest, DISABLED_TestExcludeFileFromBackups) {
+  // The file must already exist in order to set its exclusion property.
+  ScopedTempDir temp_dir_;
+  ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+  FilePath dummy_file_path = temp_dir_.path().Append("DummyFile");
+  const char dummy_data[] = "All your base are belong to us!";
+  // Dump something real into the file.
+  ASSERT_EQ(static_cast<int>(arraysize(dummy_data)),
+            WriteFile(dummy_file_path, dummy_data, arraysize(dummy_data)));
+  NSString* fileURLString =
+      [NSString stringWithUTF8String:dummy_file_path.value().c_str()];
+  NSURL* fileURL = [NSURL URLWithString:fileURLString];
+  // Initial state should be non-excluded.
+  EXPECT_FALSE(CSBackupIsItemExcluded(base::mac::NSToCFCast(fileURL), NULL));
+  // Exclude the file.
+  EXPECT_TRUE(SetFileBackupExclusion(dummy_file_path));
+  // SetFileBackupExclusion never excludes by path.
+  Boolean excluded_by_path = FALSE;
+  Boolean excluded =
+      CSBackupIsItemExcluded(base::mac::NSToCFCast(fileURL), &excluded_by_path);
+  EXPECT_TRUE(excluded);
+  EXPECT_FALSE(excluded_by_path);
+}
+
+TEST_F(MacUtilTest, NSObjectRetainRelease) {
+  base::scoped_nsobject<NSArray> array(
+      [[NSArray alloc] initWithObjects:@"foo", nil]);
+  EXPECT_EQ(1U, [array retainCount]);
+
+  NSObjectRetain(array);
+  EXPECT_EQ(2U, [array retainCount]);
+
+  NSObjectRelease(array);
+  EXPECT_EQ(1U, [array retainCount]);
+}
+
+TEST_F(MacUtilTest, IsOSEllipsis) {
+  int32 major, minor, bugfix;
+  base::SysInfo::OperatingSystemVersionNumbers(&major, &minor, &bugfix);
+
+  if (major == 10) {
+    if (minor == 6) {
+      EXPECT_TRUE(IsOSSnowLeopard());
+      EXPECT_FALSE(IsOSLion());
+      EXPECT_TRUE(IsOSLionOrEarlier());
+      EXPECT_FALSE(IsOSLionOrLater());
+      EXPECT_FALSE(IsOSMountainLion());
+      EXPECT_TRUE(IsOSMountainLionOrEarlier());
+      EXPECT_FALSE(IsOSMountainLionOrLater());
+      EXPECT_FALSE(IsOSMavericks());
+      EXPECT_TRUE(IsOSMavericksOrEarlier());
+      EXPECT_FALSE(IsOSMavericksOrLater());
+      EXPECT_FALSE(IsOSYosemite());
+      EXPECT_FALSE(IsOSYosemiteOrLater());
+      EXPECT_FALSE(IsOSLaterThanYosemite_DontCallThis());
+    } else if (minor == 7) {
+      EXPECT_FALSE(IsOSSnowLeopard());
+      EXPECT_TRUE(IsOSLion());
+      EXPECT_TRUE(IsOSLionOrEarlier());
+      EXPECT_TRUE(IsOSLionOrLater());
+      EXPECT_FALSE(IsOSMountainLion());
+      EXPECT_TRUE(IsOSMountainLionOrEarlier());
+      EXPECT_FALSE(IsOSMountainLionOrLater());
+      EXPECT_FALSE(IsOSMavericks());
+      EXPECT_TRUE(IsOSMavericksOrEarlier());
+      EXPECT_FALSE(IsOSMavericksOrLater());
+      EXPECT_FALSE(IsOSYosemite());
+      EXPECT_FALSE(IsOSYosemiteOrLater());
+      EXPECT_FALSE(IsOSLaterThanYosemite_DontCallThis());
+    } else if (minor == 8) {
+      EXPECT_FALSE(IsOSSnowLeopard());
+      EXPECT_FALSE(IsOSLion());
+      EXPECT_FALSE(IsOSLionOrEarlier());
+      EXPECT_TRUE(IsOSLionOrLater());
+      EXPECT_TRUE(IsOSMountainLion());
+      EXPECT_TRUE(IsOSMountainLionOrEarlier());
+      EXPECT_TRUE(IsOSMountainLionOrLater());
+      EXPECT_FALSE(IsOSMavericks());
+      EXPECT_TRUE(IsOSMavericksOrEarlier());
+      EXPECT_FALSE(IsOSMavericksOrLater());
+      EXPECT_FALSE(IsOSYosemite());
+      EXPECT_FALSE(IsOSYosemiteOrLater());
+      EXPECT_FALSE(IsOSLaterThanYosemite_DontCallThis());
+    } else if (minor == 9) {
+      EXPECT_FALSE(IsOSSnowLeopard());
+      EXPECT_FALSE(IsOSLion());
+      EXPECT_FALSE(IsOSLionOrEarlier());
+      EXPECT_TRUE(IsOSLionOrLater());
+      EXPECT_FALSE(IsOSMountainLion());
+      EXPECT_FALSE(IsOSMountainLionOrEarlier());
+      EXPECT_TRUE(IsOSMountainLionOrLater());
+      EXPECT_TRUE(IsOSMavericks());
+      EXPECT_TRUE(IsOSMavericksOrEarlier());
+      EXPECT_TRUE(IsOSMavericksOrLater());
+      EXPECT_FALSE(IsOSYosemite());
+      EXPECT_FALSE(IsOSYosemiteOrLater());
+      EXPECT_FALSE(IsOSLaterThanYosemite_DontCallThis());
+    } else if (minor == 10) {
+      EXPECT_FALSE(IsOSSnowLeopard());
+      EXPECT_FALSE(IsOSLion());
+      EXPECT_FALSE(IsOSLionOrEarlier());
+      EXPECT_TRUE(IsOSLionOrLater());
+      EXPECT_FALSE(IsOSMountainLion());
+      EXPECT_FALSE(IsOSMountainLionOrEarlier());
+      EXPECT_TRUE(IsOSMountainLionOrLater());
+      EXPECT_FALSE(IsOSMavericks());
+      EXPECT_FALSE(IsOSMavericksOrEarlier());
+      EXPECT_TRUE(IsOSMavericksOrLater());
+      EXPECT_TRUE(IsOSYosemite());
+      EXPECT_TRUE(IsOSYosemiteOrLater());
+      EXPECT_FALSE(IsOSLaterThanYosemite_DontCallThis());
+    } else {
+      // Not six, seven, eight, nine, or ten. Ah, ah, ah.
+      EXPECT_TRUE(false);
+    }
+  } else {
+    // Not ten. What you gonna do?
+    EXPECT_FALSE(true);
+  }
+}
+
+TEST_F(MacUtilTest, ParseModelIdentifier) {
+  std::string model;
+  int32 major = 1, minor = 2;
+
+  EXPECT_FALSE(ParseModelIdentifier("", &model, &major, &minor));
+  EXPECT_EQ(0U, model.length());
+  EXPECT_EQ(1, major);
+  EXPECT_EQ(2, minor);
+  EXPECT_FALSE(ParseModelIdentifier("FooBar", &model, &major, &minor));
+
+  EXPECT_TRUE(ParseModelIdentifier("MacPro4,1", &model, &major, &minor));
+  EXPECT_EQ(model, "MacPro");
+  EXPECT_EQ(4, major);
+  EXPECT_EQ(1, minor);
+
+  EXPECT_TRUE(ParseModelIdentifier("MacBookPro6,2", &model, &major, &minor));
+  EXPECT_EQ(model, "MacBookPro");
+  EXPECT_EQ(6, major);
+  EXPECT_EQ(2, minor);
+}
+
+TEST_F(MacUtilTest, TestRemoveQuarantineAttribute) {
+  ScopedTempDir temp_dir_;
+  ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+  FilePath dummy_folder_path = temp_dir_.path().Append("DummyFolder");
+  ASSERT_TRUE(base::CreateDirectory(dummy_folder_path));
+  const char* quarantine_str = "0000;4b392bb2;Chromium;|org.chromium.Chromium";
+  const char* file_path_str = dummy_folder_path.value().c_str();
+  EXPECT_EQ(0, setxattr(file_path_str, "com.apple.quarantine",
+      quarantine_str, strlen(quarantine_str), 0, 0));
+  EXPECT_EQ(static_cast<long>(strlen(quarantine_str)),
+      getxattr(file_path_str, "com.apple.quarantine",
+          NULL, 0, 0, 0));
+  EXPECT_TRUE(RemoveQuarantineAttribute(dummy_folder_path));
+  EXPECT_EQ(-1, getxattr(file_path_str, "com.apple.quarantine", NULL, 0, 0, 0));
+  EXPECT_EQ(ENOATTR, errno);
+}
+
+TEST_F(MacUtilTest, TestRemoveQuarantineAttributeTwice) {
+  ScopedTempDir temp_dir_;
+  ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+  FilePath dummy_folder_path = temp_dir_.path().Append("DummyFolder");
+  const char* file_path_str = dummy_folder_path.value().c_str();
+  ASSERT_TRUE(base::CreateDirectory(dummy_folder_path));
+  EXPECT_EQ(-1, getxattr(file_path_str, "com.apple.quarantine", NULL, 0, 0, 0));
+  // No quarantine attribute to begin with, but RemoveQuarantineAttribute still
+  // succeeds because in the end the folder still doesn't have the quarantine
+  // attribute set.
+  EXPECT_TRUE(RemoveQuarantineAttribute(dummy_folder_path));
+  EXPECT_TRUE(RemoveQuarantineAttribute(dummy_folder_path));
+  EXPECT_EQ(ENOATTR, errno);
+}
+
+TEST_F(MacUtilTest, TestRemoveQuarantineAttributeNonExistentPath) {
+  ScopedTempDir temp_dir_;
+  ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+  FilePath non_existent_path = temp_dir_.path().Append("DummyPath");
+  ASSERT_FALSE(PathExists(non_existent_path));
+  EXPECT_FALSE(RemoveQuarantineAttribute(non_existent_path));
+}
+
+}  // namespace
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/mach_logging.cc b/base/mac/mach_logging.cc
new file mode 100644
index 0000000..c5ff85e
--- /dev/null
+++ b/base/mac/mach_logging.cc
@@ -0,0 +1,87 @@
+// 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.
+
+#include "base/mac/mach_logging.h"
+
+#include <iomanip>
+#include <string>
+
+#include "base/strings/stringprintf.h"
+
+#if !defined(OS_IOS)
+#include <servers/bootstrap.h>
+#endif  // !OS_IOS
+
+namespace {
+
+std::string FormatMachErrorNumber(mach_error_t mach_err) {
+  // For the os/kern subsystem, give the error number in decimal as in
+  // <mach/kern_return.h>. Otherwise, give it in hexadecimal to make it easier
+  // to visualize the various bits. See <mach/error.h>.
+  if (mach_err >= 0 && mach_err < KERN_RETURN_MAX) {
+    return base::StringPrintf(" (%d)", mach_err);
+  }
+  return base::StringPrintf(" (0x%08x)", mach_err);
+}
+
+}  // namespace
+
+namespace logging {
+
+MachLogMessage::MachLogMessage(const char* file_path,
+                               int line,
+                               LogSeverity severity,
+                               mach_error_t mach_err)
+    : LogMessage(file_path, line, severity),
+      mach_err_(mach_err) {
+}
+
+MachLogMessage::~MachLogMessage() {
+  stream() << ": "
+           << mach_error_string(mach_err_)
+           << FormatMachErrorNumber(mach_err_);
+}
+
+#if !defined(OS_IOS)
+
+BootstrapLogMessage::BootstrapLogMessage(const char* file_path,
+                                         int line,
+                                         LogSeverity severity,
+                                         kern_return_t bootstrap_err)
+    : LogMessage(file_path, line, severity),
+      bootstrap_err_(bootstrap_err) {
+}
+
+BootstrapLogMessage::~BootstrapLogMessage() {
+  stream() << ": "
+           << bootstrap_strerror(bootstrap_err_);
+
+  switch (bootstrap_err_) {
+    case BOOTSTRAP_SUCCESS:
+    case BOOTSTRAP_NOT_PRIVILEGED:
+    case BOOTSTRAP_NAME_IN_USE:
+    case BOOTSTRAP_UNKNOWN_SERVICE:
+    case BOOTSTRAP_SERVICE_ACTIVE:
+    case BOOTSTRAP_BAD_COUNT:
+    case BOOTSTRAP_NO_MEMORY:
+    case BOOTSTRAP_NO_CHILDREN: {
+      // Show known bootstrap errors in decimal because that's how they're
+      // defined in <servers/bootstrap.h>.
+      stream() << " (" << bootstrap_err_ << ")";
+      break;
+    }
+
+    default: {
+      // bootstrap_strerror passes unknown errors to mach_error_string, so
+      // format them as they would be if they were handled by
+      // MachErrorMessage.
+      stream() << FormatMachErrorNumber(bootstrap_err_);
+      break;
+    }
+  }
+}
+
+#endif  // !OS_IOS
+
+}  // namespace logging
diff --git a/base/mac/mach_logging.h b/base/mac/mach_logging.h
new file mode 100644
index 0000000..b12e274
--- /dev/null
+++ b/base/mac/mach_logging.h
@@ -0,0 +1,167 @@
+// 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.
+
+#ifndef BASE_MAC_MACH_LOGGING_H_
+#define BASE_MAC_MACH_LOGGING_H_
+
+#include <mach/mach.h>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "build/build_config.h"
+
+// Use the MACH_LOG family of macros along with a mach_error_t (kern_return_t)
+// containing a Mach error. The error value will be decoded so that logged
+// messages explain the error.
+//
+// Use the BOOTSTRAP_LOG family of macros specifically for errors that occur
+// while interoperating with the bootstrap subsystem. These errors will first
+// be looked up as bootstrap error messages. If no match is found, they will
+// be treated as generic Mach errors, as in MACH_LOG.
+//
+// Examples:
+//
+//   kern_return_t kr = mach_timebase_info(&info);
+//   if (kr != KERN_SUCCESS) {
+//     MACH_LOG(ERROR, kr) << "mach_timebase_info";
+//   }
+//
+//   kr = vm_deallocate(task, address, size);
+//   MACH_DCHECK(kr == KERN_SUCCESS, kr) << "vm_deallocate";
+
+namespace logging {
+
+class BASE_EXPORT MachLogMessage : public logging::LogMessage {
+ public:
+  MachLogMessage(const char* file_path,
+                 int line,
+                 LogSeverity severity,
+                 mach_error_t mach_err);
+  ~MachLogMessage();
+
+ private:
+  mach_error_t mach_err_;
+
+  DISALLOW_COPY_AND_ASSIGN(MachLogMessage);
+};
+
+}  // namespace logging
+
+#if defined(NDEBUG)
+#define MACH_DVLOG_IS_ON(verbose_level) 0
+#else
+#define MACH_DVLOG_IS_ON(verbose_level) VLOG_IS_ON(verbose_level)
+#endif
+
+#define MACH_LOG_STREAM(severity, mach_err) \
+    COMPACT_GOOGLE_LOG_EX_ ## severity(MachLogMessage, mach_err).stream()
+#define MACH_VLOG_STREAM(verbose_level, mach_err) \
+    logging::MachLogMessage(__FILE__, __LINE__, \
+                            -verbose_level, mach_err).stream()
+
+#define MACH_LOG(severity, mach_err) \
+    LAZY_STREAM(MACH_LOG_STREAM(severity, mach_err), LOG_IS_ON(severity))
+#define MACH_LOG_IF(severity, condition, mach_err) \
+    LAZY_STREAM(MACH_LOG_STREAM(severity, mach_err), \
+                LOG_IS_ON(severity) && (condition))
+
+#define MACH_VLOG(verbose_level, mach_err) \
+    LAZY_STREAM(MACH_VLOG_STREAM(verbose_level, mach_err), \
+                VLOG_IS_ON(verbose_level))
+#define MACH_VLOG_IF(verbose_level, condition, mach_err) \
+    LAZY_STREAM(MACH_VLOG_STREAM(verbose_level, mach_err), \
+                VLOG_IS_ON(verbose_level) && (condition))
+
+#define MACH_CHECK(condition, mach_err) \
+    LAZY_STREAM(MACH_LOG_STREAM(FATAL, mach_err), !(condition)) \
+    << "Check failed: " # condition << ". "
+
+#define MACH_DLOG(severity, mach_err) \
+    LAZY_STREAM(MACH_LOG_STREAM(severity, mach_err), DLOG_IS_ON(severity))
+#define MACH_DLOG_IF(severity, condition, mach_err) \
+    LAZY_STREAM(MACH_LOG_STREAM(severity, mach_err), \
+                DLOG_IS_ON(severity) && (condition))
+
+#define MACH_DVLOG(verbose_level, mach_err) \
+    LAZY_STREAM(MACH_VLOG_STREAM(verbose_level, mach_err), \
+                MACH_DVLOG_IS_ON(verbose_level))
+#define MACH_DVLOG_IF(verbose_level, condition, mach_err) \
+    LAZY_STREAM(MACH_VLOG_STREAM(verbose_level, mach_err), \
+                MACH_DVLOG_IS_ON(verbose_level) && (condition))
+
+#define MACH_DCHECK(condition, mach_err)        \
+  LAZY_STREAM(MACH_LOG_STREAM(FATAL, mach_err), \
+              DCHECK_IS_ON() && !(condition))   \
+      << "Check failed: " #condition << ". "
+
+#if !defined(OS_IOS)
+
+namespace logging {
+
+class BASE_EXPORT BootstrapLogMessage : public logging::LogMessage {
+ public:
+  BootstrapLogMessage(const char* file_path,
+                      int line,
+                      LogSeverity severity,
+                      kern_return_t bootstrap_err);
+  ~BootstrapLogMessage();
+
+ private:
+  kern_return_t bootstrap_err_;
+
+  DISALLOW_COPY_AND_ASSIGN(BootstrapLogMessage);
+};
+
+}  // namespace logging
+
+#define BOOTSTRAP_DVLOG_IS_ON MACH_DVLOG_IS_ON
+
+#define BOOTSTRAP_LOG_STREAM(severity, bootstrap_err) \
+    COMPACT_GOOGLE_LOG_EX_ ## severity(BootstrapLogMessage, \
+                                       bootstrap_err).stream()
+#define BOOTSTRAP_VLOG_STREAM(verbose_level, bootstrap_err) \
+    logging::BootstrapLogMessage(__FILE__, __LINE__, \
+                                 -verbose_level, bootstrap_err).stream()
+
+#define BOOTSTRAP_LOG(severity, bootstrap_err) \
+    LAZY_STREAM(BOOTSTRAP_LOG_STREAM(severity, \
+                                     bootstrap_err), LOG_IS_ON(severity))
+#define BOOTSTRAP_LOG_IF(severity, condition, bootstrap_err) \
+    LAZY_STREAM(BOOTSTRAP_LOG_STREAM(severity, bootstrap_err), \
+                LOG_IS_ON(severity) && (condition))
+
+#define BOOTSTRAP_VLOG(verbose_level, bootstrap_err) \
+    LAZY_STREAM(BOOTSTRAP_VLOG_STREAM(verbose_level, bootstrap_err), \
+                VLOG_IS_ON(verbose_level))
+#define BOOTSTRAP_VLOG_IF(verbose_level, condition, bootstrap_err) \
+    LAZY_STREAM(BOOTSTRAP_VLOG_STREAM(verbose_level, bootstrap_err), \
+                VLOG_IS_ON(verbose_level) && (condition))
+
+#define BOOTSTRAP_CHECK(condition, bootstrap_err) \
+    LAZY_STREAM(BOOTSTRAP_LOG_STREAM(FATAL, bootstrap_err), !(condition)) \
+    << "Check failed: " # condition << ". "
+
+#define BOOTSTRAP_DLOG(severity, bootstrap_err) \
+    LAZY_STREAM(BOOTSTRAP_LOG_STREAM(severity, bootstrap_err), \
+                DLOG_IS_ON(severity))
+#define BOOTSTRAP_DLOG_IF(severity, condition, bootstrap_err) \
+    LAZY_STREAM(BOOTSTRAP_LOG_STREAM(severity, bootstrap_err), \
+                DLOG_IS_ON(severity) && (condition))
+
+#define BOOTSTRAP_DVLOG(verbose_level, bootstrap_err) \
+    LAZY_STREAM(BOOTSTRAP_VLOG_STREAM(verbose_level, bootstrap_err), \
+                BOOTSTRAP_DVLOG_IS_ON(verbose_level))
+#define BOOTSTRAP_DVLOG_IF(verbose_level, condition, bootstrap_err) \
+    LAZY_STREAM(BOOTSTRAP_VLOG_STREAM(verbose_level, bootstrap_err), \
+                BOOTSTRAP_DVLOG_IS_ON(verbose_level) && (condition))
+
+#define BOOTSTRAP_DCHECK(condition, bootstrap_err)        \
+  LAZY_STREAM(BOOTSTRAP_LOG_STREAM(FATAL, bootstrap_err), \
+              DCHECK_IS_ON() && !(condition))             \
+      << "Check failed: " #condition << ". "
+
+#endif  // !OS_IOS
+
+#endif  // BASE_MAC_MACH_LOGGING_H_
diff --git a/base/mac/objc_property_releaser.h b/base/mac/objc_property_releaser.h
new file mode 100644
index 0000000..973d793
--- /dev/null
+++ b/base/mac/objc_property_releaser.h
@@ -0,0 +1,127 @@
+// Copyright (c) 2011 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_MAC_OBJC_PROPERTY_RELEASER_H_
+#define BASE_MAC_OBJC_PROPERTY_RELEASER_H_
+
+#import <Foundation/Foundation.h>
+
+#include "base/base_export.h"
+
+namespace base {
+namespace mac {
+
+// ObjCPropertyReleaser is a C++ class that can automatically release
+// synthesized Objective-C properties marked "retain" or "copy". The expected
+// use is to place an ObjCPropertyReleaser object within an Objective-C class
+// definition. When built with the -fobjc-call-cxx-cdtors compiler option,
+// the ObjCPropertyReleaser's destructor will be called when the Objective-C
+// object that owns it is deallocated, and it will send a -release message to
+// the instance variables backing the appropriate properties. If
+// -fobjc-call-cxx-cdtors is not in use, ObjCPropertyReleaser's
+// ReleaseProperties method can be called from -dealloc to achieve the same
+// effect.
+//
+// Example usage:
+//
+// @interface AllaysIBF : NSObject {
+//  @private
+//   NSString* string_;
+//   NSMutableDictionary* dictionary_;
+//   NSString* notAProperty_;
+//   IBFDelegate* delegate_;  // weak
+//
+//   // It's recommended to put the class name into the property releaser's
+//   // instance variable name to gracefully handle subclassing, where
+//   // multiple classes in a hierarchy might want their own property
+//   // releasers.
+//   base::mac::ObjCPropertyReleaser propertyReleaser_AllaysIBF_;
+// }
+//
+// @property(retain, nonatomic) NSString* string;
+// @property(copy, nonatomic) NSMutableDictionary* dictionary;
+// @property(assign, nonatomic) IBFDelegate* delegate;
+// @property(retain, nonatomic) NSString* autoProp;
+//
+// @end  // @interface AllaysIBF
+//
+// @implementation AllaysIBF
+//
+// @synthesize string = string_;
+// @synthesize dictionary = dictionary_;
+// @synthesize delegate = delegate_;
+// @synthesize autoProp;
+//
+// - (id)init {
+//   if ((self = [super init])) {
+//     // Initialize with [AllaysIBF class]. Never use [self class] because
+//     // in the case of subclassing, it will return the most specific class
+//     // for |self|, which may not be the same as [AllaysIBF class]. This
+//     // would cause AllaysIBF's -.cxx_destruct or -dealloc to release
+//     // instance variables that only exist in subclasses, likely causing
+//     // mass disaster.
+//     propertyReleaser_AllaysIBF_.Init(self, [AllaysIBF class]);
+//   }
+//   return self;
+// }
+//
+// @end  // @implementation AllaysIBF
+//
+// When an instance of AllaysIBF is deallocated, the ObjCPropertyReleaser will
+// send a -release message to string_, dictionary_, and the compiler-created
+// autoProp instance variables. No -release will be sent to delegate_ as it
+// is marked "assign" and not "retain" or "copy". No -release will be sent to
+// notAProperty_ because it doesn't correspond to any declared @property.
+//
+// Another way of doing this would be to provide a base class that others can
+// inherit from, and to have the base class' -dealloc walk the property lists
+// of all subclasses in an object to send the -release messages. Since this
+// involves a base reaching into its subclasses, it's deemed scary, so don't
+// do it. ObjCPropertyReleaser's design ensures that the property releaser
+// will only operate on instance variables in the immediate object in which
+// the property releaser is placed.
+
+class BASE_EXPORT ObjCPropertyReleaser {
+ public:
+  // ObjCPropertyReleaser can only be owned by an Objective-C object, so its
+  // memory is always guaranteed to be 0-initialized. Not defining the default
+  // constructor can prevent an otherwise no-op -.cxx_construct method from
+  // showing up in Objective-C classes that contain a ObjCPropertyReleaser.
+
+  // Upon destruction (expected to occur from an Objective-C object's
+  // -.cxx_destruct method), release all properties.
+  ~ObjCPropertyReleaser() {
+    ReleaseProperties();
+  }
+
+  // Initialize this object so that it's armed to release the properties of
+  // object |object|, which must be of type |classy|. The class argument must
+  // be supplied separately and cannot be gleaned from the object's own type
+  // because an object will allays identify itself as the most-specific type
+  // that describes it, but the ObjCPropertyReleaser needs to know which class
+  // type in the class hierarchy it's responsible for releasing properties
+  // for. For the same reason, Init must be called with a |classy| argument
+  // initialized using a +class (class) method such as [MyClass class], and
+  // never a -class (instance) method such as [self class].
+  //
+  // -.cxx_construct can only call the default constructor, but
+  // ObjCPropertyReleaser needs to know about the Objective-C object that owns
+  // it, so this can't be handled in a constructor, it needs to be a distinct
+  // Init method.
+  void Init(id object, Class classy);
+
+  // Release all of the properties in object_ defined in class_ as either
+  // "retain" or "copy" and with an identifiable backing instance variable.
+  // Properties must be synthesized to have identifiable instance variables.
+  void ReleaseProperties();
+
+ private:
+  id object_;
+  Class class_;
+};
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_OBJC_PROPERTY_RELEASER_H_
diff --git a/base/mac/objc_property_releaser.mm b/base/mac/objc_property_releaser.mm
new file mode 100644
index 0000000..f7ee88f
--- /dev/null
+++ b/base/mac/objc_property_releaser.mm
@@ -0,0 +1,131 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "base/mac/objc_property_releaser.h"
+
+#import <objc/runtime.h>
+#include <stdlib.h>
+
+#include <string>
+
+#include "base/logging.h"
+
+namespace base {
+namespace mac {
+
+namespace {
+
+// Returns the name of the instance variable backing the property, if known,
+// if the property is marked "retain" or "copy". If the instance variable name
+// is not known (perhaps because it was not automatically associated with the
+// property by @synthesize) or if the property is not "retain" or "copy",
+// returns an empty string.
+std::string ReleasableInstanceName(objc_property_t property) {
+  // TODO(mark): Starting in newer system releases, the Objective-C runtime
+  // provides a function to break the property attribute string into
+  // individual attributes (property_copyAttributeList), as well as a function
+  // to look up the value of a specific attribute
+  // (property_copyAttributeValue). When the SDK defining that interface is
+  // final, this function should be adapted to walk the attribute list as
+  // returned by property_copyAttributeList when that function is available in
+  // preference to scanning through the attribute list manually.
+
+  // The format of the string returned by property_getAttributes is documented
+  // at
+  // http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtPropertyIntrospection.html#//apple_ref/doc/uid/TP40008048-CH101-SW6
+  const char* property_attributes = property_getAttributes(property);
+
+  std::string instance_name;
+  bool releasable = false;
+  while (*property_attributes) {
+    char name = *property_attributes;
+
+    const char* value = ++property_attributes;
+    while (*property_attributes && *property_attributes != ',') {
+      ++property_attributes;
+    }
+
+    switch (name) {
+      // It might seem intelligent to check the type ('T') attribute to verify
+      // that it identifies an NSObject-derived type (the attribute value
+      // begins with '@'.) This is a bad idea beacuse it fails to identify
+      // CFTypeRef-based properties declared as __attribute__((NSObject)),
+      // which just show up as pointers to their underlying CFType structs.
+      //
+      // Quoting
+      // http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocProperties.html#//apple_ref/doc/uid/TP30001163-CH17-SW27
+      //
+      // > In Mac OS X v10.6 and later, you can use the __attribute__ keyword
+      // > to specify that a Core Foundation property should be treated like
+      // > an Objective-C object for memory management:
+      // >   @property(retain) __attribute__((NSObject)) CFDictionaryRef
+      // >       myDictionary;
+      case 'C':  // copy
+      case '&':  // retain
+        releasable = true;
+        break;
+      case 'V':  // instance variable name
+        // 'V' is specified as the last attribute to occur in the
+        // documentation, but empirically, it's not always the last. In
+        // GC-supported or GC-required code, the 'P' (GC-eligible) attribute
+        // occurs after 'V'.
+        instance_name.assign(value, property_attributes - value);
+        break;
+    }
+
+    if (*property_attributes) {
+      ++property_attributes;
+    }
+  }
+
+  if (releasable) {
+    return instance_name;
+  }
+
+  return std::string();
+}
+
+}  // namespace
+
+void ObjCPropertyReleaser::Init(id object, Class classy) {
+  DCHECK(!object_);
+  DCHECK(!class_);
+  CHECK([object isKindOfClass:classy]);
+
+  object_ = object;
+  class_ = classy;
+}
+
+void ObjCPropertyReleaser::ReleaseProperties() {
+  DCHECK(object_);
+  DCHECK(class_);
+
+  unsigned int property_count = 0;
+  objc_property_t* properties = class_copyPropertyList(class_, &property_count);
+
+  for (unsigned int property_index = 0;
+       property_index < property_count;
+       ++property_index) {
+    objc_property_t property = properties[property_index];
+    std::string instance_name = ReleasableInstanceName(property);
+    if (!instance_name.empty()) {
+      id instance_value = nil;
+      Ivar instance_variable =
+          object_getInstanceVariable(object_, instance_name.c_str(),
+                                     (void**)&instance_value);
+      DCHECK(instance_variable);
+      [instance_value release];
+    }
+  }
+
+  free(properties);
+
+  // Clear object_ and class_ in case this ObjCPropertyReleaser will live on.
+  // It's only expected to release the properties it supervises once per Init.
+  object_ = nil;
+  class_ = nil;
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/objc_property_releaser_unittest.mm b/base/mac/objc_property_releaser_unittest.mm
new file mode 100644
index 0000000..50f81a8
--- /dev/null
+++ b/base/mac/objc_property_releaser_unittest.mm
@@ -0,0 +1,350 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <Foundation/Foundation.h>
+
+#import "base/mac/objc_property_releaser.h"
+#import "base/mac/scoped_nsautorelease_pool.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// "When I'm alone, I count myself."
+//   --Count von Count, http://www.youtube.com/watch?v=FKzszqa9WA4
+
+namespace {
+
+// The number of CountVonCounts outstanding.
+int ah_ah_ah;
+
+// NumberHolder exists to exercise the property attribute string parser by
+// providing a named struct and an anonymous union.
+struct NumberHolder {
+  union {
+    long long sixty_four;
+    int thirty_two;
+    short sixteen;
+    char eight;
+  } what;
+  enum {
+    SIXTY_FOUR,
+    THIRTY_TWO,
+    SIXTEEN,
+    EIGHT
+  } how;
+};
+
+}  // namespace
+
+@interface CountVonCount : NSObject<NSCopying>
+
++ (CountVonCount*)countVonCount;
+
+@end  // @interface CountVonCount
+
+@implementation CountVonCount
+
++ (CountVonCount*)countVonCount {
+  return [[[CountVonCount alloc] init] autorelease];
+}
+
+- (id)init {
+  ++ah_ah_ah;
+  return [super init];
+}
+
+- (void)dealloc {
+  --ah_ah_ah;
+  [super dealloc];
+}
+
+- (id)copyWithZone:(NSZone*)zone {
+  return [[CountVonCount allocWithZone:zone] init];
+}
+
+@end  // @implementation CountVonCount
+
+@interface ObjCPropertyTestBase : NSObject {
+ @private
+  CountVonCount* baseCvcRetain_;
+  CountVonCount* baseCvcCopy_;
+  CountVonCount* baseCvcAssign_;
+  CountVonCount* baseCvcNotProperty_;
+  CountVonCount* baseCvcNil_;
+  CountVonCount* baseCvcCustom_;
+  int baseInt_;
+  double baseDouble_;
+  void* basePointer_;
+  NumberHolder baseStruct_;
+
+  base::mac::ObjCPropertyReleaser propertyReleaser_ObjCPropertyTestBase_;
+}
+
+@property(retain, nonatomic) CountVonCount* baseCvcRetain;
+@property(copy, nonatomic) CountVonCount* baseCvcCopy;
+@property(assign, nonatomic) CountVonCount* baseCvcAssign;
+@property(retain, nonatomic) CountVonCount* baseCvcNil;
+@property(retain, nonatomic, getter=baseCustom, setter=setBaseCustom:)
+    CountVonCount* baseCvcCustom;
+@property(retain, nonatomic) CountVonCount* baseCvcDynamic;
+@property(assign, nonatomic) int baseInt;
+@property(assign, nonatomic) double baseDouble;
+@property(assign, nonatomic) void* basePointer;
+@property(assign, nonatomic) NumberHolder baseStruct;
+
+- (void)setBaseCvcNotProperty:(CountVonCount*)cvc;
+
+@end  // @interface ObjCPropertyTestBase
+
+@implementation ObjCPropertyTestBase
+
+@synthesize baseCvcRetain = baseCvcRetain_;
+@synthesize baseCvcCopy = baseCvcCopy_;
+@synthesize baseCvcAssign = baseCvcAssign_;
+@synthesize baseCvcNil = baseCvcNil_;
+@synthesize baseCvcCustom = baseCvcCustom_;
+@dynamic baseCvcDynamic;
+@synthesize baseInt = baseInt_;
+@synthesize baseDouble = baseDouble_;
+@synthesize basePointer = basePointer_;
+@synthesize baseStruct = baseStruct_;
+
+- (id)init {
+  if ((self = [super init])) {
+    propertyReleaser_ObjCPropertyTestBase_.Init(
+        self, [ObjCPropertyTestBase class]);
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [baseCvcNotProperty_ release];
+  [super dealloc];
+}
+
+- (void)setBaseCvcNotProperty:(CountVonCount*)cvc {
+  if (cvc != baseCvcNotProperty_) {
+    [baseCvcNotProperty_ release];
+    baseCvcNotProperty_ = [cvc retain];
+  }
+}
+
+@end  // @implementation ObjCPropertyTestBase
+
+@protocol ObjCPropertyTestProtocol
+
+@property(retain, nonatomic) CountVonCount* protoCvcRetain;
+@property(copy, nonatomic) CountVonCount* protoCvcCopy;
+@property(assign, nonatomic) CountVonCount* protoCvcAssign;
+@property(retain, nonatomic) CountVonCount* protoCvcNil;
+@property(retain, nonatomic, getter=protoCustom, setter=setProtoCustom:)
+    CountVonCount* protoCvcCustom;
+@property(retain, nonatomic) CountVonCount* protoCvcDynamic;
+@property(assign, nonatomic) int protoInt;
+@property(assign, nonatomic) double protoDouble;
+@property(assign, nonatomic) void* protoPointer;
+@property(assign, nonatomic) NumberHolder protoStruct;
+
+@end  // @protocol ObjCPropertyTestProtocol
+
+@interface ObjCPropertyTestDerived
+    : ObjCPropertyTestBase<ObjCPropertyTestProtocol> {
+ @private
+  CountVonCount* derivedCvcRetain_;
+  CountVonCount* derivedCvcCopy_;
+  CountVonCount* derivedCvcAssign_;
+  CountVonCount* derivedCvcNotProperty_;
+  CountVonCount* derivedCvcNil_;
+  CountVonCount* derivedCvcCustom_;
+  int derivedInt_;
+  double derivedDouble_;
+  void* derivedPointer_;
+  NumberHolder derivedStruct_;
+
+  CountVonCount* protoCvcRetain_;
+  CountVonCount* protoCvcCopy_;
+  CountVonCount* protoCvcAssign_;
+  CountVonCount* protoCvcNil_;
+  CountVonCount* protoCvcCustom_;
+  int protoInt_;
+  double protoDouble_;
+  void* protoPointer_;
+  NumberHolder protoStruct_;
+
+  base::mac::ObjCPropertyReleaser propertyReleaser_ObjCPropertyTestDerived_;
+}
+
+@property(retain, nonatomic) CountVonCount* derivedCvcRetain;
+@property(copy, nonatomic) CountVonCount* derivedCvcCopy;
+@property(assign, nonatomic) CountVonCount* derivedCvcAssign;
+@property(retain, nonatomic) CountVonCount* derivedCvcNil;
+@property(retain, nonatomic, getter=derivedCustom, setter=setDerivedCustom:)
+    CountVonCount* derivedCvcCustom;
+@property(retain, nonatomic) CountVonCount* derivedCvcDynamic;
+@property(assign, nonatomic) int derivedInt;
+@property(assign, nonatomic) double derivedDouble;
+@property(assign, nonatomic) void* derivedPointer;
+@property(assign, nonatomic) NumberHolder derivedStruct;
+
+- (void)setDerivedCvcNotProperty:(CountVonCount*)cvc;
+
+@end  // @interface ObjCPropertyTestDerived
+
+@implementation ObjCPropertyTestDerived
+
+@synthesize derivedCvcRetain = derivedCvcRetain_;
+@synthesize derivedCvcCopy = derivedCvcCopy_;
+@synthesize derivedCvcAssign = derivedCvcAssign_;
+@synthesize derivedCvcNil = derivedCvcNil_;
+@synthesize derivedCvcCustom = derivedCvcCustom_;
+@dynamic derivedCvcDynamic;
+@synthesize derivedInt = derivedInt_;
+@synthesize derivedDouble = derivedDouble_;
+@synthesize derivedPointer = derivedPointer_;
+@synthesize derivedStruct = derivedStruct_;
+
+@synthesize protoCvcRetain = protoCvcRetain_;
+@synthesize protoCvcCopy = protoCvcCopy_;
+@synthesize protoCvcAssign = protoCvcAssign_;
+@synthesize protoCvcNil = protoCvcNil_;
+@synthesize protoCvcCustom = protoCvcCustom_;
+@dynamic protoCvcDynamic;
+@synthesize protoInt = protoInt_;
+@synthesize protoDouble = protoDouble_;
+@synthesize protoPointer = protoPointer_;
+@synthesize protoStruct = protoStruct_;
+
+- (id)init {
+  if ((self = [super init])) {
+    propertyReleaser_ObjCPropertyTestDerived_.Init(
+        self, [ObjCPropertyTestDerived class]);
+  }
+  return self;
+}
+
+- (void)dealloc {
+  [derivedCvcNotProperty_ release];
+  [super dealloc];
+}
+
+- (void)setDerivedCvcNotProperty:(CountVonCount*)cvc {
+  if (cvc != derivedCvcNotProperty_) {
+    [derivedCvcNotProperty_ release];
+    derivedCvcNotProperty_ = [cvc retain];
+  }
+}
+
+@end  // @implementation ObjCPropertyTestDerived
+
+namespace {
+
+TEST(ObjCPropertyReleaserTest, SesameStreet) {
+  ObjCPropertyTestDerived* test_object = [[ObjCPropertyTestDerived alloc] init];
+
+  // Assure a clean slate.
+  EXPECT_EQ(0, ah_ah_ah);
+  EXPECT_EQ(1U, [test_object retainCount]);
+
+  CountVonCount* baseAssign = [[CountVonCount alloc] init];
+  CountVonCount* derivedAssign = [[CountVonCount alloc] init];
+  CountVonCount* protoAssign = [[CountVonCount alloc] init];
+
+  // Make sure that worked before things get more involved.
+  EXPECT_EQ(3, ah_ah_ah);
+
+  {
+    base::mac::ScopedNSAutoreleasePool pool;
+
+    test_object.baseCvcRetain = [CountVonCount countVonCount];
+    test_object.baseCvcCopy = [CountVonCount countVonCount];
+    test_object.baseCvcAssign = baseAssign;
+    test_object.baseCvcCustom = [CountVonCount countVonCount];
+    [test_object setBaseCvcNotProperty:[CountVonCount countVonCount]];
+
+    // That added 4 objects, plus 1 more that was copied.
+    EXPECT_EQ(8, ah_ah_ah);
+
+    test_object.derivedCvcRetain = [CountVonCount countVonCount];
+    test_object.derivedCvcCopy = [CountVonCount countVonCount];
+    test_object.derivedCvcAssign = derivedAssign;
+    test_object.derivedCvcCustom = [CountVonCount countVonCount];
+    [test_object setDerivedCvcNotProperty:[CountVonCount countVonCount]];
+
+    // That added 4 objects, plus 1 more that was copied.
+    EXPECT_EQ(13, ah_ah_ah);
+
+    test_object.protoCvcRetain = [CountVonCount countVonCount];
+    test_object.protoCvcCopy = [CountVonCount countVonCount];
+    test_object.protoCvcAssign = protoAssign;
+    test_object.protoCvcCustom = [CountVonCount countVonCount];
+
+    // That added 3 objects, plus 1 more that was copied.
+    EXPECT_EQ(17, ah_ah_ah);
+  }
+
+  // Now that the autorelease pool has been popped, the 3 objects that were
+  // copied when placed into the test object will have been deallocated.
+  EXPECT_EQ(14, ah_ah_ah);
+
+  // Make sure that the setters work and have the expected semantics.
+  test_object.baseCvcRetain = nil;
+  test_object.baseCvcCopy = nil;
+  test_object.baseCvcAssign = nil;
+  test_object.baseCvcCustom = nil;
+  test_object.derivedCvcRetain = nil;
+  test_object.derivedCvcCopy = nil;
+  test_object.derivedCvcAssign = nil;
+  test_object.derivedCvcCustom = nil;
+  test_object.protoCvcRetain = nil;
+  test_object.protoCvcCopy = nil;
+  test_object.protoCvcAssign = nil;
+  test_object.protoCvcCustom = nil;
+
+  // The CountVonCounts marked "retain" and "copy" should have been
+  // deallocated. Those marked assign should not have been. The only ones that
+  // should exist now are the ones marked "assign" and the ones held in
+  // non-property instance variables.
+  EXPECT_EQ(5, ah_ah_ah);
+
+  {
+    base::mac::ScopedNSAutoreleasePool pool;
+
+    // Put things back to how they were.
+    test_object.baseCvcRetain = [CountVonCount countVonCount];
+    test_object.baseCvcCopy = [CountVonCount countVonCount];
+    test_object.baseCvcAssign = baseAssign;
+    test_object.baseCvcCustom = [CountVonCount countVonCount];
+    test_object.derivedCvcRetain = [CountVonCount countVonCount];
+    test_object.derivedCvcCopy = [CountVonCount countVonCount];
+    test_object.derivedCvcAssign = derivedAssign;
+    test_object.derivedCvcCustom = [CountVonCount countVonCount];
+    test_object.protoCvcRetain = [CountVonCount countVonCount];
+    test_object.protoCvcCopy = [CountVonCount countVonCount];
+    test_object.protoCvcAssign = protoAssign;
+    test_object.protoCvcCustom = [CountVonCount countVonCount];
+
+    // 9 more CountVonCounts, 3 of which were copied.
+    EXPECT_EQ(17, ah_ah_ah);
+  }
+
+  // Now that the autorelease pool has been popped, the 3 copies are gone.
+  EXPECT_EQ(14, ah_ah_ah);
+
+  // Releasing the test object should get rid of everything that it owns.
+  [test_object release];
+
+  // The property releaser should have released all of the CountVonCounts
+  // associated with properties marked "retain" or "copy". The -dealloc
+  // methods in each should have released the single non-property objects in
+  // each. Only the CountVonCounts assigned to the properties marked "assign"
+  // should remain.
+  EXPECT_EQ(3, ah_ah_ah);
+
+  [baseAssign release];
+  [derivedAssign release];
+  [protoAssign release];
+
+  // Zero! Zero counts! Ah, ah, ah.
+  EXPECT_EQ(0, ah_ah_ah);
+}
+
+}  // namespace
diff --git a/base/mac/os_crash_dumps.cc b/base/mac/os_crash_dumps.cc
new file mode 100644
index 0000000..5d65b46
--- /dev/null
+++ b/base/mac/os_crash_dumps.cc
@@ -0,0 +1,60 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/os_crash_dumps.h"
+
+#include <signal.h>
+#include <unistd.h>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+namespace base {
+namespace mac {
+
+namespace {
+
+void ExitSignalHandler(int sig) {
+  // A call to exit() can call atexit() handlers.  If we SIGSEGV due
+  // to a corrupt heap, and if we have an atexit handler that
+  // allocates or frees memory, we are in trouble if we do not _exit.
+  _exit(128 + sig);
+}
+
+}  // namespace
+
+void DisableOSCrashDumps() {
+  // These are the POSIX signals corresponding to the Mach exceptions that
+  // Apple Crash Reporter handles.  See ux_exception() in xnu's
+  // bsd/uxkern/ux_exception.c and machine_exception() in xnu's
+  // bsd/dev/*/unix_signal.c.
+  const int signals_to_intercept[] = {
+    // Hardware faults
+    SIGILL,   // EXC_BAD_INSTRUCTION
+    SIGTRAP,  // EXC_BREAKPOINT
+    SIGFPE,   // EXC_ARITHMETIC
+    SIGBUS,   // EXC_BAD_ACCESS
+    SIGSEGV,  // EXC_BAD_ACCESS
+    // Not a hardware fault
+    SIGABRT
+  };
+
+  // For all these signals, just wire things up so we exit immediately.
+  for (size_t i = 0; i < arraysize(signals_to_intercept); ++i) {
+    struct sigaction act = {};
+    act.sa_handler = ExitSignalHandler;
+
+    // It is better to allow the signal handler to run on the stack
+    // registered with sigaltstack(), if one is present.
+    act.sa_flags = SA_ONSTACK;
+
+    if (sigemptyset(&act.sa_mask) != 0)
+      DPLOG(FATAL) << "sigemptyset() failed";
+    if (sigaction(signals_to_intercept[i], &act, NULL) != 0)
+      DPLOG(FATAL) << "sigaction() failed";
+  }
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/os_crash_dumps.h b/base/mac/os_crash_dumps.h
new file mode 100644
index 0000000..31d90fb
--- /dev/null
+++ b/base/mac/os_crash_dumps.h
@@ -0,0 +1,22 @@
+// Copyright (c) 2011 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_MAC_OS_CRASH_DUMPS_H_
+#define BASE_MAC_OS_CRASH_DUMPS_H_
+
+#include "base/base_export.h"
+
+namespace base {
+namespace mac {
+
+// On Mac OS X, it can take a really long time for the OS crash handler to
+// process a Chrome crash when debugging symbols are available.  This
+// translates into a long wait until the process actually dies.  This call
+// disables Apple Crash Reporter entirely.
+BASE_EXPORT void DisableOSCrashDumps();
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_OS_CRASH_DUMPS_H_
diff --git a/base/mac/scoped_aedesc.h b/base/mac/scoped_aedesc.h
new file mode 100644
index 0000000..a1323c0
--- /dev/null
+++ b/base/mac/scoped_aedesc.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2010 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_MAC_SCOPED_AEDESC_H_
+#define BASE_MAC_SCOPED_AEDESC_H_
+
+#import <CoreServices/CoreServices.h>
+
+#include "base/basictypes.h"
+
+namespace base {
+namespace mac {
+
+// The ScopedAEDesc is used to scope AppleEvent descriptors.  On creation,
+// it will store a NULL descriptor.  On destruction, it will dispose of the
+// descriptor.
+//
+// This class is parameterized for additional type safety checks.  You can use
+// the generic AEDesc type by not providing a template parameter:
+//  ScopedAEDesc<> desc;
+template <typename AEDescType = AEDesc>
+class ScopedAEDesc {
+ public:
+  ScopedAEDesc() {
+    AECreateDesc(typeNull, NULL, 0, &desc_);
+  }
+
+  ~ScopedAEDesc() {
+    AEDisposeDesc(&desc_);
+  }
+
+  // Used for in parameters.
+  operator const AEDescType*() {
+    return &desc_;
+  }
+
+  // Used for out parameters.
+  AEDescType* OutPointer() {
+    return &desc_;
+  }
+
+ private:
+  AEDescType desc_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedAEDesc);
+};
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_AEDESC_H_
diff --git a/base/mac/scoped_authorizationref.h b/base/mac/scoped_authorizationref.h
new file mode 100644
index 0000000..1811488
--- /dev/null
+++ b/base/mac/scoped_authorizationref.h
@@ -0,0 +1,83 @@
+// Copyright (c) 2012 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_MAC_SCOPED_AUTHORIZATIONREF_H_
+#define BASE_MAC_SCOPED_AUTHORIZATIONREF_H_
+
+#include <Security/Authorization.h>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+
+// ScopedAuthorizationRef maintains ownership of an AuthorizationRef.  It is
+// patterned after the scoped_ptr interface.
+
+namespace base {
+namespace mac {
+
+class ScopedAuthorizationRef {
+ public:
+  explicit ScopedAuthorizationRef(AuthorizationRef authorization = NULL)
+      : authorization_(authorization) {
+  }
+
+  ~ScopedAuthorizationRef() {
+    if (authorization_) {
+      AuthorizationFree(authorization_, kAuthorizationFlagDestroyRights);
+    }
+  }
+
+  void reset(AuthorizationRef authorization = NULL) {
+    if (authorization_ != authorization) {
+      if (authorization_) {
+        AuthorizationFree(authorization_, kAuthorizationFlagDestroyRights);
+      }
+      authorization_ = authorization;
+    }
+  }
+
+  bool operator==(AuthorizationRef that) const {
+    return authorization_ == that;
+  }
+
+  bool operator!=(AuthorizationRef that) const {
+    return authorization_ != that;
+  }
+
+  operator AuthorizationRef() const {
+    return authorization_;
+  }
+
+  AuthorizationRef* get_pointer() { return &authorization_; }
+
+  AuthorizationRef get() const {
+    return authorization_;
+  }
+
+  void swap(ScopedAuthorizationRef& that) {
+    AuthorizationRef temp = that.authorization_;
+    that.authorization_ = authorization_;
+    authorization_ = temp;
+  }
+
+  // ScopedAuthorizationRef::release() is like scoped_ptr<>::release.  It is
+  // NOT a wrapper for AuthorizationFree().  To force a
+  // ScopedAuthorizationRef object to call AuthorizationFree(), use
+  // ScopedAuthorizationRef::reset().
+  AuthorizationRef release() WARN_UNUSED_RESULT {
+    AuthorizationRef temp = authorization_;
+    authorization_ = NULL;
+    return temp;
+  }
+
+ private:
+  AuthorizationRef authorization_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedAuthorizationRef);
+};
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_AUTHORIZATIONREF_H_
diff --git a/base/mac/scoped_block.h b/base/mac/scoped_block.h
new file mode 100644
index 0000000..509a1c2
--- /dev/null
+++ b/base/mac/scoped_block.h
@@ -0,0 +1,92 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_SCOPED_BLOCK_H_
+#define BASE_MAC_SCOPED_BLOCK_H_
+
+#include <Block.h>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_policy.h"
+
+namespace base {
+namespace mac {
+
+// ScopedBlock<> is patterned after ScopedCFTypeRef<>, but uses Block_copy() and
+// Block_release() instead of CFRetain() and CFRelease().
+
+template<typename B>
+class ScopedBlock {
+ public:
+  explicit ScopedBlock(
+      B block = NULL,
+      base::scoped_policy::OwnershipPolicy policy = base::scoped_policy::ASSUME)
+      : block_(block) {
+    if (block_ && policy == base::scoped_policy::RETAIN)
+      block_ = Block_copy(block);
+  }
+
+  ScopedBlock(const ScopedBlock<B>& that)
+      : block_(that.block_) {
+    if (block_)
+      block_ = Block_copy(block_);
+  }
+
+  ~ScopedBlock() {
+    if (block_)
+      Block_release(block_);
+  }
+
+  ScopedBlock& operator=(const ScopedBlock<B>& that) {
+    reset(that.get(), base::scoped_policy::RETAIN);
+    return *this;
+  }
+
+  void reset(B block = NULL,
+             base::scoped_policy::OwnershipPolicy policy =
+                 base::scoped_policy::ASSUME) {
+    if (block && policy == base::scoped_policy::RETAIN)
+      block = Block_copy(block);
+    if (block_)
+      Block_release(block_);
+    block_ = block;
+  }
+
+  bool operator==(B that) const {
+    return block_ == that;
+  }
+
+  bool operator!=(B that) const {
+    return block_ != that;
+  }
+
+  operator B() const {
+    return block_;
+  }
+
+  B get() const {
+    return block_;
+  }
+
+  void swap(ScopedBlock& that) {
+    B temp = that.block_;
+    that.block_ = block_;
+    block_ = temp;
+  }
+
+  B release() WARN_UNUSED_RESULT {
+    B temp = block_;
+    block_ = NULL;
+    return temp;
+  }
+
+ private:
+  B block_;
+};
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_BLOCK_H_
diff --git a/base/mac/scoped_cffiledescriptorref.h b/base/mac/scoped_cffiledescriptorref.h
new file mode 100644
index 0000000..07196aa
--- /dev/null
+++ b/base/mac/scoped_cffiledescriptorref.h
@@ -0,0 +1,75 @@
+// Copyright 2012 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_MAC_SCOPED_CFFILEDESCRIPTORREF_H_
+#define BASE_MAC_SCOPED_CFFILEDESCRIPTORREF_H_
+
+#include <CoreFoundation/CoreFoundation.h>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+
+namespace base {
+namespace mac {
+
+// ScopedCFFileDescriptorRef is designed after ScopedCFTypeRef<>. On
+// destruction, it will invalidate the file descriptor.
+// ScopedCFFileDescriptorRef (unlike ScopedCFTypeRef<>) does not support RETAIN
+// semantics, copying, or assignment, as doing so would increase the chances
+// that a file descriptor is invalidated while still in use.
+class ScopedCFFileDescriptorRef {
+ public:
+  explicit ScopedCFFileDescriptorRef(CFFileDescriptorRef fdref = NULL)
+      : fdref_(fdref) {
+  }
+
+  ~ScopedCFFileDescriptorRef() {
+    if (fdref_) {
+      CFFileDescriptorInvalidate(fdref_);
+      CFRelease(fdref_);
+    }
+  }
+
+  void reset(CFFileDescriptorRef fdref = NULL) {
+    if (fdref_ == fdref)
+      return;
+    if (fdref_) {
+      CFFileDescriptorInvalidate(fdref_);
+      CFRelease(fdref_);
+    }
+    fdref_ = fdref;
+  }
+
+  bool operator==(CFFileDescriptorRef that) const {
+    return fdref_ == that;
+  }
+
+  bool operator!=(CFFileDescriptorRef that) const {
+    return fdref_ != that;
+  }
+
+  operator CFFileDescriptorRef() const {
+    return fdref_;
+  }
+
+  CFFileDescriptorRef get() const {
+    return fdref_;
+  }
+
+  CFFileDescriptorRef release() WARN_UNUSED_RESULT {
+    CFFileDescriptorRef temp = fdref_;
+    fdref_ = NULL;
+    return temp;
+  }
+
+ private:
+  CFFileDescriptorRef fdref_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedCFFileDescriptorRef);
+};
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_CFFILEDESCRIPTORREF_H_
diff --git a/base/mac/scoped_cftyperef.h b/base/mac/scoped_cftyperef.h
new file mode 100644
index 0000000..8567f85
--- /dev/null
+++ b/base/mac/scoped_cftyperef.h
@@ -0,0 +1,59 @@
+// Copyright (c) 2012 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_MAC_SCOPED_CFTYPEREF_H_
+#define BASE_MAC_SCOPED_CFTYPEREF_H_
+
+#include <CoreFoundation/CoreFoundation.h>
+
+#include "base/mac/scoped_typeref.h"
+
+namespace base {
+
+// ScopedCFTypeRef<> is patterned after scoped_ptr<>, but maintains ownership
+// of a CoreFoundation object: any object that can be represented as a
+// CFTypeRef.  Style deviations here are solely for compatibility with
+// scoped_ptr<>'s interface, with which everyone is already familiar.
+//
+// By default, ScopedCFTypeRef<> takes ownership of an object (in the
+// constructor or in reset()) by taking over the caller's existing ownership
+// claim.  The caller must own the object it gives to ScopedCFTypeRef<>, and
+// relinquishes an ownership claim to that object.  ScopedCFTypeRef<> does not
+// call CFRetain(). This behavior is parameterized by the |OwnershipPolicy|
+// enum. If the value |RETAIN| is passed (in the constructor or in reset()),
+// then ScopedCFTypeRef<> will call CFRetain() on the object, and the initial
+// ownership is not changed.
+
+namespace internal {
+
+struct ScopedCFTypeRefTraits {
+  static void Retain(CFTypeRef object) {
+    CFRetain(object);
+  }
+  static void Release(CFTypeRef object) {
+    CFRelease(object);
+  }
+};
+
+}  // namespace internal
+
+template<typename CFT>
+class ScopedCFTypeRef
+    : public ScopedTypeRef<CFT, internal::ScopedCFTypeRefTraits> {
+ public:
+  typedef CFT element_type;
+
+  explicit ScopedCFTypeRef(
+      CFT object = NULL,
+      base::scoped_policy::OwnershipPolicy policy = base::scoped_policy::ASSUME)
+      : ScopedTypeRef<CFT,
+                      internal::ScopedCFTypeRefTraits>(object, policy) {}
+
+  ScopedCFTypeRef(const ScopedCFTypeRef<CFT>& that)
+      : ScopedTypeRef<CFT, internal::ScopedCFTypeRefTraits>(that) {}
+};
+
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_CFTYPEREF_H_
diff --git a/base/mac/scoped_ioobject.h b/base/mac/scoped_ioobject.h
new file mode 100644
index 0000000..854039b
--- /dev/null
+++ b/base/mac/scoped_ioobject.h
@@ -0,0 +1,74 @@
+// Copyright (c) 2012 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_MAC_SCOPED_IOOBJECT_H_
+#define BASE_MAC_SCOPED_IOOBJECT_H_
+
+#include <IOKit/IOKitLib.h>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+
+namespace base {
+namespace mac {
+
+// Just like ScopedCFTypeRef but for io_object_t and subclasses.
+template<typename IOT>
+class ScopedIOObject {
+ public:
+  typedef IOT element_type;
+
+  explicit ScopedIOObject(IOT object = IO_OBJECT_NULL)
+      : object_(object) {
+  }
+
+  ~ScopedIOObject() {
+    if (object_)
+      IOObjectRelease(object_);
+  }
+
+  void reset(IOT object = IO_OBJECT_NULL) {
+    if (object_)
+      IOObjectRelease(object_);
+    object_ = object;
+  }
+
+  bool operator==(IOT that) const {
+    return object_ == that;
+  }
+
+  bool operator!=(IOT that) const {
+    return object_ != that;
+  }
+
+  operator IOT() const {
+    return object_;
+  }
+
+  IOT get() const {
+    return object_;
+  }
+
+  void swap(ScopedIOObject& that) {
+    IOT temp = that.object_;
+    that.object_ = object_;
+    object_ = temp;
+  }
+
+  IOT release() WARN_UNUSED_RESULT {
+    IOT temp = object_;
+    object_ = IO_OBJECT_NULL;
+    return temp;
+  }
+
+ private:
+  IOT object_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedIOObject);
+};
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_IOOBJECT_H_
diff --git a/base/mac/scoped_ioplugininterface.h b/base/mac/scoped_ioplugininterface.h
new file mode 100644
index 0000000..503980c
--- /dev/null
+++ b/base/mac/scoped_ioplugininterface.h
@@ -0,0 +1,76 @@
+// Copyright (c) 2012 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_MAC_SCOPED_IOPLUGININTERFACE_H_
+#define BASE_MAC_SCOPED_IOPLUGININTERFACE_H_
+
+#include <IOKit/IOKitLib.h>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+
+namespace base {
+namespace mac {
+
+// Just like ScopedCFTypeRef but for IOCFPlugInInterface and friends
+// (IOUSBInterfaceStruct and IOUSBDeviceStruct320 in particular).
+template<typename T>
+class ScopedIOPluginInterface {
+ public:
+  typedef T** InterfaceT;
+  typedef InterfaceT element_type;
+
+  explicit ScopedIOPluginInterface(InterfaceT object = NULL)
+      : object_(object) {
+  }
+
+  ~ScopedIOPluginInterface() {
+    if (object_)
+      (*object_)->Release(object_);
+  }
+
+  void reset(InterfaceT object = NULL) {
+    if (object_)
+      (*object_)->Release(object_);
+    object_ = object;
+  }
+
+  bool operator==(InterfaceT that) const {
+    return object_ == that;
+  }
+
+  bool operator!=(InterfaceT that) const {
+    return object_ != that;
+  }
+
+  operator InterfaceT() const {
+    return object_;
+  }
+
+  InterfaceT get() const {
+    return object_;
+  }
+
+  void swap(ScopedIOPluginInterface& that) {
+    InterfaceT temp = that.object_;
+    that.object_ = object_;
+    object_ = temp;
+  }
+
+  InterfaceT release() WARN_UNUSED_RESULT {
+    InterfaceT temp = object_;
+    object_ = NULL;
+    return temp;
+  }
+
+ private:
+  InterfaceT object_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedIOPluginInterface);
+};
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_IOPLUGININTERFACE_H_
diff --git a/base/mac/scoped_launch_data.h b/base/mac/scoped_launch_data.h
new file mode 100644
index 0000000..e4343b8
--- /dev/null
+++ b/base/mac/scoped_launch_data.h
@@ -0,0 +1,75 @@
+// Copyright (c) 2012 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_MAC_SCOPED_LAUNCH_DATA_H_
+#define BASE_MAC_SCOPED_LAUNCH_DATA_H_
+
+#include <launch.h>
+
+#include <algorithm>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+
+namespace base {
+namespace mac {
+
+// Just like scoped_ptr<> but for launch_data_t.
+class ScopedLaunchData {
+ public:
+  typedef launch_data_t element_type;
+
+  explicit ScopedLaunchData(launch_data_t object = NULL)
+      : object_(object) {
+  }
+
+  ~ScopedLaunchData() {
+    if (object_)
+      launch_data_free(object_);
+  }
+
+  void reset(launch_data_t object = NULL) {
+    if (object != object_) {
+      if (object_)
+        launch_data_free(object_);
+      object_ = object;
+    }
+  }
+
+  bool operator==(launch_data_t that) const {
+    return object_ == that;
+  }
+
+  bool operator!=(launch_data_t that) const {
+    return object_ != that;
+  }
+
+  operator launch_data_t() const {
+    return object_;
+  }
+
+  launch_data_t get() const {
+    return object_;
+  }
+
+  void swap(ScopedLaunchData& that) {
+    std::swap(object_, that.object_);
+  }
+
+  launch_data_t release() WARN_UNUSED_RESULT {
+    launch_data_t temp = object_;
+    object_ = NULL;
+    return temp;
+  }
+
+ private:
+  launch_data_t object_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedLaunchData);
+};
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_LAUNCH_DATA_H_
diff --git a/base/mac/scoped_mach_port.cc b/base/mac/scoped_mach_port.cc
new file mode 100644
index 0000000..13307f2
--- /dev/null
+++ b/base/mac/scoped_mach_port.cc
@@ -0,0 +1,38 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/scoped_mach_port.h"
+
+#include "base/mac/mach_logging.h"
+
+namespace base {
+namespace mac {
+namespace internal {
+
+// static
+void SendRightTraits::Free(mach_port_t port) {
+  kern_return_t kr = mach_port_deallocate(mach_task_self(), port);
+  MACH_LOG_IF(ERROR, kr != KERN_SUCCESS, kr)
+      << "ScopedMachSendRight mach_port_deallocate";
+}
+
+// static
+void ReceiveRightTraits::Free(mach_port_t port) {
+  kern_return_t kr =
+      mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_RECEIVE, -1);
+  MACH_LOG_IF(ERROR, kr != KERN_SUCCESS, kr)
+      << "ScopedMachReceiveRight mach_port_mod_refs";
+}
+
+// static
+void PortSetTraits::Free(mach_port_t port) {
+  kern_return_t kr =
+      mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_PORT_SET, -1);
+  MACH_LOG_IF(ERROR, kr != KERN_SUCCESS, kr)
+      << "ScopedMachPortSet mach_port_mod_refs";
+}
+
+}  // namespace internal
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/scoped_mach_port.h b/base/mac/scoped_mach_port.h
new file mode 100644
index 0000000..beb62b0
--- /dev/null
+++ b/base/mac/scoped_mach_port.h
@@ -0,0 +1,86 @@
+// Copyright (c) 2012 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_MAC_SCOPED_MACH_PORT_H_
+#define BASE_MAC_SCOPED_MACH_PORT_H_
+
+#include <mach/mach.h>
+
+#include "base/base_export.h"
+#include "base/scoped_generic.h"
+
+namespace base {
+namespace mac {
+
+namespace internal {
+
+struct BASE_EXPORT SendRightTraits {
+  static mach_port_t InvalidValue() {
+    return MACH_PORT_NULL;
+  }
+
+  BASE_EXPORT static void Free(mach_port_t port);
+};
+
+struct BASE_EXPORT ReceiveRightTraits {
+  static mach_port_t InvalidValue() {
+    return MACH_PORT_NULL;
+  }
+
+  BASE_EXPORT static void Free(mach_port_t port);
+};
+
+struct PortSetTraits {
+  static mach_port_t InvalidValue() {
+    return MACH_PORT_NULL;
+  }
+
+  BASE_EXPORT static void Free(mach_port_t port);
+};
+
+}  // namespace internal
+
+// A scoper for handling a Mach port that names a send right. Send rights are
+// reference counted, and this takes ownership of the right on construction
+// and then removes a reference to the right on destruction. If the reference
+// is the last one on the right, the right is deallocated.
+class BASE_EXPORT ScopedMachSendRight :
+    public base::ScopedGeneric<mach_port_t, internal::SendRightTraits> {
+ public:
+  explicit ScopedMachSendRight(mach_port_t port = traits_type::InvalidValue())
+      : ScopedGeneric(port) {}
+
+  operator mach_port_t() const { return get(); }
+};
+
+// A scoper for handling a Mach port's receive right. There is only one
+// receive right per port. This takes ownership of the receive right on
+// construction and then destroys the right on destruction, turning all
+// outstanding send rights into dead names.
+class BASE_EXPORT ScopedMachReceiveRight :
+    public base::ScopedGeneric<mach_port_t, internal::ReceiveRightTraits> {
+ public:
+  explicit ScopedMachReceiveRight(
+      mach_port_t port = traits_type::InvalidValue()) : ScopedGeneric(port) {}
+
+  operator mach_port_t() const { return get(); }
+};
+
+// A scoper for handling a Mach port set. A port set can have only one
+// reference. This takes ownership of that single reference on construction and
+// destroys the port set on destruction. Destroying a port set does not destroy
+// the receive rights that are members of the port set.
+class BASE_EXPORT ScopedMachPortSet :
+    public ScopedGeneric<mach_port_t, internal::PortSetTraits> {
+ public:
+  explicit ScopedMachPortSet(mach_port_t port = traits_type::InvalidValue())
+      : ScopedGeneric(port) {}
+
+  operator mach_port_t() const { return get(); }
+};
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_MACH_PORT_H_
diff --git a/base/mac/scoped_mach_vm.cc b/base/mac/scoped_mach_vm.cc
new file mode 100644
index 0000000..d52c77f
--- /dev/null
+++ b/base/mac/scoped_mach_vm.cc
@@ -0,0 +1,33 @@
+// 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.
+
+#include "base/mac/scoped_mach_vm.h"
+
+namespace base {
+namespace mac {
+
+void ScopedMachVM::reset(vm_address_t address, vm_size_t size) {
+  DCHECK_EQ(address % PAGE_SIZE, 0u);
+  DCHECK_EQ(size % PAGE_SIZE, 0u);
+
+  if (size_) {
+    if (address_ < address) {
+      vm_deallocate(mach_task_self(),
+                    address_,
+                    std::min(size_, address - address_));
+    }
+    if (address_ + size_ > address + size) {
+      vm_address_t deallocate_start = std::max(address_, address + size);
+      vm_deallocate(mach_task_self(),
+                    deallocate_start,
+                    address_ + size_ - deallocate_start);
+    }
+  }
+
+  address_ = address;
+  size_ = size;
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/scoped_mach_vm.h b/base/mac/scoped_mach_vm.h
new file mode 100644
index 0000000..ffc00d5
--- /dev/null
+++ b/base/mac/scoped_mach_vm.h
@@ -0,0 +1,92 @@
+// 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.
+
+#ifndef BASE_MAC_SCOPED_MACH_VM_H_
+#define BASE_MAC_SCOPED_MACH_VM_H_
+
+#include <mach/mach.h>
+
+#include <algorithm>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+// Use ScopedMachVM to supervise ownership of pages in the current process
+// through the Mach VM subsystem. Pages allocated with vm_allocate can be
+// released when exiting a scope with ScopedMachVM.
+//
+// The Mach VM subsystem operates on a page-by-page basis, and a single VM
+// allocation managed by a ScopedMachVM object may span multiple pages. As far
+// as Mach is concerned, allocated pages may be deallocated individually. This
+// is in contrast to higher-level allocators such as malloc, where the base
+// address of an allocation implies the size of an allocated block.
+// Consequently, it is not sufficient to just pass the base address of an
+// allocation to ScopedMachVM, it also needs to know the size of the
+// allocation. To avoid any confusion, both the base address and size must
+// be page-aligned.
+//
+// When dealing with Mach VM, base addresses will naturally be page-aligned,
+// but user-specified sizes may not be. If there's a concern that a size is
+// not page-aligned, use the mach_vm_round_page macro to correct it.
+//
+// Example:
+//
+//   vm_address_t address = 0;
+//   vm_size_t size = 12345;  // This requested size is not page-aligned.
+//   kern_return_t kr =
+//       vm_allocate(mach_task_self(), &address, size, VM_FLAGS_ANYWHERE);
+//   if (kr != KERN_SUCCESS) {
+//     return false;
+//   }
+//   ScopedMachVM vm_owner(address, mach_vm_round_page(size));
+
+namespace base {
+namespace mac {
+
+class BASE_EXPORT ScopedMachVM {
+ public:
+  explicit ScopedMachVM(vm_address_t address = 0, vm_size_t size = 0)
+      : address_(address), size_(size) {
+    DCHECK_EQ(address % PAGE_SIZE, 0u);
+    DCHECK_EQ(size % PAGE_SIZE, 0u);
+  }
+
+  ~ScopedMachVM() {
+    if (size_) {
+      vm_deallocate(mach_task_self(), address_, size_);
+    }
+  }
+
+  void reset(vm_address_t address = 0, vm_size_t size = 0);
+
+  vm_address_t address() const {
+    return address_;
+  }
+
+  vm_size_t size() const {
+    return size_;
+  }
+
+  void swap(ScopedMachVM& that) {
+    std::swap(address_, that.address_);
+    std::swap(size_, that.size_);
+  }
+
+  void release() {
+    address_ = 0;
+    size_ = 0;
+  }
+
+ private:
+  vm_address_t address_;
+  vm_size_t size_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedMachVM);
+};
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_MACH_VM_H_
diff --git a/base/mac/scoped_nsautorelease_pool.h b/base/mac/scoped_nsautorelease_pool.h
new file mode 100644
index 0000000..60af71a
--- /dev/null
+++ b/base/mac/scoped_nsautorelease_pool.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2011 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_MAC_SCOPED_NSAUTORELEASE_POOL_H_
+#define BASE_MAC_SCOPED_NSAUTORELEASE_POOL_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+#if defined(__OBJC__)
+@class NSAutoreleasePool;
+#else  // __OBJC__
+class NSAutoreleasePool;
+#endif  // __OBJC__
+
+namespace base {
+namespace mac {
+
+// ScopedNSAutoreleasePool allocates an NSAutoreleasePool when instantiated and
+// sends it a -drain message when destroyed.  This allows an autorelease pool to
+// be maintained in ordinary C++ code without bringing in any direct Objective-C
+// dependency.
+
+class BASE_EXPORT ScopedNSAutoreleasePool {
+ public:
+  ScopedNSAutoreleasePool();
+  ~ScopedNSAutoreleasePool();
+
+  // Clear out the pool in case its position on the stack causes it to be
+  // alive for long periods of time (such as the entire length of the app).
+  // Only use then when you're certain the items currently in the pool are
+  // no longer needed.
+  void Recycle();
+ private:
+  NSAutoreleasePool* autorelease_pool_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ScopedNSAutoreleasePool);
+};
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_NSAUTORELEASE_POOL_H_
diff --git a/base/mac/scoped_nsautorelease_pool.mm b/base/mac/scoped_nsautorelease_pool.mm
new file mode 100644
index 0000000..e542ca8
--- /dev/null
+++ b/base/mac/scoped_nsautorelease_pool.mm
@@ -0,0 +1,32 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac/scoped_nsautorelease_pool.h"
+
+#import <Foundation/Foundation.h>
+
+#include "base/logging.h"
+
+namespace base {
+namespace mac {
+
+ScopedNSAutoreleasePool::ScopedNSAutoreleasePool()
+    : autorelease_pool_([[NSAutoreleasePool alloc] init]) {
+  DCHECK(autorelease_pool_);
+}
+
+ScopedNSAutoreleasePool::~ScopedNSAutoreleasePool() {
+  [autorelease_pool_ drain];
+}
+
+// Cycle the internal pool, allowing everything there to get cleaned up and
+// start anew.
+void ScopedNSAutoreleasePool::Recycle() {
+  [autorelease_pool_ drain];
+  autorelease_pool_ = [[NSAutoreleasePool alloc] init];
+  DCHECK(autorelease_pool_);
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/scoped_nsexception_enabler.h b/base/mac/scoped_nsexception_enabler.h
new file mode 100644
index 0000000..484dd53
--- /dev/null
+++ b/base/mac/scoped_nsexception_enabler.h
@@ -0,0 +1,54 @@
+// Copyright (c) 2011 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_MAC_SCOPED_NSEXCEPTION_ENABLER_H_
+#define BASE_MAC_SCOPED_NSEXCEPTION_ENABLER_H_
+
+#import <Foundation/Foundation.h>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace mac {
+
+// BrowserCrApplication attempts to restrict throwing of NSExceptions
+// because they interact badly with C++ scoping rules.  Unfortunately,
+// there are some cases where exceptions must be supported, such as
+// when third-party printer drivers are used.  These helpers can be
+// used to enable exceptions for narrow windows.
+
+// Make it easy to safely allow NSException to be thrown in a limited
+// scope.  Note that if an exception is thrown, then this object will
+// not be appropriately destructed!  If the exception ends up in the
+// top-level event loop, things are cleared in -reportException:.  If
+// the exception is caught at a lower level, a higher level scoper
+// should eventually reset things.
+class BASE_EXPORT ScopedNSExceptionEnabler {
+ public:
+  ScopedNSExceptionEnabler();
+  ~ScopedNSExceptionEnabler();
+
+ private:
+  bool was_enabled_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedNSExceptionEnabler);
+};
+
+// Access the exception setting for the current thread.  This is for
+// the support code in BrowserCrApplication, other code should use
+// the scoper.
+BASE_EXPORT bool GetNSExceptionsAllowed();
+BASE_EXPORT void SetNSExceptionsAllowed(bool allowed);
+
+// Executes |block| with fatal-exceptions turned off, and returns the
+// result.  If an exception is thrown during the perform, nil is
+// returned.
+typedef id (^BlockReturningId)();
+BASE_EXPORT id RunBlockIgnoringExceptions(BlockReturningId block);
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_NSEXCEPTION_ENABLER_H_
diff --git a/base/mac/scoped_nsexception_enabler.mm b/base/mac/scoped_nsexception_enabler.mm
new file mode 100644
index 0000000..7b8ad92
--- /dev/null
+++ b/base/mac/scoped_nsexception_enabler.mm
@@ -0,0 +1,63 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "base/mac/scoped_nsexception_enabler.h"
+
+#import "base/lazy_instance.h"
+#import "base/threading/thread_local.h"
+
+// To make the |g_exceptionsAllowed| declaration readable.
+using base::LazyInstance;
+using base::ThreadLocalBoolean;
+
+// When C++ exceptions are disabled, the C++ library defines |try| and
+// |catch| so as to allow exception-expecting C++ code to build properly when
+// language support for exceptions is not present.  These macros interfere
+// with the use of |@try| and |@catch| in Objective-C files such as this one.
+// Undefine these macros here, after everything has been #included, since
+// there will be no C++ uses and only Objective-C uses from this point on.
+#undef try
+#undef catch
+
+namespace {
+
+// Whether to allow NSExceptions to be raised on the current thread.
+LazyInstance<ThreadLocalBoolean>::Leaky
+    g_exceptionsAllowed = LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+namespace base {
+namespace mac {
+
+bool GetNSExceptionsAllowed() {
+  return g_exceptionsAllowed.Get().Get();
+}
+
+void SetNSExceptionsAllowed(bool allowed) {
+  return g_exceptionsAllowed.Get().Set(allowed);
+}
+
+id RunBlockIgnoringExceptions(BlockReturningId block) {
+  id ret = nil;
+  @try {
+    base::mac::ScopedNSExceptionEnabler enable;
+    ret = block();
+  }
+  @catch(id exception) {
+  }
+  return ret;
+}
+
+ScopedNSExceptionEnabler::ScopedNSExceptionEnabler() {
+  was_enabled_ = GetNSExceptionsAllowed();
+  SetNSExceptionsAllowed(true);
+}
+
+ScopedNSExceptionEnabler::~ScopedNSExceptionEnabler() {
+  SetNSExceptionsAllowed(was_enabled_);
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/scoped_nsobject.h b/base/mac/scoped_nsobject.h
new file mode 100644
index 0000000..836bdcc
--- /dev/null
+++ b/base/mac/scoped_nsobject.h
@@ -0,0 +1,177 @@
+// Copyright (c) 2012 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_MAC_SCOPED_NSOBJECT_H_
+#define BASE_MAC_SCOPED_NSOBJECT_H_
+
+// Include NSObject.h directly because Foundation.h pulls in many dependencies.
+// (Approx 100k lines of code versus 1.5k for NSObject.h). scoped_nsobject gets
+// singled out because it is most typically included from other header files.
+#import <Foundation/NSObject.h>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+
+@class NSAutoreleasePool;
+
+namespace base {
+
+// scoped_nsobject<> is patterned after scoped_ptr<>, but maintains ownership
+// of an NSObject subclass object.  Style deviations here are solely for
+// compatibility with scoped_ptr<>'s interface, with which everyone is already
+// familiar.
+//
+// scoped_nsobject<> takes ownership of an object (in the constructor or in
+// reset()) by taking over the caller's existing ownership claim.  The caller
+// must own the object it gives to scoped_nsobject<>, and relinquishes an
+// ownership claim to that object.  scoped_nsobject<> does not call -retain,
+// callers have to call this manually if appropriate.
+//
+// scoped_nsprotocol<> has the same behavior as scoped_nsobject, but can be used
+// with protocols.
+//
+// scoped_nsobject<> is not to be used for NSAutoreleasePools. For
+// NSAutoreleasePools use ScopedNSAutoreleasePool from
+// scoped_nsautorelease_pool.h instead.
+// We check for bad uses of scoped_nsobject and NSAutoreleasePool at compile
+// time with a template specialization (see below).
+
+template<typename NST>
+class scoped_nsprotocol {
+ public:
+  explicit scoped_nsprotocol(NST object = nil) : object_(object) {}
+
+  scoped_nsprotocol(const scoped_nsprotocol<NST>& that)
+      : object_([that.object_ retain]) {
+  }
+
+  template <typename NSU>
+  scoped_nsprotocol(const scoped_nsprotocol<NSU>& that)
+      : object_([that.get() retain]) {
+  }
+
+  ~scoped_nsprotocol() {
+    [object_ release];
+  }
+
+  scoped_nsprotocol& operator=(const scoped_nsprotocol<NST>& that) {
+    reset([that.get() retain]);
+    return *this;
+  }
+
+  void reset(NST object = nil) {
+    // We intentionally do not check that object != object_ as the caller must
+    // either already have an ownership claim over whatever it passes to this
+    // method, or call it with the |RETAIN| policy which will have ensured that
+    // the object is retained once more when reaching this point.
+    [object_ release];
+    object_ = object;
+  }
+
+  bool operator==(NST that) const { return object_ == that; }
+  bool operator!=(NST that) const { return object_ != that; }
+
+  operator NST() const {
+    return object_;
+  }
+
+  NST get() const {
+    return object_;
+  }
+
+  void swap(scoped_nsprotocol& that) {
+    NST temp = that.object_;
+    that.object_ = object_;
+    object_ = temp;
+  }
+
+  // scoped_nsprotocol<>::release() is like scoped_ptr<>::release.  It is NOT a
+  // wrapper for [object_ release].  To force a scoped_nsprotocol<> to call
+  // [object_ release], use scoped_nsprotocol<>::reset().
+  NST release() WARN_UNUSED_RESULT {
+    NST temp = object_;
+    object_ = nil;
+    return temp;
+  }
+
+  // Shift reference to the autorelease pool to be released later.
+  NST autorelease() {
+    return [release() autorelease];
+  }
+
+ private:
+  NST object_;
+};
+
+// Free functions
+template <class C>
+void swap(scoped_nsprotocol<C>& p1, scoped_nsprotocol<C>& p2) {
+  p1.swap(p2);
+}
+
+template <class C>
+bool operator==(C p1, const scoped_nsprotocol<C>& p2) {
+  return p1 == p2.get();
+}
+
+template <class C>
+bool operator!=(C p1, const scoped_nsprotocol<C>& p2) {
+  return p1 != p2.get();
+}
+
+template<typename NST>
+class scoped_nsobject : public scoped_nsprotocol<NST*> {
+ public:
+  explicit scoped_nsobject(NST* object = nil)
+      : scoped_nsprotocol<NST*>(object) {}
+
+  scoped_nsobject(const scoped_nsobject<NST>& that)
+      : 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;
+  }
+};
+
+// Specialization to make scoped_nsobject<id> work.
+template<>
+class scoped_nsobject<id> : public scoped_nsprotocol<id> {
+ public:
+  explicit scoped_nsobject(id object = nil) : scoped_nsprotocol<id>(object) {}
+
+  scoped_nsobject(const scoped_nsobject<id>& that)
+      : 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;
+  }
+};
+
+// Do not use scoped_nsobject for NSAutoreleasePools, use
+// ScopedNSAutoreleasePool instead. This is a compile time check. See details
+// at top of header.
+template<>
+class scoped_nsobject<NSAutoreleasePool> {
+ private:
+  explicit scoped_nsobject(NSAutoreleasePool* object = nil);
+  DISALLOW_COPY_AND_ASSIGN(scoped_nsobject);
+};
+
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_NSOBJECT_H_
diff --git a/base/mac/scoped_nsobject_unittest.mm b/base/mac/scoped_nsobject_unittest.mm
new file mode 100644
index 0000000..f290c3a
--- /dev/null
+++ b/base/mac/scoped_nsobject_unittest.mm
@@ -0,0 +1,86 @@
+// Copyright (c) 2012 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 <vector>
+
+#include "base/basictypes.h"
+#include "base/mac/scoped_nsautorelease_pool.h"
+#include "base/mac/scoped_nsobject.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+TEST(ScopedNSObjectTest, ScopedNSObject) {
+  base::scoped_nsobject<NSObject> p1([[NSObject alloc] init]);
+  ASSERT_TRUE(p1.get());
+  ASSERT_EQ(1u, [p1 retainCount]);
+  base::scoped_nsobject<NSObject> p2(p1);
+  ASSERT_EQ(p1.get(), p2.get());
+  ASSERT_EQ(2u, [p1 retainCount]);
+  p2.reset();
+  ASSERT_EQ(nil, p2.get());
+  ASSERT_EQ(1u, [p1 retainCount]);
+  {
+    base::scoped_nsobject<NSObject> p3 = p1;
+    ASSERT_EQ(p1.get(), p3.get());
+    ASSERT_EQ(2u, [p1 retainCount]);
+    p3 = p1;
+    ASSERT_EQ(p1.get(), p3.get());
+    ASSERT_EQ(2u, [p1 retainCount]);
+  }
+  ASSERT_EQ(1u, [p1 retainCount]);
+  base::scoped_nsobject<NSObject> p4([p1.get() retain]);
+  ASSERT_EQ(2u, [p1 retainCount]);
+  ASSERT_TRUE(p1 == p1.get());
+  ASSERT_TRUE(p1 == p1);
+  ASSERT_FALSE(p1 != p1);
+  ASSERT_FALSE(p1 != p1.get());
+  base::scoped_nsobject<NSObject> p5([[NSObject alloc] init]);
+  ASSERT_TRUE(p1 != p5);
+  ASSERT_TRUE(p1 != p5.get());
+  ASSERT_FALSE(p1 == p5);
+  ASSERT_FALSE(p1 == p5.get());
+
+  base::scoped_nsobject<NSObject> p6 = p1;
+  ASSERT_EQ(3u, [p6 retainCount]);
+  {
+    base::mac::ScopedNSAutoreleasePool pool;
+    p6.autorelease();
+    ASSERT_EQ(nil, p6.get());
+    ASSERT_EQ(3u, [p1 retainCount]);
+  }
+  ASSERT_EQ(2u, [p1 retainCount]);
+}
+
+TEST(ScopedNSObjectTest, ScopedNSObjectInContainer) {
+  base::scoped_nsobject<id> p([[NSObject alloc] init]);
+  ASSERT_TRUE(p.get());
+  ASSERT_EQ(1u, [p retainCount]);
+  {
+    std::vector<base::scoped_nsobject<id>> objects;
+    objects.push_back(p);
+    ASSERT_EQ(2u, [p retainCount]);
+    ASSERT_EQ(p.get(), objects[0].get());
+    objects.push_back(base::scoped_nsobject<id>([[NSObject alloc] init]));
+    ASSERT_TRUE(objects[1].get());
+    ASSERT_EQ(1u, [objects[1] retainCount]);
+  }
+  ASSERT_EQ(1u, [p retainCount]);
+}
+
+TEST(ScopedNSObjectTest, ScopedNSObjectFreeFunctions) {
+  base::scoped_nsobject<id> p1([[NSObject alloc] init]);
+  id o1 = p1.get();
+  ASSERT_TRUE(o1 == p1);
+  ASSERT_FALSE(o1 != p1);
+  base::scoped_nsobject<id> p2([[NSObject alloc] init]);
+  ASSERT_TRUE(o1 != p2);
+  ASSERT_FALSE(o1 == p2);
+  id o2 = p2.get();
+  swap(p1, p2);
+  ASSERT_EQ(o2, p1.get());
+  ASSERT_EQ(o1, p2.get());
+}
+
+}  // namespace
diff --git a/base/mac/scoped_objc_class_swizzler.h b/base/mac/scoped_objc_class_swizzler.h
new file mode 100644
index 0000000..e18e4ab
--- /dev/null
+++ b/base/mac/scoped_objc_class_swizzler.h
@@ -0,0 +1,49 @@
+// 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.
+
+#ifndef BASE_MAC_SCOPED_OBJC_CLASS_SWIZZLER_H_
+#define BASE_MAC_SCOPED_OBJC_CLASS_SWIZZLER_H_
+
+#import <objc/runtime.h>
+
+#include "base/base_export.h"
+#include "base/macros.h"
+
+namespace base {
+namespace mac {
+
+// Within a given scope, swaps method implementations of a class interface, or
+// between two class interfaces. The argument and return types must match.
+class BASE_EXPORT ScopedObjCClassSwizzler {
+ public:
+  // Given two classes that each respond to |selector|, swap the implementations
+  // of those methods.
+  ScopedObjCClassSwizzler(Class target, Class source, SEL selector);
+
+  // Given two selectors on the same class interface, |target| (e.g. via
+  // inheritance or categories), swap the implementations of methods |original|
+  // and |alternate|.
+  ScopedObjCClassSwizzler(Class target, SEL original, SEL alternate);
+
+  ~ScopedObjCClassSwizzler();
+
+  // Return a callable function pointer for the replaced method. To call this
+  // from the replacing function, the first two arguments should be |self| and
+  // |_cmd|. These are followed by the (variadic) method arguments.
+  IMP GetOriginalImplementation();
+
+ private:
+  // Delegated constructor.
+  void Init(Class target, Class source, SEL original, SEL alternate);
+
+  Method old_selector_impl_;
+  Method new_selector_impl_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedObjCClassSwizzler);
+};
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_OBJC_CLASS_SWIZZLER_H_
diff --git a/base/mac/scoped_objc_class_swizzler.mm b/base/mac/scoped_objc_class_swizzler.mm
new file mode 100644
index 0000000..20e5c56
--- /dev/null
+++ b/base/mac/scoped_objc_class_swizzler.mm
@@ -0,0 +1,71 @@
+// 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.
+
+#import "base/mac/scoped_objc_class_swizzler.h"
+
+#include <string.h>
+
+#include "base/logging.h"
+
+namespace base {
+namespace mac {
+
+ScopedObjCClassSwizzler::ScopedObjCClassSwizzler(Class target,
+                                                 Class source,
+                                                 SEL selector)
+    : old_selector_impl_(NULL), new_selector_impl_(NULL) {
+  Init(target, source, selector, selector);
+}
+
+ScopedObjCClassSwizzler::ScopedObjCClassSwizzler(Class target,
+                                                 SEL original,
+                                                 SEL alternate)
+    : old_selector_impl_(NULL), new_selector_impl_(NULL) {
+  Init(target, target, original, alternate);
+}
+
+ScopedObjCClassSwizzler::~ScopedObjCClassSwizzler() {
+  if (old_selector_impl_ && new_selector_impl_)
+    method_exchangeImplementations(old_selector_impl_, new_selector_impl_);
+}
+
+IMP ScopedObjCClassSwizzler::GetOriginalImplementation() {
+  // Note that while the swizzle is in effect the "new" method is actually
+  // pointing to the original implementation, since they have been swapped.
+  return method_getImplementation(new_selector_impl_);
+}
+
+void ScopedObjCClassSwizzler::Init(Class target,
+                                   Class source,
+                                   SEL original,
+                                   SEL alternate) {
+  old_selector_impl_ = class_getInstanceMethod(target, original);
+  new_selector_impl_ = class_getInstanceMethod(source, alternate);
+  if (!old_selector_impl_ && !new_selector_impl_) {
+    // Try class methods.
+    old_selector_impl_ = class_getClassMethod(target, original);
+    new_selector_impl_ = class_getClassMethod(source, alternate);
+  }
+
+  DCHECK(old_selector_impl_);
+  DCHECK(new_selector_impl_);
+  if (!old_selector_impl_ || !new_selector_impl_)
+    return;
+
+  // The argument and return types must match exactly.
+  const char* old_types = method_getTypeEncoding(old_selector_impl_);
+  const char* new_types = method_getTypeEncoding(new_selector_impl_);
+  DCHECK(old_types);
+  DCHECK(new_types);
+  DCHECK_EQ(0, strcmp(old_types, new_types));
+  if (!old_types || !new_types || strcmp(old_types, new_types)) {
+    old_selector_impl_ = new_selector_impl_ = NULL;
+    return;
+  }
+
+  method_exchangeImplementations(old_selector_impl_, new_selector_impl_);
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/scoped_objc_class_swizzler_unittest.mm b/base/mac/scoped_objc_class_swizzler_unittest.mm
new file mode 100644
index 0000000..eacd105
--- /dev/null
+++ b/base/mac/scoped_objc_class_swizzler_unittest.mm
@@ -0,0 +1,166 @@
+// 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.
+
+#import "base/mac/scoped_objc_class_swizzler.h"
+
+#import "base/mac/scoped_nsobject.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+@interface ObjCClassSwizzlerTestOne : NSObject
++ (NSInteger)function;
+- (NSInteger)method;
+- (NSInteger)modifier;
+@end
+
+@interface ObjCClassSwizzlerTestTwo : NSObject
++ (NSInteger)function;
+- (NSInteger)method;
+- (NSInteger)modifier;
+@end
+
+@implementation ObjCClassSwizzlerTestOne : NSObject
+
++ (NSInteger)function {
+  return 10;
+}
+
+- (NSInteger)method {
+  // Multiply by a modifier to ensure |self| in a swizzled implementation
+  // refers to the original object.
+  return 1 * [self modifier];
+}
+
+- (NSInteger)modifier {
+  return 3;
+}
+
+@end
+
+@implementation ObjCClassSwizzlerTestTwo : NSObject
+
++ (NSInteger)function {
+  return 20;
+}
+
+- (NSInteger)method {
+  return 2 * [self modifier];
+}
+
+- (NSInteger)modifier {
+  return 7;
+}
+
+@end
+
+@interface ObjCClassSwizzlerTestOne (AlternateCategory)
+- (NSInteger)alternate;
+@end
+
+@implementation ObjCClassSwizzlerTestOne (AlternateCategory)
+- (NSInteger)alternate {
+  return 3 * [self modifier];
+}
+@end
+
+@interface ObjCClassSwizzlerTestOneChild : ObjCClassSwizzlerTestOne
+- (NSInteger)childAlternate;
+@end
+
+@implementation ObjCClassSwizzlerTestOneChild
+- (NSInteger)childAlternate {
+  return 5 * [self modifier];
+}
+@end
+
+namespace base {
+namespace mac {
+
+TEST(ObjCClassSwizzlerTest, SwizzleInstanceMethods) {
+  base::scoped_nsobject<ObjCClassSwizzlerTestOne> object_one(
+      [[ObjCClassSwizzlerTestOne alloc] init]);
+  base::scoped_nsobject<ObjCClassSwizzlerTestTwo> object_two(
+      [[ObjCClassSwizzlerTestTwo alloc] init]);
+  EXPECT_EQ(3, [object_one method]);
+  EXPECT_EQ(14, [object_two method]);
+
+  {
+    base::mac::ScopedObjCClassSwizzler swizzler(
+        [ObjCClassSwizzlerTestOne class],
+        [ObjCClassSwizzlerTestTwo class],
+        @selector(method));
+    EXPECT_EQ(6, [object_one method]);
+    EXPECT_EQ(7, [object_two method]);
+
+    IMP original = swizzler.GetOriginalImplementation();
+    id expected_result = reinterpret_cast<id>(3);
+    EXPECT_EQ(expected_result, original(object_one, @selector(method)));
+  }
+
+  EXPECT_EQ(3, [object_one method]);
+  EXPECT_EQ(14, [object_two method]);
+}
+
+TEST(ObjCClassSwizzlerTest, SwizzleClassMethods) {
+  EXPECT_EQ(10, [ObjCClassSwizzlerTestOne function]);
+  EXPECT_EQ(20, [ObjCClassSwizzlerTestTwo function]);
+
+  {
+    base::mac::ScopedObjCClassSwizzler swizzler(
+        [ObjCClassSwizzlerTestOne class],
+        [ObjCClassSwizzlerTestTwo class],
+        @selector(function));
+    EXPECT_EQ(20, [ObjCClassSwizzlerTestOne function]);
+    EXPECT_EQ(10, [ObjCClassSwizzlerTestTwo function]);
+
+    IMP original = swizzler.GetOriginalImplementation();
+    id expected_result = reinterpret_cast<id>(10);
+    EXPECT_EQ(expected_result, original(nil, @selector(function)));
+  }
+
+  EXPECT_EQ(10, [ObjCClassSwizzlerTestOne function]);
+  EXPECT_EQ(20, [ObjCClassSwizzlerTestTwo function]);
+}
+
+TEST(ObjCClassSwizzlerTest, SwizzleViaCategory) {
+  base::scoped_nsobject<ObjCClassSwizzlerTestOne> object_one(
+      [[ObjCClassSwizzlerTestOne alloc] init]);
+  EXPECT_EQ(3, [object_one method]);
+
+  {
+    base::mac::ScopedObjCClassSwizzler swizzler(
+        [ObjCClassSwizzlerTestOne class],
+        @selector(method),
+        @selector(alternate));
+    EXPECT_EQ(9, [object_one method]);
+
+    IMP original = swizzler.GetOriginalImplementation();
+    id expected_result = reinterpret_cast<id>(3);
+    EXPECT_EQ(expected_result, original(object_one, @selector(method)));
+  }
+
+  EXPECT_EQ(3, [object_one method]);
+}
+
+TEST(ObjCClassSwizzlerTest, SwizzleViaInheritance) {
+  base::scoped_nsobject<ObjCClassSwizzlerTestOneChild> child(
+      [[ObjCClassSwizzlerTestOneChild alloc] init]);
+  EXPECT_EQ(3, [child method]);
+
+  {
+    base::mac::ScopedObjCClassSwizzler swizzler(
+        [ObjCClassSwizzlerTestOneChild class],
+        @selector(method),
+        @selector(childAlternate));
+    EXPECT_EQ(15, [child method]);
+
+    IMP original = swizzler.GetOriginalImplementation();
+    id expected_result = reinterpret_cast<id>(3);
+    EXPECT_EQ(expected_result, original(child, @selector(method)));
+  }
+
+  EXPECT_EQ(3, [child method]);
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/scoped_sending_event.h b/base/mac/scoped_sending_event.h
new file mode 100644
index 0000000..92c2155
--- /dev/null
+++ b/base/mac/scoped_sending_event.h
@@ -0,0 +1,48 @@
+// Copyright (c) 2012 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_MAC_SCOPED_SENDING_EVENT_H_
+#define BASE_MAC_SCOPED_SENDING_EVENT_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/message_loop/message_pump_mac.h"
+
+// Nested event loops can pump IPC messages, including
+// script-initiated tab closes, which could release objects that the
+// nested event loop might message.  CrAppProtocol defines how to ask
+// the embedding NSApplication subclass if an event is currently being
+// handled, in which case such closes are deferred to the top-level
+// event loop.
+//
+// ScopedSendingEvent allows script-initiated event loops to work like
+// a nested event loop, as such events do not arrive via -sendEvent:.
+// CrAppControlProtocol lets ScopedSendingEvent tell the embedding
+// NSApplication what to return from -handlingSendEvent.
+
+@protocol CrAppControlProtocol<CrAppProtocol>
+- (void)setHandlingSendEvent:(BOOL)handlingSendEvent;
+@end
+
+namespace base {
+namespace mac {
+
+class BASE_EXPORT ScopedSendingEvent {
+ public:
+  ScopedSendingEvent();
+  ~ScopedSendingEvent();
+
+ private:
+  // The NSApp in control at the time the constructor was run, to be
+  // sure the |handling_| setting is restored appropriately.
+  NSObject<CrAppControlProtocol>* app_;
+  BOOL handling_;  // Value of -[app_ handlingSendEvent] at construction.
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedSendingEvent);
+};
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_SENDING_EVENT_H_
diff --git a/base/mac/scoped_sending_event.mm b/base/mac/scoped_sending_event.mm
new file mode 100644
index 0000000..c3813d8
--- /dev/null
+++ b/base/mac/scoped_sending_event.mm
@@ -0,0 +1,24 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "base/mac/scoped_sending_event.h"
+
+#include "base/logging.h"
+
+namespace base {
+namespace mac {
+
+ScopedSendingEvent::ScopedSendingEvent()
+    : app_(static_cast<NSObject<CrAppControlProtocol>*>(NSApp)) {
+  DCHECK([app_ conformsToProtocol:@protocol(CrAppControlProtocol)]);
+  handling_ = [app_ isHandlingSendEvent];
+  [app_ setHandlingSendEvent:YES];
+}
+
+ScopedSendingEvent::~ScopedSendingEvent() {
+  [app_ setHandlingSendEvent:handling_];
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/mac/scoped_sending_event_unittest.mm b/base/mac/scoped_sending_event_unittest.mm
new file mode 100644
index 0000000..02ef2db
--- /dev/null
+++ b/base/mac/scoped_sending_event_unittest.mm
@@ -0,0 +1,63 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "base/mac/scoped_sending_event.h"
+
+#import <Foundation/Foundation.h>
+
+#include "base/mac/scoped_nsobject.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+@interface ScopedSendingEventTestCrApp : NSObject <CrAppControlProtocol> {
+ @private
+  BOOL handlingSendEvent_;
+}
+@property(nonatomic, assign, getter=isHandlingSendEvent) BOOL handlingSendEvent;
+@end
+
+@implementation ScopedSendingEventTestCrApp
+@synthesize handlingSendEvent = handlingSendEvent_;
+@end
+
+namespace {
+
+class ScopedSendingEventTest : public testing::Test {
+ public:
+  ScopedSendingEventTest() : app_([[ScopedSendingEventTestCrApp alloc] init]) {
+    NSApp = app_.get();
+  }
+  ~ScopedSendingEventTest() override { NSApp = nil; }
+
+ private:
+  base::scoped_nsobject<ScopedSendingEventTestCrApp> app_;
+};
+
+// Sets the flag within scope, resets when leaving scope.
+TEST_F(ScopedSendingEventTest, SetHandlingSendEvent) {
+  id<CrAppProtocol> app = NSApp;
+  EXPECT_FALSE([app isHandlingSendEvent]);
+  {
+    base::mac::ScopedSendingEvent is_handling_send_event;
+    EXPECT_TRUE([app isHandlingSendEvent]);
+  }
+  EXPECT_FALSE([app isHandlingSendEvent]);
+}
+
+// Nested call restores previous value rather than resetting flag.
+TEST_F(ScopedSendingEventTest, NestedSetHandlingSendEvent) {
+  id<CrAppProtocol> app = NSApp;
+  EXPECT_FALSE([app isHandlingSendEvent]);
+  {
+    base::mac::ScopedSendingEvent is_handling_send_event;
+    EXPECT_TRUE([app isHandlingSendEvent]);
+    {
+      base::mac::ScopedSendingEvent nested_is_handling_send_event;
+      EXPECT_TRUE([app isHandlingSendEvent]);
+    }
+    EXPECT_TRUE([app isHandlingSendEvent]);
+  }
+  EXPECT_FALSE([app isHandlingSendEvent]);
+}
+
+}  // namespace
diff --git a/base/mac/scoped_typeref.h b/base/mac/scoped_typeref.h
new file mode 100644
index 0000000..61ee311
--- /dev/null
+++ b/base/mac/scoped_typeref.h
@@ -0,0 +1,132 @@
+// 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.
+
+#ifndef BASE_MAC_SCOPED_TYPEREF_H_
+#define BASE_MAC_SCOPED_TYPEREF_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/memory/scoped_policy.h"
+
+namespace base {
+
+// ScopedTypeRef<> is patterned after scoped_ptr<>, but maintains a ownership
+// of a reference to any type that is maintained by Retain and Release methods.
+//
+// The Traits structure must provide the Retain and Release methods for type T.
+// A default ScopedTypeRefTraits is used but not defined, and should be defined
+// for each type to use this interface. For example, an appropriate definition
+// of ScopedTypeRefTraits for CGLContextObj would be:
+//
+//   template<>
+//   struct ScopedTypeRefTraits<CGLContextObj> {
+//     void Retain(CGLContextObj object) { CGLContextRetain(object); }
+//     void Release(CGLContextObj object) { CGLContextRelease(object); }
+//   };
+//
+// For the many types that have pass-by-pointer create functions, the function
+// InitializeInto() is provided to allow direct initialization and assumption
+// of ownership of the object. For example, continuing to use the above
+// CGLContextObj specialization:
+//
+//   base::ScopedTypeRef<CGLContextObj> context;
+//   CGLCreateContext(pixel_format, share_group, context.InitializeInto());
+//
+// For initialization with an existing object, the caller may specify whether
+// the ScopedTypeRef<> being initialized is assuming the caller's existing
+// ownership of the object (and should not call Retain in initialization) or if
+// it should not assume this ownership and must create its own (by calling
+// Retain in initialization). This behavior is based on the |policy| parameter,
+// with |ASSUME| for the former and |RETAIN| for the latter. The default policy
+// is to |ASSUME|.
+
+template<typename T>
+struct ScopedTypeRefTraits;
+
+template<typename T, typename Traits = ScopedTypeRefTraits<T>>
+class ScopedTypeRef {
+ public:
+  typedef T element_type;
+
+  ScopedTypeRef(
+      T object = NULL,
+      base::scoped_policy::OwnershipPolicy policy = base::scoped_policy::ASSUME)
+      : object_(object) {
+    if (object_ && policy == base::scoped_policy::RETAIN)
+      Traits::Retain(object_);
+  }
+
+  ScopedTypeRef(const ScopedTypeRef<T, Traits>& that)
+      : object_(that.object_) {
+    if (object_)
+      Traits::Retain(object_);
+  }
+
+  ~ScopedTypeRef() {
+    if (object_)
+      Traits::Release(object_);
+  }
+
+  ScopedTypeRef& operator=(const ScopedTypeRef<T, Traits>& that) {
+    reset(that.get(), base::scoped_policy::RETAIN);
+    return *this;
+  }
+
+  // This is to be used only to take ownership of objects that are created
+  // by pass-by-pointer create functions. To enforce this, require that the
+  // object be reset to NULL before this may be used.
+  T* InitializeInto() WARN_UNUSED_RESULT {
+    DCHECK(!object_);
+    return &object_;
+  }
+
+  void reset(T object = NULL,
+             base::scoped_policy::OwnershipPolicy policy =
+                base::scoped_policy::ASSUME) {
+    if (object && policy == base::scoped_policy::RETAIN)
+      Traits::Retain(object);
+    if (object_)
+      Traits::Release(object_);
+    object_ = object;
+  }
+
+  bool operator==(T that) const {
+    return object_ == that;
+  }
+
+  bool operator!=(T that) const {
+    return object_ != that;
+  }
+
+  operator T() const {
+    return object_;
+  }
+
+  T get() const {
+    return object_;
+  }
+
+  void swap(ScopedTypeRef& that) {
+    T temp = that.object_;
+    that.object_ = object_;
+    object_ = temp;
+  }
+
+  // ScopedTypeRef<>::release() is like scoped_ptr<>::release.  It is NOT
+  // a wrapper for Release().  To force a ScopedTypeRef<> object to call
+  // Release(), use ScopedTypeRef<>::reset().
+  T release() WARN_UNUSED_RESULT {
+    T temp = object_;
+    object_ = NULL;
+    return temp;
+  }
+
+ private:
+  T object_;
+};
+
+}  // namespace base
+
+#endif  // BASE_MAC_SCOPED_TYPEREF_H_
diff --git a/base/mac/sdk_forward_declarations.h b/base/mac/sdk_forward_declarations.h
new file mode 100644
index 0000000..e45ab43
--- /dev/null
+++ b/base/mac/sdk_forward_declarations.h
@@ -0,0 +1,532 @@
+// Copyright (c) 2012 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 contains forward declarations for items in later SDKs than the
+// default one with which Chromium is built (currently 10.6).
+// If you call any function from this header, be sure to check at runtime for
+// respondsToSelector: before calling these functions (else your code will crash
+// on older OS X versions that chrome still supports).
+
+#ifndef BASE_MAC_SDK_FORWARD_DECLARATIONS_H_
+#define BASE_MAC_SDK_FORWARD_DECLARATIONS_H_
+
+#import <AppKit/AppKit.h>
+#import <CoreWLAN/CoreWLAN.h>
+#import <ImageCaptureCore/ImageCaptureCore.h>
+#import <IOBluetooth/IOBluetooth.h>
+
+#include "base/base_export.h"
+
+// ----------------------------------------------------------------------------
+// Either define or forward declare classes only available in OSX 10.7+.
+// ----------------------------------------------------------------------------
+
+#if !defined(MAC_OS_X_VERSION_10_7) || \
+    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
+
+@interface CWChannel : NSObject
+@end
+
+@interface CBPeripheral : NSObject
+@end
+
+@interface CBCentralManager : NSObject
+@end
+
+@interface CBUUID : NSObject
+@end
+
+#else
+
+@class CWChannel;
+@class CBPeripheral;
+@class CBCentralManager;
+@class CBUUID;
+
+#endif  // MAC_OS_X_VERSION_10_7
+
+#if !defined(MAC_OS_X_VERSION_10_8) || \
+    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_8
+
+@interface NSUUID : NSObject
+@end
+
+#else
+
+@class NSUUID;
+
+#endif  // MAC_OS_X_VERSION_10_8
+
+#if !defined(MAC_OS_X_VERSION_10_9) || \
+    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9
+
+// NSProgress is public API in 10.9, but a version of it exists and is usable
+// in 10.8.
+@interface NSProgress : NSObject
+@end
+
+@interface NSAppearance : NSObject
+@end
+
+#else
+
+@class NSProgress;
+@class NSAppearance;
+
+#endif  // MAC_OS_X_VERSION_10_9
+
+#if !defined(MAC_OS_X_VERSION_10_10) || \
+    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_10
+
+@interface NSUserActivity : NSObject
+@end
+
+#else
+
+@class NSUserActivity;
+
+#endif  // MAC_OS_X_VERSION_10_10
+
+// ----------------------------------------------------------------------------
+// Define typedefs, enums, and protocols not available in the version of the
+// OSX SDK being compiled against.
+// ----------------------------------------------------------------------------
+
+#if !defined(MAC_OS_X_VERSION_10_7) || \
+    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
+
+enum {
+  NSEventPhaseNone = 0,  // event not associated with a phase.
+  NSEventPhaseBegan = 0x1 << 0,
+  NSEventPhaseStationary = 0x1 << 1,
+  NSEventPhaseChanged = 0x1 << 2,
+  NSEventPhaseEnded = 0x1 << 3,
+  NSEventPhaseCancelled = 0x1 << 4
+};
+typedef NSUInteger NSEventPhase;
+
+enum {
+  NSFullScreenWindowMask = 1 << 14,
+};
+
+enum {
+  NSApplicationPresentationFullScreen = 1 << 10,
+};
+
+enum {
+  NSWindowCollectionBehaviorFullScreenPrimary = 1 << 7,
+  NSWindowCollectionBehaviorFullScreenAuxiliary = 1 << 8,
+};
+
+enum {
+  NSEventSwipeTrackingLockDirection = 0x1 << 0,
+  NSEventSwipeTrackingClampGestureAmount = 0x1 << 1,
+};
+typedef NSUInteger NSEventSwipeTrackingOptions;
+
+enum {
+  NSWindowAnimationBehaviorDefault = 0,
+  NSWindowAnimationBehaviorNone = 2,
+  NSWindowAnimationBehaviorDocumentWindow = 3,
+  NSWindowAnimationBehaviorUtilityWindow = 4,
+  NSWindowAnimationBehaviorAlertPanel = 5
+};
+typedef NSInteger NSWindowAnimationBehavior;
+
+enum {
+  NSWindowDocumentVersionsButton = 6,
+  NSWindowFullScreenButton,
+};
+typedef NSUInteger NSWindowButton;
+
+enum CWChannelBand {
+  kCWChannelBandUnknown = 0,
+  kCWChannelBand2GHz = 1,
+  kCWChannelBand5GHz = 2,
+};
+
+enum {
+  kCWSecurityNone = 0,
+  kCWSecurityWEP = 1,
+  kCWSecurityWPAPersonal = 2,
+  kCWSecurityWPAPersonalMixed = 3,
+  kCWSecurityWPA2Personal = 4,
+  kCWSecurityPersonal = 5,
+  kCWSecurityDynamicWEP = 6,
+  kCWSecurityWPAEnterprise = 7,
+  kCWSecurityWPAEnterpriseMixed = 8,
+  kCWSecurityWPA2Enterprise = 9,
+  kCWSecurityEnterprise = 10,
+  kCWSecurityUnknown = NSIntegerMax,
+};
+
+typedef NSInteger CWSecurity;
+
+enum {
+  kBluetoothFeatureLESupportedController = (1 << 6L),
+};
+
+@protocol IOBluetoothDeviceInquiryDelegate
+- (void)deviceInquiryStarted:(IOBluetoothDeviceInquiry*)sender;
+- (void)deviceInquiryDeviceFound:(IOBluetoothDeviceInquiry*)sender
+                          device:(IOBluetoothDevice*)device;
+- (void)deviceInquiryComplete:(IOBluetoothDeviceInquiry*)sender
+                        error:(IOReturn)error
+                      aborted:(BOOL)aborted;
+@end
+
+enum {
+  CBPeripheralStateDisconnected = 0,
+  CBPeripheralStateConnecting,
+  CBPeripheralStateConnected,
+};
+typedef NSInteger CBPeripheralState;
+
+enum {
+  CBCentralManagerStateUnknown = 0,
+  CBCentralManagerStateResetting,
+  CBCentralManagerStateUnsupported,
+  CBCentralManagerStateUnauthorized,
+  CBCentralManagerStatePoweredOff,
+  CBCentralManagerStatePoweredOn,
+};
+typedef NSInteger CBCentralManagerState;
+
+@protocol CBCentralManagerDelegate;
+
+@protocol CBCentralManagerDelegate<NSObject>
+- (void)centralManagerDidUpdateState:(CBCentralManager*)central;
+- (void)centralManager:(CBCentralManager*)central
+    didDiscoverPeripheral:(CBPeripheral*)peripheral
+        advertisementData:(NSDictionary*)advertisementData
+                     RSSI:(NSNumber*)RSSI;
+@end
+
+#endif  // MAC_OS_X_VERSION_10_7
+
+#if !defined(MAC_OS_X_VERSION_10_8) || \
+    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_8
+
+enum { NSEventPhaseMayBegin = 0x1 << 5 };
+
+#endif  // MAC_OS_X_VERSION_10_8
+
+#if !defined(MAC_OS_X_VERSION_10_9) || \
+    MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_9
+
+enum {
+  NSWindowOcclusionStateVisible = 1UL << 1,
+};
+typedef NSUInteger NSWindowOcclusionState;
+
+enum { NSWorkspaceLaunchWithErrorPresentation = 0x00000040 };
+
+#endif  // MAC_OS_X_VERSION_10_9
+
+// ----------------------------------------------------------------------------
+// Define NSStrings only available in newer versions of the OSX SDK to force
+// them to be statically linked.
+// ----------------------------------------------------------------------------
+
+extern "C" {
+#if !defined(MAC_OS_X_VERSION_10_7) || \
+    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7
+BASE_EXPORT extern NSString* const NSWindowWillEnterFullScreenNotification;
+BASE_EXPORT extern NSString* const NSWindowWillExitFullScreenNotification;
+BASE_EXPORT extern NSString* const NSWindowDidEnterFullScreenNotification;
+BASE_EXPORT extern NSString* const NSWindowDidExitFullScreenNotification;
+BASE_EXPORT extern NSString* const
+    NSWindowDidChangeBackingPropertiesNotification;
+BASE_EXPORT extern NSString* const CBAdvertisementDataServiceDataKey;
+BASE_EXPORT extern NSString* const
+    NSPreferredScrollerStyleDidChangeNotification;
+#endif  // MAC_OS_X_VERSION_10_7
+
+#if !defined(MAC_OS_X_VERSION_10_9) || \
+    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9
+BASE_EXPORT extern NSString* const NSWindowDidChangeOcclusionStateNotification;
+BASE_EXPORT extern NSString* const CBAdvertisementDataIsConnectable;
+#endif  // MAC_OS_X_VERSION_10_9
+
+#if !defined(MAC_OS_X_VERSION_10_10) || \
+    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10
+BASE_EXPORT extern NSString* const NSUserActivityTypeBrowsingWeb;
+BASE_EXPORT extern NSString* const NSAppearanceNameVibrantDark;
+#endif  // MAC_OS_X_VERSION_10_10
+}  // extern "C"
+
+// ----------------------------------------------------------------------------
+// If compiling against an older version of the OSX SDK, declare functions that
+// are available in newer versions of the OSX SDK. If compiling against a newer
+// version of the OSX SDK, redeclare those same functions to suppress
+// -Wpartial-availability warnings.
+// ----------------------------------------------------------------------------
+
+// Once Chrome no longer supports OSX 10.6, everything within this preprocessor
+// block can be removed.
+#if !defined(MAC_OS_X_VERSION_10_7) || \
+    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7
+
+@interface NSEvent (LionSDK)
++ (BOOL)isSwipeTrackingFromScrollEventsEnabled;
+- (NSEventPhase)momentumPhase;
+- (NSEventPhase)phase;
+- (BOOL)hasPreciseScrollingDeltas;
+- (CGFloat)scrollingDeltaX;
+- (CGFloat)scrollingDeltaY;
+- (void)trackSwipeEventWithOptions:(NSEventSwipeTrackingOptions)options
+          dampenAmountThresholdMin:(CGFloat)minDampenThreshold
+                               max:(CGFloat)maxDampenThreshold
+                      usingHandler:(void (^)(CGFloat gestureAmount,
+                                             NSEventPhase phase,
+                                             BOOL isComplete,
+                                             BOOL* stop))trackingHandler;
+- (BOOL)isDirectionInvertedFromDevice;
+@end
+
+@interface NSApplication (LionSDK)
+- (void)disableRelaunchOnLogin;
+@end
+
+@interface CALayer (LionSDK)
+- (CGFloat)contentsScale;
+- (void)setContentsScale:(CGFloat)contentsScale;
+@end
+
+@interface NSScreen (LionSDK)
+- (CGFloat)backingScaleFactor;
+- (NSRect)convertRectToBacking:(NSRect)aRect;
+@end
+
+@interface NSWindow (LionSDK)
+- (CGFloat)backingScaleFactor;
+- (NSWindowAnimationBehavior)animationBehavior;
+- (void)setAnimationBehavior:(NSWindowAnimationBehavior)newAnimationBehavior;
+- (void)toggleFullScreen:(id)sender;
+- (void)setRestorable:(BOOL)flag;
+- (NSRect)convertRectFromScreen:(NSRect)aRect;
+@end
+
+@interface NSCursor (LionSDKDeclarations)
++ (NSCursor*)IBeamCursorForVerticalLayout;
+@end
+
+@interface NSAnimationContext (LionSDK)
++ (void)runAnimationGroup:(void (^)(NSAnimationContext* context))changes
+        completionHandler:(void (^)(void))completionHandler;
+@property(copy) void (^completionHandler)(void);
+@end
+
+@interface NSView (LionSDK)
+- (NSSize)convertSizeFromBacking:(NSSize)size;
+- (void)setWantsBestResolutionOpenGLSurface:(BOOL)flag;
+@end
+
+@interface NSObject (ICCameraDeviceDelegateLionSDK)
+- (void)deviceDidBecomeReadyWithCompleteContentCatalog:(ICDevice*)device;
+- (void)didDownloadFile:(ICCameraFile*)file
+                  error:(NSError*)error
+                options:(NSDictionary*)options
+            contextInfo:(void*)contextInfo;
+@end
+
+@interface NSScroller (LionSDK)
++ (NSInteger)preferredScrollerStyle;
+@end
+
+@interface CWInterface (LionSDK)
+- (BOOL)associateToNetwork:(CWNetwork*)network
+                  password:(NSString*)password
+                     error:(NSError**)error;
+- (NSSet*)scanForNetworksWithName:(NSString*)networkName error:(NSError**)error;
+@end
+
+@interface CWChannel (LionSDK)
+@property(readonly) CWChannelBand channelBand;
+@end
+
+@interface CWNetwork (LionSDK)
+@property(readonly) CWChannel* wlanChannel;
+@property(readonly) NSInteger rssiValue;
+- (BOOL)supportsSecurity:(CWSecurity)security;
+@end
+
+@interface IOBluetoothHostController (LionSDK)
+- (NSString*)nameAsString;
+- (BluetoothHCIPowerState)powerState;
+@end
+
+@interface IOBluetoothL2CAPChannel (LionSDK)
+@property(readonly) BluetoothL2CAPMTU outgoingMTU;
+@end
+
+@interface IOBluetoothDevice (LionSDK)
+- (NSString*)addressString;
+- (unsigned int)classOfDevice;
+- (BluetoothConnectionHandle)connectionHandle;
+- (BluetoothHCIRSSIValue)rawRSSI;
+- (NSArray*)services;
+- (IOReturn)performSDPQuery:(id)target uuids:(NSArray*)uuids;
+@end
+
+@interface CBPeripheral (LionSDK)
+@property(readonly, nonatomic) CFUUIDRef UUID;
+@property(retain, readonly) NSString* name;
+@property(readonly) BOOL isConnected;
+@end
+
+@interface CBCentralManager (LionSDK)
+@property(readonly) CBCentralManagerState state;
+- (id)initWithDelegate:(id<CBCentralManagerDelegate>)delegate
+                 queue:(dispatch_queue_t)queue;
+- (void)scanForPeripheralsWithServices:(NSArray*)serviceUUIDs
+                               options:(NSDictionary*)options;
+- (void)stopScan;
+@end
+
+@interface CBUUID (LionSDK)
+@property(nonatomic, readonly) NSData* data;
++ (CBUUID*)UUIDWithString:(NSString*)theString;
+@end
+
+#endif  // MAC_OS_X_VERSION_10_7
+
+// Once Chrome no longer supports OSX 10.7, everything within this preprocessor
+// block can be removed.
+#if !defined(MAC_OS_X_VERSION_10_8) || \
+    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_8
+
+@interface NSColor (MountainLionSDK)
+- (CGColorRef)CGColor;
+@end
+
+@interface NSUUID (MountainLionSDK)
+- (NSString*)UUIDString;
+@end
+
+@interface NSControl (MountainLionSDK)
+@property BOOL allowsExpansionToolTips;
+@end
+
+#endif  // MAC_OS_X_VERSION_10_8
+
+// Once Chrome no longer supports OSX 10.8, everything within this preprocessor
+// block can be removed.
+#if !defined(MAC_OS_X_VERSION_10_9) || \
+    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9
+
+@interface NSProgress (MavericksSDK)
+
+- (instancetype)initWithParent:(NSProgress*)parentProgressOrNil
+                      userInfo:(NSDictionary*)userInfoOrNil;
+@property(copy) NSString* kind;
+
+@property int64_t totalUnitCount;
+@property int64_t completedUnitCount;
+
+@property(getter=isCancellable) BOOL cancellable;
+@property(getter=isPausable) BOOL pausable;
+@property(readonly, getter=isCancelled) BOOL cancelled;
+@property(readonly, getter=isPaused) BOOL paused;
+@property(copy) void (^cancellationHandler)(void);
+@property(copy) void (^pausingHandler)(void);
+- (void)cancel;
+- (void)pause;
+
+- (void)setUserInfoObject:(id)objectOrNil forKey:(NSString*)key;
+- (NSDictionary*)userInfo;
+
+@property(readonly, getter=isIndeterminate) BOOL indeterminate;
+@property(readonly) double fractionCompleted;
+
+- (void)publish;
+- (void)unpublish;
+
+@end
+
+@interface NSScreen (MavericksSDK)
++ (BOOL)screensHaveSeparateSpaces;
+@end
+
+@interface NSView (MavericksSDK)
+- (void)setCanDrawSubviewsIntoLayer:(BOOL)flag;
+- (NSAppearance*)effectiveAppearance;
+@end
+
+@interface NSWindow (MavericksSDK)
+- (NSWindowOcclusionState)occlusionState;
+@end
+
+@interface NSAppearance (MavericksSDK)
++ (id<NSObject>)appearanceNamed:(NSString*)name;
+@end
+
+@interface CBPeripheral (MavericksSDK)
+@property(readonly, nonatomic) NSUUID* identifier;
+@end
+
+#endif  // MAC_OS_X_VERSION_10_9
+
+// Once Chrome no longer supports OSX 10.9, everything within this preprocessor
+// block can be removed.
+#if !defined(MAC_OS_X_VERSION_10_10) || \
+    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10
+
+@interface NSUserActivity (YosemiteSDK)
+
+@property(readonly, copy) NSString* activityType;
+@property(copy) NSDictionary* userInfo;
+@property(copy) NSURL* webpageURL;
+
+- (instancetype)initWithActivityType:(NSString*)activityType;
+- (void)becomeCurrent;
+- (void)invalidate;
+
+@end
+
+@interface CBUUID (YosemiteSDK)
+- (NSString*)UUIDString;
+@end
+
+#endif  // MAC_OS_X_VERSION_10_10
+
+// ----------------------------------------------------------------------------
+// Chrome uses -[CWNetwork securityMode] and -[CWNetwork rssi] on OSX 10.6. The
+// former method relies on the enum CWSecurityMode which was removed in the OSX
+// 10.9 SDK. In order for Chrome to compile against an OSX 10.9+ SDK, Chrome
+// must define this enum. Chrome must also declare these methods.
+//
+// These declarations and definitions will not be necessary once Chrome no
+// longer runs on OSX 10.6.
+// ----------------------------------------------------------------------------
+#if defined(MAC_OS_X_VERSION_10_9) && \
+    MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_6
+typedef enum {
+  kCWSecurityModeOpen = 0,
+  kCWSecurityModeWEP,
+  kCWSecurityModeWPA_PSK,
+  kCWSecurityModeWPA2_PSK,
+  kCWSecurityModeWPA_Enterprise,
+  kCWSecurityModeWPA2_Enterprise,
+  kCWSecurityModeWPS,
+  kCWSecurityModeDynamicWEP
+} CWSecurityMode;
+
+@interface CWNetwork (SnowLeopardSDK)
+@property(readonly) NSNumber* rssi;
+@property(readonly) NSNumber* securityMode;
+@end
+#endif
+
+// ----------------------------------------------------------------------------
+// The symbol for kCWSSIDDidChangeNotification is available in the
+// CoreWLAN.framework for OSX versions 10.6 through 10.10. The symbol is not
+// declared in the OSX 10.9+ SDK, so when compiling against an OSX 10.9+ SDK,
+// declare the symbol.
+// ----------------------------------------------------------------------------
+#if defined(MAC_OS_X_VERSION_10_9) && \
+    MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
+BASE_EXPORT extern "C" NSString* const kCWSSIDDidChangeNotification;
+#endif
+#endif  // BASE_MAC_SDK_FORWARD_DECLARATIONS_H_
diff --git a/base/mac/sdk_forward_declarations.mm b/base/mac/sdk_forward_declarations.mm
new file mode 100644
index 0000000..2e4b2d9
--- /dev/null
+++ b/base/mac/sdk_forward_declarations.mm
@@ -0,0 +1,44 @@
+// 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.
+
+#include "base/mac/sdk_forward_declarations.h"
+
+#if !defined(MAC_OS_X_VERSION_10_7) || \
+    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7
+NSString* const NSWindowWillEnterFullScreenNotification =
+    @"NSWindowWillEnterFullScreenNotification";
+
+NSString* const NSWindowWillExitFullScreenNotification =
+    @"NSWindowWillExitFullScreenNotification";
+
+NSString* const NSWindowDidEnterFullScreenNotification =
+    @"NSWindowDidEnterFullScreenNotification";
+
+NSString* const NSWindowDidExitFullScreenNotification =
+    @"NSWindowDidExitFullScreenNotification";
+
+NSString* const NSWindowDidChangeBackingPropertiesNotification =
+    @"NSWindowDidChangeBackingPropertiesNotification";
+
+NSString* const CBAdvertisementDataServiceDataKey = @"kCBAdvDataServiceData";
+
+NSString* const NSPreferredScrollerStyleDidChangeNotification =
+    @"NSPreferredScrollerStyleDidChangeNotification";
+#endif  // MAC_OS_X_VERSION_10_7
+
+#if !defined(MAC_OS_X_VERSION_10_9) || \
+    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_9
+NSString* const NSWindowDidChangeOcclusionStateNotification =
+    @"NSWindowDidChangeOcclusionStateNotification";
+
+NSString* const CBAdvertisementDataIsConnectable = @"kCBAdvDataIsConnectable";
+#endif  // MAC_OS_X_VERSION_10_9
+
+#if !defined(MAC_OS_X_VERSION_10_10) || \
+    MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10
+NSString* const NSUserActivityTypeBrowsingWeb =
+    @"NSUserActivityTypeBrowsingWeb";
+
+NSString* const NSAppearanceNameVibrantDark = @"NSAppearanceNameVibrantDark";
+#endif  // MAC_OS_X_VERSION_10_10
diff --git a/base/macros.h b/base/macros.h
new file mode 100644
index 0000000..0325e74
--- /dev/null
+++ b/base/macros.h
@@ -0,0 +1,198 @@
+// 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 contains macros and macro-like constructs (e.g., templates) that
+// are commonly used throughout Chromium source. (It may also contain things
+// that are closely related to things that are commonly used that belong in this
+// file.)
+
+#ifndef BASE_MACROS_H_
+#define BASE_MACROS_H_
+
+#include <stddef.h>  // For size_t.
+#include <string.h>  // For memcpy.
+
+// Put this in the declarations for a class to be uncopyable.
+#define DISALLOW_COPY(TypeName) \
+  TypeName(const TypeName&) = delete
+
+// Put this in the declarations for a class to be unassignable.
+#define DISALLOW_ASSIGN(TypeName) \
+  void operator=(const TypeName&) = delete
+
+// A macro to disallow the copy constructor and operator= functions
+// This should be used in the private: declarations for a class
+#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
+  TypeName(const TypeName&);               \
+  void operator=(const TypeName&)
+
+// An older, deprecated, politically incorrect name for the above.
+// NOTE: The usage of this macro was banned from our code base, but some
+// third_party libraries are yet using it.
+// TODO(tfarina): Figure out how to fix the usage of this macro in the
+// third_party libraries and get rid of it.
+#define DISALLOW_EVIL_CONSTRUCTORS(TypeName) DISALLOW_COPY_AND_ASSIGN(TypeName)
+
+// A macro to disallow all the implicit constructors, namely the
+// default constructor, copy constructor and operator= functions.
+//
+// This should be used in the private: declarations for a class
+// that wants to prevent anyone from instantiating it. This is
+// especially useful for classes containing only static methods.
+#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
+  TypeName();                                    \
+  DISALLOW_COPY_AND_ASSIGN(TypeName)
+
+// The arraysize(arr) macro returns the # of elements in an array arr.
+// The expression is a compile-time constant, and therefore can be
+// used in defining new arrays, for example.  If you use arraysize on
+// a pointer by mistake, you will get a compile-time error.
+
+// This template function declaration is used in defining arraysize.
+// Note that the function doesn't need an implementation, as we only
+// use its type.
+template <typename T, size_t N> char (&ArraySizeHelper(T (&array)[N]))[N];
+#define arraysize(array) (sizeof(ArraySizeHelper(array)))
+
+
+// Use implicit_cast as a safe version of static_cast or const_cast
+// for upcasting in the type hierarchy (i.e. casting a pointer to Foo
+// to a pointer to SuperclassOfFoo or casting a pointer to Foo to
+// a const pointer to Foo).
+// When you use implicit_cast, the compiler checks that the cast is safe.
+// Such explicit implicit_casts are necessary in surprisingly many
+// situations where C++ demands an exact type match instead of an
+// argument type convertible to a target type.
+//
+// The From type can be inferred, so the preferred syntax for using
+// implicit_cast is the same as for static_cast etc.:
+//
+//   implicit_cast<ToType>(expr)
+//
+// implicit_cast would have been part of the C++ standard library,
+// but the proposal was submitted too late.  It will probably make
+// its way into the language in the future.
+template<typename To, typename From>
+inline To implicit_cast(From const &f) {
+  return f;
+}
+
+// The COMPILE_ASSERT macro can be used to verify that a compile time
+// expression is true. For example, you could use it to verify the
+// size of a static array:
+//
+//   COMPILE_ASSERT(arraysize(content_type_names) == CONTENT_NUM_TYPES,
+//                  content_type_names_incorrect_size);
+//
+// or to make sure a struct is smaller than a certain size:
+//
+//   COMPILE_ASSERT(sizeof(foo) < 128, foo_too_large);
+//
+// The second argument to the macro is the name of the variable. If
+// the expression is false, most compilers will issue a warning/error
+// containing the name of the variable.
+
+#undef COMPILE_ASSERT
+#define COMPILE_ASSERT(expr, msg) static_assert(expr, #msg)
+
+// bit_cast<Dest,Source> is a template function that implements the
+// equivalent of "*reinterpret_cast<Dest*>(&source)".  We need this in
+// very low-level functions like the protobuf library and fast math
+// support.
+//
+//   float f = 3.14159265358979;
+//   int i = bit_cast<int32>(f);
+//   // i = 0x40490fdb
+//
+// The classical address-casting method is:
+//
+//   // WRONG
+//   float f = 3.14159265358979;            // WRONG
+//   int i = * reinterpret_cast<int*>(&f);  // WRONG
+//
+// The address-casting method actually produces undefined behavior
+// according to ISO C++ specification section 3.10 -15 -.  Roughly, this
+// section says: if an object in memory has one type, and a program
+// accesses it with a different type, then the result is undefined
+// behavior for most values of "different type".
+//
+// This is true for any cast syntax, either *(int*)&f or
+// *reinterpret_cast<int*>(&f).  And it is particularly true for
+// conversions between integral lvalues and floating-point lvalues.
+//
+// The purpose of 3.10 -15- is to allow optimizing compilers to assume
+// that expressions with different types refer to different memory.  gcc
+// 4.0.1 has an optimizer that takes advantage of this.  So a
+// non-conforming program quietly produces wildly incorrect output.
+//
+// The problem is not the use of reinterpret_cast.  The problem is type
+// punning: holding an object in memory of one type and reading its bits
+// back using a different type.
+//
+// The C++ standard is more subtle and complex than this, but that
+// is the basic idea.
+//
+// Anyways ...
+//
+// bit_cast<> calls memcpy() which is blessed by the standard,
+// especially by the example in section 3.9 .  Also, of course,
+// bit_cast<> wraps up the nasty logic in one place.
+//
+// Fortunately memcpy() is very fast.  In optimized mode, with a
+// constant size, gcc 2.95.3, gcc 4.0.1, and msvc 7.1 produce inline
+// code with the minimal amount of data movement.  On a 32-bit system,
+// memcpy(d,s,4) compiles to one load and one store, and memcpy(d,s,8)
+// compiles to two loads and two stores.
+//
+// I tested this code with gcc 2.95.3, gcc 4.0.1, icc 8.1, and msvc 7.1.
+//
+// WARNING: if Dest or Source is a non-POD type, the result of the memcpy
+// is likely to surprise you.
+
+template <class Dest, class Source>
+inline Dest bit_cast(const Source& source) {
+  COMPILE_ASSERT(sizeof(Dest) == sizeof(Source), VerifySizesAreEqual);
+
+  Dest dest;
+  memcpy(&dest, &source, sizeof(dest));
+  return dest;
+}
+
+// Used to explicitly mark the return value of a function as unused. If you are
+// really sure you don't want to do anything with the return value of a function
+// that has been marked WARN_UNUSED_RESULT, wrap it with this. Example:
+//
+//   scoped_ptr<MyType> my_var = ...;
+//   if (TakeOwnership(my_var.get()) == SUCCESS)
+//     ignore_result(my_var.release());
+//
+template<typename T>
+inline void ignore_result(const T&) {
+}
+
+// The following enum should be used only as a constructor argument to indicate
+// that the variable has static storage class, and that the constructor should
+// do nothing to its state.  It indicates to the reader that it is legal to
+// declare a static instance of the class, provided the constructor is given
+// the base::LINKER_INITIALIZED argument.  Normally, it is unsafe to declare a
+// static variable that has a constructor or a destructor because invocation
+// order is undefined.  However, IF the type can be initialized by filling with
+// zeroes (which the loader does for static variables), AND the destructor also
+// does nothing to the storage, AND there are no virtual methods, then a
+// constructor declared as
+//       explicit MyClass(base::LinkerInitialized x) {}
+// and invoked as
+//       static MyClass my_variable_name(base::LINKER_INITIALIZED);
+namespace base {
+enum LinkerInitialized { LINKER_INITIALIZED };
+
+// Use these to declare and define a static local variable (static T;) so that
+// it is leaked so that its destructors are not called at exit. If you need
+// thread-safe initialization, use base/lazy_instance.h instead.
+#define CR_DEFINE_STATIC_LOCAL(type, name, arguments) \
+  static type& name = *new type arguments
+
+}  // base
+
+#endif  // BASE_MACROS_H_
diff --git a/base/md5.cc b/base/md5.cc
new file mode 100644
index 0000000..72c774d
--- /dev/null
+++ b/base/md5.cc
@@ -0,0 +1,299 @@
+// Copyright (c) 2011 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.
+
+// The original file was copied from sqlite, and was in the public domain.
+
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.  This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+#include "base/md5.h"
+
+#include <stddef.h>
+
+namespace {
+
+struct Context {
+  uint32_t buf[4];
+  uint32_t bits[2];
+  uint8_t in[64];
+};
+
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+void byteReverse(uint8_t* buf, unsigned longs) {
+  do {
+    uint32_t temp = static_cast<uint32_t>(
+        static_cast<unsigned>(buf[3]) << 8 |
+        buf[2]) << 16 |
+        (static_cast<unsigned>(buf[1]) << 8 | buf[0]);
+    *reinterpret_cast<uint32_t*>(buf) = temp;
+    buf += 4;
+  } while (--longs);
+}
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+  (w += f(x, y, z) + data, w = w << s | w >> (32 - s), w += x)
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data.  MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+void MD5Transform(uint32_t buf[4], const uint32_t in[16]) {
+  uint32_t a, b, c, d;
+
+  a = buf[0];
+  b = buf[1];
+  c = buf[2];
+  d = buf[3];
+
+  MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+  MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+  MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+  MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+  MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+  MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+  MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+  MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+  MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+  MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+  MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+  MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+  MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+  MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+  MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+  MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+  MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+  MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+  MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+  MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+  MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+  MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+  MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+  MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+  MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+  MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+  MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+  MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+  MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+  MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+  MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+  MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+  MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+  MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+  MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+  MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+  MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+  MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+  MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+  MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+  MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+  MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+  MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+  MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+  MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+  MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+  MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+  MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+  MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+  MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+  MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+  MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+  MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+  MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+  MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+  MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+  MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+  MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+  MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+  MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+  MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+  MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+  MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+  MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+  buf[0] += a;
+  buf[1] += b;
+  buf[2] += c;
+  buf[3] += d;
+}
+
+}  // namespace
+
+namespace base {
+
+/*
+ * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void MD5Init(MD5Context* context) {
+  struct Context* ctx = reinterpret_cast<struct Context*>(context);
+  ctx->buf[0] = 0x67452301;
+  ctx->buf[1] = 0xefcdab89;
+  ctx->buf[2] = 0x98badcfe;
+  ctx->buf[3] = 0x10325476;
+  ctx->bits[0] = 0;
+  ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void MD5Update(MD5Context* context, const StringPiece& data) {
+  struct Context* ctx = reinterpret_cast<struct Context*>(context);
+  const uint8_t* buf = reinterpret_cast<const uint8_t*>(data.data());
+  size_t len = data.size();
+
+  /* Update bitcount */
+
+  uint32_t t = ctx->bits[0];
+  if ((ctx->bits[0] = t + (static_cast<uint32_t>(len) << 3)) < t)
+    ctx->bits[1]++; /* Carry from low to high */
+  ctx->bits[1] += static_cast<uint32_t>(len >> 29);
+
+  t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
+
+  /* Handle any leading odd-sized chunks */
+
+  if (t) {
+    uint8_t* p = static_cast<uint8_t*>(ctx->in + t);
+
+    t = 64 - t;
+    if (len < t) {
+      memcpy(p, buf, len);
+      return;
+    }
+    memcpy(p, buf, t);
+    byteReverse(ctx->in, 16);
+    MD5Transform(ctx->buf, reinterpret_cast<uint32_t*>(ctx->in));
+    buf += t;
+    len -= t;
+  }
+
+  /* Process data in 64-byte chunks */
+
+  while (len >= 64) {
+    memcpy(ctx->in, buf, 64);
+    byteReverse(ctx->in, 16);
+    MD5Transform(ctx->buf, reinterpret_cast<uint32_t*>(ctx->in));
+    buf += 64;
+    len -= 64;
+  }
+
+  /* Handle any remaining bytes of data. */
+
+  memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void MD5Final(MD5Digest* digest, MD5Context* context) {
+  struct Context* ctx = reinterpret_cast<struct Context*>(context);
+  unsigned count;
+  uint8_t* p;
+
+  /* Compute number of bytes mod 64 */
+  count = (ctx->bits[0] >> 3) & 0x3F;
+
+  /* Set the first char of padding to 0x80.  This is safe since there is
+     always at least one byte free */
+  p = ctx->in + count;
+  *p++ = 0x80;
+
+  /* Bytes of padding needed to make 64 bytes */
+  count = 64 - 1 - count;
+
+  /* Pad out to 56 mod 64 */
+  if (count < 8) {
+    /* Two lots of padding:  Pad the first block to 64 bytes */
+    memset(p, 0, count);
+    byteReverse(ctx->in, 16);
+    MD5Transform(ctx->buf, reinterpret_cast<uint32_t*>(ctx->in));
+
+    /* Now fill the next block with 56 bytes */
+    memset(ctx->in, 0, 56);
+  } else {
+    /* Pad block to 56 bytes */
+    memset(p, 0, count - 8);
+  }
+  byteReverse(ctx->in, 14);
+
+  /* Append length in bits and transform */
+  memcpy(&ctx->in[14 * sizeof(ctx->bits[0])], &ctx->bits[0],
+         sizeof(ctx->bits[0]));
+  memcpy(&ctx->in[15 * sizeof(ctx->bits[1])], &ctx->bits[1],
+         sizeof(ctx->bits[1]));
+
+  MD5Transform(ctx->buf, reinterpret_cast<uint32_t*>(ctx->in));
+  byteReverse(reinterpret_cast<uint8_t*>(ctx->buf), 4);
+  memcpy(digest->a, ctx->buf, 16);
+  memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */
+}
+
+void MD5IntermediateFinal(MD5Digest* digest, const MD5Context* context) {
+  /* MD5Final mutates the MD5Context*. Make a copy for generating the
+     intermediate value. */
+  MD5Context context_copy;
+  memcpy(&context_copy, context, sizeof(context_copy));
+  MD5Final(digest, &context_copy);
+}
+
+std::string MD5DigestToBase16(const MD5Digest& digest) {
+  static char const zEncode[] = "0123456789abcdef";
+
+  std::string ret;
+  ret.resize(32);
+
+  for (int i = 0, j = 0; i < 16; i++, j += 2) {
+    uint8_t a = digest.a[i];
+    ret[j] = zEncode[(a >> 4) & 0xf];
+    ret[j + 1] = zEncode[a & 0xf];
+  }
+  return ret;
+}
+
+void MD5Sum(const void* data, size_t length, MD5Digest* digest) {
+  MD5Context ctx;
+  MD5Init(&ctx);
+  MD5Update(&ctx, StringPiece(reinterpret_cast<const char*>(data), length));
+  MD5Final(digest, &ctx);
+}
+
+std::string MD5String(const StringPiece& str) {
+  MD5Digest digest;
+  MD5Sum(str.data(), str.length(), &digest);
+  return MD5DigestToBase16(digest);
+}
+
+}  // namespace base
diff --git a/base/md5.h b/base/md5.h
new file mode 100644
index 0000000..0b4cbce
--- /dev/null
+++ b/base/md5.h
@@ -0,0 +1,77 @@
+// Copyright (c) 2011 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_MD5_H_
+#define BASE_MD5_H_
+
+#include <stdint.h>
+
+#include "base/base_export.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+// MD5 stands for Message Digest algorithm 5.
+// MD5 is a robust hash function, designed for cyptography, but often used
+// for file checksums.  The code is complex and slow, but has few
+// collisions.
+// See Also:
+//   http://en.wikipedia.org/wiki/MD5
+
+// These functions perform MD5 operations. The simplest call is MD5Sum() to
+// generate the MD5 sum of the given data.
+//
+// You can also compute the MD5 sum of data incrementally by making multiple
+// calls to MD5Update():
+//   MD5Context ctx; // intermediate MD5 data: do not use
+//   MD5Init(&ctx);
+//   MD5Update(&ctx, data1, length1);
+//   MD5Update(&ctx, data2, length2);
+//   ...
+//
+//   MD5Digest digest; // the result of the computation
+//   MD5Final(&digest, &ctx);
+//
+// You can call MD5DigestToBase16() to generate a string of the digest.
+
+// The output of an MD5 operation.
+struct MD5Digest {
+  uint8_t a[16];
+};
+
+// Used for storing intermediate data during an MD5 computation. Callers
+// should not access the data.
+typedef char MD5Context[88];
+
+// Initializes the given MD5 context structure for subsequent calls to
+// MD5Update().
+BASE_EXPORT void MD5Init(MD5Context* context);
+
+// For the given buffer of |data| as a StringPiece, updates the given MD5
+// context with the sum of the data. You can call this any number of times
+// during the computation, except that MD5Init() must have been called first.
+BASE_EXPORT void MD5Update(MD5Context* context, const StringPiece& data);
+
+// Finalizes the MD5 operation and fills the buffer with the digest.
+BASE_EXPORT void MD5Final(MD5Digest* digest, MD5Context* context);
+
+// MD5IntermediateFinal() generates a digest without finalizing the MD5
+// operation.  Can be used to generate digests for the input seen thus far,
+// without affecting the digest generated for the entire input.
+BASE_EXPORT void MD5IntermediateFinal(MD5Digest* digest,
+                                      const MD5Context* context);
+
+// Converts a digest into human-readable hexadecimal.
+BASE_EXPORT std::string MD5DigestToBase16(const MD5Digest& digest);
+
+// Computes the MD5 sum of the given data buffer with the given length.
+// The given 'digest' structure will be filled with the result data.
+BASE_EXPORT void MD5Sum(const void* data, size_t length, MD5Digest* digest);
+
+// Returns the MD5 (in hexadecimal) of a string.
+BASE_EXPORT std::string MD5String(const StringPiece& str);
+
+}  // namespace base
+
+#endif  // BASE_MD5_H_
diff --git a/base/md5_unittest.cc b/base/md5_unittest.cc
new file mode 100644
index 0000000..08c99f1
--- /dev/null
+++ b/base/md5_unittest.cc
@@ -0,0 +1,252 @@
+// Copyright (c) 2011 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 <string.h>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/md5.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(MD5, DigestToBase16) {
+  MD5Digest digest;
+
+  int data[] = {
+    0xd4, 0x1d, 0x8c, 0xd9,
+    0x8f, 0x00, 0xb2, 0x04,
+    0xe9, 0x80, 0x09, 0x98,
+    0xec, 0xf8, 0x42, 0x7e
+  };
+
+  for (int i = 0; i < 16; ++i)
+    digest.a[i] = data[i] & 0xff;
+
+  std::string actual = MD5DigestToBase16(digest);
+  std::string expected = "d41d8cd98f00b204e9800998ecf8427e";
+
+  EXPECT_EQ(expected, actual);
+}
+
+TEST(MD5, MD5SumEmtpyData) {
+  MD5Digest digest;
+  const char data[] = "";
+
+  MD5Sum(data, strlen(data), &digest);
+
+  int expected[] = {
+    0xd4, 0x1d, 0x8c, 0xd9,
+    0x8f, 0x00, 0xb2, 0x04,
+    0xe9, 0x80, 0x09, 0x98,
+    0xec, 0xf8, 0x42, 0x7e
+  };
+
+  for (int i = 0; i < 16; ++i)
+    EXPECT_EQ(expected[i], digest.a[i] & 0xFF);
+}
+
+TEST(MD5, MD5SumOneByteData) {
+  MD5Digest digest;
+  const char data[] = "a";
+
+  MD5Sum(data, strlen(data), &digest);
+
+  int expected[] = {
+    0x0c, 0xc1, 0x75, 0xb9,
+    0xc0, 0xf1, 0xb6, 0xa8,
+    0x31, 0xc3, 0x99, 0xe2,
+    0x69, 0x77, 0x26, 0x61
+  };
+
+  for (int i = 0; i < 16; ++i)
+    EXPECT_EQ(expected[i], digest.a[i] & 0xFF);
+}
+
+TEST(MD5, MD5SumLongData) {
+  const int length = 10 * 1024 * 1024 + 1;
+  scoped_ptr<char[]> data(new char[length]);
+
+  for (int i = 0; i < length; ++i)
+    data[i] = i & 0xFF;
+
+  MD5Digest digest;
+  MD5Sum(data.get(), length, &digest);
+
+  int expected[] = {
+    0x90, 0xbd, 0x6a, 0xd9,
+    0x0a, 0xce, 0xf5, 0xad,
+    0xaa, 0x92, 0x20, 0x3e,
+    0x21, 0xc7, 0xa1, 0x3e
+  };
+
+  for (int i = 0; i < 16; ++i)
+    EXPECT_EQ(expected[i], digest.a[i] & 0xFF);
+}
+
+TEST(MD5, ContextWithEmptyData) {
+  MD5Context ctx;
+  MD5Init(&ctx);
+
+  MD5Digest digest;
+  MD5Final(&digest, &ctx);
+
+  int expected[] = {
+    0xd4, 0x1d, 0x8c, 0xd9,
+    0x8f, 0x00, 0xb2, 0x04,
+    0xe9, 0x80, 0x09, 0x98,
+    0xec, 0xf8, 0x42, 0x7e
+  };
+
+  for (int i = 0; i < 16; ++i)
+    EXPECT_EQ(expected[i], digest.a[i] & 0xFF);
+}
+
+TEST(MD5, ContextWithLongData) {
+  MD5Context ctx;
+  MD5Init(&ctx);
+
+  const int length = 10 * 1024 * 1024 + 1;
+  scoped_ptr<char[]> data(new char[length]);
+
+  for (int i = 0; i < length; ++i)
+    data[i] = i & 0xFF;
+
+  int total = 0;
+  while (total < length) {
+    int len = 4097;  // intentionally not 2^k.
+    if (len > length - total)
+      len = length - total;
+
+    MD5Update(&ctx,
+              StringPiece(reinterpret_cast<char*>(data.get() + total), len));
+    total += len;
+  }
+
+  EXPECT_EQ(length, total);
+
+  MD5Digest digest;
+  MD5Final(&digest, &ctx);
+
+  int expected[] = {
+    0x90, 0xbd, 0x6a, 0xd9,
+    0x0a, 0xce, 0xf5, 0xad,
+    0xaa, 0x92, 0x20, 0x3e,
+    0x21, 0xc7, 0xa1, 0x3e
+  };
+
+  for (int i = 0; i < 16; ++i)
+    EXPECT_EQ(expected[i], digest.a[i] & 0xFF);
+}
+
+// Example data from http://www.ietf.org/rfc/rfc1321.txt A.5 Test Suite
+TEST(MD5, MD5StringTestSuite1) {
+  std::string actual = MD5String("");
+  std::string expected = "d41d8cd98f00b204e9800998ecf8427e";
+  EXPECT_EQ(expected, actual);
+}
+
+TEST(MD5, MD5StringTestSuite2) {
+  std::string actual = MD5String("a");
+  std::string expected = "0cc175b9c0f1b6a831c399e269772661";
+  EXPECT_EQ(expected, actual);
+}
+
+TEST(MD5, MD5StringTestSuite3) {
+  std::string actual = MD5String("abc");
+  std::string expected = "900150983cd24fb0d6963f7d28e17f72";
+  EXPECT_EQ(expected, actual);
+}
+
+TEST(MD5, MD5StringTestSuite4) {
+  std::string actual = MD5String("message digest");
+  std::string expected = "f96b697d7cb7938d525a2f31aaf161d0";
+  EXPECT_EQ(expected, actual);
+}
+
+TEST(MD5, MD5StringTestSuite5) {
+  std::string actual = MD5String("abcdefghijklmnopqrstuvwxyz");
+  std::string expected = "c3fcd3d76192e4007dfb496cca67e13b";
+  EXPECT_EQ(expected, actual);
+}
+
+TEST(MD5, MD5StringTestSuite6) {
+  std::string actual = MD5String("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                                 "abcdefghijklmnopqrstuvwxyz"
+                                 "0123456789");
+  std::string expected = "d174ab98d277d9f5a5611c2c9f419d9f";
+  EXPECT_EQ(expected, actual);
+}
+
+TEST(MD5, MD5StringTestSuite7) {
+  std::string actual = MD5String("12345678901234567890"
+                                 "12345678901234567890"
+                                 "12345678901234567890"
+                                 "12345678901234567890");
+  std::string expected = "57edf4a22be3c955ac49da2e2107b67a";
+  EXPECT_EQ(expected, actual);
+}
+
+TEST(MD5, ContextWithStringData) {
+  MD5Context ctx;
+  MD5Init(&ctx);
+
+  MD5Update(&ctx, "abc");
+
+  MD5Digest digest;
+  MD5Final(&digest, &ctx);
+
+  std::string actual = MD5DigestToBase16(digest);
+  std::string expected = "900150983cd24fb0d6963f7d28e17f72";
+
+  EXPECT_EQ(expected, actual);
+}
+
+// Test that a digest generated by MD5IntermediateFinal() gives the same results
+// as an independently-calculated digest, and also does not modify the context.
+TEST(MD5, IntermediateFinal) {
+  // Independent context over the header.
+  MD5Context check_header_context;
+  MD5Init(&check_header_context);
+
+  // Independent context over entire input.
+  MD5Context check_full_context;
+  MD5Init(&check_full_context);
+
+  // Context intermediate digest will be calculated from.
+  MD5Context context;
+  MD5Init(&context);
+
+  static const char kHeader[] = "header data";
+  static const char kBody[] = "payload data";
+
+  MD5Update(&context, kHeader);
+  MD5Update(&check_header_context, kHeader);
+  MD5Update(&check_full_context, kHeader);
+
+  MD5Digest check_header_digest;
+  MD5Final(&check_header_digest, &check_header_context);
+
+  MD5Digest header_digest;
+  MD5IntermediateFinal(&header_digest, &context);
+
+  MD5Update(&context, kBody);
+  MD5Update(&check_full_context, kBody);
+
+  MD5Digest check_full_digest;
+  MD5Final(&check_full_digest, &check_full_context);
+
+  MD5Digest digest;
+  MD5Final(&digest, &context);
+
+  // The header and full digest pairs are the same, and they aren't the same as
+  // each other.
+  EXPECT_TRUE(!memcmp(&header_digest, &check_header_digest,
+                      sizeof(header_digest)));
+  EXPECT_TRUE(!memcmp(&digest, &check_full_digest, sizeof(digest)));
+  EXPECT_TRUE(memcmp(&digest, &header_digest, sizeof(digest)));
+}
+
+}  // namespace base
diff --git a/base/memory/BUILD.gn b/base/memory/BUILD.gn
new file mode 100644
index 0000000..c344279
--- /dev/null
+++ b/base/memory/BUILD.gn
@@ -0,0 +1,70 @@
+# Copyright (c) 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("memory") {
+  sources = [
+    "aligned_memory.cc",
+    "aligned_memory.h",
+    "discardable_memory.cc",
+    "discardable_memory.h",
+    "discardable_memory_allocator.cc",
+    "discardable_memory_allocator.h",
+    "discardable_shared_memory.cc",
+    "discardable_shared_memory.h",
+    "linked_ptr.h",
+    "manual_constructor.h",
+    "memory_pressure_listener.cc",
+    "memory_pressure_listener.h",
+    "memory_pressure_monitor.cc",
+    "memory_pressure_monitor.h",
+    "memory_pressure_monitor_chromeos.cc",
+    "memory_pressure_monitor_chromeos.h",
+    "memory_pressure_monitor_mac.cc",
+    "memory_pressure_monitor_mac.h",
+    "memory_pressure_monitor_win.cc",
+    "memory_pressure_monitor_win.h",
+    "raw_scoped_refptr_mismatch_checker.h",
+    "ref_counted.cc",
+    "ref_counted.h",
+    "ref_counted_delete_on_message_loop.h",
+    "ref_counted_memory.cc",
+    "ref_counted_memory.h",
+    "scoped_policy.h",
+    "scoped_ptr.h",
+    "scoped_vector.h",
+    "shared_memory.h",
+    "shared_memory_android.cc",
+    "shared_memory_nacl.cc",
+    "shared_memory_posix.cc",
+    "shared_memory_win.cc",
+    "singleton.cc",
+    "singleton.h",
+    "weak_ptr.cc",
+    "weak_ptr.h",
+  ]
+
+  if (is_nacl) {
+    sources -= [
+      "discardable_memory.cc",
+      "discardable_memory.h",
+      "discardable_memory_allocator.cc",
+      "discardable_memory_allocator.h",
+      "discardable_shared_memory.cc",
+      "discardable_shared_memory.h",
+      "shared_memory_posix.cc",
+    ]
+  } else {
+    sources -= [ "shared_memory_nacl.cc" ]
+  }
+
+  if (is_android) {
+    deps = [
+      "//third_party/ashmem",
+    ]
+  }
+
+  configs += [ "//base:base_implementation" ]
+
+  visibility = [ "//base/*" ]
+}
diff --git a/base/memory/OWNERS b/base/memory/OWNERS
new file mode 100644
index 0000000..bcaf778
--- /dev/null
+++ b/base/memory/OWNERS
@@ -0,0 +1,2 @@
+per-file *chromeos*=skuhne@chromium.org
+per-file *chromeos*=oshima@chromium.org
diff --git a/base/memory/aligned_memory.cc b/base/memory/aligned_memory.cc
new file mode 100644
index 0000000..5ec88b1
--- /dev/null
+++ b/base/memory/aligned_memory.cc
@@ -0,0 +1,46 @@
+// Copyright (c) 2012 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/memory/aligned_memory.h"
+
+#include "base/logging.h"
+
+#if defined(OS_ANDROID)
+#include <malloc.h>
+#endif
+
+namespace base {
+
+void* AlignedAlloc(size_t size, size_t alignment) {
+  DCHECK_GT(size, 0U);
+  DCHECK_EQ(alignment & (alignment - 1), 0U);
+  DCHECK_EQ(alignment % sizeof(void*), 0U);
+  void* ptr = NULL;
+#if defined(COMPILER_MSVC)
+  ptr = _aligned_malloc(size, alignment);
+// Android technically supports posix_memalign(), but does not expose it in
+// the current version of the library headers used by Chrome.  Luckily,
+// memalign() on Android returns pointers which can safely be used with
+// free(), so we can use it instead.  Issue filed to document this:
+// http://code.google.com/p/android/issues/detail?id=35391
+#elif defined(OS_ANDROID)
+  ptr = memalign(alignment, size);
+#else
+  if (posix_memalign(&ptr, alignment, size))
+    ptr = NULL;
+#endif
+  // Since aligned allocations may fail for non-memory related reasons, force a
+  // crash if we encounter a failed allocation; maintaining consistent behavior
+  // with a normal allocation failure in Chrome.
+  if (!ptr) {
+    DLOG(ERROR) << "If you crashed here, your aligned allocation is incorrect: "
+                << "size=" << size << ", alignment=" << alignment;
+    CHECK(false);
+  }
+  // Sanity check alignment just to be safe.
+  DCHECK_EQ(reinterpret_cast<uintptr_t>(ptr) & (alignment - 1), 0U);
+  return ptr;
+}
+
+}  // namespace base
diff --git a/base/memory/aligned_memory.h b/base/memory/aligned_memory.h
new file mode 100644
index 0000000..1a4cba9
--- /dev/null
+++ b/base/memory/aligned_memory.h
@@ -0,0 +1,114 @@
+// Copyright (c) 2012 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.
+
+// AlignedMemory is a POD type that gives you a portable way to specify static
+// or local stack data of a given alignment and size. For example, if you need
+// static storage for a class, but you want manual control over when the object
+// is constructed and destructed (you don't want static initialization and
+// destruction), use AlignedMemory:
+//
+//   static AlignedMemory<sizeof(MyClass), ALIGNOF(MyClass)> my_class;
+//
+//   // ... at runtime:
+//   new(my_class.void_data()) MyClass();
+//
+//   // ... use it:
+//   MyClass* mc = my_class.data_as<MyClass>();
+//
+//   // ... later, to destruct my_class:
+//   my_class.data_as<MyClass>()->MyClass::~MyClass();
+//
+// Alternatively, a runtime sized aligned allocation can be created:
+//
+//   float* my_array = static_cast<float*>(AlignedAlloc(size, alignment));
+//
+//   // ... later, to release the memory:
+//   AlignedFree(my_array);
+//
+// Or using scoped_ptr:
+//
+//   scoped_ptr<float, AlignedFreeDeleter> my_array(
+//       static_cast<float*>(AlignedAlloc(size, alignment)));
+
+#ifndef BASE_MEMORY_ALIGNED_MEMORY_H_
+#define BASE_MEMORY_ALIGNED_MEMORY_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+
+#if defined(COMPILER_MSVC)
+#include <malloc.h>
+#else
+#include <stdlib.h>
+#endif
+
+namespace base {
+
+// AlignedMemory is specialized for all supported alignments.
+// Make sure we get a compiler error if someone uses an unsupported alignment.
+template <size_t Size, size_t ByteAlignment>
+struct AlignedMemory {};
+
+#define BASE_DECL_ALIGNED_MEMORY(byte_alignment) \
+    template <size_t Size> \
+    class AlignedMemory<Size, byte_alignment> { \
+     public: \
+      ALIGNAS(byte_alignment) uint8 data_[Size]; \
+      void* void_data() { return static_cast<void*>(data_); } \
+      const void* void_data() const { \
+        return static_cast<const void*>(data_); \
+      } \
+      template<typename Type> \
+      Type* data_as() { return static_cast<Type*>(void_data()); } \
+      template<typename Type> \
+      const Type* data_as() const { \
+        return static_cast<const Type*>(void_data()); \
+      } \
+     private: \
+      void* operator new(size_t); \
+      void operator delete(void*); \
+    }
+
+// Specialization for all alignments is required because MSVC (as of VS 2008)
+// does not understand ALIGNAS(ALIGNOF(Type)) or ALIGNAS(template_param).
+// Greater than 4096 alignment is not supported by some compilers, so 4096 is
+// the maximum specified here.
+BASE_DECL_ALIGNED_MEMORY(1);
+BASE_DECL_ALIGNED_MEMORY(2);
+BASE_DECL_ALIGNED_MEMORY(4);
+BASE_DECL_ALIGNED_MEMORY(8);
+BASE_DECL_ALIGNED_MEMORY(16);
+BASE_DECL_ALIGNED_MEMORY(32);
+BASE_DECL_ALIGNED_MEMORY(64);
+BASE_DECL_ALIGNED_MEMORY(128);
+BASE_DECL_ALIGNED_MEMORY(256);
+BASE_DECL_ALIGNED_MEMORY(512);
+BASE_DECL_ALIGNED_MEMORY(1024);
+BASE_DECL_ALIGNED_MEMORY(2048);
+BASE_DECL_ALIGNED_MEMORY(4096);
+
+#undef BASE_DECL_ALIGNED_MEMORY
+
+BASE_EXPORT void* AlignedAlloc(size_t size, size_t alignment);
+
+inline void AlignedFree(void* ptr) {
+#if defined(COMPILER_MSVC)
+  _aligned_free(ptr);
+#else
+  free(ptr);
+#endif
+}
+
+// Deleter for use with scoped_ptr. E.g., use as
+//   scoped_ptr<Foo, base::AlignedFreeDeleter> foo;
+struct AlignedFreeDeleter {
+  inline void operator()(void* ptr) const {
+    AlignedFree(ptr);
+  }
+};
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_ALIGNED_MEMORY_H_
diff --git a/base/memory/aligned_memory_unittest.cc b/base/memory/aligned_memory_unittest.cc
new file mode 100644
index 0000000..5d681f9
--- /dev/null
+++ b/base/memory/aligned_memory_unittest.cc
@@ -0,0 +1,100 @@
+// Copyright (c) 2012 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/memory/aligned_memory.h"
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#define EXPECT_ALIGNED(ptr, align) \
+    EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(ptr) & (align - 1))
+
+namespace {
+
+using base::AlignedMemory;
+
+TEST(AlignedMemoryTest, StaticAlignment) {
+  static AlignedMemory<8, 8> raw8;
+  static AlignedMemory<8, 16> raw16;
+  static AlignedMemory<8, 256> raw256;
+  static AlignedMemory<8, 4096> raw4096;
+
+  EXPECT_EQ(8u, ALIGNOF(raw8));
+  EXPECT_EQ(16u, ALIGNOF(raw16));
+  EXPECT_EQ(256u, ALIGNOF(raw256));
+  EXPECT_EQ(4096u, ALIGNOF(raw4096));
+
+  EXPECT_ALIGNED(raw8.void_data(), 8);
+  EXPECT_ALIGNED(raw16.void_data(), 16);
+  EXPECT_ALIGNED(raw256.void_data(), 256);
+  EXPECT_ALIGNED(raw4096.void_data(), 4096);
+}
+
+TEST(AlignedMemoryTest, StackAlignment) {
+  AlignedMemory<8, 8> raw8;
+  AlignedMemory<8, 16> raw16;
+  AlignedMemory<8, 128> raw128;
+
+  EXPECT_EQ(8u, ALIGNOF(raw8));
+  EXPECT_EQ(16u, ALIGNOF(raw16));
+  EXPECT_EQ(128u, ALIGNOF(raw128));
+
+  EXPECT_ALIGNED(raw8.void_data(), 8);
+  EXPECT_ALIGNED(raw16.void_data(), 16);
+
+  // TODO(ios): __attribute__((aligned(X))) with X >= 128 does not works on
+  // the stack when building for arm64 on iOS, http://crbug.com/349003
+#if !(defined(OS_IOS) && defined(ARCH_CPU_ARM64))
+  EXPECT_ALIGNED(raw128.void_data(), 128);
+
+  // NaCl x86-64 compiler emits non-validating instructions for >128
+  // bytes alignment.
+  // http://www.chromium.org/nativeclient/design-documents/nacl-sfi-model-on-x86-64-systems
+  // TODO(hamaji): Ideally, NaCl compiler for x86-64 should workaround
+  // this limitation and this #if should be removed.
+  // https://code.google.com/p/nativeclient/issues/detail?id=3463
+#if !(defined(OS_NACL) && defined(ARCH_CPU_X86_64))
+  AlignedMemory<8, 256> raw256;
+  EXPECT_EQ(256u, ALIGNOF(raw256));
+  EXPECT_ALIGNED(raw256.void_data(), 256);
+
+  // TODO(ios): This test hits an armv7 bug in clang. crbug.com/138066
+#if !(defined(OS_IOS) && defined(ARCH_CPU_ARM_FAMILY))
+  AlignedMemory<8, 4096> raw4096;
+  EXPECT_EQ(4096u, ALIGNOF(raw4096));
+  EXPECT_ALIGNED(raw4096.void_data(), 4096);
+#endif  // !(defined(OS_IOS) && defined(ARCH_CPU_ARM_FAMILY))
+#endif  // !(defined(OS_NACL) && defined(ARCH_CPU_X86_64))
+#endif  // !(defined(OS_IOS) && defined(ARCH_CPU_ARM64))
+}
+
+TEST(AlignedMemoryTest, DynamicAllocation) {
+  void* p = base::AlignedAlloc(8, 8);
+  EXPECT_TRUE(p);
+  EXPECT_ALIGNED(p, 8);
+  base::AlignedFree(p);
+
+  p = base::AlignedAlloc(8, 16);
+  EXPECT_TRUE(p);
+  EXPECT_ALIGNED(p, 16);
+  base::AlignedFree(p);
+
+  p = base::AlignedAlloc(8, 256);
+  EXPECT_TRUE(p);
+  EXPECT_ALIGNED(p, 256);
+  base::AlignedFree(p);
+
+  p = base::AlignedAlloc(8, 4096);
+  EXPECT_TRUE(p);
+  EXPECT_ALIGNED(p, 4096);
+  base::AlignedFree(p);
+}
+
+TEST(AlignedMemoryTest, ScopedDynamicAllocation) {
+  scoped_ptr<float, base::AlignedFreeDeleter> p(
+      static_cast<float*>(base::AlignedAlloc(8, 8)));
+  EXPECT_TRUE(p.get());
+  EXPECT_ALIGNED(p.get(), 8);
+}
+
+}  // namespace
diff --git a/base/memory/discardable_memory.cc b/base/memory/discardable_memory.cc
new file mode 100644
index 0000000..d50f185
--- /dev/null
+++ b/base/memory/discardable_memory.cc
@@ -0,0 +1,15 @@
+// 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.
+
+#include "base/memory/discardable_memory.h"
+
+namespace base {
+
+DiscardableMemory::DiscardableMemory() {
+}
+
+DiscardableMemory::~DiscardableMemory() {
+}
+
+}  // namespace base
diff --git a/base/memory/discardable_memory.h b/base/memory/discardable_memory.h
new file mode 100644
index 0000000..fc189e7
--- /dev/null
+++ b/base/memory/discardable_memory.h
@@ -0,0 +1,66 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_DISCARDABLE_MEMORY_H_
+#define BASE_MEMORY_DISCARDABLE_MEMORY_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+
+namespace base {
+
+// Discardable memory is used to cache large objects without worrying about
+// blowing out memory, both on mobile devices where there is no swap, and
+// desktop devices where unused free memory should be used to help the user
+// experience. This is preferable to releasing memory in response to an OOM
+// signal because it is simpler and provides system-wide management of
+// purgable memory, though it has less flexibility as to which objects get
+// discarded.
+//
+// Discardable memory has two states: locked and unlocked. While the memory is
+// locked, it will not be discarded. Unlocking the memory allows the
+// discardable memory system and the OS to reclaim it if needed. Locks do not
+// nest.
+//
+// Notes:
+//   - The paging behavior of memory while it is locked is not specified. While
+//     mobile platforms will not swap it out, it may qualify for swapping
+//     on desktop platforms. It is not expected that this will matter, as the
+//     preferred pattern of usage for DiscardableMemory is to lock down the
+//     memory, use it as quickly as possible, and then unlock it.
+//   - Because of memory alignment, the amount of memory allocated can be
+//     larger than the requested memory size. It is not very efficient for
+//     small allocations.
+//   - A discardable memory instance is not thread safe. It is the
+//     responsibility of users of discardable memory to ensure there are no
+//     races.
+//
+class BASE_EXPORT DiscardableMemory {
+ public:
+  DiscardableMemory();
+  virtual ~DiscardableMemory();
+
+  // Locks the memory so that it will not be purged by the system. Returns
+  // true on success. If the return value is false then this object should be
+  // discarded and a new one should be created.
+  virtual bool Lock() WARN_UNUSED_RESULT = 0;
+
+  // Unlocks the memory so that it can be purged by the system. Must be called
+  // after every successful lock call.
+  virtual void Unlock() = 0;
+
+  // Returns the memory address held by this object. The object must be locked
+  // before calling this.
+  virtual void* data() const = 0;
+
+  // Handy method to simplify calling data() with a reinterpret_cast.
+  template<typename T> T* data_as() const {
+    return reinterpret_cast<T*>(data());
+  }
+};
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_DISCARDABLE_MEMORY_H_
diff --git a/base/memory/discardable_memory_allocator.cc b/base/memory/discardable_memory_allocator.cc
new file mode 100644
index 0000000..002a3ba
--- /dev/null
+++ b/base/memory/discardable_memory_allocator.cc
@@ -0,0 +1,34 @@
+// 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/memory/discardable_memory_allocator.h"
+
+#include "base/logging.h"
+
+namespace base {
+namespace {
+
+DiscardableMemoryAllocator* g_allocator = nullptr;
+
+}  // namespace
+
+// static
+void DiscardableMemoryAllocator::SetInstance(
+    DiscardableMemoryAllocator* allocator) {
+  DCHECK(allocator);
+
+  // Make sure this function is only called once before the first call
+  // to GetInstance().
+  DCHECK(!g_allocator);
+
+  g_allocator = allocator;
+}
+
+// static
+DiscardableMemoryAllocator* DiscardableMemoryAllocator::GetInstance() {
+  DCHECK(g_allocator);
+  return g_allocator;
+}
+
+}  // namespace base
diff --git a/base/memory/discardable_memory_allocator.h b/base/memory/discardable_memory_allocator.h
new file mode 100644
index 0000000..400f87a
--- /dev/null
+++ b/base/memory/discardable_memory_allocator.h
@@ -0,0 +1,32 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_DISCARDABLE_MEMORY_ALLOCATOR_H_
+#define BASE_MEMORY_DISCARDABLE_MEMORY_ALLOCATOR_H_
+
+#include "base/base_export.h"
+#include "base/memory/scoped_ptr.h"
+
+namespace base {
+class DiscardableMemory;
+
+class BASE_EXPORT DiscardableMemoryAllocator {
+ public:
+  // Returns the allocator instance.
+  static DiscardableMemoryAllocator* GetInstance();
+
+  // Sets the allocator instance. Can only be called once, e.g. on startup.
+  // Ownership of |instance| remains with the caller.
+  static void SetInstance(DiscardableMemoryAllocator* allocator);
+
+  virtual scoped_ptr<DiscardableMemory> AllocateLockedDiscardableMemory(
+      size_t size) = 0;
+
+ protected:
+  virtual ~DiscardableMemoryAllocator() {}
+};
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_DISCARDABLE_MEMORY_ALLOCATOR_H_
diff --git a/base/memory/discardable_shared_memory.cc b/base/memory/discardable_shared_memory.cc
new file mode 100644
index 0000000..4fd1518
--- /dev/null
+++ b/base/memory/discardable_shared_memory.cc
@@ -0,0 +1,376 @@
+// 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.
+
+#include "base/memory/discardable_shared_memory.h"
+
+#if defined(OS_POSIX)
+#include <unistd.h>
+#endif
+
+#include <algorithm>
+
+#include "base/atomicops.h"
+#include "base/logging.h"
+#include "base/numerics/safe_math.h"
+#include "base/process/process_metrics.h"
+
+#if defined(OS_ANDROID)
+#include "third_party/ashmem/ashmem.h"
+#endif
+
+namespace base {
+namespace {
+
+// Use a machine-sized pointer as atomic type. It will use the Atomic32 or
+// Atomic64 routines, depending on the architecture.
+typedef intptr_t AtomicType;
+typedef uintptr_t UAtomicType;
+
+// Template specialization for timestamp serialization/deserialization. This
+// is used to serialize timestamps using Unix time on systems where AtomicType
+// does not have enough precision to contain a timestamp in the standard
+// serialized format.
+template <int>
+Time TimeFromWireFormat(int64 value);
+template <int>
+int64 TimeToWireFormat(Time time);
+
+// Serialize to Unix time when using 4-byte wire format.
+// Note: 19 January 2038, this will cease to work.
+template <>
+Time ALLOW_UNUSED_TYPE TimeFromWireFormat<4>(int64 value) {
+  return value ? Time::UnixEpoch() + TimeDelta::FromSeconds(value) : Time();
+}
+template <>
+int64 ALLOW_UNUSED_TYPE TimeToWireFormat<4>(Time time) {
+  return time > Time::UnixEpoch() ? (time - Time::UnixEpoch()).InSeconds() : 0;
+}
+
+// Standard serialization format when using 8-byte wire format.
+template <>
+Time ALLOW_UNUSED_TYPE TimeFromWireFormat<8>(int64 value) {
+  return Time::FromInternalValue(value);
+}
+template <>
+int64 ALLOW_UNUSED_TYPE TimeToWireFormat<8>(Time time) {
+  return time.ToInternalValue();
+}
+
+struct SharedState {
+  enum LockState { UNLOCKED = 0, LOCKED = 1 };
+
+  explicit SharedState(AtomicType ivalue) { value.i = ivalue; }
+  SharedState(LockState lock_state, Time timestamp) {
+    int64 wire_timestamp = TimeToWireFormat<sizeof(AtomicType)>(timestamp);
+    DCHECK_GE(wire_timestamp, 0);
+    DCHECK_EQ(lock_state & ~1, 0);
+    value.u = (static_cast<UAtomicType>(wire_timestamp) << 1) | lock_state;
+  }
+
+  LockState GetLockState() const { return static_cast<LockState>(value.u & 1); }
+
+  Time GetTimestamp() const {
+    return TimeFromWireFormat<sizeof(AtomicType)>(value.u >> 1);
+  }
+
+  // Bit 1: Lock state. Bit is set when locked.
+  // Bit 2..sizeof(AtomicType)*8: Usage timestamp. NULL time when locked or
+  // purged.
+  union {
+    AtomicType i;
+    UAtomicType u;
+  } value;
+};
+
+// Shared state is stored at offset 0 in shared memory segments.
+SharedState* SharedStateFromSharedMemory(const SharedMemory& shared_memory) {
+  DCHECK(shared_memory.memory());
+  return static_cast<SharedState*>(shared_memory.memory());
+}
+
+// Round up |size| to a multiple of alignment, which must be a power of two.
+size_t Align(size_t alignment, size_t size) {
+  DCHECK_EQ(alignment & (alignment - 1), 0u);
+  return (size + alignment - 1) & ~(alignment - 1);
+}
+
+// Round up |size| to a multiple of page size.
+size_t AlignToPageSize(size_t size) {
+  return Align(base::GetPageSize(), size);
+}
+
+}  // namespace
+
+DiscardableSharedMemory::DiscardableSharedMemory()
+    : mapped_size_(0), locked_page_count_(0) {
+}
+
+DiscardableSharedMemory::DiscardableSharedMemory(
+    SharedMemoryHandle shared_memory_handle)
+    : shared_memory_(shared_memory_handle, false),
+      mapped_size_(0),
+      locked_page_count_(0) {
+}
+
+DiscardableSharedMemory::~DiscardableSharedMemory() {
+}
+
+bool DiscardableSharedMemory::CreateAndMap(size_t size) {
+  CheckedNumeric<size_t> checked_size = size;
+  checked_size += AlignToPageSize(sizeof(SharedState));
+  if (!checked_size.IsValid())
+    return false;
+
+  if (!shared_memory_.CreateAndMapAnonymous(checked_size.ValueOrDie()))
+    return false;
+
+  mapped_size_ =
+      shared_memory_.mapped_size() - AlignToPageSize(sizeof(SharedState));
+
+  locked_page_count_ = AlignToPageSize(mapped_size_) / base::GetPageSize();
+#if DCHECK_IS_ON()
+  for (size_t page = 0; page < locked_page_count_; ++page)
+    locked_pages_.insert(page);
+#endif
+
+  DCHECK(last_known_usage_.is_null());
+  SharedState new_state(SharedState::LOCKED, Time());
+  subtle::Release_Store(&SharedStateFromSharedMemory(shared_memory_)->value.i,
+                        new_state.value.i);
+  return true;
+}
+
+bool DiscardableSharedMemory::Map(size_t size) {
+  if (!shared_memory_.Map(AlignToPageSize(sizeof(SharedState)) + size))
+    return false;
+
+  mapped_size_ =
+      shared_memory_.mapped_size() - AlignToPageSize(sizeof(SharedState));
+
+  locked_page_count_ = AlignToPageSize(mapped_size_) / base::GetPageSize();
+#if DCHECK_IS_ON()
+  for (size_t page = 0; page < locked_page_count_; ++page)
+    locked_pages_.insert(page);
+#endif
+
+  return true;
+}
+
+bool DiscardableSharedMemory::Unmap() {
+  if (!shared_memory_.Unmap())
+    return false;
+
+  mapped_size_ = 0;
+  return true;
+}
+
+DiscardableSharedMemory::LockResult DiscardableSharedMemory::Lock(
+    size_t offset, size_t length) {
+  DCHECK_EQ(AlignToPageSize(offset), offset);
+  DCHECK_EQ(AlignToPageSize(length), length);
+
+  // Calls to this function must be synchronized properly.
+  DFAKE_SCOPED_LOCK(thread_collision_warner_);
+
+  DCHECK(shared_memory_.memory());
+
+  // We need to successfully acquire the platform independent lock before
+  // individual pages can be locked.
+  if (!locked_page_count_) {
+    // Return false when instance has been purged or not initialized properly
+    // by checking if |last_known_usage_| is NULL.
+    if (last_known_usage_.is_null())
+      return FAILED;
+
+    SharedState old_state(SharedState::UNLOCKED, last_known_usage_);
+    SharedState new_state(SharedState::LOCKED, Time());
+    SharedState result(subtle::Acquire_CompareAndSwap(
+        &SharedStateFromSharedMemory(shared_memory_)->value.i,
+        old_state.value.i,
+        new_state.value.i));
+    if (result.value.u != old_state.value.u) {
+      // Update |last_known_usage_| in case the above CAS failed because of
+      // an incorrect timestamp.
+      last_known_usage_ = result.GetTimestamp();
+      return FAILED;
+    }
+  }
+
+  // Zero for length means "everything onward".
+  if (!length)
+    length = AlignToPageSize(mapped_size_) - offset;
+
+  size_t start = offset / base::GetPageSize();
+  size_t end = start + length / base::GetPageSize();
+  DCHECK_LT(start, end);
+  DCHECK_LE(end, AlignToPageSize(mapped_size_) / base::GetPageSize());
+
+  // Add pages to |locked_page_count_|.
+  // Note: Locking a page that is already locked is an error.
+  locked_page_count_ += end - start;
+#if DCHECK_IS_ON()
+  // Detect incorrect usage by keeping track of exactly what pages are locked.
+  for (auto page = start; page < end; ++page) {
+    auto result = locked_pages_.insert(page);
+    DCHECK(result.second);
+  }
+  DCHECK_EQ(locked_pages_.size(), locked_page_count_);
+#endif
+
+#if defined(OS_ANDROID)
+  SharedMemoryHandle handle = shared_memory_.handle();
+  if (SharedMemory::IsHandleValid(handle)) {
+    if (ashmem_pin_region(
+            handle.fd, AlignToPageSize(sizeof(SharedState)) + offset, length)) {
+      return PURGED;
+    }
+  }
+#endif
+
+  return SUCCESS;
+}
+
+void DiscardableSharedMemory::Unlock(size_t offset, size_t length) {
+  DCHECK_EQ(AlignToPageSize(offset), offset);
+  DCHECK_EQ(AlignToPageSize(length), length);
+
+  // Calls to this function must be synchronized properly.
+  DFAKE_SCOPED_LOCK(thread_collision_warner_);
+
+  // Zero for length means "everything onward".
+  if (!length)
+    length = AlignToPageSize(mapped_size_) - offset;
+
+  DCHECK(shared_memory_.memory());
+
+#if defined(OS_ANDROID)
+  SharedMemoryHandle handle = shared_memory_.handle();
+  if (SharedMemory::IsHandleValid(handle)) {
+    if (ashmem_unpin_region(
+            handle.fd, AlignToPageSize(sizeof(SharedState)) + offset, length)) {
+      DPLOG(ERROR) << "ashmem_unpin_region() failed";
+    }
+  }
+#endif
+
+  size_t start = offset / base::GetPageSize();
+  size_t end = start + length / base::GetPageSize();
+  DCHECK_LT(start, end);
+  DCHECK_LE(end, AlignToPageSize(mapped_size_) / base::GetPageSize());
+
+  // Remove pages from |locked_page_count_|.
+  // Note: Unlocking a page that is not locked is an error.
+  DCHECK_GE(locked_page_count_, end - start);
+  locked_page_count_ -= end - start;
+#if DCHECK_IS_ON()
+  // Detect incorrect usage by keeping track of exactly what pages are locked.
+  for (auto page = start; page < end; ++page) {
+    auto erased_count = locked_pages_.erase(page);
+    DCHECK_EQ(1u, erased_count);
+  }
+  DCHECK_EQ(locked_pages_.size(), locked_page_count_);
+#endif
+
+  // Early out and avoid releasing the platform independent lock if some pages
+  // are still locked.
+  if (locked_page_count_)
+    return;
+
+  Time current_time = Now();
+  DCHECK(!current_time.is_null());
+
+  SharedState old_state(SharedState::LOCKED, Time());
+  SharedState new_state(SharedState::UNLOCKED, current_time);
+  // Note: timestamp cannot be NULL as that is a unique value used when
+  // locked or purged.
+  DCHECK(!new_state.GetTimestamp().is_null());
+  // Timestamp precision should at least be accurate to the second.
+  DCHECK_EQ((new_state.GetTimestamp() - Time::UnixEpoch()).InSeconds(),
+            (current_time - Time::UnixEpoch()).InSeconds());
+  SharedState result(subtle::Release_CompareAndSwap(
+      &SharedStateFromSharedMemory(shared_memory_)->value.i,
+      old_state.value.i,
+      new_state.value.i));
+
+  DCHECK_EQ(old_state.value.u, result.value.u);
+
+  last_known_usage_ = current_time;
+}
+
+void* DiscardableSharedMemory::memory() const {
+  return reinterpret_cast<uint8*>(shared_memory_.memory()) +
+         AlignToPageSize(sizeof(SharedState));
+}
+
+bool DiscardableSharedMemory::Purge(Time current_time) {
+  // Calls to this function must be synchronized properly.
+  DFAKE_SCOPED_LOCK(thread_collision_warner_);
+
+  // Early out if not mapped. This can happen if the segment was previously
+  // unmapped using a call to Close().
+  if (!shared_memory_.memory())
+    return true;
+
+  SharedState old_state(SharedState::UNLOCKED, last_known_usage_);
+  SharedState new_state(SharedState::UNLOCKED, Time());
+  SharedState result(subtle::Acquire_CompareAndSwap(
+      &SharedStateFromSharedMemory(shared_memory_)->value.i,
+      old_state.value.i,
+      new_state.value.i));
+
+  // Update |last_known_usage_| to |current_time| if the memory is locked. This
+  // allows the caller to determine if purging failed because last known usage
+  // was incorrect or memory was locked. In the second case, the caller should
+  // most likely wait for some amount of time before attempting to purge the
+  // the memory again.
+  if (result.value.u != old_state.value.u) {
+    last_known_usage_ = result.GetLockState() == SharedState::LOCKED
+                            ? current_time
+                            : result.GetTimestamp();
+    return false;
+  }
+
+  last_known_usage_ = Time();
+  return true;
+}
+
+bool DiscardableSharedMemory::IsMemoryResident() const {
+  DCHECK(shared_memory_.memory());
+
+  SharedState result(subtle::NoBarrier_Load(
+      &SharedStateFromSharedMemory(shared_memory_)->value.i));
+
+  return result.GetLockState() == SharedState::LOCKED ||
+         !result.GetTimestamp().is_null();
+}
+
+void DiscardableSharedMemory::Close() {
+  shared_memory_.Close();
+}
+
+#if defined(DISCARDABLE_SHARED_MEMORY_SHRINKING)
+void DiscardableSharedMemory::Shrink() {
+#if defined(OS_POSIX)
+  SharedMemoryHandle handle = shared_memory_.handle();
+  if (!SharedMemory::IsHandleValid(handle))
+    return;
+
+  // Truncate shared memory to size of SharedState.
+  if (HANDLE_EINTR(ftruncate(SharedMemory::GetFdFromSharedMemoryHandle(handle),
+                             AlignToPageSize(sizeof(SharedState)))) != 0) {
+    DPLOG(ERROR) << "ftruncate() failed";
+    return;
+  }
+  mapped_size_ = 0;
+#else
+  NOTIMPLEMENTED();
+#endif
+}
+#endif
+
+Time DiscardableSharedMemory::Now() const {
+  return Time::Now();
+}
+
+}  // namespace base
diff --git a/base/memory/discardable_shared_memory.h b/base/memory/discardable_shared_memory.h
new file mode 100644
index 0000000..74bbe8e
--- /dev/null
+++ b/base/memory/discardable_shared_memory.h
@@ -0,0 +1,150 @@
+// 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.
+
+#ifndef BASE_MEMORY_DISCARDABLE_SHARED_MEMORY_H_
+#define BASE_MEMORY_DISCARDABLE_SHARED_MEMORY_H_
+
+#include "base/base_export.h"
+#include "base/logging.h"
+#include "base/memory/shared_memory.h"
+#include "base/threading/thread_collision_warner.h"
+#include "base/time/time.h"
+
+#if DCHECK_IS_ON()
+#include <set>
+#endif
+
+// Define DISCARDABLE_SHARED_MEMORY_SHRINKING if platform supports shrinking
+// of discardable shared memory segments.
+#if defined(OS_POSIX) && !defined(OS_ANDROID)
+#define DISCARDABLE_SHARED_MEMORY_SHRINKING
+#endif
+
+namespace base {
+
+// Platform abstraction for discardable shared memory.
+//
+// This class is not thread-safe. Clients are responsible for synchronizing
+// access to an instance of this class.
+class BASE_EXPORT DiscardableSharedMemory {
+ public:
+  enum LockResult { SUCCESS, PURGED, FAILED };
+
+  DiscardableSharedMemory();
+
+  // Create a new DiscardableSharedMemory object from an existing, open shared
+  // memory file. Memory must be locked.
+  explicit DiscardableSharedMemory(SharedMemoryHandle handle);
+
+  // Closes any open files.
+  virtual ~DiscardableSharedMemory();
+
+  // Creates and maps a locked DiscardableSharedMemory object with |size|.
+  // Returns true on success and false on failure.
+  bool CreateAndMap(size_t size);
+
+  // Maps the locked discardable memory into the caller's address space.
+  // Returns true on success, false otherwise.
+  bool Map(size_t size);
+
+  // Unmaps the discardable shared memory from the caller's address space.
+  // Returns true if successful; returns false on error or if the memory is
+  // not mapped.
+  bool Unmap();
+
+  // The actual size of the mapped memory (may be larger than requested).
+  size_t mapped_size() const { return mapped_size_; }
+
+  // Returns a shared memory handle for this DiscardableSharedMemory object.
+  SharedMemoryHandle handle() const { return shared_memory_.handle(); }
+
+  // Locks a range of memory so that it will not be purged by the system.
+  // The range of memory must be unlocked. The result of trying to lock an
+  // already locked range is undefined. |offset| and |length| must both be
+  // a multiple of the page size as returned by GetPageSize().
+  // Passing 0 for |length| means "everything onward".
+  // Returns SUCCESS if range was successfully locked and the memory is still
+  // resident, PURGED if range was successfully locked but has been purged
+  // since last time it was locked and FAILED if range could not be locked.
+  // Locking can fail for two reasons; object might have been purged, our
+  // last known usage timestamp might be out of date. Last known usage time
+  // is updated to the actual last usage timestamp if memory is still resident
+  // or 0 if not.
+  LockResult Lock(size_t offset, size_t length);
+
+  // Unlock a previously successfully locked range of memory. The range of
+  // memory must be locked. The result of trying to unlock a not
+  // previously locked range is undefined.
+  // |offset| and |length| must both be a multiple of the page size as returned
+  // by GetPageSize().
+  // Passing 0 for |length| means "everything onward".
+  void Unlock(size_t offset, size_t length);
+
+  // Gets a pointer to the opened discardable memory space. Discardable memory
+  // must have been mapped via Map().
+  void* memory() const;
+
+  // Returns the last known usage time for DiscardableSharedMemory object. This
+  // may be earlier than the "true" usage time when memory has been used by a
+  // different process. Returns NULL time if purged.
+  Time last_known_usage() const { return last_known_usage_; }
+
+  // This returns true and sets |last_known_usage_| to 0 if
+  // DiscardableSharedMemory object was successfully purged. Purging can fail
+  // for two reasons; object might be locked or our last known usage timestamp
+  // might be out of date. Last known usage time is updated to |current_time|
+  // if locked or the actual last usage timestamp if unlocked. It is often
+  // necessary to call this function twice for the object to successfully be
+  // purged. First call, updates |last_known_usage_|. Second call, successfully
+  // purges the object using the updated |last_known_usage_|.
+  // Note: there is no guarantee that multiple calls to this function will
+  // successfully purge object. DiscardableSharedMemory object might be locked
+  // or another thread/process might be able to lock and unlock it in between
+  // each call.
+  bool Purge(Time current_time);
+
+  // Returns true if memory is still resident.
+  bool IsMemoryResident() const;
+
+  // Closes the open discardable memory segment.
+  // It is safe to call Close repeatedly.
+  void Close();
+
+  // Shares the discardable memory segment to another process. Attempts to
+  // create a platform-specific |new_handle| which can be used in a remote
+  // process to access the discardable memory segment. |new_handle| is an
+  // output parameter to receive the handle for use in the remote process.
+  // Returns true on success, false otherwise.
+  bool ShareToProcess(ProcessHandle process_handle,
+                      SharedMemoryHandle* new_handle) {
+    return shared_memory_.ShareToProcess(process_handle, new_handle);
+  }
+
+#if defined(DISCARDABLE_SHARED_MEMORY_SHRINKING)
+  // Release as much memory as possible to the OS. The change in size will
+  // be reflected by the return value of mapped_size().
+  void Shrink();
+#endif
+
+ private:
+  // Virtual for tests.
+  virtual Time Now() const;
+
+  SharedMemory shared_memory_;
+  size_t mapped_size_;
+  size_t locked_page_count_;
+#if DCHECK_IS_ON()
+  std::set<size_t> locked_pages_;
+#endif
+  // Implementation is not thread-safe but still usable if clients are
+  // synchronized somehow. Use a collision warner to detect incorrect usage.
+  DFAKE_MUTEX(thread_collision_warner_);
+  Time last_known_usage_;
+
+  DISALLOW_COPY_AND_ASSIGN(DiscardableSharedMemory);
+};
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_DISCARDABLE_SHARED_MEMORY_H_
diff --git a/base/memory/discardable_shared_memory_unittest.cc b/base/memory/discardable_shared_memory_unittest.cc
new file mode 100644
index 0000000..91b0b68
--- /dev/null
+++ b/base/memory/discardable_shared_memory_unittest.cc
@@ -0,0 +1,354 @@
+// 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.
+
+#include "base/basictypes.h"
+#include "base/memory/discardable_shared_memory.h"
+#include "base/process/process_metrics.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+class TestDiscardableSharedMemory : public DiscardableSharedMemory {
+ public:
+  TestDiscardableSharedMemory() {}
+
+  explicit TestDiscardableSharedMemory(SharedMemoryHandle handle)
+      : DiscardableSharedMemory(handle) {}
+
+  void SetNow(Time now) { now_ = now; }
+
+ private:
+  // Overriden from DiscardableSharedMemory:
+  Time Now() const override { return now_; }
+
+  Time now_;
+};
+
+TEST(DiscardableSharedMemoryTest, CreateAndMap) {
+  const uint32 kDataSize = 1024;
+
+  TestDiscardableSharedMemory memory;
+  bool rv = memory.CreateAndMap(kDataSize);
+  ASSERT_TRUE(rv);
+  EXPECT_GE(memory.mapped_size(), kDataSize);
+}
+
+TEST(DiscardableSharedMemoryTest, CreateFromHandle) {
+  const uint32 kDataSize = 1024;
+
+  TestDiscardableSharedMemory memory1;
+  bool rv = memory1.CreateAndMap(kDataSize);
+  ASSERT_TRUE(rv);
+
+  SharedMemoryHandle shared_handle;
+  ASSERT_TRUE(
+      memory1.ShareToProcess(GetCurrentProcessHandle(), &shared_handle));
+  ASSERT_TRUE(SharedMemory::IsHandleValid(shared_handle));
+
+  TestDiscardableSharedMemory memory2(shared_handle);
+  rv = memory2.Map(kDataSize);
+  ASSERT_TRUE(rv);
+}
+
+TEST(DiscardableSharedMemoryTest, LockAndUnlock) {
+  const uint32 kDataSize = 1024;
+
+  TestDiscardableSharedMemory memory1;
+  bool rv = memory1.CreateAndMap(kDataSize);
+  ASSERT_TRUE(rv);
+
+  // Memory is initially locked. Unlock it.
+  memory1.SetNow(Time::FromDoubleT(1));
+  memory1.Unlock(0, 0);
+
+  // Lock and unlock memory.
+  auto lock_rv = memory1.Lock(0, 0);
+  EXPECT_EQ(DiscardableSharedMemory::SUCCESS, lock_rv);
+  memory1.SetNow(Time::FromDoubleT(2));
+  memory1.Unlock(0, 0);
+
+  // Lock again before duplicating and passing ownership to new instance.
+  lock_rv = memory1.Lock(0, 0);
+  EXPECT_EQ(DiscardableSharedMemory::SUCCESS, lock_rv);
+
+  SharedMemoryHandle shared_handle;
+  ASSERT_TRUE(
+      memory1.ShareToProcess(GetCurrentProcessHandle(), &shared_handle));
+  ASSERT_TRUE(SharedMemory::IsHandleValid(shared_handle));
+
+  TestDiscardableSharedMemory memory2(shared_handle);
+  rv = memory2.Map(kDataSize);
+  ASSERT_TRUE(rv);
+
+  // Unlock second instance.
+  memory2.SetNow(Time::FromDoubleT(3));
+  memory2.Unlock(0, 0);
+
+  // Lock second instance before passing ownership back to first instance.
+  lock_rv = memory2.Lock(0, 0);
+  EXPECT_EQ(DiscardableSharedMemory::SUCCESS, lock_rv);
+
+  // Memory should still be resident.
+  rv = memory1.IsMemoryResident();
+  EXPECT_TRUE(rv);
+
+  // Unlock first instance.
+  memory1.SetNow(Time::FromDoubleT(4));
+  memory1.Unlock(0, 0);
+}
+
+TEST(DiscardableSharedMemoryTest, Purge) {
+  const uint32 kDataSize = 1024;
+
+  TestDiscardableSharedMemory memory1;
+  bool rv = memory1.CreateAndMap(kDataSize);
+  ASSERT_TRUE(rv);
+
+  SharedMemoryHandle shared_handle;
+  ASSERT_TRUE(
+      memory1.ShareToProcess(GetCurrentProcessHandle(), &shared_handle));
+  ASSERT_TRUE(SharedMemory::IsHandleValid(shared_handle));
+
+  TestDiscardableSharedMemory memory2(shared_handle);
+  rv = memory2.Map(kDataSize);
+  ASSERT_TRUE(rv);
+
+  // This should fail as memory is locked.
+  rv = memory1.Purge(Time::FromDoubleT(1));
+  EXPECT_FALSE(rv);
+
+  memory2.SetNow(Time::FromDoubleT(2));
+  memory2.Unlock(0, 0);
+
+  ASSERT_TRUE(memory2.IsMemoryResident());
+
+  // Memory is unlocked, but our usage timestamp is incorrect.
+  rv = memory1.Purge(Time::FromDoubleT(3));
+  EXPECT_FALSE(rv);
+
+  ASSERT_TRUE(memory2.IsMemoryResident());
+
+  // Memory is unlocked and our usage timestamp should be correct.
+  rv = memory1.Purge(Time::FromDoubleT(4));
+  EXPECT_TRUE(rv);
+
+  // Lock should fail as memory has been purged.
+  auto lock_rv = memory2.Lock(0, 0);
+  EXPECT_EQ(DiscardableSharedMemory::FAILED, lock_rv);
+
+  ASSERT_FALSE(memory2.IsMemoryResident());
+}
+
+TEST(DiscardableSharedMemoryTest, LastUsed) {
+  const uint32 kDataSize = 1024;
+
+  TestDiscardableSharedMemory memory1;
+  bool rv = memory1.CreateAndMap(kDataSize);
+  ASSERT_TRUE(rv);
+
+  SharedMemoryHandle shared_handle;
+  ASSERT_TRUE(
+      memory1.ShareToProcess(GetCurrentProcessHandle(), &shared_handle));
+  ASSERT_TRUE(SharedMemory::IsHandleValid(shared_handle));
+
+  TestDiscardableSharedMemory memory2(shared_handle);
+  rv = memory2.Map(kDataSize);
+  ASSERT_TRUE(rv);
+
+  memory2.SetNow(Time::FromDoubleT(1));
+  memory2.Unlock(0, 0);
+
+  EXPECT_EQ(memory2.last_known_usage(), Time::FromDoubleT(1));
+
+  auto lock_rv = memory2.Lock(0, 0);
+  EXPECT_EQ(DiscardableSharedMemory::SUCCESS, lock_rv);
+
+  // This should fail as memory is locked.
+  rv = memory1.Purge(Time::FromDoubleT(2));
+  ASSERT_FALSE(rv);
+
+  // Last usage should have been updated to timestamp passed to Purge above.
+  EXPECT_EQ(memory1.last_known_usage(), Time::FromDoubleT(2));
+
+  memory2.SetNow(Time::FromDoubleT(3));
+  memory2.Unlock(0, 0);
+
+  // Usage time should be correct for |memory2| instance.
+  EXPECT_EQ(memory2.last_known_usage(), Time::FromDoubleT(3));
+
+  // However, usage time has not changed as far as |memory1| instance knows.
+  EXPECT_EQ(memory1.last_known_usage(), Time::FromDoubleT(2));
+
+  // Memory is unlocked, but our usage timestamp is incorrect.
+  rv = memory1.Purge(Time::FromDoubleT(4));
+  EXPECT_FALSE(rv);
+
+  // The failed purge attempt should have updated usage time to the correct
+  // value.
+  EXPECT_EQ(memory1.last_known_usage(), Time::FromDoubleT(3));
+
+  // Purge memory through |memory2| instance. The last usage time should be
+  // set to 0 as a result of this.
+  rv = memory2.Purge(Time::FromDoubleT(5));
+  EXPECT_TRUE(rv);
+  EXPECT_TRUE(memory2.last_known_usage().is_null());
+
+  // This should fail as memory has already been purged and |memory1|'s usage
+  // time is incorrect as a result.
+  rv = memory1.Purge(Time::FromDoubleT(6));
+  EXPECT_FALSE(rv);
+
+  // The failed purge attempt should have updated usage time to the correct
+  // value.
+  EXPECT_TRUE(memory1.last_known_usage().is_null());
+
+  // Purge should succeed now that usage time is correct.
+  rv = memory1.Purge(Time::FromDoubleT(7));
+  EXPECT_TRUE(rv);
+}
+
+TEST(DiscardableSharedMemoryTest, LockShouldAlwaysFailAfterSuccessfulPurge) {
+  const uint32 kDataSize = 1024;
+
+  TestDiscardableSharedMemory memory1;
+  bool rv = memory1.CreateAndMap(kDataSize);
+  ASSERT_TRUE(rv);
+
+  SharedMemoryHandle shared_handle;
+  ASSERT_TRUE(
+      memory1.ShareToProcess(GetCurrentProcessHandle(), &shared_handle));
+  ASSERT_TRUE(SharedMemory::IsHandleValid(shared_handle));
+
+  TestDiscardableSharedMemory memory2(shared_handle);
+  rv = memory2.Map(kDataSize);
+  ASSERT_TRUE(rv);
+
+  memory2.SetNow(Time::FromDoubleT(1));
+  memory2.Unlock(0, 0);
+
+  rv = memory2.Purge(Time::FromDoubleT(2));
+  EXPECT_TRUE(rv);
+
+  // Lock should fail as memory has been purged.
+  auto lock_rv = memory2.Lock(0, 0);
+  EXPECT_EQ(DiscardableSharedMemory::FAILED, lock_rv);
+}
+
+TEST(DiscardableSharedMemoryTest, LockAndUnlockRange) {
+  const uint32 kDataSize = 32;
+
+  uint32 data_size_in_bytes = kDataSize * base::GetPageSize();
+
+  TestDiscardableSharedMemory memory1;
+  bool rv = memory1.CreateAndMap(data_size_in_bytes);
+  ASSERT_TRUE(rv);
+
+  SharedMemoryHandle shared_handle;
+  ASSERT_TRUE(
+      memory1.ShareToProcess(GetCurrentProcessHandle(), &shared_handle));
+  ASSERT_TRUE(SharedMemory::IsHandleValid(shared_handle));
+
+  TestDiscardableSharedMemory memory2(shared_handle);
+  rv = memory2.Map(data_size_in_bytes);
+  ASSERT_TRUE(rv);
+
+  // Unlock first page.
+  memory2.SetNow(Time::FromDoubleT(1));
+  memory2.Unlock(0, base::GetPageSize());
+
+  rv = memory1.Purge(Time::FromDoubleT(2));
+  EXPECT_FALSE(rv);
+
+  // Lock first page again.
+  memory2.SetNow(Time::FromDoubleT(3));
+  auto lock_rv = memory2.Lock(0, base::GetPageSize());
+  EXPECT_NE(DiscardableSharedMemory::FAILED, lock_rv);
+
+  // Unlock first page.
+  memory2.SetNow(Time::FromDoubleT(4));
+  memory2.Unlock(0, base::GetPageSize());
+
+  rv = memory1.Purge(Time::FromDoubleT(5));
+  EXPECT_FALSE(rv);
+
+  // Unlock second page.
+  memory2.SetNow(Time::FromDoubleT(6));
+  memory2.Unlock(base::GetPageSize(), base::GetPageSize());
+
+  rv = memory1.Purge(Time::FromDoubleT(7));
+  EXPECT_FALSE(rv);
+
+  // Unlock anything onwards.
+  memory2.SetNow(Time::FromDoubleT(8));
+  memory2.Unlock(2 * base::GetPageSize(), 0);
+
+  // Memory is unlocked, but our usage timestamp is incorrect.
+  rv = memory1.Purge(Time::FromDoubleT(9));
+  EXPECT_FALSE(rv);
+
+  // The failed purge attempt should have updated usage time to the correct
+  // value.
+  EXPECT_EQ(Time::FromDoubleT(8), memory1.last_known_usage());
+
+  // Purge should now succeed.
+  rv = memory1.Purge(Time::FromDoubleT(10));
+  EXPECT_TRUE(rv);
+}
+
+TEST(DiscardableSharedMemoryTest, MappedSize) {
+  const uint32 kDataSize = 1024;
+
+  TestDiscardableSharedMemory memory;
+  bool rv = memory.CreateAndMap(kDataSize);
+  ASSERT_TRUE(rv);
+
+  EXPECT_LE(kDataSize, memory.mapped_size());
+
+  // Mapped size should be 0 after memory segment has been unmapped.
+  rv = memory.Unmap();
+  EXPECT_TRUE(rv);
+  EXPECT_EQ(0u, memory.mapped_size());
+}
+
+TEST(DiscardableSharedMemoryTest, Close) {
+  const uint32 kDataSize = 1024;
+
+  TestDiscardableSharedMemory memory;
+  bool rv = memory.CreateAndMap(kDataSize);
+  ASSERT_TRUE(rv);
+
+  // Mapped size should be unchanged after memory segment has been closed.
+  memory.Close();
+  EXPECT_LE(kDataSize, memory.mapped_size());
+
+  // Memory is initially locked. Unlock it.
+  memory.SetNow(Time::FromDoubleT(1));
+  memory.Unlock(0, 0);
+
+  // Lock and unlock memory.
+  auto lock_rv = memory.Lock(0, 0);
+  EXPECT_EQ(DiscardableSharedMemory::SUCCESS, lock_rv);
+  memory.SetNow(Time::FromDoubleT(2));
+  memory.Unlock(0, 0);
+}
+
+#if defined(DISCARDABLE_SHARED_MEMORY_SHRINKING)
+TEST(DiscardableSharedMemoryTest, Shrink) {
+  const uint32 kDataSize = 1024;
+
+  TestDiscardableSharedMemory memory;
+  bool rv = memory.CreateAndMap(kDataSize);
+  ASSERT_TRUE(rv);
+
+  EXPECT_NE(0u, memory.mapped_size());
+
+  // Mapped size should be 0 after shrinking memory segment.
+  memory.Shrink();
+  EXPECT_EQ(0u, memory.mapped_size());
+}
+#endif
+
+}  // namespace
+}  // namespace base
diff --git a/base/memory/linked_ptr.h b/base/memory/linked_ptr.h
new file mode 100644
index 0000000..80044ad
--- /dev/null
+++ b/base/memory/linked_ptr.h
@@ -0,0 +1,181 @@
+// Copyright (c) 2011 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.
+//
+// A "smart" pointer type with reference tracking.  Every pointer to a
+// particular object is kept on a circular linked list.  When the last pointer
+// to an object is destroyed or reassigned, the object is deleted.
+//
+// Used properly, this deletes the object when the last reference goes away.
+// There are several caveats:
+// - Like all reference counting schemes, cycles lead to leaks.
+// - Each smart pointer is actually two pointers (8 bytes instead of 4).
+// - Every time a pointer is released, the entire list of pointers to that
+//   object is traversed.  This class is therefore NOT SUITABLE when there
+//   will often be more than two or three pointers to a particular object.
+// - References are only tracked as long as linked_ptr<> objects are copied.
+//   If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS
+//   will happen (double deletion).
+//
+// A good use of this class is storing object references in STL containers.
+// You can safely put linked_ptr<> in a vector<>.
+// Other uses may not be as good.
+//
+// Note: If you use an incomplete type with linked_ptr<>, the class
+// *containing* linked_ptr<> must have a constructor and destructor (even
+// if they do nothing!).
+//
+// Thread Safety:
+//   A linked_ptr is NOT thread safe. Copying a linked_ptr object is
+//   effectively a read-write operation.
+//
+// Alternative: to linked_ptr is shared_ptr, which
+//  - is also two pointers in size (8 bytes for 32 bit addresses)
+//  - is thread safe for copying and deletion
+//  - supports weak_ptrs
+
+#ifndef BASE_MEMORY_LINKED_PTR_H_
+#define BASE_MEMORY_LINKED_PTR_H_
+
+#include "base/logging.h"  // for CHECK macros
+
+// This is used internally by all instances of linked_ptr<>.  It needs to be
+// a non-template class because different types of linked_ptr<> can refer to
+// the same object (linked_ptr<Superclass>(obj) vs linked_ptr<Subclass>(obj)).
+// So, it needs to be possible for different types of linked_ptr to participate
+// in the same circular linked list, so we need a single class type here.
+//
+// DO NOT USE THIS CLASS DIRECTLY YOURSELF.  Use linked_ptr<T>.
+class linked_ptr_internal {
+ public:
+  // Create a new circle that includes only this instance.
+  void join_new() {
+    next_ = this;
+  }
+
+  // Join an existing circle.
+  void join(linked_ptr_internal const* ptr) {
+    next_ = ptr->next_;
+    ptr->next_ = this;
+  }
+
+  // Leave whatever circle we're part of.  Returns true iff we were the
+  // last member of the circle.  Once this is done, you can join() another.
+  bool depart() {
+    if (next_ == this) return true;
+    linked_ptr_internal const* p = next_;
+    while (p->next_ != this) p = p->next_;
+    p->next_ = next_;
+    return false;
+  }
+
+ private:
+  mutable linked_ptr_internal const* next_;
+};
+
+template <typename T>
+class linked_ptr {
+ public:
+  typedef T element_type;
+
+  // Take over ownership of a raw pointer.  This should happen as soon as
+  // possible after the object is created.
+  explicit linked_ptr(T* ptr = NULL) { capture(ptr); }
+  ~linked_ptr() { depart(); }
+
+  // Copy an existing linked_ptr<>, adding ourselves to the list of references.
+  template <typename U> linked_ptr(linked_ptr<U> const& ptr) { copy(&ptr); }
+
+  linked_ptr(linked_ptr const& ptr) {
+    DCHECK_NE(&ptr, this);
+    copy(&ptr);
+  }
+
+  // Assignment releases the old value and acquires the new.
+  template <typename U> linked_ptr& operator=(linked_ptr<U> const& ptr) {
+    depart();
+    copy(&ptr);
+    return *this;
+  }
+
+  linked_ptr& operator=(linked_ptr const& ptr) {
+    if (&ptr != this) {
+      depart();
+      copy(&ptr);
+    }
+    return *this;
+  }
+
+  // Smart pointer members.
+  void reset(T* ptr = NULL) {
+    depart();
+    capture(ptr);
+  }
+  T* get() const { return value_; }
+  T* operator->() const { return value_; }
+  T& operator*() const { return *value_; }
+  // Release ownership of the pointed object and returns it.
+  // Sole ownership by this linked_ptr object is required.
+  T* release() {
+    bool last = link_.depart();
+    CHECK(last);
+    T* v = value_;
+    value_ = NULL;
+    return v;
+  }
+
+  bool operator==(const T* p) const { return value_ == p; }
+  bool operator!=(const T* p) const { return value_ != p; }
+  template <typename U>
+  bool operator==(linked_ptr<U> const& ptr) const {
+    return value_ == ptr.get();
+  }
+  template <typename U>
+  bool operator!=(linked_ptr<U> const& ptr) const {
+    return value_ != ptr.get();
+  }
+
+ private:
+  template <typename U>
+  friend class linked_ptr;
+
+  T* value_;
+  linked_ptr_internal link_;
+
+  void depart() {
+    if (link_.depart()) delete value_;
+  }
+
+  void capture(T* ptr) {
+    value_ = ptr;
+    link_.join_new();
+  }
+
+  template <typename U> void copy(linked_ptr<U> const* ptr) {
+    value_ = ptr->get();
+    if (value_)
+      link_.join(&ptr->link_);
+    else
+      link_.join_new();
+  }
+};
+
+template<typename T> inline
+bool operator==(T* ptr, const linked_ptr<T>& x) {
+  return ptr == x.get();
+}
+
+template<typename T> inline
+bool operator!=(T* ptr, const linked_ptr<T>& x) {
+  return ptr != x.get();
+}
+
+// A function to convert T* into linked_ptr<T>
+// Doing e.g. make_linked_ptr(new FooBarBaz<type>(arg)) is a shorter notation
+// for linked_ptr<FooBarBaz<type> >(new FooBarBaz<type>(arg))
+template <typename T>
+linked_ptr<T> make_linked_ptr(T* ptr) {
+  return linked_ptr<T>(ptr);
+}
+
+#endif  // BASE_MEMORY_LINKED_PTR_H_
diff --git a/base/memory/linked_ptr_unittest.cc b/base/memory/linked_ptr_unittest.cc
new file mode 100644
index 0000000..f6bc410
--- /dev/null
+++ b/base/memory/linked_ptr_unittest.cc
@@ -0,0 +1,108 @@
+// Copyright (c) 2012 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 <string>
+
+#include "base/memory/linked_ptr.h"
+#include "base/strings/stringprintf.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+int num = 0;
+
+std::string history;
+
+// Class which tracks allocation/deallocation
+struct A {
+  A(): mynum(num++) { history += base::StringPrintf("A%d ctor\n", mynum); }
+  virtual ~A() { history += base::StringPrintf("A%d dtor\n", mynum); }
+  virtual void Use() { history += base::StringPrintf("A%d use\n", mynum); }
+  int mynum;
+};
+
+// Subclass
+struct B: public A {
+  B() { history += base::StringPrintf("B%d ctor\n", mynum); }
+  ~B() override { history += base::StringPrintf("B%d dtor\n", mynum); }
+  void Use() override { history += base::StringPrintf("B%d use\n", mynum); }
+};
+
+}  // namespace
+
+TEST(LinkedPtrTest, Test) {
+  {
+    linked_ptr<A> a0, a1, a2;
+    a0 = a0;
+    a1 = a2;
+    ASSERT_EQ(a0.get(), static_cast<A*>(NULL));
+    ASSERT_EQ(a1.get(), static_cast<A*>(NULL));
+    ASSERT_EQ(a2.get(), static_cast<A*>(NULL));
+    ASSERT_TRUE(a0 == NULL);
+    ASSERT_TRUE(a1 == NULL);
+    ASSERT_TRUE(a2 == NULL);
+
+    {
+      linked_ptr<A> a3(new A);
+      a0 = a3;
+      ASSERT_TRUE(a0 == a3);
+      ASSERT_TRUE(a0 != NULL);
+      ASSERT_TRUE(a0.get() == a3);
+      ASSERT_TRUE(a0 == a3.get());
+      linked_ptr<A> a4(a0);
+      a1 = a4;
+      linked_ptr<A> a5(new A);
+      ASSERT_TRUE(a5.get() != a3);
+      ASSERT_TRUE(a5 != a3.get());
+      a2 = a5;
+      linked_ptr<B> b0(new B);
+      linked_ptr<A> a6(b0);
+      ASSERT_TRUE(b0 == a6);
+      ASSERT_TRUE(a6 == b0);
+      ASSERT_TRUE(b0 != NULL);
+      a5 = b0;
+      a5 = b0;
+      a3->Use();
+      a4->Use();
+      a5->Use();
+      a6->Use();
+      b0->Use();
+      (*b0).Use();
+      b0.get()->Use();
+    }
+
+    a0->Use();
+    a1->Use();
+    a2->Use();
+
+    a1 = a2;
+    a2.reset(new A);
+    a0.reset();
+
+    linked_ptr<A> a7;
+  }
+
+  ASSERT_EQ(history,
+    "A0 ctor\n"
+    "A1 ctor\n"
+    "A2 ctor\n"
+    "B2 ctor\n"
+    "A0 use\n"
+    "A0 use\n"
+    "B2 use\n"
+    "B2 use\n"
+    "B2 use\n"
+    "B2 use\n"
+    "B2 use\n"
+    "B2 dtor\n"
+    "A2 dtor\n"
+    "A0 use\n"
+    "A0 use\n"
+    "A1 use\n"
+    "A3 ctor\n"
+    "A0 dtor\n"
+    "A3 dtor\n"
+    "A1 dtor\n"
+  );
+}
diff --git a/base/memory/manual_constructor.h b/base/memory/manual_constructor.h
new file mode 100644
index 0000000..56081a1
--- /dev/null
+++ b/base/memory/manual_constructor.h
@@ -0,0 +1,71 @@
+// Copyright (c) 2012 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.
+
+// ManualConstructor statically-allocates space in which to store some
+// object, but does not initialize it.  You can then call the constructor
+// and destructor for the object yourself as you see fit.  This is useful
+// for memory management optimizations, where you want to initialize and
+// destroy an object multiple times but only allocate it once.
+//
+// (When I say ManualConstructor statically allocates space, I mean that
+// the ManualConstructor object itself is forced to be the right size.)
+//
+// For example usage, check out base/containers/small_map.h.
+
+#ifndef BASE_MEMORY_MANUAL_CONSTRUCTOR_H_
+#define BASE_MEMORY_MANUAL_CONSTRUCTOR_H_
+
+#include <stddef.h>
+
+#include "base/compiler_specific.h"
+#include "base/memory/aligned_memory.h"
+
+namespace base {
+
+template <typename Type>
+class ManualConstructor {
+ public:
+  // No constructor or destructor because one of the most useful uses of
+  // this class is as part of a union, and members of a union cannot have
+  // constructors or destructors.  And, anyway, the whole point of this
+  // class is to bypass these.
+
+  // Support users creating arrays of ManualConstructor<>s.  This ensures that
+  // the array itself has the correct alignment.
+  static void* operator new[](size_t size) {
+    return AlignedAlloc(size, ALIGNOF(Type));
+  }
+  static void operator delete[](void* mem) {
+    AlignedFree(mem);
+  }
+
+  inline Type* get() {
+    return space_.template data_as<Type>();
+  }
+  inline const Type* get() const  {
+    return space_.template data_as<Type>();
+  }
+
+  inline Type* operator->() { return get(); }
+  inline const Type* operator->() const { return get(); }
+
+  inline Type& operator*() { return *get(); }
+  inline const Type& operator*() const { return *get(); }
+
+  template <typename... Ts>
+  inline void Init(const Ts&... params) {
+    new(space_.void_data()) Type(params...);
+  }
+
+  inline void Destroy() {
+    get()->~Type();
+  }
+
+ private:
+  AlignedMemory<sizeof(Type), ALIGNOF(Type)> space_;
+};
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_MANUAL_CONSTRUCTOR_H_
diff --git a/base/memory/memory_pressure_listener.cc b/base/memory/memory_pressure_listener.cc
new file mode 100644
index 0000000..2a1be74
--- /dev/null
+++ b/base/memory/memory_pressure_listener.cc
@@ -0,0 +1,61 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/memory_pressure_listener.h"
+
+#include "base/lazy_instance.h"
+#include "base/observer_list_threadsafe.h"
+#include "base/trace_event/trace_event.h"
+
+namespace base {
+
+namespace {
+
+// ObserverListThreadSafe is RefCountedThreadSafe, this traits is needed
+// to ensure the LazyInstance will hold a reference to it.
+struct LeakyLazyObserverListTraits :
+    base::internal::LeakyLazyInstanceTraits<
+        ObserverListThreadSafe<MemoryPressureListener> > {
+  static ObserverListThreadSafe<MemoryPressureListener>*
+      New(void* instance) {
+    ObserverListThreadSafe<MemoryPressureListener>* ret =
+        base::internal::LeakyLazyInstanceTraits<
+            ObserverListThreadSafe<MemoryPressureListener>>::New(instance);
+    // Leaky.
+    ret->AddRef();
+    return ret;
+  }
+};
+
+LazyInstance<
+    ObserverListThreadSafe<MemoryPressureListener>,
+    LeakyLazyObserverListTraits> g_observers = LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+MemoryPressureListener::MemoryPressureListener(
+    const MemoryPressureListener::MemoryPressureCallback& callback)
+    : callback_(callback) {
+  g_observers.Get().AddObserver(this);
+}
+
+MemoryPressureListener::~MemoryPressureListener() {
+  g_observers.Get().RemoveObserver(this);
+}
+
+void MemoryPressureListener::Notify(MemoryPressureLevel memory_pressure_level) {
+  callback_.Run(memory_pressure_level);
+}
+
+// static
+void MemoryPressureListener::NotifyMemoryPressure(
+    MemoryPressureLevel memory_pressure_level) {
+  DCHECK_NE(memory_pressure_level, MEMORY_PRESSURE_LEVEL_NONE);
+  TRACE_EVENT1("memory", "MemoryPressureListener::NotifyMemoryPressure",
+      "level", memory_pressure_level);
+  g_observers.Get().Notify(FROM_HERE, &MemoryPressureListener::Notify,
+                           memory_pressure_level);
+}
+
+}  // namespace base
diff --git a/base/memory/memory_pressure_listener.h b/base/memory/memory_pressure_listener.h
new file mode 100644
index 0000000..6adaeee
--- /dev/null
+++ b/base/memory/memory_pressure_listener.h
@@ -0,0 +1,85 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// MemoryPressure provides static APIs for handling memory pressure on
+// platforms that have such signals, such as Android and ChromeOS.
+// The app will try to discard buffers that aren't deemed essential (individual
+// modules will implement their own policy).
+
+#ifndef BASE_MEMORY_MEMORY_PRESSURE_LISTENER_H_
+#define BASE_MEMORY_MEMORY_PRESSURE_LISTENER_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/callback.h"
+
+namespace base {
+
+// To start listening, create a new instance, passing a callback to a
+// function that takes a MemoryPressureLevel parameter. To stop listening,
+// simply delete the listener object. The implementation guarantees
+// that the callback will always be called on the thread that created
+// the listener.
+// Note that even on the same thread, the callback is not guaranteed to be
+// called synchronously within the system memory pressure broadcast.
+// Please see notes in MemoryPressureLevel enum below: some levels are
+// absolutely critical, and if not enough memory is returned to the system,
+// it'll potentially kill the app, and then later the app will have to be
+// cold-started.
+//
+// Example:
+//
+//    void OnMemoryPressure(MemoryPressureLevel memory_pressure_level) {
+//       ...
+//    }
+//
+//    // Start listening.
+//    MemoryPressureListener* my_listener =
+//        new MemoryPressureListener(base::Bind(&OnMemoryPressure));
+//
+//    ...
+//
+//    // Stop listening.
+//    delete my_listener;
+//
+class BASE_EXPORT MemoryPressureListener {
+ public:
+  // A Java counterpart will be generated for this enum.
+  // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.base
+  enum MemoryPressureLevel {
+    // No problems, there is enough memory to use. This event is not sent via
+    // callback, but the enum is used in other places to find out the current
+    // state of the system.
+    MEMORY_PRESSURE_LEVEL_NONE = -1,
+
+    // Modules are advised to free buffers that are cheap to re-allocate and not
+    // immediately needed.
+    MEMORY_PRESSURE_LEVEL_MODERATE = 0,
+
+    // At this level, modules are advised to free all possible memory.  The
+    // alternative is to be killed by the system, which means all memory will
+    // have to be re-created, plus the cost of a cold start.
+    MEMORY_PRESSURE_LEVEL_CRITICAL = 2,
+  };
+
+  typedef base::Callback<void(MemoryPressureLevel)> MemoryPressureCallback;
+
+  explicit MemoryPressureListener(
+      const MemoryPressureCallback& memory_pressure_callback);
+  ~MemoryPressureListener();
+
+  // Intended for use by the platform specific implementation.
+  static void NotifyMemoryPressure(MemoryPressureLevel memory_pressure_level);
+
+ private:
+  void Notify(MemoryPressureLevel memory_pressure_level);
+
+  MemoryPressureCallback callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(MemoryPressureListener);
+};
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_MEMORY_PRESSURE_LISTENER_H_
diff --git a/base/memory/memory_pressure_monitor.cc b/base/memory/memory_pressure_monitor.cc
new file mode 100644
index 0000000..00633f1
--- /dev/null
+++ b/base/memory/memory_pressure_monitor.cc
@@ -0,0 +1,31 @@
+// 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/memory/memory_pressure_monitor.h"
+
+#include "base/logging.h"
+
+namespace base {
+namespace {
+
+MemoryPressureMonitor* g_monitor = nullptr;
+
+}  // namespace
+
+MemoryPressureMonitor::MemoryPressureMonitor() {
+  DCHECK(!g_monitor);
+  g_monitor = this;
+}
+
+MemoryPressureMonitor::~MemoryPressureMonitor() {
+  DCHECK(g_monitor);
+  g_monitor = nullptr;
+}
+
+// static
+MemoryPressureMonitor* MemoryPressureMonitor::Get() {
+  return g_monitor;
+}
+
+}  // namespace base
diff --git a/base/memory/memory_pressure_monitor.h b/base/memory/memory_pressure_monitor.h
new file mode 100644
index 0000000..90c9420
--- /dev/null
+++ b/base/memory/memory_pressure_monitor.h
@@ -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.
+
+#ifndef BASE_MEMORY_MEMORY_PRESSURE_MONITOR_H_
+#define BASE_MEMORY_MEMORY_PRESSURE_MONITOR_H_
+
+#include "base/base_export.h"
+#include "base/memory/memory_pressure_listener.h"
+
+namespace base {
+
+// TODO(chrisha): Make this a concrete class with per-OS implementations rather
+// than an abstract base class.
+
+// Declares the interface for a MemoryPressureMonitor. There are multiple
+// OS specific implementations of this class. An instance of the memory
+// pressure observer is created at the process level, tracks memory usage, and
+// pushes memory state change notifications to the static function
+// base::MemoryPressureListener::NotifyMemoryPressure. This is turn notifies
+// all MemoryPressureListener instances via a callback.
+class BASE_EXPORT MemoryPressureMonitor {
+ public:
+  using MemoryPressureLevel = base::MemoryPressureListener::MemoryPressureLevel;
+
+  virtual ~MemoryPressureMonitor();
+
+  // Return the singleton MemoryPressureMonitor.
+  static MemoryPressureMonitor* Get();
+
+  // Returns the currently observed memory pressure.
+  virtual MemoryPressureLevel GetCurrentPressureLevel() const = 0;
+
+ protected:
+  MemoryPressureMonitor();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MemoryPressureMonitor);
+};
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_MEMORY_PRESSURE_MONITOR_H_
diff --git a/base/memory/memory_pressure_monitor_chromeos.cc b/base/memory/memory_pressure_monitor_chromeos.cc
new file mode 100644
index 0000000..640e463
--- /dev/null
+++ b/base/memory/memory_pressure_monitor_chromeos.cc
@@ -0,0 +1,272 @@
+// 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.
+
+#include "base/memory/memory_pressure_monitor_chromeos.h"
+
+#include <fcntl.h>
+#include <sys/select.h>
+
+#include "base/metrics/histogram_macros.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/process/process_metrics.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/time/time.h"
+
+namespace base {
+namespace chromeos {
+
+namespace {
+
+// The time between memory pressure checks. While under critical pressure, this
+// is also the timer to repeat cleanup attempts.
+const int kMemoryPressureIntervalMs = 1000;
+
+// The time which should pass between two moderate memory pressure calls.
+const int kModerateMemoryPressureCooldownMs = 10000;
+
+// Number of event polls before the next moderate pressure event can be sent.
+const int kModerateMemoryPressureCooldown =
+    kModerateMemoryPressureCooldownMs / kMemoryPressureIntervalMs;
+
+// Threshold constants to emit pressure events.
+const int kNormalMemoryPressureModerateThresholdPercent = 60;
+const int kNormalMemoryPressureCriticalThresholdPercent = 95;
+const int kAggressiveMemoryPressureModerateThresholdPercent = 35;
+const int kAggressiveMemoryPressureCriticalThresholdPercent = 70;
+
+// The possible state for memory pressure level. The values should be in line
+// with values in MemoryPressureListener::MemoryPressureLevel and should be
+// updated if more memory pressure levels are introduced.
+enum MemoryPressureLevelUMA {
+  MEMORY_PRESSURE_LEVEL_NONE = 0,
+  MEMORY_PRESSURE_LEVEL_MODERATE,
+  MEMORY_PRESSURE_LEVEL_CRITICAL,
+  NUM_MEMORY_PRESSURE_LEVELS
+};
+
+// This is the file that will exist if low memory notification is available
+// on the device.  Whenever it becomes readable, it signals a low memory
+// condition.
+const char kLowMemFile[] = "/dev/chromeos-low-mem";
+
+// Converts a |MemoryPressureThreshold| value into a used memory percentage for
+// the moderate pressure event.
+int GetModerateMemoryThresholdInPercent(
+    MemoryPressureMonitor::MemoryPressureThresholds thresholds) {
+  return thresholds == MemoryPressureMonitor::
+                           THRESHOLD_AGGRESSIVE_CACHE_DISCARD ||
+         thresholds == MemoryPressureMonitor::THRESHOLD_AGGRESSIVE
+             ? kAggressiveMemoryPressureModerateThresholdPercent
+             : kNormalMemoryPressureModerateThresholdPercent;
+}
+
+// Converts a |MemoryPressureThreshold| value into a used memory percentage for
+// the critical pressure event.
+int GetCriticalMemoryThresholdInPercent(
+    MemoryPressureMonitor::MemoryPressureThresholds thresholds) {
+  return thresholds == MemoryPressureMonitor::
+                           THRESHOLD_AGGRESSIVE_TAB_DISCARD ||
+         thresholds == MemoryPressureMonitor::THRESHOLD_AGGRESSIVE
+             ? kAggressiveMemoryPressureCriticalThresholdPercent
+             : kNormalMemoryPressureCriticalThresholdPercent;
+}
+
+// Converts free percent of memory into a memory pressure value.
+MemoryPressureListener::MemoryPressureLevel GetMemoryPressureLevelFromFillLevel(
+    int actual_fill_level,
+    int moderate_threshold,
+    int critical_threshold) {
+  if (actual_fill_level < moderate_threshold)
+    return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
+  return actual_fill_level < critical_threshold
+             ? MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE
+             : MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL;
+}
+
+// This function will be called less then once a second. It will check if
+// the kernel has detected a low memory situation.
+bool IsLowMemoryCondition(int file_descriptor) {
+  fd_set fds;
+  struct timeval tv;
+
+  FD_ZERO(&fds);
+  FD_SET(file_descriptor, &fds);
+
+  tv.tv_sec = 0;
+  tv.tv_usec = 0;
+
+  return HANDLE_EINTR(select(file_descriptor + 1, &fds, NULL, NULL, &tv)) > 0;
+}
+
+}  // namespace
+
+MemoryPressureMonitor::MemoryPressureMonitor(
+    MemoryPressureThresholds thresholds)
+    : current_memory_pressure_level_(
+          MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE),
+      moderate_pressure_repeat_count_(0),
+      moderate_pressure_threshold_percent_(
+          GetModerateMemoryThresholdInPercent(thresholds)),
+      critical_pressure_threshold_percent_(
+          GetCriticalMemoryThresholdInPercent(thresholds)),
+      low_mem_file_(HANDLE_EINTR(::open(kLowMemFile, O_RDONLY))),
+      weak_ptr_factory_(this) {
+  StartObserving();
+  LOG_IF(ERROR, !low_mem_file_.is_valid()) << "Cannot open kernel listener";
+}
+
+MemoryPressureMonitor::~MemoryPressureMonitor() {
+  StopObserving();
+}
+
+void MemoryPressureMonitor::ScheduleEarlyCheck() {
+  ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, Bind(&MemoryPressureMonitor::CheckMemoryPressure,
+                      weak_ptr_factory_.GetWeakPtr()));
+}
+
+MemoryPressureListener::MemoryPressureLevel
+MemoryPressureMonitor::GetCurrentPressureLevel() const {
+  return current_memory_pressure_level_;
+}
+
+// static
+MemoryPressureMonitor* MemoryPressureMonitor::Get() {
+  return static_cast<MemoryPressureMonitor*>(
+      base::MemoryPressureMonitor::Get());
+}
+
+void MemoryPressureMonitor::StartObserving() {
+  timer_.Start(FROM_HERE,
+               TimeDelta::FromMilliseconds(kMemoryPressureIntervalMs),
+               Bind(&MemoryPressureMonitor::
+                        CheckMemoryPressureAndRecordStatistics,
+                    weak_ptr_factory_.GetWeakPtr()));
+}
+
+void MemoryPressureMonitor::StopObserving() {
+  // If StartObserving failed, StopObserving will still get called.
+  timer_.Stop();
+}
+
+void MemoryPressureMonitor::CheckMemoryPressureAndRecordStatistics() {
+  CheckMemoryPressure();
+
+  // Record UMA histogram statistics for the current memory pressure level.
+  MemoryPressureLevelUMA memory_pressure_level_uma(MEMORY_PRESSURE_LEVEL_NONE);
+  switch (current_memory_pressure_level_) {
+    case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
+      memory_pressure_level_uma = MEMORY_PRESSURE_LEVEL_NONE;
+      break;
+    case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
+      memory_pressure_level_uma = MEMORY_PRESSURE_LEVEL_MODERATE;
+      break;
+    case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
+      memory_pressure_level_uma = MEMORY_PRESSURE_LEVEL_CRITICAL;
+      break;
+  }
+
+  UMA_HISTOGRAM_ENUMERATION("ChromeOS.MemoryPressureLevel",
+                            memory_pressure_level_uma,
+                            NUM_MEMORY_PRESSURE_LEVELS);
+}
+
+void MemoryPressureMonitor::CheckMemoryPressure() {
+  MemoryPressureListener::MemoryPressureLevel old_pressure =
+      current_memory_pressure_level_;
+
+  // If we have the kernel low memory observer, we use it's flag instead of our
+  // own computation (for now). Note that in "simulation mode" it can be null.
+  // TODO(skuhne): We need to add code which makes sure that the kernel and this
+  // computation come to similar results and then remove this override again.
+  // TODO(skuhne): Add some testing framework here to see how close the kernel
+  // and the internal functions are.
+  if (low_mem_file_.is_valid() && IsLowMemoryCondition(low_mem_file_.get())) {
+    current_memory_pressure_level_ =
+        MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL;
+  } else {
+    current_memory_pressure_level_ = GetMemoryPressureLevelFromFillLevel(
+        GetUsedMemoryInPercent(),
+        moderate_pressure_threshold_percent_,
+        critical_pressure_threshold_percent_);
+
+    // When listening to the kernel, we ignore the reported memory pressure
+    // level from our own computation and reduce critical to moderate.
+    if (low_mem_file_.is_valid() &&
+        current_memory_pressure_level_ ==
+        MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) {
+      current_memory_pressure_level_ =
+          MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE;
+    }
+  }
+
+  // In case there is no memory pressure we do not notify.
+  if (current_memory_pressure_level_ ==
+      MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE) {
+    return;
+  }
+  if (old_pressure == current_memory_pressure_level_) {
+    // If the memory pressure is still at the same level, we notify again for a
+    // critical level. In case of a moderate level repeat however, we only send
+    // a notification after a certain time has passed.
+    if (current_memory_pressure_level_ ==
+        MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE &&
+          ++moderate_pressure_repeat_count_ <
+              kModerateMemoryPressureCooldown) {
+      return;
+    }
+  } else if (current_memory_pressure_level_ ==
+               MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE &&
+             old_pressure ==
+               MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) {
+    // When we reducing the pressure level from critical to moderate, we
+    // restart the timeout and do not send another notification.
+    moderate_pressure_repeat_count_ = 0;
+    return;
+  }
+  moderate_pressure_repeat_count_ = 0;
+  MemoryPressureListener::NotifyMemoryPressure(current_memory_pressure_level_);
+}
+
+// Gets the used ChromeOS memory in percent.
+int MemoryPressureMonitor::GetUsedMemoryInPercent() {
+  base::SystemMemoryInfoKB info;
+  if (!base::GetSystemMemoryInfo(&info)) {
+    VLOG(1) << "Cannot determine the free memory of the system.";
+    return 0;
+  }
+  // TODO(skuhne): Instead of adding the kernel memory pressure calculation
+  // logic here, we should have a kernel mechanism similar to the low memory
+  // notifier in ChromeOS which offers multiple pressure states.
+  // To track this, we have crbug.com/381196.
+
+  // The available memory consists of "real" and virtual (z)ram memory.
+  // Since swappable memory uses a non pre-deterministic compression and
+  // the compression creates its own "dynamic" in the system, it gets
+  // de-emphasized by the |kSwapWeight| factor.
+  const int kSwapWeight = 4;
+
+  // The total memory we have is the "real memory" plus the virtual (z)ram.
+  int total_memory = info.total + info.swap_total / kSwapWeight;
+
+  // The kernel internally uses 50MB.
+  const int kMinFileMemory = 50 * 1024;
+
+  // Most file memory can be easily reclaimed.
+  int file_memory = info.active_file + info.inactive_file;
+  // unless it is dirty or it's a minimal portion which is required.
+  file_memory -= info.dirty + kMinFileMemory;
+
+  // Available memory is the sum of free, swap and easy reclaimable memory.
+  int available_memory =
+      info.free + info.swap_free / kSwapWeight + file_memory;
+
+  DCHECK(available_memory < total_memory);
+  int percentage = ((total_memory - available_memory) * 100) / total_memory;
+  return percentage;
+}
+
+}  // namespace chromeos
+}  // namespace base
diff --git a/base/memory/memory_pressure_monitor_chromeos.h b/base/memory/memory_pressure_monitor_chromeos.h
new file mode 100644
index 0000000..ff8992a
--- /dev/null
+++ b/base/memory/memory_pressure_monitor_chromeos.h
@@ -0,0 +1,119 @@
+// 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.
+
+#ifndef BASE_MEMORY_MEMORY_PRESSURE_MONITOR_CHROMEOS_H_
+#define BASE_MEMORY_MEMORY_PRESSURE_MONITOR_CHROMEOS_H_
+
+#include "base/base_export.h"
+#include "base/files/scoped_file.h"
+#include "base/gtest_prod_util.h"
+#include "base/macros.h"
+#include "base/memory/memory_pressure_listener.h"
+#include "base/memory/memory_pressure_monitor.h"
+#include "base/memory/weak_ptr.h"
+#include "base/timer/timer.h"
+
+namespace base {
+namespace chromeos {
+
+class TestMemoryPressureMonitor;
+
+////////////////////////////////////////////////////////////////////////////////
+// MemoryPressureMonitor
+//
+// A class to handle the observation of our free memory. It notifies the
+// MemoryPressureListener of memory fill level changes, so that it can take
+// action to reduce memory resources accordingly.
+//
+class BASE_EXPORT MemoryPressureMonitor : public base::MemoryPressureMonitor {
+ public:
+  using GetUsedMemoryInPercentCallback = int (*)();
+
+  // There are two memory pressure events:
+  // MODERATE - which will mainly release caches.
+  // CRITICAL - which will discard tabs.
+  // The |MemoryPressureThresholds| enum selects the strategy of firing these
+  // events: A conservative strategy will keep as much content in memory as
+  // possible (causing the system to swap to zram) and an aggressive strategy
+  // will release memory earlier to avoid swapping.
+  enum MemoryPressureThresholds {
+    // Use the system default.
+    THRESHOLD_DEFAULT = 0,
+    // Try to keep as much content in memory as possible.
+    THRESHOLD_CONSERVATIVE = 1,
+    // Discard caches earlier, allowing to keep more tabs in memory.
+    THRESHOLD_AGGRESSIVE_CACHE_DISCARD = 2,
+    // Discard tabs earlier, allowing the system to get faster.
+    THRESHOLD_AGGRESSIVE_TAB_DISCARD = 3,
+    // Discard caches and tabs earlier to allow the system to be faster.
+    THRESHOLD_AGGRESSIVE = 4
+  };
+
+  explicit MemoryPressureMonitor(MemoryPressureThresholds thresholds);
+  ~MemoryPressureMonitor() override;
+
+  // Redo the memory pressure calculation soon and call again if a critical
+  // memory pressure prevails. Note that this call will trigger an asynchronous
+  // action which gives the system time to release memory back into the pool.
+  void ScheduleEarlyCheck();
+
+  // Get the current memory pressure level.
+  MemoryPressureListener::MemoryPressureLevel GetCurrentPressureLevel() const
+      override;
+
+  // Returns a type-casted version of the current memory pressure monitor. A
+  // simple wrapper to base::MemoryPressureMonitor::Get.
+  static MemoryPressureMonitor* Get();
+
+ private:
+  friend TestMemoryPressureMonitor;
+  // Starts observing the memory fill level.
+  // Calls to StartObserving should always be matched with calls to
+  // StopObserving.
+  void StartObserving();
+
+  // Stop observing the memory fill level.
+  // May be safely called if StartObserving has not been called.
+  void StopObserving();
+
+  // The function which gets periodically called to check any changes in the
+  // memory pressure. It will report pressure changes as well as continuous
+  // critical pressure levels.
+  void CheckMemoryPressure();
+
+  // The function periodically checks the memory pressure changes and records
+  // the UMA histogram statistics for the current memory pressure level.
+  void CheckMemoryPressureAndRecordStatistics();
+
+  // Get the memory pressure in percent (virtual for testing).
+  virtual int GetUsedMemoryInPercent();
+
+  // The current memory pressure.
+  base::MemoryPressureListener::MemoryPressureLevel
+      current_memory_pressure_level_;
+
+  // A periodic timer to check for resource pressure changes. This will get
+  // replaced by a kernel triggered event system (see crbug.com/381196).
+  base::RepeatingTimer<MemoryPressureMonitor> timer_;
+
+  // To slow down the amount of moderate pressure event calls, this counter
+  // gets used to count the number of events since the last event occured.
+  int moderate_pressure_repeat_count_;
+
+  // The thresholds for moderate and critical pressure.
+  const int moderate_pressure_threshold_percent_;
+  const int critical_pressure_threshold_percent_;
+
+  // File descriptor used to detect low memory condition.
+  ScopedFD low_mem_file_;
+
+  base::WeakPtrFactory<MemoryPressureMonitor> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(MemoryPressureMonitor);
+};
+
+}  // namespace chromeos
+}  // namespace base
+
+#endif  // BASE_MEMORY_MEMORY_PRESSURE_MONITOR_CHROMEOS_H_
diff --git a/base/memory/memory_pressure_monitor_chromeos_unittest.cc b/base/memory/memory_pressure_monitor_chromeos_unittest.cc
new file mode 100644
index 0000000..e0afa44
--- /dev/null
+++ b/base/memory/memory_pressure_monitor_chromeos_unittest.cc
@@ -0,0 +1,166 @@
+// 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.
+
+#include "base/memory/memory_pressure_monitor_chromeos.h"
+
+#include "base/basictypes.h"
+#include "base/memory/memory_pressure_listener.h"
+#include "base/message_loop/message_loop.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace chromeos {
+
+namespace {
+
+// True if the memory notifier got called.
+// Do not read/modify value directly.
+bool on_memory_pressure_called = false;
+
+// If the memory notifier got called, this is the memory pressure reported.
+MemoryPressureListener::MemoryPressureLevel on_memory_pressure_level =
+    MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
+
+// Processes OnMemoryPressure calls.
+void OnMemoryPressure(MemoryPressureListener::MemoryPressureLevel level) {
+  on_memory_pressure_called = true;
+  on_memory_pressure_level = level;
+}
+
+// Resets the indicator for memory pressure.
+void ResetOnMemoryPressureCalled() {
+  on_memory_pressure_called = false;
+}
+
+// Returns true when OnMemoryPressure was called (and resets it).
+bool WasOnMemoryPressureCalled() {
+  bool b = on_memory_pressure_called;
+  ResetOnMemoryPressureCalled();
+  return b;
+}
+
+}  // namespace
+
+class TestMemoryPressureMonitor : public MemoryPressureMonitor {
+ public:
+  TestMemoryPressureMonitor()
+      : MemoryPressureMonitor(THRESHOLD_DEFAULT),
+        memory_in_percent_override_(0) {
+    // Disable any timers which are going on and set a special memory reporting
+    // function.
+    StopObserving();
+  }
+  ~TestMemoryPressureMonitor() override {}
+
+  void SetMemoryInPercentOverride(int percent) {
+    memory_in_percent_override_ = percent;
+  }
+
+  void CheckMemoryPressureForTest() {
+    CheckMemoryPressure();
+  }
+
+ private:
+  int GetUsedMemoryInPercent() override {
+    return memory_in_percent_override_;
+  }
+
+  int memory_in_percent_override_;
+  DISALLOW_COPY_AND_ASSIGN(TestMemoryPressureMonitor);
+};
+
+// This test tests the various transition states from memory pressure, looking
+// for the correct behavior on event reposting as well as state updates.
+TEST(ChromeOSMemoryPressureMonitorTest, CheckMemoryPressure) {
+  base::MessageLoopForUI message_loop;
+  scoped_ptr<TestMemoryPressureMonitor> monitor(
+      new TestMemoryPressureMonitor);
+  scoped_ptr<MemoryPressureListener> listener(
+      new MemoryPressureListener(base::Bind(&OnMemoryPressure)));
+  // Checking the memory pressure while 0% are used should not produce any
+  // events.
+  monitor->SetMemoryInPercentOverride(0);
+  ResetOnMemoryPressureCalled();
+
+  monitor->CheckMemoryPressureForTest();
+  message_loop.RunUntilIdle();
+  EXPECT_FALSE(WasOnMemoryPressureCalled());
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+            monitor->GetCurrentPressureLevel());
+
+  // Setting the memory level to 80% should produce a moderate pressure level.
+  monitor->SetMemoryInPercentOverride(80);
+  monitor->CheckMemoryPressureForTest();
+  message_loop.RunUntilIdle();
+  EXPECT_TRUE(WasOnMemoryPressureCalled());
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+            monitor->GetCurrentPressureLevel());
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+            on_memory_pressure_level);
+
+  // We need to check that the event gets reposted after a while.
+  int i = 0;
+  for (; i < 100; i++) {
+    monitor->CheckMemoryPressureForTest();
+    message_loop.RunUntilIdle();
+    EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+              monitor->GetCurrentPressureLevel());
+    if (WasOnMemoryPressureCalled()) {
+      EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+                on_memory_pressure_level);
+      break;
+    }
+  }
+  // Should be more then 5 and less then 100.
+  EXPECT_LE(5, i);
+  EXPECT_GE(99, i);
+
+  // Setting the memory usage to 99% should produce critical levels.
+  monitor->SetMemoryInPercentOverride(99);
+  monitor->CheckMemoryPressureForTest();
+  message_loop.RunUntilIdle();
+  EXPECT_TRUE(WasOnMemoryPressureCalled());
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+            on_memory_pressure_level);
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+            monitor->GetCurrentPressureLevel());
+
+  // Calling it again should immediately produce a second call.
+  monitor->CheckMemoryPressureForTest();
+  message_loop.RunUntilIdle();
+  EXPECT_TRUE(WasOnMemoryPressureCalled());
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+            on_memory_pressure_level);
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+            monitor->GetCurrentPressureLevel());
+
+  // When lowering the pressure again we should not get an event, but the
+  // pressure should go back to moderate.
+  monitor->SetMemoryInPercentOverride(80);
+  monitor->CheckMemoryPressureForTest();
+  message_loop.RunUntilIdle();
+  EXPECT_FALSE(WasOnMemoryPressureCalled());
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+            monitor->GetCurrentPressureLevel());
+
+  // We should need exactly the same amount of calls as before, before the next
+  // call comes in.
+  int j = 0;
+  for (; j < 100; j++) {
+    monitor->CheckMemoryPressureForTest();
+    message_loop.RunUntilIdle();
+    EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+              monitor->GetCurrentPressureLevel());
+    if (WasOnMemoryPressureCalled()) {
+      EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+                on_memory_pressure_level);
+      break;
+    }
+  }
+  // We should have needed exactly the same amount of checks as before.
+  EXPECT_EQ(j, i);
+}
+
+}  // namespace chromeos
+}  // namespace base
diff --git a/base/memory/memory_pressure_monitor_mac.cc b/base/memory/memory_pressure_monitor_mac.cc
new file mode 100644
index 0000000..f394935
--- /dev/null
+++ b/base/memory/memory_pressure_monitor_mac.cc
@@ -0,0 +1,78 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/memory_pressure_monitor_mac.h"
+
+#include <dlfcn.h>
+#include <sys/sysctl.h>
+
+#include "base/mac/mac_util.h"
+
+namespace base {
+namespace mac {
+
+MemoryPressureListener::MemoryPressureLevel
+MemoryPressureMonitor::MemoryPressureLevelForMacMemoryPressure(
+    int mac_memory_pressure) {
+  switch (mac_memory_pressure) {
+    case DISPATCH_MEMORYPRESSURE_NORMAL:
+      return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
+    case DISPATCH_MEMORYPRESSURE_WARN:
+      return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE;
+    case DISPATCH_MEMORYPRESSURE_CRITICAL:
+      return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL;
+  }
+  return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
+}
+
+void MemoryPressureMonitor::NotifyMemoryPressureChanged(
+    dispatch_source_s* event_source) {
+  int mac_memory_pressure = dispatch_source_get_data(event_source);
+  MemoryPressureListener::MemoryPressureLevel memory_pressure_level =
+      MemoryPressureLevelForMacMemoryPressure(mac_memory_pressure);
+  MemoryPressureListener::NotifyMemoryPressure(memory_pressure_level);
+}
+
+MemoryPressureMonitor::MemoryPressureMonitor()
+  : memory_level_event_source_(nullptr) {
+  // _dispatch_source_type_memorypressure is not available prior to 10.9.
+  dispatch_source_type_t dispatch_source_memorypressure =
+      static_cast<dispatch_source_type_t>
+          (dlsym(RTLD_NEXT, "_dispatch_source_type_memorypressure"));
+  if (dispatch_source_memorypressure) {
+    // The MemoryPressureListener doesn't want to know about transitions to
+    // MEMORY_PRESSURE_LEVEL_NONE so don't watch for
+    // DISPATCH_MEMORYPRESSURE_NORMAL notifications.
+    memory_level_event_source_.reset(
+        dispatch_source_create(dispatch_source_memorypressure, 0,
+                               DISPATCH_MEMORYPRESSURE_WARN |
+                                   DISPATCH_MEMORYPRESSURE_CRITICAL,
+                               dispatch_get_global_queue(
+                                   DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)));
+
+    dispatch_source_set_event_handler(memory_level_event_source_.get(), ^{
+        NotifyMemoryPressureChanged(memory_level_event_source_.get());
+    });
+    dispatch_retain(memory_level_event_source_.get());
+    dispatch_resume(memory_level_event_source_.get());
+  }
+}
+
+MemoryPressureMonitor::~MemoryPressureMonitor() {
+}
+
+MemoryPressureListener::MemoryPressureLevel
+MemoryPressureMonitor::GetCurrentPressureLevel() const {
+  if (base::mac::IsOSMountainLionOrEarlier()) {
+    return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
+  }
+  int mac_memory_pressure;
+  size_t length = sizeof(int);
+  sysctlbyname("kern.memorystatus_vm_pressure_level", &mac_memory_pressure,
+               &length, nullptr, 0);
+  return MemoryPressureLevelForMacMemoryPressure(mac_memory_pressure);
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/memory/memory_pressure_monitor_mac.h b/base/memory/memory_pressure_monitor_mac.h
new file mode 100644
index 0000000..8d4c26a
--- /dev/null
+++ b/base/memory/memory_pressure_monitor_mac.h
@@ -0,0 +1,63 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_MEMORY_PRESSURE_MONITOR_MAC_H_
+#define BASE_MEMORY_MEMORY_PRESSURE_MONITOR_MAC_H_
+
+#include <dispatch/dispatch.h>
+
+#include "base/base_export.h"
+#include "base/memory/memory_pressure_listener.h"
+#include "base/memory/memory_pressure_monitor.h"
+
+// The following was added to <dispatch/source.h> after 10.8.
+// TODO(shrike): Remove the DISPATCH_MEMORYPRESSURE_NORMAL ifndef once builders
+// reach 10.9 or higher.
+#ifndef DISPATCH_MEMORYPRESSURE_NORMAL
+
+#define DISPATCH_MEMORYPRESSURE_NORMAL    0x01
+#define DISPATCH_MEMORYPRESSURE_WARN      0x02
+#define DISPATCH_MEMORYPRESSURE_CRITICAL  0x04
+
+#endif  // DISPATCH_MEMORYPRESSURE_NORMAL
+
+namespace base {
+namespace mac {
+
+class TestMemoryPressureMonitor;
+
+struct DispatchSourceSDeleter {
+  void operator()(dispatch_source_s* ptr) {
+    dispatch_source_cancel(ptr);
+    dispatch_release(ptr);
+  }
+};
+
+// Declares the interface for the Mac MemoryPressureMonitor, which reports
+// memory pressure events and status.
+class BASE_EXPORT MemoryPressureMonitor : public base::MemoryPressureMonitor {
+ public:
+  MemoryPressureMonitor();
+  ~MemoryPressureMonitor() override;
+
+  // Returns the currently-observed memory pressure.
+  MemoryPressureLevel GetCurrentPressureLevel() const override;
+
+ private:
+  friend TestMemoryPressureMonitor;
+
+  static MemoryPressureLevel
+      MemoryPressureLevelForMacMemoryPressure(int mac_memory_pressure);
+  static void NotifyMemoryPressureChanged(dispatch_source_s* event_source);
+
+  scoped_ptr<dispatch_source_s, DispatchSourceSDeleter>
+      memory_level_event_source_;
+
+  DISALLOW_COPY_AND_ASSIGN(MemoryPressureMonitor);
+};
+
+}  // namespace mac
+}  // namespace base
+
+#endif  // BASE_MEMORY_MEMORY_PRESSURE_MONITOR_MAC_H_
diff --git a/base/memory/memory_pressure_monitor_mac_unittest.cc b/base/memory/memory_pressure_monitor_mac_unittest.cc
new file mode 100644
index 0000000..e037a9d
--- /dev/null
+++ b/base/memory/memory_pressure_monitor_mac_unittest.cc
@@ -0,0 +1,62 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/memory_pressure_monitor_mac.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace mac {
+
+class TestMemoryPressureMonitor : public MemoryPressureMonitor {
+ public:
+  using MemoryPressureMonitor::MemoryPressureLevelForMacMemoryPressure;
+
+  TestMemoryPressureMonitor() { }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestMemoryPressureMonitor);
+};
+
+TEST(MacMemoryPressureMonitorTest, MemoryPressureFromMacMemoryPressure) {
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+            TestMemoryPressureMonitor::
+                MemoryPressureLevelForMacMemoryPressure(
+                    DISPATCH_MEMORYPRESSURE_NORMAL));
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+            TestMemoryPressureMonitor::
+                MemoryPressureLevelForMacMemoryPressure(
+                    DISPATCH_MEMORYPRESSURE_WARN));
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+            TestMemoryPressureMonitor::
+                MemoryPressureLevelForMacMemoryPressure(
+                    DISPATCH_MEMORYPRESSURE_CRITICAL));
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+            TestMemoryPressureMonitor::
+                MemoryPressureLevelForMacMemoryPressure(0));
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+            TestMemoryPressureMonitor::
+                MemoryPressureLevelForMacMemoryPressure(3));
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+            TestMemoryPressureMonitor::
+                MemoryPressureLevelForMacMemoryPressure(5));
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+            TestMemoryPressureMonitor::
+                MemoryPressureLevelForMacMemoryPressure(-1));
+}
+
+TEST(MacMemoryPressureMonitorTest, CurrentMemoryPressure) {
+  TestMemoryPressureMonitor monitor;
+  MemoryPressureListener::MemoryPressureLevel memory_pressure =
+      monitor.GetCurrentPressureLevel();
+  EXPECT_TRUE(memory_pressure ==
+                  MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE ||
+              memory_pressure ==
+                  MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE ||
+              memory_pressure ==
+                  MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
+}
+
+}  // namespace mac
+}  // namespace base
diff --git a/base/memory/memory_pressure_monitor_win.cc b/base/memory/memory_pressure_monitor_win.cc
new file mode 100644
index 0000000..4349d03
--- /dev/null
+++ b/base/memory/memory_pressure_monitor_win.cc
@@ -0,0 +1,254 @@
+// 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/memory/memory_pressure_monitor_win.h"
+
+#include <windows.h>
+
+#include "base/metrics/histogram_macros.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/time/time.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+static const DWORDLONG kMBBytes = 1024 * 1024;
+
+// Enumeration of UMA memory pressure levels. This needs to be kept in sync with
+// histograms.xml and the memory pressure levels defined in
+// MemoryPressureListener.
+enum MemoryPressureLevelUMA {
+  UMA_MEMORY_PRESSURE_LEVEL_NONE = 0,
+  UMA_MEMORY_PRESSURE_LEVEL_MODERATE = 1,
+  UMA_MEMORY_PRESSURE_LEVEL_CRITICAL = 2,
+  // This must be the last value in the enum.
+  UMA_MEMORY_PRESSURE_LEVEL_COUNT,
+};
+
+// Converts a memory pressure level to an UMA enumeration value.
+MemoryPressureLevelUMA MemoryPressureLevelToUmaEnumValue(
+    MemoryPressureListener::MemoryPressureLevel level) {
+  switch (level) {
+    case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
+      return UMA_MEMORY_PRESSURE_LEVEL_NONE;
+    case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
+      return UMA_MEMORY_PRESSURE_LEVEL_MODERATE;
+    case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
+      return UMA_MEMORY_PRESSURE_LEVEL_CRITICAL;
+  }
+  NOTREACHED();
+  return UMA_MEMORY_PRESSURE_LEVEL_NONE;
+}
+
+}  // namespace
+
+// The following constants have been lifted from similar values in the ChromeOS
+// memory pressure monitor. The values were determined experimentally to ensure
+// sufficient responsiveness of the memory pressure subsystem, and minimal
+// overhead.
+const int MemoryPressureMonitor::kPollingIntervalMs = 5000;
+const int MemoryPressureMonitor::kModeratePressureCooldownMs = 10000;
+const int MemoryPressureMonitor::kModeratePressureCooldownCycles =
+    kModeratePressureCooldownMs / kPollingIntervalMs;
+
+// TODO(chrisha): Explore the following constants further with an experiment.
+
+// A system is considered 'high memory' if it has more than 1.5GB of system
+// memory available for use by the memory manager (not reserved for hardware
+// and drivers). This is a fuzzy version of the ~2GB discussed below.
+const int MemoryPressureMonitor::kLargeMemoryThresholdMb = 1536;
+
+// These are the default thresholds used for systems with < ~2GB of physical
+// memory. Such systems have been observed to always maintain ~100MB of
+// available memory, paging until that is the case. To try to avoid paging a
+// threshold slightly above this is chosen. The moderate threshold is slightly
+// less grounded in reality and chosen as 2.5x critical.
+const int MemoryPressureMonitor::kSmallMemoryDefaultModerateThresholdMb = 500;
+const int MemoryPressureMonitor::kSmallMemoryDefaultCriticalThresholdMb = 200;
+
+// These are the default thresholds used for systems with >= ~2GB of physical
+// memory. Such systems have been observed to always maintain ~300MB of
+// available memory, paging until that is the case.
+const int MemoryPressureMonitor::kLargeMemoryDefaultModerateThresholdMb = 1000;
+const int MemoryPressureMonitor::kLargeMemoryDefaultCriticalThresholdMb = 400;
+
+MemoryPressureMonitor::MemoryPressureMonitor()
+    : moderate_threshold_mb_(0),
+      critical_threshold_mb_(0),
+      current_memory_pressure_level_(
+          MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE),
+      moderate_pressure_repeat_count_(0),
+      weak_ptr_factory_(this) {
+  InferThresholds();
+  StartObserving();
+}
+
+MemoryPressureMonitor::MemoryPressureMonitor(int moderate_threshold_mb,
+                                             int critical_threshold_mb)
+    : moderate_threshold_mb_(moderate_threshold_mb),
+      critical_threshold_mb_(critical_threshold_mb),
+      current_memory_pressure_level_(
+          MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE),
+      moderate_pressure_repeat_count_(0),
+      weak_ptr_factory_(this) {
+  DCHECK_GE(moderate_threshold_mb_, critical_threshold_mb_);
+  DCHECK_LE(0, critical_threshold_mb_);
+  StartObserving();
+}
+
+MemoryPressureMonitor::~MemoryPressureMonitor() {
+  StopObserving();
+}
+
+void MemoryPressureMonitor::CheckMemoryPressureSoon() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, Bind(&MemoryPressureMonitor::CheckMemoryPressure,
+                      weak_ptr_factory_.GetWeakPtr()));
+}
+
+MemoryPressureListener::MemoryPressureLevel
+MemoryPressureMonitor::GetCurrentPressureLevel() const {
+  return current_memory_pressure_level_;
+}
+
+void MemoryPressureMonitor::InferThresholds() {
+  // Default to a 'high' memory situation, which uses more conservative
+  // thresholds.
+  bool high_memory = true;
+  MEMORYSTATUSEX mem_status = {};
+  if (GetSystemMemoryStatus(&mem_status)) {
+    static const DWORDLONG kLargeMemoryThresholdBytes =
+        static_cast<DWORDLONG>(kLargeMemoryThresholdMb) * kMBBytes;
+    high_memory = mem_status.ullTotalPhys >= kLargeMemoryThresholdBytes;
+  }
+
+  if (high_memory) {
+    moderate_threshold_mb_ = kLargeMemoryDefaultModerateThresholdMb;
+    critical_threshold_mb_ = kLargeMemoryDefaultCriticalThresholdMb;
+  } else {
+    moderate_threshold_mb_ = kSmallMemoryDefaultModerateThresholdMb;
+    critical_threshold_mb_ = kSmallMemoryDefaultCriticalThresholdMb;
+  }
+}
+
+void MemoryPressureMonitor::StartObserving() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  timer_.Start(FROM_HERE,
+               TimeDelta::FromMilliseconds(kPollingIntervalMs),
+               Bind(&MemoryPressureMonitor::
+                        CheckMemoryPressureAndRecordStatistics,
+                    weak_ptr_factory_.GetWeakPtr()));
+}
+
+void MemoryPressureMonitor::StopObserving() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  // If StartObserving failed, StopObserving will still get called.
+  timer_.Stop();
+  weak_ptr_factory_.InvalidateWeakPtrs();
+}
+
+void MemoryPressureMonitor::CheckMemoryPressure() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  // Get the previous pressure level and update the current one.
+  MemoryPressureLevel old_pressure = current_memory_pressure_level_;
+  current_memory_pressure_level_ = CalculateCurrentPressureLevel();
+
+  // |notify| will be set to true if MemoryPressureListeners need to be
+  // notified of a memory pressure level state change.
+  bool notify = false;
+  switch (current_memory_pressure_level_) {
+    case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
+      break;
+
+    case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
+      if (old_pressure != current_memory_pressure_level_) {
+        // This is a new transition to moderate pressure so notify.
+        moderate_pressure_repeat_count_ = 0;
+        notify = true;
+      } else {
+        // Already in moderate pressure, only notify if sustained over the
+        // cooldown period.
+        if (++moderate_pressure_repeat_count_ ==
+                kModeratePressureCooldownCycles) {
+          moderate_pressure_repeat_count_ = 0;
+          notify = true;
+        }
+      }
+      break;
+
+    case MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
+      // Always notify of critical pressure levels.
+      notify = true;
+      break;
+  }
+
+  if (!notify)
+    return;
+
+  // Emit a notification of the current memory pressure level. This can only
+  // happen for moderate and critical pressure levels.
+  DCHECK_NE(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+            current_memory_pressure_level_);
+  MemoryPressureListener::NotifyMemoryPressure(current_memory_pressure_level_);
+}
+
+void MemoryPressureMonitor::CheckMemoryPressureAndRecordStatistics() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  CheckMemoryPressure();
+
+  UMA_HISTOGRAM_ENUMERATION(
+      "Memory.PressureLevel",
+      MemoryPressureLevelToUmaEnumValue(current_memory_pressure_level_),
+      UMA_MEMORY_PRESSURE_LEVEL_COUNT);
+}
+
+MemoryPressureListener::MemoryPressureLevel
+MemoryPressureMonitor::CalculateCurrentPressureLevel() {
+  MEMORYSTATUSEX mem_status = {};
+  if (!GetSystemMemoryStatus(&mem_status))
+    return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
+
+  // How much system memory is actively available for use right now, in MBs.
+  int phys_free = static_cast<int>(mem_status.ullAvailPhys / kMBBytes);
+
+  // TODO(chrisha): This should eventually care about address space pressure,
+  // but the browser process (where this is running) effectively never runs out
+  // of address space. Renderers occasionally do, but it does them no good to
+  // have the browser process monitor address space pressure. Long term,
+  // renderers should run their own address space pressure monitors and act
+  // accordingly, with the browser making cross-process decisions based on
+  // system memory pressure.
+
+  // Determine if the physical memory is under critical memory pressure.
+  if (phys_free <= critical_threshold_mb_)
+    return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL;
+
+  // Determine if the physical memory is under moderate memory pressure.
+  if (phys_free <= moderate_threshold_mb_)
+    return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE;
+
+  // No memory pressure was detected.
+  return MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE;
+}
+
+bool MemoryPressureMonitor::GetSystemMemoryStatus(
+    MEMORYSTATUSEX* mem_status) {
+  DCHECK(mem_status != nullptr);
+  mem_status->dwLength = sizeof(*mem_status);
+  if (!::GlobalMemoryStatusEx(mem_status))
+    return false;
+  return true;
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/memory/memory_pressure_monitor_win.h b/base/memory/memory_pressure_monitor_win.h
new file mode 100644
index 0000000..07f04eb
--- /dev/null
+++ b/base/memory/memory_pressure_monitor_win.h
@@ -0,0 +1,144 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_MEMORY_PRESSURE_MONITOR_WIN_H_
+#define BASE_MEMORY_MEMORY_PRESSURE_MONITOR_WIN_H_
+
+#include "base/base_export.h"
+#include "base/memory/memory_pressure_listener.h"
+#include "base/memory/memory_pressure_monitor.h"
+#include "base/memory/weak_ptr.h"
+#include "base/threading/thread_checker.h"
+#include "base/timer/timer.h"
+
+// To not pull in windows.h.
+typedef struct _MEMORYSTATUSEX MEMORYSTATUSEX;
+
+namespace base {
+namespace win {
+
+// Windows memory pressure monitor. Because there is no OS provided signal this
+// polls at a low frequency (once per second), and applies internal hysteresis.
+class BASE_EXPORT MemoryPressureMonitor : public base::MemoryPressureMonitor {
+ public:
+  // Constants governing the polling and hysteresis behaviour of the observer.
+
+  // The polling interval, in milliseconds. While under critical pressure, this
+  // is also the timer to repeat cleanup attempts.
+  static const int kPollingIntervalMs;
+  // The time which should pass between 2 successive moderate memory pressure
+  // signals, in milliseconds.
+  static const int kModeratePressureCooldownMs;
+  // The number of cycles that should pass between 2 successive moderate memory
+  // pressure signals.
+  static const int kModeratePressureCooldownCycles;
+
+  // Constants governing the memory pressure level detection.
+
+  // The amount of total system memory beyond which a system is considered to be
+  // a large-memory system.
+  static const int kLargeMemoryThresholdMb;
+  // Default minimum free memory thresholds for small-memory systems, in MB.
+  static const int kSmallMemoryDefaultModerateThresholdMb;
+  static const int kSmallMemoryDefaultCriticalThresholdMb;
+  // Default minimum free memory thresholds for large-memory systems, in MB.
+  static const int kLargeMemoryDefaultModerateThresholdMb;
+  static const int kLargeMemoryDefaultCriticalThresholdMb;
+
+  // Default constructor. Will choose thresholds automatically basd on the
+  // actual amount of system memory.
+  MemoryPressureMonitor();
+
+  // Constructor with explicit memory thresholds. These represent the amount of
+  // free memory below which the applicable memory pressure state engages.
+  MemoryPressureMonitor(int moderate_threshold_mb, int critical_threshold_mb);
+
+  ~MemoryPressureMonitor() override;
+
+  // Schedules a memory pressure check to run soon. This must be called on the
+  // same thread where the monitor was instantiated.
+  void CheckMemoryPressureSoon();
+
+  // Get the current memory pressure level. This can be called from any thread.
+  MemoryPressureLevel GetCurrentPressureLevel() const override;
+
+  // Returns the moderate pressure level free memory threshold, in MB.
+  int moderate_threshold_mb() const { return moderate_threshold_mb_; }
+
+  // Returns the critical pressure level free memory threshold, in MB.
+  int critical_threshold_mb() const { return critical_threshold_mb_; }
+
+ protected:
+  // Internals are exposed for unittests.
+
+  // Automatically infers threshold values based on system memory. This invokes
+  // GetMemoryStatus so it can be mocked in unittests.
+  void InferThresholds();
+
+  // Starts observing the memory fill level. Calls to StartObserving should
+  // always be matched with calls to StopObserving.
+  void StartObserving();
+
+  // Stop observing the memory fill level. May be safely called if
+  // StartObserving has not been called. Must be called from the same thread on
+  // which the monitor was instantiated.
+  void StopObserving();
+
+  // Checks memory pressure, storing the current level, applying any hysteresis
+  // and emitting memory pressure level change signals as necessary. This
+  // function is called periodically while the monitor is observing memory
+  // pressure. This is split out from CheckMemoryPressureAndRecordStatistics so
+  // that it may be called by CheckMemoryPressureSoon and not invoke UMA
+  // logging. Must be called from the same thread on which the monitor was
+  // instantiated.
+  void CheckMemoryPressure();
+
+  // Wrapper to CheckMemoryPressure that also records the observed memory
+  // pressure level via an UMA enumeration. This is the function that is called
+  // periodically by the timer. Must be called from the same thread on which the
+  // monitor was instantiated.
+  void CheckMemoryPressureAndRecordStatistics();
+
+  // Calculates the current instantaneous memory pressure level. This does not
+  // use any hysteresis and simply returns the result at the current moment. Can
+  // be called on any thread.
+  MemoryPressureLevel CalculateCurrentPressureLevel();
+
+  // Gets system memory status. This is virtual as a unittesting hook. Returns
+  // true if the system call succeeds, false otherwise. Can be called on any
+  // thread.
+  virtual bool GetSystemMemoryStatus(MEMORYSTATUSEX* mem_status);
+
+ private:
+  // Threshold amounts of available memory that trigger pressure levels. See
+  // memory_pressure_monitor.cc for a discussion of reasonable values for these.
+  int moderate_threshold_mb_;
+  int critical_threshold_mb_;
+
+  // A periodic timer to check for memory pressure changes.
+  base::RepeatingTimer<MemoryPressureMonitor> timer_;
+
+  // The current memory pressure.
+  MemoryPressureLevel current_memory_pressure_level_;
+
+  // To slow down the amount of moderate pressure event calls, this gets used to
+  // count the number of events since the last event occured. This is used by
+  // |CheckMemoryPressure| to apply hysteresis on the raw results of
+  // |CalculateCurrentPressureLevel|.
+  int moderate_pressure_repeat_count_;
+
+  // Ensures that this object is used from a single thread.
+  base::ThreadChecker thread_checker_;
+
+  // Weak pointer factory to ourself used for scheduling calls to
+  // CheckMemoryPressure/CheckMemoryPressureAndRecordStatistics via |timer_|.
+  base::WeakPtrFactory<MemoryPressureMonitor> weak_ptr_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(MemoryPressureMonitor);
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_MEMORY_MEMORY_PRESSURE_MONITOR_WIN_H_
diff --git a/base/memory/memory_pressure_monitor_win_unittest.cc b/base/memory/memory_pressure_monitor_win_unittest.cc
new file mode 100644
index 0000000..d9a9575
--- /dev/null
+++ b/base/memory/memory_pressure_monitor_win_unittest.cc
@@ -0,0 +1,298 @@
+// 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/memory/memory_pressure_monitor_win.h"
+
+#include "base/basictypes.h"
+#include "base/memory/memory_pressure_listener.h"
+#include "base/message_loop/message_loop.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+struct PressureSettings {
+  int phys_left_mb;
+  MemoryPressureListener::MemoryPressureLevel level;
+};
+
+}  // namespace
+
+// This is outside of the anonymous namespace so that it can be seen as a friend
+// to the monitor class.
+class TestMemoryPressureMonitor : public MemoryPressureMonitor {
+ public:
+  using MemoryPressureMonitor::CalculateCurrentPressureLevel;
+  using MemoryPressureMonitor::CheckMemoryPressure;
+
+  static const DWORDLONG kMBBytes = 1024 * 1024;
+
+  explicit TestMemoryPressureMonitor(bool large_memory)
+      : mem_status_() {
+    // Generate a plausible amount of memory.
+    mem_status_.ullTotalPhys =
+        static_cast<DWORDLONG>(GenerateTotalMemoryMb(large_memory)) * kMBBytes;
+
+    // Rerun InferThresholds using the test fixture's GetSystemMemoryStatus.
+    InferThresholds();
+    // Stop the timer.
+    StopObserving();
+  }
+
+  TestMemoryPressureMonitor(int system_memory_mb,
+                            int moderate_threshold_mb,
+                            int critical_threshold_mb)
+      : MemoryPressureMonitor(moderate_threshold_mb, critical_threshold_mb),
+        mem_status_() {
+    // Set the amount of system memory.
+    mem_status_.ullTotalPhys = static_cast<DWORDLONG>(
+        system_memory_mb * kMBBytes);
+
+    // Stop the timer.
+    StopObserving();
+  }
+
+  virtual ~TestMemoryPressureMonitor() {}
+
+  MOCK_METHOD1(OnMemoryPressure,
+               void(MemoryPressureListener::MemoryPressureLevel level));
+
+  // Generates an amount of total memory that is consistent with the requested
+  // memory model.
+  int GenerateTotalMemoryMb(bool large_memory) {
+    int total_mb = 64;
+    while (total_mb < MemoryPressureMonitor::kLargeMemoryThresholdMb)
+      total_mb *= 2;
+    if (large_memory)
+      return total_mb * 2;
+    return total_mb / 2;
+  }
+
+  // Sets up the memory status to reflect the provided absolute memory left.
+  void SetMemoryFree(int phys_left_mb) {
+    // ullTotalPhys is set in the constructor and not modified.
+
+    // Set the amount of available memory.
+    mem_status_.ullAvailPhys =
+        static_cast<DWORDLONG>(phys_left_mb) * kMBBytes;
+    DCHECK_LT(mem_status_.ullAvailPhys, mem_status_.ullTotalPhys);
+
+    // These fields are unused.
+    mem_status_.dwMemoryLoad = 0;
+    mem_status_.ullTotalPageFile = 0;
+    mem_status_.ullAvailPageFile = 0;
+    mem_status_.ullTotalVirtual = 0;
+    mem_status_.ullAvailVirtual = 0;
+  }
+
+  void SetNone() {
+    SetMemoryFree(moderate_threshold_mb() + 1);
+  }
+
+  void SetModerate() {
+    SetMemoryFree(moderate_threshold_mb() - 1);
+  }
+
+  void SetCritical() {
+    SetMemoryFree(critical_threshold_mb() - 1);
+  }
+
+ private:
+  bool GetSystemMemoryStatus(MEMORYSTATUSEX* mem_status) override {
+    // Simply copy the memory status set by the test fixture.
+    *mem_status = mem_status_;
+    return true;
+  }
+
+  MEMORYSTATUSEX mem_status_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestMemoryPressureMonitor);
+};
+
+class WinMemoryPressureMonitorTest : public testing::Test {
+ protected:
+  void CalculateCurrentMemoryPressureLevelTest(
+      TestMemoryPressureMonitor* monitor) {
+
+    int mod = monitor->moderate_threshold_mb();
+    monitor->SetMemoryFree(mod + 1);
+    EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+              monitor->CalculateCurrentPressureLevel());
+
+    monitor->SetMemoryFree(mod);
+    EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+              monitor->CalculateCurrentPressureLevel());
+
+    monitor->SetMemoryFree(mod - 1);
+    EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+              monitor->CalculateCurrentPressureLevel());
+
+    int crit = monitor->critical_threshold_mb();
+    monitor->SetMemoryFree(crit + 1);
+    EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+              monitor->CalculateCurrentPressureLevel());
+
+    monitor->SetMemoryFree(crit);
+    EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+              monitor->CalculateCurrentPressureLevel());
+
+    monitor->SetMemoryFree(crit - 1);
+    EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+              monitor->CalculateCurrentPressureLevel());
+  }
+
+  base::MessageLoopForUI message_loop_;
+};
+
+// Tests the fundamental direct calculation of memory pressure with automatic
+// small-memory thresholds.
+TEST_F(WinMemoryPressureMonitorTest, CalculateCurrentMemoryPressureLevelSmall) {
+  static const int kModerateMb =
+      MemoryPressureMonitor::kSmallMemoryDefaultModerateThresholdMb;
+  static const int kCriticalMb =
+      MemoryPressureMonitor::kSmallMemoryDefaultCriticalThresholdMb;
+
+  TestMemoryPressureMonitor monitor(false);  // Small-memory model.
+
+  EXPECT_EQ(kModerateMb, monitor.moderate_threshold_mb());
+  EXPECT_EQ(kCriticalMb, monitor.critical_threshold_mb());
+
+  ASSERT_NO_FATAL_FAILURE(CalculateCurrentMemoryPressureLevelTest(&monitor));
+}
+
+// Tests the fundamental direct calculation of memory pressure with automatic
+// large-memory thresholds.
+TEST_F(WinMemoryPressureMonitorTest, CalculateCurrentMemoryPressureLevelLarge) {
+  static const int kModerateMb =
+      MemoryPressureMonitor::kLargeMemoryDefaultModerateThresholdMb;
+  static const int kCriticalMb =
+      MemoryPressureMonitor::kLargeMemoryDefaultCriticalThresholdMb;
+
+  TestMemoryPressureMonitor monitor(true);  // Large-memory model.
+
+  EXPECT_EQ(kModerateMb, monitor.moderate_threshold_mb());
+  EXPECT_EQ(kCriticalMb, monitor.critical_threshold_mb());
+
+  ASSERT_NO_FATAL_FAILURE(CalculateCurrentMemoryPressureLevelTest(&monitor));
+}
+
+// Tests the fundamental direct calculation of memory pressure with manually
+// specified threshold levels.
+TEST_F(WinMemoryPressureMonitorTest,
+       CalculateCurrentMemoryPressureLevelCustom) {
+  static const int kSystemMb = 512;
+  static const int kModerateMb = 256;
+  static const int kCriticalMb = 128;
+
+  TestMemoryPressureMonitor monitor(kSystemMb, kModerateMb, kCriticalMb);
+
+  EXPECT_EQ(kModerateMb, monitor.moderate_threshold_mb());
+  EXPECT_EQ(kCriticalMb, monitor.critical_threshold_mb());
+
+  ASSERT_NO_FATAL_FAILURE(CalculateCurrentMemoryPressureLevelTest(&monitor));
+}
+
+// This test tests the various transition states from memory pressure, looking
+// for the correct behavior on event reposting as well as state updates.
+TEST_F(WinMemoryPressureMonitorTest, CheckMemoryPressure) {
+  // Large-memory.
+  testing::StrictMock<TestMemoryPressureMonitor> monitor(true);
+  MemoryPressureListener listener(
+      base::Bind(&TestMemoryPressureMonitor::OnMemoryPressure,
+                 base::Unretained(&monitor)));
+
+  // Checking the memory pressure at 0% load should not produce any
+  // events.
+  monitor.SetNone();
+  monitor.CheckMemoryPressure();
+  message_loop_.RunUntilIdle();
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+            monitor.GetCurrentPressureLevel());
+
+  // Setting the memory level to 80% should produce a moderate pressure level.
+  EXPECT_CALL(monitor,
+              OnMemoryPressure(MemoryPressureListener::
+                                   MEMORY_PRESSURE_LEVEL_MODERATE));
+  monitor.SetModerate();
+  monitor.CheckMemoryPressure();
+  message_loop_.RunUntilIdle();
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+            monitor.GetCurrentPressureLevel());
+  testing::Mock::VerifyAndClearExpectations(&monitor);
+
+  // Check that the event gets reposted after a while.
+  for (int i = 0; i < monitor.kModeratePressureCooldownCycles; ++i) {
+    if (i + 1 == monitor.kModeratePressureCooldownCycles) {
+      EXPECT_CALL(monitor,
+                  OnMemoryPressure(MemoryPressureListener::
+                                       MEMORY_PRESSURE_LEVEL_MODERATE));
+    }
+    monitor.CheckMemoryPressure();
+    message_loop_.RunUntilIdle();
+    EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+              monitor.GetCurrentPressureLevel());
+    testing::Mock::VerifyAndClearExpectations(&monitor);
+  }
+
+  // Setting the memory usage to 99% should produce critical levels.
+  EXPECT_CALL(monitor,
+              OnMemoryPressure(MemoryPressureListener::
+                                   MEMORY_PRESSURE_LEVEL_CRITICAL));
+  monitor.SetCritical();
+  monitor.CheckMemoryPressure();
+  message_loop_.RunUntilIdle();
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+            monitor.GetCurrentPressureLevel());
+  testing::Mock::VerifyAndClearExpectations(&monitor);
+
+  // Calling it again should immediately produce a second call.
+  EXPECT_CALL(monitor,
+              OnMemoryPressure(MemoryPressureListener::
+                                   MEMORY_PRESSURE_LEVEL_CRITICAL));
+  monitor.CheckMemoryPressure();
+  message_loop_.RunUntilIdle();
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL,
+            monitor.GetCurrentPressureLevel());
+  testing::Mock::VerifyAndClearExpectations(&monitor);
+
+  // When lowering the pressure again there should be a notification and the
+  // pressure should go back to moderate.
+  EXPECT_CALL(monitor,
+              OnMemoryPressure(MemoryPressureListener::
+                                   MEMORY_PRESSURE_LEVEL_MODERATE));
+  monitor.SetModerate();
+  monitor.CheckMemoryPressure();
+  message_loop_.RunUntilIdle();
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+            monitor.GetCurrentPressureLevel());
+  testing::Mock::VerifyAndClearExpectations(&monitor);
+
+  // Check that the event gets reposted after a while.
+  for (int i = 0; i < monitor.kModeratePressureCooldownCycles; ++i) {
+    if (i + 1 == monitor.kModeratePressureCooldownCycles) {
+      EXPECT_CALL(monitor,
+                  OnMemoryPressure(MemoryPressureListener::
+                                       MEMORY_PRESSURE_LEVEL_MODERATE));
+    }
+    monitor.CheckMemoryPressure();
+    message_loop_.RunUntilIdle();
+    EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE,
+              monitor.GetCurrentPressureLevel());
+    testing::Mock::VerifyAndClearExpectations(&monitor);
+  }
+
+  // Going down to no pressure should not produce an notification.
+  monitor.SetNone();
+  monitor.CheckMemoryPressure();
+  message_loop_.RunUntilIdle();
+  EXPECT_EQ(MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE,
+            monitor.GetCurrentPressureLevel());
+  testing::Mock::VerifyAndClearExpectations(&monitor);
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/memory/raw_scoped_refptr_mismatch_checker.h b/base/memory/raw_scoped_refptr_mismatch_checker.h
new file mode 100644
index 0000000..0190558
--- /dev/null
+++ b/base/memory/raw_scoped_refptr_mismatch_checker.h
@@ -0,0 +1,129 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_RAW_SCOPED_REFPTR_MISMATCH_CHECKER_H_
+#define BASE_MEMORY_RAW_SCOPED_REFPTR_MISMATCH_CHECKER_H_
+
+#include "base/memory/ref_counted.h"
+#include "base/template_util.h"
+#include "base/tuple.h"
+#include "build/build_config.h"
+
+// It is dangerous to post a task with a T* argument where T is a subtype of
+// RefCounted(Base|ThreadSafeBase), since by the time the parameter is used, the
+// object may already have been deleted since it was not held with a
+// scoped_refptr. Example: http://crbug.com/27191
+// The following set of traits are designed to generate a compile error
+// whenever this antipattern is attempted.
+
+namespace base {
+
+// This is a base internal implementation file used by task.h and callback.h.
+// Not for public consumption, so we wrap it in namespace internal.
+namespace internal {
+
+template <typename T>
+struct NeedsScopedRefptrButGetsRawPtr {
+#if defined(OS_WIN)
+  enum {
+    value = base::false_type::value
+  };
+#else
+  enum {
+    // Human readable translation: you needed to be a scoped_refptr if you are a
+    // raw pointer type and are convertible to a RefCounted(Base|ThreadSafeBase)
+    // type.
+    value = (is_pointer<T>::value &&
+             (is_convertible<T, subtle::RefCountedBase*>::value ||
+              is_convertible<T, subtle::RefCountedThreadSafeBase*>::value))
+  };
+#endif
+};
+
+template <typename Params>
+struct ParamsUseScopedRefptrCorrectly {
+  enum { value = 0 };
+};
+
+template <>
+struct ParamsUseScopedRefptrCorrectly<Tuple<>> {
+  enum { value = 1 };
+};
+
+template <typename A>
+struct ParamsUseScopedRefptrCorrectly<Tuple<A>> {
+  enum { value = !NeedsScopedRefptrButGetsRawPtr<A>::value };
+};
+
+template <typename A, typename B>
+struct ParamsUseScopedRefptrCorrectly<Tuple<A, B>> {
+  enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<B>::value) };
+};
+
+template <typename A, typename B, typename C>
+struct ParamsUseScopedRefptrCorrectly<Tuple<A, B, C>> {
+  enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<B>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<C>::value) };
+};
+
+template <typename A, typename B, typename C, typename D>
+struct ParamsUseScopedRefptrCorrectly<Tuple<A, B, C, D>> {
+  enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<B>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<C>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<D>::value) };
+};
+
+template <typename A, typename B, typename C, typename D, typename E>
+struct ParamsUseScopedRefptrCorrectly<Tuple<A, B, C, D, E>> {
+  enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<B>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<C>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<D>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<E>::value) };
+};
+
+template <typename A, typename B, typename C, typename D, typename E,
+          typename F>
+struct ParamsUseScopedRefptrCorrectly<Tuple<A, B, C, D, E, F>> {
+  enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<B>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<C>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<D>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<E>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<F>::value) };
+};
+
+template <typename A, typename B, typename C, typename D, typename E,
+          typename F, typename G>
+struct ParamsUseScopedRefptrCorrectly<Tuple<A, B, C, D, E, F, G>> {
+  enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<B>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<C>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<D>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<E>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<F>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<G>::value) };
+};
+
+template <typename A, typename B, typename C, typename D, typename E,
+          typename F, typename G, typename H>
+struct ParamsUseScopedRefptrCorrectly<Tuple<A, B, C, D, E, F, G, H>> {
+  enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<B>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<C>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<D>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<E>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<F>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<G>::value ||
+                   NeedsScopedRefptrButGetsRawPtr<H>::value) };
+};
+
+}  // namespace internal
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_RAW_SCOPED_REFPTR_MISMATCH_CHECKER_H_
diff --git a/base/memory/ref_counted.cc b/base/memory/ref_counted.cc
new file mode 100644
index 0000000..f5924d0
--- /dev/null
+++ b/base/memory/ref_counted.cc
@@ -0,0 +1,53 @@
+// Copyright (c) 2011 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/memory/ref_counted.h"
+#include "base/threading/thread_collision_warner.h"
+
+namespace base {
+
+namespace subtle {
+
+bool RefCountedThreadSafeBase::HasOneRef() const {
+  return AtomicRefCountIsOne(
+      &const_cast<RefCountedThreadSafeBase*>(this)->ref_count_);
+}
+
+RefCountedThreadSafeBase::RefCountedThreadSafeBase() : ref_count_(0) {
+#ifndef NDEBUG
+  in_dtor_ = false;
+#endif
+}
+
+RefCountedThreadSafeBase::~RefCountedThreadSafeBase() {
+#ifndef NDEBUG
+  DCHECK(in_dtor_) << "RefCountedThreadSafe object deleted without "
+                      "calling Release()";
+#endif
+}
+
+void RefCountedThreadSafeBase::AddRef() const {
+#ifndef NDEBUG
+  DCHECK(!in_dtor_);
+#endif
+  AtomicRefCountInc(&ref_count_);
+}
+
+bool RefCountedThreadSafeBase::Release() const {
+#ifndef NDEBUG
+  DCHECK(!in_dtor_);
+  DCHECK(!AtomicRefCountIsZero(&ref_count_));
+#endif
+  if (!AtomicRefCountDec(&ref_count_)) {
+#ifndef NDEBUG
+    in_dtor_ = true;
+#endif
+    return true;
+  }
+  return false;
+}
+
+}  // namespace subtle
+
+}  // namespace base
diff --git a/base/memory/ref_counted.h b/base/memory/ref_counted.h
new file mode 100644
index 0000000..5f94b4c
--- /dev/null
+++ b/base/memory/ref_counted.h
@@ -0,0 +1,440 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_REF_COUNTED_H_
+#define BASE_MEMORY_REF_COUNTED_H_
+
+#include <cassert>
+#include <iosfwd>
+
+#include "base/atomic_ref_count.h"
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#ifndef NDEBUG
+#include "base/logging.h"
+#endif
+#include "base/move.h"
+#include "base/threading/thread_collision_warner.h"
+#include "build/build_config.h"
+
+namespace base {
+
+namespace subtle {
+
+class BASE_EXPORT RefCountedBase {
+ public:
+  bool HasOneRef() const { return ref_count_ == 1; }
+
+ protected:
+  RefCountedBase()
+      : ref_count_(0)
+  #ifndef NDEBUG
+      , in_dtor_(false)
+  #endif
+      {
+  }
+
+  ~RefCountedBase() {
+  #ifndef NDEBUG
+    DCHECK(in_dtor_) << "RefCounted object deleted without calling Release()";
+  #endif
+  }
+
+
+  void AddRef() const {
+    // TODO(maruel): Add back once it doesn't assert 500 times/sec.
+    // Current thread books the critical section "AddRelease"
+    // without release it.
+    // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_);
+  #ifndef NDEBUG
+    DCHECK(!in_dtor_);
+  #endif
+    ++ref_count_;
+  }
+
+  // Returns true if the object should self-delete.
+  bool Release() const {
+    // TODO(maruel): Add back once it doesn't assert 500 times/sec.
+    // Current thread books the critical section "AddRelease"
+    // without release it.
+    // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_);
+  #ifndef NDEBUG
+    DCHECK(!in_dtor_);
+  #endif
+    if (--ref_count_ == 0) {
+  #ifndef NDEBUG
+      in_dtor_ = true;
+  #endif
+      return true;
+    }
+    return false;
+  }
+
+ private:
+  mutable int ref_count_;
+#ifndef NDEBUG
+  mutable bool in_dtor_;
+#endif
+
+  DFAKE_MUTEX(add_release_);
+
+  DISALLOW_COPY_AND_ASSIGN(RefCountedBase);
+};
+
+class BASE_EXPORT RefCountedThreadSafeBase {
+ public:
+  bool HasOneRef() const;
+
+ protected:
+  RefCountedThreadSafeBase();
+  ~RefCountedThreadSafeBase();
+
+  void AddRef() const;
+
+  // Returns true if the object should self-delete.
+  bool Release() const;
+
+ private:
+  mutable AtomicRefCount ref_count_;
+#ifndef NDEBUG
+  mutable bool in_dtor_;
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafeBase);
+};
+
+}  // namespace subtle
+
+//
+// A base class for reference counted classes.  Otherwise, known as a cheap
+// knock-off of WebKit's RefCounted<T> class.  To use this guy just extend your
+// class from it like so:
+//
+//   class MyFoo : public base::RefCounted<MyFoo> {
+//    ...
+//    private:
+//     friend class base::RefCounted<MyFoo>;
+//     ~MyFoo();
+//   };
+//
+// You should always make your destructor private, to avoid any code deleting
+// the object accidently while there are references to it.
+template <class T>
+class RefCounted : public subtle::RefCountedBase {
+ public:
+  RefCounted() {}
+
+  void AddRef() const {
+    subtle::RefCountedBase::AddRef();
+  }
+
+  void Release() const {
+    if (subtle::RefCountedBase::Release()) {
+      delete static_cast<const T*>(this);
+    }
+  }
+
+ protected:
+  ~RefCounted() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(RefCounted<T>);
+};
+
+// Forward declaration.
+template <class T, typename Traits> class RefCountedThreadSafe;
+
+// Default traits for RefCountedThreadSafe<T>.  Deletes the object when its ref
+// count reaches 0.  Overload to delete it on a different thread etc.
+template<typename T>
+struct DefaultRefCountedThreadSafeTraits {
+  static void Destruct(const T* x) {
+    // Delete through RefCountedThreadSafe to make child classes only need to be
+    // friend with RefCountedThreadSafe instead of this struct, which is an
+    // implementation detail.
+    RefCountedThreadSafe<T,
+                         DefaultRefCountedThreadSafeTraits>::DeleteInternal(x);
+  }
+};
+
+//
+// A thread-safe variant of RefCounted<T>
+//
+//   class MyFoo : public base::RefCountedThreadSafe<MyFoo> {
+//    ...
+//   };
+//
+// If you're using the default trait, then you should add compile time
+// asserts that no one else is deleting your object.  i.e.
+//    private:
+//     friend class base::RefCountedThreadSafe<MyFoo>;
+//     ~MyFoo();
+template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T> >
+class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase {
+ public:
+  RefCountedThreadSafe() {}
+
+  void AddRef() const {
+    subtle::RefCountedThreadSafeBase::AddRef();
+  }
+
+  void Release() const {
+    if (subtle::RefCountedThreadSafeBase::Release()) {
+      Traits::Destruct(static_cast<const T*>(this));
+    }
+  }
+
+ protected:
+  ~RefCountedThreadSafe() {}
+
+ private:
+  friend struct DefaultRefCountedThreadSafeTraits<T>;
+  static void DeleteInternal(const T* x) { delete x; }
+
+  DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafe);
+};
+
+//
+// A thread-safe wrapper for some piece of data so we can place other
+// things in scoped_refptrs<>.
+//
+template<typename T>
+class RefCountedData
+    : public base::RefCountedThreadSafe< base::RefCountedData<T> > {
+ public:
+  RefCountedData() : data() {}
+  RefCountedData(const T& in_value) : data(in_value) {}
+
+  T data;
+
+ private:
+  friend class base::RefCountedThreadSafe<base::RefCountedData<T> >;
+  ~RefCountedData() {}
+};
+
+}  // namespace base
+
+//
+// A smart pointer class for reference counted objects.  Use this class instead
+// of calling AddRef and Release manually on a reference counted object to
+// avoid common memory leaks caused by forgetting to Release an object
+// reference.  Sample usage:
+//
+//   class MyFoo : public RefCounted<MyFoo> {
+//    ...
+//   };
+//
+//   void some_function() {
+//     scoped_refptr<MyFoo> foo = new MyFoo();
+//     foo->Method(param);
+//     // |foo| is released when this function returns
+//   }
+//
+//   void some_other_function() {
+//     scoped_refptr<MyFoo> foo = new MyFoo();
+//     ...
+//     foo = NULL;  // explicitly releases |foo|
+//     ...
+//     if (foo)
+//       foo->Method(param);
+//   }
+//
+// The above examples show how scoped_refptr<T> acts like a pointer to T.
+// Given two scoped_refptr<T> classes, it is also possible to exchange
+// references between the two objects, like so:
+//
+//   {
+//     scoped_refptr<MyFoo> a = new MyFoo();
+//     scoped_refptr<MyFoo> b;
+//
+//     b.swap(a);
+//     // now, |b| references the MyFoo object, and |a| references NULL.
+//   }
+//
+// To make both |a| and |b| in the above example reference the same MyFoo
+// object, simply use the assignment operator:
+//
+//   {
+//     scoped_refptr<MyFoo> a = new MyFoo();
+//     scoped_refptr<MyFoo> b;
+//
+//     b = a;
+//     // now, |a| and |b| each own a reference to the same MyFoo object.
+//   }
+//
+template <class T>
+class scoped_refptr {
+  TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(scoped_refptr)
+ public:
+  typedef T element_type;
+
+  scoped_refptr() : ptr_(NULL) {
+  }
+
+  scoped_refptr(T* p) : ptr_(p) {
+    if (ptr_)
+      AddRef(ptr_);
+  }
+
+  scoped_refptr(const scoped_refptr<T>& r) : ptr_(r.ptr_) {
+    if (ptr_)
+      AddRef(ptr_);
+  }
+
+  template <typename U>
+  scoped_refptr(const scoped_refptr<U>& r) : ptr_(r.get()) {
+    if (ptr_)
+      AddRef(ptr_);
+  }
+
+  template <typename U>
+  scoped_refptr(scoped_refptr<U>&& r) : ptr_(r.get()) {
+    r.ptr_ = nullptr;
+  }
+
+  ~scoped_refptr() {
+    if (ptr_)
+      Release(ptr_);
+  }
+
+  T* get() const { return ptr_; }
+
+  T& operator*() const {
+    assert(ptr_ != NULL);
+    return *ptr_;
+  }
+
+  T* operator->() const {
+    assert(ptr_ != NULL);
+    return ptr_;
+  }
+
+  scoped_refptr<T>& operator=(T* p) {
+    // AddRef first so that self assignment should work
+    if (p)
+      AddRef(p);
+    T* old_ptr = ptr_;
+    ptr_ = p;
+    if (old_ptr)
+      Release(old_ptr);
+    return *this;
+  }
+
+  scoped_refptr<T>& operator=(const scoped_refptr<T>& r) {
+    return *this = r.ptr_;
+  }
+
+  template <typename U>
+  scoped_refptr<T>& operator=(const scoped_refptr<U>& r) {
+    return *this = r.get();
+  }
+
+  scoped_refptr<T>& operator=(scoped_refptr<T>&& r) {
+    scoped_refptr<T>(r.Pass()).swap(*this);
+    return *this;
+  }
+
+  template <typename U>
+  scoped_refptr<T>& operator=(scoped_refptr<U>&& r) {
+    scoped_refptr<T>(r.Pass()).swap(*this);
+    return *this;
+  }
+
+  void swap(T** pp) {
+    T* p = ptr_;
+    ptr_ = *pp;
+    *pp = p;
+  }
+
+  void swap(scoped_refptr<T>& r) {
+    swap(&r.ptr_);
+  }
+
+ private:
+  template <typename U> friend class scoped_refptr;
+
+  // Allow scoped_refptr<T> to be used in boolean expressions, but not
+  // implicitly convertible to a real bool (which is dangerous).
+  //
+  // Note that this trick is only safe when the == and != operators
+  // are declared explicitly, as otherwise "refptr1 == refptr2"
+  // will compile but do the wrong thing (i.e., convert to Testable
+  // and then do the comparison).
+  typedef T* scoped_refptr::*Testable;
+
+ public:
+  operator Testable() const { return ptr_ ? &scoped_refptr::ptr_ : nullptr; }
+
+  template <typename U>
+  bool operator==(const scoped_refptr<U>& rhs) const {
+    return ptr_ == rhs.get();
+  }
+
+  template <typename U>
+  bool operator!=(const scoped_refptr<U>& rhs) const {
+    return !operator==(rhs);
+  }
+
+  template <typename U>
+  bool operator<(const scoped_refptr<U>& rhs) const {
+    return ptr_ < rhs.get();
+  }
+
+ protected:
+  T* ptr_;
+
+ private:
+  // Non-inline helpers to allow:
+  //     class Opaque;
+  //     extern template class scoped_refptr<Opaque>;
+  // Otherwise the compiler will complain that Opaque is an incomplete type.
+  static void AddRef(T* ptr);
+  static void Release(T* ptr);
+};
+
+template <typename T>
+void scoped_refptr<T>::AddRef(T* ptr) {
+  ptr->AddRef();
+}
+
+template <typename T>
+void scoped_refptr<T>::Release(T* ptr) {
+  ptr->Release();
+}
+
+// Handy utility for creating a scoped_refptr<T> out of a T* explicitly without
+// having to retype all the template arguments
+template <typename T>
+scoped_refptr<T> make_scoped_refptr(T* t) {
+  return scoped_refptr<T>(t);
+}
+
+// Temporary operator overloads to facilitate the transition. See
+// https://crbug.com/110610.
+template <typename T, typename U>
+bool operator==(const scoped_refptr<T>& lhs, const U* rhs) {
+  return lhs.get() == rhs;
+}
+
+template <typename T, typename U>
+bool operator==(const T* lhs, const scoped_refptr<U>& rhs) {
+  return lhs == rhs.get();
+}
+
+template <typename T, typename U>
+bool operator!=(const scoped_refptr<T>& lhs, const U* rhs) {
+  return !operator==(lhs, rhs);
+}
+
+template <typename T, typename U>
+bool operator!=(const T* lhs, const scoped_refptr<U>& rhs) {
+  return !operator==(lhs, rhs);
+}
+
+template <typename T>
+std::ostream& operator<<(std::ostream& out, const scoped_refptr<T>& p) {
+  return out << p.get();
+}
+
+#endif  // BASE_MEMORY_REF_COUNTED_H_
diff --git a/base/memory/ref_counted_delete_on_message_loop.h b/base/memory/ref_counted_delete_on_message_loop.h
new file mode 100644
index 0000000..6a109e8
--- /dev/null
+++ b/base/memory/ref_counted_delete_on_message_loop.h
@@ -0,0 +1,78 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_REF_COUNTED_DELETE_ON_MESSAGE_LOOP_H_
+#define BASE_MEMORY_REF_COUNTED_DELETE_ON_MESSAGE_LOOP_H_
+
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+// TODO(ricea): Remove the following include once all callers have been fixed.
+#include "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
+
+namespace base {
+
+// RefCountedDeleteOnMessageLoop is similar to RefCountedThreadSafe, and ensures
+// that the object will be deleted on a specified message loop.
+//
+// Sample usage:
+// class Foo : public RefCountedDeleteOnMessageLoop<Foo> {
+//
+//   Foo(const scoped_refptr<SingleThreadTaskRunner>& loop)
+//       : RefCountedDeleteOnMessageLoop<Foo>(loop) {
+//     ...
+//   }
+//   ...
+//  private:
+//   friend class RefCountedDeleteOnMessageLoop<Foo>;
+//   friend class DeleteHelper<Foo>;
+//
+//   ~Foo();
+// };
+
+// TODO(skyostil): Rename this to RefCountedDeleteOnTaskRunner.
+template <class T>
+class RefCountedDeleteOnMessageLoop : public subtle::RefCountedThreadSafeBase {
+ public:
+  // This constructor will accept a MessageL00pProxy object, but new code should
+  // prefer a SingleThreadTaskRunner. A SingleThreadTaskRunner for the
+  // MessageLoop on the current thread can be acquired by calling
+  // MessageLoop::current()->task_runner().
+  RefCountedDeleteOnMessageLoop(
+      const scoped_refptr<SingleThreadTaskRunner>& task_runner)
+      : task_runner_(task_runner) {
+    DCHECK(task_runner_);
+  }
+
+  void AddRef() const {
+    subtle::RefCountedThreadSafeBase::AddRef();
+  }
+
+  void Release() const {
+    if (subtle::RefCountedThreadSafeBase::Release())
+      DestructOnMessageLoop();
+  }
+
+ protected:
+  friend class DeleteHelper<RefCountedDeleteOnMessageLoop>;
+  ~RefCountedDeleteOnMessageLoop() {}
+
+  void DestructOnMessageLoop() const {
+    const T* t = static_cast<const T*>(this);
+    if (task_runner_->BelongsToCurrentThread())
+      delete t;
+    else
+      task_runner_->DeleteSoon(FROM_HERE, t);
+  }
+
+  scoped_refptr<SingleThreadTaskRunner> task_runner_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(RefCountedDeleteOnMessageLoop);
+};
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_REF_COUNTED_DELETE_ON_MESSAGE_LOOP_H_
diff --git a/base/memory/ref_counted_memory.cc b/base/memory/ref_counted_memory.cc
new file mode 100644
index 0000000..477c941
--- /dev/null
+++ b/base/memory/ref_counted_memory.cc
@@ -0,0 +1,100 @@
+// Copyright (c) 2012 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/memory/ref_counted_memory.h"
+
+#include <stdlib.h>
+
+#include "base/logging.h"
+
+namespace base {
+
+bool RefCountedMemory::Equals(
+    const scoped_refptr<RefCountedMemory>& other) const {
+  return other.get() &&
+         size() == other->size() &&
+         (memcmp(front(), other->front(), size()) == 0);
+}
+
+RefCountedMemory::RefCountedMemory() {}
+
+RefCountedMemory::~RefCountedMemory() {}
+
+const unsigned char* RefCountedStaticMemory::front() const {
+  return data_;
+}
+
+size_t RefCountedStaticMemory::size() const {
+  return length_;
+}
+
+RefCountedStaticMemory::~RefCountedStaticMemory() {}
+
+RefCountedBytes::RefCountedBytes() {}
+
+RefCountedBytes::RefCountedBytes(const std::vector<unsigned char>& initializer)
+    : data_(initializer) {
+}
+
+RefCountedBytes::RefCountedBytes(const unsigned char* p, size_t size)
+    : data_(p, p + size) {}
+
+RefCountedBytes* RefCountedBytes::TakeVector(
+    std::vector<unsigned char>* to_destroy) {
+  RefCountedBytes* bytes = new RefCountedBytes;
+  bytes->data_.swap(*to_destroy);
+  return bytes;
+}
+
+const unsigned char* RefCountedBytes::front() const {
+  // STL will assert if we do front() on an empty vector, but calling code
+  // expects a NULL.
+  return size() ? &data_.front() : NULL;
+}
+
+size_t RefCountedBytes::size() const {
+  return data_.size();
+}
+
+RefCountedBytes::~RefCountedBytes() {}
+
+RefCountedString::RefCountedString() {}
+
+RefCountedString::~RefCountedString() {}
+
+// static
+RefCountedString* RefCountedString::TakeString(std::string* to_destroy) {
+  RefCountedString* self = new RefCountedString;
+  to_destroy->swap(self->data_);
+  return self;
+}
+
+const unsigned char* RefCountedString::front() const {
+  return data_.empty() ? NULL :
+         reinterpret_cast<const unsigned char*>(data_.data());
+}
+
+size_t RefCountedString::size() const {
+  return data_.size();
+}
+
+RefCountedMallocedMemory::RefCountedMallocedMemory(
+    void* data, size_t length)
+    : data_(reinterpret_cast<unsigned char*>(data)), length_(length) {
+  DCHECK(data || length == 0);
+}
+
+const unsigned char* RefCountedMallocedMemory::front() const {
+  return length_ ? data_ : NULL;
+}
+
+size_t RefCountedMallocedMemory::size() const {
+  return length_;
+}
+
+RefCountedMallocedMemory::~RefCountedMallocedMemory() {
+  free(data_);
+}
+
+}  //  namespace base
diff --git a/base/memory/ref_counted_memory.h b/base/memory/ref_counted_memory.h
new file mode 100644
index 0000000..66dc65f
--- /dev/null
+++ b/base/memory/ref_counted_memory.h
@@ -0,0 +1,146 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_REF_COUNTED_MEMORY_H_
+#define BASE_MEMORY_REF_COUNTED_MEMORY_H_
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+
+namespace base {
+
+// A generic interface to memory. This object is reference counted because one
+// of its two subclasses own the data they carry, and we need to have
+// heterogeneous containers of these two types of memory.
+class BASE_EXPORT RefCountedMemory
+    : public base::RefCountedThreadSafe<RefCountedMemory> {
+ public:
+  // Retrieves a pointer to the beginning of the data we point to. If the data
+  // is empty, this will return NULL.
+  virtual const unsigned char* front() const = 0;
+
+  // Size of the memory pointed to.
+  virtual size_t size() const = 0;
+
+  // Returns true if |other| is byte for byte equal.
+  bool Equals(const scoped_refptr<RefCountedMemory>& other) const;
+
+  // Handy method to simplify calling front() with a reinterpret_cast.
+  template<typename T> const T* front_as() const {
+    return reinterpret_cast<const T*>(front());
+  }
+
+ protected:
+  friend class base::RefCountedThreadSafe<RefCountedMemory>;
+  RefCountedMemory();
+  virtual ~RefCountedMemory();
+};
+
+// An implementation of RefCountedMemory, where the ref counting does not
+// matter.
+class BASE_EXPORT RefCountedStaticMemory : public RefCountedMemory {
+ public:
+  RefCountedStaticMemory()
+      : data_(NULL), length_(0) {}
+  RefCountedStaticMemory(const void* data, size_t length)
+      : data_(static_cast<const unsigned char*>(length ? data : NULL)),
+        length_(length) {}
+
+  // Overridden from RefCountedMemory:
+  const unsigned char* front() const override;
+  size_t size() const override;
+
+ private:
+  ~RefCountedStaticMemory() override;
+
+  const unsigned char* data_;
+  size_t length_;
+
+  DISALLOW_COPY_AND_ASSIGN(RefCountedStaticMemory);
+};
+
+// An implementation of RefCountedMemory, where we own the data in a vector.
+class BASE_EXPORT RefCountedBytes : public RefCountedMemory {
+ public:
+  RefCountedBytes();
+
+  // Constructs a RefCountedBytes object by _copying_ from |initializer|.
+  explicit RefCountedBytes(const std::vector<unsigned char>& initializer);
+
+  // Constructs a RefCountedBytes object by copying |size| bytes from |p|.
+  RefCountedBytes(const unsigned char* p, size_t size);
+
+  // Constructs a RefCountedBytes object by performing a swap. (To non
+  // destructively build a RefCountedBytes, use the constructor that takes a
+  // vector.)
+  static RefCountedBytes* TakeVector(std::vector<unsigned char>* to_destroy);
+
+  // Overridden from RefCountedMemory:
+  const unsigned char* front() const override;
+  size_t size() const override;
+
+  const std::vector<unsigned char>& data() const { return data_; }
+  std::vector<unsigned char>& data() { return data_; }
+
+ private:
+  ~RefCountedBytes() override;
+
+  std::vector<unsigned char> data_;
+
+  DISALLOW_COPY_AND_ASSIGN(RefCountedBytes);
+};
+
+// An implementation of RefCountedMemory, where the bytes are stored in an STL
+// string. Use this if your data naturally arrives in that format.
+class BASE_EXPORT RefCountedString : public RefCountedMemory {
+ public:
+  RefCountedString();
+
+  // Constructs a RefCountedString object by performing a swap. (To non
+  // destructively build a RefCountedString, use the default constructor and
+  // copy into object->data()).
+  static RefCountedString* TakeString(std::string* to_destroy);
+
+  // Overridden from RefCountedMemory:
+  const unsigned char* front() const override;
+  size_t size() const override;
+
+  const std::string& data() const { return data_; }
+  std::string& data() { return data_; }
+
+ private:
+  ~RefCountedString() override;
+
+  std::string data_;
+
+  DISALLOW_COPY_AND_ASSIGN(RefCountedString);
+};
+
+// An implementation of RefCountedMemory that holds a chunk of memory
+// previously allocated with malloc or calloc, and that therefore must be freed
+// using free().
+class BASE_EXPORT RefCountedMallocedMemory : public base::RefCountedMemory {
+ public:
+  RefCountedMallocedMemory(void* data, size_t length);
+
+  // Overridden from RefCountedMemory:
+  const unsigned char* front() const override;
+  size_t size() const override;
+
+ private:
+  ~RefCountedMallocedMemory() override;
+
+  unsigned char* data_;
+  size_t length_;
+
+  DISALLOW_COPY_AND_ASSIGN(RefCountedMallocedMemory);
+};
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_REF_COUNTED_MEMORY_H_
diff --git a/base/memory/ref_counted_memory_unittest.cc b/base/memory/ref_counted_memory_unittest.cc
new file mode 100644
index 0000000..5bfc1c7
--- /dev/null
+++ b/base/memory/ref_counted_memory_unittest.cc
@@ -0,0 +1,89 @@
+// Copyright (c) 2011 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/memory/ref_counted_memory.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(RefCountedMemoryUnitTest, RefCountedStaticMemory) {
+  scoped_refptr<RefCountedMemory> mem = new RefCountedStaticMemory(
+      "static mem00", 10);
+
+  EXPECT_EQ(10U, mem->size());
+  EXPECT_EQ("static mem", std::string(mem->front_as<char>(), mem->size()));
+}
+
+TEST(RefCountedMemoryUnitTest, RefCountedBytes) {
+  std::vector<uint8> data;
+  data.push_back(45);
+  data.push_back(99);
+  scoped_refptr<RefCountedMemory> mem = RefCountedBytes::TakeVector(&data);
+
+  EXPECT_EQ(0U, data.size());
+
+  EXPECT_EQ(2U, mem->size());
+  EXPECT_EQ(45U, mem->front()[0]);
+  EXPECT_EQ(99U, mem->front()[1]);
+
+  scoped_refptr<RefCountedMemory> mem2;
+  {
+    unsigned char data2[] = { 12, 11, 99 };
+    mem2 = new RefCountedBytes(data2, 3);
+  }
+  EXPECT_EQ(3U, mem2->size());
+  EXPECT_EQ(12U, mem2->front()[0]);
+  EXPECT_EQ(11U, mem2->front()[1]);
+  EXPECT_EQ(99U, mem2->front()[2]);
+}
+
+TEST(RefCountedMemoryUnitTest, RefCountedString) {
+  std::string s("destroy me");
+  scoped_refptr<RefCountedMemory> mem = RefCountedString::TakeString(&s);
+
+  EXPECT_EQ(0U, s.size());
+
+  EXPECT_EQ(10U, mem->size());
+  EXPECT_EQ('d', mem->front()[0]);
+  EXPECT_EQ('e', mem->front()[1]);
+}
+
+TEST(RefCountedMemoryUnitTest, RefCountedMallocedMemory) {
+  void* data = malloc(6);
+  memcpy(data, "hello", 6);
+
+  scoped_refptr<RefCountedMemory> mem = new RefCountedMallocedMemory(data, 6);
+
+  EXPECT_EQ(6U, mem->size());
+  EXPECT_EQ(0, memcmp("hello", mem->front(), 6));
+}
+
+TEST(RefCountedMemoryUnitTest, Equals) {
+  std::string s1("same");
+  scoped_refptr<RefCountedMemory> mem1 = RefCountedString::TakeString(&s1);
+
+  std::vector<unsigned char> d2;
+  d2.push_back('s');
+  d2.push_back('a');
+  d2.push_back('m');
+  d2.push_back('e');
+  scoped_refptr<RefCountedMemory> mem2 = RefCountedBytes::TakeVector(&d2);
+
+  EXPECT_TRUE(mem1->Equals(mem2));
+
+  std::string s3("diff");
+  scoped_refptr<RefCountedMemory> mem3 = RefCountedString::TakeString(&s3);
+
+  EXPECT_FALSE(mem1->Equals(mem3));
+  EXPECT_FALSE(mem2->Equals(mem3));
+}
+
+TEST(RefCountedMemoryUnitTest, EqualsNull) {
+  std::string s("str");
+  scoped_refptr<RefCountedMemory> mem = RefCountedString::TakeString(&s);
+  EXPECT_FALSE(mem->Equals(NULL));
+}
+
+}  //  namespace base
diff --git a/base/memory/ref_counted_unittest.cc b/base/memory/ref_counted_unittest.cc
new file mode 100644
index 0000000..6f8e599
--- /dev/null
+++ b/base/memory/ref_counted_unittest.cc
@@ -0,0 +1,462 @@
+// Copyright (c) 2012 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/memory/ref_counted.h"
+
+#include "base/test/opaque_ref_counted.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class SelfAssign : public base::RefCounted<SelfAssign> {
+ protected:
+  virtual ~SelfAssign() {}
+
+ private:
+  friend class base::RefCounted<SelfAssign>;
+};
+
+class Derived : public SelfAssign {
+ protected:
+  ~Derived() override {}
+
+ private:
+  friend class base::RefCounted<Derived>;
+};
+
+class CheckDerivedMemberAccess : public scoped_refptr<SelfAssign> {
+ public:
+  CheckDerivedMemberAccess() {
+    // This shouldn't compile if we don't have access to the member variable.
+    SelfAssign** pptr = &ptr_;
+    EXPECT_EQ(*pptr, ptr_);
+  }
+};
+
+class ScopedRefPtrToSelf : public base::RefCounted<ScopedRefPtrToSelf> {
+ public:
+  ScopedRefPtrToSelf() : self_ptr_(this) {}
+
+  static bool was_destroyed() { return was_destroyed_; }
+
+  static void reset_was_destroyed() { was_destroyed_ = false; }
+
+  scoped_refptr<ScopedRefPtrToSelf> self_ptr_;
+
+ private:
+  friend class base::RefCounted<ScopedRefPtrToSelf>;
+  ~ScopedRefPtrToSelf() { was_destroyed_ = true; }
+
+  static bool was_destroyed_;
+};
+
+bool ScopedRefPtrToSelf::was_destroyed_ = false;
+
+class ScopedRefPtrCountBase : public base::RefCounted<ScopedRefPtrCountBase> {
+ public:
+  ScopedRefPtrCountBase() { ++constructor_count_; }
+
+  static int constructor_count() { return constructor_count_; }
+
+  static int destructor_count() { return destructor_count_; }
+
+  static void reset_count() {
+    constructor_count_ = 0;
+    destructor_count_ = 0;
+  }
+
+ protected:
+  virtual ~ScopedRefPtrCountBase() { ++destructor_count_; }
+
+ private:
+  friend class base::RefCounted<ScopedRefPtrCountBase>;
+
+  static int constructor_count_;
+  static int destructor_count_;
+};
+
+int ScopedRefPtrCountBase::constructor_count_ = 0;
+int ScopedRefPtrCountBase::destructor_count_ = 0;
+
+class ScopedRefPtrCountDerived : public ScopedRefPtrCountBase {
+ public:
+  ScopedRefPtrCountDerived() { ++constructor_count_; }
+
+  static int constructor_count() { return constructor_count_; }
+
+  static int destructor_count() { return destructor_count_; }
+
+  static void reset_count() {
+    constructor_count_ = 0;
+    destructor_count_ = 0;
+  }
+
+ protected:
+  ~ScopedRefPtrCountDerived() override { ++destructor_count_; }
+
+ private:
+  friend class base::RefCounted<ScopedRefPtrCountDerived>;
+
+  static int constructor_count_;
+  static int destructor_count_;
+};
+
+int ScopedRefPtrCountDerived::constructor_count_ = 0;
+int ScopedRefPtrCountDerived::destructor_count_ = 0;
+
+}  // end namespace
+
+TEST(RefCountedUnitTest, TestSelfAssignment) {
+  SelfAssign* p = new SelfAssign;
+  scoped_refptr<SelfAssign> var(p);
+  var = var;
+  EXPECT_EQ(var.get(), p);
+}
+
+TEST(RefCountedUnitTest, ScopedRefPtrMemberAccess) {
+  CheckDerivedMemberAccess check;
+}
+
+TEST(RefCountedUnitTest, ScopedRefPtrToSelfPointerAssignment) {
+  ScopedRefPtrToSelf::reset_was_destroyed();
+
+  ScopedRefPtrToSelf* check = new ScopedRefPtrToSelf();
+  EXPECT_FALSE(ScopedRefPtrToSelf::was_destroyed());
+  check->self_ptr_ = nullptr;
+  EXPECT_TRUE(ScopedRefPtrToSelf::was_destroyed());
+}
+
+TEST(RefCountedUnitTest, ScopedRefPtrToSelfMoveAssignment) {
+  ScopedRefPtrToSelf::reset_was_destroyed();
+
+  ScopedRefPtrToSelf* check = new ScopedRefPtrToSelf();
+  EXPECT_FALSE(ScopedRefPtrToSelf::was_destroyed());
+  // Releasing |check->self_ptr_| will delete |check|.
+  // The move assignment operator must assign |check->self_ptr_| first then
+  // release |check->self_ptr_|.
+  check->self_ptr_ = scoped_refptr<ScopedRefPtrToSelf>();
+  EXPECT_TRUE(ScopedRefPtrToSelf::was_destroyed());
+}
+
+TEST(RefCountedUnitTest, ScopedRefPtrToOpaque) {
+  scoped_refptr<base::OpaqueRefCounted> p = base::MakeOpaqueRefCounted();
+  base::TestOpaqueRefCounted(p);
+
+  scoped_refptr<base::OpaqueRefCounted> q;
+  q = p;
+  base::TestOpaqueRefCounted(p);
+  base::TestOpaqueRefCounted(q);
+}
+
+TEST(RefCountedUnitTest, BooleanTesting) {
+  scoped_refptr<SelfAssign> p;
+  EXPECT_FALSE(p);
+  p = new SelfAssign;
+  EXPECT_TRUE(p);
+}
+
+TEST(RefCountedUnitTest, Equality) {
+  scoped_refptr<SelfAssign> p1(new SelfAssign);
+  scoped_refptr<SelfAssign> p2(new SelfAssign);
+
+  EXPECT_EQ(p1, p1);
+  EXPECT_EQ(p2, p2);
+
+  EXPECT_NE(p1, p2);
+  EXPECT_NE(p2, p1);
+}
+
+TEST(RefCountedUnitTest, ConvertibleEquality) {
+  scoped_refptr<Derived> p1(new Derived);
+  scoped_refptr<SelfAssign> p2;
+
+  EXPECT_NE(p1, p2);
+  EXPECT_NE(p2, p1);
+
+  p2 = p1;
+
+  EXPECT_EQ(p1, p2);
+  EXPECT_EQ(p2, p1);
+}
+
+TEST(RefCountedUnitTest, SelfMoveAssignment) {
+  ScopedRefPtrCountBase::reset_count();
+
+  {
+    ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase();
+    scoped_refptr<ScopedRefPtrCountBase> p(raw);
+    EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+    EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+
+    p = p.Pass();
+    EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+    EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+    EXPECT_EQ(raw, p.get());
+
+    // p goes out of scope.
+  }
+  EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+  EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+}
+
+TEST(RefCountedUnitTest, MoveAssignment1) {
+  ScopedRefPtrCountBase::reset_count();
+
+  {
+    ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase();
+    scoped_refptr<ScopedRefPtrCountBase> p1(raw);
+    EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+    EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+
+    {
+      scoped_refptr<ScopedRefPtrCountBase> p2;
+
+      p2 = p1.Pass();
+      EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+      EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+      EXPECT_EQ(nullptr, p1.get());
+      EXPECT_EQ(raw, p2.get());
+
+      // p2 goes out of scope.
+    }
+    EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+    EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+
+    // p1 goes out of scope.
+  }
+  EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+  EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+}
+
+TEST(RefCountedUnitTest, MoveAssignment2) {
+  ScopedRefPtrCountBase::reset_count();
+
+  {
+    ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase();
+    scoped_refptr<ScopedRefPtrCountBase> p1;
+    EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+    EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+
+    {
+      scoped_refptr<ScopedRefPtrCountBase> p2(raw);
+      EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+      EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+
+      p1 = p2.Pass();
+      EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+      EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+      EXPECT_EQ(raw, p1.get());
+      EXPECT_EQ(nullptr, p2.get());
+
+      // p2 goes out of scope.
+    }
+    EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+    EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+
+    // p1 goes out of scope.
+  }
+  EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+  EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+}
+
+TEST(RefCountedUnitTest, MoveAssignmentSameInstance1) {
+  ScopedRefPtrCountBase::reset_count();
+
+  {
+    ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase();
+    scoped_refptr<ScopedRefPtrCountBase> p1(raw);
+    EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+    EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+
+    {
+      scoped_refptr<ScopedRefPtrCountBase> p2(p1);
+      EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+      EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+
+      p1 = p2.Pass();
+      EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+      EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+      EXPECT_EQ(raw, p1.get());
+      EXPECT_EQ(nullptr, p2.get());
+
+      // p2 goes out of scope.
+    }
+    EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+    EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+
+    // p1 goes out of scope.
+  }
+  EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+  EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+}
+
+TEST(RefCountedUnitTest, MoveAssignmentSameInstance2) {
+  ScopedRefPtrCountBase::reset_count();
+
+  {
+    ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase();
+    scoped_refptr<ScopedRefPtrCountBase> p1(raw);
+    EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+    EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+
+    {
+      scoped_refptr<ScopedRefPtrCountBase> p2(p1);
+      EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+      EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+
+      p2 = p1.Pass();
+      EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+      EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+      EXPECT_EQ(nullptr, p1.get());
+      EXPECT_EQ(raw, p2.get());
+
+      // p2 goes out of scope.
+    }
+    EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+    EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+
+    // p1 goes out of scope.
+  }
+  EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+  EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+}
+
+TEST(RefCountedUnitTest, MoveAssignmentDifferentInstances) {
+  ScopedRefPtrCountBase::reset_count();
+
+  {
+    ScopedRefPtrCountBase *raw1 = new ScopedRefPtrCountBase();
+    scoped_refptr<ScopedRefPtrCountBase> p1(raw1);
+    EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+    EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+
+    {
+      ScopedRefPtrCountBase *raw2 = new ScopedRefPtrCountBase();
+      scoped_refptr<ScopedRefPtrCountBase> p2(raw2);
+      EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
+      EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+
+      p1 = p2.Pass();
+      EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
+      EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+      EXPECT_EQ(raw2, p1.get());
+      EXPECT_EQ(nullptr, p2.get());
+
+      // p2 goes out of scope.
+    }
+    EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
+    EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+
+    // p1 goes out of scope.
+  }
+  EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
+  EXPECT_EQ(2, ScopedRefPtrCountBase::destructor_count());
+}
+
+TEST(RefCountedUnitTest, MoveAssignmentDerived) {
+  ScopedRefPtrCountBase::reset_count();
+  ScopedRefPtrCountDerived::reset_count();
+
+  {
+    ScopedRefPtrCountBase *raw1 = new ScopedRefPtrCountBase();
+    scoped_refptr<ScopedRefPtrCountBase> p1(raw1);
+    EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+    EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+    EXPECT_EQ(0, ScopedRefPtrCountDerived::constructor_count());
+    EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count());
+
+    {
+      ScopedRefPtrCountDerived *raw2 = new ScopedRefPtrCountDerived();
+      scoped_refptr<ScopedRefPtrCountDerived> p2(raw2);
+      EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
+      EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+      EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
+      EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count());
+
+      p1 = p2.Pass();
+      EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
+      EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+      EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
+      EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count());
+      EXPECT_EQ(raw2, p1.get());
+      EXPECT_EQ(nullptr, p2.get());
+
+      // p2 goes out of scope.
+    }
+    EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
+    EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+    EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
+    EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count());
+
+    // p1 goes out of scope.
+  }
+  EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
+  EXPECT_EQ(2, ScopedRefPtrCountBase::destructor_count());
+  EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
+  EXPECT_EQ(1, ScopedRefPtrCountDerived::destructor_count());
+}
+
+TEST(RefCountedUnitTest, MoveConstructor) {
+  ScopedRefPtrCountBase::reset_count();
+
+  {
+    ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase();
+    scoped_refptr<ScopedRefPtrCountBase> p1(raw);
+    EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+    EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+
+    {
+      scoped_refptr<ScopedRefPtrCountBase> p2(p1.Pass());
+      EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+      EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+      EXPECT_EQ(nullptr, p1.get());
+      EXPECT_EQ(raw, p2.get());
+
+      // p2 goes out of scope.
+    }
+    EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+    EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+
+    // p1 goes out of scope.
+  }
+  EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+  EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+}
+
+TEST(RefCountedUnitTest, MoveConstructorDerived) {
+  ScopedRefPtrCountBase::reset_count();
+  ScopedRefPtrCountDerived::reset_count();
+
+  {
+    ScopedRefPtrCountDerived *raw1 = new ScopedRefPtrCountDerived();
+    scoped_refptr<ScopedRefPtrCountDerived> p1(raw1);
+    EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+    EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+    EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
+    EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count());
+
+    {
+      scoped_refptr<ScopedRefPtrCountBase> p2(p1.Pass());
+      EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+      EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
+      EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
+      EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count());
+      EXPECT_EQ(nullptr, p1.get());
+      EXPECT_EQ(raw1, p2.get());
+
+      // p2 goes out of scope.
+    }
+    EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+    EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+    EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
+    EXPECT_EQ(1, ScopedRefPtrCountDerived::destructor_count());
+
+    // p1 goes out of scope.
+  }
+  EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
+  EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
+  EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
+  EXPECT_EQ(1, ScopedRefPtrCountDerived::destructor_count());
+}
+
diff --git a/base/memory/scoped_policy.h b/base/memory/scoped_policy.h
new file mode 100644
index 0000000..5dbf204
--- /dev/null
+++ b/base/memory/scoped_policy.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_SCOPED_POLICY_H_
+#define BASE_MEMORY_SCOPED_POLICY_H_
+
+namespace base {
+namespace scoped_policy {
+
+// Defines the ownership policy for a scoped object.
+enum OwnershipPolicy {
+  // The scoped object takes ownership of an object by taking over an existing
+  // ownership claim.
+  ASSUME,
+
+  // The scoped object will retain the the object and any initial ownership is
+  // not changed.
+  RETAIN
+};
+
+}  // namespace scoped_policy
+}  // namespace base
+
+#endif  // BASE_MEMORY_SCOPED_POLICY_H_
diff --git a/base/memory/scoped_ptr.h b/base/memory/scoped_ptr.h
new file mode 100644
index 0000000..987ccfa
--- /dev/null
+++ b/base/memory/scoped_ptr.h
@@ -0,0 +1,594 @@
+// Copyright (c) 2012 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.
+
+// Scopers help you manage ownership of a pointer, helping you easily manage a
+// pointer within a scope, and automatically destroying the pointer at the end
+// of a scope.  There are two main classes you will use, which correspond to the
+// operators new/delete and new[]/delete[].
+//
+// Example usage (scoped_ptr<T>):
+//   {
+//     scoped_ptr<Foo> foo(new Foo("wee"));
+//   }  // foo goes out of scope, releasing the pointer with it.
+//
+//   {
+//     scoped_ptr<Foo> foo;          // No pointer managed.
+//     foo.reset(new Foo("wee"));    // Now a pointer is managed.
+//     foo.reset(new Foo("wee2"));   // Foo("wee") was destroyed.
+//     foo.reset(new Foo("wee3"));   // Foo("wee2") was destroyed.
+//     foo->Method();                // Foo::Method() called.
+//     foo.get()->Method();          // Foo::Method() called.
+//     SomeFunc(foo.release());      // SomeFunc takes ownership, foo no longer
+//                                   // manages a pointer.
+//     foo.reset(new Foo("wee4"));   // foo manages a pointer again.
+//     foo.reset();                  // Foo("wee4") destroyed, foo no longer
+//                                   // manages a pointer.
+//   }  // foo wasn't managing a pointer, so nothing was destroyed.
+//
+// Example usage (scoped_ptr<T[]>):
+//   {
+//     scoped_ptr<Foo[]> foo(new Foo[100]);
+//     foo.get()->Method();  // Foo::Method on the 0th element.
+//     foo[10].Method();     // Foo::Method on the 10th element.
+//   }
+//
+// These scopers also implement part of the functionality of C++11 unique_ptr
+// in that they are "movable but not copyable."  You can use the scopers in
+// the parameter and return types of functions to signify ownership transfer
+// in to and out of a function.  When calling a function that has a scoper
+// as the argument type, it must be called with the result of an analogous
+// scoper's Pass() function or another function that generates a temporary;
+// passing by copy will NOT work.  Here is an example using scoped_ptr:
+//
+//   void TakesOwnership(scoped_ptr<Foo> arg) {
+//     // Do something with arg
+//   }
+//   scoped_ptr<Foo> CreateFoo() {
+//     // No need for calling Pass() because we are constructing a temporary
+//     // for the return value.
+//     return scoped_ptr<Foo>(new Foo("new"));
+//   }
+//   scoped_ptr<Foo> PassThru(scoped_ptr<Foo> arg) {
+//     return arg.Pass();
+//   }
+//
+//   {
+//     scoped_ptr<Foo> ptr(new Foo("yay"));  // ptr manages Foo("yay").
+//     TakesOwnership(ptr.Pass());           // ptr no longer owns Foo("yay").
+//     scoped_ptr<Foo> ptr2 = CreateFoo();   // ptr2 owns the return Foo.
+//     scoped_ptr<Foo> ptr3 =                // ptr3 now owns what was in ptr2.
+//         PassThru(ptr2.Pass());            // ptr2 is correspondingly nullptr.
+//   }
+//
+// Notice that if you do not call Pass() when returning from PassThru(), or
+// when invoking TakesOwnership(), the code will not compile because scopers
+// are not copyable; they only implement move semantics which require calling
+// the Pass() function to signify a destructive transfer of state. CreateFoo()
+// is different though because we are constructing a temporary on the return
+// line and thus can avoid needing to call Pass().
+//
+// Pass() properly handles upcast in initialization, i.e. you can use a
+// scoped_ptr<Child> to initialize a scoped_ptr<Parent>:
+//
+//   scoped_ptr<Foo> foo(new Foo());
+//   scoped_ptr<FooParent> parent(foo.Pass());
+
+#ifndef BASE_MEMORY_SCOPED_PTR_H_
+#define BASE_MEMORY_SCOPED_PTR_H_
+
+// This is an implementation designed to match the anticipated future TR2
+// implementation of the scoped_ptr class.
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+#include <algorithm>  // For std::swap().
+#include <iosfwd>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/move.h"
+#include "base/template_util.h"
+
+namespace base {
+
+namespace subtle {
+class RefCountedBase;
+class RefCountedThreadSafeBase;
+}  // namespace subtle
+
+// Function object which deletes its parameter, which must be a pointer.
+// If C is an array type, invokes 'delete[]' on the parameter; otherwise,
+// invokes 'delete'. The default deleter for scoped_ptr<T>.
+template <class T>
+struct DefaultDeleter {
+  DefaultDeleter() {}
+  template <typename U> DefaultDeleter(const DefaultDeleter<U>& other) {
+    // IMPLEMENTATION NOTE: C++11 20.7.1.1.2p2 only provides this constructor
+    // if U* is implicitly convertible to T* and U is not an array type.
+    //
+    // Correct implementation should use SFINAE to disable this
+    // constructor. However, since there are no other 1-argument constructors,
+    // using a COMPILE_ASSERT() based on is_convertible<> and requiring
+    // complete types is simpler and will cause compile failures for equivalent
+    // misuses.
+    //
+    // Note, the is_convertible<U*, T*> check also ensures that U is not an
+    // array. T is guaranteed to be a non-array, so any U* where U is an array
+    // cannot convert to T*.
+    enum { T_must_be_complete = sizeof(T) };
+    enum { U_must_be_complete = sizeof(U) };
+    COMPILE_ASSERT((base::is_convertible<U*, T*>::value),
+                   U_ptr_must_implicitly_convert_to_T_ptr);
+  }
+  inline void operator()(T* ptr) const {
+    enum { type_must_be_complete = sizeof(T) };
+    delete ptr;
+  }
+};
+
+// Specialization of DefaultDeleter for array types.
+template <class T>
+struct DefaultDeleter<T[]> {
+  inline void operator()(T* ptr) const {
+    enum { type_must_be_complete = sizeof(T) };
+    delete[] ptr;
+  }
+
+ private:
+  // Disable this operator for any U != T because it is undefined to execute
+  // an array delete when the static type of the array mismatches the dynamic
+  // type.
+  //
+  // References:
+  //   C++98 [expr.delete]p3
+  //   http://cplusplus.github.com/LWG/lwg-defects.html#938
+  template <typename U> void operator()(U* array) const;
+};
+
+template <class T, int n>
+struct DefaultDeleter<T[n]> {
+  // Never allow someone to declare something like scoped_ptr<int[10]>.
+  COMPILE_ASSERT(sizeof(T) == -1, do_not_use_array_with_size_as_type);
+};
+
+// Function object which invokes 'free' on its parameter, which must be
+// a pointer. Can be used to store malloc-allocated pointers in scoped_ptr:
+//
+// scoped_ptr<int, base::FreeDeleter> foo_ptr(
+//     static_cast<int*>(malloc(sizeof(int))));
+struct FreeDeleter {
+  inline void operator()(void* ptr) const {
+    free(ptr);
+  }
+};
+
+namespace internal {
+
+template <typename T> struct IsNotRefCounted {
+  enum {
+    value = !base::is_convertible<T*, base::subtle::RefCountedBase*>::value &&
+        !base::is_convertible<T*, base::subtle::RefCountedThreadSafeBase*>::
+            value
+  };
+};
+
+template <typename T>
+struct ShouldAbortOnSelfReset {
+  template <typename U>
+  static NoType Test(const typename U::AllowSelfReset*);
+
+  template <typename U>
+  static YesType Test(...);
+
+  static const bool value = sizeof(Test<T>(0)) == sizeof(YesType);
+};
+
+// Minimal implementation of the core logic of scoped_ptr, suitable for
+// reuse in both scoped_ptr and its specializations.
+template <class T, class D>
+class scoped_ptr_impl {
+ public:
+  explicit scoped_ptr_impl(T* p) : data_(p) {}
+
+  // Initializer for deleters that have data parameters.
+  scoped_ptr_impl(T* p, const D& d) : data_(p, d) {}
+
+  // Templated constructor that destructively takes the value from another
+  // scoped_ptr_impl.
+  template <typename U, typename V>
+  scoped_ptr_impl(scoped_ptr_impl<U, V>* other)
+      : data_(other->release(), other->get_deleter()) {
+    // We do not support move-only deleters.  We could modify our move
+    // emulation to have base::subtle::move() and base::subtle::forward()
+    // functions that are imperfect emulations of their C++11 equivalents,
+    // but until there's a requirement, just assume deleters are copyable.
+  }
+
+  template <typename U, typename V>
+  void TakeState(scoped_ptr_impl<U, V>* other) {
+    // See comment in templated constructor above regarding lack of support
+    // for move-only deleters.
+    reset(other->release());
+    get_deleter() = other->get_deleter();
+  }
+
+  ~scoped_ptr_impl() {
+    if (data_.ptr != nullptr) {
+      // Not using get_deleter() saves one function call in non-optimized
+      // builds.
+      static_cast<D&>(data_)(data_.ptr);
+    }
+  }
+
+  void reset(T* p) {
+    // This is a self-reset, which is no longer allowed for default deleters:
+    // https://crbug.com/162971
+    assert(!ShouldAbortOnSelfReset<D>::value || p == nullptr || p != data_.ptr);
+
+    // Note that running data_.ptr = p can lead to undefined behavior if
+    // get_deleter()(get()) deletes this. In order to prevent this, reset()
+    // should update the stored pointer before deleting its old value.
+    //
+    // However, changing reset() to use that behavior may cause current code to
+    // break in unexpected ways. If the destruction of the owned object
+    // dereferences the scoped_ptr when it is destroyed by a call to reset(),
+    // then it will incorrectly dispatch calls to |p| rather than the original
+    // value of |data_.ptr|.
+    //
+    // During the transition period, set the stored pointer to nullptr while
+    // deleting the object. Eventually, this safety check will be removed to
+    // prevent the scenario initially described from occuring and
+    // http://crbug.com/176091 can be closed.
+    T* old = data_.ptr;
+    data_.ptr = nullptr;
+    if (old != nullptr)
+      static_cast<D&>(data_)(old);
+    data_.ptr = p;
+  }
+
+  T* get() const { return data_.ptr; }
+
+  D& get_deleter() { return data_; }
+  const D& get_deleter() const { return data_; }
+
+  void swap(scoped_ptr_impl& p2) {
+    // Standard swap idiom: 'using std::swap' ensures that std::swap is
+    // present in the overload set, but we call swap unqualified so that
+    // any more-specific overloads can be used, if available.
+    using std::swap;
+    swap(static_cast<D&>(data_), static_cast<D&>(p2.data_));
+    swap(data_.ptr, p2.data_.ptr);
+  }
+
+  T* release() {
+    T* old_ptr = data_.ptr;
+    data_.ptr = nullptr;
+    return old_ptr;
+  }
+
+ private:
+  // Needed to allow type-converting constructor.
+  template <typename U, typename V> friend class scoped_ptr_impl;
+
+  // Use the empty base class optimization to allow us to have a D
+  // member, while avoiding any space overhead for it when D is an
+  // empty class.  See e.g. http://www.cantrip.org/emptyopt.html for a good
+  // discussion of this technique.
+  struct Data : public D {
+    explicit Data(T* ptr_in) : ptr(ptr_in) {}
+    Data(T* ptr_in, const D& other) : D(other), ptr(ptr_in) {}
+    T* ptr;
+  };
+
+  Data data_;
+
+  DISALLOW_COPY_AND_ASSIGN(scoped_ptr_impl);
+};
+
+}  // namespace internal
+
+}  // namespace base
+
+// A scoped_ptr<T> is like a T*, except that the destructor of scoped_ptr<T>
+// automatically deletes the pointer it holds (if any).
+// That is, scoped_ptr<T> owns the T object that it points to.
+// Like a T*, a scoped_ptr<T> may hold either nullptr or a pointer to a T
+// object. Also like T*, scoped_ptr<T> is thread-compatible, and once you
+// dereference it, you get the thread safety guarantees of T.
+//
+// The size of scoped_ptr is small. On most compilers, when using the
+// DefaultDeleter, sizeof(scoped_ptr<T>) == sizeof(T*). Custom deleters will
+// increase the size proportional to whatever state they need to have. See
+// comments inside scoped_ptr_impl<> for details.
+//
+// Current implementation targets having a strict subset of  C++11's
+// unique_ptr<> features. Known deficiencies include not supporting move-only
+// deleteres, function pointers as deleters, and deleters with reference
+// types.
+template <class T, class D = base::DefaultDeleter<T> >
+class scoped_ptr {
+  MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(scoped_ptr)
+
+  COMPILE_ASSERT(base::internal::IsNotRefCounted<T>::value,
+                 T_is_refcounted_type_and_needs_scoped_refptr);
+
+ public:
+  // The element and deleter types.
+  typedef T element_type;
+  typedef D deleter_type;
+
+  // Constructor.  Defaults to initializing with nullptr.
+  scoped_ptr() : impl_(nullptr) {}
+
+  // Constructor.  Takes ownership of p.
+  explicit scoped_ptr(element_type* p) : impl_(p) {}
+
+  // Constructor.  Allows initialization of a stateful deleter.
+  scoped_ptr(element_type* p, const D& d) : impl_(p, d) {}
+
+  // Constructor.  Allows construction from a nullptr.
+  scoped_ptr(decltype(nullptr)) : impl_(nullptr) {}
+
+  // Constructor.  Allows construction from a scoped_ptr rvalue for a
+  // convertible type and deleter.
+  //
+  // IMPLEMENTATION NOTE: C++11 unique_ptr<> keeps this constructor distinct
+  // from the normal move constructor. By C++11 20.7.1.2.1.21, this constructor
+  // has different post-conditions if D is a reference type. Since this
+  // implementation does not support deleters with reference type,
+  // we do not need a separate move constructor allowing us to avoid one
+  // use of SFINAE. You only need to care about this if you modify the
+  // implementation of scoped_ptr.
+  template <typename U, typename V>
+  scoped_ptr(scoped_ptr<U, V>&& other)
+      : impl_(&other.impl_) {
+    COMPILE_ASSERT(!base::is_array<U>::value, U_cannot_be_an_array);
+  }
+
+  // operator=.  Allows assignment from a scoped_ptr rvalue for a convertible
+  // type and deleter.
+  //
+  // IMPLEMENTATION NOTE: C++11 unique_ptr<> keeps this operator= distinct from
+  // the normal move assignment operator. By C++11 20.7.1.2.3.4, this templated
+  // form has different requirements on for move-only Deleters. Since this
+  // implementation does not support move-only Deleters, we do not need a
+  // separate move assignment operator allowing us to avoid one use of SFINAE.
+  // You only need to care about this if you modify the implementation of
+  // scoped_ptr.
+  template <typename U, typename V>
+  scoped_ptr& operator=(scoped_ptr<U, V>&& rhs) {
+    COMPILE_ASSERT(!base::is_array<U>::value, U_cannot_be_an_array);
+    impl_.TakeState(&rhs.impl_);
+    return *this;
+  }
+
+  // operator=.  Allows assignment from a nullptr. Deletes the currently owned
+  // object, if any.
+  scoped_ptr& operator=(decltype(nullptr)) {
+    reset();
+    return *this;
+  }
+
+  // Reset.  Deletes the currently owned object, if any.
+  // Then takes ownership of a new object, if given.
+  void reset(element_type* p = nullptr) { impl_.reset(p); }
+
+  // Accessors to get the owned object.
+  // operator* and operator-> will assert() if there is no current object.
+  element_type& operator*() const {
+    assert(impl_.get() != nullptr);
+    return *impl_.get();
+  }
+  element_type* operator->() const  {
+    assert(impl_.get() != nullptr);
+    return impl_.get();
+  }
+  element_type* get() const { return impl_.get(); }
+
+  // Access to the deleter.
+  deleter_type& get_deleter() { return impl_.get_deleter(); }
+  const deleter_type& get_deleter() const { return impl_.get_deleter(); }
+
+  // Allow scoped_ptr<element_type> to be used in boolean expressions, but not
+  // implicitly convertible to a real bool (which is dangerous).
+  //
+  // Note that this trick is only safe when the == and != operators
+  // are declared explicitly, as otherwise "scoped_ptr1 ==
+  // scoped_ptr2" will compile but do the wrong thing (i.e., convert
+  // to Testable and then do the comparison).
+ private:
+  typedef base::internal::scoped_ptr_impl<element_type, deleter_type>
+      scoped_ptr::*Testable;
+
+ public:
+  operator Testable() const {
+    return impl_.get() ? &scoped_ptr::impl_ : nullptr;
+  }
+
+  // Comparison operators.
+  // These return whether two scoped_ptr refer to the same object, not just to
+  // two different but equal objects.
+  bool operator==(const element_type* p) const { return impl_.get() == p; }
+  bool operator!=(const element_type* p) const { return impl_.get() != p; }
+
+  // Swap two scoped pointers.
+  void swap(scoped_ptr& p2) {
+    impl_.swap(p2.impl_);
+  }
+
+  // Release a pointer.
+  // The return value is the current pointer held by this object. If this object
+  // holds a nullptr, the return value is nullptr. After this operation, this
+  // object will hold a nullptr, and will not own the object any more.
+  element_type* release() WARN_UNUSED_RESULT {
+    return impl_.release();
+  }
+
+ private:
+  // Needed to reach into |impl_| in the constructor.
+  template <typename U, typename V> friend class scoped_ptr;
+  base::internal::scoped_ptr_impl<element_type, deleter_type> impl_;
+
+  // Forbidden for API compatibility with std::unique_ptr.
+  explicit scoped_ptr(int disallow_construction_from_null);
+
+  // Forbid comparison of scoped_ptr types.  If U != T, it totally
+  // doesn't make sense, and if U == T, it still doesn't make sense
+  // because you should never have the same object owned by two different
+  // scoped_ptrs.
+  template <class U> bool operator==(scoped_ptr<U> const& p2) const;
+  template <class U> bool operator!=(scoped_ptr<U> const& p2) const;
+};
+
+template <class T, class D>
+class scoped_ptr<T[], D> {
+  MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(scoped_ptr)
+
+ public:
+  // The element and deleter types.
+  typedef T element_type;
+  typedef D deleter_type;
+
+  // Constructor.  Defaults to initializing with nullptr.
+  scoped_ptr() : impl_(nullptr) {}
+
+  // Constructor. Stores the given array. Note that the argument's type
+  // must exactly match T*. In particular:
+  // - it cannot be a pointer to a type derived from T, because it is
+  //   inherently unsafe in the general case to access an array through a
+  //   pointer whose dynamic type does not match its static type (eg., if
+  //   T and the derived types had different sizes access would be
+  //   incorrectly calculated). Deletion is also always undefined
+  //   (C++98 [expr.delete]p3). If you're doing this, fix your code.
+  // - it cannot be const-qualified differently from T per unique_ptr spec
+  //   (http://cplusplus.github.com/LWG/lwg-active.html#2118). Users wanting
+  //   to work around this may use implicit_cast<const T*>().
+  //   However, because of the first bullet in this comment, users MUST
+  //   NOT use implicit_cast<Base*>() to upcast the static type of the array.
+  explicit scoped_ptr(element_type* array) : impl_(array) {}
+
+  // Constructor.  Allows construction from a nullptr.
+  scoped_ptr(decltype(nullptr)) : impl_(nullptr) {}
+
+  // Constructor.  Allows construction from a scoped_ptr rvalue.
+  scoped_ptr(scoped_ptr&& other) : impl_(&other.impl_) {}
+
+  // operator=.  Allows assignment from a scoped_ptr rvalue.
+  scoped_ptr& operator=(scoped_ptr&& rhs) {
+    impl_.TakeState(&rhs.impl_);
+    return *this;
+  }
+
+  // operator=.  Allows assignment from a nullptr. Deletes the currently owned
+  // array, if any.
+  scoped_ptr& operator=(decltype(nullptr)) {
+    reset();
+    return *this;
+  }
+
+  // Reset.  Deletes the currently owned array, if any.
+  // Then takes ownership of a new object, if given.
+  void reset(element_type* array = nullptr) { impl_.reset(array); }
+
+  // Accessors to get the owned array.
+  element_type& operator[](size_t i) const {
+    assert(impl_.get() != nullptr);
+    return impl_.get()[i];
+  }
+  element_type* get() const { return impl_.get(); }
+
+  // Access to the deleter.
+  deleter_type& get_deleter() { return impl_.get_deleter(); }
+  const deleter_type& get_deleter() const { return impl_.get_deleter(); }
+
+  // Allow scoped_ptr<element_type> to be used in boolean expressions, but not
+  // implicitly convertible to a real bool (which is dangerous).
+ private:
+  typedef base::internal::scoped_ptr_impl<element_type, deleter_type>
+      scoped_ptr::*Testable;
+
+ public:
+  operator Testable() const {
+    return impl_.get() ? &scoped_ptr::impl_ : nullptr;
+  }
+
+  // Comparison operators.
+  // These return whether two scoped_ptr refer to the same object, not just to
+  // two different but equal objects.
+  bool operator==(element_type* array) const { return impl_.get() == array; }
+  bool operator!=(element_type* array) const { return impl_.get() != array; }
+
+  // Swap two scoped pointers.
+  void swap(scoped_ptr& p2) {
+    impl_.swap(p2.impl_);
+  }
+
+  // Release a pointer.
+  // The return value is the current pointer held by this object. If this object
+  // holds a nullptr, the return value is nullptr. After this operation, this
+  // object will hold a nullptr, and will not own the object any more.
+  element_type* release() WARN_UNUSED_RESULT {
+    return impl_.release();
+  }
+
+ private:
+  // Force element_type to be a complete type.
+  enum { type_must_be_complete = sizeof(element_type) };
+
+  // Actually hold the data.
+  base::internal::scoped_ptr_impl<element_type, deleter_type> impl_;
+
+  // Disable initialization from any type other than element_type*, by
+  // providing a constructor that matches such an initialization, but is
+  // private and has no definition. This is disabled because it is not safe to
+  // call delete[] on an array whose static type does not match its dynamic
+  // type.
+  template <typename U> explicit scoped_ptr(U* array);
+  explicit scoped_ptr(int disallow_construction_from_null);
+
+  // Disable reset() from any type other than element_type*, for the same
+  // reasons as the constructor above.
+  template <typename U> void reset(U* array);
+  void reset(int disallow_reset_from_null);
+
+  // Forbid comparison of scoped_ptr types.  If U != T, it totally
+  // doesn't make sense, and if U == T, it still doesn't make sense
+  // because you should never have the same object owned by two different
+  // scoped_ptrs.
+  template <class U> bool operator==(scoped_ptr<U> const& p2) const;
+  template <class U> bool operator!=(scoped_ptr<U> const& p2) const;
+};
+
+// Free functions
+template <class T, class D>
+void swap(scoped_ptr<T, D>& p1, scoped_ptr<T, D>& p2) {
+  p1.swap(p2);
+}
+
+template <class T, class D>
+bool operator==(T* p1, const scoped_ptr<T, D>& p2) {
+  return p1 == p2.get();
+}
+
+template <class T, class D>
+bool operator!=(T* p1, const scoped_ptr<T, D>& p2) {
+  return p1 != p2.get();
+}
+
+// A function to convert T* into scoped_ptr<T>
+// Doing e.g. make_scoped_ptr(new FooBarBaz<type>(arg)) is a shorter notation
+// for scoped_ptr<FooBarBaz<type> >(new FooBarBaz<type>(arg))
+template <typename T>
+scoped_ptr<T> make_scoped_ptr(T* ptr) {
+  return scoped_ptr<T>(ptr);
+}
+
+template <typename T>
+std::ostream& operator<<(std::ostream& out, const scoped_ptr<T>& p) {
+  return out << p.get();
+}
+
+#endif  // BASE_MEMORY_SCOPED_PTR_H_
diff --git a/base/memory/scoped_ptr_unittest.cc b/base/memory/scoped_ptr_unittest.cc
new file mode 100644
index 0000000..766f444
--- /dev/null
+++ b/base/memory/scoped_ptr_unittest.cc
@@ -0,0 +1,695 @@
+// Copyright (c) 2012 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/memory/scoped_ptr.h"
+
+#include <sstream>
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/callback.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// Used to test depth subtyping.
+class ConDecLoggerParent {
+ public:
+  virtual ~ConDecLoggerParent() {}
+
+  virtual void SetPtr(int* ptr) = 0;
+
+  virtual int SomeMeth(int x) const = 0;
+};
+
+class ConDecLogger : public ConDecLoggerParent {
+ public:
+  ConDecLogger() : ptr_(NULL) { }
+  explicit ConDecLogger(int* ptr) { SetPtr(ptr); }
+  ~ConDecLogger() override { --*ptr_; }
+
+  void SetPtr(int* ptr) override {
+    ptr_ = ptr;
+    ++*ptr_;
+  }
+
+  int SomeMeth(int x) const override { return x; }
+
+ private:
+  int* ptr_;
+
+  DISALLOW_COPY_AND_ASSIGN(ConDecLogger);
+};
+
+struct CountingDeleter {
+  explicit CountingDeleter(int* count) : count_(count) {}
+  inline void operator()(double* ptr) const {
+    (*count_)++;
+  }
+  int* count_;
+};
+
+// Used to test assignment of convertible deleters.
+struct CountingDeleterChild : public CountingDeleter {
+  explicit CountingDeleterChild(int* count) : CountingDeleter(count) {}
+};
+
+class OverloadedNewAndDelete {
+ public:
+  void* operator new(size_t size) {
+    g_new_count++;
+    return malloc(size);
+  }
+
+  void operator delete(void* ptr) {
+    g_delete_count++;
+    free(ptr);
+  }
+
+  static void ResetCounters() {
+    g_new_count = 0;
+    g_delete_count = 0;
+  }
+
+  static int new_count() { return g_new_count; }
+  static int delete_count() { return g_delete_count; }
+
+ private:
+  static int g_new_count;
+  static int g_delete_count;
+};
+
+int OverloadedNewAndDelete::g_new_count = 0;
+int OverloadedNewAndDelete::g_delete_count = 0;
+
+scoped_ptr<ConDecLogger> PassThru(scoped_ptr<ConDecLogger> logger) {
+  return logger.Pass();
+}
+
+void GrabAndDrop(scoped_ptr<ConDecLogger> logger) {
+}
+
+// Do not delete this function!  It's existence is to test that you can
+// return a temporarily constructed version of the scoper.
+scoped_ptr<ConDecLogger> TestReturnOfType(int* constructed) {
+  return scoped_ptr<ConDecLogger>(new ConDecLogger(constructed));
+}
+
+}  // namespace
+
+TEST(ScopedPtrTest, ScopedPtr) {
+  int constructed = 0;
+
+  // Ensure size of scoped_ptr<> doesn't increase unexpectedly.
+  COMPILE_ASSERT(sizeof(int*) >= sizeof(scoped_ptr<int>),
+                 scoped_ptr_larger_than_raw_ptr);
+
+  {
+    scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed));
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper.get());
+
+    EXPECT_EQ(10, scoper->SomeMeth(10));
+    EXPECT_EQ(10, scoper.get()->SomeMeth(10));
+    EXPECT_EQ(10, (*scoper).SomeMeth(10));
+  }
+  EXPECT_EQ(0, constructed);
+
+  // Test reset() and release()
+  {
+    scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed));
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper.get());
+
+    scoper.reset(new ConDecLogger(&constructed));
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper.get());
+
+    scoper.reset();
+    EXPECT_EQ(0, constructed);
+    EXPECT_FALSE(scoper.get());
+
+    scoper.reset(new ConDecLogger(&constructed));
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper.get());
+
+    ConDecLogger* take = scoper.release();
+    EXPECT_EQ(1, constructed);
+    EXPECT_FALSE(scoper.get());
+    delete take;
+    EXPECT_EQ(0, constructed);
+
+    scoper.reset(new ConDecLogger(&constructed));
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper.get());
+  }
+  EXPECT_EQ(0, constructed);
+
+  // Test swap(), == and !=
+  {
+    scoped_ptr<ConDecLogger> scoper1;
+    scoped_ptr<ConDecLogger> scoper2;
+    EXPECT_TRUE(scoper1 == scoper2.get());
+    EXPECT_FALSE(scoper1 != scoper2.get());
+
+    ConDecLogger* logger = new ConDecLogger(&constructed);
+    scoper1.reset(logger);
+    EXPECT_EQ(logger, scoper1.get());
+    EXPECT_FALSE(scoper2.get());
+    EXPECT_FALSE(scoper1 == scoper2.get());
+    EXPECT_TRUE(scoper1 != scoper2.get());
+
+    scoper2.swap(scoper1);
+    EXPECT_EQ(logger, scoper2.get());
+    EXPECT_FALSE(scoper1.get());
+    EXPECT_FALSE(scoper1 == scoper2.get());
+    EXPECT_TRUE(scoper1 != scoper2.get());
+  }
+  EXPECT_EQ(0, constructed);
+}
+
+TEST(ScopedPtrTest, ScopedPtrDepthSubtyping) {
+  int constructed = 0;
+
+  // Test construction from a scoped_ptr to a derived class.
+  {
+    scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed));
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper.get());
+
+    scoped_ptr<ConDecLoggerParent> scoper_parent(scoper.Pass());
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper_parent.get());
+    EXPECT_FALSE(scoper.get());
+
+    EXPECT_EQ(10, scoper_parent->SomeMeth(10));
+    EXPECT_EQ(10, scoper_parent.get()->SomeMeth(10));
+    EXPECT_EQ(10, (*scoper_parent).SomeMeth(10));
+  }
+  EXPECT_EQ(0, constructed);
+
+  // Test assignment from a scoped_ptr to a derived class.
+  {
+    scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed));
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper.get());
+
+    scoped_ptr<ConDecLoggerParent> scoper_parent;
+    scoper_parent = scoper.Pass();
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper_parent.get());
+    EXPECT_FALSE(scoper.get());
+  }
+  EXPECT_EQ(0, constructed);
+
+  // Test construction of a scoped_ptr with an additional const annotation.
+  {
+    scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed));
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper.get());
+
+    scoped_ptr<const ConDecLogger> scoper_const(scoper.Pass());
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper_const.get());
+    EXPECT_FALSE(scoper.get());
+
+    EXPECT_EQ(10, scoper_const->SomeMeth(10));
+    EXPECT_EQ(10, scoper_const.get()->SomeMeth(10));
+    EXPECT_EQ(10, (*scoper_const).SomeMeth(10));
+  }
+  EXPECT_EQ(0, constructed);
+
+  // Test assignment to a scoped_ptr with an additional const annotation.
+  {
+    scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed));
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper.get());
+
+    scoped_ptr<const ConDecLogger> scoper_const;
+    scoper_const = scoper.Pass();
+    EXPECT_EQ(1, constructed);
+    EXPECT_TRUE(scoper_const.get());
+    EXPECT_FALSE(scoper.get());
+  }
+  EXPECT_EQ(0, constructed);
+
+  // Test assignment to a scoped_ptr deleter of parent type.
+  {
+    // Custom deleters never touch these value.
+    double dummy_value, dummy_value2;
+    int deletes = 0;
+    int alternate_deletes = 0;
+    scoped_ptr<double, CountingDeleter> scoper(&dummy_value,
+                                               CountingDeleter(&deletes));
+    scoped_ptr<double, CountingDeleterChild> scoper_child(
+        &dummy_value2, CountingDeleterChild(&alternate_deletes));
+
+    EXPECT_TRUE(scoper);
+    EXPECT_TRUE(scoper_child);
+    EXPECT_EQ(0, deletes);
+    EXPECT_EQ(0, alternate_deletes);
+
+    // Test this compiles and correctly overwrites the deleter state.
+    scoper = scoper_child.Pass();
+    EXPECT_TRUE(scoper);
+    EXPECT_FALSE(scoper_child);
+    EXPECT_EQ(1, deletes);
+    EXPECT_EQ(0, alternate_deletes);
+
+    scoper.reset();
+    EXPECT_FALSE(scoper);
+    EXPECT_FALSE(scoper_child);
+    EXPECT_EQ(1, deletes);
+    EXPECT_EQ(1, alternate_deletes);
+
+    scoper_child.reset(&dummy_value);
+    EXPECT_TRUE(scoper_child);
+    EXPECT_EQ(1, deletes);
+    EXPECT_EQ(1, alternate_deletes);
+    scoped_ptr<double, CountingDeleter> scoper_construct(scoper_child.Pass());
+    EXPECT_TRUE(scoper_construct);
+    EXPECT_FALSE(scoper_child);
+    EXPECT_EQ(1, deletes);
+    EXPECT_EQ(1, alternate_deletes);
+
+    scoper_construct.reset();
+    EXPECT_EQ(1, deletes);
+    EXPECT_EQ(2, alternate_deletes);
+  }
+}
+
+TEST(ScopedPtrTest, ScopedPtrWithArray) {
+  static const int kNumLoggers = 12;
+
+  int constructed = 0;
+
+  {
+    scoped_ptr<ConDecLogger[]> scoper(new ConDecLogger[kNumLoggers]);
+    EXPECT_TRUE(scoper);
+    EXPECT_EQ(&scoper[0], scoper.get());
+    for (int i = 0; i < kNumLoggers; ++i) {
+      scoper[i].SetPtr(&constructed);
+    }
+    EXPECT_EQ(12, constructed);
+
+    EXPECT_EQ(10, scoper.get()->SomeMeth(10));
+    EXPECT_EQ(10, scoper[2].SomeMeth(10));
+  }
+  EXPECT_EQ(0, constructed);
+
+  // Test reset() and release()
+  {
+    scoped_ptr<ConDecLogger[]> scoper;
+    EXPECT_FALSE(scoper.get());
+    EXPECT_FALSE(scoper.release());
+    EXPECT_FALSE(scoper.get());
+    scoper.reset();
+    EXPECT_FALSE(scoper.get());
+
+    scoper.reset(new ConDecLogger[kNumLoggers]);
+    for (int i = 0; i < kNumLoggers; ++i) {
+      scoper[i].SetPtr(&constructed);
+    }
+    EXPECT_EQ(12, constructed);
+    scoper.reset();
+    EXPECT_EQ(0, constructed);
+
+    scoper.reset(new ConDecLogger[kNumLoggers]);
+    for (int i = 0; i < kNumLoggers; ++i) {
+      scoper[i].SetPtr(&constructed);
+    }
+    EXPECT_EQ(12, constructed);
+    ConDecLogger* ptr = scoper.release();
+    EXPECT_EQ(12, constructed);
+    delete[] ptr;
+    EXPECT_EQ(0, constructed);
+  }
+  EXPECT_EQ(0, constructed);
+
+  // Test swap(), ==, !=, and type-safe Boolean.
+  {
+    scoped_ptr<ConDecLogger[]> scoper1;
+    scoped_ptr<ConDecLogger[]> scoper2;
+    EXPECT_TRUE(scoper1 == scoper2.get());
+    EXPECT_FALSE(scoper1 != scoper2.get());
+
+    ConDecLogger* loggers = new ConDecLogger[kNumLoggers];
+    for (int i = 0; i < kNumLoggers; ++i) {
+      loggers[i].SetPtr(&constructed);
+    }
+    scoper1.reset(loggers);
+    EXPECT_TRUE(scoper1);
+    EXPECT_EQ(loggers, scoper1.get());
+    EXPECT_FALSE(scoper2);
+    EXPECT_FALSE(scoper2.get());
+    EXPECT_FALSE(scoper1 == scoper2.get());
+    EXPECT_TRUE(scoper1 != scoper2.get());
+
+    scoper2.swap(scoper1);
+    EXPECT_EQ(loggers, scoper2.get());
+    EXPECT_FALSE(scoper1.get());
+    EXPECT_FALSE(scoper1 == scoper2.get());
+    EXPECT_TRUE(scoper1 != scoper2.get());
+  }
+  EXPECT_EQ(0, constructed);
+
+  {
+    ConDecLogger* loggers = new ConDecLogger[kNumLoggers];
+    scoped_ptr<ConDecLogger[]> scoper(loggers);
+    EXPECT_TRUE(scoper);
+    for (int i = 0; i < kNumLoggers; ++i) {
+      scoper[i].SetPtr(&constructed);
+    }
+    EXPECT_EQ(kNumLoggers, constructed);
+
+    // Test Pass() with constructor;
+    scoped_ptr<ConDecLogger[]> scoper2(scoper.Pass());
+    EXPECT_EQ(kNumLoggers, constructed);
+
+    // Test Pass() with assignment;
+    scoped_ptr<ConDecLogger[]> scoper3;
+    scoper3 = scoper2.Pass();
+    EXPECT_EQ(kNumLoggers, constructed);
+    EXPECT_FALSE(scoper);
+    EXPECT_FALSE(scoper2);
+    EXPECT_TRUE(scoper3);
+  }
+  EXPECT_EQ(0, constructed);
+}
+
+TEST(ScopedPtrTest, PassBehavior) {
+  int constructed = 0;
+  {
+    ConDecLogger* logger = new ConDecLogger(&constructed);
+    scoped_ptr<ConDecLogger> scoper(logger);
+    EXPECT_EQ(1, constructed);
+
+    // Test Pass() with constructor;
+    scoped_ptr<ConDecLogger> scoper2(scoper.Pass());
+    EXPECT_EQ(1, constructed);
+
+    // Test Pass() with assignment;
+    scoped_ptr<ConDecLogger> scoper3;
+    scoper3 = scoper2.Pass();
+    EXPECT_EQ(1, constructed);
+    EXPECT_FALSE(scoper.get());
+    EXPECT_FALSE(scoper2.get());
+    EXPECT_TRUE(scoper3.get());
+  }
+
+  // Test uncaught Pass() does not have side effects.
+  {
+    ConDecLogger* logger = new ConDecLogger(&constructed);
+    scoped_ptr<ConDecLogger> scoper(logger);
+    EXPECT_EQ(1, constructed);
+
+    // Should auto-destruct logger by end of scope.
+    scoped_ptr<ConDecLogger>&& rvalue = scoper.Pass();
+    // The Pass() function mimics std::move(), which does not have side-effects.
+    EXPECT_TRUE(scoper.get());
+    EXPECT_TRUE(rvalue);
+  }
+  EXPECT_EQ(0, constructed);
+
+  // Test that passing to function which does nothing does not leak.
+  {
+    ConDecLogger* logger = new ConDecLogger(&constructed);
+    scoped_ptr<ConDecLogger> scoper(logger);
+    EXPECT_EQ(1, constructed);
+
+    // Should auto-destruct logger by end of scope.
+    GrabAndDrop(scoper.Pass());
+    EXPECT_FALSE(scoper.get());
+  }
+  EXPECT_EQ(0, constructed);
+}
+
+TEST(ScopedPtrTest, ReturnTypeBehavior) {
+  int constructed = 0;
+
+  // Test that we can return a scoped_ptr.
+  {
+    ConDecLogger* logger = new ConDecLogger(&constructed);
+    scoped_ptr<ConDecLogger> scoper(logger);
+    EXPECT_EQ(1, constructed);
+
+    PassThru(scoper.Pass());
+    EXPECT_FALSE(scoper.get());
+  }
+  EXPECT_EQ(0, constructed);
+
+  // Test uncaught return type not leak.
+  {
+    ConDecLogger* logger = new ConDecLogger(&constructed);
+    scoped_ptr<ConDecLogger> scoper(logger);
+    EXPECT_EQ(1, constructed);
+
+    // Should auto-destruct logger by end of scope.
+    PassThru(scoper.Pass());
+    EXPECT_FALSE(scoper.get());
+  }
+  EXPECT_EQ(0, constructed);
+
+  // Call TestReturnOfType() so the compiler doesn't warn for an unused
+  // function.
+  {
+    TestReturnOfType(&constructed);
+  }
+  EXPECT_EQ(0, constructed);
+}
+
+TEST(ScopedPtrTest, CustomDeleter) {
+  double dummy_value;  // Custom deleter never touches this value.
+  int deletes = 0;
+  int alternate_deletes = 0;
+
+  // Normal delete support.
+  {
+    deletes = 0;
+    scoped_ptr<double, CountingDeleter> scoper(&dummy_value,
+                                               CountingDeleter(&deletes));
+    EXPECT_EQ(0, deletes);
+    EXPECT_TRUE(scoper.get());
+  }
+  EXPECT_EQ(1, deletes);
+
+  // Test reset() and release().
+  deletes = 0;
+  {
+    scoped_ptr<double, CountingDeleter> scoper(NULL,
+                                               CountingDeleter(&deletes));
+    EXPECT_FALSE(scoper.get());
+    EXPECT_FALSE(scoper.release());
+    EXPECT_FALSE(scoper.get());
+    scoper.reset();
+    EXPECT_FALSE(scoper.get());
+    EXPECT_EQ(0, deletes);
+
+    scoper.reset(&dummy_value);
+    scoper.reset();
+    EXPECT_EQ(1, deletes);
+
+    scoper.reset(&dummy_value);
+    EXPECT_EQ(&dummy_value, scoper.release());
+  }
+  EXPECT_EQ(1, deletes);
+
+  // Test get_deleter().
+  deletes = 0;
+  alternate_deletes = 0;
+  {
+    scoped_ptr<double, CountingDeleter> scoper(&dummy_value,
+                                               CountingDeleter(&deletes));
+    // Call deleter manually.
+    EXPECT_EQ(0, deletes);
+    scoper.get_deleter()(&dummy_value);
+    EXPECT_EQ(1, deletes);
+
+    // Deleter is still there after reset.
+    scoper.reset();
+    EXPECT_EQ(2, deletes);
+    scoper.get_deleter()(&dummy_value);
+    EXPECT_EQ(3, deletes);
+
+    // Deleter can be assigned into (matches C++11 unique_ptr<> spec).
+    scoper.get_deleter() = CountingDeleter(&alternate_deletes);
+    scoper.reset(&dummy_value);
+    EXPECT_EQ(0, alternate_deletes);
+
+  }
+  EXPECT_EQ(3, deletes);
+  EXPECT_EQ(1, alternate_deletes);
+
+  // Test operator= deleter support.
+  deletes = 0;
+  alternate_deletes = 0;
+  {
+    double dummy_value2;
+    scoped_ptr<double, CountingDeleter> scoper(&dummy_value,
+                                               CountingDeleter(&deletes));
+    scoped_ptr<double, CountingDeleter> scoper2(
+        &dummy_value2,
+        CountingDeleter(&alternate_deletes));
+    EXPECT_EQ(0, deletes);
+    EXPECT_EQ(0, alternate_deletes);
+
+    // Pass the second deleter through a constructor and an operator=. Then
+    // reinitialize the empty scopers to ensure that each one is deleting
+    // properly.
+    scoped_ptr<double, CountingDeleter> scoper3(scoper2.Pass());
+    scoper = scoper3.Pass();
+    EXPECT_EQ(1, deletes);
+
+    scoper2.reset(&dummy_value2);
+    scoper3.reset(&dummy_value2);
+    EXPECT_EQ(0, alternate_deletes);
+
+  }
+  EXPECT_EQ(1, deletes);
+  EXPECT_EQ(3, alternate_deletes);
+
+  // Test swap(), ==, !=, and type-safe Boolean.
+  {
+    scoped_ptr<double, CountingDeleter> scoper1(NULL,
+                                                CountingDeleter(&deletes));
+    scoped_ptr<double, CountingDeleter> scoper2(NULL,
+                                                CountingDeleter(&deletes));
+    EXPECT_TRUE(scoper1 == scoper2.get());
+    EXPECT_FALSE(scoper1 != scoper2.get());
+
+    scoper1.reset(&dummy_value);
+    EXPECT_TRUE(scoper1);
+    EXPECT_EQ(&dummy_value, scoper1.get());
+    EXPECT_FALSE(scoper2);
+    EXPECT_FALSE(scoper2.get());
+    EXPECT_FALSE(scoper1 == scoper2.get());
+    EXPECT_TRUE(scoper1 != scoper2.get());
+
+    scoper2.swap(scoper1);
+    EXPECT_EQ(&dummy_value, scoper2.get());
+    EXPECT_FALSE(scoper1.get());
+    EXPECT_FALSE(scoper1 == scoper2.get());
+    EXPECT_TRUE(scoper1 != scoper2.get());
+  }
+}
+
+// Sanity check test for overloaded new and delete operators. Does not do full
+// coverage of reset/release/Pass() operations as that is redundant with the
+// above.
+TEST(ScopedPtrTest, OverloadedNewAndDelete) {
+  {
+    OverloadedNewAndDelete::ResetCounters();
+    scoped_ptr<OverloadedNewAndDelete> scoper(new OverloadedNewAndDelete());
+    EXPECT_TRUE(scoper.get());
+
+    scoped_ptr<OverloadedNewAndDelete> scoper2(scoper.Pass());
+  }
+  EXPECT_EQ(1, OverloadedNewAndDelete::delete_count());
+  EXPECT_EQ(1, OverloadedNewAndDelete::new_count());
+}
+
+scoped_ptr<int> NullIntReturn() {
+  return nullptr;
+}
+
+TEST(ScopedPtrTest, Nullptr) {
+  scoped_ptr<int> scoper1(nullptr);
+  scoped_ptr<int> scoper2(new int);
+  scoper2 = nullptr;
+  scoped_ptr<int> scoper3(NullIntReturn());
+  scoped_ptr<int> scoper4 = NullIntReturn();
+  EXPECT_EQ(nullptr, scoper1.get());
+  EXPECT_EQ(nullptr, scoper2.get());
+  EXPECT_EQ(nullptr, scoper3.get());
+  EXPECT_EQ(nullptr, scoper4.get());
+}
+
+scoped_ptr<int[]> NullIntArrayReturn() {
+  return nullptr;
+}
+
+TEST(ScopedPtrTest, NullptrArray) {
+  scoped_ptr<int[]> scoper1(nullptr);
+  scoped_ptr<int[]> scoper2(new int[3]);
+  scoper2 = nullptr;
+  scoped_ptr<int[]> scoper3(NullIntArrayReturn());
+  scoped_ptr<int[]> scoper4 = NullIntArrayReturn();
+  EXPECT_EQ(nullptr, scoper1.get());
+  EXPECT_EQ(nullptr, scoper2.get());
+  EXPECT_EQ(nullptr, scoper3.get());
+  EXPECT_EQ(nullptr, scoper4.get());
+}
+
+class Super {};
+class Sub : public Super {};
+
+scoped_ptr<Sub> SubClassReturn() {
+  return make_scoped_ptr(new Sub);
+}
+
+TEST(ScopedPtrTest, Conversion) {
+  scoped_ptr<Sub> sub1(new Sub);
+  scoped_ptr<Sub> sub2(new Sub);
+
+  // Upcast with Pass() works.
+  scoped_ptr<Super> super1 = sub1.Pass();
+  super1 = sub2.Pass();
+
+  // Upcast with an rvalue works.
+  scoped_ptr<Super> super2 = SubClassReturn();
+  super2 = SubClassReturn();
+}
+
+// Android death tests don't work properly with assert(). Yay.
+#if !defined(NDEBUG) && defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
+TEST(ScopedPtrTest, SelfResetAbortsWithDefaultDeleter) {
+  scoped_ptr<int> x(new int);
+  EXPECT_DEATH(x.reset(x.get()), "");
+}
+
+TEST(ScopedPtrTest, SelfResetAbortsWithDefaultArrayDeleter) {
+  scoped_ptr<int[]> y(new int[4]);
+  EXPECT_DEATH(y.reset(y.get()), "");
+}
+
+TEST(ScopedPtrTest, SelfResetAbortsWithDefaultFreeDeleter) {
+  scoped_ptr<int, base::FreeDeleter> z(static_cast<int*>(malloc(sizeof(int))));
+  EXPECT_DEATH(z.reset(z.get()), "");
+}
+
+// A custom deleter that doesn't opt out should still crash.
+TEST(ScopedPtrTest, SelfResetAbortsWithCustomDeleter) {
+  struct CustomDeleter {
+    inline void operator()(int* x) { delete x; }
+  };
+  scoped_ptr<int, CustomDeleter> x(new int);
+  EXPECT_DEATH(x.reset(x.get()), "");
+}
+#endif
+
+TEST(ScopedPtrTest, SelfResetWithCustomDeleterOptOut) {
+  // A custom deleter should be able to opt out of self-reset abort behavior.
+  struct NoOpDeleter {
+#if !defined(NDEBUG)
+    typedef void AllowSelfReset;
+#endif
+    inline void operator()(int*) {}
+  };
+  scoped_ptr<int> owner(new int);
+  scoped_ptr<int, NoOpDeleter> x(owner.get());
+  x.reset(x.get());
+}
+
+// Logging a scoped_ptr<T> to an ostream shouldn't convert it to a boolean
+// value first.
+TEST(ScopedPtrTest, LoggingDoesntConvertToBoolean) {
+  scoped_ptr<int> x(new int);
+  std::stringstream s1;
+  s1 << x;
+
+  std::stringstream s2;
+  s2 << x.get();
+
+  EXPECT_EQ(s2.str(), s1.str());
+}
diff --git a/base/memory/scoped_ptr_unittest.nc b/base/memory/scoped_ptr_unittest.nc
new file mode 100644
index 0000000..b62703c
--- /dev/null
+++ b/base/memory/scoped_ptr_unittest.nc
@@ -0,0 +1,113 @@
+// Copyright (c) 2012 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/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/ref_counted.h"
+
+namespace {
+
+class Parent {
+};
+
+class Child : public Parent {
+};
+
+class RefCountedClass : public base::RefCountedThreadSafe<RefCountedClass> {
+};
+
+}  // namespace
+
+#if defined(NCTEST_NO_PASS_DOWNCAST)  // [r"fatal error: no matching constructor for initialization of 'base::internal::scoped_ptr_impl<\(anonymous namespace\)::Child, base::DefaultDeleter<\(anonymous namespace\)::Child> >::Data'"]
+
+scoped_ptr<Child> DowncastUsingPassAs(scoped_ptr<Parent> object) {
+  return object.Pass();
+}
+
+#elif defined(NCTEST_NO_REF_COUNTED_SCOPED_PTR)  // [r"fatal error: static_assert failed \"T_is_refcounted_type_and_needs_scoped_refptr\""]
+
+// scoped_ptr<> should not work for ref-counted objects.
+void WontCompile() {
+  scoped_ptr<RefCountedClass> x;
+}
+
+#elif defined(NCTEST_NO_ARRAY_WITH_SIZE)  // [r"fatal error: static_assert failed \"do_not_use_array_with_size_as_type\""]
+
+void WontCompile() {
+  scoped_ptr<int[10]> x;
+}
+
+#elif defined(NCTEST_NO_PASS_FROM_ARRAY)  // [r"fatal error: static_assert failed \"U_cannot_be_an_array\""]
+
+void WontCompile() {
+  scoped_ptr<int[]> a;
+  scoped_ptr<int*> b;
+  b = a.Pass();
+}
+
+#elif defined(NCTEST_NO_PASS_TO_ARRAY)  // [r"fatal error: no viable overloaded '='"]
+
+void WontCompile() {
+  scoped_ptr<int*> a;
+  scoped_ptr<int[]> b;
+  b = a.Pass();
+}
+
+#elif defined(NCTEST_NO_CONSTRUCT_FROM_ARRAY)  // [r"fatal error: 'impl_' is a private member of 'scoped_ptr<int \[\], base::DefaultDeleter<int \[\]> >'"]
+
+void WontCompile() {
+  scoped_ptr<int[]> a;
+  scoped_ptr<int*> b(a.Pass());
+}
+
+#elif defined(NCTEST_NO_CONSTRUCT_TO_ARRAY)  // [r"fatal error: no matching constructor for initialization of 'scoped_ptr<int \[\]>'"]
+
+void WontCompile() {
+  scoped_ptr<int*> a;
+  scoped_ptr<int[]> b(a.Pass());
+}
+
+#elif defined(NCTEST_NO_CONSTRUCT_SCOPED_PTR_ARRAY_FROM_NULL)  // [r"is ambiguous"]
+
+void WontCompile() {
+  scoped_ptr<int[]> x(NULL);
+}
+
+#elif defined(NCTEST_NO_CONSTRUCT_SCOPED_PTR_ARRAY_FROM_DERIVED)  // [r"fatal error: calling a private constructor of class 'scoped_ptr<\(anonymous namespace\)::Parent \[\], base::DefaultDeleter<\(anonymous namespace\)::Parent \[\]> >'"]
+
+void WontCompile() {
+  scoped_ptr<Parent[]> x(new Child[1]);
+}
+
+#elif defined(NCTEST_NO_RESET_SCOPED_PTR_ARRAY_FROM_NULL)  // [r"is ambiguous"]
+
+void WontCompile() {
+  scoped_ptr<int[]> x;
+  x.reset(NULL);
+}
+
+#elif defined(NCTEST_NO_RESET_SCOPED_PTR_ARRAY_FROM_DERIVED)  // [r"fatal error: 'reset' is a private member of 'scoped_ptr<\(anonymous namespace\)::Parent \[\], base::DefaultDeleter<\(anonymous namespace\)::Parent \[\]> >'"]
+
+void WontCompile() {
+  scoped_ptr<Parent[]> x;
+  x.reset(new Child[1]);
+}
+
+#elif defined(NCTEST_NO_DELETER_REFERENCE)  // [r"fatal error: base specifier must name a class"]
+
+struct Deleter {
+  void operator()(int*) {}
+};
+
+// Current implementation doesn't support Deleter Reference types. Enabling
+// support would require changes to the behavior of the constructors to match
+// including the use of SFINAE to discard the type-converting constructor
+// as per C++11 20.7.1.2.1.19.
+void WontCompile() {
+  Deleter d;
+  int n;
+  scoped_ptr<int*, Deleter&> a(&n, d);
+}
+
+#endif
diff --git a/base/memory/scoped_vector.h b/base/memory/scoped_vector.h
new file mode 100644
index 0000000..173ea5a
--- /dev/null
+++ b/base/memory/scoped_vector.h
@@ -0,0 +1,139 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_SCOPED_VECTOR_H_
+#define BASE_MEMORY_SCOPED_VECTOR_H_
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/move.h"
+#include "base/stl_util.h"
+
+// ScopedVector wraps a vector deleting the elements from its
+// destructor.
+template <class T>
+class ScopedVector {
+  MOVE_ONLY_TYPE_FOR_CPP_03(ScopedVector, RValue)
+
+ public:
+  typedef typename std::vector<T*>::allocator_type allocator_type;
+  typedef typename std::vector<T*>::size_type size_type;
+  typedef typename std::vector<T*>::difference_type difference_type;
+  typedef typename std::vector<T*>::pointer pointer;
+  typedef typename std::vector<T*>::const_pointer const_pointer;
+  typedef typename std::vector<T*>::reference reference;
+  typedef typename std::vector<T*>::const_reference const_reference;
+  typedef typename std::vector<T*>::value_type value_type;
+  typedef typename std::vector<T*>::iterator iterator;
+  typedef typename std::vector<T*>::const_iterator const_iterator;
+  typedef typename std::vector<T*>::reverse_iterator reverse_iterator;
+  typedef typename std::vector<T*>::const_reverse_iterator
+      const_reverse_iterator;
+
+  ScopedVector() {}
+  ~ScopedVector() { clear(); }
+  ScopedVector(RValue other) { swap(*other.object); }
+
+  ScopedVector& operator=(RValue rhs) {
+    swap(*rhs.object);
+    return *this;
+  }
+
+  reference operator[](size_t index) { return v_[index]; }
+  const_reference operator[](size_t index) const { return v_[index]; }
+
+  bool empty() const { return v_.empty(); }
+  size_t size() const { return v_.size(); }
+
+  reverse_iterator rbegin() { return v_.rbegin(); }
+  const_reverse_iterator rbegin() const { return v_.rbegin(); }
+  reverse_iterator rend() { return v_.rend(); }
+  const_reverse_iterator rend() const { return v_.rend(); }
+
+  iterator begin() { return v_.begin(); }
+  const_iterator begin() const { return v_.begin(); }
+  iterator end() { return v_.end(); }
+  const_iterator end() const { return v_.end(); }
+
+  const_reference front() const { return v_.front(); }
+  reference front() { return v_.front(); }
+  const_reference back() const { return v_.back(); }
+  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());
+    delete v_.back();
+    v_.pop_back();
+  }
+
+  std::vector<T*>& get() { return v_; }
+  const std::vector<T*>& get() const { return v_; }
+  void swap(std::vector<T*>& other) { v_.swap(other); }
+  void swap(ScopedVector<T>& other) { v_.swap(other.v_); }
+  void release(std::vector<T*>* out) {
+    out->swap(v_);
+    v_.clear();
+  }
+
+  void reserve(size_t capacity) { v_.reserve(capacity); }
+
+  // Resize, deleting elements in the disappearing range if we are shrinking.
+  void resize(size_t new_size) {
+    if (v_.size() > new_size)
+      STLDeleteContainerPointers(v_.begin() + new_size, v_.end());
+    v_.resize(new_size);
+  }
+
+  template<typename InputIterator>
+  void assign(InputIterator begin, InputIterator end) {
+    v_.assign(begin, end);
+  }
+
+  void clear() { STLDeleteElements(&v_); }
+
+  // Like |clear()|, but doesn't delete any elements.
+  void weak_clear() { v_.clear(); }
+
+  // Lets the ScopedVector take ownership of |x|.
+  iterator insert(iterator position, T* x) {
+    return v_.insert(position, x);
+  }
+
+  // Lets the ScopedVector take ownership of elements in [first,last).
+  template<typename InputIterator>
+  void insert(iterator position, InputIterator first, InputIterator last) {
+    v_.insert(position, first, last);
+  }
+
+  iterator erase(iterator position) {
+    delete *position;
+    return v_.erase(position);
+  }
+
+  iterator erase(iterator first, iterator last) {
+    STLDeleteContainerPointers(first, last);
+    return v_.erase(first, last);
+  }
+
+  // Like |erase()|, but doesn't delete the element at |position|.
+  iterator weak_erase(iterator position) {
+    return v_.erase(position);
+  }
+
+  // Like |erase()|, but doesn't delete the elements in [first, last).
+  iterator weak_erase(iterator first, iterator last) {
+    return v_.erase(first, last);
+  }
+
+ private:
+  std::vector<T*> v_;
+};
+
+#endif  // BASE_MEMORY_SCOPED_VECTOR_H_
diff --git a/base/memory/scoped_vector_unittest.cc b/base/memory/scoped_vector_unittest.cc
new file mode 100644
index 0000000..220cfb0
--- /dev/null
+++ b/base/memory/scoped_vector_unittest.cc
@@ -0,0 +1,324 @@
+// Copyright (c) 2012 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/memory/scoped_vector.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// The LifeCycleObject notifies its Observer upon construction & destruction.
+class LifeCycleObject {
+ public:
+  class Observer {
+   public:
+    virtual void OnLifeCycleConstruct(LifeCycleObject* o) = 0;
+    virtual void OnLifeCycleDestroy(LifeCycleObject* o) = 0;
+
+   protected:
+    virtual ~Observer() {}
+  };
+
+  ~LifeCycleObject() {
+    observer_->OnLifeCycleDestroy(this);
+  }
+
+ private:
+  friend class LifeCycleWatcher;
+
+  explicit LifeCycleObject(Observer* observer)
+      : observer_(observer) {
+    observer_->OnLifeCycleConstruct(this);
+  }
+
+  Observer* observer_;
+
+  DISALLOW_COPY_AND_ASSIGN(LifeCycleObject);
+};
+
+// The life cycle states we care about for the purposes of testing ScopedVector
+// against objects.
+enum LifeCycleState {
+  LC_INITIAL,
+  LC_CONSTRUCTED,
+  LC_DESTROYED,
+};
+
+// Because we wish to watch the life cycle of an object being constructed and
+// destroyed, and further wish to test expectations against the state of that
+// object, we cannot save state in that object itself. Instead, we use this
+// pairing of the watcher, which observes the object and notifies of
+// construction & destruction. Since we also may be testing assumptions about
+// things not getting freed, this class also acts like a scoping object and
+// deletes the |constructed_life_cycle_object_|, if any when the
+// LifeCycleWatcher is destroyed. To keep this simple, the only expected state
+// changes are:
+//   INITIAL -> CONSTRUCTED -> DESTROYED.
+// Anything more complicated than that should start another test.
+class LifeCycleWatcher : public LifeCycleObject::Observer {
+ public:
+  LifeCycleWatcher() : life_cycle_state_(LC_INITIAL) {}
+  ~LifeCycleWatcher() override {}
+
+  // Assert INITIAL -> CONSTRUCTED and no LifeCycleObject associated with this
+  // LifeCycleWatcher.
+  void OnLifeCycleConstruct(LifeCycleObject* object) override {
+    ASSERT_EQ(LC_INITIAL, life_cycle_state_);
+    ASSERT_EQ(NULL, constructed_life_cycle_object_.get());
+    life_cycle_state_ = LC_CONSTRUCTED;
+    constructed_life_cycle_object_.reset(object);
+  }
+
+  // Assert CONSTRUCTED -> DESTROYED and the |object| being destroyed is the
+  // same one we saw constructed.
+  void OnLifeCycleDestroy(LifeCycleObject* object) override {
+    ASSERT_EQ(LC_CONSTRUCTED, life_cycle_state_);
+    LifeCycleObject* constructed_life_cycle_object =
+        constructed_life_cycle_object_.release();
+    ASSERT_EQ(constructed_life_cycle_object, object);
+    life_cycle_state_ = LC_DESTROYED;
+  }
+
+  LifeCycleState life_cycle_state() const { return life_cycle_state_; }
+
+  // Factory method for creating a new LifeCycleObject tied to this
+  // LifeCycleWatcher.
+  LifeCycleObject* NewLifeCycleObject() {
+    return new LifeCycleObject(this);
+  }
+
+  // Returns true iff |object| is the same object that this watcher is tracking.
+  bool IsWatching(LifeCycleObject* object) const {
+    return object == constructed_life_cycle_object_.get();
+  }
+
+ private:
+  LifeCycleState life_cycle_state_;
+  scoped_ptr<LifeCycleObject> constructed_life_cycle_object_;
+
+  DISALLOW_COPY_AND_ASSIGN(LifeCycleWatcher);
+};
+
+TEST(ScopedVectorTest, LifeCycleWatcher) {
+  LifeCycleWatcher watcher;
+  EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
+  LifeCycleObject* object = watcher.NewLifeCycleObject();
+  EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
+  delete object;
+  EXPECT_EQ(LC_DESTROYED, watcher.life_cycle_state());
+}
+
+TEST(ScopedVectorTest, PopBack) {
+  LifeCycleWatcher watcher;
+  EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
+  ScopedVector<LifeCycleObject> scoped_vector;
+  scoped_vector.push_back(watcher.NewLifeCycleObject());
+  EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
+  EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
+  scoped_vector.pop_back();
+  EXPECT_EQ(LC_DESTROYED, watcher.life_cycle_state());
+  EXPECT_TRUE(scoped_vector.empty());
+}
+
+TEST(ScopedVectorTest, Clear) {
+  LifeCycleWatcher watcher;
+  EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
+  ScopedVector<LifeCycleObject> scoped_vector;
+  scoped_vector.push_back(watcher.NewLifeCycleObject());
+  EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
+  EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
+  scoped_vector.clear();
+  EXPECT_EQ(LC_DESTROYED, watcher.life_cycle_state());
+  EXPECT_TRUE(scoped_vector.empty());
+}
+
+TEST(ScopedVectorTest, WeakClear) {
+  LifeCycleWatcher watcher;
+  EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
+  ScopedVector<LifeCycleObject> scoped_vector;
+  scoped_vector.push_back(watcher.NewLifeCycleObject());
+  EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
+  EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
+  scoped_vector.weak_clear();
+  EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
+  EXPECT_TRUE(scoped_vector.empty());
+}
+
+TEST(ScopedVectorTest, ResizeShrink) {
+  LifeCycleWatcher first_watcher;
+  EXPECT_EQ(LC_INITIAL, first_watcher.life_cycle_state());
+  LifeCycleWatcher second_watcher;
+  EXPECT_EQ(LC_INITIAL, second_watcher.life_cycle_state());
+  ScopedVector<LifeCycleObject> scoped_vector;
+
+  scoped_vector.push_back(first_watcher.NewLifeCycleObject());
+  EXPECT_EQ(LC_CONSTRUCTED, first_watcher.life_cycle_state());
+  EXPECT_EQ(LC_INITIAL, second_watcher.life_cycle_state());
+  EXPECT_TRUE(first_watcher.IsWatching(scoped_vector[0]));
+  EXPECT_FALSE(second_watcher.IsWatching(scoped_vector[0]));
+
+  scoped_vector.push_back(second_watcher.NewLifeCycleObject());
+  EXPECT_EQ(LC_CONSTRUCTED, first_watcher.life_cycle_state());
+  EXPECT_EQ(LC_CONSTRUCTED, second_watcher.life_cycle_state());
+  EXPECT_FALSE(first_watcher.IsWatching(scoped_vector[1]));
+  EXPECT_TRUE(second_watcher.IsWatching(scoped_vector[1]));
+
+  // Test that shrinking a vector deletes elements in the disappearing range.
+  scoped_vector.resize(1);
+  EXPECT_EQ(LC_CONSTRUCTED, first_watcher.life_cycle_state());
+  EXPECT_EQ(LC_DESTROYED, second_watcher.life_cycle_state());
+  EXPECT_EQ(1u, scoped_vector.size());
+  EXPECT_TRUE(first_watcher.IsWatching(scoped_vector[0]));
+}
+
+TEST(ScopedVectorTest, ResizeGrow) {
+  LifeCycleWatcher watcher;
+  EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
+  ScopedVector<LifeCycleObject> scoped_vector;
+  scoped_vector.push_back(watcher.NewLifeCycleObject());
+  EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
+  EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
+
+  scoped_vector.resize(5);
+  EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
+  ASSERT_EQ(5u, scoped_vector.size());
+  EXPECT_TRUE(watcher.IsWatching(scoped_vector[0]));
+  EXPECT_FALSE(watcher.IsWatching(scoped_vector[1]));
+  EXPECT_FALSE(watcher.IsWatching(scoped_vector[2]));
+  EXPECT_FALSE(watcher.IsWatching(scoped_vector[3]));
+  EXPECT_FALSE(watcher.IsWatching(scoped_vector[4]));
+}
+
+TEST(ScopedVectorTest, Scope) {
+  LifeCycleWatcher watcher;
+  EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
+  {
+    ScopedVector<LifeCycleObject> scoped_vector;
+    scoped_vector.push_back(watcher.NewLifeCycleObject());
+    EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
+    EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
+  }
+  EXPECT_EQ(LC_DESTROYED, watcher.life_cycle_state());
+}
+
+TEST(ScopedVectorTest, MoveConstruct) {
+  LifeCycleWatcher watcher;
+  EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
+  {
+    ScopedVector<LifeCycleObject> scoped_vector;
+    scoped_vector.push_back(watcher.NewLifeCycleObject());
+    EXPECT_FALSE(scoped_vector.empty());
+    EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
+
+    ScopedVector<LifeCycleObject> scoped_vector_copy(scoped_vector.Pass());
+    EXPECT_TRUE(scoped_vector.empty());
+    EXPECT_FALSE(scoped_vector_copy.empty());
+    EXPECT_TRUE(watcher.IsWatching(scoped_vector_copy.back()));
+
+    EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
+  }
+  EXPECT_EQ(LC_DESTROYED, watcher.life_cycle_state());
+}
+
+TEST(ScopedVectorTest, MoveAssign) {
+  LifeCycleWatcher watcher;
+  EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
+  {
+    ScopedVector<LifeCycleObject> scoped_vector;
+    scoped_vector.push_back(watcher.NewLifeCycleObject());
+    ScopedVector<LifeCycleObject> scoped_vector_assign;
+    EXPECT_FALSE(scoped_vector.empty());
+    EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
+
+    scoped_vector_assign = scoped_vector.Pass();
+    EXPECT_TRUE(scoped_vector.empty());
+    EXPECT_FALSE(scoped_vector_assign.empty());
+    EXPECT_TRUE(watcher.IsWatching(scoped_vector_assign.back()));
+
+    EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
+  }
+  EXPECT_EQ(LC_DESTROYED, watcher.life_cycle_state());
+}
+
+class DeleteCounter {
+ public:
+  explicit DeleteCounter(int* deletes)
+      : deletes_(deletes) {
+  }
+
+  ~DeleteCounter() {
+    (*deletes_)++;
+  }
+
+  void VoidMethod0() {}
+
+ private:
+  int* const deletes_;
+
+  DISALLOW_COPY_AND_ASSIGN(DeleteCounter);
+};
+
+template <typename T>
+ScopedVector<T> PassThru(ScopedVector<T> scoper) {
+  return scoper.Pass();
+}
+
+TEST(ScopedVectorTest, Passed) {
+  int deletes = 0;
+  ScopedVector<DeleteCounter> deleter_vector;
+  deleter_vector.push_back(new DeleteCounter(&deletes));
+  EXPECT_EQ(0, deletes);
+  base::Callback<ScopedVector<DeleteCounter>(void)> callback =
+      base::Bind(&PassThru<DeleteCounter>, base::Passed(&deleter_vector));
+  EXPECT_EQ(0, deletes);
+  ScopedVector<DeleteCounter> result = callback.Run();
+  EXPECT_EQ(0, deletes);
+  result.clear();
+  EXPECT_EQ(1, deletes);
+};
+
+TEST(ScopedVectorTest, InsertRange) {
+  LifeCycleWatcher watchers[5];
+
+  std::vector<LifeCycleObject*> vec;
+  for(LifeCycleWatcher* it = watchers; it != watchers + arraysize(watchers);
+      ++it) {
+    EXPECT_EQ(LC_INITIAL, it->life_cycle_state());
+    vec.push_back(it->NewLifeCycleObject());
+    EXPECT_EQ(LC_CONSTRUCTED, it->life_cycle_state());
+  }
+  // Start scope for ScopedVector.
+  {
+    ScopedVector<LifeCycleObject> scoped_vector;
+    scoped_vector.insert(scoped_vector.end(), vec.begin() + 1, vec.begin() + 3);
+    for(LifeCycleWatcher* it = watchers; it != watchers + arraysize(watchers);
+        ++it)
+      EXPECT_EQ(LC_CONSTRUCTED, it->life_cycle_state());
+  }
+  for(LifeCycleWatcher* it = watchers; it != watchers + 1; ++it)
+    EXPECT_EQ(LC_CONSTRUCTED, it->life_cycle_state());
+  for(LifeCycleWatcher* it = watchers + 1; it != watchers + 3; ++it)
+    EXPECT_EQ(LC_DESTROYED, it->life_cycle_state());
+  for(LifeCycleWatcher* it = watchers + 3; it != watchers + arraysize(watchers);
+      ++it)
+    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/base/memory/shared_memory.h b/base/memory/shared_memory.h
new file mode 100644
index 0000000..008bb01
--- /dev/null
+++ b/base/memory/shared_memory.h
@@ -0,0 +1,329 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_SHARED_MEMORY_H_
+#define BASE_MEMORY_SHARED_MEMORY_H_
+
+#include "build/build_config.h"
+
+#include <string>
+
+#if defined(OS_POSIX)
+#include <stdio.h>
+#include <sys/types.h>
+#include <semaphore.h>
+#endif
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/process/process_handle.h"
+
+#if defined(OS_POSIX)
+#include "base/file_descriptor_posix.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
+#endif
+
+namespace base {
+
+class FilePath;
+
+// SharedMemoryHandle is a platform specific type which represents
+// the underlying OS handle to a shared memory segment.
+#if defined(OS_WIN)
+typedef HANDLE SharedMemoryHandle;
+#elif defined(OS_POSIX)
+typedef FileDescriptor SharedMemoryHandle;
+#endif
+
+// Options for creating a shared memory object.
+struct SharedMemoryCreateOptions {
+  SharedMemoryCreateOptions()
+      : name_deprecated(NULL),
+        size(0),
+        open_existing_deprecated(false),
+        executable(false),
+        share_read_only(false) {}
+
+  // DEPRECATED (crbug.com/345734):
+  // If NULL, the object is anonymous.  This pointer is owned by the caller
+  // and must live through the call to Create().
+  const std::string* name_deprecated;
+
+  // Size of the shared memory object to be created.
+  // When opening an existing object, this has no effect.
+  size_t size;
+
+  // DEPRECATED (crbug.com/345734):
+  // If true, and the shared memory already exists, Create() will open the
+  // existing shared memory and ignore the size parameter.  If false,
+  // shared memory must not exist.  This flag is meaningless unless
+  // name_deprecated is non-NULL.
+  bool open_existing_deprecated;
+
+  // If true, mappings might need to be made executable later.
+  bool executable;
+
+  // If true, the file can be shared read-only to a process.
+  bool share_read_only;
+};
+
+// Platform abstraction for shared memory.  Provides a C++ wrapper
+// around the OS primitive for a memory mapped file.
+class BASE_EXPORT SharedMemory {
+ public:
+  SharedMemory();
+
+#if defined(OS_WIN)
+  // Similar to the default constructor, except that this allows for
+  // calling LockDeprecated() to acquire the named mutex before either Create or
+  // Open are called on Windows.
+  explicit SharedMemory(const std::wstring& name);
+#endif
+
+  // Create a new SharedMemory object from an existing, open
+  // shared memory file.
+  //
+  // WARNING: This does not reduce the OS-level permissions on the handle; it
+  // only affects how the SharedMemory will be mmapped.  Use
+  // ShareReadOnlyToProcess to drop permissions.  TODO(jln,jyasskin): DCHECK
+  // that |read_only| matches the permissions of the handle.
+  SharedMemory(SharedMemoryHandle handle, bool read_only);
+
+  // Create a new SharedMemory object from an existing, open
+  // shared memory file that was created by a remote process and not shared
+  // to the current process.
+  SharedMemory(SharedMemoryHandle handle, bool read_only,
+               ProcessHandle process);
+
+  // Closes any open files.
+  ~SharedMemory();
+
+  // Return true iff the given handle is valid (i.e. not the distingished
+  // invalid value; NULL for a HANDLE and -1 for a file descriptor)
+  static bool IsHandleValid(const SharedMemoryHandle& handle);
+
+  // Returns invalid handle (see comment above for exact definition).
+  static SharedMemoryHandle NULLHandle();
+
+  // Closes a shared memory handle.
+  static void CloseHandle(const SharedMemoryHandle& handle);
+
+  // Returns the maximum number of handles that can be open at once per process.
+  static size_t GetHandleLimit();
+
+  // Duplicates The underlying OS primitive. Returns NULLHandle() on failure.
+  // The caller is responsible for destroying the duplicated OS primitive.
+  static SharedMemoryHandle DuplicateHandle(const SharedMemoryHandle& handle);
+
+#if defined(OS_POSIX)
+  // This method requires that the SharedMemoryHandle is backed by a POSIX fd.
+  static int GetFdFromSharedMemoryHandle(const SharedMemoryHandle& handle);
+#endif
+
+#if defined(OS_POSIX) && !defined(OS_ANDROID)
+  // Returns the size of the shared memory region referred to by |handle|.
+  // Returns '-1' on a failure to determine the size.
+  static int GetSizeFromSharedMemoryHandle(const SharedMemoryHandle& handle);
+#endif  // defined(OS_POSIX) && !defined(OS_ANDROID)
+
+  // Creates a shared memory object as described by the options struct.
+  // Returns true on success and false on failure.
+  bool Create(const SharedMemoryCreateOptions& options);
+
+  // Creates and maps an anonymous shared memory segment of size size.
+  // Returns true on success and false on failure.
+  bool CreateAndMapAnonymous(size_t size);
+
+  // Creates an anonymous shared memory segment of size size.
+  // Returns true on success and false on failure.
+  bool CreateAnonymous(size_t size) {
+    SharedMemoryCreateOptions options;
+    options.size = size;
+    return Create(options);
+  }
+
+  // DEPRECATED (crbug.com/345734):
+  // Creates or opens a shared memory segment based on a name.
+  // If open_existing is true, and the shared memory already exists,
+  // opens the existing shared memory and ignores the size parameter.
+  // If open_existing is false, shared memory must not exist.
+  // size is the size of the block to be created.
+  // Returns true on success, false on failure.
+  bool CreateNamedDeprecated(
+      const std::string& name, bool open_existing, size_t size) {
+    SharedMemoryCreateOptions options;
+    options.name_deprecated = &name;
+    options.open_existing_deprecated = open_existing;
+    options.size = size;
+    return Create(options);
+  }
+
+  // Deletes resources associated with a shared memory segment based on name.
+  // Not all platforms require this call.
+  bool Delete(const std::string& name);
+
+  // Opens a shared memory segment based on a name.
+  // If read_only is true, opens for read-only access.
+  // Returns true on success, false on failure.
+  bool Open(const std::string& name, bool read_only);
+
+  // Maps the shared memory into the caller's address space.
+  // Returns true on success, false otherwise.  The memory address
+  // is accessed via the memory() accessor.  The mapped address is guaranteed to
+  // have an alignment of at least MAP_MINIMUM_ALIGNMENT. This method will fail
+  // if this object is currently mapped.
+  bool Map(size_t bytes) {
+    return MapAt(0, bytes);
+  }
+
+  // Same as above, but with |offset| to specify from begining of the shared
+  // memory block to map.
+  // |offset| must be alignent to value of |SysInfo::VMAllocationGranularity()|.
+  bool MapAt(off_t offset, size_t bytes);
+  enum { MAP_MINIMUM_ALIGNMENT = 32 };
+
+  // Unmaps the shared memory from the caller's address space.
+  // Returns true if successful; returns false on error or if the
+  // memory is not mapped.
+  bool Unmap();
+
+  // The size requested when the map is first created.
+  size_t requested_size() const { return requested_size_; }
+
+  // The actual size of the mapped memory (may be larger than requested).
+  size_t mapped_size() const { return mapped_size_; }
+
+  // Gets a pointer to the opened memory space if it has been
+  // Mapped via Map().  Returns NULL if it is not mapped.
+  void *memory() const { return memory_; }
+
+  // Returns the underlying OS handle for this segment.
+  // Use of this handle for anything other than an opaque
+  // identifier is not portable.
+  SharedMemoryHandle handle() const;
+
+  // Closes the open shared memory segment. The memory will remain mapped if
+  // it was previously mapped.
+  // It is safe to call Close repeatedly.
+  void Close();
+
+  // Shares the shared memory to another process.  Attempts to create a
+  // platform-specific new_handle which can be used in a remote process to read
+  // the shared memory file.  new_handle is an output parameter to receive the
+  // handle for use in the remote process.
+  //
+  // |*this| must have been initialized using one of the Create*() or Open()
+  // methods with share_read_only=true. If it was constructed from a
+  // SharedMemoryHandle, this call will CHECK-fail.
+  //
+  // Returns true on success, false otherwise.
+  bool ShareReadOnlyToProcess(ProcessHandle process,
+                              SharedMemoryHandle* new_handle) {
+    return ShareToProcessCommon(process, new_handle, false, SHARE_READONLY);
+  }
+
+  // Logically equivalent to:
+  //   bool ok = ShareReadOnlyToProcess(process, new_handle);
+  //   Close();
+  //   return ok;
+  // Note that the memory is unmapped by calling this method, regardless of the
+  // return value.
+  bool GiveReadOnlyToProcess(ProcessHandle process,
+                             SharedMemoryHandle* new_handle) {
+    return ShareToProcessCommon(process, new_handle, true, SHARE_READONLY);
+  }
+
+  // Shares the shared memory to another process.  Attempts
+  // to create a platform-specific new_handle which can be
+  // used in a remote process to access the shared memory
+  // file.  new_handle is an output parameter to receive
+  // the handle for use in the remote process.
+  // Returns true on success, false otherwise.
+  bool ShareToProcess(ProcessHandle process,
+                      SharedMemoryHandle* new_handle) {
+    return ShareToProcessCommon(process, new_handle, false, SHARE_CURRENT_MODE);
+  }
+
+  // Logically equivalent to:
+  //   bool ok = ShareToProcess(process, new_handle);
+  //   Close();
+  //   return ok;
+  // Note that the memory is unmapped by calling this method, regardless of the
+  // return value.
+  bool GiveToProcess(ProcessHandle process,
+                     SharedMemoryHandle* new_handle) {
+    return ShareToProcessCommon(process, new_handle, true, SHARE_CURRENT_MODE);
+  }
+
+  // DEPRECATED (crbug.com/345734):
+  // Locks the shared memory.
+  //
+  // WARNING: on POSIX the memory locking primitive only works across
+  // processes, not across threads.  The LockDeprecated method is not currently
+  // used in inner loops, so we protect against multiple threads in a
+  // critical section using a class global lock.
+  void LockDeprecated();
+
+  // DEPRECATED (crbug.com/345734):
+  // Releases the shared memory lock.
+  void UnlockDeprecated();
+
+ private:
+#if defined(OS_POSIX) && !defined(OS_NACL)
+#if !defined(OS_ANDROID)
+  bool PrepareMapFile(ScopedFILE fp, ScopedFD readonly);
+  bool FilePathForMemoryName(const std::string& mem_name, FilePath* path);
+#endif
+  void LockOrUnlockCommon(int function);
+#endif  // defined(OS_POSIX) && !defined(OS_NACL)
+  enum ShareMode {
+    SHARE_READONLY,
+    SHARE_CURRENT_MODE,
+  };
+  bool ShareToProcessCommon(ProcessHandle process,
+                            SharedMemoryHandle* new_handle,
+                            bool close_self,
+                            ShareMode);
+
+#if defined(OS_WIN)
+  std::wstring       name_;
+  HANDLE             mapped_file_;
+#elif defined(OS_POSIX)
+  int                mapped_file_;
+  int                readonly_mapped_file_;
+#endif
+  size_t             mapped_size_;
+  void*              memory_;
+  bool               read_only_;
+  size_t             requested_size_;
+#if !defined(OS_POSIX)
+  HANDLE             lock_;
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(SharedMemory);
+};
+
+// DEPRECATED (crbug.com/345734):
+// A helper class that acquires the shared memory lock while
+// the SharedMemoryAutoLockDeprecated is in scope.
+class SharedMemoryAutoLockDeprecated {
+ public:
+  explicit SharedMemoryAutoLockDeprecated(SharedMemory* shared_memory)
+      : shared_memory_(shared_memory) {
+    shared_memory_->LockDeprecated();
+  }
+
+  ~SharedMemoryAutoLockDeprecated() {
+    shared_memory_->UnlockDeprecated();
+  }
+
+ private:
+  SharedMemory* shared_memory_;
+  DISALLOW_COPY_AND_ASSIGN(SharedMemoryAutoLockDeprecated);
+};
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_SHARED_MEMORY_H_
diff --git a/base/memory/shared_memory_android.cc b/base/memory/shared_memory_android.cc
new file mode 100644
index 0000000..5ba1bd6
--- /dev/null
+++ b/base/memory/shared_memory_android.cc
@@ -0,0 +1,66 @@
+// Copyright (c) 2011 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/memory/shared_memory.h"
+
+#include <sys/mman.h>
+
+#include "base/logging.h"
+#include "third_party/ashmem/ashmem.h"
+
+namespace base {
+
+// For Android, we use ashmem to implement SharedMemory. ashmem_create_region
+// will automatically pin the region. We never explicitly call pin/unpin. When
+// all the file descriptors from different processes associated with the region
+// are closed, the memory buffer will go away.
+
+bool SharedMemory::Create(const SharedMemoryCreateOptions& options) {
+  DCHECK_EQ(-1, mapped_file_ );
+
+  if (options.size > static_cast<size_t>(std::numeric_limits<int>::max()))
+    return false;
+
+  // "name" is just a label in ashmem. It is visible in /proc/pid/maps.
+  mapped_file_ = ashmem_create_region(
+      options.name_deprecated == NULL ? "" : options.name_deprecated->c_str(),
+      options.size);
+  if (-1 == mapped_file_) {
+    DLOG(ERROR) << "Shared memory creation failed";
+    return false;
+  }
+
+  int err = ashmem_set_prot_region(mapped_file_,
+                                   PROT_READ | PROT_WRITE | PROT_EXEC);
+  if (err < 0) {
+    DLOG(ERROR) << "Error " << err << " when setting protection of ashmem";
+    return false;
+  }
+
+  // Android doesn't appear to have a way to drop write access on an ashmem
+  // segment for a single descriptor.  http://crbug.com/320865
+  readonly_mapped_file_ = dup(mapped_file_);
+  if (-1 == readonly_mapped_file_) {
+    DPLOG(ERROR) << "dup() failed";
+    return false;
+  }
+
+  requested_size_ = options.size;
+
+  return true;
+}
+
+bool SharedMemory::Delete(const std::string& name) {
+  // Like on Windows, this is intentionally returning true as ashmem will
+  // automatically releases the resource when all FDs on it are closed.
+  return true;
+}
+
+bool SharedMemory::Open(const std::string& name, bool read_only) {
+  // ashmem doesn't support name mapping
+  NOTIMPLEMENTED();
+  return false;
+}
+
+}  // namespace base
diff --git a/base/memory/shared_memory_nacl.cc b/base/memory/shared_memory_nacl.cc
new file mode 100644
index 0000000..26dd4a3
--- /dev/null
+++ b/base/memory/shared_memory_nacl.cc
@@ -0,0 +1,175 @@
+// Copyright (c) 2012 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/memory/shared_memory.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <limits>
+
+#include "base/logging.h"
+
+namespace base {
+
+SharedMemory::SharedMemory()
+    : mapped_file_(-1),
+      mapped_size_(0),
+      memory_(NULL),
+      read_only_(false),
+      requested_size_(0) {
+}
+
+SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only)
+    : mapped_file_(handle.fd),
+      mapped_size_(0),
+      memory_(NULL),
+      read_only_(read_only),
+      requested_size_(0) {
+}
+
+SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only,
+                           ProcessHandle process)
+    : mapped_file_(handle.fd),
+      mapped_size_(0),
+      memory_(NULL),
+      read_only_(read_only),
+      requested_size_(0) {
+  NOTREACHED();
+}
+
+SharedMemory::~SharedMemory() {
+  Unmap();
+  Close();
+}
+
+// static
+bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) {
+  return handle.fd >= 0;
+}
+
+// static
+SharedMemoryHandle SharedMemory::NULLHandle() {
+  return SharedMemoryHandle();
+}
+
+// static
+void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) {
+  DCHECK_GE(handle.fd, 0);
+  if (close(handle.fd) < 0)
+    DPLOG(ERROR) << "close";
+}
+
+// static
+SharedMemoryHandle SharedMemory::DuplicateHandle(
+    const SharedMemoryHandle& handle) {
+  int duped_handle = HANDLE_EINTR(dup(handle.fd));
+  if (duped_handle < 0)
+    return base::SharedMemory::NULLHandle();
+  return base::FileDescriptor(duped_handle, true);
+}
+
+bool SharedMemory::CreateAndMapAnonymous(size_t size) {
+  // Untrusted code can't create descriptors or handles.
+  return false;
+}
+
+bool SharedMemory::Create(const SharedMemoryCreateOptions& options) {
+  // Untrusted code can't create descriptors or handles.
+  return false;
+}
+
+bool SharedMemory::Delete(const std::string& name) {
+  return false;
+}
+
+bool SharedMemory::Open(const std::string& name, bool read_only) {
+  return false;
+}
+
+bool SharedMemory::MapAt(off_t offset, size_t bytes) {
+  if (mapped_file_ == -1)
+    return false;
+
+  if (bytes > static_cast<size_t>(std::numeric_limits<int>::max()))
+    return false;
+
+  if (memory_)
+    return false;
+
+  memory_ = mmap(NULL, bytes, PROT_READ | (read_only_ ? 0 : PROT_WRITE),
+                 MAP_SHARED, mapped_file_, offset);
+
+  bool mmap_succeeded = memory_ != MAP_FAILED && memory_ != NULL;
+  if (mmap_succeeded) {
+    mapped_size_ = bytes;
+    DCHECK_EQ(0U, reinterpret_cast<uintptr_t>(memory_) &
+        (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1));
+  } else {
+    memory_ = NULL;
+  }
+
+  return mmap_succeeded;
+}
+
+bool SharedMemory::Unmap() {
+  if (memory_ == NULL)
+    return false;
+
+  if (munmap(memory_, mapped_size_) < 0)
+    DPLOG(ERROR) << "munmap";
+  memory_ = NULL;
+  mapped_size_ = 0;
+  return true;
+}
+
+SharedMemoryHandle SharedMemory::handle() const {
+  return FileDescriptor(mapped_file_, false);
+}
+
+void SharedMemory::Close() {
+  if (mapped_file_ > 0) {
+    if (close(mapped_file_) < 0)
+      DPLOG(ERROR) << "close";
+    mapped_file_ = -1;
+  }
+}
+
+void SharedMemory::LockDeprecated() {
+  NOTIMPLEMENTED();
+}
+
+void SharedMemory::UnlockDeprecated() {
+  NOTIMPLEMENTED();
+}
+
+bool SharedMemory::ShareToProcessCommon(ProcessHandle process,
+                                        SharedMemoryHandle *new_handle,
+                                        bool close_self,
+                                        ShareMode share_mode) {
+  if (share_mode == SHARE_READONLY) {
+    // Untrusted code can't create descriptors or handles, which is needed to
+    // drop permissions.
+    return false;
+  }
+  const int new_fd = dup(mapped_file_);
+  if (new_fd < 0) {
+    DPLOG(ERROR) << "dup() failed.";
+    return false;
+  }
+
+  new_handle->fd = new_fd;
+  new_handle->auto_close = true;
+
+  if (close_self) {
+    Unmap();
+    Close();
+  }
+  return true;
+}
+
+}  // namespace base
diff --git a/base/memory/shared_memory_posix.cc b/base/memory/shared_memory_posix.cc
new file mode 100644
index 0000000..35d746e
--- /dev/null
+++ b/base/memory/shared_memory_posix.cc
@@ -0,0 +1,547 @@
+// Copyright (c) 2012 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/memory/shared_memory.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/posix/safe_strerror.h"
+#include "base/process/process_metrics.h"
+#include "base/profiler/scoped_tracker.h"
+#include "base/scoped_generic.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread_restrictions.h"
+
+#if defined(OS_MACOSX)
+#include "base/mac/foundation_util.h"
+#endif  // OS_MACOSX
+
+#if defined(OS_ANDROID)
+#include "base/os_compat_android.h"
+#include "third_party/ashmem/ashmem.h"
+#endif
+
+namespace base {
+
+namespace {
+
+LazyInstance<Lock>::Leaky g_thread_lock_ = LAZY_INSTANCE_INITIALIZER;
+
+struct ScopedPathUnlinkerTraits {
+  static FilePath* InvalidValue() { return nullptr; }
+
+  static void Free(FilePath* path) {
+    // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466437
+    // is fixed.
+    tracked_objects::ScopedTracker tracking_profile(
+        FROM_HERE_WITH_EXPLICIT_FUNCTION(
+            "466437 SharedMemory::Create::Unlink"));
+    if (unlink(path->value().c_str()))
+      PLOG(WARNING) << "unlink";
+  }
+};
+
+// Unlinks the FilePath when the object is destroyed.
+typedef ScopedGeneric<FilePath*, ScopedPathUnlinkerTraits> ScopedPathUnlinker;
+
+#if !defined(OS_ANDROID)
+// Makes a temporary file, fdopens it, and then unlinks it. |fp| is populated
+// with the fdopened FILE. |readonly_fd| is populated with the opened fd if
+// options.share_read_only is true. |path| is populated with the location of
+// the file before it was unlinked.
+// Returns false if there's an unhandled failure.
+bool CreateAnonymousSharedMemory(const SharedMemoryCreateOptions& options,
+                                 ScopedFILE* fp,
+                                 ScopedFD* readonly_fd,
+                                 FilePath* path) {
+  // It doesn't make sense to have a open-existing private piece of shmem
+  DCHECK(!options.open_existing_deprecated);
+  // Q: Why not use the shm_open() etc. APIs?
+  // A: Because they're limited to 4mb on OS X.  FFFFFFFUUUUUUUUUUU
+  FilePath directory;
+  ScopedPathUnlinker path_unlinker;
+  if (GetShmemTempDir(options.executable, &directory)) {
+    // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466437
+    // is fixed.
+    tracked_objects::ScopedTracker tracking_profile(
+        FROM_HERE_WITH_EXPLICIT_FUNCTION(
+            "466437 SharedMemory::Create::OpenTemporaryFile"));
+    fp->reset(base::CreateAndOpenTemporaryFileInDir(directory, path));
+
+    // Deleting the file prevents anyone else from mapping it in (making it
+    // private), and prevents the need for cleanup (once the last fd is
+    // closed, it is truly freed).
+    if (*fp)
+      path_unlinker.reset(path);
+  }
+
+  if (*fp) {
+    if (options.share_read_only) {
+      // TODO(erikchen): Remove ScopedTracker below once
+      // http://crbug.com/466437 is fixed.
+      tracked_objects::ScopedTracker tracking_profile(
+          FROM_HERE_WITH_EXPLICIT_FUNCTION(
+              "466437 SharedMemory::Create::OpenReadonly"));
+      // Also open as readonly so that we can ShareReadOnlyToProcess.
+      readonly_fd->reset(HANDLE_EINTR(open(path->value().c_str(), O_RDONLY)));
+      if (!readonly_fd->is_valid()) {
+        DPLOG(ERROR) << "open(\"" << path->value() << "\", O_RDONLY) failed";
+        fp->reset();
+        return false;
+      }
+    }
+  }
+  return true;
+}
+#endif  // !defined(OS_ANDROID)
+}
+
+SharedMemory::SharedMemory()
+    : mapped_file_(-1),
+      readonly_mapped_file_(-1),
+      mapped_size_(0),
+      memory_(NULL),
+      read_only_(false),
+      requested_size_(0) {
+}
+
+SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only)
+    : mapped_file_(handle.fd),
+      readonly_mapped_file_(-1),
+      mapped_size_(0),
+      memory_(NULL),
+      read_only_(read_only),
+      requested_size_(0) {
+}
+
+SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only,
+                           ProcessHandle process)
+    : mapped_file_(handle.fd),
+      readonly_mapped_file_(-1),
+      mapped_size_(0),
+      memory_(NULL),
+      read_only_(read_only),
+      requested_size_(0) {
+  // We don't handle this case yet (note the ignored parameter); let's die if
+  // someone comes calling.
+  NOTREACHED();
+}
+
+SharedMemory::~SharedMemory() {
+  Unmap();
+  Close();
+}
+
+// static
+bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) {
+  return handle.fd >= 0;
+}
+
+// static
+SharedMemoryHandle SharedMemory::NULLHandle() {
+  return SharedMemoryHandle();
+}
+
+// static
+void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) {
+  DCHECK_GE(handle.fd, 0);
+  if (close(handle.fd) < 0)
+    DPLOG(ERROR) << "close";
+}
+
+// static
+size_t SharedMemory::GetHandleLimit() {
+  return base::GetMaxFds();
+}
+
+// static
+SharedMemoryHandle SharedMemory::DuplicateHandle(
+    const SharedMemoryHandle& handle) {
+  int duped_handle = HANDLE_EINTR(dup(handle.fd));
+  if (duped_handle < 0)
+    return base::SharedMemory::NULLHandle();
+  return base::FileDescriptor(duped_handle, true);
+}
+
+// static
+int SharedMemory::GetFdFromSharedMemoryHandle(
+    const SharedMemoryHandle& handle) {
+  return handle.fd;
+}
+
+bool SharedMemory::CreateAndMapAnonymous(size_t size) {
+  return CreateAnonymous(size) && Map(size);
+}
+
+#if !defined(OS_ANDROID)
+// static
+int SharedMemory::GetSizeFromSharedMemoryHandle(
+    const SharedMemoryHandle& handle) {
+  struct stat st;
+  if (fstat(handle.fd, &st) != 0)
+    return -1;
+  return st.st_size;
+}
+
+// Chromium mostly only uses the unique/private shmem as specified by
+// "name == L"". The exception is in the StatsTable.
+// TODO(jrg): there is no way to "clean up" all unused named shmem if
+// we restart from a crash.  (That isn't a new problem, but it is a problem.)
+// In case we want to delete it later, it may be useful to save the value
+// of mem_filename after FilePathForMemoryName().
+bool SharedMemory::Create(const SharedMemoryCreateOptions& options) {
+  // TODO(erikchen): Remove ScopedTracker below once http://crbug.com/466437
+  // is fixed.
+  tracked_objects::ScopedTracker tracking_profile1(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "466437 SharedMemory::Create::Start"));
+  DCHECK_EQ(-1, mapped_file_);
+  if (options.size == 0) return false;
+
+  if (options.size > static_cast<size_t>(std::numeric_limits<int>::max()))
+    return false;
+
+  // This function theoretically can block on the disk, but realistically
+  // the temporary files we create will just go into the buffer cache
+  // and be deleted before they ever make it out to disk.
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
+
+  ScopedFILE fp;
+  bool fix_size = true;
+  ScopedFD readonly_fd;
+
+  FilePath path;
+  if (options.name_deprecated == NULL || options.name_deprecated->empty()) {
+    bool result =
+        CreateAnonymousSharedMemory(options, &fp, &readonly_fd, &path);
+    if (!result)
+      return false;
+  } else {
+    if (!FilePathForMemoryName(*options.name_deprecated, &path))
+      return false;
+
+    // Make sure that the file is opened without any permission
+    // to other users on the system.
+    const mode_t kOwnerOnly = S_IRUSR | S_IWUSR;
+
+    // First, try to create the file.
+    int fd = HANDLE_EINTR(
+        open(path.value().c_str(), O_RDWR | O_CREAT | O_EXCL, kOwnerOnly));
+    if (fd == -1 && options.open_existing_deprecated) {
+      // If this doesn't work, try and open an existing file in append mode.
+      // Opening an existing file in a world writable directory has two main
+      // security implications:
+      // - Attackers could plant a file under their control, so ownership of
+      //   the file is checked below.
+      // - Attackers could plant a symbolic link so that an unexpected file
+      //   is opened, so O_NOFOLLOW is passed to open().
+      fd = HANDLE_EINTR(
+          open(path.value().c_str(), O_RDWR | O_APPEND | O_NOFOLLOW));
+
+      // Check that the current user owns the file.
+      // If uid != euid, then a more complex permission model is used and this
+      // API is not appropriate.
+      const uid_t real_uid = getuid();
+      const uid_t effective_uid = geteuid();
+      struct stat sb;
+      if (fd >= 0 &&
+          (fstat(fd, &sb) != 0 || sb.st_uid != real_uid ||
+           sb.st_uid != effective_uid)) {
+        LOG(ERROR) <<
+            "Invalid owner when opening existing shared memory file.";
+        close(fd);
+        return false;
+      }
+
+      // An existing file was opened, so its size should not be fixed.
+      fix_size = false;
+    }
+
+    if (options.share_read_only) {
+      // Also open as readonly so that we can ShareReadOnlyToProcess.
+      readonly_fd.reset(HANDLE_EINTR(open(path.value().c_str(), O_RDONLY)));
+      if (!readonly_fd.is_valid()) {
+        DPLOG(ERROR) << "open(\"" << path.value() << "\", O_RDONLY) failed";
+        close(fd);
+        fd = -1;
+        return false;
+      }
+    }
+    if (fd >= 0) {
+      // "a+" is always appropriate: if it's a new file, a+ is similar to w+.
+      fp.reset(fdopen(fd, "a+"));
+    }
+  }
+  if (fp && fix_size) {
+    // Get current size.
+    struct stat stat;
+    if (fstat(fileno(fp.get()), &stat) != 0)
+      return false;
+    const size_t current_size = stat.st_size;
+    if (current_size != options.size) {
+      if (HANDLE_EINTR(ftruncate(fileno(fp.get()), options.size)) != 0)
+        return false;
+    }
+    requested_size_ = options.size;
+  }
+  if (fp == NULL) {
+#if !defined(OS_MACOSX)
+    PLOG(ERROR) << "Creating shared memory in " << path.value() << " failed";
+    FilePath dir = path.DirName();
+    if (access(dir.value().c_str(), W_OK | X_OK) < 0) {
+      PLOG(ERROR) << "Unable to access(W_OK|X_OK) " << dir.value();
+      if (dir.value() == "/dev/shm") {
+        LOG(FATAL) << "This is frequently caused by incorrect permissions on "
+                   << "/dev/shm.  Try 'sudo chmod 1777 /dev/shm' to fix.";
+      }
+    }
+#else
+    PLOG(ERROR) << "Creating shared memory in " << path.value() << " failed";
+#endif
+    return false;
+  }
+
+  return PrepareMapFile(fp.Pass(), readonly_fd.Pass());
+}
+
+// Our current implementation of shmem is with mmap()ing of files.
+// These files need to be deleted explicitly.
+// In practice this call is only needed for unit tests.
+bool SharedMemory::Delete(const std::string& name) {
+  FilePath path;
+  if (!FilePathForMemoryName(name, &path))
+    return false;
+
+  if (PathExists(path))
+    return base::DeleteFile(path, false);
+
+  // Doesn't exist, so success.
+  return true;
+}
+
+bool SharedMemory::Open(const std::string& name, bool read_only) {
+  FilePath path;
+  if (!FilePathForMemoryName(name, &path))
+    return false;
+
+  read_only_ = read_only;
+
+  const char *mode = read_only ? "r" : "r+";
+  ScopedFILE fp(base::OpenFile(path, mode));
+  ScopedFD readonly_fd(HANDLE_EINTR(open(path.value().c_str(), O_RDONLY)));
+  if (!readonly_fd.is_valid()) {
+    DPLOG(ERROR) << "open(\"" << path.value() << "\", O_RDONLY) failed";
+    return false;
+  }
+  return PrepareMapFile(fp.Pass(), readonly_fd.Pass());
+}
+#endif  // !defined(OS_ANDROID)
+
+bool SharedMemory::MapAt(off_t offset, size_t bytes) {
+  if (mapped_file_ == -1)
+    return false;
+
+  if (bytes > static_cast<size_t>(std::numeric_limits<int>::max()))
+    return false;
+
+  if (memory_)
+    return false;
+
+#if defined(OS_ANDROID)
+  // On Android, Map can be called with a size and offset of zero to use the
+  // ashmem-determined size.
+  if (bytes == 0) {
+    DCHECK_EQ(0, offset);
+    int ashmem_bytes = ashmem_get_size_region(mapped_file_);
+    if (ashmem_bytes < 0)
+      return false;
+    bytes = ashmem_bytes;
+  }
+#endif
+
+  memory_ = mmap(NULL, bytes, PROT_READ | (read_only_ ? 0 : PROT_WRITE),
+                 MAP_SHARED, mapped_file_, offset);
+
+  bool mmap_succeeded = memory_ != (void*)-1 && memory_ != NULL;
+  if (mmap_succeeded) {
+    mapped_size_ = bytes;
+    DCHECK_EQ(0U, reinterpret_cast<uintptr_t>(memory_) &
+        (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1));
+  } else {
+    memory_ = NULL;
+  }
+
+  return mmap_succeeded;
+}
+
+bool SharedMemory::Unmap() {
+  if (memory_ == NULL)
+    return false;
+
+  munmap(memory_, mapped_size_);
+  memory_ = NULL;
+  mapped_size_ = 0;
+  return true;
+}
+
+SharedMemoryHandle SharedMemory::handle() const {
+  return FileDescriptor(mapped_file_, false);
+}
+
+void SharedMemory::Close() {
+  if (mapped_file_ > 0) {
+    if (close(mapped_file_) < 0)
+      PLOG(ERROR) << "close";
+    mapped_file_ = -1;
+  }
+  if (readonly_mapped_file_ > 0) {
+    if (close(readonly_mapped_file_) < 0)
+      PLOG(ERROR) << "close";
+    readonly_mapped_file_ = -1;
+  }
+}
+
+void SharedMemory::LockDeprecated() {
+  g_thread_lock_.Get().Acquire();
+  LockOrUnlockCommon(F_LOCK);
+}
+
+void SharedMemory::UnlockDeprecated() {
+  LockOrUnlockCommon(F_ULOCK);
+  g_thread_lock_.Get().Release();
+}
+
+#if !defined(OS_ANDROID)
+bool SharedMemory::PrepareMapFile(ScopedFILE fp, ScopedFD readonly_fd) {
+  DCHECK_EQ(-1, mapped_file_);
+  DCHECK_EQ(-1, readonly_mapped_file_);
+  if (fp == NULL)
+    return false;
+
+  // This function theoretically can block on the disk, but realistically
+  // the temporary files we create will just go into the buffer cache
+  // and be deleted before they ever make it out to disk.
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
+
+  struct stat st = {};
+  if (fstat(fileno(fp.get()), &st))
+    NOTREACHED();
+  if (readonly_fd.is_valid()) {
+    struct stat readonly_st = {};
+    if (fstat(readonly_fd.get(), &readonly_st))
+      NOTREACHED();
+    if (st.st_dev != readonly_st.st_dev || st.st_ino != readonly_st.st_ino) {
+      LOG(ERROR) << "writable and read-only inodes don't match; bailing";
+      return false;
+    }
+  }
+
+  mapped_file_ = HANDLE_EINTR(dup(fileno(fp.get())));
+  if (mapped_file_ == -1) {
+    if (errno == EMFILE) {
+      LOG(WARNING) << "Shared memory creation failed; out of file descriptors";
+      return false;
+    } else {
+      NOTREACHED() << "Call to dup failed, errno=" << errno;
+    }
+  }
+  readonly_mapped_file_ = readonly_fd.release();
+
+  return true;
+}
+
+// For the given shmem named |mem_name|, return a filename to mmap()
+// (and possibly create).  Modifies |filename|.  Return false on
+// error, or true of we are happy.
+bool SharedMemory::FilePathForMemoryName(const std::string& mem_name,
+                                         FilePath* path) {
+  // mem_name will be used for a filename; make sure it doesn't
+  // contain anything which will confuse us.
+  DCHECK_EQ(std::string::npos, mem_name.find('/'));
+  DCHECK_EQ(std::string::npos, mem_name.find('\0'));
+
+  FilePath temp_dir;
+  if (!GetShmemTempDir(false, &temp_dir))
+    return false;
+
+#if !defined(OS_MACOSX)
+#if defined(GOOGLE_CHROME_BUILD)
+  std::string name_base = std::string("com.google.Chrome");
+#else
+  std::string name_base = std::string("org.chromium.Chromium");
+#endif
+#else  // OS_MACOSX
+  std::string name_base = std::string(base::mac::BaseBundleID());
+#endif  // OS_MACOSX
+  *path = temp_dir.AppendASCII(name_base + ".shmem." + mem_name);
+  return true;
+}
+#endif  // !defined(OS_ANDROID)
+
+void SharedMemory::LockOrUnlockCommon(int function) {
+  DCHECK_GE(mapped_file_, 0);
+  while (lockf(mapped_file_, function, 0) < 0) {
+    if (errno == EINTR) {
+      continue;
+    } else if (errno == ENOLCK) {
+      // temporary kernel resource exaustion
+      base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(500));
+      continue;
+    } else {
+      NOTREACHED() << "lockf() failed."
+                   << " function:" << function
+                   << " fd:" << mapped_file_
+                   << " errno:" << errno
+                   << " msg:" << base::safe_strerror(errno);
+    }
+  }
+}
+
+bool SharedMemory::ShareToProcessCommon(ProcessHandle process,
+                                        SharedMemoryHandle* new_handle,
+                                        bool close_self,
+                                        ShareMode share_mode) {
+  int handle_to_dup = -1;
+  switch(share_mode) {
+    case SHARE_CURRENT_MODE:
+      handle_to_dup = mapped_file_;
+      break;
+    case SHARE_READONLY:
+      // We could imagine re-opening the file from /dev/fd, but that can't make
+      // it readonly on Mac: https://codereview.chromium.org/27265002/#msg10
+      CHECK_GE(readonly_mapped_file_, 0);
+      handle_to_dup = readonly_mapped_file_;
+      break;
+  }
+
+  const int new_fd = HANDLE_EINTR(dup(handle_to_dup));
+  if (new_fd < 0) {
+    DPLOG(ERROR) << "dup() failed.";
+    return false;
+  }
+
+  new_handle->fd = new_fd;
+  new_handle->auto_close = true;
+
+  if (close_self) {
+    Unmap();
+    Close();
+  }
+
+  return true;
+}
+
+}  // namespace base
diff --git a/base/memory/shared_memory_unittest.cc b/base/memory/shared_memory_unittest.cc
new file mode 100644
index 0000000..6fe5706
--- /dev/null
+++ b/base/memory/shared_memory_unittest.cc
@@ -0,0 +1,723 @@
+// Copyright (c) 2012 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/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/shared_memory.h"
+#include "base/process/kill.h"
+#include "base/rand_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/sys_info.h"
+#include "base/test/multiprocess_test.h"
+#include "base/threading/platform_thread.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/multiprocess_func_list.h"
+
+#if defined(OS_MACOSX)
+#include "base/mac/scoped_nsautorelease_pool.h"
+#endif
+
+#if defined(OS_POSIX)
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
+#if defined(OS_WIN)
+#include "base/win/scoped_handle.h"
+#endif
+
+static const int kNumThreads = 5;
+#if !defined(OS_IOS)  // iOS does not allow multiple processes.
+static const int kNumTasks = 5;
+#endif
+
+namespace base {
+
+namespace {
+
+// Each thread will open the shared memory.  Each thread will take a different 4
+// byte int pointer, and keep changing it, with some small pauses in between.
+// Verify that each thread's value in the shared memory is always correct.
+class MultipleThreadMain : public PlatformThread::Delegate {
+ public:
+  explicit MultipleThreadMain(int16 id) : id_(id) {}
+  ~MultipleThreadMain() override {}
+
+  static void CleanUp() {
+    SharedMemory memory;
+    memory.Delete(s_test_name_);
+  }
+
+  // PlatformThread::Delegate interface.
+  void ThreadMain() override {
+#if defined(OS_MACOSX)
+    mac::ScopedNSAutoreleasePool pool;
+#endif
+    const uint32 kDataSize = 1024;
+    SharedMemory memory;
+    bool rv = memory.CreateNamedDeprecated(s_test_name_, true, kDataSize);
+    EXPECT_TRUE(rv);
+    rv = memory.Map(kDataSize);
+    EXPECT_TRUE(rv);
+    int *ptr = static_cast<int*>(memory.memory()) + id_;
+    EXPECT_EQ(0, *ptr);
+
+    for (int idx = 0; idx < 100; idx++) {
+      *ptr = idx;
+      PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1));
+      EXPECT_EQ(*ptr, idx);
+    }
+    // Reset back to 0 for the next test that uses the same name.
+    *ptr = 0;
+
+    memory.Close();
+  }
+
+ private:
+  int16 id_;
+
+  static const char* const s_test_name_;
+
+  DISALLOW_COPY_AND_ASSIGN(MultipleThreadMain);
+};
+
+const char* const MultipleThreadMain::s_test_name_ =
+    "SharedMemoryOpenThreadTest";
+
+// TODO(port):
+// This test requires the ability to pass file descriptors between processes.
+// We haven't done that yet in Chrome for POSIX.
+#if defined(OS_WIN)
+// Each thread will open the shared memory.  Each thread will take the memory,
+// and keep changing it while trying to lock it, with some small pauses in
+// between. Verify that each thread's value in the shared memory is always
+// correct.
+class MultipleLockThread : public PlatformThread::Delegate {
+ public:
+  explicit MultipleLockThread(int id) : id_(id) {}
+  ~MultipleLockThread() override {}
+
+  // PlatformThread::Delegate interface.
+  void ThreadMain() override {
+    const uint32 kDataSize = sizeof(int);
+    SharedMemoryHandle handle = NULL;
+    {
+      SharedMemory memory1;
+      EXPECT_TRUE(memory1.CreateNamedDeprecated(
+          "SharedMemoryMultipleLockThreadTest", true, kDataSize));
+      EXPECT_TRUE(memory1.ShareToProcess(GetCurrentProcess(), &handle));
+      // TODO(paulg): Implement this once we have a posix version of
+      // SharedMemory::ShareToProcess.
+      EXPECT_TRUE(true);
+    }
+
+    SharedMemory memory2(handle, false);
+    EXPECT_TRUE(memory2.Map(kDataSize));
+    volatile int* const ptr = static_cast<int*>(memory2.memory());
+
+    for (int idx = 0; idx < 20; idx++) {
+      memory2.LockDeprecated();
+      int i = (id_ << 16) + idx;
+      *ptr = i;
+      PlatformThread::Sleep(TimeDelta::FromMilliseconds(1));
+      EXPECT_EQ(*ptr, i);
+      memory2.UnlockDeprecated();
+    }
+
+    memory2.Close();
+  }
+
+ private:
+  int id_;
+
+  DISALLOW_COPY_AND_ASSIGN(MultipleLockThread);
+};
+#endif
+
+}  // namespace
+
+// Android doesn't support SharedMemory::Open/Delete/
+// CreateNamedDeprecated(openExisting=true)
+#if !defined(OS_ANDROID)
+TEST(SharedMemoryTest, OpenClose) {
+  const uint32 kDataSize = 1024;
+  std::string test_name = "SharedMemoryOpenCloseTest";
+
+  // Open two handles to a memory segment, confirm that they are mapped
+  // separately yet point to the same space.
+  SharedMemory memory1;
+  bool rv = memory1.Delete(test_name);
+  EXPECT_TRUE(rv);
+  rv = memory1.Delete(test_name);
+  EXPECT_TRUE(rv);
+  rv = memory1.Open(test_name, false);
+  EXPECT_FALSE(rv);
+  rv = memory1.CreateNamedDeprecated(test_name, false, kDataSize);
+  EXPECT_TRUE(rv);
+  rv = memory1.Map(kDataSize);
+  EXPECT_TRUE(rv);
+  SharedMemory memory2;
+  rv = memory2.Open(test_name, false);
+  EXPECT_TRUE(rv);
+  rv = memory2.Map(kDataSize);
+  EXPECT_TRUE(rv);
+  EXPECT_NE(memory1.memory(), memory2.memory());  // Compare the pointers.
+
+  // Make sure we don't segfault. (it actually happened!)
+  ASSERT_NE(memory1.memory(), static_cast<void*>(NULL));
+  ASSERT_NE(memory2.memory(), static_cast<void*>(NULL));
+
+  // Write data to the first memory segment, verify contents of second.
+  memset(memory1.memory(), '1', kDataSize);
+  EXPECT_EQ(memcmp(memory1.memory(), memory2.memory(), kDataSize), 0);
+
+  // Close the first memory segment, and verify the second has the right data.
+  memory1.Close();
+  char *start_ptr = static_cast<char *>(memory2.memory());
+  char *end_ptr = start_ptr + kDataSize;
+  for (char* ptr = start_ptr; ptr < end_ptr; ptr++)
+    EXPECT_EQ(*ptr, '1');
+
+  // Close the second memory segment.
+  memory2.Close();
+
+  rv = memory1.Delete(test_name);
+  EXPECT_TRUE(rv);
+  rv = memory2.Delete(test_name);
+  EXPECT_TRUE(rv);
+}
+
+TEST(SharedMemoryTest, OpenExclusive) {
+  const uint32 kDataSize = 1024;
+  const uint32 kDataSize2 = 2048;
+  std::ostringstream test_name_stream;
+  test_name_stream << "SharedMemoryOpenExclusiveTest."
+                   << Time::Now().ToDoubleT();
+  std::string test_name = test_name_stream.str();
+
+  // Open two handles to a memory segment and check that
+  // open_existing_deprecated works as expected.
+  SharedMemory memory1;
+  bool rv = memory1.CreateNamedDeprecated(test_name, false, kDataSize);
+  EXPECT_TRUE(rv);
+
+  // Memory1 knows it's size because it created it.
+  EXPECT_EQ(memory1.requested_size(), kDataSize);
+
+  rv = memory1.Map(kDataSize);
+  EXPECT_TRUE(rv);
+
+  // The mapped memory1 must be at least the size we asked for.
+  EXPECT_GE(memory1.mapped_size(), kDataSize);
+
+  // The mapped memory1 shouldn't exceed rounding for allocation granularity.
+  EXPECT_LT(memory1.mapped_size(),
+            kDataSize + base::SysInfo::VMAllocationGranularity());
+
+  memset(memory1.memory(), 'G', kDataSize);
+
+  SharedMemory memory2;
+  // Should not be able to create if openExisting is false.
+  rv = memory2.CreateNamedDeprecated(test_name, false, kDataSize2);
+  EXPECT_FALSE(rv);
+
+  // Should be able to create with openExisting true.
+  rv = memory2.CreateNamedDeprecated(test_name, true, kDataSize2);
+  EXPECT_TRUE(rv);
+
+  // Memory2 shouldn't know the size because we didn't create it.
+  EXPECT_EQ(memory2.requested_size(), 0U);
+
+  // We should be able to map the original size.
+  rv = memory2.Map(kDataSize);
+  EXPECT_TRUE(rv);
+
+  // The mapped memory2 must be at least the size of the original.
+  EXPECT_GE(memory2.mapped_size(), kDataSize);
+
+  // The mapped memory2 shouldn't exceed rounding for allocation granularity.
+  EXPECT_LT(memory2.mapped_size(),
+            kDataSize2 + base::SysInfo::VMAllocationGranularity());
+
+  // Verify that opening memory2 didn't truncate or delete memory 1.
+  char *start_ptr = static_cast<char *>(memory2.memory());
+  char *end_ptr = start_ptr + kDataSize;
+  for (char* ptr = start_ptr; ptr < end_ptr; ptr++) {
+    EXPECT_EQ(*ptr, 'G');
+  }
+
+  memory1.Close();
+  memory2.Close();
+
+  rv = memory1.Delete(test_name);
+  EXPECT_TRUE(rv);
+}
+#endif
+
+// Check that memory is still mapped after its closed.
+TEST(SharedMemoryTest, CloseNoUnmap) {
+  const size_t kDataSize = 4096;
+
+  SharedMemory memory;
+  ASSERT_TRUE(memory.CreateAndMapAnonymous(kDataSize));
+  char* ptr = static_cast<char*>(memory.memory());
+  ASSERT_NE(ptr, static_cast<void*>(NULL));
+  memset(ptr, 'G', kDataSize);
+
+  memory.Close();
+
+  EXPECT_EQ(ptr, memory.memory());
+  EXPECT_EQ(SharedMemory::NULLHandle(), memory.handle());
+
+  for (size_t i = 0; i < kDataSize; i++) {
+    EXPECT_EQ('G', ptr[i]);
+  }
+
+  memory.Unmap();
+  EXPECT_EQ(nullptr, memory.memory());
+}
+
+// Create a set of N threads to each open a shared memory segment and write to
+// it. Verify that they are always reading/writing consistent data.
+TEST(SharedMemoryTest, MultipleThreads) {
+  MultipleThreadMain::CleanUp();
+  // On POSIX we have a problem when 2 threads try to create the shmem
+  // (a file) at exactly the same time, since create both creates the
+  // file and zerofills it.  We solve the problem for this unit test
+  // (make it not flaky) by starting with 1 thread, then
+  // intentionally don't clean up its shmem before running with
+  // kNumThreads.
+
+  int threadcounts[] = { 1, kNumThreads };
+  for (size_t i = 0; i < arraysize(threadcounts); i++) {
+    int numthreads = threadcounts[i];
+    scoped_ptr<PlatformThreadHandle[]> thread_handles;
+    scoped_ptr<MultipleThreadMain*[]> thread_delegates;
+
+    thread_handles.reset(new PlatformThreadHandle[numthreads]);
+    thread_delegates.reset(new MultipleThreadMain*[numthreads]);
+
+    // Spawn the threads.
+    for (int16 index = 0; index < numthreads; index++) {
+      PlatformThreadHandle pth;
+      thread_delegates[index] = new MultipleThreadMain(index);
+      EXPECT_TRUE(PlatformThread::Create(0, thread_delegates[index], &pth));
+      thread_handles[index] = pth;
+    }
+
+    // Wait for the threads to finish.
+    for (int index = 0; index < numthreads; index++) {
+      PlatformThread::Join(thread_handles[index]);
+      delete thread_delegates[index];
+    }
+  }
+  MultipleThreadMain::CleanUp();
+}
+
+// TODO(port): this test requires the MultipleLockThread class
+// (defined above), which requires the ability to pass file
+// descriptors between processes.  We haven't done that yet in Chrome
+// for POSIX.
+#if defined(OS_WIN)
+// Create a set of threads to each open a shared memory segment and write to it
+// with the lock held. Verify that they are always reading/writing consistent
+// data.
+TEST(SharedMemoryTest, Lock) {
+  PlatformThreadHandle thread_handles[kNumThreads];
+  MultipleLockThread* thread_delegates[kNumThreads];
+
+  // Spawn the threads.
+  for (int index = 0; index < kNumThreads; ++index) {
+    PlatformThreadHandle pth;
+    thread_delegates[index] = new MultipleLockThread(index);
+    EXPECT_TRUE(PlatformThread::Create(0, thread_delegates[index], &pth));
+    thread_handles[index] = pth;
+  }
+
+  // Wait for the threads to finish.
+  for (int index = 0; index < kNumThreads; ++index) {
+    PlatformThread::Join(thread_handles[index]);
+    delete thread_delegates[index];
+  }
+}
+#endif
+
+// Allocate private (unique) shared memory with an empty string for a
+// name.  Make sure several of them don't point to the same thing as
+// we might expect if the names are equal.
+TEST(SharedMemoryTest, AnonymousPrivate) {
+  int i, j;
+  int count = 4;
+  bool rv;
+  const uint32 kDataSize = 8192;
+
+  scoped_ptr<SharedMemory[]> memories(new SharedMemory[count]);
+  scoped_ptr<int*[]> pointers(new int*[count]);
+  ASSERT_TRUE(memories.get());
+  ASSERT_TRUE(pointers.get());
+
+  for (i = 0; i < count; i++) {
+    rv = memories[i].CreateAndMapAnonymous(kDataSize);
+    EXPECT_TRUE(rv);
+    int *ptr = static_cast<int*>(memories[i].memory());
+    EXPECT_TRUE(ptr);
+    pointers[i] = ptr;
+  }
+
+  for (i = 0; i < count; i++) {
+    // zero out the first int in each except for i; for that one, make it 100.
+    for (j = 0; j < count; j++) {
+      if (i == j)
+        pointers[j][0] = 100;
+      else
+        pointers[j][0] = 0;
+    }
+    // make sure there is no bleeding of the 100 into the other pointers
+    for (j = 0; j < count; j++) {
+      if (i == j)
+        EXPECT_EQ(100, pointers[j][0]);
+      else
+        EXPECT_EQ(0, pointers[j][0]);
+    }
+  }
+
+  for (int i = 0; i < count; i++) {
+    memories[i].Close();
+  }
+}
+
+TEST(SharedMemoryTest, ShareReadOnly) {
+  StringPiece contents = "Hello World";
+
+  SharedMemory writable_shmem;
+  SharedMemoryCreateOptions options;
+  options.size = contents.size();
+  options.share_read_only = true;
+  ASSERT_TRUE(writable_shmem.Create(options));
+  ASSERT_TRUE(writable_shmem.Map(options.size));
+  memcpy(writable_shmem.memory(), contents.data(), contents.size());
+  EXPECT_TRUE(writable_shmem.Unmap());
+
+  SharedMemoryHandle readonly_handle;
+  ASSERT_TRUE(writable_shmem.ShareReadOnlyToProcess(GetCurrentProcessHandle(),
+                                                    &readonly_handle));
+  SharedMemory readonly_shmem(readonly_handle, /*readonly=*/true);
+
+  ASSERT_TRUE(readonly_shmem.Map(contents.size()));
+  EXPECT_EQ(contents,
+            StringPiece(static_cast<const char*>(readonly_shmem.memory()),
+                        contents.size()));
+  EXPECT_TRUE(readonly_shmem.Unmap());
+
+  // Make sure the writable instance is still writable.
+  ASSERT_TRUE(writable_shmem.Map(contents.size()));
+  StringPiece new_contents = "Goodbye";
+  memcpy(writable_shmem.memory(), new_contents.data(), new_contents.size());
+  EXPECT_EQ(new_contents,
+            StringPiece(static_cast<const char*>(writable_shmem.memory()),
+                        new_contents.size()));
+
+  // We'd like to check that if we send the read-only segment to another
+  // process, then that other process can't reopen it read/write.  (Since that
+  // would be a security hole.)  Setting up multiple processes is hard in a
+  // unittest, so this test checks that the *current* process can't reopen the
+  // segment read/write.  I think the test here is stronger than we actually
+  // care about, but there's a remote possibility that sending a file over a
+  // pipe would transform it into read/write.
+  SharedMemoryHandle handle = readonly_shmem.handle();
+
+#if defined(OS_ANDROID)
+  // The "read-only" handle is still writable on Android:
+  // http://crbug.com/320865
+  (void)handle;
+#elif defined(OS_POSIX)
+  EXPECT_EQ(O_RDONLY, fcntl(handle.fd, F_GETFL) & O_ACCMODE)
+      << "The descriptor itself should be read-only.";
+
+  errno = 0;
+  void* writable = mmap(
+      NULL, contents.size(), PROT_READ | PROT_WRITE, MAP_SHARED, handle.fd, 0);
+  int mmap_errno = errno;
+  EXPECT_EQ(MAP_FAILED, writable)
+      << "It shouldn't be possible to re-mmap the descriptor writable.";
+  EXPECT_EQ(EACCES, mmap_errno) << strerror(mmap_errno);
+  if (writable != MAP_FAILED)
+    EXPECT_EQ(0, munmap(writable, readonly_shmem.mapped_size()));
+
+#elif defined(OS_WIN)
+  EXPECT_EQ(NULL, MapViewOfFile(handle, FILE_MAP_WRITE, 0, 0, 0))
+      << "Shouldn't be able to map memory writable.";
+
+  HANDLE temp_handle;
+  BOOL rv = ::DuplicateHandle(GetCurrentProcess(),
+                              handle,
+                              GetCurrentProcess(),
+                              &temp_handle,
+                              FILE_MAP_ALL_ACCESS,
+                              false,
+                              0);
+  EXPECT_EQ(FALSE, rv)
+      << "Shouldn't be able to duplicate the handle into a writable one.";
+  if (rv)
+    base::win::ScopedHandle writable_handle(temp_handle);
+  rv = ::DuplicateHandle(GetCurrentProcess(),
+                         handle,
+                         GetCurrentProcess(),
+                         &temp_handle,
+                         FILE_MAP_READ,
+                         false,
+                         0);
+  EXPECT_EQ(TRUE, rv)
+      << "Should be able to duplicate the handle into a readable one.";
+  if (rv)
+    base::win::ScopedHandle writable_handle(temp_handle);
+#else
+#error Unexpected platform; write a test that tries to make 'handle' writable.
+#endif  // defined(OS_POSIX) || defined(OS_WIN)
+}
+
+TEST(SharedMemoryTest, ShareToSelf) {
+  StringPiece contents = "Hello World";
+
+  SharedMemory shmem;
+  ASSERT_TRUE(shmem.CreateAndMapAnonymous(contents.size()));
+  memcpy(shmem.memory(), contents.data(), contents.size());
+  EXPECT_TRUE(shmem.Unmap());
+
+  SharedMemoryHandle shared_handle;
+  ASSERT_TRUE(shmem.ShareToProcess(GetCurrentProcessHandle(), &shared_handle));
+  SharedMemory shared(shared_handle, /*readonly=*/false);
+
+  ASSERT_TRUE(shared.Map(contents.size()));
+  EXPECT_EQ(
+      contents,
+      StringPiece(static_cast<const char*>(shared.memory()), contents.size()));
+
+  ASSERT_TRUE(shmem.ShareToProcess(GetCurrentProcessHandle(), &shared_handle));
+  SharedMemory readonly(shared_handle, /*readonly=*/true);
+
+  ASSERT_TRUE(readonly.Map(contents.size()));
+  EXPECT_EQ(contents,
+            StringPiece(static_cast<const char*>(readonly.memory()),
+                        contents.size()));
+}
+
+TEST(SharedMemoryTest, MapAt) {
+  ASSERT_TRUE(SysInfo::VMAllocationGranularity() >= sizeof(uint32));
+  const size_t kCount = SysInfo::VMAllocationGranularity();
+  const size_t kDataSize = kCount * sizeof(uint32);
+
+  SharedMemory memory;
+  ASSERT_TRUE(memory.CreateAndMapAnonymous(kDataSize));
+  uint32* ptr = static_cast<uint32*>(memory.memory());
+  ASSERT_NE(ptr, static_cast<void*>(NULL));
+
+  for (size_t i = 0; i < kCount; ++i) {
+    ptr[i] = i;
+  }
+
+  memory.Unmap();
+
+  off_t offset = SysInfo::VMAllocationGranularity();
+  ASSERT_TRUE(memory.MapAt(offset, kDataSize - offset));
+  offset /= sizeof(uint32);
+  ptr = static_cast<uint32*>(memory.memory());
+  ASSERT_NE(ptr, static_cast<void*>(NULL));
+  for (size_t i = offset; i < kCount; ++i) {
+    EXPECT_EQ(ptr[i - offset], i);
+  }
+}
+
+TEST(SharedMemoryTest, MapTwice) {
+  const uint32 kDataSize = 1024;
+  SharedMemory memory;
+  bool rv = memory.CreateAndMapAnonymous(kDataSize);
+  EXPECT_TRUE(rv);
+
+  void* old_address = memory.memory();
+
+  rv = memory.Map(kDataSize);
+  EXPECT_FALSE(rv);
+  EXPECT_EQ(old_address, memory.memory());
+}
+
+#if defined(OS_POSIX)
+// This test is not applicable for iOS (crbug.com/399384).
+#if !defined(OS_IOS)
+// Create a shared memory object, mmap it, and mprotect it to PROT_EXEC.
+TEST(SharedMemoryTest, AnonymousExecutable) {
+  const uint32 kTestSize = 1 << 16;
+
+  SharedMemory shared_memory;
+  SharedMemoryCreateOptions options;
+  options.size = kTestSize;
+  options.executable = true;
+
+  EXPECT_TRUE(shared_memory.Create(options));
+  EXPECT_TRUE(shared_memory.Map(shared_memory.requested_size()));
+
+  EXPECT_EQ(0, mprotect(shared_memory.memory(), shared_memory.requested_size(),
+                        PROT_READ | PROT_EXEC));
+}
+#endif  // !defined(OS_IOS)
+
+// Android supports a different permission model than POSIX for its "ashmem"
+// shared memory implementation. So the tests about file permissions are not
+// included on Android.
+#if !defined(OS_ANDROID)
+
+// Set a umask and restore the old mask on destruction.
+class ScopedUmaskSetter {
+ public:
+  explicit ScopedUmaskSetter(mode_t target_mask) {
+    old_umask_ = umask(target_mask);
+  }
+  ~ScopedUmaskSetter() { umask(old_umask_); }
+ private:
+  mode_t old_umask_;
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ScopedUmaskSetter);
+};
+
+// Create a shared memory object, check its permissions.
+TEST(SharedMemoryTest, FilePermissionsAnonymous) {
+  const uint32 kTestSize = 1 << 8;
+
+  SharedMemory shared_memory;
+  SharedMemoryCreateOptions options;
+  options.size = kTestSize;
+  // Set a file mode creation mask that gives all permissions.
+  ScopedUmaskSetter permissive_mask(S_IWGRP | S_IWOTH);
+
+  EXPECT_TRUE(shared_memory.Create(options));
+
+  int shm_fd = shared_memory.handle().fd;
+  struct stat shm_stat;
+  EXPECT_EQ(0, fstat(shm_fd, &shm_stat));
+  // Neither the group, nor others should be able to read the shared memory
+  // file.
+  EXPECT_FALSE(shm_stat.st_mode & S_IRWXO);
+  EXPECT_FALSE(shm_stat.st_mode & S_IRWXG);
+}
+
+// Create a shared memory object, check its permissions.
+TEST(SharedMemoryTest, FilePermissionsNamed) {
+  const uint32 kTestSize = 1 << 8;
+
+  SharedMemory shared_memory;
+  SharedMemoryCreateOptions options;
+  options.size = kTestSize;
+  std::string shared_mem_name = "shared_perm_test-" + IntToString(getpid()) +
+      "-" + Uint64ToString(RandUint64());
+  options.name_deprecated = &shared_mem_name;
+  // Set a file mode creation mask that gives all permissions.
+  ScopedUmaskSetter permissive_mask(S_IWGRP | S_IWOTH);
+
+  EXPECT_TRUE(shared_memory.Create(options));
+  // Clean-up the backing file name immediately, we don't need it.
+  EXPECT_TRUE(shared_memory.Delete(shared_mem_name));
+
+  int shm_fd = shared_memory.handle().fd;
+  struct stat shm_stat;
+  EXPECT_EQ(0, fstat(shm_fd, &shm_stat));
+  // Neither the group, nor others should have been able to open the shared
+  // memory file while its name existed.
+  EXPECT_FALSE(shm_stat.st_mode & S_IRWXO);
+  EXPECT_FALSE(shm_stat.st_mode & S_IRWXG);
+}
+#endif  // !defined(OS_ANDROID)
+
+#endif  // defined(OS_POSIX)
+
+// Map() will return addresses which are aligned to the platform page size, this
+// varies from platform to platform though.  Since we'd like to advertise a
+// minimum alignment that callers can count on, test for it here.
+TEST(SharedMemoryTest, MapMinimumAlignment) {
+  static const int kDataSize = 8192;
+
+  SharedMemory shared_memory;
+  ASSERT_TRUE(shared_memory.CreateAndMapAnonymous(kDataSize));
+  EXPECT_EQ(0U, reinterpret_cast<uintptr_t>(
+      shared_memory.memory()) & (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1));
+  shared_memory.Close();
+}
+
+#if !defined(OS_IOS)  // iOS does not allow multiple processes.
+
+// On POSIX it is especially important we test shmem across processes,
+// not just across threads.  But the test is enabled on all platforms.
+class SharedMemoryProcessTest : public MultiProcessTest {
+ public:
+
+  static void CleanUp() {
+    SharedMemory memory;
+    memory.Delete(s_test_name_);
+  }
+
+  static int TaskTestMain() {
+    int errors = 0;
+#if defined(OS_MACOSX)
+    mac::ScopedNSAutoreleasePool pool;
+#endif
+    const uint32 kDataSize = 1024;
+    SharedMemory memory;
+    bool rv = memory.CreateNamedDeprecated(s_test_name_, true, kDataSize);
+    EXPECT_TRUE(rv);
+    if (rv != true)
+      errors++;
+    rv = memory.Map(kDataSize);
+    EXPECT_TRUE(rv);
+    if (rv != true)
+      errors++;
+    int *ptr = static_cast<int*>(memory.memory());
+
+    for (int idx = 0; idx < 20; idx++) {
+      memory.LockDeprecated();
+      int i = (1 << 16) + idx;
+      *ptr = i;
+      PlatformThread::Sleep(TimeDelta::FromMilliseconds(10));
+      if (*ptr != i)
+        errors++;
+      memory.UnlockDeprecated();
+    }
+
+    memory.Close();
+    return errors;
+  }
+
+ private:
+  static const char* const s_test_name_;
+};
+
+const char* const SharedMemoryProcessTest::s_test_name_ = "MPMem";
+
+TEST_F(SharedMemoryProcessTest, Tasks) {
+  SharedMemoryProcessTest::CleanUp();
+
+  Process processes[kNumTasks];
+  for (int index = 0; index < kNumTasks; ++index) {
+    processes[index] = SpawnChild("SharedMemoryTestMain");
+    ASSERT_TRUE(processes[index].IsValid());
+  }
+
+  int exit_code = 0;
+  for (int index = 0; index < kNumTasks; ++index) {
+    EXPECT_TRUE(processes[index].WaitForExit(&exit_code));
+    EXPECT_EQ(0, exit_code);
+  }
+
+  SharedMemoryProcessTest::CleanUp();
+}
+
+MULTIPROCESS_TEST_MAIN(SharedMemoryTestMain) {
+  return SharedMemoryProcessTest::TaskTestMain();
+}
+
+#endif  // !OS_IOS
+
+}  // namespace base
diff --git a/base/memory/shared_memory_win.cc b/base/memory/shared_memory_win.cc
new file mode 100644
index 0000000..eacf0d6
--- /dev/null
+++ b/base/memory/shared_memory_win.cc
@@ -0,0 +1,297 @@
+// Copyright (c) 2011 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/memory/shared_memory.h"
+
+#include <aclapi.h>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/rand_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+
+namespace {
+
+// Returns the length of the memory section starting at the supplied address.
+size_t GetMemorySectionSize(void* address) {
+  MEMORY_BASIC_INFORMATION memory_info;
+  if (!::VirtualQuery(address, &memory_info, sizeof(memory_info)))
+    return 0;
+  return memory_info.RegionSize - (static_cast<char*>(address) -
+         static_cast<char*>(memory_info.AllocationBase));
+}
+
+}  // namespace.
+
+namespace base {
+
+SharedMemory::SharedMemory()
+    : mapped_file_(NULL),
+      memory_(NULL),
+      read_only_(false),
+      mapped_size_(0),
+      requested_size_(0),
+      lock_(NULL) {
+}
+
+SharedMemory::SharedMemory(const std::wstring& name)
+    : mapped_file_(NULL),
+      memory_(NULL),
+      read_only_(false),
+      requested_size_(0),
+      mapped_size_(0),
+      lock_(NULL),
+      name_(name) {
+}
+
+SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only)
+    : mapped_file_(handle),
+      memory_(NULL),
+      read_only_(read_only),
+      requested_size_(0),
+      mapped_size_(0),
+      lock_(NULL) {
+}
+
+SharedMemory::SharedMemory(SharedMemoryHandle handle, bool read_only,
+                           ProcessHandle process)
+    : mapped_file_(NULL),
+      memory_(NULL),
+      read_only_(read_only),
+      requested_size_(0),
+      mapped_size_(0),
+      lock_(NULL) {
+  ::DuplicateHandle(process, handle,
+                    GetCurrentProcess(), &mapped_file_,
+                    read_only_ ? FILE_MAP_READ : FILE_MAP_READ |
+                        FILE_MAP_WRITE,
+                    FALSE, 0);
+}
+
+SharedMemory::~SharedMemory() {
+  Unmap();
+  Close();
+  if (lock_ != NULL)
+    CloseHandle(lock_);
+}
+
+// static
+bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) {
+  return handle != NULL;
+}
+
+// static
+SharedMemoryHandle SharedMemory::NULLHandle() {
+  return NULL;
+}
+
+// static
+void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) {
+  DCHECK(handle != NULL);
+  ::CloseHandle(handle);
+}
+
+// static
+size_t SharedMemory::GetHandleLimit() {
+  // Rounded down from value reported here:
+  // http://blogs.technet.com/b/markrussinovich/archive/2009/09/29/3283844.aspx
+  return static_cast<size_t>(1 << 23);
+}
+
+// static
+SharedMemoryHandle SharedMemory::DuplicateHandle(
+    const SharedMemoryHandle& handle) {
+  ProcessHandle process = GetCurrentProcess();
+  SharedMemoryHandle duped_handle;
+  BOOL success = ::DuplicateHandle(process, handle, process, &duped_handle, 0,
+                                   FALSE, DUPLICATE_SAME_ACCESS);
+  if (success)
+    return duped_handle;
+  return NULLHandle();
+}
+
+bool SharedMemory::CreateAndMapAnonymous(size_t size) {
+  return CreateAnonymous(size) && Map(size);
+}
+
+bool SharedMemory::Create(const SharedMemoryCreateOptions& options) {
+  // TODO(bsy,sehr): crbug.com/210609 NaCl forces us to round up 64k here,
+  // wasting 32k per mapping on average.
+  static const size_t kSectionMask = 65536 - 1;
+  DCHECK(!options.executable);
+  DCHECK(!mapped_file_);
+  if (options.size == 0)
+    return false;
+
+  // Check maximum accounting for overflow.
+  if (options.size >
+      static_cast<size_t>(std::numeric_limits<int>::max()) - kSectionMask)
+    return false;
+
+  size_t rounded_size = (options.size + kSectionMask) & ~kSectionMask;
+  name_ = options.name_deprecated ?
+      ASCIIToUTF16(*options.name_deprecated) : L"";
+  SECURITY_ATTRIBUTES sa = { sizeof(sa), NULL, FALSE };
+  SECURITY_DESCRIPTOR sd;
+  ACL dacl;
+
+  if (options.share_read_only && name_.empty()) {
+    // Add an empty DACL to enforce anonymous read-only sections.
+    sa.lpSecurityDescriptor = &sd;
+    if (!InitializeAcl(&dacl, sizeof(dacl), ACL_REVISION))
+      return false;
+    if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION))
+      return false;
+    if (!SetSecurityDescriptorDacl(&sd, TRUE, &dacl, FALSE))
+      return false;
+
+    // Windows ignores DACLs on certain unnamed objects (like shared sections).
+    // So, we generate a random name when we need to enforce read-only.
+    uint64_t rand_values[4];
+    RandBytes(&rand_values, sizeof(rand_values));
+    name_ = StringPrintf(L"CrSharedMem_%016x%016x%016x%016x",
+                         rand_values[0], rand_values[1],
+                         rand_values[2], rand_values[3]);
+  }
+  mapped_file_ = CreateFileMapping(INVALID_HANDLE_VALUE, &sa,
+      PAGE_READWRITE, 0, static_cast<DWORD>(rounded_size),
+      name_.empty() ? nullptr : name_.c_str());
+  if (!mapped_file_)
+    return false;
+
+  requested_size_ = options.size;
+
+  // Check if the shared memory pre-exists.
+  if (GetLastError() == ERROR_ALREADY_EXISTS) {
+    // If the file already existed, set requested_size_ to 0 to show that
+    // we don't know the size.
+    requested_size_ = 0;
+    if (!options.open_existing_deprecated) {
+      Close();
+      return false;
+    }
+  }
+
+  return true;
+}
+
+bool SharedMemory::Delete(const std::string& name) {
+  // intentionally empty -- there is nothing for us to do on Windows.
+  return true;
+}
+
+bool SharedMemory::Open(const std::string& name, bool read_only) {
+  DCHECK(!mapped_file_);
+
+  name_ = ASCIIToUTF16(name);
+  read_only_ = read_only;
+  mapped_file_ = OpenFileMapping(
+      read_only_ ? FILE_MAP_READ : FILE_MAP_READ | FILE_MAP_WRITE,
+      false, name_.empty() ? NULL : name_.c_str());
+  if (mapped_file_ != NULL) {
+    // Note: size_ is not set in this case.
+    return true;
+  }
+  return false;
+}
+
+bool SharedMemory::MapAt(off_t offset, size_t bytes) {
+  if (mapped_file_ == NULL)
+    return false;
+
+  if (bytes > static_cast<size_t>(std::numeric_limits<int>::max()))
+    return false;
+
+  if (memory_)
+    return false;
+
+  memory_ = MapViewOfFile(mapped_file_,
+                          read_only_ ? FILE_MAP_READ : FILE_MAP_READ |
+                              FILE_MAP_WRITE,
+                          static_cast<uint64>(offset) >> 32,
+                          static_cast<DWORD>(offset),
+                          bytes);
+  if (memory_ != NULL) {
+    DCHECK_EQ(0U, reinterpret_cast<uintptr_t>(memory_) &
+        (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1));
+    mapped_size_ = GetMemorySectionSize(memory_);
+    return true;
+  }
+  return false;
+}
+
+bool SharedMemory::Unmap() {
+  if (memory_ == NULL)
+    return false;
+
+  UnmapViewOfFile(memory_);
+  memory_ = NULL;
+  return true;
+}
+
+bool SharedMemory::ShareToProcessCommon(ProcessHandle process,
+                                        SharedMemoryHandle* new_handle,
+                                        bool close_self,
+                                        ShareMode share_mode) {
+  *new_handle = 0;
+  DWORD access = FILE_MAP_READ;
+  DWORD options = 0;
+  HANDLE mapped_file = mapped_file_;
+  HANDLE result;
+  if (share_mode == SHARE_CURRENT_MODE && !read_only_)
+    access |= FILE_MAP_WRITE;
+  if (close_self) {
+    // DUPLICATE_CLOSE_SOURCE causes DuplicateHandle to close mapped_file.
+    options = DUPLICATE_CLOSE_SOURCE;
+    mapped_file_ = NULL;
+    Unmap();
+  }
+
+  if (process == GetCurrentProcess() && close_self) {
+    *new_handle = mapped_file;
+    return true;
+  }
+
+  if (!::DuplicateHandle(GetCurrentProcess(), mapped_file, process, &result,
+                         access, FALSE, options)) {
+    return false;
+  }
+  *new_handle = result;
+  return true;
+}
+
+
+void SharedMemory::Close() {
+  if (mapped_file_ != NULL) {
+    CloseHandle(mapped_file_);
+    mapped_file_ = NULL;
+  }
+}
+
+void SharedMemory::LockDeprecated() {
+  if (lock_ == NULL) {
+    std::wstring name = name_;
+    name.append(L"lock");
+    lock_ = CreateMutex(NULL, FALSE, name.c_str());
+    if (lock_ == NULL) {
+      DPLOG(ERROR) << "Could not create mutex.";
+      NOTREACHED();
+      return;  // There is nothing good we can do here.
+    }
+  }
+  DWORD result = WaitForSingleObject(lock_, INFINITE);
+  DCHECK_EQ(result, WAIT_OBJECT_0);
+}
+
+void SharedMemory::UnlockDeprecated() {
+  DCHECK(lock_ != NULL);
+  ReleaseMutex(lock_);
+}
+
+SharedMemoryHandle SharedMemory::handle() const {
+  return mapped_file_;
+}
+
+}  // namespace base
diff --git a/base/memory/singleton.cc b/base/memory/singleton.cc
new file mode 100644
index 0000000..f68ecaa
--- /dev/null
+++ b/base/memory/singleton.cc
@@ -0,0 +1,34 @@
+// Copyright (c) 2011 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/memory/singleton.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+namespace internal {
+
+subtle::AtomicWord WaitForInstance(subtle::AtomicWord* instance) {
+  // Handle the race. Another thread beat us and either:
+  // - Has the object in BeingCreated state
+  // - Already has the object created...
+  // We know value != NULL.  It could be kBeingCreatedMarker, or a valid ptr.
+  // Unless your constructor can be very time consuming, it is very unlikely
+  // to hit this race.  When it does, we just spin and yield the thread until
+  // the object has been created.
+  subtle::AtomicWord value;
+  while (true) {
+    // The load has acquire memory ordering as the thread which reads the
+    // instance pointer must acquire visibility over the associated data.
+    // The pairing Release_Store operation is in Singleton::get().
+    value = subtle::Acquire_Load(instance);
+    if (value != kBeingCreatedMarker)
+      break;
+    PlatformThread::YieldCurrentThread();
+  }
+  return value;
+}
+
+}  // namespace internal
+}  // namespace base
+
diff --git a/base/memory/singleton.h b/base/memory/singleton.h
new file mode 100644
index 0000000..e50bdc0
--- /dev/null
+++ b/base/memory/singleton.h
@@ -0,0 +1,283 @@
+// Copyright (c) 2011 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.
+
+// PLEASE READ: Do you really need a singleton?
+//
+// Singletons make it hard to determine the lifetime of an object, which can
+// lead to buggy code and spurious crashes.
+//
+// Instead of adding another singleton into the mix, try to identify either:
+//   a) An existing singleton that can manage your object's lifetime
+//   b) Locations where you can deterministically create the object and pass
+//      into other objects
+//
+// If you absolutely need a singleton, please keep them as trivial as possible
+// and ideally a leaf dependency. Singletons get problematic when they attempt
+// to do too much in their destructor or have circular dependencies.
+
+#ifndef BASE_MEMORY_SINGLETON_H_
+#define BASE_MEMORY_SINGLETON_H_
+
+#include "base/at_exit.h"
+#include "base/atomicops.h"
+#include "base/base_export.h"
+#include "base/memory/aligned_memory.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace base {
+namespace internal {
+
+// Our AtomicWord doubles as a spinlock, where a value of
+// kBeingCreatedMarker means the spinlock is being held for creation.
+static const subtle::AtomicWord kBeingCreatedMarker = 1;
+
+// We pull out some of the functionality into a non-templated function, so that
+// we can implement the more complicated pieces out of line in the .cc file.
+BASE_EXPORT subtle::AtomicWord WaitForInstance(subtle::AtomicWord* instance);
+
+}  // namespace internal
+}  // namespace base
+
+// TODO(joth): Move more of this file into namespace base
+
+// Default traits for Singleton<Type>. Calls operator new and operator delete on
+// the object. Registers automatic deletion at process exit.
+// Overload if you need arguments or another memory allocation function.
+template<typename Type>
+struct DefaultSingletonTraits {
+  // Allocates the object.
+  static Type* New() {
+    // The parenthesis is very important here; it forces POD type
+    // initialization.
+    return new Type();
+  }
+
+  // Destroys the object.
+  static void Delete(Type* x) {
+    delete x;
+  }
+
+  // Set to true to automatically register deletion of the object on process
+  // exit. See below for the required call that makes this happen.
+  static const bool kRegisterAtExit = true;
+
+#ifndef NDEBUG
+  // Set to false to disallow access on a non-joinable thread.  This is
+  // different from kRegisterAtExit because StaticMemorySingletonTraits allows
+  // access on non-joinable threads, and gracefully handles this.
+  static const bool kAllowedToAccessOnNonjoinableThread = false;
+#endif
+};
+
+
+// Alternate traits for use with the Singleton<Type>.  Identical to
+// DefaultSingletonTraits except that the Singleton will not be cleaned up
+// at exit.
+template<typename Type>
+struct LeakySingletonTraits : public DefaultSingletonTraits<Type> {
+  static const bool kRegisterAtExit = false;
+#ifndef NDEBUG
+  static const bool kAllowedToAccessOnNonjoinableThread = true;
+#endif
+};
+
+
+// Alternate traits for use with the Singleton<Type>.  Allocates memory
+// for the singleton instance from a static buffer.  The singleton will
+// be cleaned up at exit, but can't be revived after destruction unless
+// the Resurrect() method is called.
+//
+// This is useful for a certain category of things, notably logging and
+// tracing, where the singleton instance is of a type carefully constructed to
+// be safe to access post-destruction.
+// In logging and tracing you'll typically get stray calls at odd times, like
+// during static destruction, thread teardown and the like, and there's a
+// termination race on the heap-based singleton - e.g. if one thread calls
+// get(), but then another thread initiates AtExit processing, the first thread
+// may call into an object residing in unallocated memory. If the instance is
+// allocated from the data segment, then this is survivable.
+//
+// The destructor is to deallocate system resources, in this case to unregister
+// a callback the system will invoke when logging levels change. Note that
+// this is also used in e.g. Chrome Frame, where you have to allow for the
+// possibility of loading briefly into someone else's process space, and
+// so leaking is not an option, as that would sabotage the state of your host
+// process once you've unloaded.
+template <typename Type>
+struct StaticMemorySingletonTraits {
+  // WARNING: User has to deal with get() in the singleton class
+  // this is traits for returning NULL.
+  static Type* New() {
+    // Only constructs once and returns pointer; otherwise returns NULL.
+    if (base::subtle::NoBarrier_AtomicExchange(&dead_, 1))
+      return NULL;
+
+    return new(buffer_.void_data()) Type();
+  }
+
+  static void Delete(Type* p) {
+    if (p != NULL)
+      p->Type::~Type();
+  }
+
+  static const bool kRegisterAtExit = true;
+  static const bool kAllowedToAccessOnNonjoinableThread = true;
+
+  // Exposed for unittesting.
+  static void Resurrect() {
+    base::subtle::NoBarrier_Store(&dead_, 0);
+  }
+
+ private:
+  static base::AlignedMemory<sizeof(Type), ALIGNOF(Type)> buffer_;
+  // Signal the object was already deleted, so it is not revived.
+  static base::subtle::Atomic32 dead_;
+};
+
+template <typename Type> base::AlignedMemory<sizeof(Type), ALIGNOF(Type)>
+    StaticMemorySingletonTraits<Type>::buffer_;
+template <typename Type> base::subtle::Atomic32
+    StaticMemorySingletonTraits<Type>::dead_ = 0;
+
+// The Singleton<Type, Traits, DifferentiatingType> class manages a single
+// instance of Type which will be created on first use and will be destroyed at
+// normal process exit). The Trait::Delete function will not be called on
+// abnormal process exit.
+//
+// DifferentiatingType is used as a key to differentiate two different
+// singletons having the same memory allocation functions but serving a
+// different purpose. This is mainly used for Locks serving different purposes.
+//
+// Example usage:
+//
+// In your header:
+//   template <typename T> struct DefaultSingletonTraits;
+//   class FooClass {
+//    public:
+//     static FooClass* GetInstance();  <-- See comment below on this.
+//     void Bar() { ... }
+//    private:
+//     FooClass() { ... }
+//     friend struct DefaultSingletonTraits<FooClass>;
+//
+//     DISALLOW_COPY_AND_ASSIGN(FooClass);
+//   };
+//
+// In your source file:
+//  #include "base/memory/singleton.h"
+//  FooClass* FooClass::GetInstance() {
+//    return Singleton<FooClass>::get();
+//  }
+//
+// And to call methods on FooClass:
+//   FooClass::GetInstance()->Bar();
+//
+// NOTE: The method accessing Singleton<T>::get() has to be named as GetInstance
+// and it is important that FooClass::GetInstance() is not inlined in the
+// header. This makes sure that when source files from multiple targets include
+// this header they don't end up with different copies of the inlined code
+// creating multiple copies of the singleton.
+//
+// Singleton<> has no non-static members and doesn't need to actually be
+// instantiated.
+//
+// This class is itself thread-safe. The underlying Type must of course be
+// thread-safe if you want to use it concurrently. Two parameters may be tuned
+// depending on the user's requirements.
+//
+// Glossary:
+//   RAE = kRegisterAtExit
+//
+// On every platform, if Traits::RAE is true, the singleton will be destroyed at
+// process exit. More precisely it uses base::AtExitManager which requires an
+// object of this type to be instantiated. AtExitManager mimics the semantics
+// of atexit() such as LIFO order but under Windows is safer to call. For more
+// information see at_exit.h.
+//
+// If Traits::RAE is false, the singleton will not be freed at process exit,
+// thus the singleton will be leaked if it is ever accessed. Traits::RAE
+// shouldn't be false unless absolutely necessary. Remember that the heap where
+// the object is allocated may be destroyed by the CRT anyway.
+//
+// Caveats:
+// (a) Every call to get(), operator->() and operator*() incurs some overhead
+//     (16ns on my P4/2.8GHz) to check whether the object has already been
+//     initialized.  You may wish to cache the result of get(); it will not
+//     change.
+//
+// (b) Your factory function must never throw an exception. This class is not
+//     exception-safe.
+//
+template <typename Type,
+          typename Traits = DefaultSingletonTraits<Type>,
+          typename DifferentiatingType = Type>
+class Singleton {
+ private:
+  // Classes using the Singleton<T> pattern should declare a GetInstance()
+  // method and call Singleton::get() from within that.
+  friend Type* Type::GetInstance();
+
+  // Allow TraceLog tests to test tracing after OnExit.
+  friend class DeleteTraceLogForTesting;
+
+  // This class is safe to be constructed and copy-constructed since it has no
+  // member.
+
+  // Return a pointer to the one true instance of the class.
+  static Type* get() {
+#ifndef NDEBUG
+    // Avoid making TLS lookup on release builds.
+    if (!Traits::kAllowedToAccessOnNonjoinableThread)
+      base::ThreadRestrictions::AssertSingletonAllowed();
+#endif
+
+    // The load has acquire memory ordering as the thread which reads the
+    // 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) {
+      return reinterpret_cast<Type*>(value);
+    }
+
+    // Object isn't created yet, maybe we will get to create it, let's try...
+    if (base::subtle::Acquire_CompareAndSwap(
+          &instance_, 0, base::internal::kBeingCreatedMarker) == 0) {
+      // instance_ was NULL and is now kBeingCreatedMarker.  Only one thread
+      // will ever get here.  Threads might be spinning on us, and they will
+      // stop right after we do this store.
+      Type* newval = Traits::New();
+
+      // Releases the visibility over instance_ to the readers.
+      base::subtle::Release_Store(
+          &instance_, reinterpret_cast<base::subtle::AtomicWord>(newval));
+
+      if (newval != NULL && Traits::kRegisterAtExit)
+        base::AtExitManager::RegisterCallback(OnExit, NULL);
+
+      return newval;
+    }
+
+    // We hit a race. Wait for the other thread to complete it.
+    value = base::internal::WaitForInstance(&instance_);
+
+    return reinterpret_cast<Type*>(value);
+  }
+
+  // Adapter function for use with AtExit().  This should be called single
+  // threaded, so don't use atomic operations.
+  // Calling OnExit while singleton is in use by other threads is a mistake.
+  static void OnExit(void* /*unused*/) {
+    // AtExit should only ever be register after the singleton instance was
+    // created.  We should only ever get here with a valid instance_ pointer.
+    Traits::Delete(
+        reinterpret_cast<Type*>(base::subtle::NoBarrier_Load(&instance_)));
+    instance_ = 0;
+  }
+  static base::subtle::AtomicWord instance_;
+};
+
+template <typename Type, typename Traits, typename DifferentiatingType>
+base::subtle::AtomicWord Singleton<Type, Traits, DifferentiatingType>::
+    instance_ = 0;
+
+#endif  // BASE_MEMORY_SINGLETON_H_
diff --git a/base/memory/singleton_objc.h b/base/memory/singleton_objc.h
new file mode 100644
index 0000000..6df3f77
--- /dev/null
+++ b/base/memory/singleton_objc.h
@@ -0,0 +1,60 @@
+// Copyright (c) 2011 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.
+
+// Support for using the Singleton<T> pattern with Objective-C objects.  A
+// SingletonObjC is the same as a Singleton, except the default traits are
+// appropriate for Objective-C objects.  A typical Objective-C object of type
+// NSExampleType can be maintained as a singleton and accessed with:
+//
+//   NSExampleType* exampleSingleton = SingletonObjC<NSExampleType>::get();
+//
+// The first time this is used, it will create exampleSingleton as the result
+// of [[NSExampleType alloc] init].  Subsequent calls will return the same
+// NSExampleType* object.  The object will be released by calling
+// -[NSExampleType release] when Singleton's atexit routines run
+// (see singleton.h).
+//
+// For Objective-C objects initialized through means other than the
+// no-parameter -init selector, DefaultSingletonObjCTraits may be extended
+// as needed:
+//
+//   struct FooSingletonTraits : public DefaultSingletonObjCTraits<Foo> {
+//     static Foo* New() {
+//       return [[Foo alloc] initWithName:@"selecty"];
+//     }
+//   };
+//   ...
+//   Foo* widgetSingleton = SingletonObjC<Foo, FooSingletonTraits>::get();
+
+#ifndef BASE_MEMORY_SINGLETON_OBJC_H_
+#define BASE_MEMORY_SINGLETON_OBJC_H_
+
+#import <Foundation/Foundation.h>
+#include "base/memory/singleton.h"
+
+// Singleton traits usable to manage traditional Objective-C objects, which
+// are instantiated by sending |alloc| and |init| messages, and are deallocated
+// in a memory-managed environment when their retain counts drop to 0 by
+// sending |release| messages.
+template<typename Type>
+struct DefaultSingletonObjCTraits : public DefaultSingletonTraits<Type> {
+  static Type* New() {
+    return [[Type alloc] init];
+  }
+
+  static void Delete(Type* object) {
+    [object release];
+  }
+};
+
+// Exactly like Singleton, but without the DefaultSingletonObjCTraits as the
+// default trait class.  This makes it straightforward for Objective-C++ code
+// to hold Objective-C objects as singletons.
+template<typename Type,
+         typename Traits = DefaultSingletonObjCTraits<Type>,
+         typename DifferentiatingType = Type>
+class SingletonObjC : public Singleton<Type, Traits, DifferentiatingType> {
+};
+
+#endif  // BASE_MEMORY_SINGLETON_OBJC_H_
diff --git a/base/memory/singleton_unittest.cc b/base/memory/singleton_unittest.cc
new file mode 100644
index 0000000..dbff007
--- /dev/null
+++ b/base/memory/singleton_unittest.cc
@@ -0,0 +1,287 @@
+// Copyright (c) 2012 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/at_exit.h"
+#include "base/memory/singleton.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+COMPILE_ASSERT(DefaultSingletonTraits<int>::kRegisterAtExit == true, a);
+
+typedef void (*CallbackFunc)();
+
+class IntSingleton {
+ public:
+  static IntSingleton* GetInstance() {
+    return Singleton<IntSingleton>::get();
+  }
+
+  int value_;
+};
+
+class Init5Singleton {
+ public:
+  struct Trait;
+
+  static Init5Singleton* GetInstance() {
+    return Singleton<Init5Singleton, Trait>::get();
+  }
+
+  int value_;
+};
+
+struct Init5Singleton::Trait : public DefaultSingletonTraits<Init5Singleton> {
+  static Init5Singleton* New() {
+    Init5Singleton* instance = new Init5Singleton();
+    instance->value_ = 5;
+    return instance;
+  }
+};
+
+int* SingletonInt() {
+  return &IntSingleton::GetInstance()->value_;
+}
+
+int* SingletonInt5() {
+  return &Init5Singleton::GetInstance()->value_;
+}
+
+template <typename Type>
+struct CallbackTrait : public DefaultSingletonTraits<Type> {
+  static void Delete(Type* instance) {
+    if (instance->callback_)
+      (instance->callback_)();
+    DefaultSingletonTraits<Type>::Delete(instance);
+  }
+};
+
+class CallbackSingleton {
+ public:
+  CallbackSingleton() : callback_(NULL) { }
+  CallbackFunc callback_;
+};
+
+class CallbackSingletonWithNoLeakTrait : public CallbackSingleton {
+ public:
+  struct Trait : public CallbackTrait<CallbackSingletonWithNoLeakTrait> { };
+
+  CallbackSingletonWithNoLeakTrait() : CallbackSingleton() { }
+
+  static CallbackSingletonWithNoLeakTrait* GetInstance() {
+    return Singleton<CallbackSingletonWithNoLeakTrait, Trait>::get();
+  }
+};
+
+class CallbackSingletonWithLeakTrait : public CallbackSingleton {
+ public:
+  struct Trait : public CallbackTrait<CallbackSingletonWithLeakTrait> {
+    static const bool kRegisterAtExit = false;
+  };
+
+  CallbackSingletonWithLeakTrait() : CallbackSingleton() { }
+
+  static CallbackSingletonWithLeakTrait* GetInstance() {
+    return Singleton<CallbackSingletonWithLeakTrait, Trait>::get();
+  }
+};
+
+class CallbackSingletonWithStaticTrait : public CallbackSingleton {
+ public:
+  struct Trait;
+
+  CallbackSingletonWithStaticTrait() : CallbackSingleton() { }
+
+  static CallbackSingletonWithStaticTrait* GetInstance() {
+    return Singleton<CallbackSingletonWithStaticTrait, Trait>::get();
+  }
+};
+
+struct CallbackSingletonWithStaticTrait::Trait
+    : public StaticMemorySingletonTraits<CallbackSingletonWithStaticTrait> {
+  static void Delete(CallbackSingletonWithStaticTrait* instance) {
+    if (instance->callback_)
+      (instance->callback_)();
+    StaticMemorySingletonTraits<CallbackSingletonWithStaticTrait>::Delete(
+        instance);
+  }
+};
+
+template <class Type>
+class AlignedTestSingleton {
+ public:
+  AlignedTestSingleton() {}
+  ~AlignedTestSingleton() {}
+  static AlignedTestSingleton* GetInstance() {
+    return Singleton<AlignedTestSingleton,
+        StaticMemorySingletonTraits<AlignedTestSingleton> >::get();
+  }
+
+  Type type_;
+};
+
+
+void SingletonNoLeak(CallbackFunc CallOnQuit) {
+  CallbackSingletonWithNoLeakTrait::GetInstance()->callback_ = CallOnQuit;
+}
+
+void SingletonLeak(CallbackFunc CallOnQuit) {
+  CallbackSingletonWithLeakTrait::GetInstance()->callback_ = CallOnQuit;
+}
+
+CallbackFunc* GetLeakySingleton() {
+  return &CallbackSingletonWithLeakTrait::GetInstance()->callback_;
+}
+
+void DeleteLeakySingleton() {
+  DefaultSingletonTraits<CallbackSingletonWithLeakTrait>::Delete(
+      CallbackSingletonWithLeakTrait::GetInstance());
+}
+
+void SingletonStatic(CallbackFunc CallOnQuit) {
+  CallbackSingletonWithStaticTrait::GetInstance()->callback_ = CallOnQuit;
+}
+
+CallbackFunc* GetStaticSingleton() {
+  return &CallbackSingletonWithStaticTrait::GetInstance()->callback_;
+}
+
+}  // namespace
+
+class SingletonTest : public testing::Test {
+ public:
+  SingletonTest() {}
+
+  void SetUp() override {
+    non_leak_called_ = false;
+    leaky_called_ = false;
+    static_called_ = false;
+  }
+
+ protected:
+  void VerifiesCallbacks() {
+    EXPECT_TRUE(non_leak_called_);
+    EXPECT_FALSE(leaky_called_);
+    EXPECT_TRUE(static_called_);
+    non_leak_called_ = false;
+    leaky_called_ = false;
+    static_called_ = false;
+  }
+
+  void VerifiesCallbacksNotCalled() {
+    EXPECT_FALSE(non_leak_called_);
+    EXPECT_FALSE(leaky_called_);
+    EXPECT_FALSE(static_called_);
+    non_leak_called_ = false;
+    leaky_called_ = false;
+    static_called_ = false;
+  }
+
+  static void CallbackNoLeak() {
+    non_leak_called_ = true;
+  }
+
+  static void CallbackLeak() {
+    leaky_called_ = true;
+  }
+
+  static void CallbackStatic() {
+    static_called_ = true;
+  }
+
+ private:
+  static bool non_leak_called_;
+  static bool leaky_called_;
+  static bool static_called_;
+};
+
+bool SingletonTest::non_leak_called_ = false;
+bool SingletonTest::leaky_called_ = false;
+bool SingletonTest::static_called_ = false;
+
+TEST_F(SingletonTest, Basic) {
+  int* singleton_int;
+  int* singleton_int_5;
+  CallbackFunc* leaky_singleton;
+  CallbackFunc* static_singleton;
+
+  {
+    base::ShadowingAtExitManager sem;
+    {
+      singleton_int = SingletonInt();
+    }
+    // Ensure POD type initialization.
+    EXPECT_EQ(*singleton_int, 0);
+    *singleton_int = 1;
+
+    EXPECT_EQ(singleton_int, SingletonInt());
+    EXPECT_EQ(*singleton_int, 1);
+
+    {
+      singleton_int_5 = SingletonInt5();
+    }
+    // Is default initialized to 5.
+    EXPECT_EQ(*singleton_int_5, 5);
+
+    SingletonNoLeak(&CallbackNoLeak);
+    SingletonLeak(&CallbackLeak);
+    SingletonStatic(&CallbackStatic);
+    static_singleton = GetStaticSingleton();
+    leaky_singleton = GetLeakySingleton();
+    EXPECT_TRUE(leaky_singleton);
+  }
+
+  // Verify that only the expected callback has been called.
+  VerifiesCallbacks();
+  // Delete the leaky singleton.
+  DeleteLeakySingleton();
+
+  // The static singleton can't be acquired post-atexit.
+  EXPECT_EQ(NULL, GetStaticSingleton());
+
+  {
+    base::ShadowingAtExitManager sem;
+    // Verifiy that the variables were reset.
+    {
+      singleton_int = SingletonInt();
+      EXPECT_EQ(*singleton_int, 0);
+    }
+    {
+      singleton_int_5 = SingletonInt5();
+      EXPECT_EQ(*singleton_int_5, 5);
+    }
+    {
+      // Resurrect the static singleton, and assert that it
+      // still points to the same (static) memory.
+      CallbackSingletonWithStaticTrait::Trait::Resurrect();
+      EXPECT_EQ(GetStaticSingleton(), static_singleton);
+    }
+  }
+  // The leaky singleton shouldn't leak since SingletonLeak has not been called.
+  VerifiesCallbacksNotCalled();
+}
+
+#define EXPECT_ALIGNED(ptr, align) \
+    EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(ptr) & (align - 1))
+
+TEST_F(SingletonTest, Alignment) {
+  using base::AlignedMemory;
+
+  // Create some static singletons with increasing sizes and alignment
+  // requirements. By ordering this way, the linker will need to do some work to
+  // ensure proper alignment of the static data.
+  AlignedTestSingleton<int32>* align4 =
+      AlignedTestSingleton<int32>::GetInstance();
+  AlignedTestSingleton<AlignedMemory<32, 32> >* align32 =
+      AlignedTestSingleton<AlignedMemory<32, 32> >::GetInstance();
+  AlignedTestSingleton<AlignedMemory<128, 128> >* align128 =
+      AlignedTestSingleton<AlignedMemory<128, 128> >::GetInstance();
+  AlignedTestSingleton<AlignedMemory<4096, 4096> >* align4096 =
+      AlignedTestSingleton<AlignedMemory<4096, 4096> >::GetInstance();
+
+  EXPECT_ALIGNED(align4, 4);
+  EXPECT_ALIGNED(align32, 32);
+  EXPECT_ALIGNED(align128, 128);
+  EXPECT_ALIGNED(align4096, 4096);
+}
diff --git a/base/memory/weak_ptr.cc b/base/memory/weak_ptr.cc
new file mode 100644
index 0000000..d9ce86a
--- /dev/null
+++ b/base/memory/weak_ptr.cc
@@ -0,0 +1,77 @@
+// Copyright (c) 2011 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/memory/weak_ptr.h"
+
+namespace base {
+namespace internal {
+
+WeakReference::Flag::Flag() : is_valid_(true) {
+  // Flags only become bound when checked for validity, or invalidated,
+  // so that we can check that later validity/invalidation operations on
+  // the same Flag take place on the same sequenced thread.
+  sequence_checker_.DetachFromSequence();
+}
+
+void WeakReference::Flag::Invalidate() {
+  // The flag being invalidated with a single ref implies that there are no
+  // weak pointers in existence. Allow deletion on other thread in this case.
+  DCHECK(sequence_checker_.CalledOnValidSequencedThread() || HasOneRef())
+      << "WeakPtrs must be invalidated on the same sequenced thread.";
+  is_valid_ = false;
+}
+
+bool WeakReference::Flag::IsValid() const {
+  DCHECK(sequence_checker_.CalledOnValidSequencedThread())
+      << "WeakPtrs must be checked on the same sequenced thread.";
+  return is_valid_;
+}
+
+WeakReference::Flag::~Flag() {
+}
+
+WeakReference::WeakReference() {
+}
+
+WeakReference::WeakReference(const Flag* flag) : flag_(flag) {
+}
+
+WeakReference::~WeakReference() {
+}
+
+bool WeakReference::is_valid() const { return flag_.get() && flag_->IsValid(); }
+
+WeakReferenceOwner::WeakReferenceOwner() {
+}
+
+WeakReferenceOwner::~WeakReferenceOwner() {
+  Invalidate();
+}
+
+WeakReference WeakReferenceOwner::GetRef() const {
+  // If we hold the last reference to the Flag then create a new one.
+  if (!HasRefs())
+    flag_ = new WeakReference::Flag();
+
+  return WeakReference(flag_.get());
+}
+
+void WeakReferenceOwner::Invalidate() {
+  if (flag_.get()) {
+    flag_->Invalidate();
+    flag_ = NULL;
+  }
+}
+
+WeakPtrBase::WeakPtrBase() {
+}
+
+WeakPtrBase::~WeakPtrBase() {
+}
+
+WeakPtrBase::WeakPtrBase(const WeakReference& ref) : ref_(ref) {
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/memory/weak_ptr.h b/base/memory/weak_ptr.h
new file mode 100644
index 0000000..8a43392
--- /dev/null
+++ b/base/memory/weak_ptr.h
@@ -0,0 +1,339 @@
+// Copyright (c) 2012 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.
+
+// Weak pointers are pointers to an object that do not affect its lifetime,
+// and which may be invalidated (i.e. reset to NULL) by the object, or its
+// owner, at any time, most commonly when the object is about to be deleted.
+
+// Weak pointers are useful when an object needs to be accessed safely by one
+// or more objects other than its owner, and those callers can cope with the
+// object vanishing and e.g. tasks posted to it being silently dropped.
+// Reference-counting such an object would complicate the ownership graph and
+// make it harder to reason about the object's lifetime.
+
+// EXAMPLE:
+//
+//  class Controller {
+//   public:
+//    void SpawnWorker() { Worker::StartNew(weak_factory_.GetWeakPtr()); }
+//    void WorkComplete(const Result& result) { ... }
+//   private:
+//    // Member variables should appear before the WeakPtrFactory, to ensure
+//    // that any WeakPtrs to Controller are invalidated before its members
+//    // variable's destructors are executed, rendering them invalid.
+//    WeakPtrFactory<Controller> weak_factory_;
+//  };
+//
+//  class Worker {
+//   public:
+//    static void StartNew(const WeakPtr<Controller>& controller) {
+//      Worker* worker = new Worker(controller);
+//      // Kick off asynchronous processing...
+//    }
+//   private:
+//    Worker(const WeakPtr<Controller>& controller)
+//        : controller_(controller) {}
+//    void DidCompleteAsynchronousProcessing(const Result& result) {
+//      if (controller_)
+//        controller_->WorkComplete(result);
+//    }
+//    WeakPtr<Controller> controller_;
+//  };
+//
+// With this implementation a caller may use SpawnWorker() to dispatch multiple
+// Workers and subsequently delete the Controller, without waiting for all
+// Workers to have completed.
+
+// ------------------------- IMPORTANT: Thread-safety -------------------------
+
+// Weak pointers may be passed safely between threads, but must always be
+// dereferenced and invalidated on the same SequencedTaskRunner otherwise
+// checking the pointer would be racey.
+//
+// To ensure correct use, the first time a WeakPtr issued by a WeakPtrFactory
+// is dereferenced, the factory and its WeakPtrs become bound to the calling
+// thread or current SequencedWorkerPool token, and cannot be dereferenced or
+// invalidated on any other task runner. Bound WeakPtrs can still be handed
+// off to other task runners, e.g. to use to post tasks back to object on the
+// bound sequence.
+//
+// Invalidating the factory's WeakPtrs un-binds it from the sequence, allowing
+// it to be passed for a different sequence to use or delete it.
+
+#ifndef BASE_MEMORY_WEAK_PTR_H_
+#define BASE_MEMORY_WEAK_PTR_H_
+
+#include "base/basictypes.h"
+#include "base/base_export.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/sequence_checker.h"
+#include "base/template_util.h"
+
+namespace base {
+
+template <typename T> class SupportsWeakPtr;
+template <typename T> class WeakPtr;
+
+namespace internal {
+// These classes are part of the WeakPtr implementation.
+// DO NOT USE THESE CLASSES DIRECTLY YOURSELF.
+
+class BASE_EXPORT WeakReference {
+ public:
+  // Although Flag is bound to a specific SequencedTaskRunner, it may be
+  // deleted from another via base::WeakPtr::~WeakPtr().
+  class BASE_EXPORT Flag : public RefCountedThreadSafe<Flag> {
+   public:
+    Flag();
+
+    void Invalidate();
+    bool IsValid() const;
+
+   private:
+    friend class base::RefCountedThreadSafe<Flag>;
+
+    ~Flag();
+
+    SequenceChecker sequence_checker_;
+    bool is_valid_;
+  };
+
+  WeakReference();
+  explicit WeakReference(const Flag* flag);
+  ~WeakReference();
+
+  bool is_valid() const;
+
+ private:
+  scoped_refptr<const Flag> flag_;
+};
+
+class BASE_EXPORT WeakReferenceOwner {
+ public:
+  WeakReferenceOwner();
+  ~WeakReferenceOwner();
+
+  WeakReference GetRef() const;
+
+  bool HasRefs() const {
+    return flag_.get() && !flag_->HasOneRef();
+  }
+
+  void Invalidate();
+
+ private:
+  mutable scoped_refptr<WeakReference::Flag> flag_;
+};
+
+// This class simplifies the implementation of WeakPtr's type conversion
+// constructor by avoiding the need for a public accessor for ref_.  A
+// WeakPtr<T> cannot access the private members of WeakPtr<U>, so this
+// base class gives us a way to access ref_ in a protected fashion.
+class BASE_EXPORT WeakPtrBase {
+ public:
+  WeakPtrBase();
+  ~WeakPtrBase();
+
+ protected:
+  explicit WeakPtrBase(const WeakReference& ref);
+
+  WeakReference ref_;
+};
+
+// This class provides a common implementation of common functions that would
+// otherwise get instantiated separately for each distinct instantiation of
+// SupportsWeakPtr<>.
+class SupportsWeakPtrBase {
+ public:
+  // A safe static downcast of a WeakPtr<Base> to WeakPtr<Derived>. This
+  // conversion will only compile if there is exists a Base which inherits
+  // from SupportsWeakPtr<Base>. See base::AsWeakPtr() below for a helper
+  // function that makes calling this easier.
+  template<typename Derived>
+  static WeakPtr<Derived> StaticAsWeakPtr(Derived* t) {
+    typedef
+        is_convertible<Derived, internal::SupportsWeakPtrBase&> convertible;
+    COMPILE_ASSERT(convertible::value,
+                   AsWeakPtr_argument_inherits_from_SupportsWeakPtr);
+    return AsWeakPtrImpl<Derived>(t, *t);
+  }
+
+ private:
+  // This template function uses type inference to find a Base of Derived
+  // which is an instance of SupportsWeakPtr<Base>. We can then safely
+  // static_cast the Base* to a Derived*.
+  template <typename Derived, typename Base>
+  static WeakPtr<Derived> AsWeakPtrImpl(
+      Derived* t, const SupportsWeakPtr<Base>&) {
+    WeakPtr<Base> ptr = t->Base::AsWeakPtr();
+    return WeakPtr<Derived>(ptr.ref_, static_cast<Derived*>(ptr.ptr_));
+  }
+};
+
+}  // namespace internal
+
+template <typename T> class WeakPtrFactory;
+
+// The WeakPtr class holds a weak reference to |T*|.
+//
+// This class is designed to be used like a normal pointer.  You should always
+// null-test an object of this class before using it or invoking a method that
+// may result in the underlying object being destroyed.
+//
+// EXAMPLE:
+//
+//   class Foo { ... };
+//   WeakPtr<Foo> foo;
+//   if (foo)
+//     foo->method();
+//
+template <typename T>
+class WeakPtr : public internal::WeakPtrBase {
+ public:
+  WeakPtr() : ptr_(NULL) {
+  }
+
+  // Allow conversion from U to T provided U "is a" T. Note that this
+  // is separate from the (implicit) copy constructor.
+  template <typename U>
+  WeakPtr(const WeakPtr<U>& other) : WeakPtrBase(other), ptr_(other.ptr_) {
+  }
+
+  T* get() const { return ref_.is_valid() ? ptr_ : NULL; }
+
+  T& operator*() const {
+    DCHECK(get() != NULL);
+    return *get();
+  }
+  T* operator->() const {
+    DCHECK(get() != NULL);
+    return get();
+  }
+
+  // Allow WeakPtr<element_type> to be used in boolean expressions, but not
+  // implicitly convertible to a real bool (which is dangerous).
+  //
+  // Note that this trick is only safe when the == and != operators
+  // are declared explicitly, as otherwise "weak_ptr1 == weak_ptr2"
+  // will compile but do the wrong thing (i.e., convert to Testable
+  // and then do the comparison).
+ private:
+  typedef T* WeakPtr::*Testable;
+
+ public:
+  operator Testable() const { return get() ? &WeakPtr::ptr_ : NULL; }
+
+  void reset() {
+    ref_ = internal::WeakReference();
+    ptr_ = NULL;
+  }
+
+ private:
+  // Explicitly declare comparison operators as required by the bool
+  // trick, but keep them private.
+  template <class U> bool operator==(WeakPtr<U> const&) const;
+  template <class U> bool operator!=(WeakPtr<U> const&) const;
+
+  friend class internal::SupportsWeakPtrBase;
+  template <typename U> friend class WeakPtr;
+  friend class SupportsWeakPtr<T>;
+  friend class WeakPtrFactory<T>;
+
+  WeakPtr(const internal::WeakReference& ref, T* ptr)
+      : WeakPtrBase(ref),
+        ptr_(ptr) {
+  }
+
+  // This pointer is only valid when ref_.is_valid() is true.  Otherwise, its
+  // value is undefined (as opposed to NULL).
+  T* ptr_;
+};
+
+// A class may be composed of a WeakPtrFactory and thereby
+// control how it exposes weak pointers to itself.  This is helpful if you only
+// need weak pointers within the implementation of a class.  This class is also
+// useful when working with primitive types.  For example, you could have a
+// WeakPtrFactory<bool> that is used to pass around a weak reference to a bool.
+template <class T>
+class WeakPtrFactory {
+ public:
+  explicit WeakPtrFactory(T* ptr) : ptr_(ptr) {
+  }
+
+  ~WeakPtrFactory() {
+    ptr_ = NULL;
+  }
+
+  WeakPtr<T> GetWeakPtr() {
+    DCHECK(ptr_);
+    return WeakPtr<T>(weak_reference_owner_.GetRef(), ptr_);
+  }
+
+  // Call this method to invalidate all existing weak pointers.
+  void InvalidateWeakPtrs() {
+    DCHECK(ptr_);
+    weak_reference_owner_.Invalidate();
+  }
+
+  // Call this method to determine if any weak pointers exist.
+  bool HasWeakPtrs() const {
+    DCHECK(ptr_);
+    return weak_reference_owner_.HasRefs();
+  }
+
+ private:
+  internal::WeakReferenceOwner weak_reference_owner_;
+  T* ptr_;
+  DISALLOW_IMPLICIT_CONSTRUCTORS(WeakPtrFactory);
+};
+
+// A class may extend from SupportsWeakPtr to let others take weak pointers to
+// it. This avoids the class itself implementing boilerplate to dispense weak
+// pointers.  However, since SupportsWeakPtr's destructor won't invalidate
+// weak pointers to the class until after the derived class' members have been
+// destroyed, its use can lead to subtle use-after-destroy issues.
+template <class T>
+class SupportsWeakPtr : public internal::SupportsWeakPtrBase {
+ public:
+  SupportsWeakPtr() {}
+
+  WeakPtr<T> AsWeakPtr() {
+    return WeakPtr<T>(weak_reference_owner_.GetRef(), static_cast<T*>(this));
+  }
+
+ protected:
+  ~SupportsWeakPtr() {}
+
+ private:
+  internal::WeakReferenceOwner weak_reference_owner_;
+  DISALLOW_COPY_AND_ASSIGN(SupportsWeakPtr);
+};
+
+// Helper function that uses type deduction to safely return a WeakPtr<Derived>
+// when Derived doesn't directly extend SupportsWeakPtr<Derived>, instead it
+// extends a Base that extends SupportsWeakPtr<Base>.
+//
+// EXAMPLE:
+//   class Base : public base::SupportsWeakPtr<Producer> {};
+//   class Derived : public Base {};
+//
+//   Derived derived;
+//   base::WeakPtr<Derived> ptr = base::AsWeakPtr(&derived);
+//
+// Note that the following doesn't work (invalid type conversion) since
+// Derived::AsWeakPtr() is WeakPtr<Base> SupportsWeakPtr<Base>::AsWeakPtr(),
+// and there's no way to safely cast WeakPtr<Base> to WeakPtr<Derived> at
+// the caller.
+//
+//   base::WeakPtr<Derived> ptr = derived.AsWeakPtr();  // Fails.
+
+template <typename Derived>
+WeakPtr<Derived> AsWeakPtr(Derived* t) {
+  return internal::SupportsWeakPtrBase::StaticAsWeakPtr<Derived>(t);
+}
+
+}  // namespace base
+
+#endif  // BASE_MEMORY_WEAK_PTR_H_
diff --git a/base/memory/weak_ptr_unittest.cc b/base/memory/weak_ptr_unittest.cc
new file mode 100644
index 0000000..20e5c7b
--- /dev/null
+++ b/base/memory/weak_ptr_unittest.cc
@@ -0,0 +1,611 @@
+// Copyright (c) 2012 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/memory/weak_ptr.h"
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/debug/leak_annotations.h"
+#include "base/location.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+template <class T>
+class OffThreadObjectCreator {
+ public:
+  static T* NewObject() {
+    T* result;
+    {
+      Thread creator_thread("creator_thread");
+      creator_thread.Start();
+      creator_thread.task_runner()->PostTask(
+          FROM_HERE, base::Bind(OffThreadObjectCreator::CreateObject, &result));
+    }
+    DCHECK(result);  // We synchronized on thread destruction above.
+    return result;
+  }
+ private:
+  static void CreateObject(T** result) {
+    *result = new T;
+  }
+};
+
+struct Base {
+  std::string member;
+};
+struct Derived : public Base {};
+
+struct TargetBase {};
+struct Target : public TargetBase, public SupportsWeakPtr<Target> {
+  virtual ~Target() {}
+};
+struct DerivedTarget : public Target {};
+struct Arrow {
+  WeakPtr<Target> target;
+};
+struct TargetWithFactory : public Target {
+  TargetWithFactory() : factory(this) {}
+  WeakPtrFactory<Target> factory;
+};
+
+// Helper class to create and destroy weak pointer copies
+// and delete objects on a background thread.
+class BackgroundThread : public Thread {
+ public:
+  BackgroundThread() : Thread("owner_thread") {}
+
+  ~BackgroundThread() override { Stop(); }
+
+  void CreateArrowFromTarget(Arrow** arrow, Target* target) {
+    WaitableEvent completion(true, false);
+    task_runner()->PostTask(
+        FROM_HERE, base::Bind(&BackgroundThread::DoCreateArrowFromTarget, arrow,
+                              target, &completion));
+    completion.Wait();
+  }
+
+  void CreateArrowFromArrow(Arrow** arrow, const Arrow* other) {
+    WaitableEvent completion(true, false);
+    task_runner()->PostTask(
+        FROM_HERE, base::Bind(&BackgroundThread::DoCreateArrowFromArrow, arrow,
+                              other, &completion));
+    completion.Wait();
+  }
+
+  void DeleteTarget(Target* object) {
+    WaitableEvent completion(true, false);
+    task_runner()->PostTask(
+        FROM_HERE,
+        base::Bind(&BackgroundThread::DoDeleteTarget, object, &completion));
+    completion.Wait();
+  }
+
+  void CopyAndAssignArrow(Arrow* object) {
+    WaitableEvent completion(true, false);
+    task_runner()->PostTask(
+        FROM_HERE, base::Bind(&BackgroundThread::DoCopyAndAssignArrow, object,
+                              &completion));
+    completion.Wait();
+  }
+
+  void CopyAndAssignArrowBase(Arrow* object) {
+    WaitableEvent completion(true, false);
+    task_runner()->PostTask(
+        FROM_HERE, base::Bind(&BackgroundThread::DoCopyAndAssignArrowBase,
+                              object, &completion));
+    completion.Wait();
+  }
+
+  void DeleteArrow(Arrow* object) {
+    WaitableEvent completion(true, false);
+    task_runner()->PostTask(
+        FROM_HERE,
+        base::Bind(&BackgroundThread::DoDeleteArrow, object, &completion));
+    completion.Wait();
+  }
+
+  Target* DeRef(const Arrow* arrow) {
+    WaitableEvent completion(true, false);
+    Target* result = NULL;
+    task_runner()->PostTask(FROM_HERE, base::Bind(&BackgroundThread::DoDeRef,
+                                                  arrow, &result, &completion));
+    completion.Wait();
+    return result;
+  }
+
+ protected:
+  static void DoCreateArrowFromArrow(Arrow** arrow,
+                                     const Arrow* other,
+                                     WaitableEvent* completion) {
+    *arrow = new Arrow;
+    **arrow = *other;
+    completion->Signal();
+  }
+
+  static void DoCreateArrowFromTarget(Arrow** arrow,
+                                      Target* target,
+                                      WaitableEvent* completion) {
+    *arrow = new Arrow;
+    (*arrow)->target = target->AsWeakPtr();
+    completion->Signal();
+  }
+
+  static void DoDeRef(const Arrow* arrow,
+                      Target** result,
+                      WaitableEvent* completion) {
+    *result = arrow->target.get();
+    completion->Signal();
+  }
+
+  static void DoDeleteTarget(Target* object, WaitableEvent* completion) {
+    delete object;
+    completion->Signal();
+  }
+
+  static void DoCopyAndAssignArrow(Arrow* object, WaitableEvent* completion) {
+    // Copy constructor.
+    Arrow a = *object;
+    // Assignment operator.
+    *object = a;
+    completion->Signal();
+  }
+
+  static void DoCopyAndAssignArrowBase(
+      Arrow* object,
+      WaitableEvent* completion) {
+    // Copy constructor.
+    WeakPtr<TargetBase> b = object->target;
+    // Assignment operator.
+    WeakPtr<TargetBase> c;
+    c = object->target;
+    completion->Signal();
+  }
+
+  static void DoDeleteArrow(Arrow* object, WaitableEvent* completion) {
+    delete object;
+    completion->Signal();
+  }
+};
+
+}  // namespace
+
+TEST(WeakPtrFactoryTest, Basic) {
+  int data;
+  WeakPtrFactory<int> factory(&data);
+  WeakPtr<int> ptr = factory.GetWeakPtr();
+  EXPECT_EQ(&data, ptr.get());
+}
+
+TEST(WeakPtrFactoryTest, Comparison) {
+  int data;
+  WeakPtrFactory<int> factory(&data);
+  WeakPtr<int> ptr = factory.GetWeakPtr();
+  WeakPtr<int> ptr2 = ptr;
+  EXPECT_EQ(ptr.get(), ptr2.get());
+}
+
+TEST(WeakPtrFactoryTest, OutOfScope) {
+  WeakPtr<int> ptr;
+  EXPECT_EQ(NULL, ptr.get());
+  {
+    int data;
+    WeakPtrFactory<int> factory(&data);
+    ptr = factory.GetWeakPtr();
+  }
+  EXPECT_EQ(NULL, ptr.get());
+}
+
+TEST(WeakPtrFactoryTest, Multiple) {
+  WeakPtr<int> a, b;
+  {
+    int data;
+    WeakPtrFactory<int> factory(&data);
+    a = factory.GetWeakPtr();
+    b = factory.GetWeakPtr();
+    EXPECT_EQ(&data, a.get());
+    EXPECT_EQ(&data, b.get());
+  }
+  EXPECT_EQ(NULL, a.get());
+  EXPECT_EQ(NULL, b.get());
+}
+
+TEST(WeakPtrFactoryTest, MultipleStaged) {
+  WeakPtr<int> a;
+  {
+    int data;
+    WeakPtrFactory<int> factory(&data);
+    a = factory.GetWeakPtr();
+    {
+      WeakPtr<int> b = factory.GetWeakPtr();
+    }
+    EXPECT_TRUE(NULL != a.get());
+  }
+  EXPECT_EQ(NULL, a.get());
+}
+
+TEST(WeakPtrFactoryTest, Dereference) {
+  Base data;
+  data.member = "123456";
+  WeakPtrFactory<Base> factory(&data);
+  WeakPtr<Base> ptr = factory.GetWeakPtr();
+  EXPECT_EQ(&data, ptr.get());
+  EXPECT_EQ(data.member, (*ptr).member);
+  EXPECT_EQ(data.member, ptr->member);
+}
+
+TEST(WeakPtrFactoryTest, UpCast) {
+  Derived data;
+  WeakPtrFactory<Derived> factory(&data);
+  WeakPtr<Base> ptr = factory.GetWeakPtr();
+  ptr = factory.GetWeakPtr();
+  EXPECT_EQ(ptr.get(), &data);
+}
+
+TEST(WeakPtrTest, SupportsWeakPtr) {
+  Target target;
+  WeakPtr<Target> ptr = target.AsWeakPtr();
+  EXPECT_EQ(&target, ptr.get());
+}
+
+TEST(WeakPtrTest, DerivedTarget) {
+  DerivedTarget target;
+  WeakPtr<DerivedTarget> ptr = AsWeakPtr(&target);
+  EXPECT_EQ(&target, ptr.get());
+}
+
+TEST(WeakPtrTest, InvalidateWeakPtrs) {
+  int data;
+  WeakPtrFactory<int> factory(&data);
+  WeakPtr<int> ptr = factory.GetWeakPtr();
+  EXPECT_EQ(&data, ptr.get());
+  EXPECT_TRUE(factory.HasWeakPtrs());
+  factory.InvalidateWeakPtrs();
+  EXPECT_EQ(NULL, ptr.get());
+  EXPECT_FALSE(factory.HasWeakPtrs());
+
+  // Test that the factory can create new weak pointers after a
+  // InvalidateWeakPtrs call, and they remain valid until the next
+  // InvalidateWeakPtrs call.
+  WeakPtr<int> ptr2 = factory.GetWeakPtr();
+  EXPECT_EQ(&data, ptr2.get());
+  EXPECT_TRUE(factory.HasWeakPtrs());
+  factory.InvalidateWeakPtrs();
+  EXPECT_EQ(NULL, ptr2.get());
+  EXPECT_FALSE(factory.HasWeakPtrs());
+}
+
+TEST(WeakPtrTest, HasWeakPtrs) {
+  int data;
+  WeakPtrFactory<int> factory(&data);
+  {
+    WeakPtr<int> ptr = factory.GetWeakPtr();
+    EXPECT_TRUE(factory.HasWeakPtrs());
+  }
+  EXPECT_FALSE(factory.HasWeakPtrs());
+}
+
+TEST(WeakPtrTest, ObjectAndWeakPtrOnDifferentThreads) {
+  // Test that it is OK to create an object that supports WeakPtr on one thread,
+  // but use it on another.  This tests that we do not trip runtime checks that
+  // ensure that a WeakPtr is not used by multiple threads.
+  scoped_ptr<Target> target(OffThreadObjectCreator<Target>::NewObject());
+  WeakPtr<Target> weak_ptr = target->AsWeakPtr();
+  EXPECT_EQ(target.get(), weak_ptr.get());
+}
+
+TEST(WeakPtrTest, WeakPtrInitiateAndUseOnDifferentThreads) {
+  // Test that it is OK to create an object that has a WeakPtr member on one
+  // thread, but use it on another.  This tests that we do not trip runtime
+  // checks that ensure that a WeakPtr is not used by multiple threads.
+  scoped_ptr<Arrow> arrow(OffThreadObjectCreator<Arrow>::NewObject());
+  Target target;
+  arrow->target = target.AsWeakPtr();
+  EXPECT_EQ(&target, arrow->target.get());
+}
+
+TEST(WeakPtrTest, MoveOwnershipImplicitly) {
+  // Move object ownership to another thread by releasing all weak pointers
+  // on the original thread first, and then establish WeakPtr on a different
+  // thread.
+  BackgroundThread background;
+  background.Start();
+
+  Target* target = new Target();
+  {
+    WeakPtr<Target> weak_ptr = target->AsWeakPtr();
+    // Main thread deletes the WeakPtr, then the thread ownership of the
+    // object can be implicitly moved.
+  }
+  Arrow* arrow;
+
+  // Background thread creates WeakPtr(and implicitly owns the object).
+  background.CreateArrowFromTarget(&arrow, target);
+  EXPECT_EQ(background.DeRef(arrow), target);
+
+  {
+    // Main thread creates another WeakPtr, but this does not trigger implicitly
+    // thread ownership move.
+    Arrow arrow;
+    arrow.target = target->AsWeakPtr();
+
+    // The new WeakPtr is owned by background thread.
+    EXPECT_EQ(target, background.DeRef(&arrow));
+  }
+
+  // Target can only be deleted on background thread.
+  background.DeleteTarget(target);
+  background.DeleteArrow(arrow);
+}
+
+TEST(WeakPtrTest, MoveOwnershipOfUnreferencedObject) {
+  BackgroundThread background;
+  background.Start();
+
+  Arrow* arrow;
+  {
+    Target target;
+    // Background thread creates WeakPtr.
+    background.CreateArrowFromTarget(&arrow, &target);
+
+    // Bind to background thread.
+    EXPECT_EQ(&target, background.DeRef(arrow));
+
+    // Release the only WeakPtr.
+    arrow->target.reset();
+
+    // Now we should be able to create a new reference from this thread.
+    arrow->target = target.AsWeakPtr();
+
+    // Re-bind to main thread.
+    EXPECT_EQ(&target, arrow->target.get());
+
+    // And the main thread can now delete the target.
+  }
+
+  delete arrow;
+}
+
+TEST(WeakPtrTest, MoveOwnershipAfterInvalidate) {
+  BackgroundThread background;
+  background.Start();
+
+  Arrow arrow;
+  scoped_ptr<TargetWithFactory> target(new TargetWithFactory);
+
+  // Bind to main thread.
+  arrow.target = target->factory.GetWeakPtr();
+  EXPECT_EQ(target.get(), arrow.target.get());
+
+  target->factory.InvalidateWeakPtrs();
+  EXPECT_EQ(NULL, arrow.target.get());
+
+  arrow.target = target->factory.GetWeakPtr();
+  // Re-bind to background thread.
+  EXPECT_EQ(target.get(), background.DeRef(&arrow));
+
+  // And the background thread can now delete the target.
+  background.DeleteTarget(target.release());
+}
+
+TEST(WeakPtrTest, MainThreadRefOutlivesBackgroundThreadRef) {
+  // Originating thread has a WeakPtr that outlives others.
+  // - Main thread creates a WeakPtr
+  // - Background thread creates a WeakPtr copy from the one in main thread
+  // - Destruct the WeakPtr on background thread
+  // - Destruct the WeakPtr on main thread
+  BackgroundThread background;
+  background.Start();
+
+  Target target;
+  Arrow arrow;
+  arrow.target = target.AsWeakPtr();
+
+  Arrow* arrow_copy;
+  background.CreateArrowFromArrow(&arrow_copy, &arrow);
+  EXPECT_EQ(arrow_copy->target.get(), &target);
+  background.DeleteArrow(arrow_copy);
+}
+
+TEST(WeakPtrTest, BackgroundThreadRefOutlivesMainThreadRef) {
+  // Originating thread drops all references before another thread.
+  // - Main thread creates a WeakPtr and passes copy to background thread
+  // - Destruct the pointer on main thread
+  // - Destruct the pointer on background thread
+  BackgroundThread background;
+  background.Start();
+
+  Target target;
+  Arrow* arrow_copy;
+  {
+    Arrow arrow;
+    arrow.target = target.AsWeakPtr();
+    background.CreateArrowFromArrow(&arrow_copy, &arrow);
+  }
+  EXPECT_EQ(arrow_copy->target.get(), &target);
+  background.DeleteArrow(arrow_copy);
+}
+
+TEST(WeakPtrTest, OwnerThreadDeletesObject) {
+  // Originating thread invalidates WeakPtrs while its held by other thread.
+  // - Main thread creates WeakPtr and passes Copy to background thread
+  // - Object gets destroyed on main thread
+  //   (invalidates WeakPtr on background thread)
+  // - WeakPtr gets destroyed on Thread B
+  BackgroundThread background;
+  background.Start();
+  Arrow* arrow_copy;
+  {
+    Target target;
+    Arrow arrow;
+    arrow.target = target.AsWeakPtr();
+    background.CreateArrowFromArrow(&arrow_copy, &arrow);
+  }
+  EXPECT_EQ(NULL, arrow_copy->target.get());
+  background.DeleteArrow(arrow_copy);
+}
+
+TEST(WeakPtrTest, NonOwnerThreadCanCopyAndAssignWeakPtr) {
+  // Main thread creates a Target object.
+  Target target;
+  // Main thread creates an arrow referencing the Target.
+  Arrow *arrow = new Arrow();
+  arrow->target = target.AsWeakPtr();
+
+  // Background can copy and assign arrow (as well as the WeakPtr inside).
+  BackgroundThread background;
+  background.Start();
+  background.CopyAndAssignArrow(arrow);
+  background.DeleteArrow(arrow);
+}
+
+TEST(WeakPtrTest, NonOwnerThreadCanCopyAndAssignWeakPtrBase) {
+  // Main thread creates a Target object.
+  Target target;
+  // Main thread creates an arrow referencing the Target.
+  Arrow *arrow = new Arrow();
+  arrow->target = target.AsWeakPtr();
+
+  // Background can copy and assign arrow's WeakPtr to a base class WeakPtr.
+  BackgroundThread background;
+  background.Start();
+  background.CopyAndAssignArrowBase(arrow);
+  background.DeleteArrow(arrow);
+}
+
+TEST(WeakPtrTest, NonOwnerThreadCanDeleteWeakPtr) {
+  // Main thread creates a Target object.
+  Target target;
+  // Main thread creates an arrow referencing the Target.
+  Arrow* arrow = new Arrow();
+  arrow->target = target.AsWeakPtr();
+
+  // Background can delete arrow (as well as the WeakPtr inside).
+  BackgroundThread background;
+  background.Start();
+  background.DeleteArrow(arrow);
+}
+
+#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && GTEST_HAS_DEATH_TEST
+
+TEST(WeakPtrDeathTest, WeakPtrCopyDoesNotChangeThreadBinding) {
+  // The default style "fast" does not support multi-threaded tests
+  // (introduces deadlock on Linux).
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+
+  BackgroundThread background;
+  background.Start();
+
+  // Main thread creates a Target object.
+  Target target;
+  // Main thread creates an arrow referencing the Target.
+  Arrow arrow;
+  arrow.target = target.AsWeakPtr();
+
+  // Background copies the WeakPtr.
+  Arrow* arrow_copy;
+  background.CreateArrowFromArrow(&arrow_copy, &arrow);
+
+  // The copy is still bound to main thread so I can deref.
+  EXPECT_EQ(arrow.target.get(), arrow_copy->target.get());
+
+  // Although background thread created the copy, it can not deref the copied
+  // WeakPtr.
+  ASSERT_DEATH(background.DeRef(arrow_copy), "");
+
+  background.DeleteArrow(arrow_copy);
+}
+
+TEST(WeakPtrDeathTest, NonOwnerThreadDereferencesWeakPtrAfterReference) {
+  // The default style "fast" does not support multi-threaded tests
+  // (introduces deadlock on Linux).
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+
+  // Main thread creates a Target object.
+  Target target;
+
+  // Main thread creates an arrow referencing the Target (so target's
+  // thread ownership can not be implicitly moved).
+  Arrow arrow;
+  arrow.target = target.AsWeakPtr();
+  arrow.target.get();
+
+  // Background thread tries to deref target, which violates thread ownership.
+  BackgroundThread background;
+  background.Start();
+  ASSERT_DEATH(background.DeRef(&arrow), "");
+}
+
+TEST(WeakPtrDeathTest, NonOwnerThreadDeletesWeakPtrAfterReference) {
+  // The default style "fast" does not support multi-threaded tests
+  // (introduces deadlock on Linux).
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+
+  scoped_ptr<Target> target(new Target());
+
+  // Main thread creates an arrow referencing the Target.
+  Arrow arrow;
+  arrow.target = target->AsWeakPtr();
+
+  // Background thread tries to deref target, binding it to the thread.
+  BackgroundThread background;
+  background.Start();
+  background.DeRef(&arrow);
+
+  // Main thread deletes Target, violating thread binding.
+  ASSERT_DEATH(target.reset(), "");
+
+  // |target.reset()| died so |target| still holds the object, so we
+  // must pass it to the background thread to teardown.
+  background.DeleteTarget(target.release());
+}
+
+TEST(WeakPtrDeathTest, NonOwnerThreadDeletesObjectAfterReference) {
+  // The default style "fast" does not support multi-threaded tests
+  // (introduces deadlock on Linux).
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+
+  scoped_ptr<Target> target(new Target());
+
+  // Main thread creates an arrow referencing the Target, and references it, so
+  // that it becomes bound to the thread.
+  Arrow arrow;
+  arrow.target = target->AsWeakPtr();
+  arrow.target.get();
+
+  // Background thread tries to delete target, volating thread binding.
+  BackgroundThread background;
+  background.Start();
+  ASSERT_DEATH(background.DeleteTarget(target.release()), "");
+}
+
+TEST(WeakPtrDeathTest, NonOwnerThreadReferencesObjectAfterDeletion) {
+  // The default style "fast" does not support multi-threaded tests
+  // (introduces deadlock on Linux).
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+
+  scoped_ptr<Target> target(new Target());
+
+  // Main thread creates an arrow referencing the Target.
+  Arrow arrow;
+  arrow.target = target->AsWeakPtr();
+
+  // Background thread tries to delete target, binding the object to the thread.
+  BackgroundThread background;
+  background.Start();
+  background.DeleteTarget(target.release());
+
+  // Main thread attempts to dereference the target, violating thread binding.
+  ASSERT_DEATH(arrow.target.get(), "");
+}
+
+#endif
+
+}  // namespace base
diff --git a/base/memory/weak_ptr_unittest.nc b/base/memory/weak_ptr_unittest.nc
new file mode 100644
index 0000000..2ab428d
--- /dev/null
+++ b/base/memory/weak_ptr_unittest.nc
@@ -0,0 +1,138 @@
+// Copyright (c) 2012 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/memory/weak_ptr.h"
+
+namespace base {
+
+struct Producer : SupportsWeakPtr<Producer> {};
+struct DerivedProducer : Producer {};
+struct OtherDerivedProducer : Producer {};
+struct MultiplyDerivedProducer : Producer,
+                                 SupportsWeakPtr<MultiplyDerivedProducer> {};
+struct Unrelated {};
+struct DerivedUnrelated : Unrelated {};
+
+#if defined(NCTEST_AUTO_DOWNCAST)  // [r"fatal error: cannot initialize a member subobject of type 'base::DerivedProducer \*' with an lvalue of type 'base::Producer \*const'"]
+
+void WontCompile() {
+  Producer f;
+  WeakPtr<Producer> ptr = f.AsWeakPtr();
+  WeakPtr<DerivedProducer> derived_ptr = ptr;
+}
+
+#elif defined(NCTEST_STATIC_DOWNCAST)  // [r"fatal error: cannot initialize a member subobject of type 'base::DerivedProducer \*' with an lvalue of type 'base::Producer \*const'"]
+
+void WontCompile() {
+  Producer f;
+  WeakPtr<Producer> ptr = f.AsWeakPtr();
+  WeakPtr<DerivedProducer> derived_ptr =
+      static_cast<WeakPtr<DerivedProducer> >(ptr);
+}
+
+#elif defined(NCTEST_AUTO_REF_DOWNCAST)  // [r"fatal error: non-const lvalue reference to type 'WeakPtr<base::DerivedProducer>' cannot bind to a value of unrelated type 'WeakPtr<base::Producer>'"]
+
+void WontCompile() {
+  Producer f;
+  WeakPtr<Producer> ptr = f.AsWeakPtr();
+  WeakPtr<DerivedProducer>& derived_ptr = ptr;
+}
+
+#elif defined(NCTEST_STATIC_REF_DOWNCAST)  // [r"fatal error: non-const lvalue reference to type 'WeakPtr<base::DerivedProducer>' cannot bind to a value of unrelated type 'WeakPtr<base::Producer>'"]
+
+void WontCompile() {
+  Producer f;
+  WeakPtr<Producer> ptr = f.AsWeakPtr();
+  WeakPtr<DerivedProducer>& derived_ptr =
+      static_cast<WeakPtr<DerivedProducer>&>(ptr);
+}
+
+#elif defined(NCTEST_STATIC_ASWEAKPTR_DOWNCAST)  // [r"no matching function"]
+
+void WontCompile() {
+  Producer f;
+  WeakPtr<DerivedProducer> ptr =
+      SupportsWeakPtr<Producer>::StaticAsWeakPtr<DerivedProducer>(&f);
+}
+
+#elif defined(NCTEST_UNSAFE_HELPER_DOWNCAST)  // [r"fatal error: cannot initialize a member subobject of type 'base::DerivedProducer \*' with an lvalue of type 'base::Producer \*const'"]
+
+void WontCompile() {
+  Producer f;
+  WeakPtr<DerivedProducer> ptr = AsWeakPtr(&f);
+}
+
+#elif defined(NCTEST_UNSAFE_INSTANTIATED_HELPER_DOWNCAST)  // [r"no matching function"]
+
+void WontCompile() {
+  Producer f;
+  WeakPtr<DerivedProducer> ptr = AsWeakPtr<DerivedProducer>(&f);
+}
+
+#elif defined(NCTEST_UNSAFE_WRONG_INSANTIATED_HELPER_DOWNCAST)  // [r"fatal error: cannot initialize a member subobject of type 'base::DerivedProducer \*' with an lvalue of type 'base::Producer \*const'"]
+
+void WontCompile() {
+  Producer f; 
+  WeakPtr<DerivedProducer> ptr = AsWeakPtr<Producer>(&f);
+}
+
+#elif defined(NCTEST_UNSAFE_HELPER_CAST)  // [r"fatal error: cannot initialize a member subobject of type 'base::OtherDerivedProducer \*' with an lvalue of type 'base::DerivedProducer \*const'"]
+
+void WontCompile() {
+  DerivedProducer f;
+  WeakPtr<OtherDerivedProducer> ptr = AsWeakPtr(&f);
+}
+
+#elif defined(NCTEST_UNSAFE_INSTANTIATED_HELPER_SIDECAST)  // [r"fatal error: no matching function for call to 'AsWeakPtr'"]
+
+void WontCompile() {
+  DerivedProducer f;
+  WeakPtr<OtherDerivedProducer> ptr = AsWeakPtr<OtherDerivedProducer>(&f);
+}
+
+#elif defined(NCTEST_UNSAFE_WRONG_INSTANTIATED_HELPER_SIDECAST)  // [r"fatal error: cannot initialize a member subobject of type 'base::OtherDerivedProducer \*' with an lvalue of type 'base::DerivedProducer \*const'"]
+
+void WontCompile() {
+  DerivedProducer f;
+  WeakPtr<OtherDerivedProducer> ptr = AsWeakPtr<DerivedProducer>(&f);
+}
+
+#elif defined(NCTEST_UNRELATED_HELPER)  // [r"fatal error: cannot initialize a member subobject of type 'base::Unrelated \*' with an lvalue of type 'base::DerivedProducer \*const'"]
+
+void WontCompile() {
+  DerivedProducer f;
+  WeakPtr<Unrelated> ptr = AsWeakPtr(&f);
+}
+
+#elif defined(NCTEST_UNRELATED_INSTANTIATED_HELPER)  // [r"no matching function"]
+
+void WontCompile() {
+  DerivedProducer f;
+  WeakPtr<Unrelated> ptr = AsWeakPtr<Unrelated>(&f);
+}
+
+#elif defined(NCTEST_COMPLETELY_UNRELATED_HELPER)  // [r"fatal error: static_assert failed \"AsWeakPtr_argument_inherits_from_SupportsWeakPtr\""]
+
+void WontCompile() {
+  Unrelated f;
+  WeakPtr<Unrelated> ptr = AsWeakPtr(&f);
+}
+
+#elif defined(NCTEST_DERIVED_COMPLETELY_UNRELATED_HELPER)  // [r"fatal error: static_assert failed \"AsWeakPtr_argument_inherits_from_SupportsWeakPtr\""]
+
+void WontCompile() {
+  DerivedUnrelated f;
+  WeakPtr<Unrelated> ptr = AsWeakPtr(&f);
+}
+
+#elif defined(NCTEST_AMBIGUOUS_ANCESTORS)  // [r"fatal error: ambiguous conversion from derived class 'base::MultiplyDerivedProducer' to base class 'base::internal::SupportsWeakPtrBase':"]
+
+void WontCompile() {
+  MultiplyDerivedProducer f;
+  WeakPtr<MultiplyDerivedProducer> ptr = AsWeakPtr(&f);
+}
+
+#endif
+
+}
diff --git a/base/message_loop/incoming_task_queue.cc b/base/message_loop/incoming_task_queue.cc
new file mode 100644
index 0000000..642222e
--- /dev/null
+++ b/base/message_loop/incoming_task_queue.cc
@@ -0,0 +1,187 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop/incoming_task_queue.h"
+
+#include <limits>
+
+#include "base/location.h"
+#include "base/message_loop/message_loop.h"
+#include "base/metrics/histogram.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/time/time.h"
+
+namespace base {
+namespace internal {
+
+namespace {
+
+#ifndef NDEBUG
+// Delays larger than this are often bogus, and a warning should be emitted in
+// debug builds to warn developers.  http://crbug.com/450045
+const int kTaskDelayWarningThresholdInSeconds =
+    14 * 24 * 60 * 60;  // 14 days.
+#endif
+
+// Returns true if MessagePump::ScheduleWork() must be called one
+// time for every task that is added to the MessageLoop incoming queue.
+bool AlwaysNotifyPump(MessageLoop::Type type) {
+#if defined(OS_ANDROID)
+  // The Android UI message loop needs to get notified each time a task is
+  // added
+  // to the incoming queue.
+  return type == MessageLoop::TYPE_UI || type == MessageLoop::TYPE_JAVA;
+#else
+  return false;
+#endif
+}
+
+}  // namespace
+
+IncomingTaskQueue::IncomingTaskQueue(MessageLoop* message_loop)
+    : high_res_task_count_(0),
+      message_loop_(message_loop),
+      next_sequence_num_(0),
+      message_loop_scheduled_(false),
+      always_schedule_work_(AlwaysNotifyPump(message_loop_->type())),
+      is_ready_for_scheduling_(false) {
+}
+
+bool IncomingTaskQueue::AddToIncomingQueue(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay,
+    bool nestable) {
+  DLOG_IF(WARNING,
+          delay.InSeconds() > kTaskDelayWarningThresholdInSeconds)
+      << "Requesting super-long task delay period of " << delay.InSeconds()
+      << " seconds from here: " << from_here.ToString();
+
+  AutoLock locked(incoming_queue_lock_);
+  PendingTask pending_task(
+      from_here, task, CalculateDelayedRuntime(delay), nestable);
+#if defined(OS_WIN)
+  // We consider the task needs a high resolution timer if the delay is
+  // more than 0 and less than 32ms. This caps the relative error to
+  // less than 50% : a 33ms wait can wake at 48ms since the default
+  // resolution on Windows is between 10 and 15ms.
+  if (delay > TimeDelta() &&
+      delay.InMilliseconds() < (2 * Time::kMinLowResolutionThresholdMs)) {
+    ++high_res_task_count_;
+    pending_task.is_high_res = true;
+  }
+#endif
+  return PostPendingTask(&pending_task);
+}
+
+bool IncomingTaskQueue::HasHighResolutionTasks() {
+  AutoLock lock(incoming_queue_lock_);
+  return high_res_task_count_ > 0;
+}
+
+bool IncomingTaskQueue::IsIdleForTesting() {
+  AutoLock lock(incoming_queue_lock_);
+  return incoming_queue_.empty();
+}
+
+int IncomingTaskQueue::ReloadWorkQueue(TaskQueue* work_queue) {
+  // Make sure no tasks are lost.
+  DCHECK(work_queue->empty());
+
+  // Acquire all we can from the inter-thread queue with one lock acquisition.
+  AutoLock lock(incoming_queue_lock_);
+  if (incoming_queue_.empty()) {
+    // If the loop attempts to reload but there are no tasks in the incoming
+    // queue, that means it will go to sleep waiting for more work. If the
+    // incoming queue becomes nonempty we need to schedule it again.
+    message_loop_scheduled_ = false;
+  } else {
+    incoming_queue_.Swap(work_queue);
+  }
+  // Reset the count of high resolution tasks since our queue is now empty.
+  int high_res_tasks = high_res_task_count_;
+  high_res_task_count_ = 0;
+  return high_res_tasks;
+}
+
+void IncomingTaskQueue::WillDestroyCurrentMessageLoop() {
+  AutoLock lock(incoming_queue_lock_);
+  message_loop_ = NULL;
+}
+
+void IncomingTaskQueue::StartScheduling() {
+  AutoLock lock(incoming_queue_lock_);
+  DCHECK(!is_ready_for_scheduling_);
+  DCHECK(!message_loop_scheduled_);
+  is_ready_for_scheduling_ = true;
+  if (!incoming_queue_.empty())
+    ScheduleWork();
+}
+
+TimeTicks IncomingTaskQueue::GetNewlyAddedTaskDelay() {
+  return !incoming_queue_.empty() ? incoming_queue_.front().delayed_run_time :
+      TimeTicks();
+}
+
+IncomingTaskQueue::~IncomingTaskQueue() {
+  // Verify that WillDestroyCurrentMessageLoop() has been called.
+  DCHECK(!message_loop_);
+}
+
+TimeTicks IncomingTaskQueue::CalculateDelayedRuntime(TimeDelta delay) {
+  TimeTicks delayed_run_time;
+  if (delay > TimeDelta())
+    delayed_run_time = TimeTicks::Now() + delay;
+  else
+    DCHECK_EQ(delay.InMilliseconds(), 0) << "delay should not be negative";
+  return delayed_run_time;
+}
+
+bool IncomingTaskQueue::PostPendingTask(PendingTask* pending_task) {
+  // Warning: Don't try to short-circuit, and handle this thread's tasks more
+  // directly, as it could starve handling of foreign threads.  Put every task
+  // into this queue.
+
+  // This should only be called while the lock is taken.
+  incoming_queue_lock_.AssertAcquired();
+
+  if (!message_loop_) {
+    pending_task->task.Reset();
+    return false;
+  }
+
+  // Initialize the sequence number. The sequence number is used for delayed
+  // tasks (to faciliate FIFO sorting when two tasks have the same
+  // delayed_run_time value) and for identifying the task in about:tracing.
+  pending_task->sequence_num = next_sequence_num_++;
+
+  message_loop_->task_annotator()->DidQueueTask("MessageLoop::PostTask",
+                                                *pending_task);
+
+  bool was_empty = incoming_queue_.empty();
+  incoming_queue_.push(*pending_task);
+  pending_task->task.Reset();
+
+  if (is_ready_for_scheduling_ &&
+      (always_schedule_work_ || (!message_loop_scheduled_ && was_empty))) {
+    ScheduleWork();
+  }
+
+  return true;
+}
+
+void IncomingTaskQueue::ScheduleWork() {
+  DCHECK(is_ready_for_scheduling_);
+  // Wake up the message loop.
+  message_loop_->ScheduleWork();
+  // After we've scheduled the message loop, we do not need to do so again
+  // until we know it has processed all of the work in our queue and is
+  // waiting for more work again. The message loop will always attempt to
+  // reload from the incoming queue before waiting again so we clear this flag
+  // in ReloadWorkQueue().
+  message_loop_scheduled_ = true;
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/message_loop/incoming_task_queue.h b/base/message_loop/incoming_task_queue.h
new file mode 100644
index 0000000..544f3e9
--- /dev/null
+++ b/base/message_loop/incoming_task_queue.h
@@ -0,0 +1,114 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MESSAGE_LOOP_INCOMING_TASK_QUEUE_H_
+#define BASE_MESSAGE_LOOP_INCOMING_TASK_QUEUE_H_
+
+#include "base/base_export.h"
+#include "base/memory/ref_counted.h"
+#include "base/pending_task.h"
+#include "base/synchronization/lock.h"
+#include "base/time/time.h"
+
+namespace base {
+
+class MessageLoop;
+class WaitableEvent;
+
+namespace internal {
+
+// Implements a queue of tasks posted to the message loop running on the current
+// thread. This class takes care of synchronizing posting tasks from different
+// threads and together with MessageLoop ensures clean shutdown.
+class BASE_EXPORT IncomingTaskQueue
+    : public RefCountedThreadSafe<IncomingTaskQueue> {
+ public:
+  explicit IncomingTaskQueue(MessageLoop* message_loop);
+
+  // Appends a task to the incoming queue. Posting of all tasks is routed though
+  // AddToIncomingQueue() or TryAddToIncomingQueue() to make sure that posting
+  // task is properly synchronized between different threads.
+  //
+  // Returns true if the task was successfully added to the queue, otherwise
+  // returns false. In all cases, the ownership of |task| is transferred to the
+  // called method.
+  bool AddToIncomingQueue(const tracked_objects::Location& from_here,
+                          const Closure& task,
+                          TimeDelta delay,
+                          bool nestable);
+
+  // Returns true if the queue contains tasks that require higher than default
+  // timer resolution. Currently only needed for Windows.
+  bool HasHighResolutionTasks();
+
+  // Returns true if the message loop is "idle". Provided for testing.
+  bool IsIdleForTesting();
+
+  // Loads tasks from the |incoming_queue_| into |*work_queue|. Must be called
+  // from the thread that is running the loop. Returns the number of tasks that
+  // require high resolution timers.
+  int ReloadWorkQueue(TaskQueue* work_queue);
+
+  // Disconnects |this| from the parent message loop.
+  void WillDestroyCurrentMessageLoop();
+
+  // This should be called when the message loop becomes ready for
+  // scheduling work.
+  void StartScheduling();
+
+  // Returns the delay for the most recently added task.
+  TimeTicks GetNewlyAddedTaskDelay();
+
+ private:
+  friend class RefCountedThreadSafe<IncomingTaskQueue>;
+  virtual ~IncomingTaskQueue();
+
+  // Calculates the time at which a PendingTask should run.
+  TimeTicks CalculateDelayedRuntime(TimeDelta delay);
+
+  // Adds a task to |incoming_queue_|. The caller retains ownership of
+  // |pending_task|, but this function will reset the value of
+  // |pending_task->task|. This is needed to ensure that the posting call stack
+  // does not retain |pending_task->task| beyond this function call.
+  bool PostPendingTask(PendingTask* pending_task);
+
+  // Wakes up the message loop and schedules work.
+  void ScheduleWork();
+
+  // Number of tasks that require high resolution timing. This value is kept
+  // so that ReloadWorkQueue() completes in constant time.
+  int high_res_task_count_;
+
+  // The lock that protects access to the members of this class.
+  base::Lock incoming_queue_lock_;
+
+  // An incoming queue of tasks that are acquired under a mutex for processing
+  // on this instance's thread. These tasks have not yet been been pushed to
+  // |message_loop_|.
+  TaskQueue incoming_queue_;
+
+  // Points to the message loop that owns |this|.
+  MessageLoop* message_loop_;
+
+  // The next sequence number to use for delayed tasks.
+  int next_sequence_num_;
+
+  // True if our message loop has already been scheduled and does not need to be
+  // scheduled again until an empty reload occurs.
+  bool message_loop_scheduled_;
+
+  // True if we always need to call ScheduleWork when receiving a new task, even
+  // if the incoming queue was not empty.
+  const bool always_schedule_work_;
+
+  // False until StartScheduling() is called.
+  bool is_ready_for_scheduling_;
+
+  DISALLOW_COPY_AND_ASSIGN(IncomingTaskQueue);
+};
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_MESSAGE_LOOP_INCOMING_TASK_QUEUE_H_
diff --git a/base/message_loop/message_loop.cc b/base/message_loop/message_loop.cc
new file mode 100644
index 0000000..b3c895c
--- /dev/null
+++ b/base/message_loop/message_loop.cc
@@ -0,0 +1,738 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop/message_loop.h"
+
+#include <algorithm>
+
+#include "base/bind.h"
+#include "base/compiler_specific.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_pump_default.h"
+#include "base/metrics/histogram.h"
+#include "base/metrics/statistics_recorder.h"
+#include "base/run_loop.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/thread_local.h"
+#include "base/time/time.h"
+#include "base/tracked_objects.h"
+
+#if defined(OS_MACOSX)
+#include "base/message_loop/message_pump_mac.h"
+#endif
+#if defined(OS_POSIX) && !defined(OS_IOS)
+#include "base/message_loop/message_pump_libevent.h"
+#endif
+#if defined(OS_ANDROID)
+#include "base/message_loop/message_pump_android.h"
+#endif
+#if defined(USE_GLIB)
+#include "base/message_loop/message_pump_glib.h"
+#endif
+
+namespace base {
+
+namespace {
+
+// A lazily created thread local storage for quick access to a thread's message
+// loop, if one exists.  This should be safe and free of static constructors.
+LazyInstance<base::ThreadLocalPointer<MessageLoop> >::Leaky lazy_tls_ptr =
+    LAZY_INSTANCE_INITIALIZER;
+
+// Logical events for Histogram profiling. Run with -message-loop-histogrammer
+// to get an accounting of messages and actions taken on each thread.
+const int kTaskRunEvent = 0x1;
+#if !defined(OS_NACL)
+const int kTimerEvent = 0x2;
+
+// Provide range of message IDs for use in histogramming and debug display.
+const int kLeastNonZeroMessageId = 1;
+const int kMaxMessageId = 1099;
+const int kNumberOfDistinctMessagesDisplayed = 1100;
+
+// Provide a macro that takes an expression (such as a constant, or macro
+// constant) and creates a pair to initalize an array of pairs.  In this case,
+// our pair consists of the expressions value, and the "stringized" version
+// of the expression (i.e., the exrpression put in quotes).  For example, if
+// we have:
+//    #define FOO 2
+//    #define BAR 5
+// then the following:
+//    VALUE_TO_NUMBER_AND_NAME(FOO + BAR)
+// will expand to:
+//   {7, "FOO + BAR"}
+// We use the resulting array as an argument to our histogram, which reads the
+// number as a bucket identifier, and proceeds to use the corresponding name
+// in the pair (i.e., the quoted string) when printing out a histogram.
+#define VALUE_TO_NUMBER_AND_NAME(name) {name, #name},
+
+const LinearHistogram::DescriptionPair event_descriptions_[] = {
+  // Provide some pretty print capability in our histogram for our internal
+  // messages.
+
+  // A few events we handle (kindred to messages), and used to profile actions.
+  VALUE_TO_NUMBER_AND_NAME(kTaskRunEvent)
+  VALUE_TO_NUMBER_AND_NAME(kTimerEvent)
+
+  {-1, NULL}  // The list must be null terminated, per API to histogram.
+};
+#endif  // !defined(OS_NACL)
+
+bool enable_histogrammer_ = false;
+
+MessageLoop::MessagePumpFactory* message_pump_for_ui_factory_ = NULL;
+
+#if defined(OS_IOS)
+typedef MessagePumpIOSForIO MessagePumpForIO;
+#elif defined(OS_NACL_SFI)
+typedef MessagePumpDefault MessagePumpForIO;
+#elif defined(OS_POSIX)
+typedef MessagePumpLibevent MessagePumpForIO;
+#endif
+
+#if !defined(OS_NACL_SFI)
+MessagePumpForIO* ToPumpIO(MessagePump* pump) {
+  return static_cast<MessagePumpForIO*>(pump);
+}
+#endif  // !defined(OS_NACL_SFI)
+
+scoped_ptr<MessagePump> ReturnPump(scoped_ptr<MessagePump> pump) {
+  return pump;
+}
+
+}  // namespace
+
+//------------------------------------------------------------------------------
+
+MessageLoop::TaskObserver::TaskObserver() {
+}
+
+MessageLoop::TaskObserver::~TaskObserver() {
+}
+
+MessageLoop::DestructionObserver::~DestructionObserver() {
+}
+
+//------------------------------------------------------------------------------
+
+MessageLoop::MessageLoop(Type type)
+    : MessageLoop(type, MessagePumpFactoryCallback()) {
+  BindToCurrentThread();
+}
+
+MessageLoop::MessageLoop(scoped_ptr<MessagePump> pump)
+    : MessageLoop(TYPE_CUSTOM, Bind(&ReturnPump, Passed(&pump))) {
+  BindToCurrentThread();
+}
+
+MessageLoop::~MessageLoop() {
+  // current() could be NULL if this message loop is destructed before it is
+  // bound to a thread.
+  DCHECK(current() == this || !current());
+
+  // iOS just attaches to the loop, it doesn't Run it.
+  // TODO(stuartmorgan): Consider wiring up a Detach().
+#if !defined(OS_IOS)
+  DCHECK(!run_loop_);
+#endif
+
+#if defined(OS_WIN)
+  if (in_high_res_mode_)
+    Time::ActivateHighResolutionTimer(false);
+#endif
+  // Clean up any unprocessed tasks, but take care: deleting a task could
+  // result in the addition of more tasks (e.g., via DeleteSoon).  We set a
+  // limit on the number of times we will allow a deleted task to generate more
+  // tasks.  Normally, we should only pass through this loop once or twice.  If
+  // we end up hitting the loop limit, then it is probably due to one task that
+  // is being stubborn.  Inspect the queues to see who is left.
+  bool did_work;
+  for (int i = 0; i < 100; ++i) {
+    DeletePendingTasks();
+    ReloadWorkQueue();
+    // If we end up with empty queues, then break out of the loop.
+    did_work = DeletePendingTasks();
+    if (!did_work)
+      break;
+  }
+  DCHECK(!did_work);
+
+  // Let interested parties have one last shot at accessing this.
+  FOR_EACH_OBSERVER(DestructionObserver, destruction_observers_,
+                    WillDestroyCurrentMessageLoop());
+
+  thread_task_runner_handle_.reset();
+
+  // Tell the incoming queue that we are dying.
+  incoming_task_queue_->WillDestroyCurrentMessageLoop();
+  incoming_task_queue_ = NULL;
+  message_loop_proxy_ = NULL;
+
+  // OK, now make it so that no one can find us.
+  lazy_tls_ptr.Pointer()->Set(NULL);
+}
+
+// static
+MessageLoop* MessageLoop::current() {
+  // TODO(darin): sadly, we cannot enable this yet since people call us even
+  // when they have no intention of using us.
+  // DCHECK(loop) << "Ouch, did you forget to initialize me?";
+  return lazy_tls_ptr.Pointer()->Get();
+}
+
+// static
+void MessageLoop::EnableHistogrammer(bool enable) {
+  enable_histogrammer_ = enable;
+}
+
+// static
+bool MessageLoop::InitMessagePumpForUIFactory(MessagePumpFactory* factory) {
+  if (message_pump_for_ui_factory_)
+    return false;
+
+  message_pump_for_ui_factory_ = factory;
+  return true;
+}
+
+// static
+scoped_ptr<MessagePump> MessageLoop::CreateMessagePumpForType(Type type) {
+// TODO(rvargas): Get rid of the OS guards.
+#if defined(USE_GLIB) && !defined(OS_NACL)
+  typedef MessagePumpGlib MessagePumpForUI;
+#elif defined(OS_LINUX) && !defined(OS_NACL)
+  typedef MessagePumpLibevent MessagePumpForUI;
+#endif
+
+#if defined(OS_IOS) || defined(OS_MACOSX)
+#define MESSAGE_PUMP_UI scoped_ptr<MessagePump>(MessagePumpMac::Create())
+#elif defined(OS_NACL)
+// Currently NaCl doesn't have a UI MessageLoop.
+// TODO(abarth): Figure out if we need this.
+#define MESSAGE_PUMP_UI scoped_ptr<MessagePump>()
+#else
+#define MESSAGE_PUMP_UI scoped_ptr<MessagePump>(new MessagePumpForUI())
+#endif
+
+#if defined(OS_MACOSX)
+  // Use an OS native runloop on Mac to support timer coalescing.
+  #define MESSAGE_PUMP_DEFAULT \
+      scoped_ptr<MessagePump>(new MessagePumpCFRunLoop())
+#else
+  #define MESSAGE_PUMP_DEFAULT scoped_ptr<MessagePump>(new MessagePumpDefault())
+#endif
+
+  if (type == MessageLoop::TYPE_UI) {
+    if (message_pump_for_ui_factory_)
+      return message_pump_for_ui_factory_();
+    return MESSAGE_PUMP_UI;
+  }
+  if (type == MessageLoop::TYPE_IO)
+    return scoped_ptr<MessagePump>(new MessagePumpForIO());
+
+#if defined(OS_ANDROID)
+  if (type == MessageLoop::TYPE_JAVA)
+    return scoped_ptr<MessagePump>(new MessagePumpForUI());
+#endif
+
+  DCHECK_EQ(MessageLoop::TYPE_DEFAULT, type);
+  return MESSAGE_PUMP_DEFAULT;
+}
+
+void MessageLoop::AddDestructionObserver(
+    DestructionObserver* destruction_observer) {
+  DCHECK_EQ(this, current());
+  destruction_observers_.AddObserver(destruction_observer);
+}
+
+void MessageLoop::RemoveDestructionObserver(
+    DestructionObserver* destruction_observer) {
+  DCHECK_EQ(this, current());
+  destruction_observers_.RemoveObserver(destruction_observer);
+}
+
+void MessageLoop::PostTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task) {
+  message_loop_proxy_->PostTask(from_here, task);
+}
+
+void MessageLoop::PostDelayedTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay) {
+  message_loop_proxy_->PostDelayedTask(from_here, task, delay);
+}
+
+void MessageLoop::PostNonNestableTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task) {
+  message_loop_proxy_->PostNonNestableTask(from_here, task);
+}
+
+void MessageLoop::PostNonNestableDelayedTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay) {
+  message_loop_proxy_->PostNonNestableDelayedTask(from_here, task, delay);
+}
+
+void MessageLoop::Run() {
+  DCHECK(pump_);
+  RunLoop run_loop;
+  run_loop.Run();
+}
+
+void MessageLoop::RunUntilIdle() {
+  DCHECK(pump_);
+  RunLoop run_loop;
+  run_loop.RunUntilIdle();
+}
+
+void MessageLoop::QuitWhenIdle() {
+  DCHECK_EQ(this, current());
+  if (run_loop_) {
+    run_loop_->quit_when_idle_received_ = true;
+  } else {
+    NOTREACHED() << "Must be inside Run to call Quit";
+  }
+}
+
+void MessageLoop::QuitNow() {
+  DCHECK_EQ(this, current());
+  if (run_loop_) {
+    pump_->Quit();
+  } else {
+    NOTREACHED() << "Must be inside Run to call Quit";
+  }
+}
+
+bool MessageLoop::IsType(Type type) const {
+  return type_ == type;
+}
+
+static void QuitCurrentWhenIdle() {
+  MessageLoop::current()->QuitWhenIdle();
+}
+
+// static
+Closure MessageLoop::QuitWhenIdleClosure() {
+  return Bind(&QuitCurrentWhenIdle);
+}
+
+void MessageLoop::SetNestableTasksAllowed(bool allowed) {
+  if (allowed) {
+    // Kick the native pump just in case we enter a OS-driven nested message
+    // loop.
+    pump_->ScheduleWork();
+  }
+  nestable_tasks_allowed_ = allowed;
+}
+
+bool MessageLoop::NestableTasksAllowed() const {
+  return nestable_tasks_allowed_;
+}
+
+bool MessageLoop::IsNested() {
+  return run_loop_->run_depth_ > 1;
+}
+
+void MessageLoop::AddTaskObserver(TaskObserver* task_observer) {
+  DCHECK_EQ(this, current());
+  task_observers_.AddObserver(task_observer);
+}
+
+void MessageLoop::RemoveTaskObserver(TaskObserver* task_observer) {
+  DCHECK_EQ(this, current());
+  task_observers_.RemoveObserver(task_observer);
+}
+
+bool MessageLoop::is_running() const {
+  DCHECK_EQ(this, current());
+  return run_loop_ != NULL;
+}
+
+bool MessageLoop::HasHighResolutionTasks() {
+  return incoming_task_queue_->HasHighResolutionTasks();
+}
+
+bool MessageLoop::IsIdleForTesting() {
+  // We only check the imcoming queue|, since we don't want to lock the work
+  // queue.
+  return incoming_task_queue_->IsIdleForTesting();
+}
+
+//------------------------------------------------------------------------------
+
+scoped_ptr<MessageLoop> MessageLoop::CreateUnbound(
+    Type type, MessagePumpFactoryCallback pump_factory) {
+  return make_scoped_ptr(new MessageLoop(type, pump_factory));
+}
+
+MessageLoop::MessageLoop(Type type, MessagePumpFactoryCallback pump_factory)
+    : type_(type),
+#if defined(OS_WIN)
+      pending_high_res_tasks_(0),
+      in_high_res_mode_(false),
+#endif
+      nestable_tasks_allowed_(true),
+#if defined(OS_WIN)
+      os_modal_loop_(false),
+#endif  // OS_WIN
+      pump_factory_(pump_factory),
+      message_histogram_(NULL),
+      run_loop_(NULL),
+      incoming_task_queue_(new internal::IncomingTaskQueue(this)),
+      message_loop_proxy_(
+          new internal::MessageLoopProxyImpl(incoming_task_queue_)) {
+  // If type is TYPE_CUSTOM non-null pump_factory must be given.
+  DCHECK_EQ(type_ == TYPE_CUSTOM, !pump_factory_.is_null());
+}
+
+void MessageLoop::BindToCurrentThread() {
+  DCHECK(!pump_);
+  if (!pump_factory_.is_null())
+    pump_ = pump_factory_.Run();
+  else
+    pump_ = CreateMessagePumpForType(type_);
+
+  DCHECK(!current()) << "should only have one message loop per thread";
+  lazy_tls_ptr.Pointer()->Set(this);
+
+  incoming_task_queue_->StartScheduling();
+  message_loop_proxy_->BindToCurrentThread();
+  thread_task_runner_handle_.reset(
+      new ThreadTaskRunnerHandle(message_loop_proxy_));
+}
+
+void MessageLoop::RunHandler() {
+  DCHECK_EQ(this, current());
+
+  StartHistogrammer();
+
+#if defined(OS_WIN)
+  if (run_loop_->dispatcher_ && type() == TYPE_UI) {
+    static_cast<MessagePumpForUI*>(pump_.get())->
+        RunWithDispatcher(this, run_loop_->dispatcher_);
+    return;
+  }
+#endif
+
+  pump_->Run(this);
+}
+
+bool MessageLoop::ProcessNextDelayedNonNestableTask() {
+  if (run_loop_->run_depth_ != 1)
+    return false;
+
+  if (deferred_non_nestable_work_queue_.empty())
+    return false;
+
+  PendingTask pending_task = deferred_non_nestable_work_queue_.front();
+  deferred_non_nestable_work_queue_.pop();
+
+  RunTask(pending_task);
+  return true;
+}
+
+void MessageLoop::RunTask(const PendingTask& pending_task) {
+  DCHECK(nestable_tasks_allowed_);
+
+#if defined(OS_WIN)
+  if (pending_task.is_high_res) {
+    pending_high_res_tasks_--;
+    CHECK_GE(pending_high_res_tasks_, 0);
+  }
+#endif
+
+  // Execute the task and assume the worst: It is probably not reentrant.
+  nestable_tasks_allowed_ = false;
+
+  HistogramEvent(kTaskRunEvent);
+
+  FOR_EACH_OBSERVER(TaskObserver, task_observers_,
+                    WillProcessTask(pending_task));
+  task_annotator_.RunTask(
+      "MessageLoop::PostTask", "MessageLoop::RunTask", pending_task);
+  FOR_EACH_OBSERVER(TaskObserver, task_observers_,
+                    DidProcessTask(pending_task));
+
+  nestable_tasks_allowed_ = true;
+}
+
+bool MessageLoop::DeferOrRunPendingTask(const PendingTask& pending_task) {
+  if (pending_task.nestable || run_loop_->run_depth_ == 1) {
+    RunTask(pending_task);
+    // Show that we ran a task (Note: a new one might arrive as a
+    // consequence!).
+    return true;
+  }
+
+  // We couldn't run the task now because we're in a nested message loop
+  // and the task isn't nestable.
+  deferred_non_nestable_work_queue_.push(pending_task);
+  return false;
+}
+
+void MessageLoop::AddToDelayedWorkQueue(const PendingTask& pending_task) {
+  // Move to the delayed work queue.
+  delayed_work_queue_.push(pending_task);
+}
+
+bool MessageLoop::DeletePendingTasks() {
+  bool did_work = !work_queue_.empty();
+  while (!work_queue_.empty()) {
+    PendingTask pending_task = work_queue_.front();
+    work_queue_.pop();
+    if (!pending_task.delayed_run_time.is_null()) {
+      // We want to delete delayed tasks in the same order in which they would
+      // normally be deleted in case of any funny dependencies between delayed
+      // tasks.
+      AddToDelayedWorkQueue(pending_task);
+    }
+  }
+  did_work |= !deferred_non_nestable_work_queue_.empty();
+  while (!deferred_non_nestable_work_queue_.empty()) {
+    deferred_non_nestable_work_queue_.pop();
+  }
+  did_work |= !delayed_work_queue_.empty();
+
+  // Historically, we always delete the task regardless of valgrind status. It's
+  // not completely clear why we want to leak them in the loops above.  This
+  // code is replicating legacy behavior, and should not be considered
+  // absolutely "correct" behavior.  See TODO above about deleting all tasks
+  // when it's safe.
+  while (!delayed_work_queue_.empty()) {
+    delayed_work_queue_.pop();
+  }
+  return did_work;
+}
+
+void MessageLoop::ReloadWorkQueue() {
+  // We can improve performance of our loading tasks from the incoming queue to
+  // |*work_queue| by waiting until the last minute (|*work_queue| is empty) to
+  // load. That reduces the number of locks-per-task significantly when our
+  // queues get large.
+  if (work_queue_.empty()) {
+#if defined(OS_WIN)
+    pending_high_res_tasks_ +=
+        incoming_task_queue_->ReloadWorkQueue(&work_queue_);
+#else
+    incoming_task_queue_->ReloadWorkQueue(&work_queue_);
+#endif
+  }
+}
+
+void MessageLoop::ScheduleWork() {
+  pump_->ScheduleWork();
+}
+
+//------------------------------------------------------------------------------
+// Method and data for histogramming events and actions taken by each instance
+// on each thread.
+
+void MessageLoop::StartHistogrammer() {
+#if !defined(OS_NACL)  // NaCl build has no metrics code.
+  if (enable_histogrammer_ && !message_histogram_
+      && StatisticsRecorder::IsActive()) {
+    DCHECK(!thread_name_.empty());
+    message_histogram_ = LinearHistogram::FactoryGetWithRangeDescription(
+        "MsgLoop:" + thread_name_,
+        kLeastNonZeroMessageId, kMaxMessageId,
+        kNumberOfDistinctMessagesDisplayed,
+        message_histogram_->kHexRangePrintingFlag,
+        event_descriptions_);
+  }
+#endif
+}
+
+void MessageLoop::HistogramEvent(int event) {
+#if !defined(OS_NACL)
+  if (message_histogram_)
+    message_histogram_->Add(event);
+#endif
+}
+
+bool MessageLoop::DoWork() {
+  if (!nestable_tasks_allowed_) {
+    // Task can't be executed right now.
+    return false;
+  }
+
+  for (;;) {
+    ReloadWorkQueue();
+    if (work_queue_.empty())
+      break;
+
+    // Execute oldest task.
+    do {
+      PendingTask pending_task = work_queue_.front();
+      work_queue_.pop();
+      if (!pending_task.delayed_run_time.is_null()) {
+        AddToDelayedWorkQueue(pending_task);
+        // If we changed the topmost task, then it is time to reschedule.
+        if (delayed_work_queue_.top().task.Equals(pending_task.task))
+          pump_->ScheduleDelayedWork(pending_task.delayed_run_time);
+      } else {
+        if (DeferOrRunPendingTask(pending_task))
+          return true;
+      }
+    } while (!work_queue_.empty());
+  }
+
+  // Nothing happened.
+  return false;
+}
+
+bool MessageLoop::DoDelayedWork(TimeTicks* next_delayed_work_time) {
+  if (!nestable_tasks_allowed_ || delayed_work_queue_.empty()) {
+    recent_time_ = *next_delayed_work_time = TimeTicks();
+    return false;
+  }
+
+  // When we "fall behind," there will be a lot of tasks in the delayed work
+  // queue that are ready to run.  To increase efficiency when we fall behind,
+  // we will only call Time::Now() intermittently, and then process all tasks
+  // that are ready to run before calling it again.  As a result, the more we
+  // fall behind (and have a lot of ready-to-run delayed tasks), the more
+  // efficient we'll be at handling the tasks.
+
+  TimeTicks next_run_time = delayed_work_queue_.top().delayed_run_time;
+  if (next_run_time > recent_time_) {
+    recent_time_ = TimeTicks::Now();  // Get a better view of Now();
+    if (next_run_time > recent_time_) {
+      *next_delayed_work_time = next_run_time;
+      return false;
+    }
+  }
+
+  PendingTask pending_task = delayed_work_queue_.top();
+  delayed_work_queue_.pop();
+
+  if (!delayed_work_queue_.empty())
+    *next_delayed_work_time = delayed_work_queue_.top().delayed_run_time;
+
+  return DeferOrRunPendingTask(pending_task);
+}
+
+bool MessageLoop::DoIdleWork() {
+  if (ProcessNextDelayedNonNestableTask())
+    return true;
+
+  if (run_loop_->quit_when_idle_received_)
+    pump_->Quit();
+
+  // When we return we will do a kernel wait for more tasks.
+#if defined(OS_WIN)
+  // On Windows we activate the high resolution timer so that the wait
+  // _if_ triggered by the timer happens with good resolution. If we don't
+  // do this the default resolution is 15ms which might not be acceptable
+  // for some tasks.
+  bool high_res = pending_high_res_tasks_ > 0;
+  if (high_res != in_high_res_mode_) {
+    in_high_res_mode_ = high_res;
+    Time::ActivateHighResolutionTimer(in_high_res_mode_);
+  }
+#endif
+  return false;
+}
+
+TimeTicks MessageLoop::GetNewlyAddedTaskDelay() {
+  return incoming_task_queue_->GetNewlyAddedTaskDelay();
+}
+
+void MessageLoop::DeleteSoonInternal(const tracked_objects::Location& from_here,
+                                     void(*deleter)(const void*),
+                                     const void* object) {
+  PostNonNestableTask(from_here, Bind(deleter, object));
+}
+
+void MessageLoop::ReleaseSoonInternal(
+    const tracked_objects::Location& from_here,
+    void(*releaser)(const void*),
+    const void* object) {
+  PostNonNestableTask(from_here, Bind(releaser, object));
+}
+
+#if !defined(OS_NACL)
+//------------------------------------------------------------------------------
+// MessageLoopForUI
+
+#if defined(OS_ANDROID)
+void MessageLoopForUI::Start() {
+  // No Histogram support for UI message loop as it is managed by Java side
+  static_cast<MessagePumpForUI*>(pump_.get())->Start(this);
+}
+#endif
+
+#if defined(OS_IOS)
+void MessageLoopForUI::Attach() {
+  static_cast<MessagePumpUIApplication*>(pump_.get())->Attach(this);
+}
+#endif
+
+#if defined(USE_OZONE) || (defined(USE_X11) && !defined(USE_GLIB))
+bool MessageLoopForUI::WatchFileDescriptor(
+    int fd,
+    bool persistent,
+    MessagePumpLibevent::Mode mode,
+    MessagePumpLibevent::FileDescriptorWatcher *controller,
+    MessagePumpLibevent::Watcher *delegate) {
+  return static_cast<MessagePumpLibevent*>(pump_.get())->WatchFileDescriptor(
+      fd,
+      persistent,
+      mode,
+      controller,
+      delegate);
+}
+#endif
+
+#endif  // !defined(OS_NACL)
+
+//------------------------------------------------------------------------------
+// MessageLoopForIO
+
+#if !defined(OS_NACL_SFI)
+void MessageLoopForIO::AddIOObserver(
+    MessageLoopForIO::IOObserver* io_observer) {
+  ToPumpIO(pump_.get())->AddIOObserver(io_observer);
+}
+
+void MessageLoopForIO::RemoveIOObserver(
+    MessageLoopForIO::IOObserver* io_observer) {
+  ToPumpIO(pump_.get())->RemoveIOObserver(io_observer);
+}
+
+#if defined(OS_WIN)
+void MessageLoopForIO::RegisterIOHandler(HANDLE file, IOHandler* handler) {
+  ToPumpIO(pump_.get())->RegisterIOHandler(file, handler);
+}
+
+bool MessageLoopForIO::RegisterJobObject(HANDLE job, IOHandler* handler) {
+  return ToPumpIO(pump_.get())->RegisterJobObject(job, handler);
+}
+
+bool MessageLoopForIO::WaitForIOCompletion(DWORD timeout, IOHandler* filter) {
+  return ToPumpIO(pump_.get())->WaitForIOCompletion(timeout, filter);
+}
+#elif defined(OS_POSIX)
+bool MessageLoopForIO::WatchFileDescriptor(int fd,
+                                           bool persistent,
+                                           Mode mode,
+                                           FileDescriptorWatcher* controller,
+                                           Watcher* delegate) {
+  return ToPumpIO(pump_.get())->WatchFileDescriptor(
+      fd,
+      persistent,
+      mode,
+      controller,
+      delegate);
+}
+#endif
+
+#endif  // !defined(OS_NACL_SFI)
+
+}  // namespace base
diff --git a/base/message_loop/message_loop.h b/base/message_loop/message_loop.h
new file mode 100644
index 0000000..2d67fe5
--- /dev/null
+++ b/base/message_loop/message_loop.h
@@ -0,0 +1,693 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MESSAGE_LOOP_MESSAGE_LOOP_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_LOOP_H_
+
+#include <queue>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/callback_forward.h"
+#include "base/debug/task_annotator.h"
+#include "base/location.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/incoming_task_queue.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "base/message_loop/message_loop_proxy_impl.h"
+#include "base/message_loop/message_pump.h"
+#include "base/message_loop/timer_slack.h"
+#include "base/observer_list.h"
+#include "base/pending_task.h"
+#include "base/sequenced_task_runner_helpers.h"
+#include "base/synchronization/lock.h"
+#include "base/time/time.h"
+#include "base/tracking_info.h"
+
+// TODO(sky): these includes should not be necessary. Nuke them.
+#if defined(OS_WIN)
+#include "base/message_loop/message_pump_win.h"
+#elif defined(OS_IOS)
+#include "base/message_loop/message_pump_io_ios.h"
+#elif defined(OS_POSIX)
+#include "base/message_loop/message_pump_libevent.h"
+#endif
+
+namespace base {
+
+class HistogramBase;
+class RunLoop;
+class ThreadTaskRunnerHandle;
+class WaitableEvent;
+
+// A MessageLoop is used to process events for a particular thread.  There is
+// at most one MessageLoop instance per thread.
+//
+// Events include at a minimum Task instances submitted to PostTask and its
+// variants.  Depending on the type of message pump used by the MessageLoop
+// other events such as UI messages may be processed.  On Windows APC calls (as
+// time permits) and signals sent to a registered set of HANDLEs may also be
+// processed.
+//
+// NOTE: Unless otherwise specified, a MessageLoop's methods may only be called
+// on the thread where the MessageLoop's Run method executes.
+//
+// NOTE: MessageLoop has task reentrancy protection.  This means that if a
+// task is being processed, a second task cannot start until the first task is
+// finished.  Reentrancy can happen when processing a task, and an inner
+// message pump is created.  That inner pump then processes native messages
+// which could implicitly start an inner task.  Inner message pumps are created
+// with dialogs (DialogBox), common dialogs (GetOpenFileName), OLE functions
+// (DoDragDrop), printer functions (StartDoc) and *many* others.
+//
+// Sample workaround when inner task processing is needed:
+//   HRESULT hr;
+//   {
+//     MessageLoop::ScopedNestableTaskAllower allow(MessageLoop::current());
+//     hr = DoDragDrop(...); // Implicitly runs a modal message loop.
+//   }
+//   // Process |hr| (the result returned by DoDragDrop()).
+//
+// Please be SURE your task is reentrant (nestable) and all global variables
+// are stable and accessible before calling SetNestableTasksAllowed(true).
+//
+class BASE_EXPORT MessageLoop : public MessagePump::Delegate {
+ public:
+  // A MessageLoop has a particular type, which indicates the set of
+  // asynchronous events it may process in addition to tasks and timers.
+  //
+  // TYPE_DEFAULT
+  //   This type of ML only supports tasks and timers.
+  //
+  // TYPE_UI
+  //   This type of ML also supports native UI events (e.g., Windows messages).
+  //   See also MessageLoopForUI.
+  //
+  // TYPE_IO
+  //   This type of ML also supports asynchronous IO.  See also
+  //   MessageLoopForIO.
+  //
+  // TYPE_JAVA
+  //   This type of ML is backed by a Java message handler which is responsible
+  //   for running the tasks added to the ML. This is only for use on Android.
+  //   TYPE_JAVA behaves in essence like TYPE_UI, except during construction
+  //   where it does not use the main thread specific pump factory.
+  //
+  // TYPE_CUSTOM
+  //   MessagePump was supplied to constructor.
+  //
+  enum Type {
+    TYPE_DEFAULT,
+    TYPE_UI,
+    TYPE_CUSTOM,
+    TYPE_IO,
+#if defined(OS_ANDROID)
+    TYPE_JAVA,
+#endif  // defined(OS_ANDROID)
+  };
+
+  // Normally, it is not necessary to instantiate a MessageLoop.  Instead, it
+  // is typical to make use of the current thread's MessageLoop instance.
+  explicit MessageLoop(Type type = TYPE_DEFAULT);
+  // Creates a TYPE_CUSTOM MessageLoop with the supplied MessagePump, which must
+  // be non-NULL.
+  explicit MessageLoop(scoped_ptr<MessagePump> pump);
+
+  ~MessageLoop() override;
+
+  // Returns the MessageLoop object for the current thread, or null if none.
+  static MessageLoop* current();
+
+  static void EnableHistogrammer(bool enable_histogrammer);
+
+  typedef scoped_ptr<MessagePump> (MessagePumpFactory)();
+  // Uses the given base::MessagePumpForUIFactory to override the default
+  // MessagePump implementation for 'TYPE_UI'. Returns true if the factory
+  // was successfully registered.
+  static bool InitMessagePumpForUIFactory(MessagePumpFactory* factory);
+
+  // Creates the default MessagePump based on |type|. Caller owns return
+  // value.
+  static scoped_ptr<MessagePump> CreateMessagePumpForType(Type type);
+  // A DestructionObserver is notified when the current MessageLoop is being
+  // destroyed.  These observers are notified prior to MessageLoop::current()
+  // being changed to return NULL.  This gives interested parties the chance to
+  // do final cleanup that depends on the MessageLoop.
+  //
+  // NOTE: Any tasks posted to the MessageLoop during this notification will
+  // not be run.  Instead, they will be deleted.
+  //
+  class BASE_EXPORT DestructionObserver {
+   public:
+    virtual void WillDestroyCurrentMessageLoop() = 0;
+
+   protected:
+    virtual ~DestructionObserver();
+  };
+
+  // Add a DestructionObserver, which will start receiving notifications
+  // immediately.
+  void AddDestructionObserver(DestructionObserver* destruction_observer);
+
+  // Remove a DestructionObserver.  It is safe to call this method while a
+  // DestructionObserver is receiving a notification callback.
+  void RemoveDestructionObserver(DestructionObserver* destruction_observer);
+
+  // NOTE: Deprecated; prefer task_runner() and the TaskRunner interfaces.
+  // TODO(skyostil): Remove these functions (crbug.com/465354).
+  //
+  // The "PostTask" family of methods call the task's Run method asynchronously
+  // from within a message loop at some point in the future.
+  //
+  // With the PostTask variant, tasks are invoked in FIFO order, inter-mixed
+  // with normal UI or IO event processing.  With the PostDelayedTask variant,
+  // tasks are called after at least approximately 'delay_ms' have elapsed.
+  //
+  // The NonNestable variants work similarly except that they promise never to
+  // dispatch the task from a nested invocation of MessageLoop::Run.  Instead,
+  // such tasks get deferred until the top-most MessageLoop::Run is executing.
+  //
+  // The MessageLoop takes ownership of the Task, and deletes it after it has
+  // been Run().
+  //
+  // PostTask(from_here, task) is equivalent to
+  // PostDelayedTask(from_here, task, 0).
+  //
+  // NOTE: These methods may be called on any thread.  The Task will be invoked
+  // on the thread that executes MessageLoop::Run().
+  void PostTask(const tracked_objects::Location& from_here,
+                const Closure& task);
+
+  void PostDelayedTask(const tracked_objects::Location& from_here,
+                       const Closure& task,
+                       TimeDelta delay);
+
+  void PostNonNestableTask(const tracked_objects::Location& from_here,
+                           const Closure& task);
+
+  void PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
+                                  const Closure& task,
+                                  TimeDelta delay);
+
+  // A variant on PostTask that deletes the given object.  This is useful
+  // if the object needs to live until the next run of the MessageLoop (for
+  // example, deleting a RenderProcessHost from within an IPC callback is not
+  // good).
+  //
+  // NOTE: This method may be called on any thread.  The object will be deleted
+  // on the thread that executes MessageLoop::Run().
+  template <class T>
+  void DeleteSoon(const tracked_objects::Location& from_here, const T* object) {
+    base::subtle::DeleteHelperInternal<T, void>::DeleteViaSequencedTaskRunner(
+        this, from_here, object);
+  }
+
+  // A variant on PostTask that releases the given reference counted object
+  // (by calling its Release method).  This is useful if the object needs to
+  // live until the next run of the MessageLoop, or if the object needs to be
+  // released on a particular thread.
+  //
+  // A common pattern is to manually increment the object's reference count
+  // (AddRef), clear the pointer, then issue a ReleaseSoon.  The reference count
+  // is incremented manually to ensure clearing the pointer does not trigger a
+  // delete and to account for the upcoming decrement (ReleaseSoon).  For
+  // example:
+  //
+  // scoped_refptr<Foo> foo = ...
+  // foo->AddRef();
+  // Foo* raw_foo = foo.get();
+  // foo = NULL;
+  // message_loop->ReleaseSoon(raw_foo);
+  //
+  // NOTE: This method may be called on any thread.  The object will be
+  // released (and thus possibly deleted) on the thread that executes
+  // MessageLoop::Run().  If this is not the same as the thread that calls
+  // ReleaseSoon(FROM_HERE, ), then T MUST inherit from
+  // RefCountedThreadSafe<T>!
+  template <class T>
+  void ReleaseSoon(const tracked_objects::Location& from_here,
+                   const T* object) {
+    base::subtle::ReleaseHelperInternal<T, void>::ReleaseViaSequencedTaskRunner(
+        this, from_here, object);
+  }
+
+  // Deprecated: use RunLoop instead.
+  // Run the message loop.
+  void Run();
+
+  // Deprecated: use RunLoop instead.
+  // Process all pending tasks, windows messages, etc., but don't wait/sleep.
+  // Return as soon as all items that can be run are taken care of.
+  void RunUntilIdle();
+
+  // TODO(jbates) remove this. crbug.com/131220. See QuitWhenIdle().
+  void Quit() { QuitWhenIdle(); }
+
+  // Deprecated: use RunLoop instead.
+  //
+  // Signals the Run method to return when it becomes idle. It will continue to
+  // process pending messages and future messages as long as they are enqueued.
+  // Warning: if the MessageLoop remains busy, it may never quit. Only use this
+  // Quit method when looping procedures (such as web pages) have been shut
+  // down.
+  //
+  // This method may only be called on the same thread that called Run, and Run
+  // must still be on the call stack.
+  //
+  // Use QuitClosure variants if you need to Quit another thread's MessageLoop,
+  // but note that doing so is fairly dangerous if the target thread makes
+  // nested calls to MessageLoop::Run.  The problem being that you won't know
+  // which nested run loop you are quitting, so be careful!
+  void QuitWhenIdle();
+
+  // Deprecated: use RunLoop instead.
+  //
+  // This method is a variant of Quit, that does not wait for pending messages
+  // to be processed before returning from Run.
+  void QuitNow();
+
+  // TODO(jbates) remove this. crbug.com/131220. See QuitWhenIdleClosure().
+  static Closure QuitClosure() { return QuitWhenIdleClosure(); }
+
+  // Deprecated: use RunLoop instead.
+  // Construct a Closure that will call QuitWhenIdle(). Useful to schedule an
+  // arbitrary MessageLoop to QuitWhenIdle.
+  static Closure QuitWhenIdleClosure();
+
+  // Set the timer slack for this message loop.
+  void SetTimerSlack(TimerSlack timer_slack) {
+    pump_->SetTimerSlack(timer_slack);
+  }
+
+  // Returns true if this loop is |type|. This allows subclasses (especially
+  // those in tests) to specialize how they are identified.
+  virtual bool IsType(Type type) const;
+
+  // Returns the type passed to the constructor.
+  Type type() const { return type_; }
+
+  // Optional call to connect the thread name with this loop.
+  void set_thread_name(const std::string& thread_name) {
+    DCHECK(thread_name_.empty()) << "Should not rename this thread!";
+    thread_name_ = thread_name;
+  }
+  const std::string& thread_name() const { return thread_name_; }
+
+  // Gets the message loop proxy associated with this message loop.
+  //
+  // NOTE: Deprecated; prefer task_runner() and the TaskRunner interfaces
+  scoped_refptr<MessageLoopProxy> message_loop_proxy() {
+    return message_loop_proxy_;
+  }
+
+  // Gets the TaskRunner associated with this message loop.
+  // TODO(skyostil): Change this to return a const reference to a refptr
+  // once the internal type matches what is being returned (crbug.com/465354).
+  scoped_refptr<SingleThreadTaskRunner> task_runner() {
+    return message_loop_proxy_;
+  }
+
+  // Enables or disables the recursive task processing. This happens in the case
+  // of recursive message loops. Some unwanted message loop may occurs when
+  // using common controls or printer functions. By default, recursive task
+  // processing is disabled.
+  //
+  // Please utilize |ScopedNestableTaskAllower| instead of calling these methods
+  // directly.  In general nestable message loops are to be avoided.  They are
+  // dangerous and difficult to get right, so please use with extreme caution.
+  //
+  // The specific case where tasks get queued is:
+  // - The thread is running a message loop.
+  // - It receives a task #1 and execute it.
+  // - The task #1 implicitly start a message loop, like a MessageBox in the
+  //   unit test. This can also be StartDoc or GetSaveFileName.
+  // - The thread receives a task #2 before or while in this second message
+  //   loop.
+  // - With NestableTasksAllowed set to true, the task #2 will run right away.
+  //   Otherwise, it will get executed right after task #1 completes at "thread
+  //   message loop level".
+  void SetNestableTasksAllowed(bool allowed);
+  bool NestableTasksAllowed() const;
+
+  // Enables nestable tasks on |loop| while in scope.
+  class ScopedNestableTaskAllower {
+   public:
+    explicit ScopedNestableTaskAllower(MessageLoop* loop)
+        : loop_(loop),
+          old_state_(loop_->NestableTasksAllowed()) {
+      loop_->SetNestableTasksAllowed(true);
+    }
+    ~ScopedNestableTaskAllower() {
+      loop_->SetNestableTasksAllowed(old_state_);
+    }
+
+   private:
+    MessageLoop* loop_;
+    bool old_state_;
+  };
+
+  // Returns true if we are currently running a nested message loop.
+  bool IsNested();
+
+  // A TaskObserver is an object that receives task notifications from the
+  // MessageLoop.
+  //
+  // NOTE: A TaskObserver implementation should be extremely fast!
+  class BASE_EXPORT TaskObserver {
+   public:
+    TaskObserver();
+
+    // This method is called before processing a task.
+    virtual void WillProcessTask(const PendingTask& pending_task) = 0;
+
+    // This method is called after processing a task.
+    virtual void DidProcessTask(const PendingTask& pending_task) = 0;
+
+   protected:
+    virtual ~TaskObserver();
+  };
+
+  // These functions can only be called on the same thread that |this| is
+  // running on.
+  void AddTaskObserver(TaskObserver* task_observer);
+  void RemoveTaskObserver(TaskObserver* task_observer);
+
+#if defined(OS_WIN)
+  void set_os_modal_loop(bool os_modal_loop) {
+    os_modal_loop_ = os_modal_loop;
+  }
+
+  bool os_modal_loop() const {
+    return os_modal_loop_;
+  }
+#endif  // OS_WIN
+
+  // Can only be called from the thread that owns the MessageLoop.
+  bool is_running() const;
+
+  // Returns true if the message loop has high resolution timers enabled.
+  // Provided for testing.
+  bool HasHighResolutionTasks();
+
+  // Returns true if the message loop is "idle". Provided for testing.
+  bool IsIdleForTesting();
+
+  // Returns the TaskAnnotator which is used to add debug information to posted
+  // tasks.
+  debug::TaskAnnotator* task_annotator() { return &task_annotator_; }
+
+  // Runs the specified PendingTask.
+  void RunTask(const PendingTask& pending_task);
+
+  //----------------------------------------------------------------------------
+ protected:
+  scoped_ptr<MessagePump> pump_;
+
+ private:
+  friend class RunLoop;
+  friend class internal::IncomingTaskQueue;
+  friend class ScheduleWorkTest;
+  friend class Thread;
+
+  using MessagePumpFactoryCallback = Callback<scoped_ptr<MessagePump>()>;
+
+  // Creates a MessageLoop without binding to a thread.
+  // If |type| is TYPE_CUSTOM non-null |pump_factory| must be also given
+  // to create a message pump for this message loop.  Otherwise a default
+  // message pump for the |type| is created.
+  //
+  // It is valid to call this to create a new message loop on one thread,
+  // and then pass it to the thread where the message loop actually runs.
+  // The message loop's BindToCurrentThread() method must be called on the
+  // thread the message loop runs on, before calling Run().
+  // Before BindToCurrentThread() is called only Post*Task() functions can
+  // be called on the message loop.
+  scoped_ptr<MessageLoop> CreateUnbound(
+      Type type,
+      MessagePumpFactoryCallback pump_factory);
+
+  // Common private constructor. Other constructors delegate the initialization
+  // to this constructor.
+  MessageLoop(Type type, MessagePumpFactoryCallback pump_factory);
+
+  // Configure various members and bind this message loop to the current thread.
+  void BindToCurrentThread();
+
+  // Invokes the actual run loop using the message pump.
+  void RunHandler();
+
+  // Called to process any delayed non-nestable tasks.
+  bool ProcessNextDelayedNonNestableTask();
+
+  // Calls RunTask or queues the pending_task on the deferred task list if it
+  // cannot be run right now.  Returns true if the task was run.
+  bool DeferOrRunPendingTask(const PendingTask& pending_task);
+
+  // Adds the pending task to delayed_work_queue_.
+  void AddToDelayedWorkQueue(const PendingTask& pending_task);
+
+  // Delete tasks that haven't run yet without running them.  Used in the
+  // destructor to make sure all the task's destructors get called.  Returns
+  // true if some work was done.
+  bool DeletePendingTasks();
+
+  // Loads tasks from the incoming queue to |work_queue_| if the latter is
+  // empty.
+  void ReloadWorkQueue();
+
+  // Wakes up the message pump. Can be called on any thread. The caller is
+  // responsible for synchronizing ScheduleWork() calls.
+  void ScheduleWork();
+
+  // Start recording histogram info about events and action IF it was enabled
+  // and IF the statistics recorder can accept a registration of our histogram.
+  void StartHistogrammer();
+
+  // Add occurrence of event to our histogram, so that we can see what is being
+  // done in a specific MessageLoop instance (i.e., specific thread).
+  // If message_histogram_ is NULL, this is a no-op.
+  void HistogramEvent(int event);
+
+  // MessagePump::Delegate methods:
+  bool DoWork() override;
+  bool DoDelayedWork(TimeTicks* next_delayed_work_time) override;
+  bool DoIdleWork() override;
+  TimeTicks GetNewlyAddedTaskDelay() override;
+
+  const Type type_;
+
+  // A list of tasks that need to be processed by this instance.  Note that
+  // this queue is only accessed (push/pop) by our current thread.
+  TaskQueue work_queue_;
+
+#if defined(OS_WIN)
+  // How many high resolution tasks are in the pending task queue. This value
+  // increases by N every time we call ReloadWorkQueue() and decreases by 1
+  // every time we call RunTask() if the task needs a high resolution timer.
+  int pending_high_res_tasks_;
+  // Tracks if we have requested high resolution timers. Its only use is to
+  // turn off the high resolution timer upon loop destruction.
+  bool in_high_res_mode_;
+#endif
+
+  // Contains delayed tasks, sorted by their 'delayed_run_time' property.
+  DelayedTaskQueue delayed_work_queue_;
+
+  // A recent snapshot of Time::Now(), used to check delayed_work_queue_.
+  TimeTicks recent_time_;
+
+  // A queue of non-nestable tasks that we had to defer because when it came
+  // time to execute them we were in a nested message loop.  They will execute
+  // once we're out of nested message loops.
+  TaskQueue deferred_non_nestable_work_queue_;
+
+  ObserverList<DestructionObserver> destruction_observers_;
+
+  // A recursion block that prevents accidentally running additional tasks when
+  // insider a (accidentally induced?) nested message pump.
+  bool nestable_tasks_allowed_;
+
+#if defined(OS_WIN)
+  // Should be set to true before calling Windows APIs like TrackPopupMenu, etc
+  // which enter a modal message loop.
+  bool os_modal_loop_;
+#endif
+
+  // pump_factory_.Run() is called to create a message pump for this loop
+  // if type_ is TYPE_CUSTOM and pump_ is null.
+  MessagePumpFactoryCallback pump_factory_;
+
+  std::string thread_name_;
+  // A profiling histogram showing the counts of various messages and events.
+  HistogramBase* message_histogram_;
+
+  RunLoop* run_loop_;
+
+  ObserverList<TaskObserver> task_observers_;
+
+  debug::TaskAnnotator task_annotator_;
+
+  scoped_refptr<internal::IncomingTaskQueue> incoming_task_queue_;
+
+  // The message loop proxy associated with this message loop.
+  scoped_refptr<internal::MessageLoopProxyImpl> message_loop_proxy_;
+  scoped_ptr<ThreadTaskRunnerHandle> thread_task_runner_handle_;
+
+  template <class T, class R> friend class base::subtle::DeleteHelperInternal;
+  template <class T, class R> friend class base::subtle::ReleaseHelperInternal;
+
+  void DeleteSoonInternal(const tracked_objects::Location& from_here,
+                          void(*deleter)(const void*),
+                          const void* object);
+  void ReleaseSoonInternal(const tracked_objects::Location& from_here,
+                           void(*releaser)(const void*),
+                           const void* object);
+
+  DISALLOW_COPY_AND_ASSIGN(MessageLoop);
+};
+
+#if !defined(OS_NACL)
+
+//-----------------------------------------------------------------------------
+// MessageLoopForUI extends MessageLoop with methods that are particular to a
+// MessageLoop instantiated with TYPE_UI.
+//
+// This class is typically used like so:
+//   MessageLoopForUI::current()->...call some method...
+//
+class BASE_EXPORT MessageLoopForUI : public MessageLoop {
+ public:
+  MessageLoopForUI() : MessageLoop(TYPE_UI) {
+  }
+
+  // Returns the MessageLoopForUI of the current thread.
+  static MessageLoopForUI* current() {
+    MessageLoop* loop = MessageLoop::current();
+    DCHECK(loop);
+    DCHECK_EQ(MessageLoop::TYPE_UI, loop->type());
+    return static_cast<MessageLoopForUI*>(loop);
+  }
+
+  static bool IsCurrent() {
+    MessageLoop* loop = MessageLoop::current();
+    return loop && loop->type() == MessageLoop::TYPE_UI;
+  }
+
+#if defined(OS_IOS)
+  // On iOS, the main message loop cannot be Run().  Instead call Attach(),
+  // which connects this MessageLoop to the UI thread's CFRunLoop and allows
+  // PostTask() to work.
+  void Attach();
+#endif
+
+#if defined(OS_ANDROID)
+  // On Android, the UI message loop is handled by Java side. So Run() should
+  // never be called. Instead use Start(), which will forward all the native UI
+  // events to the Java message loop.
+  void Start();
+#endif
+
+#if defined(USE_OZONE) || (defined(USE_X11) && !defined(USE_GLIB))
+  // Please see MessagePumpLibevent for definition.
+  bool WatchFileDescriptor(
+      int fd,
+      bool persistent,
+      MessagePumpLibevent::Mode mode,
+      MessagePumpLibevent::FileDescriptorWatcher* controller,
+      MessagePumpLibevent::Watcher* delegate);
+#endif
+};
+
+// Do not add any member variables to MessageLoopForUI!  This is important b/c
+// MessageLoopForUI is often allocated via MessageLoop(TYPE_UI).  Any extra
+// data that you need should be stored on the MessageLoop's pump_ instance.
+COMPILE_ASSERT(sizeof(MessageLoop) == sizeof(MessageLoopForUI),
+               MessageLoopForUI_should_not_have_extra_member_variables);
+
+#endif  // !defined(OS_NACL)
+
+//-----------------------------------------------------------------------------
+// MessageLoopForIO extends MessageLoop with methods that are particular to a
+// MessageLoop instantiated with TYPE_IO.
+//
+// This class is typically used like so:
+//   MessageLoopForIO::current()->...call some method...
+//
+class BASE_EXPORT MessageLoopForIO : public MessageLoop {
+ public:
+  MessageLoopForIO() : MessageLoop(TYPE_IO) {
+  }
+
+  // Returns the MessageLoopForIO of the current thread.
+  static MessageLoopForIO* current() {
+    MessageLoop* loop = MessageLoop::current();
+    DCHECK_EQ(MessageLoop::TYPE_IO, loop->type());
+    return static_cast<MessageLoopForIO*>(loop);
+  }
+
+  static bool IsCurrent() {
+    MessageLoop* loop = MessageLoop::current();
+    return loop && loop->type() == MessageLoop::TYPE_IO;
+  }
+
+#if !defined(OS_NACL_SFI)
+
+#if defined(OS_WIN)
+  typedef MessagePumpForIO::IOHandler IOHandler;
+  typedef MessagePumpForIO::IOContext IOContext;
+  typedef MessagePumpForIO::IOObserver IOObserver;
+#elif defined(OS_IOS)
+  typedef MessagePumpIOSForIO::Watcher Watcher;
+  typedef MessagePumpIOSForIO::FileDescriptorWatcher
+      FileDescriptorWatcher;
+  typedef MessagePumpIOSForIO::IOObserver IOObserver;
+
+  enum Mode {
+    WATCH_READ = MessagePumpIOSForIO::WATCH_READ,
+    WATCH_WRITE = MessagePumpIOSForIO::WATCH_WRITE,
+    WATCH_READ_WRITE = MessagePumpIOSForIO::WATCH_READ_WRITE
+  };
+#elif defined(OS_POSIX)
+  typedef MessagePumpLibevent::Watcher Watcher;
+  typedef MessagePumpLibevent::FileDescriptorWatcher
+      FileDescriptorWatcher;
+  typedef MessagePumpLibevent::IOObserver IOObserver;
+
+  enum Mode {
+    WATCH_READ = MessagePumpLibevent::WATCH_READ,
+    WATCH_WRITE = MessagePumpLibevent::WATCH_WRITE,
+    WATCH_READ_WRITE = MessagePumpLibevent::WATCH_READ_WRITE
+  };
+#endif
+
+  void AddIOObserver(IOObserver* io_observer);
+  void RemoveIOObserver(IOObserver* io_observer);
+
+#if defined(OS_WIN)
+  // Please see MessagePumpWin for definitions of these methods.
+  void RegisterIOHandler(HANDLE file, IOHandler* handler);
+  bool RegisterJobObject(HANDLE job, IOHandler* handler);
+  bool WaitForIOCompletion(DWORD timeout, IOHandler* filter);
+#elif defined(OS_POSIX)
+  // Please see MessagePumpIOSForIO/MessagePumpLibevent for definition.
+  bool WatchFileDescriptor(int fd,
+                           bool persistent,
+                           Mode mode,
+                           FileDescriptorWatcher* controller,
+                           Watcher* delegate);
+#endif  // defined(OS_IOS) || defined(OS_POSIX)
+#endif  // !defined(OS_NACL_SFI)
+};
+
+// Do not add any member variables to MessageLoopForIO!  This is important b/c
+// MessageLoopForIO is often allocated via MessageLoop(TYPE_IO).  Any extra
+// data that you need should be stored on the MessageLoop's pump_ instance.
+COMPILE_ASSERT(sizeof(MessageLoop) == sizeof(MessageLoopForIO),
+               MessageLoopForIO_should_not_have_extra_member_variables);
+
+}  // namespace base
+
+#endif  // BASE_MESSAGE_LOOP_MESSAGE_LOOP_H_
diff --git a/base/message_loop/message_loop_proxy.cc b/base/message_loop/message_loop_proxy.cc
new file mode 100644
index 0000000..e5f0142
--- /dev/null
+++ b/base/message_loop/message_loop_proxy.cc
@@ -0,0 +1,17 @@
+// Copyright (c) 2012 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/message_loop/message_loop_proxy.h"
+
+#include "base/bind.h"
+
+namespace base {
+
+MessageLoopProxy::MessageLoopProxy() {
+}
+
+MessageLoopProxy::~MessageLoopProxy() {
+}
+
+}  // namespace base
diff --git a/base/message_loop/message_loop_proxy.h b/base/message_loop/message_loop_proxy.h
new file mode 100644
index 0000000..d5ecc04
--- /dev/null
+++ b/base/message_loop/message_loop_proxy.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2012 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_MESSAGE_LOOP_MESSAGE_LOOP_PROXY_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_LOOP_PROXY_H_
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "base/single_thread_task_runner.h"
+
+// MessageLoopProxy is deprecated. Code should prefer to depend on TaskRunner
+// (or the various specializations) for passing task runners around, and should
+// use ThreadTaskRunnerHandle::Get() to get the thread's associated task runner.
+//
+// See http://crbug.com/391045 for more details.
+// Example for these changes:
+//
+// base::MessageLoopProxy::current() -> base::ThreadTaskRunnerHandle::Get()
+// scoped_refptr<base::MessageLoopProxy> ->
+//     scoped_refptr<base::SingleThreadTaskRunner>
+// base::MessageLoopProxy -> base::SingleThreadTaskRunner
+
+namespace base {
+
+// This class provides a thread-safe refcounted interface to the Post* methods
+// of a message loop. This class can outlive the target message loop.
+// MessageLoopProxy objects are constructed automatically for all MessageLoops.
+// So, to access them, you can use any of the following:
+//   Thread::message_loop_proxy()
+//   MessageLoop::current()->message_loop_proxy()
+//   MessageLoopProxy::current()
+//
+// TODO(akalin): Now that we have the *TaskRunner interfaces, we can
+// merge this with MessageLoopProxyImpl.
+class BASE_EXPORT MessageLoopProxy : public SingleThreadTaskRunner {
+ public:
+  // Gets the MessageLoopProxy for the current message loop, creating one if
+  // needed.
+  static scoped_refptr<MessageLoopProxy> current();
+
+ protected:
+  MessageLoopProxy();
+  ~MessageLoopProxy() override;
+};
+
+}  // namespace base
+
+#endif  // BASE_MESSAGE_LOOP_MESSAGE_LOOP_PROXY_H_
diff --git a/base/message_loop/message_loop_proxy_impl.cc b/base/message_loop/message_loop_proxy_impl.cc
new file mode 100644
index 0000000..580620d
--- /dev/null
+++ b/base/message_loop/message_loop_proxy_impl.cc
@@ -0,0 +1,61 @@
+// Copyright (c) 2012 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/message_loop/message_loop_proxy_impl.h"
+
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/message_loop/incoming_task_queue.h"
+#include "base/message_loop/message_loop.h"
+
+namespace base {
+namespace internal {
+
+MessageLoopProxyImpl::MessageLoopProxyImpl(
+    scoped_refptr<IncomingTaskQueue> incoming_queue)
+    : incoming_queue_(incoming_queue),
+      valid_thread_id_(kInvalidThreadId) {
+}
+
+void MessageLoopProxyImpl::BindToCurrentThread() {
+  AutoLock lock(valid_thread_id_lock_);
+  DCHECK_EQ(kInvalidThreadId, valid_thread_id_);
+  valid_thread_id_ = PlatformThread::CurrentId();
+}
+
+bool MessageLoopProxyImpl::PostDelayedTask(
+    const tracked_objects::Location& from_here,
+    const base::Closure& task,
+    base::TimeDelta delay) {
+  DCHECK(!task.is_null()) << from_here.ToString();
+  return incoming_queue_->AddToIncomingQueue(from_here, task, delay, true);
+}
+
+bool MessageLoopProxyImpl::PostNonNestableDelayedTask(
+    const tracked_objects::Location& from_here,
+    const base::Closure& task,
+    base::TimeDelta delay) {
+  DCHECK(!task.is_null()) << from_here.ToString();
+  return incoming_queue_->AddToIncomingQueue(from_here, task, delay, false);
+}
+
+bool MessageLoopProxyImpl::RunsTasksOnCurrentThread() const {
+  AutoLock lock(valid_thread_id_lock_);
+  return valid_thread_id_ == PlatformThread::CurrentId();
+}
+
+MessageLoopProxyImpl::~MessageLoopProxyImpl() {
+}
+
+}  // namespace internal
+
+scoped_refptr<MessageLoopProxy>
+MessageLoopProxy::current() {
+  MessageLoop* cur_loop = MessageLoop::current();
+  if (!cur_loop)
+    return NULL;
+  return cur_loop->message_loop_proxy();
+}
+
+}  // namespace base
diff --git a/base/message_loop/message_loop_proxy_impl.h b/base/message_loop/message_loop_proxy_impl.h
new file mode 100644
index 0000000..fa611c2
--- /dev/null
+++ b/base/message_loop/message_loop_proxy_impl.h
@@ -0,0 +1,58 @@
+// Copyright (c) 2012 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_MESSAGE_LOOP_MESSAGE_LOOP_PROXY_IMPL_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_LOOP_PROXY_IMPL_H_
+
+#include "base/base_export.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "base/pending_task.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+namespace internal {
+
+class IncomingTaskQueue;
+
+// A stock implementation of MessageLoopProxy that is created and managed by a
+// MessageLoop. For now a MessageLoopProxyImpl can only be created as part of a
+// MessageLoop.
+class BASE_EXPORT MessageLoopProxyImpl : public MessageLoopProxy {
+ public:
+  explicit MessageLoopProxyImpl(
+      scoped_refptr<IncomingTaskQueue> incoming_queue);
+
+  // Initialize this message loop proxy on the current thread.
+  void BindToCurrentThread();
+
+  // MessageLoopProxy implementation
+  bool PostDelayedTask(const tracked_objects::Location& from_here,
+                       const base::Closure& task,
+                       base::TimeDelta delay) override;
+  bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
+                                  const base::Closure& task,
+                                  base::TimeDelta delay) override;
+  bool RunsTasksOnCurrentThread() const override;
+
+ private:
+  friend class RefCountedThreadSafe<MessageLoopProxyImpl>;
+  ~MessageLoopProxyImpl() override;
+
+  // THe incoming queue receiving all posted tasks.
+  scoped_refptr<IncomingTaskQueue> incoming_queue_;
+
+  // ID of the thread |this| was created on.  Could be accessed on multiple
+  // threads, protected by |valid_thread_id_lock_|.
+  PlatformThreadId valid_thread_id_;
+  mutable Lock valid_thread_id_lock_;
+
+  DISALLOW_COPY_AND_ASSIGN(MessageLoopProxyImpl);
+};
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_MESSAGE_LOOP_MESSAGE_LOOP_PROXY_IMPL_H_
diff --git a/base/message_loop/message_loop_proxy_impl_unittest.cc b/base/message_loop/message_loop_proxy_impl_unittest.cc
new file mode 100644
index 0000000..fa25371
--- /dev/null
+++ b/base/message_loop/message_loop_proxy_impl_unittest.cc
@@ -0,0 +1,129 @@
+// Copyright (c) 2012 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/message_loop/message_loop_proxy_impl.h"
+
+#include "base/bind.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace base {
+
+class MessageLoopProxyImplTest : public testing::Test {
+ public:
+  void Release() const {
+    AssertOnIOThread();
+    Quit();
+  }
+
+  void Quit() const {
+    loop_.PostTask(FROM_HERE, MessageLoop::QuitWhenIdleClosure());
+  }
+
+  void AssertOnIOThread() const {
+    ASSERT_TRUE(io_thread_->message_loop_proxy()->BelongsToCurrentThread());
+    ASSERT_EQ(io_thread_->message_loop_proxy(),
+              MessageLoopProxy::current());
+  }
+
+  void AssertOnFileThread() const {
+    ASSERT_TRUE(file_thread_->message_loop_proxy()->BelongsToCurrentThread());
+    ASSERT_EQ(file_thread_->message_loop_proxy(),
+              MessageLoopProxy::current());
+  }
+
+ protected:
+  void SetUp() override {
+    io_thread_.reset(new Thread("MessageLoopProxyImplTest_IO"));
+    file_thread_.reset(new Thread("MessageLoopProxyImplTest_File"));
+    io_thread_->Start();
+    file_thread_->Start();
+  }
+
+  void TearDown() override {
+    io_thread_->Stop();
+    file_thread_->Stop();
+  }
+
+  static void BasicFunction(MessageLoopProxyImplTest* test) {
+    test->AssertOnFileThread();
+    test->Quit();
+  }
+
+  static void AssertNotRun() {
+    FAIL() << "Callback Should not get executed.";
+  }
+
+  class DeletedOnFile {
+   public:
+    explicit DeletedOnFile(MessageLoopProxyImplTest* test) : test_(test) {}
+
+    ~DeletedOnFile() {
+      test_->AssertOnFileThread();
+      test_->Quit();
+    }
+
+   private:
+    MessageLoopProxyImplTest* test_;
+  };
+
+  scoped_ptr<Thread> io_thread_;
+  scoped_ptr<Thread> file_thread_;
+
+ private:
+  mutable MessageLoop loop_;
+};
+
+TEST_F(MessageLoopProxyImplTest, Release) {
+  EXPECT_TRUE(io_thread_->message_loop_proxy()->ReleaseSoon(FROM_HERE, this));
+  MessageLoop::current()->Run();
+}
+
+TEST_F(MessageLoopProxyImplTest, Delete) {
+  DeletedOnFile* deleted_on_file = new DeletedOnFile(this);
+  EXPECT_TRUE(file_thread_->message_loop_proxy()->DeleteSoon(
+      FROM_HERE, deleted_on_file));
+  MessageLoop::current()->Run();
+}
+
+TEST_F(MessageLoopProxyImplTest, PostTask) {
+  EXPECT_TRUE(file_thread_->message_loop_proxy()->PostTask(
+      FROM_HERE, Bind(&MessageLoopProxyImplTest::BasicFunction,
+                            Unretained(this))));
+  MessageLoop::current()->Run();
+}
+
+TEST_F(MessageLoopProxyImplTest, PostTaskAfterThreadExits) {
+  scoped_ptr<Thread> test_thread(
+      new Thread("MessageLoopProxyImplTest_Dummy"));
+  test_thread->Start();
+  scoped_refptr<MessageLoopProxy> message_loop_proxy =
+      test_thread->message_loop_proxy();
+  test_thread->Stop();
+
+  bool ret = message_loop_proxy->PostTask(
+      FROM_HERE,
+      Bind(&MessageLoopProxyImplTest::AssertNotRun));
+  EXPECT_FALSE(ret);
+}
+
+TEST_F(MessageLoopProxyImplTest, PostTaskAfterThreadIsDeleted) {
+  scoped_refptr<MessageLoopProxy> message_loop_proxy;
+  {
+    scoped_ptr<Thread> test_thread(
+        new Thread("MessageLoopProxyImplTest_Dummy"));
+    test_thread->Start();
+    message_loop_proxy = test_thread->message_loop_proxy();
+  }
+  bool ret = message_loop_proxy->PostTask(
+      FROM_HERE,
+      Bind(&MessageLoopProxyImplTest::AssertNotRun));
+  EXPECT_FALSE(ret);
+}
+
+}  // namespace base
diff --git a/base/message_loop/message_loop_proxy_unittest.cc b/base/message_loop/message_loop_proxy_unittest.cc
new file mode 100644
index 0000000..0b0d9f8
--- /dev/null
+++ b/base/message_loop/message_loop_proxy_unittest.cc
@@ -0,0 +1,266 @@
+// Copyright (c) 2012 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/message_loop/message_loop_proxy.h"
+
+#include "base/atomic_sequence_num.h"
+#include "base/bind.h"
+#include "base/debug/leak_annotations.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+class MessageLoopProxyTest : public testing::Test {
+ public:
+  MessageLoopProxyTest()
+      : current_loop_(new MessageLoop()),
+        task_thread_("task_thread"),
+        thread_sync_(true, false) {
+  }
+
+  void DeleteCurrentMessageLoop() {
+    current_loop_.reset();
+  }
+
+ protected:
+  void SetUp() override {
+    // Use SetUp() instead of the constructor to avoid posting a task to a
+    // partialy constructed object.
+    task_thread_.Start();
+
+    // Allow us to pause the |task_thread_|'s MessageLoop.
+    task_thread_.message_loop()->PostTask(
+        FROM_HERE,
+        Bind(&MessageLoopProxyTest::BlockTaskThreadHelper, Unretained(this)));
+  }
+
+  void TearDown() override {
+    // Make sure the |task_thread_| is not blocked, and stop the thread
+    // fully before destuction because its tasks may still depend on the
+    // |thread_sync_| event.
+    thread_sync_.Signal();
+    task_thread_.Stop();
+    DeleteCurrentMessageLoop();
+  }
+
+  // Make LoopRecorder threadsafe so that there is defined behavior even if a
+  // threading mistake sneaks into the PostTaskAndReplyRelay implementation.
+  class LoopRecorder : public RefCountedThreadSafe<LoopRecorder> {
+   public:
+    LoopRecorder(MessageLoop** run_on, MessageLoop** deleted_on,
+                 int* destruct_order)
+        : run_on_(run_on),
+          deleted_on_(deleted_on),
+          destruct_order_(destruct_order) {
+    }
+
+    void RecordRun() {
+      *run_on_ = MessageLoop::current();
+    }
+
+   private:
+    friend class RefCountedThreadSafe<LoopRecorder>;
+    ~LoopRecorder() {
+      *deleted_on_ = MessageLoop::current();
+      *destruct_order_ = g_order.GetNext();
+    }
+
+    MessageLoop** run_on_;
+    MessageLoop** deleted_on_;
+    int* destruct_order_;
+  };
+
+  static void RecordLoop(scoped_refptr<LoopRecorder> recorder) {
+    recorder->RecordRun();
+  }
+
+  static void RecordLoopAndQuit(scoped_refptr<LoopRecorder> recorder) {
+    recorder->RecordRun();
+    MessageLoop::current()->QuitWhenIdle();
+  }
+
+  void UnblockTaskThread() {
+    thread_sync_.Signal();
+  }
+
+  void BlockTaskThreadHelper() {
+    thread_sync_.Wait();
+  }
+
+  static StaticAtomicSequenceNumber g_order;
+
+  scoped_ptr<MessageLoop> current_loop_;
+  Thread task_thread_;
+
+ private:
+  base::WaitableEvent thread_sync_;
+};
+
+StaticAtomicSequenceNumber MessageLoopProxyTest::g_order;
+
+TEST_F(MessageLoopProxyTest, PostTaskAndReply_Basic) {
+  MessageLoop* task_run_on = NULL;
+  MessageLoop* task_deleted_on = NULL;
+  int task_delete_order = -1;
+  MessageLoop* reply_run_on = NULL;
+  MessageLoop* reply_deleted_on = NULL;
+  int reply_delete_order = -1;
+
+  scoped_refptr<LoopRecorder> task_recoder =
+      new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order);
+  scoped_refptr<LoopRecorder> reply_recoder =
+      new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
+
+  ASSERT_TRUE(task_thread_.message_loop_proxy()->PostTaskAndReply(
+      FROM_HERE,
+      Bind(&RecordLoop, task_recoder),
+      Bind(&RecordLoopAndQuit, reply_recoder)));
+
+  // Die if base::Bind doesn't retain a reference to the recorders.
+  task_recoder = NULL;
+  reply_recoder = NULL;
+  ASSERT_FALSE(task_deleted_on);
+  ASSERT_FALSE(reply_deleted_on);
+
+  UnblockTaskThread();
+  current_loop_->Run();
+
+  EXPECT_EQ(task_thread_.message_loop(), task_run_on);
+  EXPECT_EQ(current_loop_.get(), task_deleted_on);
+  EXPECT_EQ(current_loop_.get(), reply_run_on);
+  EXPECT_EQ(current_loop_.get(), reply_deleted_on);
+  EXPECT_LT(task_delete_order, reply_delete_order);
+}
+
+TEST_F(MessageLoopProxyTest, PostTaskAndReplyOnDeletedThreadDoesNotLeak) {
+  MessageLoop* task_run_on = NULL;
+  MessageLoop* task_deleted_on = NULL;
+  int task_delete_order = -1;
+  MessageLoop* reply_run_on = NULL;
+  MessageLoop* reply_deleted_on = NULL;
+  int reply_delete_order = -1;
+
+  scoped_refptr<LoopRecorder> task_recoder =
+      new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order);
+  scoped_refptr<LoopRecorder> reply_recoder =
+      new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
+
+  // Grab a MessageLoopProxy to a dead MessageLoop.
+  scoped_refptr<MessageLoopProxy> task_loop_proxy =
+      task_thread_.message_loop_proxy();
+  UnblockTaskThread();
+  task_thread_.Stop();
+
+  ASSERT_FALSE(task_loop_proxy->PostTaskAndReply(
+      FROM_HERE,
+      Bind(&RecordLoop, task_recoder),
+      Bind(&RecordLoopAndQuit, reply_recoder)));
+
+  // The relay should have properly deleted its resources leaving us as the only
+  // reference.
+  EXPECT_EQ(task_delete_order, reply_delete_order);
+  ASSERT_TRUE(task_recoder->HasOneRef());
+  ASSERT_TRUE(reply_recoder->HasOneRef());
+
+  // Nothing should have run though.
+  EXPECT_FALSE(task_run_on);
+  EXPECT_FALSE(reply_run_on);
+}
+
+TEST_F(MessageLoopProxyTest, PostTaskAndReply_SameLoop) {
+  MessageLoop* task_run_on = NULL;
+  MessageLoop* task_deleted_on = NULL;
+  int task_delete_order = -1;
+  MessageLoop* reply_run_on = NULL;
+  MessageLoop* reply_deleted_on = NULL;
+  int reply_delete_order = -1;
+
+  scoped_refptr<LoopRecorder> task_recoder =
+      new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order);
+  scoped_refptr<LoopRecorder> reply_recoder =
+      new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
+
+  // Enqueue the relay.
+  ASSERT_TRUE(current_loop_->message_loop_proxy()->PostTaskAndReply(
+      FROM_HERE,
+      Bind(&RecordLoop, task_recoder),
+      Bind(&RecordLoopAndQuit, reply_recoder)));
+
+  // Die if base::Bind doesn't retain a reference to the recorders.
+  task_recoder = NULL;
+  reply_recoder = NULL;
+  ASSERT_FALSE(task_deleted_on);
+  ASSERT_FALSE(reply_deleted_on);
+
+  current_loop_->Run();
+
+  EXPECT_EQ(current_loop_.get(), task_run_on);
+  EXPECT_EQ(current_loop_.get(), task_deleted_on);
+  EXPECT_EQ(current_loop_.get(), reply_run_on);
+  EXPECT_EQ(current_loop_.get(), reply_deleted_on);
+  EXPECT_LT(task_delete_order, reply_delete_order);
+}
+
+TEST_F(MessageLoopProxyTest, PostTaskAndReply_DeadReplyLoopDoesNotDelete) {
+  // Annotate the scope as having memory leaks to suppress heapchecker reports.
+  ANNOTATE_SCOPED_MEMORY_LEAK;
+  MessageLoop* task_run_on = NULL;
+  MessageLoop* task_deleted_on = NULL;
+  int task_delete_order = -1;
+  MessageLoop* reply_run_on = NULL;
+  MessageLoop* reply_deleted_on = NULL;
+  int reply_delete_order = -1;
+
+  scoped_refptr<LoopRecorder> task_recoder =
+      new LoopRecorder(&task_run_on, &task_deleted_on, &task_delete_order);
+  scoped_refptr<LoopRecorder> reply_recoder =
+      new LoopRecorder(&reply_run_on, &reply_deleted_on, &reply_delete_order);
+
+  // Enqueue the relay.
+  task_thread_.message_loop_proxy()->PostTaskAndReply(
+      FROM_HERE,
+      Bind(&RecordLoop, task_recoder),
+      Bind(&RecordLoopAndQuit, reply_recoder));
+
+  // Die if base::Bind doesn't retain a reference to the recorders.
+  task_recoder = NULL;
+  reply_recoder = NULL;
+  ASSERT_FALSE(task_deleted_on);
+  ASSERT_FALSE(reply_deleted_on);
+
+  UnblockTaskThread();
+
+  // Mercilessly whack the current loop before |reply| gets to run.
+  current_loop_.reset();
+
+  // This should ensure the relay has been run.  We need to record the
+  // MessageLoop pointer before stopping the thread because Thread::Stop() will
+  // NULL out its own pointer.
+  MessageLoop* task_loop = task_thread_.message_loop();
+  task_thread_.Stop();
+
+  EXPECT_EQ(task_loop, task_run_on);
+  ASSERT_FALSE(task_deleted_on);
+  EXPECT_FALSE(reply_run_on);
+  ASSERT_FALSE(reply_deleted_on);
+  EXPECT_EQ(task_delete_order, reply_delete_order);
+
+  // The PostTaskAndReplyRelay is leaked here.  Even if we had a reference to
+  // it, we cannot just delete it because PostTaskAndReplyRelay's destructor
+  // checks that MessageLoop::current() is the the same as when the
+  // PostTaskAndReplyRelay object was constructed.  However, this loop must have
+  // aleady been deleted in order to perform this test.  See
+  // http://crbug.com/86301.
+}
+
+}  // namespace
+
+}  // namespace base
diff --git a/base/message_loop/message_loop_test.cc b/base/message_loop/message_loop_test.cc
new file mode 100644
index 0000000..eca6c8f
--- /dev/null
+++ b/base/message_loop/message_loop_test.cc
@@ -0,0 +1,1014 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop/message_loop_test.h"
+
+#include "base/bind.h"
+#include "base/memory/ref_counted.h"
+#include "base/run_loop.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+
+namespace base {
+namespace test {
+
+namespace {
+
+class Foo : public RefCounted<Foo> {
+ public:
+  Foo() : test_count_(0) {
+  }
+
+  void Test0() {
+    ++test_count_;
+  }
+
+  void Test1ConstRef(const std::string& a) {
+    ++test_count_;
+    result_.append(a);
+  }
+
+  void Test1Ptr(std::string* a) {
+    ++test_count_;
+    result_.append(*a);
+  }
+
+  void Test1Int(int a) {
+    test_count_ += a;
+  }
+
+  void Test2Ptr(std::string* a, std::string* b) {
+    ++test_count_;
+    result_.append(*a);
+    result_.append(*b);
+  }
+
+  void Test2Mixed(const std::string& a, std::string* b) {
+    ++test_count_;
+    result_.append(a);
+    result_.append(*b);
+  }
+
+  int test_count() const { return test_count_; }
+  const std::string& result() const { return result_; }
+
+ private:
+  friend class RefCounted<Foo>;
+
+  ~Foo() {}
+
+  int test_count_;
+  std::string result_;
+
+  DISALLOW_COPY_AND_ASSIGN(Foo);
+};
+
+// This function runs slowly to simulate a large amount of work being done.
+void SlowFunc(TimeDelta pause, int* quit_counter) {
+    PlatformThread::Sleep(pause);
+    if (--(*quit_counter) == 0)
+      MessageLoop::current()->QuitWhenIdle();
+}
+
+// This function records the time when Run was called in a Time object, which is
+// useful for building a variety of MessageLoop tests.
+// TODO(sky): remove?
+void RecordRunTimeFunc(Time* run_time, int* quit_counter) {
+  *run_time = Time::Now();
+
+    // Cause our Run function to take some time to execute.  As a result we can
+    // count on subsequent RecordRunTimeFunc()s running at a future time,
+    // without worry about the resolution of our system clock being an issue.
+  SlowFunc(TimeDelta::FromMilliseconds(10), quit_counter);
+}
+
+}  // namespace
+
+void RunTest_PostTask(MessagePumpFactory factory) {
+  scoped_ptr<MessagePump> pump(factory());
+  MessageLoop loop(pump.Pass());
+  // Add tests to message loop
+  scoped_refptr<Foo> foo(new Foo());
+  std::string a("a"), b("b"), c("c"), d("d");
+  MessageLoop::current()->PostTask(FROM_HERE, Bind(
+      &Foo::Test0, foo.get()));
+  MessageLoop::current()->PostTask(FROM_HERE, Bind(
+    &Foo::Test1ConstRef, foo.get(), a));
+  MessageLoop::current()->PostTask(FROM_HERE, Bind(
+      &Foo::Test1Ptr, foo.get(), &b));
+  MessageLoop::current()->PostTask(FROM_HERE, Bind(
+      &Foo::Test1Int, foo.get(), 100));
+  MessageLoop::current()->PostTask(FROM_HERE, Bind(
+      &Foo::Test2Ptr, foo.get(), &a, &c));
+  MessageLoop::current()->PostTask(FROM_HERE, Bind(
+      &Foo::Test2Mixed, foo.get(), a, &d));
+  // After all tests, post a message that will shut down the message loop
+  MessageLoop::current()->PostTask(FROM_HERE, Bind(
+      &MessageLoop::Quit, Unretained(MessageLoop::current())));
+
+  // Now kick things off
+  MessageLoop::current()->Run();
+
+  EXPECT_EQ(foo->test_count(), 105);
+  EXPECT_EQ(foo->result(), "abacad");
+}
+
+void RunTest_PostDelayedTask_Basic(MessagePumpFactory factory) {
+  scoped_ptr<MessagePump> pump(factory());
+  MessageLoop loop(pump.Pass());
+
+  // Test that PostDelayedTask results in a delayed task.
+
+  const TimeDelta kDelay = TimeDelta::FromMilliseconds(100);
+
+  int num_tasks = 1;
+  Time run_time;
+
+  loop.PostDelayedTask(
+      FROM_HERE, Bind(&RecordRunTimeFunc, &run_time, &num_tasks),
+      kDelay);
+
+  Time time_before_run = Time::Now();
+  loop.Run();
+  Time time_after_run = Time::Now();
+
+  EXPECT_EQ(0, num_tasks);
+  EXPECT_LT(kDelay, time_after_run - time_before_run);
+}
+
+void RunTest_PostDelayedTask_InDelayOrder(MessagePumpFactory factory) {
+  scoped_ptr<MessagePump> pump(factory());
+  MessageLoop loop(pump.Pass());
+
+  // Test that two tasks with different delays run in the right order.
+  int num_tasks = 2;
+  Time run_time1, run_time2;
+
+  loop.PostDelayedTask(
+      FROM_HERE,
+      Bind(&RecordRunTimeFunc, &run_time1, &num_tasks),
+      TimeDelta::FromMilliseconds(200));
+  // If we get a large pause in execution (due to a context switch) here, this
+  // test could fail.
+  loop.PostDelayedTask(
+      FROM_HERE,
+      Bind(&RecordRunTimeFunc, &run_time2, &num_tasks),
+      TimeDelta::FromMilliseconds(10));
+
+  loop.Run();
+  EXPECT_EQ(0, num_tasks);
+
+  EXPECT_TRUE(run_time2 < run_time1);
+}
+
+void RunTest_PostDelayedTask_InPostOrder(MessagePumpFactory factory) {
+  scoped_ptr<MessagePump> pump(factory());
+  MessageLoop loop(pump.Pass());
+
+  // Test that two tasks with the same delay run in the order in which they
+  // were posted.
+  //
+  // NOTE: This is actually an approximate test since the API only takes a
+  // "delay" parameter, so we are not exactly simulating two tasks that get
+  // posted at the exact same time.  It would be nice if the API allowed us to
+  // specify the desired run time.
+
+  const TimeDelta kDelay = TimeDelta::FromMilliseconds(100);
+
+  int num_tasks = 2;
+  Time run_time1, run_time2;
+
+  loop.PostDelayedTask(
+      FROM_HERE,
+      Bind(&RecordRunTimeFunc, &run_time1, &num_tasks), kDelay);
+  loop.PostDelayedTask(
+      FROM_HERE,
+      Bind(&RecordRunTimeFunc, &run_time2, &num_tasks), kDelay);
+
+  loop.Run();
+  EXPECT_EQ(0, num_tasks);
+
+  EXPECT_TRUE(run_time1 < run_time2);
+}
+
+void RunTest_PostDelayedTask_InPostOrder_2(MessagePumpFactory factory) {
+  scoped_ptr<MessagePump> pump(factory());
+  MessageLoop loop(pump.Pass());
+
+  // Test that a delayed task still runs after a normal tasks even if the
+  // normal tasks take a long time to run.
+
+  const TimeDelta kPause = TimeDelta::FromMilliseconds(50);
+
+  int num_tasks = 2;
+  Time run_time;
+
+  loop.PostTask(FROM_HERE, Bind(&SlowFunc, kPause, &num_tasks));
+  loop.PostDelayedTask(
+      FROM_HERE,
+      Bind(&RecordRunTimeFunc, &run_time, &num_tasks),
+      TimeDelta::FromMilliseconds(10));
+
+  Time time_before_run = Time::Now();
+  loop.Run();
+  Time time_after_run = Time::Now();
+
+  EXPECT_EQ(0, num_tasks);
+
+  EXPECT_LT(kPause, time_after_run - time_before_run);
+}
+
+void RunTest_PostDelayedTask_InPostOrder_3(MessagePumpFactory factory) {
+  scoped_ptr<MessagePump> pump(factory());
+  MessageLoop loop(pump.Pass());
+
+  // Test that a delayed task still runs after a pile of normal tasks.  The key
+  // difference between this test and the previous one is that here we return
+  // the MessageLoop a lot so we give the MessageLoop plenty of opportunities
+  // to maybe run the delayed task.  It should know not to do so until the
+  // delayed task's delay has passed.
+
+  int num_tasks = 11;
+  Time run_time1, run_time2;
+
+  // Clutter the ML with tasks.
+  for (int i = 1; i < num_tasks; ++i)
+    loop.PostTask(FROM_HERE,
+                  Bind(&RecordRunTimeFunc, &run_time1, &num_tasks));
+
+  loop.PostDelayedTask(
+      FROM_HERE, Bind(&RecordRunTimeFunc, &run_time2, &num_tasks),
+      TimeDelta::FromMilliseconds(1));
+
+  loop.Run();
+  EXPECT_EQ(0, num_tasks);
+
+  EXPECT_TRUE(run_time2 > run_time1);
+}
+
+void RunTest_PostDelayedTask_SharedTimer(MessagePumpFactory factory) {
+  scoped_ptr<MessagePump> pump(factory());
+  MessageLoop loop(pump.Pass());
+
+  // Test that the interval of the timer, used to run the next delayed task, is
+  // set to a value corresponding to when the next delayed task should run.
+
+  // By setting num_tasks to 1, we ensure that the first task to run causes the
+  // run loop to exit.
+  int num_tasks = 1;
+  Time run_time1, run_time2;
+
+  loop.PostDelayedTask(
+      FROM_HERE,
+      Bind(&RecordRunTimeFunc, &run_time1, &num_tasks),
+      TimeDelta::FromSeconds(1000));
+  loop.PostDelayedTask(
+      FROM_HERE,
+      Bind(&RecordRunTimeFunc, &run_time2, &num_tasks),
+      TimeDelta::FromMilliseconds(10));
+
+  Time start_time = Time::Now();
+
+  loop.Run();
+  EXPECT_EQ(0, num_tasks);
+
+  // Ensure that we ran in far less time than the slower timer.
+  TimeDelta total_time = Time::Now() - start_time;
+  EXPECT_GT(5000, total_time.InMilliseconds());
+
+  // In case both timers somehow run at nearly the same time, sleep a little
+  // and then run all pending to force them both to have run.  This is just
+  // encouraging flakiness if there is any.
+  PlatformThread::Sleep(TimeDelta::FromMilliseconds(100));
+  RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(run_time1.is_null());
+  EXPECT_FALSE(run_time2.is_null());
+}
+
+// This is used to inject a test point for recording the destructor calls for
+// Closure objects send to MessageLoop::PostTask(). It is awkward usage since we
+// are trying to hook the actual destruction, which is not a common operation.
+class RecordDeletionProbe : public RefCounted<RecordDeletionProbe> {
+ public:
+  RecordDeletionProbe(RecordDeletionProbe* post_on_delete, bool* was_deleted)
+      : post_on_delete_(post_on_delete), was_deleted_(was_deleted) {
+  }
+  void Run() {}
+
+ private:
+  friend class RefCounted<RecordDeletionProbe>;
+
+  ~RecordDeletionProbe() {
+    *was_deleted_ = true;
+    if (post_on_delete_.get())
+      MessageLoop::current()->PostTask(
+          FROM_HERE, Bind(&RecordDeletionProbe::Run, post_on_delete_.get()));
+  }
+
+  scoped_refptr<RecordDeletionProbe> post_on_delete_;
+  bool* was_deleted_;
+};
+
+void RunTest_EnsureDeletion(MessagePumpFactory factory) {
+  bool a_was_deleted = false;
+  bool b_was_deleted = false;
+  {
+    scoped_ptr<MessagePump> pump(factory());
+    MessageLoop loop(pump.Pass());
+    loop.PostTask(
+        FROM_HERE, Bind(&RecordDeletionProbe::Run,
+                              new RecordDeletionProbe(NULL, &a_was_deleted)));
+    // TODO(ajwong): Do we really need 1000ms here?
+    loop.PostDelayedTask(
+        FROM_HERE, Bind(&RecordDeletionProbe::Run,
+                              new RecordDeletionProbe(NULL, &b_was_deleted)),
+        TimeDelta::FromMilliseconds(1000));
+  }
+  EXPECT_TRUE(a_was_deleted);
+  EXPECT_TRUE(b_was_deleted);
+}
+
+void RunTest_EnsureDeletion_Chain(MessagePumpFactory factory) {
+  bool a_was_deleted = false;
+  bool b_was_deleted = false;
+  bool c_was_deleted = false;
+  {
+    scoped_ptr<MessagePump> pump(factory());
+    MessageLoop loop(pump.Pass());
+    // The scoped_refptr for each of the below is held either by the chained
+    // RecordDeletionProbe, or the bound RecordDeletionProbe::Run() callback.
+    RecordDeletionProbe* a = new RecordDeletionProbe(NULL, &a_was_deleted);
+    RecordDeletionProbe* b = new RecordDeletionProbe(a, &b_was_deleted);
+    RecordDeletionProbe* c = new RecordDeletionProbe(b, &c_was_deleted);
+    loop.PostTask(FROM_HERE, Bind(&RecordDeletionProbe::Run, c));
+  }
+  EXPECT_TRUE(a_was_deleted);
+  EXPECT_TRUE(b_was_deleted);
+  EXPECT_TRUE(c_was_deleted);
+}
+
+void NestingFunc(int* depth) {
+  if (*depth > 0) {
+    *depth -= 1;
+    MessageLoop::current()->PostTask(FROM_HERE,
+                                     Bind(&NestingFunc, depth));
+
+    MessageLoop::current()->SetNestableTasksAllowed(true);
+    MessageLoop::current()->Run();
+  }
+  MessageLoop::current()->QuitWhenIdle();
+}
+
+void RunTest_Nesting(MessagePumpFactory factory) {
+  scoped_ptr<MessagePump> pump(factory());
+  MessageLoop loop(pump.Pass());
+
+  int depth = 100;
+  MessageLoop::current()->PostTask(FROM_HERE,
+                                   Bind(&NestingFunc, &depth));
+  MessageLoop::current()->Run();
+  EXPECT_EQ(depth, 0);
+}
+
+enum TaskType {
+  MESSAGEBOX,
+  ENDDIALOG,
+  RECURSIVE,
+  TIMEDMESSAGELOOP,
+  QUITMESSAGELOOP,
+  ORDERED,
+  PUMPS,
+  SLEEP,
+  RUNS,
+};
+
+struct TaskItem {
+  TaskItem(TaskType t, int c, bool s)
+      : type(t),
+        cookie(c),
+        start(s) {
+  }
+
+  TaskType type;
+  int cookie;
+  bool start;
+
+  bool operator == (const TaskItem& other) const {
+    return type == other.type && cookie == other.cookie && start == other.start;
+  }
+};
+
+std::ostream& operator <<(std::ostream& os, TaskType type) {
+  switch (type) {
+  case MESSAGEBOX:        os << "MESSAGEBOX"; break;
+  case ENDDIALOG:         os << "ENDDIALOG"; break;
+  case RECURSIVE:         os << "RECURSIVE"; break;
+  case TIMEDMESSAGELOOP:  os << "TIMEDMESSAGELOOP"; break;
+  case QUITMESSAGELOOP:   os << "QUITMESSAGELOOP"; break;
+  case ORDERED:          os << "ORDERED"; break;
+  case PUMPS:             os << "PUMPS"; break;
+  case SLEEP:             os << "SLEEP"; break;
+  default:
+    NOTREACHED();
+    os << "Unknown TaskType";
+    break;
+  }
+  return os;
+}
+
+std::ostream& operator <<(std::ostream& os, const TaskItem& item) {
+  if (item.start)
+    return os << item.type << " " << item.cookie << " starts";
+  else
+    return os << item.type << " " << item.cookie << " ends";
+}
+
+class TaskList {
+ public:
+  void RecordStart(TaskType type, int cookie) {
+    TaskItem item(type, cookie, true);
+    DVLOG(1) << item;
+    task_list_.push_back(item);
+  }
+
+  void RecordEnd(TaskType type, int cookie) {
+    TaskItem item(type, cookie, false);
+    DVLOG(1) << item;
+    task_list_.push_back(item);
+  }
+
+  size_t Size() {
+    return task_list_.size();
+  }
+
+  TaskItem Get(int n)  {
+    return task_list_[n];
+  }
+
+ private:
+  std::vector<TaskItem> task_list_;
+};
+
+void RecursiveFunc(TaskList* order, int cookie, int depth,
+                   bool is_reentrant) {
+  order->RecordStart(RECURSIVE, cookie);
+  if (depth > 0) {
+    if (is_reentrant)
+      MessageLoop::current()->SetNestableTasksAllowed(true);
+    MessageLoop::current()->PostTask(
+        FROM_HERE,
+        Bind(&RecursiveFunc, order, cookie, depth - 1, is_reentrant));
+  }
+  order->RecordEnd(RECURSIVE, cookie);
+}
+
+void QuitFunc(TaskList* order, int cookie) {
+  order->RecordStart(QUITMESSAGELOOP, cookie);
+  MessageLoop::current()->QuitWhenIdle();
+  order->RecordEnd(QUITMESSAGELOOP, cookie);
+}
+void RunTest_RecursiveDenial1(MessagePumpFactory factory) {
+  scoped_ptr<MessagePump> pump(factory());
+  MessageLoop loop(pump.Pass());
+
+  EXPECT_TRUE(MessageLoop::current()->NestableTasksAllowed());
+  TaskList order;
+  MessageLoop::current()->PostTask(
+      FROM_HERE,
+      Bind(&RecursiveFunc, &order, 1, 2, false));
+  MessageLoop::current()->PostTask(
+      FROM_HERE,
+      Bind(&RecursiveFunc, &order, 2, 2, false));
+  MessageLoop::current()->PostTask(
+      FROM_HERE,
+      Bind(&QuitFunc, &order, 3));
+
+  MessageLoop::current()->Run();
+
+  // FIFO order.
+  ASSERT_EQ(14U, order.Size());
+  EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true));
+  EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false));
+  EXPECT_EQ(order.Get(2), TaskItem(RECURSIVE, 2, true));
+  EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 2, false));
+  EXPECT_EQ(order.Get(4), TaskItem(QUITMESSAGELOOP, 3, true));
+  EXPECT_EQ(order.Get(5), TaskItem(QUITMESSAGELOOP, 3, false));
+  EXPECT_EQ(order.Get(6), TaskItem(RECURSIVE, 1, true));
+  EXPECT_EQ(order.Get(7), TaskItem(RECURSIVE, 1, false));
+  EXPECT_EQ(order.Get(8), TaskItem(RECURSIVE, 2, true));
+  EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 2, false));
+  EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, true));
+  EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 1, false));
+  EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 2, true));
+  EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 2, false));
+}
+
+void RecursiveSlowFunc(TaskList* order, int cookie, int depth,
+                       bool is_reentrant) {
+  RecursiveFunc(order, cookie, depth, is_reentrant);
+  PlatformThread::Sleep(TimeDelta::FromMilliseconds(10));
+}
+
+void OrderedFunc(TaskList* order, int cookie) {
+  order->RecordStart(ORDERED, cookie);
+  order->RecordEnd(ORDERED, cookie);
+}
+
+void RunTest_RecursiveDenial3(MessagePumpFactory factory) {
+  scoped_ptr<MessagePump> pump(factory());
+  MessageLoop loop(pump.Pass());
+
+  EXPECT_TRUE(MessageLoop::current()->NestableTasksAllowed());
+  TaskList order;
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&RecursiveSlowFunc, &order, 1, 2, false));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&RecursiveSlowFunc, &order, 2, 2, false));
+  MessageLoop::current()->PostDelayedTask(
+      FROM_HERE,
+      Bind(&OrderedFunc, &order, 3),
+      TimeDelta::FromMilliseconds(5));
+  MessageLoop::current()->PostDelayedTask(
+      FROM_HERE,
+      Bind(&QuitFunc, &order, 4),
+      TimeDelta::FromMilliseconds(5));
+
+  MessageLoop::current()->Run();
+
+  // FIFO order.
+  ASSERT_EQ(16U, order.Size());
+  EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true));
+  EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false));
+  EXPECT_EQ(order.Get(2), TaskItem(RECURSIVE, 2, true));
+  EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 2, false));
+  EXPECT_EQ(order.Get(4), TaskItem(RECURSIVE, 1, true));
+  EXPECT_EQ(order.Get(5), TaskItem(RECURSIVE, 1, false));
+  EXPECT_EQ(order.Get(6), TaskItem(ORDERED, 3, true));
+  EXPECT_EQ(order.Get(7), TaskItem(ORDERED, 3, false));
+  EXPECT_EQ(order.Get(8), TaskItem(RECURSIVE, 2, true));
+  EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 2, false));
+  EXPECT_EQ(order.Get(10), TaskItem(QUITMESSAGELOOP, 4, true));
+  EXPECT_EQ(order.Get(11), TaskItem(QUITMESSAGELOOP, 4, false));
+  EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 1, true));
+  EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 1, false));
+  EXPECT_EQ(order.Get(14), TaskItem(RECURSIVE, 2, true));
+  EXPECT_EQ(order.Get(15), TaskItem(RECURSIVE, 2, false));
+}
+
+void RunTest_RecursiveSupport1(MessagePumpFactory factory) {
+  scoped_ptr<MessagePump> pump(factory());
+  MessageLoop loop(pump.Pass());
+
+  TaskList order;
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&RecursiveFunc, &order, 1, 2, true));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&RecursiveFunc, &order, 2, 2, true));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&QuitFunc, &order, 3));
+
+  MessageLoop::current()->Run();
+
+  // FIFO order.
+  ASSERT_EQ(14U, order.Size());
+  EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true));
+  EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false));
+  EXPECT_EQ(order.Get(2), TaskItem(RECURSIVE, 2, true));
+  EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 2, false));
+  EXPECT_EQ(order.Get(4), TaskItem(QUITMESSAGELOOP, 3, true));
+  EXPECT_EQ(order.Get(5), TaskItem(QUITMESSAGELOOP, 3, false));
+  EXPECT_EQ(order.Get(6), TaskItem(RECURSIVE, 1, true));
+  EXPECT_EQ(order.Get(7), TaskItem(RECURSIVE, 1, false));
+  EXPECT_EQ(order.Get(8), TaskItem(RECURSIVE, 2, true));
+  EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 2, false));
+  EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, true));
+  EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 1, false));
+  EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 2, true));
+  EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 2, false));
+}
+
+// Tests that non nestable tasks run in FIFO if there are no nested loops.
+void RunTest_NonNestableWithNoNesting(MessagePumpFactory factory) {
+  scoped_ptr<MessagePump> pump(factory());
+  MessageLoop loop(pump.Pass());
+
+  TaskList order;
+
+  MessageLoop::current()->PostNonNestableTask(
+      FROM_HERE,
+      Bind(&OrderedFunc, &order, 1));
+  MessageLoop::current()->PostTask(FROM_HERE,
+                                   Bind(&OrderedFunc, &order, 2));
+  MessageLoop::current()->PostTask(FROM_HERE,
+                                   Bind(&QuitFunc, &order, 3));
+  MessageLoop::current()->Run();
+
+  // FIFO order.
+  ASSERT_EQ(6U, order.Size());
+  EXPECT_EQ(order.Get(0), TaskItem(ORDERED, 1, true));
+  EXPECT_EQ(order.Get(1), TaskItem(ORDERED, 1, false));
+  EXPECT_EQ(order.Get(2), TaskItem(ORDERED, 2, true));
+  EXPECT_EQ(order.Get(3), TaskItem(ORDERED, 2, false));
+  EXPECT_EQ(order.Get(4), TaskItem(QUITMESSAGELOOP, 3, true));
+  EXPECT_EQ(order.Get(5), TaskItem(QUITMESSAGELOOP, 3, false));
+}
+
+void FuncThatPumps(TaskList* order, int cookie) {
+  order->RecordStart(PUMPS, cookie);
+  {
+    MessageLoop::ScopedNestableTaskAllower allow(MessageLoop::current());
+    RunLoop().RunUntilIdle();
+  }
+  order->RecordEnd(PUMPS, cookie);
+}
+
+void SleepFunc(TaskList* order, int cookie, TimeDelta delay) {
+  order->RecordStart(SLEEP, cookie);
+  PlatformThread::Sleep(delay);
+  order->RecordEnd(SLEEP, cookie);
+}
+
+// Tests that non nestable tasks don't run when there's code in the call stack.
+void RunTest_NonNestableInNestedLoop(MessagePumpFactory factory,
+                                     bool use_delayed) {
+  scoped_ptr<MessagePump> pump(factory());
+  MessageLoop loop(pump.Pass());
+
+  TaskList order;
+
+  MessageLoop::current()->PostTask(
+      FROM_HERE,
+      Bind(&FuncThatPumps, &order, 1));
+  if (use_delayed) {
+    MessageLoop::current()->PostNonNestableDelayedTask(
+        FROM_HERE,
+        Bind(&OrderedFunc, &order, 2),
+        TimeDelta::FromMilliseconds(1));
+  } else {
+    MessageLoop::current()->PostNonNestableTask(
+        FROM_HERE,
+        Bind(&OrderedFunc, &order, 2));
+  }
+  MessageLoop::current()->PostTask(FROM_HERE,
+                                   Bind(&OrderedFunc, &order, 3));
+  MessageLoop::current()->PostTask(
+      FROM_HERE,
+      Bind(&SleepFunc, &order, 4, TimeDelta::FromMilliseconds(50)));
+  MessageLoop::current()->PostTask(FROM_HERE,
+                                   Bind(&OrderedFunc, &order, 5));
+  if (use_delayed) {
+    MessageLoop::current()->PostNonNestableDelayedTask(
+        FROM_HERE,
+        Bind(&QuitFunc, &order, 6),
+        TimeDelta::FromMilliseconds(2));
+  } else {
+    MessageLoop::current()->PostNonNestableTask(
+        FROM_HERE,
+        Bind(&QuitFunc, &order, 6));
+  }
+
+  MessageLoop::current()->Run();
+
+  // FIFO order.
+  ASSERT_EQ(12U, order.Size());
+  EXPECT_EQ(order.Get(0), TaskItem(PUMPS, 1, true));
+  EXPECT_EQ(order.Get(1), TaskItem(ORDERED, 3, true));
+  EXPECT_EQ(order.Get(2), TaskItem(ORDERED, 3, false));
+  EXPECT_EQ(order.Get(3), TaskItem(SLEEP, 4, true));
+  EXPECT_EQ(order.Get(4), TaskItem(SLEEP, 4, false));
+  EXPECT_EQ(order.Get(5), TaskItem(ORDERED, 5, true));
+  EXPECT_EQ(order.Get(6), TaskItem(ORDERED, 5, false));
+  EXPECT_EQ(order.Get(7), TaskItem(PUMPS, 1, false));
+  EXPECT_EQ(order.Get(8), TaskItem(ORDERED, 2, true));
+  EXPECT_EQ(order.Get(9), TaskItem(ORDERED, 2, false));
+  EXPECT_EQ(order.Get(10), TaskItem(QUITMESSAGELOOP, 6, true));
+  EXPECT_EQ(order.Get(11), TaskItem(QUITMESSAGELOOP, 6, false));
+}
+
+void FuncThatRuns(TaskList* order, int cookie, RunLoop* run_loop) {
+  order->RecordStart(RUNS, cookie);
+  {
+    MessageLoop::ScopedNestableTaskAllower allow(MessageLoop::current());
+    run_loop->Run();
+  }
+  order->RecordEnd(RUNS, cookie);
+}
+
+void FuncThatQuitsNow() {
+  MessageLoop::current()->QuitNow();
+}
+// Tests RunLoopQuit only quits the corresponding MessageLoop::Run.
+void RunTest_QuitNow(MessagePumpFactory factory) {
+  scoped_ptr<MessagePump> pump(factory());
+  MessageLoop loop(pump.Pass());
+
+  TaskList order;
+
+  RunLoop run_loop;
+
+  MessageLoop::current()->PostTask(FROM_HERE,
+      Bind(&FuncThatRuns, &order, 1, Unretained(&run_loop)));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 2));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&FuncThatQuitsNow));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 3));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&FuncThatQuitsNow));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 4)); // never runs
+
+  MessageLoop::current()->Run();
+
+  ASSERT_EQ(6U, order.Size());
+  int task_index = 0;
+  EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 3, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 3, false));
+  EXPECT_EQ(static_cast<size_t>(task_index), order.Size());
+}
+
+// Tests RunLoopQuit only quits the corresponding MessageLoop::Run.
+void RunTest_RunLoopQuitTop(MessagePumpFactory factory) {
+  scoped_ptr<MessagePump> pump(factory());
+  MessageLoop loop(pump.Pass());
+
+  TaskList order;
+
+  RunLoop outer_run_loop;
+  RunLoop nested_run_loop;
+
+  MessageLoop::current()->PostTask(FROM_HERE,
+      Bind(&FuncThatRuns, &order, 1, Unretained(&nested_run_loop)));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, outer_run_loop.QuitClosure());
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 2));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, nested_run_loop.QuitClosure());
+
+  outer_run_loop.Run();
+
+  ASSERT_EQ(4U, order.Size());
+  int task_index = 0;
+  EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false));
+  EXPECT_EQ(static_cast<size_t>(task_index), order.Size());
+}
+
+// Tests RunLoopQuit only quits the corresponding MessageLoop::Run.
+void RunTest_RunLoopQuitNested(MessagePumpFactory factory) {
+  scoped_ptr<MessagePump> pump(factory());
+  MessageLoop loop(pump.Pass());
+
+  TaskList order;
+
+  RunLoop outer_run_loop;
+  RunLoop nested_run_loop;
+
+  MessageLoop::current()->PostTask(FROM_HERE,
+      Bind(&FuncThatRuns, &order, 1, Unretained(&nested_run_loop)));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, nested_run_loop.QuitClosure());
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 2));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, outer_run_loop.QuitClosure());
+
+  outer_run_loop.Run();
+
+  ASSERT_EQ(4U, order.Size());
+  int task_index = 0;
+  EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false));
+  EXPECT_EQ(static_cast<size_t>(task_index), order.Size());
+}
+
+// Tests RunLoopQuit only quits the corresponding MessageLoop::Run.
+void RunTest_RunLoopQuitBogus(MessagePumpFactory factory) {
+  scoped_ptr<MessagePump> pump(factory());
+  MessageLoop loop(pump.Pass());
+
+  TaskList order;
+
+  RunLoop outer_run_loop;
+  RunLoop nested_run_loop;
+  RunLoop bogus_run_loop;
+
+  MessageLoop::current()->PostTask(FROM_HERE,
+      Bind(&FuncThatRuns, &order, 1, Unretained(&nested_run_loop)));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, bogus_run_loop.QuitClosure());
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 2));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, outer_run_loop.QuitClosure());
+  MessageLoop::current()->PostTask(
+      FROM_HERE, nested_run_loop.QuitClosure());
+
+  outer_run_loop.Run();
+
+  ASSERT_EQ(4U, order.Size());
+  int task_index = 0;
+  EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false));
+  EXPECT_EQ(static_cast<size_t>(task_index), order.Size());
+}
+
+// Tests RunLoopQuit only quits the corresponding MessageLoop::Run.
+void RunTest_RunLoopQuitDeep(MessagePumpFactory factory) {
+  scoped_ptr<MessagePump> pump(factory());
+  MessageLoop loop(pump.Pass());
+
+  TaskList order;
+
+  RunLoop outer_run_loop;
+  RunLoop nested_loop1;
+  RunLoop nested_loop2;
+  RunLoop nested_loop3;
+  RunLoop nested_loop4;
+
+  MessageLoop::current()->PostTask(FROM_HERE,
+      Bind(&FuncThatRuns, &order, 1, Unretained(&nested_loop1)));
+  MessageLoop::current()->PostTask(FROM_HERE,
+      Bind(&FuncThatRuns, &order, 2, Unretained(&nested_loop2)));
+  MessageLoop::current()->PostTask(FROM_HERE,
+      Bind(&FuncThatRuns, &order, 3, Unretained(&nested_loop3)));
+  MessageLoop::current()->PostTask(FROM_HERE,
+      Bind(&FuncThatRuns, &order, 4, Unretained(&nested_loop4)));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 5));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, outer_run_loop.QuitClosure());
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 6));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, nested_loop1.QuitClosure());
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 7));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, nested_loop2.QuitClosure());
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 8));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, nested_loop3.QuitClosure());
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 9));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, nested_loop4.QuitClosure());
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 10));
+
+  outer_run_loop.Run();
+
+  ASSERT_EQ(18U, order.Size());
+  int task_index = 0;
+  EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 2, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 3, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 4, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 5, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 5, false));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 6, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 6, false));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 7, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 7, false));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 8, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 8, false));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 9, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 9, false));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 4, false));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 3, false));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 2, false));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false));
+  EXPECT_EQ(static_cast<size_t>(task_index), order.Size());
+}
+
+// Tests RunLoopQuit works before RunWithID.
+void RunTest_RunLoopQuitOrderBefore(MessagePumpFactory factory) {
+  scoped_ptr<MessagePump> pump(factory());
+  MessageLoop loop(pump.Pass());
+
+  TaskList order;
+
+  RunLoop run_loop;
+
+  run_loop.Quit();
+
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 1)); // never runs
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&FuncThatQuitsNow)); // never runs
+
+  run_loop.Run();
+
+  ASSERT_EQ(0U, order.Size());
+}
+
+// Tests RunLoopQuit works during RunWithID.
+void RunTest_RunLoopQuitOrderDuring(MessagePumpFactory factory) {
+  scoped_ptr<MessagePump> pump(factory());
+  MessageLoop loop(pump.Pass());
+
+  TaskList order;
+
+  RunLoop run_loop;
+
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 1));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, run_loop.QuitClosure());
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 2)); // never runs
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&FuncThatQuitsNow)); // never runs
+
+  run_loop.Run();
+
+  ASSERT_EQ(2U, order.Size());
+  int task_index = 0;
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 1, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 1, false));
+  EXPECT_EQ(static_cast<size_t>(task_index), order.Size());
+}
+
+// Tests RunLoopQuit works after RunWithID.
+void RunTest_RunLoopQuitOrderAfter(MessagePumpFactory factory) {
+  scoped_ptr<MessagePump> pump(factory());
+  MessageLoop loop(pump.Pass());
+
+  TaskList order;
+
+  RunLoop run_loop;
+
+  MessageLoop::current()->PostTask(FROM_HERE,
+      Bind(&FuncThatRuns, &order, 1, Unretained(&run_loop)));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 2));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&FuncThatQuitsNow));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 3));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, run_loop.QuitClosure()); // has no affect
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&OrderedFunc, &order, 4));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&FuncThatQuitsNow));
+
+  RunLoop outer_run_loop;
+  outer_run_loop.Run();
+
+  ASSERT_EQ(8U, order.Size());
+  int task_index = 0;
+  EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 2, false));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(RUNS, 1, false));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 3, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 3, false));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 4, true));
+  EXPECT_EQ(order.Get(task_index++), TaskItem(ORDERED, 4, false));
+  EXPECT_EQ(static_cast<size_t>(task_index), order.Size());
+}
+
+void PostNTasksThenQuit(int posts_remaining) {
+  if (posts_remaining > 1) {
+    MessageLoop::current()->PostTask(
+        FROM_HERE,
+        Bind(&PostNTasksThenQuit, posts_remaining - 1));
+  } else {
+    MessageLoop::current()->QuitWhenIdle();
+  }
+}
+
+// There was a bug in the MessagePumpGLib where posting tasks recursively
+// caused the message loop to hang, due to the buffer of the internal pipe
+// becoming full. Test all MessageLoop types to ensure this issue does not
+// exist in other MessagePumps.
+//
+// On Linux, the pipe buffer size is 64KiB by default. The bug caused one
+// byte accumulated in the pipe per two posts, so we should repeat 128K
+// times to reproduce the bug.
+void RunTest_RecursivePosts(MessagePumpFactory factory) {
+  const int kNumTimes = 1 << 17;
+  scoped_ptr<MessagePump> pump(factory());
+  MessageLoop loop(pump.Pass());
+  loop.PostTask(FROM_HERE, Bind(&PostNTasksThenQuit, kNumTimes));
+  loop.Run();
+}
+
+}  // namespace test
+}  // namespace base
diff --git a/base/message_loop/message_loop_test.h b/base/message_loop/message_loop_test.h
new file mode 100644
index 0000000..3d9889c
--- /dev/null
+++ b/base/message_loop/message_loop_test.h
@@ -0,0 +1,133 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MESSAGE_LOOP_MESSAGE_LOOP_TEST_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_LOOP_TEST_H_
+
+#include "base/message_loop/message_loop.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// This file consists of tests meant to exercise the combination of MessageLoop
+// and MessagePump. To use these define the macro RUN_MESSAGE_LOOP_TESTS using
+// an ID appropriate for your MessagePump, eg
+// RUN_MESSAGE_LOOP_TESTS(UI, factory). Factory is a function called to create
+// the MessagePump.
+namespace base {
+namespace test {
+
+typedef MessageLoop::MessagePumpFactory MessagePumpFactory;
+
+void RunTest_PostTask(MessagePumpFactory factory);
+void RunTest_PostDelayedTask_Basic(MessagePumpFactory factory);
+void RunTest_PostDelayedTask_InDelayOrder(MessagePumpFactory factory);
+void RunTest_PostDelayedTask_InPostOrder(MessagePumpFactory factory);
+void RunTest_PostDelayedTask_InPostOrder_2(MessagePumpFactory factory);
+void RunTest_PostDelayedTask_InPostOrder_3(MessagePumpFactory factory);
+void RunTest_PostDelayedTask_SharedTimer(MessagePumpFactory factory);
+void RunTest_EnsureDeletion(MessagePumpFactory factory);
+void RunTest_EnsureDeletion_Chain(MessagePumpFactory factory);
+void RunTest_Nesting(MessagePumpFactory factory);
+void RunTest_RecursiveDenial1(MessagePumpFactory factory);
+void RunTest_RecursiveDenial3(MessagePumpFactory factory);
+void RunTest_RecursiveSupport1(MessagePumpFactory factory);
+void RunTest_NonNestableWithNoNesting(MessagePumpFactory factory);
+void RunTest_NonNestableInNestedLoop(MessagePumpFactory factory,
+                                     bool use_delayed);
+void RunTest_QuitNow(MessagePumpFactory factory);
+void RunTest_RunLoopQuitTop(MessagePumpFactory factory);
+void RunTest_RunLoopQuitNested(MessagePumpFactory factory);
+void RunTest_RunLoopQuitBogus(MessagePumpFactory factory);
+void RunTest_RunLoopQuitDeep(MessagePumpFactory factory);
+void RunTest_RunLoopQuitOrderBefore(MessagePumpFactory factory);
+void RunTest_RunLoopQuitOrderDuring(MessagePumpFactory factory);
+void RunTest_RunLoopQuitOrderAfter(MessagePumpFactory factory);
+void RunTest_RecursivePosts(MessagePumpFactory factory);
+
+}  // namespace test
+}  // namespace base
+
+#define RUN_MESSAGE_LOOP_TESTS(id, factory) \
+  TEST(MessageLoopTestType##id, PostTask) { \
+    base::test::RunTest_PostTask(factory); \
+  } \
+  TEST(MessageLoopTestType##id, PostDelayedTask_Basic) { \
+    base::test::RunTest_PostDelayedTask_Basic(factory); \
+  } \
+  TEST(MessageLoopTestType##id, PostDelayedTask_InDelayOrder) { \
+    base::test::RunTest_PostDelayedTask_InDelayOrder(factory); \
+  } \
+  TEST(MessageLoopTestType##id, PostDelayedTask_InPostOrder) { \
+    base::test::RunTest_PostDelayedTask_InPostOrder(factory); \
+  } \
+  TEST(MessageLoopTestType##id, PostDelayedTask_InPostOrder_2) { \
+    base::test::RunTest_PostDelayedTask_InPostOrder_2(factory); \
+  } \
+  TEST(MessageLoopTestType##id, PostDelayedTask_InPostOrder_3) { \
+    base::test::RunTest_PostDelayedTask_InPostOrder_3(factory); \
+  } \
+  TEST(MessageLoopTestType##id, PostDelayedTask_SharedTimer) { \
+    base::test::RunTest_PostDelayedTask_SharedTimer(factory); \
+  } \
+  /* TODO(darin): MessageLoop does not support deleting all tasks in the */ \
+  /* destructor. */ \
+  /* Fails, http://crbug.com/50272. */ \
+  TEST(MessageLoopTestType##id, DISABLED_EnsureDeletion) { \
+    base::test::RunTest_EnsureDeletion(factory); \
+  } \
+  /* TODO(darin): MessageLoop does not support deleting all tasks in the */ \
+  /* destructor. */ \
+  /* Fails, http://crbug.com/50272. */ \
+  TEST(MessageLoopTestType##id, DISABLED_EnsureDeletion_Chain) { \
+    base::test::RunTest_EnsureDeletion_Chain(factory); \
+  } \
+  TEST(MessageLoopTestType##id, Nesting) { \
+    base::test::RunTest_Nesting(factory); \
+  } \
+  TEST(MessageLoopTestType##id, RecursiveDenial1) { \
+    base::test::RunTest_RecursiveDenial1(factory); \
+  } \
+  TEST(MessageLoopTestType##id, RecursiveDenial3) { \
+    base::test::RunTest_RecursiveDenial3(factory); \
+  } \
+  TEST(MessageLoopTestType##id, RecursiveSupport1) { \
+    base::test::RunTest_RecursiveSupport1(factory); \
+  } \
+  TEST(MessageLoopTestType##id, NonNestableWithNoNesting) { \
+    base::test::RunTest_NonNestableWithNoNesting(factory); \
+  } \
+  TEST(MessageLoopTestType##id, NonNestableInNestedLoop) { \
+    base::test::RunTest_NonNestableInNestedLoop(factory, false); \
+  } \
+  TEST(MessageLoopTestType##id, NonNestableDelayedInNestedLoop) { \
+    base::test::RunTest_NonNestableInNestedLoop(factory, true); \
+  } \
+  TEST(MessageLoopTestType##id, QuitNow) { \
+    base::test::RunTest_QuitNow(factory); \
+  } \
+  TEST(MessageLoopTestType##id, RunLoopQuitTop) { \
+    base::test::RunTest_RunLoopQuitTop(factory); \
+  } \
+  TEST(MessageLoopTestType##id, RunLoopQuitNested) { \
+    base::test::RunTest_RunLoopQuitNested(factory); \
+  } \
+  TEST(MessageLoopTestType##id, RunLoopQuitBogus) { \
+    base::test::RunTest_RunLoopQuitBogus(factory); \
+  } \
+  TEST(MessageLoopTestType##id, RunLoopQuitDeep) { \
+    base::test::RunTest_RunLoopQuitDeep(factory); \
+  } \
+  TEST(MessageLoopTestType##id, RunLoopQuitOrderBefore) { \
+    base::test::RunTest_RunLoopQuitOrderBefore(factory); \
+  } \
+  TEST(MessageLoopTestType##id, RunLoopQuitOrderDuring) { \
+    base::test::RunTest_RunLoopQuitOrderDuring(factory); \
+  } \
+  TEST(MessageLoopTestType##id, RunLoopQuitOrderAfter) { \
+    base::test::RunTest_RunLoopQuitOrderAfter(factory); \
+  } \
+  TEST(MessageLoopTestType##id, RecursivePosts) { \
+    base::test::RunTest_RecursivePosts(factory); \
+  } \
+
+#endif  // BASE_MESSAGE_LOOP_MESSAGE_LOOP_TEST_H_
diff --git a/base/message_loop/message_loop_unittest.cc b/base/message_loop/message_loop_unittest.cc
new file mode 100644
index 0000000..ddde6bb
--- /dev/null
+++ b/base/message_loop/message_loop_unittest.cc
@@ -0,0 +1,1015 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <vector>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_proxy_impl.h"
+#include "base/message_loop/message_loop_test.h"
+#include "base/pending_task.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/run_loop.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_WIN)
+#include "base/message_loop/message_pump_dispatcher.h"
+#include "base/message_loop/message_pump_win.h"
+#include "base/process/memory.h"
+#include "base/strings/string16.h"
+#include "base/win/scoped_handle.h"
+#endif
+
+namespace base {
+
+// TODO(darin): Platform-specific MessageLoop tests should be grouped together
+// to avoid chopping this file up with so many #ifdefs.
+
+namespace {
+
+scoped_ptr<MessagePump> TypeDefaultMessagePumpFactory() {
+  return MessageLoop::CreateMessagePumpForType(MessageLoop::TYPE_DEFAULT);
+}
+
+scoped_ptr<MessagePump> TypeIOMessagePumpFactory() {
+  return MessageLoop::CreateMessagePumpForType(MessageLoop::TYPE_IO);
+}
+
+scoped_ptr<MessagePump> TypeUIMessagePumpFactory() {
+  return MessageLoop::CreateMessagePumpForType(MessageLoop::TYPE_UI);
+}
+
+class Foo : public RefCounted<Foo> {
+ public:
+  Foo() : test_count_(0) {
+  }
+
+  void Test1ConstRef(const std::string& a) {
+    ++test_count_;
+    result_.append(a);
+  }
+
+  int test_count() const { return test_count_; }
+  const std::string& result() const { return result_; }
+
+ private:
+  friend class RefCounted<Foo>;
+
+  ~Foo() {}
+
+  int test_count_;
+  std::string result_;
+};
+
+#if defined(OS_WIN)
+
+// This function runs slowly to simulate a large amount of work being done.
+static void SlowFunc(TimeDelta pause, int* quit_counter) {
+    PlatformThread::Sleep(pause);
+    if (--(*quit_counter) == 0)
+      MessageLoop::current()->QuitWhenIdle();
+}
+
+// This function records the time when Run was called in a Time object, which is
+// useful for building a variety of MessageLoop tests.
+static void RecordRunTimeFunc(Time* run_time, int* quit_counter) {
+  *run_time = Time::Now();
+
+    // Cause our Run function to take some time to execute.  As a result we can
+    // count on subsequent RecordRunTimeFunc()s running at a future time,
+    // without worry about the resolution of our system clock being an issue.
+  SlowFunc(TimeDelta::FromMilliseconds(10), quit_counter);
+}
+
+void SubPumpFunc() {
+  MessageLoop::current()->SetNestableTasksAllowed(true);
+  MSG msg;
+  while (GetMessage(&msg, NULL, 0, 0)) {
+    TranslateMessage(&msg);
+    DispatchMessage(&msg);
+  }
+  MessageLoop::current()->QuitWhenIdle();
+}
+
+void RunTest_PostDelayedTask_SharedTimer_SubPump() {
+  MessageLoop loop(MessageLoop::TYPE_UI);
+
+  // Test that the interval of the timer, used to run the next delayed task, is
+  // set to a value corresponding to when the next delayed task should run.
+
+  // By setting num_tasks to 1, we ensure that the first task to run causes the
+  // run loop to exit.
+  int num_tasks = 1;
+  Time run_time;
+
+  loop.PostTask(FROM_HERE, Bind(&SubPumpFunc));
+
+  // This very delayed task should never run.
+  loop.PostDelayedTask(
+      FROM_HERE,
+      Bind(&RecordRunTimeFunc, &run_time, &num_tasks),
+      TimeDelta::FromSeconds(1000));
+
+  // This slightly delayed task should run from within SubPumpFunc).
+  loop.PostDelayedTask(
+      FROM_HERE,
+      Bind(&PostQuitMessage, 0),
+      TimeDelta::FromMilliseconds(10));
+
+  Time start_time = Time::Now();
+
+  loop.Run();
+  EXPECT_EQ(1, num_tasks);
+
+  // Ensure that we ran in far less time than the slower timer.
+  TimeDelta total_time = Time::Now() - start_time;
+  EXPECT_GT(5000, total_time.InMilliseconds());
+
+  // In case both timers somehow run at nearly the same time, sleep a little
+  // and then run all pending to force them both to have run.  This is just
+  // encouraging flakiness if there is any.
+  PlatformThread::Sleep(TimeDelta::FromMilliseconds(100));
+  RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(run_time.is_null());
+}
+
+const wchar_t kMessageBoxTitle[] = L"MessageLoop Unit Test";
+
+enum TaskType {
+  MESSAGEBOX,
+  ENDDIALOG,
+  RECURSIVE,
+  TIMEDMESSAGELOOP,
+  QUITMESSAGELOOP,
+  ORDERED,
+  PUMPS,
+  SLEEP,
+  RUNS,
+};
+
+// Saves the order in which the tasks executed.
+struct TaskItem {
+  TaskItem(TaskType t, int c, bool s)
+      : type(t),
+        cookie(c),
+        start(s) {
+  }
+
+  TaskType type;
+  int cookie;
+  bool start;
+
+  bool operator == (const TaskItem& other) const {
+    return type == other.type && cookie == other.cookie && start == other.start;
+  }
+};
+
+std::ostream& operator <<(std::ostream& os, TaskType type) {
+  switch (type) {
+  case MESSAGEBOX:        os << "MESSAGEBOX"; break;
+  case ENDDIALOG:         os << "ENDDIALOG"; break;
+  case RECURSIVE:         os << "RECURSIVE"; break;
+  case TIMEDMESSAGELOOP:  os << "TIMEDMESSAGELOOP"; break;
+  case QUITMESSAGELOOP:   os << "QUITMESSAGELOOP"; break;
+  case ORDERED:          os << "ORDERED"; break;
+  case PUMPS:             os << "PUMPS"; break;
+  case SLEEP:             os << "SLEEP"; break;
+  default:
+    NOTREACHED();
+    os << "Unknown TaskType";
+    break;
+  }
+  return os;
+}
+
+std::ostream& operator <<(std::ostream& os, const TaskItem& item) {
+  if (item.start)
+    return os << item.type << " " << item.cookie << " starts";
+  else
+    return os << item.type << " " << item.cookie << " ends";
+}
+
+class TaskList {
+ public:
+  void RecordStart(TaskType type, int cookie) {
+    TaskItem item(type, cookie, true);
+    DVLOG(1) << item;
+    task_list_.push_back(item);
+  }
+
+  void RecordEnd(TaskType type, int cookie) {
+    TaskItem item(type, cookie, false);
+    DVLOG(1) << item;
+    task_list_.push_back(item);
+  }
+
+  size_t Size() {
+    return task_list_.size();
+  }
+
+  TaskItem Get(int n)  {
+    return task_list_[n];
+  }
+
+ private:
+  std::vector<TaskItem> task_list_;
+};
+
+// MessageLoop implicitly start a "modal message loop". Modal dialog boxes,
+// common controls (like OpenFile) and StartDoc printing function can cause
+// implicit message loops.
+void MessageBoxFunc(TaskList* order, int cookie, bool is_reentrant) {
+  order->RecordStart(MESSAGEBOX, cookie);
+  if (is_reentrant)
+    MessageLoop::current()->SetNestableTasksAllowed(true);
+  MessageBox(NULL, L"Please wait...", kMessageBoxTitle, MB_OK);
+  order->RecordEnd(MESSAGEBOX, cookie);
+}
+
+// Will end the MessageBox.
+void EndDialogFunc(TaskList* order, int cookie) {
+  order->RecordStart(ENDDIALOG, cookie);
+  HWND window = GetActiveWindow();
+  if (window != NULL) {
+    EXPECT_NE(EndDialog(window, IDCONTINUE), 0);
+    // Cheap way to signal that the window wasn't found if RunEnd() isn't
+    // called.
+    order->RecordEnd(ENDDIALOG, cookie);
+  }
+}
+
+void RecursiveFunc(TaskList* order, int cookie, int depth,
+                   bool is_reentrant) {
+  order->RecordStart(RECURSIVE, cookie);
+  if (depth > 0) {
+    if (is_reentrant)
+      MessageLoop::current()->SetNestableTasksAllowed(true);
+    MessageLoop::current()->PostTask(
+        FROM_HERE,
+        Bind(&RecursiveFunc, order, cookie, depth - 1, is_reentrant));
+  }
+  order->RecordEnd(RECURSIVE, cookie);
+}
+
+void QuitFunc(TaskList* order, int cookie) {
+  order->RecordStart(QUITMESSAGELOOP, cookie);
+  MessageLoop::current()->QuitWhenIdle();
+  order->RecordEnd(QUITMESSAGELOOP, cookie);
+}
+
+void RecursiveFuncWin(MessageLoop* target,
+                      HANDLE event,
+                      bool expect_window,
+                      TaskList* order,
+                      bool is_reentrant) {
+  target->PostTask(FROM_HERE,
+                   Bind(&RecursiveFunc, order, 1, 2, is_reentrant));
+  target->PostTask(FROM_HERE,
+                   Bind(&MessageBoxFunc, order, 2, is_reentrant));
+  target->PostTask(FROM_HERE,
+                   Bind(&RecursiveFunc, order, 3, 2, is_reentrant));
+  // The trick here is that for recursive task processing, this task will be
+  // ran _inside_ the MessageBox message loop, dismissing the MessageBox
+  // without a chance.
+  // For non-recursive task processing, this will be executed _after_ the
+  // MessageBox will have been dismissed by the code below, where
+  // expect_window_ is true.
+  target->PostTask(FROM_HERE,
+                   Bind(&EndDialogFunc, order, 4));
+  target->PostTask(FROM_HERE,
+                   Bind(&QuitFunc, order, 5));
+
+  // Enforce that every tasks are sent before starting to run the main thread
+  // message loop.
+  ASSERT_TRUE(SetEvent(event));
+
+  // Poll for the MessageBox. Don't do this at home! At the speed we do it,
+  // you will never realize one MessageBox was shown.
+  for (; expect_window;) {
+    HWND window = FindWindow(L"#32770", kMessageBoxTitle);
+    if (window) {
+      // Dismiss it.
+      for (;;) {
+        HWND button = FindWindowEx(window, NULL, L"Button", NULL);
+        if (button != NULL) {
+          EXPECT_EQ(0, SendMessage(button, WM_LBUTTONDOWN, 0, 0));
+          EXPECT_EQ(0, SendMessage(button, WM_LBUTTONUP, 0, 0));
+          break;
+        }
+      }
+      break;
+    }
+  }
+}
+
+// TODO(darin): These tests need to be ported since they test critical
+// message loop functionality.
+
+// A side effect of this test is the generation a beep. Sorry.
+void RunTest_RecursiveDenial2(MessageLoop::Type message_loop_type) {
+  MessageLoop loop(message_loop_type);
+
+  Thread worker("RecursiveDenial2_worker");
+  Thread::Options options;
+  options.message_loop_type = message_loop_type;
+  ASSERT_EQ(true, worker.StartWithOptions(options));
+  TaskList order;
+  win::ScopedHandle event(CreateEvent(NULL, FALSE, FALSE, NULL));
+  worker.message_loop()->PostTask(FROM_HERE,
+                                  Bind(&RecursiveFuncWin,
+                                             MessageLoop::current(),
+                                             event.Get(),
+                                             true,
+                                             &order,
+                                             false));
+  // Let the other thread execute.
+  WaitForSingleObject(event.Get(), INFINITE);
+  MessageLoop::current()->Run();
+
+  ASSERT_EQ(order.Size(), 17);
+  EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true));
+  EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false));
+  EXPECT_EQ(order.Get(2), TaskItem(MESSAGEBOX, 2, true));
+  EXPECT_EQ(order.Get(3), TaskItem(MESSAGEBOX, 2, false));
+  EXPECT_EQ(order.Get(4), TaskItem(RECURSIVE, 3, true));
+  EXPECT_EQ(order.Get(5), TaskItem(RECURSIVE, 3, false));
+  // When EndDialogFunc is processed, the window is already dismissed, hence no
+  // "end" entry.
+  EXPECT_EQ(order.Get(6), TaskItem(ENDDIALOG, 4, true));
+  EXPECT_EQ(order.Get(7), TaskItem(QUITMESSAGELOOP, 5, true));
+  EXPECT_EQ(order.Get(8), TaskItem(QUITMESSAGELOOP, 5, false));
+  EXPECT_EQ(order.Get(9), TaskItem(RECURSIVE, 1, true));
+  EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, false));
+  EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 3, true));
+  EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 3, false));
+  EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 1, true));
+  EXPECT_EQ(order.Get(14), TaskItem(RECURSIVE, 1, false));
+  EXPECT_EQ(order.Get(15), TaskItem(RECURSIVE, 3, true));
+  EXPECT_EQ(order.Get(16), TaskItem(RECURSIVE, 3, false));
+}
+
+// A side effect of this test is the generation a beep. Sorry.  This test also
+// needs to process windows messages on the current thread.
+void RunTest_RecursiveSupport2(MessageLoop::Type message_loop_type) {
+  MessageLoop loop(message_loop_type);
+
+  Thread worker("RecursiveSupport2_worker");
+  Thread::Options options;
+  options.message_loop_type = message_loop_type;
+  ASSERT_EQ(true, worker.StartWithOptions(options));
+  TaskList order;
+  win::ScopedHandle event(CreateEvent(NULL, FALSE, FALSE, NULL));
+  worker.message_loop()->PostTask(FROM_HERE,
+                                  Bind(&RecursiveFuncWin,
+                                             MessageLoop::current(),
+                                             event.Get(),
+                                             false,
+                                             &order,
+                                             true));
+  // Let the other thread execute.
+  WaitForSingleObject(event.Get(), INFINITE);
+  MessageLoop::current()->Run();
+
+  ASSERT_EQ(order.Size(), 18);
+  EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true));
+  EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false));
+  EXPECT_EQ(order.Get(2), TaskItem(MESSAGEBOX, 2, true));
+  // Note that this executes in the MessageBox modal loop.
+  EXPECT_EQ(order.Get(3), TaskItem(RECURSIVE, 3, true));
+  EXPECT_EQ(order.Get(4), TaskItem(RECURSIVE, 3, false));
+  EXPECT_EQ(order.Get(5), TaskItem(ENDDIALOG, 4, true));
+  EXPECT_EQ(order.Get(6), TaskItem(ENDDIALOG, 4, false));
+  EXPECT_EQ(order.Get(7), TaskItem(MESSAGEBOX, 2, false));
+  /* The order can subtly change here. The reason is that when RecursiveFunc(1)
+     is called in the main thread, if it is faster than getting to the
+     PostTask(FROM_HERE, Bind(&QuitFunc) execution, the order of task
+     execution can change. We don't care anyway that the order isn't correct.
+  EXPECT_EQ(order.Get(8), TaskItem(QUITMESSAGELOOP, 5, true));
+  EXPECT_EQ(order.Get(9), TaskItem(QUITMESSAGELOOP, 5, false));
+  EXPECT_EQ(order.Get(10), TaskItem(RECURSIVE, 1, true));
+  EXPECT_EQ(order.Get(11), TaskItem(RECURSIVE, 1, false));
+  */
+  EXPECT_EQ(order.Get(12), TaskItem(RECURSIVE, 3, true));
+  EXPECT_EQ(order.Get(13), TaskItem(RECURSIVE, 3, false));
+  EXPECT_EQ(order.Get(14), TaskItem(RECURSIVE, 1, true));
+  EXPECT_EQ(order.Get(15), TaskItem(RECURSIVE, 1, false));
+  EXPECT_EQ(order.Get(16), TaskItem(RECURSIVE, 3, true));
+  EXPECT_EQ(order.Get(17), TaskItem(RECURSIVE, 3, false));
+}
+
+#endif  // defined(OS_WIN)
+
+void PostNTasksThenQuit(int posts_remaining) {
+  if (posts_remaining > 1) {
+    MessageLoop::current()->PostTask(
+        FROM_HERE,
+        Bind(&PostNTasksThenQuit, posts_remaining - 1));
+  } else {
+    MessageLoop::current()->QuitWhenIdle();
+  }
+}
+
+#if defined(OS_WIN)
+
+class DispatcherImpl : public MessagePumpDispatcher {
+ public:
+  DispatcherImpl() : dispatch_count_(0) {}
+
+  uint32_t Dispatch(const NativeEvent& msg) override {
+    ::TranslateMessage(&msg);
+    ::DispatchMessage(&msg);
+    // Do not count WM_TIMER since it is not what we post and it will cause
+    // flakiness.
+    if (msg.message != WM_TIMER)
+      ++dispatch_count_;
+    // We treat WM_LBUTTONUP as the last message.
+    return msg.message == WM_LBUTTONUP ? POST_DISPATCH_QUIT_LOOP
+                                       : POST_DISPATCH_NONE;
+  }
+
+  int dispatch_count_;
+};
+
+void MouseDownUp() {
+  PostMessage(NULL, WM_LBUTTONDOWN, 0, 0);
+  PostMessage(NULL, WM_LBUTTONUP, 'A', 0);
+}
+
+void RunTest_Dispatcher(MessageLoop::Type message_loop_type) {
+  MessageLoop loop(message_loop_type);
+
+  MessageLoop::current()->PostDelayedTask(
+      FROM_HERE,
+      Bind(&MouseDownUp),
+      TimeDelta::FromMilliseconds(100));
+  DispatcherImpl dispatcher;
+  RunLoop run_loop(&dispatcher);
+  run_loop.Run();
+  ASSERT_EQ(2, dispatcher.dispatch_count_);
+}
+
+LRESULT CALLBACK MsgFilterProc(int code, WPARAM wparam, LPARAM lparam) {
+  if (code == MessagePumpForUI::kMessageFilterCode) {
+    MSG* msg = reinterpret_cast<MSG*>(lparam);
+    if (msg->message == WM_LBUTTONDOWN)
+      return TRUE;
+  }
+  return FALSE;
+}
+
+void RunTest_DispatcherWithMessageHook(MessageLoop::Type message_loop_type) {
+  MessageLoop loop(message_loop_type);
+
+  MessageLoop::current()->PostDelayedTask(
+      FROM_HERE,
+      Bind(&MouseDownUp),
+      TimeDelta::FromMilliseconds(100));
+  HHOOK msg_hook = SetWindowsHookEx(WH_MSGFILTER,
+                                    MsgFilterProc,
+                                    NULL,
+                                    GetCurrentThreadId());
+  DispatcherImpl dispatcher;
+  RunLoop run_loop(&dispatcher);
+  run_loop.Run();
+  ASSERT_EQ(1, dispatcher.dispatch_count_);
+  UnhookWindowsHookEx(msg_hook);
+}
+
+class TestIOHandler : public MessageLoopForIO::IOHandler {
+ public:
+  TestIOHandler(const wchar_t* name, HANDLE signal, bool wait);
+
+  void OnIOCompleted(MessageLoopForIO::IOContext* context,
+                     DWORD bytes_transfered,
+                     DWORD error) override;
+
+  void Init();
+  void WaitForIO();
+  OVERLAPPED* context() { return &context_.overlapped; }
+  DWORD size() { return sizeof(buffer_); }
+
+ private:
+  char buffer_[48];
+  MessageLoopForIO::IOContext context_;
+  HANDLE signal_;
+  win::ScopedHandle file_;
+  bool wait_;
+};
+
+TestIOHandler::TestIOHandler(const wchar_t* name, HANDLE signal, bool wait)
+    : signal_(signal), wait_(wait) {
+  memset(buffer_, 0, sizeof(buffer_));
+  memset(&context_, 0, sizeof(context_));
+  context_.handler = this;
+
+  file_.Set(CreateFile(name, GENERIC_READ, 0, NULL, OPEN_EXISTING,
+                       FILE_FLAG_OVERLAPPED, NULL));
+  EXPECT_TRUE(file_.IsValid());
+}
+
+void TestIOHandler::Init() {
+  MessageLoopForIO::current()->RegisterIOHandler(file_.Get(), this);
+
+  DWORD read;
+  EXPECT_FALSE(ReadFile(file_.Get(), buffer_, size(), &read, context()));
+  EXPECT_EQ(ERROR_IO_PENDING, GetLastError());
+  if (wait_)
+    WaitForIO();
+}
+
+void TestIOHandler::OnIOCompleted(MessageLoopForIO::IOContext* context,
+                                  DWORD bytes_transfered, DWORD error) {
+  ASSERT_TRUE(context == &context_);
+  ASSERT_TRUE(SetEvent(signal_));
+}
+
+void TestIOHandler::WaitForIO() {
+  EXPECT_TRUE(MessageLoopForIO::current()->WaitForIOCompletion(300, this));
+  EXPECT_TRUE(MessageLoopForIO::current()->WaitForIOCompletion(400, this));
+}
+
+void RunTest_IOHandler() {
+  win::ScopedHandle callback_called(CreateEvent(NULL, TRUE, FALSE, NULL));
+  ASSERT_TRUE(callback_called.IsValid());
+
+  const wchar_t* kPipeName = L"\\\\.\\pipe\\iohandler_pipe";
+  win::ScopedHandle server(
+      CreateNamedPipe(kPipeName, PIPE_ACCESS_OUTBOUND, 0, 1, 0, 0, 0, NULL));
+  ASSERT_TRUE(server.IsValid());
+
+  Thread thread("IOHandler test");
+  Thread::Options options;
+  options.message_loop_type = MessageLoop::TYPE_IO;
+  ASSERT_TRUE(thread.StartWithOptions(options));
+
+  MessageLoop* thread_loop = thread.message_loop();
+  ASSERT_TRUE(NULL != thread_loop);
+
+  TestIOHandler handler(kPipeName, callback_called.Get(), false);
+  thread_loop->PostTask(FROM_HERE, Bind(&TestIOHandler::Init,
+                                              Unretained(&handler)));
+  // Make sure the thread runs and sleeps for lack of work.
+  PlatformThread::Sleep(TimeDelta::FromMilliseconds(100));
+
+  const char buffer[] = "Hello there!";
+  DWORD written;
+  EXPECT_TRUE(WriteFile(server.Get(), buffer, sizeof(buffer), &written, NULL));
+
+  DWORD result = WaitForSingleObject(callback_called.Get(), 1000);
+  EXPECT_EQ(WAIT_OBJECT_0, result);
+
+  thread.Stop();
+}
+
+void RunTest_WaitForIO() {
+  win::ScopedHandle callback1_called(
+      CreateEvent(NULL, TRUE, FALSE, NULL));
+  win::ScopedHandle callback2_called(
+      CreateEvent(NULL, TRUE, FALSE, NULL));
+  ASSERT_TRUE(callback1_called.IsValid());
+  ASSERT_TRUE(callback2_called.IsValid());
+
+  const wchar_t* kPipeName1 = L"\\\\.\\pipe\\iohandler_pipe1";
+  const wchar_t* kPipeName2 = L"\\\\.\\pipe\\iohandler_pipe2";
+  win::ScopedHandle server1(
+      CreateNamedPipe(kPipeName1, PIPE_ACCESS_OUTBOUND, 0, 1, 0, 0, 0, NULL));
+  win::ScopedHandle server2(
+      CreateNamedPipe(kPipeName2, PIPE_ACCESS_OUTBOUND, 0, 1, 0, 0, 0, NULL));
+  ASSERT_TRUE(server1.IsValid());
+  ASSERT_TRUE(server2.IsValid());
+
+  Thread thread("IOHandler test");
+  Thread::Options options;
+  options.message_loop_type = MessageLoop::TYPE_IO;
+  ASSERT_TRUE(thread.StartWithOptions(options));
+
+  MessageLoop* thread_loop = thread.message_loop();
+  ASSERT_TRUE(NULL != thread_loop);
+
+  TestIOHandler handler1(kPipeName1, callback1_called.Get(), false);
+  TestIOHandler handler2(kPipeName2, callback2_called.Get(), true);
+  thread_loop->PostTask(FROM_HERE, Bind(&TestIOHandler::Init,
+                                              Unretained(&handler1)));
+  // TODO(ajwong): Do we really need such long Sleeps in ths function?
+  // Make sure the thread runs and sleeps for lack of work.
+  TimeDelta delay = TimeDelta::FromMilliseconds(100);
+  PlatformThread::Sleep(delay);
+  thread_loop->PostTask(FROM_HERE, Bind(&TestIOHandler::Init,
+                                              Unretained(&handler2)));
+  PlatformThread::Sleep(delay);
+
+  // At this time handler1 is waiting to be called, and the thread is waiting
+  // on the Init method of handler2, filtering only handler2 callbacks.
+
+  const char buffer[] = "Hello there!";
+  DWORD written;
+  EXPECT_TRUE(WriteFile(server1.Get(), buffer, sizeof(buffer), &written, NULL));
+  PlatformThread::Sleep(2 * delay);
+  EXPECT_EQ(WAIT_TIMEOUT, WaitForSingleObject(callback1_called.Get(), 0)) <<
+      "handler1 has not been called";
+
+  EXPECT_TRUE(WriteFile(server2.Get(), buffer, sizeof(buffer), &written, NULL));
+
+  HANDLE objects[2] = { callback1_called.Get(), callback2_called.Get() };
+  DWORD result = WaitForMultipleObjects(2, objects, TRUE, 1000);
+  EXPECT_EQ(WAIT_OBJECT_0, result);
+
+  thread.Stop();
+}
+
+#endif  // defined(OS_WIN)
+
+}  // namespace
+
+//-----------------------------------------------------------------------------
+// Each test is run against each type of MessageLoop.  That way we are sure
+// that message loops work properly in all configurations.  Of course, in some
+// cases, a unit test may only be for a particular type of loop.
+
+RUN_MESSAGE_LOOP_TESTS(Default, &TypeDefaultMessagePumpFactory);
+RUN_MESSAGE_LOOP_TESTS(UI, &TypeUIMessagePumpFactory);
+RUN_MESSAGE_LOOP_TESTS(IO, &TypeIOMessagePumpFactory);
+
+#if defined(OS_WIN)
+TEST(MessageLoopTest, PostDelayedTask_SharedTimer_SubPump) {
+  RunTest_PostDelayedTask_SharedTimer_SubPump();
+}
+
+// This test occasionally hangs http://crbug.com/44567
+TEST(MessageLoopTest, DISABLED_RecursiveDenial2) {
+  RunTest_RecursiveDenial2(MessageLoop::TYPE_DEFAULT);
+  RunTest_RecursiveDenial2(MessageLoop::TYPE_UI);
+  RunTest_RecursiveDenial2(MessageLoop::TYPE_IO);
+}
+
+TEST(MessageLoopTest, RecursiveSupport2) {
+  // This test requires a UI loop
+  RunTest_RecursiveSupport2(MessageLoop::TYPE_UI);
+}
+#endif  // defined(OS_WIN)
+
+class DummyTaskObserver : public MessageLoop::TaskObserver {
+ public:
+  explicit DummyTaskObserver(int num_tasks)
+      : num_tasks_started_(0),
+        num_tasks_processed_(0),
+        num_tasks_(num_tasks) {}
+
+  ~DummyTaskObserver() override {}
+
+  void WillProcessTask(const PendingTask& pending_task) override {
+    num_tasks_started_++;
+    EXPECT_LE(num_tasks_started_, num_tasks_);
+    EXPECT_EQ(num_tasks_started_, num_tasks_processed_ + 1);
+  }
+
+  void DidProcessTask(const PendingTask& pending_task) override {
+    num_tasks_processed_++;
+    EXPECT_LE(num_tasks_started_, num_tasks_);
+    EXPECT_EQ(num_tasks_started_, num_tasks_processed_);
+  }
+
+  int num_tasks_started() const { return num_tasks_started_; }
+  int num_tasks_processed() const { return num_tasks_processed_; }
+
+ private:
+  int num_tasks_started_;
+  int num_tasks_processed_;
+  const int num_tasks_;
+
+  DISALLOW_COPY_AND_ASSIGN(DummyTaskObserver);
+};
+
+TEST(MessageLoopTest, TaskObserver) {
+  const int kNumPosts = 6;
+  DummyTaskObserver observer(kNumPosts);
+
+  MessageLoop loop;
+  loop.AddTaskObserver(&observer);
+  loop.PostTask(FROM_HERE, Bind(&PostNTasksThenQuit, kNumPosts));
+  loop.Run();
+  loop.RemoveTaskObserver(&observer);
+
+  EXPECT_EQ(kNumPosts, observer.num_tasks_started());
+  EXPECT_EQ(kNumPosts, observer.num_tasks_processed());
+}
+
+#if defined(OS_WIN)
+TEST(MessageLoopTest, Dispatcher) {
+  // This test requires a UI loop
+  RunTest_Dispatcher(MessageLoop::TYPE_UI);
+}
+
+TEST(MessageLoopTest, DispatcherWithMessageHook) {
+  // This test requires a UI loop
+  RunTest_DispatcherWithMessageHook(MessageLoop::TYPE_UI);
+}
+
+TEST(MessageLoopTest, IOHandler) {
+  RunTest_IOHandler();
+}
+
+TEST(MessageLoopTest, WaitForIO) {
+  RunTest_WaitForIO();
+}
+
+TEST(MessageLoopTest, HighResolutionTimer) {
+  MessageLoop loop;
+  Time::EnableHighResolutionTimer(true);
+
+  const TimeDelta kFastTimer = TimeDelta::FromMilliseconds(5);
+  const TimeDelta kSlowTimer = TimeDelta::FromMilliseconds(100);
+
+  EXPECT_FALSE(loop.HasHighResolutionTasks());
+  // Post a fast task to enable the high resolution timers.
+  loop.PostDelayedTask(FROM_HERE, Bind(&PostNTasksThenQuit, 1),
+                       kFastTimer);
+  EXPECT_TRUE(loop.HasHighResolutionTasks());
+  loop.Run();
+  EXPECT_FALSE(loop.HasHighResolutionTasks());
+  EXPECT_FALSE(Time::IsHighResolutionTimerInUse());
+  // Check that a slow task does not trigger the high resolution logic.
+  loop.PostDelayedTask(FROM_HERE, Bind(&PostNTasksThenQuit, 1),
+                       kSlowTimer);
+  EXPECT_FALSE(loop.HasHighResolutionTasks());
+  loop.Run();
+  EXPECT_FALSE(loop.HasHighResolutionTasks());
+  Time::EnableHighResolutionTimer(false);
+}
+
+#endif  // defined(OS_WIN)
+
+#if defined(OS_POSIX) && !defined(OS_NACL)
+
+namespace {
+
+class QuitDelegate : public MessageLoopForIO::Watcher {
+ public:
+  void OnFileCanWriteWithoutBlocking(int fd) override {
+    MessageLoop::current()->QuitWhenIdle();
+  }
+  void OnFileCanReadWithoutBlocking(int fd) override {
+    MessageLoop::current()->QuitWhenIdle();
+  }
+};
+
+TEST(MessageLoopTest, FileDescriptorWatcherOutlivesMessageLoop) {
+  // Simulate a MessageLoop that dies before an FileDescriptorWatcher.
+  // This could happen when people use the Singleton pattern or atexit.
+
+  // Create a file descriptor.  Doesn't need to be readable or writable,
+  // as we don't need to actually get any notifications.
+  // pipe() is just the easiest way to do it.
+  int pipefds[2];
+  int err = pipe(pipefds);
+  ASSERT_EQ(0, err);
+  int fd = pipefds[1];
+  {
+    // Arrange for controller to live longer than message loop.
+    MessageLoopForIO::FileDescriptorWatcher controller;
+    {
+      MessageLoopForIO message_loop;
+
+      QuitDelegate delegate;
+      message_loop.WatchFileDescriptor(fd,
+          true, MessageLoopForIO::WATCH_WRITE, &controller, &delegate);
+      // and don't run the message loop, just destroy it.
+    }
+  }
+  if (IGNORE_EINTR(close(pipefds[0])) < 0)
+    PLOG(ERROR) << "close";
+  if (IGNORE_EINTR(close(pipefds[1])) < 0)
+    PLOG(ERROR) << "close";
+}
+
+TEST(MessageLoopTest, FileDescriptorWatcherDoubleStop) {
+  // Verify that it's ok to call StopWatchingFileDescriptor().
+  // (Errors only showed up in valgrind.)
+  int pipefds[2];
+  int err = pipe(pipefds);
+  ASSERT_EQ(0, err);
+  int fd = pipefds[1];
+  {
+    // Arrange for message loop to live longer than controller.
+    MessageLoopForIO message_loop;
+    {
+      MessageLoopForIO::FileDescriptorWatcher controller;
+
+      QuitDelegate delegate;
+      message_loop.WatchFileDescriptor(fd,
+          true, MessageLoopForIO::WATCH_WRITE, &controller, &delegate);
+      controller.StopWatchingFileDescriptor();
+    }
+  }
+  if (IGNORE_EINTR(close(pipefds[0])) < 0)
+    PLOG(ERROR) << "close";
+  if (IGNORE_EINTR(close(pipefds[1])) < 0)
+    PLOG(ERROR) << "close";
+}
+
+}  // namespace
+
+#endif  // defined(OS_POSIX) && !defined(OS_NACL)
+
+namespace {
+// Inject a test point for recording the destructor calls for Closure objects
+// send to MessageLoop::PostTask(). It is awkward usage since we are trying to
+// hook the actual destruction, which is not a common operation.
+class DestructionObserverProbe :
+  public RefCounted<DestructionObserverProbe> {
+ public:
+  DestructionObserverProbe(bool* task_destroyed,
+                           bool* destruction_observer_called)
+      : task_destroyed_(task_destroyed),
+        destruction_observer_called_(destruction_observer_called) {
+  }
+  virtual void Run() {
+    // This task should never run.
+    ADD_FAILURE();
+  }
+ private:
+  friend class RefCounted<DestructionObserverProbe>;
+
+  virtual ~DestructionObserverProbe() {
+    EXPECT_FALSE(*destruction_observer_called_);
+    *task_destroyed_ = true;
+  }
+
+  bool* task_destroyed_;
+  bool* destruction_observer_called_;
+};
+
+class MLDestructionObserver : public MessageLoop::DestructionObserver {
+ public:
+  MLDestructionObserver(bool* task_destroyed, bool* destruction_observer_called)
+      : task_destroyed_(task_destroyed),
+        destruction_observer_called_(destruction_observer_called),
+        task_destroyed_before_message_loop_(false) {
+  }
+  void WillDestroyCurrentMessageLoop() override {
+    task_destroyed_before_message_loop_ = *task_destroyed_;
+    *destruction_observer_called_ = true;
+  }
+  bool task_destroyed_before_message_loop() const {
+    return task_destroyed_before_message_loop_;
+  }
+ private:
+  bool* task_destroyed_;
+  bool* destruction_observer_called_;
+  bool task_destroyed_before_message_loop_;
+};
+
+}  // namespace
+
+TEST(MessageLoopTest, DestructionObserverTest) {
+  // Verify that the destruction observer gets called at the very end (after
+  // all the pending tasks have been destroyed).
+  MessageLoop* loop = new MessageLoop;
+  const TimeDelta kDelay = TimeDelta::FromMilliseconds(100);
+
+  bool task_destroyed = false;
+  bool destruction_observer_called = false;
+
+  MLDestructionObserver observer(&task_destroyed, &destruction_observer_called);
+  loop->AddDestructionObserver(&observer);
+  loop->PostDelayedTask(
+      FROM_HERE,
+      Bind(&DestructionObserverProbe::Run,
+                 new DestructionObserverProbe(&task_destroyed,
+                                              &destruction_observer_called)),
+      kDelay);
+  delete loop;
+  EXPECT_TRUE(observer.task_destroyed_before_message_loop());
+  // The task should have been destroyed when we deleted the loop.
+  EXPECT_TRUE(task_destroyed);
+  EXPECT_TRUE(destruction_observer_called);
+}
+
+
+// Verify that MessageLoop sets ThreadMainTaskRunner::current() and it
+// posts tasks on that message loop.
+TEST(MessageLoopTest, ThreadMainTaskRunner) {
+  MessageLoop loop;
+
+  scoped_refptr<Foo> foo(new Foo());
+  std::string a("a");
+  ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, Bind(
+      &Foo::Test1ConstRef, foo.get(), a));
+
+  // Post quit task;
+  MessageLoop::current()->PostTask(FROM_HERE, Bind(
+      &MessageLoop::Quit, Unretained(MessageLoop::current())));
+
+  // Now kick things off
+  MessageLoop::current()->Run();
+
+  EXPECT_EQ(foo->test_count(), 1);
+  EXPECT_EQ(foo->result(), "a");
+}
+
+TEST(MessageLoopTest, IsType) {
+  MessageLoop loop(MessageLoop::TYPE_UI);
+  EXPECT_TRUE(loop.IsType(MessageLoop::TYPE_UI));
+  EXPECT_FALSE(loop.IsType(MessageLoop::TYPE_IO));
+  EXPECT_FALSE(loop.IsType(MessageLoop::TYPE_DEFAULT));
+}
+
+#if defined(OS_WIN)
+void EmptyFunction() {}
+
+void PostMultipleTasks() {
+  MessageLoop::current()->PostTask(FROM_HERE, base::Bind(&EmptyFunction));
+  MessageLoop::current()->PostTask(FROM_HERE, base::Bind(&EmptyFunction));
+}
+
+static const int kSignalMsg = WM_USER + 2;
+
+void PostWindowsMessage(HWND message_hwnd) {
+  PostMessage(message_hwnd, kSignalMsg, 0, 2);
+}
+
+void EndTest(bool* did_run, HWND hwnd) {
+  *did_run = true;
+  PostMessage(hwnd, WM_CLOSE, 0, 0);
+}
+
+int kMyMessageFilterCode = 0x5002;
+
+LRESULT CALLBACK TestWndProcThunk(HWND hwnd, UINT message,
+                                  WPARAM wparam, LPARAM lparam) {
+  if (message == WM_CLOSE)
+    EXPECT_TRUE(DestroyWindow(hwnd));
+  if (message != kSignalMsg)
+    return DefWindowProc(hwnd, message, wparam, lparam);
+
+  switch (lparam) {
+  case 1:
+    // First, we post a task that will post multiple no-op tasks to make sure
+    // that the pump's incoming task queue does not become empty during the
+    // test.
+    MessageLoop::current()->PostTask(FROM_HERE, base::Bind(&PostMultipleTasks));
+    // Next, we post a task that posts a windows message to trigger the second
+    // stage of the test.
+    MessageLoop::current()->PostTask(FROM_HERE,
+                                     base::Bind(&PostWindowsMessage, hwnd));
+    break;
+  case 2:
+    // Since we're about to enter a modal loop, tell the message loop that we
+    // intend to nest tasks.
+    MessageLoop::current()->SetNestableTasksAllowed(true);
+    bool did_run = false;
+    MessageLoop::current()->PostTask(FROM_HERE,
+                                     base::Bind(&EndTest, &did_run, hwnd));
+    // Run a nested windows-style message loop and verify that our task runs. If
+    // it doesn't, then we'll loop here until the test times out.
+    MSG msg;
+    while (GetMessage(&msg, 0, 0, 0)) {
+      if (!CallMsgFilter(&msg, kMyMessageFilterCode))
+        DispatchMessage(&msg);
+      // If this message is a WM_CLOSE, explicitly exit the modal loop. Posting
+      // a WM_QUIT should handle this, but unfortunately MessagePumpWin eats
+      // WM_QUIT messages even when running inside a modal loop.
+      if (msg.message == WM_CLOSE)
+        break;
+    }
+    EXPECT_TRUE(did_run);
+    MessageLoop::current()->Quit();
+    break;
+  }
+  return 0;
+}
+
+TEST(MessageLoopTest, AlwaysHaveUserMessageWhenNesting) {
+  MessageLoop loop(MessageLoop::TYPE_UI);
+  HINSTANCE instance = GetModuleFromAddress(&TestWndProcThunk);
+  WNDCLASSEX wc = {0};
+  wc.cbSize = sizeof(wc);
+  wc.lpfnWndProc = TestWndProcThunk;
+  wc.hInstance = instance;
+  wc.lpszClassName = L"MessageLoopTest_HWND";
+  ATOM atom = RegisterClassEx(&wc);
+  ASSERT_TRUE(atom);
+
+  HWND message_hwnd = CreateWindow(MAKEINTATOM(atom), 0, 0, 0, 0, 0, 0,
+                                   HWND_MESSAGE, 0, instance, 0);
+  ASSERT_TRUE(message_hwnd) << GetLastError();
+
+  ASSERT_TRUE(PostMessage(message_hwnd, kSignalMsg, 0, 1));
+
+  loop.Run();
+
+  ASSERT_TRUE(UnregisterClass(MAKEINTATOM(atom), instance));
+}
+#endif  // defined(OS_WIN)
+
+}  // namespace base
diff --git a/base/message_loop/message_pump.cc b/base/message_loop/message_pump.cc
new file mode 100644
index 0000000..3d85b9b
--- /dev/null
+++ b/base/message_loop/message_pump.cc
@@ -0,0 +1,18 @@
+// Copyright (c) 2010 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/message_loop/message_pump.h"
+
+namespace base {
+
+MessagePump::MessagePump() {
+}
+
+MessagePump::~MessagePump() {
+}
+
+void MessagePump::SetTimerSlack(TimerSlack) {
+}
+
+}  // namespace base
diff --git a/base/message_loop/message_pump.h b/base/message_loop/message_pump.h
new file mode 100644
index 0000000..77a49ce
--- /dev/null
+++ b/base/message_loop/message_pump.h
@@ -0,0 +1,135 @@
+// Copyright (c) 2012 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_MESSAGE_LOOP_MESSAGE_PUMP_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/message_loop/timer_slack.h"
+#include "base/threading/non_thread_safe.h"
+
+namespace base {
+
+class TimeTicks;
+
+class BASE_EXPORT MessagePump : public NonThreadSafe {
+ public:
+  // Please see the comments above the Run method for an illustration of how
+  // these delegate methods are used.
+  class BASE_EXPORT Delegate {
+   public:
+    virtual ~Delegate() {}
+
+    // Called from within Run in response to ScheduleWork or when the message
+    // pump would otherwise call DoDelayedWork.  Returns true to indicate that
+    // work was done.  DoDelayedWork will still be called if DoWork returns
+    // true, but DoIdleWork will not.
+    virtual bool DoWork() = 0;
+
+    // Called from within Run in response to ScheduleDelayedWork or when the
+    // message pump would otherwise sleep waiting for more work.  Returns true
+    // to indicate that delayed work was done.  DoIdleWork will not be called
+    // if DoDelayedWork returns true.  Upon return |next_delayed_work_time|
+    // indicates the time when DoDelayedWork should be called again.  If
+    // |next_delayed_work_time| is null (per Time::is_null), then the queue of
+    // future delayed work (timer events) is currently empty, and no additional
+    // calls to this function need to be scheduled.
+    virtual bool DoDelayedWork(TimeTicks* next_delayed_work_time) = 0;
+
+    // Called from within Run just before the message pump goes to sleep.
+    // Returns true to indicate that idle work was done. Returning false means
+    // the pump will now wait.
+    virtual bool DoIdleWork() = 0;
+
+    // Returns the delay for the newly added task.
+    virtual TimeTicks GetNewlyAddedTaskDelay() = 0;
+  };
+
+  MessagePump();
+  virtual ~MessagePump();
+
+  // The Run method is called to enter the message pump's run loop.
+  //
+  // Within the method, the message pump is responsible for processing native
+  // messages as well as for giving cycles to the delegate periodically.  The
+  // message pump should take care to mix delegate callbacks with native
+  // message processing so neither type of event starves the other of cycles.
+  //
+  // The anatomy of a typical run loop:
+  //
+  //   for (;;) {
+  //     bool did_work = DoInternalWork();
+  //     if (should_quit_)
+  //       break;
+  //
+  //     did_work |= delegate_->DoWork();
+  //     if (should_quit_)
+  //       break;
+  //
+  //     TimeTicks next_time;
+  //     did_work |= delegate_->DoDelayedWork(&next_time);
+  //     if (should_quit_)
+  //       break;
+  //
+  //     if (did_work)
+  //       continue;
+  //
+  //     did_work = delegate_->DoIdleWork();
+  //     if (should_quit_)
+  //       break;
+  //
+  //     if (did_work)
+  //       continue;
+  //
+  //     WaitForWork();
+  //   }
+  //
+  // Here, DoInternalWork is some private method of the message pump that is
+  // responsible for dispatching the next UI message or notifying the next IO
+  // completion (for example).  WaitForWork is a private method that simply
+  // blocks until there is more work of any type to do.
+  //
+  // Notice that the run loop cycles between calling DoInternalWork, DoWork,
+  // and DoDelayedWork methods.  This helps ensure that none of these work
+  // queues starve the others.  This is important for message pumps that are
+  // used to drive animations, for example.
+  //
+  // Notice also that after each callout to foreign code, the run loop checks
+  // to see if it should quit.  The Quit method is responsible for setting this
+  // flag.  No further work is done once the quit flag is set.
+  //
+  // NOTE: Care must be taken to handle Run being called again from within any
+  // of the callouts to foreign code.  Native message pumps may also need to
+  // deal with other native message pumps being run outside their control
+  // (e.g., the MessageBox API on Windows pumps UI messages!).  To be specific,
+  // the callouts (DoWork and DoDelayedWork) MUST still be provided even in
+  // nested sub-loops that are "seemingly" outside the control of this message
+  // pump.  DoWork in particular must never be starved for time slices unless
+  // it returns false (meaning it has run out of things to do).
+  //
+  virtual void Run(Delegate* delegate) = 0;
+
+  // Quit immediately from the most recently entered run loop.  This method may
+  // only be used on the thread that called Run.
+  virtual void Quit() = 0;
+
+  // Schedule a DoWork callback to happen reasonably soon.  Does nothing if a
+  // DoWork callback is already scheduled.  This method may be called from any
+  // thread.  Once this call is made, DoWork should not be "starved" at least
+  // until it returns a value of false.
+  virtual void ScheduleWork() = 0;
+
+  // Schedule a DoDelayedWork callback to happen at the specified time,
+  // cancelling any pending DoDelayedWork callback.  This method may only be
+  // used on the thread that called Run.
+  virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) = 0;
+
+  // Sets the timer slack to the specified value.
+  virtual void SetTimerSlack(TimerSlack timer_slack);
+};
+
+}  // namespace base
+
+#endif  // BASE_MESSAGE_LOOP_MESSAGE_PUMP_H_
diff --git a/base/message_loop/message_pump_android.cc b/base/message_loop/message_pump_android.cc
new file mode 100644
index 0000000..babd17b
--- /dev/null
+++ b/base/message_loop/message_pump_android.cc
@@ -0,0 +1,162 @@
+// Copyright (c) 2012 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/message_loop/message_pump_android.h"
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/run_loop.h"
+#include "base/time/time.h"
+#include "jni/SystemMessageHandler_jni.h"
+
+using base::android::ScopedJavaLocalRef;
+
+// ----------------------------------------------------------------------------
+// Native JNI methods called by Java.
+// ----------------------------------------------------------------------------
+// This method can not move to anonymous namespace as it has been declared as
+// 'static' in system_message_handler_jni.h.
+static void DoRunLoopOnce(JNIEnv* env, jobject obj, jlong native_delegate,
+    jlong delayed_scheduled_time_ticks) {
+  base::MessagePump::Delegate* delegate =
+      reinterpret_cast<base::MessagePump::Delegate*>(native_delegate);
+  DCHECK(delegate);
+  // This is based on MessagePumpForUI::DoRunLoop() from desktop.
+  // Note however that our system queue is handled in the java side.
+  // In desktop we inspect and process a single system message and then
+  // we call DoWork() / DoDelayedWork().
+  // On Android, the java message queue may contain messages for other handlers
+  // that will be processed before calling here again.
+  bool did_work = delegate->DoWork();
+
+  // In the java side, |SystemMessageHandler| keeps a single "delayed" message.
+  // It's an expensive operation to |removeMessage| there, so this is optimized
+  // to avoid those calls.
+  //
+  // At this stage, |next_delayed_work_time| can be:
+  // 1) The same as previously scheduled: nothing to be done, move along. This
+  // is the typical case, since this method is called for every single message.
+  //
+  // 2) Not previously scheduled: just post a new message in java.
+  //
+  // 3) Shorter than previously scheduled: far less common. In this case,
+  // |removeMessage| and post a new one.
+  //
+  // 4) Longer than previously scheduled (or null): nothing to be done, move
+  // along.
+  //
+  // Side note: base::TimeTicks is a C++ representation and can't be
+  // compared in java. When calling |scheduleDelayedWork|, pass the
+  // |InternalValue()| to java and then back to C++ so the comparisons can be
+  // done here.
+  // This roundtrip allows comparing TimeTicks directly (cheap) and
+  // avoid comparisons with TimeDelta / Now() (expensive).
+  base::TimeTicks next_delayed_work_time;
+  did_work |= delegate->DoDelayedWork(&next_delayed_work_time);
+
+  if (!next_delayed_work_time.is_null()) {
+    // Schedule a new message if there's nothing already scheduled or there's a
+    // shorter delay than previously scheduled (see (2) and (3) above).
+    if (delayed_scheduled_time_ticks == 0 ||
+        next_delayed_work_time < base::TimeTicks::FromInternalValue(
+            delayed_scheduled_time_ticks)) {
+      Java_SystemMessageHandler_scheduleDelayedWork(env, obj,
+          next_delayed_work_time.ToInternalValue(),
+          (next_delayed_work_time -
+           base::TimeTicks::Now()).InMillisecondsRoundedUp());
+    }
+  }
+
+  // This is a major difference between android and other platforms: since we
+  // can't inspect it and process just one single message, instead we'll yeld
+  // the callstack.
+  if (did_work)
+    return;
+
+  delegate->DoIdleWork();
+}
+
+namespace base {
+
+MessagePumpForUI::MessagePumpForUI()
+    : run_loop_(NULL) {
+}
+
+MessagePumpForUI::~MessagePumpForUI() {
+}
+
+void MessagePumpForUI::Run(Delegate* delegate) {
+  NOTREACHED() << "UnitTests should rely on MessagePumpForUIStub in"
+      " test_stub_android.h";
+}
+
+void MessagePumpForUI::Start(Delegate* delegate) {
+  run_loop_ = new RunLoop();
+  // Since the RunLoop was just created above, BeforeRun should be guaranteed to
+  // return true (it only returns false if the RunLoop has been Quit already).
+  if (!run_loop_->BeforeRun())
+    NOTREACHED();
+
+  DCHECK(system_message_handler_obj_.is_null());
+
+  JNIEnv* env = base::android::AttachCurrentThread();
+  DCHECK(env);
+
+  system_message_handler_obj_.Reset(
+      Java_SystemMessageHandler_create(
+          env, reinterpret_cast<intptr_t>(delegate)));
+}
+
+void MessagePumpForUI::Quit() {
+  if (!system_message_handler_obj_.is_null()) {
+    JNIEnv* env = base::android::AttachCurrentThread();
+    DCHECK(env);
+
+    Java_SystemMessageHandler_removeAllPendingMessages(env,
+        system_message_handler_obj_.obj());
+    system_message_handler_obj_.Reset();
+  }
+
+  if (run_loop_) {
+    run_loop_->AfterRun();
+    delete run_loop_;
+    run_loop_ = NULL;
+  }
+}
+
+void MessagePumpForUI::ScheduleWork() {
+  DCHECK(!system_message_handler_obj_.is_null());
+
+  JNIEnv* env = base::android::AttachCurrentThread();
+  DCHECK(env);
+
+  Java_SystemMessageHandler_scheduleWork(env,
+      system_message_handler_obj_.obj());
+}
+
+void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
+  DCHECK(!system_message_handler_obj_.is_null());
+
+  JNIEnv* env = base::android::AttachCurrentThread();
+  DCHECK(env);
+
+  jlong millis =
+      (delayed_work_time - TimeTicks::Now()).InMillisecondsRoundedUp();
+  // Note that we're truncating to milliseconds as required by the java side,
+  // even though delayed_work_time is microseconds resolution.
+  Java_SystemMessageHandler_scheduleDelayedWork(env,
+      system_message_handler_obj_.obj(),
+      delayed_work_time.ToInternalValue(), millis);
+}
+
+// static
+bool MessagePumpForUI::RegisterBindings(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace base
diff --git a/base/message_loop/message_pump_android.h b/base/message_loop/message_pump_android.h
new file mode 100644
index 0000000..d48050d
--- /dev/null
+++ b/base/message_loop/message_pump_android.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2012 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_MESSAGE_LOOP_MESSAGE_PUMP_ANDROID_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_ANDROID_H_
+
+#include <jni.h>
+
+#include "base/android/scoped_java_ref.h"
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/message_loop/message_pump.h"
+
+namespace base {
+
+class RunLoop;
+class TimeTicks;
+
+// This class implements a MessagePump needed for TYPE_UI MessageLoops on
+// OS_ANDROID platform.
+class BASE_EXPORT MessagePumpForUI : public MessagePump {
+ public:
+  MessagePumpForUI();
+  ~MessagePumpForUI() override;
+
+  void Run(Delegate* delegate) override;
+  void Quit() override;
+  void ScheduleWork() override;
+  void ScheduleDelayedWork(const TimeTicks& delayed_work_time) override;
+
+  virtual void Start(Delegate* delegate);
+
+  static bool RegisterBindings(JNIEnv* env);
+
+ private:
+  RunLoop* run_loop_;
+  base::android::ScopedJavaGlobalRef<jobject> system_message_handler_obj_;
+
+  DISALLOW_COPY_AND_ASSIGN(MessagePumpForUI);
+};
+
+}  // namespace base
+
+#endif  // BASE_MESSAGE_LOOP_MESSAGE_PUMP_ANDROID_H_
diff --git a/base/message_loop/message_pump_default.cc b/base/message_loop/message_pump_default.cc
new file mode 100644
index 0000000..daa80d8
--- /dev/null
+++ b/base/message_loop/message_pump_default.cc
@@ -0,0 +1,97 @@
+// Copyright (c) 2006-2008 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/message_loop/message_pump_default.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "base/threading/thread_restrictions.h"
+
+#if defined(OS_MACOSX)
+#include "base/mac/scoped_nsautorelease_pool.h"
+#endif
+
+namespace base {
+
+MessagePumpDefault::MessagePumpDefault()
+    : keep_running_(true),
+      event_(false, false) {
+}
+
+MessagePumpDefault::~MessagePumpDefault() {
+}
+
+void MessagePumpDefault::Run(Delegate* delegate) {
+  DCHECK(keep_running_) << "Quit must have been called outside of Run!";
+
+  for (;;) {
+#if defined(OS_MACOSX)
+    mac::ScopedNSAutoreleasePool autorelease_pool;
+#endif
+
+    bool did_work = delegate->DoWork();
+    if (!keep_running_)
+      break;
+
+    did_work |= delegate->DoDelayedWork(&delayed_work_time_);
+    if (!keep_running_)
+      break;
+
+    if (did_work)
+      continue;
+
+    did_work = delegate->DoIdleWork();
+    if (!keep_running_)
+      break;
+
+    if (did_work)
+      continue;
+
+    ThreadRestrictions::ScopedAllowWait allow_wait;
+    if (delayed_work_time_.is_null()) {
+      event_.Wait();
+    } else {
+      TimeDelta delay = delayed_work_time_ - TimeTicks::Now();
+#if defined(OS_WIN)
+      // If the delay is greater than zero and under 1 ms we need to round up to
+      // 1 ms or else we will end up spinning until it counts down to zero
+      // because sub-ms waits aren't supported on Windows.
+      if (delay > TimeDelta())
+        delay = std::max(delay, TimeDelta::FromMilliseconds(1));
+#endif
+      if (delay > TimeDelta()) {
+        event_.TimedWait(delay);
+      } else {
+        // It looks like delayed_work_time_ indicates a time in the past, so we
+        // need to call DoDelayedWork now.
+        delayed_work_time_ = TimeTicks();
+      }
+    }
+    // Since event_ is auto-reset, we don't need to do anything special here
+    // other than service each delegate method.
+  }
+
+  keep_running_ = true;
+}
+
+void MessagePumpDefault::Quit() {
+  keep_running_ = false;
+}
+
+void MessagePumpDefault::ScheduleWork() {
+  // Since this can be called on any thread, we need to ensure that our Run
+  // loop wakes up.
+  event_.Signal();
+}
+
+void MessagePumpDefault::ScheduleDelayedWork(
+    const TimeTicks& delayed_work_time) {
+  // We know that we can't be blocked on Wait right now since this method can
+  // only be called on the same thread as Run, so we only need to update our
+  // record of how long to sleep when we do sleep.
+  delayed_work_time_ = delayed_work_time;
+}
+
+}  // namespace base
diff --git a/base/message_loop/message_pump_default.h b/base/message_loop/message_pump_default.h
new file mode 100644
index 0000000..8aeaa62
--- /dev/null
+++ b/base/message_loop/message_pump_default.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2012 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_MESSAGE_LOOP_MESSAGE_PUMP_DEFAULT_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_DEFAULT_H_
+
+#include "base/base_export.h"
+#include "base/message_loop/message_pump.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/time/time.h"
+
+namespace base {
+
+class BASE_EXPORT MessagePumpDefault : public MessagePump {
+ public:
+  MessagePumpDefault();
+  ~MessagePumpDefault() override;
+
+  // MessagePump methods:
+  void Run(Delegate* delegate) override;
+  void Quit() override;
+  void ScheduleWork() override;
+  void ScheduleDelayedWork(const TimeTicks& delayed_work_time) override;
+
+ private:
+  // This flag is set to false when Run should return.
+  bool keep_running_;
+
+  // Used to sleep until there is more work to do.
+  WaitableEvent event_;
+
+  // The time at which we should call DoDelayedWork.
+  TimeTicks delayed_work_time_;
+
+  DISALLOW_COPY_AND_ASSIGN(MessagePumpDefault);
+};
+
+}  // namespace base
+
+#endif  // BASE_MESSAGE_LOOP_MESSAGE_PUMP_DEFAULT_H_
diff --git a/base/message_loop/message_pump_dispatcher.h b/base/message_loop/message_pump_dispatcher.h
new file mode 100644
index 0000000..5b1bd55
--- /dev/null
+++ b/base/message_loop/message_pump_dispatcher.h
@@ -0,0 +1,43 @@
+// Copyright (c) 2012 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_MESSAGE_LOOP_MESSAGE_PUMP_DISPATCHER_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_DISPATCHER_H_
+
+#include <stdint.h>
+
+#include "base/base_export.h"
+#include "base/event_types.h"
+
+namespace base {
+
+// Dispatcher is used during a nested invocation of Run to dispatch events when
+// |RunLoop(dispatcher).Run()| is used.  If |RunLoop().Run()| is invoked,
+// MessageLoop does not dispatch events (or invoke TranslateMessage), rather
+// every message is passed to Dispatcher's Dispatch method for dispatch. It is
+// up to the Dispatcher whether or not to dispatch the event.
+//
+// The nested loop is exited by either posting a quit, or setting the
+// POST_DISPATCH_QUIT_LOOP flag on the return value from Dispatch.
+class BASE_EXPORT MessagePumpDispatcher {
+ public:
+  enum PostDispatchAction {
+    POST_DISPATCH_NONE = 0x0,
+    POST_DISPATCH_QUIT_LOOP = 0x1,
+    POST_DISPATCH_PERFORM_DEFAULT = 0x2,
+  };
+
+  virtual ~MessagePumpDispatcher() {}
+
+  // Dispatches the event. The return value can have more than one
+  // PostDispatchAction flags OR'ed together. If POST_DISPATCH_PERFORM_DEFAULT
+  // is set in the returned value, then the message-pump performs the default
+  // action. If POST_DISPATCH_QUIT_LOOP is set, in the return value, then the
+  // nested loop exits immediately.
+  virtual uint32_t Dispatch(const NativeEvent& event) = 0;
+};
+
+}  // namespace base
+
+#endif  // BASE_MESSAGE_LOOP_MESSAGE_PUMP_DISPATCHER_H_
diff --git a/base/message_loop/message_pump_glib.cc b/base/message_loop/message_pump_glib.cc
new file mode 100644
index 0000000..f06f60d
--- /dev/null
+++ b/base/message_loop/message_pump_glib.cc
@@ -0,0 +1,363 @@
+// Copyright (c) 2012 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/message_loop/message_pump_glib.h"
+
+#include <fcntl.h>
+#include <math.h>
+
+#include <glib.h>
+
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+namespace {
+
+// Return a timeout suitable for the glib loop, -1 to block forever,
+// 0 to return right away, or a timeout in milliseconds from now.
+int GetTimeIntervalMilliseconds(const TimeTicks& from) {
+  if (from.is_null())
+    return -1;
+
+  // Be careful here.  TimeDelta has a precision of microseconds, but we want a
+  // value in milliseconds.  If there are 5.5ms left, should the delay be 5 or
+  // 6?  It should be 6 to avoid executing delayed work too early.
+  int delay = static_cast<int>(
+      ceil((from - TimeTicks::Now()).InMillisecondsF()));
+
+  // If this value is negative, then we need to run delayed work soon.
+  return delay < 0 ? 0 : delay;
+}
+
+// A brief refresher on GLib:
+//     GLib sources have four callbacks: Prepare, Check, Dispatch and Finalize.
+// On each iteration of the GLib pump, it calls each source's Prepare function.
+// This function should return TRUE if it wants GLib to call its Dispatch, and
+// FALSE otherwise.  It can also set a timeout in this case for the next time
+// Prepare should be called again (it may be called sooner).
+//     After the Prepare calls, GLib does a poll to check for events from the
+// system.  File descriptors can be attached to the sources.  The poll may block
+// if none of the Prepare calls returned TRUE.  It will block indefinitely, or
+// by the minimum time returned by a source in Prepare.
+//     After the poll, GLib calls Check for each source that returned FALSE
+// from Prepare.  The return value of Check has the same meaning as for Prepare,
+// making Check a second chance to tell GLib we are ready for Dispatch.
+//     Finally, GLib calls Dispatch for each source that is ready.  If Dispatch
+// returns FALSE, GLib will destroy the source.  Dispatch calls may be recursive
+// (i.e., you can call Run from them), but Prepare and Check cannot.
+//     Finalize is called when the source is destroyed.
+// NOTE: It is common for subsytems to want to process pending events while
+// doing intensive work, for example the flash plugin. They usually use the
+// following pattern (recommended by the GTK docs):
+// while (gtk_events_pending()) {
+//   gtk_main_iteration();
+// }
+//
+// gtk_events_pending just calls g_main_context_pending, which does the
+// following:
+// - Call prepare on all the sources.
+// - Do the poll with a timeout of 0 (not blocking).
+// - Call check on all the sources.
+// - *Does not* call dispatch on the sources.
+// - Return true if any of prepare() or check() returned true.
+//
+// gtk_main_iteration just calls g_main_context_iteration, which does the whole
+// thing, respecting the timeout for the poll (and block, although it is
+// expected not to if gtk_events_pending returned true), and call dispatch.
+//
+// Thus it is important to only return true from prepare or check if we
+// actually have events or work to do. We also need to make sure we keep
+// internal state consistent so that if prepare/check return true when called
+// from gtk_events_pending, they will still return true when called right
+// after, from gtk_main_iteration.
+//
+// For the GLib pump we try to follow the Windows UI pump model:
+// - Whenever we receive a wakeup event or the timer for delayed work expires,
+// we run DoWork and/or DoDelayedWork. That part will also run in the other
+// event pumps.
+// - We also run DoWork, DoDelayedWork, and possibly DoIdleWork in the main
+// loop, around event handling.
+
+struct WorkSource : public GSource {
+  MessagePumpGlib* pump;
+};
+
+gboolean WorkSourcePrepare(GSource* source,
+                           gint* timeout_ms) {
+  *timeout_ms = static_cast<WorkSource*>(source)->pump->HandlePrepare();
+  // We always return FALSE, so that our timeout is honored.  If we were
+  // to return TRUE, the timeout would be considered to be 0 and the poll
+  // would never block.  Once the poll is finished, Check will be called.
+  return FALSE;
+}
+
+gboolean WorkSourceCheck(GSource* source) {
+  // Only return TRUE if Dispatch should be called.
+  return static_cast<WorkSource*>(source)->pump->HandleCheck();
+}
+
+gboolean WorkSourceDispatch(GSource* source,
+                            GSourceFunc unused_func,
+                            gpointer unused_data) {
+
+  static_cast<WorkSource*>(source)->pump->HandleDispatch();
+  // Always return TRUE so our source stays registered.
+  return TRUE;
+}
+
+// I wish these could be const, but g_source_new wants non-const.
+GSourceFuncs WorkSourceFuncs = {
+  WorkSourcePrepare,
+  WorkSourceCheck,
+  WorkSourceDispatch,
+  NULL
+};
+
+// The following is used to make sure we only run the MessagePumpGlib on one
+// thread. X only has one message pump so we can only have one UI loop per
+// process.
+#ifndef NDEBUG
+
+// Tracks the pump the most recent pump that has been run.
+struct ThreadInfo {
+  // The pump.
+  MessagePumpGlib* pump;
+
+  // ID of the thread the pump was run on.
+  PlatformThreadId thread_id;
+};
+
+// Used for accesing |thread_info|.
+static LazyInstance<Lock>::Leaky thread_info_lock = LAZY_INSTANCE_INITIALIZER;
+
+// If non-NULL it means a MessagePumpGlib exists and has been Run. This is
+// destroyed when the MessagePump is destroyed.
+ThreadInfo* thread_info = NULL;
+
+void CheckThread(MessagePumpGlib* pump) {
+  AutoLock auto_lock(thread_info_lock.Get());
+  if (!thread_info) {
+    thread_info = new ThreadInfo;
+    thread_info->pump = pump;
+    thread_info->thread_id = PlatformThread::CurrentId();
+  }
+  DCHECK(thread_info->thread_id == PlatformThread::CurrentId()) <<
+      "Running MessagePumpGlib on two different threads; "
+      "this is unsupported by GLib!";
+}
+
+void PumpDestroyed(MessagePumpGlib* pump) {
+  AutoLock auto_lock(thread_info_lock.Get());
+  if (thread_info && thread_info->pump == pump) {
+    delete thread_info;
+    thread_info = NULL;
+  }
+}
+
+#endif
+
+}  // namespace
+
+struct MessagePumpGlib::RunState {
+  Delegate* delegate;
+
+  // Used to flag that the current Run() invocation should return ASAP.
+  bool should_quit;
+
+  // Used to count how many Run() invocations are on the stack.
+  int run_depth;
+
+  // This keeps the state of whether the pump got signaled that there was new
+  // work to be done. Since we eat the message on the wake up pipe as soon as
+  // we get it, we keep that state here to stay consistent.
+  bool has_work;
+};
+
+MessagePumpGlib::MessagePumpGlib()
+    : state_(NULL),
+      context_(g_main_context_default()),
+      wakeup_gpollfd_(new GPollFD) {
+  // Create our wakeup pipe, which is used to flag when work was scheduled.
+  int fds[2];
+  int ret = pipe(fds);
+  DCHECK_EQ(ret, 0);
+  (void)ret;  // Prevent warning in release mode.
+
+  wakeup_pipe_read_  = fds[0];
+  wakeup_pipe_write_ = fds[1];
+  wakeup_gpollfd_->fd = wakeup_pipe_read_;
+  wakeup_gpollfd_->events = G_IO_IN;
+
+  work_source_ = g_source_new(&WorkSourceFuncs, sizeof(WorkSource));
+  static_cast<WorkSource*>(work_source_)->pump = this;
+  g_source_add_poll(work_source_, wakeup_gpollfd_.get());
+  // Use a low priority so that we let other events in the queue go first.
+  g_source_set_priority(work_source_, G_PRIORITY_DEFAULT_IDLE);
+  // This is needed to allow Run calls inside Dispatch.
+  g_source_set_can_recurse(work_source_, TRUE);
+  g_source_attach(work_source_, context_);
+}
+
+MessagePumpGlib::~MessagePumpGlib() {
+#ifndef NDEBUG
+  PumpDestroyed(this);
+#endif
+  g_source_destroy(work_source_);
+  g_source_unref(work_source_);
+  close(wakeup_pipe_read_);
+  close(wakeup_pipe_write_);
+}
+
+// Return the timeout we want passed to poll.
+int MessagePumpGlib::HandlePrepare() {
+  // We know we have work, but we haven't called HandleDispatch yet. Don't let
+  // the pump block so that we can do some processing.
+  if (state_ &&  // state_ may be null during tests.
+      state_->has_work)
+    return 0;
+
+  // We don't think we have work to do, but make sure not to block
+  // longer than the next time we need to run delayed work.
+  return GetTimeIntervalMilliseconds(delayed_work_time_);
+}
+
+bool MessagePumpGlib::HandleCheck() {
+  if (!state_)  // state_ may be null during tests.
+    return false;
+
+  // We usually have a single message on the wakeup pipe, since we are only
+  // signaled when the queue went from empty to non-empty, but there can be
+  // two messages if a task posted a task, hence we read at most two bytes.
+  // The glib poll will tell us whether there was data, so this read
+  // shouldn't block.
+  if (wakeup_gpollfd_->revents & G_IO_IN) {
+    char msg[2];
+    const int num_bytes = HANDLE_EINTR(read(wakeup_pipe_read_, msg, 2));
+    if (num_bytes < 1) {
+      NOTREACHED() << "Error reading from the wakeup pipe.";
+    }
+    DCHECK((num_bytes == 1 && msg[0] == '!') ||
+           (num_bytes == 2 && msg[0] == '!' && msg[1] == '!'));
+    // Since we ate the message, we need to record that we have more work,
+    // because HandleCheck() may be called without HandleDispatch being called
+    // afterwards.
+    state_->has_work = true;
+  }
+
+  if (state_->has_work)
+    return true;
+
+  if (GetTimeIntervalMilliseconds(delayed_work_time_) == 0) {
+    // The timer has expired. That condition will stay true until we process
+    // that delayed work, so we don't need to record this differently.
+    return true;
+  }
+
+  return false;
+}
+
+void MessagePumpGlib::HandleDispatch() {
+  state_->has_work = false;
+  if (state_->delegate->DoWork()) {
+    // NOTE: on Windows at this point we would call ScheduleWork (see
+    // MessagePumpGlib::HandleWorkMessage in message_pump_win.cc). But here,
+    // instead of posting a message on the wakeup pipe, we can avoid the
+    // syscalls and just signal that we have more work.
+    state_->has_work = true;
+  }
+
+  if (state_->should_quit)
+    return;
+
+  state_->delegate->DoDelayedWork(&delayed_work_time_);
+}
+
+void MessagePumpGlib::Run(Delegate* delegate) {
+#ifndef NDEBUG
+  CheckThread(this);
+#endif
+
+  RunState state;
+  state.delegate = delegate;
+  state.should_quit = false;
+  state.run_depth = state_ ? state_->run_depth + 1 : 1;
+  state.has_work = false;
+
+  RunState* previous_state = state_;
+  state_ = &state;
+
+  // We really only do a single task for each iteration of the loop.  If we
+  // have done something, assume there is likely something more to do.  This
+  // will mean that we don't block on the message pump until there was nothing
+  // more to do.  We also set this to true to make sure not to block on the
+  // first iteration of the loop, so RunUntilIdle() works correctly.
+  bool more_work_is_plausible = true;
+
+  // We run our own loop instead of using g_main_loop_quit in one of the
+  // callbacks.  This is so we only quit our own loops, and we don't quit
+  // nested loops run by others.  TODO(deanm): Is this what we want?
+  for (;;) {
+    // Don't block if we think we have more work to do.
+    bool block = !more_work_is_plausible;
+
+    more_work_is_plausible = g_main_context_iteration(context_, block);
+    if (state_->should_quit)
+      break;
+
+    more_work_is_plausible |= state_->delegate->DoWork();
+    if (state_->should_quit)
+      break;
+
+    more_work_is_plausible |=
+        state_->delegate->DoDelayedWork(&delayed_work_time_);
+    if (state_->should_quit)
+      break;
+
+    if (more_work_is_plausible)
+      continue;
+
+    more_work_is_plausible = state_->delegate->DoIdleWork();
+    if (state_->should_quit)
+      break;
+  }
+
+  state_ = previous_state;
+}
+
+void MessagePumpGlib::Quit() {
+  if (state_) {
+    state_->should_quit = true;
+  } else {
+    NOTREACHED() << "Quit called outside Run!";
+  }
+}
+
+void MessagePumpGlib::ScheduleWork() {
+  // This can be called on any thread, so we don't want to touch any state
+  // variables as we would then need locks all over.  This ensures that if
+  // we are sleeping in a poll that we will wake up.
+  char msg = '!';
+  if (HANDLE_EINTR(write(wakeup_pipe_write_, &msg, 1)) != 1) {
+    NOTREACHED() << "Could not write to the UI message loop wakeup pipe!";
+  }
+}
+
+void MessagePumpGlib::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
+  // We need to wake up the loop in case the poll timeout needs to be
+  // adjusted.  This will cause us to try to do work, but that's ok.
+  delayed_work_time_ = delayed_work_time;
+  ScheduleWork();
+}
+
+bool MessagePumpGlib::ShouldQuit() const {
+  CHECK(state_);
+  return state_->should_quit;
+}
+
+}  // namespace base
diff --git a/base/message_loop/message_pump_glib.h b/base/message_loop/message_pump_glib.h
new file mode 100644
index 0000000..9f44571
--- /dev/null
+++ b/base/message_loop/message_pump_glib.h
@@ -0,0 +1,78 @@
+// Copyright (c) 2012 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_MESSAGE_LOOP_MESSAGE_PUMP_GLIB_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_GLIB_H_
+
+#include "base/base_export.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_pump.h"
+#include "base/observer_list.h"
+#include "base/time/time.h"
+
+typedef struct _GMainContext GMainContext;
+typedef struct _GPollFD GPollFD;
+typedef struct _GSource GSource;
+
+namespace base {
+
+// This class implements a base MessagePump needed for TYPE_UI MessageLoops on
+// platforms using GLib.
+class BASE_EXPORT MessagePumpGlib : public MessagePump {
+ public:
+  MessagePumpGlib();
+  ~MessagePumpGlib() override;
+
+  // Internal methods used for processing the pump callbacks.  They are
+  // public for simplicity but should not be used directly.  HandlePrepare
+  // is called during the prepare step of glib, and returns a timeout that
+  // will be passed to the poll. HandleCheck is called after the poll
+  // has completed, and returns whether or not HandleDispatch should be called.
+  // HandleDispatch is called if HandleCheck returned true.
+  int HandlePrepare();
+  bool HandleCheck();
+  void HandleDispatch();
+
+  // Overridden from MessagePump:
+  void Run(Delegate* delegate) override;
+  void Quit() override;
+  void ScheduleWork() override;
+  void ScheduleDelayedWork(const TimeTicks& delayed_work_time) override;
+
+ private:
+  bool ShouldQuit() const;
+
+  // We may make recursive calls to Run, so we save state that needs to be
+  // separate between them in this structure type.
+  struct RunState;
+
+  RunState* state_;
+
+  // This is a GLib structure that we can add event sources to.  We use the
+  // default GLib context, which is the one to which all GTK events are
+  // dispatched.
+  GMainContext* context_;
+
+  // This is the time when we need to do delayed work.
+  TimeTicks delayed_work_time_;
+
+  // The work source.  It is shared by all calls to Run and destroyed when
+  // the message pump is destroyed.
+  GSource* work_source_;
+
+  // We use a wakeup pipe to make sure we'll get out of the glib polling phase
+  // when another thread has scheduled us to do some work.  There is a glib
+  // mechanism g_main_context_wakeup, but this won't guarantee that our event's
+  // Dispatch() will be called.
+  int wakeup_pipe_read_;
+  int wakeup_pipe_write_;
+  // Use a scoped_ptr to avoid needing the definition of GPollFD in the header.
+  scoped_ptr<GPollFD> wakeup_gpollfd_;
+
+  DISALLOW_COPY_AND_ASSIGN(MessagePumpGlib);
+};
+
+}  // namespace base
+
+#endif  // BASE_MESSAGE_LOOP_MESSAGE_PUMP_GLIB_H_
diff --git a/base/message_loop/message_pump_glib_unittest.cc b/base/message_loop/message_pump_glib_unittest.cc
new file mode 100644
index 0000000..7ddd4f0
--- /dev/null
+++ b/base/message_loop/message_pump_glib_unittest.cc
@@ -0,0 +1,534 @@
+// Copyright (c) 2012 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/message_loop/message_pump_glib.h"
+
+#include <glib.h>
+#include <math.h>
+
+#include <algorithm>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+// This class injects dummy "events" into the GLib loop. When "handled" these
+// events can run tasks. This is intended to mock gtk events (the corresponding
+// GLib source runs at the same priority).
+class EventInjector {
+ public:
+  EventInjector() : processed_events_(0) {
+    source_ = static_cast<Source*>(g_source_new(&SourceFuncs, sizeof(Source)));
+    source_->injector = this;
+    g_source_attach(source_, NULL);
+    g_source_set_can_recurse(source_, TRUE);
+  }
+
+  ~EventInjector() {
+    g_source_destroy(source_);
+    g_source_unref(source_);
+  }
+
+  int HandlePrepare() {
+    // If the queue is empty, block.
+    if (events_.empty())
+      return -1;
+    TimeDelta delta = events_[0].time - Time::NowFromSystemTime();
+    return std::max(0, static_cast<int>(ceil(delta.InMillisecondsF())));
+  }
+
+  bool HandleCheck() {
+    if (events_.empty())
+      return false;
+    return events_[0].time <= Time::NowFromSystemTime();
+  }
+
+  void HandleDispatch() {
+    if (events_.empty())
+      return;
+    Event event = events_[0];
+    events_.erase(events_.begin());
+    ++processed_events_;
+    if (!event.callback.is_null())
+      event.callback.Run();
+    else if (!event.task.is_null())
+      event.task.Run();
+  }
+
+  // Adds an event to the queue. When "handled", executes |callback|.
+  // delay_ms is relative to the last event if any, or to Now() otherwise.
+  void AddEvent(int delay_ms, const Closure& callback) {
+    AddEventHelper(delay_ms, callback, Closure());
+  }
+
+  void AddDummyEvent(int delay_ms) {
+    AddEventHelper(delay_ms, Closure(), Closure());
+  }
+
+  void AddEventAsTask(int delay_ms, const Closure& task) {
+    AddEventHelper(delay_ms, Closure(), task);
+  }
+
+  void Reset() {
+    processed_events_ = 0;
+    events_.clear();
+  }
+
+  int processed_events() const { return processed_events_; }
+
+ private:
+  struct Event {
+    Time time;
+    Closure callback;
+    Closure task;
+  };
+
+  struct Source : public GSource {
+    EventInjector* injector;
+  };
+
+  void AddEventHelper(
+      int delay_ms, const Closure& callback, const Closure& task) {
+    Time last_time;
+    if (!events_.empty())
+      last_time = (events_.end()-1)->time;
+    else
+      last_time = Time::NowFromSystemTime();
+
+    Time future = last_time + TimeDelta::FromMilliseconds(delay_ms);
+    EventInjector::Event event = {future, callback, task};
+    events_.push_back(event);
+  }
+
+  static gboolean Prepare(GSource* source, gint* timeout_ms) {
+    *timeout_ms = static_cast<Source*>(source)->injector->HandlePrepare();
+    return FALSE;
+  }
+
+  static gboolean Check(GSource* source) {
+    return static_cast<Source*>(source)->injector->HandleCheck();
+  }
+
+  static gboolean Dispatch(GSource* source,
+                           GSourceFunc unused_func,
+                           gpointer unused_data) {
+    static_cast<Source*>(source)->injector->HandleDispatch();
+    return TRUE;
+  }
+
+  Source* source_;
+  std::vector<Event> events_;
+  int processed_events_;
+  static GSourceFuncs SourceFuncs;
+  DISALLOW_COPY_AND_ASSIGN(EventInjector);
+};
+
+GSourceFuncs EventInjector::SourceFuncs = {
+  EventInjector::Prepare,
+  EventInjector::Check,
+  EventInjector::Dispatch,
+  NULL
+};
+
+void IncrementInt(int *value) {
+  ++*value;
+}
+
+// Checks how many events have been processed by the injector.
+void ExpectProcessedEvents(EventInjector* injector, int count) {
+  EXPECT_EQ(injector->processed_events(), count);
+}
+
+// Posts a task on the current message loop.
+void PostMessageLoopTask(const tracked_objects::Location& from_here,
+                         const Closure& task) {
+  MessageLoop::current()->PostTask(from_here, task);
+}
+
+// Test fixture.
+class MessagePumpGLibTest : public testing::Test {
+ public:
+  MessagePumpGLibTest() : loop_(NULL), injector_(NULL) { }
+
+  // Overridden from testing::Test:
+  void SetUp() override {
+    loop_ = new MessageLoop(MessageLoop::TYPE_UI);
+    injector_ = new EventInjector();
+  }
+  void TearDown() override {
+    delete injector_;
+    injector_ = NULL;
+    delete loop_;
+    loop_ = NULL;
+  }
+
+  MessageLoop* loop() const { return loop_; }
+  EventInjector* injector() const { return injector_; }
+
+ private:
+  MessageLoop* loop_;
+  EventInjector* injector_;
+  DISALLOW_COPY_AND_ASSIGN(MessagePumpGLibTest);
+};
+
+}  // namespace
+
+TEST_F(MessagePumpGLibTest, TestQuit) {
+  // Checks that Quit works and that the basic infrastructure is working.
+
+  // Quit from a task
+  RunLoop().RunUntilIdle();
+  EXPECT_EQ(0, injector()->processed_events());
+
+  injector()->Reset();
+  // Quit from an event
+  injector()->AddEvent(0, MessageLoop::QuitWhenIdleClosure());
+  loop()->Run();
+  EXPECT_EQ(1, injector()->processed_events());
+}
+
+TEST_F(MessagePumpGLibTest, TestEventTaskInterleave) {
+  // Checks that tasks posted by events are executed before the next event if
+  // the posted task queue is empty.
+  // MessageLoop doesn't make strong guarantees that it is the case, but the
+  // current implementation ensures it and the tests below rely on it.
+  // If changes cause this test to fail, it is reasonable to change it, but
+  // TestWorkWhileWaitingForEvents and TestEventsWhileWaitingForWork have to be
+  // changed accordingly, otherwise they can become flaky.
+  injector()->AddEventAsTask(0, Bind(&DoNothing));
+  Closure check_task =
+      Bind(&ExpectProcessedEvents, Unretained(injector()), 2);
+  Closure posted_task =
+      Bind(&PostMessageLoopTask, FROM_HERE, check_task);
+  injector()->AddEventAsTask(0, posted_task);
+  injector()->AddEventAsTask(0, Bind(&DoNothing));
+  injector()->AddEvent(0, MessageLoop::QuitWhenIdleClosure());
+  loop()->Run();
+  EXPECT_EQ(4, injector()->processed_events());
+
+  injector()->Reset();
+  injector()->AddEventAsTask(0, Bind(&DoNothing));
+  check_task =
+      Bind(&ExpectProcessedEvents, Unretained(injector()), 2);
+  posted_task = Bind(&PostMessageLoopTask, FROM_HERE, check_task);
+  injector()->AddEventAsTask(0, posted_task);
+  injector()->AddEventAsTask(10, Bind(&DoNothing));
+  injector()->AddEvent(0, MessageLoop::QuitWhenIdleClosure());
+  loop()->Run();
+  EXPECT_EQ(4, injector()->processed_events());
+}
+
+TEST_F(MessagePumpGLibTest, TestWorkWhileWaitingForEvents) {
+  int task_count = 0;
+  // Tests that we process tasks while waiting for new events.
+  // The event queue is empty at first.
+  for (int i = 0; i < 10; ++i) {
+    loop()->PostTask(FROM_HERE, Bind(&IncrementInt, &task_count));
+  }
+  // After all the previous tasks have executed, enqueue an event that will
+  // quit.
+  loop()->PostTask(
+      FROM_HERE,
+      Bind(&EventInjector::AddEvent, Unretained(injector()), 0,
+                 MessageLoop::QuitWhenIdleClosure()));
+  loop()->Run();
+  ASSERT_EQ(10, task_count);
+  EXPECT_EQ(1, injector()->processed_events());
+
+  // Tests that we process delayed tasks while waiting for new events.
+  injector()->Reset();
+  task_count = 0;
+  for (int i = 0; i < 10; ++i) {
+    loop()->PostDelayedTask(
+        FROM_HERE,
+        Bind(&IncrementInt, &task_count),
+        TimeDelta::FromMilliseconds(10*i));
+  }
+  // After all the previous tasks have executed, enqueue an event that will
+  // quit.
+  // This relies on the fact that delayed tasks are executed in delay order.
+  // That is verified in message_loop_unittest.cc.
+  loop()->PostDelayedTask(
+      FROM_HERE,
+      Bind(&EventInjector::AddEvent, Unretained(injector()), 10,
+                 MessageLoop::QuitWhenIdleClosure()),
+      TimeDelta::FromMilliseconds(150));
+  loop()->Run();
+  ASSERT_EQ(10, task_count);
+  EXPECT_EQ(1, injector()->processed_events());
+}
+
+TEST_F(MessagePumpGLibTest, TestEventsWhileWaitingForWork) {
+  // Tests that we process events while waiting for work.
+  // The event queue is empty at first.
+  for (int i = 0; i < 10; ++i) {
+    injector()->AddDummyEvent(0);
+  }
+  // After all the events have been processed, post a task that will check that
+  // the events have been processed (note: the task executes after the event
+  // that posted it has been handled, so we expect 11 at that point).
+  Closure check_task =
+      Bind(&ExpectProcessedEvents, Unretained(injector()), 11);
+  Closure posted_task =
+      Bind(&PostMessageLoopTask, FROM_HERE, check_task);
+  injector()->AddEventAsTask(10, posted_task);
+
+  // And then quit (relies on the condition tested by TestEventTaskInterleave).
+  injector()->AddEvent(10, MessageLoop::QuitWhenIdleClosure());
+  loop()->Run();
+
+  EXPECT_EQ(12, injector()->processed_events());
+}
+
+namespace {
+
+// This class is a helper for the concurrent events / posted tasks test below.
+// It will quit the main loop once enough tasks and events have been processed,
+// while making sure there is always work to do and events in the queue.
+class ConcurrentHelper : public RefCounted<ConcurrentHelper>  {
+ public:
+  explicit ConcurrentHelper(EventInjector* injector)
+      : injector_(injector),
+        event_count_(kStartingEventCount),
+        task_count_(kStartingTaskCount) {
+  }
+
+  void FromTask() {
+    if (task_count_ > 0) {
+      --task_count_;
+    }
+    if (task_count_ == 0 && event_count_ == 0) {
+        MessageLoop::current()->QuitWhenIdle();
+    } else {
+      MessageLoop::current()->PostTask(
+          FROM_HERE, Bind(&ConcurrentHelper::FromTask, this));
+    }
+  }
+
+  void FromEvent() {
+    if (event_count_ > 0) {
+      --event_count_;
+    }
+    if (task_count_ == 0 && event_count_ == 0) {
+        MessageLoop::current()->QuitWhenIdle();
+    } else {
+      injector_->AddEventAsTask(
+          0, Bind(&ConcurrentHelper::FromEvent, this));
+    }
+  }
+
+  int event_count() const { return event_count_; }
+  int task_count() const { return task_count_; }
+
+ private:
+  friend class RefCounted<ConcurrentHelper>;
+
+  ~ConcurrentHelper() {}
+
+  static const int kStartingEventCount = 20;
+  static const int kStartingTaskCount = 20;
+
+  EventInjector* injector_;
+  int event_count_;
+  int task_count_;
+};
+
+}  // namespace
+
+TEST_F(MessagePumpGLibTest, TestConcurrentEventPostedTask) {
+  // Tests that posted tasks don't starve events, nor the opposite.
+  // We use the helper class above. We keep both event and posted task queues
+  // full, the helper verifies that both tasks and events get processed.
+  // If that is not the case, either event_count_ or task_count_ will not get
+  // to 0, and MessageLoop::QuitWhenIdle() will never be called.
+  scoped_refptr<ConcurrentHelper> helper = new ConcurrentHelper(injector());
+
+  // Add 2 events to the queue to make sure it is always full (when we remove
+  // the event before processing it).
+  injector()->AddEventAsTask(
+      0, Bind(&ConcurrentHelper::FromEvent, helper.get()));
+  injector()->AddEventAsTask(
+      0, Bind(&ConcurrentHelper::FromEvent, helper.get()));
+
+  // Similarly post 2 tasks.
+  loop()->PostTask(
+      FROM_HERE, Bind(&ConcurrentHelper::FromTask, helper.get()));
+  loop()->PostTask(
+      FROM_HERE, Bind(&ConcurrentHelper::FromTask, helper.get()));
+
+  loop()->Run();
+  EXPECT_EQ(0, helper->event_count());
+  EXPECT_EQ(0, helper->task_count());
+}
+
+namespace {
+
+void AddEventsAndDrainGLib(EventInjector* injector) {
+  // Add a couple of dummy events
+  injector->AddDummyEvent(0);
+  injector->AddDummyEvent(0);
+  // Then add an event that will quit the main loop.
+  injector->AddEvent(0, MessageLoop::QuitWhenIdleClosure());
+
+  // Post a couple of dummy tasks
+  MessageLoop::current()->PostTask(FROM_HERE, Bind(&DoNothing));
+  MessageLoop::current()->PostTask(FROM_HERE, Bind(&DoNothing));
+
+  // Drain the events
+  while (g_main_context_pending(NULL)) {
+    g_main_context_iteration(NULL, FALSE);
+  }
+}
+
+}  // namespace
+
+TEST_F(MessagePumpGLibTest, TestDrainingGLib) {
+  // Tests that draining events using GLib works.
+  loop()->PostTask(
+      FROM_HERE,
+      Bind(&AddEventsAndDrainGLib, Unretained(injector())));
+  loop()->Run();
+
+  EXPECT_EQ(3, injector()->processed_events());
+}
+
+namespace {
+
+// Helper class that lets us run the GLib message loop.
+class GLibLoopRunner : public RefCounted<GLibLoopRunner> {
+ public:
+  GLibLoopRunner() : quit_(false) { }
+
+  void RunGLib() {
+    while (!quit_) {
+      g_main_context_iteration(NULL, TRUE);
+    }
+  }
+
+  void RunLoop() {
+    while (!quit_) {
+      g_main_context_iteration(NULL, TRUE);
+    }
+  }
+
+  void Quit() {
+    quit_ = true;
+  }
+
+  void Reset() {
+    quit_ = false;
+  }
+
+ private:
+  friend class RefCounted<GLibLoopRunner>;
+
+  ~GLibLoopRunner() {}
+
+  bool quit_;
+};
+
+void TestGLibLoopInternal(EventInjector* injector) {
+  // Allow tasks to be processed from 'native' event loops.
+  MessageLoop::current()->SetNestableTasksAllowed(true);
+  scoped_refptr<GLibLoopRunner> runner = new GLibLoopRunner();
+
+  int task_count = 0;
+  // Add a couple of dummy events
+  injector->AddDummyEvent(0);
+  injector->AddDummyEvent(0);
+  // Post a couple of dummy tasks
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&IncrementInt, &task_count));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&IncrementInt, &task_count));
+  // Delayed events
+  injector->AddDummyEvent(10);
+  injector->AddDummyEvent(10);
+  // Delayed work
+  MessageLoop::current()->PostDelayedTask(
+      FROM_HERE,
+      Bind(&IncrementInt, &task_count),
+      TimeDelta::FromMilliseconds(30));
+  MessageLoop::current()->PostDelayedTask(
+      FROM_HERE,
+      Bind(&GLibLoopRunner::Quit, runner.get()),
+      TimeDelta::FromMilliseconds(40));
+
+  // Run a nested, straight GLib message loop.
+  runner->RunGLib();
+
+  ASSERT_EQ(3, task_count);
+  EXPECT_EQ(4, injector->processed_events());
+  MessageLoop::current()->QuitWhenIdle();
+}
+
+void TestGtkLoopInternal(EventInjector* injector) {
+  // Allow tasks to be processed from 'native' event loops.
+  MessageLoop::current()->SetNestableTasksAllowed(true);
+  scoped_refptr<GLibLoopRunner> runner = new GLibLoopRunner();
+
+  int task_count = 0;
+  // Add a couple of dummy events
+  injector->AddDummyEvent(0);
+  injector->AddDummyEvent(0);
+  // Post a couple of dummy tasks
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&IncrementInt, &task_count));
+  MessageLoop::current()->PostTask(
+      FROM_HERE, Bind(&IncrementInt, &task_count));
+  // Delayed events
+  injector->AddDummyEvent(10);
+  injector->AddDummyEvent(10);
+  // Delayed work
+  MessageLoop::current()->PostDelayedTask(
+      FROM_HERE,
+      Bind(&IncrementInt, &task_count),
+      TimeDelta::FromMilliseconds(30));
+  MessageLoop::current()->PostDelayedTask(
+      FROM_HERE,
+      Bind(&GLibLoopRunner::Quit, runner.get()),
+      TimeDelta::FromMilliseconds(40));
+
+  // Run a nested, straight Gtk message loop.
+  runner->RunLoop();
+
+  ASSERT_EQ(3, task_count);
+  EXPECT_EQ(4, injector->processed_events());
+  MessageLoop::current()->QuitWhenIdle();
+}
+
+}  // namespace
+
+TEST_F(MessagePumpGLibTest, TestGLibLoop) {
+  // Tests that events and posted tasks are correctly executed if the message
+  // loop is not run by MessageLoop::Run() but by a straight GLib loop.
+  // Note that in this case we don't make strong guarantees about niceness
+  // between events and posted tasks.
+  loop()->PostTask(
+      FROM_HERE,
+      Bind(&TestGLibLoopInternal, Unretained(injector())));
+  loop()->Run();
+}
+
+TEST_F(MessagePumpGLibTest, TestGtkLoop) {
+  // Tests that events and posted tasks are correctly executed if the message
+  // loop is not run by MessageLoop::Run() but by a straight Gtk loop.
+  // Note that in this case we don't make strong guarantees about niceness
+  // between events and posted tasks.
+  loop()->PostTask(
+      FROM_HERE,
+      Bind(&TestGtkLoopInternal, Unretained(injector())));
+  loop()->Run();
+}
+
+}  // namespace base
diff --git a/base/message_loop/message_pump_io_ios.cc b/base/message_loop/message_pump_io_ios.cc
new file mode 100644
index 0000000..cd5ffed
--- /dev/null
+++ b/base/message_loop/message_pump_io_ios.cc
@@ -0,0 +1,209 @@
+// Copyright 2012 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/message_loop/message_pump_io_ios.h"
+
+namespace base {
+
+MessagePumpIOSForIO::FileDescriptorWatcher::FileDescriptorWatcher()
+    : is_persistent_(false),
+      fdref_(NULL),
+      callback_types_(0),
+      fd_source_(NULL),
+      watcher_(NULL) {
+}
+
+MessagePumpIOSForIO::FileDescriptorWatcher::~FileDescriptorWatcher() {
+  StopWatchingFileDescriptor();
+}
+
+bool MessagePumpIOSForIO::FileDescriptorWatcher::StopWatchingFileDescriptor() {
+  if (fdref_ == NULL)
+    return true;
+
+  CFFileDescriptorDisableCallBacks(fdref_, callback_types_);
+  if (pump_)
+    pump_->RemoveRunLoopSource(fd_source_);
+  fd_source_.reset();
+  fdref_.reset();
+  callback_types_ = 0;
+  pump_.reset();
+  watcher_ = NULL;
+  return true;
+}
+
+void MessagePumpIOSForIO::FileDescriptorWatcher::Init(
+    CFFileDescriptorRef fdref,
+    CFOptionFlags callback_types,
+    CFRunLoopSourceRef fd_source,
+    bool is_persistent) {
+  DCHECK(fdref);
+  DCHECK(!fdref_);
+
+  is_persistent_ = is_persistent;
+  fdref_.reset(fdref);
+  callback_types_ = callback_types;
+  fd_source_.reset(fd_source);
+}
+
+void MessagePumpIOSForIO::FileDescriptorWatcher::OnFileCanReadWithoutBlocking(
+    int fd,
+    MessagePumpIOSForIO* pump) {
+  DCHECK(callback_types_ & kCFFileDescriptorReadCallBack);
+  pump->WillProcessIOEvent();
+  watcher_->OnFileCanReadWithoutBlocking(fd);
+  pump->DidProcessIOEvent();
+}
+
+void MessagePumpIOSForIO::FileDescriptorWatcher::OnFileCanWriteWithoutBlocking(
+    int fd,
+    MessagePumpIOSForIO* pump) {
+  DCHECK(callback_types_ & kCFFileDescriptorWriteCallBack);
+  pump->WillProcessIOEvent();
+  watcher_->OnFileCanWriteWithoutBlocking(fd);
+  pump->DidProcessIOEvent();
+}
+
+MessagePumpIOSForIO::MessagePumpIOSForIO() : weak_factory_(this) {
+}
+
+MessagePumpIOSForIO::~MessagePumpIOSForIO() {
+}
+
+bool MessagePumpIOSForIO::WatchFileDescriptor(
+    int fd,
+    bool persistent,
+    int mode,
+    FileDescriptorWatcher *controller,
+    Watcher *delegate) {
+  DCHECK_GE(fd, 0);
+  DCHECK(controller);
+  DCHECK(delegate);
+  DCHECK(mode == WATCH_READ || mode == WATCH_WRITE || mode == WATCH_READ_WRITE);
+
+  // WatchFileDescriptor should be called on the pump thread. It is not
+  // threadsafe, and your watcher may never be registered.
+  DCHECK(watch_file_descriptor_caller_checker_.CalledOnValidThread());
+
+  CFFileDescriptorContext source_context = {0};
+  source_context.info = controller;
+
+  CFOptionFlags callback_types = 0;
+  if (mode & WATCH_READ) {
+    callback_types |= kCFFileDescriptorReadCallBack;
+  }
+  if (mode & WATCH_WRITE) {
+    callback_types |= kCFFileDescriptorWriteCallBack;
+  }
+
+  CFFileDescriptorRef fdref = controller->fdref_;
+  if (fdref == NULL) {
+    base::ScopedCFTypeRef<CFFileDescriptorRef> scoped_fdref(
+        CFFileDescriptorCreate(
+            kCFAllocatorDefault, fd, false, HandleFdIOEvent, &source_context));
+    if (scoped_fdref == NULL) {
+      NOTREACHED() << "CFFileDescriptorCreate failed";
+      return false;
+    }
+
+    CFFileDescriptorEnableCallBacks(scoped_fdref, callback_types);
+
+    // TODO(wtc): what should the 'order' argument be?
+    base::ScopedCFTypeRef<CFRunLoopSourceRef> scoped_fd_source(
+        CFFileDescriptorCreateRunLoopSource(
+            kCFAllocatorDefault, scoped_fdref, 0));
+    if (scoped_fd_source == NULL) {
+      NOTREACHED() << "CFFileDescriptorCreateRunLoopSource failed";
+      return false;
+    }
+    CFRunLoopAddSource(run_loop(), scoped_fd_source, kCFRunLoopCommonModes);
+
+    // Transfer ownership of scoped_fdref and fd_source to controller.
+    controller->Init(scoped_fdref.release(), callback_types,
+                     scoped_fd_source.release(), persistent);
+  } else {
+    // It's illegal to use this function to listen on 2 separate fds with the
+    // same |controller|.
+    if (CFFileDescriptorGetNativeDescriptor(fdref) != fd) {
+      NOTREACHED() << "FDs don't match: "
+                   << CFFileDescriptorGetNativeDescriptor(fdref)
+                   << " != " << fd;
+      return false;
+    }
+    if (persistent != controller->is_persistent_) {
+      NOTREACHED() << "persistent doesn't match";
+      return false;
+    }
+
+    // Combine old/new event masks.
+    CFFileDescriptorDisableCallBacks(fdref, controller->callback_types_);
+    controller->callback_types_ |= callback_types;
+    CFFileDescriptorEnableCallBacks(fdref, controller->callback_types_);
+  }
+
+  controller->set_watcher(delegate);
+  controller->set_pump(weak_factory_.GetWeakPtr());
+
+  return true;
+}
+
+void MessagePumpIOSForIO::RemoveRunLoopSource(CFRunLoopSourceRef source) {
+  CFRunLoopRemoveSource(run_loop(), source, kCFRunLoopCommonModes);
+}
+
+void MessagePumpIOSForIO::AddIOObserver(IOObserver *obs) {
+  io_observers_.AddObserver(obs);
+}
+
+void MessagePumpIOSForIO::RemoveIOObserver(IOObserver *obs) {
+  io_observers_.RemoveObserver(obs);
+}
+
+void MessagePumpIOSForIO::WillProcessIOEvent() {
+  FOR_EACH_OBSERVER(IOObserver, io_observers_, WillProcessIOEvent());
+}
+
+void MessagePumpIOSForIO::DidProcessIOEvent() {
+  FOR_EACH_OBSERVER(IOObserver, io_observers_, DidProcessIOEvent());
+}
+
+// static
+void MessagePumpIOSForIO::HandleFdIOEvent(CFFileDescriptorRef fdref,
+                                          CFOptionFlags callback_types,
+                                          void* context) {
+  FileDescriptorWatcher* controller =
+      static_cast<FileDescriptorWatcher*>(context);
+  DCHECK_EQ(fdref, controller->fdref_);
+
+  // Ensure that |fdref| will remain live for the duration of this function
+  // call even if |controller| is deleted or |StopWatchingFileDescriptor()| is
+  // called, either of which will cause |fdref| to be released.
+  ScopedCFTypeRef<CFFileDescriptorRef> scoped_fdref(
+      fdref, base::scoped_policy::RETAIN);
+
+  int fd = CFFileDescriptorGetNativeDescriptor(fdref);
+  MessagePumpIOSForIO* pump = controller->pump().get();
+  DCHECK(pump);
+  if (callback_types & kCFFileDescriptorWriteCallBack)
+    controller->OnFileCanWriteWithoutBlocking(fd, pump);
+
+  // Perform the read callback only if the file descriptor has not been
+  // invalidated in the write callback. As |FileDescriptorWatcher| invalidates
+  // its file descriptor on destruction, the file descriptor being valid also
+  // guarantees that |controller| has not been deleted.
+  if (callback_types & kCFFileDescriptorReadCallBack &&
+      CFFileDescriptorIsValid(fdref)) {
+    DCHECK_EQ(fdref, controller->fdref_);
+    controller->OnFileCanReadWithoutBlocking(fd, pump);
+  }
+
+  // Re-enable callbacks after the read/write if the file descriptor is still
+  // valid and the controller is persistent.
+  if (CFFileDescriptorIsValid(fdref) && controller->is_persistent_) {
+    DCHECK_EQ(fdref, controller->fdref_);
+    CFFileDescriptorEnableCallBacks(fdref, callback_types);
+  }
+}
+
+}  // namespace base
diff --git a/base/message_loop/message_pump_io_ios.h b/base/message_loop/message_pump_io_ios.h
new file mode 100644
index 0000000..317a59c
--- /dev/null
+++ b/base/message_loop/message_pump_io_ios.h
@@ -0,0 +1,144 @@
+// Copyright 2012 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_MESSAGE_LOOP_MESSAGE_PUMP_IO_IOS_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_IO_IOS_H_
+
+#include "base/base_export.h"
+#include "base/mac/scoped_cffiledescriptorref.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_pump_mac.h"
+#include "base/observer_list.h"
+#include "base/threading/thread_checker.h"
+
+namespace base {
+
+// This file introduces a class to monitor sockets and issue callbacks when
+// sockets are ready for I/O on iOS.
+class BASE_EXPORT MessagePumpIOSForIO : public MessagePumpNSRunLoop {
+ public:
+  class IOObserver {
+   public:
+    IOObserver() {}
+
+    // An IOObserver is an object that receives IO notifications from the
+    // MessagePump.
+    //
+    // NOTE: An IOObserver implementation should be extremely fast!
+    virtual void WillProcessIOEvent() = 0;
+    virtual void DidProcessIOEvent() = 0;
+
+   protected:
+    virtual ~IOObserver() {}
+  };
+
+  // Used with WatchFileDescriptor to asynchronously monitor the I/O readiness
+  // of a file descriptor.
+  class Watcher {
+   public:
+    // Called from MessageLoop::Run when an FD can be read from/written to
+    // without blocking
+    virtual void OnFileCanReadWithoutBlocking(int fd) = 0;
+    virtual void OnFileCanWriteWithoutBlocking(int fd) = 0;
+
+   protected:
+    virtual ~Watcher() {}
+  };
+
+  // Object returned by WatchFileDescriptor to manage further watching.
+  class FileDescriptorWatcher {
+   public:
+    FileDescriptorWatcher();
+    ~FileDescriptorWatcher();  // Implicitly calls StopWatchingFileDescriptor.
+
+    // NOTE: These methods aren't called StartWatching()/StopWatching() to
+    // avoid confusion with the win32 ObjectWatcher class.
+
+    // Stop watching the FD, always safe to call.  No-op if there's nothing
+    // to do.
+    bool StopWatchingFileDescriptor();
+
+   private:
+    friend class MessagePumpIOSForIO;
+    friend class MessagePumpIOSForIOTest;
+
+    // Called by MessagePumpIOSForIO, ownership of |fdref| and |fd_source|
+    // is transferred to this object.
+    void Init(CFFileDescriptorRef fdref,
+              CFOptionFlags callback_types,
+              CFRunLoopSourceRef fd_source,
+              bool is_persistent);
+
+    void set_pump(base::WeakPtr<MessagePumpIOSForIO> pump) { pump_ = pump; }
+    const base::WeakPtr<MessagePumpIOSForIO>& pump() const { return pump_; }
+
+    void set_watcher(Watcher* watcher) { watcher_ = watcher; }
+
+    void OnFileCanReadWithoutBlocking(int fd, MessagePumpIOSForIO* pump);
+    void OnFileCanWriteWithoutBlocking(int fd, MessagePumpIOSForIO* pump);
+
+    bool is_persistent_;  // false if this event is one-shot.
+    base::mac::ScopedCFFileDescriptorRef fdref_;
+    CFOptionFlags callback_types_;
+    base::ScopedCFTypeRef<CFRunLoopSourceRef> fd_source_;
+    base::WeakPtr<MessagePumpIOSForIO> pump_;
+    Watcher* watcher_;
+
+    DISALLOW_COPY_AND_ASSIGN(FileDescriptorWatcher);
+  };
+
+  enum Mode {
+    WATCH_READ = 1 << 0,
+    WATCH_WRITE = 1 << 1,
+    WATCH_READ_WRITE = WATCH_READ | WATCH_WRITE
+  };
+
+  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.
+  // Callers must provide a preallocated FileDescriptorWatcher object which
+  // can later be used to manage the lifetime of this event.
+  // If a FileDescriptorWatcher is passed in which is already attached to
+  // an event, then the effect is cumulative i.e. after the call |controller|
+  // will watch both the previous event and the new one.
+  // If an error occurs while calling this method in a cumulative fashion, the
+  // event previously attached to |controller| is aborted.
+  // Returns true on success.
+  // Must be called on the same thread the message_pump is running on.
+  bool WatchFileDescriptor(int fd,
+                           bool persistent,
+                           int mode,
+                           FileDescriptorWatcher *controller,
+                           Watcher *delegate);
+
+  void RemoveRunLoopSource(CFRunLoopSourceRef source);
+
+  void AddIOObserver(IOObserver* obs);
+  void RemoveIOObserver(IOObserver* obs);
+
+ private:
+  friend class MessagePumpIOSForIOTest;
+
+  void WillProcessIOEvent();
+  void DidProcessIOEvent();
+
+  static void HandleFdIOEvent(CFFileDescriptorRef fdref,
+                              CFOptionFlags callback_types,
+                              void* context);
+
+  ObserverList<IOObserver> io_observers_;
+  ThreadChecker watch_file_descriptor_caller_checker_;
+
+  base::WeakPtrFactory<MessagePumpIOSForIO> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(MessagePumpIOSForIO);
+};
+
+}  // namespace base
+
+#endif  // BASE_MESSAGE_LOOP_MESSAGE_PUMP_IO_IOS_H_
diff --git a/base/message_loop/message_pump_io_ios_unittest.cc b/base/message_loop/message_pump_io_ios_unittest.cc
new file mode 100644
index 0000000..ba96f83
--- /dev/null
+++ b/base/message_loop/message_pump_io_ios_unittest.cc
@@ -0,0 +1,182 @@
+// Copyright 2012 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/message_loop/message_pump_io_ios.h"
+
+#include <unistd.h>
+
+#include "base/message_loop/message_loop.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+class MessagePumpIOSForIOTest : public testing::Test {
+ protected:
+  MessagePumpIOSForIOTest()
+      : ui_loop_(MessageLoop::TYPE_UI),
+        io_thread_("MessagePumpIOSForIOTestIOThread") {}
+  ~MessagePumpIOSForIOTest() 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());
+    int ret = pipe(pipefds_);
+    ASSERT_EQ(0, ret);
+    ret = pipe(alternate_pipefds_);
+    ASSERT_EQ(0, ret);
+  }
+
+  void TearDown() override {
+    if (IGNORE_EINTR(close(pipefds_[0])) < 0)
+      PLOG(ERROR) << "close";
+    if (IGNORE_EINTR(close(pipefds_[1])) < 0)
+      PLOG(ERROR) << "close";
+  }
+
+  MessageLoop* ui_loop() { return &ui_loop_; }
+  MessageLoopForIO* io_loop() const {
+    return static_cast<MessageLoopForIO*>(io_thread_.message_loop());
+  }
+
+  void HandleFdIOEvent(MessageLoopForIO::FileDescriptorWatcher* watcher) {
+    MessagePumpIOSForIO::HandleFdIOEvent(watcher->fdref_,
+        kCFFileDescriptorReadCallBack | kCFFileDescriptorWriteCallBack,
+        watcher);
+  }
+
+  int pipefds_[2];
+  int alternate_pipefds_[2];
+
+ private:
+  MessageLoop ui_loop_;
+  Thread io_thread_;
+
+  DISALLOW_COPY_AND_ASSIGN(MessagePumpIOSForIOTest);
+};
+
+namespace {
+
+// Concrete implementation of MessagePumpIOSForIO::Watcher that does
+// nothing useful.
+class StupidWatcher : public MessagePumpIOSForIO::Watcher {
+ public:
+  ~StupidWatcher() override {}
+
+  // base:MessagePumpIOSForIO::Watcher interface
+  void OnFileCanReadWithoutBlocking(int fd) override {}
+  void OnFileCanWriteWithoutBlocking(int fd) override {}
+};
+
+#if GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
+
+// Test to make sure that we catch calling WatchFileDescriptor off of the
+//  wrong thread.
+TEST_F(MessagePumpIOSForIOTest, TestWatchingFromBadThread) {
+  MessagePumpIOSForIO::FileDescriptorWatcher watcher;
+  StupidWatcher delegate;
+
+  ASSERT_DEBUG_DEATH(io_loop()->WatchFileDescriptor(
+      STDOUT_FILENO, false, MessageLoopForIO::WATCH_READ, &watcher, &delegate),
+      "Check failed: "
+      "watch_file_descriptor_caller_checker_.CalledOnValidThread\\(\\)");
+}
+
+#endif  // GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
+
+class BaseWatcher : public MessagePumpIOSForIO::Watcher {
+ public:
+  BaseWatcher(MessagePumpIOSForIO::FileDescriptorWatcher* controller)
+      : controller_(controller) {
+    DCHECK(controller_);
+  }
+  ~BaseWatcher() override {}
+
+  // MessagePumpIOSForIO::Watcher interface
+  void OnFileCanReadWithoutBlocking(int /* fd */) override { NOTREACHED(); }
+
+  void OnFileCanWriteWithoutBlocking(int /* fd */) override { NOTREACHED(); }
+
+ protected:
+  MessagePumpIOSForIO::FileDescriptorWatcher* controller_;
+};
+
+class DeleteWatcher : public BaseWatcher {
+ public:
+  explicit DeleteWatcher(
+      MessagePumpIOSForIO::FileDescriptorWatcher* controller)
+      : BaseWatcher(controller) {}
+
+  ~DeleteWatcher() override { DCHECK(!controller_); }
+
+  void OnFileCanWriteWithoutBlocking(int /* fd */) override {
+    DCHECK(controller_);
+    delete controller_;
+    controller_ = NULL;
+  }
+};
+
+TEST_F(MessagePumpIOSForIOTest, DeleteWatcher) {
+  scoped_ptr<MessagePumpIOSForIO> pump(new MessagePumpIOSForIO);
+  MessagePumpIOSForIO::FileDescriptorWatcher* watcher =
+      new MessagePumpIOSForIO::FileDescriptorWatcher;
+  DeleteWatcher delegate(watcher);
+  pump->WatchFileDescriptor(pipefds_[1],
+      false, MessagePumpIOSForIO::WATCH_READ_WRITE, watcher, &delegate);
+
+  // Spoof a callback.
+  HandleFdIOEvent(watcher);
+}
+
+class StopWatcher : public BaseWatcher {
+ public:
+  StopWatcher(MessagePumpIOSForIO::FileDescriptorWatcher* controller,
+              MessagePumpIOSForIO* pump,
+              int fd_to_start_watching = -1)
+      : BaseWatcher(controller),
+        pump_(pump),
+        fd_to_start_watching_(fd_to_start_watching) {}
+
+  ~StopWatcher() override {}
+
+  void OnFileCanWriteWithoutBlocking(int /* fd */) override {
+    controller_->StopWatchingFileDescriptor();
+    if (fd_to_start_watching_ >= 0) {
+      pump_->WatchFileDescriptor(fd_to_start_watching_,
+          false, MessagePumpIOSForIO::WATCH_READ_WRITE, controller_, this);
+    }
+  }
+
+ private:
+  MessagePumpIOSForIO* pump_;
+  int fd_to_start_watching_;
+};
+
+TEST_F(MessagePumpIOSForIOTest, StopWatcher) {
+  scoped_ptr<MessagePumpIOSForIO> pump(new MessagePumpIOSForIO);
+  MessagePumpIOSForIO::FileDescriptorWatcher watcher;
+  StopWatcher delegate(&watcher, pump.get());
+  pump->WatchFileDescriptor(pipefds_[1],
+      false, MessagePumpIOSForIO::WATCH_READ_WRITE, &watcher, &delegate);
+
+  // Spoof a callback.
+  HandleFdIOEvent(&watcher);
+}
+
+TEST_F(MessagePumpIOSForIOTest, StopWatcherAndWatchSomethingElse) {
+  scoped_ptr<MessagePumpIOSForIO> pump(new MessagePumpIOSForIO);
+  MessagePumpIOSForIO::FileDescriptorWatcher watcher;
+  StopWatcher delegate(&watcher, pump.get(), alternate_pipefds_[1]);
+  pump->WatchFileDescriptor(pipefds_[1],
+      false, MessagePumpIOSForIO::WATCH_READ_WRITE, &watcher, &delegate);
+
+  // Spoof a callback.
+  HandleFdIOEvent(&watcher);
+}
+
+}  // namespace
+
+}  // namespace base
diff --git a/base/message_loop/message_pump_libevent.cc b/base/message_loop/message_pump_libevent.cc
new file mode 100644
index 0000000..b5b1fb7
--- /dev/null
+++ b/base/message_loop/message_pump_libevent.cc
@@ -0,0 +1,379 @@
+// Copyright (c) 2012 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/message_loop/message_pump_libevent.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "base/auto_reset.h"
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/observer_list.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
+#include "third_party/libevent/event.h"
+
+#if defined(OS_MACOSX)
+#include "base/mac/scoped_nsautorelease_pool.h"
+#endif
+
+// Lifecycle of struct event
+// Libevent uses two main data structures:
+// struct event_base (of which there is one per message pump), and
+// struct event (of which there is roughly one per socket).
+// The socket's struct event is created in
+// MessagePumpLibevent::WatchFileDescriptor(),
+// is owned by the FileDescriptorWatcher, and is destroyed in
+// StopWatchingFileDescriptor().
+// It is moved into and out of lists in struct event_base by
+// the libevent functions event_add() and event_del().
+//
+// TODO(dkegel):
+// At the moment bad things happen if a FileDescriptorWatcher
+// is active after its MessagePumpLibevent has been destroyed.
+// See MessageLoopTest.FileDescriptorWatcherOutlivesMessageLoop
+// Not clear yet whether that situation occurs in practice,
+// but if it does, we need to fix it.
+
+namespace base {
+
+// Return 0 on success
+// Too small a function to bother putting in a library?
+static int SetNonBlocking(int fd) {
+  int flags = fcntl(fd, F_GETFL, 0);
+  if (flags == -1)
+    flags = 0;
+  return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+}
+
+MessagePumpLibevent::FileDescriptorWatcher::FileDescriptorWatcher()
+    : event_(NULL),
+      pump_(NULL),
+      watcher_(NULL),
+      weak_factory_(this) {
+}
+
+MessagePumpLibevent::FileDescriptorWatcher::~FileDescriptorWatcher() {
+  if (event_) {
+    StopWatchingFileDescriptor();
+  }
+}
+
+bool MessagePumpLibevent::FileDescriptorWatcher::StopWatchingFileDescriptor() {
+  event* e = ReleaseEvent();
+  if (e == NULL)
+    return true;
+
+  // event_del() is a no-op if the event isn't active.
+  int rv = event_del(e);
+  delete e;
+  pump_ = NULL;
+  watcher_ = NULL;
+  return (rv == 0);
+}
+
+void MessagePumpLibevent::FileDescriptorWatcher::Init(event *e) {
+  DCHECK(e);
+  DCHECK(!event_);
+
+  event_ = e;
+}
+
+event *MessagePumpLibevent::FileDescriptorWatcher::ReleaseEvent() {
+  struct event *e = event_;
+  event_ = NULL;
+  return e;
+}
+
+void MessagePumpLibevent::FileDescriptorWatcher::OnFileCanReadWithoutBlocking(
+    int fd, MessagePumpLibevent* pump) {
+  // Since OnFileCanWriteWithoutBlocking() gets called first, it can stop
+  // watching the file descriptor.
+  if (!watcher_)
+    return;
+  pump->WillProcessIOEvent();
+  watcher_->OnFileCanReadWithoutBlocking(fd);
+  pump->DidProcessIOEvent();
+}
+
+void MessagePumpLibevent::FileDescriptorWatcher::OnFileCanWriteWithoutBlocking(
+    int fd, MessagePumpLibevent* pump) {
+  DCHECK(watcher_);
+  pump->WillProcessIOEvent();
+  watcher_->OnFileCanWriteWithoutBlocking(fd);
+  pump->DidProcessIOEvent();
+}
+
+MessagePumpLibevent::MessagePumpLibevent()
+    : keep_running_(true),
+      in_run_(false),
+      processed_io_events_(false),
+      event_base_(event_base_new()),
+      wakeup_pipe_in_(-1),
+      wakeup_pipe_out_(-1) {
+  if (!Init())
+     NOTREACHED();
+}
+
+MessagePumpLibevent::~MessagePumpLibevent() {
+  DCHECK(wakeup_event_);
+  DCHECK(event_base_);
+  event_del(wakeup_event_);
+  delete wakeup_event_;
+  if (wakeup_pipe_in_ >= 0) {
+    if (IGNORE_EINTR(close(wakeup_pipe_in_)) < 0)
+      DPLOG(ERROR) << "close";
+  }
+  if (wakeup_pipe_out_ >= 0) {
+    if (IGNORE_EINTR(close(wakeup_pipe_out_)) < 0)
+      DPLOG(ERROR) << "close";
+  }
+  event_base_free(event_base_);
+}
+
+bool MessagePumpLibevent::WatchFileDescriptor(int fd,
+                                              bool persistent,
+                                              int mode,
+                                              FileDescriptorWatcher *controller,
+                                              Watcher *delegate) {
+  DCHECK_GE(fd, 0);
+  DCHECK(controller);
+  DCHECK(delegate);
+  DCHECK(mode == WATCH_READ || mode == WATCH_WRITE || mode == WATCH_READ_WRITE);
+  // WatchFileDescriptor should be called on the pump thread. It is not
+  // threadsafe, and your watcher may never be registered.
+  DCHECK(watch_file_descriptor_caller_checker_.CalledOnValidThread());
+
+  int event_mask = persistent ? EV_PERSIST : 0;
+  if (mode & WATCH_READ) {
+    event_mask |= EV_READ;
+  }
+  if (mode & WATCH_WRITE) {
+    event_mask |= EV_WRITE;
+  }
+
+  scoped_ptr<event> evt(controller->ReleaseEvent());
+  if (evt.get() == NULL) {
+    // Ownership is transferred to the controller.
+    evt.reset(new event);
+  } else {
+    // Make sure we don't pick up any funky internal libevent masks.
+    int old_interest_mask = evt.get()->ev_events &
+        (EV_READ | EV_WRITE | EV_PERSIST);
+
+    // Combine old/new event masks.
+    event_mask |= old_interest_mask;
+
+    // Must disarm the event before we can reuse it.
+    event_del(evt.get());
+
+    // It's illegal to use this function to listen on 2 separate fds with the
+    // same |controller|.
+    if (EVENT_FD(evt.get()) != fd) {
+      NOTREACHED() << "FDs don't match" << EVENT_FD(evt.get()) << "!=" << fd;
+      return false;
+    }
+  }
+
+  // Set current interest mask and message pump for this event.
+  event_set(evt.get(), fd, event_mask, OnLibeventNotification, controller);
+
+  // Tell libevent which message pump this socket will belong to when we add it.
+  if (event_base_set(event_base_, evt.get())) {
+    return false;
+  }
+
+  // Add this socket to the list of monitored sockets.
+  if (event_add(evt.get(), NULL)) {
+    return false;
+  }
+
+  // Transfer ownership of evt to controller.
+  controller->Init(evt.release());
+
+  controller->set_watcher(delegate);
+  controller->set_pump(this);
+
+  return true;
+}
+
+void MessagePumpLibevent::AddIOObserver(IOObserver *obs) {
+  io_observers_.AddObserver(obs);
+}
+
+void MessagePumpLibevent::RemoveIOObserver(IOObserver *obs) {
+  io_observers_.RemoveObserver(obs);
+}
+
+// Tell libevent to break out of inner loop.
+static void timer_callback(int fd, short events, void *context)
+{
+  event_base_loopbreak((struct event_base *)context);
+}
+
+// Reentrant!
+void MessagePumpLibevent::Run(Delegate* delegate) {
+  AutoReset<bool> auto_reset_keep_running(&keep_running_, true);
+  AutoReset<bool> auto_reset_in_run(&in_run_, true);
+
+  // event_base_loopexit() + EVLOOP_ONCE is leaky, see http://crbug.com/25641.
+  // Instead, make our own timer and reuse it on each call to event_base_loop().
+  scoped_ptr<event> timer_event(new event);
+
+  for (;;) {
+#if defined(OS_MACOSX)
+    mac::ScopedNSAutoreleasePool autorelease_pool;
+#endif
+
+    bool did_work = delegate->DoWork();
+    if (!keep_running_)
+      break;
+
+    event_base_loop(event_base_, EVLOOP_NONBLOCK);
+    did_work |= processed_io_events_;
+    processed_io_events_ = false;
+    if (!keep_running_)
+      break;
+
+    did_work |= delegate->DoDelayedWork(&delayed_work_time_);
+    if (!keep_running_)
+      break;
+
+    if (did_work)
+      continue;
+
+    did_work = delegate->DoIdleWork();
+    if (!keep_running_)
+      break;
+
+    if (did_work)
+      continue;
+
+    // EVLOOP_ONCE tells libevent to only block once,
+    // but to service all pending events when it wakes up.
+    if (delayed_work_time_.is_null()) {
+      event_base_loop(event_base_, EVLOOP_ONCE);
+    } else {
+      TimeDelta delay = delayed_work_time_ - TimeTicks::Now();
+      if (delay > TimeDelta()) {
+        struct timeval poll_tv;
+        poll_tv.tv_sec = delay.InSeconds();
+        poll_tv.tv_usec = delay.InMicroseconds() % Time::kMicrosecondsPerSecond;
+        event_set(timer_event.get(), -1, 0, timer_callback, event_base_);
+        event_base_set(event_base_, timer_event.get());
+        event_add(timer_event.get(), &poll_tv);
+        event_base_loop(event_base_, EVLOOP_ONCE);
+        event_del(timer_event.get());
+      } else {
+        // It looks like delayed_work_time_ indicates a time in the past, so we
+        // need to call DoDelayedWork now.
+        delayed_work_time_ = TimeTicks();
+      }
+    }
+
+    if (!keep_running_)
+      break;
+  }
+}
+
+void MessagePumpLibevent::Quit() {
+  DCHECK(in_run_) << "Quit was called outside of Run!";
+  // Tell both libevent and Run that they should break out of their loops.
+  keep_running_ = false;
+  ScheduleWork();
+}
+
+void MessagePumpLibevent::ScheduleWork() {
+  // Tell libevent (in a threadsafe way) that it should break out of its loop.
+  char buf = 0;
+  int nwrite = HANDLE_EINTR(write(wakeup_pipe_in_, &buf, 1));
+  DCHECK(nwrite == 1 || errno == EAGAIN)
+      << "[nwrite:" << nwrite << "] [errno:" << errno << "]";
+}
+
+void MessagePumpLibevent::ScheduleDelayedWork(
+    const TimeTicks& delayed_work_time) {
+  // We know that we can't be blocked on Wait right now since this method can
+  // only be called on the same thread as Run, so we only need to update our
+  // record of how long to sleep when we do sleep.
+  delayed_work_time_ = delayed_work_time;
+}
+
+void MessagePumpLibevent::WillProcessIOEvent() {
+  FOR_EACH_OBSERVER(IOObserver, io_observers_, WillProcessIOEvent());
+}
+
+void MessagePumpLibevent::DidProcessIOEvent() {
+  FOR_EACH_OBSERVER(IOObserver, io_observers_, DidProcessIOEvent());
+}
+
+bool MessagePumpLibevent::Init() {
+  int fds[2];
+  if (pipe(fds)) {
+    DLOG(ERROR) << "pipe() failed, errno: " << errno;
+    return false;
+  }
+  if (SetNonBlocking(fds[0])) {
+    DLOG(ERROR) << "SetNonBlocking for pipe fd[0] failed, errno: " << errno;
+    return false;
+  }
+  if (SetNonBlocking(fds[1])) {
+    DLOG(ERROR) << "SetNonBlocking for pipe fd[1] failed, errno: " << errno;
+    return false;
+  }
+  wakeup_pipe_out_ = fds[0];
+  wakeup_pipe_in_ = fds[1];
+
+  wakeup_event_ = new event;
+  event_set(wakeup_event_, wakeup_pipe_out_, EV_READ | EV_PERSIST,
+            OnWakeup, this);
+  event_base_set(event_base_, wakeup_event_);
+
+  if (event_add(wakeup_event_, 0))
+    return false;
+  return true;
+}
+
+// static
+void MessagePumpLibevent::OnLibeventNotification(int fd, short flags,
+                                                 void* context) {
+  WeakPtr<FileDescriptorWatcher> controller =
+      static_cast<FileDescriptorWatcher*>(context)->weak_factory_.GetWeakPtr();
+  DCHECK(controller.get());
+  TRACE_EVENT1("toplevel", "MessagePumpLibevent::OnLibeventNotification",
+               "fd", fd);
+
+  MessagePumpLibevent* pump = controller->pump();
+  pump->processed_io_events_ = true;
+
+  if (flags & EV_WRITE) {
+    controller->OnFileCanWriteWithoutBlocking(fd, pump);
+  }
+  // Check |controller| in case it's been deleted in
+  // controller->OnFileCanWriteWithoutBlocking().
+  if (controller.get() && flags & EV_READ) {
+    controller->OnFileCanReadWithoutBlocking(fd, pump);
+  }
+}
+
+// Called if a byte is received on the wakeup pipe.
+// static
+void MessagePumpLibevent::OnWakeup(int socket, short flags, void* context) {
+  MessagePumpLibevent* that = static_cast<MessagePumpLibevent*>(context);
+  DCHECK(that->wakeup_pipe_out_ == socket);
+
+  // Remove and discard the wakeup byte.
+  char buf;
+  int nread = HANDLE_EINTR(read(socket, &buf, 1));
+  DCHECK_EQ(nread, 1);
+  that->processed_io_events_ = true;
+  // Tell libevent to break out of inner loop.
+  event_base_loopbreak(that->event_base_);
+}
+
+}  // namespace base
diff --git a/base/message_loop/message_pump_libevent.h b/base/message_loop/message_pump_libevent.h
new file mode 100644
index 0000000..3f5ad51
--- /dev/null
+++ b/base/message_loop/message_pump_libevent.h
@@ -0,0 +1,177 @@
+// Copyright (c) 2012 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_MESSAGE_LOOP_MESSAGE_PUMP_LIBEVENT_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_LIBEVENT_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_pump.h"
+#include "base/observer_list.h"
+#include "base/threading/thread_checker.h"
+#include "base/time/time.h"
+
+// Declare structs we need from libevent.h rather than including it
+struct event_base;
+struct event;
+
+namespace base {
+
+// Class to monitor sockets and issue callbacks when sockets are ready for I/O
+// TODO(dkegel): add support for background file IO somehow
+class BASE_EXPORT MessagePumpLibevent : public MessagePump {
+ public:
+  class IOObserver {
+   public:
+    IOObserver() {}
+
+    // An IOObserver is an object that receives IO notifications from the
+    // MessagePump.
+    //
+    // NOTE: An IOObserver implementation should be extremely fast!
+    virtual void WillProcessIOEvent() = 0;
+    virtual void DidProcessIOEvent() = 0;
+
+   protected:
+    virtual ~IOObserver() {}
+  };
+
+  // Used with WatchFileDescriptor to asynchronously monitor the I/O readiness
+  // of a file descriptor.
+  class Watcher {
+   public:
+    // Called from MessageLoop::Run when an FD can be read from/written to
+    // without blocking
+    virtual void OnFileCanReadWithoutBlocking(int fd) = 0;
+    virtual void OnFileCanWriteWithoutBlocking(int fd) = 0;
+
+   protected:
+    virtual ~Watcher() {}
+  };
+
+  // Object returned by WatchFileDescriptor to manage further watching.
+  class FileDescriptorWatcher {
+   public:
+    FileDescriptorWatcher();
+    ~FileDescriptorWatcher();  // Implicitly calls StopWatchingFileDescriptor.
+
+    // NOTE: These methods aren't called StartWatching()/StopWatching() to
+    // avoid confusion with the win32 ObjectWatcher class.
+
+    // Stop watching the FD, always safe to call.  No-op if there's nothing
+    // to do.
+    bool StopWatchingFileDescriptor();
+
+   private:
+    friend class MessagePumpLibevent;
+    friend class MessagePumpLibeventTest;
+
+    // Called by MessagePumpLibevent, ownership of |e| is transferred to this
+    // object.
+    void Init(event* e);
+
+    // Used by MessagePumpLibevent to take ownership of event_.
+    event* ReleaseEvent();
+
+    void set_pump(MessagePumpLibevent* pump) { pump_ = pump; }
+    MessagePumpLibevent* pump() const { return pump_; }
+
+    void set_watcher(Watcher* watcher) { watcher_ = watcher; }
+
+    void OnFileCanReadWithoutBlocking(int fd, MessagePumpLibevent* pump);
+    void OnFileCanWriteWithoutBlocking(int fd, MessagePumpLibevent* pump);
+
+    event* event_;
+    MessagePumpLibevent* pump_;
+    Watcher* watcher_;
+    WeakPtrFactory<FileDescriptorWatcher> weak_factory_;
+
+    DISALLOW_COPY_AND_ASSIGN(FileDescriptorWatcher);
+  };
+
+  enum Mode {
+    WATCH_READ = 1 << 0,
+    WATCH_WRITE = 1 << 1,
+    WATCH_READ_WRITE = WATCH_READ | WATCH_WRITE
+  };
+
+  MessagePumpLibevent();
+  ~MessagePumpLibevent() 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.
+  // Callers must provide a preallocated FileDescriptorWatcher object which
+  // can later be used to manage the lifetime of this event.
+  // If a FileDescriptorWatcher is passed in which is already attached to
+  // an event, then the effect is cumulative i.e. after the call |controller|
+  // will watch both the previous event and the new one.
+  // If an error occurs while calling this method in a cumulative fashion, the
+  // event previously attached to |controller| is aborted.
+  // Returns true on success.
+  // Must be called on the same thread the message_pump is running on.
+  // TODO(dkegel): switch to edge-triggered readiness notification
+  bool WatchFileDescriptor(int fd,
+                           bool persistent,
+                           int mode,
+                           FileDescriptorWatcher *controller,
+                           Watcher *delegate);
+
+  void AddIOObserver(IOObserver* obs);
+  void RemoveIOObserver(IOObserver* obs);
+
+  // MessagePump methods:
+  void Run(Delegate* delegate) override;
+  void Quit() override;
+  void ScheduleWork() override;
+  void ScheduleDelayedWork(const TimeTicks& delayed_work_time) override;
+
+ private:
+  friend class MessagePumpLibeventTest;
+
+  void WillProcessIOEvent();
+  void DidProcessIOEvent();
+
+  // Risky part of constructor.  Returns true on success.
+  bool Init();
+
+  // Called by libevent to tell us a registered FD can be read/written to.
+  static void OnLibeventNotification(int fd, short flags,
+                                     void* context);
+
+  // Unix pipe used to implement ScheduleWork()
+  // ... callback; called by libevent inside Run() when pipe is ready to read
+  static void OnWakeup(int socket, short flags, void* context);
+
+  // This flag is set to false when Run should return.
+  bool keep_running_;
+
+  // This flag is set when inside Run.
+  bool in_run_;
+
+  // This flag is set if libevent has processed I/O events.
+  bool processed_io_events_;
+
+  // The time at which we should call DoDelayedWork.
+  TimeTicks delayed_work_time_;
+
+  // Libevent dispatcher.  Watches all sockets registered with it, and sends
+  // readiness callbacks when a socket is ready for I/O.
+  event_base* event_base_;
+
+  // ... write end; ScheduleWork() writes a single byte to it
+  int wakeup_pipe_in_;
+  // ... read end; OnWakeup reads it and then breaks Run() out of its sleep
+  int wakeup_pipe_out_;
+  // ... libevent wrapper for read end
+  event* wakeup_event_;
+
+  ObserverList<IOObserver> io_observers_;
+  ThreadChecker watch_file_descriptor_caller_checker_;
+  DISALLOW_COPY_AND_ASSIGN(MessagePumpLibevent);
+};
+
+}  // namespace base
+
+#endif  // BASE_MESSAGE_LOOP_MESSAGE_PUMP_LIBEVENT_H_
diff --git a/base/message_loop/message_pump_libevent_unittest.cc b/base/message_loop/message_pump_libevent_unittest.cc
new file mode 100644
index 0000000..4246211
--- /dev/null
+++ b/base/message_loop/message_pump_libevent_unittest.cc
@@ -0,0 +1,272 @@
+// Copyright (c) 2012 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/message_loop/message_pump_libevent.h"
+
+#include <unistd.h>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/files/file_util.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/run_loop.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/synchronization/waitable_event_watcher.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/libevent/event.h"
+
+namespace base {
+
+class MessagePumpLibeventTest : public testing::Test {
+ protected:
+  MessagePumpLibeventTest()
+      : ui_loop_(new MessageLoop(MessageLoop::TYPE_UI)),
+        io_thread_("MessagePumpLibeventTestIOThread") {}
+  ~MessagePumpLibeventTest() 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());
+    int ret = pipe(pipefds_);
+    ASSERT_EQ(0, ret);
+  }
+
+  void TearDown() override {
+    if (IGNORE_EINTR(close(pipefds_[0])) < 0)
+      PLOG(ERROR) << "close";
+    if (IGNORE_EINTR(close(pipefds_[1])) < 0)
+      PLOG(ERROR) << "close";
+  }
+
+  MessageLoopForIO* io_loop() const {
+    return static_cast<MessageLoopForIO*>(io_thread_.message_loop());
+  }
+
+  void OnLibeventNotification(
+      MessagePumpLibevent* pump,
+      MessagePumpLibevent::FileDescriptorWatcher* controller) {
+    pump->OnLibeventNotification(0, EV_WRITE | EV_READ, controller);
+  }
+
+  int pipefds_[2];
+  scoped_ptr<MessageLoop> ui_loop_;
+
+ private:
+  Thread io_thread_;
+};
+
+namespace {
+
+// Concrete implementation of MessagePumpLibevent::Watcher that does
+// nothing useful.
+class StupidWatcher : public MessagePumpLibevent::Watcher {
+ public:
+  ~StupidWatcher() override {}
+
+  // base:MessagePumpLibevent::Watcher interface
+  void OnFileCanReadWithoutBlocking(int fd) override {}
+  void OnFileCanWriteWithoutBlocking(int fd) override {}
+};
+
+#if GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
+
+// Test to make sure that we catch calling WatchFileDescriptor off of the
+// wrong thread.
+#if defined(OS_CHROMEOS) || defined(OS_LINUX)
+// Flaky on Chrome OS and Linux: crbug.com/138845.
+#define MAYBE_TestWatchingFromBadThread DISABLED_TestWatchingFromBadThread
+#else
+#define MAYBE_TestWatchingFromBadThread TestWatchingFromBadThread
+#endif
+TEST_F(MessagePumpLibeventTest, MAYBE_TestWatchingFromBadThread) {
+  MessagePumpLibevent::FileDescriptorWatcher watcher;
+  StupidWatcher delegate;
+
+  ASSERT_DEATH(io_loop()->WatchFileDescriptor(
+      STDOUT_FILENO, false, MessageLoopForIO::WATCH_READ, &watcher, &delegate),
+      "Check failed: "
+      "watch_file_descriptor_caller_checker_.CalledOnValidThread\\(\\)");
+}
+
+TEST_F(MessagePumpLibeventTest, QuitOutsideOfRun) {
+  scoped_ptr<MessagePumpLibevent> pump(new MessagePumpLibevent);
+  ASSERT_DEATH(pump->Quit(), "Check failed: in_run_. "
+                             "Quit was called outside of Run!");
+}
+
+#endif  // GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
+
+class BaseWatcher : public MessagePumpLibevent::Watcher {
+ public:
+  explicit BaseWatcher(MessagePumpLibevent::FileDescriptorWatcher* controller)
+      : controller_(controller) {
+    DCHECK(controller_);
+  }
+  ~BaseWatcher() override {}
+
+  // base:MessagePumpLibevent::Watcher interface
+  void OnFileCanReadWithoutBlocking(int /* fd */) override { NOTREACHED(); }
+
+  void OnFileCanWriteWithoutBlocking(int /* fd */) override { NOTREACHED(); }
+
+ protected:
+  MessagePumpLibevent::FileDescriptorWatcher* controller_;
+};
+
+class DeleteWatcher : public BaseWatcher {
+ public:
+  explicit DeleteWatcher(
+      MessagePumpLibevent::FileDescriptorWatcher* controller)
+      : BaseWatcher(controller) {}
+
+  ~DeleteWatcher() override { DCHECK(!controller_); }
+
+  void OnFileCanWriteWithoutBlocking(int /* fd */) override {
+    DCHECK(controller_);
+    delete controller_;
+    controller_ = NULL;
+  }
+};
+
+TEST_F(MessagePumpLibeventTest, DeleteWatcher) {
+  scoped_ptr<MessagePumpLibevent> pump(new MessagePumpLibevent);
+  MessagePumpLibevent::FileDescriptorWatcher* watcher =
+      new MessagePumpLibevent::FileDescriptorWatcher;
+  DeleteWatcher delegate(watcher);
+  pump->WatchFileDescriptor(pipefds_[1],
+      false, MessagePumpLibevent::WATCH_READ_WRITE, watcher, &delegate);
+
+  // Spoof a libevent notification.
+  OnLibeventNotification(pump.get(), watcher);
+}
+
+class StopWatcher : public BaseWatcher {
+ public:
+  explicit StopWatcher(
+      MessagePumpLibevent::FileDescriptorWatcher* controller)
+      : BaseWatcher(controller) {}
+
+  ~StopWatcher() override {}
+
+  void OnFileCanWriteWithoutBlocking(int /* fd */) override {
+    controller_->StopWatchingFileDescriptor();
+  }
+};
+
+TEST_F(MessagePumpLibeventTest, StopWatcher) {
+  scoped_ptr<MessagePumpLibevent> pump(new MessagePumpLibevent);
+  MessagePumpLibevent::FileDescriptorWatcher watcher;
+  StopWatcher delegate(&watcher);
+  pump->WatchFileDescriptor(pipefds_[1],
+      false, MessagePumpLibevent::WATCH_READ_WRITE, &watcher, &delegate);
+
+  // Spoof a libevent notification.
+  OnLibeventNotification(pump.get(), &watcher);
+}
+
+void QuitMessageLoopAndStart(const Closure& quit_closure) {
+  quit_closure.Run();
+
+  MessageLoop::ScopedNestableTaskAllower allow(MessageLoop::current());
+  RunLoop runloop;
+  MessageLoop::current()->PostTask(FROM_HERE, runloop.QuitClosure());
+  runloop.Run();
+}
+
+class NestedPumpWatcher : public MessagePumpLibevent::Watcher {
+ public:
+  NestedPumpWatcher() {}
+  ~NestedPumpWatcher() override {}
+
+  void OnFileCanReadWithoutBlocking(int /* fd */) override {
+    RunLoop runloop;
+    MessageLoop::current()->PostTask(FROM_HERE, Bind(&QuitMessageLoopAndStart,
+                                                     runloop.QuitClosure()));
+    runloop.Run();
+  }
+
+  void OnFileCanWriteWithoutBlocking(int /* fd */) override {}
+};
+
+TEST_F(MessagePumpLibeventTest, NestedPumpWatcher) {
+  scoped_ptr<MessagePumpLibevent> pump(new MessagePumpLibevent);
+  MessagePumpLibevent::FileDescriptorWatcher watcher;
+  NestedPumpWatcher delegate;
+  pump->WatchFileDescriptor(pipefds_[1],
+      false, MessagePumpLibevent::WATCH_READ, &watcher, &delegate);
+
+  // Spoof a libevent notification.
+  OnLibeventNotification(pump.get(), &watcher);
+}
+
+void FatalClosure() {
+  FAIL() << "Reached fatal closure.";
+}
+
+class QuitWatcher : public BaseWatcher {
+ public:
+  QuitWatcher(MessagePumpLibevent::FileDescriptorWatcher* controller,
+              RunLoop* run_loop)
+      : BaseWatcher(controller), run_loop_(run_loop) {}
+  ~QuitWatcher() override {}
+
+  void OnFileCanReadWithoutBlocking(int /* fd */) override {
+    // Post a fatal closure to the MessageLoop before we quit it.
+    MessageLoop::current()->PostTask(FROM_HERE, Bind(&FatalClosure));
+
+    // Now quit the MessageLoop.
+    run_loop_->Quit();
+  }
+
+ private:
+  RunLoop* run_loop_;  // weak
+};
+
+void WriteFDWrapper(const int fd,
+                    const char* buf,
+                    int size,
+                    WaitableEvent* event) {
+  ASSERT_TRUE(WriteFileDescriptor(fd, buf, size));
+}
+
+// Tests that MessagePumpLibevent quits immediately when it is quit from
+// libevent's event_base_loop().
+TEST_F(MessagePumpLibeventTest, QuitWatcher) {
+  // Delete the old MessageLoop so that we can manage our own one here.
+  ui_loop_.reset();
+
+  MessagePumpLibevent* pump = new MessagePumpLibevent;  // owned by |loop|.
+  MessageLoop loop(make_scoped_ptr(pump));
+  RunLoop run_loop;
+  MessagePumpLibevent::FileDescriptorWatcher controller;
+  QuitWatcher delegate(&controller, &run_loop);
+  WaitableEvent event(false /* manual_reset */, false /* initially_signaled */);
+  WaitableEventWatcher watcher;
+
+  // Tell the pump to watch the pipe.
+  pump->WatchFileDescriptor(pipefds_[0], false, MessagePumpLibevent::WATCH_READ,
+                            &controller, &delegate);
+
+  // Make the IO thread wait for |event| before writing to pipefds[1].
+  const char buf = 0;
+  const WaitableEventWatcher::EventCallback write_fd_task =
+      Bind(&WriteFDWrapper, pipefds_[1], &buf, 1);
+  io_loop()->PostTask(FROM_HERE,
+                      Bind(IgnoreResult(&WaitableEventWatcher::StartWatching),
+                           Unretained(&watcher), &event, write_fd_task));
+
+  // Queue |event| to signal on |loop|.
+  loop.PostTask(FROM_HERE, Bind(&WaitableEvent::Signal, Unretained(&event)));
+
+  // Now run the MessageLoop.
+  run_loop.Run();
+}
+
+}  // namespace
+
+}  // namespace base
diff --git a/base/message_loop/message_pump_mac.h b/base/message_loop/message_pump_mac.h
new file mode 100644
index 0000000..c853202
--- /dev/null
+++ b/base/message_loop/message_pump_mac.h
@@ -0,0 +1,353 @@
+// Copyright (c) 2012 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.
+
+// The basis for all native run loops on the Mac is the CFRunLoop.  It can be
+// used directly, it can be used as the driving force behind the similar
+// Foundation NSRunLoop, and it can be used to implement higher-level event
+// loops such as the NSApplication event loop.
+//
+// This file introduces a basic CFRunLoop-based implementation of the
+// MessagePump interface called CFRunLoopBase.  CFRunLoopBase contains all
+// of the machinery necessary to dispatch events to a delegate, but does not
+// implement the specific run loop.  Concrete subclasses must provide their
+// own DoRun and Quit implementations.
+//
+// A concrete subclass that just runs a CFRunLoop loop is provided in
+// MessagePumpCFRunLoop.  For an NSRunLoop, the similar MessagePumpNSRunLoop
+// is provided.
+//
+// For the application's event loop, an implementation based on AppKit's
+// NSApplication event system is provided in MessagePumpNSApplication.
+//
+// Typically, MessagePumpNSApplication only makes sense on a Cocoa
+// application's main thread.  If a CFRunLoop-based message pump is needed on
+// any other thread, one of the other concrete subclasses is preferrable.
+// MessagePumpMac::Create is defined, which returns a new NSApplication-based
+// or NSRunLoop-based MessagePump subclass depending on which thread it is
+// called on.
+
+#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_MAC_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_MAC_H_
+
+#include "base/message_loop/message_pump.h"
+
+#include "base/basictypes.h"
+
+#include <CoreFoundation/CoreFoundation.h>
+
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop/timer_slack.h"
+
+#if defined(__OBJC__)
+#if defined(OS_IOS)
+#import <Foundation/Foundation.h>
+#else
+#import <AppKit/AppKit.h>
+
+// Clients must subclass NSApplication and implement this protocol if they use
+// MessagePumpMac.
+@protocol CrAppProtocol
+// Must return true if -[NSApplication sendEvent:] is currently on the stack.
+// See the comment for |CreateAutoreleasePool()| in the cc file for why this is
+// necessary.
+- (BOOL)isHandlingSendEvent;
+@end
+#endif  // !defined(OS_IOS)
+#endif  // defined(__OBJC__)
+
+namespace base {
+
+class RunLoop;
+class TimeTicks;
+
+// AutoreleasePoolType is a proxy type for autorelease pools. Its definition
+// depends on the translation unit (TU) in which this header appears. In pure
+// C++ TUs, it is defined as a forward C++ class declaration (that is never
+// defined), because autorelease pools are an Objective-C concept. In Automatic
+// Reference Counting (ARC) Objective-C TUs, it is similarly defined as a
+// forward C++ class declaration, because clang will not allow the type
+// "NSAutoreleasePool" in such TUs. Finally, in Manual Retain Release (MRR)
+// Objective-C TUs, it is a type alias for NSAutoreleasePool. In all cases, a
+// method that takes or returns an NSAutoreleasePool* can use
+// AutoreleasePoolType* instead.
+#if !defined(__OBJC__) || __has_feature(objc_arc)
+class AutoreleasePoolType;
+#else   // !defined(__OBJC__) || __has_feature(objc_arc)
+typedef NSAutoreleasePool AutoreleasePoolType;
+#endif  // !defined(__OBJC__) || __has_feature(objc_arc)
+
+class MessagePumpCFRunLoopBase : public MessagePump {
+  // Needs access to CreateAutoreleasePool.
+  friend class MessagePumpScopedAutoreleasePool;
+ public:
+  MessagePumpCFRunLoopBase();
+  ~MessagePumpCFRunLoopBase() override;
+
+  // Subclasses should implement the work they need to do in MessagePump::Run
+  // in the DoRun method.  MessagePumpCFRunLoopBase::Run calls DoRun directly.
+  // This arrangement is used because MessagePumpCFRunLoopBase needs to set
+  // up and tear down things before and after the "meat" of DoRun.
+  void Run(Delegate* delegate) override;
+  virtual void DoRun(Delegate* delegate) = 0;
+
+  void ScheduleWork() override;
+  void ScheduleDelayedWork(const TimeTicks& delayed_work_time) override;
+  void SetTimerSlack(TimerSlack timer_slack) override;
+
+ protected:
+  // Accessors for private data members to be used by subclasses.
+  CFRunLoopRef run_loop() const { return run_loop_; }
+  int nesting_level() const { return nesting_level_; }
+  int run_nesting_level() const { return run_nesting_level_; }
+
+  // Sets this pump's delegate.  Signals the appropriate sources if
+  // |delegateless_work_| is true.  |delegate| can be NULL.
+  void SetDelegate(Delegate* delegate);
+
+  // Return an autorelease pool to wrap around any work being performed.
+  // In some cases, CreateAutoreleasePool may return nil intentionally to
+  // preventing an autorelease pool from being created, allowing any
+  // objects autoreleased by work to fall into the current autorelease pool.
+  virtual AutoreleasePoolType* CreateAutoreleasePool();
+
+ private:
+  // Timer callback scheduled by ScheduleDelayedWork.  This does not do any
+  // work, but it signals work_source_ so that delayed work can be performed
+  // within the appropriate priority constraints.
+  static void RunDelayedWorkTimer(CFRunLoopTimerRef timer, void* info);
+
+  // Perform highest-priority work.  This is associated with work_source_
+  // signalled by ScheduleWork or RunDelayedWorkTimer.  The static method calls
+  // the instance method; the instance method returns true if it resignalled
+  // work_source_ to be called again from the loop.
+  static void RunWorkSource(void* info);
+  bool RunWork();
+
+  // Perform idle-priority work.  This is normally called by PreWaitObserver,
+  // but is also associated with idle_work_source_.  When this function
+  // actually does perform idle work, it will resignal that source.  The
+  // static method calls the instance method; the instance method returns
+  // true if idle work was done.
+  static void RunIdleWorkSource(void* info);
+  bool RunIdleWork();
+
+  // Perform work that may have been deferred because it was not runnable
+  // within a nested run loop.  This is associated with
+  // nesting_deferred_work_source_ and is signalled by
+  // MaybeScheduleNestingDeferredWork when returning from a nested loop,
+  // so that an outer loop will be able to perform the necessary tasks if it
+  // permits nestable tasks.
+  static void RunNestingDeferredWorkSource(void* info);
+  bool RunNestingDeferredWork();
+
+  // Schedules possible nesting-deferred work to be processed before the run
+  // loop goes to sleep, exits, or begins processing sources at the top of its
+  // loop.  If this function detects that a nested loop had run since the
+  // previous attempt to schedule nesting-deferred work, it will schedule a
+  // call to RunNestingDeferredWorkSource.
+  void MaybeScheduleNestingDeferredWork();
+
+  // Observer callback responsible for performing idle-priority work, before
+  // the run loop goes to sleep.  Associated with idle_work_observer_.
+  static void PreWaitObserver(CFRunLoopObserverRef observer,
+                              CFRunLoopActivity activity, void* info);
+
+  // Observer callback called before the run loop processes any sources.
+  // Associated with pre_source_observer_.
+  static void PreSourceObserver(CFRunLoopObserverRef observer,
+                                CFRunLoopActivity activity, void* info);
+
+  // Observer callback called when the run loop starts and stops, at the
+  // beginning and end of calls to CFRunLoopRun.  This is used to maintain
+  // nesting_level_.  Associated with enter_exit_observer_.
+  static void EnterExitObserver(CFRunLoopObserverRef observer,
+                                CFRunLoopActivity activity, void* info);
+
+  // Called by EnterExitObserver after performing maintenance on nesting_level_.
+  // This allows subclasses an opportunity to perform additional processing on
+  // the basis of run loops starting and stopping.
+  virtual void EnterExitRunLoop(CFRunLoopActivity activity);
+
+  // The thread's run loop.
+  CFRunLoopRef run_loop_;
+
+  // The timer, sources, and observers are described above alongside their
+  // callbacks.
+  CFRunLoopTimerRef delayed_work_timer_;
+  CFRunLoopSourceRef work_source_;
+  CFRunLoopSourceRef idle_work_source_;
+  CFRunLoopSourceRef nesting_deferred_work_source_;
+  CFRunLoopObserverRef pre_wait_observer_;
+  CFRunLoopObserverRef pre_source_observer_;
+  CFRunLoopObserverRef enter_exit_observer_;
+
+  // (weak) Delegate passed as an argument to the innermost Run call.
+  Delegate* delegate_;
+
+  // The time that delayed_work_timer_ is scheduled to fire.  This is tracked
+  // independently of CFRunLoopTimerGetNextFireDate(delayed_work_timer_)
+  // to be able to reset the timer properly after waking from system sleep.
+  // See PowerStateNotification.
+  CFAbsoluteTime delayed_work_fire_time_;
+
+  base::TimerSlack timer_slack_;
+
+  // The recursion depth of the currently-executing CFRunLoopRun loop on the
+  // run loop's thread.  0 if no run loops are running inside of whatever scope
+  // the object was created in.
+  int nesting_level_;
+
+  // The recursion depth (calculated in the same way as nesting_level_) of the
+  // innermost executing CFRunLoopRun loop started by a call to Run.
+  int run_nesting_level_;
+
+  // The deepest (numerically highest) recursion depth encountered since the
+  // most recent attempt to run nesting-deferred work.
+  int deepest_nesting_level_;
+
+  // "Delegateless" work flags are set when work is ready to be performed but
+  // must wait until a delegate is available to process it.  This can happen
+  // when a MessagePumpCFRunLoopBase is instantiated and work arrives without
+  // any call to Run on the stack.  The Run method will check for delegateless
+  // work on entry and redispatch it as needed once a delegate is available.
+  bool delegateless_work_;
+  bool delegateless_idle_work_;
+
+  DISALLOW_COPY_AND_ASSIGN(MessagePumpCFRunLoopBase);
+};
+
+class BASE_EXPORT MessagePumpCFRunLoop : public MessagePumpCFRunLoopBase {
+ public:
+  MessagePumpCFRunLoop();
+  ~MessagePumpCFRunLoop() override;
+
+  void DoRun(Delegate* delegate) override;
+  void Quit() override;
+
+ private:
+  void EnterExitRunLoop(CFRunLoopActivity activity) override;
+
+  // True if Quit is called to stop the innermost MessagePump
+  // (innermost_quittable_) but some other CFRunLoopRun loop (nesting_level_)
+  // is running inside the MessagePump's innermost Run call.
+  bool quit_pending_;
+
+  DISALLOW_COPY_AND_ASSIGN(MessagePumpCFRunLoop);
+};
+
+class BASE_EXPORT MessagePumpNSRunLoop : public MessagePumpCFRunLoopBase {
+ public:
+  MessagePumpNSRunLoop();
+  ~MessagePumpNSRunLoop() override;
+
+  void DoRun(Delegate* delegate) override;
+  void Quit() override;
+
+ private:
+  // A source that doesn't do anything but provide something signalable
+  // attached to the run loop.  This source will be signalled when Quit
+  // is called, to cause the loop to wake up so that it can stop.
+  CFRunLoopSourceRef quit_source_;
+
+  // False after Quit is called.
+  bool keep_running_;
+
+  DISALLOW_COPY_AND_ASSIGN(MessagePumpNSRunLoop);
+};
+
+#if defined(OS_IOS)
+// This is a fake message pump.  It attaches sources to the main thread's
+// CFRunLoop, so PostTask() will work, but it is unable to drive the loop
+// directly, so calling Run() or Quit() are errors.
+class MessagePumpUIApplication : public MessagePumpCFRunLoopBase {
+ public:
+  MessagePumpUIApplication();
+  ~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()|.
+  virtual void Attach(Delegate* delegate);
+
+ private:
+  RunLoop* run_loop_;
+
+  DISALLOW_COPY_AND_ASSIGN(MessagePumpUIApplication);
+};
+
+#else
+
+class MessagePumpNSApplication : public MessagePumpCFRunLoopBase {
+ public:
+  MessagePumpNSApplication();
+  ~MessagePumpNSApplication() override;
+
+  void DoRun(Delegate* delegate) override;
+  void Quit() override;
+
+ private:
+  // False after Quit is called.
+  bool keep_running_;
+
+  // True if DoRun is managing its own run loop as opposed to letting
+  // -[NSApplication run] handle it.  The outermost run loop in the application
+  // is managed by -[NSApplication run], inner run loops are handled by a loop
+  // in DoRun.
+  bool running_own_loop_;
+
+  DISALLOW_COPY_AND_ASSIGN(MessagePumpNSApplication);
+};
+
+class MessagePumpCrApplication : public MessagePumpNSApplication {
+ public:
+  MessagePumpCrApplication();
+  ~MessagePumpCrApplication() override;
+
+ protected:
+  // Returns nil if NSApp is currently in the middle of calling
+  // -sendEvent.  Requires NSApp implementing CrAppProtocol.
+  AutoreleasePoolType* CreateAutoreleasePool() override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MessagePumpCrApplication);
+};
+#endif  // !defined(OS_IOS)
+
+class BASE_EXPORT MessagePumpMac {
+ public:
+  // If not on the main thread, returns a new instance of
+  // MessagePumpNSRunLoop.
+  //
+  // On the main thread, if NSApp exists and conforms to
+  // CrAppProtocol, creates an instances of MessagePumpCrApplication.
+  //
+  // Otherwise creates an instance of MessagePumpNSApplication using a
+  // default NSApplication.
+  static MessagePump* Create();
+
+#if !defined(OS_IOS)
+  // If a pump is created before the required CrAppProtocol is
+  // created, the wrong MessagePump subclass could be used.
+  // UsingCrApp() returns false if the message pump was created before
+  // NSApp was initialized, or if NSApp does not implement
+  // CrAppProtocol.  NSApp must be initialized before calling.
+  static bool UsingCrApp();
+
+  // Wrapper to query -[NSApp isHandlingSendEvent] from C++ code.
+  // Requires NSApp to implement CrAppProtocol.
+  static bool IsHandlingSendEvent();
+#endif  // !defined(OS_IOS)
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(MessagePumpMac);
+};
+
+// Tasks posted to the message loop are posted under this mode, as well
+// as kCFRunLoopCommonModes.
+extern const CFStringRef BASE_EXPORT kMessageLoopExclusiveRunLoopMode;
+
+}  // namespace base
+
+#endif  // BASE_MESSAGE_LOOP_MESSAGE_PUMP_MAC_H_
diff --git a/base/message_loop/message_pump_mac.mm b/base/message_loop/message_pump_mac.mm
new file mode 100644
index 0000000..914977b
--- /dev/null
+++ b/base/message_loop/message_pump_mac.mm
@@ -0,0 +1,777 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "base/message_loop/message_pump_mac.h"
+
+#include <dlfcn.h>
+#import <Foundation/Foundation.h>
+
+#include <limits>
+
+#include "base/logging.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/message_loop/timer_slack.h"
+#include "base/run_loop.h"
+#include "base/time/time.h"
+
+#if !defined(OS_IOS)
+#import <AppKit/AppKit.h>
+#endif  // !defined(OS_IOS)
+
+namespace base {
+
+namespace {
+
+void CFRunLoopAddSourceToAllModes(CFRunLoopRef rl, CFRunLoopSourceRef source) {
+  CFRunLoopAddSource(rl, source, kCFRunLoopCommonModes);
+  CFRunLoopAddSource(rl, source, kMessageLoopExclusiveRunLoopMode);
+}
+
+void CFRunLoopRemoveSourceFromAllModes(CFRunLoopRef rl,
+                                       CFRunLoopSourceRef source) {
+  CFRunLoopRemoveSource(rl, source, kCFRunLoopCommonModes);
+  CFRunLoopRemoveSource(rl, source, kMessageLoopExclusiveRunLoopMode);
+}
+
+void CFRunLoopAddTimerToAllModes(CFRunLoopRef rl, CFRunLoopTimerRef timer) {
+  CFRunLoopAddTimer(rl, timer, kCFRunLoopCommonModes);
+  CFRunLoopAddTimer(rl, timer, kMessageLoopExclusiveRunLoopMode);
+}
+
+void CFRunLoopRemoveTimerFromAllModes(CFRunLoopRef rl,
+                                      CFRunLoopTimerRef timer) {
+  CFRunLoopRemoveTimer(rl, timer, kCFRunLoopCommonModes);
+  CFRunLoopRemoveTimer(rl, timer, kMessageLoopExclusiveRunLoopMode);
+}
+
+void CFRunLoopAddObserverToAllModes(CFRunLoopRef rl,
+                                    CFRunLoopObserverRef observer) {
+  CFRunLoopAddObserver(rl, observer, kCFRunLoopCommonModes);
+  CFRunLoopAddObserver(rl, observer, kMessageLoopExclusiveRunLoopMode);
+}
+
+void CFRunLoopRemoveObserverFromAllModes(CFRunLoopRef rl,
+                                         CFRunLoopObserverRef observer) {
+  CFRunLoopRemoveObserver(rl, observer, kCFRunLoopCommonModes);
+  CFRunLoopRemoveObserver(rl, observer, kMessageLoopExclusiveRunLoopMode);
+}
+
+void NoOp(void* info) {
+}
+
+const CFTimeInterval kCFTimeIntervalMax =
+    std::numeric_limits<CFTimeInterval>::max();
+
+#if !defined(OS_IOS)
+// Set to true if MessagePumpMac::Create() is called before NSApp is
+// initialized.  Only accessed from the main thread.
+bool g_not_using_cr_app = false;
+#endif
+
+// Call through to CFRunLoopTimerSetTolerance(), which is only available on
+// OS X 10.9.
+void SetTimerTolerance(CFRunLoopTimerRef timer, CFTimeInterval tolerance) {
+  typedef void (*CFRunLoopTimerSetTolerancePtr)(CFRunLoopTimerRef timer,
+      CFTimeInterval tolerance);
+
+  static CFRunLoopTimerSetTolerancePtr settimertolerance_function_ptr;
+
+  static dispatch_once_t get_timer_tolerance_function_ptr_once;
+  dispatch_once(&get_timer_tolerance_function_ptr_once, ^{
+      NSBundle* bundle =[NSBundle
+        bundleWithPath:@"/System/Library/Frameworks/CoreFoundation.framework"];
+      const char* path = [[bundle executablePath] fileSystemRepresentation];
+      CHECK(path);
+      void* library_handle = dlopen(path, RTLD_LAZY | RTLD_LOCAL);
+      CHECK(library_handle) << dlerror();
+      settimertolerance_function_ptr =
+          reinterpret_cast<CFRunLoopTimerSetTolerancePtr>(
+              dlsym(library_handle, "CFRunLoopTimerSetTolerance"));
+
+      dlclose(library_handle);
+  });
+
+  if (settimertolerance_function_ptr)
+    settimertolerance_function_ptr(timer, tolerance);
+}
+
+}  // namespace
+
+// static
+const CFStringRef kMessageLoopExclusiveRunLoopMode =
+    CFSTR("kMessageLoopExclusiveRunLoopMode");
+
+// A scoper for autorelease pools created from message pump run loops.
+// Avoids dirtying up the ScopedNSAutoreleasePool interface for the rare
+// case where an autorelease pool needs to be passed in.
+class MessagePumpScopedAutoreleasePool {
+ public:
+  explicit MessagePumpScopedAutoreleasePool(MessagePumpCFRunLoopBase* pump) :
+      pool_(pump->CreateAutoreleasePool()) {
+  }
+   ~MessagePumpScopedAutoreleasePool() {
+    [pool_ drain];
+  }
+
+ private:
+  NSAutoreleasePool* pool_;
+  DISALLOW_COPY_AND_ASSIGN(MessagePumpScopedAutoreleasePool);
+};
+
+// Must be called on the run loop thread.
+MessagePumpCFRunLoopBase::MessagePumpCFRunLoopBase()
+    : delegate_(NULL),
+      delayed_work_fire_time_(kCFTimeIntervalMax),
+      timer_slack_(base::TIMER_SLACK_NONE),
+      nesting_level_(0),
+      run_nesting_level_(0),
+      deepest_nesting_level_(0),
+      delegateless_work_(false),
+      delegateless_idle_work_(false) {
+  run_loop_ = CFRunLoopGetCurrent();
+  CFRetain(run_loop_);
+
+  // Set a repeating timer with a preposterous firing time and interval.  The
+  // timer will effectively never fire as-is.  The firing time will be adjusted
+  // as needed when ScheduleDelayedWork is called.
+  CFRunLoopTimerContext timer_context = CFRunLoopTimerContext();
+  timer_context.info = this;
+  delayed_work_timer_ = CFRunLoopTimerCreate(NULL,                // allocator
+                                             kCFTimeIntervalMax,  // fire time
+                                             kCFTimeIntervalMax,  // interval
+                                             0,                   // flags
+                                             0,                   // priority
+                                             RunDelayedWorkTimer,
+                                             &timer_context);
+  CFRunLoopAddTimerToAllModes(run_loop_, delayed_work_timer_);
+
+  CFRunLoopSourceContext source_context = CFRunLoopSourceContext();
+  source_context.info = this;
+  source_context.perform = RunWorkSource;
+  work_source_ = CFRunLoopSourceCreate(NULL,  // allocator
+                                       1,     // priority
+                                       &source_context);
+  CFRunLoopAddSourceToAllModes(run_loop_, work_source_);
+
+  source_context.perform = RunIdleWorkSource;
+  idle_work_source_ = CFRunLoopSourceCreate(NULL,  // allocator
+                                            2,     // priority
+                                            &source_context);
+  CFRunLoopAddSourceToAllModes(run_loop_, idle_work_source_);
+
+  source_context.perform = RunNestingDeferredWorkSource;
+  nesting_deferred_work_source_ = CFRunLoopSourceCreate(NULL,  // allocator
+                                                        0,     // priority
+                                                        &source_context);
+  CFRunLoopAddSourceToAllModes(run_loop_, nesting_deferred_work_source_);
+
+  CFRunLoopObserverContext observer_context = CFRunLoopObserverContext();
+  observer_context.info = this;
+  pre_wait_observer_ = CFRunLoopObserverCreate(NULL,  // allocator
+                                               kCFRunLoopBeforeWaiting,
+                                               true,  // repeat
+                                               0,     // priority
+                                               PreWaitObserver,
+                                               &observer_context);
+  CFRunLoopAddObserverToAllModes(run_loop_, pre_wait_observer_);
+
+  pre_source_observer_ = CFRunLoopObserverCreate(NULL,  // allocator
+                                                 kCFRunLoopBeforeSources,
+                                                 true,  // repeat
+                                                 0,     // priority
+                                                 PreSourceObserver,
+                                                 &observer_context);
+  CFRunLoopAddObserverToAllModes(run_loop_, pre_source_observer_);
+
+  enter_exit_observer_ = CFRunLoopObserverCreate(NULL,  // allocator
+                                                 kCFRunLoopEntry |
+                                                     kCFRunLoopExit,
+                                                 true,  // repeat
+                                                 0,     // priority
+                                                 EnterExitObserver,
+                                                 &observer_context);
+  CFRunLoopAddObserverToAllModes(run_loop_, enter_exit_observer_);
+}
+
+// Ideally called on the run loop thread.  If other run loops were running
+// lower on the run loop thread's stack when this object was created, the
+// same number of run loops must be running when this object is destroyed.
+MessagePumpCFRunLoopBase::~MessagePumpCFRunLoopBase() {
+  CFRunLoopRemoveObserverFromAllModes(run_loop_, enter_exit_observer_);
+  CFRelease(enter_exit_observer_);
+
+  CFRunLoopRemoveObserverFromAllModes(run_loop_, pre_source_observer_);
+  CFRelease(pre_source_observer_);
+
+  CFRunLoopRemoveObserverFromAllModes(run_loop_, pre_wait_observer_);
+  CFRelease(pre_wait_observer_);
+
+  CFRunLoopRemoveSourceFromAllModes(run_loop_, nesting_deferred_work_source_);
+  CFRelease(nesting_deferred_work_source_);
+
+  CFRunLoopRemoveSourceFromAllModes(run_loop_, idle_work_source_);
+  CFRelease(idle_work_source_);
+
+  CFRunLoopRemoveSourceFromAllModes(run_loop_, work_source_);
+  CFRelease(work_source_);
+
+  CFRunLoopRemoveTimerFromAllModes(run_loop_, delayed_work_timer_);
+  CFRelease(delayed_work_timer_);
+
+  CFRelease(run_loop_);
+}
+
+// Must be called on the run loop thread.
+void MessagePumpCFRunLoopBase::Run(Delegate* delegate) {
+  // nesting_level_ will be incremented in EnterExitRunLoop, so set
+  // run_nesting_level_ accordingly.
+  int last_run_nesting_level = run_nesting_level_;
+  run_nesting_level_ = nesting_level_ + 1;
+
+  Delegate* last_delegate = delegate_;
+  SetDelegate(delegate);
+
+  DoRun(delegate);
+
+  // Restore the previous state of the object.
+  SetDelegate(last_delegate);
+  run_nesting_level_ = last_run_nesting_level;
+}
+
+void MessagePumpCFRunLoopBase::SetDelegate(Delegate* delegate) {
+  delegate_ = delegate;
+
+  if (delegate) {
+    // If any work showed up but could not be dispatched for want of a
+    // delegate, set it up for dispatch again now that a delegate is
+    // available.
+    if (delegateless_work_) {
+      CFRunLoopSourceSignal(work_source_);
+      delegateless_work_ = false;
+    }
+    if (delegateless_idle_work_) {
+      CFRunLoopSourceSignal(idle_work_source_);
+      delegateless_idle_work_ = false;
+    }
+  }
+}
+
+// May be called on any thread.
+void MessagePumpCFRunLoopBase::ScheduleWork() {
+  CFRunLoopSourceSignal(work_source_);
+  CFRunLoopWakeUp(run_loop_);
+}
+
+// Must be called on the run loop thread.
+void MessagePumpCFRunLoopBase::ScheduleDelayedWork(
+    const TimeTicks& delayed_work_time) {
+  TimeDelta delta = delayed_work_time - TimeTicks::Now();
+  delayed_work_fire_time_ = CFAbsoluteTimeGetCurrent() + delta.InSecondsF();
+  CFRunLoopTimerSetNextFireDate(delayed_work_timer_, delayed_work_fire_time_);
+  if (timer_slack_ == TIMER_SLACK_MAXIMUM) {
+    SetTimerTolerance(delayed_work_timer_, delta.InSecondsF() * 0.5);
+  } else {
+    SetTimerTolerance(delayed_work_timer_, 0);
+  }
+}
+
+void MessagePumpCFRunLoopBase::SetTimerSlack(TimerSlack timer_slack) {
+  timer_slack_ = timer_slack;
+}
+
+// Called from the run loop.
+// static
+void MessagePumpCFRunLoopBase::RunDelayedWorkTimer(CFRunLoopTimerRef timer,
+                                                   void* info) {
+  MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
+
+  // The timer won't fire again until it's reset.
+  self->delayed_work_fire_time_ = kCFTimeIntervalMax;
+
+  // CFRunLoopTimers fire outside of the priority scheme for CFRunLoopSources.
+  // In order to establish the proper priority in which work and delayed work
+  // are processed one for one, the timer used to schedule delayed work must
+  // signal a CFRunLoopSource used to dispatch both work and delayed work.
+  CFRunLoopSourceSignal(self->work_source_);
+}
+
+// Called from the run loop.
+// static
+void MessagePumpCFRunLoopBase::RunWorkSource(void* info) {
+  MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
+  self->RunWork();
+}
+
+// Called by MessagePumpCFRunLoopBase::RunWorkSource.
+bool MessagePumpCFRunLoopBase::RunWork() {
+  if (!delegate_) {
+    // This point can be reached with a NULL delegate_ if Run is not on the
+    // stack but foreign code is spinning the CFRunLoop.  Arrange to come back
+    // here when a delegate is available.
+    delegateless_work_ = true;
+    return false;
+  }
+
+  // The NSApplication-based run loop only drains the autorelease pool at each
+  // UI event (NSEvent).  The autorelease pool is not drained for each
+  // CFRunLoopSource target that's run.  Use a local pool for any autoreleased
+  // objects if the app is not currently handling a UI event to ensure they're
+  // released promptly even in the absence of UI events.
+  MessagePumpScopedAutoreleasePool autorelease_pool(this);
+
+  // Call DoWork and DoDelayedWork once, and if something was done, arrange to
+  // come back here again as long as the loop is still running.
+  bool did_work = delegate_->DoWork();
+  bool resignal_work_source = did_work;
+
+  TimeTicks next_time;
+  delegate_->DoDelayedWork(&next_time);
+  if (!did_work) {
+    // Determine whether there's more delayed work, and if so, if it needs to
+    // be done at some point in the future or if it's already time to do it.
+    // Only do these checks if did_work is false. If did_work is true, this
+    // function, and therefore any additional delayed work, will get another
+    // chance to run before the loop goes to sleep.
+    bool more_delayed_work = !next_time.is_null();
+    if (more_delayed_work) {
+      TimeDelta delay = next_time - TimeTicks::Now();
+      if (delay > TimeDelta()) {
+        // There's more delayed work to be done in the future.
+        ScheduleDelayedWork(next_time);
+      } else {
+        // There's more delayed work to be done, and its time is in the past.
+        // Arrange to come back here directly as long as the loop is still
+        // running.
+        resignal_work_source = true;
+      }
+    }
+  }
+
+  if (resignal_work_source) {
+    CFRunLoopSourceSignal(work_source_);
+  }
+
+  return resignal_work_source;
+}
+
+// Called from the run loop.
+// static
+void MessagePumpCFRunLoopBase::RunIdleWorkSource(void* info) {
+  MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
+  self->RunIdleWork();
+}
+
+// Called by MessagePumpCFRunLoopBase::RunIdleWorkSource.
+bool MessagePumpCFRunLoopBase::RunIdleWork() {
+  if (!delegate_) {
+    // This point can be reached with a NULL delegate_ if Run is not on the
+    // stack but foreign code is spinning the CFRunLoop.  Arrange to come back
+    // here when a delegate is available.
+    delegateless_idle_work_ = true;
+    return false;
+  }
+
+  // The NSApplication-based run loop only drains the autorelease pool at each
+  // UI event (NSEvent).  The autorelease pool is not drained for each
+  // CFRunLoopSource target that's run.  Use a local pool for any autoreleased
+  // objects if the app is not currently handling a UI event to ensure they're
+  // released promptly even in the absence of UI events.
+  MessagePumpScopedAutoreleasePool autorelease_pool(this);
+
+  // Call DoIdleWork once, and if something was done, arrange to come back here
+  // again as long as the loop is still running.
+  bool did_work = delegate_->DoIdleWork();
+  if (did_work) {
+    CFRunLoopSourceSignal(idle_work_source_);
+  }
+
+  return did_work;
+}
+
+// Called from the run loop.
+// static
+void MessagePumpCFRunLoopBase::RunNestingDeferredWorkSource(void* info) {
+  MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
+  self->RunNestingDeferredWork();
+}
+
+// Called by MessagePumpCFRunLoopBase::RunNestingDeferredWorkSource.
+bool MessagePumpCFRunLoopBase::RunNestingDeferredWork() {
+  if (!delegate_) {
+    // This point can be reached with a NULL delegate_ if Run is not on the
+    // stack but foreign code is spinning the CFRunLoop.  There's no sense in
+    // attempting to do any work or signalling the work sources because
+    // without a delegate, work is not possible.
+    return false;
+  }
+
+  // Immediately try work in priority order.
+  if (!RunWork()) {
+    if (!RunIdleWork()) {
+      return false;
+    }
+  } else {
+    // Work was done.  Arrange for the loop to try non-nestable idle work on
+    // a subsequent pass.
+    CFRunLoopSourceSignal(idle_work_source_);
+  }
+
+  return true;
+}
+
+// Called before the run loop goes to sleep or exits, or processes sources.
+void MessagePumpCFRunLoopBase::MaybeScheduleNestingDeferredWork() {
+  // deepest_nesting_level_ is set as run loops are entered.  If the deepest
+  // level encountered is deeper than the current level, a nested loop
+  // (relative to the current level) ran since the last time nesting-deferred
+  // work was scheduled.  When that situation is encountered, schedule
+  // nesting-deferred work in case any work was deferred because nested work
+  // was disallowed.
+  if (deepest_nesting_level_ > nesting_level_) {
+    deepest_nesting_level_ = nesting_level_;
+    CFRunLoopSourceSignal(nesting_deferred_work_source_);
+  }
+}
+
+// Called from the run loop.
+// static
+void MessagePumpCFRunLoopBase::PreWaitObserver(CFRunLoopObserverRef observer,
+                                               CFRunLoopActivity activity,
+                                               void* info) {
+  MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
+
+  // Attempt to do some idle work before going to sleep.
+  self->RunIdleWork();
+
+  // The run loop is about to go to sleep.  If any of the work done since it
+  // started or woke up resulted in a nested run loop running,
+  // nesting-deferred work may have accumulated.  Schedule it for processing
+  // if appropriate.
+  self->MaybeScheduleNestingDeferredWork();
+}
+
+// Called from the run loop.
+// static
+void MessagePumpCFRunLoopBase::PreSourceObserver(CFRunLoopObserverRef observer,
+                                                 CFRunLoopActivity activity,
+                                                 void* info) {
+  MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
+
+  // The run loop has reached the top of the loop and is about to begin
+  // processing sources.  If the last iteration of the loop at this nesting
+  // level did not sleep or exit, nesting-deferred work may have accumulated
+  // if a nested loop ran.  Schedule nesting-deferred work for processing if
+  // appropriate.
+  self->MaybeScheduleNestingDeferredWork();
+}
+
+// Called from the run loop.
+// static
+void MessagePumpCFRunLoopBase::EnterExitObserver(CFRunLoopObserverRef observer,
+                                                 CFRunLoopActivity activity,
+                                                 void* info) {
+  MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
+
+  switch (activity) {
+    case kCFRunLoopEntry:
+      ++self->nesting_level_;
+      if (self->nesting_level_ > self->deepest_nesting_level_) {
+        self->deepest_nesting_level_ = self->nesting_level_;
+      }
+      break;
+
+    case kCFRunLoopExit:
+      // Not all run loops go to sleep.  If a run loop is stopped before it
+      // goes to sleep due to a CFRunLoopStop call, or if the timeout passed
+      // to CFRunLoopRunInMode expires, the run loop may proceed directly from
+      // handling sources to exiting without any sleep.  This most commonly
+      // occurs when CFRunLoopRunInMode is passed a timeout of 0, causing it
+      // to make a single pass through the loop and exit without sleep.  Some
+      // native loops use CFRunLoop in this way.  Because PreWaitObserver will
+      // not be called in these case, MaybeScheduleNestingDeferredWork needs
+      // to be called here, as the run loop exits.
+      //
+      // MaybeScheduleNestingDeferredWork consults self->nesting_level_
+      // to determine whether to schedule nesting-deferred work.  It expects
+      // the nesting level to be set to the depth of the loop that is going
+      // to sleep or exiting.  It must be called before decrementing the
+      // value so that the value still corresponds to the level of the exiting
+      // loop.
+      self->MaybeScheduleNestingDeferredWork();
+      --self->nesting_level_;
+      break;
+
+    default:
+      break;
+  }
+
+  self->EnterExitRunLoop(activity);
+}
+
+// Called by MessagePumpCFRunLoopBase::EnterExitRunLoop.  The default
+// implementation is a no-op.
+void MessagePumpCFRunLoopBase::EnterExitRunLoop(CFRunLoopActivity activity) {
+}
+
+// Base version returns a standard NSAutoreleasePool.
+AutoreleasePoolType* MessagePumpCFRunLoopBase::CreateAutoreleasePool() {
+  return [[NSAutoreleasePool alloc] init];
+}
+
+MessagePumpCFRunLoop::MessagePumpCFRunLoop()
+    : quit_pending_(false) {
+}
+
+MessagePumpCFRunLoop::~MessagePumpCFRunLoop() {}
+
+// Called by MessagePumpCFRunLoopBase::DoRun.  If other CFRunLoopRun loops were
+// running lower on the run loop thread's stack when this object was created,
+// the same number of CFRunLoopRun loops must be running for the outermost call
+// to Run.  Run/DoRun are reentrant after that point.
+void MessagePumpCFRunLoop::DoRun(Delegate* delegate) {
+  // This is completely identical to calling CFRunLoopRun(), except autorelease
+  // pool management is introduced.
+  int result;
+  do {
+    MessagePumpScopedAutoreleasePool autorelease_pool(this);
+    result = CFRunLoopRunInMode(kCFRunLoopDefaultMode,
+                                kCFTimeIntervalMax,
+                                false);
+  } while (result != kCFRunLoopRunStopped && result != kCFRunLoopRunFinished);
+}
+
+// Must be called on the run loop thread.
+void MessagePumpCFRunLoop::Quit() {
+  // Stop the innermost run loop managed by this MessagePumpCFRunLoop object.
+  if (nesting_level() == run_nesting_level()) {
+    // This object is running the innermost loop, just stop it.
+    CFRunLoopStop(run_loop());
+  } else {
+    // There's another loop running inside the loop managed by this object.
+    // In other words, someone else called CFRunLoopRunInMode on the same
+    // thread, deeper on the stack than the deepest Run call.  Don't preempt
+    // other run loops, just mark this object to quit the innermost Run as
+    // soon as the other inner loops not managed by Run are done.
+    quit_pending_ = true;
+  }
+}
+
+// Called by MessagePumpCFRunLoopBase::EnterExitObserver.
+void MessagePumpCFRunLoop::EnterExitRunLoop(CFRunLoopActivity activity) {
+  if (activity == kCFRunLoopExit &&
+      nesting_level() == run_nesting_level() &&
+      quit_pending_) {
+    // Quit was called while loops other than those managed by this object
+    // were running further inside a run loop managed by this object.  Now
+    // that all unmanaged inner run loops are gone, stop the loop running
+    // just inside Run.
+    CFRunLoopStop(run_loop());
+    quit_pending_ = false;
+  }
+}
+
+MessagePumpNSRunLoop::MessagePumpNSRunLoop()
+    : keep_running_(true) {
+  CFRunLoopSourceContext source_context = CFRunLoopSourceContext();
+  source_context.perform = NoOp;
+  quit_source_ = CFRunLoopSourceCreate(NULL,  // allocator
+                                       0,     // priority
+                                       &source_context);
+  CFRunLoopAddSourceToAllModes(run_loop(), quit_source_);
+}
+
+MessagePumpNSRunLoop::~MessagePumpNSRunLoop() {
+  CFRunLoopRemoveSourceFromAllModes(run_loop(), quit_source_);
+  CFRelease(quit_source_);
+}
+
+void MessagePumpNSRunLoop::DoRun(Delegate* delegate) {
+  while (keep_running_) {
+    // NSRunLoop manages autorelease pools itself.
+    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
+                             beforeDate:[NSDate distantFuture]];
+  }
+
+  keep_running_ = true;
+}
+
+void MessagePumpNSRunLoop::Quit() {
+  keep_running_ = false;
+  CFRunLoopSourceSignal(quit_source_);
+  CFRunLoopWakeUp(run_loop());
+}
+
+#if defined(OS_IOS)
+MessagePumpUIApplication::MessagePumpUIApplication()
+    : run_loop_(NULL) {
+}
+
+MessagePumpUIApplication::~MessagePumpUIApplication() {}
+
+void MessagePumpUIApplication::DoRun(Delegate* delegate) {
+  NOTREACHED();
+}
+
+void MessagePumpUIApplication::Quit() {
+  NOTREACHED();
+}
+
+void MessagePumpUIApplication::Attach(Delegate* delegate) {
+  DCHECK(!run_loop_);
+  run_loop_ = new RunLoop();
+  CHECK(run_loop_->BeforeRun());
+  SetDelegate(delegate);
+}
+
+#else
+
+MessagePumpNSApplication::MessagePumpNSApplication()
+    : keep_running_(true),
+      running_own_loop_(false) {
+}
+
+MessagePumpNSApplication::~MessagePumpNSApplication() {}
+
+void MessagePumpNSApplication::DoRun(Delegate* delegate) {
+  bool last_running_own_loop_ = running_own_loop_;
+
+  // NSApp must be initialized by calling:
+  // [{some class which implements CrAppProtocol} sharedApplication]
+  // Most likely candidates are CrApplication or BrowserCrApplication.
+  // These can be initialized from C++ code by calling
+  // RegisterCrApp() or RegisterBrowserCrApp().
+  CHECK(NSApp);
+
+  if (![NSApp isRunning]) {
+    running_own_loop_ = false;
+    // NSApplication manages autorelease pools itself when run this way.
+    [NSApp run];
+  } else {
+    running_own_loop_ = true;
+    NSDate* distant_future = [NSDate distantFuture];
+    while (keep_running_) {
+      MessagePumpScopedAutoreleasePool autorelease_pool(this);
+      NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask
+                                          untilDate:distant_future
+                                             inMode:NSDefaultRunLoopMode
+                                            dequeue:YES];
+      if (event) {
+        [NSApp sendEvent:event];
+      }
+    }
+    keep_running_ = true;
+  }
+
+  running_own_loop_ = last_running_own_loop_;
+}
+
+void MessagePumpNSApplication::Quit() {
+  if (!running_own_loop_) {
+    [[NSApplication sharedApplication] stop:nil];
+  } else {
+    keep_running_ = false;
+  }
+
+  // Send a fake event to wake the loop up.
+  [NSApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined
+                                      location:NSZeroPoint
+                                 modifierFlags:0
+                                     timestamp:0
+                                  windowNumber:0
+                                       context:NULL
+                                       subtype:0
+                                         data1:0
+                                         data2:0]
+           atStart:NO];
+}
+
+MessagePumpCrApplication::MessagePumpCrApplication() {
+}
+
+MessagePumpCrApplication::~MessagePumpCrApplication() {
+}
+
+// Prevents an autorelease pool from being created if the app is in the midst of
+// handling a UI event because various parts of AppKit depend on objects that
+// are created while handling a UI event to be autoreleased in the event loop.
+// An example of this is NSWindowController. When a window with a window
+// controller is closed it goes through a stack like this:
+// (Several stack frames elided for clarity)
+//
+// #0 [NSWindowController autorelease]
+// #1 DoAClose
+// #2 MessagePumpCFRunLoopBase::DoWork()
+// #3 [NSRunLoop run]
+// #4 [NSButton performClick:]
+// #5 [NSWindow sendEvent:]
+// #6 [NSApp sendEvent:]
+// #7 [NSApp run]
+//
+// -performClick: spins a nested run loop. If the pool created in DoWork was a
+// standard NSAutoreleasePool, it would release the objects that were
+// autoreleased into it once DoWork released it. This would cause the window
+// controller, which autoreleased itself in frame #0, to release itself, and
+// possibly free itself. Unfortunately this window controller controls the
+// window in frame #5. When the stack is unwound to frame #5, the window would
+// no longer exists and crashes may occur. Apple gets around this by never
+// releasing the pool it creates in frame #4, and letting frame #7 clean it up
+// when it cleans up the pool that wraps frame #7. When an autorelease pool is
+// released it releases all other pools that were created after it on the
+// autorelease pool stack.
+//
+// CrApplication is responsible for setting handlingSendEvent to true just
+// before it sends the event through the event handling mechanism, and
+// returning it to its previous value once the event has been sent.
+AutoreleasePoolType* MessagePumpCrApplication::CreateAutoreleasePool() {
+  if (MessagePumpMac::IsHandlingSendEvent())
+    return nil;
+  return MessagePumpNSApplication::CreateAutoreleasePool();
+}
+
+// static
+bool MessagePumpMac::UsingCrApp() {
+  DCHECK([NSThread isMainThread]);
+
+  // If NSApp is still not initialized, then the subclass used cannot
+  // be determined.
+  DCHECK(NSApp);
+
+  // The pump was created using MessagePumpNSApplication.
+  if (g_not_using_cr_app)
+    return false;
+
+  return [NSApp conformsToProtocol:@protocol(CrAppProtocol)];
+}
+
+// static
+bool MessagePumpMac::IsHandlingSendEvent() {
+  DCHECK([NSApp conformsToProtocol:@protocol(CrAppProtocol)]);
+  NSObject<CrAppProtocol>* app = static_cast<NSObject<CrAppProtocol>*>(NSApp);
+  return [app isHandlingSendEvent];
+}
+#endif  // !defined(OS_IOS)
+
+// static
+MessagePump* MessagePumpMac::Create() {
+  if ([NSThread isMainThread]) {
+#if defined(OS_IOS)
+    return new MessagePumpUIApplication;
+#else
+    if ([NSApp conformsToProtocol:@protocol(CrAppProtocol)])
+      return new MessagePumpCrApplication;
+
+    // The main-thread MessagePump implementations REQUIRE an NSApp.
+    // Executables which have specific requirements for their
+    // NSApplication subclass should initialize appropriately before
+    // creating an event loop.
+    [NSApplication sharedApplication];
+    g_not_using_cr_app = true;
+    return new MessagePumpNSApplication;
+#endif
+  }
+
+  return new MessagePumpNSRunLoop;
+}
+
+}  // namespace base
diff --git a/base/message_loop/message_pump_perftest.cc b/base/message_loop/message_pump_perftest.cc
new file mode 100644
index 0000000..7d833be
--- /dev/null
+++ b/base/message_loop/message_pump_perftest.cc
@@ -0,0 +1,288 @@
+// 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.
+
+#include "base/bind.h"
+#include "base/format_macros.h"
+#include "base/memory/scoped_vector.h"
+#include "base/strings/stringprintf.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/perf/perf_test.h"
+
+#if defined(OS_ANDROID)
+#include "base/android/java_handler_thread.h"
+#endif
+
+namespace base {
+
+class ScheduleWorkTest : public testing::Test {
+ public:
+  ScheduleWorkTest() : counter_(0) {}
+
+  void Increment(uint64_t amount) { counter_ += amount; }
+
+  void Schedule(int index) {
+    base::TimeTicks start = base::TimeTicks::Now();
+    base::ThreadTicks thread_start;
+    if (ThreadTicks::IsSupported())
+      thread_start = base::ThreadTicks::Now();
+    base::TimeDelta minimum = base::TimeDelta::Max();
+    base::TimeDelta maximum = base::TimeDelta();
+    base::TimeTicks now, lastnow = start;
+    uint64_t schedule_calls = 0u;
+    do {
+      for (size_t i = 0; i < kBatchSize; ++i) {
+        target_message_loop()->ScheduleWork();
+        schedule_calls++;
+      }
+      now = base::TimeTicks::Now();
+      base::TimeDelta laptime = now - lastnow;
+      lastnow = now;
+      minimum = std::min(minimum, laptime);
+      maximum = std::max(maximum, laptime);
+    } while (now - start < base::TimeDelta::FromSeconds(kTargetTimeSec));
+
+    scheduling_times_[index] = now - start;
+    if (ThreadTicks::IsSupported())
+      scheduling_thread_times_[index] =
+          base::ThreadTicks::Now() - thread_start;
+    min_batch_times_[index] = minimum;
+    max_batch_times_[index] = maximum;
+    target_message_loop()->PostTask(FROM_HERE,
+                                    base::Bind(&ScheduleWorkTest::Increment,
+                                               base::Unretained(this),
+                                               schedule_calls));
+  }
+
+  void ScheduleWork(MessageLoop::Type target_type, int num_scheduling_threads) {
+#if defined(OS_ANDROID)
+    if (target_type == MessageLoop::TYPE_JAVA) {
+      java_thread_.reset(new android::JavaHandlerThread("target"));
+      java_thread_->Start();
+    } else
+#endif
+    {
+      target_.reset(new Thread("target"));
+      target_->StartWithOptions(Thread::Options(target_type, 0u));
+    }
+
+    ScopedVector<Thread> scheduling_threads;
+    scheduling_times_.reset(new base::TimeDelta[num_scheduling_threads]);
+    scheduling_thread_times_.reset(new base::TimeDelta[num_scheduling_threads]);
+    min_batch_times_.reset(new base::TimeDelta[num_scheduling_threads]);
+    max_batch_times_.reset(new base::TimeDelta[num_scheduling_threads]);
+
+    for (int i = 0; i < num_scheduling_threads; ++i) {
+      scheduling_threads.push_back(new Thread("posting thread"));
+      scheduling_threads[i]->Start();
+    }
+
+    for (int i = 0; i < num_scheduling_threads; ++i) {
+      scheduling_threads[i]->message_loop()->PostTask(
+          FROM_HERE,
+          base::Bind(&ScheduleWorkTest::Schedule, base::Unretained(this), i));
+    }
+
+    for (int i = 0; i < num_scheduling_threads; ++i) {
+      scheduling_threads[i]->Stop();
+    }
+#if defined(OS_ANDROID)
+    if (target_type == MessageLoop::TYPE_JAVA) {
+      java_thread_->Stop();
+      java_thread_.reset();
+    } else
+#endif
+    {
+      target_->Stop();
+      target_.reset();
+    }
+    base::TimeDelta total_time;
+    base::TimeDelta total_thread_time;
+    base::TimeDelta min_batch_time = base::TimeDelta::Max();
+    base::TimeDelta max_batch_time = base::TimeDelta();
+    for (int i = 0; i < num_scheduling_threads; ++i) {
+      total_time += scheduling_times_[i];
+      total_thread_time += scheduling_thread_times_[i];
+      min_batch_time = std::min(min_batch_time, min_batch_times_[i]);
+      max_batch_time = std::max(max_batch_time, max_batch_times_[i]);
+    }
+    std::string trace = StringPrintf(
+        "%d_threads_scheduling_to_%s_pump",
+        num_scheduling_threads,
+        target_type == MessageLoop::TYPE_IO
+            ? "io"
+            : (target_type == MessageLoop::TYPE_UI ? "ui" : "default"));
+    perf_test::PrintResult(
+        "task",
+        "",
+        trace,
+        total_time.InMicroseconds() / static_cast<double>(counter_),
+        "us/task",
+        true);
+    perf_test::PrintResult(
+        "task",
+        "_min_batch_time",
+        trace,
+        min_batch_time.InMicroseconds() / static_cast<double>(kBatchSize),
+        "us/task",
+        false);
+    perf_test::PrintResult(
+        "task",
+        "_max_batch_time",
+        trace,
+        max_batch_time.InMicroseconds() / static_cast<double>(kBatchSize),
+        "us/task",
+        false);
+    if (ThreadTicks::IsSupported()) {
+      perf_test::PrintResult(
+          "task",
+          "_thread_time",
+          trace,
+          total_thread_time.InMicroseconds() / static_cast<double>(counter_),
+          "us/task",
+          true);
+    }
+  }
+
+  MessageLoop* target_message_loop() {
+#if defined(OS_ANDROID)
+    if (java_thread_)
+      return java_thread_->message_loop();
+#endif
+    return target_->message_loop();
+  }
+
+ private:
+  scoped_ptr<Thread> target_;
+#if defined(OS_ANDROID)
+  scoped_ptr<android::JavaHandlerThread> java_thread_;
+#endif
+  scoped_ptr<base::TimeDelta[]> scheduling_times_;
+  scoped_ptr<base::TimeDelta[]> scheduling_thread_times_;
+  scoped_ptr<base::TimeDelta[]> min_batch_times_;
+  scoped_ptr<base::TimeDelta[]> max_batch_times_;
+  uint64_t counter_;
+
+  static const size_t kTargetTimeSec = 5;
+  static const size_t kBatchSize = 1000;
+};
+
+TEST_F(ScheduleWorkTest, ThreadTimeToIOFromOneThread) {
+  ScheduleWork(MessageLoop::TYPE_IO, 1);
+}
+
+TEST_F(ScheduleWorkTest, ThreadTimeToIOFromTwoThreads) {
+  ScheduleWork(MessageLoop::TYPE_IO, 2);
+}
+
+TEST_F(ScheduleWorkTest, ThreadTimeToIOFromFourThreads) {
+  ScheduleWork(MessageLoop::TYPE_IO, 4);
+}
+
+TEST_F(ScheduleWorkTest, ThreadTimeToUIFromOneThread) {
+  ScheduleWork(MessageLoop::TYPE_UI, 1);
+}
+
+TEST_F(ScheduleWorkTest, ThreadTimeToUIFromTwoThreads) {
+  ScheduleWork(MessageLoop::TYPE_UI, 2);
+}
+
+TEST_F(ScheduleWorkTest, ThreadTimeToUIFromFourThreads) {
+  ScheduleWork(MessageLoop::TYPE_UI, 4);
+}
+
+TEST_F(ScheduleWorkTest, ThreadTimeToDefaultFromOneThread) {
+  ScheduleWork(MessageLoop::TYPE_DEFAULT, 1);
+}
+
+TEST_F(ScheduleWorkTest, ThreadTimeToDefaultFromTwoThreads) {
+  ScheduleWork(MessageLoop::TYPE_DEFAULT, 2);
+}
+
+TEST_F(ScheduleWorkTest, ThreadTimeToDefaultFromFourThreads) {
+  ScheduleWork(MessageLoop::TYPE_DEFAULT, 4);
+}
+
+#if defined(OS_ANDROID)
+TEST_F(ScheduleWorkTest, ThreadTimeToJavaFromOneThread) {
+  ScheduleWork(MessageLoop::TYPE_JAVA, 1);
+}
+
+TEST_F(ScheduleWorkTest, ThreadTimeToJavaFromTwoThreads) {
+  ScheduleWork(MessageLoop::TYPE_JAVA, 2);
+}
+
+TEST_F(ScheduleWorkTest, ThreadTimeToJavaFromFourThreads) {
+  ScheduleWork(MessageLoop::TYPE_JAVA, 4);
+}
+#endif
+
+class FakeMessagePump : public MessagePump {
+ public:
+  FakeMessagePump() {}
+  ~FakeMessagePump() override {}
+
+  void Run(Delegate* delegate) override {}
+
+  void Quit() override {}
+  void ScheduleWork() override {}
+  void ScheduleDelayedWork(const TimeTicks& delayed_work_time) override {}
+};
+
+class PostTaskTest : public testing::Test {
+ public:
+  void Run(int batch_size, int tasks_per_reload) {
+    base::TimeTicks start = base::TimeTicks::Now();
+    base::TimeTicks now;
+    MessageLoop loop(scoped_ptr<MessagePump>(new FakeMessagePump));
+    scoped_refptr<internal::IncomingTaskQueue> queue(
+        new internal::IncomingTaskQueue(&loop));
+    uint32_t num_posted = 0;
+    do {
+      for (int i = 0; i < batch_size; ++i) {
+        for (int j = 0; j < tasks_per_reload; ++j) {
+          queue->AddToIncomingQueue(
+              FROM_HERE, base::Bind(&DoNothing), base::TimeDelta(), false);
+          num_posted++;
+        }
+        TaskQueue loop_local_queue;
+        queue->ReloadWorkQueue(&loop_local_queue);
+        while (!loop_local_queue.empty()) {
+          PendingTask t = loop_local_queue.front();
+          loop_local_queue.pop();
+          loop.RunTask(t);
+        }
+      }
+
+      now = base::TimeTicks::Now();
+    } while (now - start < base::TimeDelta::FromSeconds(5));
+    std::string trace = StringPrintf("%d_tasks_per_reload", tasks_per_reload);
+    perf_test::PrintResult(
+        "task",
+        "",
+        trace,
+        (now - start).InMicroseconds() / static_cast<double>(num_posted),
+        "us/task",
+        true);
+  }
+};
+
+TEST_F(PostTaskTest, OneTaskPerReload) {
+  Run(10000, 1);
+}
+
+TEST_F(PostTaskTest, TenTasksPerReload) {
+  Run(10000, 10);
+}
+
+TEST_F(PostTaskTest, OneHundredTasksPerReload) {
+  Run(1000, 100);
+}
+
+}  // namespace base
diff --git a/base/message_loop/message_pump_win.cc b/base/message_loop/message_pump_win.cc
new file mode 100644
index 0000000..a84e04e
--- /dev/null
+++ b/base/message_loop/message_pump_win.cc
@@ -0,0 +1,710 @@
+// Copyright (c) 2012 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/message_loop/message_pump_win.h"
+
+#include <limits>
+#include <math.h>
+
+#include "base/message_loop/message_loop.h"
+#include "base/metrics/histogram.h"
+#include "base/process/memory.h"
+#include "base/profiler/scoped_tracker.h"
+#include "base/strings/stringprintf.h"
+#include "base/threading/thread.h"
+#include "base/trace_event/trace_event.h"
+#include "base/win/wrapped_window_proc.h"
+
+namespace base {
+
+namespace {
+
+enum MessageLoopProblems {
+  MESSAGE_POST_ERROR,
+  COMPLETION_POST_ERROR,
+  SET_TIMER_ERROR,
+  MESSAGE_LOOP_PROBLEM_MAX,
+};
+
+}  // namespace
+
+static const wchar_t kWndClassFormat[] = L"Chrome_MessagePumpWindow_%p";
+
+// Message sent to get an additional time slice for pumping (processing) another
+// task (a series of such messages creates a continuous task pump).
+static const int kMsgHaveWork = WM_USER + 1;
+
+// The default delay for the waitable timer used to wake up the UI worker
+// thread.
+static const int64 kDefaultUIWorkerThreadWakeupTimerMs = 3;
+
+//-----------------------------------------------------------------------------
+// MessagePumpWin public:
+
+void MessagePumpWin::RunWithDispatcher(
+    Delegate* delegate, MessagePumpDispatcher* dispatcher) {
+  RunState s;
+  s.delegate = delegate;
+  s.dispatcher = dispatcher;
+  s.should_quit = false;
+  s.run_depth = state_ ? state_->run_depth + 1 : 1;
+
+  RunState* previous_state = state_;
+  state_ = &s;
+
+  DoRunLoop();
+
+  state_ = previous_state;
+}
+
+void MessagePumpWin::Run(Delegate* delegate) {
+  RunWithDispatcher(delegate, NULL);
+}
+
+void MessagePumpWin::Quit() {
+  DCHECK(state_);
+  state_->should_quit = true;
+}
+
+//-----------------------------------------------------------------------------
+// MessagePumpWin protected:
+
+int MessagePumpWin::GetCurrentDelay() const {
+  if (delayed_work_time_.is_null())
+    return -1;
+
+  // Be careful here.  TimeDelta has a precision of microseconds, but we want a
+  // value in milliseconds.  If there are 5.5ms left, should the delay be 5 or
+  // 6?  It should be 6 to avoid executing delayed work too early.
+  double timeout =
+      ceil((delayed_work_time_ - TimeTicks::Now()).InMillisecondsF());
+
+  // Range check the |timeout| while converting to an integer.  If the |timeout|
+  // is negative, then we need to run delayed work soon.  If the |timeout| is
+  // "overflowingly" large, that means a delayed task was posted with a
+  // super-long delay.
+  return timeout < 0 ? 0 :
+      (timeout > std::numeric_limits<int>::max() ?
+       std::numeric_limits<int>::max() : static_cast<int>(timeout));
+}
+
+//-----------------------------------------------------------------------------
+// MessagePumpForUI public:
+
+MessagePumpForUI::MessagePumpForUI()
+    : atom_(0) {
+  InitMessageWnd();
+
+  ui_worker_thread_timer_.Set(::CreateWaitableTimer(NULL, FALSE, NULL));
+  ui_worker_thread_.reset(new base::Thread("UI Pump Worker thread"));
+  ui_worker_thread_->Start();
+  ui_worker_thread_->WaitUntilThreadStarted();
+  ui_worker_thread_->task_runner()->PostTask(
+      FROM_HERE,
+      base::Bind(&MessagePumpForUI::DoWorkerThreadRunLoop,
+                 base::Unretained(this)));
+}
+
+MessagePumpForUI::~MessagePumpForUI() {
+  DestroyWindow(message_hwnd_);
+  UnregisterClass(MAKEINTATOM(atom_),
+                  GetModuleFromAddress(&WndProcThunk));
+
+  ::QueueUserAPC(
+        reinterpret_cast<PAPCFUNC>(&MessagePumpForUI::ShutdownWorkerThread),
+        ui_worker_thread_->thread_handle().platform_handle(), NULL);
+  ui_worker_thread_->Stop();
+}
+
+void MessagePumpForUI::ScheduleWork() {
+  // If we have a regular posted task at the head of queue then we need to
+  // process it quickly.
+  if (state_ && state_->delegate->GetNewlyAddedTaskDelay().is_null()) {
+    // Make sure the MessagePump does some work for us.
+    PostWorkMessage();
+    return;
+  }
+  // Set a one shot timer to fire after 3 milliseconds. The actual resolution
+  // of the timer is dependent on timeBeginPeriod being called.
+  SetWakeupTimer(kDefaultUIWorkerThreadWakeupTimerMs);
+}
+
+void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
+  delayed_work_time_ = delayed_work_time;
+  RescheduleTimer();
+}
+
+//-----------------------------------------------------------------------------
+// MessagePumpForUI private:
+
+// 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_profile1(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "440919 MessagePumpForUI::WndProcThunk1"));
+
+  switch (message) {
+    case kMsgHaveWork:
+      reinterpret_cast<MessagePumpForUI*>(wparam)->HandleWorkMessage();
+      break;
+    case WM_TIMER:
+      reinterpret_cast<MessagePumpForUI*>(wparam)->HandleTimerMessage();
+      break;
+  }
+
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
+  tracked_objects::ScopedTracker tracking_profile2(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "440919 MessagePumpForUI::WndProcThunk2"));
+
+  return DefWindowProc(hwnd, message, wparam, lparam);
+}
+
+void MessagePumpForUI::DoRunLoop() {
+  // IF this was just a simple PeekMessage() loop (servicing all possible work
+  // queues), then Windows would try to achieve the following order according
+  // to MSDN documentation about PeekMessage with no filter):
+  //    * Sent messages
+  //    * Posted messages
+  //    * Sent messages (again)
+  //    * WM_PAINT messages
+  //    * WM_TIMER messages
+  //
+  // Summary: none of the above classes is starved, and sent messages has twice
+  // the chance of being processed (i.e., reduced service time).
+
+  for (;;) {
+    // If we do any work, we may create more messages etc., and more work may
+    // possibly be waiting in another task group.  When we (for example)
+    // ProcessNextWindowsMessage(), there is a good chance there are still more
+    // messages waiting.  On the other hand, when any of these methods return
+    // having done no work, then it is pretty unlikely that calling them again
+    // quickly will find any work to do.  Finally, if they all say they had no
+    // work, then it is a good time to consider sleeping (waiting) for more
+    // work.
+
+    bool more_work_is_plausible = ProcessNextWindowsMessage();
+    if (state_->should_quit)
+      break;
+
+    more_work_is_plausible |= state_->delegate->DoWork();
+    if (state_->should_quit)
+      break;
+
+    more_work_is_plausible |=
+        state_->delegate->DoDelayedWork(&delayed_work_time_);
+    // If we did not process any delayed work, then we can assume that our
+    // existing WM_TIMER if any will fire when delayed work should run.  We
+    // don't want to disturb that timer if it is already in flight.  However,
+    // if we did do all remaining delayed work, then lets kill the WM_TIMER.
+    if (more_work_is_plausible && delayed_work_time_.is_null())
+      KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this));
+    if (state_->should_quit)
+      break;
+
+    if (more_work_is_plausible)
+      continue;
+
+    more_work_is_plausible = state_->delegate->DoIdleWork();
+    if (state_->should_quit)
+      break;
+
+    if (more_work_is_plausible)
+      continue;
+
+    WaitForWork();  // Wait (sleep) until we have work to do again.
+  }
+}
+
+void MessagePumpForUI::InitMessageWnd() {
+  // Generate a unique window class name.
+  string16 class_name = StringPrintf(kWndClassFormat, this);
+
+  HINSTANCE instance = GetModuleFromAddress(&WndProcThunk);
+  WNDCLASSEX wc = {0};
+  wc.cbSize = sizeof(wc);
+  wc.lpfnWndProc = base::win::WrappedWindowProc<WndProcThunk>;
+  wc.hInstance = instance;
+  wc.lpszClassName = class_name.c_str();
+  atom_ = RegisterClassEx(&wc);
+  DCHECK(atom_);
+
+  message_hwnd_ = CreateWindow(MAKEINTATOM(atom_), 0, 0, 0, 0, 0, 0,
+                               HWND_MESSAGE, 0, instance, 0);
+  DCHECK(message_hwnd_);
+}
+
+void MessagePumpForUI::WaitForWork() {
+  // Wait until a message is available, up to the time needed by the timer
+  // manager to fire the next set of timers.
+  int delay = GetCurrentDelay();
+  if (delay < 0)  // Negative value means no timers waiting.
+    delay = INFINITE;
+
+  DWORD result;
+  result = MsgWaitForMultipleObjectsEx(0, NULL, delay, QS_ALLINPUT,
+                                       MWMO_INPUTAVAILABLE);
+
+  if (WAIT_OBJECT_0 == result) {
+    // A WM_* message is available.
+    // If a parent child relationship exists between windows across threads
+    // then their thread inputs are implicitly attached.
+    // This causes the MsgWaitForMultipleObjectsEx API to return indicating
+    // that messages are ready for processing (Specifically, mouse messages
+    // intended for the child window may appear if the child window has
+    // capture).
+    // The subsequent PeekMessages call may fail to return any messages thus
+    // causing us to enter a tight loop at times.
+    // The WaitMessage call below is a workaround to give the child window
+    // some time to process its input messages.
+    MSG msg = {0};
+    DWORD queue_status = GetQueueStatus(QS_MOUSE);
+    if (HIWORD(queue_status) & QS_MOUSE &&
+        !PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_NOREMOVE)) {
+      WaitMessage();
+    }
+    return;
+  }
+
+  DCHECK_NE(WAIT_FAILED, result) << GetLastError();
+}
+
+void MessagePumpForUI::HandleWorkMessage() {
+  // If we are being called outside of the context of Run, then don't try to do
+  // any work.  This could correspond to a MessageBox call or something of that
+  // sort.
+  if (!state_) {
+    // Since we handled a kMsgHaveWork message, we must still update this flag.
+    InterlockedExchange(&have_work_, 0);
+    return;
+  }
+
+  // Let whatever would have run had we not been putting messages in the queue
+  // run now.  This is an attempt to make our dummy message not starve other
+  // messages that may be in the Windows message queue.
+  ProcessPumpReplacementMessage();
+
+  // Now give the delegate a chance to do some work.  He'll let us know if he
+  // needs to do more work.
+  if (state_->delegate->DoWork())
+    ScheduleWork();
+  state_->delegate->DoDelayedWork(&delayed_work_time_);
+  RescheduleTimer();
+}
+
+void MessagePumpForUI::HandleTimerMessage() {
+  KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this));
+
+  // If we are being called outside of the context of Run, then don't do
+  // anything.  This could correspond to a MessageBox call or something of
+  // that sort.
+  if (!state_)
+    return;
+
+  state_->delegate->DoDelayedWork(&delayed_work_time_);
+  RescheduleTimer();
+}
+
+void MessagePumpForUI::RescheduleTimer() {
+  if (delayed_work_time_.is_null())
+    return;
+  //
+  // We would *like* to provide high resolution timers.  Windows timers using
+  // SetTimer() have a 10ms granularity.  We have to use WM_TIMER as a wakeup
+  // mechanism because the application can enter modal windows loops where it
+  // is not running our MessageLoop; the only way to have our timers fire in
+  // these cases is to post messages there.
+  //
+  // To provide sub-10ms timers, we process timers directly from our run loop.
+  // For the common case, timers will be processed there as the run loop does
+  // its normal work.  However, we *also* set the system timer so that WM_TIMER
+  // events fire.  This mops up the case of timers not being able to work in
+  // modal message loops.  It is possible for the SetTimer to pop and have no
+  // pending timers, because they could have already been processed by the
+  // run loop itself.
+  //
+  // We use a single SetTimer corresponding to the timer that will expire
+  // soonest.  As new timers are created and destroyed, we update SetTimer.
+  // Getting a spurrious SetTimer event firing is benign, as we'll just be
+  // processing an empty timer queue.
+  //
+  int delay_msec = GetCurrentDelay();
+  DCHECK_GE(delay_msec, 0);
+  if (delay_msec == 0) {
+    ScheduleWork();
+  } else {
+    if (delay_msec < USER_TIMER_MINIMUM)
+      delay_msec = USER_TIMER_MINIMUM;
+
+    // Create a WM_TIMER event that will wake us up to check for any pending
+    // timers (in case we are running within a nested, external sub-pump).
+    BOOL ret = SetTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this),
+                        delay_msec, NULL);
+    if (ret)
+      return;
+    // If we can't set timers, we are in big trouble... but cross our fingers
+    // for now.
+    // TODO(jar): If we don't see this error, use a CHECK() here instead.
+    UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", SET_TIMER_ERROR,
+                              MESSAGE_LOOP_PROBLEM_MAX);
+  }
+}
+
+bool MessagePumpForUI::ProcessNextWindowsMessage() {
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
+  tracked_objects::ScopedTracker tracking_profile1(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "440919 MessagePumpForUI::ProcessNextWindowsMessage1"));
+
+  // If there are sent messages in the queue then PeekMessage internally
+  // dispatches the message and returns false. We return true in this
+  // case to ensure that the message loop peeks again instead of calling
+  // MsgWaitForMultipleObjectsEx again.
+  bool sent_messages_in_queue = false;
+  DWORD queue_status = GetQueueStatus(QS_SENDMESSAGE);
+  if (HIWORD(queue_status) & QS_SENDMESSAGE)
+    sent_messages_in_queue = true;
+
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
+  tracked_objects::ScopedTracker tracking_profile2(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "440919 MessagePumpForUI::ProcessNextWindowsMessage2"));
+
+  MSG msg;
+  if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) != FALSE)
+    return ProcessMessageHelper(msg);
+
+  return sent_messages_in_queue;
+}
+
+bool MessagePumpForUI::ProcessMessageHelper(const MSG& msg) {
+  TRACE_EVENT1("base", "MessagePumpForUI::ProcessMessageHelper",
+               "message", msg.message);
+  if (WM_QUIT == msg.message) {
+    // Repost the QUIT message so that it will be retrieved by the primary
+    // GetMessage() loop.
+    state_->should_quit = true;
+    PostQuitMessage(static_cast<int>(msg.wParam));
+    return false;
+  }
+
+  // While running our main message pump, we discard kMsgHaveWork messages.
+  if (msg.message == kMsgHaveWork && msg.hwnd == message_hwnd_)
+    return ProcessPumpReplacementMessage();
+
+  if (CallMsgFilter(const_cast<MSG*>(&msg), kMessageFilterCode))
+    return true;
+
+  uint32_t action = MessagePumpDispatcher::POST_DISPATCH_PERFORM_DEFAULT;
+  if (state_->dispatcher) {
+    // TODO(vadimt): Remove ScopedTracker below once crbug.com/440919 is fixed.
+    tracked_objects::ScopedTracker tracking_profile4(
+        FROM_HERE_WITH_EXPLICIT_FUNCTION(
+            "440919 MessagePumpForUI::ProcessMessageHelper4"));
+
+    action = state_->dispatcher->Dispatch(msg);
+  }
+  if (action & MessagePumpDispatcher::POST_DISPATCH_QUIT_LOOP)
+    state_->should_quit = true;
+  if (action & MessagePumpDispatcher::POST_DISPATCH_PERFORM_DEFAULT) {
+    TranslateMessage(&msg);
+    DispatchMessage(&msg);
+  }
+
+  return true;
+}
+
+bool MessagePumpForUI::ProcessPumpReplacementMessage() {
+  // Since we discarded a kMsgHaveWork message, we must update the flag.
+  InterlockedExchange(&have_work_, 0);
+  return true;
+}
+
+void MessagePumpForUI::DoWorkerThreadRunLoop() {
+  DCHECK(ui_worker_thread_timer_.Get());
+  while (TRUE) {
+    DWORD ret = WaitForSingleObjectEx(
+        ui_worker_thread_timer_.Get(), INFINITE, TRUE);
+    // The only APC this thread could receive is the Shutdown APC.
+    if (ret == WAIT_IO_COMPLETION)
+      return;
+
+    // Make sure the MessagePump does some work for us.
+    PostWorkMessage();
+
+    // Set a one shot timer to process pending delayed tasks if any in the
+    // queue. The actual resolution of the timer is dependent on the
+    // timeBeginPeriod API being called.
+    SetWakeupTimer(kDefaultUIWorkerThreadWakeupTimerMs);
+  }
+}
+
+// static
+void CALLBACK MessagePumpForUI::ShutdownWorkerThread(ULONG_PTR param) {
+  // This function is empty because we only use the fact that an APC was posted
+  // to the worker thread to shut it down.
+  return;
+}
+
+void MessagePumpForUI::PostWorkMessage() {
+  BOOL posted = PostMessage(message_hwnd_, kMsgHaveWork,
+                            reinterpret_cast<WPARAM>(this),
+                            0);
+  if (!posted) {
+    // We have failed to insert a have-work message, so there is a chance
+    // that we will starve tasks/timers while sitting in a nested message
+    // loop. Nested loops only look at Windows Message queues, and don't
+    // look at *our* task queues, etc., so we might not get a time slice in
+    // such. :-(
+    // We could abort here, but the fear is that this failure mode is
+    // plausibly common (queue is full, of about 2000 messages), so we'll
+    // do a near-graceful recovery. Nested loops are pretty transient
+    // (we think), so this will probably be recoverable.
+    UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem",
+                              MESSAGE_POST_ERROR,
+                              MESSAGE_LOOP_PROBLEM_MAX);
+  }
+}
+
+void MessagePumpForUI::SetWakeupTimer(int64 delay_ms) {
+  // Set the timer for the delay passed in. The actual resolution of the
+  // timer is dependent on whether timeBeginPeriod was called.
+  LARGE_INTEGER due_time = {0};
+  due_time.QuadPart = -delay_ms * 10000;
+  BOOL timer_set = ::SetWaitableTimer(ui_worker_thread_timer_.Get(),
+      &due_time, 0, NULL, NULL, FALSE);
+  CHECK(timer_set);
+}
+
+//-----------------------------------------------------------------------------
+// MessagePumpForIO public:
+
+MessagePumpForIO::MessagePumpForIO() {
+  port_.Set(CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 1));
+  DCHECK(port_.IsValid());
+}
+
+MessagePumpForIO::~MessagePumpForIO() {
+}
+
+void MessagePumpForIO::ScheduleWork() {
+  if (InterlockedExchange(&have_work_, 1))
+    return;  // Someone else continued the pumping.
+
+  // Make sure the MessagePump does some work for us.
+  BOOL ret = PostQueuedCompletionStatus(port_.Get(), 0,
+                                        reinterpret_cast<ULONG_PTR>(this),
+                                        reinterpret_cast<OVERLAPPED*>(this));
+  if (ret)
+    return;  // Post worked perfectly.
+
+  // See comment in MessagePumpForUI::ScheduleWork() for this error recovery.
+  InterlockedExchange(&have_work_, 0);  // Clarify that we didn't succeed.
+  UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", COMPLETION_POST_ERROR,
+                            MESSAGE_LOOP_PROBLEM_MAX);
+}
+
+void MessagePumpForIO::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
+  // We know that we can't be blocked right now since this method can only be
+  // called on the same thread as Run, so we only need to update our record of
+  // how long to sleep when we do sleep.
+  delayed_work_time_ = delayed_work_time;
+}
+
+void MessagePumpForIO::RegisterIOHandler(HANDLE file_handle,
+                                         IOHandler* handler) {
+  ULONG_PTR key = HandlerToKey(handler, true);
+  HANDLE port = CreateIoCompletionPort(file_handle, port_.Get(), key, 1);
+  DPCHECK(port);
+}
+
+bool MessagePumpForIO::RegisterJobObject(HANDLE job_handle,
+                                         IOHandler* handler) {
+  // Job object notifications use the OVERLAPPED pointer to carry the message
+  // data. Mark the completion key correspondingly, so we will not try to
+  // convert OVERLAPPED* to IOContext*.
+  ULONG_PTR key = HandlerToKey(handler, false);
+  JOBOBJECT_ASSOCIATE_COMPLETION_PORT info;
+  info.CompletionKey = reinterpret_cast<void*>(key);
+  info.CompletionPort = port_.Get();
+  return SetInformationJobObject(job_handle,
+                                 JobObjectAssociateCompletionPortInformation,
+                                 &info,
+                                 sizeof(info)) != FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// MessagePumpForIO private:
+
+void MessagePumpForIO::DoRunLoop() {
+  for (;;) {
+    // If we do any work, we may create more messages etc., and more work may
+    // possibly be waiting in another task group.  When we (for example)
+    // WaitForIOCompletion(), there is a good chance there are still more
+    // messages waiting.  On the other hand, when any of these methods return
+    // having done no work, then it is pretty unlikely that calling them
+    // again quickly will find any work to do.  Finally, if they all say they
+    // had no work, then it is a good time to consider sleeping (waiting) for
+    // more work.
+
+    bool more_work_is_plausible = state_->delegate->DoWork();
+    if (state_->should_quit)
+      break;
+
+    more_work_is_plausible |= WaitForIOCompletion(0, NULL);
+    if (state_->should_quit)
+      break;
+
+    more_work_is_plausible |=
+        state_->delegate->DoDelayedWork(&delayed_work_time_);
+    if (state_->should_quit)
+      break;
+
+    if (more_work_is_plausible)
+      continue;
+
+    more_work_is_plausible = state_->delegate->DoIdleWork();
+    if (state_->should_quit)
+      break;
+
+    if (more_work_is_plausible)
+      continue;
+
+    WaitForWork();  // Wait (sleep) until we have work to do again.
+  }
+}
+
+// Wait until IO completes, up to the time needed by the timer manager to fire
+// the next set of timers.
+void MessagePumpForIO::WaitForWork() {
+  // We do not support nested IO message loops. This is to avoid messy
+  // recursion problems.
+  DCHECK_EQ(1, state_->run_depth) << "Cannot nest an IO message loop!";
+
+  int timeout = GetCurrentDelay();
+  if (timeout < 0)  // Negative value means no timers waiting.
+    timeout = INFINITE;
+
+  WaitForIOCompletion(timeout, NULL);
+}
+
+bool MessagePumpForIO::WaitForIOCompletion(DWORD timeout, IOHandler* filter) {
+  IOItem item;
+  if (completed_io_.empty() || !MatchCompletedIOItem(filter, &item)) {
+    // We have to ask the system for another IO completion.
+    if (!GetIOItem(timeout, &item))
+      return false;
+
+    if (ProcessInternalIOItem(item))
+      return true;
+  }
+
+  // If |item.has_valid_io_context| is false then |item.context| does not point
+  // to a context structure, and so should not be dereferenced, although it may
+  // still hold valid non-pointer data.
+  if (!item.has_valid_io_context || item.context->handler) {
+    if (filter && item.handler != filter) {
+      // Save this item for later
+      completed_io_.push_back(item);
+    } else {
+      DCHECK(!item.has_valid_io_context ||
+             (item.context->handler == item.handler));
+      WillProcessIOEvent();
+      item.handler->OnIOCompleted(item.context, item.bytes_transfered,
+                                  item.error);
+      DidProcessIOEvent();
+    }
+  } else {
+    // The handler must be gone by now, just cleanup the mess.
+    delete item.context;
+  }
+  return true;
+}
+
+// Asks the OS for another IO completion result.
+bool MessagePumpForIO::GetIOItem(DWORD timeout, IOItem* item) {
+  memset(item, 0, sizeof(*item));
+  ULONG_PTR key = NULL;
+  OVERLAPPED* overlapped = NULL;
+  if (!GetQueuedCompletionStatus(port_.Get(), &item->bytes_transfered, &key,
+                                 &overlapped, timeout)) {
+    if (!overlapped)
+      return false;  // Nothing in the queue.
+    item->error = GetLastError();
+    item->bytes_transfered = 0;
+  }
+
+  item->handler = KeyToHandler(key, &item->has_valid_io_context);
+  item->context = reinterpret_cast<IOContext*>(overlapped);
+  return true;
+}
+
+bool MessagePumpForIO::ProcessInternalIOItem(const IOItem& item) {
+  if (this == reinterpret_cast<MessagePumpForIO*>(item.context) &&
+      this == reinterpret_cast<MessagePumpForIO*>(item.handler)) {
+    // This is our internal completion.
+    DCHECK(!item.bytes_transfered);
+    InterlockedExchange(&have_work_, 0);
+    return true;
+  }
+  return false;
+}
+
+// Returns a completion item that was previously received.
+bool MessagePumpForIO::MatchCompletedIOItem(IOHandler* filter, IOItem* item) {
+  DCHECK(!completed_io_.empty());
+  for (std::list<IOItem>::iterator it = completed_io_.begin();
+       it != completed_io_.end(); ++it) {
+    if (!filter || it->handler == filter) {
+      *item = *it;
+      completed_io_.erase(it);
+      return true;
+    }
+  }
+  return false;
+}
+
+void MessagePumpForIO::AddIOObserver(IOObserver *obs) {
+  io_observers_.AddObserver(obs);
+}
+
+void MessagePumpForIO::RemoveIOObserver(IOObserver *obs) {
+  io_observers_.RemoveObserver(obs);
+}
+
+void MessagePumpForIO::WillProcessIOEvent() {
+  FOR_EACH_OBSERVER(IOObserver, io_observers_, WillProcessIOEvent());
+}
+
+void MessagePumpForIO::DidProcessIOEvent() {
+  FOR_EACH_OBSERVER(IOObserver, io_observers_, DidProcessIOEvent());
+}
+
+// static
+ULONG_PTR MessagePumpForIO::HandlerToKey(IOHandler* handler,
+                                         bool has_valid_io_context) {
+  ULONG_PTR key = reinterpret_cast<ULONG_PTR>(handler);
+
+  // |IOHandler| is at least pointer-size aligned, so the lowest two bits are
+  // always cleared. We use the lowest bit to distinguish completion keys with
+  // and without the associated |IOContext|.
+  DCHECK_EQ(key & 1, 0u);
+
+  // Mark the completion key as context-less.
+  if (!has_valid_io_context)
+    key = key | 1;
+  return key;
+}
+
+// static
+MessagePumpForIO::IOHandler* MessagePumpForIO::KeyToHandler(
+    ULONG_PTR key,
+    bool* has_valid_io_context) {
+  *has_valid_io_context = ((key & 1) == 0);
+  return reinterpret_cast<IOHandler*>(key & ~static_cast<ULONG_PTR>(1));
+}
+
+}  // namespace base
diff --git a/base/message_loop/message_pump_win.h b/base/message_loop/message_pump_win.h
new file mode 100644
index 0000000..042efdf
--- /dev/null
+++ b/base/message_loop/message_pump_win.h
@@ -0,0 +1,372 @@
+// Copyright (c) 2012 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_MESSAGE_LOOP_MESSAGE_PUMP_WIN_H_
+#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_WIN_H_
+
+#include <windows.h>
+
+#include <list>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_pump.h"
+#include "base/message_loop/message_pump_dispatcher.h"
+#include "base/observer_list.h"
+#include "base/time/time.h"
+#include "base/win/scoped_handle.h"
+
+namespace base {
+
+class Thread;
+
+// MessagePumpWin serves as the base for specialized versions of the MessagePump
+// for Windows. It provides basic functionality like handling of observers and
+// controlling the lifetime of the message pump.
+class BASE_EXPORT MessagePumpWin : public MessagePump {
+ public:
+  MessagePumpWin() : have_work_(0), state_(NULL) {}
+
+  // Like MessagePump::Run, but MSG objects are routed through dispatcher.
+  void RunWithDispatcher(Delegate* delegate, MessagePumpDispatcher* dispatcher);
+
+  // MessagePump methods:
+  void Run(Delegate* delegate) override;
+  void Quit() override;
+
+ protected:
+  struct RunState {
+    Delegate* delegate;
+    MessagePumpDispatcher* dispatcher;
+
+    // Used to flag that the current Run() invocation should return ASAP.
+    bool should_quit;
+
+    // Used to count how many Run() invocations are on the stack.
+    int run_depth;
+  };
+
+  virtual void DoRunLoop() = 0;
+  int GetCurrentDelay() const;
+
+  // The time at which delayed work should run.
+  TimeTicks delayed_work_time_;
+
+  // A boolean value used to indicate if there is a kMsgDoWork message pending
+  // in the Windows Message queue.  There is at most one such message, and it
+  // can drive execution of tasks when a native message pump is running.
+  LONG have_work_;
+
+  // State for the current invocation of Run.
+  RunState* state_;
+};
+
+//-----------------------------------------------------------------------------
+// MessagePumpForUI extends MessagePumpWin with methods that are particular to a
+// MessageLoop instantiated with TYPE_UI.
+//
+// MessagePumpForUI implements a "traditional" Windows message pump. It contains
+// a nearly infinite loop that peeks out messages, and then dispatches them.
+// Intermixed with those peeks are callouts to DoWork for pending tasks, and
+// DoDelayedWork for pending timers. When there are no events to be serviced,
+// this pump goes into a wait state. In most cases, this message pump handles
+// all processing.
+//
+// However, when a task, or windows event, invokes on the stack a native dialog
+// box or such, that window typically provides a bare bones (native?) message
+// pump.  That bare-bones message pump generally supports little more than a
+// peek of the Windows message queue, followed by a dispatch of the peeked
+// message.  MessageLoop extends that bare-bones message pump to also service
+// Tasks, at the cost of some complexity.
+//
+// The basic structure of the extension (refered to as a sub-pump) is that a
+// special message, kMsgHaveWork, is repeatedly injected into the Windows
+// Message queue.  Each time the kMsgHaveWork message is peeked, checks are
+// made for an extended set of events, including the availability of Tasks to
+// run.
+//
+// After running a task, the special message kMsgHaveWork is again posted to
+// the Windows Message queue, ensuring a future time slice for processing a
+// future event.  To prevent flooding the Windows Message queue, care is taken
+// to be sure that at most one kMsgHaveWork message is EVER pending in the
+// Window's Message queue.
+//
+// There are a few additional complexities in this system where, when there are
+// no Tasks to run, this otherwise infinite stream of messages which drives the
+// sub-pump is halted.  The pump is automatically re-started when Tasks are
+// queued.
+//
+// A second complexity is that the presence of this stream of posted tasks may
+// prevent a bare-bones message pump from ever peeking a WM_PAINT or WM_TIMER.
+// Such paint and timer events always give priority to a posted message, such as
+// kMsgHaveWork messages.  As a result, care is taken to do some peeking in
+// between the posting of each kMsgHaveWork message (i.e., after kMsgHaveWork
+// is peeked, and before a replacement kMsgHaveWork is posted).
+//
+// NOTE: Although it may seem odd that messages are used to start and stop this
+// flow (as opposed to signaling objects, etc.), it should be understood that
+// the native message pump will *only* respond to messages.  As a result, it is
+// an excellent choice.  It is also helpful that the starter messages that are
+// placed in the queue when new task arrive also awakens DoRunLoop.
+//
+class BASE_EXPORT MessagePumpForUI : public MessagePumpWin {
+ public:
+  // The application-defined code passed to the hook procedure.
+  static const int kMessageFilterCode = 0x5001;
+
+  MessagePumpForUI();
+  ~MessagePumpForUI() override;
+
+  // MessagePump methods:
+  void ScheduleWork() override;
+  void ScheduleDelayedWork(const TimeTicks& delayed_work_time) override;
+
+ private:
+  static LRESULT CALLBACK WndProcThunk(HWND window_handle,
+                                       UINT message,
+                                       WPARAM wparam,
+                                       LPARAM lparam);
+  void DoRunLoop() override;
+  void InitMessageWnd();
+  void WaitForWork();
+  void HandleWorkMessage();
+  void HandleTimerMessage();
+  void RescheduleTimer();
+  bool ProcessNextWindowsMessage();
+  bool ProcessMessageHelper(const MSG& msg);
+  bool ProcessPumpReplacementMessage();
+
+  // We spawn a worker thread to periodically post (3 ms) the kMsgHaveWork
+  // message to the UI message pump. This is to ensure that the main thread
+  // gets to process tasks and delayed tasks when there is no activity in the
+  // Windows message pump or when there is a nested modal loop (sizing/moving/
+  // drag drop/message boxes) etc.
+  void DoWorkerThreadRunLoop();
+
+  // This function is posted as part of a user mode APC to shutdown the worker
+  // thread when the main message pump is shutting down.
+  static void CALLBACK ShutdownWorkerThread(ULONG_PTR param);
+
+  // Helper function for posting the kMsgHaveWork message to wake up the pump
+  // for processing tasks.
+  void PostWorkMessage();
+
+  // Helper function to set the waitable timer used to wake up the UI worker
+  // thread for processing delayed tasks.
+  // |delay_ms| : The delay in milliseconds.
+  void SetWakeupTimer(int64 delay_ms);
+
+  // Atom representing the registered window class.
+  ATOM atom_;
+
+  // A hidden message-only window.
+  HWND message_hwnd_;
+
+  // This thread is used to periodically wake up the main thread to process
+  // tasks.
+  scoped_ptr<base::Thread> ui_worker_thread_;
+
+  // The UI worker thread waits on this timer indefinitely. When the main
+  // thread has tasks ready to be processed it sets the timer.
+  base::win::ScopedHandle ui_worker_thread_timer_;
+};
+
+//-----------------------------------------------------------------------------
+// MessagePumpForIO extends MessagePumpWin with methods that are particular to a
+// MessageLoop instantiated with TYPE_IO. This version of MessagePump does not
+// deal with Windows mesagges, and instead has a Run loop based on Completion
+// Ports so it is better suited for IO operations.
+//
+class BASE_EXPORT MessagePumpForIO : public MessagePumpWin {
+ public:
+  struct IOContext;
+
+  // Clients interested in receiving OS notifications when asynchronous IO
+  // operations complete should implement this interface and register themselves
+  // with the message pump.
+  //
+  // Typical use #1:
+  //   // Use only when there are no user's buffers involved on the actual IO,
+  //   // so that all the cleanup can be done by the message pump.
+  //   class MyFile : public IOHandler {
+  //     MyFile() {
+  //       ...
+  //       context_ = new IOContext;
+  //       context_->handler = this;
+  //       message_pump->RegisterIOHandler(file_, this);
+  //     }
+  //     ~MyFile() {
+  //       if (pending_) {
+  //         // By setting the handler to NULL, we're asking for this context
+  //         // to be deleted when received, without calling back to us.
+  //         context_->handler = NULL;
+  //       } else {
+  //         delete context_;
+  //      }
+  //     }
+  //     virtual void OnIOCompleted(IOContext* context, DWORD bytes_transfered,
+  //                                DWORD error) {
+  //         pending_ = false;
+  //     }
+  //     void DoSomeIo() {
+  //       ...
+  //       // The only buffer required for this operation is the overlapped
+  //       // structure.
+  //       ConnectNamedPipe(file_, &context_->overlapped);
+  //       pending_ = true;
+  //     }
+  //     bool pending_;
+  //     IOContext* context_;
+  //     HANDLE file_;
+  //   };
+  //
+  // Typical use #2:
+  //   class MyFile : public IOHandler {
+  //     MyFile() {
+  //       ...
+  //       message_pump->RegisterIOHandler(file_, this);
+  //     }
+  //     // Plus some code to make sure that this destructor is not called
+  //     // while there are pending IO operations.
+  //     ~MyFile() {
+  //     }
+  //     virtual void OnIOCompleted(IOContext* context, DWORD bytes_transfered,
+  //                                DWORD error) {
+  //       ...
+  //       delete context;
+  //     }
+  //     void DoSomeIo() {
+  //       ...
+  //       IOContext* context = new IOContext;
+  //       // This is not used for anything. It just prevents the context from
+  //       // being considered "abandoned".
+  //       context->handler = this;
+  //       ReadFile(file_, buffer, num_bytes, &read, &context->overlapped);
+  //     }
+  //     HANDLE file_;
+  //   };
+  //
+  // Typical use #3:
+  // Same as the previous example, except that in order to deal with the
+  // requirement stated for the destructor, the class calls WaitForIOCompletion
+  // from the destructor to block until all IO finishes.
+  //     ~MyFile() {
+  //       while(pending_)
+  //         message_pump->WaitForIOCompletion(INFINITE, this);
+  //     }
+  //
+  class IOHandler {
+   public:
+    virtual ~IOHandler() {}
+    // This will be called once the pending IO operation associated with
+    // |context| completes. |error| is the Win32 error code of the IO operation
+    // (ERROR_SUCCESS if there was no error). |bytes_transfered| will be zero
+    // on error.
+    virtual void OnIOCompleted(IOContext* context, DWORD bytes_transfered,
+                               DWORD error) = 0;
+  };
+
+  // An IOObserver is an object that receives IO notifications from the
+  // MessagePump.
+  //
+  // NOTE: An IOObserver implementation should be extremely fast!
+  class IOObserver {
+   public:
+    IOObserver() {}
+
+    virtual void WillProcessIOEvent() = 0;
+    virtual void DidProcessIOEvent() = 0;
+
+   protected:
+    virtual ~IOObserver() {}
+  };
+
+  // The extended context that should be used as the base structure on every
+  // overlapped IO operation. |handler| must be set to the registered IOHandler
+  // for the given file when the operation is started, and it can be set to NULL
+  // before the operation completes to indicate that the handler should not be
+  // called anymore, and instead, the IOContext should be deleted when the OS
+  // notifies the completion of this operation. Please remember that any buffers
+  // involved with an IO operation should be around until the callback is
+  // received, so this technique can only be used for IO that do not involve
+  // additional buffers (other than the overlapped structure itself).
+  struct IOContext {
+    OVERLAPPED overlapped;
+    IOHandler* handler;
+  };
+
+  MessagePumpForIO();
+  ~MessagePumpForIO() override;
+
+  // MessagePump methods:
+  void ScheduleWork() override;
+  void ScheduleDelayedWork(const TimeTicks& delayed_work_time) override;
+
+  // Register the handler to be used when asynchronous IO for the given file
+  // completes. The registration persists as long as |file_handle| is valid, so
+  // |handler| must be valid as long as there is pending IO for the given file.
+  void RegisterIOHandler(HANDLE file_handle, IOHandler* handler);
+
+  // Register the handler to be used to process job events. The registration
+  // persists as long as the job object is live, so |handler| must be valid
+  // until the job object is destroyed. Returns true if the registration
+  // succeeded, and false otherwise.
+  bool RegisterJobObject(HANDLE job_handle, IOHandler* handler);
+
+  // Waits for the next IO completion that should be processed by |filter|, for
+  // up to |timeout| milliseconds. Return true if any IO operation completed,
+  // regardless of the involved handler, and false if the timeout expired. If
+  // the completion port received any message and the involved IO handler
+  // matches |filter|, the callback is called before returning from this code;
+  // if the handler is not the one that we are looking for, the callback will
+  // be postponed for another time, so reentrancy problems can be avoided.
+  // External use of this method should be reserved for the rare case when the
+  // caller is willing to allow pausing regular task dispatching on this thread.
+  bool WaitForIOCompletion(DWORD timeout, IOHandler* filter);
+
+  void AddIOObserver(IOObserver* obs);
+  void RemoveIOObserver(IOObserver* obs);
+
+ private:
+  struct IOItem {
+    IOHandler* handler;
+    IOContext* context;
+    DWORD bytes_transfered;
+    DWORD error;
+
+    // In some cases |context| can be a non-pointer value casted to a pointer.
+    // |has_valid_io_context| is true if |context| is a valid IOContext
+    // pointer, and false otherwise.
+    bool has_valid_io_context;
+  };
+
+  void DoRunLoop() override;
+  void WaitForWork();
+  bool MatchCompletedIOItem(IOHandler* filter, IOItem* item);
+  bool GetIOItem(DWORD timeout, IOItem* item);
+  bool ProcessInternalIOItem(const IOItem& item);
+  void WillProcessIOEvent();
+  void DidProcessIOEvent();
+
+  // Converts an IOHandler pointer to a completion port key.
+  // |has_valid_io_context| specifies whether completion packets posted to
+  // |handler| will have valid OVERLAPPED pointers.
+  static ULONG_PTR HandlerToKey(IOHandler* handler, bool has_valid_io_context);
+
+  // Converts a completion port key to an IOHandler pointer.
+  static IOHandler* KeyToHandler(ULONG_PTR key, bool* has_valid_io_context);
+
+  // The completion port associated with this thread.
+  win::ScopedHandle port_;
+  // This list will be empty almost always. It stores IO completions that have
+  // not been delivered yet because somebody was doing cleanup.
+  std::list<IOItem> completed_io_;
+
+  ObserverList<IOObserver> io_observers_;
+};
+
+}  // namespace base
+
+#endif  // BASE_MESSAGE_LOOP_MESSAGE_PUMP_WIN_H_
diff --git a/base/message_loop/timer_slack.h b/base/message_loop/timer_slack.h
new file mode 100644
index 0000000..1ad6ca9
--- /dev/null
+++ b/base/message_loop/timer_slack.h
@@ -0,0 +1,22 @@
+// 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.
+
+#ifndef BASE_MESSAGE_LOOP_TIMER_SLACK_H_
+#define BASE_MESSAGE_LOOP_TIMER_SLACK_H_
+
+namespace base {
+
+// Amount of timer slack to use for delayed timers.  Increasing timer slack
+// allows the OS to coalesce timers more effectively.
+enum TimerSlack {
+  // Lowest value for timer slack allowed by OS.
+  TIMER_SLACK_NONE,
+
+  // Maximal value for timer slack allowed by OS.
+  TIMER_SLACK_MAXIMUM
+};
+
+}  // namespace base
+
+#endif  // BASE_MESSAGE_LOOP_TIMER_SLACK_H_
diff --git a/base/metrics/BUILD.gn b/base/metrics/BUILD.gn
new file mode 100644
index 0000000..845ac4f
--- /dev/null
+++ b/base/metrics/BUILD.gn
@@ -0,0 +1,49 @@
+# Copyright (c) 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("metrics") {
+  sources = [
+    "bucket_ranges.cc",
+    "bucket_ranges.h",
+    "field_trial.cc",
+    "field_trial.h",
+    "histogram.cc",
+    "histogram.h",
+    "histogram_base.cc",
+    "histogram_base.h",
+    "histogram_delta_serialization.cc",
+    "histogram_delta_serialization.h",
+    "histogram_flattener.h",
+    "histogram_macros.h",
+    "histogram_samples.cc",
+    "histogram_samples.h",
+    "histogram_snapshot_manager.cc",
+    "histogram_snapshot_manager.h",
+    "sample_map.cc",
+    "sample_map.h",
+    "sample_vector.cc",
+    "sample_vector.h",
+    "sparse_histogram.cc",
+    "sparse_histogram.h",
+    "statistics_recorder.cc",
+    "statistics_recorder.h",
+    "user_metrics.cc",
+    "user_metrics.h",
+    "user_metrics_action.h",
+  ]
+
+  if (is_nacl) {
+    sources -= [ "field_trial.cc" ]
+  }
+
+  configs += [ "//base:base_implementation" ]
+
+  deps = [
+    "//base/debug",
+    "//base/json",
+    "//base/memory",
+  ]
+
+  visibility = [ "//base/*" ]
+}
diff --git a/base/metrics/OWNERS b/base/metrics/OWNERS
new file mode 100644
index 0000000..3fd7c0d
--- /dev/null
+++ b/base/metrics/OWNERS
@@ -0,0 +1,3 @@
+asvitkine@chromium.org
+isherman@chromium.org
+jar@chromium.org
diff --git a/base/metrics/bucket_ranges.cc b/base/metrics/bucket_ranges.cc
new file mode 100644
index 0000000..949c813
--- /dev/null
+++ b/base/metrics/bucket_ranges.cc
@@ -0,0 +1,139 @@
+// Copyright (c) 2012 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/metrics/bucket_ranges.h"
+
+#include <cmath>
+
+#include "base/logging.h"
+
+namespace base {
+
+// Static table of checksums for all possible 8 bit bytes.
+const uint32 kCrcTable[256] = { 0x0, 0x77073096L, 0xee0e612cL,
+0x990951baL, 0x76dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0xedb8832L,
+0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x9b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 0x1adad47dL,
+0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL,
+0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L,
+0x4c69105eL, 0xd56041e4L, 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL,
+0xa50ab56bL, 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, 0xc8d75180L,
+0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL, 0x2802b89eL,
+0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL,
+0xb6662d3dL, 0x76dc4190L, 0x1db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L,
+0x6b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0xf00f934L, 0x9609a88eL,
+0xe10e9818L, 0x7f6a0dbbL, 0x86d3d2dL, 0x91646c97L, 0xe6635c01L, 0x6b6b51f4L,
+0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L,
+0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL,
+0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L,
+0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL,
+0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L,
+0x206f85b3L, 0xb966d409L, 0xce61e49fL, 0x5edef90eL, 0x29d9c998L, 0xb0d09822L,
+0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L,
+0x9abfb3b6L, 0x3b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x4db2615L,
+0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0xd6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL,
+0x9309ff9dL, 0xa00ae27L, 0x7d079eb1L, 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L,
+0x6906c2feL, 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L,
+0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L,
+0x60b08ed5L, 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L,
+0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L, 0xcb61b38cL,
+0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L,
+0x5505262fL, 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L,
+0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+0x26d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x5005713L, 0x95bf4a82L,
+0xe2b87a14L, 0x7bb12baeL, 0xcb61b38L, 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L,
+0xbdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL,
+0xf6b9265bL, 0x6fb077e1L, 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL,
+0x11010b5cL, 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 0x4969474dL,
+0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L,
+0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L,
+0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL,
+0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+0x2d02ef8dL,
+};
+
+// We generate the CRC-32 using the low order bits to select whether to XOR in
+// the reversed polynomial 0xedb88320L.  This is nice and simple, and allows us
+// to keep the quotient in a uint32.  Since we're not concerned about the nature
+// of corruptions (i.e., we don't care about bit sequencing, since we are
+// handling memory changes, which are more grotesque) so we don't bother to
+// get the CRC correct for big-endian vs little-ending calculations.  All we
+// need is a nice hash, that tends to depend on all the bits of the sample, with
+// very little chance of changes in one place impacting changes in another
+// place.
+static uint32 Crc32(uint32 sum, HistogramBase::Sample value) {
+  // TODO(jar): Switch to false and watch stats.
+  const bool kUseRealCrc = true;
+
+  if (kUseRealCrc) {
+    union {
+      HistogramBase::Sample range;
+      unsigned char bytes[sizeof(HistogramBase::Sample)];
+    } converter;
+    converter.range = value;
+    for (size_t i = 0; i < sizeof(converter); ++i)
+      sum = kCrcTable[(sum & 0xff) ^ converter.bytes[i]] ^ (sum >> 8);
+  } else {
+    // Use hash techniques provided in ReallyFastHash, except we don't care
+    // about "avalanching" (which would worsten the hash, and add collisions),
+    // and we don't care about edge cases since we have an even number of bytes.
+    union {
+      HistogramBase::Sample range;
+      uint16 ints[sizeof(HistogramBase::Sample) / 2];
+    } converter;
+    DCHECK_EQ(sizeof(HistogramBase::Sample), sizeof(converter));
+    converter.range = value;
+    sum += converter.ints[0];
+    sum = (sum << 16) ^ sum ^ (static_cast<uint32>(converter.ints[1]) << 11);
+    sum += sum >> 11;
+  }
+  return sum;
+}
+
+BucketRanges::BucketRanges(size_t num_ranges)
+    : ranges_(num_ranges, 0),
+      checksum_(0) {}
+
+BucketRanges::~BucketRanges() {}
+
+void BucketRanges::set_range(size_t i, HistogramBase::Sample value) {
+  DCHECK_LT(i, ranges_.size());
+  CHECK_GE(value, 0);
+  ranges_[i] = value;
+}
+
+uint32 BucketRanges::CalculateChecksum() const {
+  // Seed checksum.
+  uint32 checksum = static_cast<uint32>(ranges_.size());
+
+  for (size_t index = 0; index < ranges_.size(); ++index)
+    checksum = Crc32(checksum, ranges_[index]);
+  return checksum;
+}
+
+bool BucketRanges::HasValidChecksum() const {
+  return CalculateChecksum() == checksum_;
+}
+
+void BucketRanges::ResetChecksum() {
+  checksum_ = CalculateChecksum();
+}
+
+bool BucketRanges::Equals(const BucketRanges* other) const {
+  if (checksum_ != other->checksum_)
+    return false;
+  if (ranges_.size() != other->ranges_.size())
+    return false;
+  for (size_t index = 0; index < ranges_.size(); ++index) {
+    if (ranges_[index] != other->ranges_[index])
+      return false;
+  }
+  return true;
+}
+
+}  // namespace base
diff --git a/base/metrics/bucket_ranges.h b/base/metrics/bucket_ranges.h
new file mode 100644
index 0000000..fe1152f
--- /dev/null
+++ b/base/metrics/bucket_ranges.h
@@ -0,0 +1,79 @@
+// Copyright (c) 2012 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.
+//
+// BucketRanges stores the vector of ranges that delimit what samples are
+// tallied in the corresponding buckets of a histogram. Histograms that have
+// same ranges for all their corresponding buckets should share the same
+// BucketRanges object.
+//
+// E.g. A 5 buckets LinearHistogram with 1 as minimal value and 4 as maximal
+// value will need a BucketRanges with 6 ranges:
+// 0, 1, 2, 3, 4, INT_MAX
+//
+// TODO(kaiwang): Currently we keep all negative values in 0~1 bucket. Consider
+// changing 0 to INT_MIN.
+
+#ifndef BASE_METRICS_BUCKET_RANGES_H_
+#define BASE_METRICS_BUCKET_RANGES_H_
+
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/gtest_prod_util.h"
+#include "base/metrics/histogram_base.h"
+
+namespace base {
+
+class BASE_EXPORT BucketRanges {
+ public:
+  typedef std::vector<HistogramBase::Sample> Ranges;
+
+  explicit BucketRanges(size_t num_ranges);
+  ~BucketRanges();
+
+  size_t size() const { return ranges_.size(); }
+  HistogramBase::Sample range(size_t i) const { return ranges_[i]; }
+  void set_range(size_t i, HistogramBase::Sample value);
+  uint32 checksum() const { return checksum_; }
+  void set_checksum(uint32 checksum) { checksum_ = checksum; }
+
+  // A bucket is defined by a consecutive pair of entries in |ranges|, so there
+  // is one fewer bucket than there are ranges.  For example, if |ranges| is
+  // [0, 1, 3, 7, INT_MAX], then the buckets in this histogram are
+  // [0, 1), [1, 3), [3, 7), and [7, INT_MAX).
+  size_t bucket_count() const { return ranges_.size() - 1; }
+
+  // Checksum methods to verify whether the ranges are corrupted (e.g. bad
+  // memory access).
+  uint32 CalculateChecksum() const;
+  bool HasValidChecksum() const;
+  void ResetChecksum();
+
+  // Return true iff |other| object has same ranges_ as |this| object's ranges_.
+  bool Equals(const BucketRanges* other) const;
+
+ private:
+  // A monotonically increasing list of values which determine which bucket to
+  // put a sample into.  For each index, show the smallest sample that can be
+  // added to the corresponding bucket.
+  Ranges ranges_;
+
+  // Checksum for the conntents of ranges_.  Used to detect random over-writes
+  // of our data, and to quickly see if some other BucketRanges instance is
+  // possibly Equal() to this instance.
+  // TODO(kaiwang): Consider change this to uint64. Because we see a lot of
+  // noise on UMA dashboard.
+  uint32 checksum_;
+
+  DISALLOW_COPY_AND_ASSIGN(BucketRanges);
+};
+
+//////////////////////////////////////////////////////////////////////////////
+// Expose only for test.
+BASE_EXPORT_PRIVATE extern const uint32 kCrcTable[256];
+
+}  // namespace base
+
+#endif  // BASE_METRICS_BUCKET_RANGES_H_
diff --git a/base/metrics/bucket_ranges_unittest.cc b/base/metrics/bucket_ranges_unittest.cc
new file mode 100644
index 0000000..fc0699c
--- /dev/null
+++ b/base/metrics/bucket_ranges_unittest.cc
@@ -0,0 +1,92 @@
+// Copyright (c) 2012 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/metrics/bucket_ranges.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+TEST(BucketRangesTest, NormalSetup) {
+  BucketRanges ranges(5);
+  ASSERT_EQ(5u, ranges.size());
+  ASSERT_EQ(4u, ranges.bucket_count());
+
+  for (int i = 0; i < 5; ++i) {
+    EXPECT_EQ(0, ranges.range(i));
+  }
+  EXPECT_EQ(0u, ranges.checksum());
+
+  ranges.set_range(3, 100);
+  EXPECT_EQ(100, ranges.range(3));
+}
+
+TEST(BucketRangesTest, Equals) {
+  // Compare empty ranges.
+  BucketRanges ranges1(3);
+  BucketRanges ranges2(3);
+  BucketRanges ranges3(5);
+
+  EXPECT_TRUE(ranges1.Equals(&ranges2));
+  EXPECT_FALSE(ranges1.Equals(&ranges3));
+  EXPECT_FALSE(ranges2.Equals(&ranges3));
+
+  // Compare full filled ranges.
+  ranges1.set_range(0, 0);
+  ranges1.set_range(1, 1);
+  ranges1.set_range(2, 2);
+  ranges1.set_checksum(100);
+  ranges2.set_range(0, 0);
+  ranges2.set_range(1, 1);
+  ranges2.set_range(2, 2);
+  ranges2.set_checksum(100);
+
+  EXPECT_TRUE(ranges1.Equals(&ranges2));
+
+  // Checksum does not match.
+  ranges1.set_checksum(99);
+  EXPECT_FALSE(ranges1.Equals(&ranges2));
+  ranges1.set_checksum(100);
+
+  // Range does not match.
+  ranges1.set_range(1, 3);
+  EXPECT_FALSE(ranges1.Equals(&ranges2));
+}
+
+TEST(BucketRangesTest, Checksum) {
+  BucketRanges ranges(3);
+  ranges.set_range(0, 0);
+  ranges.set_range(1, 1);
+  ranges.set_range(2, 2);
+
+  ranges.ResetChecksum();
+  EXPECT_EQ(289217253u, ranges.checksum());
+
+  ranges.set_range(2, 3);
+  EXPECT_FALSE(ranges.HasValidChecksum());
+
+  ranges.ResetChecksum();
+  EXPECT_EQ(2843835776u, ranges.checksum());
+  EXPECT_TRUE(ranges.HasValidChecksum());
+}
+
+// Table was generated similarly to sample code for CRC-32 given on:
+// http://www.w3.org/TR/PNG/#D-CRCAppendix.
+TEST(BucketRangesTest, Crc32TableTest) {
+  for (int i = 0; i < 256; ++i) {
+    uint32 checksum = i;
+    for (int j = 0; j < 8; ++j) {
+      const uint32 kReversedPolynomial = 0xedb88320L;
+      if (checksum & 1)
+        checksum = kReversedPolynomial ^ (checksum >> 1);
+      else
+        checksum >>= 1;
+    }
+    EXPECT_EQ(kCrcTable[i], checksum);
+  }
+}
+
+}  // namespace
+}  // namespace base
diff --git a/base/metrics/field_trial.cc b/base/metrics/field_trial.cc
new file mode 100644
index 0000000..639f6d3
--- /dev/null
+++ b/base/metrics/field_trial.cc
@@ -0,0 +1,593 @@
+// Copyright (c) 2012 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/metrics/field_trial.h"
+
+#include <algorithm>
+
+#include "base/build_time.h"
+#include "base/logging.h"
+#include "base/rand_util.h"
+#include "base/sha1.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/sys_byteorder.h"
+
+namespace base {
+
+namespace {
+
+// Created a time value based on |year|, |month| and |day_of_month| parameters.
+Time CreateTimeFromParams(int year, int month, int day_of_month) {
+  DCHECK_GT(year, 1970);
+  DCHECK_GT(month, 0);
+  DCHECK_LT(month, 13);
+  DCHECK_GT(day_of_month, 0);
+  DCHECK_LT(day_of_month, 32);
+
+  Time::Exploded exploded;
+  exploded.year = year;
+  exploded.month = month;
+  exploded.day_of_week = 0;  // Should be unused.
+  exploded.day_of_month = day_of_month;
+  exploded.hour = 0;
+  exploded.minute = 0;
+  exploded.second = 0;
+  exploded.millisecond = 0;
+
+  return Time::FromLocalExploded(exploded);
+}
+
+// Returns the boundary value for comparing against the FieldTrial's added
+// groups for a given |divisor| (total probability) and |entropy_value|.
+FieldTrial::Probability GetGroupBoundaryValue(
+    FieldTrial::Probability divisor,
+    double entropy_value) {
+  // Add a tiny epsilon value to get consistent results when converting floating
+  // points to int. Without it, boundary values have inconsistent results, e.g.:
+  //
+  //   static_cast<FieldTrial::Probability>(100 * 0.56) == 56
+  //   static_cast<FieldTrial::Probability>(100 * 0.57) == 56
+  //   static_cast<FieldTrial::Probability>(100 * 0.58) == 57
+  //   static_cast<FieldTrial::Probability>(100 * 0.59) == 59
+  const double kEpsilon = 1e-8;
+  const FieldTrial::Probability result =
+      static_cast<FieldTrial::Probability>(divisor * entropy_value + kEpsilon);
+  // Ensure that adding the epsilon still results in a value < |divisor|.
+  return std::min(result, divisor - 1);
+}
+
+}  // namespace
+
+// statics
+const int FieldTrial::kNotFinalized = -1;
+const int FieldTrial::kDefaultGroupNumber = 0;
+bool FieldTrial::enable_benchmarking_ = false;
+
+const char FieldTrialList::kPersistentStringSeparator('/');
+const char FieldTrialList::kActivationMarker('*');
+int FieldTrialList::kNoExpirationYear = 0;
+
+//------------------------------------------------------------------------------
+// FieldTrial methods and members.
+
+FieldTrial::EntropyProvider::~EntropyProvider() {
+}
+
+void FieldTrial::Disable() {
+  DCHECK(!group_reported_);
+  enable_field_trial_ = false;
+
+  // In case we are disabled after initialization, we need to switch
+  // the trial to the default group.
+  if (group_ != kNotFinalized) {
+    // Only reset when not already the default group, because in case we were
+    // forced to the default group, the group number may not be
+    // kDefaultGroupNumber, so we should keep it as is.
+    if (group_name_ != default_group_name_)
+      SetGroupChoice(default_group_name_, kDefaultGroupNumber);
+  }
+}
+
+int FieldTrial::AppendGroup(const std::string& name,
+                            Probability group_probability) {
+  // When the group choice was previously forced, we only need to return the
+  // the id of the chosen group, and anything can be returned for the others.
+  if (forced_) {
+    DCHECK(!group_name_.empty());
+    if (name == group_name_) {
+      // Note that while |group_| may be equal to |kDefaultGroupNumber| on the
+      // forced trial, it will not have the same value as the default group
+      // number returned from the non-forced |FactoryGetFieldTrial()| call,
+      // which takes care to ensure that this does not happen.
+      return group_;
+    }
+    DCHECK_NE(next_group_number_, group_);
+    // We still return different numbers each time, in case some caller need
+    // them to be different.
+    return next_group_number_++;
+  }
+
+  DCHECK_LE(group_probability, divisor_);
+  DCHECK_GE(group_probability, 0);
+
+  if (enable_benchmarking_ || !enable_field_trial_)
+    group_probability = 0;
+
+  accumulated_group_probability_ += group_probability;
+
+  DCHECK_LE(accumulated_group_probability_, divisor_);
+  if (group_ == kNotFinalized && accumulated_group_probability_ > random_) {
+    // This is the group that crossed the random line, so we do the assignment.
+    SetGroupChoice(name, next_group_number_);
+  }
+  return next_group_number_++;
+}
+
+int FieldTrial::group() {
+  FinalizeGroupChoice();
+  if (trial_registered_)
+    FieldTrialList::NotifyFieldTrialGroupSelection(this);
+  return group_;
+}
+
+const std::string& FieldTrial::group_name() {
+  // Call |group()| to ensure group gets assigned and observers are notified.
+  group();
+  DCHECK(!group_name_.empty());
+  return group_name_;
+}
+
+void FieldTrial::SetForced() {
+  // We might have been forced before (e.g., by CreateFieldTrial) and it's
+  // first come first served, e.g., command line switch has precedence.
+  if (forced_)
+    return;
+
+  // And we must finalize the group choice before we mark ourselves as forced.
+  FinalizeGroupChoice();
+  forced_ = true;
+}
+
+// static
+void FieldTrial::EnableBenchmarking() {
+  DCHECK_EQ(0u, FieldTrialList::GetFieldTrialCount());
+  enable_benchmarking_ = true;
+}
+
+// static
+FieldTrial* FieldTrial::CreateSimulatedFieldTrial(
+    const std::string& trial_name,
+    Probability total_probability,
+    const std::string& default_group_name,
+    double entropy_value) {
+  return new FieldTrial(trial_name, total_probability, default_group_name,
+                        entropy_value);
+}
+
+FieldTrial::FieldTrial(const std::string& trial_name,
+                       const Probability total_probability,
+                       const std::string& default_group_name,
+                       double entropy_value)
+    : trial_name_(trial_name),
+      divisor_(total_probability),
+      default_group_name_(default_group_name),
+      random_(GetGroupBoundaryValue(total_probability, entropy_value)),
+      accumulated_group_probability_(0),
+      next_group_number_(kDefaultGroupNumber + 1),
+      group_(kNotFinalized),
+      enable_field_trial_(true),
+      forced_(false),
+      group_reported_(false),
+      trial_registered_(false) {
+  DCHECK_GT(total_probability, 0);
+  DCHECK(!trial_name_.empty());
+  DCHECK(!default_group_name_.empty());
+}
+
+FieldTrial::~FieldTrial() {}
+
+void FieldTrial::SetTrialRegistered() {
+  DCHECK_EQ(kNotFinalized, group_);
+  DCHECK(!trial_registered_);
+  trial_registered_ = true;
+}
+
+void FieldTrial::SetGroupChoice(const std::string& group_name, int number) {
+  group_ = number;
+  if (group_name.empty())
+    StringAppendF(&group_name_, "%d", group_);
+  else
+    group_name_ = group_name;
+  DVLOG(1) << "Field trial: " << trial_name_ << " Group choice:" << group_name_;
+}
+
+void FieldTrial::FinalizeGroupChoice() {
+  if (group_ != kNotFinalized)
+    return;
+  accumulated_group_probability_ = divisor_;
+  // Here it's OK to use |kDefaultGroupNumber| since we can't be forced and not
+  // finalized.
+  DCHECK(!forced_);
+  SetGroupChoice(default_group_name_, kDefaultGroupNumber);
+}
+
+bool FieldTrial::GetActiveGroup(ActiveGroup* active_group) const {
+  if (!group_reported_ || !enable_field_trial_)
+    return false;
+  DCHECK_NE(group_, kNotFinalized);
+  active_group->trial_name = trial_name_;
+  active_group->group_name = group_name_;
+  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.
+
+// static
+FieldTrialList* FieldTrialList::global_ = NULL;
+
+// static
+bool FieldTrialList::used_without_global_ = false;
+
+FieldTrialList::Observer::~Observer() {
+}
+
+FieldTrialList::FieldTrialList(
+    const FieldTrial::EntropyProvider* entropy_provider)
+    : entropy_provider_(entropy_provider),
+      observer_list_(new ObserverListThreadSafe<FieldTrialList::Observer>(
+          ObserverListBase<FieldTrialList::Observer>::NOTIFY_EXISTING_ONLY)) {
+  DCHECK(!global_);
+  DCHECK(!used_without_global_);
+  global_ = this;
+
+  Time two_years_from_build_time = GetBuildTime() + TimeDelta::FromDays(730);
+  Time::Exploded exploded;
+  two_years_from_build_time.LocalExplode(&exploded);
+  kNoExpirationYear = exploded.year;
+}
+
+FieldTrialList::~FieldTrialList() {
+  AutoLock auto_lock(lock_);
+  while (!registered_.empty()) {
+    RegistrationMap::iterator it = registered_.begin();
+    it->second->Release();
+    registered_.erase(it->first);
+  }
+  DCHECK_EQ(this, global_);
+  global_ = NULL;
+}
+
+// static
+FieldTrial* FieldTrialList::FactoryGetFieldTrial(
+    const std::string& trial_name,
+    FieldTrial::Probability total_probability,
+    const std::string& default_group_name,
+    const int year,
+    const int month,
+    const int day_of_month,
+    FieldTrial::RandomizationType randomization_type,
+    int* default_group_number) {
+  return FactoryGetFieldTrialWithRandomizationSeed(
+      trial_name, total_probability, default_group_name,
+      year, month, day_of_month, randomization_type, 0, default_group_number);
+}
+
+// static
+FieldTrial* FieldTrialList::FactoryGetFieldTrialWithRandomizationSeed(
+    const std::string& trial_name,
+    FieldTrial::Probability total_probability,
+    const std::string& default_group_name,
+    const int year,
+    const int month,
+    const int day_of_month,
+    FieldTrial::RandomizationType randomization_type,
+    uint32 randomization_seed,
+    int* default_group_number) {
+  if (default_group_number)
+    *default_group_number = FieldTrial::kDefaultGroupNumber;
+  // Check if the field trial has already been created in some other way.
+  FieldTrial* existing_trial = Find(trial_name);
+  if (existing_trial) {
+    CHECK(existing_trial->forced_);
+    // If the default group name differs between the existing forced trial
+    // and this trial, then use a different value for the default group number.
+    if (default_group_number &&
+        default_group_name != existing_trial->default_group_name()) {
+      // If the new default group number corresponds to the group that was
+      // chosen for the forced trial (which has been finalized when it was
+      // forced), then set the default group number to that.
+      if (default_group_name == existing_trial->group_name_internal()) {
+        *default_group_number = existing_trial->group_;
+      } else {
+        // Otherwise, use |kNonConflictingGroupNumber| (-2) for the default
+        // group number, so that it does not conflict with the |AppendGroup()|
+        // result for the chosen group.
+        const int kNonConflictingGroupNumber = -2;
+        COMPILE_ASSERT(
+            kNonConflictingGroupNumber != FieldTrial::kDefaultGroupNumber,
+            conflicting_default_group_number);
+        COMPILE_ASSERT(
+            kNonConflictingGroupNumber != FieldTrial::kNotFinalized,
+            conflicting_default_group_number);
+        *default_group_number = kNonConflictingGroupNumber;
+      }
+    }
+    return existing_trial;
+  }
+
+  double entropy_value;
+  if (randomization_type == FieldTrial::ONE_TIME_RANDOMIZED) {
+    const FieldTrial::EntropyProvider* entropy_provider =
+        GetEntropyProviderForOneTimeRandomization();
+    CHECK(entropy_provider);
+    entropy_value = entropy_provider->GetEntropyForTrial(trial_name,
+                                                         randomization_seed);
+  } else {
+    DCHECK_EQ(FieldTrial::SESSION_RANDOMIZED, randomization_type);
+    DCHECK_EQ(0U, randomization_seed);
+    entropy_value = RandDouble();
+  }
+
+  FieldTrial* field_trial = new FieldTrial(trial_name, total_probability,
+                                           default_group_name, entropy_value);
+  if (GetBuildTime() > CreateTimeFromParams(year, month, day_of_month))
+    field_trial->Disable();
+  FieldTrialList::Register(field_trial);
+  return field_trial;
+}
+
+// static
+FieldTrial* FieldTrialList::Find(const std::string& name) {
+  if (!global_)
+    return NULL;
+  AutoLock auto_lock(global_->lock_);
+  return global_->PreLockedFind(name);
+}
+
+// static
+int FieldTrialList::FindValue(const std::string& name) {
+  FieldTrial* field_trial = Find(name);
+  if (field_trial)
+    return field_trial->group();
+  return FieldTrial::kNotFinalized;
+}
+
+// static
+std::string FieldTrialList::FindFullName(const std::string& name) {
+  FieldTrial* field_trial = Find(name);
+  if (field_trial)
+    return field_trial->group_name();
+  return std::string();
+}
+
+// static
+bool FieldTrialList::TrialExists(const std::string& name) {
+  return Find(name) != NULL;
+}
+
+// static
+void FieldTrialList::StatesToString(std::string* output) {
+  FieldTrial::ActiveGroups active_groups;
+  GetActiveFieldTrialGroups(&active_groups);
+  for (FieldTrial::ActiveGroups::const_iterator it = active_groups.begin();
+       it != active_groups.end(); ++it) {
+    DCHECK_EQ(std::string::npos,
+              it->trial_name.find(kPersistentStringSeparator));
+    DCHECK_EQ(std::string::npos,
+              it->group_name.find(kPersistentStringSeparator));
+    output->append(it->trial_name);
+    output->append(1, kPersistentStringSeparator);
+    output->append(it->group_name);
+    output->append(1, kPersistentStringSeparator);
+  }
+}
+
+// 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());
+  if (!global_)
+    return;
+  AutoLock auto_lock(global_->lock_);
+
+  for (RegistrationMap::iterator it = global_->registered_.begin();
+       it != global_->registered_.end(); ++it) {
+    FieldTrial::ActiveGroup active_group;
+    if (it->second->GetActiveGroup(&active_group))
+      active_groups->push_back(active_group);
+  }
+}
+
+// static
+bool FieldTrialList::CreateTrialsFromString(
+    const std::string& trials_string,
+    FieldTrialActivationMode mode,
+    const std::set<std::string>& ignored_trial_names) {
+  DCHECK(global_);
+  if (trials_string.empty() || !global_)
+    return true;
+
+  size_t next_item = 0;
+  while (next_item < trials_string.length()) {
+    size_t name_end = trials_string.find(kPersistentStringSeparator, next_item);
+    if (name_end == trials_string.npos || next_item == name_end)
+      return false;
+    size_t group_name_end = trials_string.find(kPersistentStringSeparator,
+                                               name_end + 1);
+    if (name_end + 1 == group_name_end)
+      return false;
+    if (group_name_end == trials_string.npos)
+      group_name_end = trials_string.length();
+
+    // Verify if the trial should be activated or not.
+    std::string name;
+    bool force_activation = false;
+    if (trials_string[next_item] == kActivationMarker) {
+      // Name cannot be only the indicator.
+      if (name_end - next_item == 1)
+        return false;
+      next_item++;
+      force_activation = true;
+    }
+    name.append(trials_string, next_item, name_end - next_item);
+    std::string group_name(trials_string, name_end + 1,
+                           group_name_end - name_end - 1);
+    next_item = group_name_end + 1;
+
+    if (ignored_trial_names.find(name) != ignored_trial_names.end())
+      continue;
+
+    FieldTrial* trial = CreateFieldTrial(name, group_name);
+    if (!trial)
+      return false;
+    if (mode == ACTIVATE_TRIALS || force_activation) {
+      // Call |group()| to mark the trial as "used" and notify observers, if
+      // any. This is useful to ensure that field trials created in child
+      // processes are properly reported in crash reports.
+      trial->group();
+    }
+  }
+  return true;
+}
+
+// static
+FieldTrial* FieldTrialList::CreateFieldTrial(
+    const std::string& name,
+    const std::string& group_name) {
+  DCHECK(global_);
+  DCHECK_GE(name.size(), 0u);
+  DCHECK_GE(group_name.size(), 0u);
+  if (name.empty() || group_name.empty() || !global_)
+    return NULL;
+
+  FieldTrial* field_trial = FieldTrialList::Find(name);
+  if (field_trial) {
+    // In single process mode, or when we force them from the command line,
+    // we may have already created the field trial.
+    if (field_trial->group_name_internal() != group_name)
+      return NULL;
+    return field_trial;
+  }
+  const int kTotalProbability = 100;
+  field_trial = new FieldTrial(name, kTotalProbability, group_name, 0);
+  FieldTrialList::Register(field_trial);
+  // Force the trial, which will also finalize the group choice.
+  field_trial->SetForced();
+  return field_trial;
+}
+
+// static
+void FieldTrialList::AddObserver(Observer* observer) {
+  if (!global_)
+    return;
+  global_->observer_list_->AddObserver(observer);
+}
+
+// static
+void FieldTrialList::RemoveObserver(Observer* observer) {
+  if (!global_)
+    return;
+  global_->observer_list_->RemoveObserver(observer);
+}
+
+// static
+void FieldTrialList::NotifyFieldTrialGroupSelection(FieldTrial* field_trial) {
+  if (!global_)
+    return;
+
+  {
+    AutoLock auto_lock(global_->lock_);
+    if (field_trial->group_reported_)
+      return;
+    field_trial->group_reported_ = true;
+  }
+
+  if (!field_trial->enable_field_trial_)
+    return;
+
+  global_->observer_list_->Notify(
+      FROM_HERE, &FieldTrialList::Observer::OnFieldTrialGroupFinalized,
+      field_trial->trial_name(), field_trial->group_name_internal());
+}
+
+// static
+size_t FieldTrialList::GetFieldTrialCount() {
+  if (!global_)
+    return 0;
+  AutoLock auto_lock(global_->lock_);
+  return global_->registered_.size();
+}
+
+// static
+const FieldTrial::EntropyProvider*
+    FieldTrialList::GetEntropyProviderForOneTimeRandomization() {
+  if (!global_) {
+    used_without_global_ = true;
+    return NULL;
+  }
+
+  return global_->entropy_provider_.get();
+}
+
+FieldTrial* FieldTrialList::PreLockedFind(const std::string& name) {
+  RegistrationMap::iterator it = registered_.find(name);
+  if (registered_.end() == it)
+    return NULL;
+  return it->second;
+}
+
+// static
+void FieldTrialList::Register(FieldTrial* trial) {
+  if (!global_) {
+    used_without_global_ = true;
+    return;
+  }
+  AutoLock auto_lock(global_->lock_);
+  DCHECK(!global_->PreLockedFind(trial->trial_name()));
+  trial->AddRef();
+  trial->SetTrialRegistered();
+  global_->registered_[trial->trial_name()] = trial;
+}
+
+}  // namespace base
diff --git a/base/metrics/field_trial.h b/base/metrics/field_trial.h
new file mode 100644
index 0000000..26257ab
--- /dev/null
+++ b/base/metrics/field_trial.h
@@ -0,0 +1,520 @@
+// Copyright (c) 2012 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.
+
+// FieldTrial is a class for handling details of statistical experiments
+// performed by actual users in the field (i.e., in a shipped or beta product).
+// All code is called exclusively on the UI thread currently.
+//
+// The simplest example is an experiment to see whether one of two options
+// produces "better" results across our user population.  In that scenario, UMA
+// data is uploaded to aggregate the test results, and this FieldTrial class
+// manages the state of each such experiment (state == which option was
+// pseudo-randomly selected).
+//
+// States are typically generated randomly, either based on a one time
+// randomization (which will yield the same results, in terms of selecting
+// the client for a field trial or not, for every run of the program on a
+// given machine), or by a session randomization (generated each time the
+// application starts up, but held constant during the duration of the
+// process).
+
+//------------------------------------------------------------------------------
+// Example:  Suppose we have an experiment involving memory, such as determining
+// the impact of some pruning algorithm.
+// We assume that we already have a histogram of memory usage, such as:
+
+//   UMA_HISTOGRAM_COUNTS("Memory.RendererTotal", count);
+
+// Somewhere in main thread initialization code, we'd probably define an
+// instance of a FieldTrial, with code such as:
+
+// // FieldTrials are reference counted, and persist automagically until
+// // process teardown, courtesy of their automatic registration in
+// // FieldTrialList.
+// // Note: This field trial will run in Chrome instances compiled through
+// //       8 July, 2015, and after that all instances will be in "StandardMem".
+// scoped_refptr<base::FieldTrial> trial(
+//     base::FieldTrialList::FactoryGetFieldTrial(
+//         "MemoryExperiment", 1000, "StandardMem", 2015, 7, 8,
+//         base::FieldTrial::ONE_TIME_RANDOMIZED, NULL));
+//
+// const int high_mem_group =
+//     trial->AppendGroup("HighMem", 20);  // 2% in HighMem group.
+// const int low_mem_group =
+//     trial->AppendGroup("LowMem", 20);   // 2% in LowMem group.
+// // Take action depending of which group we randomly land in.
+// if (trial->group() == high_mem_group)
+//   SetPruningAlgorithm(kType1);  // Sample setting of browser state.
+// else if (trial->group() == low_mem_group)
+//   SetPruningAlgorithm(kType2);  // Sample alternate setting.
+
+//------------------------------------------------------------------------------
+
+#ifndef BASE_METRICS_FIELD_TRIAL_H_
+#define BASE_METRICS_FIELD_TRIAL_H_
+
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/observer_list_threadsafe.h"
+#include "base/synchronization/lock.h"
+#include "base/time/time.h"
+
+namespace base {
+
+class FieldTrialList;
+
+class BASE_EXPORT FieldTrial : public RefCounted<FieldTrial> {
+ public:
+  typedef int Probability;  // Probability type for being selected in a trial.
+
+  // Specifies the persistence of the field trial group choice.
+  enum RandomizationType {
+    // One time randomized trials will persist the group choice between
+    // restarts, which is recommended for most trials, especially those that
+    // change user visible behavior.
+    ONE_TIME_RANDOMIZED,
+    // Session randomized trials will roll the dice to select a group on every
+    // process restart.
+    SESSION_RANDOMIZED,
+  };
+
+  // EntropyProvider is an interface for providing entropy for one-time
+  // randomized (persistent) field trials.
+  class BASE_EXPORT EntropyProvider {
+   public:
+    virtual ~EntropyProvider();
+
+    // Returns a double in the range of [0, 1) to be used for the dice roll for
+    // the specified field trial. If |randomization_seed| is not 0, it will be
+    // used in preference to |trial_name| for generating the entropy by entropy
+    // providers that support it. A given instance should always return the same
+    // value given the same input |trial_name| and |randomization_seed| values.
+    virtual double GetEntropyForTrial(const std::string& trial_name,
+                                      uint32 randomization_seed) const = 0;
+  };
+
+  // A pair representing a Field Trial and its selected group.
+  struct ActiveGroup {
+    std::string trial_name;
+    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
+  // assignment (and hence is not yet participating in the trial).
+  static const int kNotFinalized;
+
+  // Disables this trial, meaning it always determines the default group
+  // has been selected. May be called immediately after construction, or
+  // at any time after initialization (should not be interleaved with
+  // AppendGroup calls). Once disabled, there is no way to re-enable a
+  // trial.
+  // TODO(mad): http://code.google.com/p/chromium/issues/detail?id=121446
+  // This doesn't properly reset to Default when a group was forced.
+  void Disable();
+
+  // Establish the name and probability of the next group in this trial.
+  // Sometimes, based on construction randomization, this call may cause the
+  // provided group to be *THE* group selected for use in this instance.
+  // The return value is the group number of the new group.
+  int AppendGroup(const std::string& name, Probability group_probability);
+
+  // Return the name of the FieldTrial (excluding the group name).
+  const std::string& trial_name() const { return trial_name_; }
+
+  // Return the randomly selected group number that was assigned, and notify
+  // any/all observers that this finalized group number has presumably been used
+  // (queried), and will never change. Note that this will force an instance to
+  // participate, and make it illegal to attempt to probabilistically add any
+  // other groups to the trial.
+  int group();
+
+  // If the group's name is empty, a string version containing the group number
+  // is used as the group name. This causes a winner to be chosen if none was.
+  const std::string& group_name();
+
+  // Set the field trial as forced, meaning that it was setup earlier than
+  // the hard coded registration of the field trial to override it.
+  // This allows the code that was hard coded to register the field trial to
+  // still succeed even though the field trial has already been registered.
+  // This must be called after appending all the groups, since we will make
+  // the group choice here. Note that this is a NOOP for already forced trials.
+  // And, as the rest of the FieldTrial code, this is not thread safe and must
+  // be done from the UI thread.
+  void SetForced();
+
+  // Enable benchmarking sets field trials to a common setting.
+  static void EnableBenchmarking();
+
+  // Creates a FieldTrial object with the specified parameters, to be used for
+  // simulation of group assignment without actually affecting global field
+  // trial state in the running process. Group assignment will be done based on
+  // |entropy_value|, which must have a range of [0, 1).
+  //
+  // Note: Using this function will not register the field trial globally in the
+  // running process - for that, use FieldTrialList::FactoryGetFieldTrial().
+  //
+  // The ownership of the returned FieldTrial is transfered to the caller which
+  // is responsible for deref'ing it (e.g. by using scoped_refptr<FieldTrial>).
+  static FieldTrial* CreateSimulatedFieldTrial(
+      const std::string& trial_name,
+      Probability total_probability,
+      const std::string& default_group_name,
+      double entropy_value);
+
+ private:
+  // Allow tests to access our innards for testing purposes.
+  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, Registration);
+  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, AbsoluteProbabilities);
+  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, RemainingProbability);
+  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, FiftyFiftyProbability);
+  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, MiddleProbabilities);
+  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);
+  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, SetForcedChangeDefault_Default);
+  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, SetForcedChangeDefault_NonDefault);
+  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, FloatBoundariesGiveEqualGroupSizes);
+  FRIEND_TEST_ALL_PREFIXES(FieldTrialTest, DoesNotSurpassTotalProbability);
+
+  friend class base::FieldTrialList;
+
+  friend class RefCounted<FieldTrial>;
+
+  // This is the group number of the 'default' group when a choice wasn't forced
+  // by a call to FieldTrialList::CreateFieldTrial. It is kept private so that
+  // consumers don't use it by mistake in cases where the group was forced.
+  static const int kDefaultGroupNumber;
+
+  // Creates a field trial with the specified parameters. Group assignment will
+  // be done based on |entropy_value|, which must have a range of [0, 1).
+  FieldTrial(const std::string& trial_name,
+             Probability total_probability,
+             const std::string& default_group_name,
+             double entropy_value);
+  virtual ~FieldTrial();
+
+  // Return the default group name of the FieldTrial.
+  std::string default_group_name() const { return default_group_name_; }
+
+  // Marks this trial as having been registered with the FieldTrialList. Must be
+  // called no more than once and before any |group()| calls have occurred.
+  void SetTrialRegistered();
+
+  // Sets the chosen group name and number.
+  void SetGroupChoice(const std::string& group_name, int number);
+
+  // Ensures that a group is chosen, if it hasn't yet been. The field trial
+  // might yet be disabled, so this call will *not* notify observers of the
+  // status.
+  void FinalizeGroupChoice();
+
+  // Returns the trial name and selected group name for this field trial via
+  // the output parameter |active_group|, but only if the group has already
+  // been chosen and has been externally observed via |group()| and the trial
+  // has not been disabled. In that case, true is returned and |active_group|
+  // is filled in; otherwise, the result is false and |active_group| is left
+  // 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_; }
+
+  // The name of the field trial, as can be found via the FieldTrialList.
+  const std::string trial_name_;
+
+  // The maximum sum of all probabilities supplied, which corresponds to 100%.
+  // This is the scaling factor used to adjust supplied probabilities.
+  const Probability divisor_;
+
+  // The name of the default group.
+  const std::string default_group_name_;
+
+  // The randomly selected probability that is used to select a group (or have
+  // the instance not participate).  It is the product of divisor_ and a random
+  // number between [0, 1).
+  Probability random_;
+
+  // Sum of the probabilities of all appended groups.
+  Probability accumulated_group_probability_;
+
+  // The number that will be returned by the next AppendGroup() call.
+  int next_group_number_;
+
+  // The pseudo-randomly assigned group number.
+  // This is kNotFinalized if no group has been assigned.
+  int group_;
+
+  // A textual name for the randomly selected group. Valid after |group()|
+  // has been called.
+  std::string group_name_;
+
+  // When enable_field_trial_ is false, field trial reverts to the 'default'
+  // group.
+  bool enable_field_trial_;
+
+  // When forced_ is true, we return the chosen group from AppendGroup when
+  // appropriate.
+  bool forced_;
+
+  // Specifies whether the group choice has been reported to observers.
+  bool group_reported_;
+
+  // Whether this trial is registered with the global FieldTrialList and thus
+  // should notify it when its group is queried.
+  bool trial_registered_;
+
+  // When benchmarking is enabled, field trials all revert to the 'default'
+  // group.
+  static bool enable_benchmarking_;
+
+  DISALLOW_COPY_AND_ASSIGN(FieldTrial);
+};
+
+//------------------------------------------------------------------------------
+// Class with a list of all active field trials.  A trial is active if it has
+// been registered, which includes evaluating its state based on its probaility.
+// Only one instance of this class exists.
+class BASE_EXPORT FieldTrialList {
+ public:
+  // Specifies whether field trials should be activated (marked as "used"), when
+  // created using |CreateTrialsFromString()|. Has no effect on trials that are
+  // prefixed with |kActivationMarker|, which will always be activated."
+  enum FieldTrialActivationMode {
+    DONT_ACTIVATE_TRIALS,
+    ACTIVATE_TRIALS,
+  };
+
+  // Define a separator character to use when creating a persistent form of an
+  // instance.  This is intended for use as a command line argument, passed to a
+  // second process to mimic our state (i.e., provide the same group name).
+  static const char kPersistentStringSeparator;  // Currently a slash.
+
+  // Define a marker character to be used as a prefix to a trial name on the
+  // command line which forces its activation.
+  static const char kActivationMarker;  // Currently an asterisk.
+
+  // Year that is guaranteed to not be expired when instantiating a field trial
+  // via |FactoryGetFieldTrial()|.  Set to two years from the build date.
+  static int kNoExpirationYear;
+
+  // Observer is notified when a FieldTrial's group is selected.
+  class BASE_EXPORT Observer {
+   public:
+    // Notify observers when FieldTrials's group is selected.
+    virtual void OnFieldTrialGroupFinalized(const std::string& trial_name,
+                                            const std::string& group_name) = 0;
+
+   protected:
+    virtual ~Observer();
+  };
+
+  // This singleton holds the global list of registered FieldTrials.
+  //
+  // To support one-time randomized field trials, specify a non-NULL
+  // |entropy_provider| which should be a source of uniformly distributed
+  // entropy values. Takes ownership of |entropy_provider|. If one time
+  // randomization is not desired, pass in NULL for |entropy_provider|.
+  explicit FieldTrialList(const FieldTrial::EntropyProvider* entropy_provider);
+
+  // Destructor Release()'s references to all registered FieldTrial instances.
+  ~FieldTrialList();
+
+  // Get a FieldTrial instance from the factory.
+  //
+  // |name| is used to register the instance with the FieldTrialList class,
+  // and can be used to find the trial (only one trial can be present for each
+  // name). |default_group_name| is the name of the default group which will
+  // be chosen if none of the subsequent appended groups get to be chosen.
+  // |default_group_number| can receive the group number of the default group as
+  // AppendGroup returns the number of the subsequence groups. |trial_name| and
+  // |default_group_name| may not be empty but |default_group_number| can be
+  // NULL if the value is not needed.
+  //
+  // Group probabilities that are later supplied must sum to less than or equal
+  // to the |total_probability|. Arguments |year|, |month| and |day_of_month|
+  // specify the expiration time. If the build time is after the expiration time
+  // then the field trial reverts to the 'default' group.
+  //
+  // Use this static method to get a startup-randomized FieldTrial or a
+  // previously created forced FieldTrial.
+  static FieldTrial* FactoryGetFieldTrial(
+      const std::string& trial_name,
+      FieldTrial::Probability total_probability,
+      const std::string& default_group_name,
+      const int year,
+      const int month,
+      const int day_of_month,
+      FieldTrial::RandomizationType randomization_type,
+      int* default_group_number);
+
+  // Same as FactoryGetFieldTrial(), but allows specifying a custom seed to be
+  // used on one-time randomized field trials (instead of a hash of the trial
+  // name, which is used otherwise or if |randomization_seed| has value 0). The
+  // |randomization_seed| value (other than 0) should never be the same for two
+  // trials, else this would result in correlated group assignments.
+  // Note: Using a custom randomization seed is only supported by the
+  // PermutedEntropyProvider (which is used when UMA is not enabled).
+  static FieldTrial* FactoryGetFieldTrialWithRandomizationSeed(
+      const std::string& trial_name,
+      FieldTrial::Probability total_probability,
+      const std::string& default_group_name,
+      const int year,
+      const int month,
+      const int day_of_month,
+      FieldTrial::RandomizationType randomization_type,
+      uint32 randomization_seed,
+      int* default_group_number);
+
+  // The Find() method can be used to test to see if a named Trial was already
+  // registered, or to retrieve a pointer to it from the global map.
+  static FieldTrial* Find(const std::string& name);
+
+  // Returns the group number chosen for the named trial, or
+  // FieldTrial::kNotFinalized if the trial does not exist.
+  static int FindValue(const std::string& name);
+
+  // Returns the group name chosen for the named trial, or the
+  // empty string if the trial does not exist.
+  static std::string FindFullName(const std::string& name);
+
+  // Returns true if the named trial has been registered.
+  static bool TrialExists(const std::string& name);
+
+  // Creates a persistent representation of active 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 for which the group has been chosen and externally
+  // observed (via |group()|) and which have not been disabled, with "/" used
+  // to separate all names and to terminate the string. This string is parsed
+  // 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
+  // not been disabled.
+  static void GetActiveFieldTrialGroups(
+      FieldTrial::ActiveGroups* active_groups);
+
+  // Use a state string (re: StatesToString()) to augment the current list of
+  // field trials to include the supplied trials, and using a 100% probability
+  // for each trial, force them to have the same group string. This is commonly
+  // used in a non-browser process, to carry randomly selected state in a
+  // browser process into this non-browser process, but could also be invoked
+  // through a command line argument to the browser process. The created field
+  // trials are all marked as "used" for the purposes of active trial reporting
+  // if |mode| is ACTIVATE_TRIALS, otherwise each trial will be marked as "used"
+  // if it is prefixed with |kActivationMarker|. Trial names in
+  // |ignored_trial_names| are ignored when parsing |prior_trials|.
+  static bool CreateTrialsFromString(
+      const std::string& prior_trials,
+      FieldTrialActivationMode mode,
+      const std::set<std::string>& ignored_trial_names);
+
+  // Create a FieldTrial with the given |name| and using 100% probability for
+  // the FieldTrial, force FieldTrial to have the same group string as
+  // |group_name|. This is commonly used in a non-browser process, to carry
+  // randomly selected state in a browser process into this non-browser process.
+  // It returns NULL if there is a FieldTrial that is already registered with
+  // the same |name| but has different finalized group string (|group_name|).
+  static FieldTrial* CreateFieldTrial(const std::string& name,
+                                      const std::string& group_name);
+
+  // Add an observer to be notified when a field trial is irrevocably committed
+  // to being part of some specific field_group (and hence the group_name is
+  // also finalized for that field_trial).
+  static void AddObserver(Observer* observer);
+
+  // Remove an observer.
+  static void RemoveObserver(Observer* observer);
+
+  // Notify all observers that a group has been finalized for |field_trial|.
+  static void NotifyFieldTrialGroupSelection(FieldTrial* field_trial);
+
+  // Return the number of active field trials.
+  static size_t GetFieldTrialCount();
+
+ private:
+  // A map from FieldTrial names to the actual instances.
+  typedef std::map<std::string, FieldTrial*> RegistrationMap;
+
+  // If one-time randomization is enabled, returns a weak pointer to the
+  // corresponding EntropyProvider. Otherwise, returns NULL.
+  static const FieldTrial::EntropyProvider*
+      GetEntropyProviderForOneTimeRandomization();
+
+  // Helper function should be called only while holding lock_.
+  FieldTrial* PreLockedFind(const std::string& name);
+
+  // Register() stores a pointer to the given trial in a global map.
+  // This method also AddRef's the indicated trial.
+  // This should always be called after creating a new FieldTrial instance.
+  static void Register(FieldTrial* trial);
+
+  static FieldTrialList* global_;  // The singleton of this class.
+
+  // This will tell us if there is an attempt to register a field
+  // trial or check if one-time randomization is enabled without
+  // creating the FieldTrialList. This is not an error, unless a
+  // FieldTrialList is created after that.
+  static bool used_without_global_;
+
+  // Lock for access to registered_.
+  base::Lock lock_;
+  RegistrationMap registered_;
+
+  // Entropy provider to be used for one-time randomized field trials. If NULL,
+  // one-time randomization is not supported.
+  scoped_ptr<const FieldTrial::EntropyProvider> entropy_provider_;
+
+  // List of observers to be notified when a group is selected for a FieldTrial.
+  scoped_refptr<ObserverListThreadSafe<Observer> > observer_list_;
+
+  DISALLOW_COPY_AND_ASSIGN(FieldTrialList);
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_FIELD_TRIAL_H_
diff --git a/base/metrics/field_trial_unittest.cc b/base/metrics/field_trial_unittest.cc
new file mode 100644
index 0000000..f1a1042
--- /dev/null
+++ b/base/metrics/field_trial_unittest.cc
@@ -0,0 +1,1133 @@
+// Copyright (c) 2012 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/metrics/field_trial.h"
+
+#include "base/build_time.h"
+#include "base/message_loop/message_loop.h"
+#include "base/rand_util.h"
+#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+// Default group name used by several tests.
+const char kDefaultGroupName[] = "DefaultGroup";
+
+// Call FieldTrialList::FactoryGetFieldTrial() with a future expiry date.
+scoped_refptr<base::FieldTrial> CreateFieldTrial(
+    const std::string& trial_name,
+    int total_probability,
+    const std::string& default_group_name,
+    int* default_group_number) {
+  return FieldTrialList::FactoryGetFieldTrial(
+      trial_name, total_probability, default_group_name,
+      base::FieldTrialList::kNoExpirationYear, 1, 1,
+      base::FieldTrial::SESSION_RANDOMIZED, default_group_number);
+}
+
+int OneYearBeforeBuildTime() {
+  Time one_year_before_build_time = GetBuildTime() - TimeDelta::FromDays(365);
+  Time::Exploded exploded;
+  one_year_before_build_time.LocalExplode(&exploded);
+  return exploded.year;
+}
+
+// FieldTrialList::Observer implementation for testing.
+class TestFieldTrialObserver : public FieldTrialList::Observer {
+ public:
+  TestFieldTrialObserver() {
+    FieldTrialList::AddObserver(this);
+  }
+
+  ~TestFieldTrialObserver() override { FieldTrialList::RemoveObserver(this); }
+
+  void OnFieldTrialGroupFinalized(const std::string& trial,
+                                  const std::string& group) override {
+    trial_name_ = trial;
+    group_name_ = group;
+  }
+
+  const std::string& trial_name() const { return trial_name_; }
+  const std::string& group_name() const { return group_name_; }
+
+ private:
+  std::string trial_name_;
+  std::string group_name_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestFieldTrialObserver);
+};
+
+}  // namespace
+
+class FieldTrialTest : public testing::Test {
+ public:
+  FieldTrialTest() : trial_list_(NULL) {}
+
+ private:
+  MessageLoop message_loop_;
+  FieldTrialList trial_list_;
+};
+
+// Test registration, and also check that destructors are called for trials
+// (and that Valgrind doesn't catch us leaking).
+TEST_F(FieldTrialTest, Registration) {
+  const char name1[] = "name 1 test";
+  const char name2[] = "name 2 test";
+  EXPECT_FALSE(FieldTrialList::Find(name1));
+  EXPECT_FALSE(FieldTrialList::Find(name2));
+
+  scoped_refptr<FieldTrial> trial1 =
+      CreateFieldTrial(name1, 10, "default name 1 test", NULL);
+  EXPECT_EQ(FieldTrial::kNotFinalized, trial1->group_);
+  EXPECT_EQ(name1, trial1->trial_name());
+  EXPECT_EQ("", trial1->group_name_internal());
+
+  trial1->AppendGroup(std::string(), 7);
+
+  EXPECT_EQ(trial1.get(), FieldTrialList::Find(name1));
+  EXPECT_FALSE(FieldTrialList::Find(name2));
+
+  scoped_refptr<FieldTrial> trial2 =
+      CreateFieldTrial(name2, 10, "default name 2 test", NULL);
+  EXPECT_EQ(FieldTrial::kNotFinalized, trial2->group_);
+  EXPECT_EQ(name2, trial2->trial_name());
+  EXPECT_EQ("", trial2->group_name_internal());
+
+  trial2->AppendGroup("a first group", 7);
+
+  EXPECT_EQ(trial1.get(), FieldTrialList::Find(name1));
+  EXPECT_EQ(trial2.get(), FieldTrialList::Find(name2));
+  // Note: FieldTrialList should delete the objects at shutdown.
+}
+
+TEST_F(FieldTrialTest, AbsoluteProbabilities) {
+  char always_true[] = " always true";
+  char default_always_true[] = " default always true";
+  char always_false[] = " always false";
+  char default_always_false[] = " default always false";
+  for (int i = 1; i < 250; ++i) {
+    // Try lots of names, by changing the first character of the name.
+    char c = static_cast<char>(i);
+    always_true[0] = c;
+    default_always_true[0] = c;
+    always_false[0] = c;
+    default_always_false[0] = c;
+
+    scoped_refptr<FieldTrial> trial_true =
+        CreateFieldTrial(always_true, 10, default_always_true, NULL);
+    const std::string winner = "TheWinner";
+    int winner_group = trial_true->AppendGroup(winner, 10);
+
+    EXPECT_EQ(winner_group, trial_true->group());
+    EXPECT_EQ(winner, trial_true->group_name());
+
+    scoped_refptr<FieldTrial> trial_false =
+        CreateFieldTrial(always_false, 10, default_always_false, NULL);
+    int loser_group = trial_false->AppendGroup("ALoser", 0);
+
+    EXPECT_NE(loser_group, trial_false->group());
+  }
+}
+
+TEST_F(FieldTrialTest, RemainingProbability) {
+  // First create a test that hasn't had a winner yet.
+  const std::string winner = "Winner";
+  const std::string loser = "Loser";
+  scoped_refptr<FieldTrial> trial;
+  int counter = 0;
+  int default_group_number = -1;
+  do {
+    std::string name = StringPrintf("trial%d", ++counter);
+    trial = CreateFieldTrial(name, 10, winner, &default_group_number);
+    trial->AppendGroup(loser, 5);  // 50% chance of not being chosen.
+    // If a group is not assigned, group_ will be kNotFinalized.
+  } while (trial->group_ != FieldTrial::kNotFinalized);
+
+  // And that 'default' group (winner) should always win.
+  EXPECT_EQ(default_group_number, trial->group());
+
+  // And that winner should ALWAYS win.
+  EXPECT_EQ(winner, trial->group_name());
+}
+
+TEST_F(FieldTrialTest, FiftyFiftyProbability) {
+  // Check that even with small divisors, we have the proper probabilities, and
+  // all outcomes are possible.  Since this is a 50-50 test, it should get both
+  // outcomes in a few tries, but we'll try no more than 100 times (and be flaky
+  // with probability around 1 in 2^99).
+  bool first_winner = false;
+  bool second_winner = false;
+  int counter = 0;
+  do {
+    std::string name = base::StringPrintf("FiftyFifty%d", ++counter);
+    std::string default_group_name = base::StringPrintf("Default FiftyFifty%d",
+                                                        ++counter);
+    scoped_refptr<FieldTrial> trial =
+        CreateFieldTrial(name, 2, default_group_name, NULL);
+    trial->AppendGroup("first", 1);  // 50% chance of being chosen.
+    // If group_ is kNotFinalized, then a group assignement hasn't been done.
+    if (trial->group_ != FieldTrial::kNotFinalized) {
+      first_winner = true;
+      continue;
+    }
+    trial->AppendGroup("second", 1);  // Always chosen at this point.
+    EXPECT_NE(FieldTrial::kNotFinalized, trial->group());
+    second_winner = true;
+  } while ((!second_winner || !first_winner) && counter < 100);
+  EXPECT_TRUE(second_winner);
+  EXPECT_TRUE(first_winner);
+}
+
+TEST_F(FieldTrialTest, MiddleProbabilities) {
+  char name[] = " same name";
+  char default_group_name[] = " default same name";
+  bool false_event_seen = false;
+  bool true_event_seen = false;
+  for (int i = 1; i < 250; ++i) {
+    char c = static_cast<char>(i);
+    name[0] = c;
+    default_group_name[0] = c;
+    scoped_refptr<FieldTrial> trial =
+        CreateFieldTrial(name, 10, default_group_name, NULL);
+    int might_win = trial->AppendGroup("MightWin", 5);
+
+    if (trial->group() == might_win) {
+      true_event_seen = true;
+    } else {
+      false_event_seen = true;
+    }
+    if (false_event_seen && true_event_seen)
+      return;  // Successful test!!!
+  }
+  // Very surprising to get here. Probability should be around 1 in 2 ** 250.
+  // One of the following will fail.
+  EXPECT_TRUE(false_event_seen);
+  EXPECT_TRUE(true_event_seen);
+}
+
+TEST_F(FieldTrialTest, OneWinner) {
+  char name[] = "Some name";
+  char default_group_name[] = "Default some name";
+  int group_count(10);
+
+  int default_group_number = -1;
+  scoped_refptr<FieldTrial> trial =
+      CreateFieldTrial(name, group_count, default_group_name, NULL);
+  int winner_index(-2);
+  std::string winner_name;
+
+  for (int i = 1; i <= group_count; ++i) {
+    int might_win = trial->AppendGroup(std::string(), 1);
+
+    // Because we keep appending groups, we want to see if the last group that
+    // was added has been assigned or not.
+    if (trial->group_ == might_win) {
+      EXPECT_EQ(-2, winner_index);
+      winner_index = might_win;
+      StringAppendF(&winner_name, "%d", might_win);
+      EXPECT_EQ(winner_name, trial->group_name());
+    }
+  }
+  EXPECT_GE(winner_index, 0);
+  // Since all groups cover the total probability, we should not have
+  // chosen the default group.
+  EXPECT_NE(trial->group(), default_group_number);
+  EXPECT_EQ(trial->group(), winner_index);
+  EXPECT_EQ(trial->group_name(), winner_name);
+}
+
+TEST_F(FieldTrialTest, DisableProbability) {
+  const std::string default_group_name = "Default group";
+  const std::string loser = "Loser";
+  const std::string name = "Trial";
+
+  // Create a field trail that has expired.
+  int default_group_number = -1;
+  FieldTrial* trial = FieldTrialList::FactoryGetFieldTrial(
+      name, 1000000000, default_group_name, OneYearBeforeBuildTime(), 1, 1,
+      FieldTrial::SESSION_RANDOMIZED,
+      &default_group_number);
+  trial->AppendGroup(loser, 999999999);  // 99.9999999% chance of being chosen.
+
+  // Because trial has expired, we should always be in the default group.
+  EXPECT_EQ(default_group_number, trial->group());
+
+  // And that default_group_name should ALWAYS win.
+  EXPECT_EQ(default_group_name, trial->group_name());
+}
+
+TEST_F(FieldTrialTest, ActiveGroups) {
+  std::string no_group("No Group");
+  scoped_refptr<FieldTrial> trial =
+      CreateFieldTrial(no_group, 10, "Default", NULL);
+
+  // There is no winner yet, so no NameGroupId should be returned.
+  FieldTrial::ActiveGroup active_group;
+  EXPECT_FALSE(trial->GetActiveGroup(&active_group));
+
+  // Create a single winning group.
+  std::string one_winner("One Winner");
+  trial = CreateFieldTrial(one_winner, 10, "Default", NULL);
+  std::string winner("Winner");
+  trial->AppendGroup(winner, 10);
+  EXPECT_FALSE(trial->GetActiveGroup(&active_group));
+  // Finalize the group selection by accessing the selected group.
+  trial->group();
+  EXPECT_TRUE(trial->GetActiveGroup(&active_group));
+  EXPECT_EQ(one_winner, active_group.trial_name);
+  EXPECT_EQ(winner, active_group.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_FALSE(multi_group_trial->GetActiveGroup(&active_group));
+  // Finalize the group selection by accessing the selected group.
+  multi_group_trial->group();
+  EXPECT_TRUE(multi_group_trial->GetActiveGroup(&active_group));
+  EXPECT_EQ(multi_group, active_group.trial_name);
+  EXPECT_EQ(multi_group_trial->group_name(), active_group.group_name);
+
+  // Now check if the list is built properly...
+  FieldTrial::ActiveGroups active_groups;
+  FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
+  EXPECT_EQ(2U, active_groups.size());
+  for (size_t i = 0; i < active_groups.size(); ++i) {
+    // Order is not guaranteed, so check all values.
+    EXPECT_NE(no_group, active_groups[i].trial_name);
+    EXPECT_TRUE(one_winner != active_groups[i].trial_name ||
+                winner == active_groups[i].group_name);
+    EXPECT_TRUE(multi_group != active_groups[i].trial_name ||
+                multi_group_trial->group_name() == active_groups[i].group_name);
+  }
+}
+
+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";
+
+  int default_group = -1;
+  scoped_refptr<FieldTrial> trial =
+      CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
+  const int secondary_group = trial->AppendGroup(kSecondaryGroupName, 50);
+
+  // Before |group()| is called, |GetActiveGroup()| should return false.
+  FieldTrial::ActiveGroup active_group;
+  EXPECT_FALSE(trial->GetActiveGroup(&active_group));
+
+  // |GetActiveFieldTrialGroups()| should also not include the trial.
+  FieldTrial::ActiveGroups active_groups;
+  FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
+  EXPECT_TRUE(active_groups.empty());
+
+  // After |group()| has been called, both APIs should succeed.
+  const int chosen_group = trial->group();
+  EXPECT_TRUE(chosen_group == default_group || chosen_group == secondary_group);
+
+  EXPECT_TRUE(trial->GetActiveGroup(&active_group));
+  EXPECT_EQ(kTrialName, active_group.trial_name);
+  if (chosen_group == default_group)
+    EXPECT_EQ(kDefaultGroupName, active_group.group_name);
+  else
+    EXPECT_EQ(kSecondaryGroupName, active_group.group_name);
+
+  FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
+  ASSERT_EQ(1U, active_groups.size());
+  EXPECT_EQ(kTrialName, active_groups[0].trial_name);
+  EXPECT_EQ(active_group.group_name, active_groups[0].group_name);
+}
+
+TEST_F(FieldTrialTest, Save) {
+  std::string save_string;
+
+  scoped_refptr<FieldTrial> trial =
+      CreateFieldTrial("Some name", 10, "Default some name", NULL);
+  // There is no winner yet, so no textual group name is associated with trial.
+  // In this case, the trial should not be included.
+  EXPECT_EQ("", trial->group_name_internal());
+  FieldTrialList::StatesToString(&save_string);
+  EXPECT_EQ("", 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::StatesToString(&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::StatesToString(&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);
+  // Finalize the group selection by accessing the selected group.
+  trial3->group();
+
+  FieldTrialList::StatesToString(&save_string);
+  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"));
+
+  FieldTrialList::CreateTrialsFromString("Some_name/Winner/xxx/yyyy/",
+                                         FieldTrialList::DONT_ACTIVATE_TRIALS,
+                                         std::set<std::string>());
+
+  FieldTrial* trial = FieldTrialList::Find("Some_name");
+  ASSERT_NE(static_cast<FieldTrial*>(NULL), trial);
+  EXPECT_EQ("Winner", trial->group_name());
+  EXPECT_EQ("Some_name", trial->trial_name());
+
+  trial = FieldTrialList::Find("xxx");
+  ASSERT_NE(static_cast<FieldTrial*>(NULL), trial);
+  EXPECT_EQ("yyyy", trial->group_name());
+  EXPECT_EQ("xxx", trial->trial_name());
+}
+
+TEST_F(FieldTrialTest, RestoreNotEndingWithSlash) {
+  EXPECT_TRUE(FieldTrialList::CreateTrialsFromString(
+      "tname/gname", FieldTrialList::DONT_ACTIVATE_TRIALS,
+      std::set<std::string>()));
+
+  FieldTrial* trial = FieldTrialList::Find("tname");
+  ASSERT_NE(static_cast<FieldTrial*>(NULL), trial);
+  EXPECT_EQ("gname", trial->group_name());
+  EXPECT_EQ("tname", trial->trial_name());
+}
+
+TEST_F(FieldTrialTest, BogusRestore) {
+  EXPECT_FALSE(FieldTrialList::CreateTrialsFromString(
+      "MissingSlash", FieldTrialList::DONT_ACTIVATE_TRIALS,
+      std::set<std::string>()));
+  EXPECT_FALSE(FieldTrialList::CreateTrialsFromString(
+      "MissingGroupName/", FieldTrialList::DONT_ACTIVATE_TRIALS,
+      std::set<std::string>()));
+  EXPECT_FALSE(FieldTrialList::CreateTrialsFromString(
+      "noname, only group/", FieldTrialList::DONT_ACTIVATE_TRIALS,
+      std::set<std::string>()));
+  EXPECT_FALSE(FieldTrialList::CreateTrialsFromString(
+      "/emptyname", FieldTrialList::DONT_ACTIVATE_TRIALS,
+      std::set<std::string>()));
+  EXPECT_FALSE(FieldTrialList::CreateTrialsFromString(
+      "*/emptyname", FieldTrialList::DONT_ACTIVATE_TRIALS,
+      std::set<std::string>()));
+}
+
+TEST_F(FieldTrialTest, DuplicateRestore) {
+  scoped_refptr<FieldTrial> trial =
+      CreateFieldTrial("Some name", 10, "Default", NULL);
+  trial->AppendGroup("Winner", 10);
+  // Finalize the group selection by accessing the selected group.
+  trial->group();
+  std::string save_string;
+  FieldTrialList::StatesToString(&save_string);
+  EXPECT_EQ("Some name/Winner/", save_string);
+
+  // It is OK if we redundantly specify a winner.
+  EXPECT_TRUE(FieldTrialList::CreateTrialsFromString(
+      save_string, FieldTrialList::DONT_ACTIVATE_TRIALS,
+      std::set<std::string>()));
+
+  // But it is an error to try to change to a different winner.
+  EXPECT_FALSE(FieldTrialList::CreateTrialsFromString(
+      "Some name/Loser/", FieldTrialList::DONT_ACTIVATE_TRIALS,
+      std::set<std::string>()));
+}
+
+TEST_F(FieldTrialTest, CreateTrialsFromStringActive) {
+  ASSERT_FALSE(FieldTrialList::TrialExists("Abc"));
+  ASSERT_FALSE(FieldTrialList::TrialExists("Xyz"));
+  ASSERT_TRUE(FieldTrialList::CreateTrialsFromString(
+      "Abc/def/Xyz/zyx/", FieldTrialList::ACTIVATE_TRIALS,
+      std::set<std::string>()));
+
+  FieldTrial::ActiveGroups active_groups;
+  FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
+  ASSERT_EQ(2U, active_groups.size());
+  EXPECT_EQ("Abc", active_groups[0].trial_name);
+  EXPECT_EQ("def", active_groups[0].group_name);
+  EXPECT_EQ("Xyz", active_groups[1].trial_name);
+  EXPECT_EQ("zyx", active_groups[1].group_name);
+}
+
+TEST_F(FieldTrialTest, CreateTrialsFromStringNotActive) {
+  ASSERT_FALSE(FieldTrialList::TrialExists("Abc"));
+  ASSERT_FALSE(FieldTrialList::TrialExists("Xyz"));
+  ASSERT_TRUE(FieldTrialList::CreateTrialsFromString(
+      "Abc/def/Xyz/zyx/", FieldTrialList::DONT_ACTIVATE_TRIALS,
+      std::set<std::string>()));
+
+  FieldTrial::ActiveGroups active_groups;
+  FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
+  ASSERT_TRUE(active_groups.empty());
+
+  // Check that the values still get returned and querying them activates them.
+  EXPECT_EQ("def", FieldTrialList::FindFullName("Abc"));
+  EXPECT_EQ("zyx", FieldTrialList::FindFullName("Xyz"));
+
+  FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
+  ASSERT_EQ(2U, active_groups.size());
+  EXPECT_EQ("Abc", active_groups[0].trial_name);
+  EXPECT_EQ("def", active_groups[0].group_name);
+  EXPECT_EQ("Xyz", active_groups[1].trial_name);
+  EXPECT_EQ("zyx", active_groups[1].group_name);
+}
+
+TEST_F(FieldTrialTest, CreateTrialsFromStringForceActivation) {
+  ASSERT_FALSE(FieldTrialList::TrialExists("Abc"));
+  ASSERT_FALSE(FieldTrialList::TrialExists("def"));
+  ASSERT_FALSE(FieldTrialList::TrialExists("Xyz"));
+  ASSERT_TRUE(FieldTrialList::CreateTrialsFromString(
+      "*Abc/cba/def/fed/*Xyz/zyx/", FieldTrialList::DONT_ACTIVATE_TRIALS,
+      std::set<std::string>()));
+
+  FieldTrial::ActiveGroups active_groups;
+  FieldTrialList::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);
+}
+
+TEST_F(FieldTrialTest, CreateTrialsFromStringActiveObserver) {
+  ASSERT_FALSE(FieldTrialList::TrialExists("Abc"));
+
+  TestFieldTrialObserver observer;
+  ASSERT_TRUE(FieldTrialList::CreateTrialsFromString(
+      "Abc/def/", FieldTrialList::ACTIVATE_TRIALS, std::set<std::string>()));
+
+  RunLoop().RunUntilIdle();
+  EXPECT_EQ("Abc", observer.trial_name());
+  EXPECT_EQ("def", observer.group_name());
+}
+
+TEST_F(FieldTrialTest, CreateTrialsFromStringNotActiveObserver) {
+  ASSERT_FALSE(FieldTrialList::TrialExists("Abc"));
+
+  TestFieldTrialObserver observer;
+  ASSERT_TRUE(FieldTrialList::CreateTrialsFromString(
+      "Abc/def/", FieldTrialList::DONT_ACTIVATE_TRIALS,
+      std::set<std::string>()));
+  RunLoop().RunUntilIdle();
+  // Observer shouldn't be notified.
+  EXPECT_TRUE(observer.trial_name().empty());
+
+  // Check that the values still get returned and querying them activates them.
+  EXPECT_EQ("def", FieldTrialList::FindFullName("Abc"));
+
+  RunLoop().RunUntilIdle();
+  EXPECT_EQ("Abc", observer.trial_name());
+  EXPECT_EQ("def", observer.group_name());
+}
+
+TEST_F(FieldTrialTest, CreateTrialsFromStringWithIgnoredFieldTrials) {
+  ASSERT_FALSE(FieldTrialList::TrialExists("Unaccepted1"));
+  ASSERT_FALSE(FieldTrialList::TrialExists("Foo"));
+  ASSERT_FALSE(FieldTrialList::TrialExists("Unaccepted2"));
+  ASSERT_FALSE(FieldTrialList::TrialExists("Bar"));
+  ASSERT_FALSE(FieldTrialList::TrialExists("Unaccepted3"));
+
+  std::set<std::string> ignored_trial_names;
+  ignored_trial_names.insert("Unaccepted1");
+  ignored_trial_names.insert("Unaccepted2");
+  ignored_trial_names.insert("Unaccepted3");
+
+  FieldTrialList::CreateTrialsFromString(
+      "Unaccepted1/Unaccepted1_name/"
+      "Foo/Foo_name/"
+      "Unaccepted2/Unaccepted2_name/"
+      "Bar/Bar_name/"
+      "Unaccepted3/Unaccepted3_name/",
+      FieldTrialList::DONT_ACTIVATE_TRIALS,
+      ignored_trial_names);
+
+  EXPECT_FALSE(FieldTrialList::TrialExists("Unaccepted1"));
+  EXPECT_TRUE(FieldTrialList::TrialExists("Foo"));
+  EXPECT_FALSE(FieldTrialList::TrialExists("Unaccepted2"));
+  EXPECT_TRUE(FieldTrialList::TrialExists("Bar"));
+  EXPECT_FALSE(FieldTrialList::TrialExists("Unaccepted3"));
+
+  FieldTrial::ActiveGroups active_groups;
+  FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
+  EXPECT_TRUE(active_groups.empty());
+
+  FieldTrial* trial = FieldTrialList::Find("Foo");
+  ASSERT_NE(static_cast<FieldTrial*>(NULL), trial);
+  EXPECT_EQ("Foo", trial->trial_name());
+  EXPECT_EQ("Foo_name", trial->group_name());
+
+  trial = FieldTrialList::Find("Bar");
+  ASSERT_NE(static_cast<FieldTrial*>(NULL), trial);
+  EXPECT_EQ("Bar", trial->trial_name());
+  EXPECT_EQ("Bar_name", trial->group_name());
+}
+
+TEST_F(FieldTrialTest, CreateFieldTrial) {
+  ASSERT_FALSE(FieldTrialList::TrialExists("Some_name"));
+
+  FieldTrialList::CreateFieldTrial("Some_name", "Winner");
+
+  FieldTrial* trial = FieldTrialList::Find("Some_name");
+  ASSERT_NE(static_cast<FieldTrial*>(NULL), trial);
+  EXPECT_EQ("Winner", trial->group_name());
+  EXPECT_EQ("Some_name", trial->trial_name());
+}
+
+TEST_F(FieldTrialTest, CreateFieldTrialIsNotActive) {
+  const char kTrialName[] = "CreateFieldTrialIsActiveTrial";
+  const char kWinnerGroup[] = "Winner";
+  ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
+  FieldTrialList::CreateFieldTrial(kTrialName, kWinnerGroup);
+
+  FieldTrial::ActiveGroups active_groups;
+  FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
+  EXPECT_TRUE(active_groups.empty());
+}
+
+TEST_F(FieldTrialTest, DuplicateFieldTrial) {
+  scoped_refptr<FieldTrial> trial =
+      CreateFieldTrial("Some_name", 10, "Default", NULL);
+  trial->AppendGroup("Winner", 10);
+
+  // It is OK if we redundantly specify a winner.
+  FieldTrial* trial1 = FieldTrialList::CreateFieldTrial("Some_name", "Winner");
+  EXPECT_TRUE(trial1 != NULL);
+
+  // But it is an error to try to change to a different winner.
+  FieldTrial* trial2 = FieldTrialList::CreateFieldTrial("Some_name", "Loser");
+  EXPECT_TRUE(trial2 == NULL);
+}
+
+TEST_F(FieldTrialTest, DisableImmediately) {
+  int default_group_number = -1;
+  scoped_refptr<FieldTrial> trial =
+      CreateFieldTrial("trial", 100, "default", &default_group_number);
+  trial->Disable();
+  ASSERT_EQ("default", trial->group_name());
+  ASSERT_EQ(default_group_number, trial->group());
+}
+
+TEST_F(FieldTrialTest, DisableAfterInitialization) {
+  scoped_refptr<FieldTrial> trial =
+      CreateFieldTrial("trial", 100, "default", NULL);
+  trial->AppendGroup("non_default", 100);
+  trial->Disable();
+  ASSERT_EQ("default", trial->group_name());
+}
+
+TEST_F(FieldTrialTest, ForcedFieldTrials) {
+  // Validate we keep the forced choice.
+  FieldTrial* forced_trial = FieldTrialList::CreateFieldTrial("Use the",
+                                                              "Force");
+  EXPECT_STREQ("Force", forced_trial->group_name().c_str());
+
+  int default_group_number = -1;
+  scoped_refptr<FieldTrial> factory_trial =
+      CreateFieldTrial("Use the", 1000, "default", &default_group_number);
+  EXPECT_EQ(factory_trial.get(), forced_trial);
+
+  int chosen_group = factory_trial->AppendGroup("Force", 100);
+  EXPECT_EQ(chosen_group, factory_trial->group());
+  int not_chosen_group = factory_trial->AppendGroup("Dark Side", 100);
+  EXPECT_NE(chosen_group, not_chosen_group);
+
+  // Since we didn't force the default group, we should not be returned the
+  // chosen group as the default group.
+  EXPECT_NE(default_group_number, chosen_group);
+  int new_group = factory_trial->AppendGroup("Duck Tape", 800);
+  EXPECT_NE(chosen_group, new_group);
+  // The new group should not be the default group either.
+  EXPECT_NE(default_group_number, new_group);
+}
+
+TEST_F(FieldTrialTest, ForcedFieldTrialsDefaultGroup) {
+  // Forcing the default should use the proper group ID.
+  FieldTrial* forced_trial = FieldTrialList::CreateFieldTrial("Trial Name",
+                                                              "Default");
+  int default_group_number = -1;
+  scoped_refptr<FieldTrial> factory_trial =
+      CreateFieldTrial("Trial Name", 1000, "Default", &default_group_number);
+  EXPECT_EQ(forced_trial, factory_trial.get());
+
+  int other_group = factory_trial->AppendGroup("Not Default", 100);
+  EXPECT_STREQ("Default", factory_trial->group_name().c_str());
+  EXPECT_EQ(default_group_number, factory_trial->group());
+  EXPECT_NE(other_group, factory_trial->group());
+
+  int new_other_group = factory_trial->AppendGroup("Not Default Either", 800);
+  EXPECT_NE(new_other_group, factory_trial->group());
+}
+
+TEST_F(FieldTrialTest, SetForced) {
+  // Start by setting a trial for which we ensure a winner...
+  int default_group_number = -1;
+  scoped_refptr<FieldTrial> forced_trial =
+      CreateFieldTrial("Use the", 1, "default", &default_group_number);
+  EXPECT_EQ(forced_trial, forced_trial);
+
+  int forced_group = forced_trial->AppendGroup("Force", 1);
+  EXPECT_EQ(forced_group, forced_trial->group());
+
+  // Now force it.
+  forced_trial->SetForced();
+
+  // Now try to set it up differently as a hard coded registration would.
+  scoped_refptr<FieldTrial> hard_coded_trial =
+      CreateFieldTrial("Use the", 1, "default", &default_group_number);
+  EXPECT_EQ(hard_coded_trial, forced_trial);
+
+  int would_lose_group = hard_coded_trial->AppendGroup("Force", 0);
+  EXPECT_EQ(forced_group, hard_coded_trial->group());
+  EXPECT_EQ(forced_group, would_lose_group);
+
+  // Same thing if we would have done it to win again.
+  scoped_refptr<FieldTrial> other_hard_coded_trial =
+      CreateFieldTrial("Use the", 1, "default", &default_group_number);
+  EXPECT_EQ(other_hard_coded_trial, forced_trial);
+
+  int would_win_group = other_hard_coded_trial->AppendGroup("Force", 1);
+  EXPECT_EQ(forced_group, other_hard_coded_trial->group());
+  EXPECT_EQ(forced_group, would_win_group);
+}
+
+TEST_F(FieldTrialTest, SetForcedDefaultOnly) {
+  const char kTrialName[] = "SetForcedDefaultOnly";
+  ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
+
+  int default_group = -1;
+  scoped_refptr<FieldTrial> trial =
+      CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
+  trial->SetForced();
+
+  trial = CreateFieldTrial(kTrialName, 100, kDefaultGroupName, NULL);
+  EXPECT_EQ(default_group, trial->group());
+  EXPECT_EQ(kDefaultGroupName, trial->group_name());
+}
+
+TEST_F(FieldTrialTest, SetForcedDefaultWithExtraGroup) {
+  const char kTrialName[] = "SetForcedDefaultWithExtraGroup";
+  ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
+
+  int default_group = -1;
+  scoped_refptr<FieldTrial> trial =
+      CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
+  trial->SetForced();
+
+  trial = CreateFieldTrial(kTrialName, 100, kDefaultGroupName, NULL);
+  const int extra_group = trial->AppendGroup("Extra", 100);
+  EXPECT_EQ(default_group, trial->group());
+  EXPECT_NE(extra_group, trial->group());
+  EXPECT_EQ(kDefaultGroupName, trial->group_name());
+}
+
+TEST_F(FieldTrialTest, SetForcedTurnFeatureOn) {
+  const char kTrialName[] = "SetForcedTurnFeatureOn";
+  const char kExtraGroupName[] = "Extra";
+  ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
+
+  // Simulate a server-side (forced) config that turns the feature on when the
+  // original hard-coded config had it disabled.
+  scoped_refptr<FieldTrial> forced_trial =
+      CreateFieldTrial(kTrialName, 100, kDefaultGroupName, NULL);
+  forced_trial->AppendGroup(kExtraGroupName, 100);
+  forced_trial->SetForced();
+
+  int default_group = -1;
+  scoped_refptr<FieldTrial> client_trial =
+      CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
+  const int extra_group = client_trial->AppendGroup(kExtraGroupName, 0);
+  EXPECT_NE(default_group, extra_group);
+
+  EXPECT_FALSE(client_trial->group_reported_);
+  EXPECT_EQ(extra_group, client_trial->group());
+  EXPECT_TRUE(client_trial->group_reported_);
+  EXPECT_EQ(kExtraGroupName, client_trial->group_name());
+}
+
+TEST_F(FieldTrialTest, SetForcedTurnFeatureOff) {
+  const char kTrialName[] = "SetForcedTurnFeatureOff";
+  const char kExtraGroupName[] = "Extra";
+  ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
+
+  // Simulate a server-side (forced) config that turns the feature off when the
+  // original hard-coded config had it enabled.
+  scoped_refptr<FieldTrial> forced_trial =
+      CreateFieldTrial(kTrialName, 100, kDefaultGroupName, NULL);
+  forced_trial->AppendGroup(kExtraGroupName, 0);
+  forced_trial->SetForced();
+
+  int default_group = -1;
+  scoped_refptr<FieldTrial> client_trial =
+      CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
+  const int extra_group = client_trial->AppendGroup(kExtraGroupName, 100);
+  EXPECT_NE(default_group, extra_group);
+
+  EXPECT_FALSE(client_trial->group_reported_);
+  EXPECT_EQ(default_group, client_trial->group());
+  EXPECT_TRUE(client_trial->group_reported_);
+  EXPECT_EQ(kDefaultGroupName, client_trial->group_name());
+}
+
+TEST_F(FieldTrialTest, SetForcedChangeDefault_Default) {
+  const char kTrialName[] = "SetForcedDefaultGroupChange";
+  const char kGroupAName[] = "A";
+  const char kGroupBName[] = "B";
+  ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
+
+  // Simulate a server-side (forced) config that switches which group is default
+  // and ensures that the non-forced code receives the correct group numbers.
+  scoped_refptr<FieldTrial> forced_trial =
+      CreateFieldTrial(kTrialName, 100, kGroupAName, NULL);
+  forced_trial->AppendGroup(kGroupBName, 100);
+  forced_trial->SetForced();
+
+  int default_group = -1;
+  scoped_refptr<FieldTrial> client_trial =
+      CreateFieldTrial(kTrialName, 100, kGroupBName, &default_group);
+  const int extra_group = client_trial->AppendGroup(kGroupAName, 50);
+  EXPECT_NE(default_group, extra_group);
+
+  EXPECT_FALSE(client_trial->group_reported_);
+  EXPECT_EQ(default_group, client_trial->group());
+  EXPECT_TRUE(client_trial->group_reported_);
+  EXPECT_EQ(kGroupBName, client_trial->group_name());
+}
+
+TEST_F(FieldTrialTest, SetForcedChangeDefault_NonDefault) {
+  const char kTrialName[] = "SetForcedDefaultGroupChange";
+  const char kGroupAName[] = "A";
+  const char kGroupBName[] = "B";
+  ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
+
+  // Simulate a server-side (forced) config that switches which group is default
+  // and ensures that the non-forced code receives the correct group numbers.
+  scoped_refptr<FieldTrial> forced_trial =
+      CreateFieldTrial(kTrialName, 100, kGroupAName, NULL);
+  forced_trial->AppendGroup(kGroupBName, 0);
+  forced_trial->SetForced();
+
+  int default_group = -1;
+  scoped_refptr<FieldTrial> client_trial =
+      CreateFieldTrial(kTrialName, 100, kGroupBName, &default_group);
+  const int extra_group = client_trial->AppendGroup(kGroupAName, 50);
+  EXPECT_NE(default_group, extra_group);
+
+  EXPECT_FALSE(client_trial->group_reported_);
+  EXPECT_EQ(extra_group, client_trial->group());
+  EXPECT_TRUE(client_trial->group_reported_);
+  EXPECT_EQ(kGroupAName, client_trial->group_name());
+}
+
+TEST_F(FieldTrialTest, Observe) {
+  const char kTrialName[] = "TrialToObserve1";
+  const char kSecondaryGroupName[] = "SecondaryGroup";
+
+  TestFieldTrialObserver observer;
+  int default_group = -1;
+  scoped_refptr<FieldTrial> trial =
+      CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
+  const int secondary_group = trial->AppendGroup(kSecondaryGroupName, 50);
+  const int chosen_group = trial->group();
+  EXPECT_TRUE(chosen_group == default_group || chosen_group == secondary_group);
+
+  RunLoop().RunUntilIdle();
+  EXPECT_EQ(kTrialName, observer.trial_name());
+  if (chosen_group == default_group)
+    EXPECT_EQ(kDefaultGroupName, observer.group_name());
+  else
+    EXPECT_EQ(kSecondaryGroupName, observer.group_name());
+}
+
+TEST_F(FieldTrialTest, ObserveDisabled) {
+  const char kTrialName[] = "TrialToObserve2";
+
+  TestFieldTrialObserver observer;
+  int default_group = -1;
+  scoped_refptr<FieldTrial> trial =
+      CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
+  trial->AppendGroup("A", 25);
+  trial->AppendGroup("B", 25);
+  trial->AppendGroup("C", 25);
+  trial->Disable();
+
+  // Observer shouldn't be notified of a disabled trial.
+  RunLoop().RunUntilIdle();
+  EXPECT_TRUE(observer.trial_name().empty());
+  EXPECT_TRUE(observer.group_name().empty());
+
+  // Observer shouldn't be notified even after a |group()| call.
+  EXPECT_EQ(default_group, trial->group());
+  RunLoop().RunUntilIdle();
+  EXPECT_TRUE(observer.trial_name().empty());
+  EXPECT_TRUE(observer.group_name().empty());
+}
+
+TEST_F(FieldTrialTest, ObserveForcedDisabled) {
+  const char kTrialName[] = "TrialToObserve3";
+
+  TestFieldTrialObserver observer;
+  int default_group = -1;
+  scoped_refptr<FieldTrial> trial =
+      CreateFieldTrial(kTrialName, 100, kDefaultGroupName, &default_group);
+  trial->AppendGroup("A", 25);
+  trial->AppendGroup("B", 25);
+  trial->AppendGroup("C", 25);
+  trial->SetForced();
+  trial->Disable();
+
+  // Observer shouldn't be notified of a disabled trial, even when forced.
+  RunLoop().RunUntilIdle();
+  EXPECT_TRUE(observer.trial_name().empty());
+  EXPECT_TRUE(observer.group_name().empty());
+
+  // Observer shouldn't be notified even after a |group()| call.
+  EXPECT_EQ(default_group, trial->group());
+  RunLoop().RunUntilIdle();
+  EXPECT_TRUE(observer.trial_name().empty());
+  EXPECT_TRUE(observer.group_name().empty());
+}
+
+TEST_F(FieldTrialTest, DisabledTrialNotActive) {
+  const char kTrialName[] = "DisabledTrial";
+  ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
+
+  scoped_refptr<FieldTrial> trial =
+      CreateFieldTrial(kTrialName, 100, kDefaultGroupName, NULL);
+  trial->AppendGroup("X", 50);
+  trial->Disable();
+
+  // Ensure the trial is not listed as active.
+  FieldTrial::ActiveGroups active_groups;
+  FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
+  EXPECT_TRUE(active_groups.empty());
+
+  // Ensure the trial is not listed in the |StatesToString()| result.
+  std::string states;
+  FieldTrialList::StatesToString(&states);
+  EXPECT_TRUE(states.empty());
+}
+
+TEST_F(FieldTrialTest, ExpirationYearNotExpired) {
+  const char kTrialName[] = "NotExpired";
+  const char kGroupName[] = "Group2";
+  const int kProbability = 100;
+  ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
+
+  scoped_refptr<FieldTrial> trial =
+      CreateFieldTrial(kTrialName, kProbability, kDefaultGroupName, NULL);
+  trial->AppendGroup(kGroupName, kProbability);
+  EXPECT_EQ(kGroupName, trial->group_name());
+}
+
+TEST_F(FieldTrialTest, FloatBoundariesGiveEqualGroupSizes) {
+  const int kBucketCount = 100;
+
+  // Try each boundary value |i / 100.0| as the entropy value.
+  for (int i = 0; i < kBucketCount; ++i) {
+    const double entropy = i / static_cast<double>(kBucketCount);
+
+    scoped_refptr<base::FieldTrial> trial(
+        new base::FieldTrial("test", kBucketCount, "default", entropy));
+    for (int j = 0; j < kBucketCount; ++j)
+      trial->AppendGroup(base::StringPrintf("%d", j), 1);
+
+    EXPECT_EQ(base::StringPrintf("%d", i), trial->group_name());
+  }
+}
+
+TEST_F(FieldTrialTest, DoesNotSurpassTotalProbability) {
+  const double kEntropyValue = 1.0 - 1e-9;
+  ASSERT_LT(kEntropyValue, 1.0);
+
+  scoped_refptr<base::FieldTrial> trial(
+      new base::FieldTrial("test", 2, "default", kEntropyValue));
+  trial->AppendGroup("1", 1);
+  trial->AppendGroup("2", 1);
+
+  EXPECT_EQ("2", trial->group_name());
+}
+
+TEST_F(FieldTrialTest, CreateSimulatedFieldTrial) {
+  const char kTrialName[] = "CreateSimulatedFieldTrial";
+  ASSERT_FALSE(FieldTrialList::TrialExists(kTrialName));
+
+  // Different cases to test, e.g. default vs. non default group being chosen.
+  struct {
+    double entropy_value;
+    const char* expected_group;
+  } test_cases[] = {
+    { 0.4, "A" },
+    { 0.85, "B" },
+    { 0.95, kDefaultGroupName },
+  };
+
+  for (size_t i = 0; i < arraysize(test_cases); ++i) {
+    TestFieldTrialObserver observer;
+    scoped_refptr<FieldTrial> trial(
+       FieldTrial::CreateSimulatedFieldTrial(kTrialName, 100, kDefaultGroupName,
+                                             test_cases[i].entropy_value));
+    trial->AppendGroup("A", 80);
+    trial->AppendGroup("B", 10);
+    EXPECT_EQ(test_cases[i].expected_group, trial->group_name());
+
+    // Field trial shouldn't have been registered with the list.
+    EXPECT_FALSE(FieldTrialList::TrialExists(kTrialName));
+    EXPECT_EQ(0u, FieldTrialList::GetFieldTrialCount());
+
+    // Observer shouldn't have been notified.
+    RunLoop().RunUntilIdle();
+    EXPECT_TRUE(observer.trial_name().empty());
+
+    // The trial shouldn't be in the active set of trials.
+    FieldTrial::ActiveGroups active_groups;
+    FieldTrialList::GetActiveFieldTrialGroups(&active_groups);
+    EXPECT_TRUE(active_groups.empty());
+
+    // The trial shouldn't be listed in the |StatesToString()| result.
+    std::string states;
+    FieldTrialList::StatesToString(&states);
+    EXPECT_TRUE(states.empty());
+  }
+}
+
+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
+  // FieldTrialList is created should crash.
+  EXPECT_DEATH(FieldTrialList::FactoryGetFieldTrial(
+      "OneTimeRandomizedTrialWithoutFieldTrialList", 100, kDefaultGroupName,
+      base::FieldTrialList::kNoExpirationYear, 1, 1,
+      base::FieldTrial::ONE_TIME_RANDOMIZED, NULL), "");
+}
+#endif
+
+}  // namespace base
diff --git a/base/metrics/histogram.cc b/base/metrics/histogram.cc
new file mode 100644
index 0000000..1550420
--- /dev/null
+++ b/base/metrics/histogram.cc
@@ -0,0 +1,845 @@
+// Copyright (c) 2012 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.
+
+// Histogram is an object that aggregates statistics, and can summarize them in
+// various forms, including ASCII graphical, HTML, and numerically (as a
+// vector of numbers corresponding to each of the aggregating buckets).
+// See header file for details and examples.
+
+#include "base/metrics/histogram.h"
+
+#include <math.h>
+
+#include <algorithm>
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "base/debug/alias.h"
+#include "base/logging.h"
+#include "base/metrics/sample_vector.h"
+#include "base/metrics/statistics_recorder.h"
+#include "base/pickle.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/synchronization/lock.h"
+#include "base/values.h"
+
+namespace base {
+
+namespace {
+
+bool ReadHistogramArguments(PickleIterator* iter,
+                            std::string* histogram_name,
+                            int* flags,
+                            int* declared_min,
+                            int* declared_max,
+                            size_t* bucket_count,
+                            uint32* range_checksum) {
+  if (!iter->ReadString(histogram_name) ||
+      !iter->ReadInt(flags) ||
+      !iter->ReadInt(declared_min) ||
+      !iter->ReadInt(declared_max) ||
+      !iter->ReadSizeT(bucket_count) ||
+      !iter->ReadUInt32(range_checksum)) {
+    DLOG(ERROR) << "Pickle error decoding Histogram: " << *histogram_name;
+    return false;
+  }
+
+  // Since these fields may have come from an untrusted renderer, do additional
+  // checks above and beyond those in Histogram::Initialize()
+  if (*declared_max <= 0 ||
+      *declared_min <= 0 ||
+      *declared_max < *declared_min ||
+      INT_MAX / sizeof(HistogramBase::Count) <= *bucket_count ||
+      *bucket_count < 2) {
+    DLOG(ERROR) << "Values error decoding Histogram: " << histogram_name;
+    return false;
+  }
+
+  // We use the arguments to find or create the local version of the histogram
+  // in this process, so we need to clear the IPC flag.
+  DCHECK(*flags & HistogramBase::kIPCSerializationSourceFlag);
+  *flags &= ~HistogramBase::kIPCSerializationSourceFlag;
+
+  return true;
+}
+
+bool ValidateRangeChecksum(const HistogramBase& histogram,
+                           uint32 range_checksum) {
+  const Histogram& casted_histogram =
+      static_cast<const Histogram&>(histogram);
+
+  return casted_histogram.bucket_ranges()->checksum() == range_checksum;
+}
+
+}  // namespace
+
+typedef HistogramBase::Count Count;
+typedef HistogramBase::Sample Sample;
+
+// static
+const size_t Histogram::kBucketCount_MAX = 16384u;
+
+HistogramBase* Histogram::FactoryGet(const std::string& name,
+                                     Sample minimum,
+                                     Sample maximum,
+                                     size_t bucket_count,
+                                     int32 flags) {
+  bool valid_arguments =
+      InspectConstructionArguments(name, &minimum, &maximum, &bucket_count);
+  DCHECK(valid_arguments);
+
+  HistogramBase* histogram = StatisticsRecorder::FindHistogram(name);
+  if (!histogram) {
+    // To avoid racy destruction at shutdown, the following will be leaked.
+    BucketRanges* ranges = new BucketRanges(bucket_count + 1);
+    InitializeBucketRanges(minimum, maximum, ranges);
+    const BucketRanges* registered_ranges =
+        StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges);
+
+    Histogram* tentative_histogram =
+        new Histogram(name, minimum, maximum, registered_ranges);
+
+    tentative_histogram->SetFlags(flags);
+    histogram =
+        StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram);
+  }
+
+  DCHECK_EQ(HISTOGRAM, histogram->GetHistogramType());
+  if (!histogram->HasConstructionArguments(minimum, maximum, bucket_count)) {
+    // The construction arguments do not match the existing histogram.  This can
+    // come about if an extension updates in the middle of a chrome run and has
+    // changed one of them, or simply by bad code within Chrome itself.  We
+    // return NULL here with the expectation that bad code in Chrome will crash
+    // on dereference, but extension/Pepper APIs will guard against NULL and not
+    // crash.
+    DLOG(ERROR) << "Histogram " << name << " has bad construction arguments";
+    return NULL;
+  }
+  return histogram;
+}
+
+HistogramBase* Histogram::FactoryTimeGet(const std::string& name,
+                                         TimeDelta minimum,
+                                         TimeDelta maximum,
+                                         size_t bucket_count,
+                                         int32 flags) {
+  return FactoryGet(name, static_cast<Sample>(minimum.InMilliseconds()),
+                    static_cast<Sample>(maximum.InMilliseconds()), bucket_count,
+                    flags);
+}
+
+// Calculate what range of values are held in each bucket.
+// We have to be careful that we don't pick a ratio between starting points in
+// consecutive buckets that is sooo small, that the integer bounds are the same
+// (effectively making one bucket get no values).  We need to avoid:
+//   ranges(i) == ranges(i + 1)
+// To avoid that, we just do a fine-grained bucket width as far as we need to
+// until we get a ratio that moves us along at least 2 units at a time.  From
+// that bucket onward we do use the exponential growth of buckets.
+//
+// static
+void Histogram::InitializeBucketRanges(Sample minimum,
+                                       Sample maximum,
+                                       BucketRanges* ranges) {
+  double log_max = log(static_cast<double>(maximum));
+  double log_ratio;
+  double log_next;
+  size_t bucket_index = 1;
+  Sample current = minimum;
+  ranges->set_range(bucket_index, current);
+  size_t bucket_count = ranges->bucket_count();
+  while (bucket_count > ++bucket_index) {
+    double log_current;
+    log_current = log(static_cast<double>(current));
+    // Calculate the count'th root of the range.
+    log_ratio = (log_max - log_current) / (bucket_count - bucket_index);
+    // See where the next bucket would start.
+    log_next = log_current + log_ratio;
+    Sample next;
+    next = static_cast<int>(floor(exp(log_next) + 0.5));
+    if (next > current)
+      current = next;
+    else
+      ++current;  // Just do a narrow bucket, and keep trying.
+    ranges->set_range(bucket_index, current);
+  }
+  ranges->set_range(ranges->bucket_count(), HistogramBase::kSampleType_MAX);
+  ranges->ResetChecksum();
+}
+
+// static
+const int Histogram::kCommonRaceBasedCountMismatch = 5;
+
+int Histogram::FindCorruption(const HistogramSamples& samples) const {
+  int inconsistencies = NO_INCONSISTENCIES;
+  Sample previous_range = -1;  // Bottom range is always 0.
+  for (size_t index = 0; index < bucket_count(); ++index) {
+    int new_range = ranges(index);
+    if (previous_range >= new_range)
+      inconsistencies |= BUCKET_ORDER_ERROR;
+    previous_range = new_range;
+  }
+
+  if (!bucket_ranges()->HasValidChecksum())
+    inconsistencies |= RANGE_CHECKSUM_ERROR;
+
+  int64 delta64 = samples.redundant_count() - samples.TotalCount();
+  if (delta64 != 0) {
+    int delta = static_cast<int>(delta64);
+    if (delta != delta64)
+      delta = INT_MAX;  // Flag all giant errors as INT_MAX.
+    if (delta > 0) {
+      UMA_HISTOGRAM_COUNTS("Histogram.InconsistentCountHigh", delta);
+      if (delta > kCommonRaceBasedCountMismatch)
+        inconsistencies |= COUNT_HIGH_ERROR;
+    } else {
+      DCHECK_GT(0, delta);
+      UMA_HISTOGRAM_COUNTS("Histogram.InconsistentCountLow", -delta);
+      if (-delta > kCommonRaceBasedCountMismatch)
+        inconsistencies |= COUNT_LOW_ERROR;
+    }
+  }
+  return inconsistencies;
+}
+
+Sample Histogram::ranges(size_t i) const {
+  return bucket_ranges_->range(i);
+}
+
+size_t Histogram::bucket_count() const {
+  return bucket_ranges_->bucket_count();
+}
+
+// static
+bool Histogram::InspectConstructionArguments(const std::string& name,
+                                             Sample* minimum,
+                                             Sample* maximum,
+                                             size_t* bucket_count) {
+  // Defensive code for backward compatibility.
+  if (*minimum < 1) {
+    DVLOG(1) << "Histogram: " << name << " has bad minimum: " << *minimum;
+    *minimum = 1;
+  }
+  if (*maximum >= kSampleType_MAX) {
+    DVLOG(1) << "Histogram: " << name << " has bad maximum: " << *maximum;
+    *maximum = kSampleType_MAX - 1;
+  }
+  if (*bucket_count >= kBucketCount_MAX) {
+    DVLOG(1) << "Histogram: " << name << " has bad bucket_count: "
+             << *bucket_count;
+    *bucket_count = kBucketCount_MAX - 1;
+  }
+
+  if (*minimum >= *maximum)
+    return false;
+  if (*bucket_count < 3)
+    return false;
+  if (*bucket_count > static_cast<size_t>(*maximum - *minimum + 2))
+    return false;
+  return true;
+}
+
+HistogramType Histogram::GetHistogramType() const {
+  return HISTOGRAM;
+}
+
+bool Histogram::HasConstructionArguments(Sample expected_minimum,
+                                         Sample expected_maximum,
+                                         size_t expected_bucket_count) const {
+  return ((expected_minimum == declared_min_) &&
+          (expected_maximum == declared_max_) &&
+          (expected_bucket_count == bucket_count()));
+}
+
+void Histogram::Add(int value) {
+  DCHECK_EQ(0, ranges(0));
+  DCHECK_EQ(kSampleType_MAX, ranges(bucket_count()));
+
+  if (value > kSampleType_MAX - 1)
+    value = kSampleType_MAX - 1;
+  if (value < 0)
+    value = 0;
+  samples_->Accumulate(value, 1);
+}
+
+scoped_ptr<HistogramSamples> Histogram::SnapshotSamples() const {
+  return SnapshotSampleVector().Pass();
+}
+
+void Histogram::AddSamples(const HistogramSamples& samples) {
+  samples_->Add(samples);
+}
+
+bool Histogram::AddSamplesFromPickle(PickleIterator* iter) {
+  return samples_->AddFromPickle(iter);
+}
+
+// The following methods provide a graphical histogram display.
+void Histogram::WriteHTMLGraph(std::string* output) const {
+  // TBD(jar) Write a nice HTML bar chart, with divs an mouse-overs etc.
+  output->append("<PRE>");
+  WriteAsciiImpl(true, "<br>", output);
+  output->append("</PRE>");
+}
+
+void Histogram::WriteAscii(std::string* output) const {
+  WriteAsciiImpl(true, "\n", output);
+}
+
+bool Histogram::SerializeInfoImpl(Pickle* pickle) const {
+  DCHECK(bucket_ranges()->HasValidChecksum());
+  return pickle->WriteString(histogram_name()) &&
+      pickle->WriteInt(flags()) &&
+      pickle->WriteInt(declared_min()) &&
+      pickle->WriteInt(declared_max()) &&
+      pickle->WriteSizeT(bucket_count()) &&
+      pickle->WriteUInt32(bucket_ranges()->checksum());
+}
+
+Histogram::Histogram(const std::string& name,
+                     Sample minimum,
+                     Sample maximum,
+                     const BucketRanges* ranges)
+  : HistogramBase(name),
+    bucket_ranges_(ranges),
+    declared_min_(minimum),
+    declared_max_(maximum) {
+  if (ranges)
+    samples_.reset(new SampleVector(ranges));
+}
+
+Histogram::~Histogram() {
+}
+
+bool Histogram::PrintEmptyBucket(size_t index) const {
+  return true;
+}
+
+// Use the actual bucket widths (like a linear histogram) until the widths get
+// over some transition value, and then use that transition width.  Exponentials
+// get so big so fast (and we don't expect to see a lot of entries in the large
+// buckets), so we need this to make it possible to see what is going on and
+// not have 0-graphical-height buckets.
+double Histogram::GetBucketSize(Count current, size_t i) const {
+  DCHECK_GT(ranges(i + 1), ranges(i));
+  static const double kTransitionWidth = 5;
+  double denominator = ranges(i + 1) - ranges(i);
+  if (denominator > kTransitionWidth)
+    denominator = kTransitionWidth;  // Stop trying to normalize.
+  return current/denominator;
+}
+
+const std::string Histogram::GetAsciiBucketRange(size_t i) const {
+  return GetSimpleAsciiBucketRange(ranges(i));
+}
+
+//------------------------------------------------------------------------------
+// Private methods
+
+// static
+HistogramBase* Histogram::DeserializeInfoImpl(PickleIterator* iter) {
+  std::string histogram_name;
+  int flags;
+  int declared_min;
+  int declared_max;
+  size_t bucket_count;
+  uint32 range_checksum;
+
+  if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
+                              &declared_max, &bucket_count, &range_checksum)) {
+    return NULL;
+  }
+
+  // Find or create the local version of the histogram in this process.
+  HistogramBase* histogram = Histogram::FactoryGet(
+      histogram_name, declared_min, declared_max, bucket_count, flags);
+
+  if (!ValidateRangeChecksum(*histogram, range_checksum)) {
+    // The serialized histogram might be corrupted.
+    return NULL;
+  }
+  return histogram;
+}
+
+scoped_ptr<SampleVector> Histogram::SnapshotSampleVector() const {
+  scoped_ptr<SampleVector> samples(new SampleVector(bucket_ranges()));
+  samples->Add(*samples_);
+  return samples.Pass();
+}
+
+void Histogram::WriteAsciiImpl(bool graph_it,
+                               const std::string& newline,
+                               std::string* output) const {
+  // Get local (stack) copies of all effectively volatile class data so that we
+  // are consistent across our output activities.
+  scoped_ptr<SampleVector> snapshot = SnapshotSampleVector();
+  Count sample_count = snapshot->TotalCount();
+
+  WriteAsciiHeader(*snapshot, sample_count, output);
+  output->append(newline);
+
+  // Prepare to normalize graphical rendering of bucket contents.
+  double max_size = 0;
+  if (graph_it)
+    max_size = GetPeakBucketSize(*snapshot);
+
+  // Calculate space needed to print bucket range numbers.  Leave room to print
+  // nearly the largest bucket range without sliding over the histogram.
+  size_t largest_non_empty_bucket = bucket_count() - 1;
+  while (0 == snapshot->GetCountAtIndex(largest_non_empty_bucket)) {
+    if (0 == largest_non_empty_bucket)
+      break;  // All buckets are empty.
+    --largest_non_empty_bucket;
+  }
+
+  // Calculate largest print width needed for any of our bucket range displays.
+  size_t print_width = 1;
+  for (size_t i = 0; i < bucket_count(); ++i) {
+    if (snapshot->GetCountAtIndex(i)) {
+      size_t width = GetAsciiBucketRange(i).size() + 1;
+      if (width > print_width)
+        print_width = width;
+    }
+  }
+
+  int64 remaining = sample_count;
+  int64 past = 0;
+  // Output the actual histogram graph.
+  for (size_t i = 0; i < bucket_count(); ++i) {
+    Count current = snapshot->GetCountAtIndex(i);
+    if (!current && !PrintEmptyBucket(i))
+      continue;
+    remaining -= current;
+    std::string range = GetAsciiBucketRange(i);
+    output->append(range);
+    for (size_t j = 0; range.size() + j < print_width + 1; ++j)
+      output->push_back(' ');
+    if (0 == current && i < bucket_count() - 1 &&
+        0 == snapshot->GetCountAtIndex(i + 1)) {
+      while (i < bucket_count() - 1 &&
+             0 == snapshot->GetCountAtIndex(i + 1)) {
+        ++i;
+      }
+      output->append("... ");
+      output->append(newline);
+      continue;  // No reason to plot emptiness.
+    }
+    double current_size = GetBucketSize(current, i);
+    if (graph_it)
+      WriteAsciiBucketGraph(current_size, max_size, output);
+    WriteAsciiBucketContext(past, current, remaining, i, output);
+    output->append(newline);
+    past += current;
+  }
+  DCHECK_EQ(sample_count, past);
+}
+
+double Histogram::GetPeakBucketSize(const SampleVector& samples) const {
+  double max = 0;
+  for (size_t i = 0; i < bucket_count() ; ++i) {
+    double current_size = GetBucketSize(samples.GetCountAtIndex(i), i);
+    if (current_size > max)
+      max = current_size;
+  }
+  return max;
+}
+
+void Histogram::WriteAsciiHeader(const SampleVector& samples,
+                                 Count sample_count,
+                                 std::string* output) const {
+  StringAppendF(output,
+                "Histogram: %s recorded %d samples",
+                histogram_name().c_str(),
+                sample_count);
+  if (0 == sample_count) {
+    DCHECK_EQ(samples.sum(), 0);
+  } else {
+    double average = static_cast<float>(samples.sum()) / sample_count;
+
+    StringAppendF(output, ", average = %.1f", average);
+  }
+  if (flags() & ~kHexRangePrintingFlag)
+    StringAppendF(output, " (flags = 0x%x)", flags() & ~kHexRangePrintingFlag);
+}
+
+void Histogram::WriteAsciiBucketContext(const int64 past,
+                                        const Count current,
+                                        const int64 remaining,
+                                        const size_t i,
+                                        std::string* output) const {
+  double scaled_sum = (past + current + remaining) / 100.0;
+  WriteAsciiBucketValue(current, scaled_sum, output);
+  if (0 < i) {
+    double percentage = past / scaled_sum;
+    StringAppendF(output, " {%3.1f%%}", percentage);
+  }
+}
+
+void Histogram::GetParameters(DictionaryValue* params) const {
+  params->SetString("type", HistogramTypeToString(GetHistogramType()));
+  params->SetInteger("min", declared_min());
+  params->SetInteger("max", declared_max());
+  params->SetInteger("bucket_count", static_cast<int>(bucket_count()));
+}
+
+void Histogram::GetCountAndBucketData(Count* count,
+                                      int64* sum,
+                                      ListValue* buckets) const {
+  scoped_ptr<SampleVector> snapshot = SnapshotSampleVector();
+  *count = snapshot->TotalCount();
+  *sum = snapshot->sum();
+  size_t index = 0;
+  for (size_t i = 0; i < bucket_count(); ++i) {
+    Sample count_at_index = snapshot->GetCountAtIndex(i);
+    if (count_at_index > 0) {
+      scoped_ptr<DictionaryValue> bucket_value(new DictionaryValue());
+      bucket_value->SetInteger("low", ranges(i));
+      if (i != bucket_count() - 1)
+        bucket_value->SetInteger("high", ranges(i + 1));
+      bucket_value->SetInteger("count", count_at_index);
+      buckets->Set(index, bucket_value.release());
+      ++index;
+    }
+  }
+}
+
+//------------------------------------------------------------------------------
+// LinearHistogram: This histogram uses a traditional set of evenly spaced
+// buckets.
+//------------------------------------------------------------------------------
+
+LinearHistogram::~LinearHistogram() {}
+
+HistogramBase* LinearHistogram::FactoryGet(const std::string& name,
+                                           Sample minimum,
+                                           Sample maximum,
+                                           size_t bucket_count,
+                                           int32 flags) {
+  return FactoryGetWithRangeDescription(
+      name, minimum, maximum, bucket_count, flags, NULL);
+}
+
+HistogramBase* LinearHistogram::FactoryTimeGet(const std::string& name,
+                                               TimeDelta minimum,
+                                               TimeDelta maximum,
+                                               size_t bucket_count,
+                                               int32 flags) {
+  return FactoryGet(name, static_cast<Sample>(minimum.InMilliseconds()),
+                    static_cast<Sample>(maximum.InMilliseconds()), bucket_count,
+                    flags);
+}
+
+HistogramBase* LinearHistogram::FactoryGetWithRangeDescription(
+      const std::string& name,
+      Sample minimum,
+      Sample maximum,
+      size_t bucket_count,
+      int32 flags,
+      const DescriptionPair descriptions[]) {
+  bool valid_arguments = Histogram::InspectConstructionArguments(
+      name, &minimum, &maximum, &bucket_count);
+  DCHECK(valid_arguments);
+
+  HistogramBase* histogram = StatisticsRecorder::FindHistogram(name);
+  if (!histogram) {
+    // To avoid racy destruction at shutdown, the following will be leaked.
+    BucketRanges* ranges = new BucketRanges(bucket_count + 1);
+    InitializeBucketRanges(minimum, maximum, ranges);
+    const BucketRanges* registered_ranges =
+        StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges);
+
+    LinearHistogram* tentative_histogram =
+        new LinearHistogram(name, minimum, maximum, registered_ranges);
+
+    // Set range descriptions.
+    if (descriptions) {
+      for (int i = 0; descriptions[i].description; ++i) {
+        tentative_histogram->bucket_description_[descriptions[i].sample] =
+            descriptions[i].description;
+      }
+    }
+
+    tentative_histogram->SetFlags(flags);
+    histogram =
+        StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram);
+  }
+
+  DCHECK_EQ(LINEAR_HISTOGRAM, histogram->GetHistogramType());
+  if (!histogram->HasConstructionArguments(minimum, maximum, bucket_count)) {
+    // The construction arguments do not match the existing histogram.  This can
+    // come about if an extension updates in the middle of a chrome run and has
+    // changed one of them, or simply by bad code within Chrome itself.  We
+    // return NULL here with the expectation that bad code in Chrome will crash
+    // on dereference, but extension/Pepper APIs will guard against NULL and not
+    // crash.
+    DLOG(ERROR) << "Histogram " << name << " has bad construction arguments";
+    return NULL;
+  }
+  return histogram;
+}
+
+HistogramType LinearHistogram::GetHistogramType() const {
+  return LINEAR_HISTOGRAM;
+}
+
+LinearHistogram::LinearHistogram(const std::string& name,
+                                 Sample minimum,
+                                 Sample maximum,
+                                 const BucketRanges* ranges)
+    : Histogram(name, minimum, maximum, ranges) {
+}
+
+double LinearHistogram::GetBucketSize(Count current, size_t i) const {
+  DCHECK_GT(ranges(i + 1), ranges(i));
+  // Adjacent buckets with different widths would have "surprisingly" many (few)
+  // samples in a histogram if we didn't normalize this way.
+  double denominator = ranges(i + 1) - ranges(i);
+  return current/denominator;
+}
+
+const std::string LinearHistogram::GetAsciiBucketRange(size_t i) const {
+  int range = ranges(i);
+  BucketDescriptionMap::const_iterator it = bucket_description_.find(range);
+  if (it == bucket_description_.end())
+    return Histogram::GetAsciiBucketRange(i);
+  return it->second;
+}
+
+bool LinearHistogram::PrintEmptyBucket(size_t index) const {
+  return bucket_description_.find(ranges(index)) == bucket_description_.end();
+}
+
+// static
+void LinearHistogram::InitializeBucketRanges(Sample minimum,
+                                             Sample maximum,
+                                             BucketRanges* ranges) {
+  double min = minimum;
+  double max = maximum;
+  size_t bucket_count = ranges->bucket_count();
+  for (size_t i = 1; i < bucket_count; ++i) {
+    double linear_range =
+        (min * (bucket_count - 1 - i) + max * (i - 1)) / (bucket_count - 2);
+    ranges->set_range(i, static_cast<Sample>(linear_range + 0.5));
+  }
+  ranges->set_range(ranges->bucket_count(), HistogramBase::kSampleType_MAX);
+  ranges->ResetChecksum();
+}
+
+// static
+HistogramBase* LinearHistogram::DeserializeInfoImpl(PickleIterator* iter) {
+  std::string histogram_name;
+  int flags;
+  int declared_min;
+  int declared_max;
+  size_t bucket_count;
+  uint32 range_checksum;
+
+  if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
+                              &declared_max, &bucket_count, &range_checksum)) {
+    return NULL;
+  }
+
+  HistogramBase* histogram = LinearHistogram::FactoryGet(
+      histogram_name, declared_min, declared_max, bucket_count, flags);
+  if (!ValidateRangeChecksum(*histogram, range_checksum)) {
+    // The serialized histogram might be corrupted.
+    return NULL;
+  }
+  return histogram;
+}
+
+//------------------------------------------------------------------------------
+// This section provides implementation for BooleanHistogram.
+//------------------------------------------------------------------------------
+
+HistogramBase* BooleanHistogram::FactoryGet(const std::string& name,
+                                            int32 flags) {
+  HistogramBase* histogram = StatisticsRecorder::FindHistogram(name);
+  if (!histogram) {
+    // To avoid racy destruction at shutdown, the following will be leaked.
+    BucketRanges* ranges = new BucketRanges(4);
+    LinearHistogram::InitializeBucketRanges(1, 2, ranges);
+    const BucketRanges* registered_ranges =
+        StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges);
+
+    BooleanHistogram* tentative_histogram =
+        new BooleanHistogram(name, registered_ranges);
+
+    tentative_histogram->SetFlags(flags);
+    histogram =
+        StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram);
+  }
+
+  DCHECK_EQ(BOOLEAN_HISTOGRAM, histogram->GetHistogramType());
+  return histogram;
+}
+
+HistogramType BooleanHistogram::GetHistogramType() const {
+  return BOOLEAN_HISTOGRAM;
+}
+
+BooleanHistogram::BooleanHistogram(const std::string& name,
+                                   const BucketRanges* ranges)
+    : LinearHistogram(name, 1, 2, ranges) {}
+
+HistogramBase* BooleanHistogram::DeserializeInfoImpl(PickleIterator* iter) {
+  std::string histogram_name;
+  int flags;
+  int declared_min;
+  int declared_max;
+  size_t bucket_count;
+  uint32 range_checksum;
+
+  if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
+                              &declared_max, &bucket_count, &range_checksum)) {
+    return NULL;
+  }
+
+  HistogramBase* histogram = BooleanHistogram::FactoryGet(
+      histogram_name, flags);
+  if (!ValidateRangeChecksum(*histogram, range_checksum)) {
+    // The serialized histogram might be corrupted.
+    return NULL;
+  }
+  return histogram;
+}
+
+//------------------------------------------------------------------------------
+// CustomHistogram:
+//------------------------------------------------------------------------------
+
+HistogramBase* CustomHistogram::FactoryGet(
+    const std::string& name,
+    const std::vector<Sample>& custom_ranges,
+    int32 flags) {
+  CHECK(ValidateCustomRanges(custom_ranges));
+
+  HistogramBase* histogram = StatisticsRecorder::FindHistogram(name);
+  if (!histogram) {
+    BucketRanges* ranges = CreateBucketRangesFromCustomRanges(custom_ranges);
+    const BucketRanges* registered_ranges =
+        StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges);
+
+    // To avoid racy destruction at shutdown, the following will be leaked.
+    CustomHistogram* tentative_histogram =
+        new CustomHistogram(name, registered_ranges);
+
+    tentative_histogram->SetFlags(flags);
+
+    histogram =
+        StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram);
+  }
+
+  DCHECK_EQ(histogram->GetHistogramType(), CUSTOM_HISTOGRAM);
+  return histogram;
+}
+
+HistogramType CustomHistogram::GetHistogramType() const {
+  return CUSTOM_HISTOGRAM;
+}
+
+// static
+std::vector<Sample> CustomHistogram::ArrayToCustomRanges(
+    const Sample* values, size_t num_values) {
+  std::vector<Sample> all_values;
+  for (size_t i = 0; i < num_values; ++i) {
+    Sample value = values[i];
+    all_values.push_back(value);
+
+    // Ensure that a guard bucket is added. If we end up with duplicate
+    // values, FactoryGet will take care of removing them.
+    all_values.push_back(value + 1);
+  }
+  return all_values;
+}
+
+CustomHistogram::CustomHistogram(const std::string& name,
+                                 const BucketRanges* ranges)
+    : Histogram(name,
+                ranges->range(1),
+                ranges->range(ranges->bucket_count() - 1),
+                ranges) {}
+
+bool CustomHistogram::SerializeInfoImpl(Pickle* pickle) const {
+  if (!Histogram::SerializeInfoImpl(pickle))
+    return false;
+
+  // Serialize ranges. First and last ranges are alwasy 0 and INT_MAX, so don't
+  // write them.
+  for (size_t i = 1; i < bucket_ranges()->bucket_count(); ++i) {
+    if (!pickle->WriteInt(bucket_ranges()->range(i)))
+      return false;
+  }
+  return true;
+}
+
+double CustomHistogram::GetBucketSize(Count current, size_t i) const {
+  return 1;
+}
+
+// static
+HistogramBase* CustomHistogram::DeserializeInfoImpl(PickleIterator* iter) {
+  std::string histogram_name;
+  int flags;
+  int declared_min;
+  int declared_max;
+  size_t bucket_count;
+  uint32 range_checksum;
+
+  if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
+                              &declared_max, &bucket_count, &range_checksum)) {
+    return NULL;
+  }
+
+  // First and last ranges are not serialized.
+  std::vector<Sample> sample_ranges(bucket_count - 1);
+
+  for (size_t i = 0; i < sample_ranges.size(); ++i) {
+    if (!iter->ReadInt(&sample_ranges[i]))
+      return NULL;
+  }
+
+  HistogramBase* histogram = CustomHistogram::FactoryGet(
+      histogram_name, sample_ranges, flags);
+  if (!ValidateRangeChecksum(*histogram, range_checksum)) {
+    // The serialized histogram might be corrupted.
+    return NULL;
+  }
+  return histogram;
+}
+
+// static
+bool CustomHistogram::ValidateCustomRanges(
+    const std::vector<Sample>& custom_ranges) {
+  bool has_valid_range = false;
+  for (size_t i = 0; i < custom_ranges.size(); i++) {
+    Sample sample = custom_ranges[i];
+    if (sample < 0 || sample > HistogramBase::kSampleType_MAX - 1)
+      return false;
+    if (sample != 0)
+      has_valid_range = true;
+  }
+  return has_valid_range;
+}
+
+// static
+BucketRanges* CustomHistogram::CreateBucketRangesFromCustomRanges(
+      const std::vector<Sample>& custom_ranges) {
+  // Remove the duplicates in the custom ranges array.
+  std::vector<int> ranges = custom_ranges;
+  ranges.push_back(0);  // Ensure we have a zero value.
+  ranges.push_back(HistogramBase::kSampleType_MAX);
+  std::sort(ranges.begin(), ranges.end());
+  ranges.erase(std::unique(ranges.begin(), ranges.end()), ranges.end());
+
+  BucketRanges* bucket_ranges = new BucketRanges(ranges.size());
+  for (size_t i = 0; i < ranges.size(); i++) {
+    bucket_ranges->set_range(i, ranges[i]);
+  }
+  bucket_ranges->ResetChecksum();
+  return bucket_ranges;
+}
+
+}  // namespace base
diff --git a/base/metrics/histogram.h b/base/metrics/histogram.h
new file mode 100644
index 0000000..c13f05e
--- /dev/null
+++ b/base/metrics/histogram.h
@@ -0,0 +1,401 @@
+// Copyright (c) 2012 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.
+
+// Histogram is an object that aggregates statistics, and can summarize them in
+// various forms, including ASCII graphical, HTML, and numerically (as a
+// vector of numbers corresponding to each of the aggregating buckets).
+
+// It supports calls to accumulate either time intervals (which are processed
+// as integral number of milliseconds), or arbitrary integral units.
+
+// For Histogram(exponential histogram), LinearHistogram and CustomHistogram,
+// the minimum for a declared range is 1 (instead of 0), while the maximum is
+// (HistogramBase::kSampleType_MAX - 1). Currently you can declare histograms
+// with ranges exceeding those limits (e.g. 0 as minimal or
+// HistogramBase::kSampleType_MAX as maximal), but those excesses will be
+// silently clamped to those limits (for backwards compatibility with existing
+// code). Best practice is to not exceed the limits.
+
+// Each use of a histogram with the same name will reference the same underlying
+// data, so it is safe to record to the same histogram from multiple locations
+// in the code. It is a runtime error if all uses of the same histogram do not
+// agree exactly in type, bucket size and range.
+
+// For Histogram and LinearHistogram, the maximum for a declared range should
+// always be larger (not equal) than minimal range. Zero and
+// HistogramBase::kSampleType_MAX are implicitly added as first and last ranges,
+// so the smallest legal bucket_count is 3. However CustomHistogram can have
+// bucket count as 2 (when you give a custom ranges vector containing only 1
+// range).
+// For these 3 kinds of histograms, the max bucket count is always
+// (Histogram::kBucketCount_MAX - 1).
+
+// The buckets layout of class Histogram is exponential. For example, buckets
+// might contain (sequentially) the count of values in the following intervals:
+// [0,1), [1,2), [2,4), [4,8), [8,16), [16,32), [32,64), [64,infinity)
+// That bucket allocation would actually result from construction of a histogram
+// for values between 1 and 64, with 8 buckets, such as:
+// Histogram count("some name", 1, 64, 8);
+// Note that the underflow bucket [0,1) and the overflow bucket [64,infinity)
+// are also counted by the constructor in the user supplied "bucket_count"
+// argument.
+// The above example has an exponential ratio of 2 (doubling the bucket width
+// in each consecutive bucket.  The Histogram class automatically calculates
+// the smallest ratio that it can use to construct the number of buckets
+// selected in the constructor.  An another example, if you had 50 buckets,
+// and millisecond time values from 1 to 10000, then the ratio between
+// consecutive bucket widths will be approximately somewhere around the 50th
+// root of 10000.  This approach provides very fine grain (narrow) buckets
+// at the low end of the histogram scale, but allows the histogram to cover a
+// gigantic range with the addition of very few buckets.
+
+// Usually we use macros to define and use a histogram, which are defined in
+// base/metrics/histogram_macros.h. Note: Callers should include that header
+// directly if they only access the histogram APIs through macros.
+//
+// Macros use a pattern involving a function static variable, that is a pointer
+// to a histogram.  This static is explicitly initialized on any thread
+// that detects a uninitialized (NULL) pointer.  The potentially racy
+// initialization is not a problem as it is always set to point to the same
+// value (i.e., the FactoryGet always returns the same value).  FactoryGet
+// is also completely thread safe, which results in a completely thread safe,
+// and relatively fast, set of counters.  To avoid races at shutdown, the static
+// pointer is NOT deleted, and we leak the histograms at process termination.
+
+#ifndef BASE_METRICS_HISTOGRAM_H_
+#define BASE_METRICS_HISTOGRAM_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/gtest_prod_util.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/bucket_ranges.h"
+#include "base/metrics/histogram_base.h"
+// TODO(asvitkine): Migrate callers to to include this directly and remove this.
+#include "base/metrics/histogram_macros.h"
+#include "base/metrics/histogram_samples.h"
+#include "base/time/time.h"
+
+namespace base {
+
+class BooleanHistogram;
+class CustomHistogram;
+class Histogram;
+class LinearHistogram;
+class Pickle;
+class PickleIterator;
+class SampleVector;
+
+class BASE_EXPORT Histogram : public HistogramBase {
+ public:
+  // Initialize maximum number of buckets in histograms as 16,384.
+  static const size_t kBucketCount_MAX;
+
+  typedef std::vector<Count> Counts;
+
+  //----------------------------------------------------------------------------
+  // For a valid histogram, input should follow these restrictions:
+  // minimum > 0 (if a minimum below 1 is specified, it will implicitly be
+  //              normalized up to 1)
+  // maximum > minimum
+  // buckets > 2 [minimum buckets needed: underflow, overflow and the range]
+  // Additionally,
+  // buckets <= (maximum - minimum + 2) - this is to ensure that we don't have
+  // more buckets than the range of numbers; having more buckets than 1 per
+  // value in the range would be nonsensical.
+  static HistogramBase* FactoryGet(const std::string& name,
+                                   Sample minimum,
+                                   Sample maximum,
+                                   size_t bucket_count,
+                                   int32 flags);
+  static HistogramBase* FactoryTimeGet(const std::string& name,
+                                       base::TimeDelta minimum,
+                                       base::TimeDelta maximum,
+                                       size_t bucket_count,
+                                       int32 flags);
+
+  static void InitializeBucketRanges(Sample minimum,
+                                     Sample maximum,
+                                     BucketRanges* ranges);
+
+  // This constant if for FindCorruption. Since snapshots of histograms are
+  // taken asynchronously relative to sampling, and our counting code currently
+  // does not prevent race conditions, it is pretty likely that we'll catch a
+  // redundant count that doesn't match the sample count.  We allow for a
+  // certain amount of slop before flagging this as an inconsistency. Even with
+  // an inconsistency, we'll snapshot it again (for UMA in about a half hour),
+  // so we'll eventually get the data, if it was not the result of a corruption.
+  static const int kCommonRaceBasedCountMismatch;
+
+  // Check to see if bucket ranges, counts and tallies in the snapshot are
+  // consistent with the bucket ranges and checksums in our histogram.  This can
+  // produce a false-alarm if a race occurred in the reading of the data during
+  // a SnapShot process, but should otherwise be false at all times (unless we
+  // have memory over-writes, or DRAM failures).
+  int FindCorruption(const HistogramSamples& samples) const override;
+
+  //----------------------------------------------------------------------------
+  // Accessors for factory construction, serialization and testing.
+  //----------------------------------------------------------------------------
+  Sample declared_min() const { return declared_min_; }
+  Sample declared_max() const { return declared_max_; }
+  virtual Sample ranges(size_t i) const;
+  virtual size_t bucket_count() const;
+  const BucketRanges* bucket_ranges() const { return bucket_ranges_; }
+
+  // This function validates histogram construction arguments. It returns false
+  // if some of the arguments are totally bad.
+  // Note. Currently it allow some bad input, e.g. 0 as minimum, but silently
+  // converts it to good input: 1.
+  // TODO(kaiwang): Be more restrict and return false for any bad input, and
+  // make this a readonly validating function.
+  static bool InspectConstructionArguments(const std::string& name,
+                                           Sample* minimum,
+                                           Sample* maximum,
+                                           size_t* bucket_count);
+
+  // HistogramBase implementation:
+  HistogramType GetHistogramType() const override;
+  bool HasConstructionArguments(Sample expected_minimum,
+                                Sample expected_maximum,
+                                size_t expected_bucket_count) const override;
+  void Add(Sample value) override;
+  scoped_ptr<HistogramSamples> SnapshotSamples() const override;
+  void AddSamples(const HistogramSamples& samples) override;
+  bool AddSamplesFromPickle(base::PickleIterator* iter) override;
+  void WriteHTMLGraph(std::string* output) const override;
+  void WriteAscii(std::string* output) const override;
+
+ protected:
+  // |ranges| should contain the underflow and overflow buckets. See top
+  // comments for example.
+  Histogram(const std::string& name,
+            Sample minimum,
+            Sample maximum,
+            const BucketRanges* ranges);
+
+  ~Histogram() override;
+
+  // HistogramBase implementation:
+  bool SerializeInfoImpl(base::Pickle* pickle) const override;
+
+  // Method to override to skip the display of the i'th bucket if it's empty.
+  virtual bool PrintEmptyBucket(size_t index) const;
+
+  // Get normalized size, relative to the ranges(i).
+  virtual double GetBucketSize(Count current, size_t i) const;
+
+  // Return a string description of what goes in a given bucket.
+  // Most commonly this is the numeric value, but in derived classes it may
+  // be a name (or string description) given to the bucket.
+  virtual const std::string GetAsciiBucketRange(size_t it) const;
+
+ private:
+  // Allow tests to corrupt our innards for testing purposes.
+  FRIEND_TEST_ALL_PREFIXES(HistogramTest, BoundsTest);
+  FRIEND_TEST_ALL_PREFIXES(HistogramTest, BucketPlacementTest);
+  FRIEND_TEST_ALL_PREFIXES(HistogramTest, CorruptBucketBounds);
+  FRIEND_TEST_ALL_PREFIXES(HistogramTest, CorruptSampleCounts);
+  FRIEND_TEST_ALL_PREFIXES(HistogramTest, NameMatchTest);
+
+  friend class StatisticsRecorder;  // To allow it to delete duplicates.
+  friend class StatisticsRecorderTest;
+
+  friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
+      base::PickleIterator* iter);
+  static HistogramBase* DeserializeInfoImpl(base::PickleIterator* iter);
+
+  // Implementation of SnapshotSamples function.
+  scoped_ptr<SampleVector> SnapshotSampleVector() const;
+
+  //----------------------------------------------------------------------------
+  // Helpers for emitting Ascii graphic.  Each method appends data to output.
+
+  void WriteAsciiImpl(bool graph_it,
+                      const std::string& newline,
+                      std::string* output) const;
+
+  // Find out how large (graphically) the largest bucket will appear to be.
+  double GetPeakBucketSize(const SampleVector& samples) const;
+
+  // Write a common header message describing this histogram.
+  void WriteAsciiHeader(const SampleVector& samples,
+                        Count sample_count,
+                        std::string* output) const;
+
+  // Write information about previous, current, and next buckets.
+  // Information such as cumulative percentage, etc.
+  void WriteAsciiBucketContext(const int64 past, const Count current,
+                               const int64 remaining, const size_t i,
+                               std::string* output) const;
+
+  // WriteJSON calls these.
+  void GetParameters(DictionaryValue* params) const override;
+
+  void GetCountAndBucketData(Count* count,
+                             int64* sum,
+                             ListValue* buckets) const override;
+
+  // Does not own this object. Should get from StatisticsRecorder.
+  const BucketRanges* bucket_ranges_;
+
+  Sample declared_min_;  // Less than this goes into the first bucket.
+  Sample declared_max_;  // Over this goes into the last bucket.
+
+  // Finally, provide the state that changes with the addition of each new
+  // sample.
+  scoped_ptr<SampleVector> samples_;
+
+  DISALLOW_COPY_AND_ASSIGN(Histogram);
+};
+
+//------------------------------------------------------------------------------
+
+// LinearHistogram is a more traditional histogram, with evenly spaced
+// buckets.
+class BASE_EXPORT LinearHistogram : public Histogram {
+ public:
+  ~LinearHistogram() override;
+
+  /* minimum should start from 1. 0 is as minimum is invalid. 0 is an implicit
+     default underflow bucket. */
+  static HistogramBase* FactoryGet(const std::string& name,
+                                   Sample minimum,
+                                   Sample maximum,
+                                   size_t bucket_count,
+                                   int32 flags);
+  static HistogramBase* FactoryTimeGet(const std::string& name,
+                                       TimeDelta minimum,
+                                       TimeDelta maximum,
+                                       size_t bucket_count,
+                                       int32 flags);
+
+  struct DescriptionPair {
+    Sample sample;
+    const char* description;  // Null means end of a list of pairs.
+  };
+
+  // Create a LinearHistogram and store a list of number/text values for use in
+  // writing the histogram graph.
+  // |descriptions| can be NULL, which means no special descriptions to set. If
+  // it's not NULL, the last element in the array must has a NULL in its
+  // "description" field.
+  static HistogramBase* FactoryGetWithRangeDescription(
+      const std::string& name,
+      Sample minimum,
+      Sample maximum,
+      size_t bucket_count,
+      int32 flags,
+      const DescriptionPair descriptions[]);
+
+  static void InitializeBucketRanges(Sample minimum,
+                                     Sample maximum,
+                                     BucketRanges* ranges);
+
+  // Overridden from Histogram:
+  HistogramType GetHistogramType() const override;
+
+ protected:
+  LinearHistogram(const std::string& name,
+                  Sample minimum,
+                  Sample maximum,
+                  const BucketRanges* ranges);
+
+  double GetBucketSize(Count current, size_t i) const override;
+
+  // If we have a description for a bucket, then return that.  Otherwise
+  // let parent class provide a (numeric) description.
+  const std::string GetAsciiBucketRange(size_t i) const override;
+
+  // Skip printing of name for numeric range if we have a name (and if this is
+  // an empty bucket).
+  bool PrintEmptyBucket(size_t index) const override;
+
+ private:
+  friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
+      base::PickleIterator* iter);
+  static HistogramBase* DeserializeInfoImpl(base::PickleIterator* iter);
+
+  // For some ranges, we store a printable description of a bucket range.
+  // If there is no description, then GetAsciiBucketRange() uses parent class
+  // to provide a description.
+  typedef std::map<Sample, std::string> BucketDescriptionMap;
+  BucketDescriptionMap bucket_description_;
+
+  DISALLOW_COPY_AND_ASSIGN(LinearHistogram);
+};
+
+//------------------------------------------------------------------------------
+
+// BooleanHistogram is a histogram for booleans.
+class BASE_EXPORT BooleanHistogram : public LinearHistogram {
+ public:
+  static HistogramBase* FactoryGet(const std::string& name, int32 flags);
+
+  HistogramType GetHistogramType() const override;
+
+ private:
+  BooleanHistogram(const std::string& name, const BucketRanges* ranges);
+
+  friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
+      base::PickleIterator* iter);
+  static HistogramBase* DeserializeInfoImpl(base::PickleIterator* iter);
+
+  DISALLOW_COPY_AND_ASSIGN(BooleanHistogram);
+};
+
+//------------------------------------------------------------------------------
+
+// CustomHistogram is a histogram for a set of custom integers.
+class BASE_EXPORT CustomHistogram : public Histogram {
+ public:
+  // |custom_ranges| contains a vector of limits on ranges. Each limit should be
+  // > 0 and < kSampleType_MAX. (Currently 0 is still accepted for backward
+  // compatibility). The limits can be unordered or contain duplication, but
+  // client should not depend on this.
+  static HistogramBase* FactoryGet(const std::string& name,
+                                   const std::vector<Sample>& custom_ranges,
+                                   int32 flags);
+
+  // Overridden from Histogram:
+  HistogramType GetHistogramType() const override;
+
+  // Helper method for transforming an array of valid enumeration values
+  // to the std::vector<int> expected by UMA_HISTOGRAM_CUSTOM_ENUMERATION.
+  // This function ensures that a guard bucket exists right after any
+  // valid sample value (unless the next higher sample is also a valid value),
+  // so that invalid samples never fall into the same bucket as valid samples.
+  // TODO(kaiwang): Change name to ArrayToCustomEnumRanges.
+  static std::vector<Sample> ArrayToCustomRanges(const Sample* values,
+                                                 size_t num_values);
+ protected:
+  CustomHistogram(const std::string& name,
+                  const BucketRanges* ranges);
+
+  // HistogramBase implementation:
+  bool SerializeInfoImpl(base::Pickle* pickle) const override;
+
+  double GetBucketSize(Count current, size_t i) const override;
+
+ private:
+  friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
+      base::PickleIterator* iter);
+  static HistogramBase* DeserializeInfoImpl(base::PickleIterator* iter);
+
+  static bool ValidateCustomRanges(const std::vector<Sample>& custom_ranges);
+  static BucketRanges* CreateBucketRangesFromCustomRanges(
+      const std::vector<Sample>& custom_ranges);
+
+  DISALLOW_COPY_AND_ASSIGN(CustomHistogram);
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_HISTOGRAM_H_
diff --git a/base/metrics/histogram_base.cc b/base/metrics/histogram_base.cc
new file mode 100644
index 0000000..de34c79
--- /dev/null
+++ b/base/metrics/histogram_base.cc
@@ -0,0 +1,151 @@
+// Copyright (c) 2012 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/metrics/histogram_base.h"
+
+#include <climits>
+
+#include "base/json/json_string_value_serializer.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_samples.h"
+#include "base/metrics/sparse_histogram.h"
+#include "base/pickle.h"
+#include "base/process/process_handle.h"
+#include "base/strings/stringprintf.h"
+#include "base/values.h"
+
+namespace base {
+
+std::string HistogramTypeToString(HistogramType type) {
+  switch (type) {
+    case HISTOGRAM:
+      return "HISTOGRAM";
+    case LINEAR_HISTOGRAM:
+      return "LINEAR_HISTOGRAM";
+    case BOOLEAN_HISTOGRAM:
+      return "BOOLEAN_HISTOGRAM";
+    case CUSTOM_HISTOGRAM:
+      return "CUSTOM_HISTOGRAM";
+    case SPARSE_HISTOGRAM:
+      return "SPARSE_HISTOGRAM";
+    default:
+      NOTREACHED();
+  }
+  return "UNKNOWN";
+}
+
+HistogramBase* DeserializeHistogramInfo(PickleIterator* iter) {
+  int type;
+  if (!iter->ReadInt(&type))
+    return NULL;
+
+  switch (type) {
+    case HISTOGRAM:
+      return Histogram::DeserializeInfoImpl(iter);
+    case LINEAR_HISTOGRAM:
+      return LinearHistogram::DeserializeInfoImpl(iter);
+    case BOOLEAN_HISTOGRAM:
+      return BooleanHistogram::DeserializeInfoImpl(iter);
+    case CUSTOM_HISTOGRAM:
+      return CustomHistogram::DeserializeInfoImpl(iter);
+    case SPARSE_HISTOGRAM:
+      return SparseHistogram::DeserializeInfoImpl(iter);
+    default:
+      return NULL;
+  }
+}
+
+const HistogramBase::Sample HistogramBase::kSampleType_MAX = INT_MAX;
+
+HistogramBase::HistogramBase(const std::string& name)
+    : histogram_name_(name),
+      flags_(kNoFlags) {}
+
+HistogramBase::~HistogramBase() {}
+
+void HistogramBase::CheckName(const StringPiece& name) const {
+  DCHECK_EQ(histogram_name(), name);
+}
+
+void HistogramBase::SetFlags(int32 flags) {
+  flags_ |= flags;
+}
+
+void HistogramBase::ClearFlags(int32 flags) {
+  flags_ &= ~flags;
+}
+
+void HistogramBase::AddTime(const TimeDelta& time) {
+  Add(static_cast<Sample>(time.InMilliseconds()));
+}
+
+void HistogramBase::AddBoolean(bool value) {
+  Add(value ? 1 : 0);
+}
+
+bool HistogramBase::SerializeInfo(Pickle* pickle) const {
+  if (!pickle->WriteInt(GetHistogramType()))
+    return false;
+  return SerializeInfoImpl(pickle);
+}
+
+int HistogramBase::FindCorruption(const HistogramSamples& samples) const {
+  // Not supported by default.
+  return NO_INCONSISTENCIES;
+}
+
+void HistogramBase::WriteJSON(std::string* output) const {
+  Count count;
+  int64 sum;
+  scoped_ptr<ListValue> buckets(new ListValue());
+  GetCountAndBucketData(&count, &sum, buckets.get());
+  scoped_ptr<DictionaryValue> parameters(new DictionaryValue());
+  GetParameters(parameters.get());
+
+  JSONStringValueSerializer serializer(output);
+  DictionaryValue root;
+  root.SetString("name", histogram_name());
+  root.SetInteger("count", count);
+  root.SetDouble("sum", static_cast<double>(sum));
+  root.SetInteger("flags", flags());
+  root.Set("params", parameters.Pass());
+  root.Set("buckets", buckets.Pass());
+  root.SetInteger("pid", GetCurrentProcId());
+  serializer.Serialize(root);
+}
+
+void HistogramBase::WriteAsciiBucketGraph(double current_size,
+                                          double max_size,
+                                          std::string* output) const {
+  const int k_line_length = 72;  // Maximal horizontal width of graph.
+  int x_count = static_cast<int>(k_line_length * (current_size / max_size)
+                                 + 0.5);
+  int x_remainder = k_line_length - x_count;
+
+  while (0 < x_count--)
+    output->append("-");
+  output->append("O");
+  while (0 < x_remainder--)
+    output->append(" ");
+}
+
+const std::string HistogramBase::GetSimpleAsciiBucketRange(
+    Sample sample) const {
+  std::string result;
+  if (kHexRangePrintingFlag & flags())
+    StringAppendF(&result, "%#x", sample);
+  else
+    StringAppendF(&result, "%d", sample);
+  return result;
+}
+
+void HistogramBase::WriteAsciiBucketValue(Count current,
+                                          double scaled_sum,
+                                          std::string* output) const {
+  StringAppendF(output, " (%d = %3.1f%%)", current, current/scaled_sum);
+}
+
+}  // namespace base
diff --git a/base/metrics/histogram_base.h b/base/metrics/histogram_base.h
new file mode 100644
index 0000000..006395b
--- /dev/null
+++ b/base/metrics/histogram_base.h
@@ -0,0 +1,184 @@
+// Copyright (c) 2012 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_METRICS_HISTOGRAM_BASE_H_
+#define BASE_METRICS_HISTOGRAM_BASE_H_
+
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include "base/atomicops.h"
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_piece.h"
+#include "base/time/time.h"
+
+namespace base {
+
+class DictionaryValue;
+class HistogramBase;
+class HistogramSamples;
+class ListValue;
+class Pickle;
+class PickleIterator;
+
+////////////////////////////////////////////////////////////////////////////////
+// These enums are used to facilitate deserialization of histograms from other
+// processes into the browser. If you create another class that inherits from
+// HistogramBase, add new histogram types and names below.
+
+enum BASE_EXPORT HistogramType {
+  HISTOGRAM,
+  LINEAR_HISTOGRAM,
+  BOOLEAN_HISTOGRAM,
+  CUSTOM_HISTOGRAM,
+  SPARSE_HISTOGRAM,
+};
+
+std::string HistogramTypeToString(HistogramType type);
+
+// Create or find existing histogram that matches the pickled info.
+// Returns NULL if the pickled data has problems.
+BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
+    base::PickleIterator* iter);
+
+////////////////////////////////////////////////////////////////////////////////
+
+class BASE_EXPORT HistogramBase {
+ public:
+  typedef int32_t Sample;                // Used for samples.
+  typedef subtle::Atomic32 AtomicCount;  // Used to count samples.
+  typedef int32_t Count;  // Used to manipulate counts in temporaries.
+
+  static const Sample kSampleType_MAX;  // INT_MAX
+
+  enum Flags {
+    kNoFlags = 0,
+
+    // Histogram should be UMA uploaded.
+    kUmaTargetedHistogramFlag = 0x1,
+
+    // Indicates that this is a stability histogram. This flag exists to specify
+    // which histograms should be included in the initial stability log. Please
+    // refer to |MetricsService::PrepareInitialStabilityLog|.
+    kUmaStabilityHistogramFlag = kUmaTargetedHistogramFlag | 0x2,
+
+    // Indicates that the histogram was pickled to be sent across an IPC
+    // Channel. If we observe this flag on a histogram being aggregated into
+    // after IPC, then we are running in a single process mode, and the
+    // aggregation should not take place (as we would be aggregating back into
+    // the source histogram!).
+    kIPCSerializationSourceFlag = 0x10,
+
+    // Only for Histogram and its sub classes: fancy bucket-naming support.
+    kHexRangePrintingFlag = 0x8000,
+  };
+
+  // Histogram data inconsistency types.
+  enum Inconsistency {
+    NO_INCONSISTENCIES = 0x0,
+    RANGE_CHECKSUM_ERROR = 0x1,
+    BUCKET_ORDER_ERROR = 0x2,
+    COUNT_HIGH_ERROR = 0x4,
+    COUNT_LOW_ERROR = 0x8,
+
+    NEVER_EXCEEDED_VALUE = 0x10
+  };
+
+  explicit HistogramBase(const std::string& name);
+  virtual ~HistogramBase();
+
+  std::string histogram_name() const { return histogram_name_; }
+
+  // Comapres |name| to the histogram name and triggers a DCHECK if they do not
+  // match. This is a helper function used by histogram macros, which results in
+  // in more compact machine code being generated by the macros.
+  void CheckName(const StringPiece& name) const;
+
+  // Operations with Flags enum.
+  int32_t flags() const { return flags_; }
+  void SetFlags(int32_t flags);
+  void ClearFlags(int32_t flags);
+
+  virtual HistogramType GetHistogramType() const = 0;
+
+  // Whether the histogram has construction arguments as parameters specified.
+  // For histograms that don't have the concept of minimum, maximum or
+  // bucket_count, this function always returns false.
+  virtual bool HasConstructionArguments(Sample expected_minimum,
+                                        Sample expected_maximum,
+                                        size_t expected_bucket_count) const = 0;
+
+  virtual void Add(Sample value) = 0;
+
+  // 2 convenient functions that call Add(Sample).
+  void AddTime(const TimeDelta& time);
+  void AddBoolean(bool value);
+
+  virtual void AddSamples(const HistogramSamples& samples) = 0;
+  virtual bool AddSamplesFromPickle(base::PickleIterator* iter) = 0;
+
+  // Serialize the histogram info into |pickle|.
+  // Note: This only serializes the construction arguments of the histogram, but
+  // does not serialize the samples.
+  bool SerializeInfo(base::Pickle* pickle) const;
+
+  // Try to find out data corruption from histogram and the samples.
+  // The returned value is a combination of Inconsistency enum.
+  virtual int FindCorruption(const HistogramSamples& samples) const;
+
+  // Snapshot the current complete set of sample data.
+  // Override with atomic/locked snapshot if needed.
+  virtual scoped_ptr<HistogramSamples> SnapshotSamples() const = 0;
+
+  // The following methods provide graphical histogram displays.
+  virtual void WriteHTMLGraph(std::string* output) const = 0;
+  virtual void WriteAscii(std::string* output) const = 0;
+
+  // Produce a JSON representation of the histogram. This is implemented with
+  // the help of GetParameters and GetCountAndBucketData; overwrite them to
+  // customize the output.
+  void WriteJSON(std::string* output) const;
+
+ protected:
+  // Subclasses should implement this function to make SerializeInfo work.
+  virtual bool SerializeInfoImpl(base::Pickle* pickle) const = 0;
+
+  // Writes information about the construction parameters in |params|.
+  virtual void GetParameters(DictionaryValue* params) const = 0;
+
+  // Writes information about the current (non-empty) buckets and their sample
+  // counts to |buckets|, the total sample count to |count| and the total sum
+  // to |sum|.
+  virtual void GetCountAndBucketData(Count* count,
+                                     int64* sum,
+                                     ListValue* buckets) const = 0;
+
+  //// Produce actual graph (set of blank vs non blank char's) for a bucket.
+  void WriteAsciiBucketGraph(double current_size,
+                             double max_size,
+                             std::string* output) const;
+
+  // Return a string description of what goes in a given bucket.
+  const std::string GetSimpleAsciiBucketRange(Sample sample) const;
+
+  // Write textual description of the bucket contents (relative to histogram).
+  // Output is the count in the buckets, as well as the percentage.
+  void WriteAsciiBucketValue(Count current,
+                             double scaled_sum,
+                             std::string* output) const;
+
+ private:
+  const std::string histogram_name_;
+  int32_t flags_;
+
+  DISALLOW_COPY_AND_ASSIGN(HistogramBase);
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_HISTOGRAM_BASE_H_
diff --git a/base/metrics/histogram_base_unittest.cc b/base/metrics/histogram_base_unittest.cc
new file mode 100644
index 0000000..2d6b6df
--- /dev/null
+++ b/base/metrics/histogram_base_unittest.cc
@@ -0,0 +1,155 @@
+// Copyright (c) 2012 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 <vector>
+
+#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_base.h"
+#include "base/metrics/sparse_histogram.h"
+#include "base/metrics/statistics_recorder.h"
+#include "base/pickle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+class HistogramBaseTest : public testing::Test {
+ protected:
+  HistogramBaseTest() {
+    // Each test will have a clean state (no Histogram / BucketRanges
+    // registered).
+    statistics_recorder_ = NULL;
+    ResetStatisticsRecorder();
+  }
+
+  ~HistogramBaseTest() override { delete statistics_recorder_; }
+
+  void ResetStatisticsRecorder() {
+    delete statistics_recorder_;
+    statistics_recorder_ = new StatisticsRecorder();
+  }
+
+ private:
+  StatisticsRecorder* statistics_recorder_;
+};
+
+TEST_F(HistogramBaseTest, DeserializeHistogram) {
+  HistogramBase* histogram = Histogram::FactoryGet(
+      "TestHistogram", 1, 1000, 10,
+      (HistogramBase::kUmaTargetedHistogramFlag |
+      HistogramBase::kIPCSerializationSourceFlag));
+
+  Pickle pickle;
+  ASSERT_TRUE(histogram->SerializeInfo(&pickle));
+
+  PickleIterator iter(pickle);
+  HistogramBase* deserialized = DeserializeHistogramInfo(&iter);
+  EXPECT_EQ(histogram, deserialized);
+
+  ResetStatisticsRecorder();
+
+  PickleIterator iter2(pickle);
+  deserialized = DeserializeHistogramInfo(&iter2);
+  EXPECT_TRUE(deserialized);
+  EXPECT_NE(histogram, deserialized);
+  EXPECT_EQ("TestHistogram", deserialized->histogram_name());
+  EXPECT_TRUE(deserialized->HasConstructionArguments(1, 1000, 10));
+
+  // kIPCSerializationSourceFlag will be cleared.
+  EXPECT_EQ(HistogramBase::kUmaTargetedHistogramFlag, deserialized->flags());
+}
+
+TEST_F(HistogramBaseTest, DeserializeLinearHistogram) {
+  HistogramBase* histogram = LinearHistogram::FactoryGet(
+      "TestHistogram", 1, 1000, 10,
+      HistogramBase::kIPCSerializationSourceFlag);
+
+  Pickle pickle;
+  ASSERT_TRUE(histogram->SerializeInfo(&pickle));
+
+  PickleIterator iter(pickle);
+  HistogramBase* deserialized = DeserializeHistogramInfo(&iter);
+  EXPECT_EQ(histogram, deserialized);
+
+  ResetStatisticsRecorder();
+
+  PickleIterator iter2(pickle);
+  deserialized = DeserializeHistogramInfo(&iter2);
+  EXPECT_TRUE(deserialized);
+  EXPECT_NE(histogram, deserialized);
+  EXPECT_EQ("TestHistogram", deserialized->histogram_name());
+  EXPECT_TRUE(deserialized->HasConstructionArguments(1, 1000, 10));
+  EXPECT_EQ(0, deserialized->flags());
+}
+
+TEST_F(HistogramBaseTest, DeserializeBooleanHistogram) {
+  HistogramBase* histogram = BooleanHistogram::FactoryGet(
+      "TestHistogram", HistogramBase::kIPCSerializationSourceFlag);
+
+  Pickle pickle;
+  ASSERT_TRUE(histogram->SerializeInfo(&pickle));
+
+  PickleIterator iter(pickle);
+  HistogramBase* deserialized = DeserializeHistogramInfo(&iter);
+  EXPECT_EQ(histogram, deserialized);
+
+  ResetStatisticsRecorder();
+
+  PickleIterator iter2(pickle);
+  deserialized = DeserializeHistogramInfo(&iter2);
+  EXPECT_TRUE(deserialized);
+  EXPECT_NE(histogram, deserialized);
+  EXPECT_EQ("TestHistogram", deserialized->histogram_name());
+  EXPECT_TRUE(deserialized->HasConstructionArguments(1, 2, 3));
+  EXPECT_EQ(0, deserialized->flags());
+}
+
+TEST_F(HistogramBaseTest, DeserializeCustomHistogram) {
+  std::vector<HistogramBase::Sample> ranges;
+  ranges.push_back(13);
+  ranges.push_back(5);
+  ranges.push_back(9);
+
+  HistogramBase* histogram = CustomHistogram::FactoryGet(
+      "TestHistogram", ranges, HistogramBase::kIPCSerializationSourceFlag);
+
+  Pickle pickle;
+  ASSERT_TRUE(histogram->SerializeInfo(&pickle));
+
+  PickleIterator iter(pickle);
+  HistogramBase* deserialized = DeserializeHistogramInfo(&iter);
+  EXPECT_EQ(histogram, deserialized);
+
+  ResetStatisticsRecorder();
+
+  PickleIterator iter2(pickle);
+  deserialized = DeserializeHistogramInfo(&iter2);
+  EXPECT_TRUE(deserialized);
+  EXPECT_NE(histogram, deserialized);
+  EXPECT_EQ("TestHistogram", deserialized->histogram_name());
+  EXPECT_TRUE(deserialized->HasConstructionArguments(5, 13, 4));
+  EXPECT_EQ(0, deserialized->flags());
+}
+
+TEST_F(HistogramBaseTest, DeserializeSparseHistogram) {
+  HistogramBase* histogram = SparseHistogram::FactoryGet(
+      "TestHistogram", HistogramBase::kIPCSerializationSourceFlag);
+
+  Pickle pickle;
+  ASSERT_TRUE(histogram->SerializeInfo(&pickle));
+
+  PickleIterator iter(pickle);
+  HistogramBase* deserialized = DeserializeHistogramInfo(&iter);
+  EXPECT_EQ(histogram, deserialized);
+
+  ResetStatisticsRecorder();
+
+  PickleIterator iter2(pickle);
+  deserialized = DeserializeHistogramInfo(&iter2);
+  EXPECT_TRUE(deserialized);
+  EXPECT_NE(histogram, deserialized);
+  EXPECT_EQ("TestHistogram", deserialized->histogram_name());
+  EXPECT_EQ(0, deserialized->flags());
+}
+
+}  // namespace base
diff --git a/base/metrics/histogram_delta_serialization.cc b/base/metrics/histogram_delta_serialization.cc
new file mode 100644
index 0000000..e4aad13
--- /dev/null
+++ b/base/metrics/histogram_delta_serialization.cc
@@ -0,0 +1,111 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/metrics/histogram_delta_serialization.h"
+
+#include "base/logging.h"
+#include "base/metrics/histogram_base.h"
+#include "base/metrics/histogram_snapshot_manager.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/pickle.h"
+#include "base/values.h"
+
+namespace base {
+
+namespace {
+
+// Create or find existing histogram and add the samples from pickle.
+// Silently returns when seeing any data problem in the pickle.
+void DeserializeHistogramAndAddSamples(PickleIterator* iter) {
+  HistogramBase* histogram = DeserializeHistogramInfo(iter);
+  if (!histogram)
+    return;
+
+  if (histogram->flags() & HistogramBase::kIPCSerializationSourceFlag) {
+    DVLOG(1) << "Single process mode, histogram observed and not copied: "
+             << histogram->histogram_name();
+    return;
+  }
+  histogram->AddSamplesFromPickle(iter);
+}
+
+}  // namespace
+
+HistogramDeltaSerialization::HistogramDeltaSerialization(
+    const std::string& caller_name)
+    : histogram_snapshot_manager_(this),
+      serialized_deltas_(NULL) {
+  inconsistencies_histogram_ =
+      LinearHistogram::FactoryGet(
+          "Histogram.Inconsistencies" + caller_name, 1,
+          HistogramBase::NEVER_EXCEEDED_VALUE,
+          HistogramBase::NEVER_EXCEEDED_VALUE + 1,
+          HistogramBase::kUmaTargetedHistogramFlag);
+
+  inconsistencies_unique_histogram_ =
+      LinearHistogram::FactoryGet(
+          "Histogram.Inconsistencies" + caller_name + "Unique", 1,
+          HistogramBase::NEVER_EXCEEDED_VALUE,
+          HistogramBase::NEVER_EXCEEDED_VALUE + 1,
+          HistogramBase::kUmaTargetedHistogramFlag);
+
+  inconsistent_snapshot_histogram_ =
+      Histogram::FactoryGet(
+          "Histogram.InconsistentSnapshot" + caller_name, 1, 1000000, 50,
+          HistogramBase::kUmaTargetedHistogramFlag);
+}
+
+HistogramDeltaSerialization::~HistogramDeltaSerialization() {
+}
+
+void HistogramDeltaSerialization::PrepareAndSerializeDeltas(
+    std::vector<std::string>* serialized_deltas) {
+  serialized_deltas_ = serialized_deltas;
+  // Note: Before serializing, we set the kIPCSerializationSourceFlag for all
+  // the histograms, so that the receiving process can distinguish them from the
+  // local histograms.
+  histogram_snapshot_manager_.PrepareDeltas(
+      Histogram::kIPCSerializationSourceFlag, Histogram::kNoFlags);
+  serialized_deltas_ = NULL;
+}
+
+// static
+void HistogramDeltaSerialization::DeserializeAndAddSamples(
+    const std::vector<std::string>& serialized_deltas) {
+  for (std::vector<std::string>::const_iterator it = serialized_deltas.begin();
+       it != serialized_deltas.end(); ++it) {
+    Pickle pickle(it->data(), checked_cast<int>(it->size()));
+    PickleIterator iter(pickle);
+    DeserializeHistogramAndAddSamples(&iter);
+  }
+}
+
+void HistogramDeltaSerialization::RecordDelta(
+    const HistogramBase& histogram,
+    const HistogramSamples& snapshot) {
+  DCHECK_NE(0, snapshot.TotalCount());
+
+  Pickle pickle;
+  histogram.SerializeInfo(&pickle);
+  snapshot.Serialize(&pickle);
+  serialized_deltas_->push_back(
+      std::string(static_cast<const char*>(pickle.data()), pickle.size()));
+}
+
+void HistogramDeltaSerialization::InconsistencyDetected(
+    HistogramBase::Inconsistency problem) {
+  inconsistencies_histogram_->Add(problem);
+}
+
+void HistogramDeltaSerialization::UniqueInconsistencyDetected(
+    HistogramBase::Inconsistency problem) {
+  inconsistencies_unique_histogram_->Add(problem);
+}
+
+void HistogramDeltaSerialization::InconsistencyDetectedInLoggedCount(
+    int amount) {
+  inconsistent_snapshot_histogram_->Add(std::abs(amount));
+}
+
+}  // namespace base
diff --git a/base/metrics/histogram_delta_serialization.h b/base/metrics/histogram_delta_serialization.h
new file mode 100644
index 0000000..a379914
--- /dev/null
+++ b/base/metrics/histogram_delta_serialization.h
@@ -0,0 +1,64 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_METRICS_HISTOGRAM_DELTA_SERIALIZATION_H_
+#define BASE_METRICS_HISTOGRAM_DELTA_SERIALIZATION_H_
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/histogram_flattener.h"
+#include "base/metrics/histogram_snapshot_manager.h"
+
+namespace base {
+
+class HistogramBase;
+
+// Serializes and restores histograms deltas.
+class BASE_EXPORT HistogramDeltaSerialization : public HistogramFlattener {
+ public:
+  // |caller_name| is string used in histograms for counting inconsistencies.
+  explicit HistogramDeltaSerialization(const std::string& caller_name);
+  ~HistogramDeltaSerialization() override;
+
+  // Computes deltas in histogram bucket counts relative to the previous call to
+  // this method. Stores the deltas in serialized form into |serialized_deltas|.
+  // If |serialized_deltas| is NULL, no data is serialized, though the next call
+  // will compute the deltas relative to this one.
+  void PrepareAndSerializeDeltas(std::vector<std::string>* serialized_deltas);
+
+  // Deserialize deltas and add samples to corresponding histograms, creating
+  // them if necessary. Silently ignores errors in |serialized_deltas|.
+  static void DeserializeAndAddSamples(
+      const std::vector<std::string>& serialized_deltas);
+
+ private:
+  // HistogramFlattener implementation.
+  void RecordDelta(const HistogramBase& histogram,
+                   const HistogramSamples& snapshot) override;
+  void InconsistencyDetected(HistogramBase::Inconsistency problem) override;
+  void UniqueInconsistencyDetected(
+      HistogramBase::Inconsistency problem) override;
+  void InconsistencyDetectedInLoggedCount(int amount) override;
+
+  // Calculates deltas in histogram counters.
+  HistogramSnapshotManager histogram_snapshot_manager_;
+
+  // Output buffer for serialized deltas.
+  std::vector<std::string>* serialized_deltas_;
+
+  // Histograms to count inconsistencies in snapshots.
+  HistogramBase* inconsistencies_histogram_;
+  HistogramBase* inconsistencies_unique_histogram_;
+  HistogramBase* inconsistent_snapshot_histogram_;
+
+  DISALLOW_COPY_AND_ASSIGN(HistogramDeltaSerialization);
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_HISTOGRAM_DELTA_SERIALIZATION_H_
diff --git a/base/metrics/histogram_delta_serialization_unittest.cc b/base/metrics/histogram_delta_serialization_unittest.cc
new file mode 100644
index 0000000..b53520c
--- /dev/null
+++ b/base/metrics/histogram_delta_serialization_unittest.cc
@@ -0,0 +1,54 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/metrics/histogram_delta_serialization.h"
+
+#include <vector>
+
+#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_base.h"
+#include "base/metrics/statistics_recorder.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(HistogramDeltaSerializationTest, DeserializeHistogramAndAddSamples) {
+  StatisticsRecorder statistic_recorder;
+  HistogramDeltaSerialization serializer("HistogramDeltaSerializationTest");
+  std::vector<std::string> deltas;
+  // Nothing was changed yet.
+  serializer.PrepareAndSerializeDeltas(&deltas);
+  EXPECT_TRUE(deltas.empty());
+
+  HistogramBase* histogram = Histogram::FactoryGet(
+      "TestHistogram", 1, 1000, 10, HistogramBase::kIPCSerializationSourceFlag);
+  histogram->Add(1);
+  histogram->Add(10);
+  histogram->Add(100);
+  histogram->Add(1000);
+
+  serializer.PrepareAndSerializeDeltas(&deltas);
+  EXPECT_FALSE(deltas.empty());
+
+  HistogramDeltaSerialization::DeserializeAndAddSamples(deltas);
+
+  // The histogram has kIPCSerializationSourceFlag. So samples will be ignored.
+  scoped_ptr<HistogramSamples> snapshot(histogram->SnapshotSamples());
+  EXPECT_EQ(1, snapshot->GetCount(1));
+  EXPECT_EQ(1, snapshot->GetCount(10));
+  EXPECT_EQ(1, snapshot->GetCount(100));
+  EXPECT_EQ(1, snapshot->GetCount(1000));
+
+  // Clear kIPCSerializationSourceFlag to emulate multi-process usage.
+  histogram->ClearFlags(HistogramBase::kIPCSerializationSourceFlag);
+  HistogramDeltaSerialization::DeserializeAndAddSamples(deltas);
+
+  scoped_ptr<HistogramSamples> snapshot2(histogram->SnapshotSamples());
+  EXPECT_EQ(2, snapshot2->GetCount(1));
+  EXPECT_EQ(2, snapshot2->GetCount(10));
+  EXPECT_EQ(2, snapshot2->GetCount(100));
+  EXPECT_EQ(2, snapshot2->GetCount(1000));
+}
+
+}  // namespace base
diff --git a/base/metrics/histogram_flattener.h b/base/metrics/histogram_flattener.h
new file mode 100644
index 0000000..ca05a4f
--- /dev/null
+++ b/base/metrics/histogram_flattener.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2012 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_METRICS_HISTOGRAM_FLATTENER_H_
+#define BASE_METRICS_HISTOGRAM_FLATTENER_H_
+
+#include <map>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/metrics/histogram.h"
+
+namespace base {
+
+class HistogramSamples;
+
+// HistogramFlattener is an interface used by HistogramSnapshotManager, which
+// handles the logistics of gathering up available histograms for recording.
+// The implementors handle the exact lower level recording mechanism, or
+// error report mechanism.
+class BASE_EXPORT HistogramFlattener {
+ public:
+  virtual void RecordDelta(const HistogramBase& histogram,
+                           const HistogramSamples& snapshot) = 0;
+
+  // Will be called each time a type of Inconsistency is seen on a histogram,
+  // during inspections done internally in HistogramSnapshotManager class.
+  virtual void InconsistencyDetected(HistogramBase::Inconsistency problem) = 0;
+
+  // Will be called when a type of Inconsistency is seen for the first time on
+  // a histogram.
+  virtual void UniqueInconsistencyDetected(
+      HistogramBase::Inconsistency problem) = 0;
+
+  // Will be called when the total logged sample count of a histogram
+  // differs from the sum of logged sample count in all the buckets.  The
+  // argument |amount| is the non-zero discrepancy.
+  virtual void InconsistencyDetectedInLoggedCount(int amount) = 0;
+
+ protected:
+  HistogramFlattener() {}
+  virtual ~HistogramFlattener() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HistogramFlattener);
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_HISTOGRAM_FLATTENER_H_
diff --git a/base/metrics/histogram_macros.h b/base/metrics/histogram_macros.h
new file mode 100644
index 0000000..2aee1a5
--- /dev/null
+++ b/base/metrics/histogram_macros.h
@@ -0,0 +1,264 @@
+// 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.
+
+#ifndef BASE_METRICS_HISTOGRAM_MACROS_H_
+#define BASE_METRICS_HISTOGRAM_MACROS_H_
+
+#include "base/atomicops.h"
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/metrics/histogram.h"
+#include "base/time/time.h"
+
+//------------------------------------------------------------------------------
+// Histograms are often put in areas where they are called many many times, and
+// performance is critical.  As a result, they are designed to have a very low
+// recurring cost of executing (adding additional samples).  Toward that end,
+// the macros declare a static pointer to the histogram in question, and only
+// take a "slow path" to construct (or find) the histogram on the first run
+// through the macro.  We leak the histograms at shutdown time so that we don't
+// have to validate using the pointers at any time during the running of the
+// process.
+
+// The following code is generally what a thread-safe static pointer
+// initialization looks like for a histogram (after a macro is expanded).  This
+// sample is an expansion (with comments) of the code for
+// LOCAL_HISTOGRAM_CUSTOM_COUNTS().
+
+/*
+  do {
+    // The pointer's presence indicates the initialization is complete.
+    // Initialization is idempotent, so it can safely be atomically repeated.
+    static base::subtle::AtomicWord atomic_histogram_pointer = 0;
+
+    // Acquire_Load() ensures that we acquire visibility to the pointed-to data
+    // in the histogram.
+    base::Histogram* histogram_pointer(reinterpret_cast<base::Histogram*>(
+        base::subtle::Acquire_Load(&atomic_histogram_pointer)));
+
+    if (!histogram_pointer) {
+      // This is the slow path, which will construct OR find the matching
+      // histogram.  FactoryGet includes locks on a global histogram name map
+      // and is completely thread safe.
+      histogram_pointer = base::Histogram::FactoryGet(
+          name, min, max, bucket_count, base::HistogramBase::kNoFlags);
+
+      // Use Release_Store to ensure that the histogram data is made available
+      // globally before we make the pointer visible.
+      // Several threads may perform this store, but the same value will be
+      // stored in all cases (for a given named/spec'ed histogram).
+      // We could do this without any barrier, since FactoryGet entered and
+      // exited a lock after construction, but this barrier makes things clear.
+      base::subtle::Release_Store(&atomic_histogram_pointer,
+          reinterpret_cast<base::subtle::AtomicWord>(histogram_pointer));
+    }
+
+    // Ensure calling contract is upheld, and the name does NOT vary.
+    DCHECK(histogram_pointer->histogram_name() == constant_histogram_name);
+
+    histogram_pointer->Add(sample);
+  } while (0);
+*/
+
+// The above pattern is repeated in several macros.  The only elements that
+// vary are the invocation of the Add(sample) vs AddTime(sample), and the choice
+// of which FactoryGet method to use.  The different FactoryGet methods have
+// various argument lists, so the function with its argument list is provided as
+// a macro argument here.  The name is only used in a DCHECK, to assure that
+// callers don't try to vary the name of the histogram (which would tend to be
+// ignored by the one-time initialization of the histogtram_pointer).
+#define STATIC_HISTOGRAM_POINTER_BLOCK(constant_histogram_name,           \
+                                       histogram_add_method_invocation,   \
+                                       histogram_factory_get_invocation)  \
+  do {                                                                    \
+    static base::subtle::AtomicWord atomic_histogram_pointer = 0;         \
+    base::HistogramBase* histogram_pointer(                               \
+        reinterpret_cast<base::HistogramBase*>(                           \
+            base::subtle::Acquire_Load(&atomic_histogram_pointer)));      \
+    if (!histogram_pointer) {                                             \
+      histogram_pointer = histogram_factory_get_invocation;               \
+      base::subtle::Release_Store(                                        \
+          &atomic_histogram_pointer,                                      \
+          reinterpret_cast<base::subtle::AtomicWord>(histogram_pointer)); \
+    }                                                                     \
+    if (DCHECK_IS_ON())                                                   \
+      histogram_pointer->CheckName(constant_histogram_name);              \
+    histogram_pointer->histogram_add_method_invocation;                   \
+  } while (0)
+
+//------------------------------------------------------------------------------
+// Provide easy general purpose histogram in a macro, just like stats counters.
+// The first four macros use 50 buckets.
+
+#define LOCAL_HISTOGRAM_TIMES(name, sample) LOCAL_HISTOGRAM_CUSTOM_TIMES( \
+    name, sample, base::TimeDelta::FromMilliseconds(1), \
+    base::TimeDelta::FromSeconds(10), 50)
+
+// For folks that need real specific times, use this to select a precise range
+// of times you want plotted, and the number of buckets you want used.
+#define LOCAL_HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) \
+    STATIC_HISTOGRAM_POINTER_BLOCK(name, AddTime(sample), \
+        base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \
+                                        base::HistogramBase::kNoFlags))
+
+#define LOCAL_HISTOGRAM_COUNTS(name, sample) LOCAL_HISTOGRAM_CUSTOM_COUNTS( \
+    name, sample, 1, 1000000, 50)
+
+#define LOCAL_HISTOGRAM_COUNTS_100(name, sample) \
+    LOCAL_HISTOGRAM_CUSTOM_COUNTS(name, sample, 1, 100, 50)
+
+#define LOCAL_HISTOGRAM_COUNTS_10000(name, sample) \
+    LOCAL_HISTOGRAM_CUSTOM_COUNTS(name, sample, 1, 10000, 50)
+
+#define LOCAL_HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \
+    STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
+        base::Histogram::FactoryGet(name, min, max, bucket_count, \
+                                    base::HistogramBase::kNoFlags))
+
+// This is a helper macro used by other macros and shouldn't be used directly.
+#define HISTOGRAM_ENUMERATION_WITH_FLAG(name, sample, boundary, flag) \
+    STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
+        base::LinearHistogram::FactoryGet(name, 1, boundary, boundary + 1, \
+            flag))
+
+#define LOCAL_HISTOGRAM_PERCENTAGE(name, under_one_hundred) \
+    LOCAL_HISTOGRAM_ENUMERATION(name, under_one_hundred, 101)
+
+#define LOCAL_HISTOGRAM_BOOLEAN(name, sample) \
+    STATIC_HISTOGRAM_POINTER_BLOCK(name, AddBoolean(sample), \
+        base::BooleanHistogram::FactoryGet(name, base::Histogram::kNoFlags))
+
+// Support histograming of an enumerated value.  The samples should always be
+// strictly less than |boundary_value| -- this prevents you from running into
+// problems down the line if you add additional buckets to the histogram.  Note
+// also that, despite explicitly setting the minimum bucket value to |1| below,
+// it is fine for enumerated histograms to be 0-indexed -- this is because
+// enumerated histograms should never have underflow.
+#define LOCAL_HISTOGRAM_ENUMERATION(name, sample, boundary_value) \
+    STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
+        base::LinearHistogram::FactoryGet(name, 1, boundary_value, \
+            boundary_value + 1, base::HistogramBase::kNoFlags))
+
+// Support histograming of an enumerated value. Samples should be one of the
+// std::vector<int> list provided via |custom_ranges|. See comments above
+// CustomRanges::FactoryGet about the requirement of |custom_ranges|.
+// You can use the helper function CustomHistogram::ArrayToCustomRanges to
+// transform a C-style array of valid sample values to a std::vector<int>.
+#define LOCAL_HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) \
+    STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
+        base::CustomHistogram::FactoryGet(name, custom_ranges, \
+                                          base::HistogramBase::kNoFlags))
+
+#define LOCAL_HISTOGRAM_MEMORY_KB(name, sample) LOCAL_HISTOGRAM_CUSTOM_COUNTS( \
+    name, sample, 1000, 500000, 50)
+
+//------------------------------------------------------------------------------
+// The following macros provide typical usage scenarios for callers that wish
+// to record histogram data, and have the data submitted/uploaded via UMA.
+// Not all systems support such UMA, but if they do, the following macros
+// should work with the service.
+
+#define UMA_HISTOGRAM_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
+    name, sample, base::TimeDelta::FromMilliseconds(1), \
+    base::TimeDelta::FromSeconds(10), 50)
+
+#define UMA_HISTOGRAM_MEDIUM_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
+    name, sample, base::TimeDelta::FromMilliseconds(10), \
+    base::TimeDelta::FromMinutes(3), 50)
+
+// Use this macro when times can routinely be much longer than 10 seconds.
+#define UMA_HISTOGRAM_LONG_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
+    name, sample, base::TimeDelta::FromMilliseconds(1), \
+    base::TimeDelta::FromHours(1), 50)
+
+// Use this macro when times can routinely be much longer than 10 seconds and
+// you want 100 buckets.
+#define UMA_HISTOGRAM_LONG_TIMES_100(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
+    name, sample, base::TimeDelta::FromMilliseconds(1), \
+    base::TimeDelta::FromHours(1), 100)
+
+#define UMA_HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) \
+    STATIC_HISTOGRAM_POINTER_BLOCK(name, AddTime(sample), \
+        base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \
+            base::HistogramBase::kUmaTargetedHistogramFlag))
+
+#define UMA_HISTOGRAM_COUNTS(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
+    name, sample, 1, 1000000, 50)
+
+#define UMA_HISTOGRAM_COUNTS_100(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
+    name, sample, 1, 100, 50)
+
+#define UMA_HISTOGRAM_COUNTS_10000(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
+    name, sample, 1, 10000, 50)
+
+#define UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \
+    STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
+        base::Histogram::FactoryGet(name, min, max, bucket_count, \
+            base::HistogramBase::kUmaTargetedHistogramFlag))
+
+#define UMA_HISTOGRAM_MEMORY_KB(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
+    name, sample, 1000, 500000, 50)
+
+#define UMA_HISTOGRAM_MEMORY_MB(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
+    name, sample, 1, 1000, 50)
+
+#define UMA_HISTOGRAM_PERCENTAGE(name, under_one_hundred) \
+    UMA_HISTOGRAM_ENUMERATION(name, under_one_hundred, 101)
+
+#define UMA_HISTOGRAM_BOOLEAN(name, sample) \
+    STATIC_HISTOGRAM_POINTER_BLOCK(name, AddBoolean(sample), \
+        base::BooleanHistogram::FactoryGet(name, \
+            base::HistogramBase::kUmaTargetedHistogramFlag))
+
+// The samples should always be strictly less than |boundary_value|.  For more
+// details, see the comment for the |LOCAL_HISTOGRAM_ENUMERATION| macro, above.
+#define UMA_HISTOGRAM_ENUMERATION(name, sample, boundary_value) \
+    HISTOGRAM_ENUMERATION_WITH_FLAG(name, sample, boundary_value, \
+        base::HistogramBase::kUmaTargetedHistogramFlag)
+
+// Similar to UMA_HISTOGRAM_ENUMERATION, but used for recording stability
+// histograms.  Use this if recording a histogram that should be part of the
+// initial stability log.
+#define UMA_STABILITY_HISTOGRAM_ENUMERATION(name, sample, boundary_value) \
+    HISTOGRAM_ENUMERATION_WITH_FLAG(name, sample, boundary_value, \
+        base::HistogramBase::kUmaStabilityHistogramFlag)
+
+#define UMA_HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) \
+    STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
+        base::CustomHistogram::FactoryGet(name, custom_ranges, \
+            base::HistogramBase::kUmaTargetedHistogramFlag))
+
+// Scoped class which logs its time on this earth as a UMA statistic. This is
+// recommended for when you want a histogram which measures the time it takes
+// for a method to execute. This measures up to 10 seconds.
+#define SCOPED_UMA_HISTOGRAM_TIMER(name) \
+  SCOPED_UMA_HISTOGRAM_TIMER_EXPANDER(name, false, __COUNTER__)
+
+// Similar scoped histogram timer, but this uses UMA_HISTOGRAM_LONG_TIMES_100,
+// which measures up to an hour, and uses 100 buckets. This is more expensive
+// to store, so only use if this often takes >10 seconds.
+#define SCOPED_UMA_HISTOGRAM_LONG_TIMER(name) \
+  SCOPED_UMA_HISTOGRAM_TIMER_EXPANDER(name, true, __COUNTER__)
+
+// This nested macro is necessary to expand __COUNTER__ to an actual value.
+#define SCOPED_UMA_HISTOGRAM_TIMER_EXPANDER(name, is_long, key) \
+  SCOPED_UMA_HISTOGRAM_TIMER_UNIQUE(name, is_long, key)
+
+#define SCOPED_UMA_HISTOGRAM_TIMER_UNIQUE(name, is_long, key) \
+  class ScopedHistogramTimer##key { \
+   public: \
+    ScopedHistogramTimer##key() : constructed_(base::TimeTicks::Now()) {} \
+    ~ScopedHistogramTimer##key() { \
+      base::TimeDelta elapsed = base::TimeTicks::Now() - constructed_; \
+      if (is_long) { \
+        UMA_HISTOGRAM_LONG_TIMES_100(name, elapsed); \
+      } else { \
+        UMA_HISTOGRAM_TIMES(name, elapsed); \
+      } \
+    } \
+   private: \
+    base::TimeTicks constructed_; \
+  } scoped_histogram_timer_##key
+
+#endif  // BASE_METRICS_HISTOGRAM_MACROS_H_
diff --git a/base/metrics/histogram_macros_unittest.cc b/base/metrics/histogram_macros_unittest.cc
new file mode 100644
index 0000000..c599161
--- /dev/null
+++ b/base/metrics/histogram_macros_unittest.cc
@@ -0,0 +1,18 @@
+// 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/metrics/histogram_macros.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(ScopedHistogramTimer, TwoTimersOneScope) {
+  SCOPED_UMA_HISTOGRAM_TIMER("TestTimer0");
+  SCOPED_UMA_HISTOGRAM_TIMER("TestTimer1");
+  SCOPED_UMA_HISTOGRAM_LONG_TIMER("TestLongTimer0");
+  SCOPED_UMA_HISTOGRAM_LONG_TIMER("TestLongTimer1");
+}
+
+}  // namespace base
diff --git a/base/metrics/histogram_samples.cc b/base/metrics/histogram_samples.cc
new file mode 100644
index 0000000..f5e03b9
--- /dev/null
+++ b/base/metrics/histogram_samples.cc
@@ -0,0 +1,138 @@
+// Copyright (c) 2012 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/metrics/histogram_samples.h"
+
+#include "base/compiler_specific.h"
+#include "base/pickle.h"
+
+namespace base {
+
+namespace {
+
+class SampleCountPickleIterator : public SampleCountIterator {
+ public:
+  explicit SampleCountPickleIterator(PickleIterator* iter);
+
+  bool Done() const override;
+  void Next() override;
+  void Get(HistogramBase::Sample* min,
+           HistogramBase::Sample* max,
+           HistogramBase::Count* count) const override;
+
+ private:
+  PickleIterator* const iter_;
+
+  HistogramBase::Sample min_;
+  HistogramBase::Sample max_;
+  HistogramBase::Count count_;
+  bool is_done_;
+};
+
+SampleCountPickleIterator::SampleCountPickleIterator(PickleIterator* iter)
+    : iter_(iter),
+      is_done_(false) {
+  Next();
+}
+
+bool SampleCountPickleIterator::Done() const {
+  return is_done_;
+}
+
+void SampleCountPickleIterator::Next() {
+  DCHECK(!Done());
+  if (!iter_->ReadInt(&min_) ||
+      !iter_->ReadInt(&max_) ||
+      !iter_->ReadInt(&count_))
+    is_done_ = true;
+}
+
+void SampleCountPickleIterator::Get(HistogramBase::Sample* min,
+                                    HistogramBase::Sample* max,
+                                    HistogramBase::Count* count) const {
+  DCHECK(!Done());
+  *min = min_;
+  *max = max_;
+  *count = count_;
+}
+
+}  // namespace
+
+HistogramSamples::HistogramSamples() : sum_(0), redundant_count_(0) {}
+
+HistogramSamples::~HistogramSamples() {}
+
+void HistogramSamples::Add(const HistogramSamples& other) {
+  sum_ += other.sum();
+  HistogramBase::Count old_redundant_count =
+      subtle::NoBarrier_Load(&redundant_count_);
+  subtle::NoBarrier_Store(&redundant_count_,
+      old_redundant_count + other.redundant_count());
+  bool success = AddSubtractImpl(other.Iterator().get(), ADD);
+  DCHECK(success);
+}
+
+bool HistogramSamples::AddFromPickle(PickleIterator* iter) {
+  int64 sum;
+  HistogramBase::Count redundant_count;
+
+  if (!iter->ReadInt64(&sum) || !iter->ReadInt(&redundant_count))
+    return false;
+  sum_ += sum;
+  HistogramBase::Count old_redundant_count =
+      subtle::NoBarrier_Load(&redundant_count_);
+  subtle::NoBarrier_Store(&redundant_count_,
+                          old_redundant_count + redundant_count);
+
+  SampleCountPickleIterator pickle_iter(iter);
+  return AddSubtractImpl(&pickle_iter, ADD);
+}
+
+void HistogramSamples::Subtract(const HistogramSamples& other) {
+  sum_ -= other.sum();
+  HistogramBase::Count old_redundant_count =
+      subtle::NoBarrier_Load(&redundant_count_);
+  subtle::NoBarrier_Store(&redundant_count_,
+                          old_redundant_count - other.redundant_count());
+  bool success = AddSubtractImpl(other.Iterator().get(), SUBTRACT);
+  DCHECK(success);
+}
+
+bool HistogramSamples::Serialize(Pickle* pickle) const {
+  if (!pickle->WriteInt64(sum_) ||
+      !pickle->WriteInt(subtle::NoBarrier_Load(&redundant_count_)))
+    return false;
+
+  HistogramBase::Sample min;
+  HistogramBase::Sample max;
+  HistogramBase::Count count;
+  for (scoped_ptr<SampleCountIterator> it = Iterator();
+       !it->Done();
+       it->Next()) {
+    it->Get(&min, &max, &count);
+    if (!pickle->WriteInt(min) ||
+        !pickle->WriteInt(max) ||
+        !pickle->WriteInt(count))
+      return false;
+  }
+  return true;
+}
+
+void HistogramSamples::IncreaseSum(int64 diff) {
+  sum_ += diff;
+}
+
+void HistogramSamples::IncreaseRedundantCount(HistogramBase::Count diff) {
+  subtle::NoBarrier_Store(&redundant_count_,
+      subtle::NoBarrier_Load(&redundant_count_) + diff);
+}
+
+SampleCountIterator::~SampleCountIterator() {}
+
+bool SampleCountIterator::GetBucketIndex(size_t* index) const {
+  DCHECK(!Done());
+  return false;
+}
+
+}  // namespace base
diff --git a/base/metrics/histogram_samples.h b/base/metrics/histogram_samples.h
new file mode 100644
index 0000000..54185cf
--- /dev/null
+++ b/base/metrics/histogram_samples.h
@@ -0,0 +1,88 @@
+// Copyright (c) 2012 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_METRICS_HISTOGRAM_SAMPLES_H_
+#define BASE_METRICS_HISTOGRAM_SAMPLES_H_
+
+#include "base/basictypes.h"
+#include "base/metrics/histogram_base.h"
+#include "base/memory/scoped_ptr.h"
+
+namespace base {
+
+class Pickle;
+class PickleIterator;
+class SampleCountIterator;
+
+// HistogramSamples is a container storing all samples of a histogram.
+class BASE_EXPORT HistogramSamples {
+ public:
+  HistogramSamples();
+  virtual ~HistogramSamples();
+
+  virtual void Accumulate(HistogramBase::Sample value,
+                          HistogramBase::Count count) = 0;
+  virtual HistogramBase::Count GetCount(HistogramBase::Sample value) const = 0;
+  virtual HistogramBase::Count TotalCount() const = 0;
+
+  virtual void Add(const HistogramSamples& other);
+
+  // Add from serialized samples.
+  virtual bool AddFromPickle(PickleIterator* iter);
+
+  virtual void Subtract(const HistogramSamples& other);
+
+  virtual scoped_ptr<SampleCountIterator> Iterator() const = 0;
+  virtual bool Serialize(Pickle* pickle) const;
+
+  // Accessor fuctions.
+  int64 sum() const { return sum_; }
+  HistogramBase::Count redundant_count() const {
+    return subtle::NoBarrier_Load(&redundant_count_);
+  }
+
+ protected:
+  // Based on |op| type, add or subtract sample counts data from the iterator.
+  enum Operator { ADD, SUBTRACT };
+  virtual bool AddSubtractImpl(SampleCountIterator* iter, Operator op) = 0;
+
+  void IncreaseSum(int64 diff);
+  void IncreaseRedundantCount(HistogramBase::Count diff);
+
+ private:
+  int64 sum_;
+
+  // |redundant_count_| helps identify memory corruption. It redundantly stores
+  // the total number of samples accumulated in the histogram. We can compare
+  // this count to the sum of the counts (TotalCount() function), and detect
+  // problems. Note, depending on the implementation of different histogram
+  // types, there might be races during histogram accumulation and snapshotting
+  // that we choose to accept. In this case, the tallies might mismatch even
+  // when no memory corruption has happened.
+  HistogramBase::AtomicCount redundant_count_;
+};
+
+class BASE_EXPORT SampleCountIterator {
+ public:
+  virtual ~SampleCountIterator();
+
+  virtual bool Done() const = 0;
+  virtual void Next() = 0;
+
+  // Get the sample and count at current position.
+  // |min| |max| and |count| can be NULL if the value is not of interest.
+  // Requires: !Done();
+  virtual void Get(HistogramBase::Sample* min,
+                   HistogramBase::Sample* max,
+                   HistogramBase::Count* count) const = 0;
+
+  // Get the index of current histogram bucket.
+  // For histograms that don't use predefined buckets, it returns false.
+  // Requires: !Done();
+  virtual bool GetBucketIndex(size_t* index) const;
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_HISTOGRAM_SAMPLES_H_
diff --git a/base/metrics/histogram_snapshot_manager.cc b/base/metrics/histogram_snapshot_manager.cc
new file mode 100644
index 0000000..a7605aa
--- /dev/null
+++ b/base/metrics/histogram_snapshot_manager.cc
@@ -0,0 +1,113 @@
+// Copyright (c) 2012 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/metrics/histogram_snapshot_manager.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/histogram_flattener.h"
+#include "base/metrics/histogram_samples.h"
+#include "base/metrics/statistics_recorder.h"
+#include "base/stl_util.h"
+
+namespace base {
+
+HistogramSnapshotManager::HistogramSnapshotManager(
+    HistogramFlattener* histogram_flattener)
+    : histogram_flattener_(histogram_flattener) {
+  DCHECK(histogram_flattener_);
+}
+
+HistogramSnapshotManager::~HistogramSnapshotManager() {
+  STLDeleteValues(&logged_samples_);
+}
+
+void HistogramSnapshotManager::PrepareDeltas(
+    HistogramBase::Flags flag_to_set,
+    HistogramBase::Flags required_flags) {
+  StatisticsRecorder::Histograms histograms;
+  StatisticsRecorder::GetHistograms(&histograms);
+  for (StatisticsRecorder::Histograms::const_iterator it = histograms.begin();
+       histograms.end() != it;
+       ++it) {
+    (*it)->SetFlags(flag_to_set);
+    if (((*it)->flags() & required_flags) == required_flags)
+      PrepareDelta(**it);
+  }
+}
+
+void HistogramSnapshotManager::PrepareDelta(const HistogramBase& histogram) {
+  DCHECK(histogram_flattener_);
+
+  // Get up-to-date snapshot of sample stats.
+  scoped_ptr<HistogramSamples> snapshot(histogram.SnapshotSamples());
+  const std::string& histogram_name = histogram.histogram_name();
+
+  int corruption = histogram.FindCorruption(*snapshot);
+
+  // Crash if we detect that our histograms have been overwritten.  This may be
+  // a fair distance from the memory smasher, but we hope to correlate these
+  // crashes with other events, such as plugins, or usage patterns, etc.
+  if (HistogramBase::BUCKET_ORDER_ERROR & corruption) {
+    // The checksum should have caught this, so crash separately if it didn't.
+    CHECK_NE(0, HistogramBase::RANGE_CHECKSUM_ERROR & corruption);
+    CHECK(false);  // Crash for the bucket order corruption.
+  }
+  // Checksum corruption might not have caused order corruption.
+  CHECK_EQ(0, HistogramBase::RANGE_CHECKSUM_ERROR & corruption);
+
+  // Note, at this point corruption can only be COUNT_HIGH_ERROR or
+  // COUNT_LOW_ERROR and they never arise together, so we don't need to extract
+  // bits from corruption.
+  if (corruption) {
+    DLOG(ERROR) << "Histogram: " << histogram_name
+                << " has data corruption: " << corruption;
+    histogram_flattener_->InconsistencyDetected(
+        static_cast<HistogramBase::Inconsistency>(corruption));
+    // Don't record corrupt data to metrics services.
+    int old_corruption = inconsistencies_[histogram_name];
+    if (old_corruption == (corruption | old_corruption))
+      return;  // We've already seen this corruption for this histogram.
+    inconsistencies_[histogram_name] |= corruption;
+    histogram_flattener_->UniqueInconsistencyDetected(
+        static_cast<HistogramBase::Inconsistency>(corruption));
+    return;
+  }
+
+  HistogramSamples* to_log;
+  std::map<std::string, HistogramSamples*>::iterator it =
+      logged_samples_.find(histogram_name);
+  if (it == logged_samples_.end()) {
+    to_log = snapshot.release();
+
+    // This histogram has not been logged before, add a new entry.
+    logged_samples_[histogram_name] = to_log;
+  } else {
+    HistogramSamples* already_logged = it->second;
+    InspectLoggedSamplesInconsistency(*snapshot, already_logged);
+    snapshot->Subtract(*already_logged);
+    already_logged->Add(*snapshot);
+    to_log = snapshot.get();
+  }
+
+  if (to_log->TotalCount() > 0)
+    histogram_flattener_->RecordDelta(histogram, *to_log);
+}
+
+void HistogramSnapshotManager::InspectLoggedSamplesInconsistency(
+      const HistogramSamples& new_snapshot,
+      HistogramSamples* logged_samples) {
+  HistogramBase::Count discrepancy =
+      logged_samples->TotalCount() - logged_samples->redundant_count();
+  if (!discrepancy)
+    return;
+
+  histogram_flattener_->InconsistencyDetectedInLoggedCount(discrepancy);
+  if (discrepancy > Histogram::kCommonRaceBasedCountMismatch) {
+    // Fix logged_samples.
+    logged_samples->Subtract(*logged_samples);
+    logged_samples->Add(new_snapshot);
+  }
+}
+
+}  // namespace base
diff --git a/base/metrics/histogram_snapshot_manager.h b/base/metrics/histogram_snapshot_manager.h
new file mode 100644
index 0000000..5a5f2e9
--- /dev/null
+++ b/base/metrics/histogram_snapshot_manager.h
@@ -0,0 +1,65 @@
+// Copyright (c) 2012 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_METRICS_HISTOGRAM_SNAPSHOT_MANAGER_H_
+#define BASE_METRICS_HISTOGRAM_SNAPSHOT_MANAGER_H_
+
+#include <map>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/metrics/histogram_base.h"
+
+namespace base {
+
+class HistogramSamples;
+class HistogramFlattener;
+
+// HistogramSnapshotManager handles the logistics of gathering up available
+// histograms for recording either to disk or for transmission (such as from
+// renderer to browser, or from browser to UMA upload). Since histograms can sit
+// in memory for an extended period of time, and are vulnerable to memory
+// corruption, this class also validates as much rendundancy as it can before
+// calling for the marginal change (a.k.a., delta) in a histogram to be
+// recorded.
+class BASE_EXPORT HistogramSnapshotManager {
+ public:
+  explicit HistogramSnapshotManager(HistogramFlattener* histogram_flattener);
+  virtual ~HistogramSnapshotManager();
+
+  // Snapshot all histograms, and ask |histogram_flattener_| to record the
+  // delta. |flags_to_set| is used to set flags for each histogram.
+  // |required_flags| is used to select histograms to be recorded.
+  // Only histograms that have all the flags specified by the argument will be
+  // chosen. If all histograms should be recorded, set it to
+  // |Histogram::kNoFlags|.
+  void PrepareDeltas(HistogramBase::Flags flags_to_set,
+                     HistogramBase::Flags required_flags);
+
+ private:
+  // Snapshot this histogram, and record the delta.
+  void PrepareDelta(const HistogramBase& histogram);
+
+  // Try to detect and fix count inconsistency of logged samples.
+  void InspectLoggedSamplesInconsistency(
+      const HistogramSamples& new_snapshot,
+      HistogramSamples* logged_samples);
+
+  // For histograms, track what we've already recorded (as a sample for
+  // each histogram) so that we can record only the delta with the next log.
+  std::map<std::string, HistogramSamples*> logged_samples_;
+
+  // List of histograms found to be corrupt, and their problems.
+  std::map<std::string, int> inconsistencies_;
+
+  // |histogram_flattener_| handles the logistics of recording the histogram
+  // deltas.
+  HistogramFlattener* histogram_flattener_;  // Weak.
+
+  DISALLOW_COPY_AND_ASSIGN(HistogramSnapshotManager);
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_HISTOGRAM_SNAPSHOT_MANAGER_H_
diff --git a/base/metrics/histogram_snapshot_manager_unittest.cc b/base/metrics/histogram_snapshot_manager_unittest.cc
new file mode 100644
index 0000000..3a1fd40
--- /dev/null
+++ b/base/metrics/histogram_snapshot_manager_unittest.cc
@@ -0,0 +1,105 @@
+// 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.
+
+#include "base/metrics/histogram_snapshot_manager.h"
+
+#include <string>
+#include <vector>
+
+#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_delta_serialization.h"
+#include "base/metrics/statistics_recorder.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+class HistogramFlattenerDeltaRecorder : public HistogramFlattener {
+ public:
+  HistogramFlattenerDeltaRecorder() {}
+
+  void RecordDelta(const HistogramBase& histogram,
+                   const HistogramSamples& snapshot) override {
+    recorded_delta_histogram_names_.push_back(histogram.histogram_name());
+  }
+
+  void InconsistencyDetected(HistogramBase::Inconsistency problem) override {
+    ASSERT_TRUE(false);
+  }
+
+  void UniqueInconsistencyDetected(
+      HistogramBase::Inconsistency problem) override {
+    ASSERT_TRUE(false);
+  }
+
+  void InconsistencyDetectedInLoggedCount(int amount) override {
+    ASSERT_TRUE(false);
+  }
+
+  std::vector<std::string> GetRecordedDeltaHistogramNames() {
+    return recorded_delta_histogram_names_;
+  }
+
+ private:
+  std::vector<std::string> recorded_delta_histogram_names_;
+
+  DISALLOW_COPY_AND_ASSIGN(HistogramFlattenerDeltaRecorder);
+};
+
+class HistogramSnapshotManagerTest : public testing::Test {
+ protected:
+  HistogramSnapshotManagerTest()
+      : histogram_snapshot_manager_(&histogram_flattener_delta_recorder_) {}
+
+  ~HistogramSnapshotManagerTest() override {}
+
+  StatisticsRecorder statistics_recorder_;
+  HistogramFlattenerDeltaRecorder histogram_flattener_delta_recorder_;
+  HistogramSnapshotManager histogram_snapshot_manager_;
+};
+
+TEST_F(HistogramSnapshotManagerTest, PrepareDeltasNoFlagsFilter) {
+  // kNoFlags filter should record all histograms.
+  UMA_HISTOGRAM_ENUMERATION("UmaHistogram", 1, 2);
+  UMA_STABILITY_HISTOGRAM_ENUMERATION("UmaStabilityHistogram", 1, 2);
+
+  histogram_snapshot_manager_.PrepareDeltas(HistogramBase::kNoFlags,
+                                            HistogramBase::kNoFlags);
+
+  const std::vector<std::string>& histograms =
+      histogram_flattener_delta_recorder_.GetRecordedDeltaHistogramNames();
+  EXPECT_EQ(2U, histograms.size());
+  EXPECT_EQ("UmaHistogram", histograms[0]);
+  EXPECT_EQ("UmaStabilityHistogram", histograms[1]);
+}
+
+TEST_F(HistogramSnapshotManagerTest, PrepareDeltasUmaHistogramFlagFilter) {
+  // Note that kUmaStabilityHistogramFlag includes kUmaTargetedHistogramFlag.
+  UMA_HISTOGRAM_ENUMERATION("UmaHistogram", 1, 2);
+  UMA_STABILITY_HISTOGRAM_ENUMERATION("UmaStabilityHistogram", 1, 2);
+
+  histogram_snapshot_manager_.PrepareDeltas(
+      HistogramBase::kNoFlags, HistogramBase::kUmaTargetedHistogramFlag);
+
+  const std::vector<std::string>& histograms =
+      histogram_flattener_delta_recorder_.GetRecordedDeltaHistogramNames();
+  EXPECT_EQ(2U, histograms.size());
+  EXPECT_EQ("UmaHistogram", histograms[0]);
+  EXPECT_EQ("UmaStabilityHistogram", histograms[1]);
+}
+
+TEST_F(HistogramSnapshotManagerTest,
+       PrepareDeltasUmaStabilityHistogramFlagFilter) {
+  UMA_HISTOGRAM_ENUMERATION("UmaHistogram", 1, 2);
+  UMA_STABILITY_HISTOGRAM_ENUMERATION("UmaStabilityHistogram", 1, 2);
+
+  histogram_snapshot_manager_.PrepareDeltas(
+      HistogramBase::kNoFlags, HistogramBase::kUmaStabilityHistogramFlag);
+
+  const std::vector<std::string>& histograms =
+      histogram_flattener_delta_recorder_.GetRecordedDeltaHistogramNames();
+  EXPECT_EQ(1U, histograms.size());
+  EXPECT_EQ("UmaStabilityHistogram", histograms[0]);
+}
+
+}  // namespace base
diff --git a/base/metrics/histogram_unittest.cc b/base/metrics/histogram_unittest.cc
new file mode 100644
index 0000000..2e3a1ee
--- /dev/null
+++ b/base/metrics/histogram_unittest.cc
@@ -0,0 +1,511 @@
+// Copyright (c) 2012 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/metrics/histogram.h"
+
+#include <climits>
+#include <algorithm>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/bucket_ranges.h"
+#include "base/metrics/sample_vector.h"
+#include "base/metrics/statistics_recorder.h"
+#include "base/pickle.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+class HistogramTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    // Each test will have a clean state (no Histogram / BucketRanges
+    // registered).
+    InitializeStatisticsRecorder();
+  }
+
+  void TearDown() override { UninitializeStatisticsRecorder(); }
+
+  void InitializeStatisticsRecorder() {
+    statistics_recorder_ = new StatisticsRecorder();
+  }
+
+  void UninitializeStatisticsRecorder() {
+    delete statistics_recorder_;
+    statistics_recorder_ = NULL;
+  }
+
+  StatisticsRecorder* statistics_recorder_;
+};
+
+// Check for basic syntax and use.
+TEST_F(HistogramTest, BasicTest) {
+  // Try basic construction
+  HistogramBase* histogram = Histogram::FactoryGet(
+      "TestHistogram", 1, 1000, 10, HistogramBase::kNoFlags);
+  EXPECT_TRUE(histogram);
+
+  HistogramBase* linear_histogram = LinearHistogram::FactoryGet(
+      "TestLinearHistogram", 1, 1000, 10, HistogramBase::kNoFlags);
+  EXPECT_TRUE(linear_histogram);
+
+  std::vector<int> custom_ranges;
+  custom_ranges.push_back(1);
+  custom_ranges.push_back(5);
+  HistogramBase* custom_histogram = CustomHistogram::FactoryGet(
+      "TestCustomHistogram", custom_ranges, HistogramBase::kNoFlags);
+  EXPECT_TRUE(custom_histogram);
+
+  // Use standard macros (but with fixed samples)
+  LOCAL_HISTOGRAM_TIMES("Test2Histogram", TimeDelta::FromDays(1));
+  LOCAL_HISTOGRAM_COUNTS("Test3Histogram", 30);
+
+  LOCAL_HISTOGRAM_ENUMERATION("Test6Histogram", 129, 130);
+}
+
+// Check that the macro correctly matches histograms by name and records their
+// data together.
+TEST_F(HistogramTest, NameMatchTest) {
+  LOCAL_HISTOGRAM_PERCENTAGE("DuplicatedHistogram", 10);
+  LOCAL_HISTOGRAM_PERCENTAGE("DuplicatedHistogram", 10);
+  HistogramBase* histogram = LinearHistogram::FactoryGet(
+      "DuplicatedHistogram", 1, 101, 102, HistogramBase::kNoFlags);
+
+  scoped_ptr<HistogramSamples> samples = histogram->SnapshotSamples();
+  EXPECT_EQ(2, samples->TotalCount());
+  EXPECT_EQ(2, samples->GetCount(10));
+}
+
+TEST_F(HistogramTest, ExponentialRangesTest) {
+  // Check that we got a nice exponential when there was enough rooom.
+  BucketRanges ranges(9);
+  Histogram::InitializeBucketRanges(1, 64, &ranges);
+  EXPECT_EQ(0, ranges.range(0));
+  int power_of_2 = 1;
+  for (int i = 1; i < 8; i++) {
+    EXPECT_EQ(power_of_2, ranges.range(i));
+    power_of_2 *= 2;
+  }
+  EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges.range(8));
+
+  // Check the corresponding Histogram will use the correct ranges.
+  Histogram* histogram = static_cast<Histogram*>(
+      Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags));
+  EXPECT_TRUE(ranges.Equals(histogram->bucket_ranges()));
+
+  // When bucket count is limited, exponential ranges will partially look like
+  // linear.
+  BucketRanges ranges2(16);
+  Histogram::InitializeBucketRanges(1, 32, &ranges2);
+
+  EXPECT_EQ(0, ranges2.range(0));
+  EXPECT_EQ(1, ranges2.range(1));
+  EXPECT_EQ(2, ranges2.range(2));
+  EXPECT_EQ(3, ranges2.range(3));
+  EXPECT_EQ(4, ranges2.range(4));
+  EXPECT_EQ(5, ranges2.range(5));
+  EXPECT_EQ(6, ranges2.range(6));
+  EXPECT_EQ(7, ranges2.range(7));
+  EXPECT_EQ(9, ranges2.range(8));
+  EXPECT_EQ(11, ranges2.range(9));
+  EXPECT_EQ(14, ranges2.range(10));
+  EXPECT_EQ(17, ranges2.range(11));
+  EXPECT_EQ(21, ranges2.range(12));
+  EXPECT_EQ(26, ranges2.range(13));
+  EXPECT_EQ(32, ranges2.range(14));
+  EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges2.range(15));
+
+  // Check the corresponding Histogram will use the correct ranges.
+  Histogram* histogram2 = static_cast<Histogram*>(
+      Histogram::FactoryGet("Histogram2", 1, 32, 15, HistogramBase::kNoFlags));
+  EXPECT_TRUE(ranges2.Equals(histogram2->bucket_ranges()));
+}
+
+TEST_F(HistogramTest, LinearRangesTest) {
+  BucketRanges ranges(9);
+  LinearHistogram::InitializeBucketRanges(1, 7, &ranges);
+  // Gets a nice linear set of bucket ranges.
+  for (int i = 0; i < 8; i++)
+    EXPECT_EQ(i, ranges.range(i));
+  EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges.range(8));
+
+  // The correspoding LinearHistogram should use the correct ranges.
+  Histogram* histogram = static_cast<Histogram*>(
+      LinearHistogram::FactoryGet("Linear", 1, 7, 8, HistogramBase::kNoFlags));
+  EXPECT_TRUE(ranges.Equals(histogram->bucket_ranges()));
+
+  // Linear ranges are not divisible.
+  BucketRanges ranges2(6);
+  LinearHistogram::InitializeBucketRanges(1, 6, &ranges2);
+  EXPECT_EQ(0, ranges2.range(0));
+  EXPECT_EQ(1, ranges2.range(1));
+  EXPECT_EQ(3, ranges2.range(2));
+  EXPECT_EQ(4, ranges2.range(3));
+  EXPECT_EQ(6, ranges2.range(4));
+  EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges2.range(5));
+  // The correspoding LinearHistogram should use the correct ranges.
+  Histogram* histogram2 = static_cast<Histogram*>(
+      LinearHistogram::FactoryGet("Linear2", 1, 6, 5, HistogramBase::kNoFlags));
+  EXPECT_TRUE(ranges2.Equals(histogram2->bucket_ranges()));
+}
+
+TEST_F(HistogramTest, ArrayToCustomRangesTest) {
+  const HistogramBase::Sample ranges[3] = {5, 10, 20};
+  std::vector<HistogramBase::Sample> ranges_vec =
+      CustomHistogram::ArrayToCustomRanges(ranges, 3);
+  ASSERT_EQ(6u, ranges_vec.size());
+  EXPECT_EQ(5, ranges_vec[0]);
+  EXPECT_EQ(6, ranges_vec[1]);
+  EXPECT_EQ(10, ranges_vec[2]);
+  EXPECT_EQ(11, ranges_vec[3]);
+  EXPECT_EQ(20, ranges_vec[4]);
+  EXPECT_EQ(21, ranges_vec[5]);
+}
+
+TEST_F(HistogramTest, CustomHistogramTest) {
+  // A well prepared custom ranges.
+  std::vector<HistogramBase::Sample> custom_ranges;
+  custom_ranges.push_back(1);
+  custom_ranges.push_back(2);
+
+  Histogram* histogram = static_cast<Histogram*>(
+      CustomHistogram::FactoryGet("TestCustomHistogram1", custom_ranges,
+                                  HistogramBase::kNoFlags));
+  const BucketRanges* ranges = histogram->bucket_ranges();
+  ASSERT_EQ(4u, ranges->size());
+  EXPECT_EQ(0, ranges->range(0));  // Auto added.
+  EXPECT_EQ(1, ranges->range(1));
+  EXPECT_EQ(2, ranges->range(2));
+  EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(3));  // Auto added.
+
+  // A unordered custom ranges.
+  custom_ranges.clear();
+  custom_ranges.push_back(2);
+  custom_ranges.push_back(1);
+  histogram = static_cast<Histogram*>(
+      CustomHistogram::FactoryGet("TestCustomHistogram2", custom_ranges,
+                                  HistogramBase::kNoFlags));
+  ranges = histogram->bucket_ranges();
+  ASSERT_EQ(4u, ranges->size());
+  EXPECT_EQ(0, ranges->range(0));
+  EXPECT_EQ(1, ranges->range(1));
+  EXPECT_EQ(2, ranges->range(2));
+  EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(3));
+
+  // A custom ranges with duplicated values.
+  custom_ranges.clear();
+  custom_ranges.push_back(4);
+  custom_ranges.push_back(1);
+  custom_ranges.push_back(4);
+  histogram = static_cast<Histogram*>(
+      CustomHistogram::FactoryGet("TestCustomHistogram3", custom_ranges,
+                                  HistogramBase::kNoFlags));
+  ranges = histogram->bucket_ranges();
+  ASSERT_EQ(4u, ranges->size());
+  EXPECT_EQ(0, ranges->range(0));
+  EXPECT_EQ(1, ranges->range(1));
+  EXPECT_EQ(4, ranges->range(2));
+  EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(3));
+}
+
+TEST_F(HistogramTest, CustomHistogramWithOnly2Buckets) {
+  // This test exploits the fact that the CustomHistogram can have 2 buckets,
+  // while the base class Histogram is *supposed* to have at least 3 buckets.
+  // We should probably change the restriction on the base class (or not inherit
+  // the base class!).
+
+  std::vector<HistogramBase::Sample> custom_ranges;
+  custom_ranges.push_back(4);
+
+  Histogram* histogram = static_cast<Histogram*>(
+      CustomHistogram::FactoryGet("2BucketsCustomHistogram", custom_ranges,
+                                  HistogramBase::kNoFlags));
+  const BucketRanges* ranges = histogram->bucket_ranges();
+  ASSERT_EQ(3u, ranges->size());
+  EXPECT_EQ(0, ranges->range(0));
+  EXPECT_EQ(4, ranges->range(1));
+  EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(2));
+}
+
+// Make sure histogram handles out-of-bounds data gracefully.
+TEST_F(HistogramTest, BoundsTest) {
+  const size_t kBucketCount = 50;
+  Histogram* histogram = static_cast<Histogram*>(
+      Histogram::FactoryGet("Bounded", 10, 100, kBucketCount,
+                            HistogramBase::kNoFlags));
+
+  // Put two samples "out of bounds" above and below.
+  histogram->Add(5);
+  histogram->Add(-50);
+
+  histogram->Add(100);
+  histogram->Add(10000);
+
+  // Verify they landed in the underflow, and overflow buckets.
+  scoped_ptr<SampleVector> samples = histogram->SnapshotSampleVector();
+  EXPECT_EQ(2, samples->GetCountAtIndex(0));
+  EXPECT_EQ(0, samples->GetCountAtIndex(1));
+  size_t array_size = histogram->bucket_count();
+  EXPECT_EQ(kBucketCount, array_size);
+  EXPECT_EQ(0, samples->GetCountAtIndex(array_size - 2));
+  EXPECT_EQ(2, samples->GetCountAtIndex(array_size - 1));
+
+  std::vector<int> custom_ranges;
+  custom_ranges.push_back(10);
+  custom_ranges.push_back(50);
+  custom_ranges.push_back(100);
+  Histogram* test_custom_histogram = static_cast<Histogram*>(
+      CustomHistogram::FactoryGet("TestCustomRangeBoundedHistogram",
+                                  custom_ranges, HistogramBase::kNoFlags));
+
+  // Put two samples "out of bounds" above and below.
+  test_custom_histogram->Add(5);
+  test_custom_histogram->Add(-50);
+  test_custom_histogram->Add(100);
+  test_custom_histogram->Add(1000);
+  test_custom_histogram->Add(INT_MAX);
+
+  // Verify they landed in the underflow, and overflow buckets.
+  scoped_ptr<SampleVector> custom_samples =
+      test_custom_histogram->SnapshotSampleVector();
+  EXPECT_EQ(2, custom_samples->GetCountAtIndex(0));
+  EXPECT_EQ(0, custom_samples->GetCountAtIndex(1));
+  size_t bucket_count = test_custom_histogram->bucket_count();
+  EXPECT_EQ(0, custom_samples->GetCountAtIndex(bucket_count - 2));
+  EXPECT_EQ(3, custom_samples->GetCountAtIndex(bucket_count - 1));
+}
+
+// Check to be sure samples land as expected is "correct" buckets.
+TEST_F(HistogramTest, BucketPlacementTest) {
+  Histogram* histogram = static_cast<Histogram*>(
+      Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags));
+
+  // Add i+1 samples to the i'th bucket.
+  histogram->Add(0);
+  int power_of_2 = 1;
+  for (int i = 1; i < 8; i++) {
+    for (int j = 0; j <= i; j++)
+      histogram->Add(power_of_2);
+    power_of_2 *= 2;
+  }
+
+  // Check to see that the bucket counts reflect our additions.
+  scoped_ptr<SampleVector> samples = histogram->SnapshotSampleVector();
+  for (int i = 0; i < 8; i++)
+    EXPECT_EQ(i + 1, samples->GetCountAtIndex(i));
+}
+
+TEST_F(HistogramTest, CorruptSampleCounts) {
+  Histogram* histogram = static_cast<Histogram*>(
+      Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags));
+
+  // Add some samples.
+  histogram->Add(20);
+  histogram->Add(40);
+
+  scoped_ptr<SampleVector> snapshot = histogram->SnapshotSampleVector();
+  EXPECT_EQ(HistogramBase::NO_INCONSISTENCIES,
+            histogram->FindCorruption(*snapshot));
+  EXPECT_EQ(2, snapshot->redundant_count());
+  EXPECT_EQ(2, snapshot->TotalCount());
+
+  snapshot->counts_[3] += 100;  // Sample count won't match redundant count.
+  EXPECT_EQ(HistogramBase::COUNT_LOW_ERROR,
+            histogram->FindCorruption(*snapshot));
+  snapshot->counts_[2] -= 200;
+  EXPECT_EQ(HistogramBase::COUNT_HIGH_ERROR,
+            histogram->FindCorruption(*snapshot));
+
+  // But we can't spot a corruption if it is compensated for.
+  snapshot->counts_[1] += 100;
+  EXPECT_EQ(HistogramBase::NO_INCONSISTENCIES,
+            histogram->FindCorruption(*snapshot));
+}
+
+TEST_F(HistogramTest, CorruptBucketBounds) {
+  Histogram* histogram = static_cast<Histogram*>(
+      Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags));
+
+  scoped_ptr<SampleVector> snapshot = histogram->SnapshotSampleVector();
+  EXPECT_EQ(HistogramBase::NO_INCONSISTENCIES,
+            histogram->FindCorruption(*snapshot));
+
+  BucketRanges* bucket_ranges =
+      const_cast<BucketRanges*>(histogram->bucket_ranges());
+  HistogramBase::Sample tmp = bucket_ranges->range(1);
+  bucket_ranges->set_range(1, bucket_ranges->range(2));
+  bucket_ranges->set_range(2, tmp);
+  EXPECT_EQ(
+      HistogramBase::BUCKET_ORDER_ERROR | HistogramBase::RANGE_CHECKSUM_ERROR,
+      histogram->FindCorruption(*snapshot));
+
+  bucket_ranges->set_range(2, bucket_ranges->range(1));
+  bucket_ranges->set_range(1, tmp);
+  EXPECT_EQ(0, histogram->FindCorruption(*snapshot));
+
+  // Show that two simple changes don't offset each other
+  bucket_ranges->set_range(3, bucket_ranges->range(3) + 1);
+  EXPECT_EQ(HistogramBase::RANGE_CHECKSUM_ERROR,
+            histogram->FindCorruption(*snapshot));
+
+  bucket_ranges->set_range(4, bucket_ranges->range(4) - 1);
+  EXPECT_EQ(HistogramBase::RANGE_CHECKSUM_ERROR,
+            histogram->FindCorruption(*snapshot));
+
+  // Repair histogram so that destructor won't DCHECK().
+  bucket_ranges->set_range(3, bucket_ranges->range(3) - 1);
+  bucket_ranges->set_range(4, bucket_ranges->range(4) + 1);
+}
+
+TEST_F(HistogramTest, HistogramSerializeInfo) {
+  Histogram* histogram = static_cast<Histogram*>(
+      Histogram::FactoryGet("Histogram", 1, 64, 8,
+                            HistogramBase::kIPCSerializationSourceFlag));
+  Pickle pickle;
+  histogram->SerializeInfo(&pickle);
+
+  PickleIterator iter(pickle);
+
+  int type;
+  EXPECT_TRUE(iter.ReadInt(&type));
+  EXPECT_EQ(HISTOGRAM, type);
+
+  std::string name;
+  EXPECT_TRUE(iter.ReadString(&name));
+  EXPECT_EQ("Histogram", name);
+
+  int flag;
+  EXPECT_TRUE(iter.ReadInt(&flag));
+  EXPECT_EQ(HistogramBase::kIPCSerializationSourceFlag, flag);
+
+  int min;
+  EXPECT_TRUE(iter.ReadInt(&min));
+  EXPECT_EQ(1, min);
+
+  int max;
+  EXPECT_TRUE(iter.ReadInt(&max));
+  EXPECT_EQ(64, max);
+
+  int64 bucket_count;
+  EXPECT_TRUE(iter.ReadInt64(&bucket_count));
+  EXPECT_EQ(8, bucket_count);
+
+  uint32 checksum;
+  EXPECT_TRUE(iter.ReadUInt32(&checksum));
+  EXPECT_EQ(histogram->bucket_ranges()->checksum(), checksum);
+
+  // No more data in the pickle.
+  EXPECT_FALSE(iter.SkipBytes(1));
+}
+
+TEST_F(HistogramTest, CustomHistogramSerializeInfo) {
+  std::vector<int> custom_ranges;
+  custom_ranges.push_back(10);
+  custom_ranges.push_back(100);
+
+  HistogramBase* custom_histogram = CustomHistogram::FactoryGet(
+      "TestCustomRangeBoundedHistogram",
+      custom_ranges,
+      HistogramBase::kNoFlags);
+  Pickle pickle;
+  custom_histogram->SerializeInfo(&pickle);
+
+  // Validate the pickle.
+  PickleIterator iter(pickle);
+
+  int i;
+  std::string s;
+  int64 bucket_count;
+  uint32 ui32;
+  EXPECT_TRUE(iter.ReadInt(&i) && iter.ReadString(&s) && iter.ReadInt(&i) &&
+              iter.ReadInt(&i) && iter.ReadInt(&i) &&
+              iter.ReadInt64(&bucket_count) && iter.ReadUInt32(&ui32));
+  EXPECT_EQ(3, bucket_count);
+
+  int range;
+  EXPECT_TRUE(iter.ReadInt(&range));
+  EXPECT_EQ(10, range);
+  EXPECT_TRUE(iter.ReadInt(&range));
+  EXPECT_EQ(100, range);
+
+  // No more data in the pickle.
+  EXPECT_FALSE(iter.SkipBytes(1));
+}
+
+TEST_F(HistogramTest, BadConstruction) {
+  HistogramBase* histogram = Histogram::FactoryGet(
+      "BadConstruction", 0, 100, 8, HistogramBase::kNoFlags);
+  EXPECT_TRUE(histogram->HasConstructionArguments(1, 100, 8));
+
+  // Try to get the same histogram name with different arguments.
+  HistogramBase* bad_histogram = Histogram::FactoryGet(
+      "BadConstruction", 0, 100, 7, HistogramBase::kNoFlags);
+  EXPECT_EQ(NULL, bad_histogram);
+  bad_histogram = Histogram::FactoryGet(
+      "BadConstruction", 0, 99, 8, HistogramBase::kNoFlags);
+  EXPECT_EQ(NULL, bad_histogram);
+
+  HistogramBase* linear_histogram = LinearHistogram::FactoryGet(
+      "BadConstructionLinear", 0, 100, 8, HistogramBase::kNoFlags);
+  EXPECT_TRUE(linear_histogram->HasConstructionArguments(1, 100, 8));
+
+  // Try to get the same histogram name with different arguments.
+  bad_histogram = LinearHistogram::FactoryGet(
+      "BadConstructionLinear", 0, 100, 7, HistogramBase::kNoFlags);
+  EXPECT_EQ(NULL, bad_histogram);
+  bad_histogram = LinearHistogram::FactoryGet(
+      "BadConstructionLinear", 10, 100, 8, HistogramBase::kNoFlags);
+  EXPECT_EQ(NULL, bad_histogram);
+}
+
+#if GTEST_HAS_DEATH_TEST
+// For Histogram, LinearHistogram and CustomHistogram, the minimum for a
+// declared range is 1, while the maximum is (HistogramBase::kSampleType_MAX -
+// 1). But we accept ranges exceeding those limits, and silently clamped to
+// those limits. This is for backwards compatibility.
+TEST(HistogramDeathTest, BadRangesTest) {
+  HistogramBase* histogram = Histogram::FactoryGet(
+      "BadRanges", 0, HistogramBase::kSampleType_MAX, 8,
+      HistogramBase::kNoFlags);
+  EXPECT_TRUE(
+      histogram->HasConstructionArguments(
+          1, HistogramBase::kSampleType_MAX - 1, 8));
+
+  HistogramBase* linear_histogram = LinearHistogram::FactoryGet(
+      "BadRangesLinear", 0, HistogramBase::kSampleType_MAX, 8,
+      HistogramBase::kNoFlags);
+  EXPECT_TRUE(
+      linear_histogram->HasConstructionArguments(
+          1, HistogramBase::kSampleType_MAX - 1, 8));
+
+  std::vector<int> custom_ranges;
+  custom_ranges.push_back(0);
+  custom_ranges.push_back(5);
+  Histogram* custom_histogram = static_cast<Histogram*>(
+      CustomHistogram::FactoryGet(
+          "BadRangesCustom", custom_ranges, HistogramBase::kNoFlags));
+  const BucketRanges* ranges = custom_histogram->bucket_ranges();
+  ASSERT_EQ(3u, ranges->size());
+  EXPECT_EQ(0, ranges->range(0));
+  EXPECT_EQ(5, ranges->range(1));
+  EXPECT_EQ(HistogramBase::kSampleType_MAX, ranges->range(2));
+
+  // CustomHistogram does not accepts kSampleType_MAX as range.
+  custom_ranges.push_back(HistogramBase::kSampleType_MAX);
+  EXPECT_DEATH(CustomHistogram::FactoryGet("BadRangesCustom2", custom_ranges,
+                                           HistogramBase::kNoFlags),
+               "");
+
+  // CustomHistogram needs at least 1 valid range.
+  custom_ranges.clear();
+  custom_ranges.push_back(0);
+  EXPECT_DEATH(CustomHistogram::FactoryGet("BadRangesCustom3", custom_ranges,
+                                           HistogramBase::kNoFlags),
+               "");
+}
+#endif
+
+}  // namespace base
diff --git a/base/metrics/sample_map.cc b/base/metrics/sample_map.cc
new file mode 100644
index 0000000..f2540a4
--- /dev/null
+++ b/base/metrics/sample_map.cc
@@ -0,0 +1,92 @@
+// Copyright (c) 2012 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/metrics/sample_map.h"
+
+#include "base/logging.h"
+
+namespace base {
+
+typedef HistogramBase::Count Count;
+typedef HistogramBase::Sample Sample;
+
+SampleMap::SampleMap() {}
+
+SampleMap::~SampleMap() {}
+
+void SampleMap::Accumulate(Sample value, Count count) {
+  sample_counts_[value] += count;
+  IncreaseSum(count * value);
+  IncreaseRedundantCount(count);
+}
+
+Count SampleMap::GetCount(Sample value) const {
+  std::map<Sample, Count>::const_iterator it = sample_counts_.find(value);
+  if (it == sample_counts_.end())
+    return 0;
+  return it->second;
+}
+
+Count SampleMap::TotalCount() const {
+  Count count = 0;
+  for (const auto& entry : sample_counts_) {
+    count += entry.second;
+  }
+  return count;
+}
+
+scoped_ptr<SampleCountIterator> SampleMap::Iterator() const {
+  return scoped_ptr<SampleCountIterator>(new SampleMapIterator(sample_counts_));
+}
+
+bool SampleMap::AddSubtractImpl(SampleCountIterator* iter,
+                                HistogramSamples::Operator op) {
+  Sample min;
+  Sample max;
+  Count count;
+  for (; !iter->Done(); iter->Next()) {
+    iter->Get(&min, &max, &count);
+    if (min + 1 != max)
+      return false;  // SparseHistogram only supports bucket with size 1.
+
+    sample_counts_[min] += (op == HistogramSamples::ADD) ? count : -count;
+  }
+  return true;
+}
+
+SampleMapIterator::SampleMapIterator(const SampleToCountMap& sample_counts)
+    : iter_(sample_counts.begin()),
+      end_(sample_counts.end()) {
+  SkipEmptyBuckets();
+}
+
+SampleMapIterator::~SampleMapIterator() {}
+
+bool SampleMapIterator::Done() const {
+  return iter_ == end_;
+}
+
+void SampleMapIterator::Next() {
+  DCHECK(!Done());
+  ++iter_;
+  SkipEmptyBuckets();
+}
+
+void SampleMapIterator::Get(Sample* min, Sample* max, Count* count) const {
+  DCHECK(!Done());
+  if (min != NULL)
+    *min = iter_->first;
+  if (max != NULL)
+    *max = iter_->first + 1;
+  if (count != NULL)
+    *count = iter_->second;
+}
+
+void SampleMapIterator::SkipEmptyBuckets() {
+  while (!Done() && iter_->second == 0) {
+    ++iter_;
+  }
+}
+
+}  // namespace base
diff --git a/base/metrics/sample_map.h b/base/metrics/sample_map.h
new file mode 100644
index 0000000..952d34a
--- /dev/null
+++ b/base/metrics/sample_map.h
@@ -0,0 +1,67 @@
+// Copyright (c) 2012 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.
+
+// SampleMap implements HistogramSamples interface. It is used by the
+// SparseHistogram class to store samples.
+
+#ifndef BASE_METRICS_SAMPLE_MAP_H_
+#define BASE_METRICS_SAMPLE_MAP_H_
+
+#include <map>
+
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/histogram_base.h"
+#include "base/metrics/histogram_samples.h"
+
+namespace base {
+
+class BASE_EXPORT_PRIVATE SampleMap : public HistogramSamples {
+ public:
+  SampleMap();
+  ~SampleMap() override;
+
+  // HistogramSamples implementation:
+  void Accumulate(HistogramBase::Sample value,
+                  HistogramBase::Count count) override;
+  HistogramBase::Count GetCount(HistogramBase::Sample value) const override;
+  HistogramBase::Count TotalCount() const override;
+  scoped_ptr<SampleCountIterator> Iterator() const override;
+
+ protected:
+  bool AddSubtractImpl(
+      SampleCountIterator* iter,
+      HistogramSamples::Operator op) override;  // |op| is ADD or SUBTRACT.
+
+ private:
+  std::map<HistogramBase::Sample, HistogramBase::Count> sample_counts_;
+
+  DISALLOW_COPY_AND_ASSIGN(SampleMap);
+};
+
+class BASE_EXPORT_PRIVATE SampleMapIterator : public SampleCountIterator {
+ public:
+  typedef std::map<HistogramBase::Sample, HistogramBase::Count>
+      SampleToCountMap;
+
+  explicit SampleMapIterator(const SampleToCountMap& sample_counts);
+  ~SampleMapIterator() override;
+
+  // SampleCountIterator implementation:
+  bool Done() const override;
+  void Next() override;
+  void Get(HistogramBase::Sample* min,
+           HistogramBase::Sample* max,
+           HistogramBase::Count* count) const override;
+
+ private:
+  void SkipEmptyBuckets();
+
+  SampleToCountMap::const_iterator iter_;
+  const SampleToCountMap::const_iterator end_;
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_SAMPLE_MAP_H_
diff --git a/base/metrics/sample_map_unittest.cc b/base/metrics/sample_map_unittest.cc
new file mode 100644
index 0000000..22ce8e1
--- /dev/null
+++ b/base/metrics/sample_map_unittest.cc
@@ -0,0 +1,157 @@
+// Copyright (c) 2012 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/metrics/sample_map.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+TEST(SampleMapTest, AccumulateTest) {
+  SampleMap samples;
+
+  samples.Accumulate(1, 100);
+  samples.Accumulate(2, 200);
+  samples.Accumulate(1, -200);
+  EXPECT_EQ(-100, samples.GetCount(1));
+  EXPECT_EQ(200, samples.GetCount(2));
+
+  EXPECT_EQ(300, samples.sum());
+  EXPECT_EQ(100, samples.TotalCount());
+  EXPECT_EQ(samples.redundant_count(), samples.TotalCount());
+}
+
+TEST(SampleMapTest, AddSubtractTest) {
+  SampleMap samples1;
+  SampleMap samples2;
+
+  samples1.Accumulate(1, 100);
+  samples1.Accumulate(2, 100);
+  samples1.Accumulate(3, 100);
+
+  samples2.Accumulate(1, 200);
+  samples2.Accumulate(2, 200);
+  samples2.Accumulate(4, 200);
+
+  samples1.Add(samples2);
+  EXPECT_EQ(300, samples1.GetCount(1));
+  EXPECT_EQ(300, samples1.GetCount(2));
+  EXPECT_EQ(100, samples1.GetCount(3));
+  EXPECT_EQ(200, samples1.GetCount(4));
+  EXPECT_EQ(2000, samples1.sum());
+  EXPECT_EQ(900, samples1.TotalCount());
+  EXPECT_EQ(samples1.redundant_count(), samples1.TotalCount());
+
+  samples1.Subtract(samples2);
+  EXPECT_EQ(100, samples1.GetCount(1));
+  EXPECT_EQ(100, samples1.GetCount(2));
+  EXPECT_EQ(100, samples1.GetCount(3));
+  EXPECT_EQ(0, samples1.GetCount(4));
+  EXPECT_EQ(600, samples1.sum());
+  EXPECT_EQ(300, samples1.TotalCount());
+  EXPECT_EQ(samples1.redundant_count(), samples1.TotalCount());
+}
+
+TEST(SampleMapIteratorTest, IterateTest) {
+  SampleMap samples;
+  samples.Accumulate(1, 100);
+  samples.Accumulate(2, 200);
+  samples.Accumulate(4, -300);
+  samples.Accumulate(5, 0);
+
+  scoped_ptr<SampleCountIterator> it = samples.Iterator();
+
+  HistogramBase::Sample min;
+  HistogramBase::Sample max;
+  HistogramBase::Count count;
+
+  it->Get(&min, &max, &count);
+  EXPECT_EQ(1, min);
+  EXPECT_EQ(2, max);
+  EXPECT_EQ(100, count);
+  EXPECT_FALSE(it->GetBucketIndex(NULL));
+
+  it->Next();
+  it->Get(&min, &max, &count);
+  EXPECT_EQ(2, min);
+  EXPECT_EQ(3, max);
+  EXPECT_EQ(200, count);
+
+  it->Next();
+  it->Get(&min, &max, &count);
+  EXPECT_EQ(4, min);
+  EXPECT_EQ(5, max);
+  EXPECT_EQ(-300, count);
+
+  it->Next();
+  EXPECT_TRUE(it->Done());
+}
+
+TEST(SampleMapIteratorTest, SkipEmptyRanges) {
+  SampleMap samples;
+  samples.Accumulate(5, 1);
+  samples.Accumulate(10, 2);
+  samples.Accumulate(15, 3);
+  samples.Accumulate(20, 4);
+  samples.Accumulate(25, 5);
+
+  SampleMap samples2;
+  samples2.Accumulate(5, 1);
+  samples2.Accumulate(20, 4);
+  samples2.Accumulate(25, 5);
+
+  samples.Subtract(samples2);
+
+  scoped_ptr<SampleCountIterator> it = samples.Iterator();
+  EXPECT_FALSE(it->Done());
+
+  HistogramBase::Sample min;
+  HistogramBase::Sample max;
+  HistogramBase::Count count;
+
+  it->Get(&min, &max, &count);
+  EXPECT_EQ(10, min);
+  EXPECT_EQ(11, max);
+  EXPECT_EQ(2, count);
+
+  it->Next();
+  EXPECT_FALSE(it->Done());
+
+  it->Get(&min, &max, &count);
+  EXPECT_EQ(15, min);
+  EXPECT_EQ(16, max);
+  EXPECT_EQ(3, count);
+
+  it->Next();
+  EXPECT_TRUE(it->Done());
+}
+
+#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && GTEST_HAS_DEATH_TEST
+
+TEST(SampleMapIteratorDeathTest, IterateDoneTest) {
+  SampleMap samples;
+
+  scoped_ptr<SampleCountIterator> it = samples.Iterator();
+
+  EXPECT_TRUE(it->Done());
+
+  HistogramBase::Sample min;
+  HistogramBase::Sample max;
+  HistogramBase::Count count;
+  EXPECT_DEATH(it->Get(&min, &max, &count), "");
+
+  EXPECT_DEATH(it->Next(), "");
+
+  samples.Accumulate(1, 100);
+  it = samples.Iterator();
+  EXPECT_FALSE(it->Done());
+}
+
+#endif
+// (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && GTEST_HAS_DEATH_TEST
+
+}  // namespace
+}  // namespace base
diff --git a/base/metrics/sample_vector.cc b/base/metrics/sample_vector.cc
new file mode 100644
index 0000000..1202527
--- /dev/null
+++ b/base/metrics/sample_vector.cc
@@ -0,0 +1,163 @@
+// Copyright (c) 2012 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/metrics/sample_vector.h"
+
+#include "base/logging.h"
+#include "base/metrics/bucket_ranges.h"
+
+namespace base {
+
+typedef HistogramBase::Count Count;
+typedef HistogramBase::Sample Sample;
+
+SampleVector::SampleVector(const BucketRanges* bucket_ranges)
+    : counts_(bucket_ranges->bucket_count()),
+      bucket_ranges_(bucket_ranges) {
+  CHECK_GE(bucket_ranges_->bucket_count(), 1u);
+}
+
+SampleVector::~SampleVector() {}
+
+void SampleVector::Accumulate(Sample value, Count count) {
+  size_t bucket_index = GetBucketIndex(value);
+  subtle::NoBarrier_Store(&counts_[bucket_index],
+      subtle::NoBarrier_Load(&counts_[bucket_index]) + count);
+  IncreaseSum(count * value);
+  IncreaseRedundantCount(count);
+}
+
+Count SampleVector::GetCount(Sample value) const {
+  size_t bucket_index = GetBucketIndex(value);
+  return subtle::NoBarrier_Load(&counts_[bucket_index]);
+}
+
+Count SampleVector::TotalCount() const {
+  Count count = 0;
+  for (size_t i = 0; i < counts_.size(); i++) {
+    count += subtle::NoBarrier_Load(&counts_[i]);
+  }
+  return count;
+}
+
+Count SampleVector::GetCountAtIndex(size_t bucket_index) const {
+  DCHECK(bucket_index < counts_.size());
+  return subtle::NoBarrier_Load(&counts_[bucket_index]);
+}
+
+scoped_ptr<SampleCountIterator> SampleVector::Iterator() const {
+  return scoped_ptr<SampleCountIterator>(
+      new SampleVectorIterator(&counts_, bucket_ranges_));
+}
+
+bool SampleVector::AddSubtractImpl(SampleCountIterator* iter,
+                                   HistogramSamples::Operator op) {
+  HistogramBase::Sample min;
+  HistogramBase::Sample max;
+  HistogramBase::Count count;
+
+  // Go through the iterator and add the counts into correct bucket.
+  size_t index = 0;
+  while (index < counts_.size() && !iter->Done()) {
+    iter->Get(&min, &max, &count);
+    if (min == bucket_ranges_->range(index) &&
+        max == bucket_ranges_->range(index + 1)) {
+      // Sample matches this bucket!
+      HistogramBase::Count old_counts =
+          subtle::NoBarrier_Load(&counts_[index]);
+      subtle::NoBarrier_Store(&counts_[index],
+          old_counts + ((op ==  HistogramSamples::ADD) ? count : -count));
+      iter->Next();
+    } else if (min > bucket_ranges_->range(index)) {
+      // Sample is larger than current bucket range. Try next.
+      index++;
+    } else {
+      // Sample is smaller than current bucket range. We scan buckets from
+      // smallest to largest, so the sample value must be invalid.
+      return false;
+    }
+  }
+
+  return iter->Done();
+}
+
+// Use simple binary search.  This is very general, but there are better
+// approaches if we knew that the buckets were linearly distributed.
+size_t SampleVector::GetBucketIndex(Sample value) const {
+  size_t bucket_count = bucket_ranges_->bucket_count();
+  CHECK_GE(bucket_count, 1u);
+  CHECK_GE(value, bucket_ranges_->range(0));
+  CHECK_LT(value, bucket_ranges_->range(bucket_count));
+
+  size_t under = 0;
+  size_t over = bucket_count;
+  size_t mid;
+  do {
+    DCHECK_GE(over, under);
+    mid = under + (over - under)/2;
+    if (mid == under)
+      break;
+    if (bucket_ranges_->range(mid) <= value)
+      under = mid;
+    else
+      over = mid;
+  } while (true);
+
+  DCHECK_LE(bucket_ranges_->range(mid), value);
+  CHECK_GT(bucket_ranges_->range(mid + 1), value);
+  return mid;
+}
+
+SampleVectorIterator::SampleVectorIterator(const std::vector<Count>* counts,
+                                           const BucketRanges* bucket_ranges)
+    : counts_(counts),
+      bucket_ranges_(bucket_ranges),
+      index_(0) {
+  CHECK_GE(bucket_ranges_->bucket_count(), counts_->size());
+  SkipEmptyBuckets();
+}
+
+SampleVectorIterator::~SampleVectorIterator() {}
+
+bool SampleVectorIterator::Done() const {
+  return index_ >= counts_->size();
+}
+
+void SampleVectorIterator::Next() {
+  DCHECK(!Done());
+  index_++;
+  SkipEmptyBuckets();
+}
+
+void SampleVectorIterator::Get(HistogramBase::Sample* min,
+                               HistogramBase::Sample* max,
+                               HistogramBase::Count* count) const {
+  DCHECK(!Done());
+  if (min != NULL)
+    *min = bucket_ranges_->range(index_);
+  if (max != NULL)
+    *max = bucket_ranges_->range(index_ + 1);
+  if (count != NULL)
+    *count = subtle::NoBarrier_Load(&(*counts_)[index_]);
+}
+
+bool SampleVectorIterator::GetBucketIndex(size_t* index) const {
+  DCHECK(!Done());
+  if (index != NULL)
+    *index = index_;
+  return true;
+}
+
+void SampleVectorIterator::SkipEmptyBuckets() {
+  if (Done())
+    return;
+
+  while (index_ < counts_->size()) {
+    if (subtle::NoBarrier_Load(&(*counts_)[index_]) != 0)
+      return;
+    index_++;
+  }
+}
+
+}  // namespace base
diff --git a/base/metrics/sample_vector.h b/base/metrics/sample_vector.h
new file mode 100644
index 0000000..55f9b96
--- /dev/null
+++ b/base/metrics/sample_vector.h
@@ -0,0 +1,83 @@
+// Copyright (c) 2012 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.
+
+// SampleVector implements HistogramSamples interface. It is used by all
+// Histogram based classes to store samples.
+
+#ifndef BASE_METRICS_SAMPLE_VECTOR_H_
+#define BASE_METRICS_SAMPLE_VECTOR_H_
+
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/histogram_base.h"
+#include "base/metrics/histogram_samples.h"
+
+namespace base {
+
+class BucketRanges;
+
+class BASE_EXPORT_PRIVATE SampleVector : public HistogramSamples {
+ public:
+  explicit SampleVector(const BucketRanges* bucket_ranges);
+  ~SampleVector() override;
+
+  // HistogramSamples implementation:
+  void Accumulate(HistogramBase::Sample value,
+                  HistogramBase::Count count) override;
+  HistogramBase::Count GetCount(HistogramBase::Sample value) const override;
+  HistogramBase::Count TotalCount() const override;
+  scoped_ptr<SampleCountIterator> Iterator() const override;
+
+  // Get count of a specific bucket.
+  HistogramBase::Count GetCountAtIndex(size_t bucket_index) const;
+
+ protected:
+  bool AddSubtractImpl(
+      SampleCountIterator* iter,
+      HistogramSamples::Operator op) override;  // |op| is ADD or SUBTRACT.
+
+  virtual size_t GetBucketIndex(HistogramBase::Sample value) const;
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(HistogramTest, CorruptSampleCounts);
+
+  std::vector<HistogramBase::AtomicCount> counts_;
+
+  // Shares the same BucketRanges with Histogram object.
+  const BucketRanges* const bucket_ranges_;
+
+  DISALLOW_COPY_AND_ASSIGN(SampleVector);
+};
+
+class BASE_EXPORT_PRIVATE SampleVectorIterator : public SampleCountIterator {
+ public:
+  SampleVectorIterator(const std::vector<HistogramBase::AtomicCount>* counts,
+                       const BucketRanges* bucket_ranges);
+  ~SampleVectorIterator() override;
+
+  // SampleCountIterator implementation:
+  bool Done() const override;
+  void Next() override;
+  void Get(HistogramBase::Sample* min,
+           HistogramBase::Sample* max,
+           HistogramBase::Count* count) const override;
+
+  // SampleVector uses predefined buckets, so iterator can return bucket index.
+  bool GetBucketIndex(size_t* index) const override;
+
+ private:
+  void SkipEmptyBuckets();
+
+  const std::vector<HistogramBase::AtomicCount>* counts_;
+  const BucketRanges* bucket_ranges_;
+
+  size_t index_;
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_SAMPLE_VECTOR_H_
diff --git a/base/metrics/sample_vector_unittest.cc b/base/metrics/sample_vector_unittest.cc
new file mode 100644
index 0000000..fd42376
--- /dev/null
+++ b/base/metrics/sample_vector_unittest.cc
@@ -0,0 +1,264 @@
+// Copyright (c) 2012 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/metrics/sample_vector.h"
+
+#include <vector>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/bucket_ranges.h"
+#include "base/metrics/histogram.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+TEST(SampleVectorTest, AccumulateTest) {
+  // Custom buckets: [1, 5) [5, 10)
+  BucketRanges ranges(3);
+  ranges.set_range(0, 1);
+  ranges.set_range(1, 5);
+  ranges.set_range(2, 10);
+  SampleVector samples(&ranges);
+
+  samples.Accumulate(1, 200);
+  samples.Accumulate(2, -300);
+  EXPECT_EQ(-100, samples.GetCountAtIndex(0));
+
+  samples.Accumulate(5, 200);
+  EXPECT_EQ(200, samples.GetCountAtIndex(1));
+
+  EXPECT_EQ(600, samples.sum());
+  EXPECT_EQ(100, samples.redundant_count());
+  EXPECT_EQ(samples.TotalCount(), samples.redundant_count());
+
+  samples.Accumulate(5, -100);
+  EXPECT_EQ(100, samples.GetCountAtIndex(1));
+
+  EXPECT_EQ(100, samples.sum());
+  EXPECT_EQ(0, samples.redundant_count());
+  EXPECT_EQ(samples.TotalCount(), samples.redundant_count());
+}
+
+TEST(SampleVectorTest, AddSubtractTest) {
+  // Custom buckets: [0, 1) [1, 2) [2, 3) [3, INT_MAX)
+  BucketRanges ranges(5);
+  ranges.set_range(0, 0);
+  ranges.set_range(1, 1);
+  ranges.set_range(2, 2);
+  ranges.set_range(3, 3);
+  ranges.set_range(4, INT_MAX);
+
+  SampleVector samples1(&ranges);
+  samples1.Accumulate(0, 100);
+  samples1.Accumulate(2, 100);
+  samples1.Accumulate(4, 100);
+  EXPECT_EQ(600, samples1.sum());
+  EXPECT_EQ(300, samples1.TotalCount());
+  EXPECT_EQ(samples1.redundant_count(), samples1.TotalCount());
+
+  SampleVector samples2(&ranges);
+  samples2.Accumulate(1, 200);
+  samples2.Accumulate(2, 200);
+  samples2.Accumulate(4, 200);
+  EXPECT_EQ(1400, samples2.sum());
+  EXPECT_EQ(600, samples2.TotalCount());
+  EXPECT_EQ(samples2.redundant_count(), samples2.TotalCount());
+
+  samples1.Add(samples2);
+  EXPECT_EQ(100, samples1.GetCountAtIndex(0));
+  EXPECT_EQ(200, samples1.GetCountAtIndex(1));
+  EXPECT_EQ(300, samples1.GetCountAtIndex(2));
+  EXPECT_EQ(300, samples1.GetCountAtIndex(3));
+  EXPECT_EQ(2000, samples1.sum());
+  EXPECT_EQ(900, samples1.TotalCount());
+  EXPECT_EQ(samples1.redundant_count(), samples1.TotalCount());
+
+  samples1.Subtract(samples2);
+  EXPECT_EQ(100, samples1.GetCountAtIndex(0));
+  EXPECT_EQ(0, samples1.GetCountAtIndex(1));
+  EXPECT_EQ(100, samples1.GetCountAtIndex(2));
+  EXPECT_EQ(100, samples1.GetCountAtIndex(3));
+  EXPECT_EQ(600, samples1.sum());
+  EXPECT_EQ(300, samples1.TotalCount());
+  EXPECT_EQ(samples1.redundant_count(), samples1.TotalCount());
+}
+
+#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && GTEST_HAS_DEATH_TEST
+TEST(SampleVectorDeathTest, BucketIndexTest) {
+  // 8 buckets with exponential layout:
+  // [0, 1) [1, 2) [2, 4) [4, 8) [8, 16) [16, 32) [32, 64) [64, INT_MAX)
+  BucketRanges ranges(9);
+  Histogram::InitializeBucketRanges(1, 64, &ranges);
+  SampleVector samples(&ranges);
+
+  // Normal case
+  samples.Accumulate(0, 1);
+  samples.Accumulate(3, 2);
+  samples.Accumulate(64, 3);
+  EXPECT_EQ(1, samples.GetCount(0));
+  EXPECT_EQ(2, samples.GetCount(2));
+  EXPECT_EQ(3, samples.GetCount(65));
+
+  // Extreme case.
+  EXPECT_DEATH(samples.Accumulate(INT_MIN, 100), "");
+  EXPECT_DEATH(samples.Accumulate(-1, 100), "");
+  EXPECT_DEATH(samples.Accumulate(INT_MAX, 100), "");
+
+  // Custom buckets: [1, 5) [5, 10)
+  // Note, this is not a valid BucketRanges for Histogram because it does not
+  // have overflow buckets.
+  BucketRanges ranges2(3);
+  ranges2.set_range(0, 1);
+  ranges2.set_range(1, 5);
+  ranges2.set_range(2, 10);
+  SampleVector samples2(&ranges2);
+
+  // Normal case.
+  samples2.Accumulate(1, 1);
+  samples2.Accumulate(4, 1);
+  samples2.Accumulate(5, 2);
+  samples2.Accumulate(9, 2);
+  EXPECT_EQ(2, samples2.GetCount(1));
+  EXPECT_EQ(4, samples2.GetCount(5));
+
+  // Extreme case.
+  EXPECT_DEATH(samples2.Accumulate(0, 100), "");
+  EXPECT_DEATH(samples2.Accumulate(10, 100), "");
+}
+
+TEST(SampleVectorDeathTest, AddSubtractBucketNotMatchTest) {
+  // Custom buckets 1: [1, 3) [3, 5)
+  BucketRanges ranges1(3);
+  ranges1.set_range(0, 1);
+  ranges1.set_range(1, 3);
+  ranges1.set_range(2, 5);
+  SampleVector samples1(&ranges1);
+
+  // Custom buckets 2: [0, 1) [1, 3) [3, 6) [6, 7)
+  BucketRanges ranges2(5);
+  ranges2.set_range(0, 0);
+  ranges2.set_range(1, 1);
+  ranges2.set_range(2, 3);
+  ranges2.set_range(3, 6);
+  ranges2.set_range(4, 7);
+  SampleVector samples2(&ranges2);
+
+  samples2.Accumulate(1, 100);
+  samples1.Add(samples2);
+  EXPECT_EQ(100, samples1.GetCountAtIndex(0));
+
+  // Extra bucket in the beginning.
+  samples2.Accumulate(0, 100);
+  EXPECT_DEATH(samples1.Add(samples2), "");
+  EXPECT_DEATH(samples1.Subtract(samples2), "");
+
+  // Extra bucket in the end.
+  samples2.Accumulate(0, -100);
+  samples2.Accumulate(6, 100);
+  EXPECT_DEATH(samples1.Add(samples2), "");
+  EXPECT_DEATH(samples1.Subtract(samples2), "");
+
+  // Bucket not match: [3, 5) VS [3, 6)
+  samples2.Accumulate(6, -100);
+  samples2.Accumulate(3, 100);
+  EXPECT_DEATH(samples1.Add(samples2), "");
+  EXPECT_DEATH(samples1.Subtract(samples2), "");
+}
+
+#endif
+// (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && GTEST_HAS_DEATH_TEST
+
+TEST(SampleVectorIteratorTest, IterateTest) {
+  BucketRanges ranges(5);
+  ranges.set_range(0, 0);
+  ranges.set_range(1, 1);
+  ranges.set_range(2, 2);
+  ranges.set_range(3, 3);
+  ranges.set_range(4, 4);
+
+  std::vector<HistogramBase::Count> counts(3);
+  counts[0] = 1;
+  counts[1] = 0;  // Iterator will bypass this empty bucket.
+  counts[2] = 2;
+
+  // BucketRanges can have larger size than counts.
+  SampleVectorIterator it(&counts, &ranges);
+  size_t index;
+
+  HistogramBase::Sample min;
+  HistogramBase::Sample max;
+  HistogramBase::Count count;
+  it.Get(&min, &max, &count);
+  EXPECT_EQ(0, min);
+  EXPECT_EQ(1, max);
+  EXPECT_EQ(1, count);
+  EXPECT_TRUE(it.GetBucketIndex(&index));
+  EXPECT_EQ(0u, index);
+
+  it.Next();
+  it.Get(&min, &max, &count);
+  EXPECT_EQ(2, min);
+  EXPECT_EQ(3, max);
+  EXPECT_EQ(2, count);
+  EXPECT_TRUE(it.GetBucketIndex(&index));
+  EXPECT_EQ(2u, index);
+
+  it.Next();
+  EXPECT_TRUE(it.Done());
+
+  // Create iterator from SampleVector.
+  SampleVector samples(&ranges);
+  samples.Accumulate(0, 0);
+  samples.Accumulate(1, 1);
+  samples.Accumulate(2, 2);
+  samples.Accumulate(3, 3);
+  scoped_ptr<SampleCountIterator> it2 = samples.Iterator();
+
+  int i;
+  for (i = 1; !it2->Done(); i++, it2->Next()) {
+    it2->Get(&min, &max, &count);
+    EXPECT_EQ(i, min);
+    EXPECT_EQ(i + 1, max);
+    EXPECT_EQ(i, count);
+
+    size_t index;
+    EXPECT_TRUE(it2->GetBucketIndex(&index));
+    EXPECT_EQ(static_cast<size_t>(i), index);
+  }
+  EXPECT_EQ(4, i);
+}
+
+#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && GTEST_HAS_DEATH_TEST
+
+TEST(SampleVectorIteratorDeathTest, IterateDoneTest) {
+  BucketRanges ranges(5);
+  ranges.set_range(0, 0);
+  ranges.set_range(1, 1);
+  ranges.set_range(2, 2);
+  ranges.set_range(3, 3);
+  ranges.set_range(4, INT_MAX);
+  SampleVector samples(&ranges);
+
+  scoped_ptr<SampleCountIterator> it = samples.Iterator();
+
+  EXPECT_TRUE(it->Done());
+
+  HistogramBase::Sample min;
+  HistogramBase::Sample max;
+  HistogramBase::Count count;
+  EXPECT_DEATH(it->Get(&min, &max, &count), "");
+
+  EXPECT_DEATH(it->Next(), "");
+
+  samples.Accumulate(2, 100);
+  it = samples.Iterator();
+  EXPECT_FALSE(it->Done());
+}
+
+#endif
+// (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && GTEST_HAS_DEATH_TEST
+
+}  // namespace
+}  // namespace base
diff --git a/base/metrics/sparse_histogram.cc b/base/metrics/sparse_histogram.cc
new file mode 100644
index 0000000..e5cdb43
--- /dev/null
+++ b/base/metrics/sparse_histogram.cc
@@ -0,0 +1,175 @@
+// Copyright (c) 2012 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/metrics/sparse_histogram.h"
+
+#include "base/metrics/sample_map.h"
+#include "base/metrics/statistics_recorder.h"
+#include "base/pickle.h"
+#include "base/strings/stringprintf.h"
+#include "base/synchronization/lock.h"
+
+namespace base {
+
+typedef HistogramBase::Count Count;
+typedef HistogramBase::Sample Sample;
+
+// static
+HistogramBase* SparseHistogram::FactoryGet(const std::string& name,
+                                           int32 flags) {
+  HistogramBase* histogram = StatisticsRecorder::FindHistogram(name);
+
+  if (!histogram) {
+    // To avoid racy destruction at shutdown, the following will be leaked.
+    HistogramBase* tentative_histogram = new SparseHistogram(name);
+    tentative_histogram->SetFlags(flags);
+    histogram =
+        StatisticsRecorder::RegisterOrDeleteDuplicate(tentative_histogram);
+  }
+  DCHECK_EQ(SPARSE_HISTOGRAM, histogram->GetHistogramType());
+  return histogram;
+}
+
+SparseHistogram::~SparseHistogram() {}
+
+HistogramType SparseHistogram::GetHistogramType() const {
+  return SPARSE_HISTOGRAM;
+}
+
+bool SparseHistogram::HasConstructionArguments(
+    Sample expected_minimum,
+    Sample expected_maximum,
+    size_t expected_bucket_count) const {
+  // SparseHistogram never has min/max/bucket_count limit.
+  return false;
+}
+
+void SparseHistogram::Add(Sample value) {
+  base::AutoLock auto_lock(lock_);
+  samples_.Accumulate(value, 1);
+}
+
+scoped_ptr<HistogramSamples> SparseHistogram::SnapshotSamples() const {
+  scoped_ptr<SampleMap> snapshot(new SampleMap());
+
+  base::AutoLock auto_lock(lock_);
+  snapshot->Add(samples_);
+  return snapshot.Pass();
+}
+
+void SparseHistogram::AddSamples(const HistogramSamples& samples) {
+  base::AutoLock auto_lock(lock_);
+  samples_.Add(samples);
+}
+
+bool SparseHistogram::AddSamplesFromPickle(PickleIterator* iter) {
+  base::AutoLock auto_lock(lock_);
+  return samples_.AddFromPickle(iter);
+}
+
+void SparseHistogram::WriteHTMLGraph(std::string* output) const {
+  output->append("<PRE>");
+  WriteAsciiImpl(true, "<br>", output);
+  output->append("</PRE>");
+}
+
+void SparseHistogram::WriteAscii(std::string* output) const {
+  WriteAsciiImpl(true, "\n", output);
+}
+
+bool SparseHistogram::SerializeInfoImpl(Pickle* pickle) const {
+  return pickle->WriteString(histogram_name()) && pickle->WriteInt(flags());
+}
+
+SparseHistogram::SparseHistogram(const std::string& name)
+    : HistogramBase(name) {}
+
+HistogramBase* SparseHistogram::DeserializeInfoImpl(PickleIterator* iter) {
+  std::string histogram_name;
+  int flags;
+  if (!iter->ReadString(&histogram_name) || !iter->ReadInt(&flags)) {
+    DLOG(ERROR) << "Pickle error decoding Histogram: " << histogram_name;
+    return NULL;
+  }
+
+  DCHECK(flags & HistogramBase::kIPCSerializationSourceFlag);
+  flags &= ~HistogramBase::kIPCSerializationSourceFlag;
+
+  return SparseHistogram::FactoryGet(histogram_name, flags);
+}
+
+void SparseHistogram::GetParameters(DictionaryValue* params) const {
+  // TODO(kaiwang): Implement. (See HistogramBase::WriteJSON.)
+}
+
+void SparseHistogram::GetCountAndBucketData(Count* count,
+                                            int64* sum,
+                                            ListValue* buckets) const {
+  // TODO(kaiwang): Implement. (See HistogramBase::WriteJSON.)
+}
+
+void SparseHistogram::WriteAsciiImpl(bool graph_it,
+                                     const std::string& newline,
+                                     std::string* output) const {
+  // Get a local copy of the data so we are consistent.
+  scoped_ptr<HistogramSamples> snapshot = SnapshotSamples();
+  Count total_count = snapshot->TotalCount();
+  double scaled_total_count = total_count / 100.0;
+
+  WriteAsciiHeader(total_count, output);
+  output->append(newline);
+
+  // Determine how wide the largest bucket range is (how many digits to print),
+  // so that we'll be able to right-align starts for the graphical bars.
+  // Determine which bucket has the largest sample count so that we can
+  // normalize the graphical bar-width relative to that sample count.
+  Count largest_count = 0;
+  Sample largest_sample = 0;
+  scoped_ptr<SampleCountIterator> it = snapshot->Iterator();
+  while (!it->Done()) {
+    Sample min;
+    Sample max;
+    Count count;
+    it->Get(&min, &max, &count);
+    if (min > largest_sample)
+      largest_sample = min;
+    if (count > largest_count)
+      largest_count = count;
+    it->Next();
+  }
+  size_t print_width = GetSimpleAsciiBucketRange(largest_sample).size() + 1;
+
+  // iterate over each item and display them
+  it = snapshot->Iterator();
+  while (!it->Done()) {
+    Sample min;
+    Sample max;
+    Count count;
+    it->Get(&min, &max, &count);
+
+    // value is min, so display it
+    std::string range = GetSimpleAsciiBucketRange(min);
+    output->append(range);
+    for (size_t j = 0; range.size() + j < print_width + 1; ++j)
+      output->push_back(' ');
+
+    if (graph_it)
+      WriteAsciiBucketGraph(count, largest_count, output);
+    WriteAsciiBucketValue(count, scaled_total_count, output);
+    output->append(newline);
+    it->Next();
+  }
+}
+
+void SparseHistogram::WriteAsciiHeader(const Count total_count,
+                                       std::string* output) const {
+  StringAppendF(output,
+                "Histogram: %s recorded %d samples",
+                histogram_name().c_str(),
+                total_count);
+  if (flags() & ~kHexRangePrintingFlag)
+    StringAppendF(output, " (flags = 0x%x)", flags() & ~kHexRangePrintingFlag);
+}
+
+}  // namespace base
diff --git a/base/metrics/sparse_histogram.h b/base/metrics/sparse_histogram.h
new file mode 100644
index 0000000..a02da59
--- /dev/null
+++ b/base/metrics/sparse_histogram.h
@@ -0,0 +1,90 @@
+// Copyright (c) 2012 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_METRICS_SPARSE_HISTOGRAM_H_
+#define BASE_METRICS_SPARSE_HISTOGRAM_H_
+
+#include <map>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/histogram_base.h"
+#include "base/metrics/sample_map.h"
+#include "base/synchronization/lock.h"
+
+namespace base {
+
+#define UMA_HISTOGRAM_SPARSE_SLOWLY(name, sample) \
+    do { \
+      base::HistogramBase* histogram = base::SparseHistogram::FactoryGet( \
+          name, base::HistogramBase::kUmaTargetedHistogramFlag); \
+      histogram->Add(sample); \
+    } while (0)
+
+class HistogramSamples;
+
+class BASE_EXPORT_PRIVATE SparseHistogram : public HistogramBase {
+ public:
+  // If there's one with same name, return the existing one. If not, create a
+  // new one.
+  static HistogramBase* FactoryGet(const std::string& name, int32 flags);
+
+  ~SparseHistogram() override;
+
+  // HistogramBase implementation:
+  HistogramType GetHistogramType() const override;
+  bool HasConstructionArguments(Sample expected_minimum,
+                                Sample expected_maximum,
+                                size_t expected_bucket_count) const override;
+  void Add(Sample value) override;
+  void AddSamples(const HistogramSamples& samples) override;
+  bool AddSamplesFromPickle(base::PickleIterator* iter) override;
+  scoped_ptr<HistogramSamples> SnapshotSamples() const override;
+  void WriteHTMLGraph(std::string* output) const override;
+  void WriteAscii(std::string* output) const override;
+
+ protected:
+  // HistogramBase implementation:
+  bool SerializeInfoImpl(base::Pickle* pickle) const override;
+
+ private:
+  // Clients should always use FactoryGet to create SparseHistogram.
+  explicit SparseHistogram(const std::string& name);
+
+  friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
+      base::PickleIterator* iter);
+  static HistogramBase* DeserializeInfoImpl(base::PickleIterator* iter);
+
+  void GetParameters(DictionaryValue* params) const override;
+  void GetCountAndBucketData(Count* count,
+                             int64* sum,
+                             ListValue* buckets) const override;
+
+  // Helpers for emitting Ascii graphic.  Each method appends data to output.
+  void WriteAsciiImpl(bool graph_it,
+                      const std::string& newline,
+                      std::string* output) const;
+
+  // Write a common header message describing this histogram.
+  void WriteAsciiHeader(const Count total_count,
+                        std::string* output) const;
+
+  // For constuctor calling.
+  friend class SparseHistogramTest;
+
+  // Protects access to |samples_|.
+  mutable base::Lock lock_;
+
+  SampleMap samples_;
+
+  DISALLOW_COPY_AND_ASSIGN(SparseHistogram);
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_SPARSE_HISTOGRAM_H_
diff --git a/base/metrics/sparse_histogram_unittest.cc b/base/metrics/sparse_histogram_unittest.cc
new file mode 100644
index 0000000..fca4d59
--- /dev/null
+++ b/base/metrics/sparse_histogram_unittest.cc
@@ -0,0 +1,130 @@
+// Copyright (c) 2012 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/metrics/sparse_histogram.h"
+
+#include <string>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/histogram_base.h"
+#include "base/metrics/histogram_samples.h"
+#include "base/metrics/sample_map.h"
+#include "base/metrics/statistics_recorder.h"
+#include "base/pickle.h"
+#include "base/strings/stringprintf.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+class SparseHistogramTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    // Each test will have a clean state (no Histogram / BucketRanges
+    // registered).
+    InitializeStatisticsRecorder();
+  }
+
+  void TearDown() override { UninitializeStatisticsRecorder(); }
+
+  void InitializeStatisticsRecorder() {
+    statistics_recorder_ = new StatisticsRecorder();
+  }
+
+  void UninitializeStatisticsRecorder() {
+    delete statistics_recorder_;
+    statistics_recorder_ = NULL;
+  }
+
+  scoped_ptr<SparseHistogram> NewSparseHistogram(const std::string& name) {
+    return scoped_ptr<SparseHistogram>(new SparseHistogram(name));
+  }
+
+  StatisticsRecorder* statistics_recorder_;
+};
+
+TEST_F(SparseHistogramTest, BasicTest) {
+  scoped_ptr<SparseHistogram> histogram(NewSparseHistogram("Sparse"));
+  scoped_ptr<HistogramSamples> snapshot(histogram->SnapshotSamples());
+  EXPECT_EQ(0, snapshot->TotalCount());
+  EXPECT_EQ(0, snapshot->sum());
+
+  histogram->Add(100);
+  scoped_ptr<HistogramSamples> snapshot1(histogram->SnapshotSamples());
+  EXPECT_EQ(1, snapshot1->TotalCount());
+  EXPECT_EQ(1, snapshot1->GetCount(100));
+
+  histogram->Add(100);
+  histogram->Add(101);
+  scoped_ptr<HistogramSamples> snapshot2(histogram->SnapshotSamples());
+  EXPECT_EQ(3, snapshot2->TotalCount());
+  EXPECT_EQ(2, snapshot2->GetCount(100));
+  EXPECT_EQ(1, snapshot2->GetCount(101));
+}
+
+TEST_F(SparseHistogramTest, MacroBasicTest) {
+  UMA_HISTOGRAM_SPARSE_SLOWLY("Sparse", 100);
+  UMA_HISTOGRAM_SPARSE_SLOWLY("Sparse", 200);
+  UMA_HISTOGRAM_SPARSE_SLOWLY("Sparse", 100);
+
+  StatisticsRecorder::Histograms histograms;
+  StatisticsRecorder::GetHistograms(&histograms);
+
+  ASSERT_EQ(1U, histograms.size());
+  HistogramBase* sparse_histogram = histograms[0];
+
+  EXPECT_EQ(SPARSE_HISTOGRAM, sparse_histogram->GetHistogramType());
+  EXPECT_EQ("Sparse", sparse_histogram->histogram_name());
+  EXPECT_EQ(HistogramBase::kUmaTargetedHistogramFlag,
+            sparse_histogram->flags());
+
+  scoped_ptr<HistogramSamples> samples = sparse_histogram->SnapshotSamples();
+  EXPECT_EQ(3, samples->TotalCount());
+  EXPECT_EQ(2, samples->GetCount(100));
+  EXPECT_EQ(1, samples->GetCount(200));
+}
+
+TEST_F(SparseHistogramTest, MacroInLoopTest) {
+  // Unlike the macros in histogram.h, SparseHistogram macros can have a
+  // variable as histogram name.
+  for (int i = 0; i < 2; i++) {
+    std::string name = StringPrintf("Sparse%d", i + 1);
+    UMA_HISTOGRAM_SPARSE_SLOWLY(name, 100);
+  }
+
+  StatisticsRecorder::Histograms histograms;
+  StatisticsRecorder::GetHistograms(&histograms);
+  ASSERT_EQ(2U, histograms.size());
+
+  std::string name1 = histograms[0]->histogram_name();
+  std::string name2 = histograms[1]->histogram_name();
+  EXPECT_TRUE(("Sparse1" == name1 && "Sparse2" == name2) ||
+              ("Sparse2" == name1 && "Sparse1" == name2));
+}
+
+TEST_F(SparseHistogramTest, Serialize) {
+  scoped_ptr<SparseHistogram> histogram(NewSparseHistogram("Sparse"));
+  histogram->SetFlags(HistogramBase::kIPCSerializationSourceFlag);
+
+  Pickle pickle;
+  histogram->SerializeInfo(&pickle);
+
+  PickleIterator iter(pickle);
+
+  int type;
+  EXPECT_TRUE(iter.ReadInt(&type));
+  EXPECT_EQ(SPARSE_HISTOGRAM, type);
+
+  std::string name;
+  EXPECT_TRUE(iter.ReadString(&name));
+  EXPECT_EQ("Sparse", name);
+
+  int flag;
+  EXPECT_TRUE(iter.ReadInt(&flag));
+  EXPECT_EQ(HistogramBase::kIPCSerializationSourceFlag, flag);
+
+  // No more data in the pickle.
+  EXPECT_FALSE(iter.SkipBytes(1));
+}
+
+}  // namespace base
diff --git a/base/metrics/statistics_recorder.cc b/base/metrics/statistics_recorder.cc
new file mode 100644
index 0000000..85408e1
--- /dev/null
+++ b/base/metrics/statistics_recorder.cc
@@ -0,0 +1,298 @@
+// Copyright (c) 2012 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/metrics/statistics_recorder.h"
+
+#include "base/at_exit.h"
+#include "base/debug/leak_annotations.h"
+#include "base/json/string_escape.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/histogram.h"
+#include "base/strings/stringprintf.h"
+#include "base/synchronization/lock.h"
+#include "base/values.h"
+
+namespace {
+// Initialize histogram statistics gathering system.
+base::LazyInstance<base::StatisticsRecorder>::Leaky g_statistics_recorder_ =
+    LAZY_INSTANCE_INITIALIZER;
+}  // namespace
+
+namespace base {
+
+// static
+void StatisticsRecorder::Initialize() {
+  // Ensure that an instance of the StatisticsRecorder object is created.
+  g_statistics_recorder_.Get();
+}
+
+// static
+bool StatisticsRecorder::IsActive() {
+  if (lock_ == NULL)
+    return false;
+  base::AutoLock auto_lock(*lock_);
+  return NULL != histograms_;
+}
+
+// static
+HistogramBase* StatisticsRecorder::RegisterOrDeleteDuplicate(
+    HistogramBase* histogram) {
+  // As per crbug.com/79322 the histograms are intentionally leaked, so we need
+  // to annotate them. Because ANNOTATE_LEAKING_OBJECT_PTR may be used only once
+  // for an object, the duplicates should not be annotated.
+  // Callers are responsible for not calling RegisterOrDeleteDuplicate(ptr)
+  // twice if (lock_ == NULL) || (!histograms_).
+  if (lock_ == NULL) {
+    ANNOTATE_LEAKING_OBJECT_PTR(histogram);  // see crbug.com/79322
+    return histogram;
+  }
+
+  HistogramBase* histogram_to_delete = NULL;
+  HistogramBase* histogram_to_return = NULL;
+  {
+    base::AutoLock auto_lock(*lock_);
+    if (histograms_ == NULL) {
+      histogram_to_return = histogram;
+    } else {
+      const std::string& name = histogram->histogram_name();
+      HistogramMap::iterator it = histograms_->find(name);
+      if (histograms_->end() == it) {
+        (*histograms_)[name] = histogram;
+        ANNOTATE_LEAKING_OBJECT_PTR(histogram);  // see crbug.com/79322
+        histogram_to_return = histogram;
+      } else if (histogram == it->second) {
+        // The histogram was registered before.
+        histogram_to_return = histogram;
+      } else {
+        // We already have one histogram with this name.
+        histogram_to_return = it->second;
+        histogram_to_delete = histogram;
+      }
+    }
+  }
+  delete histogram_to_delete;
+  return histogram_to_return;
+}
+
+// static
+const BucketRanges* StatisticsRecorder::RegisterOrDeleteDuplicateRanges(
+    const BucketRanges* ranges) {
+  DCHECK(ranges->HasValidChecksum());
+  scoped_ptr<const BucketRanges> ranges_deleter;
+
+  if (lock_ == NULL) {
+    ANNOTATE_LEAKING_OBJECT_PTR(ranges);
+    return ranges;
+  }
+
+  base::AutoLock auto_lock(*lock_);
+  if (ranges_ == NULL) {
+    ANNOTATE_LEAKING_OBJECT_PTR(ranges);
+    return ranges;
+  }
+
+  std::list<const BucketRanges*>* checksum_matching_list;
+  RangesMap::iterator ranges_it = ranges_->find(ranges->checksum());
+  if (ranges_->end() == ranges_it) {
+    // Add a new matching list to map.
+    checksum_matching_list = new std::list<const BucketRanges*>();
+    ANNOTATE_LEAKING_OBJECT_PTR(checksum_matching_list);
+    (*ranges_)[ranges->checksum()] = checksum_matching_list;
+  } else {
+    checksum_matching_list = ranges_it->second;
+  }
+
+  for (const BucketRanges* existing_ranges : *checksum_matching_list) {
+    if (existing_ranges->Equals(ranges)) {
+      if (existing_ranges == ranges) {
+        return ranges;
+      } else {
+        ranges_deleter.reset(ranges);
+        return existing_ranges;
+      }
+    }
+  }
+  // We haven't found a BucketRanges which has the same ranges. Register the
+  // new BucketRanges.
+  checksum_matching_list->push_front(ranges);
+  return ranges;
+}
+
+// static
+void StatisticsRecorder::WriteHTMLGraph(const std::string& query,
+                                        std::string* output) {
+  if (!IsActive())
+    return;
+
+  Histograms snapshot;
+  GetSnapshot(query, &snapshot);
+  for (const HistogramBase* histogram : snapshot) {
+    histogram->WriteHTMLGraph(output);
+    output->append("<br><hr><br>");
+  }
+}
+
+// static
+void StatisticsRecorder::WriteGraph(const std::string& query,
+                                    std::string* output) {
+  if (!IsActive())
+    return;
+  if (query.length())
+    StringAppendF(output, "Collections of histograms for %s\n", query.c_str());
+  else
+    output->append("Collections of all histograms\n");
+
+  Histograms snapshot;
+  GetSnapshot(query, &snapshot);
+  for (const HistogramBase* histogram : snapshot) {
+    histogram->WriteAscii(output);
+    output->append("\n");
+  }
+}
+
+// static
+std::string StatisticsRecorder::ToJSON(const std::string& query) {
+  if (!IsActive())
+    return std::string();
+
+  std::string output("{");
+  if (!query.empty()) {
+    output += "\"query\":";
+    EscapeJSONString(query, true, &output);
+    output += ",";
+  }
+
+  Histograms snapshot;
+  GetSnapshot(query, &snapshot);
+  output += "\"histograms\":[";
+  bool first_histogram = true;
+  for (const HistogramBase* histogram : snapshot) {
+    if (first_histogram)
+      first_histogram = false;
+    else
+      output += ",";
+    std::string json;
+    histogram->WriteJSON(&json);
+    output += json;
+  }
+  output += "]}";
+  return output;
+}
+
+// static
+void StatisticsRecorder::GetHistograms(Histograms* output) {
+  if (lock_ == NULL)
+    return;
+  base::AutoLock auto_lock(*lock_);
+  if (histograms_ == NULL)
+    return;
+
+  for (const auto& entry : *histograms_) {
+    DCHECK_EQ(entry.first, entry.second->histogram_name());
+    output->push_back(entry.second);
+  }
+}
+
+// static
+void StatisticsRecorder::GetBucketRanges(
+    std::vector<const BucketRanges*>* output) {
+  if (lock_ == NULL)
+    return;
+  base::AutoLock auto_lock(*lock_);
+  if (ranges_ == NULL)
+    return;
+
+  for (const auto& entry : *ranges_) {
+    for (const auto& range_entry : *entry.second) {
+      output->push_back(range_entry);
+    }
+  }
+}
+
+// static
+HistogramBase* StatisticsRecorder::FindHistogram(const std::string& name) {
+  if (lock_ == NULL)
+    return NULL;
+  base::AutoLock auto_lock(*lock_);
+  if (histograms_ == NULL)
+    return NULL;
+
+  HistogramMap::iterator it = histograms_->find(name);
+  if (histograms_->end() == it)
+    return NULL;
+  return it->second;
+}
+
+// private static
+void StatisticsRecorder::GetSnapshot(const std::string& query,
+                                     Histograms* snapshot) {
+  if (lock_ == NULL)
+    return;
+  base::AutoLock auto_lock(*lock_);
+  if (histograms_ == NULL)
+    return;
+
+  for (const auto& entry : *histograms_) {
+    if (entry.first.find(query) != std::string::npos)
+      snapshot->push_back(entry.second);
+  }
+}
+
+// This singleton instance should be started during the single threaded portion
+// of main(), and hence it is not thread safe.  It initializes globals to
+// provide support for all future calls.
+StatisticsRecorder::StatisticsRecorder() {
+  DCHECK(!histograms_);
+  if (lock_ == NULL) {
+    // This will leak on purpose. It's the only way to make sure we won't race
+    // against the static uninitialization of the module while one of our
+    // static methods relying on the lock get called at an inappropriate time
+    // during the termination phase. Since it's a static data member, we will
+    // leak one per process, which would be similar to the instance allocated
+    // during static initialization and released only on  process termination.
+    lock_ = new base::Lock;
+  }
+  base::AutoLock auto_lock(*lock_);
+  histograms_ = new HistogramMap;
+  ranges_ = new RangesMap;
+
+  if (VLOG_IS_ON(1))
+    AtExitManager::RegisterCallback(&DumpHistogramsToVlog, this);
+}
+
+// static
+void StatisticsRecorder::DumpHistogramsToVlog(void* instance) {
+  std::string output;
+  StatisticsRecorder::WriteGraph(std::string(), &output);
+  VLOG(1) << output;
+}
+
+StatisticsRecorder::~StatisticsRecorder() {
+  DCHECK(histograms_ && ranges_ && lock_);
+
+  // Clean up.
+  scoped_ptr<HistogramMap> histograms_deleter;
+  scoped_ptr<RangesMap> ranges_deleter;
+  // We don't delete lock_ on purpose to avoid having to properly protect
+  // against it going away after we checked for NULL in the static methods.
+  {
+    base::AutoLock auto_lock(*lock_);
+    histograms_deleter.reset(histograms_);
+    ranges_deleter.reset(ranges_);
+    histograms_ = NULL;
+    ranges_ = NULL;
+  }
+  // We are going to leak the histograms and the ranges.
+}
+
+
+// static
+StatisticsRecorder::HistogramMap* StatisticsRecorder::histograms_ = NULL;
+// static
+StatisticsRecorder::RangesMap* StatisticsRecorder::ranges_ = NULL;
+// static
+base::Lock* StatisticsRecorder::lock_ = NULL;
+
+}  // namespace base
diff --git a/base/metrics/statistics_recorder.h b/base/metrics/statistics_recorder.h
new file mode 100644
index 0000000..b523057
--- /dev/null
+++ b/base/metrics/statistics_recorder.h
@@ -0,0 +1,116 @@
+// Copyright (c) 2012 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.
+
+// StatisticsRecorder holds all Histograms and BucketRanges that are used by
+// Histograms in the system. It provides a general place for
+// Histograms/BucketRanges to register, and supports a global API for accessing
+// (i.e., dumping, or graphing) the data.
+
+#ifndef BASE_METRICS_STATISTICS_RECORDER_H_
+#define BASE_METRICS_STATISTICS_RECORDER_H_
+
+#include <list>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/gtest_prod_util.h"
+#include "base/lazy_instance.h"
+
+namespace base {
+
+class BucketRanges;
+class HistogramBase;
+class Lock;
+
+class BASE_EXPORT StatisticsRecorder {
+ public:
+  typedef std::vector<HistogramBase*> Histograms;
+
+  // Initializes the StatisticsRecorder system. Safe to call multiple times.
+  static void Initialize();
+
+  // Find out if histograms can now be registered into our list.
+  static bool IsActive();
+
+  // Register, or add a new histogram to the collection of statistics. If an
+  // identically named histogram is already registered, then the argument
+  // |histogram| will deleted.  The returned value is always the registered
+  // histogram (either the argument, or the pre-existing registered histogram).
+  static HistogramBase* RegisterOrDeleteDuplicate(HistogramBase* histogram);
+
+  // Register, or add a new BucketRanges. If an identically BucketRanges is
+  // already registered, then the argument |ranges| will deleted. The returned
+  // value is always the registered BucketRanges (either the argument, or the
+  // pre-existing one).
+  static const BucketRanges* RegisterOrDeleteDuplicateRanges(
+      const BucketRanges* ranges);
+
+  // Methods for appending histogram data to a string.  Only histograms which
+  // have |query| as a substring are written to |output| (an empty string will
+  // process all registered histograms).
+  static void WriteHTMLGraph(const std::string& query, std::string* output);
+  static void WriteGraph(const std::string& query, std::string* output);
+
+  // Returns the histograms with |query| as a substring as JSON text (an empty
+  // |query| will process all registered histograms).
+  static std::string ToJSON(const std::string& query);
+
+  // Method for extracting histograms which were marked for use by UMA.
+  static void GetHistograms(Histograms* output);
+
+  // Method for extracting BucketRanges used by all histograms registered.
+  static void GetBucketRanges(std::vector<const BucketRanges*>* output);
+
+  // Find a histogram by name. It matches the exact name. This method is thread
+  // safe.  It returns NULL if a matching histogram is not found.
+  static HistogramBase* FindHistogram(const std::string& name);
+
+  // GetSnapshot copies some of the pointers to registered histograms into the
+  // caller supplied vector (Histograms). Only histograms which have |query| as
+  // a substring are copied (an empty string will process all registered
+  // histograms).
+  static void GetSnapshot(const std::string& query, Histograms* snapshot);
+
+ private:
+  // We keep all registered histograms in a map, from name to histogram.
+  typedef std::map<std::string, HistogramBase*> HistogramMap;
+
+  // We keep all |bucket_ranges_| in a map, from checksum to a list of
+  // |bucket_ranges_|.  Checksum is calculated from the |ranges_| in
+  // |bucket_ranges_|.
+  typedef std::map<uint32, std::list<const BucketRanges*>*> RangesMap;
+
+  friend struct DefaultLazyInstanceTraits<StatisticsRecorder>;
+  friend class HistogramBaseTest;
+  friend class HistogramSnapshotManagerTest;
+  friend class HistogramTest;
+  friend class JsonPrefStoreTest;
+  friend class SparseHistogramTest;
+  friend class StatisticsRecorderTest;
+  FRIEND_TEST_ALL_PREFIXES(HistogramDeltaSerializationTest,
+                           DeserializeHistogramAndAddSamples);
+
+  // The constructor just initializes static members. Usually client code should
+  // use Initialize to do this. But in test code, you can friend this class and
+  // call destructor/constructor to get a clean StatisticsRecorder.
+  StatisticsRecorder();
+  ~StatisticsRecorder();
+
+  static void DumpHistogramsToVlog(void* instance);
+
+  static HistogramMap* histograms_;
+  static RangesMap* ranges_;
+
+  // Lock protects access to above maps.
+  static base::Lock* lock_;
+
+  DISALLOW_COPY_AND_ASSIGN(StatisticsRecorder);
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_STATISTICS_RECORDER_H_
diff --git a/base/metrics/statistics_recorder_unittest.cc b/base/metrics/statistics_recorder_unittest.cc
new file mode 100644
index 0000000..d26df69
--- /dev/null
+++ b/base/metrics/statistics_recorder_unittest.cc
@@ -0,0 +1,315 @@
+// Copyright (c) 2012 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 <vector>
+
+#include "base/json/json_reader.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/histogram.h"
+#include "base/metrics/statistics_recorder.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+class StatisticsRecorderTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    // Each test will have a clean state (no Histogram / BucketRanges
+    // registered).
+    InitializeStatisticsRecorder();
+  }
+
+  void TearDown() override { UninitializeStatisticsRecorder(); }
+
+  void InitializeStatisticsRecorder() {
+    statistics_recorder_ = new StatisticsRecorder();
+  }
+
+  void UninitializeStatisticsRecorder() {
+    delete statistics_recorder_;
+    statistics_recorder_ = NULL;
+  }
+
+  Histogram* CreateHistogram(const std::string& name,
+                             HistogramBase::Sample min,
+                             HistogramBase::Sample max,
+                             size_t bucket_count) {
+    BucketRanges* ranges = new BucketRanges(bucket_count + 1);
+    Histogram::InitializeBucketRanges(min, max, ranges);
+    const BucketRanges* registered_ranges =
+        StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges);
+    return new Histogram(name, min, max, registered_ranges);
+  }
+
+  void DeleteHistogram(HistogramBase* histogram) {
+    delete histogram;
+  }
+
+  StatisticsRecorder* statistics_recorder_;
+};
+
+TEST_F(StatisticsRecorderTest, NotInitialized) {
+  UninitializeStatisticsRecorder();
+
+  ASSERT_FALSE(StatisticsRecorder::IsActive());
+
+  StatisticsRecorder::Histograms registered_histograms;
+  std::vector<const BucketRanges*> registered_ranges;
+
+  StatisticsRecorder::GetHistograms(&registered_histograms);
+  EXPECT_EQ(0u, registered_histograms.size());
+
+  Histogram* histogram = CreateHistogram("TestHistogram", 1, 1000, 10);
+
+  // When StatisticsRecorder is not initialized, register is a noop.
+  EXPECT_EQ(histogram,
+            StatisticsRecorder::RegisterOrDeleteDuplicate(histogram));
+  // Manually delete histogram that was not registered.
+  DeleteHistogram(histogram);
+
+  // RegisterOrDeleteDuplicateRanges is a no-op.
+  BucketRanges* ranges = new BucketRanges(3);;
+  ranges->ResetChecksum();
+  EXPECT_EQ(ranges,
+            StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges));
+  StatisticsRecorder::GetBucketRanges(&registered_ranges);
+  EXPECT_EQ(0u, registered_ranges.size());
+}
+
+TEST_F(StatisticsRecorderTest, RegisterBucketRanges) {
+  std::vector<const BucketRanges*> registered_ranges;
+
+  BucketRanges* ranges1 = new BucketRanges(3);;
+  ranges1->ResetChecksum();
+  BucketRanges* ranges2 = new BucketRanges(4);;
+  ranges2->ResetChecksum();
+
+  // Register new ranges.
+  EXPECT_EQ(ranges1,
+            StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges1));
+  EXPECT_EQ(ranges2,
+            StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges2));
+  StatisticsRecorder::GetBucketRanges(&registered_ranges);
+  ASSERT_EQ(2u, registered_ranges.size());
+
+  // Register some ranges again.
+  EXPECT_EQ(ranges1,
+            StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges1));
+  registered_ranges.clear();
+  StatisticsRecorder::GetBucketRanges(&registered_ranges);
+  ASSERT_EQ(2u, registered_ranges.size());
+  // Make sure the ranges is still the one we know.
+  ASSERT_EQ(3u, ranges1->size());
+  EXPECT_EQ(0, ranges1->range(0));
+  EXPECT_EQ(0, ranges1->range(1));
+  EXPECT_EQ(0, ranges1->range(2));
+
+  // Register ranges with same values.
+  BucketRanges* ranges3 = new BucketRanges(3);;
+  ranges3->ResetChecksum();
+  EXPECT_EQ(ranges1,  // returning ranges1
+            StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges3));
+  registered_ranges.clear();
+  StatisticsRecorder::GetBucketRanges(&registered_ranges);
+  ASSERT_EQ(2u, registered_ranges.size());
+}
+
+TEST_F(StatisticsRecorderTest, RegisterHistogram) {
+  // Create a Histogram that was not registered.
+  Histogram* histogram = CreateHistogram("TestHistogram", 1, 1000, 10);
+
+  StatisticsRecorder::Histograms registered_histograms;
+  StatisticsRecorder::GetHistograms(&registered_histograms);
+  EXPECT_EQ(0u, registered_histograms.size());
+
+  // Register the Histogram.
+  EXPECT_EQ(histogram,
+            StatisticsRecorder::RegisterOrDeleteDuplicate(histogram));
+  StatisticsRecorder::GetHistograms(&registered_histograms);
+  EXPECT_EQ(1u, registered_histograms.size());
+
+  // Register the same Histogram again.
+  EXPECT_EQ(histogram,
+            StatisticsRecorder::RegisterOrDeleteDuplicate(histogram));
+  registered_histograms.clear();
+  StatisticsRecorder::GetHistograms(&registered_histograms);
+  EXPECT_EQ(1u, registered_histograms.size());
+}
+
+TEST_F(StatisticsRecorderTest, FindHistogram) {
+  HistogramBase* histogram1 = Histogram::FactoryGet(
+      "TestHistogram1", 1, 1000, 10, HistogramBase::kNoFlags);
+  HistogramBase* histogram2 = Histogram::FactoryGet(
+      "TestHistogram2", 1, 1000, 10, HistogramBase::kNoFlags);
+
+  EXPECT_EQ(histogram1, StatisticsRecorder::FindHistogram("TestHistogram1"));
+  EXPECT_EQ(histogram2, StatisticsRecorder::FindHistogram("TestHistogram2"));
+  EXPECT_TRUE(StatisticsRecorder::FindHistogram("TestHistogram") == NULL);
+}
+
+TEST_F(StatisticsRecorderTest, GetSnapshot) {
+  Histogram::FactoryGet("TestHistogram1", 1, 1000, 10, Histogram::kNoFlags);
+  Histogram::FactoryGet("TestHistogram2", 1, 1000, 10, Histogram::kNoFlags);
+  Histogram::FactoryGet("TestHistogram3", 1, 1000, 10, Histogram::kNoFlags);
+
+  StatisticsRecorder::Histograms snapshot;
+  StatisticsRecorder::GetSnapshot("Test", &snapshot);
+  EXPECT_EQ(3u, snapshot.size());
+
+  snapshot.clear();
+  StatisticsRecorder::GetSnapshot("1", &snapshot);
+  EXPECT_EQ(1u, snapshot.size());
+
+  snapshot.clear();
+  StatisticsRecorder::GetSnapshot("hello", &snapshot);
+  EXPECT_EQ(0u, snapshot.size());
+}
+
+TEST_F(StatisticsRecorderTest, RegisterHistogramWithFactoryGet) {
+  StatisticsRecorder::Histograms registered_histograms;
+
+  StatisticsRecorder::GetHistograms(&registered_histograms);
+  ASSERT_EQ(0u, registered_histograms.size());
+
+  // Create a histogram.
+  HistogramBase* histogram = Histogram::FactoryGet(
+      "TestHistogram", 1, 1000, 10, HistogramBase::kNoFlags);
+  registered_histograms.clear();
+  StatisticsRecorder::GetHistograms(&registered_histograms);
+  EXPECT_EQ(1u, registered_histograms.size());
+
+  // Get an existing histogram.
+  HistogramBase* histogram2 = Histogram::FactoryGet(
+      "TestHistogram", 1, 1000, 10, HistogramBase::kNoFlags);
+  registered_histograms.clear();
+  StatisticsRecorder::GetHistograms(&registered_histograms);
+  EXPECT_EQ(1u, registered_histograms.size());
+  EXPECT_EQ(histogram, histogram2);
+
+  // Create a LinearHistogram.
+  histogram = LinearHistogram::FactoryGet(
+      "TestLinearHistogram", 1, 1000, 10, HistogramBase::kNoFlags);
+  registered_histograms.clear();
+  StatisticsRecorder::GetHistograms(&registered_histograms);
+  EXPECT_EQ(2u, registered_histograms.size());
+
+  // Create a BooleanHistogram.
+  histogram = BooleanHistogram::FactoryGet(
+      "TestBooleanHistogram", HistogramBase::kNoFlags);
+  registered_histograms.clear();
+  StatisticsRecorder::GetHistograms(&registered_histograms);
+  EXPECT_EQ(3u, registered_histograms.size());
+
+  // Create a CustomHistogram.
+  std::vector<int> custom_ranges;
+  custom_ranges.push_back(1);
+  custom_ranges.push_back(5);
+  histogram = CustomHistogram::FactoryGet(
+      "TestCustomHistogram", custom_ranges, HistogramBase::kNoFlags);
+  registered_histograms.clear();
+  StatisticsRecorder::GetHistograms(&registered_histograms);
+  EXPECT_EQ(4u, registered_histograms.size());
+}
+
+TEST_F(StatisticsRecorderTest, RegisterHistogramWithMacros) {
+  StatisticsRecorder::Histograms registered_histograms;
+
+  HistogramBase* histogram = Histogram::FactoryGet(
+      "TestHistogramCounts", 1, 1000000, 50, HistogramBase::kNoFlags);
+
+  // The histogram we got from macro is the same as from FactoryGet.
+  LOCAL_HISTOGRAM_COUNTS("TestHistogramCounts", 30);
+  registered_histograms.clear();
+  StatisticsRecorder::GetHistograms(&registered_histograms);
+  ASSERT_EQ(1u, registered_histograms.size());
+  EXPECT_EQ(histogram, registered_histograms[0]);
+
+  LOCAL_HISTOGRAM_TIMES("TestHistogramTimes", TimeDelta::FromDays(1));
+  LOCAL_HISTOGRAM_ENUMERATION("TestHistogramEnumeration", 20, 200);
+
+  registered_histograms.clear();
+  StatisticsRecorder::GetHistograms(&registered_histograms);
+  EXPECT_EQ(3u, registered_histograms.size());
+}
+
+TEST_F(StatisticsRecorderTest, BucketRangesSharing) {
+  std::vector<const BucketRanges*> ranges;
+  StatisticsRecorder::GetBucketRanges(&ranges);
+  EXPECT_EQ(0u, ranges.size());
+
+  Histogram::FactoryGet("Histogram", 1, 64, 8, HistogramBase::kNoFlags);
+  Histogram::FactoryGet("Histogram2", 1, 64, 8, HistogramBase::kNoFlags);
+
+  StatisticsRecorder::GetBucketRanges(&ranges);
+  EXPECT_EQ(1u, ranges.size());
+
+  Histogram::FactoryGet("Histogram3", 1, 64, 16, HistogramBase::kNoFlags);
+
+  ranges.clear();
+  StatisticsRecorder::GetBucketRanges(&ranges);
+  EXPECT_EQ(2u, ranges.size());
+}
+
+TEST_F(StatisticsRecorderTest, ToJSON) {
+  LOCAL_HISTOGRAM_COUNTS("TestHistogram1", 30);
+  LOCAL_HISTOGRAM_COUNTS("TestHistogram1", 40);
+  LOCAL_HISTOGRAM_COUNTS("TestHistogram2", 30);
+  LOCAL_HISTOGRAM_COUNTS("TestHistogram2", 40);
+
+  std::string json(StatisticsRecorder::ToJSON(std::string()));
+
+  // Check for valid JSON.
+  scoped_ptr<Value> root;
+  root.reset(JSONReader::DeprecatedRead(json));
+  ASSERT_TRUE(root.get());
+
+  DictionaryValue* root_dict = NULL;
+  ASSERT_TRUE(root->GetAsDictionary(&root_dict));
+
+  // No query should be set.
+  ASSERT_FALSE(root_dict->HasKey("query"));
+
+  ListValue* histogram_list = NULL;
+  ASSERT_TRUE(root_dict->GetList("histograms", &histogram_list));
+  ASSERT_EQ(2u, histogram_list->GetSize());
+
+  // Examine the first histogram.
+  DictionaryValue* histogram_dict = NULL;
+  ASSERT_TRUE(histogram_list->GetDictionary(0, &histogram_dict));
+
+  int sample_count;
+  ASSERT_TRUE(histogram_dict->GetInteger("count", &sample_count));
+  EXPECT_EQ(2, sample_count);
+
+  // Test the query filter.
+  std::string query("TestHistogram2");
+  json = StatisticsRecorder::ToJSON(query);
+
+  root.reset(JSONReader::DeprecatedRead(json));
+  ASSERT_TRUE(root.get());
+  ASSERT_TRUE(root->GetAsDictionary(&root_dict));
+
+  std::string query_value;
+  ASSERT_TRUE(root_dict->GetString("query", &query_value));
+  EXPECT_EQ(query, query_value);
+
+  ASSERT_TRUE(root_dict->GetList("histograms", &histogram_list));
+  ASSERT_EQ(1u, histogram_list->GetSize());
+
+  ASSERT_TRUE(histogram_list->GetDictionary(0, &histogram_dict));
+
+  std::string histogram_name;
+  ASSERT_TRUE(histogram_dict->GetString("name", &histogram_name));
+  EXPECT_EQ("TestHistogram2", histogram_name);
+
+  json.clear();
+  UninitializeStatisticsRecorder();
+
+  // No data should be returned.
+  json = StatisticsRecorder::ToJSON(query);
+  EXPECT_TRUE(json.empty());
+}
+
+}  // namespace base
diff --git a/base/metrics/user_metrics.cc b/base/metrics/user_metrics.cc
new file mode 100644
index 0000000..9db5840
--- /dev/null
+++ b/base/metrics/user_metrics.cc
@@ -0,0 +1,74 @@
+// 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.
+
+#include "base/metrics/user_metrics.h"
+
+#include <vector>
+
+#include "base/lazy_instance.h"
+#include "base/threading/thread_checker.h"
+
+namespace base {
+namespace {
+
+// A helper class for tracking callbacks and ensuring thread-safety.
+class Callbacks {
+ public:
+  Callbacks() {}
+
+  // Records the |action|.
+  void Record(const std::string& action) {
+    DCHECK(thread_checker_.CalledOnValidThread());
+    for (size_t i = 0; i < callbacks_.size(); ++i) {
+      callbacks_[i].Run(action);
+    }
+  }
+
+  // Adds |callback| to the list of |callbacks_|.
+  void AddCallback(const ActionCallback& callback) {
+    DCHECK(thread_checker_.CalledOnValidThread());
+    callbacks_.push_back(callback);
+  }
+
+  // Removes the first instance of |callback| from the list of |callbacks_|, if
+  // there is one.
+  void RemoveCallback(const ActionCallback& callback) {
+    DCHECK(thread_checker_.CalledOnValidThread());
+    for (size_t i = 0; i < callbacks_.size(); ++i) {
+      if (callbacks_[i].Equals(callback)) {
+        callbacks_.erase(callbacks_.begin() + i);
+        return;
+      }
+    }
+  }
+
+ private:
+  base::ThreadChecker thread_checker_;
+  std::vector<ActionCallback> callbacks_;
+
+  DISALLOW_COPY_AND_ASSIGN(Callbacks);
+};
+
+base::LazyInstance<Callbacks> g_callbacks = LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+void RecordAction(const UserMetricsAction& action) {
+  g_callbacks.Get().Record(action.str_);
+}
+
+void RecordComputedAction(const std::string& action) {
+  g_callbacks.Get().Record(action);
+}
+
+void AddActionCallback(const ActionCallback& callback) {
+  g_callbacks.Get().AddCallback(callback);
+}
+
+void RemoveActionCallback(const ActionCallback& callback) {
+  g_callbacks.Get().RemoveCallback(callback);
+
+}
+
+}  // namespace base
diff --git a/base/metrics/user_metrics.h b/base/metrics/user_metrics.h
new file mode 100644
index 0000000..bcfefb8
--- /dev/null
+++ b/base/metrics/user_metrics.h
@@ -0,0 +1,60 @@
+// 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.
+
+#ifndef BASE_METRICS_USER_METRICS_H_
+#define BASE_METRICS_USER_METRICS_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/callback.h"
+#include "base/metrics/user_metrics_action.h"
+
+namespace base {
+
+// This module provides some helper functions for logging actions tracked by
+// the user metrics system.
+
+// Record that the user performed an action.
+// This method *must* be called from the main thread.
+//
+// "Action" here means a user-generated event:
+//   good: "Reload", "CloseTab", and "IMEInvoked"
+//   not good: "SSLDialogShown", "PageLoaded", "DiskFull"
+// We use this to gather anonymized information about how users are
+// interacting with the browser.
+// WARNING: In calls to this function, UserMetricsAction and a
+// string literal parameter must be on the same line, e.g.
+//   RecordAction(UserMetricsAction("my extremely long action name"));
+// This ensures that our processing scripts can associate this action's hash
+// with its metric name. Therefore, it will be possible to retrieve the metric
+// name from the hash later on.
+//
+// Once a new recorded action is added, run
+//   tools/metrics/actions/extract_actions.py
+// to add the metric to actions.xml, then update the <owner>s and <description>
+// sections. Make sure to include the actions.xml file when you upload your code
+// for review!
+//
+// For more complicated situations (like when there are many different
+// possible actions), see RecordComputedAction.
+BASE_EXPORT void RecordAction(const UserMetricsAction& action);
+
+// This function has identical input and behavior to RecordAction, but is
+// not automatically found by the action-processing scripts.  It can be used
+// when it's a pain to enumerate all possible actions, but if you use this
+// you need to also update the rules for extracting known actions in
+// tools/metrics/actions/extract_actions.py.
+BASE_EXPORT void RecordComputedAction(const std::string& action);
+
+// Called with the action string.
+typedef base::Callback<void(const std::string&)> ActionCallback;
+
+// Add/remove action callbacks (see above).
+BASE_EXPORT void AddActionCallback(const ActionCallback& callback);
+BASE_EXPORT void RemoveActionCallback(const ActionCallback& callback);
+
+}  // namespace base
+
+#endif  // BASE_METRICS_USER_METRICS_H_
diff --git a/base/metrics/user_metrics_action.h b/base/metrics/user_metrics_action.h
new file mode 100644
index 0000000..8c195b3
--- /dev/null
+++ b/base/metrics/user_metrics_action.h
@@ -0,0 +1,28 @@
+// 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.
+
+#ifndef BASE_METRICS_USER_METRICS_ACTION_H_
+#define BASE_METRICS_USER_METRICS_ACTION_H_
+
+namespace base {
+
+// UserMetricsAction exists purely to standardize on the parameters passed to
+// UserMetrics. That way, our toolset can scan the source code reliable for
+// constructors and extract the associated string constants.
+// WARNING: When using UserMetricsAction, UserMetricsAction and a string literal
+// parameter must be on the same line, e.g.
+//   RecordAction(UserMetricsAction("my extremely long action name"));
+// or
+//   RenderThread::Get()->RecordAction(
+//       UserMetricsAction("my extremely long action name"));
+// because otherwise our processing scripts won't pick up on new actions.
+// Please see tools/metrics/actions/extract_actions.py for details.
+struct UserMetricsAction {
+  const char* str_;
+  explicit UserMetricsAction(const char* str) : str_(str) {}
+};
+
+}  // namespace base
+
+#endif  // BASE_METRICS_USER_METRICS_ACTION_H_
diff --git a/base/move.h b/base/move.h
new file mode 100644
index 0000000..87dc52d
--- /dev/null
+++ b/base/move.h
@@ -0,0 +1,234 @@
+// Copyright (c) 2012 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_MOVE_H_
+#define BASE_MOVE_H_
+
+#include "base/compiler_specific.h"
+
+// Macro with the boilerplate that makes a type move-only in C++03.
+//
+// USAGE
+//
+// This macro should be used instead of DISALLOW_COPY_AND_ASSIGN to create
+// a "move-only" type.  Unlike DISALLOW_COPY_AND_ASSIGN, this macro should be
+// the first line in a class declaration.
+//
+// A class using this macro must call .Pass() (or somehow be an r-value already)
+// before it can be:
+//
+//   * Passed as a function argument
+//   * Used as the right-hand side of an assignment
+//   * Returned from a function
+//
+// Each class will still need to define their own "move constructor" and "move
+// operator=" to make this useful.  Here's an example of the macro, the move
+// constructor, and the move operator= from the scoped_ptr class:
+//
+//  template <typename T>
+//  class scoped_ptr {
+//     MOVE_ONLY_TYPE_FOR_CPP_03(scoped_ptr, RValue)
+//   public:
+//    scoped_ptr(RValue& other) : ptr_(other.release()) { }
+//    scoped_ptr& operator=(RValue& other) {
+//      swap(other);
+//      return *this;
+//    }
+//  };
+//
+// Note that the constructor must NOT be marked explicit.
+//
+// For consistency, the second parameter to the macro should always be RValue
+// unless you have a strong reason to do otherwise.  It is only exposed as a
+// macro parameter so that the move constructor and move operator= don't look
+// like they're using a phantom type.
+//
+//
+// HOW THIS WORKS
+//
+// For a thorough explanation of this technique, see:
+//
+//   http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Move_Constructor
+//
+// The summary is that we take advantage of 2 properties:
+//
+//   1) non-const references will not bind to r-values.
+//   2) C++ can apply one user-defined conversion when initializing a
+//      variable.
+//
+// The first lets us disable the copy constructor and assignment operator
+// by declaring private version of them with a non-const reference parameter.
+//
+// For l-values, direct initialization still fails like in
+// DISALLOW_COPY_AND_ASSIGN because the copy constructor and assignment
+// operators are private.
+//
+// For r-values, the situation is different. The copy constructor and
+// assignment operator are not viable due to (1), so we are trying to call
+// a non-existent constructor and non-existing operator= rather than a private
+// one.  Since we have not committed an error quite yet, we can provide an
+// alternate conversion sequence and a constructor.  We add
+//
+//   * a private struct named "RValue"
+//   * a user-defined conversion "operator RValue()"
+//   * a "move constructor" and "move operator=" that take the RValue& as
+//     their sole parameter.
+//
+// Only r-values will trigger this sequence and execute our "move constructor"
+// or "move operator=."  L-values will match the private copy constructor and
+// operator= first giving a "private in this context" error.  This combination
+// gives us a move-only type.
+//
+// For signaling a destructive transfer of data from an l-value, we provide a
+// method named Pass() which creates an r-value for the current instance
+// triggering the move constructor or move operator=.
+//
+// Other ways to get r-values is to use the result of an expression like a
+// function call.
+//
+// Here's an example with comments explaining what gets triggered where:
+//
+//    class Foo {
+//      MOVE_ONLY_TYPE_FOR_CPP_03(Foo, RValue);
+//
+//     public:
+//       ... API ...
+//       Foo(RValue other);           // Move constructor.
+//       Foo& operator=(RValue rhs);  // Move operator=
+//    };
+//
+//    Foo MakeFoo();  // Function that returns a Foo.
+//
+//    Foo f;
+//    Foo f_copy(f);  // ERROR: Foo(Foo&) is private in this context.
+//    Foo f_assign;
+//    f_assign = f;   // ERROR: operator=(Foo&) is private in this context.
+//
+//
+//    Foo f(MakeFoo());      // R-value so alternate conversion executed.
+//    Foo f_copy(f.Pass());  // R-value so alternate conversion executed.
+//    f = f_copy.Pass();     // R-value so alternate conversion executed.
+//
+//
+// IMPLEMENTATION SUBTLETIES WITH RValue
+//
+// The RValue struct is just a container for a pointer back to the original
+// object. It should only ever be created as a temporary, and no external
+// class should ever declare it or use it in a parameter.
+//
+// It is tempting to want to use the RValue type in function parameters, but
+// excluding the limited usage here for the move constructor and move
+// operator=, doing so would mean that the function could take both r-values
+// and l-values equially which is unexpected.  See COMPARED To Boost.Move for
+// more details.
+//
+// An alternate, and incorrect, implementation of the RValue class used by
+// Boost.Move makes RValue a fieldless child of the move-only type. RValue&
+// is then used in place of RValue in the various operators.  The RValue& is
+// "created" by doing *reinterpret_cast<RValue*>(this).  This has the appeal
+// of never creating a temporary RValue struct even with optimizations
+// disabled.  Also, by virtue of inheritance you can treat the RValue
+// reference as if it were the move-only type itself.  Unfortunately,
+// using the result of this reinterpret_cast<> is actually undefined behavior
+// due to C++98 5.2.10.7. In certain compilers (e.g., NaCl) the optimizer
+// will generate non-working code.
+//
+// In optimized builds, both implementations generate the same assembly so we
+// choose the one that adheres to the standard.
+//
+//
+// WHY HAVE typedef void MoveOnlyTypeForCPP03
+//
+// Callback<>/Bind() needs to understand movable-but-not-copyable semantics
+// to call .Pass() appropriately when it is expected to transfer the value.
+// The cryptic typedef MoveOnlyTypeForCPP03 is added to make this check
+// easy and automatic in helper templates for Callback<>/Bind().
+// See IsMoveOnlyType template and its usage in base/callback_internal.h
+// for more details.
+//
+//
+// COMPARED TO C++11
+//
+// In C++11, you would implement this functionality using an r-value reference
+// and our .Pass() method would be replaced with a call to std::move().
+//
+// This emulation also has a deficiency where it uses up the single
+// user-defined conversion allowed by C++ during initialization.  This can
+// cause problems in some API edge cases.  For instance, in scoped_ptr, it is
+// impossible to make a function "void Foo(scoped_ptr<Parent> p)" accept a
+// value of type scoped_ptr<Child> even if you add a constructor to
+// scoped_ptr<> that would make it look like it should work.  C++11 does not
+// have this deficiency.
+//
+//
+// COMPARED TO Boost.Move
+//
+// Our implementation similar to Boost.Move, but we keep the RValue struct
+// private to the move-only type, and we don't use the reinterpret_cast<> hack.
+//
+// In Boost.Move, RValue is the boost::rv<> template.  This type can be used
+// when writing APIs like:
+//
+//   void MyFunc(boost::rv<Foo>& f)
+//
+// that can take advantage of rv<> to avoid extra copies of a type.  However you
+// would still be able to call this version of MyFunc with an l-value:
+//
+//   Foo f;
+//   MyFunc(f);  // Uh oh, we probably just destroyed |f| w/o calling Pass().
+//
+// unless someone is very careful to also declare a parallel override like:
+//
+//   void MyFunc(const Foo& f)
+//
+// that would catch the l-values first.  This was declared unsafe in C++11 and
+// a C++11 compiler will explicitly fail MyFunc(f).  Unfortunately, we cannot
+// ensure this in C++03.
+//
+// Since we have no need for writing such APIs yet, our implementation keeps
+// RValue private and uses a .Pass() method to do the conversion instead of
+// trying to write a version of "std::move()." Writing an API like std::move()
+// would require the RValue struct to be public.
+//
+//
+// CAVEATS
+//
+// If you include a move-only type as a field inside a class that does not
+// explicitly declare a copy constructor, the containing class's implicit
+// copy constructor will change from Containing(const Containing&) to
+// Containing(Containing&).  This can cause some unexpected errors.
+//
+//   http://llvm.org/bugs/show_bug.cgi?id=11528
+//
+// The workaround is to explicitly declare your copy constructor.
+//
+#define MOVE_ONLY_TYPE_FOR_CPP_03(type, rvalue_type) \
+ private: \
+  struct rvalue_type { \
+    explicit rvalue_type(type* object) : object(object) {} \
+    type* object; \
+  }; \
+  type(type&); \
+  void operator=(type&); \
+ public: \
+  operator rvalue_type() { return rvalue_type(this); } \
+  type Pass() WARN_UNUSED_RESULT { return type(rvalue_type(this)); } \
+  typedef void MoveOnlyTypeForCPP03; \
+ private:
+
+#define MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(type) \
+ private: \
+  type(const type&); \
+  void operator=(const type&); \
+ public: \
+  type&& Pass() WARN_UNUSED_RESULT { return static_cast<type&&>(*this); } \
+  typedef void MoveOnlyTypeForCPP03; \
+ private:
+
+#define TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(type) \
+ public: \
+  type&& Pass() WARN_UNUSED_RESULT { return static_cast<type&&>(*this); } \
+ private:
+
+#endif  // BASE_MOVE_H_
diff --git a/base/move_unittest.cc b/base/move_unittest.cc
new file mode 100644
index 0000000..1f4ce84
--- /dev/null
+++ b/base/move_unittest.cc
@@ -0,0 +1,49 @@
+// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/move.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class MoveOnly {
+  MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(MoveOnly)
+
+ public:
+  MoveOnly() {}
+
+  MoveOnly(MoveOnly&& other) {}
+  MoveOnly& operator=(MoveOnly&& other) { return *this; }
+};
+
+class Container {
+ public:
+  Container() = default;
+  Container(const Container& other) = default;
+  Container& operator=(const Container& other) = default;
+
+  Container(Container&& other) { value_ = other.value_.Pass(); }
+
+  Container& operator=(Container&& other) {
+    value_ = other.value_.Pass();
+    return *this;
+  }
+
+ private:
+  MoveOnly value_;
+};
+
+Container GetContainerRvalue() {
+  Container x;
+  return x;
+}
+
+TEST(MoveTest, CopyableContainerCanBeMoved) {
+  // Container should be move-constructible and move-assignable.
+  Container y = GetContainerRvalue();
+  y = GetContainerRvalue();
+}
+
+}  // namespace
diff --git a/base/native_library.h b/base/native_library.h
new file mode 100644
index 0000000..1e764da
--- /dev/null
+++ b/base/native_library.h
@@ -0,0 +1,100 @@
+// Copyright (c) 2011 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_NATIVE_LIBRARY_H_
+#define BASE_NATIVE_LIBRARY_H_
+
+// This file defines a cross-platform "NativeLibrary" type which represents
+// a loadable module.
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/strings/string16.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#elif defined(OS_MACOSX)
+#import <CoreFoundation/CoreFoundation.h>
+#endif  // OS_*
+
+namespace base {
+
+class FilePath;
+
+#if defined(OS_WIN)
+typedef HMODULE NativeLibrary;
+#elif defined(OS_MACOSX)
+enum NativeLibraryType {
+  BUNDLE,
+  DYNAMIC_LIB
+};
+enum NativeLibraryObjCStatus {
+  OBJC_UNKNOWN,
+  OBJC_PRESENT,
+  OBJC_NOT_PRESENT,
+};
+struct NativeLibraryStruct {
+  NativeLibraryType type;
+  CFBundleRefNum bundle_resource_ref;
+  NativeLibraryObjCStatus objc_status;
+  union {
+    CFBundleRef bundle;
+    void* dylib;
+  };
+};
+typedef NativeLibraryStruct* NativeLibrary;
+#elif defined(OS_POSIX)
+typedef void* NativeLibrary;
+#endif  // OS_*
+
+struct BASE_EXPORT NativeLibraryLoadError {
+#if defined(OS_WIN)
+  NativeLibraryLoadError() : code(0) {}
+#endif  // OS_WIN
+
+  // Returns a string representation of the load error.
+  std::string ToString() const;
+
+#if defined(OS_WIN)
+  DWORD code;
+#else
+  std::string message;
+#endif  // OS_WIN
+};
+
+// Loads a native library from disk.  Release it with UnloadNativeLibrary when
+// you're done.  Returns NULL on failure.
+// If |error| is not NULL, it may be filled in on load error.
+BASE_EXPORT NativeLibrary LoadNativeLibrary(const FilePath& library_path,
+                                            NativeLibraryLoadError* error);
+
+#if defined(OS_WIN)
+// Loads a native library from disk.  Release it with UnloadNativeLibrary when
+// you're done.
+// This function retrieves the LoadLibrary function exported from kernel32.dll
+// and calls it instead of directly calling the LoadLibrary function via the
+// import table.
+BASE_EXPORT NativeLibrary LoadNativeLibraryDynamically(
+    const FilePath& library_path);
+#endif  // OS_WIN
+
+// Unloads a native library.
+BASE_EXPORT void UnloadNativeLibrary(NativeLibrary library);
+
+// Gets a function pointer from a native library.
+BASE_EXPORT void* GetFunctionPointerFromNativeLibrary(NativeLibrary library,
+                                                      const char* name);
+
+// Returns the full platform specific name for a native library.
+// For example:
+// "mylib" returns "mylib.dll" on Windows, "libmylib.so" on Linux,
+// "mylib.dylib" on Mac.
+BASE_EXPORT string16 GetNativeLibraryName(const string16& name);
+
+}  // namespace base
+
+#endif  // BASE_NATIVE_LIBRARY_H_
diff --git a/base/native_library_ios.mm b/base/native_library_ios.mm
new file mode 100644
index 0000000..030c171
--- /dev/null
+++ b/base/native_library_ios.mm
@@ -0,0 +1,40 @@
+// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/native_library.h"
+
+#include "base/logging.h"
+
+namespace base {
+
+std::string NativeLibraryLoadError::ToString() const {
+  return message;
+}
+
+// static
+NativeLibrary LoadNativeLibrary(const base::FilePath& library_path,
+                                NativeLibraryLoadError* error) {
+  NOTIMPLEMENTED();
+  return nullptr;
+}
+
+// static
+void UnloadNativeLibrary(NativeLibrary library) {
+  NOTIMPLEMENTED();
+  DCHECK(!library);
+}
+
+// static
+void* GetFunctionPointerFromNativeLibrary(NativeLibrary library,
+                                          const char* name) {
+  NOTIMPLEMENTED();
+  return nullptr;
+}
+
+// static
+string16 GetNativeLibraryName(const string16& name) {
+  return name;
+}
+
+}  // namespace base
diff --git a/base/native_library_mac.mm b/base/native_library_mac.mm
new file mode 100644
index 0000000..8122c28
--- /dev/null
+++ b/base/native_library_mac.mm
@@ -0,0 +1,131 @@
+// Copyright (c) 2011 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/native_library.h"
+
+#include <dlfcn.h>
+#include <mach-o/getsect.h>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace base {
+
+static NativeLibraryObjCStatus GetObjCStatusForImage(
+    const void* function_pointer) {
+  Dl_info info;
+  if (!dladdr(function_pointer, &info))
+    return OBJC_UNKNOWN;
+
+  // See if the the image contains an "ObjC image info" segment. This method
+  // of testing is used in _CFBundleGrokObjcImageInfoFromFile in
+  // CF-744/CFBundle.c, around lines 2447-2474.
+  //
+  // In 32-bit images, ObjC can be recognized in __OBJC,__image_info, whereas
+  // in 64-bit, the data is in __DATA,__objc_imageinfo.
+#if __LP64__
+  const section_64* section = getsectbynamefromheader_64(
+      reinterpret_cast<const struct mach_header_64*>(info.dli_fbase),
+      SEG_DATA, "__objc_imageinfo");
+#else
+  const section* section = getsectbynamefromheader(
+      reinterpret_cast<const struct mach_header*>(info.dli_fbase),
+      SEG_OBJC, "__image_info");
+#endif
+  return section == NULL ? OBJC_NOT_PRESENT : OBJC_PRESENT;
+}
+
+std::string NativeLibraryLoadError::ToString() const {
+  return message;
+}
+
+// static
+NativeLibrary LoadNativeLibrary(const base::FilePath& library_path,
+                                NativeLibraryLoadError* error) {
+  // dlopen() etc. open the file off disk.
+  if (library_path.Extension() == "dylib" || !DirectoryExists(library_path)) {
+    void* dylib = dlopen(library_path.value().c_str(), RTLD_LAZY);
+    if (!dylib) {
+      error->message = dlerror();
+      return NULL;
+    }
+    NativeLibrary native_lib = new NativeLibraryStruct();
+    native_lib->type = DYNAMIC_LIB;
+    native_lib->dylib = dylib;
+    native_lib->objc_status = OBJC_UNKNOWN;
+    return native_lib;
+  }
+  base::ScopedCFTypeRef<CFURLRef> url(CFURLCreateFromFileSystemRepresentation(
+      kCFAllocatorDefault,
+      (const UInt8*)library_path.value().c_str(),
+      library_path.value().length(),
+      true));
+  if (!url)
+    return NULL;
+  CFBundleRef bundle = CFBundleCreate(kCFAllocatorDefault, url.get());
+  if (!bundle)
+    return NULL;
+
+  NativeLibrary native_lib = new NativeLibraryStruct();
+  native_lib->type = BUNDLE;
+  native_lib->bundle = bundle;
+  native_lib->bundle_resource_ref = CFBundleOpenBundleResourceMap(bundle);
+  native_lib->objc_status = OBJC_UNKNOWN;
+  return native_lib;
+}
+
+// static
+void UnloadNativeLibrary(NativeLibrary library) {
+  if (library->objc_status == OBJC_NOT_PRESENT) {
+    if (library->type == BUNDLE) {
+      CFBundleCloseBundleResourceMap(library->bundle,
+                                     library->bundle_resource_ref);
+      CFRelease(library->bundle);
+    } else {
+      dlclose(library->dylib);
+    }
+  } else {
+    VLOG(2) << "Not unloading NativeLibrary because it may contain an ObjC "
+               "segment. library->objc_status = " << library->objc_status;
+    // Deliberately do not CFRelease the bundle or dlclose the dylib because
+    // doing so can corrupt the ObjC runtime method caches. See
+    // http://crbug.com/172319 for details.
+  }
+  delete library;
+}
+
+// static
+void* GetFunctionPointerFromNativeLibrary(NativeLibrary library,
+                                          const char* name) {
+  void* function_pointer = NULL;
+
+  // Get the function pointer using the right API for the type.
+  if (library->type == BUNDLE) {
+    base::ScopedCFTypeRef<CFStringRef> symbol_name(CFStringCreateWithCString(
+        kCFAllocatorDefault, name, kCFStringEncodingUTF8));
+    function_pointer = CFBundleGetFunctionPointerForName(library->bundle,
+                                                         symbol_name);
+  } else {
+    function_pointer = dlsym(library->dylib, name);
+  }
+
+  // If this library hasn't been tested for having ObjC, use the function
+  // pointer to look up the section information for the library.
+  if (function_pointer && library->objc_status == OBJC_UNKNOWN)
+    library->objc_status = GetObjCStatusForImage(function_pointer);
+
+  return function_pointer;
+}
+
+// static
+string16 GetNativeLibraryName(const string16& name) {
+  return name + ASCIIToUTF16(".dylib");
+}
+
+}  // namespace base
diff --git a/base/native_library_posix.cc b/base/native_library_posix.cc
new file mode 100644
index 0000000..3179a93
--- /dev/null
+++ b/base/native_library_posix.cc
@@ -0,0 +1,57 @@
+// Copyright (c) 2011 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/native_library.h"
+
+#include <dlfcn.h>
+
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace base {
+
+std::string NativeLibraryLoadError::ToString() const {
+  return message;
+}
+
+// static
+NativeLibrary LoadNativeLibrary(const FilePath& library_path,
+                                NativeLibraryLoadError* error) {
+  // dlopen() opens the file off disk.
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  // We deliberately do not use RTLD_DEEPBIND.  For the history why, please
+  // refer to the bug tracker.  Some useful bug reports to read include:
+  // http://crbug.com/17943, http://crbug.com/17557, http://crbug.com/36892,
+  // and http://crbug.com/40794.
+  void* dl = dlopen(library_path.value().c_str(), RTLD_LAZY);
+  if (!dl && error)
+    error->message = dlerror();
+
+  return dl;
+}
+
+// static
+void UnloadNativeLibrary(NativeLibrary library) {
+  int ret = dlclose(library);
+  if (ret < 0) {
+    DLOG(ERROR) << "dlclose failed: " << dlerror();
+    NOTREACHED();
+  }
+}
+
+// static
+void* GetFunctionPointerFromNativeLibrary(NativeLibrary library,
+                                          const char* name) {
+  return dlsym(library, name);
+}
+
+// static
+string16 GetNativeLibraryName(const string16& name) {
+  return ASCIIToUTF16("lib") + name + ASCIIToUTF16(".so");
+}
+
+}  // namespace base
diff --git a/base/native_library_win.cc b/base/native_library_win.cc
new file mode 100644
index 0000000..1ca3e92
--- /dev/null
+++ b/base/native_library_win.cc
@@ -0,0 +1,88 @@
+// Copyright (c) 2011 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/native_library.h"
+
+#include <windows.h>
+
+#include "base/files/file_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace base {
+
+typedef HMODULE (WINAPI* LoadLibraryFunction)(const wchar_t* file_name);
+
+namespace {
+
+NativeLibrary LoadNativeLibraryHelper(const FilePath& library_path,
+                                      LoadLibraryFunction load_library_api,
+                                      NativeLibraryLoadError* error) {
+  // LoadLibrary() opens the file off disk.
+  ThreadRestrictions::AssertIOAllowed();
+
+  // Switch the current directory to the library directory as the library
+  // may have dependencies on DLLs in this directory.
+  bool restore_directory = false;
+  FilePath current_directory;
+  if (GetCurrentDirectory(&current_directory)) {
+    FilePath plugin_path = library_path.DirName();
+    if (!plugin_path.empty()) {
+      SetCurrentDirectory(plugin_path);
+      restore_directory = true;
+    }
+  }
+
+  HMODULE module = (*load_library_api)(library_path.value().c_str());
+  if (!module && error) {
+    // GetLastError() needs to be called immediately after |load_library_api|.
+    error->code = GetLastError();
+  }
+
+  if (restore_directory)
+    SetCurrentDirectory(current_directory);
+
+  return module;
+}
+
+}  // namespace
+
+std::string NativeLibraryLoadError::ToString() const {
+  return StringPrintf("%u", code);
+}
+
+// static
+NativeLibrary LoadNativeLibrary(const FilePath& library_path,
+                                NativeLibraryLoadError* error) {
+  return LoadNativeLibraryHelper(library_path, LoadLibraryW, error);
+}
+
+NativeLibrary LoadNativeLibraryDynamically(const FilePath& library_path) {
+  typedef HMODULE (WINAPI* LoadLibraryFunction)(const wchar_t* file_name);
+
+  LoadLibraryFunction load_library;
+  load_library = reinterpret_cast<LoadLibraryFunction>(
+      GetProcAddress(GetModuleHandle(L"kernel32.dll"), "LoadLibraryW"));
+
+  return LoadNativeLibraryHelper(library_path, load_library, NULL);
+}
+
+// static
+void UnloadNativeLibrary(NativeLibrary library) {
+  FreeLibrary(library);
+}
+
+// static
+void* GetFunctionPointerFromNativeLibrary(NativeLibrary library,
+                                          const char* name) {
+  return GetProcAddress(library, name);
+}
+
+// static
+string16 GetNativeLibraryName(const string16& name) {
+  return name + ASCIIToUTF16(".dll");
+}
+
+}  // namespace base
diff --git a/base/nix/mime_util_xdg.cc b/base/nix/mime_util_xdg.cc
new file mode 100644
index 0000000..f78b6ab
--- /dev/null
+++ b/base/nix/mime_util_xdg.cc
@@ -0,0 +1,39 @@
+// Copyright (c) 2012 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/nix/mime_util_xdg.h"
+
+#include "base/files/file_path.h"
+#include "base/lazy_instance.h"
+#include "base/synchronization/lock.h"
+#include "base/third_party/xdg_mime/xdgmime.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace base {
+namespace nix {
+
+namespace {
+
+// None of the XDG stuff is thread-safe, so serialize all access under
+// this lock.
+LazyInstance<Lock>::Leaky g_mime_util_xdg_lock = LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+std::string GetFileMimeType(const FilePath& filepath) {
+  if (filepath.empty())
+    return std::string();
+  ThreadRestrictions::AssertIOAllowed();
+  AutoLock scoped_lock(g_mime_util_xdg_lock.Get());
+  return xdg_mime_get_mime_type_from_file_name(filepath.value().c_str());
+}
+
+std::string GetDataMimeType(const std::string& data) {
+  ThreadRestrictions::AssertIOAllowed();
+  AutoLock scoped_lock(g_mime_util_xdg_lock.Get());
+  return xdg_mime_get_mime_type_for_data(data.data(), data.length(), NULL);
+}
+
+}  // namespace nix
+}  // namespace base
diff --git a/base/nix/mime_util_xdg.h b/base/nix/mime_util_xdg.h
new file mode 100644
index 0000000..e40415e
--- /dev/null
+++ b/base/nix/mime_util_xdg.h
@@ -0,0 +1,31 @@
+// Copyright (c) 2011 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_NIX_MIME_UTIL_XDG_H_
+#define BASE_NIX_MIME_UTIL_XDG_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "build/build_config.h"
+
+namespace base {
+
+class FilePath;
+
+namespace nix {
+
+// Gets the mime type for a file based on its filename. The file path does not
+// have to exist. Please note because it doesn't touch the disk, this does not
+// work for directories.
+// If the mime type is unknown, this will return application/octet-stream.
+BASE_EXPORT std::string GetFileMimeType(const FilePath& filepath);
+
+// Get the mime type for a byte vector.
+BASE_EXPORT std::string GetDataMimeType(const std::string& data);
+
+}  // namespace nix
+}  // namespace base
+
+#endif  // BASE_NIX_MIME_UTIL_XDG_H_
diff --git a/base/nix/xdg_util.cc b/base/nix/xdg_util.cc
new file mode 100644
index 0000000..ef04561
--- /dev/null
+++ b/base/nix/xdg_util.cc
@@ -0,0 +1,130 @@
+// Copyright (c) 2012 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/nix/xdg_util.h"
+
+#include <string>
+
+#include "base/base_paths.h"
+#include "base/environment.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/path_service.h"
+#include "base/third_party/xdg_user_dirs/xdg_user_dir_lookup.h"
+
+namespace {
+
+// The KDE session version environment variable used in KDE 4.
+const char kKDE4SessionEnvVar[] = "KDE_SESSION_VERSION";
+
+}  // namespace
+
+namespace base {
+namespace nix {
+
+const char kDotConfigDir[] = ".config";
+const char kXdgConfigHomeEnvVar[] = "XDG_CONFIG_HOME";
+
+FilePath GetXDGDirectory(Environment* env, const char* env_name,
+                         const char* fallback_dir) {
+  FilePath path;
+  std::string env_value;
+  if (env->GetVar(env_name, &env_value) && !env_value.empty()) {
+    path = FilePath(env_value);
+  } else {
+    PathService::Get(DIR_HOME, &path);
+    path = path.Append(fallback_dir);
+  }
+  return path.StripTrailingSeparators();
+}
+
+FilePath GetXDGUserDirectory(const char* dir_name, const char* fallback_dir) {
+  FilePath path;
+  char* xdg_dir = xdg_user_dir_lookup(dir_name);
+  if (xdg_dir) {
+    path = FilePath(xdg_dir);
+    free(xdg_dir);
+  } else {
+    PathService::Get(DIR_HOME, &path);
+    path = path.Append(fallback_dir);
+  }
+  return path.StripTrailingSeparators();
+}
+
+DesktopEnvironment GetDesktopEnvironment(Environment* env) {
+  // XDG_CURRENT_DESKTOP is the newest standard circa 2012.
+  std::string xdg_current_desktop;
+  if (env->GetVar("XDG_CURRENT_DESKTOP", &xdg_current_desktop)) {
+    // Not all desktop environments set this env var as of this writing.
+    if (xdg_current_desktop == "Unity") {
+      // gnome-fallback sessions set XDG_CURRENT_DESKTOP to Unity
+      // DESKTOP_SESSION can be gnome-fallback or gnome-fallback-compiz
+      std::string desktop_session;
+      if (env->GetVar("DESKTOP_SESSION", &desktop_session) &&
+          desktop_session.find("gnome-fallback") != std::string::npos) {
+        return DESKTOP_ENVIRONMENT_GNOME;
+      }
+      return DESKTOP_ENVIRONMENT_UNITY;
+    } else if (xdg_current_desktop == "GNOME") {
+      return DESKTOP_ENVIRONMENT_GNOME;
+    } else if (xdg_current_desktop == "KDE") {
+      return DESKTOP_ENVIRONMENT_KDE4;
+    }
+  }
+
+  // DESKTOP_SESSION was what everyone used in 2010.
+  std::string desktop_session;
+  if (env->GetVar("DESKTOP_SESSION", &desktop_session)) {
+    if (desktop_session == "gnome" || desktop_session =="mate") {
+      return DESKTOP_ENVIRONMENT_GNOME;
+    } else if (desktop_session == "kde4" || desktop_session == "kde-plasma") {
+      return DESKTOP_ENVIRONMENT_KDE4;
+    } else if (desktop_session == "kde") {
+      // This may mean KDE4 on newer systems, so we have to check.
+      if (env->HasVar(kKDE4SessionEnvVar))
+        return DESKTOP_ENVIRONMENT_KDE4;
+      return DESKTOP_ENVIRONMENT_KDE3;
+    } else if (desktop_session.find("xfce") != std::string::npos ||
+               desktop_session == "xubuntu") {
+      return DESKTOP_ENVIRONMENT_XFCE;
+    }
+  }
+
+  // Fall back on some older environment variables.
+  // Useful particularly in the DESKTOP_SESSION=default case.
+  if (env->HasVar("GNOME_DESKTOP_SESSION_ID")) {
+    return DESKTOP_ENVIRONMENT_GNOME;
+  } else if (env->HasVar("KDE_FULL_SESSION")) {
+    if (env->HasVar(kKDE4SessionEnvVar))
+      return DESKTOP_ENVIRONMENT_KDE4;
+    return DESKTOP_ENVIRONMENT_KDE3;
+  }
+
+  return DESKTOP_ENVIRONMENT_OTHER;
+}
+
+const char* GetDesktopEnvironmentName(DesktopEnvironment env) {
+  switch (env) {
+    case DESKTOP_ENVIRONMENT_OTHER:
+      return NULL;
+    case DESKTOP_ENVIRONMENT_GNOME:
+      return "GNOME";
+    case DESKTOP_ENVIRONMENT_KDE3:
+      return "KDE3";
+    case DESKTOP_ENVIRONMENT_KDE4:
+      return "KDE4";
+    case DESKTOP_ENVIRONMENT_UNITY:
+      return "UNITY";
+    case DESKTOP_ENVIRONMENT_XFCE:
+      return "XFCE";
+  }
+  return NULL;
+}
+
+const char* GetDesktopEnvironmentName(Environment* env) {
+  return GetDesktopEnvironmentName(GetDesktopEnvironment(env));
+}
+
+}  // namespace nix
+}  // namespace base
diff --git a/base/nix/xdg_util.h b/base/nix/xdg_util.h
new file mode 100644
index 0000000..a8b7784
--- /dev/null
+++ b/base/nix/xdg_util.h
@@ -0,0 +1,74 @@
+// Copyright (c) 2012 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_NIX_XDG_UTIL_H_
+#define BASE_NIX_XDG_UTIL_H_
+
+// XDG refers to http://en.wikipedia.org/wiki/Freedesktop.org .
+// This file contains utilities found across free desktop environments.
+//
+// TODO(brettw) this file should be in app/x11, but is currently used by
+// net. We should have a net API to allow the embedder to specify the behavior
+// that it uses XDG for, and then move this file.
+
+#include "base/base_export.h"
+
+#ifdef nix
+#error asdf
+#endif
+
+namespace base {
+
+class Environment;
+class FilePath;
+
+namespace nix {
+
+// The default XDG config directory name.
+BASE_EXPORT extern const char kDotConfigDir[];
+
+// The XDG config directory environment variable.
+BASE_EXPORT extern const char kXdgConfigHomeEnvVar[];
+
+// Utility function for getting XDG directories.
+// |env_name| is the name of an environment variable that we want to use to get
+// a directory path. |fallback_dir| is the directory relative to $HOME that we
+// use if |env_name| cannot be found or is empty. |fallback_dir| may be NULL.
+// Examples of |env_name| are XDG_CONFIG_HOME and XDG_DATA_HOME.
+BASE_EXPORT FilePath GetXDGDirectory(Environment* env, const char* env_name,
+                                     const char* fallback_dir);
+
+// Wrapper around xdg_user_dir_lookup() from src/base/third_party/xdg-user-dirs
+// This looks up "well known" user directories like the desktop and music
+// folder. Examples of |dir_name| are DESKTOP and MUSIC.
+BASE_EXPORT FilePath GetXDGUserDirectory(const char* dir_name,
+                                         const char* fallback_dir);
+
+enum DesktopEnvironment {
+  DESKTOP_ENVIRONMENT_OTHER,
+  DESKTOP_ENVIRONMENT_GNOME,
+  // KDE3 and KDE4 are sufficiently different that we count
+  // them as two different desktop environments here.
+  DESKTOP_ENVIRONMENT_KDE3,
+  DESKTOP_ENVIRONMENT_KDE4,
+  DESKTOP_ENVIRONMENT_UNITY,
+  DESKTOP_ENVIRONMENT_XFCE,
+};
+
+// Return an entry from the DesktopEnvironment enum with a best guess
+// of which desktop environment we're using.  We use this to know when
+// to attempt to use preferences from the desktop environment --
+// proxy settings, password manager, etc.
+BASE_EXPORT DesktopEnvironment GetDesktopEnvironment(Environment* env);
+
+// Return a string representation of the given desktop environment.
+// May return NULL in the case of DESKTOP_ENVIRONMENT_OTHER.
+BASE_EXPORT const char* GetDesktopEnvironmentName(DesktopEnvironment env);
+// Convenience wrapper that calls GetDesktopEnvironment() first.
+BASE_EXPORT const char* GetDesktopEnvironmentName(Environment* env);
+
+}  // namespace nix
+}  // namespace base
+
+#endif  // BASE_NIX_XDG_UTIL_H_
diff --git a/base/nix/xdg_util_unittest.cc b/base/nix/xdg_util_unittest.cc
new file mode 100644
index 0000000..136eb5d
--- /dev/null
+++ b/base/nix/xdg_util_unittest.cc
@@ -0,0 +1,129 @@
+// Copyright (c) 2010 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/nix/xdg_util.h"
+
+#include "base/environment.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::_;
+using ::testing::Return;
+using ::testing::SetArgumentPointee;
+using ::testing::StrEq;
+
+namespace base {
+namespace nix {
+
+namespace {
+
+class MockEnvironment : public Environment {
+ public:
+  MOCK_METHOD2(GetVar, bool(const char*, std::string* result));
+  MOCK_METHOD2(SetVar, bool(const char*, const std::string& new_value));
+  MOCK_METHOD1(UnSetVar, bool(const char*));
+};
+
+// Needs to be const char* to make gmock happy.
+const char* const kDesktopGnome = "gnome";
+const char* const kDesktopGnomeFallback = "gnome-fallback";
+const char* const kDesktopMATE = "mate";
+const char* const kDesktopKDE4 = "kde4";
+const char* const kDesktopKDE = "kde";
+const char* const kDesktopXFCE = "xfce";
+const char* const kXdgDesktopGNOME = "GNOME";
+const char* const kXdgDesktopKDE = "KDE";
+const char* const kXdgDesktopUnity = "Unity";
+
+const char kDesktopSession[] = "DESKTOP_SESSION";
+const char kXdgDesktop[] = "XDG_CURRENT_DESKTOP";
+
+}  // namespace
+
+TEST(XDGUtilTest, GetDesktopEnvironmentGnome) {
+  MockEnvironment getter;
+  EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false));
+  EXPECT_CALL(getter, GetVar(StrEq(kDesktopSession), _))
+      .WillOnce(DoAll(SetArgumentPointee<1>(kDesktopGnome), Return(true)));
+
+  EXPECT_EQ(DESKTOP_ENVIRONMENT_GNOME, GetDesktopEnvironment(&getter));
+}
+
+TEST(XDGUtilTest, GetDesktopEnvironmentMATE) {
+  MockEnvironment getter;
+  EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false));
+  EXPECT_CALL(getter, GetVar(StrEq(kDesktopSession), _))
+      .WillOnce(DoAll(SetArgumentPointee<1>(kDesktopMATE), Return(true)));
+
+  EXPECT_EQ(DESKTOP_ENVIRONMENT_GNOME, GetDesktopEnvironment(&getter));
+}
+
+TEST(XDGUtilTest, GetDesktopEnvironmentKDE4) {
+  MockEnvironment getter;
+  EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false));
+  EXPECT_CALL(getter, GetVar(StrEq(kDesktopSession), _))
+      .WillOnce(DoAll(SetArgumentPointee<1>(kDesktopKDE4), Return(true)));
+
+  EXPECT_EQ(DESKTOP_ENVIRONMENT_KDE4, GetDesktopEnvironment(&getter));
+}
+
+TEST(XDGUtilTest, GetDesktopEnvironmentKDE3) {
+  MockEnvironment getter;
+  EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false));
+  EXPECT_CALL(getter, GetVar(StrEq(kDesktopSession), _))
+      .WillOnce(DoAll(SetArgumentPointee<1>(kDesktopKDE), Return(true)));
+
+  EXPECT_EQ(DESKTOP_ENVIRONMENT_KDE3, GetDesktopEnvironment(&getter));
+}
+
+TEST(XDGUtilTest, GetDesktopEnvironmentXFCE) {
+  MockEnvironment getter;
+  EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false));
+  EXPECT_CALL(getter, GetVar(StrEq(kDesktopSession), _))
+      .WillOnce(DoAll(SetArgumentPointee<1>(kDesktopXFCE), Return(true)));
+
+  EXPECT_EQ(DESKTOP_ENVIRONMENT_XFCE, GetDesktopEnvironment(&getter));
+}
+
+TEST(XDGUtilTest, GetXdgDesktopGnome) {
+  MockEnvironment getter;
+  EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false));
+  EXPECT_CALL(getter, GetVar(StrEq(kXdgDesktop), _))
+      .WillOnce(DoAll(SetArgumentPointee<1>(kXdgDesktopGNOME), Return(true)));
+
+  EXPECT_EQ(DESKTOP_ENVIRONMENT_GNOME, GetDesktopEnvironment(&getter));
+}
+
+TEST(XDGUtilTest, GetXdgDesktopGnomeFallback) {
+  MockEnvironment getter;
+  EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false));
+  EXPECT_CALL(getter, GetVar(StrEq(kXdgDesktop), _))
+      .WillOnce(DoAll(SetArgumentPointee<1>(kXdgDesktopUnity), Return(true)));
+  EXPECT_CALL(getter, GetVar(StrEq(kDesktopSession), _))
+      .WillOnce(DoAll(SetArgumentPointee<1>(kDesktopGnomeFallback),
+                      Return(true)));
+
+  EXPECT_EQ(DESKTOP_ENVIRONMENT_GNOME, GetDesktopEnvironment(&getter));
+}
+
+TEST(XDGUtilTest, GetXdgDesktopKDE4) {
+  MockEnvironment getter;
+  EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false));
+  EXPECT_CALL(getter, GetVar(StrEq(kXdgDesktop), _))
+      .WillOnce(DoAll(SetArgumentPointee<1>(kXdgDesktopKDE), Return(true)));
+
+  EXPECT_EQ(DESKTOP_ENVIRONMENT_KDE4, GetDesktopEnvironment(&getter));
+}
+
+TEST(XDGUtilTest, GetXdgDesktopUnity) {
+  MockEnvironment getter;
+  EXPECT_CALL(getter, GetVar(_, _)).WillRepeatedly(Return(false));
+  EXPECT_CALL(getter, GetVar(StrEq(kXdgDesktop), _))
+      .WillOnce(DoAll(SetArgumentPointee<1>(kXdgDesktopUnity), Return(true)));
+
+  EXPECT_EQ(DESKTOP_ENVIRONMENT_UNITY, GetDesktopEnvironment(&getter));
+}
+
+}  // namespace nix
+}  // namespace base
diff --git a/base/numerics/OWNERS b/base/numerics/OWNERS
new file mode 100644
index 0000000..41f35fc
--- /dev/null
+++ b/base/numerics/OWNERS
@@ -0,0 +1,3 @@
+jschuh@chromium.org
+tsepez@chromium.org
+
diff --git a/base/numerics/safe_conversions.h b/base/numerics/safe_conversions.h
new file mode 100644
index 0000000..5dd5191
--- /dev/null
+++ b/base/numerics/safe_conversions.h
@@ -0,0 +1,125 @@
+// 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.
+
+#ifndef BASE_NUMERICS_SAFE_CONVERSIONS_H_
+#define BASE_NUMERICS_SAFE_CONVERSIONS_H_
+
+#include <limits>
+
+#include "base/logging.h"
+#include "base/numerics/safe_conversions_impl.h"
+
+namespace base {
+
+// Convenience function that returns true if the supplied value is in range
+// for the destination type.
+template <typename Dst, typename Src>
+inline bool IsValueInRangeForNumericType(Src value) {
+  return internal::DstRangeRelationToSrcRange<Dst>(value) ==
+         internal::RANGE_VALID;
+}
+
+// checked_cast<> is analogous to static_cast<> for numeric types,
+// except that it CHECKs that the specified numeric conversion will not
+// overflow or underflow. NaN source will always trigger a CHECK.
+template <typename Dst, typename Src>
+inline Dst checked_cast(Src value) {
+  CHECK(IsValueInRangeForNumericType<Dst>(value));
+  return static_cast<Dst>(value);
+}
+
+// saturated_cast<> is analogous to static_cast<> for numeric types, except
+// that the specified numeric conversion will saturate rather than overflow or
+// underflow. NaN assignment to an integral will trigger a CHECK condition.
+template <typename Dst, typename Src>
+inline Dst saturated_cast(Src value) {
+  // Optimization for floating point values, which already saturate.
+  if (std::numeric_limits<Dst>::is_iec559)
+    return static_cast<Dst>(value);
+
+  switch (internal::DstRangeRelationToSrcRange<Dst>(value)) {
+    case internal::RANGE_VALID:
+      return static_cast<Dst>(value);
+
+    case internal::RANGE_UNDERFLOW:
+      return std::numeric_limits<Dst>::min();
+
+    case internal::RANGE_OVERFLOW:
+      return std::numeric_limits<Dst>::max();
+
+    // Should fail only on attempting to assign NaN to a saturated integer.
+    case internal::RANGE_INVALID:
+      CHECK(false);
+      return std::numeric_limits<Dst>::max();
+  }
+
+  NOTREACHED();
+  return static_cast<Dst>(value);
+}
+
+// strict_cast<> is analogous to static_cast<> for numeric types, except that
+// it will cause a compile failure if the destination type is not large enough
+// to contain any value in the source type. It performs no runtime checking.
+template <typename Dst, typename Src>
+inline Dst strict_cast(Src value) {
+  static_assert(std::numeric_limits<Src>::is_specialized,
+                "Argument must be numeric.");
+  static_assert(std::numeric_limits<Dst>::is_specialized,
+                "Result must be numeric.");
+  static_assert((internal::StaticDstRangeRelationToSrcRange<Dst, Src>::value ==
+                 internal::NUMERIC_RANGE_CONTAINED),
+                "The numeric conversion is out of range for this type. You "
+                "should probably use one of the following conversion "
+                "mechanisms on the value you want to pass:\n"
+                "- base::checked_cast\n"
+                "- base::saturated_cast\n"
+                "- base::CheckedNumeric");
+
+  return static_cast<Dst>(value);
+}
+
+// StrictNumeric implements compile time range checking between numeric types by
+// wrapping assignment operations in a strict_cast. This class is intended to be
+// used for function arguments and return types, to ensure the destination type
+// can always contain the source type. This is essentially the same as enforcing
+// -Wconversion in gcc and C4302 warnings on MSVC, but it can be applied
+// incrementally at API boundaries, making it easier to convert code so that it
+// compiles cleanly with truncation warnings enabled.
+// This template should introduce no runtime overhead, but it also provides no
+// runtime checking of any of the associated mathematical operations. Use
+// CheckedNumeric for runtime range checks of tha actual value being assigned.
+template <typename T>
+class StrictNumeric {
+ public:
+  typedef T type;
+
+  StrictNumeric() : value_(0) {}
+
+  // Copy constructor.
+  template <typename Src>
+  StrictNumeric(const StrictNumeric<Src>& rhs)
+      : value_(strict_cast<T>(rhs.value_)) {}
+
+  // This is not an explicit constructor because we implicitly upgrade regular
+  // numerics to StrictNumerics to make them easier to use.
+  template <typename Src>
+  StrictNumeric(Src value)
+      : value_(strict_cast<T>(value)) {}
+
+  // The numeric cast operator basically handles all the magic.
+  template <typename Dst>
+  operator Dst() const {
+    return strict_cast<Dst>(value_);
+  }
+
+ private:
+  T value_;
+};
+
+// Explicitly make a shorter size_t typedef for convenience.
+typedef StrictNumeric<size_t> SizeT;
+
+}  // namespace base
+
+#endif  // BASE_NUMERICS_SAFE_CONVERSIONS_H_
diff --git a/base/numerics/safe_conversions_impl.h b/base/numerics/safe_conversions_impl.h
new file mode 100644
index 0000000..4157067
--- /dev/null
+++ b/base/numerics/safe_conversions_impl.h
@@ -0,0 +1,215 @@
+// 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.
+
+#ifndef BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
+#define BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
+
+#include <limits>
+
+#include "base/template_util.h"
+
+namespace base {
+namespace internal {
+
+// The std library doesn't provide a binary max_exponent for integers, however
+// we can compute one by adding one to the number of non-sign bits. This allows
+// for accurate range comparisons between floating point and integer types.
+template <typename NumericType>
+struct MaxExponent {
+  static const int value = std::numeric_limits<NumericType>::is_iec559
+                               ? std::numeric_limits<NumericType>::max_exponent
+                               : (sizeof(NumericType) * 8 + 1 -
+                                  std::numeric_limits<NumericType>::is_signed);
+};
+
+enum IntegerRepresentation {
+  INTEGER_REPRESENTATION_UNSIGNED,
+  INTEGER_REPRESENTATION_SIGNED
+};
+
+// A range for a given nunmeric Src type is contained for a given numeric Dst
+// type if both numeric_limits<Src>::max() <= numeric_limits<Dst>::max() and
+// numeric_limits<Src>::min() >= numeric_limits<Dst>::min() are true.
+// We implement this as template specializations rather than simple static
+// comparisons to ensure type correctness in our comparisons.
+enum NumericRangeRepresentation {
+  NUMERIC_RANGE_NOT_CONTAINED,
+  NUMERIC_RANGE_CONTAINED
+};
+
+// Helper templates to statically determine if our destination type can contain
+// maximum and minimum values represented by the source type.
+
+template <
+    typename Dst,
+    typename Src,
+    IntegerRepresentation DstSign = std::numeric_limits<Dst>::is_signed
+                                            ? INTEGER_REPRESENTATION_SIGNED
+                                            : INTEGER_REPRESENTATION_UNSIGNED,
+    IntegerRepresentation SrcSign =
+        std::numeric_limits<Src>::is_signed
+            ? INTEGER_REPRESENTATION_SIGNED
+            : INTEGER_REPRESENTATION_UNSIGNED >
+struct StaticDstRangeRelationToSrcRange;
+
+// Same sign: Dst is guaranteed to contain Src only if its range is equal or
+// larger.
+template <typename Dst, typename Src, IntegerRepresentation Sign>
+struct StaticDstRangeRelationToSrcRange<Dst, Src, Sign, Sign> {
+  static const NumericRangeRepresentation value =
+      MaxExponent<Dst>::value >= MaxExponent<Src>::value
+          ? NUMERIC_RANGE_CONTAINED
+          : NUMERIC_RANGE_NOT_CONTAINED;
+};
+
+// Unsigned to signed: Dst is guaranteed to contain source only if its range is
+// larger.
+template <typename Dst, typename Src>
+struct StaticDstRangeRelationToSrcRange<Dst,
+                                        Src,
+                                        INTEGER_REPRESENTATION_SIGNED,
+                                        INTEGER_REPRESENTATION_UNSIGNED> {
+  static const NumericRangeRepresentation value =
+      MaxExponent<Dst>::value > MaxExponent<Src>::value
+          ? NUMERIC_RANGE_CONTAINED
+          : NUMERIC_RANGE_NOT_CONTAINED;
+};
+
+// Signed to unsigned: Dst cannot be statically determined to contain Src.
+template <typename Dst, typename Src>
+struct StaticDstRangeRelationToSrcRange<Dst,
+                                        Src,
+                                        INTEGER_REPRESENTATION_UNSIGNED,
+                                        INTEGER_REPRESENTATION_SIGNED> {
+  static const NumericRangeRepresentation value = NUMERIC_RANGE_NOT_CONTAINED;
+};
+
+enum RangeConstraint {
+  RANGE_VALID = 0x0,  // Value can be represented by the destination type.
+  RANGE_UNDERFLOW = 0x1,  // Value would overflow.
+  RANGE_OVERFLOW = 0x2,  // Value would underflow.
+  RANGE_INVALID = RANGE_UNDERFLOW | RANGE_OVERFLOW  // Invalid (i.e. NaN).
+};
+
+// Helper function for coercing an int back to a RangeContraint.
+inline RangeConstraint GetRangeConstraint(int integer_range_constraint) {
+  DCHECK(integer_range_constraint >= RANGE_VALID &&
+         integer_range_constraint <= RANGE_INVALID);
+  return static_cast<RangeConstraint>(integer_range_constraint);
+}
+
+// This function creates a RangeConstraint from an upper and lower bound
+// check by taking advantage of the fact that only NaN can be out of range in
+// both directions at once.
+inline RangeConstraint GetRangeConstraint(bool is_in_upper_bound,
+                                   bool is_in_lower_bound) {
+  return GetRangeConstraint((is_in_upper_bound ? 0 : RANGE_OVERFLOW) |
+                            (is_in_lower_bound ? 0 : RANGE_UNDERFLOW));
+}
+
+template <
+    typename Dst,
+    typename Src,
+    IntegerRepresentation DstSign = std::numeric_limits<Dst>::is_signed
+                                            ? INTEGER_REPRESENTATION_SIGNED
+                                            : INTEGER_REPRESENTATION_UNSIGNED,
+    IntegerRepresentation SrcSign = std::numeric_limits<Src>::is_signed
+                                            ? INTEGER_REPRESENTATION_SIGNED
+                                            : INTEGER_REPRESENTATION_UNSIGNED,
+    NumericRangeRepresentation DstRange =
+        StaticDstRangeRelationToSrcRange<Dst, Src>::value >
+struct DstRangeRelationToSrcRangeImpl;
+
+// The following templates are for ranges that must be verified at runtime. We
+// split it into checks based on signedness to avoid confusing casts and
+// compiler warnings on signed an unsigned comparisons.
+
+// Dst range is statically determined to contain Src: Nothing to check.
+template <typename Dst,
+          typename Src,
+          IntegerRepresentation DstSign,
+          IntegerRepresentation SrcSign>
+struct DstRangeRelationToSrcRangeImpl<Dst,
+                                      Src,
+                                      DstSign,
+                                      SrcSign,
+                                      NUMERIC_RANGE_CONTAINED> {
+  static RangeConstraint Check(Src value) { return RANGE_VALID; }
+};
+
+// Signed to signed narrowing: Both the upper and lower boundaries may be
+// exceeded.
+template <typename Dst, typename Src>
+struct DstRangeRelationToSrcRangeImpl<Dst,
+                                      Src,
+                                      INTEGER_REPRESENTATION_SIGNED,
+                                      INTEGER_REPRESENTATION_SIGNED,
+                                      NUMERIC_RANGE_NOT_CONTAINED> {
+  static RangeConstraint Check(Src value) {
+    return std::numeric_limits<Dst>::is_iec559
+               ? GetRangeConstraint((value < std::numeric_limits<Dst>::max()),
+                                    (value > -std::numeric_limits<Dst>::max()))
+               : GetRangeConstraint((value < std::numeric_limits<Dst>::max()),
+                                    (value > std::numeric_limits<Dst>::min()));
+  }
+};
+
+// Unsigned to unsigned narrowing: Only the upper boundary can be exceeded.
+template <typename Dst, typename Src>
+struct DstRangeRelationToSrcRangeImpl<Dst,
+                                      Src,
+                                      INTEGER_REPRESENTATION_UNSIGNED,
+                                      INTEGER_REPRESENTATION_UNSIGNED,
+                                      NUMERIC_RANGE_NOT_CONTAINED> {
+  static RangeConstraint Check(Src value) {
+    return GetRangeConstraint(value < std::numeric_limits<Dst>::max(), true);
+  }
+};
+
+// Unsigned to signed: The upper boundary may be exceeded.
+template <typename Dst, typename Src>
+struct DstRangeRelationToSrcRangeImpl<Dst,
+                                      Src,
+                                      INTEGER_REPRESENTATION_SIGNED,
+                                      INTEGER_REPRESENTATION_UNSIGNED,
+                                      NUMERIC_RANGE_NOT_CONTAINED> {
+  static RangeConstraint Check(Src value) {
+    return sizeof(Dst) > sizeof(Src)
+               ? RANGE_VALID
+               : GetRangeConstraint(
+                     value < static_cast<Src>(std::numeric_limits<Dst>::max()),
+                     true);
+  }
+};
+
+// Signed to unsigned: The upper boundary may be exceeded for a narrower Dst,
+// and any negative value exceeds the lower boundary.
+template <typename Dst, typename Src>
+struct DstRangeRelationToSrcRangeImpl<Dst,
+                                      Src,
+                                      INTEGER_REPRESENTATION_UNSIGNED,
+                                      INTEGER_REPRESENTATION_SIGNED,
+                                      NUMERIC_RANGE_NOT_CONTAINED> {
+  static RangeConstraint Check(Src value) {
+    return (MaxExponent<Dst>::value >= MaxExponent<Src>::value)
+               ? GetRangeConstraint(true, value >= static_cast<Src>(0))
+               : GetRangeConstraint(
+                     value < static_cast<Src>(std::numeric_limits<Dst>::max()),
+                     value >= static_cast<Src>(0));
+  }
+};
+
+template <typename Dst, typename Src>
+inline RangeConstraint DstRangeRelationToSrcRange(Src value) {
+  static_assert(std::numeric_limits<Src>::is_specialized,
+                "Argument must be numeric.");
+  static_assert(std::numeric_limits<Dst>::is_specialized,
+                "Result must be numeric.");
+  return DstRangeRelationToSrcRangeImpl<Dst, Src>::Check(value);
+}
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
diff --git a/base/numerics/safe_math.h b/base/numerics/safe_math.h
new file mode 100644
index 0000000..1fab032
--- /dev/null
+++ b/base/numerics/safe_math.h
@@ -0,0 +1,279 @@
+// 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.
+
+#ifndef BASE_NUMERICS_SAFE_MATH_H_
+#define BASE_NUMERICS_SAFE_MATH_H_
+
+#include "base/numerics/safe_math_impl.h"
+
+namespace base {
+
+namespace internal {
+
+// CheckedNumeric implements all the logic and operators for detecting integer
+// boundary conditions such as overflow, underflow, and invalid conversions.
+// The CheckedNumeric type implicitly converts from floating point and integer
+// data types, and contains overloads for basic arithmetic operations (i.e.: +,
+// -, *, /, %).
+//
+// The following methods convert from CheckedNumeric to standard numeric values:
+// IsValid() - Returns true if the underlying numeric value is valid (i.e. has
+//             has not wrapped and is not the result of an invalid conversion).
+// ValueOrDie() - Returns the underlying value. If the state is not valid this
+//                call will crash on a CHECK.
+// ValueOrDefault() - Returns the current value, or the supplied default if the
+//                    state is not valid.
+// ValueFloating() - Returns the underlying floating point value (valid only
+//                   only for floating point CheckedNumeric types).
+//
+// Bitwise operations are explicitly not supported, because correct
+// handling of some cases (e.g. sign manipulation) is ambiguous. Comparison
+// operations are explicitly not supported because they could result in a crash
+// on a CHECK condition. You should use patterns like the following for these
+// operations:
+// Bitwise operation:
+//     CheckedNumeric<int> checked_int = untrusted_input_value;
+//     int x = checked_int.ValueOrDefault(0) | kFlagValues;
+// Comparison:
+//   CheckedNumeric<size_t> checked_size;
+//   CheckedNumeric<int> checked_size = untrusted_input_value;
+//   checked_size = checked_size + HEADER LENGTH;
+//   if (checked_size.IsValid() && checked_size.ValueOrDie() < buffer_size)
+//     Do stuff...
+template <typename T>
+class CheckedNumeric {
+ public:
+  typedef T type;
+
+  CheckedNumeric() {}
+
+  // Copy constructor.
+  template <typename Src>
+  CheckedNumeric(const CheckedNumeric<Src>& rhs)
+      : state_(rhs.ValueUnsafe(), rhs.validity()) {}
+
+  template <typename Src>
+  CheckedNumeric(Src value, RangeConstraint validity)
+      : state_(value, validity) {}
+
+  // This is not an explicit constructor because we implicitly upgrade regular
+  // numerics to CheckedNumerics to make them easier to use.
+  template <typename Src>
+  CheckedNumeric(Src value)
+      : state_(value) {
+    static_assert(std::numeric_limits<Src>::is_specialized,
+                  "Argument must be numeric.");
+  }
+
+  // This is not an explicit constructor because we want a seamless conversion
+  // from StrictNumeric types.
+  template <typename Src>
+  CheckedNumeric(StrictNumeric<Src> value)
+      : state_(static_cast<Src>(value)) {
+  }
+
+  // IsValid() is the public API to test if a CheckedNumeric is currently valid.
+  bool IsValid() const { return validity() == RANGE_VALID; }
+
+  // ValueOrDie() The primary accessor for the underlying value. If the current
+  // state is not valid it will CHECK and crash.
+  T ValueOrDie() const {
+    CHECK(IsValid());
+    return state_.value();
+  }
+
+  // ValueOrDefault(T default_value) A convenience method that returns the
+  // current value if the state is valid, and the supplied default_value for
+  // any other state.
+  T ValueOrDefault(T default_value) const {
+    return IsValid() ? state_.value() : default_value;
+  }
+
+  // ValueFloating() - Since floating point values include their validity state,
+  // we provide an easy method for extracting them directly, without a risk of
+  // crashing on a CHECK.
+  T ValueFloating() const {
+    static_assert(std::numeric_limits<T>::is_iec559, "Argument must be float.");
+    return CheckedNumeric<T>::cast(*this).ValueUnsafe();
+  }
+
+  // validity() - DO NOT USE THIS IN EXTERNAL CODE - It is public right now for
+  // tests and to avoid a big matrix of friend operator overloads. But the
+  // values it returns are likely to change in the future.
+  // Returns: current validity state (i.e. valid, overflow, underflow, nan).
+  // TODO(jschuh): crbug.com/332611 Figure out and implement semantics for
+  // saturation/wrapping so we can expose this state consistently and implement
+  // saturated arithmetic.
+  RangeConstraint validity() const { return state_.validity(); }
+
+  // ValueUnsafe() - DO NOT USE THIS IN EXTERNAL CODE - It is public right now
+  // for tests and to avoid a big matrix of friend operator overloads. But the
+  // values it returns are likely to change in the future.
+  // Returns: the raw numeric value, regardless of the current state.
+  // TODO(jschuh): crbug.com/332611 Figure out and implement semantics for
+  // saturation/wrapping so we can expose this state consistently and implement
+  // saturated arithmetic.
+  T ValueUnsafe() const { return state_.value(); }
+
+  // Prototypes for the supported arithmetic operator overloads.
+  template <typename Src> CheckedNumeric& operator+=(Src rhs);
+  template <typename Src> CheckedNumeric& operator-=(Src rhs);
+  template <typename Src> CheckedNumeric& operator*=(Src rhs);
+  template <typename Src> CheckedNumeric& operator/=(Src rhs);
+  template <typename Src> CheckedNumeric& operator%=(Src rhs);
+
+  CheckedNumeric operator-() const {
+    RangeConstraint validity;
+    T value = CheckedNeg(state_.value(), &validity);
+    // Negation is always valid for floating point.
+    if (std::numeric_limits<T>::is_iec559)
+      return CheckedNumeric<T>(value);
+
+    validity = GetRangeConstraint(state_.validity() | validity);
+    return CheckedNumeric<T>(value, validity);
+  }
+
+  CheckedNumeric Abs() const {
+    RangeConstraint validity;
+    T value = CheckedAbs(state_.value(), &validity);
+    // Absolute value is always valid for floating point.
+    if (std::numeric_limits<T>::is_iec559)
+      return CheckedNumeric<T>(value);
+
+    validity = GetRangeConstraint(state_.validity() | validity);
+    return CheckedNumeric<T>(value, validity);
+  }
+
+  CheckedNumeric& operator++() {
+    *this += 1;
+    return *this;
+  }
+
+  CheckedNumeric operator++(int) {
+    CheckedNumeric value = *this;
+    *this += 1;
+    return value;
+  }
+
+  CheckedNumeric& operator--() {
+    *this -= 1;
+    return *this;
+  }
+
+  CheckedNumeric operator--(int) {
+    CheckedNumeric value = *this;
+    *this -= 1;
+    return value;
+  }
+
+  // These static methods behave like a convenience cast operator targeting
+  // the desired CheckedNumeric type. As an optimization, a reference is
+  // returned when Src is the same type as T.
+  template <typename Src>
+  static CheckedNumeric<T> cast(
+      Src u,
+      typename enable_if<std::numeric_limits<Src>::is_specialized, int>::type =
+          0) {
+    return u;
+  }
+
+  template <typename Src>
+  static CheckedNumeric<T> cast(
+      const CheckedNumeric<Src>& u,
+      typename enable_if<!is_same<Src, T>::value, int>::type = 0) {
+    return u;
+  }
+
+  static const CheckedNumeric<T>& cast(const CheckedNumeric<T>& u) { return u; }
+
+ private:
+  CheckedNumericState<T> state_;
+};
+
+// This is the boilerplate for the standard arithmetic operator overloads. A
+// macro isn't the prettiest solution, but it beats rewriting these five times.
+// Some details worth noting are:
+//  * We apply the standard arithmetic promotions.
+//  * We skip range checks for floating points.
+//  * We skip range checks for destination integers with sufficient range.
+// TODO(jschuh): extract these out into templates.
+#define BASE_NUMERIC_ARITHMETIC_OPERATORS(NAME, OP, COMPOUND_OP)              \
+  /* Binary arithmetic operator for CheckedNumerics of the same type. */      \
+  template <typename T>                                                       \
+  CheckedNumeric<typename ArithmeticPromotion<T>::type> operator OP(          \
+      const CheckedNumeric<T>& lhs, const CheckedNumeric<T>& rhs) {           \
+    typedef typename ArithmeticPromotion<T>::type Promotion;                  \
+    /* Floating point always takes the fast path */                           \
+    if (std::numeric_limits<T>::is_iec559)                                    \
+      return CheckedNumeric<T>(lhs.ValueUnsafe() OP rhs.ValueUnsafe());       \
+    if (IsIntegerArithmeticSafe<Promotion, T, T>::value)                      \
+      return CheckedNumeric<Promotion>(                                       \
+          lhs.ValueUnsafe() OP rhs.ValueUnsafe(),                             \
+          GetRangeConstraint(rhs.validity() | lhs.validity()));               \
+    RangeConstraint validity = RANGE_VALID;                                   \
+    T result = static_cast<T>(Checked##NAME(                                  \
+        static_cast<Promotion>(lhs.ValueUnsafe()),                            \
+        static_cast<Promotion>(rhs.ValueUnsafe()),                            \
+        &validity));                                                          \
+    return CheckedNumeric<Promotion>(                                         \
+        result,                                                               \
+        GetRangeConstraint(validity | lhs.validity() | rhs.validity()));      \
+  }                                                                           \
+  /* Assignment arithmetic operator implementation from CheckedNumeric. */    \
+  template <typename T>                                                       \
+  template <typename Src>                                                     \
+  CheckedNumeric<T>& CheckedNumeric<T>::operator COMPOUND_OP(Src rhs) {       \
+    *this = CheckedNumeric<T>::cast(*this) OP CheckedNumeric<Src>::cast(rhs); \
+    return *this;                                                             \
+  }                                                                           \
+  /* Binary arithmetic operator for CheckedNumeric of different type. */      \
+  template <typename T, typename Src>                                         \
+  CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> operator OP(     \
+      const CheckedNumeric<Src>& lhs, const CheckedNumeric<T>& rhs) {         \
+    typedef typename ArithmeticPromotion<T, Src>::type Promotion;             \
+    if (IsIntegerArithmeticSafe<Promotion, T, Src>::value)                    \
+      return CheckedNumeric<Promotion>(                                       \
+          lhs.ValueUnsafe() OP rhs.ValueUnsafe(),                             \
+          GetRangeConstraint(rhs.validity() | lhs.validity()));               \
+    return CheckedNumeric<Promotion>::cast(lhs)                               \
+        OP CheckedNumeric<Promotion>::cast(rhs);                              \
+  }                                                                           \
+  /* Binary arithmetic operator for left CheckedNumeric and right numeric. */ \
+  template <typename T, typename Src>                                         \
+  CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> operator OP(     \
+      const CheckedNumeric<T>& lhs, Src rhs) {                                \
+    typedef typename ArithmeticPromotion<T, Src>::type Promotion;             \
+    if (IsIntegerArithmeticSafe<Promotion, T, Src>::value)                    \
+      return CheckedNumeric<Promotion>(lhs.ValueUnsafe() OP rhs,              \
+                                       lhs.validity());                       \
+    return CheckedNumeric<Promotion>::cast(lhs)                               \
+        OP CheckedNumeric<Promotion>::cast(rhs);                              \
+  }                                                                           \
+  /* Binary arithmetic operator for right numeric and left CheckedNumeric. */ \
+  template <typename T, typename Src>                                         \
+  CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> operator OP(     \
+      Src lhs, const CheckedNumeric<T>& rhs) {                                \
+    typedef typename ArithmeticPromotion<T, Src>::type Promotion;             \
+    if (IsIntegerArithmeticSafe<Promotion, T, Src>::value)                    \
+      return CheckedNumeric<Promotion>(lhs OP rhs.ValueUnsafe(),              \
+                                       rhs.validity());                       \
+    return CheckedNumeric<Promotion>::cast(lhs)                               \
+        OP CheckedNumeric<Promotion>::cast(rhs);                              \
+  }
+
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Add, +, += )
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Sub, -, -= )
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Mul, *, *= )
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Div, /, /= )
+BASE_NUMERIC_ARITHMETIC_OPERATORS(Mod, %, %= )
+
+#undef BASE_NUMERIC_ARITHMETIC_OPERATORS
+
+}  // namespace internal
+
+using internal::CheckedNumeric;
+
+}  // namespace base
+
+#endif  // BASE_NUMERICS_SAFE_MATH_H_
diff --git a/base/numerics/safe_math_impl.h b/base/numerics/safe_math_impl.h
new file mode 100644
index 0000000..08f2e88
--- /dev/null
+++ b/base/numerics/safe_math_impl.h
@@ -0,0 +1,501 @@
+// 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.
+
+#ifndef BASE_NUMERICS_SAFE_MATH_IMPL_H_
+#define BASE_NUMERICS_SAFE_MATH_IMPL_H_
+
+#include <stdint.h>
+
+#include <cmath>
+#include <cstdlib>
+#include <limits>
+
+#include "base/numerics/safe_conversions.h"
+#include "base/template_util.h"
+
+namespace base {
+namespace internal {
+
+// Everything from here up to the floating point operations is portable C++,
+// but it may not be fast. This code could be split based on
+// platform/architecture and replaced with potentially faster implementations.
+
+// Integer promotion templates used by the portable checked integer arithmetic.
+template <size_t Size, bool IsSigned>
+struct IntegerForSizeAndSign;
+template <>
+struct IntegerForSizeAndSign<1, true> {
+  typedef int8_t type;
+};
+template <>
+struct IntegerForSizeAndSign<1, false> {
+  typedef uint8_t type;
+};
+template <>
+struct IntegerForSizeAndSign<2, true> {
+  typedef int16_t type;
+};
+template <>
+struct IntegerForSizeAndSign<2, false> {
+  typedef uint16_t type;
+};
+template <>
+struct IntegerForSizeAndSign<4, true> {
+  typedef int32_t type;
+};
+template <>
+struct IntegerForSizeAndSign<4, false> {
+  typedef uint32_t type;
+};
+template <>
+struct IntegerForSizeAndSign<8, true> {
+  typedef int64_t type;
+};
+template <>
+struct IntegerForSizeAndSign<8, false> {
+  typedef uint64_t type;
+};
+
+// WARNING: We have no IntegerForSizeAndSign<16, *>. If we ever add one to
+// support 128-bit math, then the ArithmeticPromotion template below will need
+// to be updated (or more likely replaced with a decltype expression).
+
+template <typename Integer>
+struct UnsignedIntegerForSize {
+  typedef typename enable_if<
+      std::numeric_limits<Integer>::is_integer,
+      typename IntegerForSizeAndSign<sizeof(Integer), false>::type>::type type;
+};
+
+template <typename Integer>
+struct SignedIntegerForSize {
+  typedef typename enable_if<
+      std::numeric_limits<Integer>::is_integer,
+      typename IntegerForSizeAndSign<sizeof(Integer), true>::type>::type type;
+};
+
+template <typename Integer>
+struct TwiceWiderInteger {
+  typedef typename enable_if<
+      std::numeric_limits<Integer>::is_integer,
+      typename IntegerForSizeAndSign<
+          sizeof(Integer) * 2,
+          std::numeric_limits<Integer>::is_signed>::type>::type type;
+};
+
+template <typename Integer>
+struct PositionOfSignBit {
+  static const typename enable_if<std::numeric_limits<Integer>::is_integer,
+                                  size_t>::type value = 8 * sizeof(Integer) - 1;
+};
+
+// Helper templates for integer manipulations.
+
+template <typename T>
+bool HasSignBit(T x) {
+  // Cast to unsigned since right shift on signed is undefined.
+  return !!(static_cast<typename UnsignedIntegerForSize<T>::type>(x) >>
+            PositionOfSignBit<T>::value);
+}
+
+// This wrapper undoes the standard integer promotions.
+template <typename T>
+T BinaryComplement(T x) {
+  return ~x;
+}
+
+// Here are the actual portable checked integer math implementations.
+// TODO(jschuh): Break this code out from the enable_if pattern and find a clean
+// way to coalesce things into the CheckedNumericState specializations below.
+
+template <typename T>
+typename enable_if<std::numeric_limits<T>::is_integer, T>::type
+CheckedAdd(T x, T y, RangeConstraint* validity) {
+  // Since the value of x+y is undefined if we have a signed type, we compute
+  // it using the unsigned type of the same size.
+  typedef typename UnsignedIntegerForSize<T>::type UnsignedDst;
+  UnsignedDst ux = static_cast<UnsignedDst>(x);
+  UnsignedDst uy = static_cast<UnsignedDst>(y);
+  UnsignedDst uresult = ux + uy;
+  // Addition is valid if the sign of (x + y) is equal to either that of x or
+  // that of y.
+  if (std::numeric_limits<T>::is_signed) {
+    if (HasSignBit(BinaryComplement((uresult ^ ux) & (uresult ^ uy))))
+      *validity = RANGE_VALID;
+    else  // Direction of wrap is inverse of result sign.
+      *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW;
+
+  } else {  // Unsigned is either valid or overflow.
+    *validity = BinaryComplement(x) >= y ? RANGE_VALID : RANGE_OVERFLOW;
+  }
+  return static_cast<T>(uresult);
+}
+
+template <typename T>
+typename enable_if<std::numeric_limits<T>::is_integer, T>::type
+CheckedSub(T x, T y, RangeConstraint* validity) {
+  // Since the value of x+y is undefined if we have a signed type, we compute
+  // it using the unsigned type of the same size.
+  typedef typename UnsignedIntegerForSize<T>::type UnsignedDst;
+  UnsignedDst ux = static_cast<UnsignedDst>(x);
+  UnsignedDst uy = static_cast<UnsignedDst>(y);
+  UnsignedDst uresult = ux - uy;
+  // Subtraction is valid if either x and y have same sign, or (x-y) and x have
+  // the same sign.
+  if (std::numeric_limits<T>::is_signed) {
+    if (HasSignBit(BinaryComplement((uresult ^ ux) & (ux ^ uy))))
+      *validity = RANGE_VALID;
+    else  // Direction of wrap is inverse of result sign.
+      *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW;
+
+  } else {  // Unsigned is either valid or underflow.
+    *validity = x >= y ? RANGE_VALID : RANGE_UNDERFLOW;
+  }
+  return static_cast<T>(uresult);
+}
+
+// Integer multiplication is a bit complicated. In the fast case we just
+// we just promote to a twice wider type, and range check the result. In the
+// slow case we need to manually check that the result won't be truncated by
+// checking with division against the appropriate bound.
+template <typename T>
+typename enable_if<
+    std::numeric_limits<T>::is_integer && sizeof(T) * 2 <= sizeof(uintmax_t),
+    T>::type
+CheckedMul(T x, T y, RangeConstraint* validity) {
+  typedef typename TwiceWiderInteger<T>::type IntermediateType;
+  IntermediateType tmp =
+      static_cast<IntermediateType>(x) * static_cast<IntermediateType>(y);
+  *validity = DstRangeRelationToSrcRange<T>(tmp);
+  return static_cast<T>(tmp);
+}
+
+template <typename T>
+typename enable_if<std::numeric_limits<T>::is_integer&& std::numeric_limits<
+                       T>::is_signed&&(sizeof(T) * 2 > sizeof(uintmax_t)),
+                   T>::type
+CheckedMul(T x, T y, RangeConstraint* validity) {
+  // If either side is zero then the result will be zero.
+  if (!x || !y) {
+    return RANGE_VALID;
+
+  } else if (x > 0) {
+    if (y > 0)
+      *validity =
+          x <= std::numeric_limits<T>::max() / y ? RANGE_VALID : RANGE_OVERFLOW;
+    else
+      *validity = y >= std::numeric_limits<T>::min() / x ? RANGE_VALID
+                                                         : RANGE_UNDERFLOW;
+
+  } else {
+    if (y > 0)
+      *validity = x >= std::numeric_limits<T>::min() / y ? RANGE_VALID
+                                                         : RANGE_UNDERFLOW;
+    else
+      *validity =
+          y >= std::numeric_limits<T>::max() / x ? RANGE_VALID : RANGE_OVERFLOW;
+  }
+
+  return x * y;
+}
+
+template <typename T>
+typename enable_if<std::numeric_limits<T>::is_integer &&
+                       !std::numeric_limits<T>::is_signed &&
+                       (sizeof(T) * 2 > sizeof(uintmax_t)),
+                   T>::type
+CheckedMul(T x, T y, RangeConstraint* validity) {
+  *validity = (y == 0 || x <= std::numeric_limits<T>::max() / y)
+                  ? RANGE_VALID
+                  : RANGE_OVERFLOW;
+  return x * y;
+}
+
+// Division just requires a check for an invalid negation on signed min/-1.
+template <typename T>
+T CheckedDiv(
+    T x,
+    T y,
+    RangeConstraint* validity,
+    typename enable_if<std::numeric_limits<T>::is_integer, int>::type = 0) {
+  if (std::numeric_limits<T>::is_signed && x == std::numeric_limits<T>::min() &&
+      y == static_cast<T>(-1)) {
+    *validity = RANGE_OVERFLOW;
+    return std::numeric_limits<T>::min();
+  }
+
+  *validity = RANGE_VALID;
+  return x / y;
+}
+
+template <typename T>
+typename enable_if<
+    std::numeric_limits<T>::is_integer&& std::numeric_limits<T>::is_signed,
+    T>::type
+CheckedMod(T x, T y, RangeConstraint* validity) {
+  *validity = y > 0 ? RANGE_VALID : RANGE_INVALID;
+  return x % y;
+}
+
+template <typename T>
+typename enable_if<
+    std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed,
+    T>::type
+CheckedMod(T x, T y, RangeConstraint* validity) {
+  *validity = RANGE_VALID;
+  return x % y;
+}
+
+template <typename T>
+typename enable_if<
+    std::numeric_limits<T>::is_integer&& std::numeric_limits<T>::is_signed,
+    T>::type
+CheckedNeg(T value, RangeConstraint* validity) {
+  *validity =
+      value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW;
+  // The negation of signed min is min, so catch that one.
+  return -value;
+}
+
+template <typename T>
+typename enable_if<
+    std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed,
+    T>::type
+CheckedNeg(T value, RangeConstraint* validity) {
+  // The only legal unsigned negation is zero.
+  *validity = value ? RANGE_UNDERFLOW : RANGE_VALID;
+  return static_cast<T>(
+      -static_cast<typename SignedIntegerForSize<T>::type>(value));
+}
+
+template <typename T>
+typename enable_if<
+    std::numeric_limits<T>::is_integer&& std::numeric_limits<T>::is_signed,
+    T>::type
+CheckedAbs(T value, RangeConstraint* validity) {
+  *validity =
+      value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW;
+  return static_cast<T>(std::abs(value));
+}
+
+template <typename T>
+typename enable_if<
+    std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed,
+    T>::type
+CheckedAbs(T value, RangeConstraint* validity) {
+  // Absolute value of a positive is just its identiy.
+  *validity = RANGE_VALID;
+  return value;
+}
+
+// These are the floating point stubs that the compiler needs to see. Only the
+// negation operation is ever called.
+#define BASE_FLOAT_ARITHMETIC_STUBS(NAME)                        \
+  template <typename T>                                          \
+  typename enable_if<std::numeric_limits<T>::is_iec559, T>::type \
+  Checked##NAME(T, T, RangeConstraint*) {                        \
+    NOTREACHED();                                                \
+    return 0;                                                    \
+  }
+
+BASE_FLOAT_ARITHMETIC_STUBS(Add)
+BASE_FLOAT_ARITHMETIC_STUBS(Sub)
+BASE_FLOAT_ARITHMETIC_STUBS(Mul)
+BASE_FLOAT_ARITHMETIC_STUBS(Div)
+BASE_FLOAT_ARITHMETIC_STUBS(Mod)
+
+#undef BASE_FLOAT_ARITHMETIC_STUBS
+
+template <typename T>
+typename enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedNeg(
+    T value,
+    RangeConstraint*) {
+  return -value;
+}
+
+template <typename T>
+typename enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedAbs(
+    T value,
+    RangeConstraint*) {
+  return std::abs(value);
+}
+
+// Floats carry around their validity state with them, but integers do not. So,
+// we wrap the underlying value in a specialization in order to hide that detail
+// and expose an interface via accessors.
+enum NumericRepresentation {
+  NUMERIC_INTEGER,
+  NUMERIC_FLOATING,
+  NUMERIC_UNKNOWN
+};
+
+template <typename NumericType>
+struct GetNumericRepresentation {
+  static const NumericRepresentation value =
+      std::numeric_limits<NumericType>::is_integer
+          ? NUMERIC_INTEGER
+          : (std::numeric_limits<NumericType>::is_iec559 ? NUMERIC_FLOATING
+                                                         : NUMERIC_UNKNOWN);
+};
+
+template <typename T, NumericRepresentation type =
+                          GetNumericRepresentation<T>::value>
+class CheckedNumericState {};
+
+// Integrals require quite a bit of additional housekeeping to manage state.
+template <typename T>
+class CheckedNumericState<T, NUMERIC_INTEGER> {
+ private:
+  T value_;
+  RangeConstraint validity_;
+
+ public:
+  template <typename Src, NumericRepresentation type>
+  friend class CheckedNumericState;
+
+  CheckedNumericState() : value_(0), validity_(RANGE_VALID) {}
+
+  template <typename Src>
+  CheckedNumericState(Src value, RangeConstraint validity)
+      : value_(static_cast<T>(value)),
+        validity_(GetRangeConstraint(validity |
+                                     DstRangeRelationToSrcRange<T>(value))) {
+    static_assert(std::numeric_limits<Src>::is_specialized,
+                  "Argument must be numeric.");
+  }
+
+  // Copy constructor.
+  template <typename Src>
+  CheckedNumericState(const CheckedNumericState<Src>& rhs)
+      : value_(static_cast<T>(rhs.value())),
+        validity_(GetRangeConstraint(
+            rhs.validity() | DstRangeRelationToSrcRange<T>(rhs.value()))) {}
+
+  template <typename Src>
+  explicit CheckedNumericState(
+      Src value,
+      typename enable_if<std::numeric_limits<Src>::is_specialized, int>::type =
+          0)
+      : value_(static_cast<T>(value)),
+        validity_(DstRangeRelationToSrcRange<T>(value)) {}
+
+  RangeConstraint validity() const { return validity_; }
+  T value() const { return value_; }
+};
+
+// Floating points maintain their own validity, but need translation wrappers.
+template <typename T>
+class CheckedNumericState<T, NUMERIC_FLOATING> {
+ private:
+  T value_;
+
+ public:
+  template <typename Src, NumericRepresentation type>
+  friend class CheckedNumericState;
+
+  CheckedNumericState() : value_(0.0) {}
+
+  template <typename Src>
+  CheckedNumericState(
+      Src value,
+      RangeConstraint validity,
+      typename enable_if<std::numeric_limits<Src>::is_integer, int>::type = 0) {
+    switch (DstRangeRelationToSrcRange<T>(value)) {
+      case RANGE_VALID:
+        value_ = static_cast<T>(value);
+        break;
+
+      case RANGE_UNDERFLOW:
+        value_ = -std::numeric_limits<T>::infinity();
+        break;
+
+      case RANGE_OVERFLOW:
+        value_ = std::numeric_limits<T>::infinity();
+        break;
+
+      case RANGE_INVALID:
+        value_ = std::numeric_limits<T>::quiet_NaN();
+        break;
+
+      default:
+        NOTREACHED();
+    }
+  }
+
+  template <typename Src>
+  explicit CheckedNumericState(
+      Src value,
+      typename enable_if<std::numeric_limits<Src>::is_specialized, int>::type =
+          0)
+      : value_(static_cast<T>(value)) {}
+
+  // Copy constructor.
+  template <typename Src>
+  CheckedNumericState(const CheckedNumericState<Src>& rhs)
+      : value_(static_cast<T>(rhs.value())) {}
+
+  RangeConstraint validity() const {
+    return GetRangeConstraint(value_ <= std::numeric_limits<T>::max(),
+                              value_ >= -std::numeric_limits<T>::max());
+  }
+  T value() const { return value_; }
+};
+
+// For integers less than 128-bit and floats 32-bit or larger, we can distil
+// C/C++ arithmetic promotions down to two simple rules:
+// 1. The type with the larger maximum exponent always takes precedence.
+// 2. The resulting type must be promoted to at least an int.
+// The following template specializations implement that promotion logic.
+enum ArithmeticPromotionCategory {
+  LEFT_PROMOTION,
+  RIGHT_PROMOTION,
+  DEFAULT_PROMOTION
+};
+
+template <typename Lhs,
+          typename Rhs = Lhs,
+          ArithmeticPromotionCategory Promotion =
+              (MaxExponent<Lhs>::value > MaxExponent<Rhs>::value)
+                  ? (MaxExponent<Lhs>::value > MaxExponent<int>::value
+                         ? LEFT_PROMOTION
+                         : DEFAULT_PROMOTION)
+                  : (MaxExponent<Rhs>::value > MaxExponent<int>::value
+                         ? RIGHT_PROMOTION
+                         : DEFAULT_PROMOTION) >
+struct ArithmeticPromotion;
+
+template <typename Lhs, typename Rhs>
+struct ArithmeticPromotion<Lhs, Rhs, LEFT_PROMOTION> {
+  typedef Lhs type;
+};
+
+template <typename Lhs, typename Rhs>
+struct ArithmeticPromotion<Lhs, Rhs, RIGHT_PROMOTION> {
+  typedef Rhs type;
+};
+
+template <typename Lhs, typename Rhs>
+struct ArithmeticPromotion<Lhs, Rhs, DEFAULT_PROMOTION> {
+  typedef int type;
+};
+
+// We can statically check if operations on the provided types can wrap, so we
+// can skip the checked operations if they're not needed. So, for an integer we
+// care if the destination type preserves the sign and is twice the width of
+// the source.
+template <typename T, typename Lhs, typename Rhs>
+struct IsIntegerArithmeticSafe {
+  static const bool value = !std::numeric_limits<T>::is_iec559 &&
+                            StaticDstRangeRelationToSrcRange<T, Lhs>::value ==
+                                NUMERIC_RANGE_CONTAINED &&
+                            sizeof(T) >= (2 * sizeof(Lhs)) &&
+                            StaticDstRangeRelationToSrcRange<T, Rhs>::value !=
+                                NUMERIC_RANGE_CONTAINED &&
+                            sizeof(T) >= (2 * sizeof(Rhs));
+};
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_NUMERICS_SAFE_MATH_IMPL_H_
diff --git a/base/numerics/safe_numerics_unittest.cc b/base/numerics/safe_numerics_unittest.cc
new file mode 100644
index 0000000..6f9a966
--- /dev/null
+++ b/base/numerics/safe_numerics_unittest.cc
@@ -0,0 +1,602 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#if defined(COMPILER_MSVC) && defined(ARCH_CPU_32_BITS)
+#include <mmintrin.h>
+#endif
+#include <stdint.h>
+
+#include <limits>
+
+#include "base/compiler_specific.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/numerics/safe_math.h"
+#include "base/template_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using std::numeric_limits;
+using base::CheckedNumeric;
+using base::checked_cast;
+using base::SizeT;
+using base::StrictNumeric;
+using base::saturated_cast;
+using base::strict_cast;
+using base::internal::MaxExponent;
+using base::internal::RANGE_VALID;
+using base::internal::RANGE_INVALID;
+using base::internal::RANGE_OVERFLOW;
+using base::internal::RANGE_UNDERFLOW;
+using base::enable_if;
+
+// These tests deliberately cause arithmetic overflows. If the compiler is
+// aggressive enough, it can const fold these overflows. Disable warnings about
+// overflows for const expressions.
+#if defined(OS_WIN)
+#pragma warning(disable:4756)
+#endif
+
+// Helper macros to wrap displaying the conversion types and line numbers.
+#define TEST_EXPECTED_VALIDITY(expected, actual)                           \
+  EXPECT_EQ(expected, CheckedNumeric<Dst>(actual).validity())              \
+      << "Result test: Value " << +(actual).ValueUnsafe() << " as " << dst \
+      << " on line " << line;
+
+#define TEST_EXPECTED_VALUE(expected, actual)                                \
+  EXPECT_EQ(static_cast<Dst>(expected),                                      \
+            CheckedNumeric<Dst>(actual).ValueUnsafe())                       \
+      << "Result test: Value " << +((actual).ValueUnsafe()) << " as " << dst \
+      << " on line " << line;
+
+// Signed integer arithmetic.
+template <typename Dst>
+static void TestSpecializedArithmetic(
+    const char* dst,
+    int line,
+    typename enable_if<
+        numeric_limits<Dst>::is_integer&& numeric_limits<Dst>::is_signed,
+        int>::type = 0) {
+  typedef numeric_limits<Dst> DstLimits;
+  TEST_EXPECTED_VALIDITY(RANGE_OVERFLOW,
+                         -CheckedNumeric<Dst>(DstLimits::min()));
+  TEST_EXPECTED_VALIDITY(RANGE_OVERFLOW,
+                         CheckedNumeric<Dst>(DstLimits::min()).Abs());
+  TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(-1).Abs());
+
+  TEST_EXPECTED_VALIDITY(RANGE_VALID,
+                         CheckedNumeric<Dst>(DstLimits::max()) + -1);
+  TEST_EXPECTED_VALIDITY(RANGE_UNDERFLOW,
+                         CheckedNumeric<Dst>(DstLimits::min()) + -1);
+  TEST_EXPECTED_VALIDITY(
+      RANGE_UNDERFLOW,
+      CheckedNumeric<Dst>(-DstLimits::max()) + -DstLimits::max());
+
+  TEST_EXPECTED_VALIDITY(RANGE_UNDERFLOW,
+                         CheckedNumeric<Dst>(DstLimits::min()) - 1);
+  TEST_EXPECTED_VALIDITY(RANGE_VALID,
+                         CheckedNumeric<Dst>(DstLimits::min()) - -1);
+  TEST_EXPECTED_VALIDITY(
+      RANGE_OVERFLOW,
+      CheckedNumeric<Dst>(DstLimits::max()) - -DstLimits::max());
+  TEST_EXPECTED_VALIDITY(
+      RANGE_UNDERFLOW,
+      CheckedNumeric<Dst>(-DstLimits::max()) - DstLimits::max());
+
+  TEST_EXPECTED_VALIDITY(RANGE_UNDERFLOW,
+                         CheckedNumeric<Dst>(DstLimits::min()) * 2);
+
+  TEST_EXPECTED_VALIDITY(RANGE_OVERFLOW,
+                         CheckedNumeric<Dst>(DstLimits::min()) / -1);
+  TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(-1) / 2);
+
+  // Modulus is legal only for integers.
+  TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>() % 1);
+  TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) % 1);
+  TEST_EXPECTED_VALUE(-1, CheckedNumeric<Dst>(-1) % 2);
+  TEST_EXPECTED_VALIDITY(RANGE_INVALID, CheckedNumeric<Dst>(-1) % -2);
+  TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(DstLimits::min()) % 2);
+  TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(DstLimits::max()) % 2);
+  // Test all the different modulus combinations.
+  TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) % CheckedNumeric<Dst>(1));
+  TEST_EXPECTED_VALUE(0, 1 % CheckedNumeric<Dst>(1));
+  TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) % 1);
+  CheckedNumeric<Dst> checked_dst = 1;
+  TEST_EXPECTED_VALUE(0, checked_dst %= 1);
+}
+
+// Unsigned integer arithmetic.
+template <typename Dst>
+static void TestSpecializedArithmetic(
+    const char* dst,
+    int line,
+    typename enable_if<
+        numeric_limits<Dst>::is_integer && !numeric_limits<Dst>::is_signed,
+        int>::type = 0) {
+  typedef numeric_limits<Dst> DstLimits;
+  TEST_EXPECTED_VALIDITY(RANGE_VALID, -CheckedNumeric<Dst>(DstLimits::min()));
+  TEST_EXPECTED_VALIDITY(RANGE_VALID,
+                         CheckedNumeric<Dst>(DstLimits::min()).Abs());
+  TEST_EXPECTED_VALIDITY(RANGE_UNDERFLOW,
+                         CheckedNumeric<Dst>(DstLimits::min()) + -1);
+  TEST_EXPECTED_VALIDITY(RANGE_UNDERFLOW,
+                         CheckedNumeric<Dst>(DstLimits::min()) - 1);
+  TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(DstLimits::min()) * 2);
+  TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) / 2);
+
+  // Modulus is legal only for integers.
+  TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>() % 1);
+  TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) % 1);
+  TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) % 2);
+  TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(DstLimits::min()) % 2);
+  TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(DstLimits::max()) % 2);
+  // Test all the different modulus combinations.
+  TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) % CheckedNumeric<Dst>(1));
+  TEST_EXPECTED_VALUE(0, 1 % CheckedNumeric<Dst>(1));
+  TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) % 1);
+  CheckedNumeric<Dst> checked_dst = 1;
+  TEST_EXPECTED_VALUE(0, checked_dst %= 1);
+}
+
+// Floating point arithmetic.
+template <typename Dst>
+void TestSpecializedArithmetic(
+    const char* dst,
+    int line,
+    typename enable_if<numeric_limits<Dst>::is_iec559, int>::type = 0) {
+  typedef numeric_limits<Dst> DstLimits;
+  TEST_EXPECTED_VALIDITY(RANGE_VALID, -CheckedNumeric<Dst>(DstLimits::min()));
+
+  TEST_EXPECTED_VALIDITY(RANGE_VALID,
+                         CheckedNumeric<Dst>(DstLimits::min()).Abs());
+  TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(-1).Abs());
+
+  TEST_EXPECTED_VALIDITY(RANGE_VALID,
+                         CheckedNumeric<Dst>(DstLimits::min()) + -1);
+  TEST_EXPECTED_VALIDITY(RANGE_VALID,
+                         CheckedNumeric<Dst>(DstLimits::max()) + 1);
+  TEST_EXPECTED_VALIDITY(
+      RANGE_UNDERFLOW,
+      CheckedNumeric<Dst>(-DstLimits::max()) + -DstLimits::max());
+
+  TEST_EXPECTED_VALIDITY(
+      RANGE_OVERFLOW,
+      CheckedNumeric<Dst>(DstLimits::max()) - -DstLimits::max());
+  TEST_EXPECTED_VALIDITY(
+      RANGE_UNDERFLOW,
+      CheckedNumeric<Dst>(-DstLimits::max()) - DstLimits::max());
+
+  TEST_EXPECTED_VALIDITY(RANGE_VALID,
+                         CheckedNumeric<Dst>(DstLimits::min()) * 2);
+
+  TEST_EXPECTED_VALUE(-0.5, CheckedNumeric<Dst>(-1.0) / 2);
+  EXPECT_EQ(static_cast<Dst>(1.0), CheckedNumeric<Dst>(1.0).ValueFloating());
+}
+
+// Generic arithmetic tests.
+template <typename Dst>
+static void TestArithmetic(const char* dst, int line) {
+  typedef numeric_limits<Dst> DstLimits;
+
+  EXPECT_EQ(true, CheckedNumeric<Dst>().IsValid());
+  EXPECT_EQ(false,
+            CheckedNumeric<Dst>(CheckedNumeric<Dst>(DstLimits::max()) *
+                                DstLimits::max()).IsValid());
+  EXPECT_EQ(static_cast<Dst>(0), CheckedNumeric<Dst>().ValueOrDie());
+  EXPECT_EQ(static_cast<Dst>(0), CheckedNumeric<Dst>().ValueOrDefault(1));
+  EXPECT_EQ(static_cast<Dst>(1),
+            CheckedNumeric<Dst>(CheckedNumeric<Dst>(DstLimits::max()) *
+                                DstLimits::max()).ValueOrDefault(1));
+
+  // Test the operator combinations.
+  TEST_EXPECTED_VALUE(2, CheckedNumeric<Dst>(1) + CheckedNumeric<Dst>(1));
+  TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) - CheckedNumeric<Dst>(1));
+  TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) * CheckedNumeric<Dst>(1));
+  TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) / CheckedNumeric<Dst>(1));
+  TEST_EXPECTED_VALUE(2, 1 + CheckedNumeric<Dst>(1));
+  TEST_EXPECTED_VALUE(0, 1 - CheckedNumeric<Dst>(1));
+  TEST_EXPECTED_VALUE(1, 1 * CheckedNumeric<Dst>(1));
+  TEST_EXPECTED_VALUE(1, 1 / CheckedNumeric<Dst>(1));
+  TEST_EXPECTED_VALUE(2, CheckedNumeric<Dst>(1) + 1);
+  TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) - 1);
+  TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) * 1);
+  TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) / 1);
+  CheckedNumeric<Dst> checked_dst = 1;
+  TEST_EXPECTED_VALUE(2, checked_dst += 1);
+  checked_dst = 1;
+  TEST_EXPECTED_VALUE(0, checked_dst -= 1);
+  checked_dst = 1;
+  TEST_EXPECTED_VALUE(1, checked_dst *= 1);
+  checked_dst = 1;
+  TEST_EXPECTED_VALUE(1, checked_dst /= 1);
+
+  // Generic negation.
+  TEST_EXPECTED_VALUE(0, -CheckedNumeric<Dst>());
+  TEST_EXPECTED_VALUE(-1, -CheckedNumeric<Dst>(1));
+  TEST_EXPECTED_VALUE(1, -CheckedNumeric<Dst>(-1));
+  TEST_EXPECTED_VALUE(static_cast<Dst>(DstLimits::max() * -1),
+                      -CheckedNumeric<Dst>(DstLimits::max()));
+
+  // Generic absolute value.
+  TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>().Abs());
+  TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1).Abs());
+  TEST_EXPECTED_VALUE(DstLimits::max(),
+                      CheckedNumeric<Dst>(DstLimits::max()).Abs());
+
+  // Generic addition.
+  TEST_EXPECTED_VALUE(1, (CheckedNumeric<Dst>() + 1));
+  TEST_EXPECTED_VALUE(2, (CheckedNumeric<Dst>(1) + 1));
+  TEST_EXPECTED_VALUE(0, (CheckedNumeric<Dst>(-1) + 1));
+  TEST_EXPECTED_VALIDITY(RANGE_VALID,
+                         CheckedNumeric<Dst>(DstLimits::min()) + 1);
+  TEST_EXPECTED_VALIDITY(
+      RANGE_OVERFLOW, CheckedNumeric<Dst>(DstLimits::max()) + DstLimits::max());
+
+  // Generic subtraction.
+  TEST_EXPECTED_VALUE(-1, (CheckedNumeric<Dst>() - 1));
+  TEST_EXPECTED_VALUE(0, (CheckedNumeric<Dst>(1) - 1));
+  TEST_EXPECTED_VALUE(-2, (CheckedNumeric<Dst>(-1) - 1));
+  TEST_EXPECTED_VALIDITY(RANGE_VALID,
+                         CheckedNumeric<Dst>(DstLimits::max()) - 1);
+
+  // Generic multiplication.
+  TEST_EXPECTED_VALUE(0, (CheckedNumeric<Dst>() * 1));
+  TEST_EXPECTED_VALUE(1, (CheckedNumeric<Dst>(1) * 1));
+  TEST_EXPECTED_VALUE(-2, (CheckedNumeric<Dst>(-1) * 2));
+  TEST_EXPECTED_VALUE(0, (CheckedNumeric<Dst>(0) * 0));
+  TEST_EXPECTED_VALUE(0, (CheckedNumeric<Dst>(-1) * 0));
+  TEST_EXPECTED_VALUE(0, (CheckedNumeric<Dst>(0) * -1));
+  TEST_EXPECTED_VALIDITY(
+      RANGE_OVERFLOW, CheckedNumeric<Dst>(DstLimits::max()) * DstLimits::max());
+
+  // Generic division.
+  TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>() / 1);
+  TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) / 1);
+  TEST_EXPECTED_VALUE(DstLimits::min() / 2,
+                      CheckedNumeric<Dst>(DstLimits::min()) / 2);
+  TEST_EXPECTED_VALUE(DstLimits::max() / 2,
+                      CheckedNumeric<Dst>(DstLimits::max()) / 2);
+
+  TestSpecializedArithmetic<Dst>(dst, line);
+}
+
+// Helper macro to wrap displaying the conversion types and line numbers.
+#define TEST_ARITHMETIC(Dst) TestArithmetic<Dst>(#Dst, __LINE__)
+
+TEST(SafeNumerics, SignedIntegerMath) {
+  TEST_ARITHMETIC(int8_t);
+  TEST_ARITHMETIC(int);
+  TEST_ARITHMETIC(intptr_t);
+  TEST_ARITHMETIC(intmax_t);
+}
+
+TEST(SafeNumerics, UnsignedIntegerMath) {
+  TEST_ARITHMETIC(uint8_t);
+  TEST_ARITHMETIC(unsigned int);
+  TEST_ARITHMETIC(uintptr_t);
+  TEST_ARITHMETIC(uintmax_t);
+}
+
+TEST(SafeNumerics, FloatingPointMath) {
+  TEST_ARITHMETIC(float);
+  TEST_ARITHMETIC(double);
+}
+
+// Enumerates the five different conversions types we need to test.
+enum NumericConversionType {
+  SIGN_PRESERVING_VALUE_PRESERVING,
+  SIGN_PRESERVING_NARROW,
+  SIGN_TO_UNSIGN_WIDEN_OR_EQUAL,
+  SIGN_TO_UNSIGN_NARROW,
+  UNSIGN_TO_SIGN_NARROW_OR_EQUAL,
+};
+
+// Template covering the different conversion tests.
+template <typename Dst, typename Src, NumericConversionType conversion>
+struct TestNumericConversion {};
+
+// EXPECT_EQ wrappers providing specific detail on test failures.
+#define TEST_EXPECTED_RANGE(expected, actual)                                  \
+  EXPECT_EQ(expected, base::internal::DstRangeRelationToSrcRange<Dst>(actual)) \
+      << "Conversion test: " << src << " value " << actual << " to " << dst    \
+      << " on line " << line;
+
+template <typename Dst, typename Src>
+struct TestNumericConversion<Dst, Src, SIGN_PRESERVING_VALUE_PRESERVING> {
+  static void Test(const char *dst, const char *src, int line) {
+    typedef numeric_limits<Src> SrcLimits;
+    typedef numeric_limits<Dst> DstLimits;
+                   // Integral to floating.
+    static_assert((DstLimits::is_iec559 && SrcLimits::is_integer) ||
+                  // Not floating to integral and...
+                  (!(DstLimits::is_integer && SrcLimits::is_iec559) &&
+                   // Same sign, same numeric, source is narrower or same.
+                   ((SrcLimits::is_signed == DstLimits::is_signed &&
+                    sizeof(Dst) >= sizeof(Src)) ||
+                   // Or signed destination and source is smaller
+                    (DstLimits::is_signed && sizeof(Dst) > sizeof(Src)))),
+                  "Comparison must be sign preserving and value preserving");
+
+    const CheckedNumeric<Dst> checked_dst = SrcLimits::max();
+    ;
+    TEST_EXPECTED_VALIDITY(RANGE_VALID, checked_dst);
+    if (MaxExponent<Dst>::value > MaxExponent<Src>::value) {
+      if (MaxExponent<Dst>::value >= MaxExponent<Src>::value * 2 - 1) {
+        // At least twice larger type.
+        TEST_EXPECTED_VALIDITY(RANGE_VALID, SrcLimits::max() * checked_dst);
+
+      } else {  // Larger, but not at least twice as large.
+        TEST_EXPECTED_VALIDITY(RANGE_OVERFLOW, SrcLimits::max() * checked_dst);
+        TEST_EXPECTED_VALIDITY(RANGE_VALID, checked_dst + 1);
+      }
+    } else {  // Same width type.
+      TEST_EXPECTED_VALIDITY(RANGE_OVERFLOW, checked_dst + 1);
+    }
+
+    TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::max());
+    TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(1));
+    if (SrcLimits::is_iec559) {
+      TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::max() * static_cast<Src>(-1));
+      TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::infinity());
+      TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::infinity() * -1);
+      TEST_EXPECTED_RANGE(RANGE_INVALID, SrcLimits::quiet_NaN());
+    } else if (numeric_limits<Src>::is_signed) {
+      TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(-1));
+      TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::min());
+    }
+  }
+};
+
+template <typename Dst, typename Src>
+struct TestNumericConversion<Dst, Src, SIGN_PRESERVING_NARROW> {
+  static void Test(const char *dst, const char *src, int line) {
+    typedef numeric_limits<Src> SrcLimits;
+    typedef numeric_limits<Dst> DstLimits;
+    static_assert(SrcLimits::is_signed == DstLimits::is_signed,
+                  "Destination and source sign must be the same");
+    static_assert(sizeof(Dst) < sizeof(Src) ||
+                   (DstLimits::is_integer && SrcLimits::is_iec559),
+                  "Destination must be narrower than source");
+
+    const CheckedNumeric<Dst> checked_dst;
+    TEST_EXPECTED_VALIDITY(RANGE_OVERFLOW, checked_dst + SrcLimits::max());
+    TEST_EXPECTED_VALUE(1, checked_dst + static_cast<Src>(1));
+    TEST_EXPECTED_VALIDITY(RANGE_UNDERFLOW, checked_dst - SrcLimits::max());
+
+    TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::max());
+    TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(1));
+    if (SrcLimits::is_iec559) {
+      TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::max() * -1);
+      TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(-1));
+      TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::infinity());
+      TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::infinity() * -1);
+      TEST_EXPECTED_RANGE(RANGE_INVALID, SrcLimits::quiet_NaN());
+    } else if (SrcLimits::is_signed) {
+      TEST_EXPECTED_VALUE(-1, checked_dst - static_cast<Src>(1));
+      TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::min());
+      TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(-1));
+    } else {
+      TEST_EXPECTED_VALIDITY(RANGE_INVALID, checked_dst - static_cast<Src>(1));
+      TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::min());
+    }
+  }
+};
+
+template <typename Dst, typename Src>
+struct TestNumericConversion<Dst, Src, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL> {
+  static void Test(const char *dst, const char *src, int line) {
+    typedef numeric_limits<Src> SrcLimits;
+    typedef numeric_limits<Dst> DstLimits;
+    static_assert(sizeof(Dst) >= sizeof(Src),
+                  "Destination must be equal or wider than source.");
+    static_assert(SrcLimits::is_signed, "Source must be signed");
+    static_assert(!DstLimits::is_signed, "Destination must be unsigned");
+
+    const CheckedNumeric<Dst> checked_dst;
+    TEST_EXPECTED_VALUE(SrcLimits::max(), checked_dst + SrcLimits::max());
+    TEST_EXPECTED_VALIDITY(RANGE_UNDERFLOW, checked_dst + static_cast<Src>(-1));
+    TEST_EXPECTED_VALIDITY(RANGE_UNDERFLOW, checked_dst + -SrcLimits::max());
+
+    TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::min());
+    TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::max());
+    TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(1));
+    TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, static_cast<Src>(-1));
+  }
+};
+
+template <typename Dst, typename Src>
+struct TestNumericConversion<Dst, Src, SIGN_TO_UNSIGN_NARROW> {
+  static void Test(const char *dst, const char *src, int line) {
+    typedef numeric_limits<Src> SrcLimits;
+    typedef numeric_limits<Dst> DstLimits;
+    static_assert((DstLimits::is_integer && SrcLimits::is_iec559) ||
+                   (sizeof(Dst) < sizeof(Src)),
+                  "Destination must be narrower than source.");
+    static_assert(SrcLimits::is_signed, "Source must be signed.");
+    static_assert(!DstLimits::is_signed, "Destination must be unsigned.");
+
+    const CheckedNumeric<Dst> checked_dst;
+    TEST_EXPECTED_VALUE(1, checked_dst + static_cast<Src>(1));
+    TEST_EXPECTED_VALIDITY(RANGE_OVERFLOW, checked_dst + SrcLimits::max());
+    TEST_EXPECTED_VALIDITY(RANGE_UNDERFLOW, checked_dst + static_cast<Src>(-1));
+    TEST_EXPECTED_VALIDITY(RANGE_UNDERFLOW, checked_dst + -SrcLimits::max());
+
+    TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::max());
+    TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(1));
+    TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, static_cast<Src>(-1));
+    if (SrcLimits::is_iec559) {
+      TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::max() * -1);
+      TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::infinity());
+      TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::infinity() * -1);
+      TEST_EXPECTED_RANGE(RANGE_INVALID, SrcLimits::quiet_NaN());
+    } else {
+      TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::min());
+    }
+  }
+};
+
+template <typename Dst, typename Src>
+struct TestNumericConversion<Dst, Src, UNSIGN_TO_SIGN_NARROW_OR_EQUAL> {
+  static void Test(const char *dst, const char *src, int line) {
+    typedef numeric_limits<Src> SrcLimits;
+    typedef numeric_limits<Dst> DstLimits;
+    static_assert(sizeof(Dst) <= sizeof(Src),
+                  "Destination must be narrower or equal to source.");
+    static_assert(!SrcLimits::is_signed, "Source must be unsigned.");
+    static_assert(DstLimits::is_signed, "Destination must be signed.");
+
+    const CheckedNumeric<Dst> checked_dst;
+    TEST_EXPECTED_VALUE(1, checked_dst + static_cast<Src>(1));
+    TEST_EXPECTED_VALIDITY(RANGE_OVERFLOW, checked_dst + SrcLimits::max());
+    TEST_EXPECTED_VALUE(SrcLimits::min(), checked_dst + SrcLimits::min());
+
+    TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::min());
+    TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::max());
+    TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(1));
+  }
+};
+
+// Helper macro to wrap displaying the conversion types and line numbers
+#define TEST_NUMERIC_CONVERSION(d, s, t) \
+  TestNumericConversion<d, s, t>::Test(#d, #s, __LINE__)
+
+TEST(SafeNumerics, IntMinOperations) {
+  TEST_NUMERIC_CONVERSION(int8_t, int8_t, SIGN_PRESERVING_VALUE_PRESERVING);
+  TEST_NUMERIC_CONVERSION(uint8_t, uint8_t, SIGN_PRESERVING_VALUE_PRESERVING);
+
+  TEST_NUMERIC_CONVERSION(int8_t, int, SIGN_PRESERVING_NARROW);
+  TEST_NUMERIC_CONVERSION(uint8_t, unsigned int, SIGN_PRESERVING_NARROW);
+  TEST_NUMERIC_CONVERSION(int8_t, float, SIGN_PRESERVING_NARROW);
+
+  TEST_NUMERIC_CONVERSION(uint8_t, int8_t, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL);
+
+  TEST_NUMERIC_CONVERSION(uint8_t, int, SIGN_TO_UNSIGN_NARROW);
+  TEST_NUMERIC_CONVERSION(uint8_t, intmax_t, SIGN_TO_UNSIGN_NARROW);
+  TEST_NUMERIC_CONVERSION(uint8_t, float, SIGN_TO_UNSIGN_NARROW);
+
+  TEST_NUMERIC_CONVERSION(int8_t, unsigned int, UNSIGN_TO_SIGN_NARROW_OR_EQUAL);
+  TEST_NUMERIC_CONVERSION(int8_t, uintmax_t, UNSIGN_TO_SIGN_NARROW_OR_EQUAL);
+}
+
+TEST(SafeNumerics, IntOperations) {
+  TEST_NUMERIC_CONVERSION(int, int, SIGN_PRESERVING_VALUE_PRESERVING);
+  TEST_NUMERIC_CONVERSION(unsigned int, unsigned int,
+                          SIGN_PRESERVING_VALUE_PRESERVING);
+  TEST_NUMERIC_CONVERSION(int, int8_t, SIGN_PRESERVING_VALUE_PRESERVING);
+  TEST_NUMERIC_CONVERSION(unsigned int, uint8_t,
+                          SIGN_PRESERVING_VALUE_PRESERVING);
+  TEST_NUMERIC_CONVERSION(int, uint8_t, SIGN_PRESERVING_VALUE_PRESERVING);
+
+  TEST_NUMERIC_CONVERSION(int, intmax_t, SIGN_PRESERVING_NARROW);
+  TEST_NUMERIC_CONVERSION(unsigned int, uintmax_t, SIGN_PRESERVING_NARROW);
+  TEST_NUMERIC_CONVERSION(int, float, SIGN_PRESERVING_NARROW);
+  TEST_NUMERIC_CONVERSION(int, double, SIGN_PRESERVING_NARROW);
+
+  TEST_NUMERIC_CONVERSION(unsigned int, int, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL);
+  TEST_NUMERIC_CONVERSION(unsigned int, int8_t, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL);
+
+  TEST_NUMERIC_CONVERSION(unsigned int, intmax_t, SIGN_TO_UNSIGN_NARROW);
+  TEST_NUMERIC_CONVERSION(unsigned int, float, SIGN_TO_UNSIGN_NARROW);
+  TEST_NUMERIC_CONVERSION(unsigned int, double, SIGN_TO_UNSIGN_NARROW);
+
+  TEST_NUMERIC_CONVERSION(int, unsigned int, UNSIGN_TO_SIGN_NARROW_OR_EQUAL);
+  TEST_NUMERIC_CONVERSION(int, uintmax_t, UNSIGN_TO_SIGN_NARROW_OR_EQUAL);
+}
+
+TEST(SafeNumerics, IntMaxOperations) {
+  TEST_NUMERIC_CONVERSION(intmax_t, intmax_t, SIGN_PRESERVING_VALUE_PRESERVING);
+  TEST_NUMERIC_CONVERSION(uintmax_t, uintmax_t,
+                          SIGN_PRESERVING_VALUE_PRESERVING);
+  TEST_NUMERIC_CONVERSION(intmax_t, int, SIGN_PRESERVING_VALUE_PRESERVING);
+  TEST_NUMERIC_CONVERSION(uintmax_t, unsigned int,
+                          SIGN_PRESERVING_VALUE_PRESERVING);
+  TEST_NUMERIC_CONVERSION(intmax_t, unsigned int,
+                          SIGN_PRESERVING_VALUE_PRESERVING);
+  TEST_NUMERIC_CONVERSION(intmax_t, uint8_t, SIGN_PRESERVING_VALUE_PRESERVING);
+
+  TEST_NUMERIC_CONVERSION(intmax_t, float, SIGN_PRESERVING_NARROW);
+  TEST_NUMERIC_CONVERSION(intmax_t, double, SIGN_PRESERVING_NARROW);
+
+  TEST_NUMERIC_CONVERSION(uintmax_t, int, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL);
+  TEST_NUMERIC_CONVERSION(uintmax_t, int8_t, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL);
+
+  TEST_NUMERIC_CONVERSION(uintmax_t, float, SIGN_TO_UNSIGN_NARROW);
+  TEST_NUMERIC_CONVERSION(uintmax_t, double, SIGN_TO_UNSIGN_NARROW);
+
+  TEST_NUMERIC_CONVERSION(intmax_t, uintmax_t, UNSIGN_TO_SIGN_NARROW_OR_EQUAL);
+}
+
+TEST(SafeNumerics, FloatOperations) {
+  TEST_NUMERIC_CONVERSION(float, intmax_t, SIGN_PRESERVING_VALUE_PRESERVING);
+  TEST_NUMERIC_CONVERSION(float, uintmax_t,
+                          SIGN_PRESERVING_VALUE_PRESERVING);
+  TEST_NUMERIC_CONVERSION(float, int, SIGN_PRESERVING_VALUE_PRESERVING);
+  TEST_NUMERIC_CONVERSION(float, unsigned int,
+                          SIGN_PRESERVING_VALUE_PRESERVING);
+
+  TEST_NUMERIC_CONVERSION(float, double, SIGN_PRESERVING_NARROW);
+}
+
+TEST(SafeNumerics, DoubleOperations) {
+  TEST_NUMERIC_CONVERSION(double, intmax_t, SIGN_PRESERVING_VALUE_PRESERVING);
+  TEST_NUMERIC_CONVERSION(double, uintmax_t,
+                          SIGN_PRESERVING_VALUE_PRESERVING);
+  TEST_NUMERIC_CONVERSION(double, int, SIGN_PRESERVING_VALUE_PRESERVING);
+  TEST_NUMERIC_CONVERSION(double, unsigned int,
+                          SIGN_PRESERVING_VALUE_PRESERVING);
+}
+
+TEST(SafeNumerics, SizeTOperations) {
+  TEST_NUMERIC_CONVERSION(size_t, int, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL);
+  TEST_NUMERIC_CONVERSION(int, size_t, UNSIGN_TO_SIGN_NARROW_OR_EQUAL);
+}
+
+TEST(SafeNumerics, CastTests) {
+// MSVC catches and warns that we're forcing saturation in these tests.
+// Since that's intentional, we need to shut this warning off.
+#if defined(COMPILER_MSVC)
+#pragma warning(disable : 4756)
+#endif
+
+  int small_positive = 1;
+  int small_negative = -1;
+  double double_small = 1.0;
+  double double_large = numeric_limits<double>::max();
+  double double_infinity = numeric_limits<float>::infinity();
+  double double_large_int = numeric_limits<int>::max();
+  double double_small_int = numeric_limits<int>::min();
+
+  // Just test that the casts compile, since the other tests cover logic.
+  EXPECT_EQ(0, checked_cast<int>(static_cast<size_t>(0)));
+  EXPECT_EQ(0, strict_cast<int>(static_cast<char>(0)));
+  EXPECT_EQ(0, strict_cast<int>(static_cast<unsigned char>(0)));
+  EXPECT_EQ(0U, strict_cast<unsigned>(static_cast<unsigned char>(0)));
+  EXPECT_EQ(1ULL, static_cast<uint64_t>(StrictNumeric<size_t>(1U)));
+  EXPECT_EQ(1ULL, static_cast<uint64_t>(SizeT(1U)));
+  EXPECT_EQ(1U, static_cast<size_t>(StrictNumeric<unsigned>(1U)));
+
+  EXPECT_TRUE(CheckedNumeric<uint64_t>(StrictNumeric<unsigned>(1U)).IsValid());
+  EXPECT_TRUE(CheckedNumeric<int>(StrictNumeric<unsigned>(1U)).IsValid());
+  EXPECT_FALSE(CheckedNumeric<unsigned>(StrictNumeric<int>(-1)).IsValid());
+
+  // These casts and coercions will fail to compile:
+  // EXPECT_EQ(0, strict_cast<int>(static_cast<size_t>(0)));
+  // EXPECT_EQ(0, strict_cast<size_t>(static_cast<int>(0)));
+  // EXPECT_EQ(1ULL, StrictNumeric<size_t>(1));
+  // EXPECT_EQ(1, StrictNumeric<size_t>(1U));
+
+  // Test various saturation corner cases.
+  EXPECT_EQ(saturated_cast<int>(small_negative),
+            static_cast<int>(small_negative));
+  EXPECT_EQ(saturated_cast<int>(small_positive),
+            static_cast<int>(small_positive));
+  EXPECT_EQ(saturated_cast<unsigned>(small_negative),
+            static_cast<unsigned>(0));
+  EXPECT_EQ(saturated_cast<int>(double_small),
+            static_cast<int>(double_small));
+  EXPECT_EQ(saturated_cast<int>(double_large), numeric_limits<int>::max());
+  EXPECT_EQ(saturated_cast<float>(double_large), double_infinity);
+  EXPECT_EQ(saturated_cast<float>(-double_large), -double_infinity);
+  EXPECT_EQ(numeric_limits<int>::min(), saturated_cast<int>(double_small_int));
+  EXPECT_EQ(numeric_limits<int>::max(), saturated_cast<int>(double_large_int));
+}
+
diff --git a/base/observer_list.h b/base/observer_list.h
new file mode 100644
index 0000000..a454430
--- /dev/null
+++ b/base/observer_list.h
@@ -0,0 +1,247 @@
+// Copyright (c) 2011 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_OBSERVER_LIST_H_
+#define BASE_OBSERVER_LIST_H_
+
+#include <algorithm>
+#include <limits>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/memory/weak_ptr.h"
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// OVERVIEW:
+//
+//   A container for a list of observers.  Unlike a normal STL vector or list,
+//   this container can be modified during iteration without invalidating the
+//   iterator.  So, it safely handles the case of an observer removing itself
+//   or other observers from the list while observers are being notified.
+//
+// TYPICAL USAGE:
+//
+//   class MyWidget {
+//    public:
+//     ...
+//
+//     class Observer {
+//      public:
+//       virtual void OnFoo(MyWidget* w) = 0;
+//       virtual void OnBar(MyWidget* w, int x, int y) = 0;
+//     };
+//
+//     void AddObserver(Observer* obs) {
+//       observer_list_.AddObserver(obs);
+//     }
+//
+//     void RemoveObserver(Observer* obs) {
+//       observer_list_.RemoveObserver(obs);
+//     }
+//
+//     void NotifyFoo() {
+//       FOR_EACH_OBSERVER(Observer, observer_list_, OnFoo(this));
+//     }
+//
+//     void NotifyBar(int x, int y) {
+//       FOR_EACH_OBSERVER(Observer, observer_list_, OnBar(this, x, y));
+//     }
+//
+//    private:
+//     base::ObserverList<Observer> observer_list_;
+//   };
+//
+//
+///////////////////////////////////////////////////////////////////////////////
+
+namespace base {
+
+template <typename ObserverType>
+class ObserverListThreadSafe;
+
+template <class ObserverType>
+class ObserverListBase
+    : public SupportsWeakPtr<ObserverListBase<ObserverType>> {
+ public:
+  // Enumeration of which observers are notified.
+  enum NotificationType {
+    // Specifies that any observers added during notification are notified.
+    // This is the default type if non type is provided to the constructor.
+    NOTIFY_ALL,
+
+    // Specifies that observers added while sending out notification are not
+    // notified.
+    NOTIFY_EXISTING_ONLY
+  };
+
+  // An iterator class that can be used to access the list of observers.  See
+  // also the FOR_EACH_OBSERVER macro defined below.
+  class Iterator {
+   public:
+    explicit Iterator(ObserverListBase<ObserverType>* list);
+    ~Iterator();
+    ObserverType* GetNext();
+
+   private:
+    WeakPtr<ObserverListBase<ObserverType>> list_;
+    size_t index_;
+    size_t max_index_;
+  };
+
+  ObserverListBase() : notify_depth_(0), type_(NOTIFY_ALL) {}
+  explicit ObserverListBase(NotificationType type)
+      : notify_depth_(0), type_(type) {}
+
+  // Add an observer to the list.  An observer should not be added to
+  // the same list more than once.
+  void AddObserver(ObserverType* obs);
+
+  // Remove an observer from the list if it is in the list.
+  void RemoveObserver(ObserverType* obs);
+
+  // Determine whether a particular observer is in the list.
+  bool HasObserver(const ObserverType* observer) const;
+
+  void Clear();
+
+ protected:
+  size_t size() const { return observers_.size(); }
+
+  void Compact();
+
+ private:
+  friend class ObserverListThreadSafe<ObserverType>;
+
+  typedef std::vector<ObserverType*> ListType;
+
+  ListType observers_;
+  int notify_depth_;
+  NotificationType type_;
+
+  friend class ObserverListBase::Iterator;
+
+  DISALLOW_COPY_AND_ASSIGN(ObserverListBase);
+};
+
+template <class ObserverType>
+ObserverListBase<ObserverType>::Iterator::Iterator(
+    ObserverListBase<ObserverType>* list)
+    : list_(list->AsWeakPtr()),
+      index_(0),
+      max_index_(list->type_ == NOTIFY_ALL ? std::numeric_limits<size_t>::max()
+                                           : list->observers_.size()) {
+  ++list_->notify_depth_;
+}
+
+template <class ObserverType>
+ObserverListBase<ObserverType>::Iterator::~Iterator() {
+  if (list_.get() && --list_->notify_depth_ == 0)
+    list_->Compact();
+}
+
+template <class ObserverType>
+ObserverType* ObserverListBase<ObserverType>::Iterator::GetNext() {
+  if (!list_.get())
+    return nullptr;
+  ListType& observers = list_->observers_;
+  // Advance if the current element is null
+  size_t max_index = std::min(max_index_, observers.size());
+  while (index_ < max_index && !observers[index_])
+    ++index_;
+  return index_ < max_index ? observers[index_++] : nullptr;
+}
+
+template <class ObserverType>
+void ObserverListBase<ObserverType>::AddObserver(ObserverType* obs) {
+  DCHECK(obs);
+  if (std::find(observers_.begin(), observers_.end(), obs)
+      != observers_.end()) {
+    NOTREACHED() << "Observers can only be added once!";
+    return;
+  }
+  observers_.push_back(obs);
+}
+
+template <class ObserverType>
+void ObserverListBase<ObserverType>::RemoveObserver(ObserverType* obs) {
+  DCHECK(obs);
+  typename ListType::iterator it =
+    std::find(observers_.begin(), observers_.end(), obs);
+  if (it != observers_.end()) {
+    if (notify_depth_) {
+      *it = nullptr;
+    } else {
+      observers_.erase(it);
+    }
+  }
+}
+
+template <class ObserverType>
+bool ObserverListBase<ObserverType>::HasObserver(
+    const ObserverType* observer) const {
+  for (size_t i = 0; i < observers_.size(); ++i) {
+    if (observers_[i] == observer)
+      return true;
+  }
+  return false;
+}
+
+template <class ObserverType>
+void ObserverListBase<ObserverType>::Clear() {
+  if (notify_depth_) {
+    for (typename ListType::iterator it = observers_.begin();
+      it != observers_.end(); ++it) {
+      *it = nullptr;
+    }
+  } else {
+    observers_.clear();
+  }
+}
+
+template <class ObserverType>
+void ObserverListBase<ObserverType>::Compact() {
+  observers_.erase(
+      std::remove(observers_.begin(), observers_.end(), nullptr),
+      observers_.end());
+}
+
+template <class ObserverType, bool check_empty = false>
+class ObserverList : public ObserverListBase<ObserverType> {
+ public:
+  typedef typename ObserverListBase<ObserverType>::NotificationType
+      NotificationType;
+
+  ObserverList() {}
+  explicit ObserverList(NotificationType type)
+      : ObserverListBase<ObserverType>(type) {}
+
+  ~ObserverList() {
+    // When check_empty is true, assert that the list is empty on destruction.
+    if (check_empty) {
+      ObserverListBase<ObserverType>::Compact();
+      DCHECK_EQ(ObserverListBase<ObserverType>::size(), 0U);
+    }
+  }
+
+  bool might_have_observers() const {
+    return ObserverListBase<ObserverType>::size() != 0;
+  }
+};
+
+#define FOR_EACH_OBSERVER(ObserverType, observer_list, func)             \
+  do {                                                                   \
+    if ((observer_list).might_have_observers()) {                        \
+      base::ObserverListBase<ObserverType>::Iterator it_inside_observer_macro( \
+          &observer_list);                                               \
+      ObserverType* obs;                                                 \
+      while ((obs = it_inside_observer_macro.GetNext()) != nullptr)      \
+        obs->func;                                                       \
+    }                                                                    \
+  } while (0)
+
+}  // namespace base
+
+#endif  // BASE_OBSERVER_LIST_H_
diff --git a/base/observer_list_threadsafe.h b/base/observer_list_threadsafe.h
new file mode 100644
index 0000000..b9b4a62
--- /dev/null
+++ b/base/observer_list_threadsafe.h
@@ -0,0 +1,273 @@
+// Copyright (c) 2012 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_OBSERVER_LIST_THREADSAFE_H_
+#define BASE_OBSERVER_LIST_THREADSAFE_H_
+
+#include <algorithm>
+#include <map>
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop/message_loop.h"
+#include "base/observer_list.h"
+#include "base/single_thread_task_runner.h"
+#include "base/stl_util.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/platform_thread.h"
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// OVERVIEW:
+//
+//   A thread-safe container for a list of observers.
+//   This is similar to the observer_list (see observer_list.h), but it
+//   is more robust for multi-threaded situations.
+//
+//   The following use cases are supported:
+//    * Observers can register for notifications from any thread.
+//      Callbacks to the observer will occur on the same thread where
+//      the observer initially called AddObserver() from.
+//    * Any thread may trigger a notification via Notify().
+//    * Observers can remove themselves from the observer list inside
+//      of a callback.
+//    * If one thread is notifying observers concurrently with an observer
+//      removing itself from the observer list, the notifications will
+//      be silently dropped.
+//
+//   The drawback of the threadsafe observer list is that notifications
+//   are not as real-time as the non-threadsafe version of this class.
+//   Notifications will always be done via PostTask() to another thread,
+//   whereas with the non-thread-safe observer_list, notifications happen
+//   synchronously and immediately.
+//
+//   IMPLEMENTATION NOTES
+//   The ObserverListThreadSafe maintains an ObserverList for each thread
+//   which uses the ThreadSafeObserver.  When Notifying the observers,
+//   we simply call PostTask to each registered thread, and then each thread
+//   will notify its regular ObserverList.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+namespace base {
+
+// Forward declaration for ObserverListThreadSafeTraits.
+template <class ObserverType>
+class ObserverListThreadSafe;
+
+namespace internal {
+
+// An UnboundMethod is a wrapper for a method where the actual object is
+// provided at Run dispatch time.
+template <class T, class Method, class Params>
+class UnboundMethod {
+ public:
+  UnboundMethod(Method m, const Params& p) : m_(m), p_(p) {
+    COMPILE_ASSERT(
+        (internal::ParamsUseScopedRefptrCorrectly<Params>::value),
+        badunboundmethodparams);
+  }
+  void Run(T* obj) const {
+    DispatchToMethod(obj, m_, p_);
+  }
+ private:
+  Method m_;
+  Params p_;
+};
+
+}  // namespace internal
+
+// This class is used to work around VS2005 not accepting:
+//
+// friend class
+//     base::RefCountedThreadSafe<ObserverListThreadSafe<ObserverType>>;
+//
+// Instead of friending the class, we could friend the actual function
+// which calls delete.  However, this ends up being
+// RefCountedThreadSafe::DeleteInternal(), which is private.  So we
+// define our own templated traits class so we can friend it.
+template <class T>
+struct ObserverListThreadSafeTraits {
+  static void Destruct(const ObserverListThreadSafe<T>* x) {
+    delete x;
+  }
+};
+
+template <class ObserverType>
+class ObserverListThreadSafe
+    : public RefCountedThreadSafe<
+        ObserverListThreadSafe<ObserverType>,
+        ObserverListThreadSafeTraits<ObserverType>> {
+ public:
+  typedef typename ObserverList<ObserverType>::NotificationType
+      NotificationType;
+
+  ObserverListThreadSafe()
+      : type_(ObserverListBase<ObserverType>::NOTIFY_ALL) {}
+  explicit ObserverListThreadSafe(NotificationType type) : type_(type) {}
+
+  // Add an observer to the list.  An observer should not be added to
+  // the same list more than once.
+  void AddObserver(ObserverType* obs) {
+    // If there is not a current MessageLoop, it is impossible to notify on it,
+    // so do not add the observer.
+    if (!MessageLoop::current())
+      return;
+
+    ObserverList<ObserverType>* list = nullptr;
+    PlatformThreadId thread_id = PlatformThread::CurrentId();
+    {
+      AutoLock lock(list_lock_);
+      if (observer_lists_.find(thread_id) == observer_lists_.end())
+        observer_lists_[thread_id] = new ObserverListContext(type_);
+      list = &(observer_lists_[thread_id]->list);
+    }
+    list->AddObserver(obs);
+  }
+
+  // Remove an observer from the list if it is in the list.
+  // If there are pending notifications in-transit to the observer, they will
+  // be aborted.
+  // If the observer to be removed is in the list, RemoveObserver MUST
+  // be called from the same thread which called AddObserver.
+  void RemoveObserver(ObserverType* obs) {
+    ObserverListContext* context = nullptr;
+    ObserverList<ObserverType>* list = nullptr;
+    PlatformThreadId thread_id = PlatformThread::CurrentId();
+    {
+      AutoLock lock(list_lock_);
+      typename ObserversListMap::iterator it = observer_lists_.find(thread_id);
+      if (it == observer_lists_.end()) {
+        // This will happen if we try to remove an observer on a thread
+        // we never added an observer for.
+        return;
+      }
+      context = it->second;
+      list = &context->list;
+
+      // If we're about to remove the last observer from the list,
+      // then we can remove this observer_list entirely.
+      if (list->HasObserver(obs) && list->size() == 1)
+        observer_lists_.erase(it);
+    }
+    list->RemoveObserver(obs);
+
+    // If RemoveObserver is called from a notification, the size will be
+    // nonzero.  Instead of deleting here, the NotifyWrapper will delete
+    // when it finishes iterating.
+    if (list->size() == 0)
+      delete context;
+  }
+
+  // Verifies that the list is currently empty (i.e. there are no observers).
+  void AssertEmpty() const {
+    AutoLock lock(list_lock_);
+    DCHECK(observer_lists_.empty());
+  }
+
+  // Notify methods.
+  // Make a thread-safe callback to each Observer in the list.
+  // Note, these calls are effectively asynchronous.  You cannot assume
+  // that at the completion of the Notify call that all Observers have
+  // been Notified.  The notification may still be pending delivery.
+  template <class Method, class... Params>
+  void Notify(const tracked_objects::Location& from_here,
+              Method m,
+              const Params&... params) {
+    internal::UnboundMethod<ObserverType, Method, Tuple<Params...>> method(
+        m, MakeTuple(params...));
+
+    AutoLock lock(list_lock_);
+    for (const auto& entry : observer_lists_) {
+      ObserverListContext* context = entry.second;
+      context->task_runner->PostTask(
+          from_here,
+          Bind(&ObserverListThreadSafe<ObserverType>::template NotifyWrapper<
+                  Method, Tuple<Params...>>,
+              this, context, method));
+    }
+  }
+
+ private:
+  // See comment above ObserverListThreadSafeTraits' definition.
+  friend struct ObserverListThreadSafeTraits<ObserverType>;
+
+  struct ObserverListContext {
+    explicit ObserverListContext(NotificationType type)
+        : task_runner(ThreadTaskRunnerHandle::Get()), list(type) {}
+
+    scoped_refptr<SingleThreadTaskRunner> task_runner;
+    ObserverList<ObserverType> list;
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(ObserverListContext);
+  };
+
+  ~ObserverListThreadSafe() {
+    STLDeleteValues(&observer_lists_);
+  }
+
+  // Wrapper which is called to fire the notifications for each thread's
+  // ObserverList.  This function MUST be called on the thread which owns
+  // the unsafe ObserverList.
+  template <class Method, class Params>
+  void NotifyWrapper(
+      ObserverListContext* context,
+      const internal::UnboundMethod<ObserverType, Method, Params>& method) {
+    // Check that this list still needs notifications.
+    {
+      AutoLock lock(list_lock_);
+      typename ObserversListMap::iterator it =
+          observer_lists_.find(PlatformThread::CurrentId());
+
+      // The ObserverList could have been removed already.  In fact, it could
+      // have been removed and then re-added!  If the master list's loop
+      // does not match this one, then we do not need to finish this
+      // notification.
+      if (it == observer_lists_.end() || it->second != context)
+        return;
+    }
+
+    {
+      typename ObserverList<ObserverType>::Iterator it(&context->list);
+      ObserverType* obs;
+      while ((obs = it.GetNext()) != nullptr)
+        method.Run(obs);
+    }
+
+    // If there are no more observers on the list, we can now delete it.
+    if (context->list.size() == 0) {
+      {
+        AutoLock lock(list_lock_);
+        // Remove |list| if it's not already removed.
+        // This can happen if multiple observers got removed in a notification.
+        // See http://crbug.com/55725.
+        typename ObserversListMap::iterator it =
+            observer_lists_.find(PlatformThread::CurrentId());
+        if (it != observer_lists_.end() && it->second == context)
+          observer_lists_.erase(it);
+      }
+      delete context;
+    }
+  }
+
+  // Key by PlatformThreadId because in tests, clients can attempt to remove
+  // observers without a MessageLoop. If this were keyed by MessageLoop, that
+  // operation would be silently ignored, leaving garbage in the ObserverList.
+  typedef std::map<PlatformThreadId, ObserverListContext*>
+      ObserversListMap;
+
+  mutable Lock list_lock_;  // Protects the observer_lists_.
+  ObserversListMap observer_lists_;
+  const NotificationType type_;
+
+  DISALLOW_COPY_AND_ASSIGN(ObserverListThreadSafe);
+};
+
+}  // namespace base
+
+#endif  // BASE_OBSERVER_LIST_THREADSAFE_H_
diff --git a/base/observer_list_unittest.cc b/base/observer_list_unittest.cc
new file mode 100644
index 0000000..2e51e45
--- /dev/null
+++ b/base/observer_list_unittest.cc
@@ -0,0 +1,545 @@
+// Copyright (c) 2012 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/observer_list.h"
+#include "base/observer_list_threadsafe.h"
+
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/location.h"
+#include "base/memory/weak_ptr.h"
+#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/platform_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+class Foo {
+ public:
+  virtual void Observe(int x) = 0;
+  virtual ~Foo() {}
+};
+
+class Adder : public Foo {
+ public:
+  explicit Adder(int scaler) : total(0), scaler_(scaler) {}
+  void Observe(int x) override { total += x * scaler_; }
+  ~Adder() override {}
+  int total;
+
+ private:
+  int scaler_;
+};
+
+class Disrupter : public Foo {
+ public:
+  Disrupter(ObserverList<Foo>* list, Foo* doomed)
+      : list_(list),
+        doomed_(doomed) {
+  }
+  ~Disrupter() override {}
+  void Observe(int x) override { list_->RemoveObserver(doomed_); }
+
+ private:
+  ObserverList<Foo>* list_;
+  Foo* doomed_;
+};
+
+class ThreadSafeDisrupter : public Foo {
+ public:
+  ThreadSafeDisrupter(ObserverListThreadSafe<Foo>* list, Foo* doomed)
+      : list_(list),
+        doomed_(doomed) {
+  }
+  ~ThreadSafeDisrupter() override {}
+  void Observe(int x) override { list_->RemoveObserver(doomed_); }
+
+ private:
+  ObserverListThreadSafe<Foo>* list_;
+  Foo* doomed_;
+};
+
+template <typename ObserverListType>
+class AddInObserve : public Foo {
+ public:
+  explicit AddInObserve(ObserverListType* observer_list)
+      : added(false),
+        observer_list(observer_list),
+        adder(1) {
+  }
+
+  void Observe(int x) override {
+    if (!added) {
+      added = true;
+      observer_list->AddObserver(&adder);
+    }
+  }
+
+  bool added;
+  ObserverListType* observer_list;
+  Adder adder;
+};
+
+
+static const int kThreadRunTime = 2000;  // ms to run the multi-threaded test.
+
+// A thread for use in the ThreadSafeObserver test
+// which will add and remove itself from the notification
+// list repeatedly.
+class AddRemoveThread : public PlatformThread::Delegate,
+                        public Foo {
+ public:
+  AddRemoveThread(ObserverListThreadSafe<Foo>* list, bool notify)
+      : list_(list),
+        loop_(nullptr),
+        in_list_(false),
+        start_(Time::Now()),
+        count_observes_(0),
+        count_addtask_(0),
+        do_notifies_(notify),
+        weak_factory_(this) {
+  }
+
+  ~AddRemoveThread() override {}
+
+  void ThreadMain() override {
+    loop_ = new MessageLoop();  // Fire up a message loop.
+    loop_->task_runner()->PostTask(
+        FROM_HERE,
+        base::Bind(&AddRemoveThread::AddTask, weak_factory_.GetWeakPtr()));
+    loop_->Run();
+    //LOG(ERROR) << "Loop 0x" << std::hex << loop_ << " done. " <<
+    //    count_observes_ << ", " << count_addtask_;
+    delete loop_;
+    loop_ = reinterpret_cast<MessageLoop*>(0xdeadbeef);
+    delete this;
+  }
+
+  // This task just keeps posting to itself in an attempt
+  // to race with the notifier.
+  void AddTask() {
+    count_addtask_++;
+
+    if ((Time::Now() - start_).InMilliseconds() > kThreadRunTime) {
+      VLOG(1) << "DONE!";
+      return;
+    }
+
+    if (!in_list_) {
+      list_->AddObserver(this);
+      in_list_ = true;
+    }
+
+    if (do_notifies_) {
+      list_->Notify(FROM_HERE, &Foo::Observe, 10);
+    }
+
+    loop_->task_runner()->PostTask(
+        FROM_HERE,
+        base::Bind(&AddRemoveThread::AddTask, weak_factory_.GetWeakPtr()));
+  }
+
+  void Quit() {
+    loop_->task_runner()->PostTask(FROM_HERE,
+                                   MessageLoop::QuitWhenIdleClosure());
+  }
+
+  void Observe(int x) override {
+    count_observes_++;
+
+    // If we're getting called after we removed ourselves from
+    // the list, that is very bad!
+    DCHECK(in_list_);
+
+    // This callback should fire on the appropriate thread
+    EXPECT_EQ(loop_, MessageLoop::current());
+
+    list_->RemoveObserver(this);
+    in_list_ = false;
+  }
+
+ private:
+  ObserverListThreadSafe<Foo>* list_;
+  MessageLoop* loop_;
+  bool in_list_;        // Are we currently registered for notifications.
+                        // in_list_ is only used on |this| thread.
+  Time start_;          // The time we started the test.
+
+  int count_observes_;  // Number of times we observed.
+  int count_addtask_;   // Number of times thread AddTask was called
+  bool do_notifies_;    // Whether these threads should do notifications.
+
+  base::WeakPtrFactory<AddRemoveThread> weak_factory_;
+};
+
+TEST(ObserverListTest, BasicTest) {
+  ObserverList<Foo> observer_list;
+  Adder a(1), b(-1), c(1), d(-1), e(-1);
+  Disrupter evil(&observer_list, &c);
+
+  observer_list.AddObserver(&a);
+  observer_list.AddObserver(&b);
+
+  EXPECT_TRUE(observer_list.HasObserver(&a));
+  EXPECT_FALSE(observer_list.HasObserver(&c));
+
+  FOR_EACH_OBSERVER(Foo, observer_list, Observe(10));
+
+  observer_list.AddObserver(&evil);
+  observer_list.AddObserver(&c);
+  observer_list.AddObserver(&d);
+
+  // Removing an observer not in the list should do nothing.
+  observer_list.RemoveObserver(&e);
+
+  FOR_EACH_OBSERVER(Foo, observer_list, Observe(10));
+
+  EXPECT_EQ(20, a.total);
+  EXPECT_EQ(-20, b.total);
+  EXPECT_EQ(0, c.total);
+  EXPECT_EQ(-10, d.total);
+  EXPECT_EQ(0, e.total);
+}
+
+TEST(ObserverListThreadSafeTest, BasicTest) {
+  MessageLoop loop;
+
+  scoped_refptr<ObserverListThreadSafe<Foo> > observer_list(
+      new ObserverListThreadSafe<Foo>);
+  Adder a(1);
+  Adder b(-1);
+  Adder c(1);
+  Adder d(-1);
+  ThreadSafeDisrupter evil(observer_list.get(), &c);
+
+  observer_list->AddObserver(&a);
+  observer_list->AddObserver(&b);
+
+  observer_list->Notify(FROM_HERE, &Foo::Observe, 10);
+  RunLoop().RunUntilIdle();
+
+  observer_list->AddObserver(&evil);
+  observer_list->AddObserver(&c);
+  observer_list->AddObserver(&d);
+
+  observer_list->Notify(FROM_HERE, &Foo::Observe, 10);
+  RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(20, a.total);
+  EXPECT_EQ(-20, b.total);
+  EXPECT_EQ(0, c.total);
+  EXPECT_EQ(-10, d.total);
+}
+
+TEST(ObserverListThreadSafeTest, RemoveObserver) {
+  MessageLoop loop;
+
+  scoped_refptr<ObserverListThreadSafe<Foo> > observer_list(
+      new ObserverListThreadSafe<Foo>);
+  Adder a(1), b(1);
+
+  // A workaround for the compiler bug. See http://crbug.com/121960.
+  EXPECT_NE(&a, &b);
+
+  // Should do nothing.
+  observer_list->RemoveObserver(&a);
+  observer_list->RemoveObserver(&b);
+
+  observer_list->Notify(FROM_HERE, &Foo::Observe, 10);
+  RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(0, a.total);
+  EXPECT_EQ(0, b.total);
+
+  observer_list->AddObserver(&a);
+
+  // Should also do nothing.
+  observer_list->RemoveObserver(&b);
+
+  observer_list->Notify(FROM_HERE, &Foo::Observe, 10);
+  RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(10, a.total);
+  EXPECT_EQ(0, b.total);
+}
+
+TEST(ObserverListThreadSafeTest, WithoutMessageLoop) {
+  scoped_refptr<ObserverListThreadSafe<Foo> > observer_list(
+      new ObserverListThreadSafe<Foo>);
+
+  Adder a(1), b(1), c(1);
+
+  // No MessageLoop, so these should not be added.
+  observer_list->AddObserver(&a);
+  observer_list->AddObserver(&b);
+
+  {
+    // Add c when there's a loop.
+    MessageLoop loop;
+    observer_list->AddObserver(&c);
+
+    observer_list->Notify(FROM_HERE, &Foo::Observe, 10);
+    RunLoop().RunUntilIdle();
+
+    EXPECT_EQ(0, a.total);
+    EXPECT_EQ(0, b.total);
+    EXPECT_EQ(10, c.total);
+
+    // Now add a when there's a loop.
+    observer_list->AddObserver(&a);
+
+    // Remove c when there's a loop.
+    observer_list->RemoveObserver(&c);
+
+    // Notify again.
+    observer_list->Notify(FROM_HERE, &Foo::Observe, 20);
+    RunLoop().RunUntilIdle();
+
+    EXPECT_EQ(20, a.total);
+    EXPECT_EQ(0, b.total);
+    EXPECT_EQ(10, c.total);
+  }
+
+  // Removing should always succeed with or without a loop.
+  observer_list->RemoveObserver(&a);
+
+  // Notifying should not fail but should also be a no-op.
+  MessageLoop loop;
+  observer_list->AddObserver(&b);
+  observer_list->Notify(FROM_HERE, &Foo::Observe, 30);
+  RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(20, a.total);
+  EXPECT_EQ(30, b.total);
+  EXPECT_EQ(10, c.total);
+}
+
+class FooRemover : public Foo {
+ public:
+  explicit FooRemover(ObserverListThreadSafe<Foo>* list) : list_(list) {}
+  ~FooRemover() override {}
+
+  void AddFooToRemove(Foo* foo) {
+    foos_.push_back(foo);
+  }
+
+  void Observe(int x) override {
+    std::vector<Foo*> tmp;
+    tmp.swap(foos_);
+    for (std::vector<Foo*>::iterator it = tmp.begin();
+         it != tmp.end(); ++it) {
+      list_->RemoveObserver(*it);
+    }
+  }
+
+ private:
+  const scoped_refptr<ObserverListThreadSafe<Foo> > list_;
+  std::vector<Foo*> foos_;
+};
+
+TEST(ObserverListThreadSafeTest, RemoveMultipleObservers) {
+  MessageLoop loop;
+  scoped_refptr<ObserverListThreadSafe<Foo> > observer_list(
+      new ObserverListThreadSafe<Foo>);
+
+  FooRemover a(observer_list.get());
+  Adder b(1);
+
+  observer_list->AddObserver(&a);
+  observer_list->AddObserver(&b);
+
+  a.AddFooToRemove(&a);
+  a.AddFooToRemove(&b);
+
+  observer_list->Notify(FROM_HERE, &Foo::Observe, 1);
+  RunLoop().RunUntilIdle();
+}
+
+// A test driver for a multi-threaded notification loop.  Runs a number
+// of observer threads, each of which constantly adds/removes itself
+// from the observer list.  Optionally, if cross_thread_notifies is set
+// to true, the observer threads will also trigger notifications to
+// all observers.
+static void ThreadSafeObserverHarness(int num_threads,
+                                      bool cross_thread_notifies) {
+  MessageLoop loop;
+
+  const int kMaxThreads = 15;
+  num_threads = num_threads > kMaxThreads ? kMaxThreads : num_threads;
+
+  scoped_refptr<ObserverListThreadSafe<Foo> > observer_list(
+      new ObserverListThreadSafe<Foo>);
+  Adder a(1);
+  Adder b(-1);
+  Adder c(1);
+  Adder d(-1);
+
+  observer_list->AddObserver(&a);
+  observer_list->AddObserver(&b);
+
+  AddRemoveThread* threaded_observer[kMaxThreads];
+  base::PlatformThreadHandle threads[kMaxThreads];
+  for (int index = 0; index < num_threads; index++) {
+    threaded_observer[index] = new AddRemoveThread(observer_list.get(), false);
+    EXPECT_TRUE(PlatformThread::Create(0,
+                threaded_observer[index], &threads[index]));
+  }
+
+  Time start = Time::Now();
+  while (true) {
+    if ((Time::Now() - start).InMilliseconds() > kThreadRunTime)
+      break;
+
+    observer_list->Notify(FROM_HERE, &Foo::Observe, 10);
+
+    RunLoop().RunUntilIdle();
+  }
+
+  for (int index = 0; index < num_threads; index++) {
+    threaded_observer[index]->Quit();
+    PlatformThread::Join(threads[index]);
+  }
+}
+
+TEST(ObserverListThreadSafeTest, CrossThreadObserver) {
+  // Use 7 observer threads.  Notifications only come from
+  // the main thread.
+  ThreadSafeObserverHarness(7, false);
+}
+
+TEST(ObserverListThreadSafeTest, CrossThreadNotifications) {
+  // Use 3 observer threads.  Notifications will fire from
+  // the main thread and all 3 observer threads.
+  ThreadSafeObserverHarness(3, true);
+}
+
+TEST(ObserverListThreadSafeTest, OutlivesMessageLoop) {
+  MessageLoop* loop = new MessageLoop;
+  scoped_refptr<ObserverListThreadSafe<Foo> > observer_list(
+      new ObserverListThreadSafe<Foo>);
+
+  Adder a(1);
+  observer_list->AddObserver(&a);
+  delete loop;
+  // Test passes if we don't crash here.
+  observer_list->Notify(FROM_HERE, &Foo::Observe, 1);
+}
+
+TEST(ObserverListTest, Existing) {
+  ObserverList<Foo> observer_list(ObserverList<Foo>::NOTIFY_EXISTING_ONLY);
+  Adder a(1);
+  AddInObserve<ObserverList<Foo> > b(&observer_list);
+
+  observer_list.AddObserver(&a);
+  observer_list.AddObserver(&b);
+
+  FOR_EACH_OBSERVER(Foo, observer_list, Observe(1));
+
+  EXPECT_TRUE(b.added);
+  // B's adder should not have been notified because it was added during
+  // notification.
+  EXPECT_EQ(0, b.adder.total);
+
+  // Notify again to make sure b's adder is notified.
+  FOR_EACH_OBSERVER(Foo, observer_list, Observe(1));
+  EXPECT_EQ(1, b.adder.total);
+}
+
+// Same as above, but for ObserverListThreadSafe
+TEST(ObserverListThreadSafeTest, Existing) {
+  MessageLoop loop;
+  scoped_refptr<ObserverListThreadSafe<Foo> > observer_list(
+      new ObserverListThreadSafe<Foo>(ObserverList<Foo>::NOTIFY_EXISTING_ONLY));
+  Adder a(1);
+  AddInObserve<ObserverListThreadSafe<Foo> > b(observer_list.get());
+
+  observer_list->AddObserver(&a);
+  observer_list->AddObserver(&b);
+
+  observer_list->Notify(FROM_HERE, &Foo::Observe, 1);
+  RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(b.added);
+  // B's adder should not have been notified because it was added during
+  // notification.
+  EXPECT_EQ(0, b.adder.total);
+
+  // Notify again to make sure b's adder is notified.
+  observer_list->Notify(FROM_HERE, &Foo::Observe, 1);
+  RunLoop().RunUntilIdle();
+  EXPECT_EQ(1, b.adder.total);
+}
+
+class AddInClearObserve : public Foo {
+ public:
+  explicit AddInClearObserve(ObserverList<Foo>* list)
+      : list_(list), added_(false), adder_(1) {}
+
+  void Observe(int /* x */) override {
+    list_->Clear();
+    list_->AddObserver(&adder_);
+    added_ = true;
+  }
+
+  bool added() const { return added_; }
+  const Adder& adder() const { return adder_; }
+
+ private:
+  ObserverList<Foo>* const list_;
+
+  bool added_;
+  Adder adder_;
+};
+
+TEST(ObserverListTest, ClearNotifyAll) {
+  ObserverList<Foo> observer_list;
+  AddInClearObserve a(&observer_list);
+
+  observer_list.AddObserver(&a);
+
+  FOR_EACH_OBSERVER(Foo, observer_list, Observe(1));
+  EXPECT_TRUE(a.added());
+  EXPECT_EQ(1, a.adder().total)
+      << "Adder should observe once and have sum of 1.";
+}
+
+TEST(ObserverListTest, ClearNotifyExistingOnly) {
+  ObserverList<Foo> observer_list(ObserverList<Foo>::NOTIFY_EXISTING_ONLY);
+  AddInClearObserve a(&observer_list);
+
+  observer_list.AddObserver(&a);
+
+  FOR_EACH_OBSERVER(Foo, observer_list, Observe(1));
+  EXPECT_TRUE(a.added());
+  EXPECT_EQ(0, a.adder().total)
+      << "Adder should not observe, so sum should still be 0.";
+}
+
+class ListDestructor : public Foo {
+ public:
+  explicit ListDestructor(ObserverList<Foo>* list) : list_(list) {}
+  ~ListDestructor() override {}
+
+  void Observe(int x) override { delete list_; }
+
+ private:
+  ObserverList<Foo>* list_;
+};
+
+
+TEST(ObserverListTest, IteratorOutlivesList) {
+  ObserverList<Foo>* observer_list = new ObserverList<Foo>;
+  ListDestructor a(observer_list);
+  observer_list->AddObserver(&a);
+
+  FOR_EACH_OBSERVER(Foo, *observer_list, Observe(0));
+  // If this test fails, there'll be Valgrind errors when this function goes out
+  // of scope.
+}
+
+}  // namespace
+}  // namespace base
diff --git a/base/os_compat_android.cc b/base/os_compat_android.cc
new file mode 100644
index 0000000..b2756b2
--- /dev/null
+++ b/base/os_compat_android.cc
@@ -0,0 +1,176 @@
+// Copyright (c) 2012 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/os_compat_android.h"
+
+#include <asm/unistd.h>
+#include <errno.h>
+#include <math.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+
+#if !defined(__LP64__)
+#include <time64.h>
+#endif
+
+#include "base/rand_util.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/stringprintf.h"
+
+extern "C" {
+// There is no futimes() avaiable in Bionic, so we provide our own
+// implementation until it is there.
+int futimes(int fd, const struct timeval tv[2]) {
+  if (tv == NULL)
+    return syscall(__NR_utimensat, fd, NULL, NULL, 0);
+
+  if (tv[0].tv_usec < 0 || tv[0].tv_usec >= 1000000 ||
+      tv[1].tv_usec < 0 || tv[1].tv_usec >= 1000000) {
+    errno = EINVAL;
+    return -1;
+  }
+
+  // Convert timeval to timespec.
+  struct timespec ts[2];
+  ts[0].tv_sec = tv[0].tv_sec;
+  ts[0].tv_nsec = tv[0].tv_usec * 1000;
+  ts[1].tv_sec = tv[1].tv_sec;
+  ts[1].tv_nsec = tv[1].tv_usec * 1000;
+  return syscall(__NR_utimensat, fd, NULL, ts, 0);
+}
+
+#if !defined(__LP64__)
+// 32-bit Android has only timegm64() and not timegm().
+// We replicate the behaviour of timegm() when the result overflows time_t.
+time_t timegm(struct tm* const t) {
+  // time_t is signed on Android.
+  static const time_t kTimeMax = ~(1L << (sizeof(time_t) * CHAR_BIT - 1));
+  static const time_t kTimeMin = (1L << (sizeof(time_t) * CHAR_BIT - 1));
+  time64_t result = timegm64(t);
+  if (result < kTimeMin || result > kTimeMax)
+    return -1;
+  return result;
+}
+#endif
+
+// The following is only needed when building with GCC 4.6 or higher
+// (i.e. not with Android GCC 4.4.3, nor with Clang).
+//
+// GCC is now capable of optimizing successive calls to sin() and cos() into
+// a single call to sincos(). This means that source code that looks like:
+//
+//     double c, s;
+//     c = cos(angle);
+//     s = sin(angle);
+//
+// Will generate machine code that looks like:
+//
+//     double c, s;
+//     sincos(angle, &s, &c);
+//
+// Unfortunately, sincos() and friends are not part of the Android libm.so
+// library provided by the NDK for API level 9. When the optimization kicks
+// in, it makes the final build fail with a puzzling message (puzzling
+// because 'sincos' doesn't appear anywhere in the sources!).
+//
+// To solve this, we provide our own implementation of the sincos() function
+// and related friends. Note that we must also explicitely tell GCC to disable
+// optimizations when generating these. Otherwise, the generated machine code
+// for each function would simply end up calling itself, resulting in a
+// runtime crash due to stack overflow.
+//
+#if defined(__GNUC__) && !defined(__clang__) && \
+    !defined(ANDROID_SINCOS_PROVIDED)
+
+// For the record, Clang does not support the 'optimize' attribute.
+// In the unlikely event that it begins performing this optimization too,
+// we'll have to find a different way to achieve this. NOTE: Tested with O1
+// which still performs the optimization.
+//
+#define GCC_NO_OPTIMIZE  __attribute__((optimize("O0")))
+
+GCC_NO_OPTIMIZE
+void sincos(double angle, double* s, double *c) {
+  *c = cos(angle);
+  *s = sin(angle);
+}
+
+GCC_NO_OPTIMIZE
+void sincosf(float angle, float* s, float* c) {
+  *c = cosf(angle);
+  *s = sinf(angle);
+}
+
+#endif // __GNUC__ && !__clang__
+
+// An implementation of mkdtemp, since it is not exposed by the NDK
+// for native API level 9 that we target.
+//
+// For any changes in the mkdtemp function, you should manually run the unittest
+// OsCompatAndroidTest.DISABLED_TestMkdTemp in your local machine to check if it
+// passes. Please don't enable it, since it creates a directory and may be
+// source of flakyness.
+char* mkdtemp(char* path) {
+  if (path == NULL) {
+    errno = EINVAL;
+    return NULL;
+  }
+
+  const int path_len = strlen(path);
+
+  // The last six characters of 'path' must be XXXXXX.
+  const base::StringPiece kSuffix("XXXXXX");
+  const int kSuffixLen = kSuffix.length();
+  if (!base::StringPiece(path, path_len).ends_with(kSuffix)) {
+    errno = EINVAL;
+    return NULL;
+  }
+
+  // If the path contains a directory, as in /tmp/foo/XXXXXXXX, make sure
+  // that /tmp/foo exists, otherwise we're going to loop a really long
+  // time for nothing below
+  char* dirsep = strrchr(path, '/');
+  if (dirsep != NULL) {
+    struct stat st;
+    int ret;
+
+    *dirsep = '\0';  // Terminating directory path temporarily
+
+    ret = stat(path, &st);
+
+    *dirsep = '/';  // Restoring directory separator
+    if (ret < 0)  // Directory probably does not exist
+      return NULL;
+    if (!S_ISDIR(st.st_mode)) {  // Not a directory
+      errno = ENOTDIR;
+      return NULL;
+    }
+  }
+
+  // Max number of tries using different random suffixes.
+  const int kMaxTries = 100;
+
+  // Now loop until we CAN create a directory by that name or we reach the max
+  // number of tries.
+  for (int i = 0; i < kMaxTries; ++i) {
+    // Fill the suffix XXXXXX with a random string composed of a-z chars.
+    for (int pos = 0; pos < kSuffixLen; ++pos) {
+      char rand_char = static_cast<char>(base::RandInt('a', 'z'));
+      path[path_len - kSuffixLen + pos] = rand_char;
+    }
+    if (mkdir(path, 0700) == 0) {
+      // We just created the directory succesfully.
+      return path;
+    }
+    if (errno != EEXIST) {
+      // The directory doesn't exist, but an error occured
+      return NULL;
+    }
+  }
+
+  // We reached the max number of tries.
+  return NULL;
+}
+
+}  // extern "C"
diff --git a/base/os_compat_android.h b/base/os_compat_android.h
new file mode 100644
index 0000000..0f25444
--- /dev/null
+++ b/base/os_compat_android.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2012 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_OS_COMPAT_ANDROID_H_
+#define BASE_OS_COMPAT_ANDROID_H_
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <utime.h>
+
+// Not implemented in Bionic.
+extern "C" int futimes(int fd, const struct timeval tv[2]);
+
+// Not exposed or implemented in Bionic.
+extern "C" char* mkdtemp(char* path);
+
+// Android has no timegm().
+extern "C" time_t timegm(struct tm* const t);
+
+// The lockf() function is not available on Android; we translate to flock().
+#define F_LOCK LOCK_EX
+#define F_ULOCK LOCK_UN
+inline int lockf(int fd, int cmd, off_t ignored_len) {
+  return flock(fd, cmd);
+}
+
+#endif  // BASE_OS_COMPAT_ANDROID_H_
diff --git a/base/os_compat_android_unittest.cc b/base/os_compat_android_unittest.cc
new file mode 100644
index 0000000..7fbdc6d
--- /dev/null
+++ b/base/os_compat_android_unittest.cc
@@ -0,0 +1,41 @@
+// Copyright (c) 2012 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/os_compat_android.h"
+
+#include "base/files/file_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+typedef testing::Test OsCompatAndroidTest;
+
+// Keep this Unittest DISABLED_ , because it actually creates a directory in the
+// device and it may be source of flakyness. For any changes in the mkdtemp
+// function, you should run this unittest in your local machine to check if it
+// passes.
+TEST_F(OsCompatAndroidTest, DISABLED_TestMkdTemp) {
+  FilePath tmp_dir;
+  EXPECT_TRUE(base::GetTempDir(&tmp_dir));
+
+  // Not six XXXXXX at the suffix of the path.
+  FilePath sub_dir = tmp_dir.Append("XX");
+  std::string sub_dir_string = sub_dir.value();
+  // this should be OK since mkdtemp just replaces characters in place
+  char* buffer = const_cast<char*>(sub_dir_string.c_str());
+  EXPECT_EQ(NULL, mkdtemp(buffer));
+
+  // Directory does not exist
+  char invalid_path2[] = "doesntoexist/foobarXXXXXX";
+  EXPECT_EQ(NULL, mkdtemp(invalid_path2));
+
+  // Successfully create a tmp dir.
+  FilePath sub_dir2 = tmp_dir.Append("XXXXXX");
+  std::string sub_dir2_string = sub_dir2.value();
+  // this should be OK since mkdtemp just replaces characters in place
+  char* buffer2 = const_cast<char*>(sub_dir2_string.c_str());
+  EXPECT_TRUE(mkdtemp(buffer2) != NULL);
+}
+
+}  // namespace base
diff --git a/base/os_compat_nacl.cc b/base/os_compat_nacl.cc
new file mode 100644
index 0000000..58fe93e
--- /dev/null
+++ b/base/os_compat_nacl.cc
@@ -0,0 +1,30 @@
+// Copyright (c) 2012 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/os_compat_nacl.h"
+
+#include <stdlib.h>
+#include <time.h>
+
+#if !defined (__GLIBC__)
+
+extern "C" {
+// Native Client has no timegm().
+time_t timegm(struct tm* tm) {
+  time_t ret;
+  char* tz;
+  tz = getenv("TZ");
+  setenv("TZ", "", 1);
+  tzset();
+  ret = mktime(tm);
+  if (tz)
+    setenv("TZ", tz, 1);
+  else
+    unsetenv("TZ");
+  tzset();
+  return ret;
+}
+}  // extern "C"
+
+#endif  // !defined (__GLIBC__)
diff --git a/base/os_compat_nacl.h b/base/os_compat_nacl.h
new file mode 100644
index 0000000..13e0e3f
--- /dev/null
+++ b/base/os_compat_nacl.h
@@ -0,0 +1,16 @@
+// Copyright (c) 2012 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_OS_COMPAT_NACL_H_
+#define BASE_OS_COMPAT_NACL_H_
+
+#include <sys/types.h>
+
+#if !defined (__GLIBC__)
+// NaCl has no timegm().
+extern "C" time_t timegm(struct tm* const t);
+#endif  // !defined (__GLIBC__)
+
+#endif  // BASE_OS_COMPAT_NACL_H_
+
diff --git a/base/path_service.cc b/base/path_service.cc
new file mode 100644
index 0000000..3c437ee
--- /dev/null
+++ b/base/path_service.cc
@@ -0,0 +1,341 @@
+// Copyright (c) 2012 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/path_service.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#include <shellapi.h>
+#include <shlobj.h>
+#endif
+
+#include "base/containers/hash_tables.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/synchronization/lock.h"
+
+using base::FilePath;
+using base::MakeAbsoluteFilePath;
+
+namespace base {
+  bool PathProvider(int key, FilePath* result);
+#if defined(OS_WIN)
+  bool PathProviderWin(int key, FilePath* result);
+#elif defined(OS_MACOSX)
+  bool PathProviderMac(int key, FilePath* result);
+#elif defined(OS_ANDROID)
+  bool PathProviderAndroid(int key, FilePath* result);
+#elif defined(OS_POSIX)
+  // PathProviderPosix is the default path provider on POSIX OSes other than
+  // Mac and Android.
+  bool PathProviderPosix(int key, FilePath* result);
+#endif
+}  // namespace base
+
+namespace {
+
+typedef base::hash_map<int, FilePath> PathMap;
+
+// We keep a linked list of providers.  In a debug build we ensure that no two
+// providers claim overlapping keys.
+struct Provider {
+  PathService::ProviderFunc func;
+  struct Provider* next;
+#ifndef NDEBUG
+  int key_start;
+  int key_end;
+#endif
+  bool is_static;
+};
+
+Provider base_provider = {
+  base::PathProvider,
+  NULL,
+#ifndef NDEBUG
+  base::PATH_START,
+  base::PATH_END,
+#endif
+  true
+};
+
+#if defined(OS_WIN)
+Provider base_provider_win = {
+  base::PathProviderWin,
+  &base_provider,
+#ifndef NDEBUG
+  base::PATH_WIN_START,
+  base::PATH_WIN_END,
+#endif
+  true
+};
+#endif
+
+#if defined(OS_MACOSX)
+Provider base_provider_mac = {
+  base::PathProviderMac,
+  &base_provider,
+#ifndef NDEBUG
+  base::PATH_MAC_START,
+  base::PATH_MAC_END,
+#endif
+  true
+};
+#endif
+
+#if defined(OS_ANDROID)
+Provider base_provider_android = {
+  base::PathProviderAndroid,
+  &base_provider,
+#ifndef NDEBUG
+  base::PATH_ANDROID_START,
+  base::PATH_ANDROID_END,
+#endif
+  true
+};
+#endif
+
+#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
+Provider base_provider_posix = {
+  base::PathProviderPosix,
+  &base_provider,
+#ifndef NDEBUG
+  base::PATH_POSIX_START,
+  base::PATH_POSIX_END,
+#endif
+  true
+};
+#endif
+
+
+struct PathData {
+  base::Lock lock;
+  PathMap cache;        // Cache mappings from path key to path value.
+  PathMap overrides;    // Track path overrides.
+  Provider* providers;  // Linked list of path service providers.
+  bool cache_disabled;  // Don't use cache if true;
+
+  PathData() : cache_disabled(false) {
+#if defined(OS_WIN)
+    providers = &base_provider_win;
+#elif defined(OS_MACOSX)
+    providers = &base_provider_mac;
+#elif defined(OS_ANDROID)
+    providers = &base_provider_android;
+#elif defined(OS_POSIX)
+    providers = &base_provider_posix;
+#endif
+  }
+
+  ~PathData() {
+    Provider* p = providers;
+    while (p) {
+      Provider* next = p->next;
+      if (!p->is_static)
+        delete p;
+      p = next;
+    }
+  }
+};
+
+static base::LazyInstance<PathData> g_path_data = LAZY_INSTANCE_INITIALIZER;
+
+static PathData* GetPathData() {
+  return g_path_data.Pointer();
+}
+
+// Tries to find |key| in the cache. |path_data| should be locked by the caller!
+bool LockedGetFromCache(int key, const PathData* path_data, FilePath* result) {
+  if (path_data->cache_disabled)
+    return false;
+  // check for a cached version
+  PathMap::const_iterator it = path_data->cache.find(key);
+  if (it != path_data->cache.end()) {
+    *result = it->second;
+    return true;
+  }
+  return false;
+}
+
+// Tries to find |key| in the overrides map. |path_data| should be locked by the
+// caller!
+bool LockedGetFromOverrides(int key, PathData* path_data, FilePath* result) {
+  // check for an overridden version.
+  PathMap::const_iterator it = path_data->overrides.find(key);
+  if (it != path_data->overrides.end()) {
+    if (!path_data->cache_disabled)
+      path_data->cache[key] = it->second;
+    *result = it->second;
+    return true;
+  }
+  return false;
+}
+
+}  // namespace
+
+// TODO(brettw): this function does not handle long paths (filename > MAX_PATH)
+// characters). This isn't supported very well by Windows right now, so it is
+// moot, but we should keep this in mind for the future.
+// static
+bool PathService::Get(int key, FilePath* result) {
+  PathData* path_data = GetPathData();
+  DCHECK(path_data);
+  DCHECK(result);
+  DCHECK_GE(key, base::DIR_CURRENT);
+
+  // special case the current directory because it can never be cached
+  if (key == base::DIR_CURRENT)
+    return base::GetCurrentDirectory(result);
+
+  Provider* provider = NULL;
+  {
+    base::AutoLock scoped_lock(path_data->lock);
+    if (LockedGetFromCache(key, path_data, result))
+      return true;
+
+    if (LockedGetFromOverrides(key, path_data, result))
+      return true;
+
+    // Get the beginning of the list while it is still locked.
+    provider = path_data->providers;
+  }
+
+  FilePath path;
+
+  // Iterating does not need the lock because only the list head might be
+  // modified on another thread.
+  while (provider) {
+    if (provider->func(key, &path))
+      break;
+    DCHECK(path.empty()) << "provider should not have modified path";
+    provider = provider->next;
+  }
+
+  if (path.empty())
+    return false;
+
+  if (path.ReferencesParent()) {
+    // Make sure path service never returns a path with ".." in it.
+    path = MakeAbsoluteFilePath(path);
+    if (path.empty())
+      return false;
+  }
+  *result = path;
+
+  base::AutoLock scoped_lock(path_data->lock);
+  if (!path_data->cache_disabled)
+    path_data->cache[key] = path;
+
+  return true;
+}
+
+// static
+bool PathService::Override(int key, const FilePath& path) {
+  // Just call the full function with true for the value of |create|, and
+  // assume that |path| may not be absolute yet.
+  return OverrideAndCreateIfNeeded(key, path, false, true);
+}
+
+// static
+bool PathService::OverrideAndCreateIfNeeded(int key,
+                                            const FilePath& path,
+                                            bool is_absolute,
+                                            bool create) {
+  PathData* path_data = GetPathData();
+  DCHECK(path_data);
+  DCHECK_GT(key, base::DIR_CURRENT) << "invalid path key";
+
+  FilePath file_path = path;
+
+  // For some locations this will fail if called from inside the sandbox there-
+  // fore we protect this call with a flag.
+  if (create) {
+    // Make sure the directory exists. We need to do this before we translate
+    // this to the absolute path because on POSIX, MakeAbsoluteFilePath fails
+    // if called on a non-existent path.
+    if (!base::PathExists(file_path) &&
+        !base::CreateDirectory(file_path))
+      return false;
+  }
+
+  // We need to have an absolute path.
+  if (!is_absolute) {
+    file_path = MakeAbsoluteFilePath(file_path);
+    if (file_path.empty())
+      return false;
+  }
+  DCHECK(file_path.IsAbsolute());
+
+  base::AutoLock scoped_lock(path_data->lock);
+
+  // Clear the cache now. Some of its entries could have depended
+  // on the value we are overriding, and are now out of sync with reality.
+  path_data->cache.clear();
+
+  path_data->overrides[key] = file_path;
+
+  return true;
+}
+
+// static
+bool PathService::RemoveOverride(int key) {
+  PathData* path_data = GetPathData();
+  DCHECK(path_data);
+
+  base::AutoLock scoped_lock(path_data->lock);
+
+  if (path_data->overrides.find(key) == path_data->overrides.end())
+    return false;
+
+  // Clear the cache now. Some of its entries could have depended on the value
+  // we are going to remove, and are now out of sync.
+  path_data->cache.clear();
+
+  path_data->overrides.erase(key);
+
+  return true;
+}
+
+// static
+void PathService::RegisterProvider(ProviderFunc func, int key_start,
+                                   int key_end) {
+  PathData* path_data = GetPathData();
+  DCHECK(path_data);
+  DCHECK_GT(key_end, key_start);
+
+  Provider* p;
+
+  p = new Provider;
+  p->is_static = false;
+  p->func = func;
+#ifndef NDEBUG
+  p->key_start = key_start;
+  p->key_end = key_end;
+#endif
+
+  base::AutoLock scoped_lock(path_data->lock);
+
+#ifndef NDEBUG
+  Provider *iter = path_data->providers;
+  while (iter) {
+    DCHECK(key_start >= iter->key_end || key_end <= iter->key_start) <<
+      "path provider collision";
+    iter = iter->next;
+  }
+#endif
+
+  p->next = path_data->providers;
+  path_data->providers = p;
+}
+
+// static
+void PathService::DisableCache() {
+  PathData* path_data = GetPathData();
+  DCHECK(path_data);
+
+  base::AutoLock scoped_lock(path_data->lock);
+  path_data->cache.clear();
+  path_data->cache_disabled = true;
+}
diff --git a/base/path_service.h b/base/path_service.h
new file mode 100644
index 0000000..025550f
--- /dev/null
+++ b/base/path_service.h
@@ -0,0 +1,92 @@
+// Copyright (c) 2012 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_PATH_SERVICE_H_
+#define BASE_PATH_SERVICE_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/base_paths.h"
+#include "base/gtest_prod_util.h"
+#include "build/build_config.h"
+
+namespace base {
+class FilePath;
+class ScopedPathOverride;
+}  // namespace base
+
+// The path service is a global table mapping keys to file system paths.  It is
+// OK to use this service from multiple threads.
+//
+class BASE_EXPORT PathService {
+ public:
+  // Retrieves a path to a special directory or file and places it into the
+  // string pointed to by 'path'. If you ask for a directory it is guaranteed
+  // to NOT have a path separator at the end. For example, "c:\windows\temp"
+  // Directories are also guaranteed to exist when this function succeeds.
+  //
+  // Returns true if the directory or file was successfully retrieved. On
+  // failure, 'path' will not be changed.
+  static bool Get(int key, base::FilePath* path);
+
+  // Overrides the path to a special directory or file.  This cannot be used to
+  // change the value of DIR_CURRENT, but that should be obvious.  Also, if the
+  // path specifies a directory that does not exist, the directory will be
+  // created by this method.  This method returns true if successful.
+  //
+  // If the given path is relative, then it will be resolved against
+  // DIR_CURRENT.
+  //
+  // WARNING: Consumers of PathService::Get may expect paths to be constant
+  // over the lifetime of the app, so this method should be used with caution.
+  //
+  // Unit tests generally should use ScopedPathOverride instead. Overrides from
+  // one test should not carry over to another.
+  static bool Override(int key, const base::FilePath& path);
+
+  // This function does the same as PathService::Override but it takes extra
+  // parameters:
+  // - |is_absolute| indicates that |path| has already been expanded into an
+  // absolute path, otherwise MakeAbsoluteFilePath() will be used. This is
+  // useful to override paths that may not exist yet, since MakeAbsoluteFilePath
+  // fails for those. Note that MakeAbsoluteFilePath also expands symbolic
+  // links, even if path.IsAbsolute() is already true.
+  // - |create| guides whether the directory to be overriden must
+  // be created in case it doesn't exist already.
+  static bool OverrideAndCreateIfNeeded(int key,
+                                        const base::FilePath& path,
+                                        bool is_absolute,
+                                        bool create);
+
+  // To extend the set of supported keys, you can register a path provider,
+  // which is just a function mirroring PathService::Get.  The ProviderFunc
+  // returns false if it cannot provide a non-empty path for the given key.
+  // Otherwise, true is returned.
+  //
+  // WARNING: This function could be called on any thread from which the
+  // PathService is used, so a the ProviderFunc MUST BE THREADSAFE.
+  //
+  typedef bool (*ProviderFunc)(int, base::FilePath*);
+
+  // Call to register a path provider.  You must specify the range "[key_start,
+  // key_end)" of supported path keys.
+  static void RegisterProvider(ProviderFunc provider,
+                               int key_start,
+                               int key_end);
+
+  // Disable internal cache.
+  static void DisableCache();
+
+ private:
+  friend class base::ScopedPathOverride;
+  FRIEND_TEST_ALL_PREFIXES(PathServiceTest, RemoveOverride);
+
+  // Removes an override for a special directory or file. Returns true if there
+  // was an override to remove or false if none was present.
+  // NOTE: This function is intended to be used by tests only!
+  static bool RemoveOverride(int key);
+};
+
+#endif  // BASE_PATH_SERVICE_H_
diff --git a/base/path_service_unittest.cc b/base/path_service_unittest.cc
new file mode 100644
index 0000000..7551d67
--- /dev/null
+++ b/base/path_service_unittest.cc
@@ -0,0 +1,274 @@
+// Copyright (c) 2012 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/path_service.h"
+
+#include "base/basictypes.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/strings/string_util.h"
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest-spi.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+#if defined(OS_WIN)
+#include "base/win/windows_version.h"
+#endif
+
+namespace {
+
+// Returns true if PathService::Get returns true and sets the path parameter
+// to non-empty for the given PathService::DirType enumeration value.
+bool ReturnsValidPath(int dir_type) {
+  base::FilePath path;
+  bool result = PathService::Get(dir_type, &path);
+
+  // Some paths might not exist on some platforms in which case confirming
+  // |result| is true and !path.empty() is the best we can do.
+  bool check_path_exists = true;
+#if defined(OS_POSIX)
+  // If chromium has never been started on this account, the cache path may not
+  // exist.
+  if (dir_type == base::DIR_CACHE)
+    check_path_exists = false;
+#endif
+#if defined(OS_LINUX)
+  // On the linux try-bots: a path is returned (e.g. /home/chrome-bot/Desktop),
+  // but it doesn't exist.
+  if (dir_type == base::DIR_USER_DESKTOP)
+    check_path_exists = false;
+#endif
+#if defined(OS_WIN)
+  if (dir_type == base::DIR_TASKBAR_PINS) {
+    // There is no pinned-to-taskbar shortcuts prior to Win7.
+    if (base::win::GetVersion() < base::win::VERSION_WIN7)
+      check_path_exists = false;
+  }
+#endif
+#if defined(OS_MACOSX)
+  if (dir_type != base::DIR_EXE && dir_type != base::DIR_MODULE &&
+      dir_type != base::FILE_EXE && dir_type != base::FILE_MODULE) {
+    if (path.ReferencesParent())
+      return false;
+  }
+#else
+  if (path.ReferencesParent())
+    return false;
+#endif
+  return result && !path.empty() && (!check_path_exists ||
+                                     base::PathExists(path));
+}
+
+#if defined(OS_WIN)
+// Function to test any directory keys that are not supported on some versions
+// of Windows. Checks that the function fails and that the returned path is
+// empty.
+bool ReturnsInvalidPath(int dir_type) {
+  base::FilePath path;
+  bool result = PathService::Get(dir_type, &path);
+  return !result && path.empty();
+}
+#endif
+
+}  // namespace
+
+// On the Mac this winds up using some autoreleased objects, so we need to
+// be a PlatformTest.
+typedef PlatformTest PathServiceTest;
+
+// Test that all PathService::Get calls return a value and a true result
+// in the development environment.  (This test was created because a few
+// later changes to Get broke the semantics of the function and yielded the
+// correct value while returning false.)
+TEST_F(PathServiceTest, Get) {
+  for (int key = base::PATH_START + 1; key < base::PATH_END; ++key) {
+#if defined(OS_ANDROID)
+    if (key == base::FILE_MODULE || key == base::DIR_USER_DESKTOP ||
+        key == base::DIR_HOME)
+      continue;  // Android doesn't implement these.
+#elif defined(OS_IOS)
+    if (key == base::DIR_USER_DESKTOP)
+      continue;  // iOS doesn't implement DIR_USER_DESKTOP;
+#endif
+    EXPECT_PRED1(ReturnsValidPath, key);
+  }
+#if defined(OS_WIN)
+  for (int key = base::PATH_WIN_START + 1; key < base::PATH_WIN_END; ++key) {
+    bool valid = true;
+    if (key == base::DIR_APP_SHORTCUTS)
+      valid = base::win::GetVersion() >= base::win::VERSION_WIN8;
+
+    if (valid)
+      EXPECT_TRUE(ReturnsValidPath(key)) << key;
+    else
+      EXPECT_TRUE(ReturnsInvalidPath(key)) << key;
+  }
+#elif defined(OS_MACOSX)
+  for (int key = base::PATH_MAC_START + 1; key < base::PATH_MAC_END; ++key) {
+    EXPECT_PRED1(ReturnsValidPath, key);
+  }
+#elif defined(OS_ANDROID)
+  for (int key = base::PATH_ANDROID_START + 1; key < base::PATH_ANDROID_END;
+       ++key) {
+    EXPECT_PRED1(ReturnsValidPath, key);
+  }
+#elif defined(OS_POSIX)
+  for (int key = base::PATH_POSIX_START + 1; key < base::PATH_POSIX_END;
+       ++key) {
+    EXPECT_PRED1(ReturnsValidPath, key);
+  }
+#endif
+}
+
+// Test that all versions of the Override function of PathService do what they
+// are supposed to do.
+TEST_F(PathServiceTest, Override) {
+  int my_special_key = 666;
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  base::FilePath fake_cache_dir(temp_dir.path().AppendASCII("cache"));
+  // PathService::Override should always create the path provided if it doesn't
+  // exist.
+  EXPECT_TRUE(PathService::Override(my_special_key, fake_cache_dir));
+  EXPECT_TRUE(base::PathExists(fake_cache_dir));
+
+  base::FilePath fake_cache_dir2(temp_dir.path().AppendASCII("cache2"));
+  // PathService::OverrideAndCreateIfNeeded should obey the |create| parameter.
+  PathService::OverrideAndCreateIfNeeded(my_special_key,
+                                         fake_cache_dir2,
+                                         false,
+                                         false);
+  EXPECT_FALSE(base::PathExists(fake_cache_dir2));
+  EXPECT_TRUE(PathService::OverrideAndCreateIfNeeded(my_special_key,
+                                                     fake_cache_dir2,
+                                                     false,
+                                                     true));
+  EXPECT_TRUE(base::PathExists(fake_cache_dir2));
+
+#if defined(OS_POSIX)
+  base::FilePath non_existent(
+      base::MakeAbsoluteFilePath(temp_dir.path()).AppendASCII("non_existent"));
+  EXPECT_TRUE(non_existent.IsAbsolute());
+  EXPECT_FALSE(base::PathExists(non_existent));
+#if !defined(OS_ANDROID)
+  // This fails because MakeAbsoluteFilePath fails for non-existent files.
+  // Earlier versions of Bionic libc don't fail for non-existent files, so
+  // skip this check on Android.
+  EXPECT_FALSE(PathService::OverrideAndCreateIfNeeded(my_special_key,
+                                                      non_existent,
+                                                      false,
+                                                      false));
+#endif
+  // This works because indicating that |non_existent| is absolute skips the
+  // internal MakeAbsoluteFilePath call.
+  EXPECT_TRUE(PathService::OverrideAndCreateIfNeeded(my_special_key,
+                                                     non_existent,
+                                                     true,
+                                                     false));
+  // Check that the path has been overridden and no directory was created.
+  EXPECT_FALSE(base::PathExists(non_existent));
+  base::FilePath path;
+  EXPECT_TRUE(PathService::Get(my_special_key, &path));
+  EXPECT_EQ(non_existent, path);
+#endif
+}
+
+// Check if multiple overrides can co-exist.
+TEST_F(PathServiceTest, OverrideMultiple) {
+  int my_special_key = 666;
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  base::FilePath fake_cache_dir1(temp_dir.path().AppendASCII("1"));
+  EXPECT_TRUE(PathService::Override(my_special_key, fake_cache_dir1));
+  EXPECT_TRUE(base::PathExists(fake_cache_dir1));
+  ASSERT_EQ(1, base::WriteFile(fake_cache_dir1.AppendASCII("t1"), ".", 1));
+
+  base::FilePath fake_cache_dir2(temp_dir.path().AppendASCII("2"));
+  EXPECT_TRUE(PathService::Override(my_special_key + 1, fake_cache_dir2));
+  EXPECT_TRUE(base::PathExists(fake_cache_dir2));
+  ASSERT_EQ(1, base::WriteFile(fake_cache_dir2.AppendASCII("t2"), ".", 1));
+
+  base::FilePath result;
+  EXPECT_TRUE(PathService::Get(my_special_key, &result));
+  // Override might have changed the path representation but our test file
+  // should be still there.
+  EXPECT_TRUE(base::PathExists(result.AppendASCII("t1")));
+  EXPECT_TRUE(PathService::Get(my_special_key + 1, &result));
+  EXPECT_TRUE(base::PathExists(result.AppendASCII("t2")));
+}
+
+TEST_F(PathServiceTest, RemoveOverride) {
+  // Before we start the test we have to call RemoveOverride at least once to
+  // clear any overrides that might have been left from other tests.
+  PathService::RemoveOverride(base::DIR_TEMP);
+
+  base::FilePath original_user_data_dir;
+  EXPECT_TRUE(PathService::Get(base::DIR_TEMP, &original_user_data_dir));
+  EXPECT_FALSE(PathService::RemoveOverride(base::DIR_TEMP));
+
+  base::ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  EXPECT_TRUE(PathService::Override(base::DIR_TEMP, temp_dir.path()));
+  base::FilePath new_user_data_dir;
+  EXPECT_TRUE(PathService::Get(base::DIR_TEMP, &new_user_data_dir));
+  EXPECT_NE(original_user_data_dir, new_user_data_dir);
+
+  EXPECT_TRUE(PathService::RemoveOverride(base::DIR_TEMP));
+  EXPECT_TRUE(PathService::Get(base::DIR_TEMP, &new_user_data_dir));
+  EXPECT_EQ(original_user_data_dir, new_user_data_dir);
+}
+
+#if defined(OS_WIN)
+TEST_F(PathServiceTest, GetProgramFiles) {
+  base::FilePath programfiles_dir;
+#if defined(_WIN64)
+  // 64-bit on 64-bit.
+  EXPECT_TRUE(PathService::Get(base::DIR_PROGRAM_FILES,
+      &programfiles_dir));
+  EXPECT_EQ(programfiles_dir.value(),
+      FILE_PATH_LITERAL("C:\\Program Files"));
+  EXPECT_TRUE(PathService::Get(base::DIR_PROGRAM_FILESX86,
+      &programfiles_dir));
+  EXPECT_EQ(programfiles_dir.value(),
+      FILE_PATH_LITERAL("C:\\Program Files (x86)"));
+  EXPECT_TRUE(PathService::Get(base::DIR_PROGRAM_FILES6432,
+      &programfiles_dir));
+  EXPECT_EQ(programfiles_dir.value(),
+      FILE_PATH_LITERAL("C:\\Program Files"));
+#else
+  if (base::win::OSInfo::GetInstance()->wow64_status() ==
+      base::win::OSInfo::WOW64_ENABLED) {
+    // 32-bit on 64-bit.
+    EXPECT_TRUE(PathService::Get(base::DIR_PROGRAM_FILES,
+        &programfiles_dir));
+    EXPECT_EQ(programfiles_dir.value(),
+        FILE_PATH_LITERAL("C:\\Program Files (x86)"));
+    EXPECT_TRUE(PathService::Get(base::DIR_PROGRAM_FILESX86,
+        &programfiles_dir));
+    EXPECT_EQ(programfiles_dir.value(),
+        FILE_PATH_LITERAL("C:\\Program Files (x86)"));
+    EXPECT_TRUE(PathService::Get(base::DIR_PROGRAM_FILES6432,
+        &programfiles_dir));
+    EXPECT_EQ(programfiles_dir.value(),
+        FILE_PATH_LITERAL("C:\\Program Files"));
+  } else {
+    // 32-bit on 32-bit.
+    EXPECT_TRUE(PathService::Get(base::DIR_PROGRAM_FILES,
+        &programfiles_dir));
+    EXPECT_EQ(programfiles_dir.value(),
+        FILE_PATH_LITERAL("C:\\Program Files"));
+    EXPECT_TRUE(PathService::Get(base::DIR_PROGRAM_FILESX86,
+        &programfiles_dir));
+    EXPECT_EQ(programfiles_dir.value(),
+        FILE_PATH_LITERAL("C:\\Program Files"));
+    EXPECT_TRUE(PathService::Get(base::DIR_PROGRAM_FILES6432,
+        &programfiles_dir));
+    EXPECT_EQ(programfiles_dir.value(),
+        FILE_PATH_LITERAL("C:\\Program Files"));
+  }
+#endif
+}
+#endif
diff --git a/base/pending_task.cc b/base/pending_task.cc
new file mode 100644
index 0000000..3d78914
--- /dev/null
+++ b/base/pending_task.cc
@@ -0,0 +1,56 @@
+// Copyright (c) 2011 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/pending_task.h"
+
+#include "base/tracked_objects.h"
+
+namespace base {
+
+PendingTask::PendingTask(const tracked_objects::Location& posted_from,
+                         const base::Closure& task)
+    : base::TrackingInfo(posted_from, TimeTicks()),
+      task(task),
+      posted_from(posted_from),
+      sequence_num(0),
+      nestable(true),
+      is_high_res(false) {
+}
+
+PendingTask::PendingTask(const tracked_objects::Location& posted_from,
+                         const base::Closure& task,
+                         TimeTicks delayed_run_time,
+                         bool nestable)
+    : base::TrackingInfo(posted_from, delayed_run_time),
+      task(task),
+      posted_from(posted_from),
+      sequence_num(0),
+      nestable(nestable),
+      is_high_res(false) {
+}
+
+PendingTask::~PendingTask() {
+}
+
+bool PendingTask::operator<(const PendingTask& other) const {
+  // Since the top of a priority queue is defined as the "greatest" element, we
+  // need to invert the comparison here.  We want the smaller time to be at the
+  // top of the heap.
+
+  if (delayed_run_time < other.delayed_run_time)
+    return false;
+
+  if (delayed_run_time > other.delayed_run_time)
+    return true;
+
+  // If the times happen to match, then we use the sequence number to decide.
+  // Compare the difference to support integer roll-over.
+  return (sequence_num - other.sequence_num) > 0;
+}
+
+void TaskQueue::Swap(TaskQueue* queue) {
+  c.swap(queue->c);  // Calls std::deque::swap.
+}
+
+}  // namespace base
diff --git a/base/pending_task.h b/base/pending_task.h
new file mode 100644
index 0000000..fddfc86
--- /dev/null
+++ b/base/pending_task.h
@@ -0,0 +1,60 @@
+// Copyright (c) 2011 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_PENDING_TASK_H_
+#define BASE_PENDING_TASK_H_
+
+#include <queue>
+
+#include "base/base_export.h"
+#include "base/callback.h"
+#include "base/location.h"
+#include "base/time/time.h"
+#include "base/tracking_info.h"
+
+namespace base {
+
+// Contains data about a pending task. Stored in TaskQueue and DelayedTaskQueue
+// for use by classes that queue and execute tasks.
+struct BASE_EXPORT PendingTask : public TrackingInfo {
+  PendingTask(const tracked_objects::Location& posted_from,
+              const Closure& task);
+  PendingTask(const tracked_objects::Location& posted_from,
+              const Closure& task,
+              TimeTicks delayed_run_time,
+              bool nestable);
+  ~PendingTask();
+
+  // Used to support sorting.
+  bool operator<(const PendingTask& other) const;
+
+  // The task to run.
+  Closure task;
+
+  // The site this PendingTask was posted from.
+  tracked_objects::Location posted_from;
+
+  // Secondary sort key for run time.
+  int sequence_num;
+
+  // OK to dispatch from a nested loop.
+  bool nestable;
+
+  // Needs high resolution timers.
+  bool is_high_res;
+};
+
+// Wrapper around std::queue specialized for PendingTask which adds a Swap
+// helper method.
+class BASE_EXPORT TaskQueue : public std::queue<PendingTask> {
+ public:
+  void Swap(TaskQueue* queue);
+};
+
+// PendingTasks are sorted by their |delayed_run_time| property.
+typedef std::priority_queue<base::PendingTask> DelayedTaskQueue;
+
+}  // namespace base
+
+#endif  // BASE_PENDING_TASK_H_
diff --git a/base/pickle.cc b/base/pickle.cc
new file mode 100644
index 0000000..cf4a865
--- /dev/null
+++ b/base/pickle.cc
@@ -0,0 +1,380 @@
+// Copyright (c) 2012 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/pickle.h"
+
+#include <stdlib.h>
+
+#include <algorithm>  // for max()
+
+namespace base {
+
+// static
+const int Pickle::kPayloadUnit = 64;
+
+static const size_t kCapacityReadOnly = static_cast<size_t>(-1);
+
+PickleIterator::PickleIterator(const Pickle& pickle)
+    : payload_(pickle.payload()),
+      read_index_(0),
+      end_index_(pickle.payload_size()) {
+}
+
+template <typename Type>
+inline bool PickleIterator::ReadBuiltinType(Type* result) {
+  const char* read_from = GetReadPointerAndAdvance<Type>();
+  if (!read_from)
+    return false;
+  if (sizeof(Type) > sizeof(uint32))
+    memcpy(result, read_from, sizeof(*result));
+  else
+    *result = *reinterpret_cast<const Type*>(read_from);
+  return true;
+}
+
+inline void PickleIterator::Advance(size_t size) {
+  size_t aligned_size = AlignInt(size, sizeof(uint32_t));
+  if (end_index_ - read_index_ < aligned_size) {
+    read_index_ = end_index_;
+  } else {
+    read_index_ += aligned_size;
+  }
+}
+
+template<typename Type>
+inline const char* PickleIterator::GetReadPointerAndAdvance() {
+  if (sizeof(Type) > end_index_ - read_index_) {
+    read_index_ = end_index_;
+    return NULL;
+  }
+  const char* current_read_ptr = payload_ + read_index_;
+  Advance(sizeof(Type));
+  return current_read_ptr;
+}
+
+const char* PickleIterator::GetReadPointerAndAdvance(int num_bytes) {
+  if (num_bytes < 0 ||
+      end_index_ - read_index_ < static_cast<size_t>(num_bytes)) {
+    read_index_ = end_index_;
+    return NULL;
+  }
+  const char* current_read_ptr = payload_ + read_index_;
+  Advance(num_bytes);
+  return current_read_ptr;
+}
+
+inline const char* PickleIterator::GetReadPointerAndAdvance(
+    int num_elements,
+    size_t size_element) {
+  // Check for int32 overflow.
+  int64 num_bytes = static_cast<int64>(num_elements) * size_element;
+  int num_bytes32 = static_cast<int>(num_bytes);
+  if (num_bytes != static_cast<int64>(num_bytes32))
+    return NULL;
+  return GetReadPointerAndAdvance(num_bytes32);
+}
+
+bool PickleIterator::ReadBool(bool* result) {
+  return ReadBuiltinType(result);
+}
+
+bool PickleIterator::ReadInt(int* result) {
+  return ReadBuiltinType(result);
+}
+
+bool PickleIterator::ReadLong(long* result) {
+  return ReadBuiltinType(result);
+}
+
+bool PickleIterator::ReadUInt16(uint16* result) {
+  return ReadBuiltinType(result);
+}
+
+bool PickleIterator::ReadUInt32(uint32* result) {
+  return ReadBuiltinType(result);
+}
+
+bool PickleIterator::ReadInt64(int64* result) {
+  return ReadBuiltinType(result);
+}
+
+bool PickleIterator::ReadUInt64(uint64* result) {
+  return ReadBuiltinType(result);
+}
+
+bool PickleIterator::ReadSizeT(size_t* result) {
+  // Always read size_t as a 64-bit value to ensure compatibility between 32-bit
+  // and 64-bit processes.
+  uint64 result_uint64 = 0;
+  bool success = ReadBuiltinType(&result_uint64);
+  *result = static_cast<size_t>(result_uint64);
+  // Fail if the cast above truncates the value.
+  return success && (*result == result_uint64);
+}
+
+bool PickleIterator::ReadFloat(float* result) {
+  // crbug.com/315213
+  // The source data may not be properly aligned, and unaligned float reads
+  // cause SIGBUS on some ARM platforms, so force using memcpy to copy the data
+  // into the result.
+  const char* read_from = GetReadPointerAndAdvance<float>();
+  if (!read_from)
+    return false;
+  memcpy(result, read_from, sizeof(*result));
+  return true;
+}
+
+bool PickleIterator::ReadDouble(double* result) {
+  // crbug.com/315213
+  // The source data may not be properly aligned, and unaligned double reads
+  // cause SIGBUS on some ARM platforms, so force using memcpy to copy the data
+  // into the result.
+  const char* read_from = GetReadPointerAndAdvance<double>();
+  if (!read_from)
+    return false;
+  memcpy(result, read_from, sizeof(*result));
+  return true;
+}
+
+bool PickleIterator::ReadString(std::string* result) {
+  int len;
+  if (!ReadInt(&len))
+    return false;
+  const char* read_from = GetReadPointerAndAdvance(len);
+  if (!read_from)
+    return false;
+
+  result->assign(read_from, len);
+  return true;
+}
+
+bool PickleIterator::ReadStringPiece(StringPiece* result) {
+  int len;
+  if (!ReadInt(&len))
+    return false;
+  const char* read_from = GetReadPointerAndAdvance(len);
+  if (!read_from)
+    return false;
+
+  *result = StringPiece(read_from, len);
+  return true;
+}
+
+bool PickleIterator::ReadString16(string16* result) {
+  int len;
+  if (!ReadInt(&len))
+    return false;
+  const char* read_from = GetReadPointerAndAdvance(len, sizeof(char16));
+  if (!read_from)
+    return false;
+
+  result->assign(reinterpret_cast<const char16*>(read_from), len);
+  return true;
+}
+
+bool PickleIterator::ReadStringPiece16(StringPiece16* result) {
+  int len;
+  if (!ReadInt(&len))
+    return false;
+  const char* read_from = GetReadPointerAndAdvance(len, sizeof(char16));
+  if (!read_from)
+    return false;
+
+  *result = StringPiece16(reinterpret_cast<const char16*>(read_from), len);
+  return true;
+}
+
+bool PickleIterator::ReadData(const char** data, int* length) {
+  *length = 0;
+  *data = 0;
+
+  if (!ReadInt(length))
+    return false;
+
+  return ReadBytes(data, *length);
+}
+
+bool PickleIterator::ReadBytes(const char** data, int length) {
+  const char* read_from = GetReadPointerAndAdvance(length);
+  if (!read_from)
+    return false;
+  *data = read_from;
+  return true;
+}
+
+// Payload is uint32 aligned.
+
+Pickle::Pickle()
+    : header_(NULL),
+      header_size_(sizeof(Header)),
+      capacity_after_header_(0),
+      write_offset_(0) {
+  Resize(kPayloadUnit);
+  header_->payload_size = 0;
+}
+
+Pickle::Pickle(int header_size)
+    : header_(NULL),
+      header_size_(AlignInt(header_size, sizeof(uint32))),
+      capacity_after_header_(0),
+      write_offset_(0) {
+  DCHECK_GE(static_cast<size_t>(header_size), sizeof(Header));
+  DCHECK_LE(header_size, kPayloadUnit);
+  Resize(kPayloadUnit);
+  header_->payload_size = 0;
+}
+
+Pickle::Pickle(const char* data, int data_len)
+    : header_(reinterpret_cast<Header*>(const_cast<char*>(data))),
+      header_size_(0),
+      capacity_after_header_(kCapacityReadOnly),
+      write_offset_(0) {
+  if (data_len >= static_cast<int>(sizeof(Header)))
+    header_size_ = data_len - header_->payload_size;
+
+  if (header_size_ > static_cast<unsigned int>(data_len))
+    header_size_ = 0;
+
+  if (header_size_ != AlignInt(header_size_, sizeof(uint32)))
+    header_size_ = 0;
+
+  // If there is anything wrong with the data, we're not going to use it.
+  if (!header_size_)
+    header_ = NULL;
+}
+
+Pickle::Pickle(const Pickle& other)
+    : header_(NULL),
+      header_size_(other.header_size_),
+      capacity_after_header_(0),
+      write_offset_(other.write_offset_) {
+  size_t payload_size = header_size_ + other.header_->payload_size;
+  Resize(payload_size);
+  memcpy(header_, other.header_, payload_size);
+}
+
+Pickle::~Pickle() {
+  if (capacity_after_header_ != kCapacityReadOnly)
+    free(header_);
+}
+
+Pickle& Pickle::operator=(const Pickle& other) {
+  if (this == &other) {
+    NOTREACHED();
+    return *this;
+  }
+  if (capacity_after_header_ == kCapacityReadOnly) {
+    header_ = NULL;
+    capacity_after_header_ = 0;
+  }
+  if (header_size_ != other.header_size_) {
+    free(header_);
+    header_ = NULL;
+    header_size_ = other.header_size_;
+  }
+  Resize(other.header_->payload_size);
+  memcpy(header_, other.header_,
+         other.header_size_ + other.header_->payload_size);
+  write_offset_ = other.write_offset_;
+  return *this;
+}
+
+bool Pickle::WriteString(const StringPiece& value) {
+  if (!WriteInt(static_cast<int>(value.size())))
+    return false;
+
+  return WriteBytes(value.data(), static_cast<int>(value.size()));
+}
+
+bool Pickle::WriteString16(const StringPiece16& value) {
+  if (!WriteInt(static_cast<int>(value.size())))
+    return false;
+
+  return WriteBytes(value.data(),
+                    static_cast<int>(value.size()) * sizeof(char16));
+}
+
+bool Pickle::WriteData(const char* data, int length) {
+  return length >= 0 && WriteInt(length) && WriteBytes(data, length);
+}
+
+bool Pickle::WriteBytes(const void* data, int length) {
+  WriteBytesCommon(data, length);
+  return true;
+}
+
+void Pickle::Reserve(size_t length) {
+  size_t data_len = AlignInt(length, sizeof(uint32));
+  DCHECK_GE(data_len, length);
+#ifdef ARCH_CPU_64_BITS
+  DCHECK_LE(data_len, kuint32max);
+#endif
+  DCHECK_LE(write_offset_, kuint32max - data_len);
+  size_t new_size = write_offset_ + data_len;
+  if (new_size > capacity_after_header_)
+    Resize(capacity_after_header_ * 2 + new_size);
+}
+
+void Pickle::Resize(size_t new_capacity) {
+  CHECK_NE(capacity_after_header_, kCapacityReadOnly);
+  capacity_after_header_ = AlignInt(new_capacity, kPayloadUnit);
+  void* p = realloc(header_, GetTotalAllocatedSize());
+  CHECK(p);
+  header_ = reinterpret_cast<Header*>(p);
+}
+
+size_t Pickle::GetTotalAllocatedSize() const {
+  if (capacity_after_header_ == kCapacityReadOnly)
+    return 0;
+  return header_size_ + capacity_after_header_;
+}
+
+// static
+const char* Pickle::FindNext(size_t header_size,
+                             const char* start,
+                             const char* end) {
+  DCHECK_EQ(header_size, AlignInt(header_size, sizeof(uint32)));
+  DCHECK_LE(header_size, static_cast<size_t>(kPayloadUnit));
+
+  size_t length = static_cast<size_t>(end - start);
+  if (length < sizeof(Header))
+    return NULL;
+
+  const Header* hdr = reinterpret_cast<const Header*>(start);
+  if (length < header_size || length - header_size < hdr->payload_size)
+    return NULL;
+  return start + header_size + hdr->payload_size;
+}
+
+template <size_t length> void Pickle::WriteBytesStatic(const void* data) {
+  WriteBytesCommon(data, length);
+}
+
+template void Pickle::WriteBytesStatic<2>(const void* data);
+template void Pickle::WriteBytesStatic<4>(const void* data);
+template void Pickle::WriteBytesStatic<8>(const void* data);
+
+inline void Pickle::WriteBytesCommon(const void* data, size_t length) {
+  DCHECK_NE(kCapacityReadOnly, capacity_after_header_)
+      << "oops: pickle is readonly";
+  MSAN_CHECK_MEM_IS_INITIALIZED(data, length);
+  size_t data_len = AlignInt(length, sizeof(uint32));
+  DCHECK_GE(data_len, length);
+#ifdef ARCH_CPU_64_BITS
+  DCHECK_LE(data_len, kuint32max);
+#endif
+  DCHECK_LE(write_offset_, kuint32max - data_len);
+  size_t new_size = write_offset_ + data_len;
+  if (new_size > capacity_after_header_) {
+    Resize(std::max(capacity_after_header_ * 2, new_size));
+  }
+
+  char* write = mutable_payload() + write_offset_;
+  memcpy(write, data, length);
+  memset(write + length, 0, data_len - length);
+  header_->payload_size = static_cast<uint32>(new_size);
+  write_offset_ = new_size;
+}
+
+}  // namespace base
diff --git a/base/pickle.h b/base/pickle.h
new file mode 100644
index 0000000..c9fef71
--- /dev/null
+++ b/base/pickle.h
@@ -0,0 +1,317 @@
+// Copyright (c) 2012 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_PICKLE_H_
+#define BASE_PICKLE_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/gtest_prod_util.h"
+#include "base/logging.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+class Pickle;
+
+// PickleIterator reads data from a Pickle. The Pickle object must remain valid
+// while the PickleIterator object is in use.
+class BASE_EXPORT PickleIterator {
+ public:
+  PickleIterator() : payload_(NULL), read_index_(0), end_index_(0) {}
+  explicit PickleIterator(const Pickle& pickle);
+
+  // Methods for reading the payload of the Pickle. To read from the start of
+  // the Pickle, create a PickleIterator from a Pickle. If successful, these
+  // methods return true. Otherwise, false is returned to indicate that the
+  // result could not be extracted. It is not possible to read from the iterator
+  // after that.
+  bool ReadBool(bool* result) WARN_UNUSED_RESULT;
+  bool ReadInt(int* result) WARN_UNUSED_RESULT;
+  bool ReadLong(long* result) WARN_UNUSED_RESULT;
+  bool ReadUInt16(uint16* result) WARN_UNUSED_RESULT;
+  bool ReadUInt32(uint32* result) WARN_UNUSED_RESULT;
+  bool ReadInt64(int64* result) WARN_UNUSED_RESULT;
+  bool ReadUInt64(uint64* result) WARN_UNUSED_RESULT;
+  bool ReadSizeT(size_t* result) WARN_UNUSED_RESULT;
+  bool ReadFloat(float* result) WARN_UNUSED_RESULT;
+  bool ReadDouble(double* result) WARN_UNUSED_RESULT;
+  bool ReadString(std::string* result) WARN_UNUSED_RESULT;
+  // The StringPiece data will only be valid for the lifetime of the message.
+  bool ReadStringPiece(StringPiece* result) WARN_UNUSED_RESULT;
+  bool ReadString16(string16* result) WARN_UNUSED_RESULT;
+  // The StringPiece16 data will only be valid for the lifetime of the message.
+  bool ReadStringPiece16(StringPiece16* result) WARN_UNUSED_RESULT;
+
+  // A pointer to the data will be placed in |*data|, and the length will be
+  // placed in |*length|. The pointer placed into |*data| points into the
+  // message's buffer so it will be scoped to the lifetime of the message (or
+  // until the message data is mutated). Do not keep the pointer around!
+  bool ReadData(const char** data, int* length) WARN_UNUSED_RESULT;
+
+  // A pointer to the data will be placed in |*data|. The caller specifies the
+  // number of bytes to read, and ReadBytes will validate this length. The
+  // pointer placed into |*data| points into the message's buffer so it will be
+  // scoped to the lifetime of the message (or until the message data is
+  // mutated). Do not keep the pointer around!
+  bool ReadBytes(const char** data, int length) WARN_UNUSED_RESULT;
+
+  // A safer version of ReadInt() that checks for the result not being negative.
+  // Use it for reading the object sizes.
+  bool ReadLength(int* result) WARN_UNUSED_RESULT {
+    return ReadInt(result) && *result >= 0;
+  }
+
+  // Skips bytes in the read buffer and returns true if there are at least
+  // num_bytes available. Otherwise, does nothing and returns false.
+  bool SkipBytes(int num_bytes) WARN_UNUSED_RESULT {
+    return !!GetReadPointerAndAdvance(num_bytes);
+  }
+
+ private:
+  // Aligns 'i' by rounding it up to the next multiple of 'alignment'.
+  static size_t AlignInt(size_t i, int alignment) {
+    return i + (alignment - (i % alignment)) % alignment;
+  }
+
+  // Read Type from Pickle.
+  template <typename Type>
+  bool ReadBuiltinType(Type* result);
+
+  // Advance read_index_ but do not allow it to exceed end_index_.
+  // Keeps read_index_ aligned.
+  void Advance(size_t size);
+
+  // Get read pointer for Type and advance read pointer.
+  template<typename Type>
+  const char* GetReadPointerAndAdvance();
+
+  // Get read pointer for |num_bytes| and advance read pointer. This method
+  // checks num_bytes for negativity and wrapping.
+  const char* GetReadPointerAndAdvance(int num_bytes);
+
+  // Get read pointer for (num_elements * size_element) bytes and advance read
+  // pointer. This method checks for int overflow, negativity and wrapping.
+  const char* GetReadPointerAndAdvance(int num_elements,
+                                       size_t size_element);
+
+  const char* payload_;  // Start of our pickle's payload.
+  size_t read_index_;  // Offset of the next readable byte in payload.
+  size_t end_index_;  // Payload size.
+
+  FRIEND_TEST_ALL_PREFIXES(PickleTest, GetReadPointerAndAdvance);
+};
+
+// This class provides facilities for basic binary value packing and unpacking.
+//
+// The Pickle class supports appending primitive values (ints, strings, etc.)
+// to a pickle instance.  The Pickle instance grows its internal memory buffer
+// dynamically to hold the sequence of primitive values.   The internal memory
+// buffer is exposed as the "data" of the Pickle.  This "data" can be passed
+// to a Pickle object to initialize it for reading.
+//
+// When reading from a Pickle object, it is important for the consumer to know
+// what value types to read and in what order to read them as the Pickle does
+// not keep track of the type of data written to it.
+//
+// The Pickle's data has a header which contains the size of the Pickle's
+// payload.  It can optionally support additional space in the header.  That
+// space is controlled by the header_size parameter passed to the Pickle
+// constructor.
+//
+class BASE_EXPORT Pickle {
+ public:
+  // Initialize a Pickle object using the default header size.
+  Pickle();
+
+  // Initialize a Pickle object with the specified header size in bytes, which
+  // must be greater-than-or-equal-to sizeof(Pickle::Header).  The header size
+  // will be rounded up to ensure that the header size is 32bit-aligned.
+  explicit Pickle(int header_size);
+
+  // Initializes a Pickle from a const block of data.  The data is not copied;
+  // instead the data is merely referenced by this Pickle.  Only const methods
+  // should be used on the Pickle when initialized this way.  The header
+  // padding size is deduced from the data length.
+  Pickle(const char* data, int data_len);
+
+  // Initializes a Pickle as a deep copy of another Pickle.
+  Pickle(const Pickle& other);
+
+  // Note: There are no virtual methods in this class.  This destructor is
+  // virtual as an element of defensive coding.  Other classes have derived from
+  // this class, and there is a *chance* that they will cast into this base
+  // class before destruction.  At least one such class does have a virtual
+  // destructor, suggesting at least some need to call more derived destructors.
+  virtual ~Pickle();
+
+  // Performs a deep copy.
+  Pickle& operator=(const Pickle& other);
+
+  // Returns the number of bytes written in the Pickle, including the header.
+  size_t size() const { return header_size_ + header_->payload_size; }
+
+  // Returns the data for this Pickle.
+  const void* data() const { return header_; }
+
+  // Returns the effective memory capacity of this Pickle, that is, the total
+  // number of bytes currently dynamically allocated or 0 in the case of a
+  // read-only Pickle. This should be used only for diagnostic / profiling
+  // purposes.
+  size_t GetTotalAllocatedSize() const;
+
+  // Methods for adding to the payload of the Pickle.  These values are
+  // appended to the end of the Pickle's payload.  When reading values from a
+  // Pickle, it is important to read them in the order in which they were added
+  // to the Pickle.
+
+  bool WriteBool(bool value) {
+    return WriteInt(value ? 1 : 0);
+  }
+  bool WriteInt(int value) {
+    return WritePOD(value);
+  }
+  // WARNING: DO NOT USE THIS METHOD IF PICKLES ARE PERSISTED IN ANY WAY.
+  // It will write whatever a "long" is on this architecture. On 32-bit
+  // platforms, it is 32 bits. On 64-bit platforms, it is 64 bits. If persisted
+  // pickles are still around after upgrading to 64-bit, or if they are copied
+  // between dissimilar systems, YOUR PICKLES WILL HAVE GONE BAD.
+  bool WriteLongUsingDangerousNonPortableLessPersistableForm(long value) {
+    return WritePOD(value);
+  }
+  bool WriteUInt16(uint16 value) {
+    return WritePOD(value);
+  }
+  bool WriteUInt32(uint32 value) {
+    return WritePOD(value);
+  }
+  bool WriteInt64(int64 value) {
+    return WritePOD(value);
+  }
+  bool WriteUInt64(uint64 value) {
+    return WritePOD(value);
+  }
+  bool WriteSizeT(size_t value) {
+    // Always write size_t as a 64-bit value to ensure compatibility between
+    // 32-bit and 64-bit processes.
+    return WritePOD(static_cast<uint64>(value));
+  }
+  bool WriteFloat(float value) {
+    return WritePOD(value);
+  }
+  bool WriteDouble(double value) {
+    return WritePOD(value);
+  }
+  bool WriteString(const StringPiece& value);
+  bool WriteString16(const StringPiece16& value);
+  // "Data" is a blob with a length. When you read it out you will be given the
+  // length. See also WriteBytes.
+  bool WriteData(const char* data, int length);
+  // "Bytes" is a blob with no length. The caller must specify the length both
+  // when reading and writing. It is normally used to serialize PoD types of a
+  // known size. See also WriteData.
+  bool WriteBytes(const void* data, int length);
+
+  // Reserves space for upcoming writes when multiple writes will be made and
+  // their sizes are computed in advance. It can be significantly faster to call
+  // Reserve() before calling WriteFoo() multiple times.
+  void Reserve(size_t additional_capacity);
+
+  // Payload follows after allocation of Header (header size is customizable).
+  struct Header {
+    uint32 payload_size;  // Specifies the size of the payload.
+  };
+
+  // Returns the header, cast to a user-specified type T.  The type T must be a
+  // subclass of Header and its size must correspond to the header_size passed
+  // to the Pickle constructor.
+  template <class T>
+  T* headerT() {
+    DCHECK_EQ(header_size_, sizeof(T));
+    return static_cast<T*>(header_);
+  }
+  template <class T>
+  const T* headerT() const {
+    DCHECK_EQ(header_size_, sizeof(T));
+    return static_cast<const T*>(header_);
+  }
+
+  // The payload is the pickle data immediately following the header.
+  size_t payload_size() const {
+    return header_ ? header_->payload_size : 0;
+  }
+
+  const char* payload() const {
+    return reinterpret_cast<const char*>(header_) + header_size_;
+  }
+
+  // Returns the address of the byte immediately following the currently valid
+  // header + payload.
+  const char* end_of_payload() const {
+    // This object may be invalid.
+    return header_ ? payload() + payload_size() : NULL;
+  }
+
+ protected:
+  char* mutable_payload() {
+    return reinterpret_cast<char*>(header_) + header_size_;
+  }
+
+  size_t capacity_after_header() const {
+    return capacity_after_header_;
+  }
+
+  // Resize the capacity, note that the input value should not include the size
+  // of the header.
+  void Resize(size_t new_capacity);
+
+  // Aligns 'i' by rounding it up to the next multiple of 'alignment'
+  static size_t AlignInt(size_t i, int alignment) {
+    return i + (alignment - (i % alignment)) % alignment;
+  }
+
+  // Find the end of the pickled data that starts at range_start.  Returns NULL
+  // if the entire Pickle is not found in the given data range.
+  static const char* FindNext(size_t header_size,
+                              const char* range_start,
+                              const char* range_end);
+
+  // The allocation granularity of the payload.
+  static const int kPayloadUnit;
+
+ private:
+  friend class PickleIterator;
+
+  Header* header_;
+  size_t header_size_;  // Supports extra data between header and payload.
+  // Allocation size of payload (or -1 if allocation is const). Note: this
+  // doesn't count the header.
+  size_t capacity_after_header_;
+  // The offset at which we will write the next field. Note: this doesn't count
+  // the header.
+  size_t write_offset_;
+
+  // Just like WriteBytes, but with a compile-time size, for performance.
+  template<size_t length> void BASE_EXPORT WriteBytesStatic(const void* data);
+
+  // Writes a POD by copying its bytes.
+  template <typename T> bool WritePOD(const T& data) {
+    WriteBytesStatic<sizeof(data)>(&data);
+    return true;
+  }
+  inline void WriteBytesCommon(const void* data, size_t length);
+
+  FRIEND_TEST_ALL_PREFIXES(PickleTest, Resize);
+  FRIEND_TEST_ALL_PREFIXES(PickleTest, FindNext);
+  FRIEND_TEST_ALL_PREFIXES(PickleTest, FindNextWithIncompleteHeader);
+  FRIEND_TEST_ALL_PREFIXES(PickleTest, FindNextOverflow);
+};
+
+}  // namespace base
+
+#endif  // BASE_PICKLE_H_
diff --git a/base/pickle_unittest.cc b/base/pickle_unittest.cc
new file mode 100644
index 0000000..b0a8f21
--- /dev/null
+++ b/base/pickle_unittest.cc
@@ -0,0 +1,431 @@
+// Copyright (c) 2012 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 <string>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/pickle.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+const bool testbool1 = false;
+const bool testbool2 = true;
+const int testint = 2093847192;
+const long testlong = 1093847192;
+const uint16 testuint16 = 32123;
+const uint32 testuint32 = 1593847192;
+const int64 testint64 = -0x7E8CA9253104BDFCLL;
+const uint64 testuint64 = 0xCE8CA9253104BDF7ULL;
+const size_t testsizet = 0xFEDC7654;
+const float testfloat = 3.1415926935f;
+const double testdouble = 2.71828182845904523;
+const std::string teststring("Hello world");  // note non-aligned string length
+const std::wstring testwstring(L"Hello, world");
+const string16 teststring16(ASCIIToUTF16("Hello, world"));
+const char testrawstring[] = "Hello new world"; // Test raw string writing
+// Test raw char16 writing, assumes UTF16 encoding is ANSI for alpha chars.
+const char16 testrawstring16[] = {'A', 'l', 'o', 'h', 'a', 0};
+const char testdata[] = "AAA\0BBB\0";
+const int testdatalen = arraysize(testdata) - 1;
+
+// checks that the results can be read correctly from the Pickle
+void VerifyResult(const Pickle& pickle) {
+  PickleIterator iter(pickle);
+
+  bool outbool;
+  EXPECT_TRUE(iter.ReadBool(&outbool));
+  EXPECT_FALSE(outbool);
+  EXPECT_TRUE(iter.ReadBool(&outbool));
+  EXPECT_TRUE(outbool);
+
+  int outint;
+  EXPECT_TRUE(iter.ReadInt(&outint));
+  EXPECT_EQ(testint, outint);
+
+  long outlong;
+  EXPECT_TRUE(iter.ReadLong(&outlong));
+  EXPECT_EQ(testlong, outlong);
+
+  uint16 outuint16;
+  EXPECT_TRUE(iter.ReadUInt16(&outuint16));
+  EXPECT_EQ(testuint16, outuint16);
+
+  uint32 outuint32;
+  EXPECT_TRUE(iter.ReadUInt32(&outuint32));
+  EXPECT_EQ(testuint32, outuint32);
+
+  int64 outint64;
+  EXPECT_TRUE(iter.ReadInt64(&outint64));
+  EXPECT_EQ(testint64, outint64);
+
+  uint64 outuint64;
+  EXPECT_TRUE(iter.ReadUInt64(&outuint64));
+  EXPECT_EQ(testuint64, outuint64);
+
+  size_t outsizet;
+  EXPECT_TRUE(iter.ReadSizeT(&outsizet));
+  EXPECT_EQ(testsizet, outsizet);
+
+  float outfloat;
+  EXPECT_TRUE(iter.ReadFloat(&outfloat));
+  EXPECT_EQ(testfloat, outfloat);
+
+  double outdouble;
+  EXPECT_TRUE(iter.ReadDouble(&outdouble));
+  EXPECT_EQ(testdouble, outdouble);
+
+  std::string outstring;
+  EXPECT_TRUE(iter.ReadString(&outstring));
+  EXPECT_EQ(teststring, outstring);
+
+  string16 outstring16;
+  EXPECT_TRUE(iter.ReadString16(&outstring16));
+  EXPECT_EQ(teststring16, outstring16);
+
+  StringPiece outstringpiece;
+  EXPECT_TRUE(iter.ReadStringPiece(&outstringpiece));
+  EXPECT_EQ(testrawstring, outstringpiece);
+
+  StringPiece16 outstringpiece16;
+  EXPECT_TRUE(iter.ReadStringPiece16(&outstringpiece16));
+  EXPECT_EQ(testrawstring16, outstringpiece16);
+
+  const char* outdata;
+  int outdatalen;
+  EXPECT_TRUE(iter.ReadData(&outdata, &outdatalen));
+  EXPECT_EQ(testdatalen, outdatalen);
+  EXPECT_EQ(memcmp(testdata, outdata, outdatalen), 0);
+
+  // reads past the end should fail
+  EXPECT_FALSE(iter.ReadInt(&outint));
+}
+
+}  // namespace
+
+TEST(PickleTest, EncodeDecode) {
+  Pickle pickle;
+
+  EXPECT_TRUE(pickle.WriteBool(testbool1));
+  EXPECT_TRUE(pickle.WriteBool(testbool2));
+  EXPECT_TRUE(pickle.WriteInt(testint));
+  EXPECT_TRUE(
+      pickle.WriteLongUsingDangerousNonPortableLessPersistableForm(testlong));
+  EXPECT_TRUE(pickle.WriteUInt16(testuint16));
+  EXPECT_TRUE(pickle.WriteUInt32(testuint32));
+  EXPECT_TRUE(pickle.WriteInt64(testint64));
+  EXPECT_TRUE(pickle.WriteUInt64(testuint64));
+  EXPECT_TRUE(pickle.WriteSizeT(testsizet));
+  EXPECT_TRUE(pickle.WriteFloat(testfloat));
+  EXPECT_TRUE(pickle.WriteDouble(testdouble));
+  EXPECT_TRUE(pickle.WriteString(teststring));
+  EXPECT_TRUE(pickle.WriteString16(teststring16));
+  EXPECT_TRUE(pickle.WriteString(testrawstring));
+  EXPECT_TRUE(pickle.WriteString16(testrawstring16));
+  EXPECT_TRUE(pickle.WriteData(testdata, testdatalen));
+  VerifyResult(pickle);
+
+  // test copy constructor
+  Pickle pickle2(pickle);
+  VerifyResult(pickle2);
+
+  // test operator=
+  Pickle pickle3;
+  pickle3 = pickle;
+  VerifyResult(pickle3);
+}
+
+// Tests that reading/writing a size_t works correctly when the source process
+// is 64-bit.  We rely on having both 32- and 64-bit trybots to validate both
+// arms of the conditional in this test.
+TEST(PickleTest, SizeTFrom64Bit) {
+  Pickle pickle;
+  // Under the hood size_t is always written as a 64-bit value, so simulate a
+  // 64-bit size_t even on 32-bit architectures by explicitly writing a uint64.
+  EXPECT_TRUE(pickle.WriteUInt64(testuint64));
+
+  PickleIterator iter(pickle);
+  size_t outsizet;
+  if (sizeof(size_t) < sizeof(uint64)) {
+    // ReadSizeT() should return false when the original written value can't be
+    // represented as a size_t.
+    EXPECT_FALSE(iter.ReadSizeT(&outsizet));
+  } else {
+    EXPECT_TRUE(iter.ReadSizeT(&outsizet));
+    EXPECT_EQ(testuint64, outsizet);
+  }
+}
+
+// Tests that we can handle really small buffers.
+TEST(PickleTest, SmallBuffer) {
+  scoped_ptr<char[]> buffer(new char[1]);
+
+  // We should not touch the buffer.
+  Pickle pickle(buffer.get(), 1);
+
+  PickleIterator iter(pickle);
+  int data;
+  EXPECT_FALSE(iter.ReadInt(&data));
+}
+
+// Tests that we can handle improper headers.
+TEST(PickleTest, BigSize) {
+  int buffer[] = { 0x56035200, 25, 40, 50 };
+
+  Pickle pickle(reinterpret_cast<char*>(buffer), sizeof(buffer));
+
+  PickleIterator iter(pickle);
+  int data;
+  EXPECT_FALSE(iter.ReadInt(&data));
+}
+
+TEST(PickleTest, UnalignedSize) {
+  int buffer[] = { 10, 25, 40, 50 };
+
+  Pickle pickle(reinterpret_cast<char*>(buffer), sizeof(buffer));
+
+  PickleIterator iter(pickle);
+  int data;
+  EXPECT_FALSE(iter.ReadInt(&data));
+}
+
+TEST(PickleTest, ZeroLenStr) {
+  Pickle pickle;
+  EXPECT_TRUE(pickle.WriteString(std::string()));
+
+  PickleIterator iter(pickle);
+  std::string outstr;
+  EXPECT_TRUE(iter.ReadString(&outstr));
+  EXPECT_EQ("", outstr);
+}
+
+TEST(PickleTest, ZeroLenStr16) {
+  Pickle pickle;
+  EXPECT_TRUE(pickle.WriteString16(string16()));
+
+  PickleIterator iter(pickle);
+  std::string outstr;
+  EXPECT_TRUE(iter.ReadString(&outstr));
+  EXPECT_EQ("", outstr);
+}
+
+TEST(PickleTest, BadLenStr) {
+  Pickle pickle;
+  EXPECT_TRUE(pickle.WriteInt(-2));
+
+  PickleIterator iter(pickle);
+  std::string outstr;
+  EXPECT_FALSE(iter.ReadString(&outstr));
+}
+
+TEST(PickleTest, BadLenStr16) {
+  Pickle pickle;
+  EXPECT_TRUE(pickle.WriteInt(-1));
+
+  PickleIterator iter(pickle);
+  string16 outstr;
+  EXPECT_FALSE(iter.ReadString16(&outstr));
+}
+
+TEST(PickleTest, FindNext) {
+  Pickle pickle;
+  EXPECT_TRUE(pickle.WriteInt(1));
+  EXPECT_TRUE(pickle.WriteString("Domo"));
+
+  const char* start = reinterpret_cast<const char*>(pickle.data());
+  const char* end = start + pickle.size();
+
+  EXPECT_TRUE(end == Pickle::FindNext(pickle.header_size_, start, end));
+  EXPECT_TRUE(NULL == Pickle::FindNext(pickle.header_size_, start, end - 1));
+  EXPECT_TRUE(end == Pickle::FindNext(pickle.header_size_, start, end + 1));
+}
+
+TEST(PickleTest, FindNextWithIncompleteHeader) {
+  size_t header_size = sizeof(Pickle::Header);
+  scoped_ptr<char[]> buffer(new char[header_size - 1]);
+  memset(buffer.get(), 0x1, header_size - 1);
+
+  const char* start = buffer.get();
+  const char* end = start + header_size - 1;
+
+  EXPECT_TRUE(NULL == Pickle::FindNext(header_size, start, end));
+}
+
+#if defined(COMPILER_MSVC)
+#pragma warning(push)
+#pragma warning(disable: 4146)
+#endif
+TEST(PickleTest, FindNextOverflow) {
+  size_t header_size = sizeof(Pickle::Header);
+  size_t header_size2 = 2 * header_size;
+  size_t payload_received = 100;
+  scoped_ptr<char[]> buffer(new char[header_size2 + payload_received]);
+  const char* start = buffer.get();
+  Pickle::Header* header = reinterpret_cast<Pickle::Header*>(buffer.get());
+  const char* end = start + header_size2 + payload_received;
+  // It is impossible to construct an overflow test otherwise.
+  if (sizeof(size_t) > sizeof(header->payload_size) ||
+      sizeof(uintptr_t) > sizeof(header->payload_size))
+    return;
+
+  header->payload_size = -(reinterpret_cast<uintptr_t>(start) + header_size2);
+  EXPECT_TRUE(NULL == Pickle::FindNext(header_size2, start, end));
+
+  header->payload_size = -header_size2;
+  EXPECT_TRUE(NULL == Pickle::FindNext(header_size2, start, end));
+
+  header->payload_size = 0;
+  end = start + header_size;
+  EXPECT_TRUE(NULL == Pickle::FindNext(header_size2, start, end));
+}
+#if defined(COMPILER_MSVC)
+#pragma warning(pop)
+#endif
+
+TEST(PickleTest, GetReadPointerAndAdvance) {
+  Pickle pickle;
+
+  PickleIterator iter(pickle);
+  EXPECT_FALSE(iter.GetReadPointerAndAdvance(1));
+
+  EXPECT_TRUE(pickle.WriteInt(1));
+  EXPECT_TRUE(pickle.WriteInt(2));
+  int bytes = sizeof(int) * 2;
+
+  EXPECT_TRUE(PickleIterator(pickle).GetReadPointerAndAdvance(0));
+  EXPECT_TRUE(PickleIterator(pickle).GetReadPointerAndAdvance(1));
+  EXPECT_FALSE(PickleIterator(pickle).GetReadPointerAndAdvance(-1));
+  EXPECT_TRUE(PickleIterator(pickle).GetReadPointerAndAdvance(bytes));
+  EXPECT_FALSE(PickleIterator(pickle).GetReadPointerAndAdvance(bytes + 1));
+  EXPECT_FALSE(PickleIterator(pickle).GetReadPointerAndAdvance(INT_MAX));
+  EXPECT_FALSE(PickleIterator(pickle).GetReadPointerAndAdvance(INT_MIN));
+}
+
+TEST(PickleTest, Resize) {
+  size_t unit = Pickle::kPayloadUnit;
+  scoped_ptr<char[]> data(new char[unit]);
+  char* data_ptr = data.get();
+  for (size_t i = 0; i < unit; i++)
+    data_ptr[i] = 'G';
+
+  // construct a message that will be exactly the size of one payload unit,
+  // note that any data will have a 4-byte header indicating the size
+  const size_t payload_size_after_header = unit - sizeof(uint32);
+  Pickle pickle;
+  pickle.WriteData(data_ptr,
+      static_cast<int>(payload_size_after_header - sizeof(uint32)));
+  size_t cur_payload = payload_size_after_header;
+
+  // note: we assume 'unit' is a power of 2
+  EXPECT_EQ(unit, pickle.capacity_after_header());
+  EXPECT_EQ(pickle.payload_size(), payload_size_after_header);
+
+  // fill out a full page (noting data header)
+  pickle.WriteData(data_ptr, static_cast<int>(unit - sizeof(uint32)));
+  cur_payload += unit;
+  EXPECT_EQ(unit * 2, pickle.capacity_after_header());
+  EXPECT_EQ(cur_payload, pickle.payload_size());
+
+  // one more byte should double the capacity
+  pickle.WriteData(data_ptr, 1);
+  cur_payload += 8;
+  EXPECT_EQ(unit * 4, pickle.capacity_after_header());
+  EXPECT_EQ(cur_payload, pickle.payload_size());
+}
+
+namespace {
+
+struct CustomHeader : Pickle::Header {
+  int blah;
+};
+
+}  // namespace
+
+TEST(PickleTest, HeaderPadding) {
+  const uint32 kMagic = 0x12345678;
+
+  Pickle pickle(sizeof(CustomHeader));
+  pickle.WriteInt(kMagic);
+
+  // this should not overwrite the 'int' payload
+  pickle.headerT<CustomHeader>()->blah = 10;
+
+  PickleIterator iter(pickle);
+  int result;
+  ASSERT_TRUE(iter.ReadInt(&result));
+
+  EXPECT_EQ(static_cast<uint32>(result), kMagic);
+}
+
+TEST(PickleTest, EqualsOperator) {
+  Pickle source;
+  source.WriteInt(1);
+
+  Pickle copy_refs_source_buffer(static_cast<const char*>(source.data()),
+                                 source.size());
+  Pickle copy;
+  copy = copy_refs_source_buffer;
+  ASSERT_EQ(source.size(), copy.size());
+}
+
+TEST(PickleTest, EvilLengths) {
+  Pickle source;
+  std::string str(100000, 'A');
+  EXPECT_TRUE(source.WriteData(str.c_str(), 100000));
+  // ReadString16 used to have its read buffer length calculation wrong leading
+  // to out-of-bounds reading.
+  PickleIterator iter(source);
+  string16 str16;
+  EXPECT_FALSE(iter.ReadString16(&str16));
+
+  // And check we didn't break ReadString16.
+  str16 = (wchar_t) 'A';
+  Pickle str16_pickle;
+  EXPECT_TRUE(str16_pickle.WriteString16(str16));
+  iter = PickleIterator(str16_pickle);
+  EXPECT_TRUE(iter.ReadString16(&str16));
+  EXPECT_EQ(1U, str16.length());
+
+  // Check we don't fail in a length check with invalid String16 size.
+  // (1<<31) * sizeof(char16) == 0, so this is particularly evil.
+  Pickle bad_len;
+  EXPECT_TRUE(bad_len.WriteInt(1 << 31));
+  iter = PickleIterator(bad_len);
+  EXPECT_FALSE(iter.ReadString16(&str16));
+}
+
+// Check we can write zero bytes of data and 'data' can be NULL.
+TEST(PickleTest, ZeroLength) {
+  Pickle pickle;
+  EXPECT_TRUE(pickle.WriteData(NULL, 0));
+
+  PickleIterator iter(pickle);
+  const char* outdata;
+  int outdatalen;
+  EXPECT_TRUE(iter.ReadData(&outdata, &outdatalen));
+  EXPECT_EQ(0, outdatalen);
+  // We can't assert that outdata is NULL.
+}
+
+// Check that ReadBytes works properly with an iterator initialized to NULL.
+TEST(PickleTest, ReadBytes) {
+  Pickle pickle;
+  int data = 0x7abcd;
+  EXPECT_TRUE(pickle.WriteBytes(&data, sizeof(data)));
+
+  PickleIterator iter(pickle);
+  const char* outdata_char = NULL;
+  EXPECT_TRUE(iter.ReadBytes(&outdata_char, sizeof(data)));
+
+  int outdata;
+  memcpy(&outdata, outdata_char, sizeof(outdata));
+  EXPECT_EQ(data, outdata);
+}
+
+}  // namespace base
diff --git a/base/port.h b/base/port.h
new file mode 100644
index 0000000..ba61713
--- /dev/null
+++ b/base/port.h
@@ -0,0 +1,18 @@
+// Copyright (c) 2006-2008 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_PORT_H_
+#define BASE_PORT_H_
+
+#include <stdarg.h>
+#include "build/build_config.h"
+
+// Define an OS-neutral wrapper for shared library entry points
+#if defined(OS_WIN)
+#define API_CALL __stdcall
+#else
+#define API_CALL
+#endif
+
+#endif  // BASE_PORT_H_
diff --git a/base/posix/eintr_wrapper.h b/base/posix/eintr_wrapper.h
new file mode 100644
index 0000000..5a5dc75
--- /dev/null
+++ b/base/posix/eintr_wrapper.h
@@ -0,0 +1,67 @@
+// Copyright (c) 2012 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 provides a wrapper around system calls which may be interrupted by a
+// signal and return EINTR. See man 7 signal.
+// To prevent long-lasting loops (which would likely be a bug, such as a signal
+// that should be masked) to go unnoticed, there is a limit after which the
+// caller will nonetheless see an EINTR in Debug builds.
+//
+// On Windows, this wrapper macro does nothing.
+//
+// Don't wrap close calls in HANDLE_EINTR. Use IGNORE_EINTR if the return
+// value of close is significant. See http://crbug.com/269623.
+
+#ifndef BASE_POSIX_EINTR_WRAPPER_H_
+#define BASE_POSIX_EINTR_WRAPPER_H_
+
+#include "build/build_config.h"
+
+#if defined(OS_POSIX)
+
+#include <errno.h>
+
+#if defined(NDEBUG)
+
+#define HANDLE_EINTR(x) ({ \
+  decltype(x) eintr_wrapper_result; \
+  do { \
+    eintr_wrapper_result = (x); \
+  } while (eintr_wrapper_result == -1 && errno == EINTR); \
+  eintr_wrapper_result; \
+})
+
+#else
+
+#define HANDLE_EINTR(x) ({ \
+  int eintr_wrapper_counter = 0; \
+  decltype(x) eintr_wrapper_result; \
+  do { \
+    eintr_wrapper_result = (x); \
+  } while (eintr_wrapper_result == -1 && errno == EINTR && \
+           eintr_wrapper_counter++ < 100); \
+  eintr_wrapper_result; \
+})
+
+#endif  // NDEBUG
+
+#define IGNORE_EINTR(x) ({ \
+  decltype(x) eintr_wrapper_result; \
+  do { \
+    eintr_wrapper_result = (x); \
+    if (eintr_wrapper_result == -1 && errno == EINTR) { \
+      eintr_wrapper_result = 0; \
+    } \
+  } while (0); \
+  eintr_wrapper_result; \
+})
+
+#else
+
+#define HANDLE_EINTR(x) (x)
+#define IGNORE_EINTR(x) (x)
+
+#endif  // OS_POSIX
+
+#endif  // BASE_POSIX_EINTR_WRAPPER_H_
diff --git a/base/posix/file_descriptor_shuffle.cc b/base/posix/file_descriptor_shuffle.cc
new file mode 100644
index 0000000..d2fd39a
--- /dev/null
+++ b/base/posix/file_descriptor_shuffle.cc
@@ -0,0 +1,100 @@
+// Copyright (c) 2011 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/posix/file_descriptor_shuffle.h"
+
+#include <unistd.h>
+#include <stddef.h>
+#include <ostream>
+
+#include "base/posix/eintr_wrapper.h"
+#include "base/logging.h"
+
+namespace base {
+
+bool PerformInjectiveMultimapDestructive(
+    InjectiveMultimap* m, InjectionDelegate* delegate) {
+  static const size_t kMaxExtraFDs = 16;
+  int extra_fds[kMaxExtraFDs];
+  unsigned next_extra_fd = 0;
+
+  // DANGER: this function must not allocate or lock.
+  // Cannot use STL iterators here, since debug iterators use locks.
+
+  for (size_t i_index = 0; i_index < m->size(); ++i_index) {
+    InjectiveMultimap::value_type* i = &(*m)[i_index];
+    int temp_fd = -1;
+
+    // We DCHECK the injectiveness of the mapping.
+    for (size_t j_index = i_index + 1; j_index < m->size(); ++j_index) {
+      InjectiveMultimap::value_type* j = &(*m)[j_index];
+      DCHECK(i->dest != j->dest) << "Both fd " << i->source
+          << " and " << j->source << " map to " << i->dest;
+    }
+
+    const bool is_identity = i->source == i->dest;
+
+    for (size_t j_index = i_index + 1; j_index < m->size(); ++j_index) {
+      InjectiveMultimap::value_type* j = &(*m)[j_index];
+      if (!is_identity && i->dest == j->source) {
+        if (temp_fd == -1) {
+          if (!delegate->Duplicate(&temp_fd, i->dest))
+            return false;
+          if (next_extra_fd < kMaxExtraFDs) {
+            extra_fds[next_extra_fd++] = temp_fd;
+          } else {
+            RAW_LOG(ERROR, "PerformInjectiveMultimapDestructive overflowed "
+                           "extra_fds. Leaking file descriptors!");
+          }
+        }
+
+        j->source = temp_fd;
+        j->close = false;
+      }
+
+      if (i->close && i->source == j->dest)
+        i->close = false;
+
+      if (i->close && i->source == j->source) {
+        i->close = false;
+        j->close = true;
+      }
+    }
+
+    if (!is_identity) {
+      if (!delegate->Move(i->source, i->dest))
+        return false;
+    }
+
+    if (!is_identity && i->close)
+      delegate->Close(i->source);
+  }
+
+  for (unsigned i = 0; i < next_extra_fd; i++)
+    delegate->Close(extra_fds[i]);
+
+  return true;
+}
+
+bool PerformInjectiveMultimap(const InjectiveMultimap& m_in,
+                              InjectionDelegate* delegate) {
+  InjectiveMultimap m(m_in);
+  return PerformInjectiveMultimapDestructive(&m, delegate);
+}
+
+bool FileDescriptorTableInjection::Duplicate(int* result, int fd) {
+  *result = HANDLE_EINTR(dup(fd));
+  return *result >= 0;
+}
+
+bool FileDescriptorTableInjection::Move(int src, int dest) {
+  return HANDLE_EINTR(dup2(src, dest)) != -1;
+}
+
+void FileDescriptorTableInjection::Close(int fd) {
+  int ret = IGNORE_EINTR(close(fd));
+  DPCHECK(ret == 0);
+}
+
+}  // namespace base
diff --git a/base/posix/file_descriptor_shuffle.h b/base/posix/file_descriptor_shuffle.h
new file mode 100644
index 0000000..78e3a7d
--- /dev/null
+++ b/base/posix/file_descriptor_shuffle.h
@@ -0,0 +1,87 @@
+// Copyright (c) 2011 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_POSIX_FILE_DESCRIPTOR_SHUFFLE_H_
+#define BASE_POSIX_FILE_DESCRIPTOR_SHUFFLE_H_
+
+// This code exists to shuffle file descriptors, which is commonly needed when
+// forking subprocesses. The naive approach (just call dup2 to set up the
+// desired descriptors) is very simple, but wrong: it won't handle edge cases
+// (like mapping 0 -> 1, 1 -> 0) correctly.
+//
+// In order to unittest this code, it's broken into the abstract action (an
+// injective multimap) and the concrete code for dealing with file descriptors.
+// Users should use the code like this:
+//   base::InjectiveMultimap file_descriptor_map;
+//   file_descriptor_map.push_back(base::InjectionArc(devnull, 0, true));
+//   file_descriptor_map.push_back(base::InjectionArc(devnull, 2, true));
+//   file_descriptor_map.push_back(base::InjectionArc(pipe[1], 1, true));
+//   base::ShuffleFileDescriptors(file_descriptor_map);
+//
+// and trust the the Right Thing will get done.
+
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+
+namespace base {
+
+// A Delegate which performs the actions required to perform an injective
+// multimapping in place.
+class InjectionDelegate {
+ public:
+  // Duplicate |fd|, an element of the domain, and write a fresh element of the
+  // domain into |result|. Returns true iff successful.
+  virtual bool Duplicate(int* result, int fd) = 0;
+  // Destructively move |src| to |dest|, overwriting |dest|. Returns true iff
+  // successful.
+  virtual bool Move(int src, int dest) = 0;
+  // Delete an element of the domain.
+  virtual void Close(int fd) = 0;
+
+ protected:
+  virtual ~InjectionDelegate() {}
+};
+
+// An implementation of the InjectionDelegate interface using the file
+// descriptor table of the current process as the domain.
+class BASE_EXPORT FileDescriptorTableInjection : public InjectionDelegate {
+  bool Duplicate(int* result, int fd) override;
+  bool Move(int src, int dest) override;
+  void Close(int fd) override;
+};
+
+// A single arc of the directed graph which describes an injective multimapping.
+struct InjectionArc {
+  InjectionArc(int in_source, int in_dest, bool in_close)
+      : source(in_source),
+        dest(in_dest),
+        close(in_close) {
+  }
+
+  int source;
+  int dest;
+  bool close;  // if true, delete the source element after performing the
+               // mapping.
+};
+
+typedef std::vector<InjectionArc> InjectiveMultimap;
+
+BASE_EXPORT bool PerformInjectiveMultimap(const InjectiveMultimap& map,
+                                          InjectionDelegate* delegate);
+
+BASE_EXPORT bool PerformInjectiveMultimapDestructive(
+    InjectiveMultimap* map,
+    InjectionDelegate* delegate);
+
+// This function will not call malloc but will mutate |map|
+static inline bool ShuffleFileDescriptors(InjectiveMultimap* map) {
+  FileDescriptorTableInjection delegate;
+  return PerformInjectiveMultimapDestructive(map, &delegate);
+}
+
+}  // namespace base
+
+#endif  // BASE_POSIX_FILE_DESCRIPTOR_SHUFFLE_H_
diff --git a/base/posix/file_descriptor_shuffle_unittest.cc b/base/posix/file_descriptor_shuffle_unittest.cc
new file mode 100644
index 0000000..3dfbf7e
--- /dev/null
+++ b/base/posix/file_descriptor_shuffle_unittest.cc
@@ -0,0 +1,281 @@
+// Copyright (c) 2012 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/posix/file_descriptor_shuffle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// 'Duplicated' file descriptors start at this number
+const int kDuplicateBase = 1000;
+
+}  // namespace
+
+namespace base {
+
+struct Action {
+  enum Type {
+    CLOSE,
+    MOVE,
+    DUPLICATE,
+  };
+
+  Action(Type in_type, int in_fd1, int in_fd2 = -1)
+      : type(in_type),
+        fd1(in_fd1),
+        fd2(in_fd2) {
+  }
+
+  bool operator==(const Action& other) const {
+    return other.type == type &&
+           other.fd1 == fd1 &&
+           other.fd2 == fd2;
+  }
+
+  Type type;
+  int fd1;
+  int fd2;
+};
+
+class InjectionTracer : public InjectionDelegate {
+ public:
+  InjectionTracer()
+      : next_duplicate_(kDuplicateBase) {
+  }
+
+  bool Duplicate(int* result, int fd) override {
+    *result = next_duplicate_++;
+    actions_.push_back(Action(Action::DUPLICATE, *result, fd));
+    return true;
+  }
+
+  bool Move(int src, int dest) override {
+    actions_.push_back(Action(Action::MOVE, src, dest));
+    return true;
+  }
+
+  void Close(int fd) override { actions_.push_back(Action(Action::CLOSE, fd)); }
+
+  const std::vector<Action>& actions() const { return actions_; }
+
+ private:
+  int next_duplicate_;
+  std::vector<Action> actions_;
+};
+
+TEST(FileDescriptorShuffleTest, Empty) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  EXPECT_EQ(0u, tracer.actions().size());
+}
+
+TEST(FileDescriptorShuffleTest, Noop) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+  map.push_back(InjectionArc(0, 0, false));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  EXPECT_EQ(0u, tracer.actions().size());
+}
+
+TEST(FileDescriptorShuffleTest, NoopAndClose) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+  map.push_back(InjectionArc(0, 0, true));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  EXPECT_EQ(0u, tracer.actions().size());
+}
+
+TEST(FileDescriptorShuffleTest, Simple1) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+  map.push_back(InjectionArc(0, 1, false));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  ASSERT_EQ(1u, tracer.actions().size());
+  EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
+}
+
+TEST(FileDescriptorShuffleTest, Simple2) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+  map.push_back(InjectionArc(0, 1, false));
+  map.push_back(InjectionArc(2, 3, false));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  ASSERT_EQ(2u, tracer.actions().size());
+  EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
+  EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 2, 3));
+}
+
+TEST(FileDescriptorShuffleTest, Simple3) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+  map.push_back(InjectionArc(0, 1, true));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  ASSERT_EQ(2u, tracer.actions().size());
+  EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
+  EXPECT_TRUE(tracer.actions()[1] == Action(Action::CLOSE, 0));
+}
+
+TEST(FileDescriptorShuffleTest, Simple4) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+  map.push_back(InjectionArc(10, 0, true));
+  map.push_back(InjectionArc(1, 1, true));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  ASSERT_EQ(2u, tracer.actions().size());
+  EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 10, 0));
+  EXPECT_TRUE(tracer.actions()[1] == Action(Action::CLOSE, 10));
+}
+
+TEST(FileDescriptorShuffleTest, Cycle) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+  map.push_back(InjectionArc(0, 1, false));
+  map.push_back(InjectionArc(1, 0, false));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  ASSERT_EQ(4u, tracer.actions().size());
+  EXPECT_TRUE(tracer.actions()[0] ==
+              Action(Action::DUPLICATE, kDuplicateBase, 1));
+  EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 1));
+  EXPECT_TRUE(tracer.actions()[2] == Action(Action::MOVE, kDuplicateBase, 0));
+  EXPECT_TRUE(tracer.actions()[3] == Action(Action::CLOSE, kDuplicateBase));
+}
+
+TEST(FileDescriptorShuffleTest, CycleAndClose1) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+  map.push_back(InjectionArc(0, 1, true));
+  map.push_back(InjectionArc(1, 0, false));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  ASSERT_EQ(4u, tracer.actions().size());
+  EXPECT_TRUE(tracer.actions()[0] ==
+              Action(Action::DUPLICATE, kDuplicateBase, 1));
+  EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 1));
+  EXPECT_TRUE(tracer.actions()[2] == Action(Action::MOVE, kDuplicateBase, 0));
+  EXPECT_TRUE(tracer.actions()[3] == Action(Action::CLOSE, kDuplicateBase));
+}
+
+TEST(FileDescriptorShuffleTest, CycleAndClose2) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+  map.push_back(InjectionArc(0, 1, false));
+  map.push_back(InjectionArc(1, 0, true));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  ASSERT_EQ(4u, tracer.actions().size());
+  EXPECT_TRUE(tracer.actions()[0] ==
+              Action(Action::DUPLICATE, kDuplicateBase, 1));
+  EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 1));
+  EXPECT_TRUE(tracer.actions()[2] == Action(Action::MOVE, kDuplicateBase, 0));
+  EXPECT_TRUE(tracer.actions()[3] == Action(Action::CLOSE, kDuplicateBase));
+}
+
+TEST(FileDescriptorShuffleTest, CycleAndClose3) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+  map.push_back(InjectionArc(0, 1, true));
+  map.push_back(InjectionArc(1, 0, true));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  ASSERT_EQ(4u, tracer.actions().size());
+  EXPECT_TRUE(tracer.actions()[0] ==
+              Action(Action::DUPLICATE, kDuplicateBase, 1));
+  EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 1));
+  EXPECT_TRUE(tracer.actions()[2] == Action(Action::MOVE, kDuplicateBase, 0));
+  EXPECT_TRUE(tracer.actions()[3] == Action(Action::CLOSE, kDuplicateBase));
+}
+
+TEST(FileDescriptorShuffleTest, Fanout) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+  map.push_back(InjectionArc(0, 1, false));
+  map.push_back(InjectionArc(0, 2, false));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  ASSERT_EQ(2u, tracer.actions().size());
+  EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
+  EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 2));
+}
+
+TEST(FileDescriptorShuffleTest, FanoutAndClose1) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+  map.push_back(InjectionArc(0, 1, true));
+  map.push_back(InjectionArc(0, 2, false));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  ASSERT_EQ(3u, tracer.actions().size());
+  EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
+  EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 2));
+  EXPECT_TRUE(tracer.actions()[2] == Action(Action::CLOSE, 0));
+}
+
+TEST(FileDescriptorShuffleTest, FanoutAndClose2) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+  map.push_back(InjectionArc(0, 1, false));
+  map.push_back(InjectionArc(0, 2, true));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  ASSERT_EQ(3u, tracer.actions().size());
+  EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
+  EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 2));
+  EXPECT_TRUE(tracer.actions()[2] == Action(Action::CLOSE, 0));
+}
+
+TEST(FileDescriptorShuffleTest, FanoutAndClose3) {
+  InjectiveMultimap map;
+  InjectionTracer tracer;
+  map.push_back(InjectionArc(0, 1, true));
+  map.push_back(InjectionArc(0, 2, true));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &tracer));
+  ASSERT_EQ(3u, tracer.actions().size());
+  EXPECT_TRUE(tracer.actions()[0] == Action(Action::MOVE, 0, 1));
+  EXPECT_TRUE(tracer.actions()[1] == Action(Action::MOVE, 0, 2));
+  EXPECT_TRUE(tracer.actions()[2] == Action(Action::CLOSE, 0));
+}
+
+class FailingDelegate : public InjectionDelegate {
+ public:
+  bool Duplicate(int* result, int fd) override { return false; }
+
+  bool Move(int src, int dest) override { return false; }
+
+  void Close(int fd) override {}
+};
+
+TEST(FileDescriptorShuffleTest, EmptyWithFailure) {
+  InjectiveMultimap map;
+  FailingDelegate failing;
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &failing));
+}
+
+TEST(FileDescriptorShuffleTest, NoopWithFailure) {
+  InjectiveMultimap map;
+  FailingDelegate failing;
+  map.push_back(InjectionArc(0, 0, false));
+
+  EXPECT_TRUE(PerformInjectiveMultimap(map, &failing));
+}
+
+TEST(FileDescriptorShuffleTest, Simple1WithFailure) {
+  InjectiveMultimap map;
+  FailingDelegate failing;
+  map.push_back(InjectionArc(0, 1, false));
+
+  EXPECT_FALSE(PerformInjectiveMultimap(map, &failing));
+}
+
+}  // namespace base
diff --git a/base/posix/global_descriptors.cc b/base/posix/global_descriptors.cc
new file mode 100644
index 0000000..6c18783
--- /dev/null
+++ b/base/posix/global_descriptors.cc
@@ -0,0 +1,85 @@
+// Copyright (c) 2012 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/posix/global_descriptors.h"
+
+#include <vector>
+#include <utility>
+
+#include "base/logging.h"
+
+namespace base {
+
+GlobalDescriptors::Descriptor::Descriptor(Key key, int fd)
+    : key(key), fd(fd), region(base::MemoryMappedFile::Region::kWholeFile) {
+}
+
+GlobalDescriptors::Descriptor::Descriptor(Key key,
+                                          int fd,
+                                          base::MemoryMappedFile::Region region)
+    : key(key), fd(fd), region(region) {
+}
+
+// static
+GlobalDescriptors* GlobalDescriptors::GetInstance() {
+  typedef Singleton<base::GlobalDescriptors,
+                    LeakySingletonTraits<base::GlobalDescriptors> >
+      GlobalDescriptorsSingleton;
+  return GlobalDescriptorsSingleton::get();
+}
+
+int GlobalDescriptors::Get(Key key) const {
+  const int ret = MaybeGet(key);
+
+  if (ret == -1)
+    DLOG(FATAL) << "Unknown global descriptor: " << key;
+  return ret;
+}
+
+int GlobalDescriptors::MaybeGet(Key key) const {
+  for (Mapping::const_iterator
+       i = descriptors_.begin(); i != descriptors_.end(); ++i) {
+    if (i->key == key)
+      return i->fd;
+  }
+
+  return -1;
+}
+
+void GlobalDescriptors::Set(Key key, int fd) {
+  Set(key, fd, base::MemoryMappedFile::Region::kWholeFile);
+}
+
+void GlobalDescriptors::Set(Key key,
+                            int fd,
+                            base::MemoryMappedFile::Region region) {
+  for (auto& i : descriptors_) {
+    if (i.key == key) {
+      i.fd = fd;
+      i.region = region;
+      return;
+    }
+  }
+
+  descriptors_.push_back(Descriptor(key, fd, region));
+}
+
+base::MemoryMappedFile::Region GlobalDescriptors::GetRegion(Key key) const {
+  for (const auto& i : descriptors_) {
+    if (i.key == key)
+      return i.region;
+  }
+  DLOG(FATAL) << "Unknown global descriptor: " << key;
+  return base::MemoryMappedFile::Region::kWholeFile;
+}
+
+void GlobalDescriptors::Reset(const Mapping& mapping) {
+  descriptors_ = mapping;
+}
+
+GlobalDescriptors::GlobalDescriptors() {}
+
+GlobalDescriptors::~GlobalDescriptors() {}
+
+}  // namespace base
diff --git a/base/posix/global_descriptors.h b/base/posix/global_descriptors.h
new file mode 100644
index 0000000..c774634
--- /dev/null
+++ b/base/posix/global_descriptors.h
@@ -0,0 +1,92 @@
+// Copyright (c) 2012 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_POSIX_GLOBAL_DESCRIPTORS_H_
+#define BASE_POSIX_GLOBAL_DESCRIPTORS_H_
+
+#include "build/build_config.h"
+
+#include <vector>
+#include <utility>
+
+#include <stdint.h>
+
+#include "base/files/memory_mapped_file.h"
+#include "base/memory/singleton.h"
+
+namespace base {
+
+// It's common practice to install file descriptors into well known slot
+// numbers before execing a child; stdin, stdout and stderr are ubiqutous
+// examples.
+//
+// However, when using a zygote model, this becomes troublesome. Since the
+// descriptors which need to be in these slots generally aren't known, any code
+// could open a resource and take one of the reserved descriptors. Simply
+// overwriting the slot isn't a viable solution.
+//
+// We could try to fill the reserved slots as soon as possible, but this is a
+// fragile solution since global constructors etc are able to open files.
+//
+// Instead, we retreat from the idea of installing descriptors in specific
+// slots and add a layer of indirection in the form of this singleton object.
+// It maps from an abstract key to a descriptor. If independent modules each
+// need to define keys, then values should be chosen randomly so as not to
+// collide.
+class BASE_EXPORT GlobalDescriptors {
+ public:
+  typedef uint32_t Key;
+  struct Descriptor {
+    Descriptor(Key key, int fd);
+    Descriptor(Key key, int fd, base::MemoryMappedFile::Region region);
+
+    // Globally unique key.
+    Key key;
+    // Actual FD.
+    int fd;
+    // Optional region, defaults to kWholeFile.
+    base::MemoryMappedFile::Region region;
+  };
+  typedef std::vector<Descriptor> Mapping;
+
+  // Often we want a canonical descriptor for a given Key. In this case, we add
+  // the following constant to the key value:
+#if !defined(OS_ANDROID)
+  static const int kBaseDescriptor = 3;  // 0, 1, 2 are already taken.
+#else
+  static const int kBaseDescriptor = 4;  // 3 used by __android_log_write().
+#endif
+
+  // Return the singleton instance of GlobalDescriptors.
+  static GlobalDescriptors* GetInstance();
+
+  // Get a descriptor given a key. It is a fatal error if the key is not known.
+  int Get(Key key) const;
+
+  // Get a descriptor given a key. Returns -1 on error.
+  int MaybeGet(Key key) const;
+
+  // Get a region given a key. It is a fatal error if the key is not known.
+  base::MemoryMappedFile::Region GetRegion(Key key) const;
+
+  // Set the descriptor for the given |key|. This sets the region associated
+  // with |key| to kWholeFile.
+  void Set(Key key, int fd);
+
+  // Set the descriptor and |region| for the given |key|.
+  void Set(Key key, int fd, base::MemoryMappedFile::Region region);
+
+  void Reset(const Mapping& mapping);
+
+ private:
+  friend struct DefaultSingletonTraits<GlobalDescriptors>;
+  GlobalDescriptors();
+  ~GlobalDescriptors();
+
+  Mapping descriptors_;
+};
+
+}  // namespace base
+
+#endif  // BASE_POSIX_GLOBAL_DESCRIPTORS_H_
diff --git a/base/posix/safe_strerror.cc b/base/posix/safe_strerror.cc
new file mode 100644
index 0000000..e80e8f8
--- /dev/null
+++ b/base/posix/safe_strerror.cc
@@ -0,0 +1,124 @@
+// Copyright (c) 2006-2009 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.
+
+#if defined(__ANDROID__)
+// Post-L versions of bionic define the GNU-specific strerror_r if _GNU_SOURCE
+// is defined, but the symbol is renamed to __gnu_strerror_r which only exists
+// on those later versions. To preserve ABI compatibility with older versions,
+// undefine _GNU_SOURCE and use the POSIX version.
+#undef _GNU_SOURCE
+#endif
+
+#include "base/posix/safe_strerror.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "build/build_config.h"
+
+namespace base {
+
+#define USE_HISTORICAL_STRERRO_R (defined(__GLIBC__) || defined(OS_NACL))
+
+#if USE_HISTORICAL_STRERRO_R && defined(__GNUC__)
+// GCC will complain about the unused second wrap function unless we tell it
+// that we meant for them to be potentially unused, which is exactly what this
+// attribute is for.
+#define POSSIBLY_UNUSED __attribute__((unused))
+#else
+#define POSSIBLY_UNUSED
+#endif
+
+#if USE_HISTORICAL_STRERRO_R
+// glibc has two strerror_r functions: a historical GNU-specific one that
+// returns type char *, and a POSIX.1-2001 compliant one available since 2.3.4
+// that returns int. This wraps the GNU-specific one.
+static void POSSIBLY_UNUSED wrap_posix_strerror_r(
+    char *(*strerror_r_ptr)(int, char *, size_t),
+    int err,
+    char *buf,
+    size_t len) {
+  // GNU version.
+  char *rc = (*strerror_r_ptr)(err, buf, len);
+  if (rc != buf) {
+    // glibc did not use buf and returned a static string instead. Copy it
+    // into buf.
+    buf[0] = '\0';
+    strncat(buf, rc, len - 1);
+  }
+  // The GNU version never fails. Unknown errors get an "unknown error" message.
+  // The result is always null terminated.
+}
+#endif  // USE_HISTORICAL_STRERRO_R
+
+// Wrapper for strerror_r functions that implement the POSIX interface. POSIX
+// does not define the behaviour for some of the edge cases, so we wrap it to
+// guarantee that they are handled. This is compiled on all POSIX platforms, but
+// it will only be used on Linux if the POSIX strerror_r implementation is
+// being used (see below).
+static void POSSIBLY_UNUSED wrap_posix_strerror_r(
+    int (*strerror_r_ptr)(int, char *, size_t),
+    int err,
+    char *buf,
+    size_t len) {
+  int old_errno = errno;
+  // Have to cast since otherwise we get an error if this is the GNU version
+  // (but in such a scenario this function is never called). Sadly we can't use
+  // C++-style casts because the appropriate one is reinterpret_cast but it's
+  // considered illegal to reinterpret_cast a type to itself, so we get an
+  // error in the opposite case.
+  int result = (*strerror_r_ptr)(err, buf, len);
+  if (result == 0) {
+    // POSIX is vague about whether the string will be terminated, although
+    // it indirectly implies that typically ERANGE will be returned, instead
+    // of truncating the string. We play it safe by always terminating the
+    // string explicitly.
+    buf[len - 1] = '\0';
+  } else {
+    // Error. POSIX is vague about whether the return value is itself a system
+    // error code or something else. On Linux currently it is -1 and errno is
+    // set. On BSD-derived systems it is a system error and errno is unchanged.
+    // We try and detect which case it is so as to put as much useful info as
+    // we can into our message.
+    int strerror_error;  // The error encountered in strerror
+    int new_errno = errno;
+    if (new_errno != old_errno) {
+      // errno was changed, so probably the return value is just -1 or something
+      // else that doesn't provide any info, and errno is the error.
+      strerror_error = new_errno;
+    } else {
+      // Either the error from strerror_r was the same as the previous value, or
+      // errno wasn't used. Assume the latter.
+      strerror_error = result;
+    }
+    // snprintf truncates and always null-terminates.
+    snprintf(buf,
+             len,
+             "Error %d while retrieving error %d",
+             strerror_error,
+             err);
+  }
+  errno = old_errno;
+}
+
+void safe_strerror_r(int err, char *buf, size_t len) {
+  if (buf == NULL || len <= 0) {
+    return;
+  }
+  // If using glibc (i.e., Linux), the compiler will automatically select the
+  // appropriate overloaded function based on the function type of strerror_r.
+  // The other one will be elided from the translation unit since both are
+  // static.
+  wrap_posix_strerror_r(&strerror_r, err, buf, len);
+}
+
+std::string safe_strerror(int err) {
+  const int buffer_size = 256;
+  char buf[buffer_size];
+  safe_strerror_r(err, buf, sizeof(buf));
+  return std::string(buf);
+}
+
+}  // namespace base
diff --git a/base/posix/safe_strerror.h b/base/posix/safe_strerror.h
new file mode 100644
index 0000000..862a750
--- /dev/null
+++ b/base/posix/safe_strerror.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2011 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_POSIX_SAFE_STRERROR_H_
+#define BASE_POSIX_SAFE_STRERROR_H_
+
+#include <string>
+
+#include "base/base_export.h"
+
+namespace base {
+
+// BEFORE using anything from this file, first look at PLOG and friends in
+// logging.h and use them instead if applicable.
+//
+// This file declares safe, portable alternatives to the POSIX strerror()
+// function. strerror() is inherently unsafe in multi-threaded apps and should
+// never be used. Doing so can cause crashes. Additionally, the thread-safe
+// alternative strerror_r varies in semantics across platforms. Use these
+// functions instead.
+
+// Thread-safe strerror function with dependable semantics that never fails.
+// It will write the string form of error "err" to buffer buf of length len.
+// If there is an error calling the OS's strerror_r() function then a message to
+// that effect will be printed into buf, truncating if necessary. The final
+// result is always null-terminated. The value of errno is never changed.
+//
+// Use this instead of strerror_r().
+BASE_EXPORT void safe_strerror_r(int err, char *buf, size_t len);
+
+// Calls safe_strerror_r with a buffer of suitable size and returns the result
+// in a C++ string.
+//
+// Use this instead of strerror(). Note though that safe_strerror_r will be
+// more robust in the case of heap corruption errors, since it doesn't need to
+// allocate a string.
+BASE_EXPORT std::string safe_strerror(int err);
+
+}  // namespace base
+
+#endif  // BASE_POSIX_SAFE_STRERROR_H_
diff --git a/base/posix/unix_domain_socket_linux.cc b/base/posix/unix_domain_socket_linux.cc
new file mode 100644
index 0000000..62c930f
--- /dev/null
+++ b/base/posix/unix_domain_socket_linux.cc
@@ -0,0 +1,245 @@
+// Copyright (c) 2011 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/posix/unix_domain_socket_linux.h"
+
+#include <errno.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include <vector>
+
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/memory/scoped_vector.h"
+#include "base/pickle.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/stl_util.h"
+
+#if !defined(OS_NACL_NONSFI)
+#include <sys/uio.h>
+#endif
+
+namespace base {
+
+const size_t UnixDomainSocket::kMaxFileDescriptors = 16;
+
+#if !defined(OS_NACL_NONSFI)
+// Creates a connected pair of UNIX-domain SOCK_SEQPACKET sockets, and passes
+// ownership of the newly allocated file descriptors to |one| and |two|.
+// Returns true on success.
+static bool CreateSocketPair(ScopedFD* one, ScopedFD* two) {
+  int raw_socks[2];
+  if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, raw_socks) == -1)
+    return false;
+  one->reset(raw_socks[0]);
+  two->reset(raw_socks[1]);
+  return true;
+}
+
+// static
+bool UnixDomainSocket::EnableReceiveProcessId(int fd) {
+  const int enable = 1;
+  return setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &enable, sizeof(enable)) == 0;
+}
+#endif  // !defined(OS_NACL_NONSFI)
+
+// static
+bool UnixDomainSocket::SendMsg(int fd,
+                               const void* buf,
+                               size_t length,
+                               const std::vector<int>& fds) {
+  struct msghdr msg = {};
+  struct iovec iov = { const_cast<void*>(buf), length };
+  msg.msg_iov = &iov;
+  msg.msg_iovlen = 1;
+
+  char* control_buffer = NULL;
+  if (fds.size()) {
+    const unsigned control_len = CMSG_SPACE(sizeof(int) * fds.size());
+    control_buffer = new char[control_len];
+
+    struct cmsghdr* cmsg;
+    msg.msg_control = control_buffer;
+    msg.msg_controllen = control_len;
+    cmsg = CMSG_FIRSTHDR(&msg);
+    cmsg->cmsg_level = SOL_SOCKET;
+    cmsg->cmsg_type = SCM_RIGHTS;
+    cmsg->cmsg_len = CMSG_LEN(sizeof(int) * fds.size());
+    memcpy(CMSG_DATA(cmsg), &fds[0], sizeof(int) * fds.size());
+    msg.msg_controllen = cmsg->cmsg_len;
+  }
+
+  // Avoid a SIGPIPE if the other end breaks the connection.
+  // Due to a bug in the Linux kernel (net/unix/af_unix.c) MSG_NOSIGNAL isn't
+  // regarded for SOCK_SEQPACKET in the AF_UNIX domain, but it is mandated by
+  // POSIX.
+  const int flags = MSG_NOSIGNAL;
+  const ssize_t r = HANDLE_EINTR(sendmsg(fd, &msg, flags));
+  const bool ret = static_cast<ssize_t>(length) == r;
+  delete[] control_buffer;
+  return ret;
+}
+
+// static
+ssize_t UnixDomainSocket::RecvMsg(int fd,
+                                  void* buf,
+                                  size_t length,
+                                  ScopedVector<ScopedFD>* fds) {
+  return UnixDomainSocket::RecvMsgWithPid(fd, buf, length, fds, NULL);
+}
+
+// static
+ssize_t UnixDomainSocket::RecvMsgWithPid(int fd,
+                                         void* buf,
+                                         size_t length,
+                                         ScopedVector<ScopedFD>* fds,
+                                         ProcessId* pid) {
+  return UnixDomainSocket::RecvMsgWithFlags(fd, buf, length, 0, fds, pid);
+}
+
+// static
+ssize_t UnixDomainSocket::RecvMsgWithFlags(int fd,
+                                           void* buf,
+                                           size_t length,
+                                           int flags,
+                                           ScopedVector<ScopedFD>* fds,
+                                           ProcessId* out_pid) {
+  fds->clear();
+
+  struct msghdr msg = {};
+  struct iovec iov = { buf, length };
+  msg.msg_iov = &iov;
+  msg.msg_iovlen = 1;
+
+  const size_t kControlBufferSize =
+      CMSG_SPACE(sizeof(int) * kMaxFileDescriptors)
+#if !defined(OS_NACL_NONSFI)
+      // The PNaCl toolchain for Non-SFI binary build does not support ucred.
+      + CMSG_SPACE(sizeof(struct ucred))
+#endif
+      ;
+  char control_buffer[kControlBufferSize];
+  msg.msg_control = control_buffer;
+  msg.msg_controllen = sizeof(control_buffer);
+
+  const ssize_t r = HANDLE_EINTR(recvmsg(fd, &msg, flags));
+  if (r == -1)
+    return -1;
+
+  int* wire_fds = NULL;
+  unsigned wire_fds_len = 0;
+  ProcessId pid = -1;
+
+  if (msg.msg_controllen > 0) {
+    struct cmsghdr* cmsg;
+    for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+      const unsigned payload_len = cmsg->cmsg_len - CMSG_LEN(0);
+      if (cmsg->cmsg_level == SOL_SOCKET &&
+          cmsg->cmsg_type == SCM_RIGHTS) {
+        DCHECK_EQ(payload_len % sizeof(int), 0u);
+        DCHECK_EQ(wire_fds, static_cast<void*>(nullptr));
+        wire_fds = reinterpret_cast<int*>(CMSG_DATA(cmsg));
+        wire_fds_len = payload_len / sizeof(int);
+      }
+#if !defined(OS_NACL_NONSFI)
+      // The PNaCl toolchain for Non-SFI binary build does not support
+      // SCM_CREDENTIALS.
+      if (cmsg->cmsg_level == SOL_SOCKET &&
+          cmsg->cmsg_type == SCM_CREDENTIALS) {
+        DCHECK_EQ(payload_len, sizeof(struct ucred));
+        DCHECK_EQ(pid, -1);
+        pid = reinterpret_cast<struct ucred*>(CMSG_DATA(cmsg))->pid;
+      }
+#endif
+    }
+  }
+
+  if (msg.msg_flags & MSG_TRUNC || msg.msg_flags & MSG_CTRUNC) {
+    for (unsigned i = 0; i < wire_fds_len; ++i)
+      close(wire_fds[i]);
+    errno = EMSGSIZE;
+    return -1;
+  }
+
+  if (wire_fds) {
+    for (unsigned i = 0; i < wire_fds_len; ++i)
+      fds->push_back(new ScopedFD(wire_fds[i]));
+  }
+
+  if (out_pid) {
+    // |pid| will legitimately be -1 if we read EOF, so only DCHECK if we
+    // actually received a message.  Unfortunately, Linux allows sending zero
+    // length messages, which are indistinguishable from EOF, so this check
+    // has false negatives.
+    if (r > 0 || msg.msg_controllen > 0)
+      DCHECK_GE(pid, 0);
+
+    *out_pid = pid;
+  }
+
+  return r;
+}
+
+#if !defined(OS_NACL_NONSFI)
+// static
+ssize_t UnixDomainSocket::SendRecvMsg(int fd,
+                                      uint8_t* reply,
+                                      unsigned max_reply_len,
+                                      int* result_fd,
+                                      const Pickle& request) {
+  return UnixDomainSocket::SendRecvMsgWithFlags(fd, reply, max_reply_len,
+                                                0,  /* recvmsg_flags */
+                                                result_fd, request);
+}
+
+// static
+ssize_t UnixDomainSocket::SendRecvMsgWithFlags(int fd,
+                                               uint8_t* reply,
+                                               unsigned max_reply_len,
+                                               int recvmsg_flags,
+                                               int* result_fd,
+                                               const Pickle& request) {
+  // This socketpair is only used for the IPC and is cleaned up before
+  // returning.
+  ScopedFD recv_sock, send_sock;
+  if (!CreateSocketPair(&recv_sock, &send_sock))
+    return -1;
+
+  {
+    std::vector<int> send_fds;
+    send_fds.push_back(send_sock.get());
+    if (!SendMsg(fd, request.data(), request.size(), send_fds))
+      return -1;
+  }
+
+  // Close the sending end of the socket right away so that if our peer closes
+  // it before sending a response (e.g., from exiting), RecvMsgWithFlags() will
+  // return EOF instead of hanging.
+  send_sock.reset();
+
+  ScopedVector<ScopedFD> recv_fds;
+  // When porting to OSX keep in mind it doesn't support MSG_NOSIGNAL, so the
+  // sender might get a SIGPIPE.
+  const ssize_t reply_len = RecvMsgWithFlags(
+      recv_sock.get(), reply, max_reply_len, recvmsg_flags, &recv_fds, NULL);
+  recv_sock.reset();
+  if (reply_len == -1)
+    return -1;
+
+  // If we received more file descriptors than caller expected, then we treat
+  // that as an error.
+  if (recv_fds.size() > (result_fd != NULL ? 1 : 0)) {
+    NOTREACHED();
+    return -1;
+  }
+
+  if (result_fd)
+    *result_fd = recv_fds.empty() ? -1 : recv_fds[0]->release();
+
+  return reply_len;
+}
+#endif  // !defined(OS_NACL_NONSFI)
+
+}  // namespace base
diff --git a/base/posix/unix_domain_socket_linux.h b/base/posix/unix_domain_socket_linux.h
new file mode 100644
index 0000000..94da4b4
--- /dev/null
+++ b/base/posix/unix_domain_socket_linux.h
@@ -0,0 +1,103 @@
+// Copyright (c) 2011 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_POSIX_UNIX_DOMAIN_SOCKET_LINUX_H_
+#define BASE_POSIX_UNIX_DOMAIN_SOCKET_LINUX_H_
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/files/scoped_file.h"
+#include "base/memory/scoped_vector.h"
+#include "base/process/process_handle.h"
+
+namespace base {
+
+class Pickle;
+
+class BASE_EXPORT UnixDomainSocket {
+ public:
+  // Maximum number of file descriptors that can be read by RecvMsg().
+  static const size_t kMaxFileDescriptors;
+
+#if !defined(OS_NACL_NONSFI)
+  // Use to enable receiving process IDs in RecvMsgWithPid.  Should be called on
+  // the receiving socket (i.e., the socket passed to RecvMsgWithPid). Returns
+  // true if successful.
+  static bool EnableReceiveProcessId(int fd);
+#endif  // !defined(OS_NACL_NONSFI)
+
+  // Use sendmsg to write the given msg and include a vector of file
+  // descriptors. Returns true if successful.
+  static bool SendMsg(int fd,
+                      const void* msg,
+                      size_t length,
+                      const std::vector<int>& fds);
+
+  // Use recvmsg to read a message and an array of file descriptors. Returns
+  // -1 on failure. Note: will read, at most, |kMaxFileDescriptors| descriptors.
+  static ssize_t RecvMsg(int fd,
+                         void* msg,
+                         size_t length,
+                         ScopedVector<ScopedFD>* fds);
+
+  // Same as RecvMsg above, but also returns the sender's process ID (as seen
+  // from the caller's namespace).  However, before using this function to
+  // receive process IDs, EnableReceiveProcessId() should be called on the
+  // receiving socket.
+  static ssize_t RecvMsgWithPid(int fd,
+                                void* msg,
+                                size_t length,
+                                ScopedVector<ScopedFD>* fds,
+                                ProcessId* pid);
+
+#if !defined(OS_NACL_NONSFI)
+  // Perform a sendmsg/recvmsg pair.
+  //   1. This process creates a UNIX SEQPACKET socketpair. Using
+  //      connection-oriented sockets (SEQPACKET or STREAM) is critical here,
+  //      because if one of the ends closes the other one must be notified.
+  //   2. This process writes a request to |fd| with an SCM_RIGHTS control
+  //      message containing on end of the fresh socket pair.
+  //   3. This process blocks reading from the other end of the fresh
+  //      socketpair.
+  //   4. The target process receives the request, processes it and writes the
+  //      reply to the end of the socketpair contained in the request.
+  //   5. This process wakes up and continues.
+  //
+  //   fd: descriptor to send the request on
+  //   reply: buffer for the reply
+  //   reply_len: size of |reply|
+  //   result_fd: (may be NULL) the file descriptor returned in the reply
+  //              (if any)
+  //   request: the bytes to send in the request
+  static ssize_t SendRecvMsg(int fd,
+                             uint8_t* reply,
+                             unsigned reply_len,
+                             int* result_fd,
+                             const Pickle& request);
+
+  // Similar to SendRecvMsg(), but |recvmsg_flags| allows to control the flags
+  // of the recvmsg(2) call.
+  static ssize_t SendRecvMsgWithFlags(int fd,
+                                      uint8_t* reply,
+                                      unsigned reply_len,
+                                      int recvmsg_flags,
+                                      int* result_fd,
+                                      const Pickle& request);
+#endif  // !defined(OS_NACL_NONSFI)
+ private:
+  // Similar to RecvMsg, but allows to specify |flags| for recvmsg(2).
+  static ssize_t RecvMsgWithFlags(int fd,
+                                  void* msg,
+                                  size_t length,
+                                  int flags,
+                                  ScopedVector<ScopedFD>* fds,
+                                  ProcessId* pid);
+};
+
+}  // namespace base
+
+#endif  // BASE_POSIX_UNIX_DOMAIN_SOCKET_LINUX_H_
diff --git a/base/posix/unix_domain_socket_linux_unittest.cc b/base/posix/unix_domain_socket_linux_unittest.cc
new file mode 100644
index 0000000..175ec52
--- /dev/null
+++ b/base/posix/unix_domain_socket_linux_unittest.cc
@@ -0,0 +1,161 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
+#include "base/location.h"
+#include "base/memory/scoped_vector.h"
+#include "base/pickle.h"
+#include "base/posix/unix_domain_socket_linux.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+TEST(UnixDomainSocketTest, SendRecvMsgAbortOnReplyFDClose) {
+  Thread message_thread("UnixDomainSocketTest");
+  ASSERT_TRUE(message_thread.Start());
+
+  int fds[2];
+  ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds));
+  ScopedFD scoped_fd0(fds[0]);
+  ScopedFD scoped_fd1(fds[1]);
+
+  // Have the thread send a synchronous message via the socket.
+  Pickle request;
+  message_thread.task_runner()->PostTask(
+      FROM_HERE,
+      Bind(IgnoreResult(&UnixDomainSocket::SendRecvMsg), fds[1],
+           static_cast<uint8_t*>(NULL), 0U, static_cast<int*>(NULL), request));
+
+  // Receive the message.
+  ScopedVector<ScopedFD> message_fds;
+  uint8_t buffer[16];
+  ASSERT_EQ(static_cast<int>(request.size()),
+            UnixDomainSocket::RecvMsg(fds[0], buffer, sizeof(buffer),
+                                      &message_fds));
+  ASSERT_EQ(1U, message_fds.size());
+
+  // Close the reply FD.
+  message_fds.clear();
+
+  // Check that the thread didn't get blocked.
+  WaitableEvent event(false, false);
+  message_thread.task_runner()->PostTask(
+      FROM_HERE, Bind(&WaitableEvent::Signal, Unretained(&event)));
+  ASSERT_TRUE(event.TimedWait(TimeDelta::FromMilliseconds(5000)));
+}
+
+TEST(UnixDomainSocketTest, SendRecvMsgAvoidsSIGPIPE) {
+  // Make sure SIGPIPE isn't being ignored.
+  struct sigaction act = {}, oldact;
+  act.sa_handler = SIG_DFL;
+  ASSERT_EQ(0, sigaction(SIGPIPE, &act, &oldact));
+  int fds[2];
+  ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds));
+  ScopedFD scoped_fd1(fds[1]);
+  ASSERT_EQ(0, IGNORE_EINTR(close(fds[0])));
+
+  // Have the thread send a synchronous message via the socket. Unless the
+  // message is sent with MSG_NOSIGNAL, this shall result in SIGPIPE.
+  Pickle request;
+  ASSERT_EQ(-1,
+      UnixDomainSocket::SendRecvMsg(fds[1], static_cast<uint8_t*>(NULL),
+                                    0U, static_cast<int*>(NULL), request));
+  ASSERT_EQ(EPIPE, errno);
+  // Restore the SIGPIPE handler.
+  ASSERT_EQ(0, sigaction(SIGPIPE, &oldact, NULL));
+}
+
+// Simple sanity check within a single process that receiving PIDs works.
+TEST(UnixDomainSocketTest, RecvPid) {
+  int fds[2];
+  ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds));
+  ScopedFD recv_sock(fds[0]);
+  ScopedFD send_sock(fds[1]);
+
+  ASSERT_TRUE(UnixDomainSocket::EnableReceiveProcessId(recv_sock.get()));
+
+  static const char kHello[] = "hello";
+  ASSERT_TRUE(UnixDomainSocket::SendMsg(
+      send_sock.get(), kHello, sizeof(kHello), std::vector<int>()));
+
+  // Extra receiving buffer space to make sure we really received only
+  // sizeof(kHello) bytes and it wasn't just truncated to fit the buffer.
+  char buf[sizeof(kHello) + 1];
+  ProcessId sender_pid;
+  ScopedVector<ScopedFD> fd_vec;
+  const ssize_t nread = UnixDomainSocket::RecvMsgWithPid(
+      recv_sock.get(), buf, sizeof(buf), &fd_vec, &sender_pid);
+  ASSERT_EQ(sizeof(kHello), static_cast<size_t>(nread));
+  ASSERT_EQ(0, memcmp(buf, kHello, sizeof(kHello)));
+  ASSERT_EQ(0U, fd_vec.size());
+
+  ASSERT_EQ(getpid(), sender_pid);
+}
+
+// Same as above, but send the max number of file descriptors too.
+TEST(UnixDomainSocketTest, RecvPidWithMaxDescriptors) {
+  int fds[2];
+  ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds));
+  ScopedFD recv_sock(fds[0]);
+  ScopedFD send_sock(fds[1]);
+
+  ASSERT_TRUE(UnixDomainSocket::EnableReceiveProcessId(recv_sock.get()));
+
+  static const char kHello[] = "hello";
+  std::vector<int> send_fds(UnixDomainSocket::kMaxFileDescriptors,
+                            send_sock.get());
+  ASSERT_TRUE(UnixDomainSocket::SendMsg(
+      send_sock.get(), kHello, sizeof(kHello), send_fds));
+
+  // Extra receiving buffer space to make sure we really received only
+  // sizeof(kHello) bytes and it wasn't just truncated to fit the buffer.
+  char buf[sizeof(kHello) + 1];
+  ProcessId sender_pid;
+  ScopedVector<ScopedFD> recv_fds;
+  const ssize_t nread = UnixDomainSocket::RecvMsgWithPid(
+      recv_sock.get(), buf, sizeof(buf), &recv_fds, &sender_pid);
+  ASSERT_EQ(sizeof(kHello), static_cast<size_t>(nread));
+  ASSERT_EQ(0, memcmp(buf, kHello, sizeof(kHello)));
+  ASSERT_EQ(UnixDomainSocket::kMaxFileDescriptors, recv_fds.size());
+
+  ASSERT_EQ(getpid(), sender_pid);
+}
+
+// Check that RecvMsgWithPid doesn't DCHECK fail when reading EOF from a
+// disconnected socket.
+TEST(UnixDomianSocketTest, RecvPidDisconnectedSocket) {
+  int fds[2];
+  ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_SEQPACKET, 0, fds));
+  ScopedFD recv_sock(fds[0]);
+  ScopedFD send_sock(fds[1]);
+
+  ASSERT_TRUE(UnixDomainSocket::EnableReceiveProcessId(recv_sock.get()));
+
+  send_sock.reset();
+
+  char ch;
+  ProcessId sender_pid;
+  ScopedVector<ScopedFD> recv_fds;
+  const ssize_t nread = UnixDomainSocket::RecvMsgWithPid(
+      recv_sock.get(), &ch, sizeof(ch), &recv_fds, &sender_pid);
+  ASSERT_EQ(0, nread);
+  ASSERT_EQ(-1, sender_pid);
+  ASSERT_EQ(0U, recv_fds.size());
+}
+
+}  // namespace
+
+}  // namespace base
diff --git a/base/power_monitor/power_monitor.cc b/base/power_monitor/power_monitor.cc
new file mode 100644
index 0000000..98c9c68
--- /dev/null
+++ b/base/power_monitor/power_monitor.cc
@@ -0,0 +1,62 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/power_monitor/power_monitor.h"
+#include "base/power_monitor/power_monitor_source.h"
+
+namespace base {
+
+static PowerMonitor* g_power_monitor = NULL;
+
+PowerMonitor::PowerMonitor(scoped_ptr<PowerMonitorSource> source)
+    : observers_(new ObserverListThreadSafe<PowerObserver>()),
+      source_(source.Pass()) {
+  DCHECK(!g_power_monitor);
+  g_power_monitor = this;
+}
+
+PowerMonitor::~PowerMonitor() {
+  DCHECK_EQ(this, g_power_monitor);
+  g_power_monitor = NULL;
+}
+
+// static
+PowerMonitor* PowerMonitor::Get() {
+  return g_power_monitor;
+}
+
+void PowerMonitor::AddObserver(PowerObserver* obs) {
+  observers_->AddObserver(obs);
+}
+
+void PowerMonitor::RemoveObserver(PowerObserver* obs) {
+  observers_->RemoveObserver(obs);
+}
+
+PowerMonitorSource* PowerMonitor::Source() {
+  return source_.get();
+}
+
+bool PowerMonitor::IsOnBatteryPower() {
+  return source_->IsOnBatteryPower();
+}
+
+void PowerMonitor::NotifyPowerStateChange(bool battery_in_use) {
+  DVLOG(1) << "PowerStateChange: " << (battery_in_use ? "On" : "Off")
+           << " battery";
+  observers_->Notify(FROM_HERE, &PowerObserver::OnPowerStateChange,
+                     battery_in_use);
+}
+
+void PowerMonitor::NotifySuspend() {
+  DVLOG(1) << "Power Suspending";
+  observers_->Notify(FROM_HERE, &PowerObserver::OnSuspend);
+}
+
+void PowerMonitor::NotifyResume() {
+  DVLOG(1) << "Power Resuming";
+  observers_->Notify(FROM_HERE, &PowerObserver::OnResume);
+}
+
+}  // namespace base
diff --git a/base/power_monitor/power_monitor.h b/base/power_monitor/power_monitor.h
new file mode 100644
index 0000000..4acb3bf
--- /dev/null
+++ b/base/power_monitor/power_monitor.h
@@ -0,0 +1,55 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_POWER_MONITOR_POWER_MONITOR_H_
+#define BASE_POWER_MONITOR_POWER_MONITOR_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/observer_list_threadsafe.h"
+#include "base/power_monitor/power_observer.h"
+
+namespace base {
+
+class PowerMonitorSource;
+
+// A class used to monitor the power state change and notify the observers about
+// the change event.
+class BASE_EXPORT PowerMonitor {
+ public:
+  // Takes ownership of |source|.
+  explicit PowerMonitor(scoped_ptr<PowerMonitorSource> source);
+  ~PowerMonitor();
+
+  // Get the process-wide PowerMonitor (if not present, returns NULL).
+  static PowerMonitor* Get();
+
+  // Add and remove an observer.
+  // Can be called from any thread.
+  // Must not be called from within a notification callback.
+  void AddObserver(PowerObserver* observer);
+  void RemoveObserver(PowerObserver* observer);
+
+  // Is the computer currently on battery power.
+  bool IsOnBatteryPower();
+
+ private:
+  friend class PowerMonitorSource;
+
+  PowerMonitorSource* Source();
+
+  void NotifyPowerStateChange(bool battery_in_use);
+  void NotifySuspend();
+  void NotifyResume();
+
+  scoped_refptr<ObserverListThreadSafe<PowerObserver> > observers_;
+  scoped_ptr<PowerMonitorSource> source_;
+
+  DISALLOW_COPY_AND_ASSIGN(PowerMonitor);
+};
+
+}  // namespace base
+
+#endif  // BASE_POWER_MONITOR_POWER_MONITOR_H_
diff --git a/base/power_monitor/power_monitor_device_source.cc b/base/power_monitor/power_monitor_device_source.cc
new file mode 100644
index 0000000..0a39975
--- /dev/null
+++ b/base/power_monitor/power_monitor_device_source.cc
@@ -0,0 +1,39 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/power_monitor/power_monitor_device_source.h"
+
+#include "base/time/time.h"
+
+namespace base {
+
+#if defined(ENABLE_BATTERY_MONITORING)
+// The amount of time (in ms) to wait before running the initial
+// battery check.
+static int kDelayedBatteryCheckMs = 10 * 1000;
+#endif  // defined(ENABLE_BATTERY_MONITORING)
+
+PowerMonitorDeviceSource::PowerMonitorDeviceSource() {
+  DCHECK(MessageLoop::current());
+#if defined(ENABLE_BATTERY_MONITORING)
+  delayed_battery_check_.Start(FROM_HERE,
+      base::TimeDelta::FromMilliseconds(kDelayedBatteryCheckMs), this,
+      &PowerMonitorDeviceSource::BatteryCheck);
+#endif  // defined(ENABLE_BATTERY_MONITORING)
+#if defined(OS_MACOSX)
+  PlatformInit();
+#endif
+}
+
+PowerMonitorDeviceSource::~PowerMonitorDeviceSource() {
+#if defined(OS_MACOSX)
+  PlatformDestroy();
+#endif
+}
+
+void PowerMonitorDeviceSource::BatteryCheck() {
+  ProcessPowerEvent(PowerMonitorSource::POWER_STATE_EVENT);
+}
+
+}  // namespace base
diff --git a/base/power_monitor/power_monitor_device_source.h b/base/power_monitor/power_monitor_device_source.h
new file mode 100644
index 0000000..29f17c2
--- /dev/null
+++ b/base/power_monitor/power_monitor_device_source.h
@@ -0,0 +1,117 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_POWER_MONITOR_POWER_MONITOR_DEVICE_SOURCE_H_
+#define BASE_POWER_MONITOR_POWER_MONITOR_DEVICE_SOURCE_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/observer_list_threadsafe.h"
+#include "base/power_monitor/power_monitor_source.h"
+#include "base/power_monitor/power_observer.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+
+// Windows HiRes timers drain the battery faster so we need to know the battery
+// status.  This isn't true for other platforms.
+#define ENABLE_BATTERY_MONITORING 1
+#else
+#undef ENABLE_BATTERY_MONITORING
+#endif  // !OS_WIN
+
+#if defined(ENABLE_BATTERY_MONITORING)
+#include "base/timer/timer.h"
+#endif  // defined(ENABLE_BATTERY_MONITORING)
+
+#if defined(OS_IOS)
+#include <objc/runtime.h>
+#endif  // OS_IOS
+
+namespace base {
+
+// A class used to monitor the power state change and notify the observers about
+// the change event.
+class BASE_EXPORT PowerMonitorDeviceSource : public PowerMonitorSource {
+ public:
+  PowerMonitorDeviceSource();
+  ~PowerMonitorDeviceSource() override;
+
+#if defined(OS_MACOSX)
+  // Allocate system resources needed by the PowerMonitor class.
+  //
+  // This function must be called before instantiating an instance of the class
+  // and before the Sandbox is initialized.
+#if !defined(OS_IOS)
+  static void AllocateSystemIOPorts();
+#else
+  static void AllocateSystemIOPorts() {}
+#endif  // OS_IOS
+#endif  // OS_MACOSX
+
+#if defined(OS_CHROMEOS)
+  // On Chrome OS, Chrome receives power-related events from powerd, the system
+  // power daemon, via D-Bus signals received on the UI thread. base can't
+  // directly depend on that code, so this class instead exposes static methods
+  // so that events can be passed in.
+  static void SetPowerSource(bool on_battery);
+  static void HandleSystemSuspending();
+  static void HandleSystemResumed();
+#endif
+
+ private:
+#if defined(OS_WIN)
+  // Represents a message-only window for power message handling on Windows.
+  // Only allow PowerMonitor to create it.
+  class PowerMessageWindow {
+   public:
+    PowerMessageWindow();
+    ~PowerMessageWindow();
+
+   private:
+    static LRESULT CALLBACK WndProcThunk(HWND hwnd,
+                                         UINT message,
+                                         WPARAM wparam,
+                                         LPARAM lparam);
+    // Instance of the module containing the window procedure.
+    HMODULE instance_;
+    // A hidden message-only window.
+    HWND message_hwnd_;
+  };
+#endif  // OS_WIN
+
+#if defined(OS_MACOSX)
+  void PlatformInit();
+  void PlatformDestroy();
+#endif
+
+  // Platform-specific method to check whether the system is currently
+  // running on battery power.  Returns true if running on batteries,
+  // false otherwise.
+  bool IsOnBatteryPowerImpl() override;
+
+  // Checks the battery status and notifies observers if the battery
+  // status has changed.
+  void BatteryCheck();
+
+#if defined(OS_IOS)
+  // Holds pointers to system event notification observers.
+  std::vector<id> notification_observers_;
+#endif
+
+#if defined(ENABLE_BATTERY_MONITORING)
+  base::OneShotTimer<PowerMonitorDeviceSource> delayed_battery_check_;
+#endif
+
+#if defined(OS_WIN)
+  PowerMessageWindow power_message_window_;
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(PowerMonitorDeviceSource);
+};
+
+}  // namespace base
+
+#endif  // BASE_POWER_MONITOR_POWER_MONITOR_DEVICE_SOURCE_H_
diff --git a/base/power_monitor/power_monitor_device_source_android.cc b/base/power_monitor/power_monitor_device_source_android.cc
new file mode 100644
index 0000000..4d9eb52
--- /dev/null
+++ b/base/power_monitor/power_monitor_device_source_android.cc
@@ -0,0 +1,45 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/power_monitor/power_monitor_device_source_android.h"
+
+#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 "jni/PowerMonitor_jni.h"
+
+namespace base {
+
+// A helper function which is a friend of PowerMonitorSource.
+void ProcessPowerEventHelper(PowerMonitorSource::PowerEvent event) {
+  PowerMonitorSource::ProcessPowerEvent(event);
+}
+
+namespace android {
+
+// Native implementation of PowerMonitor.java.
+void OnBatteryChargingChanged(JNIEnv* env, jclass clazz) {
+  ProcessPowerEventHelper(PowerMonitorSource::POWER_STATE_EVENT);
+}
+
+void OnMainActivityResumed(JNIEnv* env, jclass clazz) {
+  ProcessPowerEventHelper(PowerMonitorSource::RESUME_EVENT);
+}
+
+void OnMainActivitySuspended(JNIEnv* env, jclass clazz) {
+  ProcessPowerEventHelper(PowerMonitorSource::SUSPEND_EVENT);
+}
+
+}  // namespace android
+
+bool PowerMonitorDeviceSource::IsOnBatteryPowerImpl() {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  return base::android::Java_PowerMonitor_isBatteryPower(env);
+}
+
+bool RegisterPowerMonitor(JNIEnv* env) {
+  return base::android::RegisterNativesImpl(env);
+}
+
+}  // namespace base
diff --git a/base/power_monitor/power_monitor_device_source_android.h b/base/power_monitor/power_monitor_device_source_android.h
new file mode 100644
index 0000000..024f95a
--- /dev/null
+++ b/base/power_monitor/power_monitor_device_source_android.h
@@ -0,0 +1,17 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_POWER_MONITOR_POWER_MONITOR_DEVICE_SOURCE_ANDROID_H_
+#define BASE_POWER_MONITOR_POWER_MONITOR_DEVICE_SOURCE_ANDROID_H_
+
+#include <jni.h>
+
+namespace base {
+
+// Registers the JNI bindings for PowerMonitorDeviceSource.
+bool RegisterPowerMonitor(JNIEnv* env);
+
+}  // namespace base
+
+#endif  // BASE_POWER_MONITOR_POWER_MONITOR_DEVICE_SOURCE_ANDROID_H_
diff --git a/base/power_monitor/power_monitor_device_source_chromeos.cc b/base/power_monitor/power_monitor_device_source_chromeos.cc
new file mode 100644
index 0000000..c3466ee
--- /dev/null
+++ b/base/power_monitor/power_monitor_device_source_chromeos.cc
@@ -0,0 +1,40 @@
+// 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.
+
+#include "base/power_monitor/power_monitor.h"
+#include "base/power_monitor/power_monitor_device_source.h"
+#include "base/power_monitor/power_monitor_source.h"
+
+namespace base {
+
+namespace {
+
+// The most-recently-seen power source.
+bool g_on_battery = false;
+
+}  // namespace
+
+// static
+void PowerMonitorDeviceSource::SetPowerSource(bool on_battery) {
+  if (on_battery != g_on_battery) {
+    g_on_battery = on_battery;
+    ProcessPowerEvent(POWER_STATE_EVENT);
+  }
+}
+
+// static
+void PowerMonitorDeviceSource::HandleSystemSuspending() {
+  ProcessPowerEvent(SUSPEND_EVENT);
+}
+
+// static
+void PowerMonitorDeviceSource::HandleSystemResumed() {
+  ProcessPowerEvent(RESUME_EVENT);
+}
+
+bool PowerMonitorDeviceSource::IsOnBatteryPowerImpl() {
+  return g_on_battery;
+}
+
+}  // namespace base
diff --git a/base/power_monitor/power_monitor_device_source_ios.mm b/base/power_monitor/power_monitor_device_source_ios.mm
new file mode 100644
index 0000000..dc12f1c
--- /dev/null
+++ b/base/power_monitor/power_monitor_device_source_ios.mm
@@ -0,0 +1,40 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/power_monitor/power_monitor_device_source.h"
+
+#import <UIKit/UIKit.h>
+
+namespace base {
+
+void PowerMonitorDeviceSource::PlatformInit() {
+  NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
+  id foreground =
+      [nc addObserverForName:UIApplicationWillEnterForegroundNotification
+                      object:nil
+                       queue:nil
+                  usingBlock:^(NSNotification* notification) {
+                      ProcessPowerEvent(RESUME_EVENT);
+                  }];
+  id background =
+      [nc addObserverForName:UIApplicationDidEnterBackgroundNotification
+                      object:nil
+                       queue:nil
+                  usingBlock:^(NSNotification* notification) {
+                      ProcessPowerEvent(SUSPEND_EVENT);
+                  }];
+  notification_observers_.push_back(foreground);
+  notification_observers_.push_back(background);
+}
+
+void PowerMonitorDeviceSource::PlatformDestroy() {
+  NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
+  for (std::vector<id>::iterator it = notification_observers_.begin();
+       it != notification_observers_.end(); ++it) {
+    [nc removeObserver:*it];
+  }
+  notification_observers_.clear();
+}
+
+}  // namespace base
diff --git a/base/power_monitor/power_monitor_device_source_mac.mm b/base/power_monitor/power_monitor_device_source_mac.mm
new file mode 100644
index 0000000..8c48117
--- /dev/null
+++ b/base/power_monitor/power_monitor_device_source_mac.mm
@@ -0,0 +1,107 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Implementation based on sample code from
+// http://developer.apple.com/library/mac/#qa/qa1340/_index.html.
+
+#include "base/power_monitor/power_monitor_device_source.h"
+
+#include "base/power_monitor/power_monitor.h"
+#include "base/power_monitor/power_monitor_source.h"
+
+#include <IOKit/IOMessage.h>
+#include <IOKit/pwr_mgt/IOPMLib.h>
+
+namespace base {
+
+void ProcessPowerEventHelper(PowerMonitorSource::PowerEvent event) {
+  PowerMonitorSource::ProcessPowerEvent(event);
+}
+
+namespace {
+
+io_connect_t g_system_power_io_port = 0;
+IONotificationPortRef g_notification_port_ref = 0;
+io_object_t g_notifier_object = 0;
+
+void SystemPowerEventCallback(void*,
+                              io_service_t service,
+                              natural_t message_type,
+                              void* message_argument) {
+  switch (message_type) {
+    // If this message is not handled the system may delay sleep for 30 seconds.
+    case kIOMessageCanSystemSleep:
+      IOAllowPowerChange(g_system_power_io_port,
+          reinterpret_cast<intptr_t>(message_argument));
+      break;
+    case kIOMessageSystemWillSleep:
+      ProcessPowerEventHelper(base::PowerMonitorSource::SUSPEND_EVENT);
+      IOAllowPowerChange(g_system_power_io_port,
+          reinterpret_cast<intptr_t>(message_argument));
+      break;
+
+    case kIOMessageSystemWillPowerOn:
+      ProcessPowerEventHelper(PowerMonitorSource::RESUME_EVENT);
+      break;
+  }
+}
+
+}  // namespace
+
+// The reason we can't include this code in the constructor is because
+// PlatformInit() requires an active runloop and the IO port needs to be
+// allocated at sandbox initialization time, before there's a runloop.
+// See crbug.com/83783 .
+
+// static
+void PowerMonitorDeviceSource::AllocateSystemIOPorts() {
+  DCHECK_EQ(g_system_power_io_port, 0u);
+
+  // Notification port allocated by IORegisterForSystemPower.
+  g_system_power_io_port = IORegisterForSystemPower(
+      NULL, &g_notification_port_ref, SystemPowerEventCallback,
+      &g_notifier_object);
+
+  DCHECK_NE(g_system_power_io_port, 0u);
+}
+
+void PowerMonitorDeviceSource::PlatformInit() {
+  // Need to call AllocateSystemIOPorts() before creating a PowerMonitor
+  // object.
+  DCHECK_NE(g_system_power_io_port, 0u);
+  if (g_system_power_io_port == 0)
+    return;
+
+  // Add the notification port to the application runloop
+  CFRunLoopAddSource(
+      CFRunLoopGetCurrent(),
+      IONotificationPortGetRunLoopSource(g_notification_port_ref),
+      kCFRunLoopCommonModes);
+}
+
+void PowerMonitorDeviceSource::PlatformDestroy() {
+  DCHECK_NE(g_system_power_io_port, 0u);
+  if (g_system_power_io_port == 0)
+    return;
+
+  // Remove the sleep notification port from the application runloop
+  CFRunLoopRemoveSource(
+      CFRunLoopGetCurrent(),
+      IONotificationPortGetRunLoopSource(g_notification_port_ref),
+      kCFRunLoopCommonModes);
+
+  // Deregister for system sleep notifications
+  IODeregisterForSystemPower(&g_notifier_object);
+
+  // IORegisterForSystemPower implicitly opens the Root Power Domain IOService,
+  // so we close it here.
+  IOServiceClose(g_system_power_io_port);
+
+  g_system_power_io_port = 0;
+
+  // Destroy the notification port allocated by IORegisterForSystemPower.
+  IONotificationPortDestroy(g_notification_port_ref);
+}
+
+}  // namespace base
diff --git a/base/power_monitor/power_monitor_device_source_posix.cc b/base/power_monitor/power_monitor_device_source_posix.cc
new file mode 100644
index 0000000..f24e5b2
--- /dev/null
+++ b/base/power_monitor/power_monitor_device_source_posix.cc
@@ -0,0 +1,14 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/power_monitor/power_monitor_device_source.h"
+
+namespace base {
+
+bool PowerMonitorDeviceSource::IsOnBatteryPowerImpl() {
+  NOTIMPLEMENTED();
+  return false;
+}
+
+}  // namespace base
diff --git a/base/power_monitor/power_monitor_device_source_win.cc b/base/power_monitor/power_monitor_device_source_win.cc
new file mode 100644
index 0000000..69bc6aa
--- /dev/null
+++ b/base/power_monitor/power_monitor_device_source_win.cc
@@ -0,0 +1,111 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#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 {
+
+void ProcessPowerEventHelper(PowerMonitorSource::PowerEvent event) {
+  PowerMonitorSource::ProcessPowerEvent(event);
+}
+
+namespace {
+
+const wchar_t kWindowClassName[] = L"Base_PowerMessageWindow";
+
+void ProcessWmPowerBroadcastMessage(WPARAM event_id) {
+  PowerMonitorSource::PowerEvent power_event;
+  switch (event_id) {
+    case PBT_APMPOWERSTATUSCHANGE:  // The power status changed.
+      power_event = PowerMonitorSource::POWER_STATE_EVENT;
+      break;
+    case PBT_APMRESUMEAUTOMATIC:  // Resume from suspend.
+      //case PBT_APMRESUMESUSPEND:  // User-initiated resume from suspend.
+      // We don't notify for this latter event
+      // because if it occurs it is always sent as a
+      // second event after PBT_APMRESUMEAUTOMATIC.
+      power_event = PowerMonitorSource::RESUME_EVENT;
+      break;
+    case PBT_APMSUSPEND:  // System has been suspended.
+      power_event = PowerMonitorSource::SUSPEND_EVENT;
+      break;
+    default:
+      return;
+
+      // Other Power Events:
+      // PBT_APMBATTERYLOW - removed in Vista.
+      // PBT_APMOEMEVENT - removed in Vista.
+      // PBT_APMQUERYSUSPEND - removed in Vista.
+      // PBT_APMQUERYSUSPENDFAILED - removed in Vista.
+      // PBT_APMRESUMECRITICAL - removed in Vista.
+      // PBT_POWERSETTINGCHANGE - user changed the power settings.
+  }
+
+  ProcessPowerEventHelper(power_event);
+}
+
+}  // namespace
+
+// Function to query the system to see if it is currently running on
+// battery power.  Returns true if running on battery.
+bool PowerMonitorDeviceSource::IsOnBatteryPowerImpl() {
+  SYSTEM_POWER_STATUS status;
+  if (!GetSystemPowerStatus(&status)) {
+    DPLOG(ERROR) << "GetSystemPowerStatus failed";
+    return false;
+  }
+  return (status.ACLineStatus == 0);
+}
+
+PowerMonitorDeviceSource::PowerMessageWindow::PowerMessageWindow()
+    : instance_(NULL), message_hwnd_(NULL) {
+  if (!MessageLoopForUI::IsCurrent()) {
+    // Creating this window in (e.g.) a renderer inhibits shutdown on Windows.
+    // See http://crbug.com/230122. TODO(vandebo): http://crbug.com/236031
+    DLOG(ERROR)
+        << "Cannot create windows on non-UI thread, power monitor disabled!";
+    return;
+  }
+  WNDCLASSEX window_class;
+  base::win::InitializeWindowClass(
+      kWindowClassName,
+      &base::win::WrappedWindowProc<
+          PowerMonitorDeviceSource::PowerMessageWindow::WndProcThunk>,
+      0, 0, 0, NULL, NULL, NULL, NULL, NULL,
+      &window_class);
+  instance_ = window_class.hInstance;
+  ATOM clazz = RegisterClassEx(&window_class);
+  DCHECK(clazz);
+
+  message_hwnd_ = CreateWindowEx(WS_EX_NOACTIVATE, kWindowClassName,
+      NULL, WS_POPUP, 0, 0, 0, 0, NULL, NULL, instance_, NULL);
+}
+
+PowerMonitorDeviceSource::PowerMessageWindow::~PowerMessageWindow() {
+  if (message_hwnd_) {
+    DestroyWindow(message_hwnd_);
+    UnregisterClass(kWindowClassName, instance_);
+  }
+}
+
+// static
+LRESULT CALLBACK PowerMonitorDeviceSource::PowerMessageWindow::WndProcThunk(
+    HWND hwnd,
+    UINT message,
+    WPARAM wparam,
+    LPARAM lparam) {
+  switch (message) {
+    case WM_POWERBROADCAST:
+      ProcessWmPowerBroadcastMessage(wparam);
+      return TRUE;
+    default:
+      return ::DefWindowProc(hwnd, message, wparam, lparam);
+  }
+}
+
+}  // namespace base
diff --git a/base/power_monitor/power_monitor_source.cc b/base/power_monitor/power_monitor_source.cc
new file mode 100644
index 0000000..6868cb1
--- /dev/null
+++ b/base/power_monitor/power_monitor_source.cc
@@ -0,0 +1,66 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/power_monitor/power_monitor_source.h"
+
+#include "base/power_monitor/power_monitor.h"
+
+namespace base {
+
+PowerMonitorSource::PowerMonitorSource()
+    : on_battery_power_(false),
+      suspended_(false) {
+}
+
+PowerMonitorSource::~PowerMonitorSource() {
+}
+
+bool PowerMonitorSource::IsOnBatteryPower() {
+  AutoLock auto_lock(battery_lock_);
+  return on_battery_power_;
+}
+
+void PowerMonitorSource::ProcessPowerEvent(PowerEvent event_id) {
+  PowerMonitor* monitor = PowerMonitor::Get();
+  if (!monitor)
+    return;
+
+  PowerMonitorSource* source = monitor->Source();
+
+  // Suppress duplicate notifications.  Some platforms may
+  // send multiple notifications of the same event.
+  switch (event_id) {
+    case POWER_STATE_EVENT:
+      {
+        bool new_on_battery_power = source->IsOnBatteryPowerImpl();
+        bool changed = false;
+
+        {
+          AutoLock auto_lock(source->battery_lock_);
+          if (source->on_battery_power_ != new_on_battery_power) {
+              changed = true;
+              source->on_battery_power_ = new_on_battery_power;
+          }
+        }
+
+        if (changed)
+          monitor->NotifyPowerStateChange(new_on_battery_power);
+      }
+      break;
+    case RESUME_EVENT:
+      if (source->suspended_) {
+        source->suspended_ = false;
+        monitor->NotifyResume();
+      }
+      break;
+    case SUSPEND_EVENT:
+      if (!source->suspended_) {
+        source->suspended_ = true;
+        monitor->NotifySuspend();
+      }
+      break;
+  }
+}
+
+}  // namespace base
diff --git a/base/power_monitor/power_monitor_source.h b/base/power_monitor/power_monitor_source.h
new file mode 100644
index 0000000..b8f4185
--- /dev/null
+++ b/base/power_monitor/power_monitor_source.h
@@ -0,0 +1,65 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_POWER_MONITOR_POWER_MONITOR_SOURCE_H_
+#define BASE_POWER_MONITOR_POWER_MONITOR_SOURCE_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/observer_list_threadsafe.h"
+#include "base/synchronization/lock.h"
+
+namespace base {
+
+class PowerMonitor;
+
+// Communicates power state changes to the power monitor.
+class BASE_EXPORT PowerMonitorSource {
+ public:
+  PowerMonitorSource();
+  virtual ~PowerMonitorSource();
+
+  // Normalized list of power events.
+  enum PowerEvent {
+    POWER_STATE_EVENT,  // The Power status of the system has changed.
+    SUSPEND_EVENT,      // The system is being suspended.
+    RESUME_EVENT        // The system is being resumed.
+  };
+
+  // Is the computer currently on battery power. Can be called on any thread.
+  bool IsOnBatteryPower();
+
+ protected:
+  friend class PowerMonitorTest;
+
+  // Friend function that is allowed to access the protected ProcessPowerEvent.
+  friend void ProcessPowerEventHelper(PowerEvent);
+
+  // Get the process-wide PowerMonitorSource (if not present, returns NULL).
+  static PowerMonitorSource* Get();
+
+  // ProcessPowerEvent should only be called from a single thread, most likely
+  // the UI thread or, in child processes, the IO thread.
+  static void ProcessPowerEvent(PowerEvent event_id);
+
+  // Platform-specific method to check whether the system is currently
+  // running on battery power.  Returns true if running on batteries,
+  // false otherwise.
+  virtual bool IsOnBatteryPowerImpl() = 0;
+
+ private:
+  bool on_battery_power_;
+  bool suspended_;
+
+  // This lock guards access to on_battery_power_, to ensure that
+  // IsOnBatteryPower can be called from any thread.
+  Lock battery_lock_;
+
+  DISALLOW_COPY_AND_ASSIGN(PowerMonitorSource);
+};
+
+}  // namespace base
+
+#endif  // BASE_POWER_MONITOR_POWER_MONITOR_SOURCE_H_
diff --git a/base/power_monitor/power_monitor_unittest.cc b/base/power_monitor/power_monitor_unittest.cc
new file mode 100644
index 0000000..2df8261
--- /dev/null
+++ b/base/power_monitor/power_monitor_unittest.cc
@@ -0,0 +1,80 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/power_monitor/power_monitor.h"
+#include "base/test/power_monitor_test_base.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+class PowerMonitorTest : public testing::Test {
+ protected:
+  PowerMonitorTest() {
+    power_monitor_source_ = new PowerMonitorTestSource();
+    power_monitor_.reset(new PowerMonitor(
+        scoped_ptr<PowerMonitorSource>(power_monitor_source_)));
+  }
+  ~PowerMonitorTest() override{};
+
+  PowerMonitorTestSource* source() { return power_monitor_source_; }
+  PowerMonitor* monitor() { return power_monitor_.get(); }
+
+ private:
+  PowerMonitorTestSource* power_monitor_source_;
+  scoped_ptr<PowerMonitor> power_monitor_;
+
+  DISALLOW_COPY_AND_ASSIGN(PowerMonitorTest);
+};
+
+// PowerMonitorSource is tightly coupled with the PowerMonitor, so this test
+// Will cover both classes
+TEST_F(PowerMonitorTest, PowerNotifications) {
+  const int kObservers = 5;
+
+  PowerMonitorTestObserver observers[kObservers];
+  for (int index = 0; index < kObservers; ++index)
+    monitor()->AddObserver(&observers[index]);
+
+  // Sending resume when not suspended should have no effect.
+  source()->GenerateResumeEvent();
+  EXPECT_EQ(observers[0].resumes(), 0);
+
+  // Pretend we suspended.
+  source()->GenerateSuspendEvent();
+  // Ensure all observers were notified of the event
+  for (int index = 0; index < kObservers; ++index)
+    EXPECT_EQ(observers[index].suspends(), 1);
+
+  // Send a second suspend notification.  This should be suppressed.
+  source()->GenerateSuspendEvent();
+  EXPECT_EQ(observers[0].suspends(), 1);
+
+  // Pretend we were awakened.
+  source()->GenerateResumeEvent();
+  EXPECT_EQ(observers[0].resumes(), 1);
+
+  // Send a duplicate resume notification.  This should be suppressed.
+  source()->GenerateResumeEvent();
+  EXPECT_EQ(observers[0].resumes(), 1);
+
+  // Pretend the device has gone on battery power
+  source()->GeneratePowerStateEvent(true);
+  EXPECT_EQ(observers[0].power_state_changes(), 1);
+  EXPECT_EQ(observers[0].last_power_state(), true);
+
+  // Repeated indications the device is on battery power should be suppressed.
+  source()->GeneratePowerStateEvent(true);
+  EXPECT_EQ(observers[0].power_state_changes(), 1);
+
+  // Pretend the device has gone off battery power
+  source()->GeneratePowerStateEvent(false);
+  EXPECT_EQ(observers[0].power_state_changes(), 2);
+  EXPECT_EQ(observers[0].last_power_state(), false);
+
+  // Repeated indications the device is off battery power should be suppressed.
+  source()->GeneratePowerStateEvent(false);
+  EXPECT_EQ(observers[0].power_state_changes(), 2);
+}
+
+}  // namespace base
diff --git a/base/power_monitor/power_observer.h b/base/power_monitor/power_observer.h
new file mode 100644
index 0000000..6be70bb
--- /dev/null
+++ b/base/power_monitor/power_observer.h
@@ -0,0 +1,31 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_POWER_MONITOR_POWER_OBSERVER_H_
+#define BASE_POWER_MONITOR_POWER_OBSERVER_H_
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+
+namespace base {
+
+class BASE_EXPORT PowerObserver {
+ public:
+  // Notification of a change in power status of the computer, such
+  // as from switching between battery and A/C power.
+  virtual void OnPowerStateChange(bool on_battery_power) {};
+
+  // Notification that the system is suspending.
+  virtual void OnSuspend() {}
+
+  // Notification that the system is resuming.
+  virtual void OnResume() {}
+
+ protected:
+  virtual ~PowerObserver() {}
+};
+
+}  // namespace base
+
+#endif  // BASE_POWER_MONITOR_POWER_OBSERVER_H_
diff --git a/base/prefs/OWNERS b/base/prefs/OWNERS
new file mode 100644
index 0000000..97ab695
--- /dev/null
+++ b/base/prefs/OWNERS
@@ -0,0 +1,5 @@
+battre@chromium.org
+bauerb@chromium.org
+gab@chromium.org
+mnissler@chromium.org
+pam@chromium.org
diff --git a/base/prefs/README b/base/prefs/README
new file mode 100644
index 0000000..52d9c43
--- /dev/null
+++ b/base/prefs/README
@@ -0,0 +1,6 @@
+Prefs is a general-purpose key-value store for application preferences.
+
+The Prefs code lives in base/prefs but is not part of the
+'base/base.gyp:base' library because of a desire to keep its use
+optional. If you use Prefs, you should add a GYP dependency on
+base/base.gyp:base_prefs.
diff --git a/base/prefs/base_prefs_export.h b/base/prefs/base_prefs_export.h
new file mode 100644
index 0000000..3d207db
--- /dev/null
+++ b/base/prefs/base_prefs_export.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2012 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_PREFS_BASE_PREFS_EXPORT_H_
+#define BASE_PREFS_BASE_PREFS_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(BASE_PREFS_IMPLEMENTATION)
+#define BASE_PREFS_EXPORT __declspec(dllexport)
+#else
+#define BASE_PREFS_EXPORT __declspec(dllimport)
+#endif  // defined(BASE_PREFS_IMPLEMENTATION)
+
+#else  // defined(WIN32)
+#if defined(BASE_PREFS_IMPLEMENTATION)
+#define BASE_PREFS_EXPORT __attribute__((visibility("default")))
+#else
+#define BASE_PREFS_EXPORT
+#endif
+#endif
+
+#else  // defined(COMPONENT_BUILD)
+#define BASE_PREFS_EXPORT
+#endif
+
+#endif  // BASE_PREFS_BASE_PREFS_EXPORT_H_
diff --git a/base/prefs/default_pref_store.cc b/base/prefs/default_pref_store.cc
new file mode 100644
index 0000000..92abba1
--- /dev/null
+++ b/base/prefs/default_pref_store.cc
@@ -0,0 +1,53 @@
+// Copyright (c) 2012 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/prefs/default_pref_store.h"
+#include "base/logging.h"
+
+using base::Value;
+
+DefaultPrefStore::DefaultPrefStore() {}
+
+bool DefaultPrefStore::GetValue(const std::string& key,
+                                const Value** result) const {
+  return prefs_.GetValue(key, result);
+}
+
+void DefaultPrefStore::AddObserver(PrefStore::Observer* observer) {
+  observers_.AddObserver(observer);
+}
+
+void DefaultPrefStore::RemoveObserver(PrefStore::Observer* observer) {
+  observers_.RemoveObserver(observer);
+}
+
+bool DefaultPrefStore::HasObservers() const {
+  return observers_.might_have_observers();
+}
+
+void DefaultPrefStore::SetDefaultValue(const std::string& key,
+                                       scoped_ptr<Value> value) {
+  DCHECK(!GetValue(key, NULL));
+  prefs_.SetValue(key, value.release());
+}
+
+void DefaultPrefStore::ReplaceDefaultValue(const std::string& key,
+                                           scoped_ptr<Value> value) {
+  const Value* old_value = NULL;
+  GetValue(key, &old_value);
+  bool notify = !old_value->Equals(value.get());
+  prefs_.SetValue(key, value.release());
+  if (notify)
+    FOR_EACH_OBSERVER(Observer, observers_, OnPrefValueChanged(key));
+}
+
+DefaultPrefStore::const_iterator DefaultPrefStore::begin() const {
+  return prefs_.begin();
+}
+
+DefaultPrefStore::const_iterator DefaultPrefStore::end() const {
+  return prefs_.end();
+}
+
+DefaultPrefStore::~DefaultPrefStore() {}
diff --git a/base/prefs/default_pref_store.h b/base/prefs/default_pref_store.h
new file mode 100644
index 0000000..e736b06
--- /dev/null
+++ b/base/prefs/default_pref_store.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2012 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_PREFS_DEFAULT_PREF_STORE_H_
+#define BASE_PREFS_DEFAULT_PREF_STORE_H_
+
+#include <string>
+
+#include "base/observer_list.h"
+#include "base/prefs/base_prefs_export.h"
+#include "base/prefs/pref_store.h"
+#include "base/prefs/pref_value_map.h"
+#include "base/values.h"
+
+// Used within a PrefRegistry to keep track of default preference values.
+class BASE_PREFS_EXPORT DefaultPrefStore : public PrefStore {
+ public:
+  typedef PrefValueMap::const_iterator const_iterator;
+
+  DefaultPrefStore();
+
+  // PrefStore implementation:
+  bool GetValue(const std::string& key,
+                const base::Value** result) const override;
+  void AddObserver(PrefStore::Observer* observer) override;
+  void RemoveObserver(PrefStore::Observer* observer) override;
+  bool HasObservers() const override;
+
+  // Sets a |value| for |key|. Should only be called if a value has not been
+  // set yet; otherwise call ReplaceDefaultValue().
+  void SetDefaultValue(const std::string& key, scoped_ptr<base::Value> value);
+
+  // Replaces the the value for |key| with a new value. Should only be called
+  // if a value has alreday been set; otherwise call SetDefaultValue().
+  void ReplaceDefaultValue(const std::string& key,
+                           scoped_ptr<base::Value> value);
+
+  const_iterator begin() const;
+  const_iterator end() const;
+
+ private:
+  ~DefaultPrefStore() override;
+
+  PrefValueMap prefs_;
+
+  base::ObserverList<PrefStore::Observer, true> observers_;
+
+  DISALLOW_COPY_AND_ASSIGN(DefaultPrefStore);
+};
+
+#endif  // BASE_PREFS_DEFAULT_PREF_STORE_H_
diff --git a/base/prefs/default_pref_store_unittest.cc b/base/prefs/default_pref_store_unittest.cc
new file mode 100644
index 0000000..9299937
--- /dev/null
+++ b/base/prefs/default_pref_store_unittest.cc
@@ -0,0 +1,69 @@
+// Copyright (c) 2012 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/prefs/default_pref_store.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::StringValue;
+using base::Value;
+
+namespace {
+
+class MockPrefStoreObserver : public PrefStore::Observer {
+ public:
+  explicit MockPrefStoreObserver(DefaultPrefStore* pref_store);
+  ~MockPrefStoreObserver() override;
+
+  int change_count() {
+    return change_count_;
+  }
+
+  // PrefStore::Observer implementation:
+  void OnPrefValueChanged(const std::string& key) override;
+  void OnInitializationCompleted(bool succeeded) override {}
+
+ private:
+  DefaultPrefStore* pref_store_;
+
+  int change_count_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockPrefStoreObserver);
+};
+
+MockPrefStoreObserver::MockPrefStoreObserver(DefaultPrefStore* pref_store)
+    : pref_store_(pref_store), change_count_(0) {
+  pref_store_->AddObserver(this);
+}
+
+MockPrefStoreObserver::~MockPrefStoreObserver() {
+  pref_store_->RemoveObserver(this);
+}
+
+void MockPrefStoreObserver::OnPrefValueChanged(const std::string& key) {
+  change_count_++;
+}
+
+}  // namespace
+
+TEST(DefaultPrefStoreTest, NotifyPrefValueChanged) {
+  scoped_refptr<DefaultPrefStore> pref_store(new DefaultPrefStore);
+  MockPrefStoreObserver observer(pref_store.get());
+  std::string kPrefKey("pref_key");
+
+  // Setting a default value shouldn't send a change notification.
+  pref_store->SetDefaultValue(kPrefKey,
+                              scoped_ptr<Value>(new StringValue("foo")));
+  EXPECT_EQ(0, observer.change_count());
+
+  // Replacing the default value should send a change notification...
+  pref_store->ReplaceDefaultValue(kPrefKey,
+                                  scoped_ptr<Value>(new StringValue("bar")));
+  EXPECT_EQ(1, observer.change_count());
+
+  // But only if the value actually changed.
+  pref_store->ReplaceDefaultValue(kPrefKey,
+                                  scoped_ptr<Value>(new StringValue("bar")));
+  EXPECT_EQ(1, observer.change_count());
+}
+
diff --git a/base/prefs/json_pref_store.cc b/base/prefs/json_pref_store.cc
new file mode 100644
index 0000000..c2ff425
--- /dev/null
+++ b/base/prefs/json_pref_store.cc
@@ -0,0 +1,546 @@
+// Copyright (c) 2012 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/prefs/json_pref_store.h"
+
+#include <algorithm>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/json/json_file_value_serializer.h"
+#include "base/json/json_string_value_serializer.h"
+#include "base/memory/ref_counted.h"
+#include "base/metrics/histogram.h"
+#include "base/prefs/pref_filter.h"
+#include "base/sequenced_task_runner.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/task_runner_util.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "base/time/default_clock.h"
+#include "base/values.h"
+
+// Result returned from internal read tasks.
+struct JsonPrefStore::ReadResult {
+ public:
+  ReadResult();
+  ~ReadResult();
+
+  scoped_ptr<base::Value> value;
+  PrefReadError error;
+  bool no_dir;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ReadResult);
+};
+
+JsonPrefStore::ReadResult::ReadResult()
+    : error(PersistentPrefStore::PREF_READ_ERROR_NONE), no_dir(false) {
+}
+
+JsonPrefStore::ReadResult::~ReadResult() {
+}
+
+namespace {
+
+// Some extensions we'll tack on to copies of the Preferences files.
+const base::FilePath::CharType kBadExtension[] = FILE_PATH_LITERAL("bad");
+
+PersistentPrefStore::PrefReadError HandleReadErrors(
+    const base::Value* value,
+    const base::FilePath& path,
+    int error_code,
+    const std::string& error_msg) {
+  if (!value) {
+    DVLOG(1) << "Error while loading JSON file: " << error_msg
+             << ", file: " << path.value();
+    switch (error_code) {
+      case JSONFileValueDeserializer::JSON_ACCESS_DENIED:
+        return PersistentPrefStore::PREF_READ_ERROR_ACCESS_DENIED;
+        break;
+      case JSONFileValueDeserializer::JSON_CANNOT_READ_FILE:
+        return PersistentPrefStore::PREF_READ_ERROR_FILE_OTHER;
+        break;
+      case JSONFileValueDeserializer::JSON_FILE_LOCKED:
+        return PersistentPrefStore::PREF_READ_ERROR_FILE_LOCKED;
+        break;
+      case JSONFileValueDeserializer::JSON_NO_SUCH_FILE:
+        return PersistentPrefStore::PREF_READ_ERROR_NO_FILE;
+        break;
+      default:
+        // JSON errors indicate file corruption of some sort.
+        // Since the file is corrupt, move it to the side and continue with
+        // empty preferences.  This will result in them losing their settings.
+        // We keep the old file for possible support and debugging assistance
+        // as well as to detect if they're seeing these errors repeatedly.
+        // TODO(erikkay) Instead, use the last known good file.
+        base::FilePath bad = path.ReplaceExtension(kBadExtension);
+
+        // If they've ever had a parse error before, put them in another bucket.
+        // TODO(erikkay) if we keep this error checking for very long, we may
+        // want to differentiate between recent and long ago errors.
+        bool bad_existed = base::PathExists(bad);
+        base::Move(path, bad);
+        return bad_existed ? PersistentPrefStore::PREF_READ_ERROR_JSON_REPEAT
+                           : PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE;
+    }
+  } else if (!value->IsType(base::Value::TYPE_DICTIONARY)) {
+    return PersistentPrefStore::PREF_READ_ERROR_JSON_TYPE;
+  }
+  return PersistentPrefStore::PREF_READ_ERROR_NONE;
+}
+
+// Records a sample for |size| in the Settings.JsonDataReadSizeKilobytes
+// histogram suffixed with the base name of the JSON file under |path|.
+void RecordJsonDataSizeHistogram(const base::FilePath& path, size_t size) {
+  std::string spaceless_basename;
+  base::ReplaceChars(path.BaseName().MaybeAsASCII(), " ", "_",
+                     &spaceless_basename);
+
+  // The histogram below is an expansion of the UMA_HISTOGRAM_CUSTOM_COUNTS
+  // macro adapted to allow for a dynamically suffixed histogram name.
+  // Note: The factory creates and owns the histogram.
+  base::HistogramBase* histogram = base::Histogram::FactoryGet(
+      "Settings.JsonDataReadSizeKilobytes." + spaceless_basename, 1, 10000, 50,
+      base::HistogramBase::kUmaTargetedHistogramFlag);
+  histogram->Add(static_cast<int>(size) / 1024);
+}
+
+scoped_ptr<JsonPrefStore::ReadResult> ReadPrefsFromDisk(
+    const base::FilePath& path,
+    const base::FilePath& alternate_path) {
+  if (!base::PathExists(path) && !alternate_path.empty() &&
+      base::PathExists(alternate_path)) {
+    base::Move(alternate_path, path);
+  }
+
+  int error_code;
+  std::string error_msg;
+  scoped_ptr<JsonPrefStore::ReadResult> read_result(
+      new JsonPrefStore::ReadResult);
+  JSONFileValueDeserializer deserializer(path);
+  read_result->value.reset(deserializer.Deserialize(&error_code, &error_msg));
+  read_result->error =
+      HandleReadErrors(read_result->value.get(), path, error_code, error_msg);
+  read_result->no_dir = !base::PathExists(path.DirName());
+
+  if (read_result->error == PersistentPrefStore::PREF_READ_ERROR_NONE)
+    RecordJsonDataSizeHistogram(path, deserializer.get_last_read_size());
+
+  return read_result.Pass();
+}
+
+}  // namespace
+
+// static
+scoped_refptr<base::SequencedTaskRunner> JsonPrefStore::GetTaskRunnerForFile(
+    const base::FilePath& filename,
+    base::SequencedWorkerPool* worker_pool) {
+  std::string token("json_pref_store-");
+  token.append(filename.AsUTF8Unsafe());
+  return worker_pool->GetSequencedTaskRunnerWithShutdownBehavior(
+      worker_pool->GetNamedSequenceToken(token),
+      base::SequencedWorkerPool::BLOCK_SHUTDOWN);
+}
+
+JsonPrefStore::JsonPrefStore(
+    const base::FilePath& filename,
+    const scoped_refptr<base::SequencedTaskRunner>& sequenced_task_runner,
+    scoped_ptr<PrefFilter> pref_filter)
+    : JsonPrefStore(filename,
+                    base::FilePath(),
+                    sequenced_task_runner,
+                    pref_filter.Pass()) {
+}
+
+JsonPrefStore::JsonPrefStore(
+    const base::FilePath& filename,
+    const base::FilePath& alternate_filename,
+    const scoped_refptr<base::SequencedTaskRunner>& sequenced_task_runner,
+    scoped_ptr<PrefFilter> pref_filter)
+    : path_(filename),
+      alternate_path_(alternate_filename),
+      sequenced_task_runner_(sequenced_task_runner),
+      prefs_(new base::DictionaryValue()),
+      read_only_(false),
+      writer_(filename, sequenced_task_runner),
+      pref_filter_(pref_filter.Pass()),
+      initialized_(false),
+      filtering_in_progress_(false),
+      pending_lossy_write_(false),
+      read_error_(PREF_READ_ERROR_NONE),
+      write_count_histogram_(writer_.commit_interval(), path_) {
+  DCHECK(!path_.empty());
+}
+
+bool JsonPrefStore::GetValue(const std::string& key,
+                             const base::Value** result) const {
+  DCHECK(CalledOnValidThread());
+
+  base::Value* tmp = NULL;
+  if (!prefs_->Get(key, &tmp))
+    return false;
+
+  if (result)
+    *result = tmp;
+  return true;
+}
+
+void JsonPrefStore::AddObserver(PrefStore::Observer* observer) {
+  DCHECK(CalledOnValidThread());
+
+  observers_.AddObserver(observer);
+}
+
+void JsonPrefStore::RemoveObserver(PrefStore::Observer* observer) {
+  DCHECK(CalledOnValidThread());
+
+  observers_.RemoveObserver(observer);
+}
+
+bool JsonPrefStore::HasObservers() const {
+  DCHECK(CalledOnValidThread());
+
+  return observers_.might_have_observers();
+}
+
+bool JsonPrefStore::IsInitializationComplete() const {
+  DCHECK(CalledOnValidThread());
+
+  return initialized_;
+}
+
+bool JsonPrefStore::GetMutableValue(const std::string& key,
+                                    base::Value** result) {
+  DCHECK(CalledOnValidThread());
+
+  return prefs_->Get(key, result);
+}
+
+void JsonPrefStore::SetValue(const std::string& key,
+                             base::Value* value,
+                             uint32 flags) {
+  DCHECK(CalledOnValidThread());
+
+  DCHECK(value);
+  scoped_ptr<base::Value> new_value(value);
+  base::Value* old_value = NULL;
+  prefs_->Get(key, &old_value);
+  if (!old_value || !value->Equals(old_value)) {
+    prefs_->Set(key, new_value.Pass());
+    ReportValueChanged(key, flags);
+  }
+}
+
+void JsonPrefStore::SetValueSilently(const std::string& key,
+                                     base::Value* value,
+                                     uint32 flags) {
+  DCHECK(CalledOnValidThread());
+
+  DCHECK(value);
+  scoped_ptr<base::Value> new_value(value);
+  base::Value* old_value = NULL;
+  prefs_->Get(key, &old_value);
+  if (!old_value || !value->Equals(old_value)) {
+    prefs_->Set(key, new_value.Pass());
+    ScheduleWrite(flags);
+  }
+}
+
+void JsonPrefStore::RemoveValue(const std::string& key, uint32 flags) {
+  DCHECK(CalledOnValidThread());
+
+  if (prefs_->RemovePath(key, NULL))
+    ReportValueChanged(key, flags);
+}
+
+void JsonPrefStore::RemoveValueSilently(const std::string& key, uint32 flags) {
+  DCHECK(CalledOnValidThread());
+
+  prefs_->RemovePath(key, NULL);
+  ScheduleWrite(flags);
+}
+
+bool JsonPrefStore::ReadOnly() const {
+  DCHECK(CalledOnValidThread());
+
+  return read_only_;
+}
+
+PersistentPrefStore::PrefReadError JsonPrefStore::GetReadError() const {
+  DCHECK(CalledOnValidThread());
+
+  return read_error_;
+}
+
+PersistentPrefStore::PrefReadError JsonPrefStore::ReadPrefs() {
+  DCHECK(CalledOnValidThread());
+
+  OnFileRead(ReadPrefsFromDisk(path_, alternate_path_));
+  return filtering_in_progress_ ? PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE
+                                : read_error_;
+}
+
+void JsonPrefStore::ReadPrefsAsync(ReadErrorDelegate* error_delegate) {
+  DCHECK(CalledOnValidThread());
+
+  initialized_ = false;
+  error_delegate_.reset(error_delegate);
+
+  // Weakly binds the read task so that it doesn't kick in during shutdown.
+  base::PostTaskAndReplyWithResult(
+      sequenced_task_runner_.get(),
+      FROM_HERE,
+      base::Bind(&ReadPrefsFromDisk, path_, alternate_path_),
+      base::Bind(&JsonPrefStore::OnFileRead, AsWeakPtr()));
+}
+
+void JsonPrefStore::CommitPendingWrite() {
+  DCHECK(CalledOnValidThread());
+
+  // Schedule a write for any lossy writes that are outstanding to ensure that
+  // they get flushed when this function is called.
+  SchedulePendingLossyWrites();
+
+  if (writer_.HasPendingWrite() && !read_only_)
+    writer_.DoScheduledWrite();
+}
+
+void JsonPrefStore::SchedulePendingLossyWrites() {
+  if (pending_lossy_write_)
+    writer_.ScheduleWrite(this);
+}
+
+void JsonPrefStore::ReportValueChanged(const std::string& key, uint32 flags) {
+  DCHECK(CalledOnValidThread());
+
+  if (pref_filter_)
+    pref_filter_->FilterUpdate(key);
+
+  FOR_EACH_OBSERVER(PrefStore::Observer, observers_, OnPrefValueChanged(key));
+
+  ScheduleWrite(flags);
+}
+
+void JsonPrefStore::RegisterOnNextSuccessfulWriteCallback(
+    const base::Closure& on_next_successful_write) {
+  DCHECK(CalledOnValidThread());
+
+  writer_.RegisterOnNextSuccessfulWriteCallback(on_next_successful_write);
+}
+
+void JsonPrefStore::OnFileRead(scoped_ptr<ReadResult> read_result) {
+  DCHECK(CalledOnValidThread());
+
+  DCHECK(read_result);
+
+  scoped_ptr<base::DictionaryValue> unfiltered_prefs(new base::DictionaryValue);
+
+  read_error_ = read_result->error;
+
+  bool initialization_successful = !read_result->no_dir;
+
+  if (initialization_successful) {
+    switch (read_error_) {
+      case PREF_READ_ERROR_ACCESS_DENIED:
+      case PREF_READ_ERROR_FILE_OTHER:
+      case PREF_READ_ERROR_FILE_LOCKED:
+      case PREF_READ_ERROR_JSON_TYPE:
+      case PREF_READ_ERROR_FILE_NOT_SPECIFIED:
+        read_only_ = true;
+        break;
+      case PREF_READ_ERROR_NONE:
+        DCHECK(read_result->value.get());
+        unfiltered_prefs.reset(
+            static_cast<base::DictionaryValue*>(read_result->value.release()));
+        break;
+      case PREF_READ_ERROR_NO_FILE:
+        // If the file just doesn't exist, maybe this is first run.  In any case
+        // there's no harm in writing out default prefs in this case.
+        break;
+      case PREF_READ_ERROR_JSON_PARSE:
+      case PREF_READ_ERROR_JSON_REPEAT:
+        break;
+      case PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE:
+        // This is a special error code to be returned by ReadPrefs when it
+        // can't complete synchronously, it should never be returned by the read
+        // operation itself.
+        NOTREACHED();
+        break;
+      case PREF_READ_ERROR_LEVELDB_IO:
+      case PREF_READ_ERROR_LEVELDB_CORRUPTION_READ_ONLY:
+      case PREF_READ_ERROR_LEVELDB_CORRUPTION:
+        // These are specific to LevelDBPrefStore.
+        NOTREACHED();
+      case PREF_READ_ERROR_MAX_ENUM:
+        NOTREACHED();
+        break;
+    }
+  }
+
+  if (pref_filter_) {
+    filtering_in_progress_ = true;
+    const PrefFilter::PostFilterOnLoadCallback post_filter_on_load_callback(
+        base::Bind(
+            &JsonPrefStore::FinalizeFileRead, AsWeakPtr(),
+            initialization_successful));
+    pref_filter_->FilterOnLoad(post_filter_on_load_callback,
+                               unfiltered_prefs.Pass());
+  } else {
+    FinalizeFileRead(initialization_successful, unfiltered_prefs.Pass(), false);
+  }
+}
+
+JsonPrefStore::~JsonPrefStore() {
+  CommitPendingWrite();
+}
+
+bool JsonPrefStore::SerializeData(std::string* output) {
+  DCHECK(CalledOnValidThread());
+
+  pending_lossy_write_ = false;
+
+  write_count_histogram_.RecordWriteOccured();
+
+  if (pref_filter_)
+    pref_filter_->FilterSerializeData(prefs_.get());
+
+  JSONStringValueSerializer serializer(output);
+  // Not pretty-printing prefs shrinks pref file size by ~30%. To obtain
+  // readable prefs for debugging purposes, you can dump your prefs into any
+  // command-line or online JSON pretty printing tool.
+  serializer.set_pretty_print(false);
+  return serializer.Serialize(*prefs_);
+}
+
+void JsonPrefStore::FinalizeFileRead(bool initialization_successful,
+                                     scoped_ptr<base::DictionaryValue> prefs,
+                                     bool schedule_write) {
+  DCHECK(CalledOnValidThread());
+
+  filtering_in_progress_ = false;
+
+  if (!initialization_successful) {
+    FOR_EACH_OBSERVER(PrefStore::Observer,
+                      observers_,
+                      OnInitializationCompleted(false));
+    return;
+  }
+
+  prefs_ = prefs.Pass();
+
+  initialized_ = true;
+
+  if (schedule_write)
+    ScheduleWrite(DEFAULT_PREF_WRITE_FLAGS);
+
+  if (error_delegate_ && read_error_ != PREF_READ_ERROR_NONE)
+    error_delegate_->OnError(read_error_);
+
+  FOR_EACH_OBSERVER(PrefStore::Observer,
+                    observers_,
+                    OnInitializationCompleted(true));
+
+  return;
+}
+
+void JsonPrefStore::ScheduleWrite(uint32 flags) {
+  if (read_only_)
+    return;
+
+  if (flags & LOSSY_PREF_WRITE_FLAG)
+    pending_lossy_write_ = true;
+  else
+    writer_.ScheduleWrite(this);
+}
+
+// NOTE: This value should NOT be changed without renaming the histogram
+// otherwise it will create incompatible buckets.
+const int32_t
+    JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins = 5;
+
+JsonPrefStore::WriteCountHistogram::WriteCountHistogram(
+    const base::TimeDelta& commit_interval,
+    const base::FilePath& path)
+    : WriteCountHistogram(commit_interval,
+                          path,
+                          scoped_ptr<base::Clock>(new base::DefaultClock)) {
+}
+
+JsonPrefStore::WriteCountHistogram::WriteCountHistogram(
+    const base::TimeDelta& commit_interval,
+    const base::FilePath& path,
+    scoped_ptr<base::Clock> clock)
+    : commit_interval_(commit_interval),
+      path_(path),
+      clock_(clock.release()),
+      report_interval_(
+          base::TimeDelta::FromMinutes(kHistogramWriteReportIntervalMins)),
+      last_report_time_(clock_->Now()),
+      writes_since_last_report_(0) {
+}
+
+JsonPrefStore::WriteCountHistogram::~WriteCountHistogram() {
+  ReportOutstandingWrites();
+}
+
+void JsonPrefStore::WriteCountHistogram::RecordWriteOccured() {
+  ReportOutstandingWrites();
+
+  ++writes_since_last_report_;
+}
+
+void JsonPrefStore::WriteCountHistogram::ReportOutstandingWrites() {
+  base::Time current_time = clock_->Now();
+  base::TimeDelta time_since_last_report = current_time - last_report_time_;
+
+  if (time_since_last_report <= report_interval_)
+    return;
+
+  // If the time since the last report exceeds the report interval, report all
+  // the writes since the last report. They must have all occurred in the same
+  // report interval.
+  base::HistogramBase* histogram = GetHistogram();
+  histogram->Add(writes_since_last_report_);
+
+  // There may be several report intervals that elapsed that don't have any
+  // writes in them. Report these too.
+  int64 total_num_intervals_elapsed =
+      (time_since_last_report / report_interval_);
+  for (int64 i = 0; i < total_num_intervals_elapsed - 1; ++i)
+    histogram->Add(0);
+
+  writes_since_last_report_ = 0;
+  last_report_time_ += total_num_intervals_elapsed * report_interval_;
+}
+
+base::HistogramBase* JsonPrefStore::WriteCountHistogram::GetHistogram() {
+  std::string spaceless_basename;
+  base::ReplaceChars(path_.BaseName().MaybeAsASCII(), " ", "_",
+                     &spaceless_basename);
+  std::string histogram_name =
+      "Settings.JsonDataWriteCount." + spaceless_basename;
+
+  // The min value for a histogram is 1. The max value is the maximum number of
+  // writes that can occur in the window being recorded. The number of buckets
+  // used is the max value (plus the underflow/overflow buckets).
+  int32_t min_value = 1;
+  int32_t max_value = report_interval_ / commit_interval_;
+  int32_t num_buckets = max_value + 1;
+
+  // NOTE: These values should NOT be changed without renaming the histogram
+  // otherwise it will create incompatible buckets.
+  DCHECK_EQ(30, max_value);
+  DCHECK_EQ(31, num_buckets);
+
+  // The histogram below is an expansion of the UMA_HISTOGRAM_CUSTOM_COUNTS
+  // macro adapted to allow for a dynamically suffixed histogram name.
+  // Note: The factory creates and owns the histogram.
+  base::HistogramBase* histogram = base::Histogram::FactoryGet(
+      histogram_name, min_value, max_value, num_buckets,
+      base::HistogramBase::kUmaTargetedHistogramFlag);
+  return histogram;
+}
diff --git a/base/prefs/json_pref_store.h b/base/prefs/json_pref_store.h
new file mode 100644
index 0000000..d6943e0
--- /dev/null
+++ b/base/prefs/json_pref_store.h
@@ -0,0 +1,228 @@
+// Copyright (c) 2012 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_PREFS_JSON_PREF_STORE_H_
+#define BASE_PREFS_JSON_PREF_STORE_H_
+
+#include <set>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/callback_forward.h"
+#include "base/compiler_specific.h"
+#include "base/files/file_path.h"
+#include "base/files/important_file_writer.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
+#include "base/prefs/base_prefs_export.h"
+#include "base/prefs/persistent_pref_store.h"
+#include "base/threading/non_thread_safe.h"
+
+class PrefFilter;
+
+namespace base {
+class Clock;
+class DictionaryValue;
+class FilePath;
+class HistogramBase;
+class JsonPrefStoreLossyWriteTest;
+class SequencedTaskRunner;
+class SequencedWorkerPool;
+class Value;
+FORWARD_DECLARE_TEST(JsonPrefStoreTest, WriteCountHistogramTestBasic);
+FORWARD_DECLARE_TEST(JsonPrefStoreTest, WriteCountHistogramTestSinglePeriod);
+FORWARD_DECLARE_TEST(JsonPrefStoreTest, WriteCountHistogramTestMultiplePeriods);
+FORWARD_DECLARE_TEST(JsonPrefStoreTest, WriteCountHistogramTestPeriodWithGaps);
+}
+
+// A writable PrefStore implementation that is used for user preferences.
+class BASE_PREFS_EXPORT JsonPrefStore
+    : public PersistentPrefStore,
+      public base::ImportantFileWriter::DataSerializer,
+      public base::SupportsWeakPtr<JsonPrefStore>,
+      public base::NonThreadSafe {
+ public:
+  struct ReadResult;
+
+  // Returns instance of SequencedTaskRunner which guarantees that file
+  // operations on the same file will be executed in sequenced order.
+  static scoped_refptr<base::SequencedTaskRunner> GetTaskRunnerForFile(
+      const base::FilePath& pref_filename,
+      base::SequencedWorkerPool* worker_pool);
+
+  // Same as the constructor below with no alternate filename.
+  JsonPrefStore(
+      const base::FilePath& pref_filename,
+      const scoped_refptr<base::SequencedTaskRunner>& sequenced_task_runner,
+      scoped_ptr<PrefFilter> pref_filter);
+
+  // |sequenced_task_runner| must be a shutdown-blocking task runner, ideally
+  // created by the GetTaskRunnerForFile() method above.
+  // |pref_filename| is the path to the file to read prefs from.
+  // |pref_alternate_filename| is the path to an alternate file which the
+  // desired prefs may have previously been written to. If |pref_filename|
+  // doesn't exist and |pref_alternate_filename| does, |pref_alternate_filename|
+  // will be moved to |pref_filename| before the read occurs.
+  JsonPrefStore(
+      const base::FilePath& pref_filename,
+      const base::FilePath& pref_alternate_filename,
+      const scoped_refptr<base::SequencedTaskRunner>& sequenced_task_runner,
+      scoped_ptr<PrefFilter> pref_filter);
+
+  // PrefStore overrides:
+  bool GetValue(const std::string& key,
+                const base::Value** result) const override;
+  void AddObserver(PrefStore::Observer* observer) override;
+  void RemoveObserver(PrefStore::Observer* observer) override;
+  bool HasObservers() const override;
+  bool IsInitializationComplete() const override;
+
+  // PersistentPrefStore overrides:
+  bool GetMutableValue(const std::string& key, base::Value** result) override;
+  void SetValue(const std::string& key,
+                base::Value* value,
+                uint32 flags) override;
+  void SetValueSilently(const std::string& key,
+                        base::Value* value,
+                        uint32 flags) override;
+  void RemoveValue(const std::string& key, uint32 flags) override;
+  bool ReadOnly() const override;
+  PrefReadError GetReadError() const override;
+  // Note this method may be asynchronous if this instance has a |pref_filter_|
+  // in which case it will return PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE.
+  // See details in pref_filter.h.
+  PrefReadError ReadPrefs() override;
+  void ReadPrefsAsync(ReadErrorDelegate* error_delegate) override;
+  void CommitPendingWrite() override;
+  void SchedulePendingLossyWrites() override;
+  void ReportValueChanged(const std::string& key, uint32 flags) override;
+
+  // Just like RemoveValue(), but doesn't notify observers. Used when doing some
+  // cleanup that shouldn't otherwise alert observers.
+  void RemoveValueSilently(const std::string& key, uint32 flags);
+
+  // Registers |on_next_successful_write| to be called once, on the next
+  // successful write event of |writer_|.
+  void RegisterOnNextSuccessfulWriteCallback(
+      const base::Closure& on_next_successful_write);
+
+ private:
+  // Represents a histogram for recording the number of writes to the pref file
+  // that occur every kHistogramWriteReportIntervalInMins minutes.
+  class BASE_PREFS_EXPORT WriteCountHistogram {
+   public:
+    static const int32_t kHistogramWriteReportIntervalMins;
+
+    WriteCountHistogram(const base::TimeDelta& commit_interval,
+                        const base::FilePath& path);
+    // Constructor for testing. |clock| is a test Clock that is used to retrieve
+    // the time.
+    WriteCountHistogram(const base::TimeDelta& commit_interval,
+                        const base::FilePath& path,
+                        scoped_ptr<base::Clock> clock);
+    ~WriteCountHistogram();
+
+    // Record that a write has occured.
+    void RecordWriteOccured();
+
+    // Reports writes (that have not yet been reported) in all of the recorded
+    // intervals that have elapsed up until current time.
+    void ReportOutstandingWrites();
+
+    base::HistogramBase* GetHistogram();
+
+   private:
+    // The minimum interval at which writes can occur.
+    const base::TimeDelta commit_interval_;
+
+    // The path to the file.
+    const base::FilePath path_;
+
+    // Clock which is used to retrieve the current time.
+    scoped_ptr<base::Clock> clock_;
+
+    // The interval at which to report write counts.
+    const base::TimeDelta report_interval_;
+
+    // The time at which the last histogram value was reported for the number
+    // of write counts.
+    base::Time last_report_time_;
+
+    // The number of writes that have occured since the last write count was
+    // reported.
+    uint32_t writes_since_last_report_;
+
+    DISALLOW_COPY_AND_ASSIGN(WriteCountHistogram);
+  };
+
+  FRIEND_TEST_ALL_PREFIXES(base::JsonPrefStoreTest,
+                           WriteCountHistogramTestBasic);
+  FRIEND_TEST_ALL_PREFIXES(base::JsonPrefStoreTest,
+                           WriteCountHistogramTestSinglePeriod);
+  FRIEND_TEST_ALL_PREFIXES(base::JsonPrefStoreTest,
+                           WriteCountHistogramTestMultiplePeriods);
+  FRIEND_TEST_ALL_PREFIXES(base::JsonPrefStoreTest,
+                           WriteCountHistogramTestPeriodWithGaps);
+  friend class base::JsonPrefStoreLossyWriteTest;
+
+  ~JsonPrefStore() override;
+
+  // This method is called after the JSON file has been read.  It then hands
+  // |value| (or an empty dictionary in some read error cases) to the
+  // |pref_filter| if one is set. It also gives a callback pointing at
+  // FinalizeFileRead() to that |pref_filter_| which is then responsible for
+  // invoking it when done. If there is no |pref_filter_|, FinalizeFileRead()
+  // is invoked directly.
+  void OnFileRead(scoped_ptr<ReadResult> read_result);
+
+  // ImportantFileWriter::DataSerializer overrides:
+  bool SerializeData(std::string* output) override;
+
+  // This method is called after the JSON file has been read and the result has
+  // potentially been intercepted and modified by |pref_filter_|.
+  // |initialization_successful| is pre-determined by OnFileRead() and should
+  // be used when reporting OnInitializationCompleted().
+  // |schedule_write| indicates whether a write should be immediately scheduled
+  // (typically because the |pref_filter_| has already altered the |prefs|) --
+  // this will be ignored if this store is read-only.
+  void FinalizeFileRead(bool initialization_successful,
+                        scoped_ptr<base::DictionaryValue> prefs,
+                        bool schedule_write);
+
+  // Schedule a write with the file writer as long as |flags| doesn't contain
+  // WriteablePrefStore::LOSSY_PREF_WRITE_FLAG.
+  void ScheduleWrite(uint32 flags);
+
+  const base::FilePath path_;
+  const base::FilePath alternate_path_;
+  const scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner_;
+
+  scoped_ptr<base::DictionaryValue> prefs_;
+
+  bool read_only_;
+
+  // Helper for safely writing pref data.
+  base::ImportantFileWriter writer_;
+
+  scoped_ptr<PrefFilter> pref_filter_;
+  base::ObserverList<PrefStore::Observer, true> observers_;
+
+  scoped_ptr<ReadErrorDelegate> error_delegate_;
+
+  bool initialized_;
+  bool filtering_in_progress_;
+  bool pending_lossy_write_;
+  PrefReadError read_error_;
+
+  std::set<std::string> keys_need_empty_value_;
+
+  WriteCountHistogram write_count_histogram_;
+
+  DISALLOW_COPY_AND_ASSIGN(JsonPrefStore);
+};
+
+#endif  // BASE_PREFS_JSON_PREF_STORE_H_
diff --git a/base/prefs/json_pref_store_unittest.cc b/base/prefs/json_pref_store_unittest.cc
new file mode 100644
index 0000000..4c7bc1f
--- /dev/null
+++ b/base/prefs/json_pref_store_unittest.cc
@@ -0,0 +1,951 @@
+// Copyright (c) 2012 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/prefs/json_pref_store.h"
+
+#include "base/bind.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/location.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/metrics/histogram_samples.h"
+#include "base/metrics/statistics_recorder.h"
+#include "base/path_service.h"
+#include "base/prefs/pref_filter.h"
+#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/simple_test_clock.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "base/threading/thread.h"
+#include "base/values.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+const char kHomePage[] = "homepage";
+
+// Set the time on the given SimpleTestClock to the given time in minutes.
+void SetCurrentTimeInMinutes(double minutes, base::SimpleTestClock* clock) {
+  const int32_t kBaseTimeMins = 100;
+  clock->SetNow(base::Time::FromDoubleT((kBaseTimeMins + minutes) * 60));
+}
+
+// A PrefFilter that will intercept all calls to FilterOnLoad() and hold on
+// to the |prefs| until explicitly asked to release them.
+class InterceptingPrefFilter : public PrefFilter {
+ public:
+  InterceptingPrefFilter();
+  ~InterceptingPrefFilter() override;
+
+  // PrefFilter implementation:
+  void FilterOnLoad(
+      const PostFilterOnLoadCallback& post_filter_on_load_callback,
+      scoped_ptr<base::DictionaryValue> pref_store_contents) override;
+  void FilterUpdate(const std::string& path) override {}
+  void FilterSerializeData(
+      base::DictionaryValue* pref_store_contents) override {}
+
+  bool has_intercepted_prefs() const { return intercepted_prefs_ != NULL; }
+
+  // Finalize an intercepted read, handing |intercepted_prefs_| back to its
+  // JsonPrefStore.
+  void ReleasePrefs();
+
+ private:
+  PostFilterOnLoadCallback post_filter_on_load_callback_;
+  scoped_ptr<base::DictionaryValue> intercepted_prefs_;
+
+  DISALLOW_COPY_AND_ASSIGN(InterceptingPrefFilter);
+};
+
+InterceptingPrefFilter::InterceptingPrefFilter() {}
+InterceptingPrefFilter::~InterceptingPrefFilter() {}
+
+void InterceptingPrefFilter::FilterOnLoad(
+    const PostFilterOnLoadCallback& post_filter_on_load_callback,
+    scoped_ptr<base::DictionaryValue> pref_store_contents) {
+  post_filter_on_load_callback_ = post_filter_on_load_callback;
+  intercepted_prefs_ = pref_store_contents.Pass();
+}
+
+void InterceptingPrefFilter::ReleasePrefs() {
+  EXPECT_FALSE(post_filter_on_load_callback_.is_null());
+  post_filter_on_load_callback_.Run(intercepted_prefs_.Pass(), false);
+  post_filter_on_load_callback_.Reset();
+}
+
+class MockPrefStoreObserver : public PrefStore::Observer {
+ public:
+  MOCK_METHOD1(OnPrefValueChanged, void (const std::string&));
+  MOCK_METHOD1(OnInitializationCompleted, void (bool));
+};
+
+class MockReadErrorDelegate : public PersistentPrefStore::ReadErrorDelegate {
+ public:
+  MOCK_METHOD1(OnError, void(PersistentPrefStore::PrefReadError));
+};
+
+}  // namespace
+
+class JsonPrefStoreTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+
+    ASSERT_TRUE(PathService::Get(base::DIR_TEST_DATA, &data_dir_));
+    data_dir_ = data_dir_.AppendASCII("prefs");
+    ASSERT_TRUE(PathExists(data_dir_));
+  }
+
+  void TearDown() override {
+    // Make sure all pending tasks have been processed (e.g., deleting the
+    // JsonPrefStore may post write tasks).
+    RunLoop().RunUntilIdle();
+  }
+
+  // The path to temporary directory used to contain the test operations.
+  base::ScopedTempDir temp_dir_;
+  // The path to the directory where the test data is stored.
+  base::FilePath data_dir_;
+  // A message loop that we can use as the file thread message loop.
+  MessageLoop message_loop_;
+
+ private:
+  // Ensure histograms are reset for each test.
+  StatisticsRecorder statistics_recorder_;
+};
+
+// Test fallback behavior for a nonexistent file.
+TEST_F(JsonPrefStoreTest, NonExistentFile) {
+  base::FilePath bogus_input_file = temp_dir_.path().AppendASCII("read.txt");
+  ASSERT_FALSE(PathExists(bogus_input_file));
+  scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
+      bogus_input_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
+  EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
+            pref_store->ReadPrefs());
+  EXPECT_FALSE(pref_store->ReadOnly());
+}
+
+// Test fallback behavior for a nonexistent file and alternate file.
+TEST_F(JsonPrefStoreTest, NonExistentFileAndAlternateFile) {
+  base::FilePath bogus_input_file = temp_dir_.path().AppendASCII("read.txt");
+  base::FilePath bogus_alternate_input_file =
+      temp_dir_.path().AppendASCII("read_alternate.txt");
+  ASSERT_FALSE(PathExists(bogus_input_file));
+  ASSERT_FALSE(PathExists(bogus_alternate_input_file));
+  scoped_refptr<JsonPrefStore> pref_store =
+      new JsonPrefStore(bogus_input_file, bogus_alternate_input_file,
+                        message_loop_.task_runner(), scoped_ptr<PrefFilter>());
+  EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
+            pref_store->ReadPrefs());
+  EXPECT_FALSE(pref_store->ReadOnly());
+}
+
+// Test fallback behavior for an invalid file.
+TEST_F(JsonPrefStoreTest, InvalidFile) {
+  base::FilePath invalid_file_original = data_dir_.AppendASCII("invalid.json");
+  base::FilePath invalid_file = temp_dir_.path().AppendASCII("invalid.json");
+  ASSERT_TRUE(base::CopyFile(invalid_file_original, invalid_file));
+  scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
+      invalid_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
+  EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE,
+            pref_store->ReadPrefs());
+  EXPECT_FALSE(pref_store->ReadOnly());
+
+  // The file should have been moved aside.
+  EXPECT_FALSE(PathExists(invalid_file));
+  base::FilePath moved_aside = temp_dir_.path().AppendASCII("invalid.bad");
+  EXPECT_TRUE(PathExists(moved_aside));
+  EXPECT_TRUE(TextContentsEqual(invalid_file_original, moved_aside));
+}
+
+// This function is used to avoid code duplication while testing synchronous and
+// asynchronous version of the JsonPrefStore loading.
+void RunBasicJsonPrefStoreTest(JsonPrefStore* pref_store,
+                               const base::FilePath& output_file,
+                               const base::FilePath& golden_output_file) {
+  const char kNewWindowsInTabs[] = "tabs.new_windows_in_tabs";
+  const char kMaxTabs[] = "tabs.max_tabs";
+  const char kLongIntPref[] = "long_int.pref";
+
+  std::string cnn("http://www.cnn.com");
+
+  const Value* actual;
+  EXPECT_TRUE(pref_store->GetValue(kHomePage, &actual));
+  std::string string_value;
+  EXPECT_TRUE(actual->GetAsString(&string_value));
+  EXPECT_EQ(cnn, string_value);
+
+  const char kSomeDirectory[] = "some_directory";
+
+  EXPECT_TRUE(pref_store->GetValue(kSomeDirectory, &actual));
+  base::FilePath::StringType path;
+  EXPECT_TRUE(actual->GetAsString(&path));
+  EXPECT_EQ(base::FilePath::StringType(FILE_PATH_LITERAL("/usr/local/")), path);
+  base::FilePath some_path(FILE_PATH_LITERAL("/usr/sbin/"));
+
+  pref_store->SetValue(kSomeDirectory, new StringValue(some_path.value()),
+                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  EXPECT_TRUE(pref_store->GetValue(kSomeDirectory, &actual));
+  EXPECT_TRUE(actual->GetAsString(&path));
+  EXPECT_EQ(some_path.value(), path);
+
+  // Test reading some other data types from sub-dictionaries.
+  EXPECT_TRUE(pref_store->GetValue(kNewWindowsInTabs, &actual));
+  bool boolean = false;
+  EXPECT_TRUE(actual->GetAsBoolean(&boolean));
+  EXPECT_TRUE(boolean);
+
+  pref_store->SetValue(kNewWindowsInTabs, new FundamentalValue(false),
+                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  EXPECT_TRUE(pref_store->GetValue(kNewWindowsInTabs, &actual));
+  EXPECT_TRUE(actual->GetAsBoolean(&boolean));
+  EXPECT_FALSE(boolean);
+
+  EXPECT_TRUE(pref_store->GetValue(kMaxTabs, &actual));
+  int integer = 0;
+  EXPECT_TRUE(actual->GetAsInteger(&integer));
+  EXPECT_EQ(20, integer);
+  pref_store->SetValue(kMaxTabs, new FundamentalValue(10),
+                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  EXPECT_TRUE(pref_store->GetValue(kMaxTabs, &actual));
+  EXPECT_TRUE(actual->GetAsInteger(&integer));
+  EXPECT_EQ(10, integer);
+
+  pref_store->SetValue(kLongIntPref,
+                       new StringValue(base::Int64ToString(214748364842LL)),
+                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  EXPECT_TRUE(pref_store->GetValue(kLongIntPref, &actual));
+  EXPECT_TRUE(actual->GetAsString(&string_value));
+  int64 value;
+  base::StringToInt64(string_value, &value);
+  EXPECT_EQ(214748364842LL, value);
+
+  // Serialize and compare to expected output.
+  ASSERT_TRUE(PathExists(golden_output_file));
+  pref_store->CommitPendingWrite();
+  RunLoop().RunUntilIdle();
+  EXPECT_TRUE(TextContentsEqual(golden_output_file, output_file));
+  ASSERT_TRUE(base::DeleteFile(output_file, false));
+}
+
+TEST_F(JsonPrefStoreTest, Basic) {
+  ASSERT_TRUE(base::CopyFile(data_dir_.AppendASCII("read.json"),
+                             temp_dir_.path().AppendASCII("write.json")));
+
+  // Test that the persistent value can be loaded.
+  base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
+  ASSERT_TRUE(PathExists(input_file));
+  scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
+      input_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
+  ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
+  EXPECT_FALSE(pref_store->ReadOnly());
+  EXPECT_TRUE(pref_store->IsInitializationComplete());
+
+  // The JSON file looks like this:
+  // {
+  //   "homepage": "http://www.cnn.com",
+  //   "some_directory": "/usr/local/",
+  //   "tabs": {
+  //     "new_windows_in_tabs": true,
+  //     "max_tabs": 20
+  //   }
+  // }
+
+  RunBasicJsonPrefStoreTest(
+      pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json"));
+}
+
+TEST_F(JsonPrefStoreTest, BasicAsync) {
+  ASSERT_TRUE(base::CopyFile(data_dir_.AppendASCII("read.json"),
+                             temp_dir_.path().AppendASCII("write.json")));
+
+  // Test that the persistent value can be loaded.
+  base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
+  ASSERT_TRUE(PathExists(input_file));
+  scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
+      input_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
+
+  {
+    MockPrefStoreObserver mock_observer;
+    pref_store->AddObserver(&mock_observer);
+
+    MockReadErrorDelegate* mock_error_delegate = new MockReadErrorDelegate;
+    pref_store->ReadPrefsAsync(mock_error_delegate);
+
+    EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1);
+    EXPECT_CALL(*mock_error_delegate,
+                OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0);
+    RunLoop().RunUntilIdle();
+    pref_store->RemoveObserver(&mock_observer);
+
+    EXPECT_FALSE(pref_store->ReadOnly());
+    EXPECT_TRUE(pref_store->IsInitializationComplete());
+  }
+
+  // The JSON file looks like this:
+  // {
+  //   "homepage": "http://www.cnn.com",
+  //   "some_directory": "/usr/local/",
+  //   "tabs": {
+  //     "new_windows_in_tabs": true,
+  //     "max_tabs": 20
+  //   }
+  // }
+
+  RunBasicJsonPrefStoreTest(
+      pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json"));
+}
+
+TEST_F(JsonPrefStoreTest, PreserveEmptyValues) {
+  FilePath pref_file = temp_dir_.path().AppendASCII("empty_values.json");
+
+  scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
+      pref_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
+
+  // Set some keys with empty values.
+  pref_store->SetValue("list", new base::ListValue,
+                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  pref_store->SetValue("dict", new base::DictionaryValue,
+                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+
+  // Write to file.
+  pref_store->CommitPendingWrite();
+  RunLoop().RunUntilIdle();
+
+  // Reload.
+  pref_store = new JsonPrefStore(pref_file, message_loop_.task_runner(),
+                                 scoped_ptr<PrefFilter>());
+  ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
+  ASSERT_FALSE(pref_store->ReadOnly());
+
+  // Check values.
+  const Value* result = NULL;
+  EXPECT_TRUE(pref_store->GetValue("list", &result));
+  EXPECT_TRUE(ListValue().Equals(result));
+  EXPECT_TRUE(pref_store->GetValue("dict", &result));
+  EXPECT_TRUE(DictionaryValue().Equals(result));
+}
+
+// This test is just documenting some potentially non-obvious behavior. It
+// shouldn't be taken as normative.
+TEST_F(JsonPrefStoreTest, RemoveClearsEmptyParent) {
+  FilePath pref_file = temp_dir_.path().AppendASCII("empty_values.json");
+
+  scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
+      pref_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
+
+  base::DictionaryValue* dict = new base::DictionaryValue;
+  dict->SetString("key", "value");
+  pref_store->SetValue("dict", dict,
+                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+
+  pref_store->RemoveValue("dict.key",
+                          WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+
+  const base::Value* retrieved_dict = NULL;
+  bool has_dict = pref_store->GetValue("dict", &retrieved_dict);
+  EXPECT_FALSE(has_dict);
+}
+
+// Tests asynchronous reading of the file when there is no file.
+TEST_F(JsonPrefStoreTest, AsyncNonExistingFile) {
+  base::FilePath bogus_input_file = temp_dir_.path().AppendASCII("read.txt");
+  ASSERT_FALSE(PathExists(bogus_input_file));
+  scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
+      bogus_input_file, message_loop_.task_runner(), scoped_ptr<PrefFilter>());
+  MockPrefStoreObserver mock_observer;
+  pref_store->AddObserver(&mock_observer);
+
+  MockReadErrorDelegate *mock_error_delegate = new MockReadErrorDelegate;
+  pref_store->ReadPrefsAsync(mock_error_delegate);
+
+  EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1);
+  EXPECT_CALL(*mock_error_delegate,
+              OnError(PersistentPrefStore::PREF_READ_ERROR_NO_FILE)).Times(1);
+  RunLoop().RunUntilIdle();
+  pref_store->RemoveObserver(&mock_observer);
+
+  EXPECT_FALSE(pref_store->ReadOnly());
+}
+
+TEST_F(JsonPrefStoreTest, ReadWithInterceptor) {
+  ASSERT_TRUE(base::CopyFile(data_dir_.AppendASCII("read.json"),
+                             temp_dir_.path().AppendASCII("write.json")));
+
+  // Test that the persistent value can be loaded.
+  base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
+  ASSERT_TRUE(PathExists(input_file));
+
+  scoped_ptr<InterceptingPrefFilter> intercepting_pref_filter(
+      new InterceptingPrefFilter());
+  InterceptingPrefFilter* raw_intercepting_pref_filter_ =
+      intercepting_pref_filter.get();
+  scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
+      input_file, message_loop_.task_runner(), intercepting_pref_filter.Pass());
+
+  ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE,
+            pref_store->ReadPrefs());
+  EXPECT_FALSE(pref_store->ReadOnly());
+
+  // The store shouldn't be considered initialized until the interceptor
+  // returns.
+  EXPECT_TRUE(raw_intercepting_pref_filter_->has_intercepted_prefs());
+  EXPECT_FALSE(pref_store->IsInitializationComplete());
+  EXPECT_FALSE(pref_store->GetValue(kHomePage, NULL));
+
+  raw_intercepting_pref_filter_->ReleasePrefs();
+
+  EXPECT_FALSE(raw_intercepting_pref_filter_->has_intercepted_prefs());
+  EXPECT_TRUE(pref_store->IsInitializationComplete());
+  EXPECT_TRUE(pref_store->GetValue(kHomePage, NULL));
+
+  // The JSON file looks like this:
+  // {
+  //   "homepage": "http://www.cnn.com",
+  //   "some_directory": "/usr/local/",
+  //   "tabs": {
+  //     "new_windows_in_tabs": true,
+  //     "max_tabs": 20
+  //   }
+  // }
+
+  RunBasicJsonPrefStoreTest(
+      pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json"));
+}
+
+TEST_F(JsonPrefStoreTest, ReadAsyncWithInterceptor) {
+  ASSERT_TRUE(base::CopyFile(data_dir_.AppendASCII("read.json"),
+                             temp_dir_.path().AppendASCII("write.json")));
+
+  // Test that the persistent value can be loaded.
+  base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
+  ASSERT_TRUE(PathExists(input_file));
+
+  scoped_ptr<InterceptingPrefFilter> intercepting_pref_filter(
+      new InterceptingPrefFilter());
+  InterceptingPrefFilter* raw_intercepting_pref_filter_ =
+      intercepting_pref_filter.get();
+  scoped_refptr<JsonPrefStore> pref_store = new JsonPrefStore(
+      input_file, message_loop_.task_runner(), intercepting_pref_filter.Pass());
+
+  MockPrefStoreObserver mock_observer;
+  pref_store->AddObserver(&mock_observer);
+
+  // Ownership of the |mock_error_delegate| is handed to the |pref_store| below.
+  MockReadErrorDelegate* mock_error_delegate = new MockReadErrorDelegate;
+
+  {
+    pref_store->ReadPrefsAsync(mock_error_delegate);
+
+    EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(0);
+    // EXPECT_CALL(*mock_error_delegate,
+    //             OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0);
+    RunLoop().RunUntilIdle();
+
+    EXPECT_FALSE(pref_store->ReadOnly());
+    EXPECT_TRUE(raw_intercepting_pref_filter_->has_intercepted_prefs());
+    EXPECT_FALSE(pref_store->IsInitializationComplete());
+    EXPECT_FALSE(pref_store->GetValue(kHomePage, NULL));
+  }
+
+  {
+    EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1);
+    // EXPECT_CALL(*mock_error_delegate,
+    //             OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0);
+
+    raw_intercepting_pref_filter_->ReleasePrefs();
+
+    EXPECT_FALSE(pref_store->ReadOnly());
+    EXPECT_FALSE(raw_intercepting_pref_filter_->has_intercepted_prefs());
+    EXPECT_TRUE(pref_store->IsInitializationComplete());
+    EXPECT_TRUE(pref_store->GetValue(kHomePage, NULL));
+  }
+
+  pref_store->RemoveObserver(&mock_observer);
+
+  // The JSON file looks like this:
+  // {
+  //   "homepage": "http://www.cnn.com",
+  //   "some_directory": "/usr/local/",
+  //   "tabs": {
+  //     "new_windows_in_tabs": true,
+  //     "max_tabs": 20
+  //   }
+  // }
+
+  RunBasicJsonPrefStoreTest(
+      pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json"));
+}
+
+TEST_F(JsonPrefStoreTest, AlternateFile) {
+  ASSERT_TRUE(
+      base::CopyFile(data_dir_.AppendASCII("read.json"),
+                     temp_dir_.path().AppendASCII("alternate.json")));
+
+  // Test that the alternate file is moved to the main file and read as-is from
+  // there.
+  base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
+  base::FilePath alternate_input_file =
+      temp_dir_.path().AppendASCII("alternate.json");
+  ASSERT_FALSE(PathExists(input_file));
+  ASSERT_TRUE(PathExists(alternate_input_file));
+  scoped_refptr<JsonPrefStore> pref_store =
+      new JsonPrefStore(input_file, alternate_input_file,
+                        message_loop_.task_runner(), scoped_ptr<PrefFilter>());
+
+  ASSERT_FALSE(PathExists(input_file));
+  ASSERT_TRUE(PathExists(alternate_input_file));
+  ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
+
+  ASSERT_TRUE(PathExists(input_file));
+  ASSERT_FALSE(PathExists(alternate_input_file));
+
+  EXPECT_FALSE(pref_store->ReadOnly());
+  EXPECT_TRUE(pref_store->IsInitializationComplete());
+
+  // The JSON file looks like this:
+  // {
+  //   "homepage": "http://www.cnn.com",
+  //   "some_directory": "/usr/local/",
+  //   "tabs": {
+  //     "new_windows_in_tabs": true,
+  //     "max_tabs": 20
+  //   }
+  // }
+
+  RunBasicJsonPrefStoreTest(
+      pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json"));
+}
+
+TEST_F(JsonPrefStoreTest, AlternateFileIgnoredWhenMainFileExists) {
+  ASSERT_TRUE(
+      base::CopyFile(data_dir_.AppendASCII("read.json"),
+                     temp_dir_.path().AppendASCII("write.json")));
+  ASSERT_TRUE(
+      base::CopyFile(data_dir_.AppendASCII("invalid.json"),
+                     temp_dir_.path().AppendASCII("alternate.json")));
+
+  // Test that the alternate file is ignored and that the read occurs from the
+  // existing main file. There is no attempt at even deleting the alternate
+  // file as this scenario should never happen in normal user-data-dirs.
+  base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
+  base::FilePath alternate_input_file =
+      temp_dir_.path().AppendASCII("alternate.json");
+  ASSERT_TRUE(PathExists(input_file));
+  ASSERT_TRUE(PathExists(alternate_input_file));
+  scoped_refptr<JsonPrefStore> pref_store =
+      new JsonPrefStore(input_file, alternate_input_file,
+                        message_loop_.task_runner(), scoped_ptr<PrefFilter>());
+
+  ASSERT_TRUE(PathExists(input_file));
+  ASSERT_TRUE(PathExists(alternate_input_file));
+  ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
+
+  ASSERT_TRUE(PathExists(input_file));
+  ASSERT_TRUE(PathExists(alternate_input_file));
+
+  EXPECT_FALSE(pref_store->ReadOnly());
+  EXPECT_TRUE(pref_store->IsInitializationComplete());
+
+  // The JSON file looks like this:
+  // {
+  //   "homepage": "http://www.cnn.com",
+  //   "some_directory": "/usr/local/",
+  //   "tabs": {
+  //     "new_windows_in_tabs": true,
+  //     "max_tabs": 20
+  //   }
+  // }
+
+  RunBasicJsonPrefStoreTest(
+      pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json"));
+}
+
+TEST_F(JsonPrefStoreTest, AlternateFileDNE) {
+  ASSERT_TRUE(
+      base::CopyFile(data_dir_.AppendASCII("read.json"),
+                     temp_dir_.path().AppendASCII("write.json")));
+
+  // Test that the basic read works fine when an alternate file is specified but
+  // does not exist.
+  base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
+  base::FilePath alternate_input_file =
+      temp_dir_.path().AppendASCII("alternate.json");
+  ASSERT_TRUE(PathExists(input_file));
+  ASSERT_FALSE(PathExists(alternate_input_file));
+  scoped_refptr<JsonPrefStore> pref_store =
+      new JsonPrefStore(input_file, alternate_input_file,
+                        message_loop_.task_runner(), scoped_ptr<PrefFilter>());
+
+  ASSERT_TRUE(PathExists(input_file));
+  ASSERT_FALSE(PathExists(alternate_input_file));
+  ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs());
+
+  ASSERT_TRUE(PathExists(input_file));
+  ASSERT_FALSE(PathExists(alternate_input_file));
+
+  EXPECT_FALSE(pref_store->ReadOnly());
+  EXPECT_TRUE(pref_store->IsInitializationComplete());
+
+  // The JSON file looks like this:
+  // {
+  //   "homepage": "http://www.cnn.com",
+  //   "some_directory": "/usr/local/",
+  //   "tabs": {
+  //     "new_windows_in_tabs": true,
+  //     "max_tabs": 20
+  //   }
+  // }
+
+  RunBasicJsonPrefStoreTest(
+      pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json"));
+}
+
+TEST_F(JsonPrefStoreTest, BasicAsyncWithAlternateFile) {
+  ASSERT_TRUE(
+      base::CopyFile(data_dir_.AppendASCII("read.json"),
+                     temp_dir_.path().AppendASCII("alternate.json")));
+
+  // Test that the alternate file is moved to the main file and read as-is from
+  // there even when the read is made asynchronously.
+  base::FilePath input_file = temp_dir_.path().AppendASCII("write.json");
+  base::FilePath alternate_input_file =
+      temp_dir_.path().AppendASCII("alternate.json");
+  ASSERT_FALSE(PathExists(input_file));
+  ASSERT_TRUE(PathExists(alternate_input_file));
+  scoped_refptr<JsonPrefStore> pref_store =
+      new JsonPrefStore(input_file, alternate_input_file,
+                        message_loop_.task_runner(), scoped_ptr<PrefFilter>());
+
+  ASSERT_FALSE(PathExists(input_file));
+  ASSERT_TRUE(PathExists(alternate_input_file));
+
+  {
+    MockPrefStoreObserver mock_observer;
+    pref_store->AddObserver(&mock_observer);
+
+    MockReadErrorDelegate* mock_error_delegate = new MockReadErrorDelegate;
+    pref_store->ReadPrefsAsync(mock_error_delegate);
+
+    EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1);
+    EXPECT_CALL(*mock_error_delegate,
+                OnError(PersistentPrefStore::PREF_READ_ERROR_NONE)).Times(0);
+    RunLoop().RunUntilIdle();
+    pref_store->RemoveObserver(&mock_observer);
+
+    EXPECT_FALSE(pref_store->ReadOnly());
+    EXPECT_TRUE(pref_store->IsInitializationComplete());
+  }
+
+  ASSERT_TRUE(PathExists(input_file));
+  ASSERT_FALSE(PathExists(alternate_input_file));
+
+  // The JSON file looks like this:
+  // {
+  //   "homepage": "http://www.cnn.com",
+  //   "some_directory": "/usr/local/",
+  //   "tabs": {
+  //     "new_windows_in_tabs": true,
+  //     "max_tabs": 20
+  //   }
+  // }
+
+  RunBasicJsonPrefStoreTest(
+      pref_store.get(), input_file, data_dir_.AppendASCII("write.golden.json"));
+}
+
+TEST_F(JsonPrefStoreTest, WriteCountHistogramTestBasic) {
+  SimpleTestClock* test_clock = new SimpleTestClock;
+  SetCurrentTimeInMinutes(0, test_clock);
+  JsonPrefStore::WriteCountHistogram histogram(
+      base::TimeDelta::FromSeconds(10),
+      base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
+      scoped_ptr<base::Clock>(test_clock));
+  int32 report_interval =
+      JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
+
+  histogram.RecordWriteOccured();
+
+  SetCurrentTimeInMinutes(1.5 * report_interval, test_clock);
+  histogram.ReportOutstandingWrites();
+  scoped_ptr<HistogramSamples> samples =
+      histogram.GetHistogram()->SnapshotSamples();
+  ASSERT_EQ(1, samples->GetCount(1));
+  ASSERT_EQ(1, samples->TotalCount());
+
+  ASSERT_EQ("Settings.JsonDataWriteCount.Local_State",
+            histogram.GetHistogram()->histogram_name());
+  ASSERT_TRUE(histogram.GetHistogram()->HasConstructionArguments(1, 30, 31));
+}
+
+TEST_F(JsonPrefStoreTest, WriteCountHistogramTestSinglePeriod) {
+  SimpleTestClock* test_clock = new SimpleTestClock;
+  SetCurrentTimeInMinutes(0, test_clock);
+  JsonPrefStore::WriteCountHistogram histogram(
+      base::TimeDelta::FromSeconds(10),
+      base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
+      scoped_ptr<base::Clock>(test_clock));
+  int32 report_interval =
+      JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
+
+  histogram.RecordWriteOccured();
+  SetCurrentTimeInMinutes(0.5 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+  SetCurrentTimeInMinutes(0.7 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+
+  // Nothing should be recorded until the report period has elapsed.
+  scoped_ptr<HistogramSamples> samples =
+      histogram.GetHistogram()->SnapshotSamples();
+  ASSERT_EQ(0, samples->TotalCount());
+
+  SetCurrentTimeInMinutes(1.3 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+
+  // Now the report period has elapsed.
+  samples = histogram.GetHistogram()->SnapshotSamples();
+  ASSERT_EQ(1, samples->GetCount(3));
+  ASSERT_EQ(1, samples->TotalCount());
+
+  // The last write won't be recorded because the second count period hasn't
+  // fully elapsed.
+  SetCurrentTimeInMinutes(1.5 * report_interval, test_clock);
+  histogram.ReportOutstandingWrites();
+
+  samples = histogram.GetHistogram()->SnapshotSamples();
+  ASSERT_EQ(1, samples->GetCount(3));
+  ASSERT_EQ(1, samples->TotalCount());
+}
+
+TEST_F(JsonPrefStoreTest, WriteCountHistogramTestMultiplePeriods) {
+  SimpleTestClock* test_clock = new SimpleTestClock;
+  SetCurrentTimeInMinutes(0, test_clock);
+  JsonPrefStore::WriteCountHistogram histogram(
+      base::TimeDelta::FromSeconds(10),
+      base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
+      scoped_ptr<base::Clock>(test_clock));
+  int32 report_interval =
+      JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
+
+  histogram.RecordWriteOccured();
+  SetCurrentTimeInMinutes(0.5 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+  SetCurrentTimeInMinutes(0.7 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+  SetCurrentTimeInMinutes(1.3 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+  SetCurrentTimeInMinutes(1.5 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+  SetCurrentTimeInMinutes(2.1 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+  SetCurrentTimeInMinutes(2.5 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+  SetCurrentTimeInMinutes(2.7 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+  SetCurrentTimeInMinutes(3.3 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+
+  // The last write won't be recorded because the second count period hasn't
+  // fully elapsed
+  SetCurrentTimeInMinutes(3.5 * report_interval, test_clock);
+  histogram.ReportOutstandingWrites();
+  scoped_ptr<HistogramSamples> samples =
+      histogram.GetHistogram()->SnapshotSamples();
+  ASSERT_EQ(2, samples->GetCount(3));
+  ASSERT_EQ(1, samples->GetCount(2));
+  ASSERT_EQ(3, samples->TotalCount());
+}
+
+TEST_F(JsonPrefStoreTest, WriteCountHistogramTestPeriodWithGaps) {
+  SimpleTestClock* test_clock = new SimpleTestClock;
+  SetCurrentTimeInMinutes(0, test_clock);
+  JsonPrefStore::WriteCountHistogram histogram(
+      base::TimeDelta::FromSeconds(10),
+      base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
+      scoped_ptr<base::Clock>(test_clock));
+  int32 report_interval =
+      JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
+
+  // 1 write in the first period.
+  histogram.RecordWriteOccured();
+
+  // No writes in the second and third periods.
+
+  // 2 writes in the fourth period.
+  SetCurrentTimeInMinutes(3.1 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+  SetCurrentTimeInMinutes(3.3 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+
+  // No writes in the fifth period.
+
+  // 3 writes in the sixth period.
+  SetCurrentTimeInMinutes(5.1 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+  SetCurrentTimeInMinutes(5.3 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+  SetCurrentTimeInMinutes(5.5 * report_interval, test_clock);
+  histogram.RecordWriteOccured();
+
+  SetCurrentTimeInMinutes(6.1 * report_interval, test_clock);
+  histogram.ReportOutstandingWrites();
+  scoped_ptr<HistogramSamples> samples =
+      histogram.GetHistogram()->SnapshotSamples();
+  ASSERT_EQ(3, samples->GetCount(0));
+  ASSERT_EQ(1, samples->GetCount(1));
+  ASSERT_EQ(1, samples->GetCount(2));
+  ASSERT_EQ(1, samples->GetCount(3));
+  ASSERT_EQ(6, samples->TotalCount());
+}
+
+class JsonPrefStoreLossyWriteTest : public JsonPrefStoreTest {
+ protected:
+  void SetUp() override {
+    JsonPrefStoreTest::SetUp();
+    test_file_ = temp_dir_.path().AppendASCII("test.json");
+  }
+
+  // Creates a JsonPrefStore with the given |file_writer|.
+  scoped_refptr<JsonPrefStore> CreatePrefStore() {
+    return new JsonPrefStore(test_file_, message_loop_.task_runner(),
+                             scoped_ptr<PrefFilter>());
+  }
+
+  // Return the ImportantFileWriter for a given JsonPrefStore.
+  ImportantFileWriter* GetImportantFileWriter(
+      scoped_refptr<JsonPrefStore> pref_store) {
+    return &(pref_store->writer_);
+  }
+
+  // Get the contents of kTestFile. Pumps the message loop before returning the
+  // result.
+  std::string GetTestFileContents() {
+    RunLoop().RunUntilIdle();
+    std::string file_contents;
+    ReadFileToString(test_file_, &file_contents);
+    return file_contents;
+  }
+
+ private:
+  base::FilePath test_file_;
+};
+
+TEST_F(JsonPrefStoreLossyWriteTest, LossyWriteBasic) {
+  scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
+  ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store);
+
+  // Set a normal pref and check that it gets scheduled to be written.
+  ASSERT_FALSE(file_writer->HasPendingWrite());
+  pref_store->SetValue("normal", new base::StringValue("normal"),
+                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  ASSERT_TRUE(file_writer->HasPendingWrite());
+  file_writer->DoScheduledWrite();
+  ASSERT_EQ("{\"normal\":\"normal\"}", GetTestFileContents());
+  ASSERT_FALSE(file_writer->HasPendingWrite());
+
+  // Set a lossy pref and check that it is not scheduled to be written.
+  // SetValue/RemoveValue.
+  pref_store->SetValue("lossy", new base::StringValue("lossy"),
+                       WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
+  ASSERT_FALSE(file_writer->HasPendingWrite());
+  pref_store->RemoveValue("lossy", WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
+  ASSERT_FALSE(file_writer->HasPendingWrite());
+
+  // SetValueSilently/RemoveValueSilently.
+  pref_store->SetValueSilently("lossy", new base::StringValue("lossy"),
+                               WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
+  ASSERT_FALSE(file_writer->HasPendingWrite());
+  pref_store->RemoveValueSilently("lossy",
+                                  WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
+  ASSERT_FALSE(file_writer->HasPendingWrite());
+
+  // ReportValueChanged.
+  pref_store->SetValue("lossy", new base::StringValue("lossy"),
+                       WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
+  ASSERT_FALSE(file_writer->HasPendingWrite());
+  pref_store->ReportValueChanged("lossy",
+                                 WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
+  ASSERT_FALSE(file_writer->HasPendingWrite());
+
+  // Call CommitPendingWrite and check that the lossy pref and the normal pref
+  // are there with the last values set above.
+  pref_store->CommitPendingWrite();
+  ASSERT_FALSE(file_writer->HasPendingWrite());
+  ASSERT_EQ("{\"lossy\":\"lossy\",\"normal\":\"normal\"}",
+            GetTestFileContents());
+}
+
+TEST_F(JsonPrefStoreLossyWriteTest, LossyWriteMixedLossyFirst) {
+  scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
+  ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store);
+
+  // Set a lossy pref and check that it is not scheduled to be written.
+  ASSERT_FALSE(file_writer->HasPendingWrite());
+  pref_store->SetValue("lossy", new base::StringValue("lossy"),
+                       WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
+  ASSERT_FALSE(file_writer->HasPendingWrite());
+
+  // Set a normal pref and check that it is scheduled to be written.
+  pref_store->SetValue("normal", new base::StringValue("normal"),
+                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  ASSERT_TRUE(file_writer->HasPendingWrite());
+
+  // Call DoScheduledWrite and check both prefs get written.
+  file_writer->DoScheduledWrite();
+  ASSERT_EQ("{\"lossy\":\"lossy\",\"normal\":\"normal\"}",
+            GetTestFileContents());
+  ASSERT_FALSE(file_writer->HasPendingWrite());
+}
+
+TEST_F(JsonPrefStoreLossyWriteTest, LossyWriteMixedLossySecond) {
+  scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
+  ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store);
+
+  // Set a normal pref and check that it is scheduled to be written.
+  ASSERT_FALSE(file_writer->HasPendingWrite());
+  pref_store->SetValue("normal", new base::StringValue("normal"),
+                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  ASSERT_TRUE(file_writer->HasPendingWrite());
+
+  // Set a lossy pref and check that the write is still scheduled.
+  pref_store->SetValue("lossy", new base::StringValue("lossy"),
+                       WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
+  ASSERT_TRUE(file_writer->HasPendingWrite());
+
+  // Call DoScheduledWrite and check both prefs get written.
+  file_writer->DoScheduledWrite();
+  ASSERT_EQ("{\"lossy\":\"lossy\",\"normal\":\"normal\"}",
+            GetTestFileContents());
+  ASSERT_FALSE(file_writer->HasPendingWrite());
+}
+
+TEST_F(JsonPrefStoreLossyWriteTest, ScheduleLossyWrite) {
+  scoped_refptr<JsonPrefStore> pref_store = CreatePrefStore();
+  ImportantFileWriter* file_writer = GetImportantFileWriter(pref_store);
+
+  // Set a lossy pref and check that it is not scheduled to be written.
+  pref_store->SetValue("lossy", new base::StringValue("lossy"),
+                       WriteablePrefStore::LOSSY_PREF_WRITE_FLAG);
+  ASSERT_FALSE(file_writer->HasPendingWrite());
+
+  // Schedule pending lossy writes and check that it is scheduled.
+  pref_store->SchedulePendingLossyWrites();
+  ASSERT_TRUE(file_writer->HasPendingWrite());
+
+  // Call CommitPendingWrite and check that the lossy pref is there with the
+  // last value set above.
+  pref_store->CommitPendingWrite();
+  ASSERT_FALSE(file_writer->HasPendingWrite());
+  ASSERT_EQ("{\"lossy\":\"lossy\"}", GetTestFileContents());
+}
+
+}  // namespace base
diff --git a/base/prefs/mock_pref_change_callback.cc b/base/prefs/mock_pref_change_callback.cc
new file mode 100644
index 0000000..96b7197
--- /dev/null
+++ b/base/prefs/mock_pref_change_callback.cc
@@ -0,0 +1,24 @@
+// Copyright (c) 2011 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/prefs/mock_pref_change_callback.h"
+
+#include "base/bind.h"
+
+MockPrefChangeCallback::MockPrefChangeCallback(PrefService* prefs)
+    : prefs_(prefs) {
+}
+
+MockPrefChangeCallback::~MockPrefChangeCallback() {}
+
+PrefChangeRegistrar::NamedChangeCallback MockPrefChangeCallback::GetCallback() {
+  return base::Bind(&MockPrefChangeCallback::OnPreferenceChanged,
+                    base::Unretained(this));
+}
+
+void MockPrefChangeCallback::Expect(const std::string& pref_name,
+                                    const base::Value* value) {
+  EXPECT_CALL(*this, OnPreferenceChanged(pref_name))
+      .With(PrefValueMatches(prefs_, pref_name, value));
+}
diff --git a/base/prefs/mock_pref_change_callback.h b/base/prefs/mock_pref_change_callback.h
new file mode 100644
index 0000000..3030fab
--- /dev/null
+++ b/base/prefs/mock_pref_change_callback.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2011 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_PREFS_MOCK_PREF_CHANGE_CALLBACK_H_
+#define BASE_PREFS_MOCK_PREF_CHANGE_CALLBACK_H_
+
+#include <string>
+
+#include "base/prefs/pref_change_registrar.h"
+#include "base/prefs/pref_service.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+using testing::Pointee;
+using testing::Property;
+using testing::Truly;
+
+// Matcher that checks whether the current value of the preference named
+// |pref_name| in |prefs| matches |value|. If |value| is NULL, the matcher
+// checks that the value is not set.
+MATCHER_P3(PrefValueMatches, prefs, pref_name, value, "") {
+  const PrefService::Preference* pref = prefs->FindPreference(pref_name);
+  if (!pref)
+    return false;
+
+  const base::Value* actual_value = pref->GetValue();
+  if (!actual_value)
+    return value == NULL;
+  if (!value)
+    return actual_value == NULL;
+  return value->Equals(actual_value);
+}
+
+// A mock for testing preference notifications and easy setup of expectations.
+class MockPrefChangeCallback {
+ public:
+  explicit MockPrefChangeCallback(PrefService* prefs);
+  virtual ~MockPrefChangeCallback();
+
+  PrefChangeRegistrar::NamedChangeCallback GetCallback();
+
+  MOCK_METHOD1(OnPreferenceChanged, void(const std::string&));
+
+  void Expect(const std::string& pref_name,
+              const base::Value* value);
+
+ private:
+  PrefService* prefs_;
+};
+
+#endif  // BASE_PREFS_MOCK_PREF_CHANGE_CALLBACK_H_
diff --git a/base/prefs/overlay_user_pref_store.cc b/base/prefs/overlay_user_pref_store.cc
new file mode 100644
index 0000000..4c236f1
--- /dev/null
+++ b/base/prefs/overlay_user_pref_store.cc
@@ -0,0 +1,184 @@
+// Copyright (c) 2012 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/prefs/overlay_user_pref_store.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "base/values.h"
+
+OverlayUserPrefStore::OverlayUserPrefStore(
+    PersistentPrefStore* underlay)
+    : underlay_(underlay) {
+  underlay_->AddObserver(this);
+}
+
+bool OverlayUserPrefStore::IsSetInOverlay(const std::string& key) const {
+  return overlay_.GetValue(key, NULL);
+}
+
+void OverlayUserPrefStore::AddObserver(PrefStore::Observer* observer) {
+  observers_.AddObserver(observer);
+}
+
+void OverlayUserPrefStore::RemoveObserver(PrefStore::Observer* observer) {
+  observers_.RemoveObserver(observer);
+}
+
+bool OverlayUserPrefStore::HasObservers() const {
+  return observers_.might_have_observers();
+}
+
+bool OverlayUserPrefStore::IsInitializationComplete() const {
+  return underlay_->IsInitializationComplete();
+}
+
+bool OverlayUserPrefStore::GetValue(const std::string& key,
+                                    const base::Value** result) const {
+  // If the |key| shall NOT be stored in the overlay store, there must not
+  // be an entry.
+  DCHECK(ShallBeStoredInOverlay(key) || !overlay_.GetValue(key, NULL));
+
+  if (overlay_.GetValue(key, result))
+    return true;
+  return underlay_->GetValue(GetUnderlayKey(key), result);
+}
+
+bool OverlayUserPrefStore::GetMutableValue(const std::string& key,
+                                           base::Value** result) {
+  if (!ShallBeStoredInOverlay(key))
+    return underlay_->GetMutableValue(GetUnderlayKey(key), result);
+
+  if (overlay_.GetValue(key, result))
+    return true;
+
+  // Try to create copy of underlay if the overlay does not contain a value.
+  base::Value* underlay_value = NULL;
+  if (!underlay_->GetMutableValue(GetUnderlayKey(key), &underlay_value))
+    return false;
+
+  *result = underlay_value->DeepCopy();
+  overlay_.SetValue(key, *result);
+  return true;
+}
+
+void OverlayUserPrefStore::SetValue(const std::string& key,
+                                    base::Value* value,
+                                    uint32 flags) {
+  if (!ShallBeStoredInOverlay(key)) {
+    underlay_->SetValue(GetUnderlayKey(key), value, flags);
+    return;
+  }
+
+  if (overlay_.SetValue(key, value))
+    ReportValueChanged(key, flags);
+}
+
+void OverlayUserPrefStore::SetValueSilently(const std::string& key,
+                                            base::Value* value,
+                                            uint32 flags) {
+  if (!ShallBeStoredInOverlay(key)) {
+    underlay_->SetValueSilently(GetUnderlayKey(key), value, flags);
+    return;
+  }
+
+  overlay_.SetValue(key, value);
+}
+
+void OverlayUserPrefStore::RemoveValue(const std::string& key, uint32 flags) {
+  if (!ShallBeStoredInOverlay(key)) {
+    underlay_->RemoveValue(GetUnderlayKey(key), flags);
+    return;
+  }
+
+  if (overlay_.RemoveValue(key))
+    ReportValueChanged(key, flags);
+}
+
+bool OverlayUserPrefStore::ReadOnly() const {
+  return false;
+}
+
+PersistentPrefStore::PrefReadError OverlayUserPrefStore::GetReadError() const {
+  return PersistentPrefStore::PREF_READ_ERROR_NONE;
+}
+
+PersistentPrefStore::PrefReadError OverlayUserPrefStore::ReadPrefs() {
+  // We do not read intentionally.
+  OnInitializationCompleted(true);
+  return PersistentPrefStore::PREF_READ_ERROR_NONE;
+}
+
+void OverlayUserPrefStore::ReadPrefsAsync(
+    ReadErrorDelegate* error_delegate_raw) {
+  scoped_ptr<ReadErrorDelegate> error_delegate(error_delegate_raw);
+  // We do not read intentionally.
+  OnInitializationCompleted(true);
+}
+
+void OverlayUserPrefStore::CommitPendingWrite() {
+  underlay_->CommitPendingWrite();
+  // We do not write our content intentionally.
+}
+
+void OverlayUserPrefStore::SchedulePendingLossyWrites() {
+  underlay_->SchedulePendingLossyWrites();
+}
+
+void OverlayUserPrefStore::ReportValueChanged(const std::string& key,
+                                              uint32 flags) {
+  FOR_EACH_OBSERVER(PrefStore::Observer, observers_, OnPrefValueChanged(key));
+}
+
+void OverlayUserPrefStore::OnPrefValueChanged(const std::string& key) {
+  if (!overlay_.GetValue(GetOverlayKey(key), NULL))
+    ReportValueChanged(GetOverlayKey(key), DEFAULT_PREF_WRITE_FLAGS);
+}
+
+void OverlayUserPrefStore::OnInitializationCompleted(bool succeeded) {
+  FOR_EACH_OBSERVER(PrefStore::Observer, observers_,
+                    OnInitializationCompleted(succeeded));
+}
+
+void OverlayUserPrefStore::RegisterOverlayPref(const std::string& key) {
+  RegisterOverlayPref(key, key);
+}
+
+void OverlayUserPrefStore::RegisterOverlayPref(
+    const std::string& overlay_key,
+    const std::string& underlay_key) {
+  DCHECK(!overlay_key.empty()) << "Overlay key is empty";
+  DCHECK(overlay_to_underlay_names_map_.find(overlay_key) ==
+         overlay_to_underlay_names_map_.end()) <<
+      "Overlay key already registered";
+  DCHECK(!underlay_key.empty()) << "Underlay key is empty";
+  DCHECK(underlay_to_overlay_names_map_.find(underlay_key) ==
+         underlay_to_overlay_names_map_.end()) <<
+      "Underlay key already registered";
+  overlay_to_underlay_names_map_[overlay_key] = underlay_key;
+  underlay_to_overlay_names_map_[underlay_key] = overlay_key;
+}
+
+OverlayUserPrefStore::~OverlayUserPrefStore() {
+  underlay_->RemoveObserver(this);
+}
+
+const std::string& OverlayUserPrefStore::GetOverlayKey(
+    const std::string& underlay_key) const {
+  NamesMap::const_iterator i =
+      underlay_to_overlay_names_map_.find(underlay_key);
+  return i != underlay_to_overlay_names_map_.end() ? i->second : underlay_key;
+}
+
+const std::string& OverlayUserPrefStore::GetUnderlayKey(
+    const std::string& overlay_key) const {
+  NamesMap::const_iterator i =
+      overlay_to_underlay_names_map_.find(overlay_key);
+  return i != overlay_to_underlay_names_map_.end() ? i->second : overlay_key;
+}
+
+bool OverlayUserPrefStore::ShallBeStoredInOverlay(
+    const std::string& key) const {
+  return overlay_to_underlay_names_map_.find(key) !=
+      overlay_to_underlay_names_map_.end();
+}
diff --git a/base/prefs/overlay_user_pref_store.h b/base/prefs/overlay_user_pref_store.h
new file mode 100644
index 0000000..885da08
--- /dev/null
+++ b/base/prefs/overlay_user_pref_store.h
@@ -0,0 +1,87 @@
+// Copyright (c) 2012 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_PREFS_OVERLAY_USER_PREF_STORE_H_
+#define BASE_PREFS_OVERLAY_USER_PREF_STORE_H_
+
+#include <map>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/observer_list.h"
+#include "base/prefs/base_prefs_export.h"
+#include "base/prefs/persistent_pref_store.h"
+#include "base/prefs/pref_value_map.h"
+
+// PersistentPrefStore that directs all write operations into an in-memory
+// PrefValueMap. Read operations are first answered by the PrefValueMap.
+// If the PrefValueMap does not contain a value for the requested key,
+// the look-up is passed on to an underlying PersistentPrefStore |underlay_|.
+class BASE_PREFS_EXPORT OverlayUserPrefStore : public PersistentPrefStore,
+                                               public PrefStore::Observer {
+ public:
+  explicit OverlayUserPrefStore(PersistentPrefStore* underlay);
+
+  // Returns true if a value has been set for the |key| in this
+  // OverlayUserPrefStore, i.e. if it potentially overrides a value
+  // from the |underlay_|.
+  virtual bool IsSetInOverlay(const std::string& key) const;
+
+  // Methods of PrefStore.
+  void AddObserver(PrefStore::Observer* observer) override;
+  void RemoveObserver(PrefStore::Observer* observer) override;
+  bool HasObservers() const override;
+  bool IsInitializationComplete() const override;
+  bool GetValue(const std::string& key,
+                const base::Value** result) const override;
+
+  // Methods of PersistentPrefStore.
+  bool GetMutableValue(const std::string& key, base::Value** result) override;
+  void SetValue(const std::string& key,
+                base::Value* value,
+                uint32 flags) override;
+  void SetValueSilently(const std::string& key,
+                        base::Value* value,
+                        uint32 flags) override;
+  void RemoveValue(const std::string& key, uint32 flags) override;
+  bool ReadOnly() const override;
+  PrefReadError GetReadError() const override;
+  PrefReadError ReadPrefs() override;
+  void ReadPrefsAsync(ReadErrorDelegate* delegate) override;
+  void CommitPendingWrite() override;
+  void SchedulePendingLossyWrites() override;
+  void ReportValueChanged(const std::string& key, uint32 flags) override;
+
+  // Methods of PrefStore::Observer.
+  void OnPrefValueChanged(const std::string& key) override;
+  void OnInitializationCompleted(bool succeeded) override;
+
+  void RegisterOverlayPref(const std::string& key);
+  void RegisterOverlayPref(const std::string& overlay_key,
+                           const std::string& underlay_key);
+
+ protected:
+  ~OverlayUserPrefStore() override;
+
+ private:
+  typedef std::map<std::string, std::string> NamesMap;
+
+  const std::string& GetOverlayKey(const std::string& underlay_key) const;
+  const std::string& GetUnderlayKey(const std::string& overlay_key) const;
+
+  // Returns true if |key| corresponds to a preference that shall be stored in
+  // an in-memory PrefStore that is not persisted to disk.
+  bool ShallBeStoredInOverlay(const std::string& key) const;
+
+  base::ObserverList<PrefStore::Observer, true> observers_;
+  PrefValueMap overlay_;
+  scoped_refptr<PersistentPrefStore> underlay_;
+  NamesMap overlay_to_underlay_names_map_;
+  NamesMap underlay_to_overlay_names_map_;
+
+  DISALLOW_COPY_AND_ASSIGN(OverlayUserPrefStore);
+};
+
+#endif  // BASE_PREFS_OVERLAY_USER_PREF_STORE_H_
diff --git a/base/prefs/overlay_user_pref_store_unittest.cc b/base/prefs/overlay_user_pref_store_unittest.cc
new file mode 100644
index 0000000..06b4ec9
--- /dev/null
+++ b/base/prefs/overlay_user_pref_store_unittest.cc
@@ -0,0 +1,283 @@
+// Copyright (c) 2012 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/prefs/overlay_user_pref_store.h"
+
+#include "base/prefs/pref_store_observer_mock.h"
+#include "base/prefs/testing_pref_store.h"
+#include "base/values.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::Mock;
+using ::testing::StrEq;
+
+namespace base {
+namespace {
+
+const char kBrowserWindowPlacement[] = "browser.window_placement";
+const char kShowBookmarkBar[] = "bookmark_bar.show_on_all_tabs";
+
+const char* const overlay_key = kBrowserWindowPlacement;
+const char* const regular_key = kShowBookmarkBar;
+// With the removal of the kWebKitGlobalXXX prefs, we'll no longer have real
+// prefs using the overlay pref store, so make up keys here.
+const char mapped_overlay_key[] = "test.per_tab.javascript_enabled";
+const char mapped_underlay_key[] = "test.per_profile.javascript_enabled";
+
+}  // namespace
+
+class OverlayUserPrefStoreTest : public testing::Test {
+ protected:
+  OverlayUserPrefStoreTest()
+      : underlay_(new TestingPrefStore()),
+        overlay_(new OverlayUserPrefStore(underlay_.get())) {
+    overlay_->RegisterOverlayPref(overlay_key);
+    overlay_->RegisterOverlayPref(mapped_overlay_key, mapped_underlay_key);
+  }
+
+  ~OverlayUserPrefStoreTest() override {}
+
+  scoped_refptr<TestingPrefStore> underlay_;
+  scoped_refptr<OverlayUserPrefStore> overlay_;
+};
+
+TEST_F(OverlayUserPrefStoreTest, Observer) {
+  PrefStoreObserverMock obs;
+  overlay_->AddObserver(&obs);
+
+  // Check that underlay first value is reported.
+  underlay_->SetValue(overlay_key, new FundamentalValue(42),
+                      WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  obs.VerifyAndResetChangedKey(overlay_key);
+
+  // Check that underlay overwriting is reported.
+  underlay_->SetValue(overlay_key, new FundamentalValue(43),
+                      WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  obs.VerifyAndResetChangedKey(overlay_key);
+
+  // Check that overwriting change in overlay is reported.
+  overlay_->SetValue(overlay_key, new FundamentalValue(44),
+                     WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  obs.VerifyAndResetChangedKey(overlay_key);
+
+  // Check that hidden underlay change is not reported.
+  underlay_->SetValue(overlay_key, new FundamentalValue(45),
+                      WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  EXPECT_TRUE(obs.changed_keys.empty());
+
+  // Check that overlay remove is reported.
+  overlay_->RemoveValue(overlay_key,
+                        WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  obs.VerifyAndResetChangedKey(overlay_key);
+
+  // Check that underlay remove is reported.
+  underlay_->RemoveValue(overlay_key,
+                         WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  obs.VerifyAndResetChangedKey(overlay_key);
+
+  // Check respecting of silence.
+  overlay_->SetValueSilently(overlay_key, new FundamentalValue(46),
+                             WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  EXPECT_TRUE(obs.changed_keys.empty());
+
+  overlay_->RemoveObserver(&obs);
+
+  // Check successful unsubscription.
+  underlay_->SetValue(overlay_key, new FundamentalValue(47),
+                      WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  overlay_->SetValue(overlay_key, new FundamentalValue(48),
+                     WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  EXPECT_TRUE(obs.changed_keys.empty());
+}
+
+TEST_F(OverlayUserPrefStoreTest, GetAndSet) {
+  const Value* value = NULL;
+  EXPECT_FALSE(overlay_->GetValue(overlay_key, &value));
+  EXPECT_FALSE(underlay_->GetValue(overlay_key, &value));
+
+  underlay_->SetValue(overlay_key, new FundamentalValue(42),
+                      WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+
+  // Value shines through:
+  EXPECT_TRUE(overlay_->GetValue(overlay_key, &value));
+  EXPECT_TRUE(base::FundamentalValue(42).Equals(value));
+
+  EXPECT_TRUE(underlay_->GetValue(overlay_key, &value));
+  EXPECT_TRUE(base::FundamentalValue(42).Equals(value));
+
+  overlay_->SetValue(overlay_key, new FundamentalValue(43),
+                     WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+
+  EXPECT_TRUE(overlay_->GetValue(overlay_key, &value));
+  EXPECT_TRUE(base::FundamentalValue(43).Equals(value));
+
+  EXPECT_TRUE(underlay_->GetValue(overlay_key, &value));
+  EXPECT_TRUE(base::FundamentalValue(42).Equals(value));
+
+  overlay_->RemoveValue(overlay_key,
+                        WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+
+  // Value shines through:
+  EXPECT_TRUE(overlay_->GetValue(overlay_key, &value));
+  EXPECT_TRUE(base::FundamentalValue(42).Equals(value));
+
+  EXPECT_TRUE(underlay_->GetValue(overlay_key, &value));
+  EXPECT_TRUE(base::FundamentalValue(42).Equals(value));
+}
+
+// Check that GetMutableValue does not return the dictionary of the underlay.
+TEST_F(OverlayUserPrefStoreTest, ModifyDictionaries) {
+  underlay_->SetValue(overlay_key, new DictionaryValue,
+                      WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+
+  Value* modify = NULL;
+  EXPECT_TRUE(overlay_->GetMutableValue(overlay_key, &modify));
+  ASSERT_TRUE(modify);
+  ASSERT_TRUE(modify->IsType(Value::TYPE_DICTIONARY));
+  static_cast<DictionaryValue*>(modify)->SetInteger(overlay_key, 42);
+
+  Value* original_in_underlay = NULL;
+  EXPECT_TRUE(underlay_->GetMutableValue(overlay_key, &original_in_underlay));
+  ASSERT_TRUE(original_in_underlay);
+  ASSERT_TRUE(original_in_underlay->IsType(Value::TYPE_DICTIONARY));
+  EXPECT_TRUE(static_cast<DictionaryValue*>(original_in_underlay)->empty());
+
+  Value* modified = NULL;
+  EXPECT_TRUE(overlay_->GetMutableValue(overlay_key, &modified));
+  ASSERT_TRUE(modified);
+  ASSERT_TRUE(modified->IsType(Value::TYPE_DICTIONARY));
+  EXPECT_TRUE(Value::Equals(modify, static_cast<DictionaryValue*>(modified)));
+}
+
+// Here we consider a global preference that is not overlayed.
+TEST_F(OverlayUserPrefStoreTest, GlobalPref) {
+  PrefStoreObserverMock obs;
+  overlay_->AddObserver(&obs);
+
+  const Value* value = NULL;
+
+  // Check that underlay first value is reported.
+  underlay_->SetValue(regular_key, new FundamentalValue(42),
+                      WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  obs.VerifyAndResetChangedKey(regular_key);
+
+  // Check that underlay overwriting is reported.
+  underlay_->SetValue(regular_key, new FundamentalValue(43),
+                      WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  obs.VerifyAndResetChangedKey(regular_key);
+
+  // Check that we get this value from the overlay
+  EXPECT_TRUE(overlay_->GetValue(regular_key, &value));
+  EXPECT_TRUE(base::FundamentalValue(43).Equals(value));
+
+  // Check that overwriting change in overlay is reported.
+  overlay_->SetValue(regular_key, new FundamentalValue(44),
+                     WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  obs.VerifyAndResetChangedKey(regular_key);
+
+  // Check that we get this value from the overlay and the underlay.
+  EXPECT_TRUE(overlay_->GetValue(regular_key, &value));
+  EXPECT_TRUE(base::FundamentalValue(44).Equals(value));
+  EXPECT_TRUE(underlay_->GetValue(regular_key, &value));
+  EXPECT_TRUE(base::FundamentalValue(44).Equals(value));
+
+  // Check that overlay remove is reported.
+  overlay_->RemoveValue(regular_key,
+                        WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  obs.VerifyAndResetChangedKey(regular_key);
+
+  // Check that value was removed from overlay and underlay
+  EXPECT_FALSE(overlay_->GetValue(regular_key, &value));
+  EXPECT_FALSE(underlay_->GetValue(regular_key, &value));
+
+  // Check respecting of silence.
+  overlay_->SetValueSilently(regular_key, new FundamentalValue(46),
+                             WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  EXPECT_TRUE(obs.changed_keys.empty());
+
+  overlay_->RemoveObserver(&obs);
+
+  // Check successful unsubscription.
+  underlay_->SetValue(regular_key, new FundamentalValue(47),
+                      WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  overlay_->SetValue(regular_key, new FundamentalValue(48),
+                     WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  EXPECT_TRUE(obs.changed_keys.empty());
+}
+
+// Check that names mapping works correctly.
+TEST_F(OverlayUserPrefStoreTest, NamesMapping) {
+  PrefStoreObserverMock obs;
+  overlay_->AddObserver(&obs);
+
+  const Value* value = NULL;
+
+  // Check that if there is no override in the overlay, changing underlay value
+  // is reported as changing an overlay value.
+  underlay_->SetValue(mapped_underlay_key, new FundamentalValue(42),
+                      WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  obs.VerifyAndResetChangedKey(mapped_overlay_key);
+
+  // Check that underlay overwriting is reported.
+  underlay_->SetValue(mapped_underlay_key, new FundamentalValue(43),
+                      WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  obs.VerifyAndResetChangedKey(mapped_overlay_key);
+
+  // Check that we get this value from the overlay with both keys
+  EXPECT_TRUE(overlay_->GetValue(mapped_overlay_key, &value));
+  EXPECT_TRUE(base::FundamentalValue(43).Equals(value));
+  // In this case, overlay reads directly from the underlay.
+  EXPECT_TRUE(overlay_->GetValue(mapped_underlay_key, &value));
+  EXPECT_TRUE(base::FundamentalValue(43).Equals(value));
+
+  // Check that overwriting change in overlay is reported.
+  overlay_->SetValue(mapped_overlay_key, new FundamentalValue(44),
+                     WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  obs.VerifyAndResetChangedKey(mapped_overlay_key);
+
+  // Check that we get an overriden value from overlay, while reading the
+  // value from underlay still holds an old value.
+  EXPECT_TRUE(overlay_->GetValue(mapped_overlay_key, &value));
+  EXPECT_TRUE(base::FundamentalValue(44).Equals(value));
+  EXPECT_TRUE(overlay_->GetValue(mapped_underlay_key, &value));
+  EXPECT_TRUE(base::FundamentalValue(43).Equals(value));
+  EXPECT_TRUE(underlay_->GetValue(mapped_underlay_key, &value));
+  EXPECT_TRUE(base::FundamentalValue(43).Equals(value));
+
+  // Check that hidden underlay change is not reported.
+  underlay_->SetValue(mapped_underlay_key, new FundamentalValue(45),
+                      WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  EXPECT_TRUE(obs.changed_keys.empty());
+
+  // Check that overlay remove is reported.
+  overlay_->RemoveValue(mapped_overlay_key,
+                        WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  obs.VerifyAndResetChangedKey(mapped_overlay_key);
+
+  // Check that underlay remove is reported.
+  underlay_->RemoveValue(mapped_underlay_key,
+                         WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  obs.VerifyAndResetChangedKey(mapped_overlay_key);
+
+  // Check that value was removed.
+  EXPECT_FALSE(overlay_->GetValue(mapped_overlay_key, &value));
+  EXPECT_FALSE(overlay_->GetValue(mapped_underlay_key, &value));
+
+  // Check respecting of silence.
+  overlay_->SetValueSilently(mapped_overlay_key, new FundamentalValue(46),
+                             WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  EXPECT_TRUE(obs.changed_keys.empty());
+
+  overlay_->RemoveObserver(&obs);
+
+  // Check successful unsubscription.
+  underlay_->SetValue(mapped_underlay_key, new FundamentalValue(47),
+                      WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  overlay_->SetValue(mapped_overlay_key, new FundamentalValue(48),
+                     WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  EXPECT_TRUE(obs.changed_keys.empty());
+}
+
+}  // namespace base
diff --git a/base/prefs/persistent_pref_store.h b/base/prefs/persistent_pref_store.h
new file mode 100644
index 0000000..ad8a0a3
--- /dev/null
+++ b/base/prefs/persistent_pref_store.h
@@ -0,0 +1,80 @@
+// Copyright (c) 2012 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_PREFS_PERSISTENT_PREF_STORE_H_
+#define BASE_PREFS_PERSISTENT_PREF_STORE_H_
+
+#include <string>
+
+#include "base/prefs/base_prefs_export.h"
+#include "base/prefs/writeable_pref_store.h"
+
+// This interface is complementary to the PrefStore interface, declaring
+// additional functionality that adds support for setting values and persisting
+// the data to some backing store.
+class BASE_PREFS_EXPORT PersistentPrefStore : public WriteablePrefStore {
+ public:
+  // Unique integer code for each type of error so we can report them
+  // distinctly in a histogram.
+  // NOTE: Don't change the explicit values of the enums as it will change the
+  // server's meaning of the histogram.
+  enum PrefReadError {
+    PREF_READ_ERROR_NONE = 0,
+    PREF_READ_ERROR_JSON_PARSE = 1,
+    PREF_READ_ERROR_JSON_TYPE = 2,
+    PREF_READ_ERROR_ACCESS_DENIED = 3,
+    PREF_READ_ERROR_FILE_OTHER = 4,
+    PREF_READ_ERROR_FILE_LOCKED = 5,
+    PREF_READ_ERROR_NO_FILE = 6,
+    PREF_READ_ERROR_JSON_REPEAT = 7,
+    // PREF_READ_ERROR_OTHER = 8,  // Deprecated.
+    PREF_READ_ERROR_FILE_NOT_SPECIFIED = 9,
+    // Indicates that ReadPrefs() couldn't complete synchronously and is waiting
+    // for an asynchronous task to complete first.
+    PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE = 10,
+    PREF_READ_ERROR_LEVELDB_IO = 11,
+    PREF_READ_ERROR_LEVELDB_CORRUPTION_READ_ONLY = 12,
+    PREF_READ_ERROR_LEVELDB_CORRUPTION = 13,
+    PREF_READ_ERROR_MAX_ENUM
+  };
+
+  class ReadErrorDelegate {
+   public:
+    virtual ~ReadErrorDelegate() {}
+
+    virtual void OnError(PrefReadError error) = 0;
+  };
+
+  // Whether the store is in a pseudo-read-only mode where changes are not
+  // actually persisted to disk.  This happens in some cases when there are
+  // read errors during startup.
+  virtual bool ReadOnly() const = 0;
+
+  // Gets the read error. Only valid if IsInitializationComplete() returns true.
+  virtual PrefReadError GetReadError() const = 0;
+
+  // Reads the preferences from disk. Notifies observers via
+  // "PrefStore::OnInitializationCompleted" when done.
+  virtual PrefReadError ReadPrefs() = 0;
+
+  // Reads the preferences from disk asynchronously. Notifies observers via
+  // "PrefStore::OnInitializationCompleted" when done. Also it fires
+  // |error_delegate| if it is not NULL and reading error has occurred.
+  // Owns |error_delegate|.
+  virtual void ReadPrefsAsync(ReadErrorDelegate* error_delegate) = 0;
+
+  // Lands any pending writes to disk.
+  virtual void CommitPendingWrite() = 0;
+
+  // Schedule a write if there is any lossy data pending. Unlike
+  // CommitPendingWrite() this does not immediately sync to disk, instead it
+  // triggers an eventual write if there is lossy data pending and if there
+  // isn't one scheduled already.
+  virtual void SchedulePendingLossyWrites() = 0;
+
+ protected:
+  ~PersistentPrefStore() override {}
+};
+
+#endif  // BASE_PREFS_PERSISTENT_PREF_STORE_H_
diff --git a/base/prefs/pref_change_registrar.cc b/base/prefs/pref_change_registrar.cc
new file mode 100644
index 0000000..1319348
--- /dev/null
+++ b/base/prefs/pref_change_registrar.cc
@@ -0,0 +1,94 @@
+// Copyright (c) 2010 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/prefs/pref_change_registrar.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/prefs/pref_service.h"
+
+PrefChangeRegistrar::PrefChangeRegistrar() : service_(NULL) {}
+
+PrefChangeRegistrar::~PrefChangeRegistrar() {
+  // If you see an invalid memory access in this destructor, this
+  // PrefChangeRegistrar might be subscribed to an OffTheRecordProfileImpl that
+  // has been destroyed. This should not happen any more but be warned.
+  // Feel free to contact battre@chromium.org in case this happens.
+  RemoveAll();
+}
+
+void PrefChangeRegistrar::Init(PrefService* service) {
+  DCHECK(IsEmpty() || service_ == service);
+  service_ = service;
+}
+
+void PrefChangeRegistrar::Add(const std::string& path,
+                              const base::Closure& obs) {
+  Add(path, base::Bind(&PrefChangeRegistrar::InvokeUnnamedCallback, obs));
+}
+
+void PrefChangeRegistrar::Add(const std::string& path,
+                              const NamedChangeCallback& obs) {
+  if (!service_) {
+    NOTREACHED();
+    return;
+  }
+  DCHECK(!IsObserved(path)) << "Already had this pref registered.";
+
+  service_->AddPrefObserver(path, this);
+  observers_[path] = obs;
+}
+
+void PrefChangeRegistrar::Remove(const std::string& path) {
+  DCHECK(IsObserved(path));
+
+  observers_.erase(path);
+  service_->RemovePrefObserver(path, this);
+}
+
+void PrefChangeRegistrar::RemoveAll() {
+  for (ObserverMap::const_iterator it = observers_.begin();
+       it != observers_.end(); ++it) {
+    service_->RemovePrefObserver(it->first, this);
+  }
+
+  observers_.clear();
+}
+
+bool PrefChangeRegistrar::IsEmpty() const {
+  return observers_.empty();
+}
+
+bool PrefChangeRegistrar::IsObserved(const std::string& pref) {
+  return observers_.find(pref) != observers_.end();
+}
+
+bool PrefChangeRegistrar::IsManaged() {
+  for (ObserverMap::const_iterator it = observers_.begin();
+       it != observers_.end(); ++it) {
+    const PrefService::Preference* pref = service_->FindPreference(it->first);
+    if (pref && pref->IsManaged())
+      return true;
+  }
+  return false;
+}
+
+void PrefChangeRegistrar::OnPreferenceChanged(PrefService* service,
+                                              const std::string& pref) {
+  if (IsObserved(pref))
+    observers_[pref].Run(pref);
+}
+
+void PrefChangeRegistrar::InvokeUnnamedCallback(const base::Closure& callback,
+                                                const std::string& pref_name) {
+  callback.Run();
+}
+
+PrefService* PrefChangeRegistrar::prefs() {
+  return service_;
+}
+
+const PrefService* PrefChangeRegistrar::prefs() const {
+  return service_;
+}
diff --git a/base/prefs/pref_change_registrar.h b/base/prefs/pref_change_registrar.h
new file mode 100644
index 0000000..acf0a68
--- /dev/null
+++ b/base/prefs/pref_change_registrar.h
@@ -0,0 +1,81 @@
+// Copyright (c) 2010 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_PREFS_PREF_CHANGE_REGISTRAR_H_
+#define BASE_PREFS_PREF_CHANGE_REGISTRAR_H_
+
+#include <map>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/prefs/base_prefs_export.h"
+#include "base/prefs/pref_observer.h"
+
+class PrefService;
+
+// Automatically manages the registration of one or more pref change observers
+// with a PrefStore. Functions much like NotificationRegistrar, but specifically
+// manages observers of preference changes. When the Registrar is destroyed,
+// all registered observers are automatically unregistered with the PrefStore.
+class BASE_PREFS_EXPORT PrefChangeRegistrar : public PrefObserver {
+ public:
+  // You can register this type of callback if you need to know the
+  // path of the preference that is changing.
+  typedef base::Callback<void(const std::string&)> NamedChangeCallback;
+
+  PrefChangeRegistrar();
+  virtual ~PrefChangeRegistrar();
+
+  // Must be called before adding or removing observers. Can be called more
+  // than once as long as the value of |service| doesn't change.
+  void Init(PrefService* service);
+
+  // Adds a pref observer for the specified pref |path| and |obs| observer
+  // object. All registered observers will be automatically unregistered
+  // when the registrar's destructor is called.
+  //
+  // The second version binds a callback that will receive the path of
+  // the preference that is changing as its parameter.
+  //
+  // Only one observer may be registered per path.
+  void Add(const std::string& path, const base::Closure& obs);
+  void Add(const std::string& path, const NamedChangeCallback& obs);
+
+  // Removes the pref observer registered for |path|.
+  void Remove(const std::string& path);
+
+  // Removes all observers that have been previously added with a call to Add.
+  void RemoveAll();
+
+  // Returns true if no pref observers are registered.
+  bool IsEmpty() const;
+
+  // Check whether |pref| is in the set of preferences being observed.
+  bool IsObserved(const std::string& pref);
+
+  // Check whether any of the observed preferences has the managed bit set.
+  bool IsManaged();
+
+  // Return the PrefService for this registrar.
+  PrefService* prefs();
+  const PrefService* prefs() const;
+
+ private:
+  // PrefObserver:
+  void OnPreferenceChanged(PrefService* service,
+                           const std::string& pref_name) override;
+
+  static void InvokeUnnamedCallback(const base::Closure& callback,
+                                    const std::string& pref_name);
+
+  typedef std::map<std::string, NamedChangeCallback> ObserverMap;
+
+  ObserverMap observers_;
+  PrefService* service_;
+
+  DISALLOW_COPY_AND_ASSIGN(PrefChangeRegistrar);
+};
+
+#endif  // BASE_PREFS_PREF_CHANGE_REGISTRAR_H_
diff --git a/base/prefs/pref_change_registrar_unittest.cc b/base/prefs/pref_change_registrar_unittest.cc
new file mode 100644
index 0000000..da425cf
--- /dev/null
+++ b/base/prefs/pref_change_registrar_unittest.cc
@@ -0,0 +1,198 @@
+// Copyright (c) 2010 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/bind.h"
+#include "base/bind_helpers.h"
+#include "base/prefs/pref_change_registrar.h"
+#include "base/prefs/pref_observer.h"
+#include "base/prefs/pref_registry_simple.h"
+#include "base/prefs/testing_pref_service.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::Mock;
+using testing::Eq;
+
+namespace base {
+namespace {
+
+const char kHomePage[] = "homepage";
+const char kHomePageIsNewTabPage[] = "homepage_is_newtabpage";
+const char kApplicationLocale[] = "intl.app_locale";
+
+// A mock provider that allows us to capture pref observer changes.
+class MockPrefService : public TestingPrefServiceSimple {
+ public:
+  MockPrefService() {}
+  virtual ~MockPrefService() {}
+
+  MOCK_METHOD2(AddPrefObserver, void(const std::string&, PrefObserver*));
+  MOCK_METHOD2(RemovePrefObserver, void(const std::string&, PrefObserver*));
+};
+
+}  // namespace
+
+class PrefChangeRegistrarTest : public testing::Test {
+ public:
+  PrefChangeRegistrarTest() {}
+  ~PrefChangeRegistrarTest() override {}
+
+ protected:
+  void SetUp() override;
+
+  base::Closure observer() const {
+    return base::Bind(&base::DoNothing);
+  }
+
+  MockPrefService* service() const { return service_.get(); }
+
+ private:
+  scoped_ptr<MockPrefService> service_;
+};
+
+void PrefChangeRegistrarTest::SetUp() {
+  service_.reset(new MockPrefService());
+}
+
+TEST_F(PrefChangeRegistrarTest, AddAndRemove) {
+  PrefChangeRegistrar registrar;
+  registrar.Init(service());
+
+  // Test adding.
+  EXPECT_CALL(*service(),
+              AddPrefObserver(Eq(std::string("test.pref.1")), &registrar));
+  EXPECT_CALL(*service(),
+              AddPrefObserver(Eq(std::string("test.pref.2")), &registrar));
+  registrar.Add("test.pref.1", observer());
+  registrar.Add("test.pref.2", observer());
+  EXPECT_FALSE(registrar.IsEmpty());
+
+  // Test removing.
+  Mock::VerifyAndClearExpectations(service());
+  EXPECT_CALL(*service(),
+              RemovePrefObserver(Eq(std::string("test.pref.1")), &registrar));
+  EXPECT_CALL(*service(),
+              RemovePrefObserver(Eq(std::string("test.pref.2")), &registrar));
+  registrar.Remove("test.pref.1");
+  registrar.Remove("test.pref.2");
+  EXPECT_TRUE(registrar.IsEmpty());
+
+  // Explicitly check the expectations now to make sure that the Removes
+  // worked (rather than the registrar destructor doing the work).
+  Mock::VerifyAndClearExpectations(service());
+}
+
+TEST_F(PrefChangeRegistrarTest, AutoRemove) {
+  PrefChangeRegistrar registrar;
+  registrar.Init(service());
+
+  // Setup of auto-remove.
+  EXPECT_CALL(*service(),
+              AddPrefObserver(Eq(std::string("test.pref.1")), &registrar));
+  registrar.Add("test.pref.1", observer());
+  Mock::VerifyAndClearExpectations(service());
+  EXPECT_FALSE(registrar.IsEmpty());
+
+  // Test auto-removing.
+  EXPECT_CALL(*service(),
+              RemovePrefObserver(Eq(std::string("test.pref.1")), &registrar));
+}
+
+TEST_F(PrefChangeRegistrarTest, RemoveAll) {
+  PrefChangeRegistrar registrar;
+  registrar.Init(service());
+
+  EXPECT_CALL(*service(),
+              AddPrefObserver(Eq(std::string("test.pref.1")), &registrar));
+  EXPECT_CALL(*service(),
+              AddPrefObserver(Eq(std::string("test.pref.2")), &registrar));
+  registrar.Add("test.pref.1", observer());
+  registrar.Add("test.pref.2", observer());
+  Mock::VerifyAndClearExpectations(service());
+
+  EXPECT_CALL(*service(),
+              RemovePrefObserver(Eq(std::string("test.pref.1")), &registrar));
+  EXPECT_CALL(*service(),
+              RemovePrefObserver(Eq(std::string("test.pref.2")), &registrar));
+  registrar.RemoveAll();
+  EXPECT_TRUE(registrar.IsEmpty());
+
+  // Explicitly check the expectations now to make sure that the RemoveAll
+  // worked (rather than the registrar destructor doing the work).
+  Mock::VerifyAndClearExpectations(service());
+}
+
+class ObserveSetOfPreferencesTest : public testing::Test {
+ public:
+  virtual void SetUp() {
+    pref_service_.reset(new TestingPrefServiceSimple);
+    PrefRegistrySimple* registry = pref_service_->registry();
+    registry->RegisterStringPref(kHomePage, "http://google.com");
+    registry->RegisterBooleanPref(kHomePageIsNewTabPage, false);
+    registry->RegisterStringPref(kApplicationLocale, std::string());
+  }
+
+  PrefChangeRegistrar* CreatePrefChangeRegistrar() {
+    PrefChangeRegistrar* pref_set = new PrefChangeRegistrar();
+    base::Closure callback = base::Bind(&base::DoNothing);
+    pref_set->Init(pref_service_.get());
+    pref_set->Add(kHomePage, callback);
+    pref_set->Add(kHomePageIsNewTabPage, callback);
+    return pref_set;
+  }
+
+  MOCK_METHOD1(OnPreferenceChanged, void(const std::string&));
+
+  scoped_ptr<TestingPrefServiceSimple> pref_service_;
+};
+
+TEST_F(ObserveSetOfPreferencesTest, IsObserved) {
+  scoped_ptr<PrefChangeRegistrar> pref_set(CreatePrefChangeRegistrar());
+  EXPECT_TRUE(pref_set->IsObserved(kHomePage));
+  EXPECT_TRUE(pref_set->IsObserved(kHomePageIsNewTabPage));
+  EXPECT_FALSE(pref_set->IsObserved(kApplicationLocale));
+}
+
+TEST_F(ObserveSetOfPreferencesTest, IsManaged) {
+  scoped_ptr<PrefChangeRegistrar> pref_set(CreatePrefChangeRegistrar());
+  EXPECT_FALSE(pref_set->IsManaged());
+  pref_service_->SetManagedPref(kHomePage,
+                                new StringValue("http://crbug.com"));
+  EXPECT_TRUE(pref_set->IsManaged());
+  pref_service_->SetManagedPref(kHomePageIsNewTabPage,
+                                new FundamentalValue(true));
+  EXPECT_TRUE(pref_set->IsManaged());
+  pref_service_->RemoveManagedPref(kHomePage);
+  EXPECT_TRUE(pref_set->IsManaged());
+  pref_service_->RemoveManagedPref(kHomePageIsNewTabPage);
+  EXPECT_FALSE(pref_set->IsManaged());
+}
+
+TEST_F(ObserveSetOfPreferencesTest, Observe) {
+  using testing::_;
+  using testing::Mock;
+
+  PrefChangeRegistrar pref_set;
+  PrefChangeRegistrar::NamedChangeCallback callback = base::Bind(
+      &ObserveSetOfPreferencesTest::OnPreferenceChanged,
+      base::Unretained(this));
+  pref_set.Init(pref_service_.get());
+  pref_set.Add(kHomePage, callback);
+  pref_set.Add(kHomePageIsNewTabPage, callback);
+
+  EXPECT_CALL(*this, OnPreferenceChanged(kHomePage));
+  pref_service_->SetUserPref(kHomePage, new StringValue("http://crbug.com"));
+  Mock::VerifyAndClearExpectations(this);
+
+  EXPECT_CALL(*this, OnPreferenceChanged(kHomePageIsNewTabPage));
+  pref_service_->SetUserPref(kHomePageIsNewTabPage,
+                             new FundamentalValue(true));
+  Mock::VerifyAndClearExpectations(this);
+
+  EXPECT_CALL(*this, OnPreferenceChanged(_)).Times(0);
+  pref_service_->SetUserPref(kApplicationLocale, new StringValue("en_US.utf8"));
+  Mock::VerifyAndClearExpectations(this);
+}
+
+}  // namespace base
diff --git a/base/prefs/pref_filter.h b/base/prefs/pref_filter.h
new file mode 100644
index 0000000..82a44c6
--- /dev/null
+++ b/base/prefs/pref_filter.h
@@ -0,0 +1,55 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PREFS_PREF_FILTER_H_
+#define BASE_PREFS_PREF_FILTER_H_
+
+#include <string>
+
+#include "base/callback_forward.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/prefs/base_prefs_export.h"
+
+namespace base {
+class DictionaryValue;
+class Value;
+}  // namespace base
+
+// Filters preferences as they are loaded from disk or updated at runtime.
+// Currently supported only by JsonPrefStore.
+class BASE_PREFS_EXPORT PrefFilter {
+ public:
+  // A callback to be invoked when |prefs| have been read (and possibly
+  // pre-modified) and are now ready to be handed back to this callback's
+  // builder. |schedule_write| indicates whether a write should be immediately
+  // scheduled (typically because the |prefs| were pre-modified).
+  typedef base::Callback<void(scoped_ptr<base::DictionaryValue> prefs,
+                              bool schedule_write)> PostFilterOnLoadCallback;
+
+  virtual ~PrefFilter() {}
+
+  // This method is given ownership of the |pref_store_contents| read from disk
+  // before the underlying PersistentPrefStore gets to use them. It must hand
+  // them back via |post_filter_on_load_callback|, but may modify them first.
+  // Note: This method is asynchronous, which may make calls like
+  // PersistentPrefStore::ReadPrefs() asynchronous. The owner of filtered
+  // PersistentPrefStores should handle this to make the reads look synchronous
+  // to external users (see SegregatedPrefStore::ReadPrefs() for an example).
+  virtual void FilterOnLoad(
+      const PostFilterOnLoadCallback& post_filter_on_load_callback,
+      scoped_ptr<base::DictionaryValue> pref_store_contents) = 0;
+
+  // Receives notification when a pref store value is changed, before Observers
+  // are notified.
+  virtual void FilterUpdate(const std::string& path) = 0;
+
+  // Receives notification when the pref store is about to serialize data
+  // contained in |pref_store_contents| to a string. Modifications to
+  // |pref_store_contents| will be persisted to disk and also affect the
+  // in-memory state.
+  virtual void FilterSerializeData(
+      base::DictionaryValue* pref_store_contents) = 0;
+};
+
+#endif  // BASE_PREFS_PREF_FILTER_H_
diff --git a/base/prefs/pref_member.cc b/base/prefs/pref_member.cc
new file mode 100644
index 0000000..64c3d6a
--- /dev/null
+++ b/base/prefs/pref_member.cc
@@ -0,0 +1,221 @@
+// Copyright (c) 2012 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/prefs/pref_member.h"
+
+#include "base/callback.h"
+#include "base/callback_helpers.h"
+#include "base/location.h"
+#include "base/prefs/pref_service.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/value_conversions.h"
+
+using base::SingleThreadTaskRunner;
+
+namespace subtle {
+
+PrefMemberBase::PrefMemberBase()
+    : prefs_(NULL),
+      setting_value_(false) {
+}
+
+PrefMemberBase::~PrefMemberBase() {
+  Destroy();
+}
+
+void PrefMemberBase::Init(const std::string& pref_name,
+                          PrefService* prefs,
+                          const NamedChangeCallback& observer) {
+  observer_ = observer;
+  Init(pref_name, prefs);
+}
+
+void PrefMemberBase::Init(const std::string& pref_name, PrefService* prefs) {
+  DCHECK(prefs);
+  DCHECK(pref_name_.empty());  // Check that Init is only called once.
+  prefs_ = prefs;
+  pref_name_ = pref_name;
+  // Check that the preference is registered.
+  DCHECK(prefs_->FindPreference(pref_name_)) << pref_name << " not registered.";
+
+  // Add ourselves as a pref observer so we can keep our local value in sync.
+  prefs_->AddPrefObserver(pref_name, this);
+}
+
+void PrefMemberBase::Destroy() {
+  if (prefs_ && !pref_name_.empty()) {
+    prefs_->RemovePrefObserver(pref_name_, this);
+    prefs_ = NULL;
+  }
+}
+
+void PrefMemberBase::MoveToThread(
+    scoped_refptr<SingleThreadTaskRunner> task_runner) {
+  VerifyValuePrefName();
+  // Load the value from preferences if it hasn't been loaded so far.
+  if (!internal())
+    UpdateValueFromPref(base::Closure());
+  internal()->MoveToThread(task_runner.Pass());
+}
+
+void PrefMemberBase::OnPreferenceChanged(PrefService* service,
+                                         const std::string& pref_name) {
+  VerifyValuePrefName();
+  UpdateValueFromPref((!setting_value_ && !observer_.is_null()) ?
+      base::Bind(observer_, pref_name) : base::Closure());
+}
+
+void PrefMemberBase::UpdateValueFromPref(const base::Closure& callback) const {
+  VerifyValuePrefName();
+  const PrefService::Preference* pref = prefs_->FindPreference(pref_name_);
+  DCHECK(pref);
+  if (!internal())
+    CreateInternal();
+  internal()->UpdateValue(pref->GetValue()->DeepCopy(),
+                          pref->IsManaged(),
+                          pref->IsUserModifiable(),
+                          callback);
+}
+
+void PrefMemberBase::VerifyPref() const {
+  VerifyValuePrefName();
+  if (!internal())
+    UpdateValueFromPref(base::Closure());
+}
+
+void PrefMemberBase::InvokeUnnamedCallback(const base::Closure& callback,
+                                           const std::string& pref_name) {
+  callback.Run();
+}
+
+PrefMemberBase::Internal::Internal()
+    : thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
+      is_managed_(false),
+      is_user_modifiable_(false) {
+}
+PrefMemberBase::Internal::~Internal() { }
+
+bool PrefMemberBase::Internal::IsOnCorrectThread() const {
+  return thread_task_runner_->BelongsToCurrentThread();
+}
+
+void PrefMemberBase::Internal::UpdateValue(
+    base::Value* v,
+    bool is_managed,
+    bool is_user_modifiable,
+    const base::Closure& callback) const {
+  scoped_ptr<base::Value> value(v);
+  base::ScopedClosureRunner closure_runner(callback);
+  if (IsOnCorrectThread()) {
+    bool rv = UpdateValueInternal(*value);
+    DCHECK(rv);
+    is_managed_ = is_managed;
+    is_user_modifiable_ = is_user_modifiable;
+  } else {
+    bool may_run = thread_task_runner_->PostTask(
+        FROM_HERE, base::Bind(&PrefMemberBase::Internal::UpdateValue, this,
+                              value.release(), is_managed, is_user_modifiable,
+                              closure_runner.Release()));
+    DCHECK(may_run);
+  }
+}
+
+void PrefMemberBase::Internal::MoveToThread(
+    scoped_refptr<SingleThreadTaskRunner> task_runner) {
+  CheckOnCorrectThread();
+  thread_task_runner_ = task_runner.Pass();
+}
+
+bool PrefMemberVectorStringUpdate(const base::Value& value,
+                                  std::vector<std::string>* string_vector) {
+  if (!value.IsType(base::Value::TYPE_LIST))
+    return false;
+  const base::ListValue* list = static_cast<const base::ListValue*>(&value);
+
+  std::vector<std::string> local_vector;
+  for (base::ListValue::const_iterator it = list->begin();
+       it != list->end(); ++it) {
+    std::string string_value;
+    if (!(*it)->GetAsString(&string_value))
+      return false;
+
+    local_vector.push_back(string_value);
+  }
+
+  string_vector->swap(local_vector);
+  return true;
+}
+
+}  // namespace subtle
+
+template <>
+void PrefMember<bool>::UpdatePref(const bool& value) {
+  prefs()->SetBoolean(pref_name(), value);
+}
+
+template <>
+bool PrefMember<bool>::Internal::UpdateValueInternal(
+    const base::Value& value) const {
+  return value.GetAsBoolean(&value_);
+}
+
+template <>
+void PrefMember<int>::UpdatePref(const int& value) {
+  prefs()->SetInteger(pref_name(), value);
+}
+
+template <>
+bool PrefMember<int>::Internal::UpdateValueInternal(
+    const base::Value& value) const {
+  return value.GetAsInteger(&value_);
+}
+
+template <>
+void PrefMember<double>::UpdatePref(const double& value) {
+  prefs()->SetDouble(pref_name(), value);
+}
+
+template <>
+bool PrefMember<double>::Internal::UpdateValueInternal(const base::Value& value)
+    const {
+  return value.GetAsDouble(&value_);
+}
+
+template <>
+void PrefMember<std::string>::UpdatePref(const std::string& value) {
+  prefs()->SetString(pref_name(), value);
+}
+
+template <>
+bool PrefMember<std::string>::Internal::UpdateValueInternal(
+    const base::Value& value)
+    const {
+  return value.GetAsString(&value_);
+}
+
+template <>
+void PrefMember<base::FilePath>::UpdatePref(const base::FilePath& value) {
+  prefs()->SetFilePath(pref_name(), value);
+}
+
+template <>
+bool PrefMember<base::FilePath>::Internal::UpdateValueInternal(
+    const base::Value& value)
+    const {
+  return base::GetValueAsFilePath(value, &value_);
+}
+
+template <>
+void PrefMember<std::vector<std::string> >::UpdatePref(
+    const std::vector<std::string>& value) {
+  base::ListValue list_value;
+  list_value.AppendStrings(value);
+  prefs()->Set(pref_name(), list_value);
+}
+
+template <>
+bool PrefMember<std::vector<std::string> >::Internal::UpdateValueInternal(
+    const base::Value& value) const {
+  return subtle::PrefMemberVectorStringUpdate(value, &value_);
+}
diff --git a/base/prefs/pref_member.h b/base/prefs/pref_member.h
new file mode 100644
index 0000000..6dceb43
--- /dev/null
+++ b/base/prefs/pref_member.h
@@ -0,0 +1,355 @@
+// Copyright (c) 2012 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.
+//
+// A helper class that stays in sync with a preference (bool, int, real,
+// string or filepath).  For example:
+//
+// class MyClass {
+//  public:
+//   MyClass(PrefService* prefs) {
+//     my_string_.Init(prefs::kHomePage, prefs);
+//   }
+//  private:
+//   StringPrefMember my_string_;
+// };
+//
+// my_string_ should stay in sync with the prefs::kHomePage pref and will
+// update if either the pref changes or if my_string_.SetValue is called.
+//
+// An optional observer can be passed into the Init method which can be used to
+// notify MyClass of changes. Note that if you use SetValue(), the observer
+// will not be notified.
+
+#ifndef BASE_PREFS_PREF_MEMBER_H_
+#define BASE_PREFS_PREF_MEMBER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/callback_forward.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/prefs/base_prefs_export.h"
+#include "base/prefs/pref_observer.h"
+#include "base/single_thread_task_runner.h"
+#include "base/values.h"
+
+class PrefService;
+
+namespace subtle {
+
+class BASE_PREFS_EXPORT PrefMemberBase : public PrefObserver {
+ public:
+  // Type of callback you can register if you need to know the name of
+  // the pref that is changing.
+  typedef base::Callback<void(const std::string&)> NamedChangeCallback;
+
+  PrefService* prefs() { return prefs_; }
+  const PrefService* prefs() const { return prefs_; }
+
+ protected:
+  class BASE_PREFS_EXPORT Internal
+      : public base::RefCountedThreadSafe<Internal> {
+   public:
+    Internal();
+
+    // Update the value, either by calling |UpdateValueInternal| directly
+    // or by dispatching to the right thread.
+    // Takes ownership of |value|.
+    void UpdateValue(base::Value* value,
+                     bool is_managed,
+                     bool is_user_modifiable,
+                     const base::Closure& callback) const;
+
+    void MoveToThread(scoped_refptr<base::SingleThreadTaskRunner> task_runner);
+
+    // See PrefMember<> for description.
+    bool IsManaged() const {
+      return is_managed_;
+    }
+
+    bool IsUserModifiable() const {
+      return is_user_modifiable_;
+    }
+
+   protected:
+    friend class base::RefCountedThreadSafe<Internal>;
+    virtual ~Internal();
+
+    void CheckOnCorrectThread() const {
+      DCHECK(IsOnCorrectThread());
+    }
+
+   private:
+    // This method actually updates the value. It should only be called from
+    // the thread the PrefMember is on.
+    virtual bool UpdateValueInternal(const base::Value& value) const = 0;
+
+    bool IsOnCorrectThread() const;
+
+    scoped_refptr<base::SingleThreadTaskRunner> thread_task_runner_;
+    mutable bool is_managed_;
+    mutable bool is_user_modifiable_;
+
+    DISALLOW_COPY_AND_ASSIGN(Internal);
+  };
+
+  PrefMemberBase();
+  virtual ~PrefMemberBase();
+
+  // See PrefMember<> for description.
+  void Init(const std::string& pref_name,
+            PrefService* prefs,
+            const NamedChangeCallback& observer);
+  void Init(const std::string& pref_name, PrefService* prefs);
+
+  virtual void CreateInternal() const = 0;
+
+  // See PrefMember<> for description.
+  void Destroy();
+
+  void MoveToThread(scoped_refptr<base::SingleThreadTaskRunner> task_runner);
+
+  // PrefObserver
+  void OnPreferenceChanged(PrefService* service,
+                           const std::string& pref_name) override;
+
+  void VerifyValuePrefName() const {
+    DCHECK(!pref_name_.empty());
+  }
+
+  // This method is used to do the actual sync with the preference.
+  // Note: it is logically const, because it doesn't modify the state
+  // seen by the outside world. It is just doing a lazy load behind the scenes.
+  void UpdateValueFromPref(const base::Closure& callback) const;
+
+  // Verifies the preference name, and lazily loads the preference value if
+  // it hasn't been loaded yet.
+  void VerifyPref() const;
+
+  const std::string& pref_name() const { return pref_name_; }
+
+  virtual Internal* internal() const = 0;
+
+  // Used to allow registering plain base::Closure callbacks.
+  static void InvokeUnnamedCallback(const base::Closure& callback,
+                                    const std::string& pref_name);
+
+ private:
+  // Ordered the members to compact the class instance.
+  std::string pref_name_;
+  NamedChangeCallback observer_;
+  PrefService* prefs_;
+
+ protected:
+  bool setting_value_;
+};
+
+// This function implements StringListPrefMember::UpdateValue().
+// It is exposed here for testing purposes.
+bool BASE_PREFS_EXPORT PrefMemberVectorStringUpdate(
+    const base::Value& value,
+    std::vector<std::string>* string_vector);
+
+}  // namespace subtle
+
+template <typename ValueType>
+class PrefMember : public subtle::PrefMemberBase {
+ public:
+  // Defer initialization to an Init method so it's easy to make this class be
+  // a member variable.
+  PrefMember() {}
+  virtual ~PrefMember() {}
+
+  // Do the actual initialization of the class.  Use the two-parameter
+  // version if you don't want any notifications of changes.  This
+  // method should only be called on the UI thread.
+  void Init(const std::string& pref_name,
+            PrefService* prefs,
+            const NamedChangeCallback& observer) {
+    subtle::PrefMemberBase::Init(pref_name, prefs, observer);
+  }
+  void Init(const std::string& pref_name,
+            PrefService* prefs,
+            const base::Closure& observer) {
+    subtle::PrefMemberBase::Init(
+        pref_name, prefs,
+        base::Bind(&PrefMemberBase::InvokeUnnamedCallback, observer));
+  }
+  void Init(const std::string& pref_name, PrefService* prefs) {
+    subtle::PrefMemberBase::Init(pref_name, prefs);
+  }
+
+  // Unsubscribes the PrefMember from the PrefService. After calling this
+  // function, the PrefMember may not be used any more on the UI thread.
+  // Assuming |MoveToThread| was previously called, |GetValue|, |IsManaged|,
+  // and |IsUserModifiable| can still be called from the other thread but
+  // the results will no longer update from the PrefService.
+  // This method should only be called on the UI thread.
+  void Destroy() {
+    subtle::PrefMemberBase::Destroy();
+  }
+
+  // Moves the PrefMember to another thread, allowing read accesses from there.
+  // Changes from the PrefService will be propagated asynchronously
+  // via PostTask.
+  // This method should only be used from the thread the PrefMember is currently
+  // on, which is the UI thread by default.
+  void MoveToThread(scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
+    subtle::PrefMemberBase::MoveToThread(task_runner);
+  }
+
+  // Check whether the pref is managed, i.e. controlled externally through
+  // enterprise configuration management (e.g. windows group policy). Returns
+  // false for unknown prefs.
+  // This method should only be used from the thread the PrefMember is currently
+  // on, which is the UI thread unless changed by |MoveToThread|.
+  bool IsManaged() const {
+    VerifyPref();
+    return internal_->IsManaged();
+  }
+
+  // Checks whether the pref can be modified by the user. This returns false
+  // when the pref is managed by a policy or an extension, and when a command
+  // line flag overrides the pref.
+  // This method should only be used from the thread the PrefMember is currently
+  // on, which is the UI thread unless changed by |MoveToThread|.
+  bool IsUserModifiable() const {
+    VerifyPref();
+    return internal_->IsUserModifiable();
+  }
+
+  // Retrieve the value of the member variable.
+  // This method should only be used from the thread the PrefMember is currently
+  // on, which is the UI thread unless changed by |MoveToThread|.
+  ValueType GetValue() const {
+    VerifyPref();
+    return internal_->value();
+  }
+
+  // Provided as a convenience.
+  ValueType operator*() const {
+    return GetValue();
+  }
+
+  // Set the value of the member variable.
+  // This method should only be called on the UI thread.
+  void SetValue(const ValueType& value) {
+    VerifyValuePrefName();
+    setting_value_ = true;
+    UpdatePref(value);
+    setting_value_ = false;
+  }
+
+  // Returns the pref name.
+  const std::string& GetPrefName() const {
+    return pref_name();
+  }
+
+ private:
+  class Internal : public subtle::PrefMemberBase::Internal {
+   public:
+    Internal() : value_(ValueType()) {}
+
+    ValueType value() {
+      CheckOnCorrectThread();
+      return value_;
+    }
+
+   protected:
+    ~Internal() override {}
+
+    BASE_PREFS_EXPORT bool UpdateValueInternal(
+        const base::Value& value) const override;
+
+    // We cache the value of the pref so we don't have to keep walking the pref
+    // tree.
+    mutable ValueType value_;
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(Internal);
+  };
+
+  Internal* internal() const override { return internal_.get(); }
+  void CreateInternal() const override { internal_ = new Internal(); }
+
+  // This method is used to do the actual sync with pref of the specified type.
+  void BASE_PREFS_EXPORT UpdatePref(const ValueType& value);
+
+  mutable scoped_refptr<Internal> internal_;
+
+  DISALLOW_COPY_AND_ASSIGN(PrefMember);
+};
+
+// Declaration of template specialization need to be repeated here
+// specifically for each specialization (rather than just once above)
+// or at least one of our compilers won't be happy in all cases.
+// Specifically, it was failing on ChromeOS with a complaint about
+// PrefMember<FilePath>::UpdateValueInternal not being defined when
+// built in a chroot with the following parameters:
+//
+// FEATURES="noclean nostrip" USE="-chrome_debug -chrome_remoting
+// -chrome_internal -chrome_pdf component_build"
+// ~/trunk/goma/goma-wrapper cros_chrome_make --board=${BOARD}
+// --install --runhooks
+
+template <>
+BASE_PREFS_EXPORT void PrefMember<bool>::UpdatePref(const bool& value);
+
+template <>
+BASE_PREFS_EXPORT bool PrefMember<bool>::Internal::UpdateValueInternal(
+    const base::Value& value) const;
+
+template <>
+BASE_PREFS_EXPORT void PrefMember<int>::UpdatePref(const int& value);
+
+template <>
+BASE_PREFS_EXPORT bool PrefMember<int>::Internal::UpdateValueInternal(
+    const base::Value& value) const;
+
+template <>
+BASE_PREFS_EXPORT void PrefMember<double>::UpdatePref(const double& value);
+
+template <>
+BASE_PREFS_EXPORT bool PrefMember<double>::Internal::UpdateValueInternal(
+    const base::Value& value) const;
+
+template <>
+BASE_PREFS_EXPORT void PrefMember<std::string>::UpdatePref(
+    const std::string& value);
+
+template <>
+BASE_PREFS_EXPORT bool PrefMember<std::string>::Internal::UpdateValueInternal(
+    const base::Value& value) const;
+
+template <>
+BASE_PREFS_EXPORT void PrefMember<base::FilePath>::UpdatePref(
+    const base::FilePath& value);
+
+template <>
+BASE_PREFS_EXPORT bool
+PrefMember<base::FilePath>::Internal::UpdateValueInternal(
+    const base::Value& value) const;
+
+template <>
+BASE_PREFS_EXPORT void PrefMember<std::vector<std::string> >::UpdatePref(
+    const std::vector<std::string>& value);
+
+template <>
+BASE_PREFS_EXPORT bool
+PrefMember<std::vector<std::string> >::Internal::UpdateValueInternal(
+    const base::Value& value) const;
+
+typedef PrefMember<bool> BooleanPrefMember;
+typedef PrefMember<int> IntegerPrefMember;
+typedef PrefMember<double> DoublePrefMember;
+typedef PrefMember<std::string> StringPrefMember;
+typedef PrefMember<base::FilePath> FilePathPrefMember;
+// This preference member is expensive for large string arrays.
+typedef PrefMember<std::vector<std::string> > StringListPrefMember;
+
+#endif  // BASE_PREFS_PREF_MEMBER_H_
diff --git a/base/prefs/pref_member_unittest.cc b/base/prefs/pref_member_unittest.cc
new file mode 100644
index 0000000..a776e2c
--- /dev/null
+++ b/base/prefs/pref_member_unittest.cc
@@ -0,0 +1,325 @@
+// Copyright (c) 2011 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/prefs/pref_member.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/prefs/pref_registry_simple.h"
+#include "base/prefs/testing_pref_service.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const char kBoolPref[] = "bool";
+const char kIntPref[] = "int";
+const char kDoublePref[] = "double";
+const char kStringPref[] = "string";
+const char kStringListPref[] = "string_list";
+
+void RegisterTestPrefs(PrefRegistrySimple* registry) {
+  registry->RegisterBooleanPref(kBoolPref, false);
+  registry->RegisterIntegerPref(kIntPref, 0);
+  registry->RegisterDoublePref(kDoublePref, 0.0);
+  registry->RegisterStringPref(kStringPref, "default");
+  registry->RegisterListPref(kStringListPref, new base::ListValue());
+}
+
+class GetPrefValueHelper
+    : public base::RefCountedThreadSafe<GetPrefValueHelper> {
+ public:
+  GetPrefValueHelper() : value_(false), pref_thread_("pref thread") {
+    pref_thread_.Start();
+  }
+
+  void Init(const std::string& pref_name, PrefService* prefs) {
+    pref_.Init(pref_name, prefs);
+    pref_.MoveToThread(pref_thread_.task_runner());
+  }
+
+  void Destroy() {
+    pref_.Destroy();
+  }
+
+  void FetchValue() {
+    base::WaitableEvent event(true, false);
+    ASSERT_TRUE(pref_thread_.task_runner()->PostTask(
+        FROM_HERE,
+        base::Bind(&GetPrefValueHelper::GetPrefValue, this, &event)));
+    event.Wait();
+  }
+
+  // The thread must be stopped on the main thread. GetPrefValueHelper being
+  // ref-counted, the destructor can be called from any thread.
+  void StopThread() {
+    pref_thread_.Stop();
+  }
+
+  bool value() { return value_; }
+
+ private:
+  friend class base::RefCountedThreadSafe<GetPrefValueHelper>;
+  ~GetPrefValueHelper() {}
+
+  void GetPrefValue(base::WaitableEvent* event) {
+    value_ = pref_.GetValue();
+    event->Signal();
+  }
+
+  BooleanPrefMember pref_;
+  bool value_;
+
+  base::Thread pref_thread_;  // The thread |pref_| runs on.
+};
+
+class PrefMemberTestClass {
+ public:
+  explicit PrefMemberTestClass(PrefService* prefs)
+      : observe_cnt_(0), prefs_(prefs) {
+    str_.Init(kStringPref, prefs,
+              base::Bind(&PrefMemberTestClass::OnPreferenceChanged,
+                         base::Unretained(this)));
+  }
+
+  void OnPreferenceChanged(const std::string& pref_name) {
+    EXPECT_EQ(pref_name, kStringPref);
+    EXPECT_EQ(str_.GetValue(), prefs_->GetString(kStringPref));
+    ++observe_cnt_;
+  }
+
+  StringPrefMember str_;
+  int observe_cnt_;
+
+ private:
+  PrefService* prefs_;
+};
+
+}  // anonymous namespace
+
+class PrefMemberTest : public testing::Test {
+  base::MessageLoop message_loop_;
+};
+
+TEST_F(PrefMemberTest, BasicGetAndSet) {
+  TestingPrefServiceSimple prefs;
+  RegisterTestPrefs(prefs.registry());
+
+  // Test bool
+  BooleanPrefMember boolean;
+  boolean.Init(kBoolPref, &prefs);
+
+  // Check the defaults
+  EXPECT_FALSE(prefs.GetBoolean(kBoolPref));
+  EXPECT_FALSE(boolean.GetValue());
+  EXPECT_FALSE(*boolean);
+
+  // Try changing through the member variable.
+  boolean.SetValue(true);
+  EXPECT_TRUE(boolean.GetValue());
+  EXPECT_TRUE(prefs.GetBoolean(kBoolPref));
+  EXPECT_TRUE(*boolean);
+
+  // Try changing back through the pref.
+  prefs.SetBoolean(kBoolPref, false);
+  EXPECT_FALSE(prefs.GetBoolean(kBoolPref));
+  EXPECT_FALSE(boolean.GetValue());
+  EXPECT_FALSE(*boolean);
+
+  // Test int
+  IntegerPrefMember integer;
+  integer.Init(kIntPref, &prefs);
+
+  // Check the defaults
+  EXPECT_EQ(0, prefs.GetInteger(kIntPref));
+  EXPECT_EQ(0, integer.GetValue());
+  EXPECT_EQ(0, *integer);
+
+  // Try changing through the member variable.
+  integer.SetValue(5);
+  EXPECT_EQ(5, integer.GetValue());
+  EXPECT_EQ(5, prefs.GetInteger(kIntPref));
+  EXPECT_EQ(5, *integer);
+
+  // Try changing back through the pref.
+  prefs.SetInteger(kIntPref, 2);
+  EXPECT_EQ(2, prefs.GetInteger(kIntPref));
+  EXPECT_EQ(2, integer.GetValue());
+  EXPECT_EQ(2, *integer);
+
+  // Test double
+  DoublePrefMember double_member;
+  double_member.Init(kDoublePref, &prefs);
+
+  // Check the defaults
+  EXPECT_EQ(0.0, prefs.GetDouble(kDoublePref));
+  EXPECT_EQ(0.0, double_member.GetValue());
+  EXPECT_EQ(0.0, *double_member);
+
+  // Try changing through the member variable.
+  double_member.SetValue(1.0);
+  EXPECT_EQ(1.0, double_member.GetValue());
+  EXPECT_EQ(1.0, prefs.GetDouble(kDoublePref));
+  EXPECT_EQ(1.0, *double_member);
+
+  // Try changing back through the pref.
+  prefs.SetDouble(kDoublePref, 3.0);
+  EXPECT_EQ(3.0, prefs.GetDouble(kDoublePref));
+  EXPECT_EQ(3.0, double_member.GetValue());
+  EXPECT_EQ(3.0, *double_member);
+
+  // Test string
+  StringPrefMember string;
+  string.Init(kStringPref, &prefs);
+
+  // Check the defaults
+  EXPECT_EQ("default", prefs.GetString(kStringPref));
+  EXPECT_EQ("default", string.GetValue());
+  EXPECT_EQ("default", *string);
+
+  // Try changing through the member variable.
+  string.SetValue("foo");
+  EXPECT_EQ("foo", string.GetValue());
+  EXPECT_EQ("foo", prefs.GetString(kStringPref));
+  EXPECT_EQ("foo", *string);
+
+  // Try changing back through the pref.
+  prefs.SetString(kStringPref, "bar");
+  EXPECT_EQ("bar", prefs.GetString(kStringPref));
+  EXPECT_EQ("bar", string.GetValue());
+  EXPECT_EQ("bar", *string);
+
+  // Test string list
+  base::ListValue expected_list;
+  std::vector<std::string> expected_vector;
+  StringListPrefMember string_list;
+  string_list.Init(kStringListPref, &prefs);
+
+  // Check the defaults
+  EXPECT_TRUE(expected_list.Equals(prefs.GetList(kStringListPref)));
+  EXPECT_EQ(expected_vector, string_list.GetValue());
+  EXPECT_EQ(expected_vector, *string_list);
+
+  // Try changing through the pref member.
+  expected_list.AppendString("foo");
+  expected_vector.push_back("foo");
+  string_list.SetValue(expected_vector);
+
+  EXPECT_TRUE(expected_list.Equals(prefs.GetList(kStringListPref)));
+  EXPECT_EQ(expected_vector, string_list.GetValue());
+  EXPECT_EQ(expected_vector, *string_list);
+
+  // Try adding through the pref.
+  expected_list.AppendString("bar");
+  expected_vector.push_back("bar");
+  prefs.Set(kStringListPref, expected_list);
+
+  EXPECT_TRUE(expected_list.Equals(prefs.GetList(kStringListPref)));
+  EXPECT_EQ(expected_vector, string_list.GetValue());
+  EXPECT_EQ(expected_vector, *string_list);
+
+  // Try removing through the pref.
+  expected_list.Remove(0, NULL);
+  expected_vector.erase(expected_vector.begin());
+  prefs.Set(kStringListPref, expected_list);
+
+  EXPECT_TRUE(expected_list.Equals(prefs.GetList(kStringListPref)));
+  EXPECT_EQ(expected_vector, string_list.GetValue());
+  EXPECT_EQ(expected_vector, *string_list);
+}
+
+TEST_F(PrefMemberTest, InvalidList) {
+  // Set the vector to an initial good value.
+  std::vector<std::string> expected_vector;
+  expected_vector.push_back("foo");
+
+  // Try to add a valid list first.
+  base::ListValue list;
+  list.AppendString("foo");
+  std::vector<std::string> vector;
+  EXPECT_TRUE(subtle::PrefMemberVectorStringUpdate(list, &vector));
+  EXPECT_EQ(expected_vector, vector);
+
+  // Now try to add an invalid list.  |vector| should not be changed.
+  list.AppendInteger(0);
+  EXPECT_FALSE(subtle::PrefMemberVectorStringUpdate(list, &vector));
+  EXPECT_EQ(expected_vector, vector);
+}
+
+TEST_F(PrefMemberTest, TwoPrefs) {
+  // Make sure two DoublePrefMembers stay in sync.
+  TestingPrefServiceSimple prefs;
+  RegisterTestPrefs(prefs.registry());
+
+  DoublePrefMember pref1;
+  pref1.Init(kDoublePref, &prefs);
+  DoublePrefMember pref2;
+  pref2.Init(kDoublePref, &prefs);
+
+  pref1.SetValue(2.3);
+  EXPECT_EQ(2.3, *pref2);
+
+  pref2.SetValue(3.5);
+  EXPECT_EQ(3.5, *pref1);
+
+  prefs.SetDouble(kDoublePref, 4.2);
+  EXPECT_EQ(4.2, *pref1);
+  EXPECT_EQ(4.2, *pref2);
+}
+
+TEST_F(PrefMemberTest, Observer) {
+  TestingPrefServiceSimple prefs;
+  RegisterTestPrefs(prefs.registry());
+
+  PrefMemberTestClass test_obj(&prefs);
+  EXPECT_EQ("default", *test_obj.str_);
+
+  // Calling SetValue should not fire the observer.
+  test_obj.str_.SetValue("hello");
+  EXPECT_EQ(0, test_obj.observe_cnt_);
+  EXPECT_EQ("hello", prefs.GetString(kStringPref));
+
+  // Changing the pref does fire the observer.
+  prefs.SetString(kStringPref, "world");
+  EXPECT_EQ(1, test_obj.observe_cnt_);
+  EXPECT_EQ("world", *(test_obj.str_));
+
+  // Not changing the value should not fire the observer.
+  prefs.SetString(kStringPref, "world");
+  EXPECT_EQ(1, test_obj.observe_cnt_);
+  EXPECT_EQ("world", *(test_obj.str_));
+
+  prefs.SetString(kStringPref, "hello");
+  EXPECT_EQ(2, test_obj.observe_cnt_);
+  EXPECT_EQ("hello", prefs.GetString(kStringPref));
+}
+
+TEST_F(PrefMemberTest, NoInit) {
+  // Make sure not calling Init on a PrefMember doesn't cause problems.
+  IntegerPrefMember pref;
+}
+
+TEST_F(PrefMemberTest, MoveToThread) {
+  TestingPrefServiceSimple prefs;
+  scoped_refptr<GetPrefValueHelper> helper(new GetPrefValueHelper());
+  RegisterTestPrefs(prefs.registry());
+  helper->Init(kBoolPref, &prefs);
+
+  helper->FetchValue();
+  EXPECT_FALSE(helper->value());
+
+  prefs.SetBoolean(kBoolPref, true);
+
+  helper->FetchValue();
+  EXPECT_TRUE(helper->value());
+
+  helper->Destroy();
+
+  helper->FetchValue();
+  EXPECT_TRUE(helper->value());
+
+  helper->StopThread();
+}
diff --git a/base/prefs/pref_notifier.h b/base/prefs/pref_notifier.h
new file mode 100644
index 0000000..e0df260
--- /dev/null
+++ b/base/prefs/pref_notifier.h
@@ -0,0 +1,26 @@
+// Copyright (c) 2011 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_PREFS_PREF_NOTIFIER_H_
+#define BASE_PREFS_PREF_NOTIFIER_H_
+
+#include <string>
+
+// Delegate interface used by PrefValueStore to notify its owner about changes
+// to the preference values.
+// TODO(mnissler, danno): Move this declaration to pref_value_store.h once we've
+// cleaned up all public uses of this interface.
+class PrefNotifier {
+ public:
+  virtual ~PrefNotifier() {}
+
+  // Sends out a change notification for the preference identified by
+  // |pref_name|.
+  virtual void OnPreferenceChanged(const std::string& pref_name) = 0;
+
+  // Broadcasts the intialization completed notification.
+  virtual void OnInitializationCompleted(bool succeeded) = 0;
+};
+
+#endif  // BASE_PREFS_PREF_NOTIFIER_H_
diff --git a/base/prefs/pref_notifier_impl.cc b/base/prefs/pref_notifier_impl.cc
new file mode 100644
index 0000000..7ae5fe6
--- /dev/null
+++ b/base/prefs/pref_notifier_impl.cc
@@ -0,0 +1,117 @@
+// Copyright (c) 2012 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/prefs/pref_notifier_impl.h"
+
+#include "base/logging.h"
+#include "base/prefs/pref_service.h"
+#include "base/stl_util.h"
+
+PrefNotifierImpl::PrefNotifierImpl()
+    : pref_service_(NULL) {
+}
+
+PrefNotifierImpl::PrefNotifierImpl(PrefService* service)
+    : pref_service_(service) {
+}
+
+PrefNotifierImpl::~PrefNotifierImpl() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  // Verify that there are no pref observers when we shut down.
+  for (PrefObserverMap::iterator it = pref_observers_.begin();
+       it != pref_observers_.end(); ++it) {
+    PrefObserverList::Iterator obs_iterator(it->second);
+    if (obs_iterator.GetNext()) {
+      LOG(WARNING) << "pref observer found at shutdown " << it->first;
+    }
+  }
+
+  // Same for initialization observers.
+  if (!init_observers_.empty())
+    LOG(WARNING) << "Init observer found at shutdown.";
+
+  STLDeleteContainerPairSecondPointers(pref_observers_.begin(),
+                                       pref_observers_.end());
+  pref_observers_.clear();
+  init_observers_.clear();
+}
+
+void PrefNotifierImpl::AddPrefObserver(const std::string& path,
+                                       PrefObserver* obs) {
+  // Get the pref observer list associated with the path.
+  PrefObserverList* observer_list = NULL;
+  const PrefObserverMap::iterator observer_iterator =
+      pref_observers_.find(path);
+  if (observer_iterator == pref_observers_.end()) {
+    observer_list = new PrefObserverList;
+    pref_observers_[path] = observer_list;
+  } else {
+    observer_list = observer_iterator->second;
+  }
+
+  // Add the pref observer. ObserverList will DCHECK if it already is
+  // in the list.
+  observer_list->AddObserver(obs);
+}
+
+void PrefNotifierImpl::RemovePrefObserver(const std::string& path,
+                                          PrefObserver* obs) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  const PrefObserverMap::iterator observer_iterator =
+      pref_observers_.find(path);
+  if (observer_iterator == pref_observers_.end()) {
+    return;
+  }
+
+  PrefObserverList* observer_list = observer_iterator->second;
+  observer_list->RemoveObserver(obs);
+}
+
+void PrefNotifierImpl::AddInitObserver(base::Callback<void(bool)> obs) {
+  init_observers_.push_back(obs);
+}
+
+void PrefNotifierImpl::OnPreferenceChanged(const std::string& path) {
+  FireObservers(path);
+}
+
+void PrefNotifierImpl::OnInitializationCompleted(bool succeeded) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  // We must make a copy of init_observers_ and clear it before we run
+  // observers, or we can end up in this method re-entrantly before
+  // clearing the observers list.
+  PrefInitObserverList observers(init_observers_);
+  init_observers_.clear();
+
+  for (PrefInitObserverList::iterator it = observers.begin();
+       it != observers.end();
+       ++it) {
+    it->Run(succeeded);
+  }
+}
+
+void PrefNotifierImpl::FireObservers(const std::string& path) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  // Only send notifications for registered preferences.
+  if (!pref_service_->FindPreference(path))
+    return;
+
+  const PrefObserverMap::iterator observer_iterator =
+      pref_observers_.find(path);
+  if (observer_iterator == pref_observers_.end())
+    return;
+
+  FOR_EACH_OBSERVER(PrefObserver,
+                    *(observer_iterator->second),
+                    OnPreferenceChanged(pref_service_, path));
+}
+
+void PrefNotifierImpl::SetPrefService(PrefService* pref_service) {
+  DCHECK(pref_service_ == NULL);
+  pref_service_ = pref_service;
+}
diff --git a/base/prefs/pref_notifier_impl.h b/base/prefs/pref_notifier_impl.h
new file mode 100644
index 0000000..cbf025c
--- /dev/null
+++ b/base/prefs/pref_notifier_impl.h
@@ -0,0 +1,73 @@
+// Copyright (c) 2011 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_PREFS_PREF_NOTIFIER_IMPL_H_
+#define BASE_PREFS_PREF_NOTIFIER_IMPL_H_
+
+#include <list>
+#include <string>
+
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/containers/hash_tables.h"
+#include "base/observer_list.h"
+#include "base/prefs/base_prefs_export.h"
+#include "base/prefs/pref_notifier.h"
+#include "base/prefs/pref_observer.h"
+#include "base/threading/thread_checker.h"
+
+class PrefService;
+
+// The PrefNotifier implementation used by the PrefService.
+class BASE_PREFS_EXPORT PrefNotifierImpl
+    : public NON_EXPORTED_BASE(PrefNotifier) {
+ public:
+  PrefNotifierImpl();
+  explicit PrefNotifierImpl(PrefService* pref_service);
+  ~PrefNotifierImpl() override;
+
+  // If the pref at the given path changes, we call the observer's
+  // OnPreferenceChanged method.
+  void AddPrefObserver(const std::string& path, PrefObserver* observer);
+  void RemovePrefObserver(const std::string& path, PrefObserver* observer);
+
+  // We run the callback once, when initialization completes. The bool
+  // parameter will be set to true for successful initialization,
+  // false for unsuccessful.
+  void AddInitObserver(base::Callback<void(bool)> observer);
+
+  void SetPrefService(PrefService* pref_service);
+
+ protected:
+  // PrefNotifier overrides.
+  void OnPreferenceChanged(const std::string& pref_name) override;
+  void OnInitializationCompleted(bool succeeded) override;
+
+  // A map from pref names to a list of observers. Observers get fired in the
+  // order they are added. These should only be accessed externally for unit
+  // testing.
+  typedef base::ObserverList<PrefObserver> PrefObserverList;
+  typedef base::hash_map<std::string, PrefObserverList*> PrefObserverMap;
+
+  typedef std::list<base::Callback<void(bool)>> PrefInitObserverList;
+
+  const PrefObserverMap* pref_observers() const { return &pref_observers_; }
+
+ private:
+  // For the given pref_name, fire any observer of the pref. Virtual so it can
+  // be mocked for unit testing.
+  virtual void FireObservers(const std::string& path);
+
+  // Weak reference; the notifier is owned by the PrefService.
+  PrefService* pref_service_;
+
+  PrefObserverMap pref_observers_;
+  PrefInitObserverList init_observers_;
+
+  base::ThreadChecker thread_checker_;
+
+  DISALLOW_COPY_AND_ASSIGN(PrefNotifierImpl);
+};
+
+#endif  // BASE_PREFS_PREF_NOTIFIER_IMPL_H_
diff --git a/base/prefs/pref_notifier_impl_unittest.cc b/base/prefs/pref_notifier_impl_unittest.cc
new file mode 100644
index 0000000..c3cbf4f
--- /dev/null
+++ b/base/prefs/pref_notifier_impl_unittest.cc
@@ -0,0 +1,220 @@
+// Copyright (c) 2011 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/bind.h"
+#include "base/callback.h"
+#include "base/prefs/mock_pref_change_callback.h"
+#include "base/prefs/pref_notifier_impl.h"
+#include "base/prefs/pref_observer.h"
+#include "base/prefs/pref_registry_simple.h"
+#include "base/prefs/pref_service.h"
+#include "base/prefs/pref_value_store.h"
+#include "base/prefs/testing_pref_service.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::Field;
+using testing::Invoke;
+using testing::Mock;
+using testing::Truly;
+
+namespace {
+
+const char kChangedPref[] = "changed_pref";
+const char kUnchangedPref[] = "unchanged_pref";
+
+class MockPrefInitObserver {
+ public:
+  MOCK_METHOD1(OnInitializationCompleted, void(bool));
+};
+
+// This is an unmodified PrefNotifierImpl, except we make
+// OnPreferenceChanged public for tests.
+class TestingPrefNotifierImpl : public PrefNotifierImpl {
+ public:
+  explicit TestingPrefNotifierImpl(PrefService* service)
+      : PrefNotifierImpl(service) {
+  }
+
+  // Make public for tests.
+  using PrefNotifierImpl::OnPreferenceChanged;
+};
+
+// Mock PrefNotifier that allows tracking of observers and notifications.
+class MockPrefNotifier : public PrefNotifierImpl {
+ public:
+  explicit MockPrefNotifier(PrefService* pref_service)
+      : PrefNotifierImpl(pref_service) {}
+  virtual ~MockPrefNotifier() {}
+
+  MOCK_METHOD1(FireObservers, void(const std::string& path));
+
+  size_t CountObserver(const std::string& path, PrefObserver* obs) {
+    PrefObserverMap::const_iterator observer_iterator =
+        pref_observers()->find(path);
+    if (observer_iterator == pref_observers()->end())
+      return false;
+
+    PrefObserverList* observer_list = observer_iterator->second;
+    PrefObserverList::Iterator it(observer_list);
+    PrefObserver* existing_obs;
+    size_t count = 0;
+    while ((existing_obs = it.GetNext()) != NULL) {
+      if (existing_obs == obs)
+        count++;
+    }
+
+    return count;
+  }
+
+  // Make public for tests below.
+  using PrefNotifierImpl::OnPreferenceChanged;
+  using PrefNotifierImpl::OnInitializationCompleted;
+};
+
+class PrefObserverMock : public PrefObserver {
+ public:
+  PrefObserverMock() {}
+  virtual ~PrefObserverMock() {}
+
+  MOCK_METHOD2(OnPreferenceChanged, void(PrefService*, const std::string&));
+};
+
+// Test fixture class.
+class PrefNotifierTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    pref_service_.registry()->RegisterBooleanPref(kChangedPref, true);
+    pref_service_.registry()->RegisterBooleanPref(kUnchangedPref, true);
+  }
+
+  TestingPrefServiceSimple pref_service_;
+
+  PrefObserverMock obs1_;
+  PrefObserverMock obs2_;
+};
+
+TEST_F(PrefNotifierTest, OnPreferenceChanged) {
+  MockPrefNotifier notifier(&pref_service_);
+  EXPECT_CALL(notifier, FireObservers(kChangedPref)).Times(1);
+  notifier.OnPreferenceChanged(kChangedPref);
+}
+
+TEST_F(PrefNotifierTest, OnInitializationCompleted) {
+  MockPrefNotifier notifier(&pref_service_);
+  MockPrefInitObserver observer;
+  notifier.AddInitObserver(
+      base::Bind(&MockPrefInitObserver::OnInitializationCompleted,
+                 base::Unretained(&observer)));
+  EXPECT_CALL(observer, OnInitializationCompleted(true));
+  notifier.OnInitializationCompleted(true);
+}
+
+TEST_F(PrefNotifierTest, AddAndRemovePrefObservers) {
+  const char pref_name[] = "homepage";
+  const char pref_name2[] = "proxy";
+
+  MockPrefNotifier notifier(&pref_service_);
+  notifier.AddPrefObserver(pref_name, &obs1_);
+  ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs1_));
+  ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs1_));
+  ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_));
+  ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_));
+
+  // Re-adding the same observer for the same pref doesn't change anything.
+  // Skip this in debug mode, since it hits a DCHECK and death tests aren't
+  // thread-safe.
+#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
+  notifier.AddPrefObserver(pref_name, &obs1_);
+  ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs1_));
+  ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs1_));
+  ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_));
+  ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_));
+#endif
+
+  // Ensure that we can add the same observer to a different pref.
+  notifier.AddPrefObserver(pref_name2, &obs1_);
+  ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs1_));
+  ASSERT_EQ(1u, notifier.CountObserver(pref_name2, &obs1_));
+  ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_));
+  ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_));
+
+  // Ensure that we can add another observer to the same pref.
+  notifier.AddPrefObserver(pref_name, &obs2_);
+  ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs1_));
+  ASSERT_EQ(1u, notifier.CountObserver(pref_name2, &obs1_));
+  ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs2_));
+  ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_));
+
+  // Ensure that we can remove all observers, and that removing a non-existent
+  // observer is harmless.
+  notifier.RemovePrefObserver(pref_name, &obs1_);
+  ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs1_));
+  ASSERT_EQ(1u, notifier.CountObserver(pref_name2, &obs1_));
+  ASSERT_EQ(1u, notifier.CountObserver(pref_name, &obs2_));
+  ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_));
+
+  notifier.RemovePrefObserver(pref_name, &obs2_);
+  ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs1_));
+  ASSERT_EQ(1u, notifier.CountObserver(pref_name2, &obs1_));
+  ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_));
+  ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_));
+
+  notifier.RemovePrefObserver(pref_name, &obs1_);
+  ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs1_));
+  ASSERT_EQ(1u, notifier.CountObserver(pref_name2, &obs1_));
+  ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_));
+  ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_));
+
+  notifier.RemovePrefObserver(pref_name2, &obs1_);
+  ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs1_));
+  ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs1_));
+  ASSERT_EQ(0u, notifier.CountObserver(pref_name, &obs2_));
+  ASSERT_EQ(0u, notifier.CountObserver(pref_name2, &obs2_));
+}
+
+TEST_F(PrefNotifierTest, FireObservers) {
+  TestingPrefNotifierImpl notifier(&pref_service_);
+  notifier.AddPrefObserver(kChangedPref, &obs1_);
+  notifier.AddPrefObserver(kUnchangedPref, &obs1_);
+
+  EXPECT_CALL(obs1_, OnPreferenceChanged(&pref_service_, kChangedPref));
+  EXPECT_CALL(obs2_, OnPreferenceChanged(_, _)).Times(0);
+  notifier.OnPreferenceChanged(kChangedPref);
+  Mock::VerifyAndClearExpectations(&obs1_);
+  Mock::VerifyAndClearExpectations(&obs2_);
+
+  notifier.AddPrefObserver(kChangedPref, &obs2_);
+  notifier.AddPrefObserver(kUnchangedPref, &obs2_);
+
+  EXPECT_CALL(obs1_, OnPreferenceChanged(&pref_service_, kChangedPref));
+  EXPECT_CALL(obs2_, OnPreferenceChanged(&pref_service_, kChangedPref));
+  notifier.OnPreferenceChanged(kChangedPref);
+  Mock::VerifyAndClearExpectations(&obs1_);
+  Mock::VerifyAndClearExpectations(&obs2_);
+
+  // Make sure removing an observer from one pref doesn't affect anything else.
+  notifier.RemovePrefObserver(kChangedPref, &obs1_);
+
+  EXPECT_CALL(obs1_, OnPreferenceChanged(_, _)).Times(0);
+  EXPECT_CALL(obs2_, OnPreferenceChanged(&pref_service_, kChangedPref));
+  notifier.OnPreferenceChanged(kChangedPref);
+  Mock::VerifyAndClearExpectations(&obs1_);
+  Mock::VerifyAndClearExpectations(&obs2_);
+
+  // Make sure removing an observer entirely doesn't affect anything else.
+  notifier.RemovePrefObserver(kUnchangedPref, &obs1_);
+
+  EXPECT_CALL(obs1_, OnPreferenceChanged(_, _)).Times(0);
+  EXPECT_CALL(obs2_, OnPreferenceChanged(&pref_service_, kChangedPref));
+  notifier.OnPreferenceChanged(kChangedPref);
+  Mock::VerifyAndClearExpectations(&obs1_);
+  Mock::VerifyAndClearExpectations(&obs2_);
+
+  notifier.RemovePrefObserver(kChangedPref, &obs2_);
+  notifier.RemovePrefObserver(kUnchangedPref, &obs2_);
+}
+
+}  // namespace
diff --git a/base/prefs/pref_observer.h b/base/prefs/pref_observer.h
new file mode 100644
index 0000000..5d8f5b6
--- /dev/null
+++ b/base/prefs/pref_observer.h
@@ -0,0 +1,21 @@
+// Copyright (c) 2012 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_PREFS_PREF_OBSERVER_H_
+#define BASE_PREFS_PREF_OBSERVER_H_
+
+#include <string>
+
+class PrefService;
+
+// Used internally to the Prefs subsystem to pass preference change
+// notifications between PrefService, PrefNotifierImpl and
+// PrefChangeRegistrar.
+class PrefObserver {
+ public:
+  virtual void OnPreferenceChanged(PrefService* service,
+                                   const std::string& pref_name) = 0;
+};
+
+#endif  // BASE_PREFS_PREF_OBSERVER_H_
diff --git a/base/prefs/pref_registry.cc b/base/prefs/pref_registry.cc
new file mode 100644
index 0000000..74f4b52
--- /dev/null
+++ b/base/prefs/pref_registry.cc
@@ -0,0 +1,66 @@
+// Copyright (c) 2012 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/prefs/pref_registry.h"
+
+#include "base/logging.h"
+#include "base/prefs/default_pref_store.h"
+#include "base/prefs/pref_store.h"
+#include "base/stl_util.h"
+#include "base/values.h"
+
+PrefRegistry::PrefRegistry()
+    : defaults_(new DefaultPrefStore()) {
+}
+
+PrefRegistry::~PrefRegistry() {
+}
+
+uint32 PrefRegistry::GetRegistrationFlags(const std::string& pref_name) const {
+  const auto& it = registration_flags_.find(pref_name);
+  if (it == registration_flags_.end())
+    return NO_REGISTRATION_FLAGS;
+  return it->second;
+}
+
+scoped_refptr<PrefStore> PrefRegistry::defaults() {
+  return defaults_.get();
+}
+
+PrefRegistry::const_iterator PrefRegistry::begin() const {
+  return defaults_->begin();
+}
+
+PrefRegistry::const_iterator PrefRegistry::end() const {
+  return defaults_->end();
+}
+
+void PrefRegistry::SetDefaultPrefValue(const std::string& pref_name,
+                                       base::Value* value) {
+  DCHECK(value);
+  const base::Value* current_value = NULL;
+  DCHECK(defaults_->GetValue(pref_name, &current_value))
+      << "Setting default for unregistered pref: " << pref_name;
+  DCHECK(value->IsType(current_value->GetType()))
+      << "Wrong type for new default: " << pref_name;
+
+  defaults_->ReplaceDefaultValue(pref_name, make_scoped_ptr(value));
+}
+
+void PrefRegistry::RegisterPreference(const std::string& path,
+                                      base::Value* default_value,
+                                      uint32 flags) {
+  base::Value::Type orig_type = default_value->GetType();
+  DCHECK(orig_type != base::Value::TYPE_NULL &&
+         orig_type != base::Value::TYPE_BINARY) <<
+         "invalid preference type: " << orig_type;
+  DCHECK(!defaults_->GetValue(path, NULL)) <<
+      "Trying to register a previously registered pref: " << path;
+  DCHECK(!ContainsKey(registration_flags_, path)) <<
+      "Trying to register a previously registered pref: " << path;
+
+  defaults_->SetDefaultValue(path, make_scoped_ptr(default_value));
+  if (flags != NO_REGISTRATION_FLAGS)
+    registration_flags_[path] = flags;
+}
diff --git a/base/prefs/pref_registry.h b/base/prefs/pref_registry.h
new file mode 100644
index 0000000..caf2a1a
--- /dev/null
+++ b/base/prefs/pref_registry.h
@@ -0,0 +1,86 @@
+// Copyright (c) 2012 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_PREFS_PREF_REGISTRY_H_
+#define BASE_PREFS_PREF_REGISTRY_H_
+
+#include "base/containers/hash_tables.h"
+#include "base/memory/ref_counted.h"
+#include "base/prefs/base_prefs_export.h"
+#include "base/prefs/pref_value_map.h"
+
+namespace base {
+class Value;
+}
+
+class DefaultPrefStore;
+class PrefStore;
+
+// Preferences need to be registered with a type and default value
+// before they are used.
+//
+// The way you use a PrefRegistry is that you register all required
+// preferences on it (via one of its subclasses), then pass it as a
+// construction parameter to PrefService.
+//
+// Currently, registrations after constructing the PrefService will
+// also work, but this is being deprecated.
+class BASE_PREFS_EXPORT PrefRegistry : public base::RefCounted<PrefRegistry> {
+ public:
+  // Registration flags that can be specified which impact how the pref will
+  // behave or be stored. This will be passed in a bitmask when the pref is
+  // registered. Subclasses of PrefRegistry can specify their own flags. Care
+  // must be taken to ensure none of these overlap with the flags below.
+  enum PrefRegistrationFlags : uint32 {
+    // No flags are specified.
+    NO_REGISTRATION_FLAGS = 0,
+
+    // The first 8 bits are reserved for subclasses of PrefRegistry to use.
+
+    // This marks the pref as "lossy". There is no strict time guarantee on when
+    // a lossy pref will be persisted to permanent storage when it is modified.
+    LOSSY_PREF = 1 << 8,
+  };
+
+  typedef PrefValueMap::const_iterator const_iterator;
+  typedef base::hash_map<std::string, uint32> PrefRegistrationFlagsMap;
+
+  PrefRegistry();
+
+  // Retrieve the set of registration flags for the given preference. The return
+  // value is a bitmask of PrefRegistrationFlags.
+  uint32 GetRegistrationFlags(const std::string& pref_name) const;
+
+  // Gets the registered defaults.
+  scoped_refptr<PrefStore> defaults();
+
+  // Allows iteration over defaults.
+  const_iterator begin() const;
+  const_iterator end() const;
+
+  // Changes the default value for a preference. Takes ownership of |value|.
+  //
+  // |pref_name| must be a previously registered preference.
+  void SetDefaultPrefValue(const std::string& pref_name, base::Value* value);
+
+ protected:
+  friend class base::RefCounted<PrefRegistry>;
+  virtual ~PrefRegistry();
+
+  // Used by subclasses to register a default value and registration flags for
+  // a preference. |flags| is a bitmask of |PrefRegistrationFlags|.
+  void RegisterPreference(const std::string& path,
+                          base::Value* default_value,
+                          uint32 flags);
+
+  scoped_refptr<DefaultPrefStore> defaults_;
+
+  // A map of pref name to a bitmask of PrefRegistrationFlags.
+  PrefRegistrationFlagsMap registration_flags_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(PrefRegistry);
+};
+
+#endif  // BASE_PREFS_PREF_REGISTRY_H_
diff --git a/base/prefs/pref_registry_simple.cc b/base/prefs/pref_registry_simple.cc
new file mode 100644
index 0000000..93c2686
--- /dev/null
+++ b/base/prefs/pref_registry_simple.cc
@@ -0,0 +1,161 @@
+// Copyright (c) 2012 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/prefs/pref_registry_simple.h"
+
+#include "base/files/file_path.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/values.h"
+
+PrefRegistrySimple::PrefRegistrySimple() {
+}
+
+PrefRegistrySimple::~PrefRegistrySimple() {
+}
+
+void PrefRegistrySimple::RegisterBooleanPref(const std::string& path,
+                                             bool default_value) {
+  RegisterPrefAndNotify(path, new base::FundamentalValue(default_value),
+                        NO_REGISTRATION_FLAGS);
+}
+
+void PrefRegistrySimple::RegisterIntegerPref(const std::string& path,
+                                             int default_value) {
+  RegisterPrefAndNotify(path, new base::FundamentalValue(default_value),
+                        NO_REGISTRATION_FLAGS);
+}
+
+void PrefRegistrySimple::RegisterDoublePref(const std::string& path,
+                                            double default_value) {
+  RegisterPrefAndNotify(path, new base::FundamentalValue(default_value),
+                        NO_REGISTRATION_FLAGS);
+}
+
+void PrefRegistrySimple::RegisterStringPref(const std::string& path,
+                                            const std::string& default_value) {
+  RegisterPrefAndNotify(path, new base::StringValue(default_value),
+                        NO_REGISTRATION_FLAGS);
+}
+
+void PrefRegistrySimple::RegisterFilePathPref(
+    const std::string& path,
+    const base::FilePath& default_value) {
+  RegisterPrefAndNotify(path, new base::StringValue(default_value.value()),
+                        NO_REGISTRATION_FLAGS);
+}
+
+void PrefRegistrySimple::RegisterListPref(const std::string& path) {
+  RegisterPrefAndNotify(path, new base::ListValue(), NO_REGISTRATION_FLAGS);
+}
+
+void PrefRegistrySimple::RegisterListPref(const std::string& path,
+                                          base::ListValue* default_value) {
+  RegisterPrefAndNotify(path, default_value, NO_REGISTRATION_FLAGS);
+}
+
+void PrefRegistrySimple::RegisterDictionaryPref(const std::string& path) {
+  RegisterPrefAndNotify(path, new base::DictionaryValue(),
+                        NO_REGISTRATION_FLAGS);
+}
+
+void PrefRegistrySimple::RegisterDictionaryPref(
+    const std::string& path,
+    base::DictionaryValue* default_value) {
+  RegisterPrefAndNotify(path, default_value, NO_REGISTRATION_FLAGS);
+}
+
+void PrefRegistrySimple::RegisterInt64Pref(const std::string& path,
+                                           int64 default_value) {
+  RegisterPrefAndNotify(
+      path, new base::StringValue(base::Int64ToString(default_value)),
+      NO_REGISTRATION_FLAGS);
+}
+
+void PrefRegistrySimple::RegisterUint64Pref(const std::string& path,
+                                            uint64 default_value) {
+  RegisterPrefAndNotify(
+      path, new base::StringValue(base::Uint64ToString(default_value)),
+      NO_REGISTRATION_FLAGS);
+}
+
+void PrefRegistrySimple::RegisterBooleanPref(const std::string& path,
+                                             bool default_value,
+                                             uint32 flags) {
+  RegisterPrefAndNotify(path, new base::FundamentalValue(default_value), flags);
+}
+
+void PrefRegistrySimple::RegisterIntegerPref(const std::string& path,
+                                             int default_value,
+                                             uint32 flags) {
+  RegisterPrefAndNotify(path, new base::FundamentalValue(default_value), flags);
+}
+
+void PrefRegistrySimple::RegisterDoublePref(const std::string& path,
+                                            double default_value,
+                                            uint32 flags) {
+  RegisterPrefAndNotify(path, new base::FundamentalValue(default_value), flags);
+}
+
+void PrefRegistrySimple::RegisterStringPref(const std::string& path,
+                                            const std::string& default_value,
+                                            uint32 flags) {
+  RegisterPrefAndNotify(path, new base::StringValue(default_value), flags);
+}
+
+void PrefRegistrySimple::RegisterFilePathPref(
+    const std::string& path,
+    const base::FilePath& default_value,
+    uint32 flags) {
+  RegisterPrefAndNotify(path, new base::StringValue(default_value.value()),
+                        flags);
+}
+
+void PrefRegistrySimple::RegisterListPref(const std::string& path,
+                                          uint32 flags) {
+  RegisterPrefAndNotify(path, new base::ListValue(), flags);
+}
+
+void PrefRegistrySimple::RegisterListPref(const std::string& path,
+                                          base::ListValue* default_value,
+                                          uint32 flags) {
+  RegisterPrefAndNotify(path, default_value, flags);
+}
+
+void PrefRegistrySimple::RegisterDictionaryPref(const std::string& path,
+                                                uint32 flags) {
+  RegisterPrefAndNotify(path, new base::DictionaryValue(), flags);
+}
+
+void PrefRegistrySimple::RegisterDictionaryPref(
+    const std::string& path,
+    base::DictionaryValue* default_value,
+    uint32 flags) {
+  RegisterPrefAndNotify(path, default_value, flags);
+}
+
+void PrefRegistrySimple::RegisterInt64Pref(const std::string& path,
+                                           int64 default_value,
+                                           uint32 flags) {
+  RegisterPrefAndNotify(
+      path, new base::StringValue(base::Int64ToString(default_value)), flags);
+}
+
+void PrefRegistrySimple::RegisterUint64Pref(const std::string& path,
+                                            uint64 default_value,
+                                            uint32 flags) {
+  RegisterPrefAndNotify(
+      path, new base::StringValue(base::Uint64ToString(default_value)), flags);
+}
+
+void PrefRegistrySimple::OnPrefRegistered(const std::string& path,
+                                          base::Value* default_value,
+                                          uint32 flags) {
+}
+
+void PrefRegistrySimple::RegisterPrefAndNotify(const std::string& path,
+                                               base::Value* default_value,
+                                               uint32 flags) {
+  RegisterPreference(path, default_value, flags);
+  OnPrefRegistered(path, default_value, flags);
+}
diff --git a/base/prefs/pref_registry_simple.h b/base/prefs/pref_registry_simple.h
new file mode 100644
index 0000000..6b69e30
--- /dev/null
+++ b/base/prefs/pref_registry_simple.h
@@ -0,0 +1,84 @@
+// Copyright (c) 2012 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_PREFS_PREF_REGISTRY_SIMPLE_H_
+#define BASE_PREFS_PREF_REGISTRY_SIMPLE_H_
+
+#include <string>
+
+#include "base/prefs/base_prefs_export.h"
+#include "base/prefs/pref_registry.h"
+
+namespace base {
+class DictionaryValue;
+class FilePath;
+class ListValue;
+}
+
+// A simple implementation of PrefRegistry.
+class BASE_PREFS_EXPORT PrefRegistrySimple : public PrefRegistry {
+ public:
+  PrefRegistrySimple();
+
+  void RegisterBooleanPref(const std::string& path, bool default_value);
+  void RegisterIntegerPref(const std::string& path, int default_value);
+  void RegisterDoublePref(const std::string& path, double default_value);
+  void RegisterStringPref(const std::string& path,
+                          const std::string& default_value);
+  void RegisterFilePathPref(const std::string& path,
+                            const base::FilePath& default_value);
+  void RegisterListPref(const std::string& path);
+  void RegisterDictionaryPref(const std::string& path);
+  void RegisterListPref(const std::string& path,
+                        base::ListValue* default_value);
+  void RegisterDictionaryPref(const std::string& path,
+                              base::DictionaryValue* default_value);
+  void RegisterInt64Pref(const std::string& path, int64 default_value);
+  void RegisterUint64Pref(const std::string&, uint64 default_value);
+
+  // Versions of registration functions that accept PrefRegistrationFlags.
+  // |flags| is a bitmask of PrefRegistrationFlags.
+  void RegisterBooleanPref(const std::string&,
+                           bool default_value,
+                           uint32 flags);
+  void RegisterIntegerPref(const std::string&, int default_value, uint32 flags);
+  void RegisterDoublePref(const std::string&,
+                          double default_value,
+                          uint32 flags);
+  void RegisterStringPref(const std::string&,
+                          const std::string& default_value,
+                          uint32 flags);
+  void RegisterFilePathPref(const std::string&,
+                            const base::FilePath& default_value,
+                            uint32 flags);
+  void RegisterListPref(const std::string&, uint32 flags);
+  void RegisterDictionaryPref(const std::string&, uint32 flags);
+  void RegisterListPref(const std::string&,
+                        base::ListValue* default_value,
+                        uint32 flags);
+  void RegisterDictionaryPref(const std::string&,
+                              base::DictionaryValue* default_value,
+                              uint32 flags);
+  void RegisterInt64Pref(const std::string&, int64 default_value, uint32 flags);
+  void RegisterUint64Pref(const std::string&,
+                          uint64 default_value,
+                          uint32 flags);
+
+ protected:
+  ~PrefRegistrySimple() override;
+
+  // Allows subclasses to hook into pref registration.
+  virtual void OnPrefRegistered(const std::string&,
+                                base::Value* default_value,
+                                uint32 flags);
+
+ private:
+  void RegisterPrefAndNotify(const std::string&,
+                             base::Value* default_value,
+                             uint32 flags);
+
+  DISALLOW_COPY_AND_ASSIGN(PrefRegistrySimple);
+};
+
+#endif  // BASE_PREFS_PREF_REGISTRY_SIMPLE_H_
diff --git a/base/prefs/pref_service.cc b/base/prefs/pref_service.cc
new file mode 100644
index 0000000..a9749b2
--- /dev/null
+++ b/base/prefs/pref_service.cc
@@ -0,0 +1,614 @@
+// Copyright (c) 2012 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/prefs/pref_service.h"
+
+#include <algorithm>
+
+#include "base/bind.h"
+#include "base/files/file_path.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/metrics/histogram.h"
+#include "base/prefs/default_pref_store.h"
+#include "base/prefs/pref_notifier_impl.h"
+#include "base/prefs/pref_registry.h"
+#include "base/prefs/pref_value_store.h"
+#include "base/single_thread_task_runner.h"
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/value_conversions.h"
+#include "build/build_config.h"
+
+namespace {
+
+class ReadErrorHandler : public PersistentPrefStore::ReadErrorDelegate {
+ public:
+  ReadErrorHandler(base::Callback<void(PersistentPrefStore::PrefReadError)> cb)
+      : callback_(cb) {}
+
+  void OnError(PersistentPrefStore::PrefReadError error) override {
+    callback_.Run(error);
+  }
+
+ private:
+  base::Callback<void(PersistentPrefStore::PrefReadError)> callback_;
+};
+
+// Returns the WriteablePrefStore::PrefWriteFlags for the pref with the given
+// |path|.
+uint32 GetWriteFlags(const PrefService::Preference* pref) {
+  uint32 write_flags = WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS;
+
+  if (!pref)
+    return write_flags;
+
+  if (pref->registration_flags() & PrefRegistry::LOSSY_PREF)
+    write_flags |= WriteablePrefStore::LOSSY_PREF_WRITE_FLAG;
+  return write_flags;
+}
+
+}  // namespace
+
+PrefService::PrefService(
+    PrefNotifierImpl* pref_notifier,
+    PrefValueStore* pref_value_store,
+    PersistentPrefStore* user_prefs,
+    PrefRegistry* pref_registry,
+    base::Callback<void(PersistentPrefStore::PrefReadError)>
+        read_error_callback,
+    bool async)
+    : pref_notifier_(pref_notifier),
+      pref_value_store_(pref_value_store),
+      pref_registry_(pref_registry),
+      user_pref_store_(user_prefs),
+      read_error_callback_(read_error_callback) {
+  pref_notifier_->SetPrefService(this);
+
+  // TODO(battre): This is a check for crbug.com/435208 to make sure that
+  // access violations are caused by a use-after-free bug and not by an
+  // initialization bug.
+  CHECK(pref_registry_);
+  CHECK(pref_value_store_);
+
+  InitFromStorage(async);
+}
+
+PrefService::~PrefService() {
+  DCHECK(CalledOnValidThread());
+
+  // Reset pointers so accesses after destruction reliably crash.
+  pref_value_store_.reset();
+  pref_registry_ = NULL;
+  user_pref_store_ = NULL;
+  pref_notifier_.reset();
+}
+
+void PrefService::InitFromStorage(bool async) {
+  if (user_pref_store_->IsInitializationComplete()) {
+    read_error_callback_.Run(user_pref_store_->GetReadError());
+  } else if (!async) {
+    read_error_callback_.Run(user_pref_store_->ReadPrefs());
+  } else {
+    // Guarantee that initialization happens after this function returned.
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE,
+        base::Bind(&PersistentPrefStore::ReadPrefsAsync, user_pref_store_.get(),
+                   new ReadErrorHandler(read_error_callback_)));
+  }
+}
+
+void PrefService::CommitPendingWrite() {
+  DCHECK(CalledOnValidThread());
+  user_pref_store_->CommitPendingWrite();
+}
+
+void PrefService::SchedulePendingLossyWrites() {
+  DCHECK(CalledOnValidThread());
+  user_pref_store_->SchedulePendingLossyWrites();
+}
+
+bool PrefService::GetBoolean(const std::string& path) const {
+  DCHECK(CalledOnValidThread());
+
+  bool result = false;
+
+  const base::Value* value = GetPreferenceValue(path);
+  if (!value) {
+    NOTREACHED() << "Trying to read an unregistered pref: " << path;
+    return result;
+  }
+  bool rv = value->GetAsBoolean(&result);
+  DCHECK(rv);
+  return result;
+}
+
+int PrefService::GetInteger(const std::string& path) const {
+  DCHECK(CalledOnValidThread());
+
+  int result = 0;
+
+  const base::Value* value = GetPreferenceValue(path);
+  if (!value) {
+    NOTREACHED() << "Trying to read an unregistered pref: " << path;
+    return result;
+  }
+  bool rv = value->GetAsInteger(&result);
+  DCHECK(rv);
+  return result;
+}
+
+double PrefService::GetDouble(const std::string& path) const {
+  DCHECK(CalledOnValidThread());
+
+  double result = 0.0;
+
+  const base::Value* value = GetPreferenceValue(path);
+  if (!value) {
+    NOTREACHED() << "Trying to read an unregistered pref: " << path;
+    return result;
+  }
+  bool rv = value->GetAsDouble(&result);
+  DCHECK(rv);
+  return result;
+}
+
+std::string PrefService::GetString(const std::string& path) const {
+  DCHECK(CalledOnValidThread());
+
+  std::string result;
+
+  const base::Value* value = GetPreferenceValue(path);
+  if (!value) {
+    NOTREACHED() << "Trying to read an unregistered pref: " << path;
+    return result;
+  }
+  bool rv = value->GetAsString(&result);
+  DCHECK(rv);
+  return result;
+}
+
+base::FilePath PrefService::GetFilePath(const std::string& path) const {
+  DCHECK(CalledOnValidThread());
+
+  base::FilePath result;
+
+  const base::Value* value = GetPreferenceValue(path);
+  if (!value) {
+    NOTREACHED() << "Trying to read an unregistered pref: " << path;
+    return base::FilePath(result);
+  }
+  bool rv = base::GetValueAsFilePath(*value, &result);
+  DCHECK(rv);
+  return result;
+}
+
+bool PrefService::HasPrefPath(const std::string& path) const {
+  const Preference* pref = FindPreference(path);
+  return pref && !pref->IsDefaultValue();
+}
+
+scoped_ptr<base::DictionaryValue> PrefService::GetPreferenceValues() const {
+  DCHECK(CalledOnValidThread());
+  scoped_ptr<base::DictionaryValue> out(new base::DictionaryValue);
+  for (const auto& it : *pref_registry_) {
+    out->Set(it.first, GetPreferenceValue(it.first)->CreateDeepCopy());
+  }
+  return out.Pass();
+}
+
+scoped_ptr<base::DictionaryValue> PrefService::GetPreferenceValuesOmitDefaults()
+    const {
+  DCHECK(CalledOnValidThread());
+  scoped_ptr<base::DictionaryValue> out(new base::DictionaryValue);
+  for (const auto& it : *pref_registry_) {
+    const Preference* pref = FindPreference(it.first);
+    if (pref->IsDefaultValue())
+      continue;
+    out->Set(it.first, pref->GetValue()->CreateDeepCopy());
+  }
+  return out.Pass();
+}
+
+scoped_ptr<base::DictionaryValue>
+PrefService::GetPreferenceValuesWithoutPathExpansion() const {
+  DCHECK(CalledOnValidThread());
+  scoped_ptr<base::DictionaryValue> out(new base::DictionaryValue);
+  for (const auto& it : *pref_registry_) {
+    const base::Value* value = GetPreferenceValue(it.first);
+    DCHECK(value);
+    out->SetWithoutPathExpansion(it.first, value->CreateDeepCopy());
+  }
+  return out.Pass();
+}
+
+const PrefService::Preference* PrefService::FindPreference(
+    const std::string& pref_name) const {
+  DCHECK(CalledOnValidThread());
+  PreferenceMap::iterator it = prefs_map_.find(pref_name);
+  if (it != prefs_map_.end())
+    return &(it->second);
+  const base::Value* default_value = NULL;
+  if (!pref_registry_->defaults()->GetValue(pref_name, &default_value))
+    return NULL;
+  it = prefs_map_.insert(
+      std::make_pair(pref_name, Preference(
+          this, pref_name, default_value->GetType()))).first;
+  return &(it->second);
+}
+
+bool PrefService::ReadOnly() const {
+  return user_pref_store_->ReadOnly();
+}
+
+PrefService::PrefInitializationStatus PrefService::GetInitializationStatus()
+    const {
+  if (!user_pref_store_->IsInitializationComplete())
+    return INITIALIZATION_STATUS_WAITING;
+
+  switch (user_pref_store_->GetReadError()) {
+    case PersistentPrefStore::PREF_READ_ERROR_NONE:
+      return INITIALIZATION_STATUS_SUCCESS;
+    case PersistentPrefStore::PREF_READ_ERROR_NO_FILE:
+      return INITIALIZATION_STATUS_CREATED_NEW_PREF_STORE;
+    default:
+      return INITIALIZATION_STATUS_ERROR;
+  }
+}
+
+bool PrefService::IsManagedPreference(const std::string& pref_name) const {
+  const Preference* pref = FindPreference(pref_name);
+  return pref && pref->IsManaged();
+}
+
+bool PrefService::IsPreferenceManagedByCustodian(
+    const std::string& pref_name) const {
+  const Preference* pref = FindPreference(pref_name);
+  return pref && pref->IsManagedByCustodian();
+}
+
+bool PrefService::IsUserModifiablePreference(
+    const std::string& pref_name) const {
+  const Preference* pref = FindPreference(pref_name);
+  return pref && pref->IsUserModifiable();
+}
+
+const base::DictionaryValue* PrefService::GetDictionary(
+    const std::string& path) const {
+  DCHECK(CalledOnValidThread());
+
+  const base::Value* value = GetPreferenceValue(path);
+  if (!value) {
+    NOTREACHED() << "Trying to read an unregistered pref: " << path;
+    return NULL;
+  }
+  if (value->GetType() != base::Value::TYPE_DICTIONARY) {
+    NOTREACHED();
+    return NULL;
+  }
+  return static_cast<const base::DictionaryValue*>(value);
+}
+
+const base::Value* PrefService::GetUserPrefValue(
+    const std::string& path) const {
+  DCHECK(CalledOnValidThread());
+
+  const Preference* pref = FindPreference(path);
+  if (!pref) {
+    NOTREACHED() << "Trying to get an unregistered pref: " << path;
+    return NULL;
+  }
+
+  // Look for an existing preference in the user store. If it doesn't
+  // exist, return NULL.
+  base::Value* value = NULL;
+  if (!user_pref_store_->GetMutableValue(path, &value))
+    return NULL;
+
+  if (!value->IsType(pref->GetType())) {
+    NOTREACHED() << "Pref value type doesn't match registered type.";
+    return NULL;
+  }
+
+  return value;
+}
+
+void PrefService::SetDefaultPrefValue(const std::string& path,
+                                      base::Value* value) {
+  DCHECK(CalledOnValidThread());
+  pref_registry_->SetDefaultPrefValue(path, value);
+}
+
+const base::Value* PrefService::GetDefaultPrefValue(
+    const std::string& path) const {
+  DCHECK(CalledOnValidThread());
+  // Lookup the preference in the default store.
+  const base::Value* value = NULL;
+  if (!pref_registry_->defaults()->GetValue(path, &value)) {
+    NOTREACHED() << "Default value missing for pref: " << path;
+    return NULL;
+  }
+  return value;
+}
+
+const base::ListValue* PrefService::GetList(const std::string& path) const {
+  DCHECK(CalledOnValidThread());
+
+  const base::Value* value = GetPreferenceValue(path);
+  if (!value) {
+    NOTREACHED() << "Trying to read an unregistered pref: " << path;
+    return NULL;
+  }
+  if (value->GetType() != base::Value::TYPE_LIST) {
+    NOTREACHED();
+    return NULL;
+  }
+  return static_cast<const base::ListValue*>(value);
+}
+
+void PrefService::AddPrefObserver(const std::string& path, PrefObserver* obs) {
+  pref_notifier_->AddPrefObserver(path, obs);
+}
+
+void PrefService::RemovePrefObserver(const std::string& path,
+                                     PrefObserver* obs) {
+  pref_notifier_->RemovePrefObserver(path, obs);
+}
+
+void PrefService::AddPrefInitObserver(base::Callback<void(bool)> obs) {
+  pref_notifier_->AddInitObserver(obs);
+}
+
+PrefRegistry* PrefService::DeprecatedGetPrefRegistry() {
+  return pref_registry_.get();
+}
+
+void PrefService::ClearPref(const std::string& path) {
+  DCHECK(CalledOnValidThread());
+
+  const Preference* pref = FindPreference(path);
+  if (!pref) {
+    NOTREACHED() << "Trying to clear an unregistered pref: " << path;
+    return;
+  }
+  user_pref_store_->RemoveValue(path, GetWriteFlags(pref));
+}
+
+void PrefService::Set(const std::string& path, const base::Value& value) {
+  SetUserPrefValue(path, value.DeepCopy());
+}
+
+void PrefService::SetBoolean(const std::string& path, bool value) {
+  SetUserPrefValue(path, new base::FundamentalValue(value));
+}
+
+void PrefService::SetInteger(const std::string& path, int value) {
+  SetUserPrefValue(path, new base::FundamentalValue(value));
+}
+
+void PrefService::SetDouble(const std::string& path, double value) {
+  SetUserPrefValue(path, new base::FundamentalValue(value));
+}
+
+void PrefService::SetString(const std::string& path, const std::string& value) {
+  SetUserPrefValue(path, new base::StringValue(value));
+}
+
+void PrefService::SetFilePath(const std::string& path,
+                              const base::FilePath& value) {
+  SetUserPrefValue(path, base::CreateFilePathValue(value));
+}
+
+void PrefService::SetInt64(const std::string& path, int64 value) {
+  SetUserPrefValue(path, new base::StringValue(base::Int64ToString(value)));
+}
+
+int64 PrefService::GetInt64(const std::string& path) const {
+  DCHECK(CalledOnValidThread());
+
+  const base::Value* value = GetPreferenceValue(path);
+  if (!value) {
+    NOTREACHED() << "Trying to read an unregistered pref: " << path;
+    return 0;
+  }
+  std::string result("0");
+  bool rv = value->GetAsString(&result);
+  DCHECK(rv);
+
+  int64 val;
+  base::StringToInt64(result, &val);
+  return val;
+}
+
+void PrefService::SetUint64(const std::string& path, uint64 value) {
+  SetUserPrefValue(path, new base::StringValue(base::Uint64ToString(value)));
+}
+
+uint64 PrefService::GetUint64(const std::string& path) const {
+  DCHECK(CalledOnValidThread());
+
+  const base::Value* value = GetPreferenceValue(path);
+  if (!value) {
+    NOTREACHED() << "Trying to read an unregistered pref: " << path;
+    return 0;
+  }
+  std::string result("0");
+  bool rv = value->GetAsString(&result);
+  DCHECK(rv);
+
+  uint64 val;
+  base::StringToUint64(result, &val);
+  return val;
+}
+
+base::Value* PrefService::GetMutableUserPref(const std::string& path,
+                                             base::Value::Type type) {
+  CHECK(type == base::Value::TYPE_DICTIONARY || type == base::Value::TYPE_LIST);
+  DCHECK(CalledOnValidThread());
+
+  const Preference* pref = FindPreference(path);
+  if (!pref) {
+    NOTREACHED() << "Trying to get an unregistered pref: " << path;
+    return NULL;
+  }
+  if (pref->GetType() != type) {
+    NOTREACHED() << "Wrong type for GetMutableValue: " << path;
+    return NULL;
+  }
+
+  // Look for an existing preference in the user store. If it doesn't
+  // exist or isn't the correct type, create a new user preference.
+  base::Value* value = NULL;
+  if (!user_pref_store_->GetMutableValue(path, &value) ||
+      !value->IsType(type)) {
+    if (type == base::Value::TYPE_DICTIONARY) {
+      value = new base::DictionaryValue;
+    } else if (type == base::Value::TYPE_LIST) {
+      value = new base::ListValue;
+    } else {
+      NOTREACHED();
+    }
+    user_pref_store_->SetValueSilently(path, value, GetWriteFlags(pref));
+  }
+  return value;
+}
+
+void PrefService::ReportUserPrefChanged(const std::string& key) {
+  DCHECK(CalledOnValidThread());
+  user_pref_store_->ReportValueChanged(key, GetWriteFlags(FindPreference(key)));
+}
+
+void PrefService::SetUserPrefValue(const std::string& path,
+                                   base::Value* new_value) {
+  scoped_ptr<base::Value> owned_value(new_value);
+  DCHECK(CalledOnValidThread());
+
+  const Preference* pref = FindPreference(path);
+  if (!pref) {
+    NOTREACHED() << "Trying to write an unregistered pref: " << path;
+    return;
+  }
+  if (pref->GetType() != new_value->GetType()) {
+    NOTREACHED() << "Trying to set pref " << path
+                 << " of type " << pref->GetType()
+                 << " to value of type " << new_value->GetType();
+    return;
+  }
+
+  user_pref_store_->SetValue(path, owned_value.release(), GetWriteFlags(pref));
+}
+
+void PrefService::UpdateCommandLinePrefStore(PrefStore* command_line_store) {
+  pref_value_store_->UpdateCommandLinePrefStore(command_line_store);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// PrefService::Preference
+
+PrefService::Preference::Preference(const PrefService* service,
+                                    const std::string& name,
+                                    base::Value::Type type)
+    : name_(name), type_(type), pref_service_(service) {
+  DCHECK(service);
+  // Cache the registration flags at creation time to avoid multiple map lookups
+  // later.
+  registration_flags_ = service->pref_registry_->GetRegistrationFlags(name_);
+}
+
+const std::string PrefService::Preference::name() const {
+  return name_;
+}
+
+base::Value::Type PrefService::Preference::GetType() const {
+  return type_;
+}
+
+const base::Value* PrefService::Preference::GetValue() const {
+  const base::Value* result= pref_service_->GetPreferenceValue(name_);
+  DCHECK(result) << "Must register pref before getting its value";
+  return result;
+}
+
+const base::Value* PrefService::Preference::GetRecommendedValue() const {
+  DCHECK(pref_service_->FindPreference(name_))
+      << "Must register pref before getting its value";
+
+  const base::Value* found_value = NULL;
+  if (pref_value_store()->GetRecommendedValue(name_, type_, &found_value)) {
+    DCHECK(found_value->IsType(type_));
+    return found_value;
+  }
+
+  // The pref has no recommended value.
+  return NULL;
+}
+
+bool PrefService::Preference::IsManaged() const {
+  return pref_value_store()->PrefValueInManagedStore(name_);
+}
+
+bool PrefService::Preference::IsManagedByCustodian() const {
+  return pref_value_store()->PrefValueInSupervisedStore(name_.c_str());
+}
+
+bool PrefService::Preference::IsRecommended() const {
+  return pref_value_store()->PrefValueFromRecommendedStore(name_);
+}
+
+bool PrefService::Preference::HasExtensionSetting() const {
+  return pref_value_store()->PrefValueInExtensionStore(name_);
+}
+
+bool PrefService::Preference::HasUserSetting() const {
+  return pref_value_store()->PrefValueInUserStore(name_);
+}
+
+bool PrefService::Preference::IsExtensionControlled() const {
+  return pref_value_store()->PrefValueFromExtensionStore(name_);
+}
+
+bool PrefService::Preference::IsUserControlled() const {
+  return pref_value_store()->PrefValueFromUserStore(name_);
+}
+
+bool PrefService::Preference::IsDefaultValue() const {
+  return pref_value_store()->PrefValueFromDefaultStore(name_);
+}
+
+bool PrefService::Preference::IsUserModifiable() const {
+  return pref_value_store()->PrefValueUserModifiable(name_);
+}
+
+bool PrefService::Preference::IsExtensionModifiable() const {
+  return pref_value_store()->PrefValueExtensionModifiable(name_);
+}
+
+const base::Value* PrefService::GetPreferenceValue(
+    const std::string& path) const {
+  DCHECK(CalledOnValidThread());
+
+  // TODO(battre): This is a check for crbug.com/435208. After analyzing some
+  // crash dumps it looks like the PrefService is accessed even though it has
+  // been cleared already.
+  CHECK(pref_registry_);
+  CHECK(pref_registry_->defaults());
+  CHECK(pref_value_store_);
+
+  const base::Value* default_value = NULL;
+  if (pref_registry_->defaults()->GetValue(path, &default_value)) {
+    const base::Value* found_value = NULL;
+    base::Value::Type default_type = default_value->GetType();
+    if (pref_value_store_->GetValue(path, default_type, &found_value)) {
+      DCHECK(found_value->IsType(default_type));
+      return found_value;
+    } else {
+      // Every registered preference has at least a default value.
+      NOTREACHED() << "no valid value found for registered pref " << path;
+    }
+  }
+
+  return NULL;
+}
diff --git a/base/prefs/pref_service.h b/base/prefs/pref_service.h
new file mode 100644
index 0000000..25c2f8b
--- /dev/null
+++ b/base/prefs/pref_service.h
@@ -0,0 +1,382 @@
+// Copyright (c) 2012 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 provides a way to access the application's current preferences.
+
+// Chromium settings and storage represent user-selected preferences and
+// information and MUST not be extracted, overwritten or modified except
+// through Chromium defined APIs.
+
+#ifndef BASE_PREFS_PREF_SERVICE_H_
+#define BASE_PREFS_PREF_SERVICE_H_
+
+#include <set>
+#include <string>
+
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/containers/hash_tables.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/observer_list.h"
+#include "base/prefs/base_prefs_export.h"
+#include "base/prefs/persistent_pref_store.h"
+#include "base/threading/non_thread_safe.h"
+#include "base/values.h"
+
+class PrefNotifier;
+class PrefNotifierImpl;
+class PrefObserver;
+class PrefRegistry;
+class PrefValueStore;
+class PrefStore;
+
+namespace base {
+class FilePath;
+}
+
+namespace subtle {
+class PrefMemberBase;
+class ScopedUserPrefUpdateBase;
+}
+
+// Base class for PrefServices. You can use the base class to read and
+// interact with preferences, but not to register new preferences; for
+// that see e.g. PrefRegistrySimple.
+//
+// Settings and storage accessed through this class represent
+// user-selected preferences and information and MUST not be
+// extracted, overwritten or modified except through the defined APIs.
+class BASE_PREFS_EXPORT PrefService : public base::NonThreadSafe {
+ public:
+  enum PrefInitializationStatus {
+    INITIALIZATION_STATUS_WAITING,
+    INITIALIZATION_STATUS_SUCCESS,
+    INITIALIZATION_STATUS_CREATED_NEW_PREF_STORE,
+    INITIALIZATION_STATUS_ERROR
+  };
+
+  // A helper class to store all the information associated with a preference.
+  class BASE_PREFS_EXPORT Preference {
+   public:
+    // The type of the preference is determined by the type with which it is
+    // registered. This type needs to be a boolean, integer, double, string,
+    // dictionary (a branch), or list.  You shouldn't need to construct this on
+    // your own; use the PrefService::Register*Pref methods instead.
+    Preference(const PrefService* service,
+               const std::string& name,
+               base::Value::Type type);
+    ~Preference() {}
+
+    // Returns the name of the Preference (i.e., the key, e.g.,
+    // browser.window_placement).
+    const std::string name() const;
+
+    // Returns the registered type of the preference.
+    base::Value::Type GetType() const;
+
+    // Returns the value of the Preference, falling back to the registered
+    // default value if no other has been set.
+    const base::Value* GetValue() const;
+
+    // Returns the value recommended by the admin, if any.
+    const base::Value* GetRecommendedValue() const;
+
+    // Returns true if the Preference is managed, i.e. set by an admin policy.
+    // Since managed prefs have the highest priority, this also indicates
+    // whether the pref is actually being controlled by the policy setting.
+    bool IsManaged() const;
+
+    // Returns true if the Preference is controlled by the custodian of the
+    // supervised user. Since a supervised user is not expected to have an admin
+    // policy, this is the controlling pref if set.
+    bool IsManagedByCustodian() const;
+
+    // Returns true if the Preference is recommended, i.e. set by an admin
+    // policy but the user is allowed to change it.
+    bool IsRecommended() const;
+
+    // Returns true if the Preference has a value set by an extension, even if
+    // that value is being overridden by a higher-priority source.
+    bool HasExtensionSetting() const;
+
+    // Returns true if the Preference has a user setting, even if that value is
+    // being overridden by a higher-priority source.
+    bool HasUserSetting() const;
+
+    // Returns true if the Preference value is currently being controlled by an
+    // extension, and not by any higher-priority source.
+    bool IsExtensionControlled() const;
+
+    // Returns true if the Preference value is currently being controlled by a
+    // user setting, and not by any higher-priority source.
+    bool IsUserControlled() const;
+
+    // Returns true if the Preference is currently using its default value,
+    // and has not been set by any higher-priority source (even with the same
+    // value).
+    bool IsDefaultValue() const;
+
+    // Returns true if the user can change the Preference value, which is the
+    // case if no higher-priority source than the user store controls the
+    // Preference.
+    bool IsUserModifiable() const;
+
+    // Returns true if an extension can change the Preference value, which is
+    // the case if no higher-priority source than the extension store controls
+    // the Preference.
+    bool IsExtensionModifiable() const;
+
+    // Return the registration flags for this pref as a bitmask of
+    // PrefRegistry::PrefRegistrationFlags.
+    uint32 registration_flags() const { return registration_flags_; }
+
+   private:
+    friend class PrefService;
+
+    PrefValueStore* pref_value_store() const {
+      return pref_service_->pref_value_store_.get();
+    }
+
+    const std::string name_;
+
+    const base::Value::Type type_;
+
+    uint32 registration_flags_;
+
+    // Reference to the PrefService in which this pref was created.
+    const PrefService* pref_service_;
+  };
+
+  // You may wish to use PrefServiceFactory or one of its subclasses
+  // for simplified construction.
+  PrefService(
+      PrefNotifierImpl* pref_notifier,
+      PrefValueStore* pref_value_store,
+      PersistentPrefStore* user_prefs,
+      PrefRegistry* pref_registry,
+      base::Callback<void(PersistentPrefStore::PrefReadError)>
+          read_error_callback,
+      bool async);
+  virtual ~PrefService();
+
+  // Lands pending writes to disk. This should only be used if we need to save
+  // immediately (basically, during shutdown).
+  void CommitPendingWrite();
+
+  // Schedule a write if there is any lossy data pending. Unlike
+  // CommitPendingWrite() this does not immediately sync to disk, instead it
+  // triggers an eventual write if there is lossy data pending and if there
+  // isn't one scheduled already.
+  void SchedulePendingLossyWrites();
+
+  // Returns true if the preference for the given preference name is available
+  // and is managed.
+  bool IsManagedPreference(const std::string& pref_name) const;
+
+  // Returns true if the preference for the given preference name is available
+  // and is controlled by the parent/guardian of the child Account.
+  bool IsPreferenceManagedByCustodian(const std::string& pref_name) const;
+
+  // Returns |true| if a preference with the given name is available and its
+  // value can be changed by the user.
+  bool IsUserModifiablePreference(const std::string& pref_name) const;
+
+  // Look up a preference.  Returns NULL if the preference is not
+  // registered.
+  const PrefService::Preference* FindPreference(const std::string& path) const;
+
+  // If the path is valid and the value at the end of the path matches the type
+  // specified, it will return the specified value.  Otherwise, the default
+  // value (set when the pref was registered) will be returned.
+  bool GetBoolean(const std::string& path) const;
+  int GetInteger(const std::string& path) const;
+  double GetDouble(const std::string& path) const;
+  std::string GetString(const std::string& path) const;
+  base::FilePath GetFilePath(const std::string& path) const;
+
+  // Returns the branch if it exists, or the registered default value otherwise.
+  // Note that |path| must point to a registered preference. In that case, these
+  // functions will never return NULL.
+  const base::DictionaryValue* GetDictionary(const std::string& path) const;
+  const base::ListValue* GetList(const std::string& path) const;
+
+  // Removes a user pref and restores the pref to its default value.
+  void ClearPref(const std::string& path);
+
+  // If the path is valid (i.e., registered), update the pref value in the user
+  // prefs.
+  // To set the value of dictionary or list values in the pref tree use
+  // Set(), but to modify the value of a dictionary or list use either
+  // ListPrefUpdate or DictionaryPrefUpdate from scoped_user_pref_update.h.
+  void Set(const std::string& path, const base::Value& value);
+  void SetBoolean(const std::string& path, bool value);
+  void SetInteger(const std::string& path, int value);
+  void SetDouble(const std::string& path, double value);
+  void SetString(const std::string& path, const std::string& value);
+  void SetFilePath(const std::string& path, const base::FilePath& value);
+
+  // Int64 helper methods that actually store the given value as a string.
+  // Note that if obtaining the named value via GetDictionary or GetList, the
+  // Value type will be TYPE_STRING.
+  void SetInt64(const std::string& path, int64 value);
+  int64 GetInt64(const std::string& path) const;
+
+  // As above, but for unsigned values.
+  void SetUint64(const std::string& path, uint64 value);
+  uint64 GetUint64(const std::string& path) const;
+
+  // Returns the value of the given preference, from the user pref store. If
+  // the preference is not set in the user pref store, returns NULL.
+  const base::Value* GetUserPrefValue(const std::string& path) const;
+
+  // Changes the default value for a preference. Takes ownership of |value|.
+  //
+  // Will cause a pref change notification to be fired if this causes
+  // the effective value to change.
+  void SetDefaultPrefValue(const std::string& path, base::Value* value);
+
+  // Returns the default value of the given preference. |path| must point to a
+  // registered preference. In that case, will never return NULL.
+  const base::Value* GetDefaultPrefValue(const std::string& path) const;
+
+  // Returns true if a value has been set for the specified path.
+  // NOTE: this is NOT the same as FindPreference. In particular
+  // FindPreference returns whether RegisterXXX has been invoked, where as
+  // this checks if a value exists for the path.
+  bool HasPrefPath(const std::string& path) const;
+
+  // Returns a dictionary with effective preference values.
+  scoped_ptr<base::DictionaryValue> GetPreferenceValues() const;
+
+  // Returns a dictionary with effective preference values, omitting prefs that
+  // are at their default values.
+  scoped_ptr<base::DictionaryValue> GetPreferenceValuesOmitDefaults() const;
+
+  // Returns a dictionary with effective preference values. Contrary to
+  // GetPreferenceValues(), the paths of registered preferences are not split on
+  // '.' characters. If a registered preference stores a dictionary, however,
+  // the hierarchical structure inside the preference will be preserved.
+  // For example, if "foo.bar" is a registered preference, the result could look
+  // like this:
+  //   {"foo.bar": {"a": {"b": true}}}.
+  scoped_ptr<base::DictionaryValue> GetPreferenceValuesWithoutPathExpansion()
+      const;
+
+  bool ReadOnly() const;
+
+  PrefInitializationStatus GetInitializationStatus() const;
+
+  // Tell our PrefValueStore to update itself to |command_line_store|.
+  // Takes ownership of the store.
+  virtual void UpdateCommandLinePrefStore(PrefStore* command_line_store);
+
+  // We run the callback once, when initialization completes. The bool
+  // parameter will be set to true for successful initialization,
+  // false for unsuccessful.
+  void AddPrefInitObserver(base::Callback<void(bool)> callback);
+
+  // Returns the PrefRegistry object for this service. You should not
+  // use this; the intent is for no registrations to take place after
+  // PrefService has been constructed.
+  //
+  // Instead of using this method, the recommended approach is to
+  // register all preferences for a class Xyz up front in a static
+  // Xyz::RegisterPrefs function, which gets invoked early in the
+  // application's start-up, before a PrefService is created.
+  //
+  // As an example, prefs registration in Chrome is triggered by the
+  // functions chrome::RegisterPrefs (for global preferences) and
+  // chrome::RegisterProfilePrefs (for user-specific preferences)
+  // implemented in chrome/browser/prefs/browser_prefs.cc.
+  PrefRegistry* DeprecatedGetPrefRegistry();
+
+ protected:
+  // The PrefNotifier handles registering and notifying preference observers.
+  // It is created and owned by this PrefService. Subclasses may access it for
+  // unit testing.
+  scoped_ptr<PrefNotifierImpl> pref_notifier_;
+
+  // The PrefValueStore provides prioritized preference values. It is owned by
+  // this PrefService. Subclasses may access it for unit testing.
+  scoped_ptr<PrefValueStore> pref_value_store_;
+
+  scoped_refptr<PrefRegistry> pref_registry_;
+
+  // Pref Stores and profile that we passed to the PrefValueStore.
+  scoped_refptr<PersistentPrefStore> user_pref_store_;
+
+  // Callback to call when a read error occurs.
+  base::Callback<void(PersistentPrefStore::PrefReadError)> read_error_callback_;
+
+ private:
+  // Hash map expected to be fastest here since it minimises expensive
+  // string comparisons. Order is unimportant, and deletions are rare.
+  // Confirmed on Android where this speeded Chrome startup by roughly 50ms
+  // vs. std::map, and by roughly 180ms vs. std::set of Preference pointers.
+  typedef base::hash_map<std::string, Preference> PreferenceMap;
+
+  // Give access to ReportUserPrefChanged() and GetMutableUserPref().
+  friend class subtle::ScopedUserPrefUpdateBase;
+  friend class PrefServiceTest_WriteablePrefStoreFlags_Test;
+
+  // Registration of pref change observers must be done using the
+  // PrefChangeRegistrar, which is declared as a friend here to grant it
+  // access to the otherwise protected members Add/RemovePrefObserver.
+  // PrefMember registers for preferences changes notification directly to
+  // avoid the storage overhead of the registrar, so its base class must be
+  // declared as a friend, too.
+  friend class PrefChangeRegistrar;
+  friend class subtle::PrefMemberBase;
+
+  // These are protected so they can only be accessed by the friend
+  // classes listed above.
+  //
+  // If the pref at the given path changes, we call the observer's
+  // OnPreferenceChanged method. Note that observers should not call
+  // these methods directly but rather use a PrefChangeRegistrar to
+  // make sure the observer gets cleaned up properly.
+  //
+  // Virtual for testing.
+  virtual void AddPrefObserver(const std::string& path, PrefObserver* obs);
+  virtual void RemovePrefObserver(const std::string& path, PrefObserver* obs);
+
+  // Sends notification of a changed preference. This needs to be called by
+  // a ScopedUserPrefUpdate if a DictionaryValue or ListValue is changed.
+  void ReportUserPrefChanged(const std::string& key);
+
+  // Sets the value for this pref path in the user pref store and informs the
+  // PrefNotifier of the change.
+  void SetUserPrefValue(const std::string& path, base::Value* new_value);
+
+  // Load preferences from storage, attempting to diagnose and handle errors.
+  // This should only be called from the constructor.
+  void InitFromStorage(bool async);
+
+  // Used to set the value of dictionary or list values in the user pref store.
+  // This will create a dictionary or list if one does not exist in the user
+  // pref store. This method returns NULL only if you're requesting an
+  // unregistered pref or a non-dict/non-list pref.
+  // |type| may only be Values::TYPE_DICTIONARY or Values::TYPE_LIST and
+  // |path| must point to a registered preference of type |type|.
+  // Ownership of the returned value remains at the user pref store.
+  base::Value* GetMutableUserPref(const std::string& path,
+                                  base::Value::Type type);
+
+  // GetPreferenceValue is the equivalent of FindPreference(path)->GetValue(),
+  // it has been added for performance. If is faster because it does
+  // not need to find or create a Preference object to get the
+  // value (GetValue() calls back though the preference service to
+  // actually get the value.).
+  const base::Value* GetPreferenceValue(const std::string& path) const;
+
+  // Local cache of registered Preference objects. The pref_registry_
+  // is authoritative with respect to what the types and default values
+  // of registered preferences are.
+  mutable PreferenceMap prefs_map_;
+
+  DISALLOW_COPY_AND_ASSIGN(PrefService);
+};
+
+#endif  // BASE_PREFS_PREF_SERVICE_H_
diff --git a/base/prefs/pref_service_factory.cc b/base/prefs/pref_service_factory.cc
new file mode 100644
index 0000000..8caf073
--- /dev/null
+++ b/base/prefs/pref_service_factory.cc
@@ -0,0 +1,65 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/prefs/pref_service_factory.h"
+
+#include "base/bind.h"
+#include "base/prefs/default_pref_store.h"
+#include "base/prefs/json_pref_store.h"
+#include "base/prefs/pref_filter.h"
+#include "base/prefs/pref_notifier_impl.h"
+#include "base/prefs/pref_service.h"
+#include "base/prefs/pref_value_store.h"
+#include "base/sequenced_task_runner.h"
+
+namespace base {
+
+namespace {
+
+// Do-nothing default implementation.
+void DoNothingHandleReadError(PersistentPrefStore::PrefReadError error) {
+}
+
+}  // namespace
+
+PrefServiceFactory::PrefServiceFactory()
+    : managed_prefs_(NULL),
+      supervised_user_prefs_(NULL),
+      extension_prefs_(NULL),
+      command_line_prefs_(NULL),
+      user_prefs_(NULL),
+      recommended_prefs_(NULL),
+      read_error_callback_(base::Bind(&DoNothingHandleReadError)),
+      async_(false) {}
+
+PrefServiceFactory::~PrefServiceFactory() {}
+
+void PrefServiceFactory::SetUserPrefsFile(
+    const base::FilePath& prefs_file,
+    base::SequencedTaskRunner* task_runner) {
+  user_prefs_ = new JsonPrefStore(
+      prefs_file, task_runner, scoped_ptr<PrefFilter>());
+}
+
+scoped_ptr<PrefService> PrefServiceFactory::Create(
+    PrefRegistry* pref_registry) {
+  PrefNotifierImpl* pref_notifier = new PrefNotifierImpl();
+  scoped_ptr<PrefService> pref_service(
+      new PrefService(pref_notifier,
+                      new PrefValueStore(managed_prefs_.get(),
+                                         supervised_user_prefs_.get(),
+                                         extension_prefs_.get(),
+                                         command_line_prefs_.get(),
+                                         user_prefs_.get(),
+                                         recommended_prefs_.get(),
+                                         pref_registry->defaults().get(),
+                                         pref_notifier),
+                      user_prefs_.get(),
+                      pref_registry,
+                      read_error_callback_,
+                      async_));
+  return pref_service.Pass();
+}
+
+}  // namespace base
diff --git a/base/prefs/pref_service_factory.h b/base/prefs/pref_service_factory.h
new file mode 100644
index 0000000..ca608c2
--- /dev/null
+++ b/base/prefs/pref_service_factory.h
@@ -0,0 +1,91 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PREFS_PREF_SERVICE_FACTORY_H_
+#define BASE_PREFS_PREF_SERVICE_FACTORY_H_
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "base/prefs/base_prefs_export.h"
+#include "base/prefs/persistent_pref_store.h"
+#include "base/prefs/pref_registry.h"
+#include "base/prefs/pref_store.h"
+
+class PrefService;
+
+namespace base {
+
+class FilePath;
+class SequencedTaskRunner;
+
+// A class that allows convenient building of PrefService.
+class BASE_PREFS_EXPORT PrefServiceFactory {
+ public:
+  PrefServiceFactory();
+  virtual ~PrefServiceFactory();
+
+  // Functions for setting the various parameters of the PrefService to build.
+  void set_managed_prefs(const scoped_refptr<PrefStore>& managed_prefs) {
+    managed_prefs_ = managed_prefs;
+  }
+  void set_supervised_user_prefs(
+      const scoped_refptr<PrefStore>& supervised_user_prefs) {
+    supervised_user_prefs_ = supervised_user_prefs;
+  }
+  void set_extension_prefs(const scoped_refptr<PrefStore>& extension_prefs) {
+    extension_prefs_ = extension_prefs;
+  }
+  void set_command_line_prefs(
+      const scoped_refptr<PrefStore>& command_line_prefs) {
+    command_line_prefs_ = command_line_prefs;
+  }
+  void set_user_prefs(const scoped_refptr<PersistentPrefStore>& user_prefs) {
+    user_prefs_ = user_prefs;
+  }
+  void set_recommended_prefs(
+      const scoped_refptr<PrefStore>& recommended_prefs) {
+    recommended_prefs_ = recommended_prefs;
+  }
+
+  // Sets up error callback for the PrefService.  A do-nothing default
+  // is provided if this is not called.
+  void set_read_error_callback(
+      const base::Callback<void(PersistentPrefStore::PrefReadError)>&
+          read_error_callback) {
+    read_error_callback_ = read_error_callback;
+  }
+
+  // Specifies to use an actual file-backed user pref store.
+  void SetUserPrefsFile(const base::FilePath& prefs_file,
+                        base::SequencedTaskRunner* task_runner);
+
+  void set_async(bool async) {
+    async_ = async;
+  }
+
+  // Creates a PrefService object initialized with the parameters from
+  // this factory.
+  scoped_ptr<PrefService> Create(PrefRegistry* registry);
+
+ protected:
+  scoped_refptr<PrefStore> managed_prefs_;
+  scoped_refptr<PrefStore> supervised_user_prefs_;
+  scoped_refptr<PrefStore> extension_prefs_;
+  scoped_refptr<PrefStore> command_line_prefs_;
+  scoped_refptr<PersistentPrefStore> user_prefs_;
+  scoped_refptr<PrefStore> recommended_prefs_;
+
+  base::Callback<void(PersistentPrefStore::PrefReadError)> read_error_callback_;
+
+  // Defaults to false.
+  bool async_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(PrefServiceFactory);
+};
+
+}  // namespace base
+
+#endif  // BASE_PREFS_PREF_SERVICE_FACTORY_H_
diff --git a/base/prefs/pref_service_unittest.cc b/base/prefs/pref_service_unittest.cc
new file mode 100644
index 0000000..262d7e9
--- /dev/null
+++ b/base/prefs/pref_service_unittest.cc
@@ -0,0 +1,428 @@
+// Copyright (c) 2012 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 <string>
+
+#include "base/prefs/json_pref_store.h"
+#include "base/prefs/mock_pref_change_callback.h"
+#include "base/prefs/pref_change_registrar.h"
+#include "base/prefs/pref_registry_simple.h"
+#include "base/prefs/pref_service_factory.h"
+#include "base/prefs/pref_value_store.h"
+#include "base/prefs/testing_pref_service.h"
+#include "base/prefs/testing_pref_store.h"
+#include "base/values.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::Mock;
+
+const char kPrefName[] = "pref.name";
+
+TEST(PrefServiceTest, NoObserverFire) {
+  TestingPrefServiceSimple prefs;
+
+  const char pref_name[] = "homepage";
+  prefs.registry()->RegisterStringPref(pref_name, std::string());
+
+  const char new_pref_value[] = "http://www.google.com/";
+  MockPrefChangeCallback obs(&prefs);
+  PrefChangeRegistrar registrar;
+  registrar.Init(&prefs);
+  registrar.Add(pref_name, obs.GetCallback());
+
+  // This should fire the checks in MockPrefChangeCallback::OnPreferenceChanged.
+  const base::StringValue expected_value(new_pref_value);
+  obs.Expect(pref_name, &expected_value);
+  prefs.SetString(pref_name, new_pref_value);
+  Mock::VerifyAndClearExpectations(&obs);
+
+  // Setting the pref to the same value should not set the pref value a second
+  // time.
+  EXPECT_CALL(obs, OnPreferenceChanged(_)).Times(0);
+  prefs.SetString(pref_name, new_pref_value);
+  Mock::VerifyAndClearExpectations(&obs);
+
+  // Clearing the pref should cause the pref to fire.
+  const base::StringValue expected_default_value((std::string()));
+  obs.Expect(pref_name, &expected_default_value);
+  prefs.ClearPref(pref_name);
+  Mock::VerifyAndClearExpectations(&obs);
+
+  // Clearing the pref again should not cause the pref to fire.
+  EXPECT_CALL(obs, OnPreferenceChanged(_)).Times(0);
+  prefs.ClearPref(pref_name);
+  Mock::VerifyAndClearExpectations(&obs);
+}
+
+TEST(PrefServiceTest, HasPrefPath) {
+  TestingPrefServiceSimple prefs;
+
+  const char path[] = "fake.path";
+
+  // Shouldn't initially have a path.
+  EXPECT_FALSE(prefs.HasPrefPath(path));
+
+  // Register the path. This doesn't set a value, so the path still shouldn't
+  // exist.
+  prefs.registry()->RegisterStringPref(path, std::string());
+  EXPECT_FALSE(prefs.HasPrefPath(path));
+
+  // Set a value and make sure we have a path.
+  prefs.SetString(path, "blah");
+  EXPECT_TRUE(prefs.HasPrefPath(path));
+}
+
+TEST(PrefServiceTest, Observers) {
+  const char pref_name[] = "homepage";
+
+  TestingPrefServiceSimple prefs;
+  prefs.SetUserPref(pref_name,
+                    new base::StringValue("http://www.cnn.com"));
+  prefs.registry()->RegisterStringPref(pref_name, std::string());
+
+  const char new_pref_value[] = "http://www.google.com/";
+  const base::StringValue expected_new_pref_value(new_pref_value);
+  MockPrefChangeCallback obs(&prefs);
+  PrefChangeRegistrar registrar;
+  registrar.Init(&prefs);
+  registrar.Add(pref_name, obs.GetCallback());
+
+  PrefChangeRegistrar registrar_two;
+  registrar_two.Init(&prefs);
+
+  // This should fire the checks in MockPrefChangeCallback::OnPreferenceChanged.
+  obs.Expect(pref_name, &expected_new_pref_value);
+  prefs.SetString(pref_name, new_pref_value);
+  Mock::VerifyAndClearExpectations(&obs);
+
+  // Now try adding a second pref observer.
+  const char new_pref_value2[] = "http://www.youtube.com/";
+  const base::StringValue expected_new_pref_value2(new_pref_value2);
+  MockPrefChangeCallback obs2(&prefs);
+  obs.Expect(pref_name, &expected_new_pref_value2);
+  obs2.Expect(pref_name, &expected_new_pref_value2);
+  registrar_two.Add(pref_name, obs2.GetCallback());
+  // This should fire the checks in obs and obs2.
+  prefs.SetString(pref_name, new_pref_value2);
+  Mock::VerifyAndClearExpectations(&obs);
+  Mock::VerifyAndClearExpectations(&obs2);
+
+  // Set a recommended value.
+  const base::StringValue recommended_pref_value("http://www.gmail.com/");
+  obs.Expect(pref_name, &expected_new_pref_value2);
+  obs2.Expect(pref_name, &expected_new_pref_value2);
+  // This should fire the checks in obs and obs2 but with an unchanged value
+  // as the recommended value is being overridden by the user-set value.
+  prefs.SetRecommendedPref(pref_name, recommended_pref_value.DeepCopy());
+  Mock::VerifyAndClearExpectations(&obs);
+  Mock::VerifyAndClearExpectations(&obs2);
+
+  // Make sure obs2 still works after removing obs.
+  registrar.Remove(pref_name);
+  EXPECT_CALL(obs, OnPreferenceChanged(_)).Times(0);
+  obs2.Expect(pref_name, &expected_new_pref_value);
+  // This should only fire the observer in obs2.
+  prefs.SetString(pref_name, new_pref_value);
+  Mock::VerifyAndClearExpectations(&obs);
+  Mock::VerifyAndClearExpectations(&obs2);
+}
+
+// Make sure that if a preference changes type, so the wrong type is stored in
+// the user pref file, it uses the correct fallback value instead.
+TEST(PrefServiceTest, GetValueChangedType) {
+  const int kTestValue = 10;
+  TestingPrefServiceSimple prefs;
+  prefs.registry()->RegisterIntegerPref(kPrefName, kTestValue);
+
+  // Check falling back to a recommended value.
+  prefs.SetUserPref(kPrefName,
+                    new base::StringValue("not an integer"));
+  const PrefService::Preference* pref = prefs.FindPreference(kPrefName);
+  ASSERT_TRUE(pref);
+  const base::Value* value = pref->GetValue();
+  ASSERT_TRUE(value);
+  EXPECT_EQ(base::Value::TYPE_INTEGER, value->GetType());
+  int actual_int_value = -1;
+  EXPECT_TRUE(value->GetAsInteger(&actual_int_value));
+  EXPECT_EQ(kTestValue, actual_int_value);
+}
+
+TEST(PrefServiceTest, GetValueAndGetRecommendedValue) {
+  const int kDefaultValue = 5;
+  const int kUserValue = 10;
+  const int kRecommendedValue = 15;
+  TestingPrefServiceSimple prefs;
+  prefs.registry()->RegisterIntegerPref(kPrefName, kDefaultValue);
+
+  // Create pref with a default value only.
+  const PrefService::Preference* pref = prefs.FindPreference(kPrefName);
+  ASSERT_TRUE(pref);
+
+  // Check that GetValue() returns the default value.
+  const base::Value* value = pref->GetValue();
+  ASSERT_TRUE(value);
+  EXPECT_EQ(base::Value::TYPE_INTEGER, value->GetType());
+  int actual_int_value = -1;
+  EXPECT_TRUE(value->GetAsInteger(&actual_int_value));
+  EXPECT_EQ(kDefaultValue, actual_int_value);
+
+  // Check that GetRecommendedValue() returns no value.
+  value = pref->GetRecommendedValue();
+  ASSERT_FALSE(value);
+
+  // Set a user-set value.
+  prefs.SetUserPref(kPrefName, new base::FundamentalValue(kUserValue));
+
+  // Check that GetValue() returns the user-set value.
+  value = pref->GetValue();
+  ASSERT_TRUE(value);
+  EXPECT_EQ(base::Value::TYPE_INTEGER, value->GetType());
+  actual_int_value = -1;
+  EXPECT_TRUE(value->GetAsInteger(&actual_int_value));
+  EXPECT_EQ(kUserValue, actual_int_value);
+
+  // Check that GetRecommendedValue() returns no value.
+  value = pref->GetRecommendedValue();
+  ASSERT_FALSE(value);
+
+  // Set a recommended value.
+  prefs.SetRecommendedPref(kPrefName,
+                           new base::FundamentalValue(kRecommendedValue));
+
+  // Check that GetValue() returns the user-set value.
+  value = pref->GetValue();
+  ASSERT_TRUE(value);
+  EXPECT_EQ(base::Value::TYPE_INTEGER, value->GetType());
+  actual_int_value = -1;
+  EXPECT_TRUE(value->GetAsInteger(&actual_int_value));
+  EXPECT_EQ(kUserValue, actual_int_value);
+
+  // Check that GetRecommendedValue() returns the recommended value.
+  value = pref->GetRecommendedValue();
+  ASSERT_TRUE(value);
+  EXPECT_EQ(base::Value::TYPE_INTEGER, value->GetType());
+  actual_int_value = -1;
+  EXPECT_TRUE(value->GetAsInteger(&actual_int_value));
+  EXPECT_EQ(kRecommendedValue, actual_int_value);
+
+  // Remove the user-set value.
+  prefs.RemoveUserPref(kPrefName);
+
+  // Check that GetValue() returns the recommended value.
+  value = pref->GetValue();
+  ASSERT_TRUE(value);
+  EXPECT_EQ(base::Value::TYPE_INTEGER, value->GetType());
+  actual_int_value = -1;
+  EXPECT_TRUE(value->GetAsInteger(&actual_int_value));
+  EXPECT_EQ(kRecommendedValue, actual_int_value);
+
+  // Check that GetRecommendedValue() returns the recommended value.
+  value = pref->GetRecommendedValue();
+  ASSERT_TRUE(value);
+  EXPECT_EQ(base::Value::TYPE_INTEGER, value->GetType());
+  actual_int_value = -1;
+  EXPECT_TRUE(value->GetAsInteger(&actual_int_value));
+  EXPECT_EQ(kRecommendedValue, actual_int_value);
+}
+
+// A PrefStore which just stores the last write flags that were used to write
+// values to it.
+class WriteFlagChecker : public TestingPrefStore {
+ public:
+  WriteFlagChecker() {}
+
+  void ReportValueChanged(const std::string& key, uint32 flags) override {
+    SetLastWriteFlags(flags);
+  }
+
+  void SetValue(const std::string& key,
+                base::Value* value,
+                uint32 flags) override {
+    SetLastWriteFlags(flags);
+    delete value;
+  }
+
+  void SetValueSilently(const std::string& key,
+                        base::Value* value,
+                        uint32 flags) override {
+    SetLastWriteFlags(flags);
+    delete value;
+  }
+
+  void RemoveValue(const std::string& key, uint32 flags) override {
+    SetLastWriteFlags(flags);
+  }
+
+  uint32 GetLastFlagsAndClear() {
+    CHECK(last_write_flags_set_);
+    uint32 result = last_write_flags_;
+    last_write_flags_set_ = false;
+    last_write_flags_ = WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS;
+    return result;
+  }
+
+  bool last_write_flags_set() { return last_write_flags_set_; }
+
+ private:
+  ~WriteFlagChecker() override {}
+
+  void SetLastWriteFlags(uint32 flags) {
+    CHECK(!last_write_flags_set_);
+    last_write_flags_set_ = true;
+    last_write_flags_ = flags;
+  }
+
+  bool last_write_flags_set_ = false;
+  uint32 last_write_flags_ = WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS;
+};
+
+TEST(PrefServiceTest, WriteablePrefStoreFlags) {
+  scoped_refptr<WriteFlagChecker> flag_checker(new WriteFlagChecker);
+  scoped_refptr<PrefRegistrySimple> registry(new PrefRegistrySimple);
+  base::PrefServiceFactory factory;
+  factory.set_user_prefs(flag_checker);
+  scoped_ptr<PrefService> prefs(factory.Create(registry.get()));
+
+  // The first 8 bits of write flags are reserved for subclasses. Create a
+  // custom flag in this range
+  uint32 kCustomRegistrationFlag = 1 << 2;
+
+  // A map of the registration flags that will be tested and the write flags
+  // they are expected to convert to.
+  struct RegistrationToWriteFlags {
+    const char* pref_name;
+    uint32 registration_flags;
+    uint32 write_flags;
+  };
+  const RegistrationToWriteFlags kRegistrationToWriteFlags[] = {
+      {"none",
+       PrefRegistry::NO_REGISTRATION_FLAGS,
+       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS},
+      {"lossy",
+       PrefRegistry::LOSSY_PREF,
+       WriteablePrefStore::LOSSY_PREF_WRITE_FLAG},
+      {"custom",
+       kCustomRegistrationFlag,
+       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS},
+      {"lossyandcustom",
+       PrefRegistry::LOSSY_PREF | kCustomRegistrationFlag,
+       WriteablePrefStore::LOSSY_PREF_WRITE_FLAG}};
+
+  for (size_t i = 0; i < arraysize(kRegistrationToWriteFlags); ++i) {
+    RegistrationToWriteFlags entry = kRegistrationToWriteFlags[i];
+    registry->RegisterDictionaryPref(
+        entry.pref_name, new base::DictionaryValue(), entry.registration_flags);
+
+    SCOPED_TRACE("Currently testing pref with name: " +
+                 std::string(entry.pref_name));
+
+    prefs->GetMutableUserPref(entry.pref_name, base::Value::TYPE_DICTIONARY);
+    EXPECT_TRUE(flag_checker->last_write_flags_set());
+    EXPECT_EQ(entry.write_flags, flag_checker->GetLastFlagsAndClear());
+
+    prefs->ReportUserPrefChanged(entry.pref_name);
+    EXPECT_TRUE(flag_checker->last_write_flags_set());
+    EXPECT_EQ(entry.write_flags, flag_checker->GetLastFlagsAndClear());
+
+    prefs->ClearPref(entry.pref_name);
+    EXPECT_TRUE(flag_checker->last_write_flags_set());
+    EXPECT_EQ(entry.write_flags, flag_checker->GetLastFlagsAndClear());
+
+    prefs->SetUserPrefValue(entry.pref_name, new base::DictionaryValue());
+    EXPECT_TRUE(flag_checker->last_write_flags_set());
+    EXPECT_EQ(entry.write_flags, flag_checker->GetLastFlagsAndClear());
+  }
+}
+
+class PrefServiceSetValueTest : public testing::Test {
+ protected:
+  static const char kName[];
+  static const char kValue[];
+
+  PrefServiceSetValueTest() : observer_(&prefs_) {}
+
+  TestingPrefServiceSimple prefs_;
+  MockPrefChangeCallback observer_;
+};
+
+const char PrefServiceSetValueTest::kName[] = "name";
+const char PrefServiceSetValueTest::kValue[] = "value";
+
+TEST_F(PrefServiceSetValueTest, SetStringValue) {
+  const char default_string[] = "default";
+  const base::StringValue default_value(default_string);
+  prefs_.registry()->RegisterStringPref(kName, default_string);
+
+  PrefChangeRegistrar registrar;
+  registrar.Init(&prefs_);
+  registrar.Add(kName, observer_.GetCallback());
+
+  // Changing the controlling store from default to user triggers notification.
+  observer_.Expect(kName, &default_value);
+  prefs_.Set(kName, default_value);
+  Mock::VerifyAndClearExpectations(&observer_);
+
+  EXPECT_CALL(observer_, OnPreferenceChanged(_)).Times(0);
+  prefs_.Set(kName, default_value);
+  Mock::VerifyAndClearExpectations(&observer_);
+
+  base::StringValue new_value(kValue);
+  observer_.Expect(kName, &new_value);
+  prefs_.Set(kName, new_value);
+  Mock::VerifyAndClearExpectations(&observer_);
+}
+
+TEST_F(PrefServiceSetValueTest, SetDictionaryValue) {
+  prefs_.registry()->RegisterDictionaryPref(kName);
+  PrefChangeRegistrar registrar;
+  registrar.Init(&prefs_);
+  registrar.Add(kName, observer_.GetCallback());
+
+  EXPECT_CALL(observer_, OnPreferenceChanged(_)).Times(0);
+  prefs_.RemoveUserPref(kName);
+  Mock::VerifyAndClearExpectations(&observer_);
+
+  base::DictionaryValue new_value;
+  new_value.SetString(kName, kValue);
+  observer_.Expect(kName, &new_value);
+  prefs_.Set(kName, new_value);
+  Mock::VerifyAndClearExpectations(&observer_);
+
+  EXPECT_CALL(observer_, OnPreferenceChanged(_)).Times(0);
+  prefs_.Set(kName, new_value);
+  Mock::VerifyAndClearExpectations(&observer_);
+
+  base::DictionaryValue empty;
+  observer_.Expect(kName, &empty);
+  prefs_.Set(kName, empty);
+  Mock::VerifyAndClearExpectations(&observer_);
+}
+
+TEST_F(PrefServiceSetValueTest, SetListValue) {
+  prefs_.registry()->RegisterListPref(kName);
+  PrefChangeRegistrar registrar;
+  registrar.Init(&prefs_);
+  registrar.Add(kName, observer_.GetCallback());
+
+  EXPECT_CALL(observer_, OnPreferenceChanged(_)).Times(0);
+  prefs_.RemoveUserPref(kName);
+  Mock::VerifyAndClearExpectations(&observer_);
+
+  base::ListValue new_value;
+  new_value.Append(new base::StringValue(kValue));
+  observer_.Expect(kName, &new_value);
+  prefs_.Set(kName, new_value);
+  Mock::VerifyAndClearExpectations(&observer_);
+
+  EXPECT_CALL(observer_, OnPreferenceChanged(_)).Times(0);
+  prefs_.Set(kName, new_value);
+  Mock::VerifyAndClearExpectations(&observer_);
+
+  base::ListValue empty;
+  observer_.Expect(kName, &empty);
+  prefs_.Set(kName, empty);
+  Mock::VerifyAndClearExpectations(&observer_);
+}
diff --git a/base/prefs/pref_store.cc b/base/prefs/pref_store.cc
new file mode 100644
index 0000000..f286a33
--- /dev/null
+++ b/base/prefs/pref_store.cc
@@ -0,0 +1,13 @@
+// Copyright (c) 2012 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/prefs/pref_store.h"
+
+bool PrefStore::HasObservers() const {
+  return false;
+}
+
+bool PrefStore::IsInitializationComplete() const {
+  return true;
+}
diff --git a/base/prefs/pref_store.h b/base/prefs/pref_store.h
new file mode 100644
index 0000000..b736ac3
--- /dev/null
+++ b/base/prefs/pref_store.h
@@ -0,0 +1,63 @@
+// Copyright (c) 2012 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_PREFS_PREF_STORE_H_
+#define BASE_PREFS_PREF_STORE_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/prefs/base_prefs_export.h"
+
+namespace base {
+class Value;
+}
+
+// This is an abstract interface for reading and writing from/to a persistent
+// preference store, used by PrefService. An implementation using a JSON file
+// can be found in JsonPrefStore, while an implementation without any backing
+// store for testing can be found in TestingPrefStore. Furthermore, there is
+// CommandLinePrefStore, which bridges command line options to preferences and
+// ConfigurationPolicyPrefStore, which is used for hooking up configuration
+// policy with the preference subsystem.
+class BASE_PREFS_EXPORT PrefStore : public base::RefCounted<PrefStore> {
+ public:
+  // Observer interface for monitoring PrefStore.
+  class BASE_PREFS_EXPORT Observer {
+   public:
+    // Called when the value for the given |key| in the store changes.
+    virtual void OnPrefValueChanged(const std::string& key) = 0;
+    // Notification about the PrefStore being fully initialized.
+    virtual void OnInitializationCompleted(bool succeeded) = 0;
+
+   protected:
+    virtual ~Observer() {}
+  };
+
+  PrefStore() {}
+
+  // Add and remove observers.
+  virtual void AddObserver(Observer* observer) {}
+  virtual void RemoveObserver(Observer* observer) {}
+  virtual bool HasObservers() const;
+
+  // Whether the store has completed all asynchronous initialization.
+  virtual bool IsInitializationComplete() const;
+
+  // Get the value for a given preference |key| and stores it in |*result|.
+  // |*result| is only modified if the return value is true and if |result|
+  // is not NULL. Ownership of the |*result| value remains with the PrefStore.
+  virtual bool GetValue(const std::string& key,
+                        const base::Value** result) const = 0;
+
+ protected:
+  friend class base::RefCounted<PrefStore>;
+  virtual ~PrefStore() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(PrefStore);
+};
+
+#endif  // BASE_PREFS_PREF_STORE_H_
diff --git a/base/prefs/pref_store_observer_mock.cc b/base/prefs/pref_store_observer_mock.cc
new file mode 100644
index 0000000..f1a31bb
--- /dev/null
+++ b/base/prefs/pref_store_observer_mock.cc
@@ -0,0 +1,29 @@
+// Copyright (c) 2011 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/prefs/pref_store_observer_mock.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+PrefStoreObserverMock::PrefStoreObserverMock()
+    : initialized(false), initialization_success(false) {}
+
+PrefStoreObserverMock::~PrefStoreObserverMock() {}
+
+void PrefStoreObserverMock::VerifyAndResetChangedKey(
+    const std::string& expected) {
+  EXPECT_EQ(1u, changed_keys.size());
+  if (changed_keys.size() >= 1)
+    EXPECT_EQ(expected, changed_keys.front());
+  changed_keys.clear();
+}
+
+void PrefStoreObserverMock::OnPrefValueChanged(const std::string& key) {
+  changed_keys.push_back(key);
+}
+
+void PrefStoreObserverMock::OnInitializationCompleted(bool success) {
+  initialized = true;
+  initialization_success = success;
+}
diff --git a/base/prefs/pref_store_observer_mock.h b/base/prefs/pref_store_observer_mock.h
new file mode 100644
index 0000000..1b24b4e
--- /dev/null
+++ b/base/prefs/pref_store_observer_mock.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2011 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_PREFS_PREF_STORE_OBSERVER_MOCK_H_
+#define BASE_PREFS_PREF_STORE_OBSERVER_MOCK_H_
+
+#include <string>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/prefs/pref_store.h"
+
+// A mock implementation of PrefStore::Observer.
+class PrefStoreObserverMock : public PrefStore::Observer {
+ public:
+  PrefStoreObserverMock();
+  ~PrefStoreObserverMock() override;
+
+  void VerifyAndResetChangedKey(const std::string& expected);
+
+  // PrefStore::Observer implementation
+  void OnPrefValueChanged(const std::string& key) override;
+  void OnInitializationCompleted(bool success) override;
+
+  std::vector<std::string> changed_keys;
+  bool initialized;
+  bool initialization_success;  // Only valid if |initialized|.
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(PrefStoreObserverMock);
+};
+
+#endif  // BASE_PREFS_PREF_STORE_OBSERVER_MOCK_H_
diff --git a/base/prefs/pref_value_map.cc b/base/prefs/pref_value_map.cc
new file mode 100644
index 0000000..5f2dc50
--- /dev/null
+++ b/base/prefs/pref_value_map.cc
@@ -0,0 +1,160 @@
+// Copyright (c) 2011 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/prefs/pref_value_map.h"
+
+#include <map>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/stl_util.h"
+#include "base/values.h"
+
+PrefValueMap::PrefValueMap() {}
+
+PrefValueMap::~PrefValueMap() {
+  Clear();
+}
+
+bool PrefValueMap::GetValue(const std::string& key,
+                            const base::Value** value) const {
+  const Map::const_iterator entry = prefs_.find(key);
+  if (entry == prefs_.end())
+    return false;
+
+  if (value)
+    *value = entry->second;
+  return true;
+}
+
+bool PrefValueMap::GetValue(const std::string& key, base::Value** value) {
+  const Map::const_iterator entry = prefs_.find(key);
+  if (entry == prefs_.end())
+    return false;
+
+  if (value)
+    *value = entry->second;
+  return true;
+}
+
+bool PrefValueMap::SetValue(const std::string& key, base::Value* value) {
+  DCHECK(value);
+  auto result = prefs_.insert(std::make_pair(key, value));
+  if (result.second)
+    return true;
+
+  scoped_ptr<base::Value> value_ptr(value);
+  const Map::iterator& entry = result.first;
+  if (base::Value::Equals(entry->second, value))
+    return false;
+
+  delete entry->second;
+  entry->second = value_ptr.release();
+
+  return true;
+}
+
+bool PrefValueMap::RemoveValue(const std::string& key) {
+  const Map::iterator entry = prefs_.find(key);
+  if (entry == prefs_.end())
+    return false;
+
+  delete entry->second;
+  prefs_.erase(entry);
+  return true;
+}
+
+void PrefValueMap::Clear() {
+  STLDeleteValues(&prefs_);
+}
+
+void PrefValueMap::Swap(PrefValueMap* other) {
+  prefs_.swap(other->prefs_);
+}
+
+PrefValueMap::iterator PrefValueMap::begin() {
+  return prefs_.begin();
+}
+
+PrefValueMap::iterator PrefValueMap::end() {
+  return prefs_.end();
+}
+
+PrefValueMap::const_iterator PrefValueMap::begin() const {
+  return prefs_.begin();
+}
+
+PrefValueMap::const_iterator PrefValueMap::end() const {
+  return prefs_.end();
+}
+
+bool PrefValueMap::GetBoolean(const std::string& key,
+                              bool* value) const {
+  const base::Value* stored_value = nullptr;
+  return GetValue(key, &stored_value) && stored_value->GetAsBoolean(value);
+}
+
+void PrefValueMap::SetBoolean(const std::string& key, bool value) {
+  SetValue(key, new base::FundamentalValue(value));
+}
+
+bool PrefValueMap::GetString(const std::string& key,
+                             std::string* value) const {
+  const base::Value* stored_value = nullptr;
+  return GetValue(key, &stored_value) && stored_value->GetAsString(value);
+}
+
+void PrefValueMap::SetString(const std::string& key,
+                             const std::string& value) {
+  SetValue(key, new base::StringValue(value));
+}
+
+bool PrefValueMap::GetInteger(const std::string& key, int* value) const {
+  const base::Value* stored_value = nullptr;
+  return GetValue(key, &stored_value) && stored_value->GetAsInteger(value);
+}
+
+void PrefValueMap::SetInteger(const std::string& key, const int value) {
+  SetValue(key, new base::FundamentalValue(value));
+}
+
+void PrefValueMap::SetDouble(const std::string& key, const double value) {
+  SetValue(key, new base::FundamentalValue(value));
+}
+
+void PrefValueMap::GetDifferingKeys(
+    const PrefValueMap* other,
+    std::vector<std::string>* differing_keys) const {
+  differing_keys->clear();
+
+  // Put everything into ordered maps.
+  std::map<std::string, base::Value*> this_prefs(prefs_.begin(), prefs_.end());
+  std::map<std::string, base::Value*> other_prefs(other->prefs_.begin(),
+                                                  other->prefs_.end());
+
+  // Walk over the maps in lockstep, adding everything that is different.
+  auto this_pref(this_prefs.begin());
+  auto other_pref(other_prefs.begin());
+  while (this_pref != this_prefs.end() && other_pref != other_prefs.end()) {
+    const int diff = this_pref->first.compare(other_pref->first);
+    if (diff == 0) {
+      if (!this_pref->second->Equals(other_pref->second))
+        differing_keys->push_back(this_pref->first);
+      ++this_pref;
+      ++other_pref;
+    } else if (diff < 0) {
+      differing_keys->push_back(this_pref->first);
+      ++this_pref;
+    } else if (diff > 0) {
+      differing_keys->push_back(other_pref->first);
+      ++other_pref;
+    }
+  }
+
+  // Add the remaining entries.
+  for ( ; this_pref != this_prefs.end(); ++this_pref)
+      differing_keys->push_back(this_pref->first);
+  for ( ; other_pref != other_prefs.end(); ++other_pref)
+      differing_keys->push_back(other_pref->first);
+}
diff --git a/base/prefs/pref_value_map.h b/base/prefs/pref_value_map.h
new file mode 100644
index 0000000..12b30c6
--- /dev/null
+++ b/base/prefs/pref_value_map.h
@@ -0,0 +1,90 @@
+// Copyright (c) 2011 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_PREFS_PREF_VALUE_MAP_H_
+#define BASE_PREFS_PREF_VALUE_MAP_H_
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/containers/hash_tables.h"
+#include "base/prefs/base_prefs_export.h"
+
+namespace base {
+class Value;
+}
+
+// A generic string to value map used by the PrefStore implementations.
+class BASE_PREFS_EXPORT PrefValueMap {
+ public:
+  using Map = base::hash_map<std::string, base::Value*>;
+  using iterator = Map::iterator;
+  using const_iterator = Map::const_iterator;
+
+  PrefValueMap();
+  virtual ~PrefValueMap();
+
+  // Gets the value for |key| and stores it in |value|. Ownership remains with
+  // the map. Returns true if a value is present. If not, |value| is not
+  // touched.
+  bool GetValue(const std::string& key, const base::Value** value) const;
+  bool GetValue(const std::string& key, base::Value** value);
+
+  // Sets a new |value| for |key|. Takes ownership of |value|, which must be
+  // non-NULL. Returns true if the value changed.
+  bool SetValue(const std::string& key, base::Value* value);
+
+  // Removes the value for |key| from the map. Returns true if a value was
+  // removed.
+  bool RemoveValue(const std::string& key);
+
+  // Clears the map.
+  void Clear();
+
+  // Swaps the contents of two maps.
+  void Swap(PrefValueMap* other);
+
+  iterator begin();
+  iterator end();
+  const_iterator begin() const;
+  const_iterator end() const;
+
+  // Gets a boolean value for |key| and stores it in |value|. Returns true if
+  // the value was found and of the proper type.
+  bool GetBoolean(const std::string& key, bool* value) const;
+
+  // Sets the value for |key| to the boolean |value|.
+  void SetBoolean(const std::string& key, bool value);
+
+  // Gets a string value for |key| and stores it in |value|. Returns true if
+  // the value was found and of the proper type.
+  bool GetString(const std::string& key, std::string* value) const;
+
+  // Sets the value for |key| to the string |value|.
+  void SetString(const std::string& key, const std::string& value);
+
+  // Gets an int value for |key| and stores it in |value|. Returns true if
+  // the value was found and of the proper type.
+  bool GetInteger(const std::string& key, int* value) const;
+
+  // Sets the value for |key| to the int |value|.
+  void SetInteger(const std::string& key, const int value);
+
+  // Sets the value for |key| to the double |value|.
+  void SetDouble(const std::string& key, const double value);
+
+  // Compares this value map against |other| and stores all key names that have
+  // different values in |differing_keys|. This includes keys that are present
+  // only in one of the maps.
+  void GetDifferingKeys(const PrefValueMap* other,
+                        std::vector<std::string>* differing_keys) const;
+
+ private:
+  Map prefs_;
+
+  DISALLOW_COPY_AND_ASSIGN(PrefValueMap);
+};
+
+#endif  // BASE_PREFS_PREF_VALUE_MAP_H_
diff --git a/base/prefs/pref_value_map_unittest.cc b/base/prefs/pref_value_map_unittest.cc
new file mode 100644
index 0000000..82499da
--- /dev/null
+++ b/base/prefs/pref_value_map_unittest.cc
@@ -0,0 +1,126 @@
+// Copyright (c) 2011 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/prefs/pref_value_map.h"
+
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+TEST(PrefValueMapTest, SetValue) {
+  PrefValueMap map;
+  const Value* result = NULL;
+  EXPECT_FALSE(map.GetValue("key", &result));
+  EXPECT_FALSE(result);
+
+  EXPECT_TRUE(map.SetValue("key", new StringValue("test")));
+  EXPECT_FALSE(map.SetValue("key", new StringValue("test")));
+  EXPECT_TRUE(map.SetValue("key", new StringValue("hi mom!")));
+
+  EXPECT_TRUE(map.GetValue("key", &result));
+  EXPECT_TRUE(StringValue("hi mom!").Equals(result));
+}
+
+TEST(PrefValueMapTest, GetAndSetIntegerValue) {
+  PrefValueMap map;
+  ASSERT_TRUE(map.SetValue("key", new FundamentalValue(5)));
+
+  int int_value = 0;
+  EXPECT_TRUE(map.GetInteger("key", &int_value));
+  EXPECT_EQ(5, int_value);
+
+  map.SetInteger("key", -14);
+  EXPECT_TRUE(map.GetInteger("key", &int_value));
+  EXPECT_EQ(-14, int_value);
+}
+
+TEST(PrefValueMapTest, SetDoubleValue) {
+  PrefValueMap map;
+  ASSERT_TRUE(map.SetValue("key", new FundamentalValue(5.5)));
+
+  const Value* result = NULL;
+  ASSERT_TRUE(map.GetValue("key", &result));
+  double double_value = 0.;
+  EXPECT_TRUE(result->GetAsDouble(&double_value));
+  EXPECT_DOUBLE_EQ(5.5, double_value);
+}
+
+TEST(PrefValueMapTest, RemoveValue) {
+  PrefValueMap map;
+  EXPECT_FALSE(map.RemoveValue("key"));
+
+  EXPECT_TRUE(map.SetValue("key", new StringValue("test")));
+  EXPECT_TRUE(map.GetValue("key", NULL));
+
+  EXPECT_TRUE(map.RemoveValue("key"));
+  EXPECT_FALSE(map.GetValue("key", NULL));
+
+  EXPECT_FALSE(map.RemoveValue("key"));
+}
+
+TEST(PrefValueMapTest, Clear) {
+  PrefValueMap map;
+  EXPECT_TRUE(map.SetValue("key", new StringValue("test")));
+  EXPECT_TRUE(map.GetValue("key", NULL));
+
+  map.Clear();
+
+  EXPECT_FALSE(map.GetValue("key", NULL));
+}
+
+TEST(PrefValueMapTest, GetDifferingKeys) {
+  PrefValueMap reference;
+  EXPECT_TRUE(reference.SetValue("b", new StringValue("test")));
+  EXPECT_TRUE(reference.SetValue("c", new StringValue("test")));
+  EXPECT_TRUE(reference.SetValue("e", new StringValue("test")));
+
+  PrefValueMap check;
+  std::vector<std::string> differing_paths;
+  std::vector<std::string> expected_differing_paths;
+
+  reference.GetDifferingKeys(&check, &differing_paths);
+  expected_differing_paths.push_back("b");
+  expected_differing_paths.push_back("c");
+  expected_differing_paths.push_back("e");
+  EXPECT_EQ(expected_differing_paths, differing_paths);
+
+  EXPECT_TRUE(check.SetValue("a", new StringValue("test")));
+  EXPECT_TRUE(check.SetValue("c", new StringValue("test")));
+  EXPECT_TRUE(check.SetValue("d", new StringValue("test")));
+
+  reference.GetDifferingKeys(&check, &differing_paths);
+  expected_differing_paths.clear();
+  expected_differing_paths.push_back("a");
+  expected_differing_paths.push_back("b");
+  expected_differing_paths.push_back("d");
+  expected_differing_paths.push_back("e");
+  EXPECT_EQ(expected_differing_paths, differing_paths);
+}
+
+TEST(PrefValueMapTest, SwapTwoMaps) {
+  PrefValueMap first_map;
+  EXPECT_TRUE(first_map.SetValue("a", new StringValue("test")));
+  EXPECT_TRUE(first_map.SetValue("b", new StringValue("test")));
+  EXPECT_TRUE(first_map.SetValue("c", new StringValue("test")));
+
+  PrefValueMap second_map;
+  EXPECT_TRUE(second_map.SetValue("d", new StringValue("test")));
+  EXPECT_TRUE(second_map.SetValue("e", new StringValue("test")));
+  EXPECT_TRUE(second_map.SetValue("f", new StringValue("test")));
+
+  first_map.Swap(&second_map);
+
+  EXPECT_TRUE(first_map.GetValue("d", NULL));
+  EXPECT_TRUE(first_map.GetValue("e", NULL));
+  EXPECT_TRUE(first_map.GetValue("f", NULL));
+
+  EXPECT_TRUE(second_map.GetValue("a", NULL));
+  EXPECT_TRUE(second_map.GetValue("b", NULL));
+  EXPECT_TRUE(second_map.GetValue("c", NULL));
+}
+
+}  // namespace
+}  // namespace base
diff --git a/base/prefs/pref_value_store.cc b/base/prefs/pref_value_store.cc
new file mode 100644
index 0000000..1a0ec08
--- /dev/null
+++ b/base/prefs/pref_value_store.cc
@@ -0,0 +1,288 @@
+// Copyright (c) 2012 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/prefs/pref_value_store.h"
+
+#include "base/logging.h"
+#include "base/prefs/pref_notifier.h"
+#include "base/prefs/pref_observer.h"
+
+PrefValueStore::PrefStoreKeeper::PrefStoreKeeper()
+    : pref_value_store_(NULL),
+      type_(PrefValueStore::INVALID_STORE) {
+}
+
+PrefValueStore::PrefStoreKeeper::~PrefStoreKeeper() {
+  if (pref_store_.get()) {
+    pref_store_->RemoveObserver(this);
+    pref_store_ = NULL;
+  }
+  pref_value_store_ = NULL;
+}
+
+void PrefValueStore::PrefStoreKeeper::Initialize(
+    PrefValueStore* store,
+    PrefStore* pref_store,
+    PrefValueStore::PrefStoreType type) {
+  if (pref_store_.get()) {
+    pref_store_->RemoveObserver(this);
+    DCHECK(!pref_store_->HasObservers());
+  }
+  type_ = type;
+  pref_value_store_ = store;
+  pref_store_ = pref_store;
+  if (pref_store_.get())
+    pref_store_->AddObserver(this);
+}
+
+void PrefValueStore::PrefStoreKeeper::OnPrefValueChanged(
+    const std::string& key) {
+  pref_value_store_->OnPrefValueChanged(type_, key);
+}
+
+void PrefValueStore::PrefStoreKeeper::OnInitializationCompleted(
+    bool succeeded) {
+  pref_value_store_->OnInitializationCompleted(type_, succeeded);
+}
+
+PrefValueStore::PrefValueStore(PrefStore* managed_prefs,
+                               PrefStore* supervised_user_prefs,
+                               PrefStore* extension_prefs,
+                               PrefStore* command_line_prefs,
+                               PrefStore* user_prefs,
+                               PrefStore* recommended_prefs,
+                               PrefStore* default_prefs,
+                               PrefNotifier* pref_notifier)
+    : pref_notifier_(pref_notifier),
+      initialization_failed_(false) {
+  InitPrefStore(MANAGED_STORE, managed_prefs);
+  InitPrefStore(SUPERVISED_USER_STORE, supervised_user_prefs);
+  InitPrefStore(EXTENSION_STORE, extension_prefs);
+  InitPrefStore(COMMAND_LINE_STORE, command_line_prefs);
+  InitPrefStore(USER_STORE, user_prefs);
+  InitPrefStore(RECOMMENDED_STORE, recommended_prefs);
+  InitPrefStore(DEFAULT_STORE, default_prefs);
+
+  CheckInitializationCompleted();
+}
+
+PrefValueStore::~PrefValueStore() {}
+
+PrefValueStore* PrefValueStore::CloneAndSpecialize(
+    PrefStore* managed_prefs,
+    PrefStore* supervised_user_prefs,
+    PrefStore* extension_prefs,
+    PrefStore* command_line_prefs,
+    PrefStore* user_prefs,
+    PrefStore* recommended_prefs,
+    PrefStore* default_prefs,
+    PrefNotifier* pref_notifier) {
+  DCHECK(pref_notifier);
+  if (!managed_prefs)
+    managed_prefs = GetPrefStore(MANAGED_STORE);
+  if (!supervised_user_prefs)
+    supervised_user_prefs = GetPrefStore(SUPERVISED_USER_STORE);
+  if (!extension_prefs)
+    extension_prefs = GetPrefStore(EXTENSION_STORE);
+  if (!command_line_prefs)
+    command_line_prefs = GetPrefStore(COMMAND_LINE_STORE);
+  if (!user_prefs)
+    user_prefs = GetPrefStore(USER_STORE);
+  if (!recommended_prefs)
+    recommended_prefs = GetPrefStore(RECOMMENDED_STORE);
+  if (!default_prefs)
+    default_prefs = GetPrefStore(DEFAULT_STORE);
+
+  return new PrefValueStore(
+      managed_prefs, supervised_user_prefs, extension_prefs, command_line_prefs,
+      user_prefs, recommended_prefs, default_prefs, pref_notifier);
+}
+
+void PrefValueStore::set_callback(const PrefChangedCallback& callback) {
+  pref_changed_callback_ = callback;
+}
+
+bool PrefValueStore::GetValue(const std::string& name,
+                              base::Value::Type type,
+                              const base::Value** out_value) const {
+  // Check the |PrefStore|s in order of their priority from highest to lowest,
+  // looking for the first preference value with the given |name| and |type|.
+  for (size_t i = 0; i <= PREF_STORE_TYPE_MAX; ++i) {
+    if (GetValueFromStoreWithType(name, type, static_cast<PrefStoreType>(i),
+                                  out_value))
+      return true;
+  }
+  return false;
+}
+
+bool PrefValueStore::GetRecommendedValue(const std::string& name,
+                                         base::Value::Type type,
+                                         const base::Value** out_value) const {
+  return GetValueFromStoreWithType(name, type, RECOMMENDED_STORE, out_value);
+}
+
+void PrefValueStore::NotifyPrefChanged(
+    const std::string& path,
+    PrefValueStore::PrefStoreType new_store) {
+  DCHECK(new_store != INVALID_STORE);
+  // A notification is sent when the pref value in any store changes. If this
+  // store is currently being overridden by a higher-priority store, the
+  // effective value of the pref will not have changed.
+  pref_notifier_->OnPreferenceChanged(path);
+  if (!pref_changed_callback_.is_null())
+    pref_changed_callback_.Run(path);
+}
+
+bool PrefValueStore::PrefValueInManagedStore(const std::string& name) const {
+  return PrefValueInStore(name, MANAGED_STORE);
+}
+
+bool PrefValueStore::PrefValueInSupervisedStore(const std::string& name) const {
+  return PrefValueInStore(name, SUPERVISED_USER_STORE);
+}
+
+bool PrefValueStore::PrefValueInExtensionStore(const std::string& name) const {
+  return PrefValueInStore(name, EXTENSION_STORE);
+}
+
+bool PrefValueStore::PrefValueInUserStore(const std::string& name) const {
+  return PrefValueInStore(name, USER_STORE);
+}
+
+bool PrefValueStore::PrefValueFromExtensionStore(
+    const std::string& name) const {
+  return ControllingPrefStoreForPref(name) == EXTENSION_STORE;
+}
+
+bool PrefValueStore::PrefValueFromUserStore(const std::string& name) const {
+  return ControllingPrefStoreForPref(name) == USER_STORE;
+}
+
+bool PrefValueStore::PrefValueFromRecommendedStore(
+    const std::string& name) const {
+  return ControllingPrefStoreForPref(name) == RECOMMENDED_STORE;
+}
+
+bool PrefValueStore::PrefValueFromDefaultStore(const std::string& name) const {
+  return ControllingPrefStoreForPref(name) == DEFAULT_STORE;
+}
+
+bool PrefValueStore::PrefValueUserModifiable(const std::string& name) const {
+  PrefStoreType effective_store = ControllingPrefStoreForPref(name);
+  return effective_store >= USER_STORE ||
+         effective_store == INVALID_STORE;
+}
+
+bool PrefValueStore::PrefValueExtensionModifiable(
+    const std::string& name) const {
+  PrefStoreType effective_store = ControllingPrefStoreForPref(name);
+  return effective_store >= EXTENSION_STORE ||
+         effective_store == INVALID_STORE;
+}
+
+void PrefValueStore::UpdateCommandLinePrefStore(PrefStore* command_line_prefs) {
+  InitPrefStore(COMMAND_LINE_STORE, command_line_prefs);
+}
+
+bool PrefValueStore::PrefValueInStore(
+    const std::string& name,
+    PrefValueStore::PrefStoreType store) const {
+  // Declare a temp Value* and call GetValueFromStore,
+  // ignoring the output value.
+  const base::Value* tmp_value = NULL;
+  return GetValueFromStore(name, store, &tmp_value);
+}
+
+bool PrefValueStore::PrefValueInStoreRange(
+    const std::string& name,
+    PrefValueStore::PrefStoreType first_checked_store,
+    PrefValueStore::PrefStoreType last_checked_store) const {
+  if (first_checked_store > last_checked_store) {
+    NOTREACHED();
+    return false;
+  }
+
+  for (size_t i = first_checked_store;
+       i <= static_cast<size_t>(last_checked_store); ++i) {
+    if (PrefValueInStore(name, static_cast<PrefStoreType>(i)))
+      return true;
+  }
+  return false;
+}
+
+PrefValueStore::PrefStoreType PrefValueStore::ControllingPrefStoreForPref(
+    const std::string& name) const {
+  for (size_t i = 0; i <= PREF_STORE_TYPE_MAX; ++i) {
+    if (PrefValueInStore(name, static_cast<PrefStoreType>(i)))
+      return static_cast<PrefStoreType>(i);
+  }
+  return INVALID_STORE;
+}
+
+bool PrefValueStore::GetValueFromStore(const std::string& name,
+                                       PrefValueStore::PrefStoreType store_type,
+                                       const base::Value** out_value) const {
+  // Only return true if we find a value and it is the correct type, so stale
+  // values with the incorrect type will be ignored.
+  const PrefStore* store = GetPrefStore(static_cast<PrefStoreType>(store_type));
+  if (store && store->GetValue(name, out_value))
+    return true;
+
+  // No valid value found for the given preference name: set the return value
+  // to false.
+  *out_value = NULL;
+  return false;
+}
+
+bool PrefValueStore::GetValueFromStoreWithType(
+    const std::string& name,
+    base::Value::Type type,
+    PrefStoreType store,
+    const base::Value** out_value) const {
+  if (GetValueFromStore(name, store, out_value)) {
+    if ((*out_value)->IsType(type))
+      return true;
+
+    LOG(WARNING) << "Expected type for " << name << " is " << type
+                 << " but got " << (*out_value)->GetType()
+                 << " in store " << store;
+  }
+
+  *out_value = NULL;
+  return false;
+}
+
+void PrefValueStore::OnPrefValueChanged(PrefValueStore::PrefStoreType type,
+                                        const std::string& key) {
+  NotifyPrefChanged(key, type);
+}
+
+void PrefValueStore::OnInitializationCompleted(
+    PrefValueStore::PrefStoreType type, bool succeeded) {
+  if (initialization_failed_)
+    return;
+  if (!succeeded) {
+    initialization_failed_ = true;
+    pref_notifier_->OnInitializationCompleted(false);
+    return;
+  }
+  CheckInitializationCompleted();
+}
+
+void PrefValueStore::InitPrefStore(PrefValueStore::PrefStoreType type,
+                                   PrefStore* pref_store) {
+  pref_stores_[type].Initialize(this, pref_store, type);
+}
+
+void PrefValueStore::CheckInitializationCompleted() {
+  if (initialization_failed_)
+    return;
+  for (size_t i = 0; i <= PREF_STORE_TYPE_MAX; ++i) {
+    scoped_refptr<PrefStore> store =
+        GetPrefStore(static_cast<PrefStoreType>(i));
+    if (store.get() && !store->IsInitializationComplete())
+      return;
+  }
+  pref_notifier_->OnInitializationCompleted(true);
+}
diff --git a/base/prefs/pref_value_store.h b/base/prefs/pref_value_store.h
new file mode 100644
index 0000000..5160115
--- /dev/null
+++ b/base/prefs/pref_value_store.h
@@ -0,0 +1,268 @@
+// Copyright (c) 2012 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_PREFS_PREF_VALUE_STORE_H_
+#define BASE_PREFS_PREF_VALUE_STORE_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/prefs/base_prefs_export.h"
+#include "base/prefs/pref_store.h"
+#include "base/values.h"
+
+class PrefNotifier;
+class PrefStore;
+
+// The PrefValueStore manages various sources of values for Preferences
+// (e.g., configuration policies, extensions, and user settings). It returns
+// the value of a Preference from the source with the highest priority, and
+// allows setting user-defined values for preferences that are not managed.
+//
+// Unless otherwise explicitly noted, all of the methods of this class must
+// be called on the UI thread.
+class BASE_PREFS_EXPORT PrefValueStore {
+ public:
+  typedef base::Callback<void(const std::string&)> PrefChangedCallback;
+
+  // In decreasing order of precedence:
+  //   |managed_prefs| contains all preferences from mandatory policies.
+  //   |supervised_user_prefs| contains all preferences from supervised user
+  //        settings, i.e. settings configured for a supervised user by their
+  //        custodian.
+  //   |extension_prefs| contains preference values set by extensions.
+  //   |command_line_prefs| contains preference values set by command-line
+  //        switches.
+  //   |user_prefs| contains all user-set preference values.
+  //   |recommended_prefs| contains all preferences from recommended policies.
+  //   |default_prefs| contains application-default preference values. It must
+  //        be non-null if any preferences are to be registered.
+  //
+  // |pref_notifier| facilitates broadcasting preference change notifications
+  // to the world.
+  PrefValueStore(PrefStore* managed_prefs,
+                 PrefStore* supervised_user_prefs,
+                 PrefStore* extension_prefs,
+                 PrefStore* command_line_prefs,
+                 PrefStore* user_prefs,
+                 PrefStore* recommended_prefs,
+                 PrefStore* default_prefs,
+                 PrefNotifier* pref_notifier);
+  virtual ~PrefValueStore();
+
+  // Creates a clone of this PrefValueStore with PrefStores overwritten
+  // by the parameters passed, if unequal NULL.
+  PrefValueStore* CloneAndSpecialize(PrefStore* managed_prefs,
+                                     PrefStore* supervised_user_prefs,
+                                     PrefStore* extension_prefs,
+                                     PrefStore* command_line_prefs,
+                                     PrefStore* user_prefs,
+                                     PrefStore* recommended_prefs,
+                                     PrefStore* default_prefs,
+                                     PrefNotifier* pref_notifier);
+
+  // A PrefValueStore can have exactly one callback that is directly
+  // notified of preferences changing in the store. This does not
+  // filter through the PrefNotifier mechanism, which may not forward
+  // certain changes (e.g. unregistered prefs).
+  void set_callback(const PrefChangedCallback& callback);
+
+  // Gets the value for the given preference name that has the specified value
+  // type. Values stored in a PrefStore that have the matching |name| but
+  // a non-matching |type| are silently skipped. Returns true if a valid value
+  // was found in any of the available PrefStores. Most callers should use
+  // Preference::GetValue() instead of calling this method directly.
+  bool GetValue(const std::string& name,
+                base::Value::Type type,
+                const base::Value** out_value) const;
+
+  // Gets the recommended value for the given preference name that has the
+  // specified value type. A value stored in the recommended PrefStore that has
+  // the matching |name| but a non-matching |type| is silently ignored. Returns
+  // true if a valid value was found. Most callers should use
+  // Preference::GetRecommendedValue() instead of calling this method directly.
+  bool GetRecommendedValue(const std::string& name,
+                           base::Value::Type type,
+                           const base::Value** out_value) const;
+
+  // These methods return true if a preference with the given name is in the
+  // indicated pref store, even if that value is currently being overridden by
+  // a higher-priority source.
+  bool PrefValueInManagedStore(const std::string& name) const;
+  bool PrefValueInSupervisedStore(const std::string& name) const;
+  bool PrefValueInExtensionStore(const std::string& name) const;
+  bool PrefValueInUserStore(const std::string& name) const;
+
+  // These methods return true if a preference with the given name is actually
+  // being controlled by the indicated pref store and not being overridden by
+  // a higher-priority source.
+  bool PrefValueFromExtensionStore(const std::string& name) const;
+  bool PrefValueFromUserStore(const std::string& name) const;
+  bool PrefValueFromRecommendedStore(const std::string& name) const;
+  bool PrefValueFromDefaultStore(const std::string& name) const;
+
+  // Check whether a Preference value is modifiable by the user, i.e. whether
+  // there is no higher-priority source controlling it.
+  bool PrefValueUserModifiable(const std::string& name) const;
+
+  // Check whether a Preference value is modifiable by an extension, i.e.
+  // whether there is no higher-priority source controlling it.
+  bool PrefValueExtensionModifiable(const std::string& name) const;
+
+  // Update the command line PrefStore with |command_line_prefs|.
+  void UpdateCommandLinePrefStore(PrefStore* command_line_prefs);
+
+ private:
+  // PrefStores must be listed here in order from highest to lowest priority.
+  //   MANAGED contains all managed preference values that are provided by
+  //      mandatory policies (e.g. Windows Group Policy or cloud policy).
+  //   SUPERVISED_USER contains preferences that are valid for supervised users.
+  //   EXTENSION contains preference values set by extensions.
+  //   COMMAND_LINE contains preference values set by command-line switches.
+  //   USER contains all user-set preference values.
+  //   RECOMMENDED contains all preferences that are provided by recommended
+  //      policies.
+  //   DEFAULT contains all application default preference values.
+  enum PrefStoreType {
+    // INVALID_STORE is not associated with an actual PrefStore but used as
+    // an invalid marker, e.g. as a return value.
+    INVALID_STORE = -1,
+    MANAGED_STORE = 0,
+    SUPERVISED_USER_STORE,
+    EXTENSION_STORE,
+    COMMAND_LINE_STORE,
+    USER_STORE,
+    RECOMMENDED_STORE,
+    DEFAULT_STORE,
+    PREF_STORE_TYPE_MAX = DEFAULT_STORE
+  };
+
+  // Keeps a PrefStore reference on behalf of the PrefValueStore and monitors
+  // the PrefStore for changes, forwarding notifications to PrefValueStore. This
+  // indirection is here for the sake of disambiguating notifications from the
+  // individual PrefStores.
+  class PrefStoreKeeper : public PrefStore::Observer {
+   public:
+    PrefStoreKeeper();
+    ~PrefStoreKeeper() override;
+
+    // Takes ownership of |pref_store|.
+    void Initialize(PrefValueStore* store,
+                    PrefStore* pref_store,
+                    PrefStoreType type);
+
+    PrefStore* store() { return pref_store_.get(); }
+    const PrefStore* store() const { return pref_store_.get(); }
+
+   private:
+    // PrefStore::Observer implementation.
+    void OnPrefValueChanged(const std::string& key) override;
+    void OnInitializationCompleted(bool succeeded) override;
+
+    // PrefValueStore this keeper is part of.
+    PrefValueStore* pref_value_store_;
+
+    // The PrefStore managed by this keeper.
+    scoped_refptr<PrefStore> pref_store_;
+
+    // Type of the pref store.
+    PrefStoreType type_;
+
+    DISALLOW_COPY_AND_ASSIGN(PrefStoreKeeper);
+  };
+
+  typedef std::map<std::string, base::Value::Type> PrefTypeMap;
+
+  friend class PrefValueStorePolicyRefreshTest;
+  FRIEND_TEST_ALL_PREFIXES(PrefValueStorePolicyRefreshTest, TestPolicyRefresh);
+  FRIEND_TEST_ALL_PREFIXES(PrefValueStorePolicyRefreshTest,
+                           TestRefreshPolicyPrefsCompletion);
+  FRIEND_TEST_ALL_PREFIXES(PrefValueStorePolicyRefreshTest,
+                           TestConcurrentPolicyRefresh);
+
+  // Returns true if the preference with the given name has a value in the
+  // given PrefStoreType, of the same value type as the preference was
+  // registered with.
+  bool PrefValueInStore(const std::string& name, PrefStoreType store) const;
+
+  // Returns true if a preference has an explicit value in any of the
+  // stores in the range specified by |first_checked_store| and
+  // |last_checked_store|, even if that value is currently being
+  // overridden by a higher-priority store.
+  bool PrefValueInStoreRange(const std::string& name,
+                             PrefStoreType first_checked_store,
+                             PrefStoreType last_checked_store) const;
+
+  // Returns the pref store type identifying the source that controls the
+  // Preference identified by |name|. If none of the sources has a value,
+  // INVALID_STORE is returned. In practice, the default PrefStore
+  // should always have a value for any registered preferencem, so INVALID_STORE
+  // indicates an error.
+  PrefStoreType ControllingPrefStoreForPref(const std::string& name) const;
+
+  // Get a value from the specified |store|.
+  bool GetValueFromStore(const std::string& name,
+                         PrefStoreType store,
+                         const base::Value** out_value) const;
+
+  // Get a value from the specified |store| if its |type| matches.
+  bool GetValueFromStoreWithType(const std::string& name,
+                                 base::Value::Type type,
+                                 PrefStoreType store,
+                                 const base::Value** out_value) const;
+
+  // Called upon changes in individual pref stores in order to determine whether
+  // the user-visible pref value has changed. Triggers the change notification
+  // if the effective value of the preference has changed, or if the store
+  // controlling the pref has changed.
+  void NotifyPrefChanged(const std::string& path, PrefStoreType new_store);
+
+  // Called from the PrefStoreKeeper implementation when a pref value for |key|
+  // changed in the pref store for |type|.
+  void OnPrefValueChanged(PrefStoreType type, const std::string& key);
+
+  // Handle the event that the store for |type| has completed initialization.
+  void OnInitializationCompleted(PrefStoreType type, bool succeeded);
+
+  // Initializes a pref store keeper. Sets up a PrefStoreKeeper that will take
+  // ownership of the passed |pref_store|.
+  void InitPrefStore(PrefStoreType type, PrefStore* pref_store);
+
+  // Checks whether initialization is completed and tells the notifier if that
+  // is the case.
+  void CheckInitializationCompleted();
+
+  // Get the PrefStore pointer for the given type. May return NULL if there is
+  // no PrefStore for that type.
+  PrefStore* GetPrefStore(PrefStoreType type) {
+    return pref_stores_[type].store();
+  }
+  const PrefStore* GetPrefStore(PrefStoreType type) const {
+    return pref_stores_[type].store();
+  }
+
+  // Keeps the PrefStore references in order of precedence.
+  PrefStoreKeeper pref_stores_[PREF_STORE_TYPE_MAX + 1];
+
+  PrefChangedCallback pref_changed_callback_;
+
+  // Used for generating notifications. This is a weak reference,
+  // since the notifier is owned by the corresponding PrefService.
+  PrefNotifier* pref_notifier_;
+
+  // A mapping of preference names to their registered types.
+  PrefTypeMap pref_types_;
+
+  // True if not all of the PrefStores were initialized successfully.
+  bool initialization_failed_;
+
+  DISALLOW_COPY_AND_ASSIGN(PrefValueStore);
+};
+
+#endif  // BASE_PREFS_PREF_VALUE_STORE_H_
diff --git a/base/prefs/pref_value_store_unittest.cc b/base/prefs/pref_value_store_unittest.cc
new file mode 100644
index 0000000..e214adf
--- /dev/null
+++ b/base/prefs/pref_value_store_unittest.cc
@@ -0,0 +1,670 @@
+// Copyright (c) 2012 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 <string>
+
+#include "base/bind.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/prefs/pref_notifier.h"
+#include "base/prefs/pref_value_store.h"
+#include "base/prefs/testing_pref_store.h"
+#include "base/values.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::Mock;
+using testing::_;
+
+namespace {
+
+// Allows to capture pref notifications through gmock.
+class MockPrefNotifier : public PrefNotifier {
+ public:
+  MOCK_METHOD1(OnPreferenceChanged, void(const std::string&));
+  MOCK_METHOD1(OnInitializationCompleted, void(bool));
+};
+
+// Allows to capture sync model associator interaction.
+class MockPrefModelAssociator {
+ public:
+  MOCK_METHOD1(ProcessPrefChange, void(const std::string&));
+};
+
+}  // namespace
+
+// Names of the preferences used in this test.
+namespace prefs {
+const char kManagedPref[] = "this.pref.managed";
+const char kSupervisedUserPref[] = "this.pref.supervised_user";
+const char kCommandLinePref[] = "this.pref.command_line";
+const char kExtensionPref[] = "this.pref.extension";
+const char kUserPref[] = "this.pref.user";
+const char kRecommendedPref[] = "this.pref.recommended";
+const char kDefaultPref[] = "this.pref.default";
+const char kMissingPref[] = "this.pref.does_not_exist";
+}
+
+// Potentially expected values of all preferences used in this test program.
+namespace managed_pref {
+const char kManagedValue[] = "managed:managed";
+}
+
+namespace supervised_user_pref {
+const char kManagedValue[] = "supervised_user:managed";
+const char kSupervisedUserValue[] = "supervised_user:supervised_user";
+}
+
+namespace extension_pref {
+const char kManagedValue[] = "extension:managed";
+const char kSupervisedUserValue[] = "extension:supervised_user";
+const char kExtensionValue[] = "extension:extension";
+}
+
+namespace command_line_pref {
+const char kManagedValue[] = "command_line:managed";
+const char kSupervisedUserValue[] = "command_line:supervised_user";
+const char kExtensionValue[] = "command_line:extension";
+const char kCommandLineValue[] = "command_line:command_line";
+}
+
+namespace user_pref {
+const char kManagedValue[] = "user:managed";
+const char kSupervisedUserValue[] = "supervised_user:supervised_user";
+const char kExtensionValue[] = "user:extension";
+const char kCommandLineValue[] = "user:command_line";
+const char kUserValue[] = "user:user";
+}
+
+namespace recommended_pref {
+const char kManagedValue[] = "recommended:managed";
+const char kSupervisedUserValue[] = "recommended:supervised_user";
+const char kExtensionValue[] = "recommended:extension";
+const char kCommandLineValue[] = "recommended:command_line";
+const char kUserValue[] = "recommended:user";
+const char kRecommendedValue[] = "recommended:recommended";
+}
+
+namespace default_pref {
+const char kManagedValue[] = "default:managed";
+const char kSupervisedUserValue[] = "default:supervised_user";
+const char kExtensionValue[] = "default:extension";
+const char kCommandLineValue[] = "default:command_line";
+const char kUserValue[] = "default:user";
+const char kRecommendedValue[] = "default:recommended";
+const char kDefaultValue[] = "default:default";
+}
+
+class PrefValueStoreTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    // Create TestingPrefStores.
+    CreateManagedPrefs();
+    CreateSupervisedUserPrefs();
+    CreateExtensionPrefs();
+    CreateCommandLinePrefs();
+    CreateUserPrefs();
+    CreateRecommendedPrefs();
+    CreateDefaultPrefs();
+    sync_associator_.reset(new MockPrefModelAssociator());
+
+    // Create a fresh PrefValueStore.
+    pref_value_store_.reset(
+        new PrefValueStore(managed_pref_store_.get(),
+                           supervised_user_pref_store_.get(),
+                           extension_pref_store_.get(),
+                           command_line_pref_store_.get(),
+                           user_pref_store_.get(),
+                           recommended_pref_store_.get(),
+                           default_pref_store_.get(),
+                           &pref_notifier_));
+
+    pref_value_store_->set_callback(
+        base::Bind(&MockPrefModelAssociator::ProcessPrefChange,
+                   base::Unretained(sync_associator_.get())));
+  }
+
+  void CreateManagedPrefs() {
+    managed_pref_store_ = new TestingPrefStore;
+    managed_pref_store_->SetString(
+        prefs::kManagedPref,
+        managed_pref::kManagedValue);
+  }
+
+  void CreateSupervisedUserPrefs() {
+    supervised_user_pref_store_ = new TestingPrefStore;
+    supervised_user_pref_store_->SetString(
+        prefs::kManagedPref,
+        supervised_user_pref::kManagedValue);
+    supervised_user_pref_store_->SetString(
+        prefs::kSupervisedUserPref,
+        supervised_user_pref::kSupervisedUserValue);
+  }
+
+  void CreateExtensionPrefs() {
+    extension_pref_store_ = new TestingPrefStore;
+    extension_pref_store_->SetString(
+        prefs::kManagedPref,
+        extension_pref::kManagedValue);
+    extension_pref_store_->SetString(
+        prefs::kSupervisedUserPref,
+        extension_pref::kSupervisedUserValue);
+    extension_pref_store_->SetString(
+        prefs::kExtensionPref,
+        extension_pref::kExtensionValue);
+  }
+
+  void CreateCommandLinePrefs() {
+    command_line_pref_store_ = new TestingPrefStore;
+    command_line_pref_store_->SetString(
+        prefs::kManagedPref,
+        command_line_pref::kManagedValue);
+    command_line_pref_store_->SetString(
+        prefs::kSupervisedUserPref,
+        command_line_pref::kSupervisedUserValue);
+    command_line_pref_store_->SetString(
+        prefs::kExtensionPref,
+        command_line_pref::kExtensionValue);
+    command_line_pref_store_->SetString(
+        prefs::kCommandLinePref,
+        command_line_pref::kCommandLineValue);
+  }
+
+  void CreateUserPrefs() {
+    user_pref_store_ = new TestingPrefStore;
+    user_pref_store_->SetString(
+        prefs::kManagedPref,
+        user_pref::kManagedValue);
+    user_pref_store_->SetString(
+        prefs::kSupervisedUserPref,
+        user_pref::kSupervisedUserValue);
+    user_pref_store_->SetString(
+        prefs::kCommandLinePref,
+        user_pref::kCommandLineValue);
+    user_pref_store_->SetString(
+        prefs::kExtensionPref,
+        user_pref::kExtensionValue);
+    user_pref_store_->SetString(
+        prefs::kUserPref,
+        user_pref::kUserValue);
+  }
+
+  void CreateRecommendedPrefs() {
+    recommended_pref_store_ = new TestingPrefStore;
+    recommended_pref_store_->SetString(
+        prefs::kManagedPref,
+        recommended_pref::kManagedValue);
+    recommended_pref_store_->SetString(
+        prefs::kSupervisedUserPref,
+        recommended_pref::kSupervisedUserValue);
+    recommended_pref_store_->SetString(
+        prefs::kCommandLinePref,
+        recommended_pref::kCommandLineValue);
+    recommended_pref_store_->SetString(
+        prefs::kExtensionPref,
+        recommended_pref::kExtensionValue);
+    recommended_pref_store_->SetString(
+        prefs::kUserPref,
+        recommended_pref::kUserValue);
+    recommended_pref_store_->SetString(
+        prefs::kRecommendedPref,
+        recommended_pref::kRecommendedValue);
+  }
+
+  void CreateDefaultPrefs() {
+    default_pref_store_ = new TestingPrefStore;
+    default_pref_store_->SetString(
+        prefs::kSupervisedUserPref,
+        default_pref::kSupervisedUserValue);
+    default_pref_store_->SetString(
+        prefs::kManagedPref,
+        default_pref::kManagedValue);
+    default_pref_store_->SetString(
+        prefs::kCommandLinePref,
+        default_pref::kCommandLineValue);
+    default_pref_store_->SetString(
+        prefs::kExtensionPref,
+        default_pref::kExtensionValue);
+    default_pref_store_->SetString(
+        prefs::kUserPref,
+        default_pref::kUserValue);
+    default_pref_store_->SetString(
+        prefs::kRecommendedPref,
+        default_pref::kRecommendedValue);
+    default_pref_store_->SetString(
+        prefs::kDefaultPref,
+        default_pref::kDefaultValue);
+  }
+
+  void ExpectValueChangeNotifications(const std::string& name) {
+    EXPECT_CALL(pref_notifier_, OnPreferenceChanged(name));
+    EXPECT_CALL(*sync_associator_, ProcessPrefChange(name));
+  }
+
+  void CheckAndClearValueChangeNotifications() {
+    Mock::VerifyAndClearExpectations(&pref_notifier_);
+    Mock::VerifyAndClearExpectations(sync_associator_.get());
+  }
+
+  MockPrefNotifier pref_notifier_;
+  scoped_ptr<MockPrefModelAssociator> sync_associator_;
+  scoped_ptr<PrefValueStore> pref_value_store_;
+
+  scoped_refptr<TestingPrefStore> managed_pref_store_;
+  scoped_refptr<TestingPrefStore> supervised_user_pref_store_;
+  scoped_refptr<TestingPrefStore> extension_pref_store_;
+  scoped_refptr<TestingPrefStore> command_line_pref_store_;
+  scoped_refptr<TestingPrefStore> user_pref_store_;
+  scoped_refptr<TestingPrefStore> recommended_pref_store_;
+  scoped_refptr<TestingPrefStore> default_pref_store_;
+};
+
+TEST_F(PrefValueStoreTest, GetValue) {
+  const base::Value* value;
+
+  // The following tests read a value from the PrefService. The preferences are
+  // set in a way such that all lower-priority stores have a value and we can
+  // test whether overrides work correctly.
+
+  // Test getting a managed value.
+  value = NULL;
+  ASSERT_TRUE(pref_value_store_->GetValue(prefs::kManagedPref,
+                                          base::Value::TYPE_STRING, &value));
+  std::string actual_str_value;
+  EXPECT_TRUE(value->GetAsString(&actual_str_value));
+  EXPECT_EQ(managed_pref::kManagedValue, actual_str_value);
+
+  // Test getting a supervised user value.
+  value = NULL;
+  ASSERT_TRUE(pref_value_store_->GetValue(prefs::kSupervisedUserPref,
+                                          base::Value::TYPE_STRING, &value));
+  EXPECT_TRUE(value->GetAsString(&actual_str_value));
+  EXPECT_EQ(supervised_user_pref::kSupervisedUserValue, actual_str_value);
+
+  // Test getting an extension value.
+  value = NULL;
+  ASSERT_TRUE(pref_value_store_->GetValue(prefs::kExtensionPref,
+                                          base::Value::TYPE_STRING, &value));
+  EXPECT_TRUE(value->GetAsString(&actual_str_value));
+  EXPECT_EQ(extension_pref::kExtensionValue, actual_str_value);
+
+  // Test getting a command-line value.
+  value = NULL;
+  ASSERT_TRUE(pref_value_store_->GetValue(prefs::kCommandLinePref,
+                                          base::Value::TYPE_STRING, &value));
+  EXPECT_TRUE(value->GetAsString(&actual_str_value));
+  EXPECT_EQ(command_line_pref::kCommandLineValue, actual_str_value);
+
+  // Test getting a user-set value.
+  value = NULL;
+  ASSERT_TRUE(pref_value_store_->GetValue(prefs::kUserPref,
+                                          base::Value::TYPE_STRING, &value));
+  EXPECT_TRUE(value->GetAsString(&actual_str_value));
+  EXPECT_EQ(user_pref::kUserValue, actual_str_value);
+
+  // Test getting a user set value overwriting a recommended value.
+  value = NULL;
+  ASSERT_TRUE(pref_value_store_->GetValue(prefs::kRecommendedPref,
+                                          base::Value::TYPE_STRING, &value));
+  EXPECT_TRUE(value->GetAsString(&actual_str_value));
+  EXPECT_EQ(recommended_pref::kRecommendedValue,
+            actual_str_value);
+
+  // Test getting a default value.
+  value = NULL;
+  ASSERT_TRUE(pref_value_store_->GetValue(prefs::kDefaultPref,
+                                          base::Value::TYPE_STRING, &value));
+  EXPECT_TRUE(value->GetAsString(&actual_str_value));
+  EXPECT_EQ(default_pref::kDefaultValue, actual_str_value);
+
+  // Test getting a preference value that the |PrefValueStore|
+  // does not contain.
+  base::FundamentalValue tmp_dummy_value(true);
+  value = &tmp_dummy_value;
+  ASSERT_FALSE(pref_value_store_->GetValue(prefs::kMissingPref,
+                                           base::Value::TYPE_STRING, &value));
+  ASSERT_FALSE(value);
+}
+
+TEST_F(PrefValueStoreTest, GetRecommendedValue) {
+  const base::Value* value;
+
+  // The following tests read a value from the PrefService. The preferences are
+  // set in a way such that all lower-priority stores have a value and we can
+  // test whether overrides do not clutter the recommended value.
+
+  // Test getting recommended value when a managed value is present.
+  value = NULL;
+  ASSERT_TRUE(pref_value_store_->GetRecommendedValue(
+      prefs::kManagedPref,
+      base::Value::TYPE_STRING, &value));
+  std::string actual_str_value;
+  EXPECT_TRUE(value->GetAsString(&actual_str_value));
+  EXPECT_EQ(recommended_pref::kManagedValue, actual_str_value);
+
+  // Test getting recommended value when a supervised user value is present.
+  value = NULL;
+  ASSERT_TRUE(pref_value_store_->GetRecommendedValue(
+      prefs::kSupervisedUserPref,
+      base::Value::TYPE_STRING, &value));
+  EXPECT_TRUE(value->GetAsString(&actual_str_value));
+  EXPECT_EQ(recommended_pref::kSupervisedUserValue, actual_str_value);
+
+  // Test getting recommended value when an extension value is present.
+  value = NULL;
+  ASSERT_TRUE(pref_value_store_->GetRecommendedValue(
+      prefs::kExtensionPref,
+      base::Value::TYPE_STRING, &value));
+  EXPECT_TRUE(value->GetAsString(&actual_str_value));
+  EXPECT_EQ(recommended_pref::kExtensionValue, actual_str_value);
+
+  // Test getting recommended value when a command-line value is present.
+  value = NULL;
+  ASSERT_TRUE(pref_value_store_->GetRecommendedValue(
+      prefs::kCommandLinePref,
+      base::Value::TYPE_STRING, &value));
+  EXPECT_TRUE(value->GetAsString(&actual_str_value));
+  EXPECT_EQ(recommended_pref::kCommandLineValue, actual_str_value);
+
+  // Test getting recommended value when a user-set value is present.
+  value = NULL;
+  ASSERT_TRUE(pref_value_store_->GetRecommendedValue(
+      prefs::kUserPref,
+      base::Value::TYPE_STRING, &value));
+  EXPECT_TRUE(value->GetAsString(&actual_str_value));
+  EXPECT_EQ(recommended_pref::kUserValue, actual_str_value);
+
+  // Test getting recommended value when no higher-priority value is present.
+  value = NULL;
+  ASSERT_TRUE(pref_value_store_->GetRecommendedValue(
+      prefs::kRecommendedPref,
+      base::Value::TYPE_STRING, &value));
+  EXPECT_TRUE(value->GetAsString(&actual_str_value));
+  EXPECT_EQ(recommended_pref::kRecommendedValue,
+            actual_str_value);
+
+  // Test getting recommended value when no recommended value is present.
+  base::FundamentalValue tmp_dummy_value(true);
+  value = &tmp_dummy_value;
+  ASSERT_FALSE(pref_value_store_->GetRecommendedValue(
+      prefs::kDefaultPref,
+      base::Value::TYPE_STRING, &value));
+  ASSERT_FALSE(value);
+
+  // Test getting a preference value that the |PrefValueStore|
+  // does not contain.
+  value = &tmp_dummy_value;
+  ASSERT_FALSE(pref_value_store_->GetRecommendedValue(
+      prefs::kMissingPref,
+      base::Value::TYPE_STRING, &value));
+  ASSERT_FALSE(value);
+}
+
+TEST_F(PrefValueStoreTest, PrefChanges) {
+  // Check pref controlled by highest-priority store.
+  ExpectValueChangeNotifications(prefs::kManagedPref);
+  managed_pref_store_->NotifyPrefValueChanged(prefs::kManagedPref);
+  CheckAndClearValueChangeNotifications();
+
+  ExpectValueChangeNotifications(prefs::kManagedPref);
+  supervised_user_pref_store_->NotifyPrefValueChanged(prefs::kManagedPref);
+  CheckAndClearValueChangeNotifications();
+
+  ExpectValueChangeNotifications(prefs::kManagedPref);
+  extension_pref_store_->NotifyPrefValueChanged(prefs::kManagedPref);
+  CheckAndClearValueChangeNotifications();
+
+  ExpectValueChangeNotifications(prefs::kManagedPref);
+  command_line_pref_store_->NotifyPrefValueChanged(prefs::kManagedPref);
+  CheckAndClearValueChangeNotifications();
+
+  ExpectValueChangeNotifications(prefs::kManagedPref);
+  user_pref_store_->NotifyPrefValueChanged(prefs::kManagedPref);
+  CheckAndClearValueChangeNotifications();
+
+  ExpectValueChangeNotifications(prefs::kManagedPref);
+  recommended_pref_store_->NotifyPrefValueChanged(prefs::kManagedPref);
+  CheckAndClearValueChangeNotifications();
+
+  ExpectValueChangeNotifications(prefs::kManagedPref);
+  default_pref_store_->NotifyPrefValueChanged(prefs::kManagedPref);
+  CheckAndClearValueChangeNotifications();
+
+  // Check pref controlled by user store.
+  ExpectValueChangeNotifications(prefs::kUserPref);
+  managed_pref_store_->NotifyPrefValueChanged(prefs::kUserPref);
+  CheckAndClearValueChangeNotifications();
+
+  ExpectValueChangeNotifications(prefs::kUserPref);
+  extension_pref_store_->NotifyPrefValueChanged(prefs::kUserPref);
+  CheckAndClearValueChangeNotifications();
+
+  ExpectValueChangeNotifications(prefs::kUserPref);
+  command_line_pref_store_->NotifyPrefValueChanged(prefs::kUserPref);
+  CheckAndClearValueChangeNotifications();
+
+  ExpectValueChangeNotifications(prefs::kUserPref);
+  user_pref_store_->NotifyPrefValueChanged(prefs::kUserPref);
+  CheckAndClearValueChangeNotifications();
+
+  ExpectValueChangeNotifications(prefs::kUserPref);
+  recommended_pref_store_->NotifyPrefValueChanged(prefs::kUserPref);
+  CheckAndClearValueChangeNotifications();
+
+  ExpectValueChangeNotifications(prefs::kUserPref);
+  default_pref_store_->NotifyPrefValueChanged(prefs::kUserPref);
+  CheckAndClearValueChangeNotifications();
+
+  // Check pref controlled by default-pref store.
+  ExpectValueChangeNotifications(prefs::kDefaultPref);
+  managed_pref_store_->NotifyPrefValueChanged(prefs::kDefaultPref);
+  CheckAndClearValueChangeNotifications();
+
+  ExpectValueChangeNotifications(prefs::kDefaultPref);
+  extension_pref_store_->NotifyPrefValueChanged(prefs::kDefaultPref);
+  CheckAndClearValueChangeNotifications();
+
+  ExpectValueChangeNotifications(prefs::kDefaultPref);
+  command_line_pref_store_->NotifyPrefValueChanged(prefs::kDefaultPref);
+  CheckAndClearValueChangeNotifications();
+
+  ExpectValueChangeNotifications(prefs::kDefaultPref);
+  user_pref_store_->NotifyPrefValueChanged(prefs::kDefaultPref);
+  CheckAndClearValueChangeNotifications();
+
+  ExpectValueChangeNotifications(prefs::kDefaultPref);
+  recommended_pref_store_->NotifyPrefValueChanged(prefs::kDefaultPref);
+  CheckAndClearValueChangeNotifications();
+
+  ExpectValueChangeNotifications(prefs::kDefaultPref);
+  default_pref_store_->NotifyPrefValueChanged(prefs::kDefaultPref);
+  CheckAndClearValueChangeNotifications();
+}
+
+TEST_F(PrefValueStoreTest, OnInitializationCompleted) {
+  EXPECT_CALL(pref_notifier_, OnInitializationCompleted(true)).Times(0);
+  managed_pref_store_->SetInitializationCompleted();
+  supervised_user_pref_store_->SetInitializationCompleted();
+  extension_pref_store_->SetInitializationCompleted();
+  command_line_pref_store_->SetInitializationCompleted();
+  recommended_pref_store_->SetInitializationCompleted();
+  default_pref_store_->SetInitializationCompleted();
+  Mock::VerifyAndClearExpectations(&pref_notifier_);
+
+  // The notification should only be triggered after the last store is done.
+  EXPECT_CALL(pref_notifier_, OnInitializationCompleted(true)).Times(1);
+  user_pref_store_->SetInitializationCompleted();
+  Mock::VerifyAndClearExpectations(&pref_notifier_);
+}
+
+TEST_F(PrefValueStoreTest, PrefValueInManagedStore) {
+  EXPECT_TRUE(pref_value_store_->PrefValueInManagedStore(
+      prefs::kManagedPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueInManagedStore(
+      prefs::kSupervisedUserPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueInManagedStore(
+      prefs::kExtensionPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueInManagedStore(
+      prefs::kCommandLinePref));
+  EXPECT_FALSE(pref_value_store_->PrefValueInManagedStore(
+      prefs::kUserPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueInManagedStore(
+      prefs::kRecommendedPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueInManagedStore(
+      prefs::kDefaultPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueInManagedStore(
+      prefs::kMissingPref));
+}
+
+TEST_F(PrefValueStoreTest, PrefValueInExtensionStore) {
+  EXPECT_TRUE(pref_value_store_->PrefValueInExtensionStore(
+      prefs::kManagedPref));
+  EXPECT_TRUE(pref_value_store_->PrefValueInExtensionStore(
+      prefs::kSupervisedUserPref));
+  EXPECT_TRUE(pref_value_store_->PrefValueInExtensionStore(
+      prefs::kExtensionPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueInExtensionStore(
+      prefs::kCommandLinePref));
+  EXPECT_FALSE(pref_value_store_->PrefValueInExtensionStore(
+      prefs::kUserPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueInExtensionStore(
+      prefs::kRecommendedPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueInExtensionStore(
+      prefs::kDefaultPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueInExtensionStore(
+      prefs::kMissingPref));
+}
+
+TEST_F(PrefValueStoreTest, PrefValueInUserStore) {
+  EXPECT_TRUE(pref_value_store_->PrefValueInUserStore(
+      prefs::kManagedPref));
+  EXPECT_TRUE(pref_value_store_->PrefValueInUserStore(
+      prefs::kSupervisedUserPref));
+  EXPECT_TRUE(pref_value_store_->PrefValueInUserStore(
+      prefs::kExtensionPref));
+  EXPECT_TRUE(pref_value_store_->PrefValueInUserStore(
+      prefs::kCommandLinePref));
+  EXPECT_TRUE(pref_value_store_->PrefValueInUserStore(
+      prefs::kUserPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueInUserStore(
+      prefs::kRecommendedPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueInUserStore(
+      prefs::kDefaultPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueInUserStore(
+      prefs::kMissingPref));
+}
+
+TEST_F(PrefValueStoreTest, PrefValueFromExtensionStore) {
+  EXPECT_FALSE(pref_value_store_->PrefValueFromExtensionStore(
+      prefs::kManagedPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromExtensionStore(
+      prefs::kSupervisedUserPref));
+  EXPECT_TRUE(pref_value_store_->PrefValueFromExtensionStore(
+      prefs::kExtensionPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromExtensionStore(
+      prefs::kCommandLinePref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromExtensionStore(
+      prefs::kUserPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromExtensionStore(
+      prefs::kRecommendedPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromExtensionStore(
+      prefs::kDefaultPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromExtensionStore(
+      prefs::kMissingPref));
+}
+
+TEST_F(PrefValueStoreTest, PrefValueFromUserStore) {
+  EXPECT_FALSE(pref_value_store_->PrefValueFromUserStore(
+      prefs::kManagedPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromUserStore(
+      prefs::kSupervisedUserPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromUserStore(
+      prefs::kExtensionPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromUserStore(
+      prefs::kCommandLinePref));
+  EXPECT_TRUE(pref_value_store_->PrefValueFromUserStore(
+      prefs::kUserPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromUserStore(
+      prefs::kRecommendedPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromUserStore(
+      prefs::kDefaultPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromUserStore(
+      prefs::kMissingPref));
+}
+
+TEST_F(PrefValueStoreTest, PrefValueFromRecommendedStore) {
+  EXPECT_FALSE(pref_value_store_->PrefValueFromRecommendedStore(
+      prefs::kManagedPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromRecommendedStore(
+      prefs::kSupervisedUserPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromRecommendedStore(
+      prefs::kExtensionPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromRecommendedStore(
+      prefs::kCommandLinePref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromRecommendedStore(
+      prefs::kUserPref));
+  EXPECT_TRUE(pref_value_store_->PrefValueFromRecommendedStore(
+      prefs::kRecommendedPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromRecommendedStore(
+      prefs::kDefaultPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromRecommendedStore(
+      prefs::kMissingPref));
+}
+
+TEST_F(PrefValueStoreTest, PrefValueFromDefaultStore) {
+  EXPECT_FALSE(pref_value_store_->PrefValueFromDefaultStore(
+      prefs::kManagedPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromDefaultStore(
+      prefs::kSupervisedUserPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromDefaultStore(
+      prefs::kExtensionPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromDefaultStore(
+      prefs::kCommandLinePref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromDefaultStore(
+      prefs::kUserPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromDefaultStore(
+      prefs::kRecommendedPref));
+  EXPECT_TRUE(pref_value_store_->PrefValueFromDefaultStore(
+      prefs::kDefaultPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueFromDefaultStore(
+      prefs::kMissingPref));
+}
+
+TEST_F(PrefValueStoreTest, PrefValueUserModifiable) {
+  EXPECT_FALSE(pref_value_store_->PrefValueUserModifiable(
+      prefs::kManagedPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueUserModifiable(
+      prefs::kSupervisedUserPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueUserModifiable(
+      prefs::kExtensionPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueUserModifiable(
+      prefs::kCommandLinePref));
+  EXPECT_TRUE(pref_value_store_->PrefValueUserModifiable(
+      prefs::kUserPref));
+  EXPECT_TRUE(pref_value_store_->PrefValueUserModifiable(
+      prefs::kRecommendedPref));
+  EXPECT_TRUE(pref_value_store_->PrefValueUserModifiable(
+      prefs::kDefaultPref));
+  EXPECT_TRUE(pref_value_store_->PrefValueUserModifiable(
+      prefs::kMissingPref));
+}
+
+TEST_F(PrefValueStoreTest, PrefValueExtensionModifiable) {
+  EXPECT_FALSE(pref_value_store_->PrefValueExtensionModifiable(
+      prefs::kManagedPref));
+  EXPECT_FALSE(pref_value_store_->PrefValueExtensionModifiable(
+      prefs::kSupervisedUserPref));
+  EXPECT_TRUE(pref_value_store_->PrefValueExtensionModifiable(
+      prefs::kExtensionPref));
+  EXPECT_TRUE(pref_value_store_->PrefValueExtensionModifiable(
+      prefs::kCommandLinePref));
+  EXPECT_TRUE(pref_value_store_->PrefValueExtensionModifiable(
+      prefs::kUserPref));
+  EXPECT_TRUE(pref_value_store_->PrefValueExtensionModifiable(
+      prefs::kRecommendedPref));
+  EXPECT_TRUE(pref_value_store_->PrefValueExtensionModifiable(
+      prefs::kDefaultPref));
+  EXPECT_TRUE(pref_value_store_->PrefValueExtensionModifiable(
+      prefs::kMissingPref));
+}
diff --git a/base/prefs/scoped_user_pref_update.cc b/base/prefs/scoped_user_pref_update.cc
new file mode 100644
index 0000000..1440a57
--- /dev/null
+++ b/base/prefs/scoped_user_pref_update.cc
@@ -0,0 +1,37 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/prefs/scoped_user_pref_update.h"
+
+#include "base/logging.h"
+#include "base/prefs/pref_notifier.h"
+#include "base/prefs/pref_service.h"
+
+namespace subtle {
+
+ScopedUserPrefUpdateBase::ScopedUserPrefUpdateBase(PrefService* service,
+                                                   const std::string& path)
+    : service_(service), path_(path), value_(NULL) {
+  DCHECK(service_->CalledOnValidThread());
+}
+
+ScopedUserPrefUpdateBase::~ScopedUserPrefUpdateBase() {
+  Notify();
+}
+
+base::Value* ScopedUserPrefUpdateBase::GetValueOfType(base::Value::Type type) {
+  DCHECK(CalledOnValidThread());
+  if (!value_)
+    value_ = service_->GetMutableUserPref(path_, type);
+  return value_;
+}
+
+void ScopedUserPrefUpdateBase::Notify() {
+  if (value_) {
+    service_->ReportUserPrefChanged(path_);
+    value_ = NULL;
+  }
+}
+
+}  // namespace subtle
diff --git a/base/prefs/scoped_user_pref_update.h b/base/prefs/scoped_user_pref_update.h
new file mode 100644
index 0000000..f8bebfe
--- /dev/null
+++ b/base/prefs/scoped_user_pref_update.h
@@ -0,0 +1,108 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// A helper class that assists preferences in firing notifications when lists
+// or dictionaries are changed.
+
+#ifndef BASE_PREFS_SCOPED_USER_PREF_UPDATE_H_
+#define BASE_PREFS_SCOPED_USER_PREF_UPDATE_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/prefs/base_prefs_export.h"
+#include "base/prefs/pref_service.h"
+#include "base/threading/non_thread_safe.h"
+#include "base/values.h"
+
+class PrefService;
+
+namespace base {
+class DictionaryValue;
+class ListValue;
+}
+
+namespace subtle {
+
+// Base class for ScopedUserPrefUpdateTemplate that contains the parts
+// that do not depend on ScopedUserPrefUpdateTemplate's template parameter.
+//
+// We need this base class mostly for making it a friend of PrefService
+// and getting access to PrefService::GetMutableUserPref and
+// PrefService::ReportUserPrefChanged.
+class BASE_PREFS_EXPORT ScopedUserPrefUpdateBase : public base::NonThreadSafe {
+ protected:
+  ScopedUserPrefUpdateBase(PrefService* service, const std::string& path);
+
+  // Calls Notify().
+  ~ScopedUserPrefUpdateBase();
+
+  // Sets |value_| to |service_|->GetMutableUserPref and returns it.
+  base::Value* GetValueOfType(base::Value::Type type);
+
+ private:
+  // If |value_| is not null, triggers a notification of PrefObservers and
+  // resets |value_|.
+  void Notify();
+
+  // Weak pointer.
+  PrefService* service_;
+  // Path of the preference being updated.
+  std::string path_;
+  // Cache of value from user pref store (set between Get() and Notify() calls).
+  base::Value* value_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedUserPrefUpdateBase);
+};
+
+}  // namespace subtle
+
+// Class to support modifications to DictionaryValues and ListValues while
+// guaranteeing that PrefObservers are notified of changed values.
+//
+// This class may only be used on the UI thread as it requires access to the
+// PrefService.
+template <typename T, base::Value::Type type_enum_value>
+class ScopedUserPrefUpdate : public subtle::ScopedUserPrefUpdateBase {
+ public:
+  ScopedUserPrefUpdate(PrefService* service, const std::string& path)
+      : ScopedUserPrefUpdateBase(service, path) {}
+
+  // Triggers an update notification if Get() was called.
+  virtual ~ScopedUserPrefUpdate() {}
+
+  // Returns a mutable |T| instance that
+  // - is already in the user pref store, or
+  // - is (silently) created and written to the user pref store if none existed
+  //   before.
+  //
+  // Calling Get() implies that an update notification is necessary at
+  // destruction time.
+  //
+  // The ownership of the return value remains with the user pref store.
+  // Virtual so it can be overriden in subclasses that transform the value
+  // before returning it (for example to return a subelement of a dictionary).
+  virtual T* Get() {
+    return static_cast<T*>(GetValueOfType(type_enum_value));
+  }
+
+  T& operator*() {
+    return *Get();
+  }
+
+  T* operator->() {
+    return Get();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ScopedUserPrefUpdate);
+};
+
+typedef ScopedUserPrefUpdate<base::DictionaryValue,
+                             base::Value::TYPE_DICTIONARY>
+    DictionaryPrefUpdate;
+typedef ScopedUserPrefUpdate<base::ListValue, base::Value::TYPE_LIST>
+    ListPrefUpdate;
+
+#endif  // BASE_PREFS_SCOPED_USER_PREF_UPDATE_H_
diff --git a/base/prefs/scoped_user_pref_update_unittest.cc b/base/prefs/scoped_user_pref_update_unittest.cc
new file mode 100644
index 0000000..48e3dc4
--- /dev/null
+++ b/base/prefs/scoped_user_pref_update_unittest.cc
@@ -0,0 +1,81 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/prefs/mock_pref_change_callback.h"
+#include "base/prefs/pref_change_registrar.h"
+#include "base/prefs/pref_registry_simple.h"
+#include "base/prefs/scoped_user_pref_update.h"
+#include "base/prefs/testing_pref_service.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::Mock;
+
+class ScopedUserPrefUpdateTest : public testing::Test {
+ public:
+  ScopedUserPrefUpdateTest() : observer_(&prefs_) {}
+  ~ScopedUserPrefUpdateTest() override {}
+
+ protected:
+  void SetUp() override {
+    prefs_.registry()->RegisterDictionaryPref(kPref);
+    registrar_.Init(&prefs_);
+    registrar_.Add(kPref, observer_.GetCallback());
+  }
+
+  static const char kPref[];
+  static const char kKey[];
+  static const char kValue[];
+
+  TestingPrefServiceSimple prefs_;
+  MockPrefChangeCallback observer_;
+  PrefChangeRegistrar registrar_;
+};
+
+const char ScopedUserPrefUpdateTest::kPref[] = "name";
+const char ScopedUserPrefUpdateTest::kKey[] = "key";
+const char ScopedUserPrefUpdateTest::kValue[] = "value";
+
+TEST_F(ScopedUserPrefUpdateTest, RegularUse) {
+  // Dictionary that will be expected to be set at the end.
+  base::DictionaryValue expected_dictionary;
+  expected_dictionary.SetString(kKey, kValue);
+
+  {
+    EXPECT_CALL(observer_, OnPreferenceChanged(_)).Times(0);
+    DictionaryPrefUpdate update(&prefs_, kPref);
+    base::DictionaryValue* value = update.Get();
+    ASSERT_TRUE(value);
+    value->SetString(kKey, kValue);
+
+    // The dictionary was created for us but the creation should have happened
+    // silently without notifications.
+    Mock::VerifyAndClearExpectations(&observer_);
+
+    // Modifications happen online and are instantly visible, though.
+    const base::DictionaryValue* current_value = prefs_.GetDictionary(kPref);
+    ASSERT_TRUE(current_value);
+    EXPECT_TRUE(expected_dictionary.Equals(current_value));
+
+    // Now we are leaving the scope of the update so we should be notified.
+    observer_.Expect(kPref, &expected_dictionary);
+  }
+  Mock::VerifyAndClearExpectations(&observer_);
+
+  const base::DictionaryValue* current_value = prefs_.GetDictionary(kPref);
+  ASSERT_TRUE(current_value);
+  EXPECT_TRUE(expected_dictionary.Equals(current_value));
+}
+
+TEST_F(ScopedUserPrefUpdateTest, NeverTouchAnything) {
+  const base::DictionaryValue* old_value = prefs_.GetDictionary(kPref);
+  EXPECT_CALL(observer_, OnPreferenceChanged(_)).Times(0);
+  {
+    DictionaryPrefUpdate update(&prefs_, kPref);
+  }
+  const base::DictionaryValue* new_value = prefs_.GetDictionary(kPref);
+  EXPECT_EQ(old_value, new_value);
+  Mock::VerifyAndClearExpectations(&observer_);
+}
diff --git a/base/prefs/testing_pref_service.cc b/base/prefs/testing_pref_service.cc
new file mode 100644
index 0000000..5899376
--- /dev/null
+++ b/base/prefs/testing_pref_service.cc
@@ -0,0 +1,54 @@
+// Copyright (c) 2012 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/prefs/testing_pref_service.h"
+
+#include "base/bind.h"
+#include "base/compiler_specific.h"
+#include "base/prefs/default_pref_store.h"
+#include "base/prefs/pref_notifier_impl.h"
+#include "base/prefs/pref_registry_simple.h"
+#include "base/prefs/pref_value_store.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+template <>
+TestingPrefServiceBase<PrefService, PrefRegistry>::TestingPrefServiceBase(
+    TestingPrefStore* managed_prefs,
+    TestingPrefStore* user_prefs,
+    TestingPrefStore* recommended_prefs,
+    PrefRegistry* pref_registry,
+    PrefNotifierImpl* pref_notifier)
+    : PrefService(
+          pref_notifier,
+          new PrefValueStore(managed_prefs,
+                             NULL,
+                             NULL,
+                             NULL,
+                             user_prefs,
+                             recommended_prefs,
+                             pref_registry->defaults().get(),
+                             pref_notifier),
+          user_prefs,
+          pref_registry,
+          base::Bind(&TestingPrefServiceBase<PrefService,
+                                             PrefRegistry>::HandleReadError),
+          false),
+      managed_prefs_(managed_prefs),
+      user_prefs_(user_prefs),
+      recommended_prefs_(recommended_prefs) {}
+
+TestingPrefServiceSimple::TestingPrefServiceSimple()
+    : TestingPrefServiceBase<PrefService, PrefRegistry>(
+          new TestingPrefStore(),
+          new TestingPrefStore(),
+          new TestingPrefStore(),
+          new PrefRegistrySimple(),
+          new PrefNotifierImpl()) {}
+
+TestingPrefServiceSimple::~TestingPrefServiceSimple() {
+}
+
+PrefRegistrySimple* TestingPrefServiceSimple::registry() {
+  return static_cast<PrefRegistrySimple*>(DeprecatedGetPrefRegistry());
+}
diff --git a/base/prefs/testing_pref_service.h b/base/prefs/testing_pref_service.h
new file mode 100644
index 0000000..7587383
--- /dev/null
+++ b/base/prefs/testing_pref_service.h
@@ -0,0 +1,195 @@
+// Copyright (c) 2012 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_PREFS_TESTING_PREF_SERVICE_H_
+#define BASE_PREFS_TESTING_PREF_SERVICE_H_
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/prefs/pref_registry.h"
+#include "base/prefs/pref_service.h"
+#include "base/prefs/testing_pref_store.h"
+
+class PrefNotifierImpl;
+class PrefRegistrySimple;
+class TestingPrefStore;
+
+// A PrefService subclass for testing. It operates totally in memory and
+// provides additional API for manipulating preferences at the different levels
+// (managed, extension, user) conveniently.
+//
+// Use this via its specializations, e.g. TestingPrefServiceSimple.
+template <class SuperPrefService, class ConstructionPrefRegistry>
+class TestingPrefServiceBase : public SuperPrefService {
+ public:
+  virtual ~TestingPrefServiceBase();
+
+  // Read the value of a preference from the managed layer. Returns NULL if the
+  // preference is not defined at the managed layer.
+  const base::Value* GetManagedPref(const std::string& path) const;
+
+  // Set a preference on the managed layer and fire observers if the preference
+  // changed. Assumes ownership of |value|.
+  void SetManagedPref(const std::string& path, base::Value* value);
+
+  // Clear the preference on the managed layer and fire observers if the
+  // preference has been defined previously.
+  void RemoveManagedPref(const std::string& path);
+
+  // Similar to the above, but for user preferences.
+  const base::Value* GetUserPref(const std::string& path) const;
+  void SetUserPref(const std::string& path, base::Value* value);
+  void RemoveUserPref(const std::string& path);
+
+  // Similar to the above, but for recommended policy preferences.
+  const base::Value* GetRecommendedPref(const std::string& path) const;
+  void SetRecommendedPref(const std::string& path, base::Value* value);
+  void RemoveRecommendedPref(const std::string& path);
+
+  // Do-nothing implementation for TestingPrefService.
+  static void HandleReadError(PersistentPrefStore::PrefReadError error) {}
+
+ protected:
+  TestingPrefServiceBase(
+      TestingPrefStore* managed_prefs,
+      TestingPrefStore* user_prefs,
+      TestingPrefStore* recommended_prefs,
+      ConstructionPrefRegistry* pref_registry,
+      PrefNotifierImpl* pref_notifier);
+
+ private:
+  // Reads the value of the preference indicated by |path| from |pref_store|.
+  // Returns NULL if the preference was not found.
+  const base::Value* GetPref(TestingPrefStore* pref_store,
+                             const std::string& path) const;
+
+  // Sets the value for |path| in |pref_store|.
+  void SetPref(TestingPrefStore* pref_store,
+               const std::string& path,
+               base::Value* value);
+
+  // Removes the preference identified by |path| from |pref_store|.
+  void RemovePref(TestingPrefStore* pref_store, const std::string& path);
+
+  // Pointers to the pref stores our value store uses.
+  scoped_refptr<TestingPrefStore> managed_prefs_;
+  scoped_refptr<TestingPrefStore> user_prefs_;
+  scoped_refptr<TestingPrefStore> recommended_prefs_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestingPrefServiceBase);
+};
+
+// Test version of PrefService.
+class TestingPrefServiceSimple
+    : public TestingPrefServiceBase<PrefService, PrefRegistry> {
+ public:
+  TestingPrefServiceSimple();
+  ~TestingPrefServiceSimple() override;
+
+  // This is provided as a convenience for registering preferences on
+  // an existing TestingPrefServiceSimple instance. On a production
+  // PrefService you would do all registrations before constructing
+  // it, passing it a PrefRegistry via its constructor (or via
+  // e.g. PrefServiceFactory).
+  PrefRegistrySimple* registry();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestingPrefServiceSimple);
+};
+
+template<>
+TestingPrefServiceBase<PrefService, PrefRegistry>::TestingPrefServiceBase(
+    TestingPrefStore* managed_prefs,
+    TestingPrefStore* user_prefs,
+    TestingPrefStore* recommended_prefs,
+    PrefRegistry* pref_registry,
+    PrefNotifierImpl* pref_notifier);
+
+template<class SuperPrefService, class ConstructionPrefRegistry>
+TestingPrefServiceBase<
+    SuperPrefService, ConstructionPrefRegistry>::~TestingPrefServiceBase() {
+}
+
+template <class SuperPrefService, class ConstructionPrefRegistry>
+const base::Value* TestingPrefServiceBase<
+    SuperPrefService,
+    ConstructionPrefRegistry>::GetManagedPref(const std::string& path) const {
+  return GetPref(managed_prefs_.get(), path);
+}
+
+template <class SuperPrefService, class ConstructionPrefRegistry>
+void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::
+    SetManagedPref(const std::string& path, base::Value* value) {
+  SetPref(managed_prefs_.get(), path, value);
+}
+
+template <class SuperPrefService, class ConstructionPrefRegistry>
+void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::
+    RemoveManagedPref(const std::string& path) {
+  RemovePref(managed_prefs_.get(), path);
+}
+
+template <class SuperPrefService, class ConstructionPrefRegistry>
+const base::Value*
+TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::GetUserPref(
+    const std::string& path) const {
+  return GetPref(user_prefs_.get(), path);
+}
+
+template <class SuperPrefService, class ConstructionPrefRegistry>
+void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::
+    SetUserPref(const std::string& path, base::Value* value) {
+  SetPref(user_prefs_.get(), path, value);
+}
+
+template <class SuperPrefService, class ConstructionPrefRegistry>
+void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::
+    RemoveUserPref(const std::string& path) {
+  RemovePref(user_prefs_.get(), path);
+}
+
+template <class SuperPrefService, class ConstructionPrefRegistry>
+const base::Value*
+TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::
+    GetRecommendedPref(const std::string& path) const {
+  return GetPref(recommended_prefs_, path);
+}
+
+template <class SuperPrefService, class ConstructionPrefRegistry>
+void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::
+    SetRecommendedPref(const std::string& path, base::Value* value) {
+  SetPref(recommended_prefs_.get(), path, value);
+}
+
+template <class SuperPrefService, class ConstructionPrefRegistry>
+void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::
+    RemoveRecommendedPref(const std::string& path) {
+  RemovePref(recommended_prefs_.get(), path);
+}
+
+template <class SuperPrefService, class ConstructionPrefRegistry>
+const base::Value*
+TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::GetPref(
+    TestingPrefStore* pref_store,
+    const std::string& path) const {
+  const base::Value* res;
+  return pref_store->GetValue(path, &res) ? res : NULL;
+}
+
+template <class SuperPrefService, class ConstructionPrefRegistry>
+void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::
+    SetPref(TestingPrefStore* pref_store,
+            const std::string& path,
+            base::Value* value) {
+  pref_store->SetValue(path, value,
+                       WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+}
+
+template <class SuperPrefService, class ConstructionPrefRegistry>
+void TestingPrefServiceBase<SuperPrefService, ConstructionPrefRegistry>::
+    RemovePref(TestingPrefStore* pref_store, const std::string& path) {
+  pref_store->RemoveValue(path, WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+}
+
+#endif  // BASE_PREFS_TESTING_PREF_SERVICE_H_
diff --git a/base/prefs/testing_pref_store.cc b/base/prefs/testing_pref_store.cc
new file mode 100644
index 0000000..1a1e6bc
--- /dev/null
+++ b/base/prefs/testing_pref_store.cc
@@ -0,0 +1,176 @@
+// Copyright (c) 2012 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/prefs/testing_pref_store.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "base/values.h"
+
+TestingPrefStore::TestingPrefStore()
+    : read_only_(true),
+      read_success_(true),
+      read_error_(PersistentPrefStore::PREF_READ_ERROR_NONE),
+      block_async_read_(false),
+      pending_async_read_(false),
+      init_complete_(false),
+      committed_(true) {}
+
+bool TestingPrefStore::GetValue(const std::string& key,
+                                const base::Value** value) const {
+  return prefs_.GetValue(key, value);
+}
+
+bool TestingPrefStore::GetMutableValue(const std::string& key,
+                                       base::Value** value) {
+  return prefs_.GetValue(key, value);
+}
+
+void TestingPrefStore::AddObserver(PrefStore::Observer* observer) {
+  observers_.AddObserver(observer);
+}
+
+void TestingPrefStore::RemoveObserver(PrefStore::Observer* observer) {
+  observers_.RemoveObserver(observer);
+}
+
+bool TestingPrefStore::HasObservers() const {
+  return observers_.might_have_observers();
+}
+
+bool TestingPrefStore::IsInitializationComplete() const {
+  return init_complete_;
+}
+
+void TestingPrefStore::SetValue(const std::string& key,
+                                base::Value* value,
+                                uint32 flags) {
+  if (prefs_.SetValue(key, value)) {
+    committed_ = false;
+    NotifyPrefValueChanged(key);
+  }
+}
+
+void TestingPrefStore::SetValueSilently(const std::string& key,
+                                        base::Value* value,
+                                        uint32 flags) {
+  if (prefs_.SetValue(key, value))
+    committed_ = false;
+}
+
+void TestingPrefStore::RemoveValue(const std::string& key, uint32 flags) {
+  if (prefs_.RemoveValue(key)) {
+    committed_ = false;
+    NotifyPrefValueChanged(key);
+  }
+}
+
+bool TestingPrefStore::ReadOnly() const {
+  return read_only_;
+}
+
+PersistentPrefStore::PrefReadError TestingPrefStore::GetReadError() const {
+  return read_error_;
+}
+
+PersistentPrefStore::PrefReadError TestingPrefStore::ReadPrefs() {
+  NotifyInitializationCompleted();
+  return read_error_;
+}
+
+void TestingPrefStore::ReadPrefsAsync(ReadErrorDelegate* error_delegate) {
+  DCHECK(!pending_async_read_);
+  error_delegate_.reset(error_delegate);
+  if (block_async_read_)
+    pending_async_read_ = true;
+  else
+    NotifyInitializationCompleted();
+}
+
+void TestingPrefStore::CommitPendingWrite() { committed_ = true; }
+
+void TestingPrefStore::SchedulePendingLossyWrites() {}
+
+void TestingPrefStore::SetInitializationCompleted() {
+  NotifyInitializationCompleted();
+}
+
+void TestingPrefStore::NotifyPrefValueChanged(const std::string& key) {
+  FOR_EACH_OBSERVER(Observer, observers_, OnPrefValueChanged(key));
+}
+
+void TestingPrefStore::NotifyInitializationCompleted() {
+  DCHECK(!init_complete_);
+  init_complete_ = true;
+  if (read_success_ && read_error_ != PREF_READ_ERROR_NONE && error_delegate_)
+    error_delegate_->OnError(read_error_);
+  FOR_EACH_OBSERVER(
+      Observer, observers_, OnInitializationCompleted(read_success_));
+}
+
+void TestingPrefStore::ReportValueChanged(const std::string& key,
+                                          uint32 flags) {
+  FOR_EACH_OBSERVER(Observer, observers_, OnPrefValueChanged(key));
+}
+
+void TestingPrefStore::SetString(const std::string& key,
+                                 const std::string& value) {
+  SetValue(key, new base::StringValue(value), DEFAULT_PREF_WRITE_FLAGS);
+}
+
+void TestingPrefStore::SetInteger(const std::string& key, int value) {
+  SetValue(key, new base::FundamentalValue(value), DEFAULT_PREF_WRITE_FLAGS);
+}
+
+void TestingPrefStore::SetBoolean(const std::string& key, bool value) {
+  SetValue(key, new base::FundamentalValue(value), DEFAULT_PREF_WRITE_FLAGS);
+}
+
+bool TestingPrefStore::GetString(const std::string& key,
+                                 std::string* value) const {
+  const base::Value* stored_value;
+  if (!prefs_.GetValue(key, &stored_value) || !stored_value)
+    return false;
+
+  return stored_value->GetAsString(value);
+}
+
+bool TestingPrefStore::GetInteger(const std::string& key, int* value) const {
+  const base::Value* stored_value;
+  if (!prefs_.GetValue(key, &stored_value) || !stored_value)
+    return false;
+
+  return stored_value->GetAsInteger(value);
+}
+
+bool TestingPrefStore::GetBoolean(const std::string& key, bool* value) const {
+  const base::Value* stored_value;
+  if (!prefs_.GetValue(key, &stored_value) || !stored_value)
+    return false;
+
+  return stored_value->GetAsBoolean(value);
+}
+
+void TestingPrefStore::SetBlockAsyncRead(bool block_async_read) {
+  DCHECK(!init_complete_);
+  block_async_read_ = block_async_read;
+  if (pending_async_read_ && !block_async_read_)
+    NotifyInitializationCompleted();
+}
+
+void TestingPrefStore::set_read_only(bool read_only) {
+  read_only_ = read_only;
+}
+
+void TestingPrefStore::set_read_success(bool read_success) {
+  DCHECK(!init_complete_);
+  read_success_ = read_success;
+}
+
+void TestingPrefStore::set_read_error(
+    PersistentPrefStore::PrefReadError read_error) {
+  DCHECK(!init_complete_);
+  read_error_ = read_error;
+}
+
+TestingPrefStore::~TestingPrefStore() {}
diff --git a/base/prefs/testing_pref_store.h b/base/prefs/testing_pref_store.h
new file mode 100644
index 0000000..f43a030
--- /dev/null
+++ b/base/prefs/testing_pref_store.h
@@ -0,0 +1,112 @@
+// Copyright (c) 2012 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_PREFS_TESTING_PREF_STORE_H_
+#define BASE_PREFS_TESTING_PREF_STORE_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/observer_list.h"
+#include "base/prefs/persistent_pref_store.h"
+#include "base/prefs/pref_value_map.h"
+
+// |TestingPrefStore| is a preference store implementation that allows tests to
+// explicitly manipulate the contents of the store, triggering notifications
+// where appropriate.
+class TestingPrefStore : public PersistentPrefStore {
+ public:
+  TestingPrefStore();
+
+  // Overriden from PrefStore.
+  bool GetValue(const std::string& key,
+                const base::Value** result) const override;
+  void AddObserver(PrefStore::Observer* observer) override;
+  void RemoveObserver(PrefStore::Observer* observer) override;
+  bool HasObservers() const override;
+  bool IsInitializationComplete() const override;
+
+  // PersistentPrefStore overrides:
+  bool GetMutableValue(const std::string& key, base::Value** result) override;
+  void ReportValueChanged(const std::string& key, uint32 flags) override;
+  void SetValue(const std::string& key,
+                base::Value* value,
+                uint32 flags) override;
+  void SetValueSilently(const std::string& key,
+                        base::Value* value,
+                        uint32 flags) override;
+  void RemoveValue(const std::string& key, uint32 flags) override;
+  bool ReadOnly() const override;
+  PrefReadError GetReadError() const override;
+  PersistentPrefStore::PrefReadError ReadPrefs() override;
+  void ReadPrefsAsync(ReadErrorDelegate* error_delegate) override;
+  void CommitPendingWrite() override;
+  void SchedulePendingLossyWrites() override;
+
+  // Marks the store as having completed initialization.
+  void SetInitializationCompleted();
+
+  // Used for tests to trigger notifications explicitly.
+  void NotifyPrefValueChanged(const std::string& key);
+  void NotifyInitializationCompleted();
+
+  // Some convenience getters/setters.
+  void SetString(const std::string& key, const std::string& value);
+  void SetInteger(const std::string& key, int value);
+  void SetBoolean(const std::string& key, bool value);
+
+  bool GetString(const std::string& key, std::string* value) const;
+  bool GetInteger(const std::string& key, int* value) const;
+  bool GetBoolean(const std::string& key, bool* value) const;
+
+  // Determines whether ReadPrefsAsync completes immediately. Defaults to false
+  // (non-blocking). To block, invoke this with true (blocking) before the call
+  // to ReadPrefsAsync. To unblock, invoke again with false (non-blocking) after
+  // the call to ReadPrefsAsync.
+  void SetBlockAsyncRead(bool block_async_read);
+
+  // Getter and Setter methods for setting and getting the state of the
+  // |TestingPrefStore|.
+  virtual void set_read_only(bool read_only);
+  void set_read_success(bool read_success);
+  void set_read_error(PersistentPrefStore::PrefReadError read_error);
+  bool committed() { return committed_; }
+
+ protected:
+  ~TestingPrefStore() override;
+
+ private:
+  // Stores the preference values.
+  PrefValueMap prefs_;
+
+  // Flag that indicates if the PrefStore is read-only
+  bool read_only_;
+
+  // The result to pass to PrefStore::Observer::OnInitializationCompleted
+  bool read_success_;
+
+  // The result to return from ReadPrefs or ReadPrefsAsync.
+  PersistentPrefStore::PrefReadError read_error_;
+
+  // Whether a call to ReadPrefsAsync should block.
+  bool block_async_read_;
+
+  // Whether there is a pending call to ReadPrefsAsync.
+  bool pending_async_read_;
+
+  // Whether initialization has been completed.
+  bool init_complete_;
+
+  // Whether the store contents have been committed to disk since the last
+  // mutation.
+  bool committed_;
+
+  scoped_ptr<ReadErrorDelegate> error_delegate_;
+  base::ObserverList<PrefStore::Observer, true> observers_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestingPrefStore);
+};
+
+#endif  // BASE_PREFS_TESTING_PREF_STORE_H_
diff --git a/base/prefs/value_map_pref_store.cc b/base/prefs/value_map_pref_store.cc
new file mode 100644
index 0000000..d850150
--- /dev/null
+++ b/base/prefs/value_map_pref_store.cc
@@ -0,0 +1,63 @@
+// Copyright (c) 2012 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/prefs/value_map_pref_store.h"
+
+#include <algorithm>
+
+#include "base/stl_util.h"
+#include "base/values.h"
+
+ValueMapPrefStore::ValueMapPrefStore() {}
+
+bool ValueMapPrefStore::GetValue(const std::string& key,
+                                 const base::Value** value) const {
+  return prefs_.GetValue(key, value);
+}
+
+void ValueMapPrefStore::AddObserver(PrefStore::Observer* observer) {
+  observers_.AddObserver(observer);
+}
+
+void ValueMapPrefStore::RemoveObserver(PrefStore::Observer* observer) {
+  observers_.RemoveObserver(observer);
+}
+
+bool ValueMapPrefStore::HasObservers() const {
+  return observers_.might_have_observers();
+}
+
+void ValueMapPrefStore::SetValue(const std::string& key,
+                                 base::Value* value,
+                                 uint32 flags) {
+  if (prefs_.SetValue(key, value))
+    FOR_EACH_OBSERVER(Observer, observers_, OnPrefValueChanged(key));
+}
+
+void ValueMapPrefStore::RemoveValue(const std::string& key, uint32 flags) {
+  if (prefs_.RemoveValue(key))
+    FOR_EACH_OBSERVER(Observer, observers_, OnPrefValueChanged(key));
+}
+
+bool ValueMapPrefStore::GetMutableValue(const std::string& key,
+                                        base::Value** value) {
+  return prefs_.GetValue(key, value);
+}
+
+void ValueMapPrefStore::ReportValueChanged(const std::string& key,
+                                           uint32 flags) {
+  FOR_EACH_OBSERVER(Observer, observers_, OnPrefValueChanged(key));
+}
+
+void ValueMapPrefStore::SetValueSilently(const std::string& key,
+                                         base::Value* value,
+                                         uint32 flags) {
+  prefs_.SetValue(key, value);
+}
+
+ValueMapPrefStore::~ValueMapPrefStore() {}
+
+void ValueMapPrefStore::NotifyInitializationCompleted() {
+  FOR_EACH_OBSERVER(Observer, observers_, OnInitializationCompleted(true));
+}
diff --git a/base/prefs/value_map_pref_store.h b/base/prefs/value_map_pref_store.h
new file mode 100644
index 0000000..9d8fa3e
--- /dev/null
+++ b/base/prefs/value_map_pref_store.h
@@ -0,0 +1,55 @@
+// Copyright (c) 2012 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_PREFS_VALUE_MAP_PREF_STORE_H_
+#define BASE_PREFS_VALUE_MAP_PREF_STORE_H_
+
+#include <map>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/observer_list.h"
+#include "base/prefs/base_prefs_export.h"
+#include "base/prefs/pref_value_map.h"
+#include "base/prefs/writeable_pref_store.h"
+
+// A basic PrefStore implementation that uses a simple name-value map for
+// storing the preference values.
+class BASE_PREFS_EXPORT ValueMapPrefStore : public WriteablePrefStore {
+ public:
+  ValueMapPrefStore();
+
+  // PrefStore overrides:
+  bool GetValue(const std::string& key,
+                const base::Value** value) const override;
+  void AddObserver(PrefStore::Observer* observer) override;
+  void RemoveObserver(PrefStore::Observer* observer) override;
+  bool HasObservers() const override;
+
+  // WriteablePrefStore overrides:
+  void SetValue(const std::string& key,
+                base::Value* value,
+                uint32 flags) override;
+  void RemoveValue(const std::string& key, uint32 flags) override;
+  bool GetMutableValue(const std::string& key, base::Value** value) override;
+  void ReportValueChanged(const std::string& key, uint32 flags) override;
+  void SetValueSilently(const std::string& key,
+                        base::Value* value,
+                        uint32 flags) override;
+
+ protected:
+  ~ValueMapPrefStore() override;
+
+  // Notify observers about the initialization completed event.
+  void NotifyInitializationCompleted();
+
+ private:
+  PrefValueMap prefs_;
+
+  base::ObserverList<PrefStore::Observer, true> observers_;
+
+  DISALLOW_COPY_AND_ASSIGN(ValueMapPrefStore);
+};
+
+#endif  // BASE_PREFS_VALUE_MAP_PREF_STORE_H_
diff --git a/base/prefs/writeable_pref_store.h b/base/prefs/writeable_pref_store.h
new file mode 100644
index 0000000..d85b4c8
--- /dev/null
+++ b/base/prefs/writeable_pref_store.h
@@ -0,0 +1,69 @@
+// 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.
+
+#ifndef BASE_PREFS_WRITEABLE_PREF_STORE_H_
+#define BASE_PREFS_WRITEABLE_PREF_STORE_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/prefs/pref_store.h"
+
+namespace base {
+class Value;
+}
+
+// A pref store that can be written to as well as read from.
+class BASE_PREFS_EXPORT WriteablePrefStore : public PrefStore {
+ public:
+  // PrefWriteFlags can be used to change the way a pref will be written to
+  // storage.
+  enum PrefWriteFlags : uint32 {
+    // No flags are specified.
+    DEFAULT_PREF_WRITE_FLAGS = 0,
+
+    // This marks the pref as "lossy". There is no strict time guarantee on when
+    // a lossy pref will be persisted to permanent storage when it is modified.
+    LOSSY_PREF_WRITE_FLAG = 1 << 1
+  };
+
+  WriteablePrefStore() {}
+
+  // Sets a |value| for |key| in the store. Assumes ownership of |value|, which
+  // must be non-NULL. |flags| is a bitmask of PrefWriteFlags.
+  virtual void SetValue(const std::string& key,
+                        base::Value* value,
+                        uint32 flags) = 0;
+
+  // Removes the value for |key|.
+  virtual void RemoveValue(const std::string& key, uint32 flags) = 0;
+
+  // Equivalent to PrefStore::GetValue but returns a mutable value.
+  virtual bool GetMutableValue(const std::string& key,
+                               base::Value** result) = 0;
+
+  // Triggers a value changed notification. This function needs to be called
+  // if one retrieves a list or dictionary with GetMutableValue and change its
+  // value. SetValue takes care of notifications itself. Note that
+  // ReportValueChanged will trigger notifications even if nothing has changed.
+  // |flags| is a bitmask of PrefWriteFlags.
+  virtual void ReportValueChanged(const std::string& key, uint32 flags) = 0;
+
+  // Same as SetValue, but doesn't generate notifications. This is used by
+  // PrefService::GetMutableUserPref() in order to put empty entries
+  // into the user pref store. Using SetValue is not an option since existing
+  // tests rely on the number of notifications generated. |flags| is a bitmask
+  // of PrefWriteFlags.
+  virtual void SetValueSilently(const std::string& key,
+                                base::Value* value,
+                                uint32 flags) = 0;
+
+ protected:
+  ~WriteablePrefStore() override {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(WriteablePrefStore);
+};
+
+#endif  // BASE_PREFS_WRITEABLE_PREF_STORE_H_
diff --git a/base/process/BUILD.gn b/base/process/BUILD.gn
new file mode 100644
index 0000000..814459b
--- /dev/null
+++ b/base/process/BUILD.gn
@@ -0,0 +1,108 @@
+# Copyright (c) 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("process") {
+  sources = [
+    "internal_linux.cc",
+    "internal_linux.h",
+    "kill.cc",
+    "kill.h",
+    "kill_mac.cc",
+    "kill_posix.cc",
+    "kill_win.cc",
+    "launch.cc",
+    "launch.h",
+    "launch_ios.cc",
+    "launch_mac.cc",
+    "launch_posix.cc",
+    "launch_win.cc",
+    "memory.cc",
+    "memory.h",
+    "memory_linux.cc",
+    "memory_mac.mm",
+    "memory_win.cc",
+    "process.h",
+    "process_handle_freebsd.cc",
+    "process_handle_linux.cc",
+    "process_handle_mac.cc",
+    "process_handle_openbsd.cc",
+    "process_handle_posix.cc",
+    "process_handle_win.cc",
+    "process_info.h",
+    "process_info_linux.cc",
+    "process_info_mac.cc",
+    "process_info_win.cc",
+    "process_iterator.cc",
+    "process_iterator.h",
+    "process_iterator_freebsd.cc",
+    "process_iterator_linux.cc",
+    "process_iterator_mac.cc",
+    "process_iterator_openbsd.cc",
+    "process_iterator_win.cc",
+    "process_linux.cc",
+    "process_mac.cc",
+    "process_metrics.cc",
+    "process_metrics.h",
+    "process_metrics_freebsd.cc",
+    "process_metrics_ios.cc",
+    "process_metrics_linux.cc",
+    "process_metrics_mac.cc",
+    "process_metrics_openbsd.cc",
+    "process_metrics_posix.cc",
+    "process_metrics_win.cc",
+    "process_posix.cc",
+    "process_win.cc",
+  ]
+
+  sources -= [
+    "process_handle_freebsd.cc",
+    "process_handle_openbsd.cc",
+    "process_iterator_freebsd.cc",
+    "process_iterator_openbsd.cc",
+    "process_metrics_freebsd.cc",
+    "process_metrics_openbsd.cc",
+  ]
+
+  if (is_android) {
+    # Android uses some Linux sources, put those back.
+    set_sources_assignment_filter([])
+    sources += [
+      "internal_linux.cc",
+      "memory_linux.cc",
+      "process_handle_linux.cc",
+      "process_iterator_linux.cc",
+      "process_metrics_linux.cc",
+    ]
+    set_sources_assignment_filter(sources_assignment_filter)
+  }
+
+  if (is_nacl) {
+    sources -= [
+      "kill.cc",
+      "kill.h",
+      "kill_posix.cc",
+      "launch.cc",
+      "launch.h",
+      "launch_posix.cc",
+      "memory.cc",
+      "memory.h",
+      "process_iterator.cc",
+      "process_iterator.h",
+      "process_metrics.cc",
+      "process_metrics_posix.cc",
+      "process_posix.cc",
+    ]
+  }
+
+  configs += [ "//base:base_implementation" ]
+
+  deps = [
+    "//base/memory",
+    "//base/third_party/dynamic_annotations",
+  ]
+
+  allow_circular_includes_from = [ "//base/memory" ]
+
+  visibility = [ "//base/*" ]
+}
diff --git a/base/process/internal_linux.cc b/base/process/internal_linux.cc
new file mode 100644
index 0000000..d2e9ec5
--- /dev/null
+++ b/base/process/internal_linux.cc
@@ -0,0 +1,187 @@
+// Copyright (c) 2012 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/process/internal_linux.h"
+
+#include <unistd.h>
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/time/time.h"
+
+namespace base {
+namespace internal {
+
+const char kProcDir[] = "/proc";
+
+const char kStatFile[] = "stat";
+
+base::FilePath GetProcPidDir(pid_t pid) {
+  return base::FilePath(kProcDir).Append(IntToString(pid));
+}
+
+pid_t ProcDirSlotToPid(const char* d_name) {
+  int i;
+  for (i = 0; i < NAME_MAX && d_name[i]; ++i) {
+    if (!IsAsciiDigit(d_name[i])) {
+      return 0;
+    }
+  }
+  if (i == NAME_MAX)
+    return 0;
+
+  // Read the process's command line.
+  pid_t pid;
+  std::string pid_string(d_name);
+  if (!StringToInt(pid_string, &pid)) {
+    NOTREACHED();
+    return 0;
+  }
+  return pid;
+}
+
+bool ReadProcFile(const FilePath& file, std::string* buffer) {
+  buffer->clear();
+  // Synchronously reading files in /proc is safe.
+  ThreadRestrictions::ScopedAllowIO allow_io;
+
+  if (!ReadFileToString(file, buffer)) {
+    DLOG(WARNING) << "Failed to read " << file.MaybeAsASCII();
+    return false;
+  }
+  return !buffer->empty();
+}
+
+bool ReadProcStats(pid_t pid, std::string* buffer) {
+  FilePath stat_file = internal::GetProcPidDir(pid).Append(kStatFile);
+  return ReadProcFile(stat_file, buffer);
+}
+
+bool ParseProcStats(const std::string& stats_data,
+                    std::vector<std::string>* proc_stats) {
+  // |stats_data| may be empty if the process disappeared somehow.
+  // e.g. http://crbug.com/145811
+  if (stats_data.empty())
+    return false;
+
+  // The stat file is formatted as:
+  // pid (process name) data1 data2 .... dataN
+  // Look for the closing paren by scanning backwards, to avoid being fooled by
+  // processes with ')' in the name.
+  size_t open_parens_idx = stats_data.find(" (");
+  size_t close_parens_idx = stats_data.rfind(") ");
+  if (open_parens_idx == std::string::npos ||
+      close_parens_idx == std::string::npos ||
+      open_parens_idx > close_parens_idx) {
+    DLOG(WARNING) << "Failed to find matched parens in '" << stats_data << "'";
+    NOTREACHED();
+    return false;
+  }
+  open_parens_idx++;
+
+  proc_stats->clear();
+  // PID.
+  proc_stats->push_back(stats_data.substr(0, open_parens_idx));
+  // Process name without parentheses.
+  proc_stats->push_back(
+      stats_data.substr(open_parens_idx + 1,
+                        close_parens_idx - (open_parens_idx + 1)));
+
+  // Split the rest.
+  std::vector<std::string> other_stats;
+  SplitString(stats_data.substr(close_parens_idx + 2), ' ', &other_stats);
+  for (size_t i = 0; i < other_stats.size(); ++i)
+    proc_stats->push_back(other_stats[i]);
+  return true;
+}
+
+typedef std::map<std::string, std::string> ProcStatMap;
+void ParseProcStat(const std::string& contents, ProcStatMap* output) {
+  base::StringPairs key_value_pairs;
+  SplitStringIntoKeyValuePairs(contents, ' ', '\n', &key_value_pairs);
+  for (size_t i = 0; i < key_value_pairs.size(); ++i) {
+    output->insert(key_value_pairs[i]);
+  }
+}
+
+int64 GetProcStatsFieldAsInt64(const std::vector<std::string>& proc_stats,
+                               ProcStatsFields field_num) {
+  DCHECK_GE(field_num, VM_PPID);
+  CHECK_LT(static_cast<size_t>(field_num), proc_stats.size());
+
+  int64 value;
+  return StringToInt64(proc_stats[field_num], &value) ? value : 0;
+}
+
+size_t GetProcStatsFieldAsSizeT(const std::vector<std::string>& proc_stats,
+                                ProcStatsFields field_num) {
+  DCHECK_GE(field_num, VM_PPID);
+  CHECK_LT(static_cast<size_t>(field_num), proc_stats.size());
+
+  size_t value;
+  return StringToSizeT(proc_stats[field_num], &value) ? value : 0;
+}
+
+int64 ReadProcStatsAndGetFieldAsInt64(pid_t pid, ProcStatsFields field_num) {
+  std::string stats_data;
+  if (!ReadProcStats(pid, &stats_data))
+    return 0;
+  std::vector<std::string> proc_stats;
+  if (!ParseProcStats(stats_data, &proc_stats))
+    return 0;
+  return GetProcStatsFieldAsInt64(proc_stats, field_num);
+}
+
+size_t ReadProcStatsAndGetFieldAsSizeT(pid_t pid,
+                                       ProcStatsFields field_num) {
+  std::string stats_data;
+  if (!ReadProcStats(pid, &stats_data))
+    return 0;
+  std::vector<std::string> proc_stats;
+  if (!ParseProcStats(stats_data, &proc_stats))
+    return 0;
+  return GetProcStatsFieldAsSizeT(proc_stats, field_num);
+}
+
+Time GetBootTime() {
+  FilePath path("/proc/stat");
+  std::string contents;
+  if (!ReadProcFile(path, &contents))
+    return Time();
+  ProcStatMap proc_stat;
+  ParseProcStat(contents, &proc_stat);
+  ProcStatMap::const_iterator btime_it = proc_stat.find("btime");
+  if (btime_it == proc_stat.end())
+    return Time();
+  int btime;
+  if (!StringToInt(btime_it->second, &btime))
+    return Time();
+  return Time::FromTimeT(btime);
+}
+
+TimeDelta ClockTicksToTimeDelta(int clock_ticks) {
+  // This queries the /proc-specific scaling factor which is
+  // conceptually the system hertz.  To dump this value on another
+  // system, try
+  //   od -t dL /proc/self/auxv
+  // and look for the number after 17 in the output; mine is
+  //   0000040          17         100           3   134512692
+  // which means the answer is 100.
+  // It may be the case that this value is always 100.
+  static const int kHertz = sysconf(_SC_CLK_TCK);
+
+  return TimeDelta::FromMicroseconds(
+      Time::kMicrosecondsPerSecond * clock_ticks / kHertz);
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/process/internal_linux.h b/base/process/internal_linux.h
new file mode 100644
index 0000000..1837f94
--- /dev/null
+++ b/base/process/internal_linux.h
@@ -0,0 +1,90 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains internal routines that are called by other files in
+// base/process/.
+
+#ifndef BASE_PROCESS_INTERNAL_LINUX_H_
+#define BASE_PROCESS_INTERNAL_LINUX_H_
+
+#include <unistd.h>
+
+#include "base/files/file_path.h"
+
+namespace base {
+
+class Time;
+class TimeDelta;
+
+namespace internal {
+
+// "/proc"
+extern const char kProcDir[];
+
+// "stat"
+extern const char kStatFile[];
+
+// Returns a FilePath to "/proc/pid".
+base::FilePath GetProcPidDir(pid_t pid);
+
+// Take a /proc directory entry named |d_name|, and if it is the directory for
+// a process, convert it to a pid_t.
+// Returns 0 on failure.
+// e.g. /proc/self/ will return 0, whereas /proc/1234 will return 1234.
+pid_t ProcDirSlotToPid(const char* d_name);
+
+// Reads /proc/<pid>/stat into |buffer|. Returns true if the file can be read
+// and is non-empty.
+bool ReadProcStats(pid_t pid, std::string* buffer);
+
+// Takes |stats_data| and populates |proc_stats| with the values split by
+// spaces. Taking into account the 2nd field may, in itself, contain spaces.
+// Returns true if successful.
+bool ParseProcStats(const std::string& stats_data,
+                    std::vector<std::string>* proc_stats);
+
+// Fields from /proc/<pid>/stat, 0-based. See man 5 proc.
+// If the ordering ever changes, carefully review functions that use these
+// values.
+enum ProcStatsFields {
+  VM_COMM           = 1,   // Filename of executable, without parentheses.
+  VM_STATE          = 2,   // Letter indicating the state of the process.
+  VM_PPID           = 3,   // PID of the parent.
+  VM_PGRP           = 4,   // Process group id.
+  VM_UTIME          = 13,  // Time scheduled in user mode in clock ticks.
+  VM_STIME          = 14,  // Time scheduled in kernel mode in clock ticks.
+  VM_NUMTHREADS     = 19,  // Number of threads.
+  VM_STARTTIME      = 21,  // The time the process started in clock ticks.
+  VM_VSIZE          = 22,  // Virtual memory size in bytes.
+  VM_RSS            = 23,  // Resident Set Size in pages.
+};
+
+// Reads the |field_num|th field from |proc_stats|. Returns 0 on failure.
+// This version does not handle the first 3 values, since the first value is
+// simply |pid|, and the next two values are strings.
+int64 GetProcStatsFieldAsInt64(const std::vector<std::string>& proc_stats,
+                               ProcStatsFields field_num);
+
+// Same as GetProcStatsFieldAsInt64(), but for size_t values.
+size_t GetProcStatsFieldAsSizeT(const std::vector<std::string>& proc_stats,
+                                ProcStatsFields field_num);
+
+// Convenience wrapper around GetProcStatsFieldAsInt64(), ParseProcStats() and
+// ReadProcStats(). See GetProcStatsFieldAsInt64() for details.
+int64 ReadProcStatsAndGetFieldAsInt64(pid_t pid, ProcStatsFields field_num);
+
+// Same as ReadProcStatsAndGetFieldAsInt64() but for size_t values.
+size_t ReadProcStatsAndGetFieldAsSizeT(pid_t pid,
+                                       ProcStatsFields field_num);
+
+// Returns the time that the OS started. Clock ticks are relative to this.
+Time GetBootTime();
+
+// Converts Linux clock ticks to a wall time delta.
+TimeDelta ClockTicksToTimeDelta(int clock_ticks);
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_PROCESS_INTERNAL_LINUX_H_
diff --git a/base/process/kill.cc b/base/process/kill.cc
new file mode 100644
index 0000000..5d8ba6a
--- /dev/null
+++ b/base/process/kill.cc
@@ -0,0 +1,23 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/kill.h"
+
+#include "base/process/process_iterator.h"
+
+namespace base {
+
+bool KillProcesses(const FilePath::StringType& executable_name,
+                   int exit_code,
+                   const ProcessFilter* filter) {
+  bool result = true;
+  NamedProcessIterator iter(executable_name, filter);
+  while (const ProcessEntry* entry = iter.NextProcessEntry()) {
+    Process process = Process::Open(entry->pid());
+    result &= process.Terminate(exit_code, true);
+  }
+  return result;
+}
+
+}  // namespace base
diff --git a/base/process/kill.h b/base/process/kill.h
new file mode 100644
index 0000000..dbd32e1
--- /dev/null
+++ b/base/process/kill.h
@@ -0,0 +1,133 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains routines to kill processes and get the exit code and
+// termination status.
+
+#ifndef BASE_PROCESS_KILL_H_
+#define BASE_PROCESS_KILL_H_
+
+#include "base/files/file_path.h"
+#include "base/process/process.h"
+#include "base/process/process_handle.h"
+#include "base/time/time.h"
+
+namespace base {
+
+class ProcessFilter;
+
+// Return status values from GetTerminationStatus.  Don't use these as
+// exit code arguments to KillProcess*(), use platform/application
+// specific values instead.
+enum TerminationStatus {
+  TERMINATION_STATUS_NORMAL_TERMINATION,   // zero exit status
+  TERMINATION_STATUS_ABNORMAL_TERMINATION, // non-zero exit status
+  TERMINATION_STATUS_PROCESS_WAS_KILLED,   // e.g. SIGKILL or task manager kill
+  TERMINATION_STATUS_PROCESS_CRASHED,      // e.g. Segmentation fault
+  TERMINATION_STATUS_STILL_RUNNING,        // child hasn't exited yet
+#if defined(OS_CHROMEOS)
+  // Used for the case when oom-killer kills a process on ChromeOS.
+  TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM,
+#endif
+#if defined(OS_ANDROID)
+  // On Android processes are spawned from the system Zygote and we do not get
+  // the termination status.  We can't know if the termination was a crash or an
+  // oom kill for sure, but we can use status of the strong process bindings as
+  // a hint.
+  TERMINATION_STATUS_OOM_PROTECTED,        // child was protected from oom kill
+#endif
+  TERMINATION_STATUS_MAX_ENUM
+};
+
+// Attempts to kill all the processes on the current machine that were launched
+// from the given executable name, ending them with the given exit code.  If
+// filter is non-null, then only processes selected by the filter are killed.
+// Returns true if all processes were able to be killed off, false if at least
+// one couldn't be killed.
+BASE_EXPORT bool KillProcesses(const FilePath::StringType& executable_name,
+                               int exit_code,
+                               const ProcessFilter* filter);
+
+#if defined(OS_POSIX)
+// Attempts to kill the process group identified by |process_group_id|. Returns
+// true on success.
+BASE_EXPORT bool KillProcessGroup(ProcessHandle process_group_id);
+#endif  // defined(OS_POSIX)
+
+// Get the termination status of the process by interpreting the
+// circumstances of the child process' death. |exit_code| is set to
+// the status returned by waitpid() on POSIX, and from
+// GetExitCodeProcess() on Windows.  |exit_code| may be NULL if the
+// caller is not interested in it.  Note that on Linux, this function
+// will only return a useful result the first time it is called after
+// the child exits (because it will reap the child and the information
+// will no longer be available).
+BASE_EXPORT TerminationStatus GetTerminationStatus(ProcessHandle handle,
+                                                   int* exit_code);
+
+#if defined(OS_POSIX)
+// Send a kill signal to the process and then wait for the process to exit
+// and get the termination status.
+//
+// This is used in situations where it is believed that the process is dead
+// or dying (because communication with the child process has been cut).
+// In order to avoid erroneously returning that the process is still running
+// because the kernel is still cleaning it up, this will wait for the process
+// to terminate. In order to avoid the risk of hanging while waiting for the
+// process to terminate, send a SIGKILL to the process before waiting for the
+// termination status.
+//
+// Note that it is not an option to call WaitForExitCode and then
+// GetTerminationStatus as the child will be reaped when WaitForExitCode
+// returns, and this information will be lost.
+//
+BASE_EXPORT TerminationStatus GetKnownDeadTerminationStatus(
+    ProcessHandle handle, int* exit_code);
+#endif  // defined(OS_POSIX)
+
+// Wait for all the processes based on the named executable to exit.  If filter
+// is non-null, then only processes selected by the filter are waited on.
+// Returns after all processes have exited or wait_milliseconds have expired.
+// Returns true if all the processes exited, false otherwise.
+BASE_EXPORT bool WaitForProcessesToExit(
+    const FilePath::StringType& executable_name,
+    base::TimeDelta wait,
+    const ProcessFilter* filter);
+
+// Waits a certain amount of time (can be 0) for all the processes with a given
+// executable name to exit, then kills off any of them that are still around.
+// If filter is non-null, then only processes selected by the filter are waited
+// on.  Killed processes are ended with the given exit code.  Returns false if
+// any processes needed to be killed, true if they all exited cleanly within
+// the wait_milliseconds delay.
+BASE_EXPORT bool CleanupProcesses(const FilePath::StringType& executable_name,
+                                  base::TimeDelta wait,
+                                  int exit_code,
+                                  const ProcessFilter* filter);
+
+// This method ensures that the specified process eventually terminates, and
+// then it closes the given process handle.
+//
+// It assumes that the process has already been signalled to exit, and it
+// begins by waiting a small amount of time for it to exit.  If the process
+// does not appear to have exited, then this function starts to become
+// aggressive about ensuring that the process terminates.
+//
+// On Linux this method does not block the calling thread.
+// On OS X this method may block for up to 2 seconds.
+//
+// NOTE: The process must have been opened with the PROCESS_TERMINATE and
+// SYNCHRONIZE permissions.
+//
+BASE_EXPORT void EnsureProcessTerminated(Process process);
+
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
+// The nicer version of EnsureProcessTerminated() that is patient and will
+// wait for |pid| to finish and then reap it.
+BASE_EXPORT void EnsureProcessGetsReaped(ProcessId pid);
+#endif
+
+}  // namespace base
+
+#endif  // BASE_PROCESS_KILL_H_
diff --git a/base/process/kill_mac.cc b/base/process/kill_mac.cc
new file mode 100644
index 0000000..a4e0a14
--- /dev/null
+++ b/base/process/kill_mac.cc
@@ -0,0 +1,172 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/kill.h"
+
+#include <signal.h>
+#include <sys/event.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+
+namespace base {
+
+namespace {
+
+const int kWaitBeforeKillSeconds = 2;
+
+// Reap |child| process. This call blocks until completion.
+void BlockingReap(pid_t child) {
+  const pid_t result = HANDLE_EINTR(waitpid(child, NULL, 0));
+  if (result == -1) {
+    DPLOG(ERROR) << "waitpid(" << child << ", NULL, 0)";
+  }
+}
+
+// Waits for |timeout| seconds for the given |child| to exit and reap it. If
+// the child doesn't exit within the time specified, kills it.
+//
+// This function takes two approaches: first, it tries to use kqueue to
+// observe when the process exits. kevent can monitor a kqueue with a
+// timeout, so this method is preferred to wait for a specified period of
+// time. Once the kqueue indicates the process has exited, waitpid will reap
+// the exited child. If the kqueue doesn't provide an exit event notification,
+// before the timeout expires, or if the kqueue fails or misbehaves, the
+// process will be mercilessly killed and reaped.
+//
+// A child process passed to this function may be in one of several states:
+// running, terminated and not yet reaped, and (apparently, and unfortunately)
+// terminated and already reaped. Normally, a process will at least have been
+// asked to exit before this function is called, but this is not required.
+// If a process is terminating and unreaped, there may be a window between the
+// time that kqueue will no longer recognize it and when it becomes an actual
+// zombie that a non-blocking (WNOHANG) waitpid can reap. This condition is
+// detected when kqueue indicates that the process is not running and a
+// non-blocking waitpid fails to reap the process but indicates that it is
+// still running. In this event, a blocking attempt to reap the process
+// collects the known-dying child, preventing zombies from congregating.
+//
+// In the event that the kqueue misbehaves entirely, as it might under a
+// EMFILE condition ("too many open files", or out of file descriptors), this
+// function will forcibly kill and reap the child without delay. This
+// eliminates another potential zombie vector. (If you're out of file
+// descriptors, you're probably deep into something else, but that doesn't
+// mean that zombies be allowed to kick you while you're down.)
+//
+// The fact that this function seemingly can be called to wait on a child
+// that's not only already terminated but already reaped is a bit of a
+// problem: a reaped child's pid can be reclaimed and may refer to a distinct
+// process in that case. The fact that this function can seemingly be called
+// to wait on a process that's not even a child is also a problem: kqueue will
+// work in that case, but waitpid won't, and killing a non-child might not be
+// the best approach.
+void WaitForChildToDie(pid_t child, int timeout) {
+  DCHECK_GT(child, 0);
+  DCHECK_GT(timeout, 0);
+
+  // DON'T ADD ANY EARLY RETURNS TO THIS FUNCTION without ensuring that
+  // |child| has been reaped. Specifically, even if a kqueue, kevent, or other
+  // call fails, this function should fall back to the last resort of trying
+  // to kill and reap the process. Not observing this rule will resurrect
+  // zombies.
+
+  int result;
+
+  ScopedFD kq(HANDLE_EINTR(kqueue()));
+  if (!kq.is_valid()) {
+    DPLOG(ERROR) << "kqueue()";
+  } else {
+    struct kevent change = {0};
+    EV_SET(&change, child, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL);
+    result = HANDLE_EINTR(kevent(kq.get(), &change, 1, NULL, 0, NULL));
+
+    if (result == -1) {
+      if (errno != ESRCH) {
+        DPLOG(ERROR) << "kevent (setup " << child << ")";
+      } else {
+        // At this point, one of the following has occurred:
+        // 1. The process has died but has not yet been reaped.
+        // 2. The process has died and has already been reaped.
+        // 3. The process is in the process of dying. It's no longer
+        //    kqueueable, but it may not be waitable yet either. Mark calls
+        //    this case the "zombie death race".
+
+        result = HANDLE_EINTR(waitpid(child, NULL, WNOHANG));
+
+        if (result != 0) {
+          // A positive result indicates case 1. waitpid succeeded and reaped
+          // the child. A result of -1 indicates case 2. The child has already
+          // been reaped. In both of these cases, no further action is
+          // necessary.
+          return;
+        }
+
+        // |result| is 0, indicating case 3. The process will be waitable in
+        // short order. Fall back out of the kqueue code to kill it (for good
+        // measure) and reap it.
+      }
+    } else {
+      // Keep track of the elapsed time to be able to restart kevent if it's
+      // interrupted.
+      TimeDelta remaining_delta = TimeDelta::FromSeconds(timeout);
+      TimeTicks deadline = TimeTicks::Now() + remaining_delta;
+      result = -1;
+      struct kevent event = {0};
+      while (remaining_delta.InMilliseconds() > 0) {
+        const struct timespec remaining_timespec = remaining_delta.ToTimeSpec();
+        result = kevent(kq.get(), NULL, 0, &event, 1, &remaining_timespec);
+        if (result == -1 && errno == EINTR) {
+          remaining_delta = deadline - TimeTicks::Now();
+          result = 0;
+        } else {
+          break;
+        }
+      }
+
+      if (result == -1) {
+        DPLOG(ERROR) << "kevent (wait " << child << ")";
+      } else if (result > 1) {
+        DLOG(ERROR) << "kevent (wait " << child << "): unexpected result "
+                    << result;
+      } else if (result == 1) {
+        if ((event.fflags & NOTE_EXIT) &&
+            (event.ident == static_cast<uintptr_t>(child))) {
+          // The process is dead or dying. This won't block for long, if at
+          // all.
+          BlockingReap(child);
+          return;
+        } else {
+          DLOG(ERROR) << "kevent (wait " << child
+                      << "): unexpected event: fflags=" << event.fflags
+                      << ", ident=" << event.ident;
+        }
+      }
+    }
+  }
+
+  // The child is still alive, or is very freshly dead. Be sure by sending it
+  // a signal. This is safe even if it's freshly dead, because it will be a
+  // zombie (or on the way to zombiedom) and kill will return 0 even if the
+  // signal is not delivered to a live process.
+  result = kill(child, SIGKILL);
+  if (result == -1) {
+    DPLOG(ERROR) << "kill(" << child << ", SIGKILL)";
+  } else {
+    // The child is definitely on the way out now. BlockingReap won't need to
+    // wait for long, if at all.
+    BlockingReap(child);
+  }
+}
+
+}  // namespace
+
+void EnsureProcessTerminated(Process process) {
+  WaitForChildToDie(process.Pid(), kWaitBeforeKillSeconds);
+}
+
+}  // namespace base
diff --git a/base/process/kill_posix.cc b/base/process/kill_posix.cc
new file mode 100644
index 0000000..f0d2d44
--- /dev/null
+++ b/base/process/kill_posix.cc
@@ -0,0 +1,229 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/kill.h"
+
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/process/process_iterator.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+namespace {
+
+TerminationStatus GetTerminationStatusImpl(ProcessHandle handle,
+                                           bool can_block,
+                                           int* exit_code) {
+  int status = 0;
+  const pid_t result = HANDLE_EINTR(waitpid(handle, &status,
+                                            can_block ? 0 : WNOHANG));
+  if (result == -1) {
+    DPLOG(ERROR) << "waitpid(" << handle << ")";
+    if (exit_code)
+      *exit_code = 0;
+    return TERMINATION_STATUS_NORMAL_TERMINATION;
+  } else if (result == 0) {
+    // the child hasn't exited yet.
+    if (exit_code)
+      *exit_code = 0;
+    return TERMINATION_STATUS_STILL_RUNNING;
+  }
+
+  if (exit_code)
+    *exit_code = status;
+
+  if (WIFSIGNALED(status)) {
+    switch (WTERMSIG(status)) {
+      case SIGABRT:
+      case SIGBUS:
+      case SIGFPE:
+      case SIGILL:
+      case SIGSEGV:
+        return TERMINATION_STATUS_PROCESS_CRASHED;
+      case SIGKILL:
+#if defined(OS_CHROMEOS)
+        // On ChromeOS, only way a process gets kill by SIGKILL
+        // is by oom-killer.
+        return TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM;
+#endif
+      case SIGINT:
+      case SIGTERM:
+        return TERMINATION_STATUS_PROCESS_WAS_KILLED;
+      default:
+        break;
+    }
+  }
+
+  if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
+    return TERMINATION_STATUS_ABNORMAL_TERMINATION;
+
+  return TERMINATION_STATUS_NORMAL_TERMINATION;
+}
+
+}  // namespace
+
+#if !defined(OS_NACL_NONSFI)
+bool KillProcessGroup(ProcessHandle process_group_id) {
+  bool result = kill(-1 * process_group_id, SIGKILL) == 0;
+  if (!result)
+    DPLOG(ERROR) << "Unable to terminate process group " << process_group_id;
+  return result;
+}
+#endif  // !defined(OS_NACL_NONSFI)
+
+TerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code) {
+  return GetTerminationStatusImpl(handle, false /* can_block */, exit_code);
+}
+
+TerminationStatus GetKnownDeadTerminationStatus(ProcessHandle handle,
+                                                int* exit_code) {
+  bool result = kill(handle, SIGKILL) == 0;
+
+  if (!result)
+    DPLOG(ERROR) << "Unable to terminate process " << handle;
+
+  return GetTerminationStatusImpl(handle, true /* can_block */, exit_code);
+}
+
+#if !defined(OS_NACL_NONSFI)
+bool WaitForProcessesToExit(const FilePath::StringType& executable_name,
+                            TimeDelta wait,
+                            const ProcessFilter* filter) {
+  bool result = false;
+
+  // TODO(port): This is inefficient, but works if there are multiple procs.
+  // TODO(port): use waitpid to avoid leaving zombies around
+
+  TimeTicks end_time = TimeTicks::Now() + wait;
+  do {
+    NamedProcessIterator iter(executable_name, filter);
+    if (!iter.NextProcessEntry()) {
+      result = true;
+      break;
+    }
+    PlatformThread::Sleep(TimeDelta::FromMilliseconds(100));
+  } while ((end_time - TimeTicks::Now()) > TimeDelta());
+
+  return result;
+}
+
+bool CleanupProcesses(const FilePath::StringType& executable_name,
+                      TimeDelta wait,
+                      int exit_code,
+                      const ProcessFilter* filter) {
+  bool exited_cleanly = WaitForProcessesToExit(executable_name, wait, filter);
+  if (!exited_cleanly)
+    KillProcesses(executable_name, exit_code, filter);
+  return exited_cleanly;
+}
+
+#if !defined(OS_MACOSX)
+
+namespace {
+
+// Return true if the given child is dead. This will also reap the process.
+// Doesn't block.
+static bool IsChildDead(pid_t child) {
+  const pid_t result = HANDLE_EINTR(waitpid(child, NULL, WNOHANG));
+  if (result == -1) {
+    DPLOG(ERROR) << "waitpid(" << child << ")";
+    NOTREACHED();
+  } else if (result > 0) {
+    // The child has died.
+    return true;
+  }
+
+  return false;
+}
+
+// A thread class which waits for the given child to exit and reaps it.
+// If the child doesn't exit within a couple of seconds, kill it.
+class BackgroundReaper : public PlatformThread::Delegate {
+ public:
+  BackgroundReaper(pid_t child, unsigned timeout)
+      : child_(child),
+        timeout_(timeout) {
+  }
+
+  // Overridden from PlatformThread::Delegate:
+  void ThreadMain() override {
+    WaitForChildToDie();
+    delete this;
+  }
+
+  void WaitForChildToDie() {
+    // Wait forever case.
+    if (timeout_ == 0) {
+      pid_t r = HANDLE_EINTR(waitpid(child_, NULL, 0));
+      if (r != child_) {
+        DPLOG(ERROR) << "While waiting for " << child_
+                     << " to terminate, we got the following result: " << r;
+      }
+      return;
+    }
+
+    // There's no good way to wait for a specific child to exit in a timed
+    // fashion. (No kqueue on Linux), so we just loop and sleep.
+
+    // Wait for 2 * timeout_ 500 milliseconds intervals.
+    for (unsigned i = 0; i < 2 * timeout_; ++i) {
+      PlatformThread::Sleep(TimeDelta::FromMilliseconds(500));
+      if (IsChildDead(child_))
+        return;
+    }
+
+    if (kill(child_, SIGKILL) == 0) {
+      // SIGKILL is uncatchable. Since the signal was delivered, we can
+      // just wait for the process to die now in a blocking manner.
+      if (HANDLE_EINTR(waitpid(child_, NULL, 0)) < 0)
+        DPLOG(WARNING) << "waitpid";
+    } else {
+      DLOG(ERROR) << "While waiting for " << child_ << " to terminate we"
+                  << " failed to deliver a SIGKILL signal (" << errno << ").";
+    }
+  }
+
+ private:
+  const pid_t child_;
+  // Number of seconds to wait, if 0 then wait forever and do not attempt to
+  // kill |child_|.
+  const unsigned timeout_;
+
+  DISALLOW_COPY_AND_ASSIGN(BackgroundReaper);
+};
+
+}  // namespace
+
+void EnsureProcessTerminated(Process process) {
+  // If the child is already dead, then there's nothing to do.
+  if (IsChildDead(process.Pid()))
+    return;
+
+  const unsigned timeout = 2;  // seconds
+  BackgroundReaper* reaper = new BackgroundReaper(process.Pid(), timeout);
+  PlatformThread::CreateNonJoinable(0, reaper);
+}
+
+void EnsureProcessGetsReaped(ProcessId pid) {
+  // If the child is already dead, then there's nothing to do.
+  if (IsChildDead(pid))
+    return;
+
+  BackgroundReaper* reaper = new BackgroundReaper(pid, 0);
+  PlatformThread::CreateNonJoinable(0, reaper);
+}
+
+#endif  // !defined(OS_MACOSX)
+#endif  // !defined(OS_NACL_NONSFI)
+
+}  // namespace base
diff --git a/base/process/kill_win.cc b/base/process/kill_win.cc
new file mode 100644
index 0000000..0da3a26
--- /dev/null
+++ b/base/process/kill_win.cc
@@ -0,0 +1,198 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/kill.h"
+
+#include <io.h>
+#include <windows.h>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "base/process/process_iterator.h"
+#include "base/win/object_watcher.h"
+
+namespace base {
+
+namespace {
+
+// Exit codes with special meanings on Windows.
+const DWORD kNormalTerminationExitCode = 0;
+const DWORD kDebuggerInactiveExitCode = 0xC0000354;
+const DWORD kKeyboardInterruptExitCode = 0xC000013A;
+const DWORD kDebuggerTerminatedExitCode = 0x40010004;
+
+// This exit code is used by the Windows task manager when it kills a
+// process.  It's value is obviously not that unique, and it's
+// surprising to me that the task manager uses this value, but it
+// seems to be common practice on Windows to test for it as an
+// indication that the task manager has killed something if the
+// process goes away.
+const DWORD kProcessKilledExitCode = 1;
+
+// Maximum amount of time (in milliseconds) to wait for the process to exit.
+static const int kWaitInterval = 2000;
+
+class TimerExpiredTask : public win::ObjectWatcher::Delegate {
+ public:
+  explicit TimerExpiredTask(Process process);
+  ~TimerExpiredTask() override;
+
+  void TimedOut();
+
+  // MessageLoop::Watcher -----------------------------------------------------
+  void OnObjectSignaled(HANDLE object) override;
+
+ private:
+  void KillProcess();
+
+  // The process that we are watching.
+  Process process_;
+
+  win::ObjectWatcher watcher_;
+
+  DISALLOW_COPY_AND_ASSIGN(TimerExpiredTask);
+};
+
+TimerExpiredTask::TimerExpiredTask(Process process) : process_(process.Pass()) {
+  watcher_.StartWatching(process_.Handle(), this);
+}
+
+TimerExpiredTask::~TimerExpiredTask() {
+  TimedOut();
+}
+
+void TimerExpiredTask::TimedOut() {
+  if (process_.IsValid())
+    KillProcess();
+}
+
+void TimerExpiredTask::OnObjectSignaled(HANDLE object) {
+  process_.Close();
+}
+
+void TimerExpiredTask::KillProcess() {
+  // Stop watching the process handle since we're killing it.
+  watcher_.StopWatching();
+
+  // OK, time to get frisky.  We don't actually care when the process
+  // terminates.  We just care that it eventually terminates, and that's what
+  // TerminateProcess should do for us. Don't check for the result code since
+  // it fails quite often. This should be investigated eventually.
+  process_.Terminate(kProcessKilledExitCode, false);
+
+  // Now, just cleanup as if the process exited normally.
+  OnObjectSignaled(process_.Handle());
+}
+
+}  // namespace
+
+TerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code) {
+  DWORD tmp_exit_code = 0;
+
+  if (!::GetExitCodeProcess(handle, &tmp_exit_code)) {
+    DPLOG(FATAL) << "GetExitCodeProcess() failed";
+    if (exit_code) {
+      // This really is a random number.  We haven't received any
+      // information about the exit code, presumably because this
+      // process doesn't have permission to get the exit code, or
+      // because of some other cause for GetExitCodeProcess to fail
+      // (MSDN docs don't give the possible failure error codes for
+      // this function, so it could be anything).  But we don't want
+      // to leave exit_code uninitialized, since that could cause
+      // random interpretations of the exit code.  So we assume it
+      // terminated "normally" in this case.
+      *exit_code = kNormalTerminationExitCode;
+    }
+    // Assume the child has exited normally if we can't get the exit
+    // code.
+    return TERMINATION_STATUS_NORMAL_TERMINATION;
+  }
+  if (tmp_exit_code == STILL_ACTIVE) {
+    DWORD wait_result = WaitForSingleObject(handle, 0);
+    if (wait_result == WAIT_TIMEOUT) {
+      if (exit_code)
+        *exit_code = wait_result;
+      return TERMINATION_STATUS_STILL_RUNNING;
+    }
+
+    if (wait_result == WAIT_FAILED) {
+      DPLOG(ERROR) << "WaitForSingleObject() failed";
+    } else {
+      DCHECK_EQ(WAIT_OBJECT_0, wait_result);
+
+      // Strange, the process used 0x103 (STILL_ACTIVE) as exit code.
+      NOTREACHED();
+    }
+
+    return TERMINATION_STATUS_ABNORMAL_TERMINATION;
+  }
+
+  if (exit_code)
+    *exit_code = tmp_exit_code;
+
+  switch (tmp_exit_code) {
+    case kNormalTerminationExitCode:
+      return TERMINATION_STATUS_NORMAL_TERMINATION;
+    case kDebuggerInactiveExitCode:  // STATUS_DEBUGGER_INACTIVE.
+    case kKeyboardInterruptExitCode:  // Control-C/end session.
+    case kDebuggerTerminatedExitCode:  // Debugger terminated process.
+    case kProcessKilledExitCode:  // Task manager kill.
+      return TERMINATION_STATUS_PROCESS_WAS_KILLED;
+    default:
+      // All other exit codes indicate crashes.
+      return TERMINATION_STATUS_PROCESS_CRASHED;
+  }
+}
+
+bool WaitForProcessesToExit(const FilePath::StringType& executable_name,
+                            TimeDelta wait,
+                            const ProcessFilter* filter) {
+  bool result = true;
+  DWORD start_time = GetTickCount();
+
+  NamedProcessIterator iter(executable_name, filter);
+  for (const ProcessEntry* entry = iter.NextProcessEntry(); entry;
+       entry = iter.NextProcessEntry()) {
+    DWORD remaining_wait = static_cast<DWORD>(std::max(
+        static_cast<int64>(0),
+        wait.InMilliseconds() - (GetTickCount() - start_time)));
+    HANDLE process = OpenProcess(SYNCHRONIZE,
+                                 FALSE,
+                                 entry->th32ProcessID);
+    DWORD wait_result = WaitForSingleObject(process, remaining_wait);
+    CloseHandle(process);
+    result &= (wait_result == WAIT_OBJECT_0);
+  }
+
+  return result;
+}
+
+bool CleanupProcesses(const FilePath::StringType& executable_name,
+                      TimeDelta wait,
+                      int exit_code,
+                      const ProcessFilter* filter) {
+  if (WaitForProcessesToExit(executable_name, wait, filter))
+    return true;
+  KillProcesses(executable_name, exit_code, filter);
+  return false;
+}
+
+void EnsureProcessTerminated(Process process) {
+  DCHECK(!process.is_current());
+
+  // If already signaled, then we are done!
+  if (WaitForSingleObject(process.Handle(), 0) == WAIT_OBJECT_0) {
+    return;
+  }
+
+  MessageLoop::current()->PostDelayedTask(
+      FROM_HERE,
+      Bind(&TimerExpiredTask::TimedOut,
+           Owned(new TimerExpiredTask(process.Pass()))),
+      TimeDelta::FromMilliseconds(kWaitInterval));
+}
+
+}  // namespace base
diff --git a/base/process/launch.cc b/base/process/launch.cc
new file mode 100644
index 0000000..c179b2f
--- /dev/null
+++ b/base/process/launch.cc
@@ -0,0 +1,56 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/launch.h"
+
+namespace base {
+
+LaunchOptions::LaunchOptions()
+    : wait(false),
+#if defined(OS_WIN)
+      start_hidden(false),
+      handles_to_inherit(NULL),
+      inherit_handles(false),
+      as_user(NULL),
+      empty_desktop_name(false),
+      job_handle(NULL),
+      stdin_handle(NULL),
+      stdout_handle(NULL),
+      stderr_handle(NULL),
+      force_breakaway_from_job_(false)
+#else
+      clear_environ(false),
+      fds_to_remap(NULL),
+      maximize_rlimits(NULL),
+      new_process_group(false)
+#if defined(OS_LINUX)
+      , clone_flags(0)
+      , allow_new_privs(false)
+      , kill_on_parent_death(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
+#endif  // !defined(OS_WIN)
+    {
+}
+
+LaunchOptions::~LaunchOptions() {
+}
+
+LaunchOptions LaunchOptionsForTest() {
+  LaunchOptions options;
+#if defined(OS_LINUX)
+  // To prevent accidental privilege sharing to an untrusted child, processes
+  // are started with PR_SET_NO_NEW_PRIVS. Do not set that here, since this
+  // new child will be used for testing only.
+  options.allow_new_privs = true;
+#endif
+  return options;
+}
+
+}  // namespace base
diff --git a/base/process/launch.h b/base/process/launch.h
new file mode 100644
index 0000000..56f27a8
--- /dev/null
+++ b/base/process/launch.h
@@ -0,0 +1,321 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains functions for launching subprocesses.
+
+#ifndef BASE_PROCESS_LAUNCH_H_
+#define BASE_PROCESS_LAUNCH_H_
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/environment.h"
+#include "base/process/process.h"
+#include "base/process/process_handle.h"
+#include "base/strings/string_piece.h"
+
+#if defined(OS_POSIX)
+#include "base/posix/file_descriptor_shuffle.h"
+#elif defined(OS_WIN)
+#include <windows.h>
+#endif
+
+namespace base {
+
+class CommandLine;
+
+#if defined(OS_WIN)
+typedef std::vector<HANDLE> HandlesToInheritVector;
+#endif
+// TODO(viettrungluu): Only define this on POSIX?
+typedef std::vector<std::pair<int, int> > FileHandleMappingVector;
+
+// 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();
+
+  // If true, wait for the process to complete.
+  bool wait;
+
+#if defined(OS_WIN)
+  bool start_hidden;
+
+  // If non-null, inherit exactly the list of handles in this vector (these
+  // handles must be inheritable). This is only supported on Vista and higher.
+  HandlesToInheritVector* handles_to_inherit;
+
+  // If true, the new process inherits handles from the parent. In production
+  // code this flag should be used only when running short-lived, trusted
+  // binaries, because open handles from other libraries and subsystems will
+  // leak to the child process, causing errors such as open socket hangs.
+  // Note: If |handles_to_inherit| is non-null, this flag is ignored and only
+  // those handles will be inherited (on Vista and higher).
+  bool inherit_handles;
+
+  // If non-null, runs as if the user represented by the token had launched it.
+  // Whether the application is visible on the interactive desktop depends on
+  // the token belonging to an interactive logon session.
+  //
+  // To avoid hard to diagnose problems, when specified this loads the
+  // environment variables associated with the user and if this operation fails
+  // the entire call fails as well.
+  UserTokenHandle as_user;
+
+  // If true, use an empty string for the desktop name.
+  bool empty_desktop_name;
+
+  // If non-null, launches the application in that job object. The process will
+  // be terminated immediately and LaunchProcess() will fail if assignment to
+  // the job object fails.
+  HANDLE job_handle;
+
+  // Handles for the redirection of stdin, stdout and stderr. The handles must
+  // be inheritable. Caller should either set all three of them or none (i.e.
+  // there is no way to redirect stderr without redirecting stdin). The
+  // |inherit_handles| flag must be set to true when redirecting stdio stream.
+  HANDLE stdin_handle;
+  HANDLE stdout_handle;
+  HANDLE stderr_handle;
+
+  // If set to true, ensures that the child process is launched with the
+  // CREATE_BREAKAWAY_FROM_JOB flag which allows it to breakout of the parent
+  // job if any.
+  bool force_breakaway_from_job_;
+#else
+  // Set/unset environment variables. These are applied on top of the parent
+  // process environment.  Empty (the default) means to inherit the same
+  // environment. See AlterEnvironment().
+  EnvironmentMap environ;
+
+  // Clear the environment for the new process before processing changes from
+  // |environ|.
+  bool clear_environ;
+
+  // If non-null, remap file descriptors according to the mapping of
+  // src fd->dest fd to propagate FDs into the child process.
+  // This pointer is owned by the caller and must live through the
+  // call to LaunchProcess().
+  const FileHandleMappingVector* fds_to_remap;
+
+  // Each element is an RLIMIT_* constant that should be raised to its
+  // rlim_max.  This pointer is owned by the caller and must live through
+  // the call to LaunchProcess().
+  const std::vector<int>* maximize_rlimits;
+
+  // If true, start the process in a new process group, instead of
+  // inheriting the parent's process group.  The pgid of the child process
+  // will be the same as its pid.
+  bool new_process_group;
+
+#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
+  // true, then this bit will not be set in the new child process.
+  bool allow_new_privs;
+
+  // Sets parent process death signal to SIGKILL.
+  bool kill_on_parent_death;
+#endif  // defined(OS_LINUX)
+
+#if defined(OS_POSIX)
+  // If not empty, change to this directory before execing the new process.
+  base::FilePath current_directory;
+
+  // 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.
+  int ctrl_terminal_fd;
+#endif  // defined(OS_CHROMEOS)
+
+#if defined(OS_MACOSX)
+  // If this name is non-empty, the new child, after fork() but before exec(),
+  // will look up this server name in the bootstrap namespace. The resulting
+  // service port will be replaced as the bootstrap port in the child. Because
+  // the process's IPC space is cleared on exec(), any rights to the old
+  // bootstrap port will not be transferred to the new process.
+  std::string replacement_bootstrap_name;
+#endif
+
+#endif  // !defined(OS_WIN)
+};
+
+// Launch a process via the command line |cmdline|.
+// See the documentation of LaunchOptions for details on |options|.
+//
+// Returns a valid Process upon success.
+//
+// Unix-specific notes:
+// - All file descriptors open in the parent process will be closed in the
+//   child process except for any preserved by options::fds_to_remap, and
+//   stdin, stdout, and stderr. If not remapped by options::fds_to_remap,
+//   stdin is reopened as /dev/null, and the child is allowed to inherit its
+//   parent's stdout and stderr.
+// - If the first argument on the command line does not contain a slash,
+//   PATH will be searched.  (See man execvp.)
+BASE_EXPORT Process LaunchProcess(const CommandLine& cmdline,
+                                  const LaunchOptions& options);
+
+#if defined(OS_WIN)
+// Windows-specific LaunchProcess that takes the command line as a
+// string.  Useful for situations where you need to control the
+// command line arguments directly, but prefer the CommandLine version
+// if launching Chrome itself.
+//
+// The first command line argument should be the path to the process,
+// and don't forget to quote it.
+//
+// Example (including literal quotes)
+//  cmdline = "c:\windows\explorer.exe" -foo "c:\bar\"
+BASE_EXPORT Process LaunchProcess(const string16& cmdline,
+                                  const LaunchOptions& options);
+
+// Launches a process with elevated privileges.  This does not behave exactly
+// like LaunchProcess as it uses ShellExecuteEx instead of CreateProcess to
+// create the process.  This means the process will have elevated privileges
+// and thus some common operations like OpenProcess will fail. Currently the
+// only supported LaunchOptions are |start_hidden| and |wait|.
+BASE_EXPORT Process LaunchElevatedProcess(const CommandLine& cmdline,
+                                          const LaunchOptions& options);
+
+#elif defined(OS_POSIX)
+// A POSIX-specific version of LaunchProcess that takes an argv array
+// instead of a CommandLine.  Useful for situations where you need to
+// control the command line arguments directly, but prefer the
+// CommandLine version if launching Chrome itself.
+BASE_EXPORT Process LaunchProcess(const std::vector<std::string>& argv,
+                                  const LaunchOptions& options);
+
+// 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.
+BASE_EXPORT void CloseSuperfluousFds(const InjectiveMultimap& saved_map);
+#endif  // defined(OS_POSIX)
+
+#if defined(OS_WIN)
+// Set |job_object|'s JOBOBJECT_EXTENDED_LIMIT_INFORMATION
+// BasicLimitInformation.LimitFlags to |limit_flags|.
+BASE_EXPORT bool SetJobObjectLimitFlags(HANDLE job_object, DWORD limit_flags);
+
+// Output multi-process printf, cout, cerr, etc to the cmd.exe console that ran
+// chrome. This is not thread-safe: only call from main thread.
+BASE_EXPORT void RouteStdioToConsole();
+#endif  // defined(OS_WIN)
+
+// Executes the application specified by |cl| and wait for it to exit. Stores
+// the output (stdout) in |output|. Redirects stderr to /dev/null. Returns true
+// on success (application launched and exited cleanly, with exit code
+// indicating success).
+BASE_EXPORT bool GetAppOutput(const CommandLine& cl, std::string* output);
+
+#if defined(OS_WIN)
+// A Windows-specific version of GetAppOutput that takes a command line string
+// instead of a CommandLine object. Useful for situations where you need to
+// control the command line arguments directly.
+BASE_EXPORT bool GetAppOutput(const StringPiece16& cl, std::string* output);
+#endif
+
+#if defined(OS_POSIX)
+// A POSIX-specific version of GetAppOutput that takes an argv array
+// instead of a CommandLine.  Useful for situations where you need to
+// control the command line arguments directly.
+BASE_EXPORT bool GetAppOutput(const std::vector<std::string>& argv,
+                              std::string* output);
+
+// A restricted version of |GetAppOutput()| which (a) clears the environment,
+// and (b) stores at most |max_output| bytes; also, it doesn't search the path
+// for the command.
+BASE_EXPORT bool GetAppOutputRestricted(const CommandLine& cl,
+                                        std::string* output, size_t max_output);
+
+// A version of |GetAppOutput()| which also returns the exit code of the
+// executed command. Returns true if the application runs and exits cleanly. If
+// this is the case the exit code of the application is available in
+// |*exit_code|.
+BASE_EXPORT bool GetAppOutputWithExitCode(const CommandLine& cl,
+                                          std::string* output, int* exit_code);
+#endif  // defined(OS_POSIX)
+
+// If supported on the platform, and the user has sufficent rights, increase
+// the current process's scheduling priority to a high priority.
+BASE_EXPORT void RaiseProcessToHighPriority();
+
+#if defined(OS_MACOSX)
+// Restore the default exception handler, setting it to Apple Crash Reporter
+// (ReportCrash).  When forking and execing a new process, the child will
+// inherit the parent's exception ports, which may be set to the Breakpad
+// instance running inside the parent.  The parent's Breakpad instance should
+// not handle the child's exceptions.  Calling RestoreDefaultExceptionHandler
+// in the child after forking will restore the standard exception handler.
+// See http://crbug.com/20371/ for more details.
+void RestoreDefaultExceptionHandler();
+
+// Look up the bootstrap server named |replacement_bootstrap_name| via the
+// current |bootstrap_port|. Then replace the task's bootstrap port with the
+// received right.
+void ReplaceBootstrapPort(const std::string& replacement_bootstrap_name);
+#endif  // defined(OS_MACOSX)
+
+// Creates a LaunchOptions object suitable for launching processes in a test
+// binary. This should not be called in production/released code.
+BASE_EXPORT LaunchOptions LaunchOptionsForTest();
+
+#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_LAUNCH_H_
diff --git a/base/process/launch_ios.cc b/base/process/launch_ios.cc
new file mode 100644
index 0000000..3c700f8
--- /dev/null
+++ b/base/process/launch_ios.cc
@@ -0,0 +1,13 @@
+// Copyright (c) 2012 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/process/launch.h"
+
+namespace base {
+
+void RaiseProcessToHighPriority() {
+  // Impossible on iOS. Do nothing.
+}
+
+}  // namespace base
diff --git a/base/process/launch_mac.cc b/base/process/launch_mac.cc
new file mode 100644
index 0000000..ce02475
--- /dev/null
+++ b/base/process/launch_mac.cc
@@ -0,0 +1,48 @@
+// Copyright (c) 2012 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/process/launch.h"
+
+#include <mach/mach.h>
+#include <servers/bootstrap.h>
+
+#include "base/logging.h"
+
+namespace base {
+
+void RestoreDefaultExceptionHandler() {
+  // This function is tailored to remove the Breakpad exception handler.
+  // exception_mask matches s_exception_mask in
+  // breakpad/src/client/mac/handler/exception_handler.cc
+  const exception_mask_t exception_mask = EXC_MASK_BAD_ACCESS |
+                                          EXC_MASK_BAD_INSTRUCTION |
+                                          EXC_MASK_ARITHMETIC |
+                                          EXC_MASK_BREAKPOINT;
+
+  // Setting the exception port to MACH_PORT_NULL may not be entirely
+  // kosher to restore the default exception handler, but in practice,
+  // it results in the exception port being set to Apple Crash Reporter,
+  // the desired behavior.
+  task_set_exception_ports(mach_task_self(), exception_mask, MACH_PORT_NULL,
+                           EXCEPTION_DEFAULT, THREAD_STATE_NONE);
+}
+
+void ReplaceBootstrapPort(const std::string& new_bootstrap_name) {
+  // This function is called between fork() and exec(), so it should take care
+  // to run properly in that situation.
+
+  mach_port_t port = MACH_PORT_NULL;
+  kern_return_t kr = bootstrap_look_up(bootstrap_port,
+      new_bootstrap_name.c_str(), &port);
+  if (kr != KERN_SUCCESS) {
+    RAW_LOG(FATAL, "Failed to look up replacement bootstrap port.");
+  }
+
+  kr = task_set_bootstrap_port(mach_task_self(), port);
+  if (kr != KERN_SUCCESS) {
+    RAW_LOG(FATAL, "Failed to replace bootstrap port.");
+  }
+}
+
+}  // namespace base
diff --git a/base/process/launch_posix.cc b/base/process/launch_posix.cc
new file mode 100644
index 0000000..77edc12
--- /dev/null
+++ b/base/process/launch_posix.cc
@@ -0,0 +1,785 @@
+// Copyright (c) 2012 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/process/launch.h"
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sched.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <sys/resource.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <iterator>
+#include <limits>
+#include <set>
+
+#include "base/allocator/type_profiler_control.h"
+#include "base/command_line.h"
+#include "base/compiler_specific.h"
+#include "base/debug/debugger.h"
+#include "base/debug/stack_trace.h"
+#include "base/files/dir_reader_posix.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/process/process.h"
+#include "base/process/process_metrics.h"
+#include "base/strings/stringprintf.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "base/third_party/valgrind/valgrind.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread_restrictions.h"
+#include "build/build_config.h"
+
+#if defined(OS_LINUX)
+#include <sys/prctl.h>
+#endif
+
+#if defined(OS_CHROMEOS)
+#include <sys/ioctl.h>
+#endif
+
+#if defined(OS_FREEBSD)
+#include <sys/event.h>
+#include <sys/ucontext.h>
+#endif
+
+#if defined(OS_MACOSX)
+#include <crt_externs.h>
+#include <sys/event.h>
+#else
+extern char** environ;
+#endif
+
+namespace base {
+
+namespace {
+
+// Get the process's "environment" (i.e. the thing that setenv/getenv
+// work with).
+char** GetEnvironment() {
+#if defined(OS_MACOSX)
+  return *_NSGetEnviron();
+#else
+  return environ;
+#endif
+}
+
+// Set the process's "environment" (i.e. the thing that setenv/getenv
+// work with).
+void SetEnvironment(char** env) {
+#if defined(OS_MACOSX)
+  *_NSGetEnviron() = env;
+#else
+  environ = env;
+#endif
+}
+
+// Set the calling thread's signal mask to new_sigmask and return
+// the previous signal mask.
+sigset_t SetSignalMask(const sigset_t& new_sigmask) {
+  sigset_t old_sigmask;
+#if defined(OS_ANDROID)
+  // POSIX says pthread_sigmask() must be used in multi-threaded processes,
+  // but Android's pthread_sigmask() was broken until 4.1:
+  // https://code.google.com/p/android/issues/detail?id=15337
+  // http://stackoverflow.com/questions/13777109/pthread-sigmask-on-android-not-working
+  RAW_CHECK(sigprocmask(SIG_SETMASK, &new_sigmask, &old_sigmask) == 0);
+#else
+  RAW_CHECK(pthread_sigmask(SIG_SETMASK, &new_sigmask, &old_sigmask) == 0);
+#endif
+  return old_sigmask;
+}
+
+#if !defined(OS_LINUX) || \
+    (!defined(__i386__) && !defined(__x86_64__) && !defined(__arm__))
+void ResetChildSignalHandlersToDefaults() {
+  // The previous signal handlers are likely to be meaningless in the child's
+  // context so we reset them to the defaults for now. http://crbug.com/44953
+  // These signal handlers are set up at least in browser_main_posix.cc:
+  // BrowserMainPartsPosix::PreEarlyInitialization and stack_trace_posix.cc:
+  // EnableInProcessStackDumping.
+  signal(SIGHUP, SIG_DFL);
+  signal(SIGINT, SIG_DFL);
+  signal(SIGILL, SIG_DFL);
+  signal(SIGABRT, SIG_DFL);
+  signal(SIGFPE, SIG_DFL);
+  signal(SIGBUS, SIG_DFL);
+  signal(SIGSEGV, SIG_DFL);
+  signal(SIGSYS, SIG_DFL);
+  signal(SIGTERM, SIG_DFL);
+}
+
+#else
+
+// TODO(jln): remove the Linux special case once kernels are fixed.
+
+// Internally the kernel makes sigset_t an array of long large enough to have
+// one bit per signal.
+typedef uint64_t kernel_sigset_t;
+
+// This is what struct sigaction looks like to the kernel at least on X86 and
+// ARM. MIPS, for instance, is very different.
+struct kernel_sigaction {
+  void* k_sa_handler;  // For this usage it only needs to be a generic pointer.
+  unsigned long k_sa_flags;
+  void* k_sa_restorer;  // For this usage it only needs to be a generic pointer.
+  kernel_sigset_t k_sa_mask;
+};
+
+// glibc's sigaction() will prevent access to sa_restorer, so we need to roll
+// our own.
+int sys_rt_sigaction(int sig, const struct kernel_sigaction* act,
+                     struct kernel_sigaction* oact) {
+  return syscall(SYS_rt_sigaction, sig, act, oact, sizeof(kernel_sigset_t));
+}
+
+// This function is intended to be used in between fork() and execve() and will
+// reset all signal handlers to the default.
+// The motivation for going through all of them is that sa_restorer can leak
+// from parents and help defeat ASLR on buggy kernels.  We reset it to NULL.
+// See crbug.com/177956.
+void ResetChildSignalHandlersToDefaults(void) {
+  for (int signum = 1; ; ++signum) {
+    struct kernel_sigaction act = {0};
+    int sigaction_get_ret = sys_rt_sigaction(signum, NULL, &act);
+    if (sigaction_get_ret && errno == EINVAL) {
+#if !defined(NDEBUG)
+      // Linux supports 32 real-time signals from 33 to 64.
+      // If the number of signals in the Linux kernel changes, someone should
+      // look at this code.
+      const int kNumberOfSignals = 64;
+      RAW_CHECK(signum == kNumberOfSignals + 1);
+#endif  // !defined(NDEBUG)
+      break;
+    }
+    // All other failures are fatal.
+    if (sigaction_get_ret) {
+      RAW_LOG(FATAL, "sigaction (get) failed.");
+    }
+
+    // The kernel won't allow to re-set SIGKILL or SIGSTOP.
+    if (signum != SIGSTOP && signum != SIGKILL) {
+      act.k_sa_handler = reinterpret_cast<void*>(SIG_DFL);
+      act.k_sa_restorer = NULL;
+      if (sys_rt_sigaction(signum, &act, NULL)) {
+        RAW_LOG(FATAL, "sigaction (set) failed.");
+      }
+    }
+#if !defined(NDEBUG)
+    // Now ask the kernel again and check that no restorer will leak.
+    if (sys_rt_sigaction(signum, NULL, &act) || act.k_sa_restorer) {
+      RAW_LOG(FATAL, "Cound not fix sa_restorer.");
+    }
+#endif  // !defined(NDEBUG)
+  }
+}
+#endif  // !defined(OS_LINUX) ||
+        // (!defined(__i386__) && !defined(__x86_64__) && !defined(__arm__))
+
+#if defined(OS_LINUX)
+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);
+}
+#endif  // defined(OS_LINUX)
+
+}  // anonymous namespace
+
+// Functor for |ScopedDIR| (below).
+struct ScopedDIRClose {
+  inline void operator()(DIR* x) const {
+    if (x)
+      closedir(x);
+  }
+};
+
+// Automatically closes |DIR*|s.
+typedef scoped_ptr<DIR, ScopedDIRClose> ScopedDIR;
+
+#if defined(OS_LINUX)
+static const char kFDDir[] = "/proc/self/fd";
+#elif defined(OS_MACOSX)
+static const char kFDDir[] = "/dev/fd";
+#elif defined(OS_SOLARIS)
+static const char kFDDir[] = "/dev/fd";
+#elif defined(OS_FREEBSD)
+static const char kFDDir[] = "/dev/fd";
+#elif defined(OS_OPENBSD)
+static const char kFDDir[] = "/dev/fd";
+#elif defined(OS_ANDROID)
+static const char kFDDir[] = "/proc/self/fd";
+#endif
+
+void CloseSuperfluousFds(const base::InjectiveMultimap& saved_mapping) {
+  // DANGER: no calls to malloc or locks are allowed from now on:
+  // http://crbug.com/36678
+
+  // Get the maximum number of FDs possible.
+  size_t max_fds = GetMaxFds();
+
+  DirReaderPosix fd_dir(kFDDir);
+  if (!fd_dir.IsValid()) {
+    // Fallback case: Try every possible fd.
+    for (size_t i = 0; i < max_fds; ++i) {
+      const int fd = static_cast<int>(i);
+      if (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO)
+        continue;
+      // Cannot use STL iterators here, since debug iterators use locks.
+      size_t j;
+      for (j = 0; j < saved_mapping.size(); j++) {
+        if (fd == saved_mapping[j].dest)
+          break;
+      }
+      if (j < saved_mapping.size())
+        continue;
+
+      // Since we're just trying to close anything we can find,
+      // ignore any error return values of close().
+      close(fd);
+    }
+    return;
+  }
+
+  const int dir_fd = fd_dir.fd();
+
+  for ( ; fd_dir.Next(); ) {
+    // Skip . and .. entries.
+    if (fd_dir.name()[0] == '.')
+      continue;
+
+    char *endptr;
+    errno = 0;
+    const long int fd = strtol(fd_dir.name(), &endptr, 10);
+    if (fd_dir.name()[0] == 0 || *endptr || fd < 0 || errno)
+      continue;
+    if (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO)
+      continue;
+    // Cannot use STL iterators here, since debug iterators use locks.
+    size_t i;
+    for (i = 0; i < saved_mapping.size(); i++) {
+      if (fd == saved_mapping[i].dest)
+        break;
+    }
+    if (i < saved_mapping.size())
+      continue;
+    if (fd == dir_fd)
+      continue;
+
+    // When running under Valgrind, Valgrind opens several FDs for its
+    // own use and will complain if we try to close them.  All of
+    // these FDs are >= |max_fds|, so we can check against that here
+    // before closing.  See https://bugs.kde.org/show_bug.cgi?id=191758
+    if (fd < static_cast<int>(max_fds)) {
+      int ret = IGNORE_EINTR(close(fd));
+      DPCHECK(ret == 0);
+    }
+  }
+}
+
+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();
+  }
+
+  InjectiveMultimap fd_shuffle1;
+  InjectiveMultimap fd_shuffle2;
+  fd_shuffle1.reserve(fd_shuffle_size);
+  fd_shuffle2.reserve(fd_shuffle_size);
+
+  scoped_ptr<char* []> argv_cstr(new char* [argv.size() + 1]);
+  for (size_t i = 0; i < argv.size(); i++) {
+    argv_cstr[i] = const_cast<char*>(argv[i].c_str());
+  }
+  argv_cstr[argv.size()] = NULL;
+
+  scoped_ptr<char*[]> new_environ;
+  char* const empty_environ = NULL;
+  char* const* old_environ = GetEnvironment();
+  if (options.clear_environ)
+    old_environ = &empty_environ;
+  if (!options.environ.empty())
+    new_environ = AlterEnvironment(old_environ, options.environ);
+
+  sigset_t full_sigset;
+  sigfillset(&full_sigset);
+  const sigset_t orig_sigmask = SetSignalMask(full_sigset);
+
+  const char* current_directory = nullptr;
+  if (!options.current_directory.empty()) {
+    current_directory = options.current_directory.value().c_str();
+  }
+
+  pid_t pid;
+#if defined(OS_LINUX)
+  if (options.clone_flags) {
+    // Signal handling in this function assumes the creation of a new
+    // process, so we check that a thread is not being created by mistake
+    // and that signal handling follows the process-creation rules.
+    RAW_CHECK(
+        !(options.clone_flags & (CLONE_SIGHAND | CLONE_THREAD | CLONE_VM)));
+
+    // 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
+  {
+    pid = fork();
+  }
+
+  // Always restore the original signal mask in the parent.
+  if (pid != 0) {
+    SetSignalMask(orig_sigmask);
+  }
+
+  if (pid < 0) {
+    DPLOG(ERROR) << "fork";
+    return Process();
+  } else if (pid == 0) {
+    // Child process
+
+    // DANGER: no calls to malloc or locks are allowed from now on:
+    // http://crbug.com/36678
+
+    // DANGER: fork() rule: in the child, if you don't end up doing exec*(),
+    // you call _exit() instead of exit(). This is because _exit() does not
+    // call any previously-registered (in the parent) exit handlers, which
+    // might do things like block waiting for threads that don't even exist
+    // in the child.
+
+    // If a child process uses the readline library, the process block forever.
+    // In BSD like OSes including OS X it is safe to assign /dev/null as stdin.
+    // See http://crbug.com/56596.
+    base::ScopedFD null_fd(HANDLE_EINTR(open("/dev/null", O_RDONLY)));
+    if (!null_fd.is_valid()) {
+      RAW_LOG(ERROR, "Failed to open /dev/null");
+      _exit(127);
+    }
+
+    int new_fd = HANDLE_EINTR(dup2(null_fd.get(), STDIN_FILENO));
+    if (new_fd != STDIN_FILENO) {
+      RAW_LOG(ERROR, "Failed to dup /dev/null for stdin");
+      _exit(127);
+    }
+
+    if (options.new_process_group) {
+      // Instead of inheriting the process group ID of the parent, the child
+      // starts off a new process group with pgid equal to its process ID.
+      if (setpgid(0, 0) < 0) {
+        RAW_LOG(ERROR, "setpgid failed");
+        _exit(127);
+      }
+    }
+
+    // Stop type-profiler.
+    // The profiler should be stopped between fork and exec since it inserts
+    // locks at new/delete expressions.  See http://crbug.com/36678.
+    base::type_profiler::Controller::Stop();
+
+    if (options.maximize_rlimits) {
+      // Some resource limits need to be maximal in this child.
+      for (size_t i = 0; i < options.maximize_rlimits->size(); ++i) {
+        const int resource = (*options.maximize_rlimits)[i];
+        struct rlimit limit;
+        if (getrlimit(resource, &limit) < 0) {
+          RAW_LOG(WARNING, "getrlimit failed");
+        } else if (limit.rlim_cur < limit.rlim_max) {
+          limit.rlim_cur = limit.rlim_max;
+          if (setrlimit(resource, &limit) < 0) {
+            RAW_LOG(WARNING, "setrlimit failed");
+          }
+        }
+      }
+    }
+
+#if defined(OS_MACOSX)
+    RestoreDefaultExceptionHandler();
+    if (!options.replacement_bootstrap_name.empty())
+      ReplaceBootstrapPort(options.replacement_bootstrap_name);
+#endif  // defined(OS_MACOSX)
+
+    ResetChildSignalHandlersToDefaults();
+    SetSignalMask(orig_sigmask);
+
+#if 0
+    // When debugging it can be helpful to check that we really aren't making
+    // any hidden calls to malloc.
+    void *malloc_thunk =
+        reinterpret_cast<void*>(reinterpret_cast<intptr_t>(malloc) & ~4095);
+    mprotect(malloc_thunk, 4096, PROT_READ | PROT_WRITE | PROT_EXEC);
+    memset(reinterpret_cast<void*>(malloc), 0xff, 8);
+#endif  // 0
+
+#if defined(OS_CHROMEOS)
+    if (options.ctrl_terminal_fd >= 0) {
+      // Set process' controlling terminal.
+      if (HANDLE_EINTR(setsid()) != -1) {
+        if (HANDLE_EINTR(
+                ioctl(options.ctrl_terminal_fd, TIOCSCTTY, NULL)) == -1) {
+          RAW_LOG(WARNING, "ioctl(TIOCSCTTY), ctrl terminal not set");
+        }
+      } else {
+        RAW_LOG(WARNING, "setsid failed, ctrl terminal not set");
+      }
+    }
+#endif  // defined(OS_CHROMEOS)
+
+    if (options.fds_to_remap) {
+      // Cannot use STL iterators here, since debug iterators use locks.
+      for (size_t i = 0; i < options.fds_to_remap->size(); ++i) {
+        const FileHandleMappingVector::value_type& value =
+            (*options.fds_to_remap)[i];
+        fd_shuffle1.push_back(InjectionArc(value.first, value.second, false));
+        fd_shuffle2.push_back(InjectionArc(value.first, value.second, false));
+      }
+    }
+
+    if (!options.environ.empty() || options.clear_environ)
+      SetEnvironment(new_environ.get());
+
+    // fd_shuffle1 is mutated by this call because it cannot malloc.
+    if (!ShuffleFileDescriptors(&fd_shuffle1))
+      _exit(127);
+
+    CloseSuperfluousFds(fd_shuffle2);
+
+    // Set NO_NEW_PRIVS by default. Since NO_NEW_PRIVS only exists in kernel
+    // 3.5+, do not check the return value of prctl here.
+#if defined(OS_LINUX)
+#ifndef PR_SET_NO_NEW_PRIVS
+#define PR_SET_NO_NEW_PRIVS 38
+#endif
+    if (!options.allow_new_privs) {
+      if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) && errno != EINVAL) {
+        // Only log if the error is not EINVAL (i.e. not supported).
+        RAW_LOG(FATAL, "prctl(PR_SET_NO_NEW_PRIVS) failed");
+      }
+    }
+
+    if (options.kill_on_parent_death) {
+      if (prctl(PR_SET_PDEATHSIG, SIGKILL) != 0) {
+        RAW_LOG(ERROR, "prctl(PR_SET_PDEATHSIG) failed");
+        _exit(127);
+      }
+    }
+#endif
+
+    if (current_directory != nullptr) {
+      RAW_CHECK(chdir(current_directory) == 0);
+    }
+
+    if (options.pre_exec_delegate != nullptr) {
+      options.pre_exec_delegate->RunAsyncSafe();
+    }
+
+    execvp(argv_cstr[0], argv_cstr.get());
+
+    RAW_LOG(ERROR, "LaunchProcess: failed to execvp:");
+    RAW_LOG(ERROR, argv_cstr[0]);
+    _exit(127);
+  } else {
+    // Parent process
+    if (options.wait) {
+      // While this isn't strictly disk IO, waiting for another process to
+      // finish is the sort of thing ThreadRestrictions is trying to prevent.
+      base::ThreadRestrictions::AssertIOAllowed();
+      pid_t ret = HANDLE_EINTR(waitpid(pid, 0, 0));
+      DPCHECK(ret > 0);
+    }
+  }
+
+  return Process(pid);
+}
+
+void RaiseProcessToHighPriority() {
+  // On POSIX, we don't actually do anything here.  We could try to nice() or
+  // setpriority() or sched_getscheduler, but these all require extra rights.
+}
+
+// Return value used by GetAppOutputInternal to encapsulate the various exit
+// scenarios from the function.
+enum GetAppOutputInternalResult {
+  EXECUTE_FAILURE,
+  EXECUTE_SUCCESS,
+  GOT_MAX_OUTPUT,
+};
+
+// Executes the application specified by |argv| and wait for it to exit. Stores
+// the output (stdout) in |output|. If |do_search_path| is set, it searches the
+// path for the application; in that case, |envp| must be null, and it will use
+// the current environment. If |do_search_path| is false, |argv[0]| should fully
+// specify the path of the application, and |envp| will be used as the
+// environment. Redirects stderr to /dev/null.
+// If we successfully start the application and get all requested output, we
+// return GOT_MAX_OUTPUT, or if there is a problem starting or exiting
+// the application we return RUN_FAILURE. Otherwise we return EXECUTE_SUCCESS.
+// The GOT_MAX_OUTPUT return value exists so a caller that asks for limited
+// output can treat this as a success, despite having an exit code of SIG_PIPE
+// due to us closing the output pipe.
+// In the case of EXECUTE_SUCCESS, the application exit code will be returned
+// in |*exit_code|, which should be checked to determine if the application
+// ran successfully.
+static GetAppOutputInternalResult GetAppOutputInternal(
+    const std::vector<std::string>& argv,
+    char* const envp[],
+    std::string* output,
+    size_t max_output,
+    bool do_search_path,
+    int* exit_code) {
+  // Doing a blocking wait for another command to finish counts as IO.
+  base::ThreadRestrictions::AssertIOAllowed();
+  // exit_code must be supplied so calling function can determine success.
+  DCHECK(exit_code);
+  *exit_code = EXIT_FAILURE;
+
+  int pipe_fd[2];
+  pid_t pid;
+  InjectiveMultimap fd_shuffle1, fd_shuffle2;
+  scoped_ptr<char*[]> argv_cstr(new char*[argv.size() + 1]);
+
+  fd_shuffle1.reserve(3);
+  fd_shuffle2.reserve(3);
+
+  // Either |do_search_path| should be false or |envp| should be null, but not
+  // both.
+  DCHECK(!do_search_path ^ !envp);
+
+  if (pipe(pipe_fd) < 0)
+    return EXECUTE_FAILURE;
+
+  switch (pid = fork()) {
+    case -1:  // error
+      close(pipe_fd[0]);
+      close(pipe_fd[1]);
+      return EXECUTE_FAILURE;
+    case 0:  // child
+      {
+        // DANGER: no calls to malloc or locks are allowed from now on:
+        // http://crbug.com/36678
+
+#if defined(OS_MACOSX)
+        RestoreDefaultExceptionHandler();
+#endif
+
+        // Obscure fork() rule: in the child, if you don't end up doing exec*(),
+        // you call _exit() instead of exit(). This is because _exit() does not
+        // call any previously-registered (in the parent) exit handlers, which
+        // might do things like block waiting for threads that don't even exist
+        // in the child.
+        int dev_null = open("/dev/null", O_WRONLY);
+        if (dev_null < 0)
+          _exit(127);
+
+        // Stop type-profiler.
+        // The profiler should be stopped between fork and exec since it inserts
+        // locks at new/delete expressions.  See http://crbug.com/36678.
+        base::type_profiler::Controller::Stop();
+
+        fd_shuffle1.push_back(InjectionArc(pipe_fd[1], STDOUT_FILENO, true));
+        fd_shuffle1.push_back(InjectionArc(dev_null, STDERR_FILENO, true));
+        fd_shuffle1.push_back(InjectionArc(dev_null, STDIN_FILENO, true));
+        // Adding another element here? Remeber to increase the argument to
+        // reserve(), above.
+
+        for (size_t i = 0; i < fd_shuffle1.size(); ++i)
+          fd_shuffle2.push_back(fd_shuffle1[i]);
+
+        if (!ShuffleFileDescriptors(&fd_shuffle1))
+          _exit(127);
+
+        CloseSuperfluousFds(fd_shuffle2);
+
+        for (size_t i = 0; i < argv.size(); i++)
+          argv_cstr[i] = const_cast<char*>(argv[i].c_str());
+        argv_cstr[argv.size()] = NULL;
+        if (do_search_path)
+          execvp(argv_cstr[0], argv_cstr.get());
+        else
+          execve(argv_cstr[0], argv_cstr.get(), envp);
+        _exit(127);
+      }
+    default:  // parent
+      {
+        // Close our writing end of pipe now. Otherwise later read would not
+        // be able to detect end of child's output (in theory we could still
+        // write to the pipe).
+        close(pipe_fd[1]);
+
+        output->clear();
+        char buffer[256];
+        size_t output_buf_left = max_output;
+        ssize_t bytes_read = 1;  // A lie to properly handle |max_output == 0|
+                                 // case in the logic below.
+
+        while (output_buf_left > 0) {
+          bytes_read = HANDLE_EINTR(read(pipe_fd[0], buffer,
+                                    std::min(output_buf_left, sizeof(buffer))));
+          if (bytes_read <= 0)
+            break;
+          output->append(buffer, bytes_read);
+          output_buf_left -= static_cast<size_t>(bytes_read);
+        }
+        close(pipe_fd[0]);
+
+        // Always wait for exit code (even if we know we'll declare
+        // GOT_MAX_OUTPUT).
+        Process process(pid);
+        bool success = process.WaitForExit(exit_code);
+
+        // If we stopped because we read as much as we wanted, we return
+        // GOT_MAX_OUTPUT (because the child may exit due to |SIGPIPE|).
+        if (!output_buf_left && bytes_read > 0)
+          return GOT_MAX_OUTPUT;
+        else if (success)
+          return EXECUTE_SUCCESS;
+        return EXECUTE_FAILURE;
+      }
+  }
+}
+
+bool GetAppOutput(const CommandLine& cl, std::string* output) {
+  return GetAppOutput(cl.argv(), output);
+}
+
+bool GetAppOutput(const std::vector<std::string>& argv, std::string* output) {
+  // Run |execve()| with the current environment and store "unlimited" data.
+  int exit_code;
+  GetAppOutputInternalResult result = GetAppOutputInternal(
+      argv, NULL, output, std::numeric_limits<std::size_t>::max(), true,
+      &exit_code);
+  return result == EXECUTE_SUCCESS && exit_code == EXIT_SUCCESS;
+}
+
+// TODO(viettrungluu): Conceivably, we should have a timeout as well, so we
+// don't hang if what we're calling hangs.
+bool GetAppOutputRestricted(const CommandLine& cl,
+                            std::string* output, size_t max_output) {
+  // Run |execve()| with the empty environment.
+  char* const empty_environ = NULL;
+  int exit_code;
+  GetAppOutputInternalResult result = GetAppOutputInternal(
+      cl.argv(), &empty_environ, output, max_output, false, &exit_code);
+  return result == GOT_MAX_OUTPUT || (result == EXECUTE_SUCCESS &&
+                                      exit_code == EXIT_SUCCESS);
+}
+
+bool GetAppOutputWithExitCode(const CommandLine& cl,
+                              std::string* output,
+                              int* exit_code) {
+  // Run |execve()| with the current environment and store "unlimited" data.
+  GetAppOutputInternalResult result = GetAppOutputInternal(
+      cl.argv(), NULL, output, std::numeric_limits<std::size_t>::max(), true,
+      exit_code);
+  return result == EXECUTE_SUCCESS;
+}
+
+#if defined(OS_LINUX)
+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;
+}
+#endif  // defined(OS_LINUX)
+
+}  // namespace base
diff --git a/base/process/launch_win.cc b/base/process/launch_win.cc
new file mode 100644
index 0000000..ebc19b8
--- /dev/null
+++ b/base/process/launch_win.cc
@@ -0,0 +1,353 @@
+// Copyright (c) 2012 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/process/launch.h"
+
+#include <fcntl.h>
+#include <io.h>
+#include <shellapi.h>
+#include <windows.h>
+#include <userenv.h>
+#include <psapi.h>
+
+#include <ios>
+#include <limits>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/command_line.h"
+#include "base/debug/stack_trace.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/metrics/histogram.h"
+#include "base/process/kill.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/sys_info.h"
+#include "base/win/object_watcher.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/scoped_process_information.h"
+#include "base/win/startup_information.h"
+#include "base/win/windows_version.h"
+
+// userenv.dll is required for CreateEnvironmentBlock().
+#pragma comment(lib, "userenv.lib")
+
+namespace base {
+
+namespace {
+
+// This exit code is used by the Windows task manager when it kills a
+// process.  It's value is obviously not that unique, and it's
+// surprising to me that the task manager uses this value, but it
+// seems to be common practice on Windows to test for it as an
+// indication that the task manager has killed something if the
+// process goes away.
+const DWORD kProcessKilledExitCode = 1;
+
+}  // namespace
+
+void RouteStdioToConsole() {
+  // Don't change anything if stdout or stderr already point to a
+  // valid stream.
+  //
+  // If we are running under Buildbot or under Cygwin's default
+  // terminal (mintty), stderr and stderr will be pipe handles.  In
+  // that case, we don't want to open CONOUT$, because its output
+  // likely does not go anywhere.
+  //
+  // We don't use GetStdHandle() to check stdout/stderr here because
+  // it can return dangling IDs of handles that were never inherited
+  // by this process.  These IDs could have been reused by the time
+  // this function is called.  The CRT checks the validity of
+  // stdout/stderr on startup (before the handle IDs can be reused).
+  // _fileno(stdout) will return -2 (_NO_CONSOLE_FILENO) if stdout was
+  // invalid.
+  if (_fileno(stdout) >= 0 || _fileno(stderr) >= 0)
+    return;
+
+  if (!AttachConsole(ATTACH_PARENT_PROCESS)) {
+    unsigned int result = GetLastError();
+    // Was probably already attached.
+    if (result == ERROR_ACCESS_DENIED)
+      return;
+    // Don't bother creating a new console for each child process if the
+    // parent process is invalid (eg: crashed).
+    if (result == ERROR_GEN_FAILURE)
+      return;
+    // Make a new console if attaching to parent fails with any other error.
+    // It should be ERROR_INVALID_HANDLE at this point, which means the browser
+    // was likely not started from a console.
+    AllocConsole();
+  }
+
+  // Arbitrary byte count to use when buffering output lines.  More
+  // means potential waste, less means more risk of interleaved
+  // log-lines in output.
+  enum { kOutputBufferSize = 64 * 1024 };
+
+  if (freopen("CONOUT$", "w", stdout)) {
+    setvbuf(stdout, NULL, _IOLBF, kOutputBufferSize);
+    // Overwrite FD 1 for the benefit of any code that uses this FD
+    // directly.  This is safe because the CRT allocates FDs 0, 1 and
+    // 2 at startup even if they don't have valid underlying Windows
+    // handles.  This means we won't be overwriting an FD created by
+    // _open() after startup.
+    _dup2(_fileno(stdout), 1);
+  }
+  if (freopen("CONOUT$", "w", stderr)) {
+    setvbuf(stderr, NULL, _IOLBF, kOutputBufferSize);
+    _dup2(_fileno(stderr), 2);
+  }
+
+  // Fix all cout, wcout, cin, wcin, cerr, wcerr, clog and wclog.
+  std::ios::sync_with_stdio();
+}
+
+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();
+
+  bool inherit_handles = options.inherit_handles;
+  DWORD flags = 0;
+  if (options.handles_to_inherit) {
+    if (options.handles_to_inherit->empty()) {
+      inherit_handles = false;
+    } else {
+      if (base::win::GetVersion() < base::win::VERSION_VISTA) {
+        DLOG(ERROR) << "Specifying handles to inherit requires Vista or later.";
+        return Process();
+      }
+
+      if (options.handles_to_inherit->size() >
+              std::numeric_limits<DWORD>::max() / sizeof(HANDLE)) {
+        DLOG(ERROR) << "Too many handles to inherit.";
+        return Process();
+      }
+
+      if (!startup_info_wrapper.InitializeProcThreadAttributeList(1)) {
+        DPLOG(ERROR);
+        return Process();
+      }
+
+      if (!startup_info_wrapper.UpdateProcThreadAttribute(
+              PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
+              const_cast<HANDLE*>(&options.handles_to_inherit->at(0)),
+              static_cast<DWORD>(options.handles_to_inherit->size() *
+                  sizeof(HANDLE)))) {
+        DPLOG(ERROR);
+        return Process();
+      }
+
+      inherit_handles = true;
+      flags |= EXTENDED_STARTUPINFO_PRESENT;
+    }
+  }
+
+  if (options.empty_desktop_name)
+    startup_info->lpDesktop = const_cast<wchar_t*>(L"");
+  startup_info->dwFlags = STARTF_USESHOWWINDOW;
+  startup_info->wShowWindow = options.start_hidden ? SW_HIDE : SW_SHOW;
+
+  if (options.stdin_handle || options.stdout_handle || options.stderr_handle) {
+    DCHECK(inherit_handles);
+    DCHECK(options.stdin_handle);
+    DCHECK(options.stdout_handle);
+    DCHECK(options.stderr_handle);
+    startup_info->dwFlags |= STARTF_USESTDHANDLES;
+    startup_info->hStdInput = options.stdin_handle;
+    startup_info->hStdOutput = options.stdout_handle;
+    startup_info->hStdError = options.stderr_handle;
+  }
+
+  if (options.job_handle) {
+    flags |= CREATE_SUSPENDED;
+
+    // If this code is run under a debugger, the launched process is
+    // automatically associated with a job object created by the debugger.
+    // The CREATE_BREAKAWAY_FROM_JOB flag is used to prevent this.
+    flags |= CREATE_BREAKAWAY_FROM_JOB;
+  }
+
+  if (options.force_breakaway_from_job_)
+    flags |= CREATE_BREAKAWAY_FROM_JOB;
+
+  PROCESS_INFORMATION temp_process_info = {};
+
+  string16 writable_cmdline(cmdline);
+  if (options.as_user) {
+    flags |= CREATE_UNICODE_ENVIRONMENT;
+    void* enviroment_block = NULL;
+
+    if (!CreateEnvironmentBlock(&enviroment_block, options.as_user, FALSE)) {
+      DPLOG(ERROR);
+      return Process();
+    }
+
+    BOOL launched =
+        CreateProcessAsUser(options.as_user, NULL,
+                            &writable_cmdline[0],
+                            NULL, NULL, inherit_handles, flags,
+                            enviroment_block, NULL, startup_info,
+                            &temp_process_info);
+    DestroyEnvironmentBlock(enviroment_block);
+    if (!launched) {
+      DPLOG(ERROR) << "Command line:" << std::endl << UTF16ToUTF8(cmdline)
+                   << std::endl;;
+      return Process();
+    }
+  } else {
+    if (!CreateProcess(NULL,
+                       &writable_cmdline[0], NULL, NULL,
+                       inherit_handles, flags, NULL, NULL,
+                       startup_info, &temp_process_info)) {
+      DPLOG(ERROR) << "Command line:" << std::endl << UTF16ToUTF8(cmdline)
+                   << std::endl;;
+      return Process();
+    }
+  }
+  base::win::ScopedProcessInformation process_info(temp_process_info);
+
+  if (options.job_handle) {
+    if (0 == AssignProcessToJobObject(options.job_handle,
+                                      process_info.process_handle())) {
+      DLOG(ERROR) << "Could not AssignProcessToObject.";
+      Process scoped_process(process_info.TakeProcessHandle());
+      scoped_process.Terminate(kProcessKilledExitCode, true);
+      return Process();
+    }
+
+    ResumeThread(process_info.thread_handle());
+  }
+
+  if (options.wait)
+    WaitForSingleObject(process_info.process_handle(), INFINITE);
+
+  return Process(process_info.TakeProcessHandle());
+}
+
+Process LaunchElevatedProcess(const CommandLine& cmdline,
+                              const LaunchOptions& options) {
+  const string16 file = cmdline.GetProgram().value();
+  const string16 arguments = cmdline.GetArgumentsString();
+
+  SHELLEXECUTEINFO shex_info = {0};
+  shex_info.cbSize = sizeof(shex_info);
+  shex_info.fMask = SEE_MASK_NOCLOSEPROCESS;
+  shex_info.hwnd = GetActiveWindow();
+  shex_info.lpVerb = L"runas";
+  shex_info.lpFile = file.c_str();
+  shex_info.lpParameters = arguments.c_str();
+  shex_info.lpDirectory = NULL;
+  shex_info.nShow = options.start_hidden ? SW_HIDE : SW_SHOW;
+  shex_info.hInstApp = NULL;
+
+  if (!ShellExecuteEx(&shex_info)) {
+    DPLOG(ERROR);
+    return Process();
+  }
+
+  if (options.wait)
+    WaitForSingleObject(shex_info.hProcess, INFINITE);
+
+  return Process(shex_info.hProcess);
+}
+
+bool SetJobObjectLimitFlags(HANDLE job_object, DWORD limit_flags) {
+  JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info = {0};
+  limit_info.BasicLimitInformation.LimitFlags = limit_flags;
+  return 0 != SetInformationJobObject(
+      job_object,
+      JobObjectExtendedLimitInformation,
+      &limit_info,
+      sizeof(limit_info));
+}
+
+bool GetAppOutput(const CommandLine& cl, std::string* output) {
+  return GetAppOutput(cl.GetCommandLineString(), output);
+}
+
+bool GetAppOutput(const StringPiece16& cl, std::string* output) {
+  HANDLE out_read = NULL;
+  HANDLE out_write = NULL;
+
+  SECURITY_ATTRIBUTES sa_attr;
+  // Set the bInheritHandle flag so pipe handles are inherited.
+  sa_attr.nLength = sizeof(SECURITY_ATTRIBUTES);
+  sa_attr.bInheritHandle = TRUE;
+  sa_attr.lpSecurityDescriptor = NULL;
+
+  // Create the pipe for the child process's STDOUT.
+  if (!CreatePipe(&out_read, &out_write, &sa_attr, 0)) {
+    NOTREACHED() << "Failed to create pipe";
+    return false;
+  }
+
+  // Ensure we don't leak the handles.
+  win::ScopedHandle scoped_out_read(out_read);
+  win::ScopedHandle scoped_out_write(out_write);
+
+  // Ensure the read handle to the pipe for STDOUT is not inherited.
+  if (!SetHandleInformation(out_read, HANDLE_FLAG_INHERIT, 0)) {
+    NOTREACHED() << "Failed to disabled pipe inheritance";
+    return false;
+  }
+
+  FilePath::StringType writable_command_line_string;
+  writable_command_line_string.assign(cl.data(), cl.size());
+
+  STARTUPINFO start_info = {};
+
+  start_info.cb = sizeof(STARTUPINFO);
+  start_info.hStdOutput = out_write;
+  // Keep the normal stdin and stderr.
+  start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
+  start_info.hStdError = GetStdHandle(STD_ERROR_HANDLE);
+  start_info.dwFlags |= STARTF_USESTDHANDLES;
+
+  // Create the child process.
+  PROCESS_INFORMATION temp_process_info = {};
+  if (!CreateProcess(NULL,
+                     &writable_command_line_string[0],
+                     NULL, NULL,
+                     TRUE,  // Handles are inherited.
+                     0, NULL, NULL, &start_info, &temp_process_info)) {
+    NOTREACHED() << "Failed to start process";
+    return false;
+  }
+  base::win::ScopedProcessInformation proc_info(temp_process_info);
+
+  // Close our writing end of pipe now. Otherwise later read would not be able
+  // to detect end of child's output.
+  scoped_out_write.Close();
+
+  // Read output from the child process's pipe for STDOUT
+  const int kBufferSize = 1024;
+  char buffer[kBufferSize];
+
+  for (;;) {
+    DWORD bytes_read = 0;
+    BOOL success = ReadFile(out_read, buffer, kBufferSize, &bytes_read, NULL);
+    if (!success || bytes_read == 0)
+      break;
+    output->append(buffer, bytes_read);
+  }
+
+  // Let's wait for the process to finish.
+  WaitForSingleObject(proc_info.process_handle(), INFINITE);
+
+  return true;
+}
+
+void RaiseProcessToHighPriority() {
+  SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
+}
+
+}  // namespace base
diff --git a/base/process/memory.cc b/base/process/memory.cc
new file mode 100644
index 0000000..133a72a
--- /dev/null
+++ b/base/process/memory.cc
@@ -0,0 +1,48 @@
+// 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.
+
+#include "base/debug/alias.h"
+#include "base/logging.h"
+#include "base/process/memory.h"
+
+namespace base {
+
+namespace {
+
+// Breakpad server classifies base::`anonymous namespace'::OnNoMemory as
+// out-of-memory crash.
+NOINLINE void OnNoMemory(size_t size) {
+  size_t tmp_size = size;
+  base::debug::Alias(&tmp_size);
+  LOG(FATAL) << "Out of memory. size=" << tmp_size;
+}
+
+}  // namespace
+
+void TerminateBecauseOutOfMemory(size_t size) {
+  OnNoMemory(size);
+}
+
+// Defined in memory_mac.mm for Mac.
+#if !defined(OS_MACOSX)
+
+bool UncheckedCalloc(size_t num_items, size_t size, void** result) {
+  const size_t alloc_size = num_items * size;
+
+  // Overflow check
+  if (size && ((alloc_size / size) != num_items)) {
+    *result = NULL;
+    return false;
+  }
+
+  if (!UncheckedMalloc(alloc_size, result))
+    return false;
+
+  memset(*result, 0, alloc_size);
+  return true;
+}
+
+#endif
+
+}  // namespace base
diff --git a/base/process/memory.h b/base/process/memory.h
new file mode 100644
index 0000000..da27151
--- /dev/null
+++ b/base/process/memory.h
@@ -0,0 +1,86 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PROCESS_MEMORY_H_
+#define BASE_PROCESS_MEMORY_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/process/process_handle.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
+#ifdef PVALLOC_AVAILABLE
+// Build config explicitly tells us whether or not pvalloc is available.
+#elif defined(LIBC_GLIBC) && !defined(USE_TCMALLOC)
+#define PVALLOC_AVAILABLE 1
+#else
+#define PVALLOC_AVAILABLE 0
+#endif
+
+namespace base {
+
+// Enables low fragmentation heap (LFH) for every heaps of this process. This
+// won't have any effect on heaps created after this function call. It will not
+// modify data allocated in the heaps before calling this function. So it is
+// better to call this function early in initialization and again before
+// entering the main loop.
+// Note: Returns true on Windows 2000 without doing anything.
+BASE_EXPORT bool EnableLowFragmentationHeap();
+
+// Enables 'terminate on heap corruption' flag. Helps protect against heap
+// overflow. Has no effect if the OS doesn't provide the necessary facility.
+BASE_EXPORT void EnableTerminationOnHeapCorruption();
+
+// Turns on process termination if memory runs out.
+BASE_EXPORT void EnableTerminationOnOutOfMemory();
+
+// Terminates process. Should be called only for out of memory errors.
+// Crash reporting classifies such crashes as OOM.
+BASE_EXPORT void TerminateBecauseOutOfMemory(size_t size);
+
+#if defined(OS_WIN)
+// Returns the module handle to which an address belongs. The reference count
+// of the module is not incremented.
+BASE_EXPORT HMODULE GetModuleFromAddress(void* address);
+#endif
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+BASE_EXPORT extern size_t g_oom_size;
+
+// The maximum allowed value for the OOM score.
+const int kMaxOomScore = 1000;
+
+// This adjusts /proc/<pid>/oom_score_adj so the Linux OOM killer will
+// prefer to kill certain process types over others. The range for the
+// adjustment is [-1000, 1000], with [0, 1000] being user accessible.
+// If the Linux system doesn't support the newer oom_score_adj range
+// of [0, 1000], then we revert to using the older oom_adj, and
+// translate the given value into [0, 15].  Some aliasing of values
+// may occur in that case, of course.
+BASE_EXPORT bool AdjustOOMScore(ProcessId process, int score);
+#endif
+
+// Special allocator functions for callers that want to check for OOM.
+// These will not abort if the allocation fails even if
+// EnableTerminationOnOutOfMemory has been called.
+// This can be useful for huge and/or unpredictable size memory allocations.
+// Please only use this if you really handle the case when the allocation
+// fails. Doing otherwise would risk security.
+// These functions may still crash on OOM when running under memory tools,
+// specifically ASan and other sanitizers.
+// Return value tells whether the allocation succeeded. If it fails |result| is
+// set to NULL, otherwise it holds the memory address.
+BASE_EXPORT WARN_UNUSED_RESULT bool UncheckedMalloc(size_t size,
+                                                    void** result);
+BASE_EXPORT WARN_UNUSED_RESULT bool UncheckedCalloc(size_t num_items,
+                                                    size_t size,
+                                                    void** result);
+
+}  // namespace base
+
+#endif  // BASE_PROCESS_MEMORY_H_
diff --git a/base/process/memory_linux.cc b/base/process/memory_linux.cc
new file mode 100644
index 0000000..6dbe8b7
--- /dev/null
+++ b/base/process/memory_linux.cc
@@ -0,0 +1,213 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/memory.h"
+
+#include <new>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/process/internal_linux.h"
+#include "base/strings/string_number_conversions.h"
+
+#if defined(USE_TCMALLOC)
+// Used by UncheckedMalloc. If tcmalloc is linked to the executable
+// this will be replaced by a strong symbol that actually implement
+// the semantics and don't call new handler in case the allocation fails.
+extern "C" {
+
+__attribute__((weak, visibility("default")))
+void* tc_malloc_skip_new_handler_weak(size_t size);
+
+void* tc_malloc_skip_new_handler_weak(size_t size) {
+  return malloc(size);
+}
+
+}
+#endif
+
+namespace base {
+
+size_t g_oom_size = 0U;
+
+namespace {
+
+#if !defined(OS_ANDROID)
+void OnNoMemorySize(size_t size) {
+  g_oom_size = size;
+
+  if (size != 0)
+    LOG(FATAL) << "Out of memory, size = " << size;
+  LOG(FATAL) << "Out of memory.";
+}
+
+void OnNoMemory() {
+  OnNoMemorySize(0);
+}
+#endif  // !defined(OS_ANDROID)
+
+}  // namespace
+
+#if !defined(ADDRESS_SANITIZER) && !defined(MEMORY_SANITIZER) && \
+    !defined(THREAD_SANITIZER) && !defined(LEAK_SANITIZER)
+
+#if defined(LIBC_GLIBC) && !defined(USE_TCMALLOC)
+
+extern "C" {
+void* __libc_malloc(size_t size);
+void* __libc_realloc(void* ptr, size_t size);
+void* __libc_calloc(size_t nmemb, size_t size);
+void* __libc_valloc(size_t size);
+#if PVALLOC_AVAILABLE == 1
+void* __libc_pvalloc(size_t size);
+#endif
+void* __libc_memalign(size_t alignment, size_t size);
+
+// Overriding the system memory allocation functions:
+//
+// For security reasons, we want malloc failures to be fatal. Too much code
+// doesn't check for a NULL return value from malloc and unconditionally uses
+// the resulting pointer. If the first offset that they try to access is
+// attacker controlled, then the attacker can direct the code to access any
+// part of memory.
+//
+// Thus, we define all the standard malloc functions here and mark them as
+// visibility 'default'. This means that they replace the malloc functions for
+// all Chromium code and also for all code in shared libraries. There are tests
+// for this in process_util_unittest.cc.
+//
+// If we are using tcmalloc, then the problem is moot since tcmalloc handles
+// this for us. Thus this code is in a !defined(USE_TCMALLOC) block.
+//
+// If we are testing the binary with AddressSanitizer, we should not
+// redefine malloc and let AddressSanitizer do it instead.
+//
+// We call the real libc functions in this code by using __libc_malloc etc.
+// Previously we tried using dlsym(RTLD_NEXT, ...) but that failed depending on
+// the link order. Since ld.so needs calloc during symbol resolution, it
+// defines its own versions of several of these functions in dl-minimal.c.
+// Depending on the runtime library order, dlsym ended up giving us those
+// functions and bad things happened. See crbug.com/31809
+//
+// This means that any code which calls __libc_* gets the raw libc versions of
+// these functions.
+
+#define DIE_ON_OOM_1(function_name) \
+  void* function_name(size_t) __attribute__ ((visibility("default"))); \
+  \
+  void* function_name(size_t size) { \
+    void* ret = __libc_##function_name(size); \
+    if (ret == NULL && size != 0) \
+      OnNoMemorySize(size); \
+    return ret; \
+  }
+
+#define DIE_ON_OOM_2(function_name, arg1_type) \
+  void* function_name(arg1_type, size_t) \
+      __attribute__ ((visibility("default"))); \
+  \
+  void* function_name(arg1_type arg1, size_t size) { \
+    void* ret = __libc_##function_name(arg1, size); \
+    if (ret == NULL && size != 0) \
+      OnNoMemorySize(size); \
+    return ret; \
+  }
+
+DIE_ON_OOM_1(malloc)
+DIE_ON_OOM_1(valloc)
+#if PVALLOC_AVAILABLE == 1
+DIE_ON_OOM_1(pvalloc)
+#endif
+
+DIE_ON_OOM_2(calloc, size_t)
+DIE_ON_OOM_2(realloc, void*)
+DIE_ON_OOM_2(memalign, size_t)
+
+// posix_memalign has a unique signature and doesn't have a __libc_ variant.
+int posix_memalign(void** ptr, size_t alignment, size_t size)
+    __attribute__ ((visibility("default")));
+
+int posix_memalign(void** ptr, size_t alignment, size_t size) {
+  // This will use the safe version of memalign, above.
+  *ptr = memalign(alignment, size);
+  return 0;
+}
+
+}  // extern C
+
+#else
+
+// TODO(mostynb@opera.com): dlsym dance
+
+#endif  // LIBC_GLIBC && !USE_TCMALLOC
+
+#endif  // !*_SANITIZER
+
+void EnableTerminationOnHeapCorruption() {
+  // On Linux, there nothing to do AFAIK.
+}
+
+void EnableTerminationOnOutOfMemory() {
+#if defined(OS_ANDROID)
+  // Android doesn't support setting a new handler.
+  DLOG(WARNING) << "Not feasible.";
+#else
+  // Set the new-out of memory handler.
+  std::set_new_handler(&OnNoMemory);
+  // If we're using glibc's allocator, the above functions will override
+  // malloc and friends and make them die on out of memory.
+#endif
+}
+
+// NOTE: This is not the only version of this function in the source:
+// the setuid sandbox (in process_util_linux.c, in the sandbox source)
+// also has its own C version.
+bool AdjustOOMScore(ProcessId process, int score) {
+  if (score < 0 || score > kMaxOomScore)
+    return false;
+
+  FilePath oom_path(internal::GetProcPidDir(process));
+
+  // Attempt to write the newer oom_score_adj file first.
+  FilePath oom_file = oom_path.AppendASCII("oom_score_adj");
+  if (PathExists(oom_file)) {
+    std::string score_str = IntToString(score);
+    DVLOG(1) << "Adjusting oom_score_adj of " << process << " to "
+             << score_str;
+    int score_len = static_cast<int>(score_str.length());
+    return (score_len == WriteFile(oom_file, score_str.c_str(), score_len));
+  }
+
+  // If the oom_score_adj file doesn't exist, then we write the old
+  // style file and translate the oom_adj score to the range 0-15.
+  oom_file = oom_path.AppendASCII("oom_adj");
+  if (PathExists(oom_file)) {
+    // Max score for the old oom_adj range.  Used for conversion of new
+    // values to old values.
+    const int kMaxOldOomScore = 15;
+
+    int converted_score = score * kMaxOldOomScore / kMaxOomScore;
+    std::string score_str = IntToString(converted_score);
+    DVLOG(1) << "Adjusting oom_adj of " << process << " to " << score_str;
+    int score_len = static_cast<int>(score_str.length());
+    return (score_len == WriteFile(oom_file, score_str.c_str(), score_len));
+  }
+
+  return false;
+}
+
+bool UncheckedMalloc(size_t size, void** result) {
+#if defined(MEMORY_TOOL_REPLACES_ALLOCATOR) || \
+    (!defined(LIBC_GLIBC) && !defined(USE_TCMALLOC))
+  *result = malloc(size);
+#elif defined(LIBC_GLIBC) && !defined(USE_TCMALLOC)
+  *result = __libc_malloc(size);
+#elif defined(USE_TCMALLOC)
+  *result = tc_malloc_skip_new_handler_weak(size);
+#endif
+  return *result != NULL;
+}
+
+}  // namespace base
diff --git a/base/process/memory_mac.mm b/base/process/memory_mac.mm
new file mode 100644
index 0000000..4d719f8
--- /dev/null
+++ b/base/process/memory_mac.mm
@@ -0,0 +1,561 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/memory.h"
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <errno.h>
+#include <mach/mach.h>
+#include <mach/mach_vm.h>
+#include <malloc/malloc.h>
+#import <objc/runtime.h>
+
+#include <new>
+
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/mac/mac_util.h"
+#include "base/mac/mach_logging.h"
+#include "base/scoped_clear_errno.h"
+#include "third_party/apple_apsl/CFBase.h"
+#include "third_party/apple_apsl/malloc.h"
+
+namespace base {
+
+void EnableTerminationOnHeapCorruption() {
+#if !ARCH_CPU_64_BITS
+  DLOG(WARNING) << "EnableTerminationOnHeapCorruption only works on 64-bit";
+#endif
+}
+
+// ------------------------------------------------------------------------
+
+namespace {
+
+bool g_oom_killer_enabled;
+
+#if !defined(ADDRESS_SANITIZER)
+
+// Starting with Mac OS X 10.7, the zone allocators set up by the system are
+// read-only, to prevent them from being overwritten in an attack. However,
+// blindly unprotecting and reprotecting the zone allocators fails with
+// GuardMalloc because GuardMalloc sets up its zone allocator using a block of
+// memory in its bss. Explicit saving/restoring of the protection is required.
+//
+// This function takes a pointer to a malloc zone, de-protects it if necessary,
+// and returns (in the out parameters) a region of memory (if any) to be
+// re-protected when modifications are complete. This approach assumes that
+// there is no contention for the protection of this memory.
+void DeprotectMallocZone(ChromeMallocZone* default_zone,
+                         mach_vm_address_t* reprotection_start,
+                         mach_vm_size_t* reprotection_length,
+                         vm_prot_t* reprotection_value) {
+  mach_port_t unused;
+  *reprotection_start = reinterpret_cast<mach_vm_address_t>(default_zone);
+  struct vm_region_basic_info_64 info;
+  mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64;
+  kern_return_t result =
+      mach_vm_region(mach_task_self(),
+                     reprotection_start,
+                     reprotection_length,
+                     VM_REGION_BASIC_INFO_64,
+                     reinterpret_cast<vm_region_info_t>(&info),
+                     &count,
+                     &unused);
+  MACH_CHECK(result == KERN_SUCCESS, result) << "mach_vm_region";
+
+  // The kernel always returns a null object for VM_REGION_BASIC_INFO_64, but
+  // balance it with a deallocate in case this ever changes. See 10.9.2
+  // xnu-2422.90.20/osfmk/vm/vm_map.c vm_map_region.
+  mach_port_deallocate(mach_task_self(), unused);
+
+  // Does the region fully enclose the zone pointers? Possibly unwarranted
+  // simplification used: using the size of a full version 8 malloc zone rather
+  // than the actual smaller size if the passed-in zone is not version 8.
+  CHECK(*reprotection_start <=
+            reinterpret_cast<mach_vm_address_t>(default_zone));
+  mach_vm_size_t zone_offset = reinterpret_cast<mach_vm_size_t>(default_zone) -
+      reinterpret_cast<mach_vm_size_t>(*reprotection_start);
+  CHECK(zone_offset + sizeof(ChromeMallocZone) <= *reprotection_length);
+
+  if (info.protection & VM_PROT_WRITE) {
+    // No change needed; the zone is already writable.
+    *reprotection_start = 0;
+    *reprotection_length = 0;
+    *reprotection_value = VM_PROT_NONE;
+  } else {
+    *reprotection_value = info.protection;
+    result = mach_vm_protect(mach_task_self(),
+                             *reprotection_start,
+                             *reprotection_length,
+                             false,
+                             info.protection | VM_PROT_WRITE);
+    MACH_CHECK(result == KERN_SUCCESS, result) << "mach_vm_protect";
+  }
+}
+
+// === C malloc/calloc/valloc/realloc/posix_memalign ===
+
+typedef void* (*malloc_type)(struct _malloc_zone_t* zone,
+                             size_t size);
+typedef void* (*calloc_type)(struct _malloc_zone_t* zone,
+                             size_t num_items,
+                             size_t size);
+typedef void* (*valloc_type)(struct _malloc_zone_t* zone,
+                             size_t size);
+typedef void (*free_type)(struct _malloc_zone_t* zone,
+                          void* ptr);
+typedef void* (*realloc_type)(struct _malloc_zone_t* zone,
+                              void* ptr,
+                              size_t size);
+typedef void* (*memalign_type)(struct _malloc_zone_t* zone,
+                               size_t alignment,
+                               size_t size);
+
+malloc_type g_old_malloc;
+calloc_type g_old_calloc;
+valloc_type g_old_valloc;
+free_type g_old_free;
+realloc_type g_old_realloc;
+memalign_type g_old_memalign;
+
+malloc_type g_old_malloc_purgeable;
+calloc_type g_old_calloc_purgeable;
+valloc_type g_old_valloc_purgeable;
+free_type g_old_free_purgeable;
+realloc_type g_old_realloc_purgeable;
+memalign_type g_old_memalign_purgeable;
+
+void* oom_killer_malloc(struct _malloc_zone_t* zone,
+                        size_t size) {
+  void* result = g_old_malloc(zone, size);
+  if (!result && size)
+    TerminateBecauseOutOfMemory(size);
+  return result;
+}
+
+void* oom_killer_calloc(struct _malloc_zone_t* zone,
+                        size_t num_items,
+                        size_t size) {
+  void* result = g_old_calloc(zone, num_items, size);
+  if (!result && num_items && size)
+    TerminateBecauseOutOfMemory(num_items * size);
+  return result;
+}
+
+void* oom_killer_valloc(struct _malloc_zone_t* zone,
+                        size_t size) {
+  void* result = g_old_valloc(zone, size);
+  if (!result && size)
+    TerminateBecauseOutOfMemory(size);
+  return result;
+}
+
+void oom_killer_free(struct _malloc_zone_t* zone,
+                     void* ptr) {
+  g_old_free(zone, ptr);
+}
+
+void* oom_killer_realloc(struct _malloc_zone_t* zone,
+                         void* ptr,
+                         size_t size) {
+  void* result = g_old_realloc(zone, ptr, size);
+  if (!result && size)
+    TerminateBecauseOutOfMemory(size);
+  return result;
+}
+
+void* oom_killer_memalign(struct _malloc_zone_t* zone,
+                          size_t alignment,
+                          size_t size) {
+  void* result = g_old_memalign(zone, alignment, size);
+  // Only die if posix_memalign would have returned ENOMEM, since there are
+  // other reasons why NULL might be returned (see
+  // http://opensource.apple.com/source/Libc/Libc-583/gen/malloc.c ).
+  if (!result && size && alignment >= sizeof(void*) &&
+      (alignment & (alignment - 1)) == 0) {
+    TerminateBecauseOutOfMemory(size);
+  }
+  return result;
+}
+
+void* oom_killer_malloc_purgeable(struct _malloc_zone_t* zone,
+                                  size_t size) {
+  void* result = g_old_malloc_purgeable(zone, size);
+  if (!result && size)
+    TerminateBecauseOutOfMemory(size);
+  return result;
+}
+
+void* oom_killer_calloc_purgeable(struct _malloc_zone_t* zone,
+                                  size_t num_items,
+                                  size_t size) {
+  void* result = g_old_calloc_purgeable(zone, num_items, size);
+  if (!result && num_items && size)
+    TerminateBecauseOutOfMemory(num_items * size);
+  return result;
+}
+
+void* oom_killer_valloc_purgeable(struct _malloc_zone_t* zone,
+                                  size_t size) {
+  void* result = g_old_valloc_purgeable(zone, size);
+  if (!result && size)
+    TerminateBecauseOutOfMemory(size);
+  return result;
+}
+
+void oom_killer_free_purgeable(struct _malloc_zone_t* zone,
+                               void* ptr) {
+  g_old_free_purgeable(zone, ptr);
+}
+
+void* oom_killer_realloc_purgeable(struct _malloc_zone_t* zone,
+                                   void* ptr,
+                                   size_t size) {
+  void* result = g_old_realloc_purgeable(zone, ptr, size);
+  if (!result && size)
+    TerminateBecauseOutOfMemory(size);
+  return result;
+}
+
+void* oom_killer_memalign_purgeable(struct _malloc_zone_t* zone,
+                                    size_t alignment,
+                                    size_t size) {
+  void* result = g_old_memalign_purgeable(zone, alignment, size);
+  // Only die if posix_memalign would have returned ENOMEM, since there are
+  // other reasons why NULL might be returned (see
+  // http://opensource.apple.com/source/Libc/Libc-583/gen/malloc.c ).
+  if (!result && size && alignment >= sizeof(void*)
+      && (alignment & (alignment - 1)) == 0) {
+    TerminateBecauseOutOfMemory(size);
+  }
+  return result;
+}
+
+#endif  // !defined(ADDRESS_SANITIZER)
+
+// === C++ operator new ===
+
+void oom_killer_new() {
+  TerminateBecauseOutOfMemory(0);
+}
+
+#if !defined(ADDRESS_SANITIZER)
+
+// === Core Foundation CFAllocators ===
+
+bool CanGetContextForCFAllocator() {
+  return !base::mac::IsOSLaterThanYosemite_DontCallThis();
+}
+
+CFAllocatorContext* ContextForCFAllocator(CFAllocatorRef allocator) {
+  if (base::mac::IsOSSnowLeopard()) {
+    ChromeCFAllocatorLeopards* our_allocator =
+        const_cast<ChromeCFAllocatorLeopards*>(
+            reinterpret_cast<const ChromeCFAllocatorLeopards*>(allocator));
+    return &our_allocator->_context;
+  } else if (base::mac::IsOSLion() ||
+             base::mac::IsOSMountainLion() ||
+             base::mac::IsOSMavericks() ||
+             base::mac::IsOSYosemite()) {
+    ChromeCFAllocatorLions* our_allocator =
+        const_cast<ChromeCFAllocatorLions*>(
+            reinterpret_cast<const ChromeCFAllocatorLions*>(allocator));
+    return &our_allocator->_context;
+  } else {
+    return NULL;
+  }
+}
+
+CFAllocatorAllocateCallBack g_old_cfallocator_system_default;
+CFAllocatorAllocateCallBack g_old_cfallocator_malloc;
+CFAllocatorAllocateCallBack g_old_cfallocator_malloc_zone;
+
+void* oom_killer_cfallocator_system_default(CFIndex alloc_size,
+                                            CFOptionFlags hint,
+                                            void* info) {
+  void* result = g_old_cfallocator_system_default(alloc_size, hint, info);
+  if (!result)
+    TerminateBecauseOutOfMemory(alloc_size);
+  return result;
+}
+
+void* oom_killer_cfallocator_malloc(CFIndex alloc_size,
+                                    CFOptionFlags hint,
+                                    void* info) {
+  void* result = g_old_cfallocator_malloc(alloc_size, hint, info);
+  if (!result)
+    TerminateBecauseOutOfMemory(alloc_size);
+  return result;
+}
+
+void* oom_killer_cfallocator_malloc_zone(CFIndex alloc_size,
+                                         CFOptionFlags hint,
+                                         void* info) {
+  void* result = g_old_cfallocator_malloc_zone(alloc_size, hint, info);
+  if (!result)
+    TerminateBecauseOutOfMemory(alloc_size);
+  return result;
+}
+
+#endif  // !defined(ADDRESS_SANITIZER)
+
+// === Cocoa NSObject allocation ===
+
+typedef id (*allocWithZone_t)(id, SEL, NSZone*);
+allocWithZone_t g_old_allocWithZone;
+
+id oom_killer_allocWithZone(id self, SEL _cmd, NSZone* zone)
+{
+  id result = g_old_allocWithZone(self, _cmd, zone);
+  if (!result)
+    TerminateBecauseOutOfMemory(0);
+  return result;
+}
+
+}  // namespace
+
+bool UncheckedMalloc(size_t size, void** result) {
+#if defined(ADDRESS_SANITIZER)
+  *result = malloc(size);
+#else
+  if (g_old_malloc) {
+    *result = g_old_malloc(malloc_default_zone(), size);
+  } else {
+    *result = malloc(size);
+  }
+#endif  // defined(ADDRESS_SANITIZER)
+
+  return *result != NULL;
+}
+
+bool UncheckedCalloc(size_t num_items, size_t size, void** result) {
+#if defined(ADDRESS_SANITIZER)
+  *result = calloc(num_items, size);
+#else
+  if (g_old_calloc) {
+    *result = g_old_calloc(malloc_default_zone(), num_items, size);
+  } else {
+    *result = calloc(num_items, size);
+  }
+#endif  // defined(ADDRESS_SANITIZER)
+
+  return *result != NULL;
+}
+
+void* UncheckedMalloc(size_t size) {
+  void* address;
+  return UncheckedMalloc(size, &address) ? address : NULL;
+}
+
+void* UncheckedCalloc(size_t num_items, size_t size) {
+  void* address;
+  return UncheckedCalloc(num_items, size, &address) ? address : NULL;
+}
+
+void EnableTerminationOnOutOfMemory() {
+  if (g_oom_killer_enabled)
+    return;
+
+  g_oom_killer_enabled = true;
+
+  // === C malloc/calloc/valloc/realloc/posix_memalign ===
+
+  // This approach is not perfect, as requests for amounts of memory larger than
+  // MALLOC_ABSOLUTE_MAX_SIZE (currently SIZE_T_MAX - (2 * PAGE_SIZE)) will
+  // still fail with a NULL rather than dying (see
+  // http://opensource.apple.com/source/Libc/Libc-583/gen/malloc.c for details).
+  // Unfortunately, it's the best we can do. Also note that this does not affect
+  // allocations from non-default zones.
+
+#if !defined(ADDRESS_SANITIZER)
+  // Don't do anything special on OOM for the malloc zones replaced by
+  // AddressSanitizer, as modifying or protecting them may not work correctly.
+
+  CHECK(!g_old_malloc && !g_old_calloc && !g_old_valloc && !g_old_realloc &&
+        !g_old_memalign) << "Old allocators unexpectedly non-null";
+
+  CHECK(!g_old_malloc_purgeable && !g_old_calloc_purgeable &&
+        !g_old_valloc_purgeable && !g_old_realloc_purgeable &&
+        !g_old_memalign_purgeable) << "Old allocators unexpectedly non-null";
+
+  ChromeMallocZone* default_zone =
+      reinterpret_cast<ChromeMallocZone*>(malloc_default_zone());
+  ChromeMallocZone* purgeable_zone =
+      reinterpret_cast<ChromeMallocZone*>(malloc_default_purgeable_zone());
+
+  mach_vm_address_t default_reprotection_start = 0;
+  mach_vm_size_t default_reprotection_length = 0;
+  vm_prot_t default_reprotection_value = VM_PROT_NONE;
+  DeprotectMallocZone(default_zone,
+                      &default_reprotection_start,
+                      &default_reprotection_length,
+                      &default_reprotection_value);
+
+  mach_vm_address_t purgeable_reprotection_start = 0;
+  mach_vm_size_t purgeable_reprotection_length = 0;
+  vm_prot_t purgeable_reprotection_value = VM_PROT_NONE;
+  if (purgeable_zone) {
+    DeprotectMallocZone(purgeable_zone,
+                        &purgeable_reprotection_start,
+                        &purgeable_reprotection_length,
+                        &purgeable_reprotection_value);
+  }
+
+  // Default zone
+
+  g_old_malloc = default_zone->malloc;
+  g_old_calloc = default_zone->calloc;
+  g_old_valloc = default_zone->valloc;
+  g_old_free = default_zone->free;
+  g_old_realloc = default_zone->realloc;
+  CHECK(g_old_malloc && g_old_calloc && g_old_valloc && g_old_free &&
+        g_old_realloc)
+      << "Failed to get system allocation functions.";
+
+  default_zone->malloc = oom_killer_malloc;
+  default_zone->calloc = oom_killer_calloc;
+  default_zone->valloc = oom_killer_valloc;
+  default_zone->free = oom_killer_free;
+  default_zone->realloc = oom_killer_realloc;
+
+  if (default_zone->version >= 5) {
+    g_old_memalign = default_zone->memalign;
+    if (g_old_memalign)
+      default_zone->memalign = oom_killer_memalign;
+  }
+
+  // Purgeable zone (if it exists)
+
+  if (purgeable_zone) {
+    g_old_malloc_purgeable = purgeable_zone->malloc;
+    g_old_calloc_purgeable = purgeable_zone->calloc;
+    g_old_valloc_purgeable = purgeable_zone->valloc;
+    g_old_free_purgeable = purgeable_zone->free;
+    g_old_realloc_purgeable = purgeable_zone->realloc;
+    CHECK(g_old_malloc_purgeable && g_old_calloc_purgeable &&
+          g_old_valloc_purgeable && g_old_free_purgeable &&
+          g_old_realloc_purgeable)
+        << "Failed to get system allocation functions.";
+
+    purgeable_zone->malloc = oom_killer_malloc_purgeable;
+    purgeable_zone->calloc = oom_killer_calloc_purgeable;
+    purgeable_zone->valloc = oom_killer_valloc_purgeable;
+    purgeable_zone->free = oom_killer_free_purgeable;
+    purgeable_zone->realloc = oom_killer_realloc_purgeable;
+
+    if (purgeable_zone->version >= 5) {
+      g_old_memalign_purgeable = purgeable_zone->memalign;
+      if (g_old_memalign_purgeable)
+        purgeable_zone->memalign = oom_killer_memalign_purgeable;
+    }
+  }
+
+  // Restore protection if it was active.
+
+  if (default_reprotection_start) {
+    kern_return_t result = mach_vm_protect(mach_task_self(),
+                                           default_reprotection_start,
+                                           default_reprotection_length,
+                                           false,
+                                           default_reprotection_value);
+    MACH_CHECK(result == KERN_SUCCESS, result) << "mach_vm_protect";
+  }
+
+  if (purgeable_reprotection_start) {
+    kern_return_t result = mach_vm_protect(mach_task_self(),
+                                           purgeable_reprotection_start,
+                                           purgeable_reprotection_length,
+                                           false,
+                                           purgeable_reprotection_value);
+    MACH_CHECK(result == KERN_SUCCESS, result) << "mach_vm_protect";
+  }
+#endif
+
+  // === C malloc_zone_batch_malloc ===
+
+  // batch_malloc is omitted because the default malloc zone's implementation
+  // only supports batch_malloc for "tiny" allocations from the free list. It
+  // will fail for allocations larger than "tiny", and will only allocate as
+  // many blocks as it's able to from the free list. These factors mean that it
+  // can return less than the requested memory even in a non-out-of-memory
+  // situation. There's no good way to detect whether a batch_malloc failure is
+  // due to these other factors, or due to genuine memory or address space
+  // exhaustion. The fact that it only allocates space from the "tiny" free list
+  // means that it's likely that a failure will not be due to memory exhaustion.
+  // Similarly, these constraints on batch_malloc mean that callers must always
+  // be expecting to receive less memory than was requested, even in situations
+  // where memory pressure is not a concern. Finally, the only public interface
+  // to batch_malloc is malloc_zone_batch_malloc, which is specific to the
+  // system's malloc implementation. It's unlikely that anyone's even heard of
+  // it.
+
+  // === C++ operator new ===
+
+  // Yes, operator new does call through to malloc, but this will catch failures
+  // that our imperfect handling of malloc cannot.
+
+  std::set_new_handler(oom_killer_new);
+
+#ifndef ADDRESS_SANITIZER
+  // === Core Foundation CFAllocators ===
+
+  // This will not catch allocation done by custom allocators, but will catch
+  // all allocation done by system-provided ones.
+
+  CHECK(!g_old_cfallocator_system_default && !g_old_cfallocator_malloc &&
+        !g_old_cfallocator_malloc_zone)
+      << "Old allocators unexpectedly non-null";
+
+  bool cf_allocator_internals_known = CanGetContextForCFAllocator();
+
+  if (cf_allocator_internals_known) {
+    CFAllocatorContext* context =
+        ContextForCFAllocator(kCFAllocatorSystemDefault);
+    CHECK(context) << "Failed to get context for kCFAllocatorSystemDefault.";
+    g_old_cfallocator_system_default = context->allocate;
+    CHECK(g_old_cfallocator_system_default)
+        << "Failed to get kCFAllocatorSystemDefault allocation function.";
+    context->allocate = oom_killer_cfallocator_system_default;
+
+    context = ContextForCFAllocator(kCFAllocatorMalloc);
+    CHECK(context) << "Failed to get context for kCFAllocatorMalloc.";
+    g_old_cfallocator_malloc = context->allocate;
+    CHECK(g_old_cfallocator_malloc)
+        << "Failed to get kCFAllocatorMalloc allocation function.";
+    context->allocate = oom_killer_cfallocator_malloc;
+
+    context = ContextForCFAllocator(kCFAllocatorMallocZone);
+    CHECK(context) << "Failed to get context for kCFAllocatorMallocZone.";
+    g_old_cfallocator_malloc_zone = context->allocate;
+    CHECK(g_old_cfallocator_malloc_zone)
+        << "Failed to get kCFAllocatorMallocZone allocation function.";
+    context->allocate = oom_killer_cfallocator_malloc_zone;
+  } else {
+    DLOG(WARNING) << "Internals of CFAllocator not known; out-of-memory "
+                     "failures via CFAllocator will not result in termination. "
+                     "http://crbug.com/45650";
+  }
+#endif
+
+  // === Cocoa NSObject allocation ===
+
+  // Note that both +[NSObject new] and +[NSObject alloc] call through to
+  // +[NSObject allocWithZone:].
+
+  CHECK(!g_old_allocWithZone)
+      << "Old allocator unexpectedly non-null";
+
+  Class nsobject_class = [NSObject class];
+  Method orig_method = class_getClassMethod(nsobject_class,
+                                            @selector(allocWithZone:));
+  g_old_allocWithZone = reinterpret_cast<allocWithZone_t>(
+      method_getImplementation(orig_method));
+  CHECK(g_old_allocWithZone)
+      << "Failed to get allocWithZone allocation function.";
+  method_setImplementation(orig_method,
+                           reinterpret_cast<IMP>(oom_killer_allocWithZone));
+}
+
+}  // namespace base
diff --git a/base/process/memory_stubs.cc b/base/process/memory_stubs.cc
new file mode 100644
index 0000000..b06c7d5
--- /dev/null
+++ b/base/process/memory_stubs.cc
@@ -0,0 +1,19 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/memory.h"
+
+namespace base {
+
+void EnableTerminationOnOutOfMemory() {
+}
+
+void EnableTerminationOnHeapCorruption() {
+}
+
+bool AdjustOOMScore(ProcessId process, int score) {
+  return false;
+}
+
+}  // namespace base
diff --git a/base/process/memory_unittest.cc b/base/process/memory_unittest.cc
new file mode 100644
index 0000000..0276b49
--- /dev/null
+++ b/base/process/memory_unittest.cc
@@ -0,0 +1,419 @@
+// Copyright (c) 2012 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.
+
+#define _CRT_SECURE_NO_WARNINGS
+
+#include "base/process/memory.h"
+
+#include <limits>
+
+#include "base/compiler_specific.h"
+#include "base/debug/alias.h"
+#include "base/strings/stringprintf.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+#if defined(OS_POSIX)
+#include <errno.h>
+#endif
+#if defined(OS_MACOSX)
+#include <malloc/malloc.h>
+#include "base/mac/mac_util.h"
+#include "base/process/memory_unittest_mac.h"
+#endif
+#if defined(OS_LINUX)
+#include <malloc.h>
+#include "base/test/malloc_wrapper.h"
+#endif
+
+#if defined(OS_WIN)
+// HeapQueryInformation function pointer.
+typedef BOOL (WINAPI* HeapQueryFn)  \
+    (HANDLE, HEAP_INFORMATION_CLASS, PVOID, SIZE_T, PSIZE_T);
+
+const int kConstantInModule = 42;
+
+TEST(ProcessMemoryTest, GetModuleFromAddress) {
+  // Since the unit tests are their own EXE, this should be
+  // equivalent to the EXE's HINSTANCE.
+  //
+  // kConstantInModule is a constant in this file and
+  // therefore within the unit test EXE.
+  EXPECT_EQ(::GetModuleHandle(NULL),
+            base::GetModuleFromAddress(
+                const_cast<int*>(&kConstantInModule)));
+
+  // Any address within the kernel32 module should return
+  // kernel32's HMODULE.  Our only assumption here is that
+  // kernel32 is larger than 4 bytes.
+  HMODULE kernel32 = ::GetModuleHandle(L"kernel32.dll");
+  HMODULE kernel32_from_address =
+      base::GetModuleFromAddress(reinterpret_cast<DWORD*>(kernel32) + 1);
+  EXPECT_EQ(kernel32, kernel32_from_address);
+}
+
+TEST(ProcessMemoryTest, EnableLFH) {
+  ASSERT_TRUE(base::EnableLowFragmentationHeap());
+  if (IsDebuggerPresent()) {
+    // Under these conditions, LFH can't be enabled. There's no point to test
+    // anything.
+    const char* no_debug_env = getenv("_NO_DEBUG_HEAP");
+    if (!no_debug_env || strcmp(no_debug_env, "1"))
+      return;
+  }
+  HMODULE kernel32 = GetModuleHandle(L"kernel32.dll");
+  ASSERT_TRUE(kernel32 != NULL);
+  HeapQueryFn heap_query = reinterpret_cast<HeapQueryFn>(GetProcAddress(
+      kernel32,
+      "HeapQueryInformation"));
+
+  // On Windows 2000, the function is not exported. This is not a reason to
+  // fail but we won't be able to retrieves information about the heap, so we
+  // should stop here.
+  if (heap_query == NULL)
+    return;
+
+  HANDLE heaps[1024] = { 0 };
+  unsigned number_heaps = GetProcessHeaps(1024, heaps);
+  EXPECT_GT(number_heaps, 0u);
+  for (unsigned i = 0; i < number_heaps; ++i) {
+    ULONG flag = 0;
+    SIZE_T length;
+    ASSERT_NE(0, heap_query(heaps[i],
+                            HeapCompatibilityInformation,
+                            &flag,
+                            sizeof(flag),
+                            &length));
+    // If flag is 0, the heap is a standard heap that does not support
+    // look-asides. If flag is 1, the heap supports look-asides. If flag is 2,
+    // the heap is a low-fragmentation heap (LFH). Note that look-asides are not
+    // supported on the LFH.
+
+    // We don't have any documented way of querying the HEAP_NO_SERIALIZE flag.
+    EXPECT_LE(flag, 2u);
+    EXPECT_NE(flag, 1u);
+  }
+}
+#endif  // defined(OS_WIN)
+
+#if defined(OS_MACOSX)
+
+// For the following Mac tests:
+// Note that base::EnableTerminationOnHeapCorruption() is called as part of
+// test suite setup and does not need to be done again, else mach_override
+// will fail.
+
+TEST(ProcessMemoryTest, MacTerminateOnHeapCorruption) {
+  // Assert that freeing an unallocated pointer will crash the process.
+  char buf[9];
+  asm("" : "=r" (buf));  // Prevent clang from being too smart.
+#if ARCH_CPU_64_BITS
+  // On 64 bit Macs, the malloc system automatically abort()s on heap corruption
+  // but does not output anything.
+  ASSERT_DEATH(free(buf), "");
+#elif defined(ADDRESS_SANITIZER)
+  // AddressSanitizer replaces malloc() and prints a different error message on
+  // heap corruption.
+  ASSERT_DEATH(free(buf), "attempting free on address which "
+      "was not malloc\\(\\)-ed");
+#else
+  ADD_FAILURE() << "This test is not supported in this build configuration.";
+#endif
+}
+
+#endif  // defined(OS_MACOSX)
+
+// Android doesn't implement set_new_handler, so we can't use the
+// OutOfMemoryTest cases. OpenBSD does not support these tests either.
+// Don't test these on ASan/TSan/MSan configurations: only test the real
+// allocator.
+// TODO(vandebo) make this work on Windows too.
+#if !defined(OS_ANDROID) && !defined(OS_OPENBSD) && !defined(OS_WIN) && \
+    !defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
+
+#if defined(USE_TCMALLOC)
+extern "C" {
+int tc_set_new_mode(int mode);
+}
+#endif  // defined(USE_TCMALLOC)
+
+namespace {
+const char *kOomRegex = "Out of memory";
+}  // namespace
+
+class OutOfMemoryTest : public testing::Test {
+ public:
+  OutOfMemoryTest()
+    : value_(NULL),
+    // Make test size as large as possible minus a few pages so
+    // that alignment or other rounding doesn't make it wrap.
+    test_size_(std::numeric_limits<std::size_t>::max() - 12 * 1024),
+    signed_test_size_(std::numeric_limits<ssize_t>::max()) {
+  }
+
+#if defined(USE_TCMALLOC)
+  void SetUp() override { tc_set_new_mode(1); }
+
+  void TearDown() override { tc_set_new_mode(0); }
+#endif  // defined(USE_TCMALLOC)
+
+ protected:
+  void* value_;
+  size_t test_size_;
+  ssize_t signed_test_size_;
+};
+
+class OutOfMemoryDeathTest : public OutOfMemoryTest {
+ public:
+  void SetUpInDeathAssert() {
+    // Must call EnableTerminationOnOutOfMemory() because that is called from
+    // chrome's main function and therefore hasn't been called yet.
+    // Since this call may result in another thread being created and death
+    // tests shouldn't be started in a multithread environment, this call
+    // should be done inside of the ASSERT_DEATH.
+    base::EnableTerminationOnOutOfMemory();
+  }
+};
+
+TEST_F(OutOfMemoryDeathTest, New) {
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = operator new(test_size_);
+    }, kOomRegex);
+}
+
+TEST_F(OutOfMemoryDeathTest, NewArray) {
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = new char[test_size_];
+    }, kOomRegex);
+}
+
+TEST_F(OutOfMemoryDeathTest, Malloc) {
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = malloc(test_size_);
+    }, kOomRegex);
+}
+
+TEST_F(OutOfMemoryDeathTest, Realloc) {
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = realloc(NULL, test_size_);
+    }, kOomRegex);
+}
+
+TEST_F(OutOfMemoryDeathTest, Calloc) {
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = calloc(1024, test_size_ / 1024L);
+    }, kOomRegex);
+}
+
+TEST_F(OutOfMemoryDeathTest, Valloc) {
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = valloc(test_size_);
+    }, kOomRegex);
+}
+
+#if defined(OS_LINUX)
+
+#if PVALLOC_AVAILABLE == 1
+TEST_F(OutOfMemoryDeathTest, Pvalloc) {
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = pvalloc(test_size_);
+    }, kOomRegex);
+}
+#endif  // PVALLOC_AVAILABLE == 1
+
+TEST_F(OutOfMemoryDeathTest, Memalign) {
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = memalign(4, test_size_);
+    }, kOomRegex);
+}
+
+TEST_F(OutOfMemoryDeathTest, ViaSharedLibraries) {
+  // This tests that the run-time symbol resolution is overriding malloc for
+  // shared libraries as well as for our code.
+  ASSERT_DEATH({
+    SetUpInDeathAssert();
+    value_ = MallocWrapper(test_size_);
+  }, kOomRegex);
+}
+#endif  // OS_LINUX
+
+// Android doesn't implement posix_memalign().
+#if defined(OS_POSIX) && !defined(OS_ANDROID)
+TEST_F(OutOfMemoryDeathTest, Posix_memalign) {
+  // Grab the return value of posix_memalign to silence a compiler warning
+  // about unused return values. We don't actually care about the return
+  // value, since we're asserting death.
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      EXPECT_EQ(ENOMEM, posix_memalign(&value_, 8, test_size_));
+    }, kOomRegex);
+}
+#endif  // defined(OS_POSIX) && !defined(OS_ANDROID)
+
+#if defined(OS_MACOSX)
+
+// Purgeable zone tests
+
+TEST_F(OutOfMemoryDeathTest, MallocPurgeable) {
+  malloc_zone_t* zone = malloc_default_purgeable_zone();
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = malloc_zone_malloc(zone, test_size_);
+    }, kOomRegex);
+}
+
+TEST_F(OutOfMemoryDeathTest, ReallocPurgeable) {
+  malloc_zone_t* zone = malloc_default_purgeable_zone();
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = malloc_zone_realloc(zone, NULL, test_size_);
+    }, kOomRegex);
+}
+
+TEST_F(OutOfMemoryDeathTest, CallocPurgeable) {
+  malloc_zone_t* zone = malloc_default_purgeable_zone();
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = malloc_zone_calloc(zone, 1024, test_size_ / 1024L);
+    }, kOomRegex);
+}
+
+TEST_F(OutOfMemoryDeathTest, VallocPurgeable) {
+  malloc_zone_t* zone = malloc_default_purgeable_zone();
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = malloc_zone_valloc(zone, test_size_);
+    }, kOomRegex);
+}
+
+TEST_F(OutOfMemoryDeathTest, PosixMemalignPurgeable) {
+  malloc_zone_t* zone = malloc_default_purgeable_zone();
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      value_ = malloc_zone_memalign(zone, 8, test_size_);
+    }, kOomRegex);
+}
+
+// Since these allocation functions take a signed size, it's possible that
+// calling them just once won't be enough to exhaust memory. In the 32-bit
+// environment, it's likely that these allocation attempts will fail because
+// not enough contiguous address space is available. In the 64-bit environment,
+// it's likely that they'll fail because they would require a preposterous
+// amount of (virtual) memory.
+
+TEST_F(OutOfMemoryDeathTest, CFAllocatorSystemDefault) {
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      while ((value_ =
+              base::AllocateViaCFAllocatorSystemDefault(signed_test_size_))) {}
+    }, kOomRegex);
+}
+
+TEST_F(OutOfMemoryDeathTest, CFAllocatorMalloc) {
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      while ((value_ =
+              base::AllocateViaCFAllocatorMalloc(signed_test_size_))) {}
+    }, kOomRegex);
+}
+
+TEST_F(OutOfMemoryDeathTest, CFAllocatorMallocZone) {
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      while ((value_ =
+              base::AllocateViaCFAllocatorMallocZone(signed_test_size_))) {}
+    }, kOomRegex);
+}
+
+#if !defined(ARCH_CPU_64_BITS)
+
+// See process_util_unittest_mac.mm for an explanation of why this test isn't
+// run in the 64-bit environment.
+
+TEST_F(OutOfMemoryDeathTest, PsychoticallyBigObjCObject) {
+  ASSERT_DEATH({
+      SetUpInDeathAssert();
+      while ((value_ = base::AllocatePsychoticallyBigObjCObject())) {}
+    }, kOomRegex);
+}
+
+#endif  // !ARCH_CPU_64_BITS
+#endif  // OS_MACOSX
+
+class OutOfMemoryHandledTest : public OutOfMemoryTest {
+ public:
+  static const size_t kSafeMallocSize = 512;
+  static const size_t kSafeCallocSize = 128;
+  static const size_t kSafeCallocItems = 4;
+
+  void SetUp() override {
+    OutOfMemoryTest::SetUp();
+
+    // We enable termination on OOM - just as Chrome does at early
+    // initialization - and test that UncheckedMalloc and  UncheckedCalloc
+    // properly by-pass this in order to allow the caller to handle OOM.
+    base::EnableTerminationOnOutOfMemory();
+  }
+};
+
+// TODO(b.kelemen): make UncheckedMalloc and UncheckedCalloc work
+// on Windows as well.
+// UncheckedMalloc() and UncheckedCalloc() work as regular malloc()/calloc()
+// under sanitizer tools.
+#if !defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
+TEST_F(OutOfMemoryHandledTest, UncheckedMalloc) {
+#if defined(OS_MACOSX) && ARCH_CPU_32_BITS
+  // The Mavericks malloc library changed in a way which breaks the tricks used
+  // to implement EnableTerminationOnOutOfMemory() with UncheckedMalloc() under
+  // 32-bit.  The 64-bit malloc library works as desired without tricks.
+  if (base::mac::IsOSMavericksOrLater())
+    return;
+#endif
+  EXPECT_TRUE(base::UncheckedMalloc(kSafeMallocSize, &value_));
+  EXPECT_TRUE(value_ != NULL);
+  free(value_);
+
+  EXPECT_FALSE(base::UncheckedMalloc(test_size_, &value_));
+  EXPECT_TRUE(value_ == NULL);
+}
+
+TEST_F(OutOfMemoryHandledTest, UncheckedCalloc) {
+#if defined(OS_MACOSX) && ARCH_CPU_32_BITS
+  // The Mavericks malloc library changed in a way which breaks the tricks used
+  // to implement EnableTerminationOnOutOfMemory() with UncheckedCalloc() under
+  // 32-bit.  The 64-bit malloc library works as desired without tricks.
+  if (base::mac::IsOSMavericksOrLater())
+    return;
+#endif
+  EXPECT_TRUE(base::UncheckedCalloc(1, kSafeMallocSize, &value_));
+  EXPECT_TRUE(value_ != NULL);
+  const char* bytes = static_cast<const char*>(value_);
+  for (size_t i = 0; i < kSafeMallocSize; ++i)
+    EXPECT_EQ(0, bytes[i]);
+  free(value_);
+
+  EXPECT_TRUE(
+      base::UncheckedCalloc(kSafeCallocItems, kSafeCallocSize, &value_));
+  EXPECT_TRUE(value_ != NULL);
+  bytes = static_cast<const char*>(value_);
+  for (size_t i = 0; i < (kSafeCallocItems * kSafeCallocSize); ++i)
+    EXPECT_EQ(0, bytes[i]);
+  free(value_);
+
+  EXPECT_FALSE(base::UncheckedCalloc(1, test_size_, &value_));
+  EXPECT_TRUE(value_ == NULL);
+}
+#endif  // !defined(MEMORY_TOOL_REPLACES_ALLOCATOR)
+#endif  // !defined(OS_ANDROID) && !defined(OS_OPENBSD) && !defined(OS_WIN) &&
+        // !defined(ADDRESS_SANITIZER)
diff --git a/base/process/memory_unittest_mac.h b/base/process/memory_unittest_mac.h
new file mode 100644
index 0000000..472d2c5
--- /dev/null
+++ b/base/process/memory_unittest_mac.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2010 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 contains helpers for the process_util_unittest to allow it to fully
+// test the Mac code.
+
+#ifndef BASE_PROCESS_MEMORY_UNITTEST_MAC_H_
+#define BASE_PROCESS_MEMORY_UNITTEST_MAC_H_
+
+#include "base/basictypes.h"
+
+namespace base {
+
+// Allocates memory via system allocators. Alas, they take a _signed_ size for
+// allocation.
+void* AllocateViaCFAllocatorSystemDefault(ssize_t size);
+void* AllocateViaCFAllocatorMalloc(ssize_t size);
+void* AllocateViaCFAllocatorMallocZone(ssize_t size);
+
+#if !defined(ARCH_CPU_64_BITS)
+// See process_util_unittest_mac.mm for an explanation of why this function
+// isn't implemented for the 64-bit environment.
+
+// Allocates a huge Objective C object.
+void* AllocatePsychoticallyBigObjCObject();
+
+#endif  // !ARCH_CPU_64_BITS
+
+}  // namespace base
+
+#endif  // BASE_PROCESS_MEMORY_UNITTEST_MAC_H_
diff --git a/base/process/memory_unittest_mac.mm b/base/process/memory_unittest_mac.mm
new file mode 100644
index 0000000..bc4bf65
--- /dev/null
+++ b/base/process/memory_unittest_mac.mm
@@ -0,0 +1,59 @@
+// Copyright (c) 2010 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/process/memory_unittest_mac.h"
+
+#import <Foundation/Foundation.h>
+#include <CoreFoundation/CoreFoundation.h>
+
+#if !defined(ARCH_CPU_64_BITS)
+
+// In the 64-bit environment, the Objective-C 2.0 Runtime Reference states
+// that sizeof(anInstance) is constrained to 32 bits. That's not necessarily
+// "psychotically big" and in fact a 64-bit program is expected to be able to
+// successfully allocate an object that large, likely reserving a good deal of
+// swap space. The only way to test the behavior of memory exhaustion for
+// Objective-C allocation in this environment would be to loop over allocation
+// of these large objects, but that would slowly consume all available memory
+// and cause swap file proliferation. That's bad, so this behavior isn't
+// tested in the 64-bit environment.
+
+@interface PsychoticallyBigObjCObject : NSObject
+{
+  // In the 32-bit environment, the compiler limits Objective-C objects to
+  // < 2GB in size.
+  int justUnder2Gigs_[(2U * 1024 * 1024 * 1024 - 1) / sizeof(int)];
+}
+
+@end
+
+@implementation PsychoticallyBigObjCObject
+
+@end
+
+namespace base {
+
+void* AllocatePsychoticallyBigObjCObject() {
+  return [[PsychoticallyBigObjCObject alloc] init];
+}
+
+}  // namespace base
+
+#endif  // ARCH_CPU_64_BITS
+
+namespace base {
+
+void* AllocateViaCFAllocatorSystemDefault(ssize_t size) {
+  return CFAllocatorAllocate(kCFAllocatorSystemDefault, size, 0);
+}
+
+void* AllocateViaCFAllocatorMalloc(ssize_t size) {
+  return CFAllocatorAllocate(kCFAllocatorMalloc, size, 0);
+}
+
+void* AllocateViaCFAllocatorMallocZone(ssize_t size) {
+  return CFAllocatorAllocate(kCFAllocatorMallocZone, size, 0);
+}
+
+}  // namespace base
diff --git a/base/process/memory_win.cc b/base/process/memory_win.cc
new file mode 100644
index 0000000..fc57b48
--- /dev/null
+++ b/base/process/memory_win.cc
@@ -0,0 +1,102 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/memory.h"
+
+#include <new.h>
+#include <psapi.h>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+
+namespace base {
+
+namespace {
+
+#pragma warning(push)
+#pragma warning(disable: 4702)
+
+int OnNoMemory(size_t) {
+  // Kill the process. This is important for security since most of code
+  // does not check the result of memory allocation.
+  __debugbreak();
+  _exit(1);
+  return 0;
+}
+
+#pragma warning(pop)
+
+// HeapSetInformation function pointer.
+typedef BOOL (WINAPI* HeapSetFn)(HANDLE, HEAP_INFORMATION_CLASS, PVOID, SIZE_T);
+
+}  // namespace
+
+bool EnableLowFragmentationHeap() {
+  HMODULE kernel32 = GetModuleHandle(L"kernel32.dll");
+  HeapSetFn heap_set = reinterpret_cast<HeapSetFn>(GetProcAddress(
+      kernel32,
+      "HeapSetInformation"));
+
+  // On Windows 2000, the function is not exported. This is not a reason to
+  // fail.
+  if (!heap_set)
+    return true;
+
+  unsigned number_heaps = GetProcessHeaps(0, NULL);
+  if (!number_heaps)
+    return false;
+
+  // Gives us some extra space in the array in case a thread is creating heaps
+  // at the same time we're querying them.
+  static const int MARGIN = 8;
+  scoped_ptr<HANDLE[]> heaps(new HANDLE[number_heaps + MARGIN]);
+  number_heaps = GetProcessHeaps(number_heaps + MARGIN, heaps.get());
+  if (!number_heaps)
+    return false;
+
+  for (unsigned i = 0; i < number_heaps; ++i) {
+    ULONG lfh_flag = 2;
+    // Don't bother with the result code. It may fails on heaps that have the
+    // HEAP_NO_SERIALIZE flag. This is expected and not a problem at all.
+    heap_set(heaps[i],
+             HeapCompatibilityInformation,
+             &lfh_flag,
+             sizeof(lfh_flag));
+  }
+  return true;
+}
+
+void EnableTerminationOnHeapCorruption() {
+  // Ignore the result code. Supported on XP SP3 and Vista.
+  HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
+}
+
+void EnableTerminationOnOutOfMemory() {
+  _set_new_handler(&OnNoMemory);
+  _set_new_mode(1);
+}
+
+HMODULE GetModuleFromAddress(void* address) {
+  HMODULE instance = NULL;
+  if (!::GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
+                            GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
+                            static_cast<char*>(address),
+                            &instance)) {
+    NOTREACHED();
+  }
+  return instance;
+}
+
+// TODO(b.kelemen): implement it with the required semantics. On Linux this is
+// implemented with a weak symbol that is overridden by tcmalloc. This is
+// neccessary because base cannot have a direct dependency on tcmalloc. Since
+// weak symbols are not supported on Windows this will involve some build time
+// magic, much like what is done for libcrt in order to override the allocation
+// functions.
+bool UncheckedMalloc(size_t size, void** result) {
+  *result = malloc(size);
+  return *result != NULL;
+}
+
+}  // namespace base
diff --git a/base/process/process.h b/base/process/process.h
new file mode 100644
index 0000000..1559554
--- /dev/null
+++ b/base/process/process.h
@@ -0,0 +1,157 @@
+// Copyright 2011 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_PROCESS_PROCESS_H_
+#define BASE_PROCESS_PROCESS_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/move.h"
+#include "base/process/process_handle.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include "base/win/scoped_handle.h"
+#endif
+
+namespace base {
+
+// Provides a move-only encapsulation of a process.
+//
+// This object is not tied to the lifetime of the underlying process: the
+// process may be killed and this object may still around, and it will still
+// claim to be valid. The actual behavior in that case is OS dependent like so:
+//
+// Windows: The underlying ProcessHandle will be valid after the process dies
+// and can be used to gather some information about that process, but most
+// methods will obviously fail.
+//
+// POSIX: The underlying PorcessHandle is not guaranteed to remain valid after
+// the process dies, and it may be reused by the system, which means that it may
+// end up pointing to the wrong process.
+class BASE_EXPORT Process {
+  MOVE_ONLY_TYPE_FOR_CPP_03(Process, RValue)
+
+ public:
+  explicit Process(ProcessHandle handle = kNullProcessHandle);
+
+  // Move constructor for C++03 move emulation of this type.
+  Process(RValue other);
+
+  // The destructor does not terminate the process.
+  ~Process();
+
+  // Move operator= for C++03 move emulation of this type.
+  Process& operator=(RValue other);
+
+  // Returns an object for the current process.
+  static Process Current();
+
+  // Returns a Process for the given |pid|.
+  static Process Open(ProcessId pid);
+
+  // 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 OpenWithExtraPrivileges(ProcessId pid);
+
+#if defined(OS_WIN)
+  // Returns a Process for the given |pid|, using some |desired_access|.
+  // See ::OpenProcess documentation for valid |desired_access|.
+  static Process OpenWithAccess(ProcessId pid, DWORD desired_access);
+#endif
+
+  // 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.
+  // TODO(rvargas) crbug.com/417532: Remove this code.
+  static Process DeprecatedGetProcessFromHandle(ProcessHandle handle);
+
+  // Returns true if processes can be backgrounded.
+  static bool CanBackgroundProcesses();
+
+  // Returns true if this objects represents a valid process.
+  bool IsValid() const;
+
+  // Returns a handle for this process. There is no guarantee about when that
+  // handle becomes invalid because this object retains ownership.
+  ProcessHandle Handle() const;
+
+  // Returns a second object that represents this process.
+  Process Duplicate() const;
+
+  // Get the PID for this process.
+  ProcessId Pid() const;
+
+  // Returns true if this process is the current process.
+  bool is_current() const;
+
+  // Close the process handle. This will not terminate the process.
+  void Close();
+
+  // Terminates the process with extreme prejudice. The given |exit_code| will
+  // be the exit code of the process. If |wait| is true, this method will wait
+  // for up to one minute for the process to actually terminate.
+  // Returns true if the process terminates within the allowed time.
+  // NOTE: On POSIX |exit_code| is ignored.
+  bool Terminate(int exit_code, bool wait) const;
+
+  // Waits for the process to exit. Returns true on success.
+  // On POSIX, if the process has been signaled then |exit_code| is set to -1.
+  // On Linux this must be a child process, however on Mac and Windows it can be
+  // any process.
+  // NOTE: |exit_code| is optional, nullptr can be passed if the exit code is
+  // not required.
+  bool WaitForExit(int* exit_code);
+
+  // Same as WaitForExit() but only waits for up to |timeout|.
+  // NOTE: |exit_code| is optional, nullptr can be passed if the exit code
+  // is not required.
+  bool WaitForExitWithTimeout(TimeDelta timeout, int* exit_code);
+
+#if defined(OS_MACOSX)
+  // The Mac needs a Mach port in order to manipulate a process's priority,
+  // and there's no good way to get that from base given the pid. These Mac
+  // variants of the IsProcessBackgrounded and SetProcessBackgrounded API take
+  // the Mach port for this reason. See crbug.com/460102
+  //
+  // A process is backgrounded when its priority is lower than normal.
+  // Return true if the process with mach port |task_port| is backgrounded,
+  // false otherwise.
+  bool IsProcessBackgrounded(mach_port_t task_port) const;
+
+  // Set the process with the specified mach port as backgrounded. If value is
+  // true, the priority of the process will be lowered. If value is false, the
+  // priority of the process will be made "normal" - equivalent to default
+  // process priority. Returns true if the priority was changed, false
+  // otherwise.
+  bool SetProcessBackgrounded(mach_port_t task_port, bool value);
+#else
+  // A process is backgrounded when it's priority is lower than normal.
+  // Return true if this process is backgrounded, false otherwise.
+  bool IsProcessBackgrounded() const;
+
+  // Set a process as backgrounded. If value is true, the priority of the
+  // process will be lowered. If value is false, the priority of the process
+  // will be made "normal" - equivalent to default process priority.
+  // Returns true if the priority was changed, false otherwise.
+  bool SetProcessBackgrounded(bool value);
+#endif  // defined(OS_MACOSX)
+  // Returns an integer representing the priority of a process. The meaning
+  // of this value is OS dependent.
+  int GetPriority() const;
+
+ private:
+#if defined(OS_WIN)
+  bool is_current_process_;
+  win::ScopedHandle process_;
+#else
+  ProcessHandle process_;
+#endif
+};
+
+}  // namespace base
+
+#endif  // BASE_PROCESS_PROCESS_H_
diff --git a/base/process/process_handle.h b/base/process/process_handle.h
new file mode 100644
index 0000000..77f2c58
--- /dev/null
+++ b/base/process/process_handle.h
@@ -0,0 +1,59 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PROCESS_PROCESS_HANDLE_H_
+#define BASE_PROCESS_PROCESS_HANDLE_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/files/file_path.h"
+#include "build/build_config.h"
+
+#include <sys/types.h>
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
+namespace base {
+
+// ProcessHandle is a platform specific type which represents the underlying OS
+// handle to a process.
+// ProcessId is a number which identifies the process in the OS.
+#if defined(OS_WIN)
+typedef HANDLE ProcessHandle;
+typedef DWORD ProcessId;
+typedef HANDLE UserTokenHandle;
+const ProcessHandle kNullProcessHandle = NULL;
+const ProcessId kNullProcessId = 0;
+#elif defined(OS_POSIX)
+// On POSIX, our ProcessHandle will just be the PID.
+typedef pid_t ProcessHandle;
+typedef pid_t ProcessId;
+const ProcessHandle kNullProcessHandle = 0;
+const ProcessId kNullProcessId = 0;
+#endif  // defined(OS_WIN)
+
+// Returns the id of the current process.
+BASE_EXPORT ProcessId GetCurrentProcId();
+
+// Returns the ProcessHandle of the current process.
+BASE_EXPORT ProcessHandle GetCurrentProcessHandle();
+
+// Returns the unique ID for the specified process. This is functionally the
+// same as Windows' GetProcessId(), but works on versions of Windows before
+// Win XP SP1 as well.
+// DEPRECATED. New code should be using Process::Pid() instead.
+BASE_EXPORT ProcessId GetProcId(ProcessHandle process);
+
+#if defined(OS_POSIX)
+// Returns the path to the executable of the given process.
+BASE_EXPORT FilePath GetProcessExecutablePath(ProcessHandle process);
+
+// Returns the ID for the parent of the given process.
+BASE_EXPORT ProcessId GetParentProcessId(ProcessHandle process);
+#endif
+
+}  // namespace base
+
+#endif  // BASE_PROCESS_PROCESS_HANDLE_H_
diff --git a/base/process/process_handle_freebsd.cc b/base/process/process_handle_freebsd.cc
new file mode 100644
index 0000000..e465a85
--- /dev/null
+++ b/base/process/process_handle_freebsd.cc
@@ -0,0 +1,40 @@
+// Copyright (c) 2011 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/process/process_handle.h"
+
+#include <sys/sysctl.h>
+#include <sys/types.h>
+#include <sys/user.h>
+#include <unistd.h>
+
+namespace base {
+
+ProcessId GetParentProcessId(ProcessHandle process) {
+  struct kinfo_proc info;
+  size_t length;
+  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, process };
+
+  if (sysctl(mib, arraysize(mib), &info, &length, NULL, 0) < 0)
+    return -1;
+
+  return info.ki_ppid;
+}
+
+FilePath GetProcessExecutablePath(ProcessHandle process) {
+  char pathname[PATH_MAX];
+  size_t length;
+  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, process };
+
+  length = sizeof(pathname);
+
+  if (sysctl(mib, arraysize(mib), pathname, &length, NULL, 0) < 0 ||
+      length == 0) {
+    return FilePath();
+  }
+
+  return FilePath(std::string(pathname));
+}
+
+}  // namespace base
diff --git a/base/process/process_handle_linux.cc b/base/process/process_handle_linux.cc
new file mode 100644
index 0000000..950b888
--- /dev/null
+++ b/base/process/process_handle_linux.cc
@@ -0,0 +1,30 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_handle.h"
+
+#include "base/files/file_util.h"
+#include "base/process/internal_linux.h"
+
+namespace base {
+
+ProcessId GetParentProcessId(ProcessHandle process) {
+  ProcessId pid =
+      internal::ReadProcStatsAndGetFieldAsInt64(process, internal::VM_PPID);
+  if (pid)
+    return pid;
+  return -1;
+}
+
+FilePath GetProcessExecutablePath(ProcessHandle process) {
+  FilePath stat_file = internal::GetProcPidDir(process).Append("exe");
+  FilePath exe_name;
+  if (!ReadSymbolicLink(stat_file, &exe_name)) {
+    // No such process.  Happens frequently in e.g. TerminateAllChromeProcesses
+    return FilePath();
+  }
+  return exe_name;
+}
+
+}  // namespace base
diff --git a/base/process/process_handle_mac.cc b/base/process/process_handle_mac.cc
new file mode 100644
index 0000000..cbf0bc5
--- /dev/null
+++ b/base/process/process_handle_mac.cc
@@ -0,0 +1,36 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_handle.h"
+
+#include <libproc.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+
+#include "base/logging.h"
+
+namespace base {
+
+ProcessId GetParentProcessId(ProcessHandle process) {
+  struct kinfo_proc info;
+  size_t length = sizeof(struct kinfo_proc);
+  int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, process };
+  if (sysctl(mib, 4, &info, &length, NULL, 0) < 0) {
+    DPLOG(ERROR) << "sysctl";
+    return -1;
+  }
+  if (length == 0)
+    return -1;
+  return info.kp_eproc.e_ppid;
+}
+
+FilePath GetProcessExecutablePath(ProcessHandle process) {
+  char pathbuf[PROC_PIDPATHINFO_MAXSIZE];
+  if (!proc_pidpath(process, pathbuf, sizeof(pathbuf)))
+    return FilePath();
+
+  return FilePath(pathbuf);
+}
+
+}  // namespace base
diff --git a/base/process/process_handle_openbsd.cc b/base/process/process_handle_openbsd.cc
new file mode 100644
index 0000000..3508ccb
--- /dev/null
+++ b/base/process/process_handle_openbsd.cc
@@ -0,0 +1,49 @@
+// Copyright (c) 2011 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/process/process_handle.h"
+
+#include <sys/sysctl.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+namespace base {
+
+ProcessId GetParentProcessId(ProcessHandle process) {
+  struct kinfo_proc info;
+  size_t length;
+  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, process,
+                sizeof(struct kinfo_proc), 0 };
+
+  if (sysctl(mib, arraysize(mib), NULL, &length, NULL, 0) < 0)
+    return -1;
+
+  mib[5] = (length / sizeof(struct kinfo_proc));
+
+  if (sysctl(mib, arraysize(mib), &info, &length, NULL, 0) < 0)
+    return -1;
+
+  return info.p_ppid;
+}
+
+FilePath GetProcessExecutablePath(ProcessHandle process) {
+  struct kinfo_proc kp;
+  size_t len;
+  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, process,
+                sizeof(struct kinfo_proc), 0 };
+
+  if (sysctl(mib, arraysize(mib), NULL, &len, NULL, 0) == -1)
+    return FilePath();
+  mib[5] = (len / sizeof(struct kinfo_proc));
+  if (sysctl(mib, arraysize(mib), &kp, &len, NULL, 0) < 0)
+    return FilePath();
+  if ((kp.p_flag & P_SYSTEM) != 0)
+    return FilePath();
+  if (strcmp(kp.p_comm, "chrome") == 0)
+    return FilePath(kp.p_comm);
+
+  return FilePath();
+}
+
+}  // namespace base
diff --git a/base/process/process_handle_posix.cc b/base/process/process_handle_posix.cc
new file mode 100644
index 0000000..4e332df
--- /dev/null
+++ b/base/process/process_handle_posix.cc
@@ -0,0 +1,23 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_handle.h"
+
+#include <unistd.h>
+
+namespace base {
+
+ProcessId GetCurrentProcId() {
+  return getpid();
+}
+
+ProcessHandle GetCurrentProcessHandle() {
+  return GetCurrentProcId();
+}
+
+ProcessId GetProcId(ProcessHandle process) {
+  return process;
+}
+
+}  // namespace base
diff --git a/base/process/process_handle_win.cc b/base/process/process_handle_win.cc
new file mode 100644
index 0000000..f2ffff8
--- /dev/null
+++ b/base/process/process_handle_win.cc
@@ -0,0 +1,28 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_handle.h"
+
+#include <windows.h>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/windows_version.h"
+
+namespace base {
+
+ProcessId GetCurrentProcId() {
+  return ::GetCurrentProcessId();
+}
+
+ProcessHandle GetCurrentProcessHandle() {
+  return ::GetCurrentProcess();
+}
+
+ProcessId GetProcId(ProcessHandle process) {
+  // This returns 0 if we have insufficient rights to query the process handle.
+  return GetProcessId(process);
+}
+
+}  // namespace base
diff --git a/base/process/process_info.h b/base/process/process_info.h
new file mode 100644
index 0000000..85f204d
--- /dev/null
+++ b/base/process/process_info.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2012 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_PROCESS_PROCESS_INFO_H_
+#define BASE_PROCESS_PROCESS_INFO_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "build/build_config.h"
+
+namespace base {
+
+class Time;
+
+// Vends information about the current process.
+class BASE_EXPORT CurrentProcessInfo {
+ public:
+  // Returns the time at which the process was launched. May be empty if an
+  // error occurred retrieving the information.
+  static const Time CreationTime();
+};
+
+#if defined(OS_WIN)
+
+enum IntegrityLevel {
+  INTEGRITY_UNKNOWN,
+  LOW_INTEGRITY,
+  MEDIUM_INTEGRITY,
+  HIGH_INTEGRITY,
+};
+
+// Returns the integrity level of the process. Returns INTEGRITY_UNKNOWN if the
+// system does not support integrity levels (pre-Vista) or in the case of an
+// underlying system failure.
+BASE_EXPORT IntegrityLevel GetCurrentProcessIntegrityLevel();
+
+#endif  // defined(OS_WIN)
+
+
+
+}  // namespace base
+
+#endif  // BASE_PROCESS_PROCESS_INFO_H_
diff --git a/base/process/process_info_linux.cc b/base/process/process_info_linux.cc
new file mode 100644
index 0000000..9ec2313
--- /dev/null
+++ b/base/process/process_info_linux.cc
@@ -0,0 +1,27 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_info.h"
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/process/internal_linux.h"
+#include "base/process/process_handle.h"
+#include "base/time/time.h"
+
+namespace base {
+
+//static
+const Time CurrentProcessInfo::CreationTime() {
+  ProcessHandle pid = GetCurrentProcessHandle();
+  int64 start_ticks =
+      internal::ReadProcStatsAndGetFieldAsInt64(pid, internal::VM_STARTTIME);
+  DCHECK(start_ticks);
+  TimeDelta start_offset = internal::ClockTicksToTimeDelta(start_ticks);
+  Time boot_time = internal::GetBootTime();
+  DCHECK(!boot_time.is_null());
+  return Time(boot_time + start_offset);
+}
+
+}  // namespace base
diff --git a/base/process/process_info_mac.cc b/base/process/process_info_mac.cc
new file mode 100644
index 0000000..b7cfdce
--- /dev/null
+++ b/base/process/process_info_mac.cc
@@ -0,0 +1,31 @@
+// Copyright (c) 2012 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/process/process_info.h"
+
+#include <sys/sysctl.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
+
+namespace base {
+
+//static
+const Time CurrentProcessInfo::CreationTime() {
+  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid() };
+  size_t len = 0;
+  if (sysctl(mib, arraysize(mib), NULL, &len, NULL, 0) < 0)
+    return Time();
+
+  scoped_ptr<struct kinfo_proc, base::FreeDeleter>
+      proc(static_cast<struct kinfo_proc*>(malloc(len)));
+  if (sysctl(mib, arraysize(mib), proc.get(), &len, NULL, 0) < 0)
+    return Time();
+  return Time::FromTimeVal(proc->kp_proc.p_un.__p_starttime);
+}
+
+}  // namespace base
diff --git a/base/process/process_info_win.cc b/base/process/process_info_win.cc
new file mode 100644
index 0000000..2b9c406
--- /dev/null
+++ b/base/process/process_info_win.cc
@@ -0,0 +1,79 @@
+// Copyright (c) 2012 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/process/process_info.h"
+
+#include <windows.h>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/windows_version.h"
+
+namespace base {
+
+// static
+const Time CurrentProcessInfo::CreationTime() {
+  FILETIME creation_time = {};
+  FILETIME ignore = {};
+  if (::GetProcessTimes(::GetCurrentProcess(), &creation_time, &ignore,
+      &ignore, &ignore) == false)
+    return Time();
+
+  return Time::FromFileTime(creation_time);
+}
+
+IntegrityLevel GetCurrentProcessIntegrityLevel() {
+  if (win::GetVersion() < base::win::VERSION_VISTA)
+    return INTEGRITY_UNKNOWN;
+
+  HANDLE process_token;
+  if (!::OpenProcessToken(::GetCurrentProcess(),
+                          TOKEN_QUERY | TOKEN_QUERY_SOURCE, &process_token)) {
+    return INTEGRITY_UNKNOWN;
+  }
+  win::ScopedHandle scoped_process_token(process_token);
+
+  DWORD token_info_length = 0;
+  if (::GetTokenInformation(process_token, TokenIntegrityLevel, NULL, 0,
+                            &token_info_length) ||
+      ::GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+    return INTEGRITY_UNKNOWN;
+  }
+
+  scoped_ptr<char[]> token_label_bytes(new char[token_info_length]);
+  if (!token_label_bytes.get())
+    return INTEGRITY_UNKNOWN;
+
+  TOKEN_MANDATORY_LABEL* token_label =
+      reinterpret_cast<TOKEN_MANDATORY_LABEL*>(token_label_bytes.get());
+  if (!token_label)
+    return INTEGRITY_UNKNOWN;
+
+  if (!::GetTokenInformation(process_token, TokenIntegrityLevel, token_label,
+                             token_info_length, &token_info_length)) {
+    return INTEGRITY_UNKNOWN;
+  }
+
+  DWORD integrity_level = *::GetSidSubAuthority(
+      token_label->Label.Sid,
+      static_cast<DWORD>(*::GetSidSubAuthorityCount(token_label->Label.Sid)-1));
+
+  if (integrity_level < SECURITY_MANDATORY_MEDIUM_RID)
+    return LOW_INTEGRITY;
+
+  if (integrity_level >= SECURITY_MANDATORY_MEDIUM_RID &&
+      integrity_level < SECURITY_MANDATORY_HIGH_RID) {
+    return MEDIUM_INTEGRITY;
+  }
+
+  if (integrity_level >= SECURITY_MANDATORY_HIGH_RID)
+    return HIGH_INTEGRITY;
+
+  NOTREACHED();
+  return INTEGRITY_UNKNOWN;
+}
+
+}  // namespace base
diff --git a/base/process/process_iterator.cc b/base/process/process_iterator.cc
new file mode 100644
index 0000000..b9ef047
--- /dev/null
+++ b/base/process/process_iterator.cc
@@ -0,0 +1,65 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_iterator.h"
+
+namespace base {
+
+#if defined(OS_POSIX)
+ProcessEntry::ProcessEntry() : pid_(0), ppid_(0), gid_(0) {}
+ProcessEntry::~ProcessEntry() {}
+#endif
+
+const ProcessEntry* ProcessIterator::NextProcessEntry() {
+  bool result = false;
+  do {
+    result = CheckForNextProcess();
+  } while (result && !IncludeEntry());
+  if (result)
+    return &entry_;
+  return NULL;
+}
+
+ProcessIterator::ProcessEntries ProcessIterator::Snapshot() {
+  ProcessEntries found;
+  while (const ProcessEntry* process_entry = NextProcessEntry()) {
+    found.push_back(*process_entry);
+  }
+  return found;
+}
+
+bool ProcessIterator::IncludeEntry() {
+  return !filter_ || filter_->Includes(entry_);
+}
+
+NamedProcessIterator::NamedProcessIterator(
+    const FilePath::StringType& executable_name,
+    const ProcessFilter* filter) : ProcessIterator(filter),
+                                   executable_name_(executable_name) {
+#if defined(OS_ANDROID)
+  // On Android, the process name contains only the last 15 characters, which
+  // is in file /proc/<pid>/stat, the string between open parenthesis and close
+  // parenthesis. Please See ProcessIterator::CheckForNextProcess for details.
+  // Now if the length of input process name is greater than 15, only save the
+  // last 15 characters.
+  if (executable_name_.size() > 15) {
+    executable_name_ = FilePath::StringType(executable_name_,
+                                            executable_name_.size() - 15, 15);
+  }
+#endif
+}
+
+NamedProcessIterator::~NamedProcessIterator() {
+}
+
+int GetProcessCount(const FilePath::StringType& executable_name,
+                    const ProcessFilter* filter) {
+  int count = 0;
+  NamedProcessIterator iter(executable_name, filter);
+  while (iter.NextProcessEntry())
+    ++count;
+  return count;
+}
+
+}  // namespace base
diff --git a/base/process/process_iterator.h b/base/process/process_iterator.h
new file mode 100644
index 0000000..ec6500e
--- /dev/null
+++ b/base/process/process_iterator.h
@@ -0,0 +1,148 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains methods to iterate over processes on the system.
+
+#ifndef BASE_PROCESS_PROCESS_ITERATOR_H_
+#define BASE_PROCESS_PROCESS_ITERATOR_H_
+
+#include <list>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/files/file_path.h"
+#include "base/process/process.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#include <tlhelp32.h>
+#elif defined(OS_MACOSX) || defined(OS_OPENBSD)
+#include <sys/sysctl.h>
+#elif defined(OS_FREEBSD)
+#include <sys/user.h>
+#elif defined(OS_POSIX)
+#include <dirent.h>
+#endif
+
+namespace base {
+
+#if defined(OS_WIN)
+struct ProcessEntry : public PROCESSENTRY32 {
+  ProcessId pid() const { return th32ProcessID; }
+  ProcessId parent_pid() const { return th32ParentProcessID; }
+  const wchar_t* exe_file() const { return szExeFile; }
+};
+#elif defined(OS_POSIX)
+struct BASE_EXPORT ProcessEntry {
+  ProcessEntry();
+  ~ProcessEntry();
+
+  ProcessId pid() const { return pid_; }
+  ProcessId parent_pid() const { return ppid_; }
+  ProcessId gid() const { return gid_; }
+  const char* exe_file() const { return exe_file_.c_str(); }
+  const std::vector<std::string>& cmd_line_args() const {
+    return cmd_line_args_;
+  }
+
+  ProcessId pid_;
+  ProcessId ppid_;
+  ProcessId gid_;
+  std::string exe_file_;
+  std::vector<std::string> cmd_line_args_;
+};
+#endif  // defined(OS_POSIX)
+
+// Used to filter processes by process ID.
+class ProcessFilter {
+ public:
+  // Returns true to indicate set-inclusion and false otherwise.  This method
+  // should not have side-effects and should be idempotent.
+  virtual bool Includes(const ProcessEntry& entry) const = 0;
+
+ protected:
+  virtual ~ProcessFilter() {}
+};
+
+// This class provides a way to iterate through a list of processes on the
+// current machine with a specified filter.
+// To use, create an instance and then call NextProcessEntry() until it returns
+// false.
+class BASE_EXPORT ProcessIterator {
+ public:
+  typedef std::list<ProcessEntry> ProcessEntries;
+
+  explicit ProcessIterator(const ProcessFilter* filter);
+  virtual ~ProcessIterator();
+
+  // If there's another process that matches the given executable name,
+  // returns a const pointer to the corresponding PROCESSENTRY32.
+  // If there are no more matching processes, returns NULL.
+  // The returned pointer will remain valid until NextProcessEntry()
+  // is called again or this NamedProcessIterator goes out of scope.
+  const ProcessEntry* NextProcessEntry();
+
+  // Takes a snapshot of all the ProcessEntry found.
+  ProcessEntries Snapshot();
+
+ protected:
+  virtual bool IncludeEntry();
+  const ProcessEntry& entry() { return entry_; }
+
+ private:
+  // Determines whether there's another process (regardless of executable)
+  // left in the list of all processes.  Returns true and sets entry_ to
+  // that process's info if there is one, false otherwise.
+  bool CheckForNextProcess();
+
+  // Initializes a PROCESSENTRY32 data structure so that it's ready for
+  // use with Process32First/Process32Next.
+  void InitProcessEntry(ProcessEntry* entry);
+
+#if defined(OS_WIN)
+  HANDLE snapshot_;
+  bool started_iteration_;
+#elif defined(OS_MACOSX) || defined(OS_BSD)
+  std::vector<kinfo_proc> kinfo_procs_;
+  size_t index_of_kinfo_proc_;
+#elif defined(OS_POSIX)
+  DIR* procfs_dir_;
+#endif
+  ProcessEntry entry_;
+  const ProcessFilter* filter_;
+
+  DISALLOW_COPY_AND_ASSIGN(ProcessIterator);
+};
+
+// This class provides a way to iterate through the list of processes
+// on the current machine that were started from the given executable
+// name.  To use, create an instance and then call NextProcessEntry()
+// until it returns false.
+class BASE_EXPORT NamedProcessIterator : public ProcessIterator {
+ public:
+  NamedProcessIterator(const FilePath::StringType& executable_name,
+                       const ProcessFilter* filter);
+  ~NamedProcessIterator() override;
+
+ protected:
+  bool IncludeEntry() override;
+
+ private:
+  FilePath::StringType executable_name_;
+
+  DISALLOW_COPY_AND_ASSIGN(NamedProcessIterator);
+};
+
+// Returns the number of processes on the machine that are running from the
+// given executable name.  If filter is non-null, then only processes selected
+// by the filter will be counted.
+BASE_EXPORT int GetProcessCount(const FilePath::StringType& executable_name,
+                                const ProcessFilter* filter);
+
+}  // namespace base
+
+#endif  // BASE_PROCESS_PROCESS_ITERATOR_H_
diff --git a/base/process/process_iterator_freebsd.cc b/base/process/process_iterator_freebsd.cc
new file mode 100644
index 0000000..5b1e2ab
--- /dev/null
+++ b/base/process/process_iterator_freebsd.cc
@@ -0,0 +1,126 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_iterator.h"
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <unistd.h>
+
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+
+namespace base {
+
+ProcessIterator::ProcessIterator(const ProcessFilter* filter)
+    : index_of_kinfo_proc_(),
+      filter_(filter) {
+
+  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_UID, getuid() };
+
+  bool done = false;
+  int try_num = 1;
+  const int max_tries = 10;
+
+  do {
+    size_t len = 0;
+    if (sysctl(mib, arraysize(mib), NULL, &len, NULL, 0) < 0) {
+      LOG(ERROR) << "failed to get the size needed for the process list";
+      kinfo_procs_.resize(0);
+      done = true;
+    } else {
+      size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc);
+      // Leave some spare room for process table growth (more could show up
+      // between when we check and now)
+      num_of_kinfo_proc += 16;
+      kinfo_procs_.resize(num_of_kinfo_proc);
+      len = num_of_kinfo_proc * sizeof(struct kinfo_proc);
+      if (sysctl(mib, arraysize(mib), &kinfo_procs_[0], &len, NULL, 0) <0) {
+        // If we get a mem error, it just means we need a bigger buffer, so
+        // loop around again.  Anything else is a real error and give up.
+        if (errno != ENOMEM) {
+          LOG(ERROR) << "failed to get the process list";
+          kinfo_procs_.resize(0);
+          done = true;
+        }
+      } else {
+        // Got the list, just make sure we're sized exactly right
+        size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc);
+        kinfo_procs_.resize(num_of_kinfo_proc);
+        done = true;
+      }
+    }
+  } while (!done && (try_num++ < max_tries));
+
+  if (!done) {
+    LOG(ERROR) << "failed to collect the process list in a few tries";
+    kinfo_procs_.resize(0);
+  }
+}
+
+ProcessIterator::~ProcessIterator() {
+}
+
+bool ProcessIterator::CheckForNextProcess() {
+  std::string data;
+
+  for (; index_of_kinfo_proc_ < kinfo_procs_.size(); ++index_of_kinfo_proc_) {
+    size_t length;
+    struct kinfo_proc kinfo = kinfo_procs_[index_of_kinfo_proc_];
+    int mib[] = { CTL_KERN, KERN_PROC_ARGS, kinfo.ki_pid };
+
+    if ((kinfo.ki_pid > 0) && (kinfo.ki_stat == SZOMB))
+      continue;
+
+    length = 0;
+    if (sysctl(mib, arraysize(mib), NULL, &length, NULL, 0) < 0) {
+      LOG(ERROR) << "failed to figure out the buffer size for a command line";
+      continue;
+    }
+
+    data.resize(length);
+
+    if (sysctl(mib, arraysize(mib), &data[0], &length, NULL, 0) < 0) {
+      LOG(ERROR) << "failed to fetch a commandline";
+      continue;
+    }
+
+    std::string delimiters;
+    delimiters.push_back('\0');
+    Tokenize(data, delimiters, &entry_.cmd_line_args_);
+
+    size_t exec_name_end = data.find('\0');
+    if (exec_name_end == std::string::npos) {
+      LOG(ERROR) << "command line data didn't match expected format";
+      continue;
+    }
+
+    entry_.pid_ = kinfo.ki_pid;
+    entry_.ppid_ = kinfo.ki_ppid;
+    entry_.gid_ = kinfo.ki_pgid;
+
+    size_t last_slash = data.rfind('/', exec_name_end);
+    if (last_slash == std::string::npos) {
+      entry_.exe_file_.assign(data, 0, exec_name_end);
+    } else {
+      entry_.exe_file_.assign(data, last_slash + 1,
+                              exec_name_end - last_slash - 1);
+    }
+
+    // Start w/ the next entry next time through
+    ++index_of_kinfo_proc_;
+
+    return true;
+  }
+  return false;
+}
+
+bool NamedProcessIterator::IncludeEntry() {
+  if (executable_name_ != entry().exe_file())
+    return false;
+
+  return ProcessIterator::IncludeEntry();
+}
+
+}  // namespace base
diff --git a/base/process/process_iterator_linux.cc b/base/process/process_iterator_linux.cc
new file mode 100644
index 0000000..3319552
--- /dev/null
+++ b/base/process/process_iterator_linux.cc
@@ -0,0 +1,137 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_iterator.h"
+
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/process/internal_linux.h"
+#include "base/strings/string_util.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace base {
+
+namespace {
+
+// Reads the |field_num|th field from |proc_stats|.
+// Returns an empty string on failure.
+// This version only handles VM_COMM and VM_STATE, which are the only fields
+// that are strings.
+std::string GetProcStatsFieldAsString(
+    const std::vector<std::string>& proc_stats,
+    internal::ProcStatsFields field_num) {
+  if (field_num < internal::VM_COMM || field_num > internal::VM_STATE) {
+    NOTREACHED();
+    return std::string();
+  }
+
+  if (proc_stats.size() > static_cast<size_t>(field_num))
+    return proc_stats[field_num];
+
+  NOTREACHED();
+  return 0;
+}
+
+// Reads /proc/<pid>/cmdline and populates |proc_cmd_line_args| with the command
+// line arguments. Returns true if successful.
+// Note: /proc/<pid>/cmdline contains command line arguments separated by single
+// null characters. We tokenize it into a vector of strings using '\0' as a
+// delimiter.
+bool GetProcCmdline(pid_t pid, std::vector<std::string>* proc_cmd_line_args) {
+  // Synchronously reading files in /proc is safe.
+  ThreadRestrictions::ScopedAllowIO allow_io;
+
+  FilePath cmd_line_file = internal::GetProcPidDir(pid).Append("cmdline");
+  std::string cmd_line;
+  if (!ReadFileToString(cmd_line_file, &cmd_line))
+    return false;
+  std::string delimiters;
+  delimiters.push_back('\0');
+  Tokenize(cmd_line, delimiters, proc_cmd_line_args);
+  return true;
+}
+
+}  // namespace
+
+ProcessIterator::ProcessIterator(const ProcessFilter* filter)
+    : filter_(filter) {
+  procfs_dir_ = opendir(internal::kProcDir);
+}
+
+ProcessIterator::~ProcessIterator() {
+  if (procfs_dir_) {
+    closedir(procfs_dir_);
+    procfs_dir_ = NULL;
+  }
+}
+
+bool ProcessIterator::CheckForNextProcess() {
+  // TODO(port): skip processes owned by different UID
+
+  pid_t pid = kNullProcessId;
+  std::vector<std::string> cmd_line_args;
+  std::string stats_data;
+  std::vector<std::string> proc_stats;
+
+  // Arbitrarily guess that there will never be more than 200 non-process
+  // files in /proc.  Hardy has 53 and Lucid has 61.
+  int skipped = 0;
+  const int kSkipLimit = 200;
+  while (skipped < kSkipLimit) {
+    dirent* slot = readdir(procfs_dir_);
+    // all done looking through /proc?
+    if (!slot)
+      return false;
+
+    // If not a process, keep looking for one.
+    pid = internal::ProcDirSlotToPid(slot->d_name);
+    if (!pid) {
+      skipped++;
+      continue;
+    }
+
+    if (!GetProcCmdline(pid, &cmd_line_args))
+      continue;
+
+    if (!internal::ReadProcStats(pid, &stats_data))
+      continue;
+    if (!internal::ParseProcStats(stats_data, &proc_stats))
+      continue;
+
+    std::string runstate =
+        GetProcStatsFieldAsString(proc_stats, internal::VM_STATE);
+    if (runstate.size() != 1) {
+      NOTREACHED();
+      continue;
+    }
+
+    // Is the process in 'Zombie' state, i.e. dead but waiting to be reaped?
+    // Allowed values: D R S T Z
+    if (runstate[0] != 'Z')
+      break;
+
+    // Nope, it's a zombie; somebody isn't cleaning up after their children.
+    // (e.g. WaitForProcessesToExit doesn't clean up after dead children yet.)
+    // There could be a lot of zombies, can't really decrement i here.
+  }
+  if (skipped >= kSkipLimit) {
+    NOTREACHED();
+    return false;
+  }
+
+  entry_.pid_ = pid;
+  entry_.ppid_ = GetProcStatsFieldAsInt64(proc_stats, internal::VM_PPID);
+  entry_.gid_ = GetProcStatsFieldAsInt64(proc_stats, internal::VM_PGRP);
+  entry_.cmd_line_args_.assign(cmd_line_args.begin(), cmd_line_args.end());
+  entry_.exe_file_ = GetProcessExecutablePath(pid).BaseName().value();
+  return true;
+}
+
+bool NamedProcessIterator::IncludeEntry() {
+  if (executable_name_ != entry().exe_file())
+    return false;
+  return ProcessIterator::IncludeEntry();
+}
+
+}  // namespace base
diff --git a/base/process/process_iterator_mac.cc b/base/process/process_iterator_mac.cc
new file mode 100644
index 0000000..e35c2ae
--- /dev/null
+++ b/base/process/process_iterator_mac.cc
@@ -0,0 +1,135 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_iterator.h"
+
+#include <errno.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+
+namespace base {
+
+ProcessIterator::ProcessIterator(const ProcessFilter* filter)
+    : index_of_kinfo_proc_(0),
+      filter_(filter) {
+  // Get a snapshot of all of my processes (yes, as we loop it can go stale, but
+  // but trying to find where we were in a constantly changing list is basically
+  // impossible.
+
+  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_UID, geteuid() };
+
+  // Since more processes could start between when we get the size and when
+  // we get the list, we do a loop to keep trying until we get it.
+  bool done = false;
+  int try_num = 1;
+  const int max_tries = 10;
+  do {
+    // Get the size of the buffer
+    size_t len = 0;
+    if (sysctl(mib, arraysize(mib), NULL, &len, NULL, 0) < 0) {
+      DLOG(ERROR) << "failed to get the size needed for the process list";
+      kinfo_procs_.resize(0);
+      done = true;
+    } else {
+      size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc);
+      // Leave some spare room for process table growth (more could show up
+      // between when we check and now)
+      num_of_kinfo_proc += 16;
+      kinfo_procs_.resize(num_of_kinfo_proc);
+      len = num_of_kinfo_proc * sizeof(struct kinfo_proc);
+      // Load the list of processes
+      if (sysctl(mib, arraysize(mib), &kinfo_procs_[0], &len, NULL, 0) < 0) {
+        // If we get a mem error, it just means we need a bigger buffer, so
+        // loop around again.  Anything else is a real error and give up.
+        if (errno != ENOMEM) {
+          DLOG(ERROR) << "failed to get the process list";
+          kinfo_procs_.resize(0);
+          done = true;
+        }
+      } else {
+        // Got the list, just make sure we're sized exactly right
+        size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc);
+        kinfo_procs_.resize(num_of_kinfo_proc);
+        done = true;
+      }
+    }
+  } while (!done && (try_num++ < max_tries));
+
+  if (!done) {
+    DLOG(ERROR) << "failed to collect the process list in a few tries";
+    kinfo_procs_.resize(0);
+  }
+}
+
+ProcessIterator::~ProcessIterator() {
+}
+
+bool ProcessIterator::CheckForNextProcess() {
+  std::string data;
+  for (; index_of_kinfo_proc_ < kinfo_procs_.size(); ++index_of_kinfo_proc_) {
+    kinfo_proc& kinfo = kinfo_procs_[index_of_kinfo_proc_];
+
+    // Skip processes just awaiting collection
+    if ((kinfo.kp_proc.p_pid > 0) && (kinfo.kp_proc.p_stat == SZOMB))
+      continue;
+
+    int mib[] = { CTL_KERN, KERN_PROCARGS, kinfo.kp_proc.p_pid };
+
+    // Find out what size buffer we need.
+    size_t data_len = 0;
+    if (sysctl(mib, arraysize(mib), NULL, &data_len, NULL, 0) < 0) {
+      DVPLOG(1) << "failed to figure out the buffer size for a commandline";
+      continue;
+    }
+
+    data.resize(data_len);
+    if (sysctl(mib, arraysize(mib), &data[0], &data_len, NULL, 0) < 0) {
+      DVPLOG(1) << "failed to fetch a commandline";
+      continue;
+    }
+
+    // |data| contains all the command line parameters of the process, separated
+    // by blocks of one or more null characters. We tokenize |data| into a
+    // vector of strings using '\0' as a delimiter and populate
+    // |entry_.cmd_line_args_|.
+    std::string delimiters;
+    delimiters.push_back('\0');
+    Tokenize(data, delimiters, &entry_.cmd_line_args_);
+
+    // |data| starts with the full executable path followed by a null character.
+    // We search for the first instance of '\0' and extract everything before it
+    // to populate |entry_.exe_file_|.
+    size_t exec_name_end = data.find('\0');
+    if (exec_name_end == std::string::npos) {
+      DLOG(ERROR) << "command line data didn't match expected format";
+      continue;
+    }
+
+    entry_.pid_ = kinfo.kp_proc.p_pid;
+    entry_.ppid_ = kinfo.kp_eproc.e_ppid;
+    entry_.gid_ = kinfo.kp_eproc.e_pgid;
+    size_t last_slash = data.rfind('/', exec_name_end);
+    if (last_slash == std::string::npos)
+      entry_.exe_file_.assign(data, 0, exec_name_end);
+    else
+      entry_.exe_file_.assign(data, last_slash + 1,
+                              exec_name_end - last_slash - 1);
+    // Start w/ the next entry next time through
+    ++index_of_kinfo_proc_;
+    // Done
+    return true;
+  }
+  return false;
+}
+
+bool NamedProcessIterator::IncludeEntry() {
+  return (executable_name_ == entry().exe_file() &&
+          ProcessIterator::IncludeEntry());
+}
+
+}  // namespace base
diff --git a/base/process/process_iterator_openbsd.cc b/base/process/process_iterator_openbsd.cc
new file mode 100644
index 0000000..7c44eb1
--- /dev/null
+++ b/base/process/process_iterator_openbsd.cc
@@ -0,0 +1,128 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_iterator.h"
+
+#include <errno.h>
+#include <sys/sysctl.h>
+
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+
+namespace base {
+
+ProcessIterator::ProcessIterator(const ProcessFilter* filter)
+    : index_of_kinfo_proc_(),
+      filter_(filter) {
+
+  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_UID, getuid(),
+                sizeof(struct kinfo_proc), 0 };
+
+  bool done = false;
+  int try_num = 1;
+  const int max_tries = 10;
+
+  do {
+    size_t len = 0;
+    if (sysctl(mib, arraysize(mib), NULL, &len, NULL, 0) < 0) {
+      DLOG(ERROR) << "failed to get the size needed for the process list";
+      kinfo_procs_.resize(0);
+      done = true;
+    } else {
+      size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc);
+      // Leave some spare room for process table growth (more could show up
+      // between when we check and now)
+      num_of_kinfo_proc += 16;
+      kinfo_procs_.resize(num_of_kinfo_proc);
+      len = num_of_kinfo_proc * sizeof(struct kinfo_proc);
+      if (sysctl(mib, arraysize(mib), &kinfo_procs_[0], &len, NULL, 0) < 0) {
+        // If we get a mem error, it just means we need a bigger buffer, so
+        // loop around again.  Anything else is a real error and give up.
+        if (errno != ENOMEM) {
+          DLOG(ERROR) << "failed to get the process list";
+          kinfo_procs_.resize(0);
+          done = true;
+        }
+      } else {
+        // Got the list, just make sure we're sized exactly right
+        size_t num_of_kinfo_proc = len / sizeof(struct kinfo_proc);
+        kinfo_procs_.resize(num_of_kinfo_proc);
+        done = true;
+      }
+    }
+  } while (!done && (try_num++ < max_tries));
+
+  if (!done) {
+    DLOG(ERROR) << "failed to collect the process list in a few tries";
+    kinfo_procs_.resize(0);
+  }
+}
+
+ProcessIterator::~ProcessIterator() {
+}
+
+bool ProcessIterator::CheckForNextProcess() {
+  std::string data;
+  for (; index_of_kinfo_proc_ < kinfo_procs_.size(); ++index_of_kinfo_proc_) {
+    kinfo_proc& kinfo = kinfo_procs_[index_of_kinfo_proc_];
+
+    // Skip processes just awaiting collection
+    if ((kinfo.p_pid > 0) && (kinfo.p_stat == SZOMB))
+      continue;
+
+    int mib[] = { CTL_KERN, KERN_PROC_ARGS, kinfo.p_pid };
+
+    // Find out what size buffer we need.
+    size_t data_len = 0;
+    if (sysctl(mib, arraysize(mib), NULL, &data_len, NULL, 0) < 0) {
+      DVPLOG(1) << "failed to figure out the buffer size for a commandline";
+      continue;
+    }
+
+    data.resize(data_len);
+    if (sysctl(mib, arraysize(mib), &data[0], &data_len, NULL, 0) < 0) {
+      DVPLOG(1) << "failed to fetch a commandline";
+      continue;
+    }
+
+    // |data| contains all the command line parameters of the process, separated
+    // by blocks of one or more null characters. We tokenize |data| into a
+    // vector of strings using '\0' as a delimiter and populate
+    // |entry_.cmd_line_args_|.
+    std::string delimiters;
+    delimiters.push_back('\0');
+    Tokenize(data, delimiters, &entry_.cmd_line_args_);
+
+    // |data| starts with the full executable path followed by a null character.
+    // We search for the first instance of '\0' and extract everything before it
+    // to populate |entry_.exe_file_|.
+    size_t exec_name_end = data.find('\0');
+    if (exec_name_end == std::string::npos) {
+      DLOG(ERROR) << "command line data didn't match expected format";
+      continue;
+    }
+
+    entry_.pid_ = kinfo.p_pid;
+    entry_.ppid_ = kinfo.p_ppid;
+    entry_.gid_ = kinfo.p__pgid;
+    size_t last_slash = data.rfind('/', exec_name_end);
+    if (last_slash == std::string::npos)
+      entry_.exe_file_.assign(data, 0, exec_name_end);
+    else
+      entry_.exe_file_.assign(data, last_slash + 1,
+                              exec_name_end - last_slash - 1);
+    // Start w/ the next entry next time through
+    ++index_of_kinfo_proc_;
+    // Done
+    return true;
+  }
+  return false;
+}
+
+bool NamedProcessIterator::IncludeEntry() {
+  return (executable_name_ == entry().exe_file() &&
+          ProcessIterator::IncludeEntry());
+}
+
+}  // namespace base
diff --git a/base/process/process_iterator_win.cc b/base/process/process_iterator_win.cc
new file mode 100644
index 0000000..9d5a970
--- /dev/null
+++ b/base/process/process_iterator_win.cc
@@ -0,0 +1,41 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_iterator.h"
+
+namespace base {
+
+ProcessIterator::ProcessIterator(const ProcessFilter* filter)
+    : started_iteration_(false),
+      filter_(filter) {
+  snapshot_ = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+}
+
+ProcessIterator::~ProcessIterator() {
+  CloseHandle(snapshot_);
+}
+
+bool ProcessIterator::CheckForNextProcess() {
+  InitProcessEntry(&entry_);
+
+  if (!started_iteration_) {
+    started_iteration_ = true;
+    return !!Process32First(snapshot_, &entry_);
+  }
+
+  return !!Process32Next(snapshot_, &entry_);
+}
+
+void ProcessIterator::InitProcessEntry(ProcessEntry* entry) {
+  memset(entry, 0, sizeof(*entry));
+  entry->dwSize = sizeof(*entry);
+}
+
+bool NamedProcessIterator::IncludeEntry() {
+  // Case insensitive.
+  return _wcsicmp(executable_name_.c_str(), entry().exe_file()) == 0 &&
+         ProcessIterator::IncludeEntry();
+}
+
+}  // namespace base
diff --git a/base/process/process_linux.cc b/base/process/process_linux.cc
new file mode 100644
index 0000000..88a310e
--- /dev/null
+++ b/base/process/process_linux.cc
@@ -0,0 +1,139 @@
+// Copyright (c) 2011 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/process/process.h"
+
+#include <errno.h>
+#include <sys/resource.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"
+
+namespace base {
+
+namespace {
+
+const int kForegroundPriority = 0;
+
+#if defined(OS_CHROMEOS)
+// We are more aggressive in our lowering of background process priority
+// for chromeos as we have much more control over other processes running
+// on the machine.
+//
+// TODO(davemoore) Refactor this by adding support for higher levels to set
+// the foregrounding / backgrounding process so we don't have to keep
+// chrome / chromeos specific logic here.
+const int kBackgroundPriority = 19;
+const char kControlPath[] = "/sys/fs/cgroup/cpu%s/cgroup.procs";
+const char kForeground[] = "/chrome_renderers/foreground";
+const char kBackground[] = "/chrome_renderers/background";
+const char kProcPath[] = "/proc/%d/cgroup";
+
+struct CGroups {
+  // Check for cgroups files. ChromeOS supports these by default. It creates
+  // a cgroup mount in /sys/fs/cgroup and then configures two cpu task groups,
+  // one contains at most a single foreground renderer and the other contains
+  // all background renderers. This allows us to limit the impact of background
+  // renderers on foreground ones to a greater level than simple renicing.
+  bool enabled;
+  base::FilePath foreground_file;
+  base::FilePath background_file;
+
+  CGroups() {
+    foreground_file =
+        base::FilePath(base::StringPrintf(kControlPath, kForeground));
+    background_file =
+        base::FilePath(base::StringPrintf(kControlPath, kBackground));
+    base::FileSystemType foreground_type;
+    base::FileSystemType background_type;
+    enabled =
+        base::GetFileSystemType(foreground_file, &foreground_type) &&
+        base::GetFileSystemType(background_file, &background_type) &&
+        foreground_type == FILE_SYSTEM_CGROUP &&
+        background_type == FILE_SYSTEM_CGROUP;
+  }
+};
+
+base::LazyInstance<CGroups> cgroups = LAZY_INSTANCE_INITIALIZER;
+#else
+const int kBackgroundPriority = 5;
+#endif
+
+struct CheckForNicePermission {
+  CheckForNicePermission() : can_reraise_priority(false) {
+    // We won't be able to raise the priority if we don't have the right rlimit.
+    // The limit may be adjusted in /etc/security/limits.conf for PAM systems.
+    struct rlimit rlim;
+    if ((getrlimit(RLIMIT_NICE, &rlim) == 0) &&
+        (20 - kForegroundPriority) <= static_cast<int>(rlim.rlim_cur)) {
+        can_reraise_priority = true;
+    }
+  };
+
+  bool can_reraise_priority;
+};
+
+}  // namespace
+
+// static
+bool Process::CanBackgroundProcesses() {
+#if defined(OS_CHROMEOS)
+  if (cgroups.Get().enabled)
+    return true;
+#endif
+
+  static LazyInstance<CheckForNicePermission> check_for_nice_permission =
+      LAZY_INSTANCE_INITIALIZER;
+  return check_for_nice_permission.Get().can_reraise_priority;
+}
+
+bool Process::IsProcessBackgrounded() const {
+  DCHECK(IsValid());
+
+#if defined(OS_CHROMEOS)
+  if (cgroups.Get().enabled) {
+    std::string proc;
+    if (base::ReadFileToString(
+            base::FilePath(StringPrintf(kProcPath, process_)),
+            &proc)) {
+      std::vector<std::string> proc_parts;
+      base::SplitString(proc, ':', &proc_parts);
+      DCHECK_EQ(proc_parts.size(), 3u);
+      bool ret = proc_parts[2] == std::string(kBackground);
+      return ret;
+    } else {
+      return false;
+    }
+  }
+#endif
+  return GetPriority() == kBackgroundPriority;
+}
+
+bool Process::SetProcessBackgrounded(bool background) {
+  DCHECK(IsValid());
+
+#if defined(OS_CHROMEOS)
+  if (cgroups.Get().enabled) {
+    std::string pid = StringPrintf("%d", process_);
+    const base::FilePath file =
+        background ?
+            cgroups.Get().background_file : cgroups.Get().foreground_file;
+    return base::WriteFile(file, pid.c_str(), pid.size()) > 0;
+  }
+#endif // OS_CHROMEOS
+
+  if (!CanBackgroundProcesses())
+    return false;
+
+  int priority = background ? kBackgroundPriority : kForegroundPriority;
+  int result = setpriority(PRIO_PROCESS, process_, priority);
+  DPCHECK(result == 0);
+  return result == 0;
+}
+
+}  // namespace base
diff --git a/base/process/process_mac.cc b/base/process/process_mac.cc
new file mode 100644
index 0000000..1913cc3
--- /dev/null
+++ b/base/process/process_mac.cc
@@ -0,0 +1,128 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process.h"
+
+#include "base/mac/mac_util.h"
+#include "base/mac/mach_logging.h"
+
+#include <mach/mach.h>
+
+// The following was added to <mach/task_policy.h> after 10.8.
+// TODO(shrike): Remove the TASK_OVERRIDE_QOS_POLICY ifndef once builders
+// reach 10.9 or higher.
+#ifndef TASK_OVERRIDE_QOS_POLICY
+
+#define TASK_OVERRIDE_QOS_POLICY 9
+
+typedef struct task_category_policy task_category_policy_data_t;
+typedef struct task_category_policy* task_category_policy_t;
+
+enum task_latency_qos {
+  LATENCY_QOS_TIER_UNSPECIFIED = 0x0,
+  LATENCY_QOS_TIER_0 = ((0xFF << 16) | 1),
+  LATENCY_QOS_TIER_1 = ((0xFF << 16) | 2),
+  LATENCY_QOS_TIER_2 = ((0xFF << 16) | 3),
+  LATENCY_QOS_TIER_3 = ((0xFF << 16) | 4),
+  LATENCY_QOS_TIER_4 = ((0xFF << 16) | 5),
+  LATENCY_QOS_TIER_5 = ((0xFF << 16) | 6)
+};
+typedef integer_t task_latency_qos_t;
+enum task_throughput_qos {
+  THROUGHPUT_QOS_TIER_UNSPECIFIED = 0x0,
+  THROUGHPUT_QOS_TIER_0 = ((0xFE << 16) | 1),
+  THROUGHPUT_QOS_TIER_1 = ((0xFE << 16) | 2),
+  THROUGHPUT_QOS_TIER_2 = ((0xFE << 16) | 3),
+  THROUGHPUT_QOS_TIER_3 = ((0xFE << 16) | 4),
+  THROUGHPUT_QOS_TIER_4 = ((0xFE << 16) | 5),
+  THROUGHPUT_QOS_TIER_5 = ((0xFE << 16) | 6),
+};
+
+#define LATENCY_QOS_LAUNCH_DEFAULT_TIER LATENCY_QOS_TIER_3
+#define THROUGHPUT_QOS_LAUNCH_DEFAULT_TIER THROUGHPUT_QOS_TIER_3
+
+typedef integer_t task_throughput_qos_t;
+
+struct task_qos_policy {
+  task_latency_qos_t task_latency_qos_tier;
+  task_throughput_qos_t task_throughput_qos_tier;
+};
+
+typedef struct task_qos_policy* task_qos_policy_t;
+#define TASK_QOS_POLICY_COUNT \
+  ((mach_msg_type_number_t)(sizeof(struct task_qos_policy) / sizeof(integer_t)))
+
+#endif  // TASK_OVERRIDE_QOS_POLICY
+
+namespace base {
+
+bool Process::CanBackgroundProcesses() {
+  return true;
+}
+
+bool Process::IsProcessBackgrounded(mach_port_t task_port) const {
+  // See SetProcessBackgrounded().
+  DCHECK(IsValid());
+  DCHECK_NE(task_port, TASK_NULL);
+
+  task_category_policy_data_t category_policy;
+  mach_msg_type_number_t task_info_count = TASK_CATEGORY_POLICY_COUNT;
+  boolean_t get_default = FALSE;
+
+  kern_return_t result =
+      task_policy_get(task_port, TASK_CATEGORY_POLICY,
+                      reinterpret_cast<task_policy_t>(&category_policy),
+                      &task_info_count, &get_default);
+  MACH_LOG_IF(ERROR, result != KERN_SUCCESS, result) <<
+      "task_policy_get TASK_CATEGORY_POLICY";
+
+  if (result == KERN_SUCCESS && get_default == FALSE) {
+    return category_policy.role == TASK_BACKGROUND_APPLICATION;
+  }
+  return false;
+}
+
+bool Process::SetProcessBackgrounded(mach_port_t task_port, bool background) {
+  DCHECK(IsValid());
+  DCHECK_NE(task_port, TASK_NULL);
+
+  if (!CanBackgroundProcesses()) {
+    return false;
+  } else if (IsProcessBackgrounded(task_port) == background) {
+    return true;
+  }
+
+  task_category_policy category_policy;
+  category_policy.role =
+      background ? TASK_BACKGROUND_APPLICATION : TASK_FOREGROUND_APPLICATION;
+  kern_return_t result =
+      task_policy_set(task_port, TASK_CATEGORY_POLICY,
+                      reinterpret_cast<task_policy_t>(&category_policy),
+                      TASK_CATEGORY_POLICY_COUNT);
+
+  if (result != KERN_SUCCESS) {
+    MACH_LOG(ERROR, result) << "task_policy_set TASK_CATEGORY_POLICY";
+    return false;
+  } else if (!mac::IsOSMavericksOrLater()) {
+    return true;
+  }
+
+  // Latency QoS regulates timer throttling/accuracy. Select default tier
+  // on foreground because precise timer firing isn't needed.
+  struct task_qos_policy qos_policy = {
+      background ? LATENCY_QOS_TIER_5 : LATENCY_QOS_TIER_UNSPECIFIED,
+      background ? THROUGHPUT_QOS_TIER_5 : THROUGHPUT_QOS_TIER_UNSPECIFIED
+  };
+  result = task_policy_set(task_port, TASK_OVERRIDE_QOS_POLICY,
+                           reinterpret_cast<task_policy_t>(&qos_policy),
+                           TASK_QOS_POLICY_COUNT);
+  if (result != KERN_SUCCESS) {
+    MACH_LOG(ERROR, result) << "task_policy_set TASK_OVERRIDE_QOS_POLICY";
+    return false;
+  }
+
+  return true;
+}
+
+}  // namespace base
diff --git a/base/process/process_metrics.cc b/base/process/process_metrics.cc
new file mode 100644
index 0000000..e486339
--- /dev/null
+++ b/base/process/process_metrics.cc
@@ -0,0 +1,87 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_metrics.h"
+
+#include "base/logging.h"
+#include "base/values.h"
+
+namespace base {
+
+SystemMetrics::SystemMetrics() {
+  committed_memory_ = 0;
+}
+
+SystemMetrics SystemMetrics::Sample() {
+  SystemMetrics system_metrics;
+
+  system_metrics.committed_memory_ = GetSystemCommitCharge();
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+  GetSystemMemoryInfo(&system_metrics.memory_info_);
+  GetSystemDiskInfo(&system_metrics.disk_info_);
+#endif
+#if defined(OS_CHROMEOS)
+  GetSwapInfo(&system_metrics.swap_info_);
+#endif
+
+  return system_metrics;
+}
+
+scoped_ptr<Value> SystemMetrics::ToValue() const {
+  scoped_ptr<DictionaryValue> res(new DictionaryValue());
+
+  res->SetInteger("committed_memory", static_cast<int>(committed_memory_));
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+  res->Set("meminfo", memory_info_.ToValue());
+  res->Set("diskinfo", disk_info_.ToValue());
+#endif
+#if defined(OS_CHROMEOS)
+  res->Set("swapinfo", swap_info_.ToValue());
+#endif
+
+  return res.Pass();
+}
+
+double ProcessMetrics::GetPlatformIndependentCPUUsage() {
+#if defined(OS_WIN)
+  return GetCPUUsage() * processor_count_;
+#else
+  return GetCPUUsage();
+#endif
+}
+
+#if defined(OS_MACOSX) || defined(OS_LINUX)
+int ProcessMetrics::CalculateIdleWakeupsPerSecond(
+    uint64 absolute_idle_wakeups) {
+  TimeTicks time = TimeTicks::Now();
+
+  if (last_absolute_idle_wakeups_ == 0) {
+    // First call, just set the last values.
+    last_idle_wakeups_time_ = time;
+    last_absolute_idle_wakeups_ = absolute_idle_wakeups;
+    return 0;
+  }
+
+  int64 wakeups_delta = absolute_idle_wakeups - last_absolute_idle_wakeups_;
+  int64 time_delta = (time - last_idle_wakeups_time_).InMicroseconds();
+  if (time_delta == 0) {
+    NOTREACHED();
+    return 0;
+  }
+
+  last_idle_wakeups_time_ = time;
+  last_absolute_idle_wakeups_ = absolute_idle_wakeups;
+
+  // Round to average wakeups per second.
+  int64 wakeups_delta_for_ms = wakeups_delta * Time::kMicrosecondsPerSecond;
+  return (wakeups_delta_for_ms + time_delta / 2) / time_delta;
+}
+#else
+int ProcessMetrics::GetIdleWakeupsPerSecond() {
+  NOTIMPLEMENTED();  // http://crbug.com/120488
+  return 0;
+}
+#endif  // defined(OS_MACOSX) || defined(OS_LINUX)
+
+}  // namespace base
diff --git a/base/process/process_metrics.h b/base/process/process_metrics.h
new file mode 100644
index 0000000..5916b94
--- /dev/null
+++ b/base/process/process_metrics.h
@@ -0,0 +1,392 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains routines for gathering resource statistics for processes
+// running on the system.
+
+#ifndef BASE_PROCESS_PROCESS_METRICS_H_
+#define BASE_PROCESS_PROCESS_METRICS_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/gtest_prod_util.h"
+#include "base/process/process_handle.h"
+#include "base/time/time.h"
+#include "base/values.h"
+
+#if defined(OS_MACOSX)
+#include <mach/mach.h>
+#endif
+
+namespace base {
+
+#if defined(OS_WIN)
+struct IoCounters : public IO_COUNTERS {
+};
+#elif defined(OS_POSIX)
+struct IoCounters {
+  uint64_t ReadOperationCount;
+  uint64_t WriteOperationCount;
+  uint64_t OtherOperationCount;
+  uint64_t ReadTransferCount;
+  uint64_t WriteTransferCount;
+  uint64_t OtherTransferCount;
+};
+#endif
+
+// Working Set (resident) memory usage broken down by
+//
+// On Windows:
+// priv (private): These pages (kbytes) cannot be shared with any other process.
+// shareable:      These pages (kbytes) can be shared with other processes under
+//                 the right circumstances.
+// shared :        These pages (kbytes) are currently shared with at least one
+//                 other process.
+//
+// On Linux:
+// priv:           Pages mapped only by this process.
+// shared:         PSS or 0 if the kernel doesn't support this.
+// shareable:      0
+
+// On ChromeOS:
+// priv:           Pages mapped only by this process.
+// shared:         PSS or 0 if the kernel doesn't support this.
+// shareable:      0
+// swapped         Pages swapped out to zram.
+//
+// On OS X: TODO(thakis): Revise.
+// priv:           Memory.
+// shared:         0
+// shareable:      0
+//
+struct WorkingSetKBytes {
+  WorkingSetKBytes() : priv(0), shareable(0), shared(0) {}
+  size_t priv;
+  size_t shareable;
+  size_t shared;
+#if defined(OS_CHROMEOS)
+  size_t swapped;
+#endif
+};
+
+// Committed (resident + paged) memory usage broken down by
+// private: These pages cannot be shared with any other process.
+// mapped:  These pages are mapped into the view of a section (backed by
+//          pagefile.sys)
+// image:   These pages are mapped into the view of an image section (backed by
+//          file system)
+struct CommittedKBytes {
+  CommittedKBytes() : priv(0), mapped(0), image(0) {}
+  size_t priv;
+  size_t mapped;
+  size_t image;
+};
+
+// Convert a POSIX timeval to microseconds.
+BASE_EXPORT int64 TimeValToMicroseconds(const struct timeval& tv);
+
+// Provides performance metrics for a specified process (CPU usage, memory and
+// IO counters). To use it, invoke CreateProcessMetrics() to get an instance
+// for a specific process, then access the information with the different get
+// methods.
+class BASE_EXPORT ProcessMetrics {
+ public:
+  ~ProcessMetrics();
+
+  // Creates a ProcessMetrics for the specified process.
+  // The caller owns the returned object.
+#if !defined(OS_MACOSX) || defined(OS_IOS)
+  static ProcessMetrics* CreateProcessMetrics(ProcessHandle process);
+#else
+  class PortProvider {
+   public:
+    virtual ~PortProvider() {}
+
+    // Should return the mach task for |process| if possible, or else
+    // |MACH_PORT_NULL|. Only processes that this returns tasks for will have
+    // metrics on OS X (except for the current process, which always gets
+    // metrics).
+    virtual mach_port_t TaskForPid(ProcessHandle process) const = 0;
+  };
+
+  // The port provider needs to outlive the ProcessMetrics object returned by
+  // this function. If NULL is passed as provider, the returned object
+  // only returns valid metrics if |process| is the current process.
+  static ProcessMetrics* CreateProcessMetrics(ProcessHandle process,
+                                              PortProvider* port_provider);
+#endif  // !defined(OS_MACOSX) || defined(OS_IOS)
+
+  // Returns the current space allocated for the pagefile, in bytes (these pages
+  // may or may not be in memory).  On Linux, this returns the total virtual
+  // memory size.
+  size_t GetPagefileUsage() const;
+  // Returns the peak space allocated for the pagefile, in bytes.
+  size_t GetPeakPagefileUsage() const;
+  // Returns the current working set size, in bytes.  On Linux, this returns
+  // the resident set size.
+  size_t GetWorkingSetSize() const;
+  // Returns the peak working set size, in bytes.
+  size_t GetPeakWorkingSetSize() const;
+  // Returns private and sharedusage, in bytes. Private bytes is the amount of
+  // memory currently allocated to a process that cannot be shared. Returns
+  // false on platform specific error conditions.  Note: |private_bytes|
+  // returns 0 on unsupported OSes: prior to XP SP2.
+  bool GetMemoryBytes(size_t* private_bytes,
+                      size_t* shared_bytes);
+  // Fills a CommittedKBytes with both resident and paged
+  // memory usage as per definition of CommittedBytes.
+  void GetCommittedKBytes(CommittedKBytes* usage) const;
+  // Fills a WorkingSetKBytes containing resident private and shared memory
+  // usage in bytes, as per definition of WorkingSetBytes.
+  bool GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const;
+
+#if defined(OS_MACOSX)
+  // Fills both CommitedKBytes and WorkingSetKBytes in a single operation. This
+  // is more efficient on Mac OS X, as the two can be retrieved with a single
+  // system call.
+  bool GetCommittedAndWorkingSetKBytes(CommittedKBytes* usage,
+                                       WorkingSetKBytes* ws_usage) const;
+#endif
+
+  // Returns the CPU usage in percent since the last time this method or
+  // GetPlatformIndependentCPUUsage() was called. The first time this method
+  // is called it returns 0 and will return the actual CPU info on subsequent
+  // calls. On Windows, the CPU usage value is for all CPUs. So if you have
+  // 2 CPUs and your process is using all the cycles of 1 CPU and not the other
+  // CPU, this method returns 50.
+  double GetCPUUsage();
+
+  // Returns the number of average idle cpu wakeups per second since the last
+  // call.
+  int GetIdleWakeupsPerSecond();
+
+  // Same as GetCPUUsage(), but will return consistent values on all platforms
+  // (cancelling the Windows exception mentioned above) by returning a value in
+  // the range of 0 to (100 * numCPUCores) everywhere.
+  double GetPlatformIndependentCPUUsage();
+
+  // Retrieves accounting information for all I/O operations performed by the
+  // process.
+  // If IO information is retrieved successfully, the function returns true
+  // and fills in the IO_COUNTERS passed in. The function returns false
+  // otherwise.
+  bool GetIOCounters(IoCounters* io_counters) const;
+
+ private:
+#if !defined(OS_MACOSX) || defined(OS_IOS)
+  explicit ProcessMetrics(ProcessHandle process);
+#else
+  ProcessMetrics(ProcessHandle process, PortProvider* port_provider);
+#endif  // !defined(OS_MACOSX) || defined(OS_IOS)
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+  bool GetWorkingSetKBytesStatm(WorkingSetKBytes* ws_usage) const;
+#endif
+
+#if defined(OS_CHROMEOS)
+  bool GetWorkingSetKBytesTotmaps(WorkingSetKBytes *ws_usage) const;
+#endif
+
+#if defined(OS_MACOSX) || defined(OS_LINUX)
+  int CalculateIdleWakeupsPerSecond(uint64 absolute_idle_wakeups);
+#endif
+
+  ProcessHandle process_;
+
+  int processor_count_;
+
+  // Used to store the previous times and CPU usage counts so we can
+  // compute the CPU usage between calls.
+  TimeTicks last_cpu_time_;
+  int64 last_system_time_;
+
+#if defined(OS_MACOSX) || defined(OS_LINUX)
+  // Same thing for idle wakeups.
+  TimeTicks last_idle_wakeups_time_;
+  uint64 last_absolute_idle_wakeups_;
+#endif
+
+#if !defined(OS_IOS)
+#if defined(OS_MACOSX)
+  // Queries the port provider if it's set.
+  mach_port_t TaskForPid(ProcessHandle process) const;
+
+  PortProvider* port_provider_;
+#elif defined(OS_POSIX)
+  // Jiffie count at the last_cpu_time_ we updated.
+  int last_cpu_;
+#endif  // defined(OS_POSIX)
+#endif  // !defined(OS_IOS)
+
+  DISALLOW_COPY_AND_ASSIGN(ProcessMetrics);
+};
+
+// Returns the memory committed by the system in KBytes.
+// Returns 0 if it can't compute the commit charge.
+BASE_EXPORT size_t GetSystemCommitCharge();
+
+// Returns the number of bytes in a memory page.
+BASE_EXPORT size_t GetPageSize();
+
+#if defined(OS_POSIX)
+// Returns the maximum number of file descriptors that can be open by a process
+// at once. If the number is unavailable, a conservative best guess is returned.
+BASE_EXPORT size_t GetMaxFds();
+
+// Sets the file descriptor soft limit to |max_descriptors| or the OS hard
+// limit, whichever is lower.
+BASE_EXPORT void SetFdLimit(unsigned int max_descriptors);
+#endif  // defined(OS_POSIX)
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+// Parse the data found in /proc/<pid>/stat and return the sum of the
+// CPU-related ticks.  Returns -1 on parse error.
+// Exposed for testing.
+BASE_EXPORT int ParseProcStatCPU(const std::string& input);
+
+// Get the number of threads of |process| as available in /proc/<pid>/stat.
+// This should be used with care as no synchronization with running threads is
+// done. This is mostly useful to guarantee being single-threaded.
+// Returns 0 on failure.
+BASE_EXPORT int GetNumberOfThreads(ProcessHandle process);
+
+// /proc/self/exe refers to the current executable.
+BASE_EXPORT extern const char kProcSelfExe[];
+
+// Data from /proc/meminfo about system-wide memory consumption.
+// Values are in KB.
+struct BASE_EXPORT SystemMemoryInfoKB {
+  SystemMemoryInfoKB();
+
+  // Serializes the platform specific fields to value.
+  scoped_ptr<Value> ToValue() const;
+
+  int total;
+  int free;
+  int buffers;
+  int cached;
+  int active_anon;
+  int inactive_anon;
+  int active_file;
+  int inactive_file;
+  int swap_total;
+  int swap_free;
+  int dirty;
+
+  // vmstats data.
+  int pswpin;
+  int pswpout;
+  int pgmajfault;
+
+#ifdef OS_CHROMEOS
+  int shmem;
+  int slab;
+  // Gem data will be -1 if not supported.
+  int gem_objects;
+  long long gem_size;
+#endif
+};
+
+// Parses a string containing the contents of /proc/meminfo
+// returns true on success or false for a parsing error
+BASE_EXPORT bool ParseProcMeminfo(const std::string& input,
+                                  SystemMemoryInfoKB* meminfo);
+
+// Parses a string containing the contents of /proc/vmstat
+// returns true on success or false for a parsing error
+BASE_EXPORT bool ParseProcVmstat(const std::string& input,
+                                 SystemMemoryInfoKB* meminfo);
+
+// Retrieves data from /proc/meminfo and /proc/vmstat
+// about system-wide memory consumption.
+// Fills in the provided |meminfo| structure. Returns true on success.
+// Exposed for memory debugging widget.
+BASE_EXPORT bool GetSystemMemoryInfo(SystemMemoryInfoKB* meminfo);
+
+// Data from /proc/diskstats about system-wide disk I/O.
+struct BASE_EXPORT SystemDiskInfo {
+  SystemDiskInfo();
+
+  // Serializes the platform specific fields to value.
+  scoped_ptr<Value> ToValue() const;
+
+  uint64 reads;
+  uint64 reads_merged;
+  uint64 sectors_read;
+  uint64 read_time;
+  uint64 writes;
+  uint64 writes_merged;
+  uint64 sectors_written;
+  uint64 write_time;
+  uint64 io;
+  uint64 io_time;
+  uint64 weighted_io_time;
+};
+
+// Checks whether the candidate string is a valid disk name, [hsv]d[a-z]+
+// for a generic disk or mmcblk[0-9]+ for the MMC case.
+// Names of disk partitions (e.g. sda1) are not valid.
+BASE_EXPORT bool IsValidDiskName(const std::string& candidate);
+
+// Retrieves data from /proc/diskstats about system-wide disk I/O.
+// Fills in the provided |diskinfo| structure. Returns true on success.
+BASE_EXPORT bool GetSystemDiskInfo(SystemDiskInfo* diskinfo);
+#endif  // defined(OS_LINUX) || defined(OS_ANDROID)
+
+#if defined(OS_CHROMEOS)
+// Data from files in directory /sys/block/zram0 about ZRAM usage.
+struct BASE_EXPORT SwapInfo {
+  SwapInfo()
+      : num_reads(0),
+        num_writes(0),
+        compr_data_size(0),
+        orig_data_size(0),
+        mem_used_total(0) {
+  }
+
+  // Serializes the platform specific fields to value.
+  scoped_ptr<Value> ToValue() const;
+
+  uint64 num_reads;
+  uint64 num_writes;
+  uint64 compr_data_size;
+  uint64 orig_data_size;
+  uint64 mem_used_total;
+};
+
+// In ChromeOS, reads files from /sys/block/zram0 that contain ZRAM usage data.
+// Fills in the provided |swap_data| structure.
+BASE_EXPORT void GetSwapInfo(SwapInfo* swap_info);
+#endif  // defined(OS_CHROMEOS)
+
+// Collects and holds performance metrics for system memory and disk.
+// Provides functionality to retrieve the data on various platforms and
+// to serialize the stored data.
+class SystemMetrics {
+ public:
+  SystemMetrics();
+
+  static SystemMetrics Sample();
+
+  // Serializes the system metrics to value.
+  scoped_ptr<Value> ToValue() const;
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(SystemMetricsTest, SystemMetrics);
+
+  size_t committed_memory_;
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+  SystemMemoryInfoKB memory_info_;
+  SystemDiskInfo disk_info_;
+#endif
+#if defined(OS_CHROMEOS)
+  SwapInfo swap_info_;
+#endif
+};
+
+}  // namespace base
+
+#endif  // BASE_PROCESS_PROCESS_METRICS_H_
diff --git a/base/process/process_metrics_freebsd.cc b/base/process/process_metrics_freebsd.cc
new file mode 100644
index 0000000..9d4149d
--- /dev/null
+++ b/base/process/process_metrics_freebsd.cc
@@ -0,0 +1,122 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_metrics.h"
+
+#include <sys/sysctl.h>
+#include <sys/user.h>
+#include <unistd.h>
+
+#include "base/sys_info.h"
+
+namespace base {
+
+ProcessMetrics::ProcessMetrics(ProcessHandle process)
+    : process_(process),
+      last_system_time_(0),
+      last_cpu_(0) {
+  processor_count_ = base::SysInfo::NumberOfProcessors();
+}
+
+// static
+ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) {
+  return new ProcessMetrics(process);
+}
+
+size_t ProcessMetrics::GetPagefileUsage() const {
+  struct kinfo_proc info;
+  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, process_ };
+  size_t length = sizeof(info);
+
+  if (sysctl(mib, arraysize(mib), &info, &length, NULL, 0) < 0)
+    return 0;
+
+  return info.ki_size;
+}
+
+size_t ProcessMetrics::GetPeakPagefileUsage() const {
+  return 0;
+}
+
+size_t ProcessMetrics::GetWorkingSetSize() const {
+  struct kinfo_proc info;
+  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, process_ };
+  size_t length = sizeof(info);
+
+  if (sysctl(mib, arraysize(mib), &info, &length, NULL, 0) < 0)
+    return 0;
+
+  return info.ki_rssize * getpagesize();
+}
+
+size_t ProcessMetrics::GetPeakWorkingSetSize() const {
+  return 0;
+}
+
+bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes,
+                                    size_t* shared_bytes) {
+  WorkingSetKBytes ws_usage;
+  if (!GetWorkingSetKBytes(&ws_usage))
+    return false;
+
+  if (private_bytes)
+    *private_bytes = ws_usage.priv << 10;
+
+  if (shared_bytes)
+    *shared_bytes = ws_usage.shared * 1024;
+
+  return true;
+}
+
+bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
+// TODO(bapt) be sure we can't be precise
+  size_t priv = GetWorkingSetSize();
+  if (!priv)
+    return false;
+  ws_usage->priv = priv / 1024;
+  ws_usage->shareable = 0;
+  ws_usage->shared = 0;
+
+  return true;
+}
+
+double ProcessMetrics::GetCPUUsage() {
+  struct kinfo_proc info;
+  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, process_ };
+  size_t length = sizeof(info);
+
+  if (sysctl(mib, arraysize(mib), &info, &length, NULL, 0) < 0)
+    return 0;
+
+  return (info.ki_pctcpu / FSCALE) * 100.0;
+}
+
+bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const {
+  return false;
+}
+
+size_t GetSystemCommitCharge() {
+  int mib[2], pagesize;
+  unsigned long mem_total, mem_free, mem_inactive;
+  size_t length = sizeof(mem_total);
+
+  if (sysctl(mib, arraysize(mib), &mem_total, &length, NULL, 0) < 0)
+    return 0;
+
+  length = sizeof(mem_free);
+  if (sysctlbyname("vm.stats.vm.v_free_count", &mem_free, &length, NULL, 0) < 0)
+    return 0;
+
+  length = sizeof(mem_inactive);
+  if (sysctlbyname("vm.stats.vm.v_inactive_count", &mem_inactive, &length,
+      NULL, 0) < 0) {
+    return 0;
+  }
+
+  pagesize = getpagesize();
+
+  return mem_total - (mem_free*pagesize) - (mem_inactive*pagesize);
+}
+
+}  // namespace base
diff --git a/base/process/process_metrics_ios.cc b/base/process/process_metrics_ios.cc
new file mode 100644
index 0000000..07f2c8d
--- /dev/null
+++ b/base/process/process_metrics_ios.cc
@@ -0,0 +1,85 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_metrics.h"
+
+#include <mach/task.h>
+
+#include "base/logging.h"
+
+namespace base {
+
+namespace {
+
+bool GetTaskInfo(task_basic_info_64* task_info_data) {
+  mach_msg_type_number_t count = TASK_BASIC_INFO_64_COUNT;
+  kern_return_t kr = task_info(mach_task_self(),
+                               TASK_BASIC_INFO_64,
+                               reinterpret_cast<task_info_t>(task_info_data),
+                               &count);
+  return kr == KERN_SUCCESS;
+}
+
+}  // namespace
+
+ProcessMetrics::ProcessMetrics(ProcessHandle process) {}
+
+ProcessMetrics::~ProcessMetrics() {}
+
+// static
+ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) {
+  return new ProcessMetrics(process);
+}
+
+double ProcessMetrics::GetCPUUsage() {
+  NOTIMPLEMENTED();
+  return 0;
+}
+
+size_t ProcessMetrics::GetPagefileUsage() const {
+  task_basic_info_64 task_info_data;
+  if (!GetTaskInfo(&task_info_data))
+    return 0;
+  return task_info_data.virtual_size;
+}
+
+size_t ProcessMetrics::GetWorkingSetSize() const {
+  task_basic_info_64 task_info_data;
+  if (!GetTaskInfo(&task_info_data))
+    return 0;
+  return task_info_data.resident_size;
+}
+
+size_t GetMaxFds() {
+  static const rlim_t kSystemDefaultMaxFds = 256;
+  rlim_t max_fds;
+  struct rlimit nofile;
+  if (getrlimit(RLIMIT_NOFILE, &nofile)) {
+    // Error case: Take a best guess.
+    max_fds = kSystemDefaultMaxFds;
+  } else {
+    max_fds = nofile.rlim_cur;
+  }
+
+  if (max_fds > INT_MAX)
+    max_fds = INT_MAX;
+
+  return static_cast<size_t>(max_fds);
+}
+
+void SetFdLimit(unsigned int max_descriptors) {
+  // Unimplemented.
+}
+
+size_t GetPageSize() {
+  return getpagesize();
+}
+
+// Bytes committed by the system.
+size_t GetSystemCommitCharge() {
+  NOTIMPLEMENTED();
+  return 0;
+}
+
+}  // namespace base
diff --git a/base/process/process_metrics_linux.cc b/base/process/process_metrics_linux.cc
new file mode 100644
index 0000000..c564a67
--- /dev/null
+++ b/base/process/process_metrics_linux.cc
@@ -0,0 +1,916 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_metrics.h"
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/process/internal_linux.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_tokenizer.h"
+#include "base/strings/string_util.h"
+#include "base/sys_info.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace base {
+
+namespace {
+
+void TrimKeyValuePairs(StringPairs* pairs) {
+  DCHECK(pairs);
+  StringPairs& p_ref = *pairs;
+  for (size_t i = 0; i < p_ref.size(); ++i) {
+    TrimWhitespaceASCII(p_ref[i].first, TRIM_ALL, &p_ref[i].first);
+    TrimWhitespaceASCII(p_ref[i].second, TRIM_ALL, &p_ref[i].second);
+  }
+}
+
+#if defined(OS_CHROMEOS)
+// Read a file with a single number string and return the number as a uint64.
+static uint64 ReadFileToUint64(const FilePath file) {
+  std::string file_as_string;
+  if (!ReadFileToString(file, &file_as_string))
+    return 0;
+  TrimWhitespaceASCII(file_as_string, TRIM_ALL, &file_as_string);
+  uint64 file_as_uint64 = 0;
+  if (!StringToUint64(file_as_string, &file_as_uint64))
+    return 0;
+  return file_as_uint64;
+}
+#endif
+
+// Read /proc/<pid>/status and return the value for |field|, or 0 on failure.
+// Only works for fields in the form of "Field: value kB".
+size_t ReadProcStatusAndGetFieldAsSizeT(pid_t pid, const std::string& field) {
+  std::string status;
+  {
+    // Synchronously reading files in /proc does not hit the disk.
+    ThreadRestrictions::ScopedAllowIO allow_io;
+    FilePath stat_file = internal::GetProcPidDir(pid).Append("status");
+    if (!ReadFileToString(stat_file, &status))
+      return 0;
+  }
+
+  StringPairs pairs;
+  SplitStringIntoKeyValuePairs(status, ':', '\n', &pairs);
+  TrimKeyValuePairs(&pairs);
+  for (size_t i = 0; i < pairs.size(); ++i) {
+    const std::string& key = pairs[i].first;
+    const std::string& value_str = pairs[i].second;
+    if (key == field) {
+      std::vector<std::string> split_value_str;
+      SplitString(value_str, ' ', &split_value_str);
+      if (split_value_str.size() != 2 || split_value_str[1] != "kB") {
+        NOTREACHED();
+        return 0;
+      }
+      size_t value;
+      if (!StringToSizeT(split_value_str[0], &value)) {
+        NOTREACHED();
+        return 0;
+      }
+      return value;
+    }
+  }
+  NOTREACHED();
+  return 0;
+}
+
+#if defined(OS_LINUX)
+// Read /proc/<pid>/sched and look for |field|. On succes, return true and
+// write the value for |field| into |result|.
+// Only works for fields in the form of "field    :     uint_value"
+bool ReadProcSchedAndGetFieldAsUint64(pid_t pid,
+                                      const std::string& field,
+                                      uint64* result) {
+  std::string sched_data;
+  {
+    // Synchronously reading files in /proc does not hit the disk.
+    ThreadRestrictions::ScopedAllowIO allow_io;
+    FilePath sched_file = internal::GetProcPidDir(pid).Append("sched");
+    if (!ReadFileToString(sched_file, &sched_data))
+      return false;
+  }
+
+  StringPairs pairs;
+  SplitStringIntoKeyValuePairs(sched_data, ':', '\n', &pairs);
+  TrimKeyValuePairs(&pairs);
+  for (size_t i = 0; i < pairs.size(); ++i) {
+    const std::string& key = pairs[i].first;
+    const std::string& value_str = pairs[i].second;
+    if (key == field) {
+      uint64 value;
+      if (!StringToUint64(value_str, &value))
+        return false;
+      *result = value;
+      return true;
+    }
+  }
+  return false;
+}
+#endif  // defined(OS_LINUX)
+
+// Get the total CPU of a single process.  Return value is number of jiffies
+// on success or -1 on error.
+int GetProcessCPU(pid_t pid) {
+  // Use /proc/<pid>/task to find all threads and parse their /stat file.
+  FilePath task_path = internal::GetProcPidDir(pid).Append("task");
+
+  DIR* dir = opendir(task_path.value().c_str());
+  if (!dir) {
+    DPLOG(ERROR) << "opendir(" << task_path.value() << ")";
+    return -1;
+  }
+
+  int total_cpu = 0;
+  while (struct dirent* ent = readdir(dir)) {
+    pid_t tid = internal::ProcDirSlotToPid(ent->d_name);
+    if (!tid)
+      continue;
+
+    // Synchronously reading files in /proc does not hit the disk.
+    ThreadRestrictions::ScopedAllowIO allow_io;
+
+    std::string stat;
+    FilePath stat_path =
+        task_path.Append(ent->d_name).Append(internal::kStatFile);
+    if (ReadFileToString(stat_path, &stat)) {
+      int cpu = ParseProcStatCPU(stat);
+      if (cpu > 0)
+        total_cpu += cpu;
+    }
+  }
+  closedir(dir);
+
+  return total_cpu;
+}
+
+}  // namespace
+
+// static
+ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) {
+  return new ProcessMetrics(process);
+}
+
+// On linux, we return vsize.
+size_t ProcessMetrics::GetPagefileUsage() const {
+  return internal::ReadProcStatsAndGetFieldAsSizeT(process_,
+                                                   internal::VM_VSIZE);
+}
+
+// On linux, we return the high water mark of vsize.
+size_t ProcessMetrics::GetPeakPagefileUsage() const {
+  return ReadProcStatusAndGetFieldAsSizeT(process_, "VmPeak") * 1024;
+}
+
+// On linux, we return RSS.
+size_t ProcessMetrics::GetWorkingSetSize() const {
+  return internal::ReadProcStatsAndGetFieldAsSizeT(process_, internal::VM_RSS) *
+      getpagesize();
+}
+
+// On linux, we return the high water mark of RSS.
+size_t ProcessMetrics::GetPeakWorkingSetSize() const {
+  return ReadProcStatusAndGetFieldAsSizeT(process_, "VmHWM") * 1024;
+}
+
+bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes,
+                                    size_t* shared_bytes) {
+  WorkingSetKBytes ws_usage;
+  if (!GetWorkingSetKBytes(&ws_usage))
+    return false;
+
+  if (private_bytes)
+    *private_bytes = ws_usage.priv * 1024;
+
+  if (shared_bytes)
+    *shared_bytes = ws_usage.shared * 1024;
+
+  return true;
+}
+
+bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
+#if defined(OS_CHROMEOS)
+  if (GetWorkingSetKBytesTotmaps(ws_usage))
+    return true;
+#endif
+  return GetWorkingSetKBytesStatm(ws_usage);
+}
+
+double ProcessMetrics::GetCPUUsage() {
+  TimeTicks time = TimeTicks::Now();
+
+  if (last_cpu_ == 0) {
+    // First call, just set the last values.
+    last_cpu_time_ = time;
+    last_cpu_ = GetProcessCPU(process_);
+    return 0;
+  }
+
+  int64 time_delta = (time - last_cpu_time_).InMicroseconds();
+  DCHECK_NE(time_delta, 0);
+  if (time_delta == 0)
+    return 0;
+
+  int cpu = GetProcessCPU(process_);
+
+  // We have the number of jiffies in the time period.  Convert to percentage.
+  // Note this means we will go *over* 100 in the case where multiple threads
+  // are together adding to more than one CPU's worth.
+  TimeDelta cpu_time = internal::ClockTicksToTimeDelta(cpu);
+  TimeDelta last_cpu_time = internal::ClockTicksToTimeDelta(last_cpu_);
+  double percentage = 100.0 * (cpu_time - last_cpu_time).InSecondsF() /
+      TimeDelta::FromMicroseconds(time_delta).InSecondsF();
+
+  last_cpu_time_ = time;
+  last_cpu_ = cpu;
+
+  return percentage;
+}
+
+// To have /proc/self/io file you must enable CONFIG_TASK_IO_ACCOUNTING
+// in your kernel configuration.
+bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const {
+  // Synchronously reading files in /proc does not hit the disk.
+  ThreadRestrictions::ScopedAllowIO allow_io;
+
+  std::string proc_io_contents;
+  FilePath io_file = internal::GetProcPidDir(process_).Append("io");
+  if (!ReadFileToString(io_file, &proc_io_contents))
+    return false;
+
+  io_counters->OtherOperationCount = 0;
+  io_counters->OtherTransferCount = 0;
+
+  StringPairs pairs;
+  SplitStringIntoKeyValuePairs(proc_io_contents, ':', '\n', &pairs);
+  TrimKeyValuePairs(&pairs);
+  for (size_t i = 0; i < pairs.size(); ++i) {
+    const std::string& key = pairs[i].first;
+    const std::string& value_str = pairs[i].second;
+    uint64* target_counter = NULL;
+    if (key == "syscr")
+      target_counter = &io_counters->ReadOperationCount;
+    else if (key == "syscw")
+      target_counter = &io_counters->WriteOperationCount;
+    else if (key == "rchar")
+      target_counter = &io_counters->ReadTransferCount;
+    else if (key == "wchar")
+      target_counter = &io_counters->WriteTransferCount;
+    if (!target_counter)
+      continue;
+    bool converted = StringToUint64(value_str, target_counter);
+    DCHECK(converted);
+  }
+  return true;
+}
+
+ProcessMetrics::ProcessMetrics(ProcessHandle process)
+    : process_(process),
+      last_system_time_(0),
+#if defined(OS_LINUX)
+      last_absolute_idle_wakeups_(0),
+#endif
+      last_cpu_(0) {
+  processor_count_ = SysInfo::NumberOfProcessors();
+}
+
+#if defined(OS_CHROMEOS)
+// Private, Shared and Proportional working set sizes are obtained from
+// /proc/<pid>/totmaps
+bool ProcessMetrics::GetWorkingSetKBytesTotmaps(WorkingSetKBytes *ws_usage)
+  const {
+  // The format of /proc/<pid>/totmaps is:
+  //
+  // Rss:                6120 kB
+  // Pss:                3335 kB
+  // Shared_Clean:       1008 kB
+  // Shared_Dirty:       4012 kB
+  // Private_Clean:         4 kB
+  // Private_Dirty:      1096 kB
+  // Referenced:          XXX kB
+  // Anonymous:           XXX kB
+  // AnonHugePages:       XXX kB
+  // Swap:                XXX kB
+  // Locked:              XXX kB
+  const size_t kPssIndex = (1 * 3) + 1;
+  const size_t kPrivate_CleanIndex = (4 * 3) + 1;
+  const size_t kPrivate_DirtyIndex = (5 * 3) + 1;
+  const size_t kSwapIndex = (9 * 3) + 1;
+
+  std::string totmaps_data;
+  {
+    FilePath totmaps_file = internal::GetProcPidDir(process_).Append("totmaps");
+    ThreadRestrictions::ScopedAllowIO allow_io;
+    bool ret = ReadFileToString(totmaps_file, &totmaps_data);
+    if (!ret || totmaps_data.length() == 0)
+      return false;
+  }
+
+  std::vector<std::string> totmaps_fields;
+  SplitStringAlongWhitespace(totmaps_data, &totmaps_fields);
+
+  DCHECK_EQ("Pss:", totmaps_fields[kPssIndex-1]);
+  DCHECK_EQ("Private_Clean:", totmaps_fields[kPrivate_CleanIndex - 1]);
+  DCHECK_EQ("Private_Dirty:", totmaps_fields[kPrivate_DirtyIndex - 1]);
+  DCHECK_EQ("Swap:", totmaps_fields[kSwapIndex-1]);
+
+  int pss = 0;
+  int private_clean = 0;
+  int private_dirty = 0;
+  int swap = 0;
+  bool ret = true;
+  ret &= StringToInt(totmaps_fields[kPssIndex], &pss);
+  ret &= StringToInt(totmaps_fields[kPrivate_CleanIndex], &private_clean);
+  ret &= StringToInt(totmaps_fields[kPrivate_DirtyIndex], &private_dirty);
+  ret &= StringToInt(totmaps_fields[kSwapIndex], &swap);
+
+  // On ChromeOS swap is to zram. We count this as private / shared, as
+  // increased swap decreases available RAM to user processes, which would
+  // otherwise create surprising results.
+  ws_usage->priv = private_clean + private_dirty + swap;
+  ws_usage->shared = pss + swap;
+  ws_usage->shareable = 0;
+  ws_usage->swapped = swap;
+  return ret;
+}
+#endif
+
+// Private and Shared working set sizes are obtained from /proc/<pid>/statm.
+bool ProcessMetrics::GetWorkingSetKBytesStatm(WorkingSetKBytes* ws_usage)
+    const {
+  // Use statm instead of smaps because smaps is:
+  // a) Large and slow to parse.
+  // b) Unavailable in the SUID sandbox.
+
+  // First we need to get the page size, since everything is measured in pages.
+  // For details, see: man 5 proc.
+  const int page_size_kb = getpagesize() / 1024;
+  if (page_size_kb <= 0)
+    return false;
+
+  std::string statm;
+  {
+    FilePath statm_file = internal::GetProcPidDir(process_).Append("statm");
+    // Synchronously reading files in /proc does not hit the disk.
+    ThreadRestrictions::ScopedAllowIO allow_io;
+    bool ret = ReadFileToString(statm_file, &statm);
+    if (!ret || statm.length() == 0)
+      return false;
+  }
+
+  std::vector<std::string> statm_vec;
+  SplitString(statm, ' ', &statm_vec);
+  if (statm_vec.size() != 7)
+    return false;  // Not the format we expect.
+
+  int statm_rss, statm_shared;
+  bool ret = true;
+  ret &= StringToInt(statm_vec[1], &statm_rss);
+  ret &= StringToInt(statm_vec[2], &statm_shared);
+
+  ws_usage->priv = (statm_rss - statm_shared) * page_size_kb;
+  ws_usage->shared = statm_shared * page_size_kb;
+
+  // Sharable is not calculated, as it does not provide interesting data.
+  ws_usage->shareable = 0;
+
+#if defined(OS_CHROMEOS)
+  // Can't get swapped memory from statm.
+  ws_usage->swapped = 0;
+#endif
+
+  return ret;
+}
+
+size_t GetSystemCommitCharge() {
+  SystemMemoryInfoKB meminfo;
+  if (!GetSystemMemoryInfo(&meminfo))
+    return 0;
+  return meminfo.total - meminfo.free - meminfo.buffers - meminfo.cached;
+}
+
+int ParseProcStatCPU(const std::string& input) {
+  // |input| may be empty if the process disappeared somehow.
+  // e.g. http://crbug.com/145811.
+  if (input.empty())
+    return -1;
+
+  size_t start = input.find_last_of(')');
+  if (start == input.npos)
+    return -1;
+
+  // Number of spaces remaining until reaching utime's index starting after the
+  // last ')'.
+  int num_spaces_remaining = internal::VM_UTIME - 1;
+
+  size_t i = start;
+  while ((i = input.find(' ', i + 1)) != input.npos) {
+    // Validate the assumption that there aren't any contiguous spaces
+    // in |input| before utime.
+    DCHECK_NE(input[i - 1], ' ');
+    if (--num_spaces_remaining == 0) {
+      int utime = 0;
+      int stime = 0;
+      if (sscanf(&input.data()[i], "%d %d", &utime, &stime) != 2)
+        return -1;
+
+      return utime + stime;
+    }
+  }
+
+  return -1;
+}
+
+const char kProcSelfExe[] = "/proc/self/exe";
+
+int GetNumberOfThreads(ProcessHandle process) {
+  return internal::ReadProcStatsAndGetFieldAsInt64(process,
+                                                   internal::VM_NUMTHREADS);
+}
+
+namespace {
+
+// The format of /proc/diskstats is:
+//  Device major number
+//  Device minor number
+//  Device name
+//  Field  1 -- # of reads completed
+//      This is the total number of reads completed successfully.
+//  Field  2 -- # of reads merged, field 6 -- # of writes merged
+//      Reads and writes which are adjacent to each other may be merged for
+//      efficiency.  Thus two 4K reads may become one 8K read before it is
+//      ultimately handed to the disk, and so it will be counted (and queued)
+//      as only one I/O.  This field lets you know how often this was done.
+//  Field  3 -- # of sectors read
+//      This is the total number of sectors read successfully.
+//  Field  4 -- # of milliseconds spent reading
+//      This is the total number of milliseconds spent by all reads (as
+//      measured from __make_request() to end_that_request_last()).
+//  Field  5 -- # of writes completed
+//      This is the total number of writes completed successfully.
+//  Field  6 -- # of writes merged
+//      See the description of field 2.
+//  Field  7 -- # of sectors written
+//      This is the total number of sectors written successfully.
+//  Field  8 -- # of milliseconds spent writing
+//      This is the total number of milliseconds spent by all writes (as
+//      measured from __make_request() to end_that_request_last()).
+//  Field  9 -- # of I/Os currently in progress
+//      The only field that should go to zero. Incremented as requests are
+//      given to appropriate struct request_queue and decremented as they
+//      finish.
+//  Field 10 -- # of milliseconds spent doing I/Os
+//      This field increases so long as field 9 is nonzero.
+//  Field 11 -- weighted # of milliseconds spent doing I/Os
+//      This field is incremented at each I/O start, I/O completion, I/O
+//      merge, or read of these stats by the number of I/Os in progress
+//      (field 9) times the number of milliseconds spent doing I/O since the
+//      last update of this field.  This can provide an easy measure of both
+//      I/O completion time and the backlog that may be accumulating.
+
+const size_t kDiskDriveName = 2;
+const size_t kDiskReads = 3;
+const size_t kDiskReadsMerged = 4;
+const size_t kDiskSectorsRead = 5;
+const size_t kDiskReadTime = 6;
+const size_t kDiskWrites = 7;
+const size_t kDiskWritesMerged = 8;
+const size_t kDiskSectorsWritten = 9;
+const size_t kDiskWriteTime = 10;
+const size_t kDiskIO = 11;
+const size_t kDiskIOTime = 12;
+const size_t kDiskWeightedIOTime = 13;
+
+}  // namespace
+
+SystemMemoryInfoKB::SystemMemoryInfoKB() {
+  total = 0;
+  free = 0;
+  buffers = 0;
+  cached = 0;
+  active_anon = 0;
+  inactive_anon = 0;
+  active_file = 0;
+  inactive_file = 0;
+  swap_total = 0;
+  swap_free = 0;
+  dirty = 0;
+
+  pswpin = 0;
+  pswpout = 0;
+  pgmajfault = 0;
+
+#ifdef OS_CHROMEOS
+  shmem = 0;
+  slab = 0;
+  gem_objects = -1;
+  gem_size = -1;
+#endif
+}
+
+scoped_ptr<Value> SystemMemoryInfoKB::ToValue() const {
+  scoped_ptr<DictionaryValue> res(new DictionaryValue());
+
+  res->SetInteger("total", total);
+  res->SetInteger("free", free);
+  res->SetInteger("buffers", buffers);
+  res->SetInteger("cached", cached);
+  res->SetInteger("active_anon", active_anon);
+  res->SetInteger("inactive_anon", inactive_anon);
+  res->SetInteger("active_file", active_file);
+  res->SetInteger("inactive_file", inactive_file);
+  res->SetInteger("swap_total", swap_total);
+  res->SetInteger("swap_free", swap_free);
+  res->SetInteger("swap_used", swap_total - swap_free);
+  res->SetInteger("dirty", dirty);
+  res->SetInteger("pswpin", pswpin);
+  res->SetInteger("pswpout", pswpout);
+  res->SetInteger("pgmajfault", pgmajfault);
+#ifdef OS_CHROMEOS
+  res->SetInteger("shmem", shmem);
+  res->SetInteger("slab", slab);
+  res->SetInteger("gem_objects", gem_objects);
+  res->SetInteger("gem_size", gem_size);
+#endif
+
+  return res.Pass();
+}
+
+// exposed for testing
+bool ParseProcMeminfo(const std::string& meminfo_data,
+                      SystemMemoryInfoKB* meminfo) {
+  // The format of /proc/meminfo is:
+  //
+  // MemTotal:      8235324 kB
+  // MemFree:       1628304 kB
+  // Buffers:        429596 kB
+  // Cached:        4728232 kB
+  // ...
+  // There is no guarantee on the ordering or position
+  // though it doesn't appear to change very often
+
+  // As a basic sanity check, let's make sure we at least get non-zero
+  // MemTotal value
+  meminfo->total = 0;
+
+  std::vector<std::string> meminfo_lines;
+  Tokenize(meminfo_data, "\n", &meminfo_lines);
+  for (std::vector<std::string>::iterator it = meminfo_lines.begin();
+       it != meminfo_lines.end(); ++it) {
+    std::vector<std::string> tokens;
+    SplitStringAlongWhitespace(*it, &tokens);
+    // HugePages_* only has a number and no suffix so we can't rely on
+    // there being exactly 3 tokens.
+    if (tokens.size() <= 1) {
+      DLOG(WARNING) << "meminfo: tokens: " << tokens.size()
+                    << " malformed line: " << *it;
+      continue;
+    }
+
+    int* target = NULL;
+    if (tokens[0] == "MemTotal:")
+      target = &meminfo->total;
+    else if (tokens[0] == "MemFree:")
+      target = &meminfo->free;
+    else if (tokens[0] == "Buffers:")
+      target = &meminfo->buffers;
+    else if (tokens[0] == "Cached:")
+      target = &meminfo->cached;
+    else if (tokens[0] == "Active(anon):")
+      target = &meminfo->active_anon;
+    else if (tokens[0] == "Inactive(anon):")
+      target = &meminfo->inactive_anon;
+    else if (tokens[0] == "Active(file):")
+      target = &meminfo->active_file;
+    else if (tokens[0] == "Inactive(file):")
+      target = &meminfo->inactive_file;
+    else if (tokens[0] == "SwapTotal:")
+      target = &meminfo->swap_total;
+    else if (tokens[0] == "SwapFree:")
+      target = &meminfo->swap_free;
+    else if (tokens[0] == "Dirty:")
+      target = &meminfo->dirty;
+#if defined(OS_CHROMEOS)
+    // Chrome OS has a tweaked kernel that allows us to query Shmem, which is
+    // usually video memory otherwise invisible to the OS.
+    else if (tokens[0] == "Shmem:")
+      target = &meminfo->shmem;
+    else if (tokens[0] == "Slab:")
+      target = &meminfo->slab;
+#endif
+    if (target)
+      StringToInt(tokens[1], target);
+  }
+
+  // Make sure we got a valid MemTotal.
+  return meminfo->total > 0;
+}
+
+// exposed for testing
+bool ParseProcVmstat(const std::string& vmstat_data,
+                     SystemMemoryInfoKB* meminfo) {
+  // The format of /proc/vmstat is:
+  //
+  // nr_free_pages 299878
+  // nr_inactive_anon 239863
+  // nr_active_anon 1318966
+  // nr_inactive_file 2015629
+  // ...
+  //
+  // We iterate through the whole file because the position of the
+  // fields are dependent on the kernel version and configuration.
+
+  std::vector<std::string> vmstat_lines;
+  Tokenize(vmstat_data, "\n", &vmstat_lines);
+  for (std::vector<std::string>::iterator it = vmstat_lines.begin();
+       it != vmstat_lines.end(); ++it) {
+    std::vector<std::string> tokens;
+    SplitString(*it, ' ', &tokens);
+    if (tokens.size() != 2)
+      continue;
+
+    if (tokens[0] == "pswpin") {
+      StringToInt(tokens[1], &meminfo->pswpin);
+    } else if (tokens[0] == "pswpout") {
+      StringToInt(tokens[1], &meminfo->pswpout);
+    } else if (tokens[0] == "pgmajfault") {
+      StringToInt(tokens[1], &meminfo->pgmajfault);
+    }
+  }
+
+  return true;
+}
+
+bool GetSystemMemoryInfo(SystemMemoryInfoKB* meminfo) {
+  // Synchronously reading files in /proc and /sys are safe.
+  ThreadRestrictions::ScopedAllowIO allow_io;
+
+  // Used memory is: total - free - buffers - caches
+  FilePath meminfo_file("/proc/meminfo");
+  std::string meminfo_data;
+  if (!ReadFileToString(meminfo_file, &meminfo_data)) {
+    DLOG(WARNING) << "Failed to open " << meminfo_file.value();
+    return false;
+  }
+
+  if (!ParseProcMeminfo(meminfo_data, meminfo)) {
+    DLOG(WARNING) << "Failed to parse " << meminfo_file.value();
+    return false;
+  }
+
+#if defined(OS_CHROMEOS)
+  // Report on Chrome OS GEM object graphics memory. /run/debugfs_gpu is a
+  // bind mount into /sys/kernel/debug and synchronously reading the in-memory
+  // files in /sys is fast.
+#if defined(ARCH_CPU_ARM_FAMILY)
+  FilePath geminfo_file("/run/debugfs_gpu/exynos_gem_objects");
+#else
+  FilePath geminfo_file("/run/debugfs_gpu/i915_gem_objects");
+#endif
+  std::string geminfo_data;
+  meminfo->gem_objects = -1;
+  meminfo->gem_size = -1;
+  if (ReadFileToString(geminfo_file, &geminfo_data)) {
+    int gem_objects = -1;
+    long long gem_size = -1;
+    int num_res = sscanf(geminfo_data.c_str(),
+                         "%d objects, %lld bytes",
+                         &gem_objects, &gem_size);
+    if (num_res == 2) {
+      meminfo->gem_objects = gem_objects;
+      meminfo->gem_size = gem_size;
+    }
+  }
+
+#if defined(ARCH_CPU_ARM_FAMILY)
+  // Incorporate Mali graphics memory if present.
+  FilePath mali_memory_file("/sys/class/misc/mali0/device/memory");
+  std::string mali_memory_data;
+  if (ReadFileToString(mali_memory_file, &mali_memory_data)) {
+    long long mali_size = -1;
+    int num_res = sscanf(mali_memory_data.c_str(), "%lld bytes", &mali_size);
+    if (num_res == 1)
+      meminfo->gem_size += mali_size;
+  }
+#endif  // defined(ARCH_CPU_ARM_FAMILY)
+#endif  // defined(OS_CHROMEOS)
+
+  FilePath vmstat_file("/proc/vmstat");
+  std::string vmstat_data;
+  if (!ReadFileToString(vmstat_file, &vmstat_data)) {
+    DLOG(WARNING) << "Failed to open " << vmstat_file.value();
+    return false;
+  }
+  if (!ParseProcVmstat(vmstat_data, meminfo)) {
+    DLOG(WARNING) << "Failed to parse " << vmstat_file.value();
+    return false;
+  }
+
+  return true;
+}
+
+SystemDiskInfo::SystemDiskInfo() {
+  reads = 0;
+  reads_merged = 0;
+  sectors_read = 0;
+  read_time = 0;
+  writes = 0;
+  writes_merged = 0;
+  sectors_written = 0;
+  write_time = 0;
+  io = 0;
+  io_time = 0;
+  weighted_io_time = 0;
+}
+
+scoped_ptr<Value> SystemDiskInfo::ToValue() const {
+  scoped_ptr<DictionaryValue> res(new DictionaryValue());
+
+  // Write out uint64 variables as doubles.
+  // Note: this may discard some precision, but for JS there's no other option.
+  res->SetDouble("reads", static_cast<double>(reads));
+  res->SetDouble("reads_merged", static_cast<double>(reads_merged));
+  res->SetDouble("sectors_read", static_cast<double>(sectors_read));
+  res->SetDouble("read_time", static_cast<double>(read_time));
+  res->SetDouble("writes", static_cast<double>(writes));
+  res->SetDouble("writes_merged", static_cast<double>(writes_merged));
+  res->SetDouble("sectors_written", static_cast<double>(sectors_written));
+  res->SetDouble("write_time", static_cast<double>(write_time));
+  res->SetDouble("io", static_cast<double>(io));
+  res->SetDouble("io_time", static_cast<double>(io_time));
+  res->SetDouble("weighted_io_time", static_cast<double>(weighted_io_time));
+
+  return res.Pass();
+}
+
+bool IsValidDiskName(const std::string& candidate) {
+  if (candidate.length() < 3)
+    return false;
+  if (candidate[1] == 'd' &&
+      (candidate[0] == 'h' || candidate[0] == 's' || candidate[0] == 'v')) {
+    // [hsv]d[a-z]+ case
+    for (size_t i = 2; i < candidate.length(); ++i) {
+      if (!islower(candidate[i]))
+        return false;
+    }
+    return true;
+  }
+
+  const char kMMCName[] = "mmcblk";
+  const size_t kMMCNameLen = strlen(kMMCName);
+  if (candidate.length() < kMMCNameLen + 1)
+    return false;
+  if (candidate.compare(0, kMMCNameLen, kMMCName) != 0)
+    return false;
+
+  // mmcblk[0-9]+ case
+  for (size_t i = kMMCNameLen; i < candidate.length(); ++i) {
+    if (!isdigit(candidate[i]))
+      return false;
+  }
+  return true;
+}
+
+bool GetSystemDiskInfo(SystemDiskInfo* diskinfo) {
+  // Synchronously reading files in /proc does not hit the disk.
+  ThreadRestrictions::ScopedAllowIO allow_io;
+
+  FilePath diskinfo_file("/proc/diskstats");
+  std::string diskinfo_data;
+  if (!ReadFileToString(diskinfo_file, &diskinfo_data)) {
+    DLOG(WARNING) << "Failed to open " << diskinfo_file.value();
+    return false;
+  }
+
+  std::vector<std::string> diskinfo_lines;
+  size_t line_count = Tokenize(diskinfo_data, "\n", &diskinfo_lines);
+  if (line_count == 0) {
+    DLOG(WARNING) << "No lines found";
+    return false;
+  }
+
+  diskinfo->reads = 0;
+  diskinfo->reads_merged = 0;
+  diskinfo->sectors_read = 0;
+  diskinfo->read_time = 0;
+  diskinfo->writes = 0;
+  diskinfo->writes_merged = 0;
+  diskinfo->sectors_written = 0;
+  diskinfo->write_time = 0;
+  diskinfo->io = 0;
+  diskinfo->io_time = 0;
+  diskinfo->weighted_io_time = 0;
+
+  uint64 reads = 0;
+  uint64 reads_merged = 0;
+  uint64 sectors_read = 0;
+  uint64 read_time = 0;
+  uint64 writes = 0;
+  uint64 writes_merged = 0;
+  uint64 sectors_written = 0;
+  uint64 write_time = 0;
+  uint64 io = 0;
+  uint64 io_time = 0;
+  uint64 weighted_io_time = 0;
+
+  for (size_t i = 0; i < line_count; i++) {
+    std::vector<std::string> disk_fields;
+    SplitStringAlongWhitespace(diskinfo_lines[i], &disk_fields);
+
+    // Fields may have overflowed and reset to zero.
+    if (IsValidDiskName(disk_fields[kDiskDriveName])) {
+      StringToUint64(disk_fields[kDiskReads], &reads);
+      StringToUint64(disk_fields[kDiskReadsMerged], &reads_merged);
+      StringToUint64(disk_fields[kDiskSectorsRead], &sectors_read);
+      StringToUint64(disk_fields[kDiskReadTime], &read_time);
+      StringToUint64(disk_fields[kDiskWrites], &writes);
+      StringToUint64(disk_fields[kDiskWritesMerged], &writes_merged);
+      StringToUint64(disk_fields[kDiskSectorsWritten], &sectors_written);
+      StringToUint64(disk_fields[kDiskWriteTime], &write_time);
+      StringToUint64(disk_fields[kDiskIO], &io);
+      StringToUint64(disk_fields[kDiskIOTime], &io_time);
+      StringToUint64(disk_fields[kDiskWeightedIOTime], &weighted_io_time);
+
+      diskinfo->reads += reads;
+      diskinfo->reads_merged += reads_merged;
+      diskinfo->sectors_read += sectors_read;
+      diskinfo->read_time += read_time;
+      diskinfo->writes += writes;
+      diskinfo->writes_merged += writes_merged;
+      diskinfo->sectors_written += sectors_written;
+      diskinfo->write_time += write_time;
+      diskinfo->io += io;
+      diskinfo->io_time += io_time;
+      diskinfo->weighted_io_time += weighted_io_time;
+    }
+  }
+
+  return true;
+}
+
+#if defined(OS_CHROMEOS)
+scoped_ptr<Value> SwapInfo::ToValue() const {
+  scoped_ptr<DictionaryValue> res(new DictionaryValue());
+
+  // Write out uint64 variables as doubles.
+  // Note: this may discard some precision, but for JS there's no other option.
+  res->SetDouble("num_reads", static_cast<double>(num_reads));
+  res->SetDouble("num_writes", static_cast<double>(num_writes));
+  res->SetDouble("orig_data_size", static_cast<double>(orig_data_size));
+  res->SetDouble("compr_data_size", static_cast<double>(compr_data_size));
+  res->SetDouble("mem_used_total", static_cast<double>(mem_used_total));
+  if (compr_data_size > 0)
+    res->SetDouble("compression_ratio", static_cast<double>(orig_data_size) /
+                                        static_cast<double>(compr_data_size));
+  else
+    res->SetDouble("compression_ratio", 0);
+
+  return res.Pass();
+}
+
+void GetSwapInfo(SwapInfo* swap_info) {
+  // Synchronously reading files in /sys/block/zram0 does not hit the disk.
+  ThreadRestrictions::ScopedAllowIO allow_io;
+
+  FilePath zram_path("/sys/block/zram0");
+  uint64 orig_data_size = ReadFileToUint64(zram_path.Append("orig_data_size"));
+  if (orig_data_size <= 4096) {
+    // A single page is compressed at startup, and has a high compression
+    // ratio. We ignore this as it doesn't indicate any real swapping.
+    swap_info->orig_data_size = 0;
+    swap_info->num_reads = 0;
+    swap_info->num_writes = 0;
+    swap_info->compr_data_size = 0;
+    swap_info->mem_used_total = 0;
+    return;
+  }
+  swap_info->orig_data_size = orig_data_size;
+  swap_info->num_reads = ReadFileToUint64(zram_path.Append("num_reads"));
+  swap_info->num_writes = ReadFileToUint64(zram_path.Append("num_writes"));
+  swap_info->compr_data_size =
+      ReadFileToUint64(zram_path.Append("compr_data_size"));
+  swap_info->mem_used_total =
+      ReadFileToUint64(zram_path.Append("mem_used_total"));
+}
+#endif  // defined(OS_CHROMEOS)
+
+#if defined(OS_LINUX)
+int ProcessMetrics::GetIdleWakeupsPerSecond() {
+  uint64 wake_ups;
+  const char kWakeupStat[] = "se.statistics.nr_wakeups";
+  return ReadProcSchedAndGetFieldAsUint64(process_, kWakeupStat, &wake_ups) ?
+      CalculateIdleWakeupsPerSecond(wake_ups) : 0;
+}
+#endif  // defined(OS_LINUX)
+
+}  // namespace base
diff --git a/base/process/process_metrics_mac.cc b/base/process/process_metrics_mac.cc
new file mode 100644
index 0000000..f84b435
--- /dev/null
+++ b/base/process/process_metrics_mac.cc
@@ -0,0 +1,361 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_metrics.h"
+
+#include <mach/mach.h>
+#include <mach/mach_vm.h>
+#include <mach/shared_region.h>
+#include <sys/sysctl.h>
+
+#include "base/containers/hash_tables.h"
+#include "base/logging.h"
+#include "base/mac/mach_logging.h"
+#include "base/mac/scoped_mach_port.h"
+#include "base/sys_info.h"
+
+#if !defined(TASK_POWER_INFO)
+// Doesn't exist in the 10.6 or 10.7 SDKs.
+#define TASK_POWER_INFO        21
+struct task_power_info {
+        uint64_t                total_user;
+        uint64_t                total_system;
+        uint64_t                task_interrupt_wakeups;
+        uint64_t                task_platform_idle_wakeups;
+        uint64_t                task_timer_wakeups_bin_1;
+        uint64_t                task_timer_wakeups_bin_2;
+};
+typedef struct task_power_info        task_power_info_data_t;
+typedef struct task_power_info        *task_power_info_t;
+#define TASK_POWER_INFO_COUNT        ((mach_msg_type_number_t) \
+                (sizeof (task_power_info_data_t) / sizeof (natural_t)))
+#endif
+
+namespace base {
+
+namespace {
+
+bool GetTaskInfo(mach_port_t task, task_basic_info_64* task_info_data) {
+  if (task == MACH_PORT_NULL)
+    return false;
+  mach_msg_type_number_t count = TASK_BASIC_INFO_64_COUNT;
+  kern_return_t kr = task_info(task,
+                               TASK_BASIC_INFO_64,
+                               reinterpret_cast<task_info_t>(task_info_data),
+                               &count);
+  // Most likely cause for failure: |task| is a zombie.
+  return kr == KERN_SUCCESS;
+}
+
+bool GetCPUTypeForProcess(pid_t pid, cpu_type_t* cpu_type) {
+  size_t len = sizeof(*cpu_type);
+  int result = sysctlbyname("sysctl.proc_cputype",
+                            cpu_type,
+                            &len,
+                            NULL,
+                            0);
+  if (result != 0) {
+    DPLOG(ERROR) << "sysctlbyname(""sysctl.proc_cputype"")";
+    return false;
+  }
+
+  return true;
+}
+
+bool IsAddressInSharedRegion(mach_vm_address_t addr, cpu_type_t type) {
+  if (type == CPU_TYPE_I386) {
+    return addr >= SHARED_REGION_BASE_I386 &&
+           addr < (SHARED_REGION_BASE_I386 + SHARED_REGION_SIZE_I386);
+  } else if (type == CPU_TYPE_X86_64) {
+    return addr >= SHARED_REGION_BASE_X86_64 &&
+           addr < (SHARED_REGION_BASE_X86_64 + SHARED_REGION_SIZE_X86_64);
+  } else {
+    return false;
+  }
+}
+
+}  // namespace
+
+// Getting a mach task from a pid for another process requires permissions in
+// general, so there doesn't really seem to be a way to do these (and spinning
+// up ps to fetch each stats seems dangerous to put in a base api for anyone to
+// call). Child processes ipc their port, so return something if available,
+// otherwise return 0.
+
+// static
+ProcessMetrics* ProcessMetrics::CreateProcessMetrics(
+    ProcessHandle process,
+    ProcessMetrics::PortProvider* port_provider) {
+  return new ProcessMetrics(process, port_provider);
+}
+
+size_t ProcessMetrics::GetPagefileUsage() const {
+  task_basic_info_64 task_info_data;
+  if (!GetTaskInfo(TaskForPid(process_), &task_info_data))
+    return 0;
+  return task_info_data.virtual_size;
+}
+
+size_t ProcessMetrics::GetPeakPagefileUsage() const {
+  return 0;
+}
+
+size_t ProcessMetrics::GetWorkingSetSize() const {
+  task_basic_info_64 task_info_data;
+  if (!GetTaskInfo(TaskForPid(process_), &task_info_data))
+    return 0;
+  return task_info_data.resident_size;
+}
+
+size_t ProcessMetrics::GetPeakWorkingSetSize() const {
+  return 0;
+}
+
+// This is a rough approximation of the algorithm that libtop uses.
+// private_bytes is the size of private resident memory.
+// shared_bytes is the size of shared resident memory.
+bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes,
+                                    size_t* shared_bytes) {
+  size_t private_pages_count = 0;
+  size_t shared_pages_count = 0;
+
+  if (!private_bytes && !shared_bytes)
+    return true;
+
+  mach_port_t task = TaskForPid(process_);
+  if (task == MACH_PORT_NULL) {
+    DLOG(ERROR) << "Invalid process";
+    return false;
+  }
+
+  cpu_type_t cpu_type;
+  if (!GetCPUTypeForProcess(process_, &cpu_type))
+    return false;
+
+  // The same region can be referenced multiple times. To avoid double counting
+  // we need to keep track of which regions we've already counted.
+  base::hash_set<int> seen_objects;
+
+  // We iterate through each VM region in the task's address map. For shared
+  // memory we add up all the pages that are marked as shared. Like libtop we
+  // try to avoid counting pages that are also referenced by other tasks. Since
+  // we don't have access to the VM regions of other tasks the only hint we have
+  // is if the address is in the shared region area.
+  //
+  // Private memory is much simpler. We simply count the pages that are marked
+  // as private or copy on write (COW).
+  //
+  // See libtop_update_vm_regions in
+  // http://www.opensource.apple.com/source/top/top-67/libtop.c
+  mach_vm_size_t size = 0;
+  for (mach_vm_address_t address = MACH_VM_MIN_ADDRESS;; address += size) {
+    vm_region_top_info_data_t info;
+    mach_msg_type_number_t info_count = VM_REGION_TOP_INFO_COUNT;
+    mach_port_t object_name;
+    kern_return_t kr = mach_vm_region(task,
+                                      &address,
+                                      &size,
+                                      VM_REGION_TOP_INFO,
+                                      reinterpret_cast<vm_region_info_t>(&info),
+                                      &info_count,
+                                      &object_name);
+    if (kr == KERN_INVALID_ADDRESS) {
+      // We're at the end of the address space.
+      break;
+    } else if (kr != KERN_SUCCESS) {
+      MACH_DLOG(ERROR, kr) << "mach_vm_region";
+      return false;
+    }
+
+    // The kernel always returns a null object for VM_REGION_TOP_INFO, but
+    // balance it with a deallocate in case this ever changes. See 10.9.2
+    // xnu-2422.90.20/osfmk/vm/vm_map.c vm_map_region.
+    mach_port_deallocate(mach_task_self(), object_name);
+
+    if (IsAddressInSharedRegion(address, cpu_type) &&
+        info.share_mode != SM_PRIVATE)
+      continue;
+
+    if (info.share_mode == SM_COW && info.ref_count == 1)
+      info.share_mode = SM_PRIVATE;
+
+    switch (info.share_mode) {
+      case SM_PRIVATE:
+        private_pages_count += info.private_pages_resident;
+        private_pages_count += info.shared_pages_resident;
+        break;
+      case SM_COW:
+        private_pages_count += info.private_pages_resident;
+        // Fall through
+      case SM_SHARED:
+        if (seen_objects.count(info.obj_id) == 0) {
+          // Only count the first reference to this region.
+          seen_objects.insert(info.obj_id);
+          shared_pages_count += info.shared_pages_resident;
+        }
+        break;
+      default:
+        break;
+    }
+  }
+
+  if (private_bytes)
+    *private_bytes = private_pages_count * PAGE_SIZE;
+  if (shared_bytes)
+    *shared_bytes = shared_pages_count * PAGE_SIZE;
+
+  return true;
+}
+
+void ProcessMetrics::GetCommittedKBytes(CommittedKBytes* usage) const {
+  WorkingSetKBytes unused;
+  if (!GetCommittedAndWorkingSetKBytes(usage, &unused)) {
+    *usage = CommittedKBytes();
+  }
+}
+
+bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
+  CommittedKBytes unused;
+  return GetCommittedAndWorkingSetKBytes(&unused, ws_usage);
+}
+
+bool ProcessMetrics::GetCommittedAndWorkingSetKBytes(
+    CommittedKBytes* usage,
+    WorkingSetKBytes* ws_usage) const {
+  task_basic_info_64 task_info_data;
+  if (!GetTaskInfo(TaskForPid(process_), &task_info_data))
+    return false;
+
+  usage->priv = task_info_data.virtual_size / 1024;
+  usage->mapped = 0;
+  usage->image = 0;
+
+  ws_usage->priv = task_info_data.resident_size / 1024;
+  ws_usage->shareable = 0;
+  ws_usage->shared = 0;
+
+  return true;
+}
+
+#define TIME_VALUE_TO_TIMEVAL(a, r) do {  \
+  (r)->tv_sec = (a)->seconds;             \
+  (r)->tv_usec = (a)->microseconds;       \
+} while (0)
+
+double ProcessMetrics::GetCPUUsage() {
+  mach_port_t task = TaskForPid(process_);
+  if (task == MACH_PORT_NULL)
+    return 0;
+
+  // Libtop explicitly loops over the threads (libtop_pinfo_update_cpu_usage()
+  // in libtop.c), but this is more concise and gives the same results:
+  task_thread_times_info thread_info_data;
+  mach_msg_type_number_t thread_info_count = TASK_THREAD_TIMES_INFO_COUNT;
+  kern_return_t kr = task_info(task,
+                               TASK_THREAD_TIMES_INFO,
+                               reinterpret_cast<task_info_t>(&thread_info_data),
+                               &thread_info_count);
+  if (kr != KERN_SUCCESS) {
+    // Most likely cause: |task| is a zombie.
+    return 0;
+  }
+
+  task_basic_info_64 task_info_data;
+  if (!GetTaskInfo(task, &task_info_data))
+    return 0;
+
+  /* Set total_time. */
+  // thread info contains live time...
+  struct timeval user_timeval, system_timeval, task_timeval;
+  TIME_VALUE_TO_TIMEVAL(&thread_info_data.user_time, &user_timeval);
+  TIME_VALUE_TO_TIMEVAL(&thread_info_data.system_time, &system_timeval);
+  timeradd(&user_timeval, &system_timeval, &task_timeval);
+
+  // ... task info contains terminated time.
+  TIME_VALUE_TO_TIMEVAL(&task_info_data.user_time, &user_timeval);
+  TIME_VALUE_TO_TIMEVAL(&task_info_data.system_time, &system_timeval);
+  timeradd(&user_timeval, &task_timeval, &task_timeval);
+  timeradd(&system_timeval, &task_timeval, &task_timeval);
+
+  TimeTicks time = TimeTicks::Now();
+  int64 task_time = TimeValToMicroseconds(task_timeval);
+
+  if (last_system_time_ == 0) {
+    // First call, just set the last values.
+    last_cpu_time_ = time;
+    last_system_time_ = task_time;
+    return 0;
+  }
+
+  int64 system_time_delta = task_time - last_system_time_;
+  int64 time_delta = (time - last_cpu_time_).InMicroseconds();
+  DCHECK_NE(0U, time_delta);
+  if (time_delta == 0)
+    return 0;
+
+  last_cpu_time_ = time;
+  last_system_time_ = task_time;
+
+  return static_cast<double>(system_time_delta * 100.0) / time_delta;
+}
+
+int ProcessMetrics::GetIdleWakeupsPerSecond() {
+  mach_port_t task = TaskForPid(process_);
+  if (task == MACH_PORT_NULL)
+    return 0;
+
+  task_power_info power_info_data;
+  mach_msg_type_number_t power_info_count = TASK_POWER_INFO_COUNT;
+  kern_return_t kr = task_info(task,
+                               TASK_POWER_INFO,
+                               reinterpret_cast<task_info_t>(&power_info_data),
+                               &power_info_count);
+  if (kr != KERN_SUCCESS) {
+    // Most likely cause: |task| is a zombie, or this is on a pre-10.8.4 system
+    // where TASK_POWER_INFO isn't supported yet.
+    return 0;
+  }
+  return CalculateIdleWakeupsPerSecond(
+      power_info_data.task_platform_idle_wakeups);
+}
+
+bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const {
+  return false;
+}
+
+ProcessMetrics::ProcessMetrics(ProcessHandle process,
+                               ProcessMetrics::PortProvider* port_provider)
+    : process_(process),
+      last_system_time_(0),
+      last_absolute_idle_wakeups_(0),
+      port_provider_(port_provider) {
+  processor_count_ = SysInfo::NumberOfProcessors();
+}
+
+mach_port_t ProcessMetrics::TaskForPid(ProcessHandle process) const {
+  mach_port_t task = MACH_PORT_NULL;
+  if (port_provider_)
+    task = port_provider_->TaskForPid(process_);
+  if (task == MACH_PORT_NULL && process_ == getpid())
+    task = mach_task_self();
+  return task;
+}
+
+// Bytes committed by the system.
+size_t GetSystemCommitCharge() {
+  base::mac::ScopedMachSendRight host(mach_host_self());
+  mach_msg_type_number_t count = HOST_VM_INFO_COUNT;
+  vm_statistics_data_t data;
+  kern_return_t kr = host_statistics(host, HOST_VM_INFO,
+                                     reinterpret_cast<host_info_t>(&data),
+                                     &count);
+  if (kr != KERN_SUCCESS) {
+    MACH_DLOG(WARNING, kr) << "host_statistics";
+    return 0;
+  }
+
+  return (data.active_count * PAGE_SIZE) / 1024;
+}
+
+}  // namespace base
diff --git a/base/process/process_metrics_openbsd.cc b/base/process/process_metrics_openbsd.cc
new file mode 100644
index 0000000..72927a1
--- /dev/null
+++ b/base/process/process_metrics_openbsd.cc
@@ -0,0 +1,161 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_metrics.h"
+
+#include <sys/param.h>
+#include <sys/sysctl.h>
+
+namespace base {
+
+// static
+ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) {
+  return new ProcessMetrics(process);
+}
+
+size_t ProcessMetrics::GetPagefileUsage() const {
+  struct kinfo_proc info;
+  size_t length;
+  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, process_,
+                sizeof(struct kinfo_proc), 0 };
+
+  if (sysctl(mib, arraysize(mib), NULL, &length, NULL, 0) < 0)
+    return -1;
+
+  mib[5] = (length / sizeof(struct kinfo_proc));
+
+  if (sysctl(mib, arraysize(mib), &info, &length, NULL, 0) < 0)
+    return -1;
+
+  return (info.p_vm_tsize + info.p_vm_dsize + info.p_vm_ssize);
+}
+
+size_t ProcessMetrics::GetPeakPagefileUsage() const {
+  return 0;
+}
+
+size_t ProcessMetrics::GetWorkingSetSize() const {
+  struct kinfo_proc info;
+  size_t length;
+  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, process_,
+                sizeof(struct kinfo_proc), 0 };
+
+  if (sysctl(mib, arraysize(mib), NULL, &length, NULL, 0) < 0)
+    return -1;
+
+  mib[5] = (length / sizeof(struct kinfo_proc));
+
+  if (sysctl(mib, arraysize(mib), &info, &length, NULL, 0) < 0)
+    return -1;
+
+  return info.p_vm_rssize * getpagesize();
+}
+
+size_t ProcessMetrics::GetPeakWorkingSetSize() const {
+  return 0;
+}
+
+bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes,
+                                    size_t* shared_bytes) {
+  WorkingSetKBytes ws_usage;
+
+  if (!GetWorkingSetKBytes(&ws_usage))
+    return false;
+
+  if (private_bytes)
+    *private_bytes = ws_usage.priv << 10;
+
+  if (shared_bytes)
+    *shared_bytes = ws_usage.shared * 1024;
+
+  return true;
+}
+
+bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
+  // TODO(bapt): be sure we can't be precise
+  size_t priv = GetWorkingSetSize();
+  if (!priv)
+    return false;
+  ws_usage->priv = priv / 1024;
+  ws_usage->shareable = 0;
+  ws_usage->shared = 0;
+
+  return true;
+}
+
+bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const {
+  return false;
+}
+
+static int GetProcessCPU(pid_t pid) {
+  struct kinfo_proc info;
+  size_t length;
+  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, pid,
+                sizeof(struct kinfo_proc), 0 };
+
+  if (sysctl(mib, arraysize(mib), NULL, &length, NULL, 0) < 0)
+    return -1;
+
+  mib[5] = (length / sizeof(struct kinfo_proc));
+
+  if (sysctl(mib, arraysize(mib), &info, &length, NULL, 0) < 0)
+    return 0;
+
+  return info.p_pctcpu;
+}
+
+double ProcessMetrics::GetCPUUsage() {
+  TimeTicks time = TimeTicks::Now();
+
+  if (last_cpu_ == 0) {
+    // First call, just set the last values.
+    last_cpu_time_ = time;
+    last_cpu_ = GetProcessCPU(process_);
+    return 0;
+  }
+
+  int64 time_delta = (time - last_cpu_time_).InMicroseconds();
+  DCHECK_NE(time_delta, 0);
+
+  if (time_delta == 0)
+    return 0;
+
+  int cpu = GetProcessCPU(process_);
+
+  last_cpu_time_ = time;
+  last_cpu_ = cpu;
+
+  double percentage = static_cast<double>((cpu * 100.0) / FSCALE);
+
+  return percentage;
+}
+
+ProcessMetrics::ProcessMetrics(ProcessHandle process)
+    : process_(process),
+      last_system_time_(0),
+      last_cpu_(0) {
+
+  processor_count_ = base::SysInfo::NumberOfProcessors();
+}
+
+size_t GetSystemCommitCharge() {
+  int mib[] = { CTL_VM, VM_METER };
+  int pagesize;
+  struct vmtotal vmtotal;
+  unsigned long mem_total, mem_free, mem_inactive;
+  size_t len = sizeof(vmtotal);
+
+  if (sysctl(mib, arraysize(mib), &vmtotal, &len, NULL, 0) < 0)
+    return 0;
+
+  mem_total = vmtotal.t_vm;
+  mem_free = vmtotal.t_free;
+  mem_inactive = vmtotal.t_vm - vmtotal.t_avm;
+
+  pagesize = getpagesize();
+
+  return mem_total - (mem_free*pagesize) - (mem_inactive*pagesize);
+}
+
+}  // namespace base
diff --git a/base/process/process_metrics_posix.cc b/base/process/process_metrics_posix.cc
new file mode 100644
index 0000000..42b3f2d
--- /dev/null
+++ b/base/process/process_metrics_posix.cc
@@ -0,0 +1,75 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_metrics.h"
+
+#include <sys/resource.h>
+#include <sys/time.h>
+
+#include "base/logging.h"
+
+namespace base {
+
+int64 TimeValToMicroseconds(const struct timeval& tv) {
+  int64 ret = tv.tv_sec;  // Avoid (int * int) integer overflow.
+  ret *= Time::kMicrosecondsPerSecond;
+  ret += tv.tv_usec;
+  return ret;
+}
+
+ProcessMetrics::~ProcessMetrics() { }
+
+#if defined(OS_LINUX)
+static const rlim_t kSystemDefaultMaxFds = 8192;
+#elif defined(OS_MACOSX)
+static const rlim_t kSystemDefaultMaxFds = 256;
+#elif defined(OS_SOLARIS)
+static const rlim_t kSystemDefaultMaxFds = 8192;
+#elif defined(OS_FREEBSD)
+static const rlim_t kSystemDefaultMaxFds = 8192;
+#elif defined(OS_OPENBSD)
+static const rlim_t kSystemDefaultMaxFds = 256;
+#elif defined(OS_ANDROID)
+static const rlim_t kSystemDefaultMaxFds = 1024;
+#endif
+
+size_t GetMaxFds() {
+  rlim_t max_fds;
+  struct rlimit nofile;
+  if (getrlimit(RLIMIT_NOFILE, &nofile)) {
+    // getrlimit failed. Take a best guess.
+    max_fds = kSystemDefaultMaxFds;
+    RAW_LOG(ERROR, "getrlimit(RLIMIT_NOFILE) failed");
+  } else {
+    max_fds = nofile.rlim_cur;
+  }
+
+  if (max_fds > INT_MAX)
+    max_fds = INT_MAX;
+
+  return static_cast<size_t>(max_fds);
+}
+
+
+void SetFdLimit(unsigned int max_descriptors) {
+  struct rlimit limits;
+  if (getrlimit(RLIMIT_NOFILE, &limits) == 0) {
+    unsigned int new_limit = max_descriptors;
+    if (limits.rlim_max > 0 && limits.rlim_max < max_descriptors) {
+      new_limit = limits.rlim_max;
+    }
+    limits.rlim_cur = new_limit;
+    if (setrlimit(RLIMIT_NOFILE, &limits) != 0) {
+      PLOG(INFO) << "Failed to set file descriptor limit";
+    }
+  } else {
+    PLOG(INFO) << "Failed to get file descriptor limit";
+  }
+}
+
+size_t GetPageSize() {
+  return getpagesize();
+}
+
+}  // namespace base
diff --git a/base/process/process_metrics_unittest.cc b/base/process/process_metrics_unittest.cc
new file mode 100644
index 0000000..76767b0
--- /dev/null
+++ b/base/process/process_metrics_unittest.cc
@@ -0,0 +1,363 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_metrics.h"
+
+#include <sstream>
+#include <string>
+
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+
+namespace base {
+namespace debug {
+
+// Tests for SystemMetrics.
+// Exists as a class so it can be a friend of SystemMetrics.
+class SystemMetricsTest : public testing::Test {
+ public:
+  SystemMetricsTest() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SystemMetricsTest);
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+TEST_F(SystemMetricsTest, IsValidDiskName) {
+  std::string invalid_input1 = "";
+  std::string invalid_input2 = "s";
+  std::string invalid_input3 = "sdz+";
+  std::string invalid_input4 = "hda0";
+  std::string invalid_input5 = "mmcbl";
+  std::string invalid_input6 = "mmcblka";
+  std::string invalid_input7 = "mmcblkb";
+  std::string invalid_input8 = "mmmblk0";
+
+  EXPECT_FALSE(IsValidDiskName(invalid_input1));
+  EXPECT_FALSE(IsValidDiskName(invalid_input2));
+  EXPECT_FALSE(IsValidDiskName(invalid_input3));
+  EXPECT_FALSE(IsValidDiskName(invalid_input4));
+  EXPECT_FALSE(IsValidDiskName(invalid_input5));
+  EXPECT_FALSE(IsValidDiskName(invalid_input6));
+  EXPECT_FALSE(IsValidDiskName(invalid_input7));
+  EXPECT_FALSE(IsValidDiskName(invalid_input8));
+
+  std::string valid_input1 = "sda";
+  std::string valid_input2 = "sdaaaa";
+  std::string valid_input3 = "hdz";
+  std::string valid_input4 = "mmcblk0";
+  std::string valid_input5 = "mmcblk999";
+
+  EXPECT_TRUE(IsValidDiskName(valid_input1));
+  EXPECT_TRUE(IsValidDiskName(valid_input2));
+  EXPECT_TRUE(IsValidDiskName(valid_input3));
+  EXPECT_TRUE(IsValidDiskName(valid_input4));
+  EXPECT_TRUE(IsValidDiskName(valid_input5));
+}
+
+TEST_F(SystemMetricsTest, ParseMeminfo) {
+  struct SystemMemoryInfoKB meminfo;
+  std::string invalid_input1 = "abc";
+  std::string invalid_input2 = "MemTotal:";
+  // Partial file with no MemTotal
+  std::string invalid_input3 =
+    "MemFree:         3913968 kB\n"
+    "Buffers:         2348340 kB\n"
+    "Cached:         49071596 kB\n"
+    "SwapCached:           12 kB\n"
+    "Active:         36393900 kB\n"
+    "Inactive:       21221496 kB\n"
+    "Active(anon):    5674352 kB\n"
+    "Inactive(anon):   633992 kB\n";
+  EXPECT_FALSE(ParseProcMeminfo(invalid_input1, &meminfo));
+  EXPECT_FALSE(ParseProcMeminfo(invalid_input2, &meminfo));
+  EXPECT_FALSE(ParseProcMeminfo(invalid_input3, &meminfo));
+
+  std::string valid_input1 =
+    "MemTotal:        3981504 kB\n"
+    "MemFree:          140764 kB\n"
+    "Buffers:          116480 kB\n"
+    "Cached:           406160 kB\n"
+    "SwapCached:        21304 kB\n"
+    "Active:          3152040 kB\n"
+    "Inactive:         472856 kB\n"
+    "Active(anon):    2972352 kB\n"
+    "Inactive(anon):   270108 kB\n"
+    "Active(file):     179688 kB\n"
+    "Inactive(file):   202748 kB\n"
+    "Unevictable:           0 kB\n"
+    "Mlocked:               0 kB\n"
+    "SwapTotal:       5832280 kB\n"
+    "SwapFree:        3672368 kB\n"
+    "Dirty:               184 kB\n"
+    "Writeback:             0 kB\n"
+    "AnonPages:       3101224 kB\n"
+    "Mapped:           142296 kB\n"
+    "Shmem:            140204 kB\n"
+    "Slab:              54212 kB\n"
+    "SReclaimable:      30936 kB\n"
+    "SUnreclaim:        23276 kB\n"
+    "KernelStack:        2464 kB\n"
+    "PageTables:        24812 kB\n"
+    "NFS_Unstable:          0 kB\n"
+    "Bounce:                0 kB\n"
+    "WritebackTmp:          0 kB\n"
+    "CommitLimit:     7823032 kB\n"
+    "Committed_AS:    7973536 kB\n"
+    "VmallocTotal:   34359738367 kB\n"
+    "VmallocUsed:      375940 kB\n"
+    "VmallocChunk:   34359361127 kB\n"
+    "DirectMap4k:       72448 kB\n"
+    "DirectMap2M:     4061184 kB\n";
+  // output from a much older kernel where the Active and Inactive aren't
+  // broken down into anon and file and Huge Pages are enabled
+  std::string valid_input2 =
+    "MemTotal:       255908 kB\n"
+    "MemFree:         69936 kB\n"
+    "Buffers:         15812 kB\n"
+    "Cached:         115124 kB\n"
+    "SwapCached:          0 kB\n"
+    "Active:          92700 kB\n"
+    "Inactive:        63792 kB\n"
+    "HighTotal:           0 kB\n"
+    "HighFree:            0 kB\n"
+    "LowTotal:       255908 kB\n"
+    "LowFree:         69936 kB\n"
+    "SwapTotal:      524280 kB\n"
+    "SwapFree:       524200 kB\n"
+    "Dirty:               4 kB\n"
+    "Writeback:           0 kB\n"
+    "Mapped:          42236 kB\n"
+    "Slab:            25912 kB\n"
+    "Committed_AS:   118680 kB\n"
+    "PageTables:       1236 kB\n"
+    "VmallocTotal:  3874808 kB\n"
+    "VmallocUsed:      1416 kB\n"
+    "VmallocChunk:  3872908 kB\n"
+    "HugePages_Total:     0\n"
+    "HugePages_Free:      0\n"
+    "Hugepagesize:     4096 kB\n";
+
+  EXPECT_TRUE(ParseProcMeminfo(valid_input1, &meminfo));
+  EXPECT_EQ(meminfo.total, 3981504);
+  EXPECT_EQ(meminfo.free, 140764);
+  EXPECT_EQ(meminfo.buffers, 116480);
+  EXPECT_EQ(meminfo.cached, 406160);
+  EXPECT_EQ(meminfo.active_anon, 2972352);
+  EXPECT_EQ(meminfo.active_file, 179688);
+  EXPECT_EQ(meminfo.inactive_anon, 270108);
+  EXPECT_EQ(meminfo.inactive_file, 202748);
+  EXPECT_EQ(meminfo.swap_total, 5832280);
+  EXPECT_EQ(meminfo.swap_free, 3672368);
+  EXPECT_EQ(meminfo.dirty, 184);
+#if defined(OS_CHROMEOS)
+  EXPECT_EQ(meminfo.shmem, 140204);
+  EXPECT_EQ(meminfo.slab, 54212);
+#endif
+  EXPECT_TRUE(ParseProcMeminfo(valid_input2, &meminfo));
+  EXPECT_EQ(meminfo.total, 255908);
+  EXPECT_EQ(meminfo.free, 69936);
+  EXPECT_EQ(meminfo.buffers, 15812);
+  EXPECT_EQ(meminfo.cached, 115124);
+  EXPECT_EQ(meminfo.swap_total, 524280);
+  EXPECT_EQ(meminfo.swap_free, 524200);
+  EXPECT_EQ(meminfo.dirty, 4);
+}
+
+TEST_F(SystemMetricsTest, ParseVmstat) {
+  struct SystemMemoryInfoKB meminfo;
+  // part of vmstat from a 3.2 kernel with numa enabled
+  std::string valid_input1 =
+    "nr_free_pages 905104\n"
+    "nr_inactive_anon 142478"
+    "nr_active_anon 1520046\n"
+    "nr_inactive_file 4481001\n"
+    "nr_active_file 8313439\n"
+    "nr_unevictable 5044\n"
+    "nr_mlock 5044\n"
+    "nr_anon_pages 1633780\n"
+    "nr_mapped 104742\n"
+    "nr_file_pages 12828218\n"
+    "nr_dirty 245\n"
+    "nr_writeback 0\n"
+    "nr_slab_reclaimable 831609\n"
+    "nr_slab_unreclaimable 41164\n"
+    "nr_page_table_pages 31470\n"
+    "nr_kernel_stack 1735\n"
+    "nr_unstable 0\n"
+    "nr_bounce 0\n"
+    "nr_vmscan_write 406\n"
+    "nr_vmscan_immediate_reclaim 281\n"
+    "nr_writeback_temp 0\n"
+    "nr_isolated_anon 0\n"
+    "nr_isolated_file 0\n"
+    "nr_shmem 28820\n"
+    "nr_dirtied 84674644\n"
+    "nr_written 75307109\n"
+    "nr_anon_transparent_hugepages 0\n"
+    "nr_dirty_threshold 1536206\n"
+    "nr_dirty_background_threshold 768103\n"
+    "pgpgin 30777108\n"
+    "pgpgout 319023278\n"
+    "pswpin 179\n"
+    "pswpout 406\n"
+    "pgalloc_dma 0\n"
+    "pgalloc_dma32 20833399\n"
+    "pgalloc_normal 1622609290\n"
+    "pgalloc_movable 0\n"
+    "pgfree 1644355583\n"
+    "pgactivate 75391882\n"
+    "pgdeactivate 4121019\n"
+    "pgfault 2542879679\n"
+    "pgmajfault 487192\n";
+  std::string valid_input2 =
+    "nr_free_pages 180125\n"
+    "nr_inactive_anon 51\n"
+    "nr_active_anon 38832\n"
+    "nr_inactive_file 50171\n"
+    "nr_active_file 47510\n"
+    "nr_unevictable 0\n"
+    "nr_mlock 0\n"
+    "nr_anon_pages 38825\n"
+    "nr_mapped 24043\n"
+    "nr_file_pages 97733\n"
+    "nr_dirty 0\n"
+    "nr_writeback 0\n"
+    "nr_slab_reclaimable 4032\n"
+    "nr_slab_unreclaimable 2848\n"
+    "nr_page_table_pages 1505\n"
+    "nr_kernel_stack 626\n"
+    "nr_unstable 0\n"
+    "nr_bounce 0\n"
+    "nr_vmscan_write 0\n"
+    "nr_vmscan_immediate_reclaim 0\n"
+    "nr_writeback_temp 0\n"
+    "nr_isolated_anon 0\n"
+    "nr_isolated_file 0\n"
+    "nr_shmem 58\n"
+    "nr_dirtied 435358\n"
+    "nr_written 401258\n"
+    "nr_anon_transparent_hugepages 0\n"
+    "nr_dirty_threshold 18566\n"
+    "nr_dirty_background_threshold 4641\n"
+    "pgpgin 299464\n"
+    "pgpgout 2437788\n"
+    "pswpin 12\n"
+    "pswpout 901\n"
+    "pgalloc_normal 144213030\n"
+    "pgalloc_high 164501274\n"
+    "pgalloc_movable 0\n"
+    "pgfree 308894908\n"
+    "pgactivate 239320\n"
+    "pgdeactivate 1\n"
+    "pgfault 716044601\n"
+    "pgmajfault 2023\n"
+    "pgrefill_normal 0\n"
+    "pgrefill_high 0\n"
+    "pgrefill_movable 0\n";
+  EXPECT_TRUE(ParseProcVmstat(valid_input1, &meminfo));
+  EXPECT_EQ(meminfo.pswpin, 179);
+  EXPECT_EQ(meminfo.pswpout, 406);
+  EXPECT_EQ(meminfo.pgmajfault, 487192);
+  EXPECT_TRUE(ParseProcVmstat(valid_input2, &meminfo));
+  EXPECT_EQ(meminfo.pswpin, 12);
+  EXPECT_EQ(meminfo.pswpout, 901);
+  EXPECT_EQ(meminfo.pgmajfault, 2023);
+}
+#endif  // defined(OS_LINUX) || defined(OS_ANDROID)
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+TEST(SystemMetrics2Test, GetSystemMemoryInfo) {
+  base::SystemMemoryInfoKB info;
+  EXPECT_TRUE(base::GetSystemMemoryInfo(&info));
+
+  // Ensure each field received a value.
+  EXPECT_GT(info.total, 0);
+  EXPECT_GT(info.free, 0);
+  EXPECT_GT(info.buffers, 0);
+  EXPECT_GT(info.cached, 0);
+  EXPECT_GT(info.active_anon, 0);
+  EXPECT_GT(info.inactive_anon, 0);
+  EXPECT_GT(info.active_file, 0);
+  EXPECT_GT(info.inactive_file, 0);
+
+  // All the values should be less than the total amount of memory.
+  EXPECT_LT(info.free, info.total);
+  EXPECT_LT(info.buffers, info.total);
+  EXPECT_LT(info.cached, info.total);
+  EXPECT_LT(info.active_anon, info.total);
+  EXPECT_LT(info.inactive_anon, info.total);
+  EXPECT_LT(info.active_file, info.total);
+  EXPECT_LT(info.inactive_file, info.total);
+
+#if defined(OS_CHROMEOS)
+  // Chrome OS exposes shmem.
+  EXPECT_GT(info.shmem, 0);
+  EXPECT_LT(info.shmem, info.total);
+  // Chrome unit tests are not run on actual Chrome OS hardware, so gem_objects
+  // and gem_size cannot be tested here.
+#endif
+}
+#endif  // defined(OS_LINUX) || defined(OS_ANDROID)
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+TEST(ProcessMetricsTest, ParseProcStatCPU) {
+  // /proc/self/stat for a process running "top".
+  const char kTopStat[] = "960 (top) S 16230 960 16230 34818 960 "
+      "4202496 471 0 0 0 "
+      "12 16 0 0 "  // <- These are the goods.
+      "20 0 1 0 121946157 15077376 314 18446744073709551615 4194304 "
+      "4246868 140733983044336 18446744073709551615 140244213071219 "
+      "0 0 0 138047495 0 0 0 17 1 0 0 0 0 0";
+  EXPECT_EQ(12 + 16, base::ParseProcStatCPU(kTopStat));
+
+  // cat /proc/self/stat on a random other machine I have.
+  const char kSelfStat[] = "5364 (cat) R 5354 5364 5354 34819 5364 "
+      "0 142 0 0 0 "
+      "0 0 0 0 "  // <- No CPU, apparently.
+      "16 0 1 0 1676099790 2957312 114 4294967295 134512640 134528148 "
+      "3221224832 3221224344 3086339742 0 0 0 0 0 0 0 17 0 0 0";
+
+  EXPECT_EQ(0, base::ParseProcStatCPU(kSelfStat));
+
+  // Some weird long-running process with a weird name that I created for the
+  // purposes of this test.
+  const char kWeirdNameStat[] = "26115 (Hello) You ()))  ) R 24614 26115 24614"
+      " 34839 26115 4218880 227 0 0 0 "
+      "5186 11 0 0 "
+      "20 0 1 0 36933953 4296704 90 18446744073709551615 4194304 4196116 "
+      "140735857761568 140735857761160 4195644 0 0 0 0 0 0 0 17 14 0 0 0 0 0 "
+      "6295056 6295616 16519168 140735857770710 140735857770737 "
+      "140735857770737 140735857774557 0";
+  EXPECT_EQ(5186 + 11, base::ParseProcStatCPU(kWeirdNameStat));
+}
+#endif // defined(OS_LINUX) || defined(OS_ANDROID)
+
+// Disable on Android because base_unittests runs inside a Dalvik VM that
+// starts and stop threads (crbug.com/175563).
+#if defined(OS_LINUX)
+// http://crbug.com/396455
+TEST(ProcessMetricsTest, DISABLED_GetNumberOfThreads) {
+  const base::ProcessHandle current = base::GetCurrentProcessHandle();
+  const int initial_threads = base::GetNumberOfThreads(current);
+  ASSERT_GT(initial_threads, 0);
+  const int kNumAdditionalThreads = 10;
+  {
+    scoped_ptr<base::Thread> my_threads[kNumAdditionalThreads];
+    for (int i = 0; i < kNumAdditionalThreads; ++i) {
+      my_threads[i].reset(new base::Thread("GetNumberOfThreadsTest"));
+      my_threads[i]->Start();
+      ASSERT_EQ(base::GetNumberOfThreads(current), initial_threads + 1 + i);
+    }
+  }
+  // The Thread destructor will stop them.
+  ASSERT_EQ(initial_threads, base::GetNumberOfThreads(current));
+}
+#endif  // defined(OS_LINUX)
+
+}  // namespace debug
+}  // namespace base
diff --git a/base/process/process_metrics_unittest_ios.cc b/base/process/process_metrics_unittest_ios.cc
new file mode 100644
index 0000000..3e1ca35
--- /dev/null
+++ b/base/process/process_metrics_unittest_ios.cc
@@ -0,0 +1,16 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_metrics.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(ProcessMetricsTestIos, Memory) {
+  scoped_ptr<base::ProcessMetrics> process_metrics(
+      base::ProcessMetrics::CreateProcessMetrics(
+          base::GetCurrentProcessHandle()));
+
+  ASSERT_NE(0u, process_metrics->GetWorkingSetSize());
+}
diff --git a/base/process/process_metrics_win.cc b/base/process/process_metrics_win.cc
new file mode 100644
index 0000000..6c424e3
--- /dev/null
+++ b/base/process/process_metrics_win.cc
@@ -0,0 +1,288 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process/process_metrics.h"
+
+#include <windows.h>
+#include <psapi.h>
+
+#include "base/logging.h"
+#include "base/sys_info.h"
+
+namespace base {
+
+// System pagesize. This value remains constant on x86/64 architectures.
+const int PAGESIZE_KB = 4;
+
+ProcessMetrics::~ProcessMetrics() { }
+
+// static
+ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) {
+  return new ProcessMetrics(process);
+}
+
+size_t ProcessMetrics::GetPagefileUsage() const {
+  PROCESS_MEMORY_COUNTERS pmc;
+  if (GetProcessMemoryInfo(process_, &pmc, sizeof(pmc))) {
+    return pmc.PagefileUsage;
+  }
+  return 0;
+}
+
+// Returns the peak space allocated for the pagefile, in bytes.
+size_t ProcessMetrics::GetPeakPagefileUsage() const {
+  PROCESS_MEMORY_COUNTERS pmc;
+  if (GetProcessMemoryInfo(process_, &pmc, sizeof(pmc))) {
+    return pmc.PeakPagefileUsage;
+  }
+  return 0;
+}
+
+// Returns the current working set size, in bytes.
+size_t ProcessMetrics::GetWorkingSetSize() const {
+  PROCESS_MEMORY_COUNTERS pmc;
+  if (GetProcessMemoryInfo(process_, &pmc, sizeof(pmc))) {
+    return pmc.WorkingSetSize;
+  }
+  return 0;
+}
+
+// Returns the peak working set size, in bytes.
+size_t ProcessMetrics::GetPeakWorkingSetSize() const {
+  PROCESS_MEMORY_COUNTERS pmc;
+  if (GetProcessMemoryInfo(process_, &pmc, sizeof(pmc))) {
+    return pmc.PeakWorkingSetSize;
+  }
+  return 0;
+}
+
+bool ProcessMetrics::GetMemoryBytes(size_t* private_bytes,
+                                    size_t* shared_bytes) {
+  // PROCESS_MEMORY_COUNTERS_EX is not supported until XP SP2.
+  // GetProcessMemoryInfo() will simply fail on prior OS. So the requested
+  // information is simply not available. Hence, we will return 0 on unsupported
+  // OSes. Unlike most Win32 API, we don't need to initialize the "cb" member.
+  PROCESS_MEMORY_COUNTERS_EX pmcx;
+  if (private_bytes &&
+      GetProcessMemoryInfo(process_,
+                           reinterpret_cast<PROCESS_MEMORY_COUNTERS*>(&pmcx),
+                           sizeof(pmcx))) {
+    *private_bytes = pmcx.PrivateUsage;
+  }
+
+  if (shared_bytes) {
+    WorkingSetKBytes ws_usage;
+    if (!GetWorkingSetKBytes(&ws_usage))
+      return false;
+
+    *shared_bytes = ws_usage.shared * 1024;
+  }
+
+  return true;
+}
+
+void ProcessMetrics::GetCommittedKBytes(CommittedKBytes* usage) const {
+  MEMORY_BASIC_INFORMATION mbi = {0};
+  size_t committed_private = 0;
+  size_t committed_mapped = 0;
+  size_t committed_image = 0;
+  void* base_address = NULL;
+  while (VirtualQueryEx(process_, base_address, &mbi, sizeof(mbi)) ==
+      sizeof(mbi)) {
+    if (mbi.State == MEM_COMMIT) {
+      if (mbi.Type == MEM_PRIVATE) {
+        committed_private += mbi.RegionSize;
+      } else if (mbi.Type == MEM_MAPPED) {
+        committed_mapped += mbi.RegionSize;
+      } else if (mbi.Type == MEM_IMAGE) {
+        committed_image += mbi.RegionSize;
+      } else {
+        NOTREACHED();
+      }
+    }
+    void* new_base = (static_cast<BYTE*>(mbi.BaseAddress)) + mbi.RegionSize;
+    // Avoid infinite loop by weird MEMORY_BASIC_INFORMATION.
+    // If we query 64bit processes in a 32bit process, VirtualQueryEx()
+    // returns such data.
+    if (new_base <= base_address) {
+      usage->image = 0;
+      usage->mapped = 0;
+      usage->priv = 0;
+      return;
+    }
+    base_address = new_base;
+  }
+  usage->image = committed_image / 1024;
+  usage->mapped = committed_mapped / 1024;
+  usage->priv = committed_private / 1024;
+}
+
+bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
+  size_t ws_private = 0;
+  size_t ws_shareable = 0;
+  size_t ws_shared = 0;
+
+  DCHECK(ws_usage);
+  memset(ws_usage, 0, sizeof(*ws_usage));
+
+  DWORD number_of_entries = 4096;  // Just a guess.
+  PSAPI_WORKING_SET_INFORMATION* buffer = NULL;
+  int retries = 5;
+  for (;;) {
+    DWORD buffer_size = sizeof(PSAPI_WORKING_SET_INFORMATION) +
+                        (number_of_entries * sizeof(PSAPI_WORKING_SET_BLOCK));
+
+    // if we can't expand the buffer, don't leak the previous
+    // contents or pass a NULL pointer to QueryWorkingSet
+    PSAPI_WORKING_SET_INFORMATION* new_buffer =
+        reinterpret_cast<PSAPI_WORKING_SET_INFORMATION*>(
+            realloc(buffer, buffer_size));
+    if (!new_buffer) {
+      free(buffer);
+      return false;
+    }
+    buffer = new_buffer;
+
+    // Call the function once to get number of items
+    if (QueryWorkingSet(process_, buffer, buffer_size))
+      break;  // Success
+
+    if (GetLastError() != ERROR_BAD_LENGTH) {
+      free(buffer);
+      return false;
+    }
+
+    number_of_entries = static_cast<DWORD>(buffer->NumberOfEntries);
+
+    // Maybe some entries are being added right now. Increase the buffer to
+    // take that into account.
+    number_of_entries = static_cast<DWORD>(number_of_entries * 1.25);
+
+    if (--retries == 0) {
+      free(buffer);  // If we're looping, eventually fail.
+      return false;
+    }
+  }
+
+  // On windows 2000 the function returns 1 even when the buffer is too small.
+  // The number of entries that we are going to parse is the minimum between the
+  // size we allocated and the real number of entries.
+  number_of_entries =
+      std::min(number_of_entries, static_cast<DWORD>(buffer->NumberOfEntries));
+  for (unsigned int i = 0; i < number_of_entries; i++) {
+    if (buffer->WorkingSetInfo[i].Shared) {
+      ws_shareable++;
+      if (buffer->WorkingSetInfo[i].ShareCount > 1)
+        ws_shared++;
+    } else {
+      ws_private++;
+    }
+  }
+
+  ws_usage->priv = ws_private * PAGESIZE_KB;
+  ws_usage->shareable = ws_shareable * PAGESIZE_KB;
+  ws_usage->shared = ws_shared * PAGESIZE_KB;
+  free(buffer);
+  return true;
+}
+
+static uint64 FileTimeToUTC(const FILETIME& ftime) {
+  LARGE_INTEGER li;
+  li.LowPart = ftime.dwLowDateTime;
+  li.HighPart = ftime.dwHighDateTime;
+  return li.QuadPart;
+}
+
+double ProcessMetrics::GetCPUUsage() {
+  FILETIME creation_time;
+  FILETIME exit_time;
+  FILETIME kernel_time;
+  FILETIME user_time;
+
+  if (!GetProcessTimes(process_, &creation_time, &exit_time,
+                       &kernel_time, &user_time)) {
+    // We don't assert here because in some cases (such as in the Task Manager)
+    // we may call this function on a process that has just exited but we have
+    // not yet received the notification.
+    return 0;
+  }
+  int64 system_time = (FileTimeToUTC(kernel_time) + FileTimeToUTC(user_time)) /
+                        processor_count_;
+  TimeTicks time = TimeTicks::Now();
+
+  if (last_system_time_ == 0) {
+    // First call, just set the last values.
+    last_system_time_ = system_time;
+    last_cpu_time_ = time;
+    return 0;
+  }
+
+  int64 system_time_delta = system_time - last_system_time_;
+  // FILETIME is in 100-nanosecond units, so this needs microseconds times 10.
+  int64 time_delta = (time - last_cpu_time_).InMicroseconds() * 10;
+  DCHECK_NE(0U, time_delta);
+  if (time_delta == 0)
+    return 0;
+
+
+  last_system_time_ = system_time;
+  last_cpu_time_ = time;
+
+  return static_cast<double>(system_time_delta * 100.0) / time_delta;
+}
+
+bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const {
+  return GetProcessIoCounters(process_, io_counters) != FALSE;
+}
+
+ProcessMetrics::ProcessMetrics(ProcessHandle process)
+    : process_(process),
+      processor_count_(base::SysInfo::NumberOfProcessors()),
+      last_system_time_(0) {
+}
+
+// GetPerformanceInfo is not available on WIN2K.  So we'll
+// load it on-the-fly.
+const wchar_t kPsapiDllName[] = L"psapi.dll";
+typedef BOOL (WINAPI *GetPerformanceInfoFunction) (
+    PPERFORMANCE_INFORMATION pPerformanceInformation,
+    DWORD cb);
+
+// Beware of races if called concurrently from multiple threads.
+static BOOL InternalGetPerformanceInfo(
+    PPERFORMANCE_INFORMATION pPerformanceInformation, DWORD cb) {
+  static GetPerformanceInfoFunction GetPerformanceInfo_func = NULL;
+  if (!GetPerformanceInfo_func) {
+    HMODULE psapi_dll = ::GetModuleHandle(kPsapiDllName);
+    if (psapi_dll)
+      GetPerformanceInfo_func = reinterpret_cast<GetPerformanceInfoFunction>(
+          GetProcAddress(psapi_dll, "GetPerformanceInfo"));
+
+    if (!GetPerformanceInfo_func) {
+      // The function could be loaded!
+      memset(pPerformanceInformation, 0, cb);
+      return FALSE;
+    }
+  }
+  return GetPerformanceInfo_func(pPerformanceInformation, cb);
+}
+
+size_t GetSystemCommitCharge() {
+  // Get the System Page Size.
+  SYSTEM_INFO system_info;
+  GetSystemInfo(&system_info);
+
+  PERFORMANCE_INFORMATION info;
+  if (!InternalGetPerformanceInfo(&info, sizeof(info))) {
+    DLOG(ERROR) << "Failed to fetch internal performance info.";
+    return 0;
+  }
+  return (info.CommitTotal * system_info.dwPageSize) / 1024;
+}
+
+size_t GetPageSize() {
+  return PAGESIZE_KB * 1024;
+}
+
+}  // namespace base
diff --git a/base/process/process_posix.cc b/base/process/process_posix.cc
new file mode 100644
index 0000000..47b0d5b
--- /dev/null
+++ b/base/process/process_posix.cc
@@ -0,0 +1,379 @@
+// Copyright 2011 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/process/process.h"
+
+#include <sys/resource.h>
+#include <sys/wait.h>
+
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/process/kill.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+
+#if defined(OS_MACOSX)
+#include <sys/event.h>
+#endif
+
+namespace {
+
+#if !defined(OS_NACL_NONSFI)
+
+bool WaitpidWithTimeout(base::ProcessHandle handle,
+                        int* status,
+                        base::TimeDelta wait) {
+  // This POSIX version of this function only guarantees that we wait no less
+  // than |wait| for the process to exit.  The child process may
+  // exit sometime before the timeout has ended but we may still block for up
+  // to 256 milliseconds after the fact.
+  //
+  // waitpid() has no direct support on POSIX for specifying a timeout, you can
+  // either ask it to block indefinitely or return immediately (WNOHANG).
+  // When a child process terminates a SIGCHLD signal is sent to the parent.
+  // Catching this signal would involve installing a signal handler which may
+  // affect other parts of the application and would be difficult to debug.
+  //
+  // Our strategy is to call waitpid() once up front to check if the process
+  // has already exited, otherwise to loop for |wait|, sleeping for
+  // at most 256 milliseconds each time using usleep() and then calling
+  // waitpid().  The amount of time we sleep starts out at 1 milliseconds, and
+  // we double it every 4 sleep cycles.
+  //
+  // usleep() is speced to exit if a signal is received for which a handler
+  // has been installed.  This means that when a SIGCHLD is sent, it will exit
+  // depending on behavior external to this function.
+  //
+  // This function is used primarily for unit tests, if we want to use it in
+  // the application itself it would probably be best to examine other routes.
+
+  if (wait == base::TimeDelta::Max()) {
+    return HANDLE_EINTR(waitpid(handle, status, 0)) > 0;
+  }
+
+  pid_t ret_pid = HANDLE_EINTR(waitpid(handle, status, WNOHANG));
+  static const int64 kMaxSleepInMicroseconds = 1 << 18;  // ~256 milliseconds.
+  int64 max_sleep_time_usecs = 1 << 10;  // ~1 milliseconds.
+  int64 double_sleep_time = 0;
+
+  // If the process hasn't exited yet, then sleep and try again.
+  base::TimeTicks wakeup_time = base::TimeTicks::Now() + wait;
+  while (ret_pid == 0) {
+    base::TimeTicks now = base::TimeTicks::Now();
+    if (now > wakeup_time)
+      break;
+    // Guaranteed to be non-negative!
+    int64 sleep_time_usecs = (wakeup_time - now).InMicroseconds();
+    // Sleep for a bit while we wait for the process to finish.
+    if (sleep_time_usecs > max_sleep_time_usecs)
+      sleep_time_usecs = max_sleep_time_usecs;
+
+    // usleep() will return 0 and set errno to EINTR on receipt of a signal
+    // such as SIGCHLD.
+    usleep(sleep_time_usecs);
+    ret_pid = HANDLE_EINTR(waitpid(handle, status, WNOHANG));
+
+    if ((max_sleep_time_usecs < kMaxSleepInMicroseconds) &&
+        (double_sleep_time++ % 4 == 0)) {
+      max_sleep_time_usecs *= 2;
+    }
+  }
+
+  return ret_pid > 0;
+}
+
+#if defined(OS_MACOSX)
+// Using kqueue on Mac so that we can wait on non-child processes.
+// We can't use kqueues on child processes because we need to reap
+// our own children using wait.
+static bool WaitForSingleNonChildProcess(base::ProcessHandle handle,
+                                         base::TimeDelta wait) {
+  DCHECK_GT(handle, 0);
+  DCHECK_GT(wait, base::TimeDelta());
+
+  base::ScopedFD kq(kqueue());
+  if (!kq.is_valid()) {
+    DPLOG(ERROR) << "kqueue";
+    return false;
+  }
+
+  struct kevent change = {0};
+  EV_SET(&change, handle, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL);
+  int result = HANDLE_EINTR(kevent(kq.get(), &change, 1, NULL, 0, NULL));
+  if (result == -1) {
+    if (errno == ESRCH) {
+      // If the process wasn't found, it must be dead.
+      return true;
+    }
+
+    DPLOG(ERROR) << "kevent (setup " << handle << ")";
+    return false;
+  }
+
+  // Keep track of the elapsed time to be able to restart kevent if it's
+  // interrupted.
+  bool wait_forever = (wait == base::TimeDelta::Max());
+  base::TimeDelta remaining_delta;
+  base::TimeTicks deadline;
+  if (!wait_forever) {
+    remaining_delta = wait;
+    deadline = base::TimeTicks::Now() + remaining_delta;
+  }
+
+  result = -1;
+  struct kevent event = {0};
+
+  while (wait_forever || remaining_delta > base::TimeDelta()) {
+    struct timespec remaining_timespec;
+    struct timespec* remaining_timespec_ptr;
+    if (wait_forever) {
+      remaining_timespec_ptr = NULL;
+    } else {
+      remaining_timespec = remaining_delta.ToTimeSpec();
+      remaining_timespec_ptr = &remaining_timespec;
+    }
+
+    result = kevent(kq.get(), NULL, 0, &event, 1, remaining_timespec_ptr);
+
+    if (result == -1 && errno == EINTR) {
+      if (!wait_forever) {
+        remaining_delta = deadline - base::TimeTicks::Now();
+      }
+      result = 0;
+    } else {
+      break;
+    }
+  }
+
+  if (result < 0) {
+    DPLOG(ERROR) << "kevent (wait " << handle << ")";
+    return false;
+  } else if (result > 1) {
+    DLOG(ERROR) << "kevent (wait " << handle << "): unexpected result "
+                << result;
+    return false;
+  } else if (result == 0) {
+    // Timed out.
+    return false;
+  }
+
+  DCHECK_EQ(result, 1);
+
+  if (event.filter != EVFILT_PROC ||
+      (event.fflags & NOTE_EXIT) == 0 ||
+      event.ident != static_cast<uintptr_t>(handle)) {
+    DLOG(ERROR) << "kevent (wait " << handle
+                << "): unexpected event: filter=" << event.filter
+                << ", fflags=" << event.fflags
+                << ", ident=" << event.ident;
+    return false;
+  }
+
+  return true;
+}
+#endif  // OS_MACOSX
+
+bool WaitForExitWithTimeoutImpl(base::ProcessHandle handle,
+                                int* exit_code,
+                                base::TimeDelta timeout) {
+  base::ProcessHandle parent_pid = base::GetParentProcessId(handle);
+  base::ProcessHandle our_pid = base::GetCurrentProcessHandle();
+  if (parent_pid != our_pid) {
+#if defined(OS_MACOSX)
+    // On Mac we can wait on non child processes.
+    return WaitForSingleNonChildProcess(handle, timeout);
+#else
+    // Currently on Linux we can't handle non child processes.
+    NOTIMPLEMENTED();
+#endif  // OS_MACOSX
+  }
+
+  int status;
+  if (!WaitpidWithTimeout(handle, &status, timeout))
+    return false;
+  if (WIFSIGNALED(status)) {
+    if (exit_code)
+      *exit_code = -1;
+    return true;
+  }
+  if (WIFEXITED(status)) {
+    if (exit_code)
+      *exit_code = WEXITSTATUS(status);
+    return true;
+  }
+  return false;
+}
+#endif  // !defined(OS_NACL_NONSFI)
+
+}  // namespace
+
+namespace base {
+
+Process::Process(ProcessHandle handle) : process_(handle) {
+}
+
+Process::~Process() {
+}
+
+Process::Process(RValue other)
+    : process_(other.object->process_) {
+  other.object->Close();
+}
+
+Process& Process::operator=(RValue other) {
+  if (this != other.object) {
+    process_ = other.object->process_;
+    other.object->Close();
+  }
+  return *this;
+}
+
+// static
+Process Process::Current() {
+  return Process(GetCurrentProcessHandle());
+}
+
+// static
+Process Process::Open(ProcessId pid) {
+  if (pid == GetCurrentProcId())
+    return Current();
+
+  // On POSIX process handles are the same as PIDs.
+  return Process(pid);
+}
+
+// static
+Process Process::OpenWithExtraPrivileges(ProcessId pid) {
+  // On POSIX there are no privileges to set.
+  return Open(pid);
+}
+
+// static
+Process Process::DeprecatedGetProcessFromHandle(ProcessHandle handle) {
+  DCHECK_NE(handle, GetCurrentProcessHandle());
+  return Process(handle);
+}
+
+#if !defined(OS_LINUX) && !defined(OS_MACOSX)
+// static
+bool Process::CanBackgroundProcesses() {
+  return false;
+}
+#endif  // !defined(OS_LINUX) && !defined(OS_MACOSX)
+
+bool Process::IsValid() const {
+  return process_ != kNullProcessHandle;
+}
+
+ProcessHandle Process::Handle() const {
+  return process_;
+}
+
+Process Process::Duplicate() const {
+  if (is_current())
+    return Current();
+
+  return Process(process_);
+}
+
+ProcessId Process::Pid() const {
+  DCHECK(IsValid());
+  return GetProcId(process_);
+}
+
+bool Process::is_current() const {
+  return process_ == GetCurrentProcessHandle();
+}
+
+void Process::Close() {
+  process_ = kNullProcessHandle;
+  // if the process wasn't terminated (so we waited) or the state
+  // wasn't already collected w/ a wait from process_utils, we're gonna
+  // end up w/ a zombie when it does finally exit.
+}
+
+#if !defined(OS_NACL_NONSFI)
+bool Process::Terminate(int exit_code, bool wait) const {
+  // result_code isn't supportable.
+  DCHECK(IsValid());
+  DCHECK_GT(process_, 1);
+  bool result = kill(process_, SIGTERM) == 0;
+  if (result && wait) {
+    int tries = 60;
+
+    if (RunningOnValgrind()) {
+      // Wait for some extra time when running under Valgrind since the child
+      // processes may take some time doing leak checking.
+      tries *= 2;
+    }
+
+    unsigned sleep_ms = 4;
+
+    // The process may not end immediately due to pending I/O
+    bool exited = false;
+    while (tries-- > 0) {
+      pid_t pid = HANDLE_EINTR(waitpid(process_, NULL, WNOHANG));
+      if (pid == process_) {
+        exited = true;
+        break;
+      }
+      if (pid == -1) {
+        if (errno == ECHILD) {
+          // The wait may fail with ECHILD if another process also waited for
+          // the same pid, causing the process state to get cleaned up.
+          exited = true;
+          break;
+        }
+        DPLOG(ERROR) << "Error waiting for process " << process_;
+      }
+
+      usleep(sleep_ms * 1000);
+      const unsigned kMaxSleepMs = 1000;
+      if (sleep_ms < kMaxSleepMs)
+        sleep_ms *= 2;
+    }
+
+    // If we're waiting and the child hasn't died by now, force it
+    // with a SIGKILL.
+    if (!exited)
+      result = kill(process_, SIGKILL) == 0;
+  }
+
+  if (!result)
+    DPLOG(ERROR) << "Unable to terminate process " << process_;
+
+  return result;
+}
+#endif  // !defined(OS_NACL_NONSFI)
+
+bool Process::WaitForExit(int* exit_code) {
+  return WaitForExitWithTimeout(TimeDelta::Max(), exit_code);
+}
+
+bool Process::WaitForExitWithTimeout(TimeDelta timeout, int* exit_code) {
+  return WaitForExitWithTimeoutImpl(Handle(), exit_code, timeout);
+}
+
+#if !defined(OS_LINUX) && !defined(OS_MACOSX)
+bool Process::IsProcessBackgrounded() const {
+  // See SetProcessBackgrounded().
+  DCHECK(IsValid());
+  return false;
+}
+
+bool Process::SetProcessBackgrounded(bool value) {
+  // Not implemented for POSIX systems other than Mac and Linux. With POSIX, if
+  // we were to lower the process priority we wouldn't be able to raise it back
+  // to its initial priority.
+  NOTIMPLEMENTED();
+  return false;
+}
+#endif  // !defined(OS_LINUX) && !defined(OS_MACOSX)
+
+int Process::GetPriority() const {
+  DCHECK(IsValid());
+  return getpriority(PRIO_PROCESS, process_);
+}
+
+}  // namespace base
diff --git a/base/process/process_unittest.cc b/base/process/process_unittest.cc
new file mode 100644
index 0000000..e094c03
--- /dev/null
+++ b/base/process/process_unittest.cc
@@ -0,0 +1,226 @@
+// 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.
+
+#include "base/process/process.h"
+
+#include "base/process/kill.h"
+#include "base/test/multiprocess_test.h"
+#include "base/test/test_timeouts.h"
+#include "base/threading/platform_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/multiprocess_func_list.h"
+
+#if defined(OS_MACOSX)
+#include <mach/mach.h>
+#endif  // OS_MACOSX
+
+namespace {
+
+#if defined(OS_WIN)
+const int kExpectedStillRunningExitCode = 0x102;
+#else
+const int kExpectedStillRunningExitCode = 0;
+#endif
+
+}  // namespace
+
+namespace base {
+
+class ProcessTest : public MultiProcessTest {
+};
+
+TEST_F(ProcessTest, Create) {
+  Process process(SpawnChild("SimpleChildProcess"));
+  ASSERT_TRUE(process.IsValid());
+  ASSERT_FALSE(process.is_current());
+  process.Close();
+  ASSERT_FALSE(process.IsValid());
+}
+
+TEST_F(ProcessTest, CreateCurrent) {
+  Process process = Process::Current();
+  ASSERT_TRUE(process.IsValid());
+  ASSERT_TRUE(process.is_current());
+  process.Close();
+  ASSERT_FALSE(process.IsValid());
+}
+
+TEST_F(ProcessTest, Move) {
+  Process process1(SpawnChild("SimpleChildProcess"));
+  EXPECT_TRUE(process1.IsValid());
+
+  Process process2;
+  EXPECT_FALSE(process2.IsValid());
+
+  process2 = process1.Pass();
+  EXPECT_TRUE(process2.IsValid());
+  EXPECT_FALSE(process1.IsValid());
+  EXPECT_FALSE(process2.is_current());
+
+  Process process3 = Process::Current();
+  process2 = process3.Pass();
+  EXPECT_TRUE(process2.is_current());
+  EXPECT_TRUE(process2.IsValid());
+  EXPECT_FALSE(process3.IsValid());
+}
+
+TEST_F(ProcessTest, Duplicate) {
+  Process process1(SpawnChild("SimpleChildProcess"));
+  ASSERT_TRUE(process1.IsValid());
+
+  Process process2 = process1.Duplicate();
+  ASSERT_TRUE(process1.IsValid());
+  ASSERT_TRUE(process2.IsValid());
+  EXPECT_EQ(process1.Pid(), process2.Pid());
+  EXPECT_FALSE(process1.is_current());
+  EXPECT_FALSE(process2.is_current());
+
+  process1.Close();
+  ASSERT_TRUE(process2.IsValid());
+}
+
+TEST_F(ProcessTest, DuplicateCurrent) {
+  Process process1 = Process::Current();
+  ASSERT_TRUE(process1.IsValid());
+
+  Process process2 = process1.Duplicate();
+  ASSERT_TRUE(process1.IsValid());
+  ASSERT_TRUE(process2.IsValid());
+  EXPECT_EQ(process1.Pid(), process2.Pid());
+  EXPECT_TRUE(process1.is_current());
+  EXPECT_TRUE(process2.is_current());
+
+  process1.Close();
+  ASSERT_TRUE(process2.IsValid());
+}
+
+TEST_F(ProcessTest, DeprecatedGetProcessFromHandle) {
+  Process process1(SpawnChild("SimpleChildProcess"));
+  ASSERT_TRUE(process1.IsValid());
+
+  Process process2 = Process::DeprecatedGetProcessFromHandle(process1.Handle());
+  ASSERT_TRUE(process1.IsValid());
+  ASSERT_TRUE(process2.IsValid());
+  EXPECT_EQ(process1.Pid(), process2.Pid());
+  EXPECT_FALSE(process1.is_current());
+  EXPECT_FALSE(process2.is_current());
+
+  process1.Close();
+  ASSERT_TRUE(process2.IsValid());
+}
+
+MULTIPROCESS_TEST_MAIN(SleepyChildProcess) {
+  PlatformThread::Sleep(TestTimeouts::action_max_timeout());
+  return 0;
+}
+
+TEST_F(ProcessTest, Terminate) {
+  Process process(SpawnChild("SleepyChildProcess"));
+  ASSERT_TRUE(process.IsValid());
+
+  const int kDummyExitCode = 42;
+  int exit_code = kDummyExitCode;
+  EXPECT_EQ(TERMINATION_STATUS_STILL_RUNNING,
+            GetTerminationStatus(process.Handle(), &exit_code));
+  EXPECT_EQ(kExpectedStillRunningExitCode, exit_code);
+
+  exit_code = kDummyExitCode;
+  int kExpectedExitCode = 250;
+  process.Terminate(kExpectedExitCode, false);
+  process.WaitForExitWithTimeout(TestTimeouts::action_max_timeout(),
+                                 &exit_code);
+
+  EXPECT_NE(TERMINATION_STATUS_STILL_RUNNING,
+            GetTerminationStatus(process.Handle(), &exit_code));
+#if !defined(OS_POSIX)
+  // The POSIX implementation actually ignores the exit_code.
+  EXPECT_EQ(kExpectedExitCode, exit_code);
+#endif
+}
+
+MULTIPROCESS_TEST_MAIN(FastSleepyChildProcess) {
+  PlatformThread::Sleep(TestTimeouts::tiny_timeout() * 10);
+  return 0;
+}
+
+TEST_F(ProcessTest, WaitForExit) {
+  Process process(SpawnChild("FastSleepyChildProcess"));
+  ASSERT_TRUE(process.IsValid());
+
+  const int kDummyExitCode = 42;
+  int exit_code = kDummyExitCode;
+  EXPECT_TRUE(process.WaitForExit(&exit_code));
+  EXPECT_EQ(0, exit_code);
+}
+
+TEST_F(ProcessTest, WaitForExitWithTimeout) {
+  Process process(SpawnChild("SleepyChildProcess"));
+  ASSERT_TRUE(process.IsValid());
+
+  const int kDummyExitCode = 42;
+  int exit_code = kDummyExitCode;
+  TimeDelta timeout = TestTimeouts::tiny_timeout();
+  EXPECT_FALSE(process.WaitForExitWithTimeout(timeout, &exit_code));
+  EXPECT_EQ(kDummyExitCode, exit_code);
+
+  process.Terminate(kDummyExitCode, false);
+}
+
+// Ensure that the priority of a process is restored correctly after
+// backgrounding and restoring.
+// Note: a platform may not be willing or able to lower the priority of
+// a process. The calls to SetProcessBackground should be noops then.
+TEST_F(ProcessTest, SetProcessBackgrounded) {
+  Process process(SpawnChild("SimpleChildProcess"));
+  int old_priority = process.GetPriority();
+#if defined(OS_MACOSX)
+  // On the Mac, backgrounding a process requires a port to that process.
+  // In the browser it's available through the MachBroker class, which is not
+  // part of base. Additionally, there is an indefinite amount of time between
+  // spawning a process and receiving its port. Because this test just checks
+  // the ability to background/foreground a process, we can use the current
+  // process's port instead.
+  mach_port_t process_port = mach_task_self();
+  EXPECT_TRUE(process.SetProcessBackgrounded(process_port, true));
+  EXPECT_TRUE(process.IsProcessBackgrounded(process_port));
+  EXPECT_TRUE(process.SetProcessBackgrounded(process_port, false));
+  EXPECT_FALSE(process.IsProcessBackgrounded(process_port));
+#elif defined(OS_WIN)
+  EXPECT_TRUE(process.SetProcessBackgrounded(true));
+  EXPECT_TRUE(process.IsProcessBackgrounded());
+  EXPECT_TRUE(process.SetProcessBackgrounded(false));
+  EXPECT_FALSE(process.IsProcessBackgrounded());
+#else
+  process.SetProcessBackgrounded(true);
+  process.SetProcessBackgrounded(false);
+#endif
+  int new_priority = process.GetPriority();
+  EXPECT_EQ(old_priority, new_priority);
+}
+
+// Same as SetProcessBackgrounded but to this very process. It uses
+// a different code path at least for Windows.
+TEST_F(ProcessTest, SetProcessBackgroundedSelf) {
+  Process process = Process::Current();
+  int old_priority = process.GetPriority();
+#if defined(OS_MACOSX)
+  mach_port_t process_port = mach_task_self();
+  EXPECT_TRUE(process.SetProcessBackgrounded(process_port, true));
+  EXPECT_TRUE(process.IsProcessBackgrounded(process_port));
+  EXPECT_TRUE(process.SetProcessBackgrounded(process_port, false));
+  EXPECT_FALSE(process.IsProcessBackgrounded(process_port));
+#elif defined(OS_WIN)
+  EXPECT_TRUE(process.SetProcessBackgrounded(true));
+  EXPECT_TRUE(process.IsProcessBackgrounded());
+  EXPECT_TRUE(process.SetProcessBackgrounded(false));
+  EXPECT_FALSE(process.IsProcessBackgrounded());
+#else
+  process.SetProcessBackgrounded(true);
+  process.SetProcessBackgrounded(false);
+#endif
+  int new_priority = process.GetPriority();
+  EXPECT_EQ(old_priority, new_priority);
+}
+
+}  // namespace base
diff --git a/base/process/process_util_unittest.cc b/base/process/process_util_unittest.cc
new file mode 100644
index 0000000..1f7f1b2
--- /dev/null
+++ b/base/process/process_util_unittest.cc
@@ -0,0 +1,1112 @@
+// Copyright (c) 2012 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.
+
+#define _CRT_SECURE_NO_WARNINGS
+
+#include <limits>
+
+#include "base/command_line.h"
+#include "base/debug/alias.h"
+#include "base/debug/stack_trace.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/path_service.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/process/kill.h"
+#include "base/process/launch.h"
+#include "base/process/memory.h"
+#include "base/process/process.h"
+#include "base/process/process_metrics.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/synchronization/waitable_event.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 "base/threading/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 <malloc.h>
+#include <sched.h>
+#include <sys/syscall.h>
+#endif
+#if defined(OS_POSIX)
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sched.h>
+#include <signal.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#endif
+#if defined(OS_WIN)
+#include <windows.h>
+#include "base/win/windows_version.h"
+#endif
+#if defined(OS_MACOSX)
+#include <mach/vm_param.h>
+#include <malloc/malloc.h>
+#include "base/mac/mac_util.h"
+#endif
+
+using base::FilePath;
+
+namespace {
+
+#if defined(OS_ANDROID)
+const char kShellPath[] = "/system/bin/sh";
+const char kPosixShell[] = "sh";
+#else
+const char kShellPath[] = "/bin/sh";
+const char kPosixShell[] = "bash";
+#endif
+
+const char kSignalFileSlow[] = "SlowChildProcess.die";
+const char kSignalFileKill[] = "KilledChildProcess.die";
+
+#if defined(OS_POSIX)
+const char kSignalFileTerm[] = "TerminatedChildProcess.die";
+#endif
+
+#if defined(OS_WIN)
+const int kExpectedStillRunningExitCode = 0x102;
+const int kExpectedKilledExitCode = 1;
+#else
+const int kExpectedStillRunningExitCode = 0;
+#endif
+
+// Sleeps until file filename is created.
+void WaitToDie(const char* filename) {
+  FILE* fp;
+  do {
+    base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10));
+    fp = fopen(filename, "r");
+  } while (!fp);
+  fclose(fp);
+}
+
+// Signals children they should die now.
+void SignalChildren(const char* filename) {
+  FILE* fp = fopen(filename, "w");
+  fclose(fp);
+}
+
+// Using a pipe to the child to wait for an event was considered, but
+// there were cases in the past where pipes caused problems (other
+// libraries closing the fds, child deadlocking). This is a simple
+// case, so it's not worth the risk.  Using wait loops is discouraged
+// in most instances.
+base::TerminationStatus WaitForChildTermination(base::ProcessHandle handle,
+                                                int* exit_code) {
+  // Now we wait until the result is something other than STILL_RUNNING.
+  base::TerminationStatus status = base::TERMINATION_STATUS_STILL_RUNNING;
+  const base::TimeDelta kInterval = base::TimeDelta::FromMilliseconds(20);
+  base::TimeDelta waited;
+  do {
+    status = base::GetTerminationStatus(handle, exit_code);
+    base::PlatformThread::Sleep(kInterval);
+    waited += kInterval;
+  } while (status == base::TERMINATION_STATUS_STILL_RUNNING &&
+           waited < TestTimeouts::action_max_timeout());
+
+  return status;
+}
+
+}  // namespace
+
+class ProcessUtilTest : public base::MultiProcessTest {
+ public:
+#if defined(OS_POSIX)
+  // Spawn a child process that counts how many file descriptors are open.
+  int CountOpenFDsInChild();
+#endif
+  // Converts the filename to a platform specific filepath.
+  // On Android files can not be created in arbitrary directories.
+  static std::string GetSignalFilePath(const char* filename);
+};
+
+std::string ProcessUtilTest::GetSignalFilePath(const char* filename) {
+#if !defined(OS_ANDROID)
+  return filename;
+#else
+  FilePath tmp_dir;
+  PathService::Get(base::DIR_CACHE, &tmp_dir);
+  tmp_dir = tmp_dir.Append(filename);
+  return tmp_dir.value();
+#endif
+}
+
+MULTIPROCESS_TEST_MAIN(SimpleChildProcess) {
+  return 0;
+}
+
+// TODO(viettrungluu): This should be in a "MultiProcessTestTest".
+TEST_F(ProcessUtilTest, SpawnChild) {
+  base::Process process = SpawnChild("SimpleChildProcess");
+  ASSERT_TRUE(process.IsValid());
+  int exit_code;
+  EXPECT_TRUE(process.WaitForExitWithTimeout(
+                  TestTimeouts::action_max_timeout(), &exit_code));
+}
+
+MULTIPROCESS_TEST_MAIN(SlowChildProcess) {
+  WaitToDie(ProcessUtilTest::GetSignalFilePath(kSignalFileSlow).c_str());
+  return 0;
+}
+
+TEST_F(ProcessUtilTest, KillSlowChild) {
+  const std::string signal_file =
+      ProcessUtilTest::GetSignalFilePath(kSignalFileSlow);
+  remove(signal_file.c_str());
+  base::Process process = SpawnChild("SlowChildProcess");
+  ASSERT_TRUE(process.IsValid());
+  SignalChildren(signal_file.c_str());
+  int exit_code;
+  EXPECT_TRUE(process.WaitForExitWithTimeout(
+                  TestTimeouts::action_max_timeout(), &exit_code));
+  remove(signal_file.c_str());
+}
+
+// Times out on Linux and Win, flakes on other platforms, http://crbug.com/95058
+TEST_F(ProcessUtilTest, DISABLED_GetTerminationStatusExit) {
+  const std::string signal_file =
+      ProcessUtilTest::GetSignalFilePath(kSignalFileSlow);
+  remove(signal_file.c_str());
+  base::Process process = SpawnChild("SlowChildProcess");
+  ASSERT_TRUE(process.IsValid());
+
+  int exit_code = 42;
+  EXPECT_EQ(base::TERMINATION_STATUS_STILL_RUNNING,
+            base::GetTerminationStatus(process.Handle(), &exit_code));
+  EXPECT_EQ(kExpectedStillRunningExitCode, exit_code);
+
+  SignalChildren(signal_file.c_str());
+  exit_code = 42;
+  base::TerminationStatus status =
+      WaitForChildTermination(process.Handle(), &exit_code);
+  EXPECT_EQ(base::TERMINATION_STATUS_NORMAL_TERMINATION, status);
+  EXPECT_EQ(0, exit_code);
+  remove(signal_file.c_str());
+}
+
+#if defined(OS_WIN)
+// TODO(cpu): figure out how to test this in other platforms.
+TEST_F(ProcessUtilTest, GetProcId) {
+  base::ProcessId id1 = base::GetProcId(GetCurrentProcess());
+  EXPECT_NE(0ul, id1);
+  base::Process process = SpawnChild("SimpleChildProcess");
+  ASSERT_TRUE(process.IsValid());
+  base::ProcessId id2 = process.Pid();
+  EXPECT_NE(0ul, id2);
+  EXPECT_NE(id1, id2);
+}
+#endif
+
+#if !defined(OS_MACOSX)
+// This test is disabled on Mac, since it's flaky due to ReportCrash
+// taking a variable amount of time to parse and load the debug and
+// symbol data for this unit test's executable before firing the
+// signal handler.
+//
+// TODO(gspencer): turn this test process into a very small program
+// with no symbols (instead of using the multiprocess testing
+// framework) to reduce the ReportCrash overhead.
+const char kSignalFileCrash[] = "CrashingChildProcess.die";
+
+MULTIPROCESS_TEST_MAIN(CrashingChildProcess) {
+  WaitToDie(ProcessUtilTest::GetSignalFilePath(kSignalFileCrash).c_str());
+#if defined(OS_POSIX)
+  // Have to disable to signal handler for segv so we can get a crash
+  // instead of an abnormal termination through the crash dump handler.
+  ::signal(SIGSEGV, SIG_DFL);
+#endif
+  // Make this process have a segmentation fault.
+  volatile int* oops = NULL;
+  *oops = 0xDEAD;
+  return 1;
+}
+
+// This test intentionally crashes, so we don't need to run it under
+// AddressSanitizer.
+#if defined(ADDRESS_SANITIZER) || defined(SYZYASAN)
+#define MAYBE_GetTerminationStatusCrash DISABLED_GetTerminationStatusCrash
+#else
+#define MAYBE_GetTerminationStatusCrash GetTerminationStatusCrash
+#endif
+TEST_F(ProcessUtilTest, MAYBE_GetTerminationStatusCrash) {
+  const std::string signal_file =
+    ProcessUtilTest::GetSignalFilePath(kSignalFileCrash);
+  remove(signal_file.c_str());
+  base::Process process = SpawnChild("CrashingChildProcess");
+  ASSERT_TRUE(process.IsValid());
+
+  int exit_code = 42;
+  EXPECT_EQ(base::TERMINATION_STATUS_STILL_RUNNING,
+            base::GetTerminationStatus(process.Handle(), &exit_code));
+  EXPECT_EQ(kExpectedStillRunningExitCode, exit_code);
+
+  SignalChildren(signal_file.c_str());
+  exit_code = 42;
+  base::TerminationStatus status =
+      WaitForChildTermination(process.Handle(), &exit_code);
+  EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_CRASHED, status);
+
+#if defined(OS_WIN)
+  EXPECT_EQ(0xc0000005, exit_code);
+#elif defined(OS_POSIX)
+  int signaled = WIFSIGNALED(exit_code);
+  EXPECT_NE(0, signaled);
+  int signal = WTERMSIG(exit_code);
+  EXPECT_EQ(SIGSEGV, signal);
+#endif
+
+  // Reset signal handlers back to "normal".
+  base::debug::EnableInProcessStackDumping();
+  remove(signal_file.c_str());
+}
+#endif  // !defined(OS_MACOSX)
+
+MULTIPROCESS_TEST_MAIN(KilledChildProcess) {
+  WaitToDie(ProcessUtilTest::GetSignalFilePath(kSignalFileKill).c_str());
+#if defined(OS_WIN)
+  // Kill ourselves.
+  HANDLE handle = ::OpenProcess(PROCESS_ALL_ACCESS, 0, ::GetCurrentProcessId());
+  ::TerminateProcess(handle, kExpectedKilledExitCode);
+#elif defined(OS_POSIX)
+  // Send a SIGKILL to this process, just like the OOM killer would.
+  ::kill(getpid(), SIGKILL);
+#endif
+  return 1;
+}
+
+#if defined(OS_POSIX)
+MULTIPROCESS_TEST_MAIN(TerminatedChildProcess) {
+  WaitToDie(ProcessUtilTest::GetSignalFilePath(kSignalFileTerm).c_str());
+  // Send a SIGTERM to this process.
+  ::kill(getpid(), SIGTERM);
+  return 1;
+}
+#endif
+
+TEST_F(ProcessUtilTest, GetTerminationStatusSigKill) {
+  const std::string signal_file =
+    ProcessUtilTest::GetSignalFilePath(kSignalFileKill);
+  remove(signal_file.c_str());
+  base::Process process = SpawnChild("KilledChildProcess");
+  ASSERT_TRUE(process.IsValid());
+
+  int exit_code = 42;
+  EXPECT_EQ(base::TERMINATION_STATUS_STILL_RUNNING,
+            base::GetTerminationStatus(process.Handle(), &exit_code));
+  EXPECT_EQ(kExpectedStillRunningExitCode, exit_code);
+
+  SignalChildren(signal_file.c_str());
+  exit_code = 42;
+  base::TerminationStatus status =
+      WaitForChildTermination(process.Handle(), &exit_code);
+#if defined(OS_CHROMEOS)
+  EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM, status);
+#else
+  EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_WAS_KILLED, status);
+#endif
+
+#if defined(OS_WIN)
+  EXPECT_EQ(kExpectedKilledExitCode, exit_code);
+#elif defined(OS_POSIX)
+  int signaled = WIFSIGNALED(exit_code);
+  EXPECT_NE(0, signaled);
+  int signal = WTERMSIG(exit_code);
+  EXPECT_EQ(SIGKILL, signal);
+#endif
+  remove(signal_file.c_str());
+}
+
+#if defined(OS_POSIX)
+TEST_F(ProcessUtilTest, GetTerminationStatusSigTerm) {
+  const std::string signal_file =
+    ProcessUtilTest::GetSignalFilePath(kSignalFileTerm);
+  remove(signal_file.c_str());
+  base::Process process = SpawnChild("TerminatedChildProcess");
+  ASSERT_TRUE(process.IsValid());
+
+  int exit_code = 42;
+  EXPECT_EQ(base::TERMINATION_STATUS_STILL_RUNNING,
+            base::GetTerminationStatus(process.Handle(), &exit_code));
+  EXPECT_EQ(kExpectedStillRunningExitCode, exit_code);
+
+  SignalChildren(signal_file.c_str());
+  exit_code = 42;
+  base::TerminationStatus status =
+      WaitForChildTermination(process.Handle(), &exit_code);
+  EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_WAS_KILLED, status);
+
+  int signaled = WIFSIGNALED(exit_code);
+  EXPECT_NE(0, signaled);
+  int signal = WTERMSIG(exit_code);
+  EXPECT_EQ(SIGTERM, signal);
+  remove(signal_file.c_str());
+}
+#endif
+
+#if defined(OS_WIN)
+// TODO(estade): if possible, port this test.
+TEST_F(ProcessUtilTest, GetAppOutput) {
+  // Let's create a decently long message.
+  std::string message;
+  for (int i = 0; i < 1025; i++) {  // 1025 so it does not end on a kilo-byte
+                                    // boundary.
+    message += "Hello!";
+  }
+  // cmd.exe's echo always adds a \r\n to its output.
+  std::string expected(message);
+  expected += "\r\n";
+
+  FilePath cmd(L"cmd.exe");
+  base::CommandLine cmd_line(cmd);
+  cmd_line.AppendArg("/c");
+  cmd_line.AppendArg("echo " + message + "");
+  std::string output;
+  ASSERT_TRUE(base::GetAppOutput(cmd_line, &output));
+  EXPECT_EQ(expected, output);
+
+  // Let's make sure stderr is ignored.
+  base::CommandLine other_cmd_line(cmd);
+  other_cmd_line.AppendArg("/c");
+  // http://msdn.microsoft.com/library/cc772622.aspx
+  cmd_line.AppendArg("echo " + message + " >&2");
+  output.clear();
+  ASSERT_TRUE(base::GetAppOutput(other_cmd_line, &output));
+  EXPECT_EQ("", output);
+}
+
+// TODO(estade): if possible, port this test.
+TEST_F(ProcessUtilTest, LaunchAsUser) {
+  base::UserTokenHandle token;
+  ASSERT_TRUE(OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &token));
+  base::LaunchOptions options;
+  options.as_user = token;
+  EXPECT_TRUE(base::LaunchProcess(MakeCmdLine("SimpleChildProcess"),
+                                  options).IsValid());
+}
+
+static const char kEventToTriggerHandleSwitch[] = "event-to-trigger-handle";
+
+MULTIPROCESS_TEST_MAIN(TriggerEventChildProcess) {
+  std::string handle_value_string =
+      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+          kEventToTriggerHandleSwitch);
+  CHECK(!handle_value_string.empty());
+
+  uint64 handle_value_uint64;
+  CHECK(base::StringToUint64(handle_value_string, &handle_value_uint64));
+  // Give ownership of the handle to |event|.
+  base::WaitableEvent event(base::win::ScopedHandle(
+      reinterpret_cast<HANDLE>(handle_value_uint64)));
+
+  event.Signal();
+
+  return 0;
+}
+
+TEST_F(ProcessUtilTest, InheritSpecifiedHandles) {
+  // Manually create the event, so that it can be inheritable.
+  SECURITY_ATTRIBUTES security_attributes = {};
+  security_attributes.nLength = static_cast<DWORD>(sizeof(security_attributes));
+  security_attributes.lpSecurityDescriptor = NULL;
+  security_attributes.bInheritHandle = true;
+
+  // Takes ownership of the event handle.
+  base::WaitableEvent event(base::win::ScopedHandle(
+      CreateEvent(&security_attributes, true, false, NULL)));
+  base::HandlesToInheritVector handles_to_inherit;
+  handles_to_inherit.push_back(event.handle());
+  base::LaunchOptions options;
+  options.handles_to_inherit = &handles_to_inherit;
+
+  base::CommandLine cmd_line = MakeCmdLine("TriggerEventChildProcess");
+  cmd_line.AppendSwitchASCII(kEventToTriggerHandleSwitch,
+      base::Uint64ToString(reinterpret_cast<uint64>(event.handle())));
+
+  // This functionality actually requires Vista or later. Make sure that it
+  // fails properly on XP.
+  if (base::win::GetVersion() < base::win::VERSION_VISTA) {
+    EXPECT_FALSE(base::LaunchProcess(cmd_line, options).IsValid());
+    return;
+  }
+
+  // Launch the process and wait for it to trigger the event.
+  ASSERT_TRUE(base::LaunchProcess(cmd_line, options).IsValid());
+  EXPECT_TRUE(event.TimedWait(TestTimeouts::action_max_timeout()));
+}
+#endif  // defined(OS_WIN)
+
+#if defined(OS_POSIX)
+
+namespace {
+
+// Returns the maximum number of files that a process can have open.
+// Returns 0 on error.
+int GetMaxFilesOpenInProcess() {
+  struct rlimit rlim;
+  if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) {
+    return 0;
+  }
+
+  // rlim_t is a uint64 - clip to maxint. We do this since FD #s are ints
+  // which are all 32 bits on the supported platforms.
+  rlim_t max_int = static_cast<rlim_t>(std::numeric_limits<int32>::max());
+  if (rlim.rlim_cur > max_int) {
+    return max_int;
+  }
+
+  return rlim.rlim_cur;
+}
+
+const int kChildPipe = 20;  // FD # for write end of pipe in child process.
+
+#if defined(OS_MACOSX)
+
+// <http://opensource.apple.com/source/xnu/xnu-2422.1.72/bsd/sys/guarded.h>
+#if !defined(_GUARDID_T)
+#define _GUARDID_T
+typedef __uint64_t guardid_t;
+#endif  // _GUARDID_T
+
+// From .../MacOSX10.9.sdk/usr/include/sys/syscall.h
+#if !defined(SYS_change_fdguard_np)
+#define SYS_change_fdguard_np 444
+#endif
+
+// <http://opensource.apple.com/source/xnu/xnu-2422.1.72/bsd/sys/guarded.h>
+#if !defined(GUARD_DUP)
+#define GUARD_DUP (1u << 1)
+#endif
+
+// <http://opensource.apple.com/source/xnu/xnu-2422.1.72/bsd/kern/kern_guarded.c?txt>
+//
+// Atomically replaces |guard|/|guardflags| with |nguard|/|nguardflags| on |fd|.
+int change_fdguard_np(int fd,
+                      const guardid_t *guard, u_int guardflags,
+                      const guardid_t *nguard, u_int nguardflags,
+                      int *fdflagsp) {
+  return syscall(SYS_change_fdguard_np, fd, guard, guardflags,
+                 nguard, nguardflags, fdflagsp);
+}
+
+// Attempt to set a file-descriptor guard on |fd|.  In case of success, remove
+// it and return |true| to indicate that it can be guarded.  Returning |false|
+// means either that |fd| is guarded by some other code, or more likely EBADF.
+//
+// Starting with 10.9, libdispatch began setting GUARD_DUP on a file descriptor.
+// Unfortunately, it is spun up as part of +[NSApplication initialize], which is
+// not really something that Chromium can avoid using on OSX.  See
+// <http://crbug.com/338157>.  This function allows querying whether the file
+// descriptor is guarded before attempting to close it.
+bool CanGuardFd(int fd) {
+  // The syscall is first provided in 10.9/Mavericks.
+  if (!base::mac::IsOSMavericksOrLater())
+    return true;
+
+  // Saves the original flags to reset later.
+  int original_fdflags = 0;
+
+  // This can be any value at all, it just has to match up between the two
+  // calls.
+  const guardid_t kGuard = 15;
+
+  // Attempt to change the guard.  This can fail with EBADF if the file
+  // descriptor is bad, or EINVAL if the fd already has a guard set.
+  int ret =
+      change_fdguard_np(fd, NULL, 0, &kGuard, GUARD_DUP, &original_fdflags);
+  if (ret == -1)
+    return false;
+
+  // Remove the guard.  It should not be possible to fail in removing the guard
+  // just added.
+  ret = change_fdguard_np(fd, &kGuard, GUARD_DUP, NULL, 0, &original_fdflags);
+  DPCHECK(ret == 0);
+
+  return true;
+}
+#endif  // OS_MACOSX
+
+}  // namespace
+
+MULTIPROCESS_TEST_MAIN(ProcessUtilsLeakFDChildProcess) {
+  // This child process counts the number of open FDs, it then writes that
+  // number out to a pipe connected to the parent.
+  int num_open_files = 0;
+  int write_pipe = kChildPipe;
+  int max_files = GetMaxFilesOpenInProcess();
+  for (int i = STDERR_FILENO + 1; i < max_files; i++) {
+#if defined(OS_MACOSX)
+    // Ignore guarded or invalid file descriptors.
+    if (!CanGuardFd(i))
+      continue;
+#endif
+
+    if (i != kChildPipe) {
+      int fd;
+      if ((fd = HANDLE_EINTR(dup(i))) != -1) {
+        close(fd);
+        num_open_files += 1;
+      }
+    }
+  }
+
+  int written = HANDLE_EINTR(write(write_pipe, &num_open_files,
+                                   sizeof(num_open_files)));
+  DCHECK_EQ(static_cast<size_t>(written), sizeof(num_open_files));
+  int ret = IGNORE_EINTR(close(write_pipe));
+  DPCHECK(ret == 0);
+
+  return 0;
+}
+
+int ProcessUtilTest::CountOpenFDsInChild() {
+  int fds[2];
+  if (pipe(fds) < 0)
+    NOTREACHED();
+
+  base::FileHandleMappingVector fd_mapping_vec;
+  fd_mapping_vec.push_back(std::pair<int, int>(fds[1], kChildPipe));
+  base::LaunchOptions options;
+  options.fds_to_remap = &fd_mapping_vec;
+  base::Process process =
+      SpawnChildWithOptions("ProcessUtilsLeakFDChildProcess", options);
+  CHECK(process.IsValid());
+  int ret = IGNORE_EINTR(close(fds[1]));
+  DPCHECK(ret == 0);
+
+  // Read number of open files in client process from pipe;
+  int num_open_files = -1;
+  ssize_t bytes_read =
+      HANDLE_EINTR(read(fds[0], &num_open_files, sizeof(num_open_files)));
+  CHECK_EQ(bytes_read, static_cast<ssize_t>(sizeof(num_open_files)));
+
+#if defined(THREAD_SANITIZER)
+  // Compiler-based ThreadSanitizer makes this test slow.
+  base::TimeDelta timeout = base::TimeDelta::FromSeconds(3);
+#else
+  base::TimeDelta timeout = base::TimeDelta::FromSeconds(1);
+#endif
+  int exit_code;
+  CHECK(process.WaitForExitWithTimeout(timeout, &exit_code));
+  ret = IGNORE_EINTR(close(fds[0]));
+  DPCHECK(ret == 0);
+
+  return num_open_files;
+}
+
+#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER)
+// ProcessUtilTest.FDRemapping is flaky when ran under xvfb-run on Precise.
+// The problem is 100% reproducible with both ASan and TSan.
+// See http://crbug.com/136720.
+#define MAYBE_FDRemapping DISABLED_FDRemapping
+#else
+#define MAYBE_FDRemapping FDRemapping
+#endif
+TEST_F(ProcessUtilTest, MAYBE_FDRemapping) {
+  int fds_before = CountOpenFDsInChild();
+
+  // open some dummy fds to make sure they don't propagate over to the
+  // child process.
+  int dev_null = open("/dev/null", O_RDONLY);
+  int sockets[2];
+  socketpair(AF_UNIX, SOCK_STREAM, 0, sockets);
+
+  int fds_after = CountOpenFDsInChild();
+
+  ASSERT_EQ(fds_after, fds_before);
+
+  int ret;
+  ret = IGNORE_EINTR(close(sockets[0]));
+  DPCHECK(ret == 0);
+  ret = IGNORE_EINTR(close(sockets[1]));
+  DPCHECK(ret == 0);
+  ret = IGNORE_EINTR(close(dev_null));
+  DPCHECK(ret == 0);
+}
+
+namespace {
+
+std::string TestLaunchProcess(const std::vector<std::string>& args,
+                              const base::EnvironmentMap& env_changes,
+                              const bool clear_environ,
+                              const int clone_flags) {
+  base::FileHandleMappingVector fds_to_remap;
+
+  int fds[2];
+  PCHECK(pipe(fds) == 0);
+
+  fds_to_remap.push_back(std::make_pair(fds[1], 1));
+  base::LaunchOptions options;
+  options.wait = true;
+  options.environ = env_changes;
+  options.clear_environ = clear_environ;
+  options.fds_to_remap = &fds_to_remap;
+#if defined(OS_LINUX)
+  options.clone_flags = clone_flags;
+#else
+  CHECK_EQ(0, clone_flags);
+#endif  // OS_LINUX
+  EXPECT_TRUE(base::LaunchProcess(args, options).IsValid());
+  PCHECK(IGNORE_EINTR(close(fds[1])) == 0);
+
+  char buf[512];
+  const ssize_t n = HANDLE_EINTR(read(fds[0], buf, sizeof(buf)));
+
+  PCHECK(IGNORE_EINTR(close(fds[0])) == 0);
+
+  return std::string(buf, n);
+}
+
+const char kLargeString[] =
+    "0123456789012345678901234567890123456789012345678901234567890123456789"
+    "0123456789012345678901234567890123456789012345678901234567890123456789"
+    "0123456789012345678901234567890123456789012345678901234567890123456789"
+    "0123456789012345678901234567890123456789012345678901234567890123456789"
+    "0123456789012345678901234567890123456789012345678901234567890123456789"
+    "0123456789012345678901234567890123456789012345678901234567890123456789"
+    "0123456789012345678901234567890123456789012345678901234567890123456789";
+
+}  // namespace
+
+TEST_F(ProcessUtilTest, LaunchProcess) {
+  base::EnvironmentMap env_changes;
+  std::vector<std::string> echo_base_test;
+  echo_base_test.push_back(kPosixShell);
+  echo_base_test.push_back("-c");
+  echo_base_test.push_back("echo $BASE_TEST");
+
+  std::vector<std::string> print_env;
+  print_env.push_back("/usr/bin/env");
+  const int no_clone_flags = 0;
+  const bool no_clear_environ = false;
+
+  const char kBaseTest[] = "BASE_TEST";
+
+  env_changes[kBaseTest] = "bar";
+  EXPECT_EQ("bar\n",
+            TestLaunchProcess(
+                echo_base_test, env_changes, no_clear_environ, no_clone_flags));
+  env_changes.clear();
+
+  EXPECT_EQ(0, setenv(kBaseTest, "testing", 1 /* override */));
+  EXPECT_EQ("testing\n",
+            TestLaunchProcess(
+                echo_base_test, env_changes, no_clear_environ, no_clone_flags));
+
+  env_changes[kBaseTest] = std::string();
+  EXPECT_EQ("\n",
+            TestLaunchProcess(
+                echo_base_test, env_changes, no_clear_environ, no_clone_flags));
+
+  env_changes[kBaseTest] = "foo";
+  EXPECT_EQ("foo\n",
+            TestLaunchProcess(
+                echo_base_test, env_changes, no_clear_environ, no_clone_flags));
+
+  env_changes.clear();
+  EXPECT_EQ(0, setenv(kBaseTest, kLargeString, 1 /* override */));
+  EXPECT_EQ(std::string(kLargeString) + "\n",
+            TestLaunchProcess(
+                echo_base_test, env_changes, no_clear_environ, no_clone_flags));
+
+  env_changes[kBaseTest] = "wibble";
+  EXPECT_EQ("wibble\n",
+            TestLaunchProcess(
+                echo_base_test, env_changes, no_clear_environ, no_clone_flags));
+
+#if defined(OS_LINUX)
+  // 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));
+  }
+
+  EXPECT_EQ(
+      "BASE_TEST=wibble\n",
+      TestLaunchProcess(
+          print_env, env_changes, true /* clear_environ */, no_clone_flags));
+  env_changes.clear();
+  EXPECT_EQ(
+      "",
+      TestLaunchProcess(
+          print_env, env_changes, true /* clear_environ */, no_clone_flags));
+#endif
+}
+
+TEST_F(ProcessUtilTest, GetAppOutput) {
+  std::string output;
+
+#if defined(OS_ANDROID)
+  std::vector<std::string> argv;
+  argv.push_back("sh");  // Instead of /bin/sh, force path search to find it.
+  argv.push_back("-c");
+
+  argv.push_back("exit 0");
+  EXPECT_TRUE(base::GetAppOutput(base::CommandLine(argv), &output));
+  EXPECT_STREQ("", output.c_str());
+
+  argv[2] = "exit 1";
+  EXPECT_FALSE(base::GetAppOutput(base::CommandLine(argv), &output));
+  EXPECT_STREQ("", output.c_str());
+
+  argv[2] = "echo foobar42";
+  EXPECT_TRUE(base::GetAppOutput(base::CommandLine(argv), &output));
+  EXPECT_STREQ("foobar42\n", output.c_str());
+#else
+  EXPECT_TRUE(base::GetAppOutput(base::CommandLine(FilePath("true")),
+                                 &output));
+  EXPECT_STREQ("", output.c_str());
+
+  EXPECT_FALSE(base::GetAppOutput(base::CommandLine(FilePath("false")),
+                                  &output));
+
+  std::vector<std::string> argv;
+  argv.push_back("/bin/echo");
+  argv.push_back("-n");
+  argv.push_back("foobar42");
+  EXPECT_TRUE(base::GetAppOutput(base::CommandLine(argv), &output));
+  EXPECT_STREQ("foobar42", output.c_str());
+#endif  // defined(OS_ANDROID)
+}
+
+// Flakes on Android, crbug.com/375840
+#if defined(OS_ANDROID)
+#define MAYBE_GetAppOutputRestricted DISABLED_GetAppOutputRestricted
+#else
+#define MAYBE_GetAppOutputRestricted GetAppOutputRestricted
+#endif
+TEST_F(ProcessUtilTest, MAYBE_GetAppOutputRestricted) {
+  // Unfortunately, since we can't rely on the path, we need to know where
+  // everything is. So let's use /bin/sh, which is on every POSIX system, and
+  // its built-ins.
+  std::vector<std::string> argv;
+  argv.push_back(std::string(kShellPath));  // argv[0]
+  argv.push_back("-c");  // argv[1]
+
+  // On success, should set |output|. We use |/bin/sh -c 'exit 0'| instead of
+  // |true| since the location of the latter may be |/bin| or |/usr/bin| (and we
+  // need absolute paths).
+  argv.push_back("exit 0");   // argv[2]; equivalent to "true"
+  std::string output = "abc";
+  EXPECT_TRUE(base::GetAppOutputRestricted(base::CommandLine(argv), &output,
+                                           100));
+  EXPECT_STREQ("", output.c_str());
+
+  argv[2] = "exit 1";  // equivalent to "false"
+  output = "before";
+  EXPECT_FALSE(base::GetAppOutputRestricted(base::CommandLine(argv), &output,
+                                            100));
+  EXPECT_STREQ("", output.c_str());
+
+  // Amount of output exactly equal to space allowed.
+  argv[2] = "echo 123456789";  // (the sh built-in doesn't take "-n")
+  output.clear();
+  EXPECT_TRUE(base::GetAppOutputRestricted(base::CommandLine(argv), &output,
+                                           10));
+  EXPECT_STREQ("123456789\n", output.c_str());
+
+  // Amount of output greater than space allowed.
+  output.clear();
+  EXPECT_TRUE(base::GetAppOutputRestricted(base::CommandLine(argv), &output,
+                                           5));
+  EXPECT_STREQ("12345", output.c_str());
+
+  // Amount of output less than space allowed.
+  output.clear();
+  EXPECT_TRUE(base::GetAppOutputRestricted(base::CommandLine(argv), &output,
+                                           15));
+  EXPECT_STREQ("123456789\n", output.c_str());
+
+  // Zero space allowed.
+  output = "abc";
+  EXPECT_TRUE(base::GetAppOutputRestricted(base::CommandLine(argv), &output,
+                                           0));
+  EXPECT_STREQ("", output.c_str());
+}
+
+#if !defined(OS_MACOSX) && !defined(OS_OPENBSD)
+// TODO(benwells): GetAppOutputRestricted should terminate applications
+// with SIGPIPE when we have enough output. http://crbug.com/88502
+TEST_F(ProcessUtilTest, GetAppOutputRestrictedSIGPIPE) {
+  std::vector<std::string> argv;
+  std::string output;
+
+  argv.push_back(std::string(kShellPath));  // argv[0]
+  argv.push_back("-c");
+#if defined(OS_ANDROID)
+  argv.push_back("while echo 12345678901234567890; do :; done");
+  EXPECT_TRUE(base::GetAppOutputRestricted(base::CommandLine(argv), &output,
+                                           10));
+  EXPECT_STREQ("1234567890", output.c_str());
+#else
+  argv.push_back("yes");
+  EXPECT_TRUE(base::GetAppOutputRestricted(base::CommandLine(argv), &output,
+                                           10));
+  EXPECT_STREQ("y\ny\ny\ny\ny\n", output.c_str());
+#endif
+}
+#endif
+
+#if defined(ADDRESS_SANITIZER) && defined(OS_MACOSX) && \
+    defined(ARCH_CPU_64_BITS)
+// Times out under AddressSanitizer on 64-bit OS X, see
+// http://crbug.com/298197.
+#define MAYBE_GetAppOutputRestrictedNoZombies \
+    DISABLED_GetAppOutputRestrictedNoZombies
+#else
+#define MAYBE_GetAppOutputRestrictedNoZombies GetAppOutputRestrictedNoZombies
+#endif
+TEST_F(ProcessUtilTest, MAYBE_GetAppOutputRestrictedNoZombies) {
+  std::vector<std::string> argv;
+
+  argv.push_back(std::string(kShellPath));  // argv[0]
+  argv.push_back("-c");  // argv[1]
+  argv.push_back("echo 123456789012345678901234567890");  // argv[2]
+
+  // Run |GetAppOutputRestricted()| 300 (> default per-user processes on Mac OS
+  // 10.5) times with an output buffer big enough to capture all output.
+  for (int i = 0; i < 300; i++) {
+    std::string output;
+    EXPECT_TRUE(base::GetAppOutputRestricted(base::CommandLine(argv), &output,
+                                             100));
+    EXPECT_STREQ("123456789012345678901234567890\n", output.c_str());
+  }
+
+  // Ditto, but with an output buffer too small to capture all output.
+  for (int i = 0; i < 300; i++) {
+    std::string output;
+    EXPECT_TRUE(base::GetAppOutputRestricted(base::CommandLine(argv), &output,
+                                             10));
+    EXPECT_STREQ("1234567890", output.c_str());
+  }
+}
+
+TEST_F(ProcessUtilTest, GetAppOutputWithExitCode) {
+  // Test getting output from a successful application.
+  std::vector<std::string> argv;
+  std::string output;
+  int exit_code;
+  argv.push_back(std::string(kShellPath));  // argv[0]
+  argv.push_back("-c");  // argv[1]
+  argv.push_back("echo foo");  // argv[2];
+  EXPECT_TRUE(base::GetAppOutputWithExitCode(base::CommandLine(argv), &output,
+                                             &exit_code));
+  EXPECT_STREQ("foo\n", output.c_str());
+  EXPECT_EQ(exit_code, 0);
+
+  // Test getting output from an application which fails with a specific exit
+  // code.
+  output.clear();
+  argv[2] = "echo foo; exit 2";
+  EXPECT_TRUE(base::GetAppOutputWithExitCode(base::CommandLine(argv), &output,
+                                             &exit_code));
+  EXPECT_STREQ("foo\n", output.c_str());
+  EXPECT_EQ(exit_code, 2);
+}
+
+TEST_F(ProcessUtilTest, GetParentProcessId) {
+  base::ProcessId ppid = base::GetParentProcessId(base::GetCurrentProcId());
+  EXPECT_EQ(ppid, getppid());
+}
+
+// TODO(port): port those unit tests.
+bool IsProcessDead(base::ProcessHandle child) {
+  // waitpid() will actually reap the process which is exactly NOT what we
+  // want to test for.  The good thing is that if it can't find the process
+  // we'll get a nice value for errno which we can test for.
+  const pid_t result = HANDLE_EINTR(waitpid(child, NULL, WNOHANG));
+  return result == -1 && errno == ECHILD;
+}
+
+TEST_F(ProcessUtilTest, DelayedTermination) {
+  base::Process child_process = SpawnChild("process_util_test_never_die");
+  ASSERT_TRUE(child_process.IsValid());
+  base::EnsureProcessTerminated(child_process.Duplicate());
+  int exit_code;
+  child_process.WaitForExitWithTimeout(base::TimeDelta::FromSeconds(5),
+                                       &exit_code);
+
+  // Check that process was really killed.
+  EXPECT_TRUE(IsProcessDead(child_process.Handle()));
+}
+
+MULTIPROCESS_TEST_MAIN(process_util_test_never_die) {
+  while (1) {
+    sleep(500);
+  }
+  return 0;
+}
+
+TEST_F(ProcessUtilTest, ImmediateTermination) {
+  base::Process child_process = SpawnChild("process_util_test_die_immediately");
+  ASSERT_TRUE(child_process.IsValid());
+  // Give it time to die.
+  sleep(2);
+  base::EnsureProcessTerminated(child_process.Duplicate());
+
+  // Check that process was really killed.
+  EXPECT_TRUE(IsProcessDead(child_process.Handle()));
+}
+
+MULTIPROCESS_TEST_MAIN(process_util_test_die_immediately) {
+  return 0;
+}
+
+#if !defined(OS_ANDROID)
+const char kPipeValue = '\xcc';
+
+class ReadFromPipeDelegate : public base::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(ProcessUtilTest, PreExecHook) {
+  int pipe_fds[2];
+  ASSERT_EQ(0, pipe(pipe_fds));
+
+  base::ScopedFD read_fd(pipe_fds[0]);
+  base::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());
+  base::LaunchOptions options;
+  options.fds_to_remap = &fds_to_remap;
+  options.pre_exec_delegate = &read_from_pipe_delegate;
+  base::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_ANDROID)
+
+#endif  // defined(OS_POSIX)
+
+#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(ProcessUtilTest, CloneFlags) {
+  if (RunningOnValgrind() ||
+      !base::PathExists(FilePath("/proc/self/ns/user")) ||
+      !base::PathExists(FilePath("/proc/self/ns/pid"))) {
+    // User or PID namespaces are not supported.
+    return;
+  }
+
+  base::LaunchOptions options;
+  options.clone_flags = CLONE_NEWUSER | CLONE_NEWPID;
+
+  base::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 =
+      base::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));
+}
+
+MULTIPROCESS_TEST_MAIN(CheckCwdProcess) {
+  base::FilePath expected;
+  CHECK(base::GetTempDir(&expected));
+  base::FilePath actual;
+  CHECK(base::GetCurrentDirectory(&actual));
+  CHECK(actual == expected);
+  return kSuccess;
+}
+
+TEST_F(ProcessUtilTest, CurrentDirectory) {
+  // TODO(rickyz): Add support for passing arguments to multiprocess children,
+  // then create a special directory for this test.
+  base::FilePath tmp_dir;
+  ASSERT_TRUE(base::GetTempDir(&tmp_dir));
+
+  base::LaunchOptions options;
+  options.current_directory = tmp_dir;
+
+  base::Process process(SpawnChildWithOptions("CheckCwdProcess", options));
+  ASSERT_TRUE(process.IsValid());
+
+  int exit_code = 42;
+  EXPECT_TRUE(process.WaitForExit(&exit_code));
+  EXPECT_EQ(kSuccess, exit_code);
+}
+
+TEST_F(ProcessUtilTest, InvalidCurrentDirectory) {
+  base::LaunchOptions options;
+  options.current_directory = base::FilePath("/dev/null");
+
+  base::Process process(SpawnChildWithOptions("SimpleChildProcess", options));
+  ASSERT_TRUE(process.IsValid());
+
+  int exit_code = kSuccess;
+  EXPECT_TRUE(process.WaitForExit(&exit_code));
+  EXPECT_NE(kSuccess, exit_code);
+}
+#endif
diff --git a/base/process/process_win.cc b/base/process/process_win.cc
new file mode 100644
index 0000000..2ad72c7
--- /dev/null
+++ b/base/process/process_win.cc
@@ -0,0 +1,206 @@
+// Copyright (c) 2011 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/process/process.h"
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/field_trial.h"
+#include "base/numerics/safe_conversions.h"
+#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)
+    : is_current_process_(false),
+      process_(handle) {
+  CHECK_NE(handle, ::GetCurrentProcess());
+}
+
+Process::Process(RValue other)
+    : is_current_process_(other.object->is_current_process_),
+      process_(other.object->process_.Take()) {
+  other.object->Close();
+}
+
+Process::~Process() {
+}
+
+Process& Process::operator=(RValue other) {
+  if (this != other.object) {
+    process_.Set(other.object->process_.Take());
+    is_current_process_ = other.object->is_current_process_;
+    other.object->Close();
+  }
+  return *this;
+}
+
+// static
+Process Process::Current() {
+  Process process;
+  process.is_current_process_ = true;
+  return process.Pass();
+}
+
+// static
+Process Process::Open(ProcessId pid) {
+  return Process(::OpenProcess(kBasicProcessAccess, FALSE, pid));
+}
+
+// static
+Process Process::OpenWithExtraPrivileges(ProcessId pid) {
+  DWORD access = kBasicProcessAccess | PROCESS_DUP_HANDLE | PROCESS_VM_READ;
+  return Process(::OpenProcess(access, FALSE, pid));
+}
+
+// static
+Process Process::OpenWithAccess(ProcessId pid, DWORD desired_access) {
+  return Process(::OpenProcess(desired_access, FALSE, pid));
+}
+
+// static
+Process Process::DeprecatedGetProcessFromHandle(ProcessHandle handle) {
+  DCHECK_NE(handle, ::GetCurrentProcess());
+  ProcessHandle out_handle;
+  if (!::DuplicateHandle(GetCurrentProcess(), handle,
+                         GetCurrentProcess(), &out_handle,
+                         0, FALSE, DUPLICATE_SAME_ACCESS)) {
+    return Process();
+  }
+  return Process(out_handle);
+}
+
+// static
+bool Process::CanBackgroundProcesses() {
+  return true;
+}
+
+bool Process::IsValid() const {
+  return process_.IsValid() || is_current();
+}
+
+ProcessHandle Process::Handle() const {
+  return is_current_process_ ? GetCurrentProcess() : process_.Get();
+}
+
+Process Process::Duplicate() const {
+  if (is_current())
+    return Current();
+
+  ProcessHandle out_handle;
+  if (!IsValid() || !::DuplicateHandle(GetCurrentProcess(),
+                                       Handle(),
+                                       GetCurrentProcess(),
+                                       &out_handle,
+                                       0,
+                                       FALSE,
+                                       DUPLICATE_SAME_ACCESS)) {
+    return Process();
+  }
+  return Process(out_handle);
+}
+
+ProcessId Process::Pid() const {
+  DCHECK(IsValid());
+  return GetProcId(Handle());
+}
+
+bool Process::is_current() const {
+  return is_current_process_;
+}
+
+void Process::Close() {
+  is_current_process_ = false;
+  if (!process_.IsValid())
+    return;
+
+  process_.Close();
+}
+
+bool Process::Terminate(int exit_code, bool wait) const {
+  DCHECK(IsValid());
+  bool result = (::TerminateProcess(Handle(), exit_code) != FALSE);
+  if (result && wait) {
+    // The process may not end immediately due to pending I/O
+    if (::WaitForSingleObject(Handle(), 60 * 1000) != WAIT_OBJECT_0)
+      DPLOG(ERROR) << "Error waiting for process exit";
+  } else if (!result) {
+    DPLOG(ERROR) << "Unable to terminate process";
+  }
+  return result;
+}
+
+bool Process::WaitForExit(int* exit_code) {
+  return WaitForExitWithTimeout(TimeDelta::FromMilliseconds(INFINITE),
+                                exit_code);
+}
+
+bool Process::WaitForExitWithTimeout(TimeDelta timeout, int* exit_code) {
+  // Limit timeout to INFINITE.
+  DWORD timeout_ms = saturated_cast<DWORD>(timeout.InMilliseconds());
+  if (::WaitForSingleObject(Handle(), timeout_ms) != WAIT_OBJECT_0)
+    return false;
+
+  DWORD temp_code;  // Don't clobber out-parameters in case of failure.
+  if (!::GetExitCodeProcess(Handle(), &temp_code))
+    return false;
+
+  if (exit_code)
+    *exit_code = temp_code;
+  return true;
+}
+
+bool Process::IsProcessBackgrounded() const {
+  DCHECK(IsValid());
+  DWORD priority = GetPriority();
+  if (priority == 0)
+    return false;  // Failure case.
+  return ((priority == BELOW_NORMAL_PRIORITY_CLASS) ||
+          (priority == IDLE_PRIORITY_CLASS));
+}
+
+bool Process::SetProcessBackgrounded(bool value) {
+  DCHECK(IsValid());
+  // Vista and above introduce a real background mode, which not only
+  // sets the priority class on the threads but also on the IO generated
+  // by it. Unfortunately it can only be set for the calling process.
+  DWORD priority;
+  if ((base::win::GetVersion() >= base::win::VERSION_VISTA) && (is_current())) {
+    priority = value ? PROCESS_MODE_BACKGROUND_BEGIN :
+                       PROCESS_MODE_BACKGROUND_END;
+  } else {
+    // 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);
+}
+
+int Process::GetPriority() const {
+  DCHECK(IsValid());
+  return ::GetPriorityClass(Handle());
+}
+
+}  // namespace base
diff --git a/base/profiler/alternate_timer.cc b/base/profiler/alternate_timer.cc
new file mode 100644
index 0000000..02763cd
--- /dev/null
+++ b/base/profiler/alternate_timer.cc
@@ -0,0 +1,36 @@
+// Copyright (c) 2012 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/profiler/alternate_timer.h"
+
+#include "base/basictypes.h"
+
+namespace {
+
+tracked_objects::NowFunction* g_time_function = NULL;
+tracked_objects::TimeSourceType g_time_source_type =
+    tracked_objects::TIME_SOURCE_TYPE_WALL_TIME;
+
+}  // anonymous namespace
+
+namespace tracked_objects {
+
+const char kAlternateProfilerTime[] = "CHROME_PROFILER_TIME";
+
+// Set an alternate timer function to replace the OS time function when
+// profiling.
+void SetAlternateTimeSource(NowFunction* now_function, TimeSourceType type) {
+  g_time_function = now_function;
+  g_time_source_type = type;
+}
+
+NowFunction* GetAlternateTimeSource() {
+  return g_time_function;
+}
+
+TimeSourceType GetTimeSourceType() {
+  return g_time_source_type;
+}
+
+}  // namespace tracked_objects
diff --git a/base/profiler/alternate_timer.h b/base/profiler/alternate_timer.h
new file mode 100644
index 0000000..fdc75dc
--- /dev/null
+++ b/base/profiler/alternate_timer.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2012 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 is a glue file, which allows third party code to call into our profiler
+// without having to include most any functions from base.
+
+#ifndef BASE_PROFILER_ALTERNATE_TIMER_H_
+#define BASE_PROFILER_ALTERNATE_TIMER_H_
+
+#include "base/base_export.h"
+
+namespace tracked_objects {
+
+enum TimeSourceType {
+  TIME_SOURCE_TYPE_WALL_TIME,
+  TIME_SOURCE_TYPE_TCMALLOC
+};
+
+// Provide type for an alternate timer function.
+typedef unsigned int NowFunction();
+
+// Environment variable name that is used to activate alternate timer profiling
+// (such as using TCMalloc allocations to provide a pseudo-timer) for tasks
+// instead of wall clock profiling.
+BASE_EXPORT extern const char kAlternateProfilerTime[];
+
+// Set an alternate timer function to replace the OS time function when
+// profiling.  Typically this is called by an allocator that is providing a
+// function that indicates how much memory has been allocated on any given
+// thread.
+BASE_EXPORT void SetAlternateTimeSource(NowFunction* now_function,
+                                        TimeSourceType type);
+
+// Gets the pointer to a function that was set via SetAlternateTimeSource().
+// Returns NULL if no set was done prior to calling GetAlternateTimeSource.
+NowFunction* GetAlternateTimeSource();
+
+// Returns the type of the currently set time source.
+BASE_EXPORT TimeSourceType GetTimeSourceType();
+
+}  // namespace tracked_objects
+
+#endif  // BASE_PROFILER_ALTERNATE_TIMER_H_
diff --git a/base/profiler/native_stack_sampler.cc b/base/profiler/native_stack_sampler.cc
new file mode 100644
index 0000000..8b4731b
--- /dev/null
+++ b/base/profiler/native_stack_sampler.cc
@@ -0,0 +1,13 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/profiler/native_stack_sampler.h"
+
+namespace base {
+
+NativeStackSampler::NativeStackSampler() {}
+
+NativeStackSampler::~NativeStackSampler() {}
+
+}  // namespace base
diff --git a/base/profiler/native_stack_sampler.h b/base/profiler/native_stack_sampler.h
new file mode 100644
index 0000000..bc170dc
--- /dev/null
+++ b/base/profiler/native_stack_sampler.h
@@ -0,0 +1,50 @@
+// 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_PROFILER_NATIVE_STACK_SAMPLER_H_
+#define BASE_PROFILER_NATIVE_STACK_SAMPLER_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "base/profiler/stack_sampling_profiler.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+// NativeStackSampler is an implementation detail of StackSamplingProfiler. It
+// abstracts the native implementation required to record a stack sample for a
+// given thread.
+class NativeStackSampler {
+ public:
+  virtual ~NativeStackSampler();
+
+  // Creates a stack sampler that records samples for |thread_handle|. Returns
+  // null if this platform does not support stack sampling.
+  static scoped_ptr<NativeStackSampler> Create(PlatformThreadId thread_id);
+
+  // The following functions are all called on the SamplingThread (not the
+  // thread being sampled).
+
+  // Notifies the sampler that we're starting to record a new profile. Modules
+  // shared across samples in the profile should be recorded in |modules|.
+  virtual void ProfileRecordingStarting(
+      std::vector<StackSamplingProfiler::Module>* modules) = 0;
+
+  // Records a stack sample to |sample|.
+  virtual void RecordStackSample(StackSamplingProfiler::Sample* sample) = 0;
+
+  // Notifies the sampler that we've stopped recording the current
+  // profile.
+  virtual void ProfileRecordingStopped() = 0;
+
+ protected:
+  NativeStackSampler();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NativeStackSampler);
+};
+
+}  // namespace base
+
+#endif  // BASE_PROFILER_NATIVE_STACK_SAMPLER_H_
+
diff --git a/base/profiler/scoped_profile.cc b/base/profiler/scoped_profile.cc
new file mode 100644
index 0000000..f06a8c6
--- /dev/null
+++ b/base/profiler/scoped_profile.cc
@@ -0,0 +1,34 @@
+// Copyright (c) 2011 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/profiler/scoped_profile.h"
+
+#include "base/location.h"
+#include "base/tracked_objects.h"
+
+
+namespace tracked_objects {
+
+
+ScopedProfile::ScopedProfile(const Location& location, Mode mode)
+    : birth_(NULL) {
+  if (mode == DISABLED)
+    return;
+
+  birth_ = ThreadData::TallyABirthIfActive(location);
+  if (!birth_)
+    return;
+
+  stopwatch_.Start();
+}
+
+ScopedProfile::~ScopedProfile() {
+  if (!birth_)
+    return;
+
+  stopwatch_.Stop();
+  ThreadData::TallyRunInAScopedRegionIfTracking(birth_, stopwatch_);
+}
+
+}  // namespace tracked_objects
diff --git a/base/profiler/scoped_profile.h b/base/profiler/scoped_profile.h
new file mode 100644
index 0000000..2c4105d
--- /dev/null
+++ b/base/profiler/scoped_profile.h
@@ -0,0 +1,65 @@
+// Copyright (c) 2011 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_PROFILER_SCOPED_PROFILE_H_
+#define BASE_PROFILER_SCOPED_PROFILE_H_
+
+//------------------------------------------------------------------------------
+// ScopedProfile provides basic helper functions for profiling a short
+// region of code within a scope.  It is separate from the related ThreadData
+// class so that it can be included without much other cruft, and provide the
+// macros listed below.
+
+#include "base/base_export.h"
+#include "base/location.h"
+#include "base/profiler/tracked_time.h"
+#include "base/tracked_objects.h"
+
+#define PASTE_LINE_NUMBER_ON_NAME(name, line) name##line
+
+#define LINE_BASED_VARIABLE_NAME_FOR_PROFILING                                 \
+    PASTE_LINE_NUMBER_ON_NAME(some_profiler_variable_, __LINE__)
+
+// Defines the containing scope as a profiled region. This allows developers to
+// profile their code and see results on their about:profiler page, as well as
+// on the UMA dashboard.
+#define TRACK_RUN_IN_THIS_SCOPED_REGION(dispatch_function_name)            \
+  ::tracked_objects::ScopedProfile LINE_BASED_VARIABLE_NAME_FOR_PROFILING( \
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(#dispatch_function_name),           \
+      ::tracked_objects::ScopedProfile::ENABLED)
+
+// Same as TRACK_RUN_IN_THIS_SCOPED_REGION except that there's an extra param
+// which is concatenated with the function name for better filtering.
+#define TRACK_SCOPED_REGION(category_name, dispatch_function_name)         \
+  ::tracked_objects::ScopedProfile LINE_BASED_VARIABLE_NAME_FOR_PROFILING( \
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(                                    \
+          "[" category_name "]" dispatch_function_name),                   \
+      ::tracked_objects::ScopedProfile::ENABLED)
+
+namespace tracked_objects {
+class Births;
+
+class BASE_EXPORT ScopedProfile {
+ public:
+  // Mode of operation. Specifies whether ScopedProfile should be a no-op or
+  // needs to create and tally a task.
+  enum Mode {
+    DISABLED,  // Do nothing.
+    ENABLED    // Create and tally a task.
+  };
+
+  ScopedProfile(const Location& location, Mode mode);
+  ~ScopedProfile();
+
+ private:
+  Births* birth_;  // Place in code where tracking started.
+  TaskStopwatch stopwatch_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedProfile);
+};
+
+}  // namespace tracked_objects
+
+#endif  // BASE_PROFILER_SCOPED_PROFILE_H_
diff --git a/base/profiler/scoped_tracker.cc b/base/profiler/scoped_tracker.cc
new file mode 100644
index 0000000..d15b7de
--- /dev/null
+++ b/base/profiler/scoped_tracker.cc
@@ -0,0 +1,26 @@
+// 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.
+
+#include "base/profiler/scoped_tracker.h"
+
+#include "base/bind.h"
+
+namespace tracked_objects {
+
+namespace {
+
+ScopedProfile::Mode g_scoped_profile_mode = ScopedProfile::DISABLED;
+
+}  // namespace
+
+// static
+void ScopedTracker::Enable() {
+  g_scoped_profile_mode = ScopedProfile::ENABLED;
+}
+
+ScopedTracker::ScopedTracker(const Location& location)
+    : scoped_profile_(location, g_scoped_profile_mode) {
+}
+
+}  // namespace tracked_objects
diff --git a/base/profiler/scoped_tracker.h b/base/profiler/scoped_tracker.h
new file mode 100644
index 0000000..23e2f07
--- /dev/null
+++ b/base/profiler/scoped_tracker.h
@@ -0,0 +1,76 @@
+// 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.
+
+#ifndef BASE_PROFILER_SCOPED_TRACKER_H_
+#define BASE_PROFILER_SCOPED_TRACKER_H_
+
+//------------------------------------------------------------------------------
+// Utilities for temporarily instrumenting code to dig into issues that were
+// found using profiler data.
+
+#include "base/base_export.h"
+#include "base/bind.h"
+#include "base/callback_forward.h"
+#include "base/location.h"
+#include "base/profiler/scoped_profile.h"
+
+namespace tracked_objects {
+
+// ScopedTracker instruments a region within the code if the instrumentation is
+// enabled. It can be used, for example, to find out if a source of jankiness is
+// inside the instrumented code region.
+// Details:
+// 1. This class creates a task (like ones created by PostTask calls or IPC
+// message handlers). This task can be seen in chrome://profiler and is sent as
+// a part of profiler data to the UMA server. See profiler_event.proto.
+// 2. That task's lifetime is same as the lifetime of the ScopedTracker
+// instance.
+// 3. The execution time associated with the task is the wallclock time between
+// its constructor and destructor, minus wallclock times of directly nested
+// tasks.
+// 4. Task creation that this class utilizes is highly optimized.
+// 5. The class doesn't create a task unless this was enabled for the current
+// process. Search for ScopedTracker::Enable for the current list of processes
+// and channels where it's activated.
+// 6. The class is designed for temporarily instrumenting code to find
+// performance problems, after which the instrumentation must be removed.
+class BASE_EXPORT ScopedTracker {
+ public:
+  ScopedTracker(const Location& location);
+
+  // Enables instrumentation for the remainder of the current process' life. If
+  // this function is not called, all profiler instrumentations are no-ops.
+  static void Enable();
+
+  // Augments a |callback| with provided |location|. This is useful for
+  // instrumenting cases when we know that a jank is in a callback and there are
+  // many possible callbacks, but they come from a relatively small number of
+  // places. We can instrument these few places and at least know which one
+  // passes the janky callback.
+  template <typename P1>
+  static base::Callback<void(P1)> TrackCallback(
+      const Location& location,
+      const base::Callback<void(P1)>& callback) {
+    return base::Bind(&ScopedTracker::ExecuteAndTrackCallback<P1>, location,
+                      callback);
+  }
+
+ private:
+  // Executes |callback|, augmenting it with provided |location|.
+  template <typename P1>
+  static void ExecuteAndTrackCallback(const Location& location,
+                                      const base::Callback<void(P1)>& callback,
+                                      P1 p1) {
+    ScopedTracker tracking_profile(location);
+    callback.Run(p1);
+  }
+
+  const ScopedProfile scoped_profile_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedTracker);
+};
+
+}  // namespace tracked_objects
+
+#endif  // BASE_PROFILER_SCOPED_TRACKER_H_
diff --git a/base/profiler/stack_sampling_profiler.cc b/base/profiler/stack_sampling_profiler.cc
new file mode 100644
index 0000000..9da6628
--- /dev/null
+++ b/base/profiler/stack_sampling_profiler.cc
@@ -0,0 +1,311 @@
+// 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/profiler/stack_sampling_profiler.h"
+
+#include <algorithm>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/memory/singleton.h"
+#include "base/profiler/native_stack_sampler.h"
+#include "base/synchronization/lock.h"
+#include "base/timer/elapsed_timer.h"
+
+namespace base {
+
+// DefaultProfileProcessor ----------------------------------------------------
+
+namespace {
+
+// Singleton class responsible for providing the default processing for profiles
+// (i.e. for profiles generated by profilers without their own completed
+// callback).
+class DefaultProfileProcessor {
+ public:
+  using CompletedCallback = StackSamplingProfiler::CompletedCallback;
+
+  ~DefaultProfileProcessor();
+
+  static DefaultProfileProcessor* GetInstance();
+
+  // Sets the callback to use for processing profiles captured without a
+  // per-profiler completed callback. Pending completed profiles are stored in
+  // this object until a non-null callback is provided here. This function is
+  // thread-safe.
+  void SetCompletedCallback(CompletedCallback callback);
+
+  // Processes |profiles|. This function is thread safe.
+  void ProcessProfiles(
+      const StackSamplingProfiler::CallStackProfiles& profiles);
+
+ private:
+  friend struct DefaultSingletonTraits<DefaultProfileProcessor>;
+
+  DefaultProfileProcessor();
+
+  // Copies the pending profiles from |profiles_| into |profiles|, and clears
+  // |profiles_|. This function may be called on any thread.
+  void GetAndClearPendingProfiles(
+      StackSamplingProfiler::CallStackProfiles* profiles);
+
+  // Gets the current completed callback, with proper locking.
+  CompletedCallback GetCompletedCallback() const;
+
+  mutable Lock callback_lock_;
+  CompletedCallback default_completed_callback_;
+
+  Lock profiles_lock_;
+  StackSamplingProfiler::CallStackProfiles profiles_;
+
+  DISALLOW_COPY_AND_ASSIGN(DefaultProfileProcessor);
+};
+
+DefaultProfileProcessor::~DefaultProfileProcessor() {}
+
+// static
+DefaultProfileProcessor* DefaultProfileProcessor::GetInstance() {
+  return Singleton<DefaultProfileProcessor>::get();
+}
+
+void DefaultProfileProcessor::SetCompletedCallback(CompletedCallback callback) {
+  {
+    AutoLock scoped_lock(callback_lock_);
+    default_completed_callback_ = callback;
+  }
+
+  if (!callback.is_null()) {
+    // Provide any pending profiles to the callback immediately.
+    StackSamplingProfiler::CallStackProfiles profiles;
+    GetAndClearPendingProfiles(&profiles);
+    if (!profiles.empty())
+      callback.Run(profiles);
+  }
+}
+
+void DefaultProfileProcessor::ProcessProfiles(
+    const StackSamplingProfiler::CallStackProfiles& profiles) {
+  CompletedCallback callback = GetCompletedCallback();
+
+  // Store pending profiles if we don't have a valid callback.
+  if (!callback.is_null()) {
+    callback.Run(profiles);
+  } else {
+    AutoLock scoped_lock(profiles_lock_);
+    profiles_.insert(profiles_.end(), profiles.begin(), profiles.end());
+  }
+}
+
+DefaultProfileProcessor::DefaultProfileProcessor() {}
+
+void DefaultProfileProcessor::GetAndClearPendingProfiles(
+    StackSamplingProfiler::CallStackProfiles* profiles) {
+  profiles->clear();
+
+  AutoLock scoped_lock(profiles_lock_);
+  profiles_.swap(*profiles);
+}
+
+DefaultProfileProcessor::CompletedCallback
+DefaultProfileProcessor::GetCompletedCallback() const {
+  AutoLock scoped_lock(callback_lock_);
+  return default_completed_callback_;
+}
+
+}  // namespace
+
+// StackSamplingProfiler::Module ----------------------------------------------
+
+StackSamplingProfiler::Module::Module() : base_address(nullptr) {}
+StackSamplingProfiler::Module::Module(const void* base_address,
+                                      const std::string& id,
+                                      const FilePath& filename)
+    : base_address(base_address), id(id), filename(filename) {}
+
+StackSamplingProfiler::Module::~Module() {}
+
+// StackSamplingProfiler::Frame -----------------------------------------------
+
+StackSamplingProfiler::Frame::Frame(const void* instruction_pointer,
+                                    size_t module_index)
+    : instruction_pointer(instruction_pointer),
+      module_index(module_index) {}
+
+StackSamplingProfiler::Frame::~Frame() {}
+
+// StackSamplingProfiler::CallStackProfile ------------------------------------
+
+StackSamplingProfiler::CallStackProfile::CallStackProfile()
+    : preserve_sample_ordering(false), user_data(0) {}
+
+StackSamplingProfiler::CallStackProfile::~CallStackProfile() {}
+
+// StackSamplingProfiler::SamplingThread --------------------------------------
+
+StackSamplingProfiler::SamplingThread::SamplingThread(
+    scoped_ptr<NativeStackSampler> native_sampler,
+    const SamplingParams& params,
+    CompletedCallback completed_callback)
+    : native_sampler_(native_sampler.Pass()),
+      params_(params),
+      stop_event_(false, false),
+      completed_callback_(completed_callback) {
+}
+
+StackSamplingProfiler::SamplingThread::~SamplingThread() {}
+
+void StackSamplingProfiler::SamplingThread::ThreadMain() {
+  PlatformThread::SetName("Chrome_SamplingProfilerThread");
+
+  CallStackProfiles profiles;
+  CollectProfiles(&profiles);
+  completed_callback_.Run(profiles);
+}
+
+// Depending on how long the sampling takes and the length of the sampling
+// interval, a burst of samples could take arbitrarily longer than
+// samples_per_burst * sampling_interval. In this case, we (somewhat
+// arbitrarily) honor the number of samples requested rather than strictly
+// adhering to the sampling intervals. Once we have established users for the
+// StackSamplingProfiler and the collected data to judge, we may go the other
+// way or make this behavior configurable.
+bool StackSamplingProfiler::SamplingThread::CollectProfile(
+    CallStackProfile* profile,
+    TimeDelta* elapsed_time) {
+  ElapsedTimer profile_timer;
+  CallStackProfile current_profile;
+  native_sampler_->ProfileRecordingStarting(&current_profile.modules);
+  current_profile.sampling_period = params_.sampling_interval;
+  bool burst_completed = true;
+  TimeDelta previous_elapsed_sample_time;
+  for (int i = 0; i < params_.samples_per_burst; ++i) {
+    if (i != 0) {
+      // Always wait, even if for 0 seconds, so we can observe a signal on
+      // stop_event_.
+      if (stop_event_.TimedWait(
+              std::max(params_.sampling_interval - previous_elapsed_sample_time,
+                       TimeDelta()))) {
+        burst_completed = false;
+        break;
+      }
+    }
+    ElapsedTimer sample_timer;
+    current_profile.samples.push_back(Sample());
+    native_sampler_->RecordStackSample(&current_profile.samples.back());
+    previous_elapsed_sample_time = sample_timer.Elapsed();
+  }
+
+  *elapsed_time = profile_timer.Elapsed();
+  current_profile.profile_duration = *elapsed_time;
+  current_profile.preserve_sample_ordering = params_.preserve_sample_ordering;
+  current_profile.user_data = params_.user_data;
+  native_sampler_->ProfileRecordingStopped();
+
+  if (burst_completed)
+    *profile = current_profile;
+
+  return burst_completed;
+}
+
+// In an analogous manner to CollectProfile() and samples exceeding the expected
+// total sampling time, bursts may also exceed the burst_interval. We adopt the
+// same wait-and-see approach here.
+void StackSamplingProfiler::SamplingThread::CollectProfiles(
+    CallStackProfiles* profiles) {
+  if (stop_event_.TimedWait(params_.initial_delay))
+    return;
+
+  TimeDelta previous_elapsed_profile_time;
+  for (int i = 0; i < params_.bursts; ++i) {
+    if (i != 0) {
+      // Always wait, even if for 0 seconds, so we can observe a signal on
+      // stop_event_.
+      if (stop_event_.TimedWait(
+              std::max(params_.burst_interval - previous_elapsed_profile_time,
+                       TimeDelta())))
+        return;
+    }
+
+    CallStackProfile profile;
+    if (!CollectProfile(&profile, &previous_elapsed_profile_time))
+      return;
+    profiles->push_back(profile);
+  }
+}
+
+void StackSamplingProfiler::SamplingThread::Stop() {
+  stop_event_.Signal();
+}
+
+// StackSamplingProfiler ------------------------------------------------------
+
+StackSamplingProfiler::SamplingParams::SamplingParams()
+    : initial_delay(TimeDelta::FromMilliseconds(0)),
+      bursts(1),
+      burst_interval(TimeDelta::FromMilliseconds(10000)),
+      samples_per_burst(300),
+      sampling_interval(TimeDelta::FromMilliseconds(100)),
+      preserve_sample_ordering(false),
+      user_data(0) {
+}
+
+StackSamplingProfiler::StackSamplingProfiler(PlatformThreadId thread_id,
+                                             const SamplingParams& params)
+    : thread_id_(thread_id), params_(params) {}
+
+StackSamplingProfiler::StackSamplingProfiler(PlatformThreadId thread_id,
+                                             const SamplingParams& params,
+                                             CompletedCallback callback)
+    : thread_id_(thread_id), params_(params), completed_callback_(callback) {}
+
+StackSamplingProfiler::~StackSamplingProfiler() {
+  Stop();
+  if (!sampling_thread_handle_.is_null())
+    PlatformThread::Join(sampling_thread_handle_);
+}
+
+void StackSamplingProfiler::Start() {
+  scoped_ptr<NativeStackSampler> native_sampler =
+      NativeStackSampler::Create(thread_id_);
+  if (!native_sampler)
+    return;
+
+  CompletedCallback callback =
+      !completed_callback_.is_null() ? completed_callback_ :
+      Bind(&DefaultProfileProcessor::ProcessProfiles,
+           Unretained(DefaultProfileProcessor::GetInstance()));
+  sampling_thread_.reset(
+      new SamplingThread(native_sampler.Pass(), params_, callback));
+  if (!PlatformThread::Create(0, sampling_thread_.get(),
+                              &sampling_thread_handle_))
+    sampling_thread_.reset();
+}
+
+void StackSamplingProfiler::Stop() {
+  if (sampling_thread_)
+    sampling_thread_->Stop();
+}
+
+// static
+void StackSamplingProfiler::SetDefaultCompletedCallback(
+    CompletedCallback callback) {
+  DefaultProfileProcessor::GetInstance()->SetCompletedCallback(callback);
+}
+
+// StackSamplingProfiler::Frame global functions ------------------------------
+
+bool operator==(const StackSamplingProfiler::Frame &a,
+                const StackSamplingProfiler::Frame &b) {
+  return a.instruction_pointer == b.instruction_pointer &&
+      a.module_index == b.module_index;
+}
+
+bool operator<(const StackSamplingProfiler::Frame &a,
+               const StackSamplingProfiler::Frame &b) {
+  return (a.module_index < b.module_index) ||
+      (a.module_index == b.module_index &&
+       a.instruction_pointer < b.instruction_pointer);
+}
+
+}  // namespace base
diff --git a/base/profiler/stack_sampling_profiler.h b/base/profiler/stack_sampling_profiler.h
new file mode 100644
index 0000000..9d52f27
--- /dev/null
+++ b/base/profiler/stack_sampling_profiler.h
@@ -0,0 +1,264 @@
+// 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_PROFILER_STACK_SAMPLING_PROFILER_H_
+#define BASE_PROFILER_STACK_SAMPLING_PROFILER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string16.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/platform_thread.h"
+#include "base/time/time.h"
+
+namespace base {
+
+class NativeStackSampler;
+
+// StackSamplingProfiler periodically stops a thread to sample its stack, for
+// the purpose of collecting information about which code paths are
+// executing. This information is used in aggregate by UMA to identify hot
+// and/or janky code paths.
+//
+// Sample StackSamplingProfiler usage:
+//
+//   // Create and customize params as desired.
+//   base::StackStackSamplingProfiler::SamplingParams params;
+//   // Any thread's ID may be passed as the target.
+//   base::StackSamplingProfiler profiler(base::PlatformThread::CurrentId()),
+//       params);
+//
+//   // Or, to process the profiles within Chrome rather than via UMA, use a
+//   // custom completed callback:
+//   base::StackStackSamplingProfiler::CompletedCallback
+//       thread_safe_callback = ...;
+//   base::StackSamplingProfiler profiler(base::PlatformThread::CurrentId()),
+//       params, thread_safe_callback);
+//
+//   profiler.Start();
+//   // ... work being done on the target thread here ...
+//   profiler.Stop();  // optional, stops collection before complete per params
+//
+// The default SamplingParams causes stacks to be recorded in a single burst at
+// a 10Hz interval for a total of 30 seconds. All of these parameters may be
+// altered as desired.
+//
+// When all call stack profiles are complete or the profiler is stopped, if the
+// custom completed callback was set it is called from a thread created by the
+// profiler with the completed profiles. A profile is considered complete if all
+// requested samples were recorded for the profile (i.e. it was not stopped
+// prematurely).  If no callback was set, the default completed callback will be
+// called with the profiles. It is expected that the the default completed
+// callback is set by the metrics system to allow profiles to be provided via
+// UMA.
+//
+// The results of the profiling are passed to the completed callback and consist
+// of a vector of CallStackProfiles. Each CallStackProfile corresponds to a
+// burst as specified in SamplingParams and contains a set of Samples and
+// Modules. One Sample corresponds to a single recorded stack, and the Modules
+// record those modules associated with the recorded stack frames.
+class BASE_EXPORT StackSamplingProfiler {
+ public:
+  // Module represents the module (DLL or exe) corresponding to a stack frame.
+  struct BASE_EXPORT Module {
+    Module();
+    Module(const void* base_address, const std::string& id,
+           const FilePath& filename);
+    ~Module();
+
+    // Points to the base address of the module.
+    const void* base_address;
+
+    // An opaque binary string that uniquely identifies a particular program
+    // version with high probability. This is parsed from headers of the loaded
+    // module.
+    // For binaries generated by GNU tools:
+    //   Contents of the .note.gnu.build-id field.
+    // On Windows:
+    //   GUID + AGE in the debug image headers of a module.
+    std::string id;
+
+    // The filename of the module.
+    FilePath filename;
+  };
+
+  // Frame represents an individual sampled stack frame with module information.
+  struct BASE_EXPORT Frame {
+    // Identifies an unknown module.
+    static const size_t kUnknownModuleIndex = static_cast<size_t>(-1);
+
+    Frame(const void* instruction_pointer, size_t module_index);
+    ~Frame();
+
+    // The sampled instruction pointer within the function.
+    const void* instruction_pointer;
+
+    // Index of the module in CallStackProfile::modules. We don't represent
+    // module state directly here to save space.
+    size_t module_index;
+  };
+
+  // Sample represents a set of stack frames.
+  using Sample = std::vector<Frame>;
+
+  // CallStackProfile represents a set of samples.
+  struct BASE_EXPORT CallStackProfile {
+    CallStackProfile();
+    ~CallStackProfile();
+
+    std::vector<Module> modules;
+    std::vector<Sample> samples;
+
+    // Duration of this profile.
+    TimeDelta profile_duration;
+
+    // Time between samples.
+    TimeDelta sampling_period;
+
+    // True if sample ordering is important and should be preserved if and when
+    // this profile is compressed and processed.
+    bool preserve_sample_ordering;
+
+    // User data associated with this profile.
+    uintptr_t user_data;
+  };
+
+  using CallStackProfiles = std::vector<CallStackProfile>;
+
+  // Represents parameters that configure the sampling.
+  struct BASE_EXPORT SamplingParams {
+    SamplingParams();
+
+    // Time to delay before first samples are taken. Defaults to 0.
+    TimeDelta initial_delay;
+
+    // Number of sampling bursts to perform. Defaults to 1.
+    int bursts;
+
+    // Interval between sampling bursts. This is the desired duration from the
+    // start of one burst to the start of the next burst. Defaults to 10s.
+    TimeDelta burst_interval;
+
+    // Number of samples to record per burst. Defaults to 300.
+    int samples_per_burst;
+
+    // Interval between samples during a sampling burst. This is the desired
+    // duration from the start of one sample to the start of the next
+    // sample. Defaults to 100ms.
+    TimeDelta sampling_interval;
+
+    // True if sample ordering is important and should be preserved if and when
+    // this profile is compressed and processed. Defaults to false.
+    bool preserve_sample_ordering;
+
+    // User data associated with this profile.
+    uintptr_t user_data;
+  };
+
+  // The callback type used to collect completed profiles.
+  //
+  // IMPORTANT NOTE: the callback is invoked on a thread the profiler
+  // constructs, rather than on the thread used to construct the profiler and
+  // set the callback, and thus the callback must be callable on any thread. For
+  // threads with message loops that create StackSamplingProfilers, posting a
+  // task to the message loop with a copy of the profiles is the recommended
+  // thread-safe callback implementation.
+  using CompletedCallback = Callback<void(const CallStackProfiles&)>;
+
+  // Creates a profiler that sends completed profiles to the default completed
+  // callback.
+  StackSamplingProfiler(PlatformThreadId thread_id,
+                        const SamplingParams& params);
+  // Creates a profiler that sends completed profiles to |completed_callback|.
+  StackSamplingProfiler(PlatformThreadId thread_id,
+                        const SamplingParams& params,
+                        CompletedCallback callback);
+  ~StackSamplingProfiler();
+
+  // Initializes the profiler and starts sampling.
+  void Start();
+
+  // Stops the profiler and any ongoing sampling. Calling this function is
+  // optional; if not invoked profiling terminates when all the profiling bursts
+  // specified in the SamplingParams are completed.
+  void Stop();
+
+  // Sets a callback to process profiles collected by profiler instances without
+  // a completed callback. Profiles are queued internally until a non-null
+  // callback is provided to this function,
+  //
+  // The callback is typically called on a thread created by the profiler.  If
+  // completed profiles are queued when set, however, it will also be called
+  // immediately on the calling thread.
+  static void SetDefaultCompletedCallback(CompletedCallback callback);
+
+ private:
+  // SamplingThread is a separate thread used to suspend and sample stacks from
+  // the target thread.
+  class SamplingThread : public PlatformThread::Delegate {
+   public:
+    // Samples stacks using |native_sampler|. When complete, invokes
+    // |completed_callback| with the collected call stack profiles.
+    // |completed_callback| must be callable on any thread.
+    SamplingThread(scoped_ptr<NativeStackSampler> native_sampler,
+                   const SamplingParams& params,
+                   CompletedCallback completed_callback);
+    ~SamplingThread() override;
+
+    // PlatformThread::Delegate:
+    void ThreadMain() override;
+
+    void Stop();
+
+   private:
+    // Collects a call stack profile from a single burst. Returns true if the
+    // profile was collected, or false if collection was stopped before it
+    // completed.
+    bool CollectProfile(CallStackProfile* profile, TimeDelta* elapsed_time);
+
+    // Collects call stack profiles from all bursts, or until the sampling is
+    // stopped. If stopped before complete, |call_stack_profiles| will contain
+    // only full bursts.
+    void CollectProfiles(CallStackProfiles* profiles);
+
+    scoped_ptr<NativeStackSampler> native_sampler_;
+    const SamplingParams params_;
+
+    // If Stop() is called, it signals this event to force the sampling to
+    // terminate before all the samples specified in |params_| are collected.
+    WaitableEvent stop_event_;
+
+    const CompletedCallback completed_callback_;
+
+    DISALLOW_COPY_AND_ASSIGN(SamplingThread);
+  };
+
+  // The thread whose stack will be sampled.
+  PlatformThreadId thread_id_;
+
+  const SamplingParams params_;
+
+  scoped_ptr<SamplingThread> sampling_thread_;
+  PlatformThreadHandle sampling_thread_handle_;
+
+  const CompletedCallback completed_callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(StackSamplingProfiler);
+};
+
+// The metrics provider code wants to put Samples in a map and compare them,
+// which requires us to define a few operators.
+BASE_EXPORT bool operator==(const StackSamplingProfiler::Frame& a,
+                            const StackSamplingProfiler::Frame& b);
+BASE_EXPORT bool operator<(const StackSamplingProfiler::Frame& a,
+                           const StackSamplingProfiler::Frame& b);
+
+}  // namespace base
+
+#endif  // BASE_PROFILER_STACK_SAMPLING_PROFILER_H_
diff --git a/base/profiler/stack_sampling_profiler_posix.cc b/base/profiler/stack_sampling_profiler_posix.cc
new file mode 100644
index 0000000..bce37e1
--- /dev/null
+++ b/base/profiler/stack_sampling_profiler_posix.cc
@@ -0,0 +1,14 @@
+// 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/profiler/native_stack_sampler.h"
+
+namespace base {
+
+scoped_ptr<NativeStackSampler> NativeStackSampler::Create(
+    PlatformThreadId thread_id) {
+  return scoped_ptr<NativeStackSampler>();
+}
+
+}  // namespace base
diff --git a/base/profiler/stack_sampling_profiler_unittest.cc b/base/profiler/stack_sampling_profiler_unittest.cc
new file mode 100644
index 0000000..5ade15a
--- /dev/null
+++ b/base/profiler/stack_sampling_profiler_unittest.cc
@@ -0,0 +1,445 @@
+// 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/bind.h"
+#include "base/compiler_specific.h"
+#include "base/path_service.h"
+#include "base/profiler/stack_sampling_profiler.h"
+#include "base/strings/stringprintf.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/platform_thread.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+using SamplingParams = StackSamplingProfiler::SamplingParams;
+using Frame = StackSamplingProfiler::Frame;
+using Module = StackSamplingProfiler::Module;
+using Sample = StackSamplingProfiler::Sample;
+using CallStackProfile = StackSamplingProfiler::CallStackProfile;
+using CallStackProfiles = StackSamplingProfiler::CallStackProfiles;
+
+namespace {
+
+// A thread to target for profiling, whose stack is guaranteed to contain
+// SignalAndWaitUntilSignaled() when coordinated with the main thread.
+class TargetThread : public PlatformThread::Delegate {
+ public:
+  TargetThread();
+
+  // PlatformThread::Delegate:
+  void ThreadMain() override;
+
+  // Waits for the thread to have started and be executing in
+  // SignalAndWaitUntilSignaled().
+  void WaitForThreadStart();
+
+  // Allows the thread to return from SignalAndWaitUntilSignaled() and finish
+  // execution.
+  void SignalThreadToFinish();
+
+  // This function is guaranteed to be executing between calls to
+  // WaitForThreadStart() and SignalThreadToFinish(). This function is static so
+  // that we can get a straightforward address for it in one of the tests below,
+  // rather than dealing with the complexity of a member function pointer
+  // representation.
+  static void SignalAndWaitUntilSignaled(WaitableEvent* thread_started_event,
+                                         WaitableEvent* finish_event);
+
+  PlatformThreadId id() const { return id_; }
+
+ private:
+  WaitableEvent thread_started_event_;
+  WaitableEvent finish_event_;
+  PlatformThreadId id_;
+
+  DISALLOW_COPY_AND_ASSIGN(TargetThread);
+};
+
+TargetThread::TargetThread()
+    : thread_started_event_(false, false), finish_event_(false, false),
+      id_(0) {}
+
+void TargetThread::ThreadMain() {
+  id_ = PlatformThread::CurrentId();
+  SignalAndWaitUntilSignaled(&thread_started_event_, &finish_event_);
+}
+
+void TargetThread::WaitForThreadStart() {
+  thread_started_event_.Wait();
+}
+
+void TargetThread::SignalThreadToFinish() {
+  finish_event_.Signal();
+}
+
+// static
+// Disable inlining for this function so that it gets its own stack frame.
+NOINLINE void TargetThread::SignalAndWaitUntilSignaled(
+    WaitableEvent* thread_started_event,
+    WaitableEvent* finish_event) {
+  thread_started_event->Signal();
+  volatile int x = 1;
+  finish_event->Wait();
+  x = 0;  // Prevent tail call to WaitableEvent::Wait().
+  ALLOW_UNUSED_LOCAL(x);
+}
+
+// Called on the profiler thread when complete, to collect profiles.
+void SaveProfiles(CallStackProfiles* profiles,
+                  const CallStackProfiles& pending_profiles) {
+  *profiles = pending_profiles;
+}
+
+// Called on the profiler thread when complete. Collects profiles produced by
+// the profiler, and signals an event to allow the main thread to know that that
+// the profiler is done.
+void SaveProfilesAndSignalEvent(CallStackProfiles* profiles,
+                                WaitableEvent* event,
+                                const CallStackProfiles& pending_profiles) {
+  *profiles = pending_profiles;
+  event->Signal();
+}
+
+// Executes the function with the target thread running and executing within
+// SignalAndWaitUntilSignaled(). Performs all necessary target thread startup
+// and shutdown work before and afterward.
+template <class Function>
+void WithTargetThread(Function function) {
+  TargetThread target_thread;
+  PlatformThreadHandle target_thread_handle;
+  EXPECT_TRUE(PlatformThread::Create(0, &target_thread, &target_thread_handle));
+
+  target_thread.WaitForThreadStart();
+
+  function(target_thread.id());
+
+  target_thread.SignalThreadToFinish();
+
+  PlatformThread::Join(target_thread_handle);
+}
+
+// Captures profiles as specified by |params| on the TargetThread, and returns
+// them in |profiles|. Waits up to |profiler_wait_time| for the profiler to
+// complete.
+void CaptureProfilesWithObjectCallback(const SamplingParams& params,
+                                       CallStackProfiles* profiles,
+                                       TimeDelta profiler_wait_time) {
+  profiles->clear();
+
+  WithTargetThread([&params, profiles, profiler_wait_time](
+      PlatformThreadId target_thread_id) {
+    WaitableEvent sampling_thread_completed(true, false);
+    const StackSamplingProfiler::CompletedCallback callback =
+        Bind(&SaveProfilesAndSignalEvent, Unretained(profiles),
+             Unretained(&sampling_thread_completed));
+    StackSamplingProfiler profiler(target_thread_id, params, callback);
+    profiler.Start();
+    sampling_thread_completed.TimedWait(profiler_wait_time);
+    profiler.Stop();
+    sampling_thread_completed.Wait();
+  });
+}
+
+// Captures profiles as specified by |params| on the TargetThread, and returns
+// them in |profiles|. Uses the default callback rather than a per-object
+// callback.
+void CaptureProfilesWithDefaultCallback(const SamplingParams& params,
+                                        CallStackProfiles* profiles) {
+  profiles->clear();
+
+  WithTargetThread([&params, profiles](PlatformThreadId target_thread_id) {
+    WaitableEvent sampling_thread_completed(false, false);
+    StackSamplingProfiler::SetDefaultCompletedCallback(
+        Bind(&SaveProfilesAndSignalEvent, Unretained(profiles),
+             Unretained(&sampling_thread_completed)));
+
+    StackSamplingProfiler profiler(target_thread_id, params);
+    profiler.Start();
+    sampling_thread_completed.Wait();
+
+    StackSamplingProfiler::SetDefaultCompletedCallback(
+        StackSamplingProfiler::CompletedCallback());
+  });
+}
+
+// Runs the profiler with |params| on the TargetThread, with no default or
+// per-object callback.
+void RunProfilerWithNoCallback(const SamplingParams& params,
+                               TimeDelta profiler_wait_time) {
+  WithTargetThread([&params, profiler_wait_time](
+      PlatformThreadId target_thread_id) {
+    StackSamplingProfiler profiler(target_thread_id, params);
+    profiler.Start();
+    // Since we don't specify a callback, we don't have a synchronization
+    // mechanism with the sampling thread. Just sleep instead.
+    PlatformThread::Sleep(profiler_wait_time);
+    profiler.Stop();
+  });
+}
+
+// If this executable was linked with /INCREMENTAL (the default for non-official
+// debug and release builds on Windows), function addresses do not correspond to
+// function code itself, but instead to instructions in the Incremental Link
+// Table that jump to the functions. Checks for a jump instruction and if
+// present does a little decompilation to find the function's actual starting
+// address.
+const void* MaybeFixupFunctionAddressForILT(const void* function_address) {
+#if defined(_WIN64)
+  const unsigned char* opcode =
+      reinterpret_cast<const unsigned char*>(function_address);
+  if (*opcode == 0xe9) {
+    // This is a relative jump instruction. Assume we're in the ILT and compute
+    // the function start address from the instruction offset.
+    const int32* offset = reinterpret_cast<const int32*>(opcode + 1);
+    const unsigned char* next_instruction =
+        reinterpret_cast<const unsigned char*>(offset + 1);
+    return next_instruction + *offset;
+  }
+#endif
+  return function_address;
+}
+
+// Searches through the frames in |sample|, returning an iterator to the first
+// frame that has an instruction pointer between |function_address| and
+// |function_address| + |size|. Returns sample.end() if no such frames are
+// found.
+Sample::const_iterator FindFirstFrameWithinFunction(
+    const Sample& sample,
+    const void* function_address,
+    int function_size) {
+  function_address = MaybeFixupFunctionAddressForILT(function_address);
+  for (auto it = sample.begin(); it != sample.end(); ++it) {
+    if ((it->instruction_pointer >= function_address) &&
+        (it->instruction_pointer <
+         (static_cast<const unsigned char*>(function_address) + function_size)))
+      return it;
+  }
+  return sample.end();
+}
+
+// Formats a sample into a string that can be output for test diagnostics.
+std::string FormatSampleForDiagnosticOutput(
+    const Sample& sample,
+    const std::vector<Module>& modules) {
+  std::string output;
+  for (const Frame& frame: sample) {
+    output += StringPrintf(
+        "0x%p %s\n", frame.instruction_pointer,
+        modules[frame.module_index].filename.AsUTF8Unsafe().c_str());
+  }
+  return output;
+}
+
+// Returns a duration that is longer than the test timeout. We would use
+// TimeDelta::Max() but https://crbug.com/465948.
+TimeDelta AVeryLongTimeDelta() { return TimeDelta::FromDays(1); }
+
+}  // namespace
+
+
+// The tests below are enabled for Win x64 only, pending implementation of the
+// tested functionality on other platforms/architectures.
+
+// Checks that the basic expected information is present in a sampled call stack
+// profile.
+#if defined(_WIN64)
+#define MAYBE_Basic Basic
+#else
+#define MAYBE_Basic DISABLED_Basic
+#endif
+TEST(StackSamplingProfilerTest, MAYBE_Basic) {
+  SamplingParams params;
+  params.sampling_interval = TimeDelta::FromMilliseconds(0);
+  params.samples_per_burst = 1;
+  params.user_data = 100;
+  params.preserve_sample_ordering = true;
+
+  std::vector<CallStackProfile> profiles;
+  CaptureProfilesWithObjectCallback(params, &profiles, AVeryLongTimeDelta());
+
+  // Check that the profile and samples sizes are correct, and the module
+  // indices are in range.
+  ASSERT_EQ(1u, profiles.size());
+  const CallStackProfile& profile = profiles[0];
+  ASSERT_EQ(1u, profile.samples.size());
+  EXPECT_EQ(params.sampling_interval, profile.sampling_period);
+  const Sample& sample = profile.samples[0];
+  for (const auto& frame : sample) {
+    ASSERT_GE(frame.module_index, 0u);
+    ASSERT_LT(frame.module_index, profile.modules.size());
+  }
+  EXPECT_EQ(100u, profile.user_data);
+  EXPECT_EQ(true, profile.preserve_sample_ordering);
+
+  // Check that the stack contains a frame for
+  // TargetThread::SignalAndWaitUntilSignaled() and that the frame has this
+  // executable's module.
+  //
+  // Since we don't have a good way to know the function size, use 100 bytes as
+  // a reasonable window to locate the instruction pointer.
+  Sample::const_iterator loc = FindFirstFrameWithinFunction(
+      sample,
+      reinterpret_cast<const void*>(&TargetThread::SignalAndWaitUntilSignaled),
+      100);
+  ASSERT_TRUE(loc != sample.end())
+      << "Function at "
+      << MaybeFixupFunctionAddressForILT(
+          reinterpret_cast<const void*>(
+              &TargetThread::SignalAndWaitUntilSignaled))
+      << " was not found in stack:\n"
+      << FormatSampleForDiagnosticOutput(sample, profile.modules);
+  FilePath executable_path;
+  EXPECT_TRUE(PathService::Get(FILE_EXE, &executable_path));
+  EXPECT_EQ(executable_path, profile.modules[loc->module_index].filename);
+}
+
+// Checks that the expected number of profiles and samples are present in the
+// call stack profiles produced.
+#if defined(_WIN64)
+#define MAYBE_MultipleProfilesAndSamples MultipleProfilesAndSamples
+#else
+#define MAYBE_MultipleProfilesAndSamples DISABLED_MultipleProfilesAndSamples
+#endif
+TEST(StackSamplingProfilerTest, MAYBE_MultipleProfilesAndSamples) {
+  SamplingParams params;
+  params.burst_interval = params.sampling_interval =
+      TimeDelta::FromMilliseconds(0);
+  params.bursts = 2;
+  params.samples_per_burst = 3;
+
+  std::vector<CallStackProfile> profiles;
+  CaptureProfilesWithObjectCallback(params, &profiles, AVeryLongTimeDelta());
+
+  ASSERT_EQ(2u, profiles.size());
+  EXPECT_EQ(3u, profiles[0].samples.size());
+  EXPECT_EQ(3u, profiles[1].samples.size());
+}
+
+// Checks that no call stack profiles are captured if the profiling is stopped
+// during the initial delay.
+#if defined(_WIN64)
+#define MAYBE_StopDuringInitialDelay StopDuringInitialDelay
+#else
+#define MAYBE_StopDuringInitialDelay DISABLED_StopDuringInitialDelay
+#endif
+TEST(StackSamplingProfilerTest, MAYBE_StopDuringInitialDelay) {
+  SamplingParams params;
+  params.initial_delay = TimeDelta::FromSeconds(60);
+
+  std::vector<CallStackProfile> profiles;
+  CaptureProfilesWithObjectCallback(params, &profiles,
+                                    TimeDelta::FromMilliseconds(0));
+
+  EXPECT_TRUE(profiles.empty());
+}
+
+// Checks that the single completed call stack profile is captured if the
+// profiling is stopped between bursts.
+#if defined(_WIN64)
+#define MAYBE_StopDuringInterBurstInterval StopDuringInterBurstInterval
+#else
+#define MAYBE_StopDuringInterBurstInterval DISABLED_StopDuringInterBurstInterval
+#endif
+TEST(StackSamplingProfilerTest, MAYBE_StopDuringInterBurstInterval) {
+  SamplingParams params;
+  params.sampling_interval = TimeDelta::FromMilliseconds(0);
+  params.burst_interval = TimeDelta::FromSeconds(60);
+  params.bursts = 2;
+  params.samples_per_burst = 1;
+
+  std::vector<CallStackProfile> profiles;
+  CaptureProfilesWithObjectCallback(params, &profiles,
+                                    TimeDelta::FromMilliseconds(50));
+
+  ASSERT_EQ(1u, profiles.size());
+  EXPECT_EQ(1u, profiles[0].samples.size());
+}
+
+// Checks that only completed call stack profiles are captured.
+#if defined(_WIN64)
+#define MAYBE_StopDuringInterSampleInterval StopDuringInterSampleInterval
+#else
+#define MAYBE_StopDuringInterSampleInterval \
+  DISABLED_StopDuringInterSampleInterval
+#endif
+TEST(StackSamplingProfilerTest, MAYBE_StopDuringInterSampleInterval) {
+  SamplingParams params;
+  params.sampling_interval = TimeDelta::FromSeconds(60);
+  params.samples_per_burst = 2;
+
+  std::vector<CallStackProfile> profiles;
+  CaptureProfilesWithObjectCallback(params, &profiles,
+                                    TimeDelta::FromMilliseconds(50));
+
+  EXPECT_TRUE(profiles.empty());
+}
+
+// Checks that profiles are captured via the default completed callback.
+#if defined(_WIN64)
+#define MAYBE_DefaultCallback DefaultCallback
+#else
+#define MAYBE_DefaultCallback DISABLED_DefaultCallback
+#endif
+TEST(StackSamplingProfilerTest, MAYBE_DefaultCallback) {
+  SamplingParams params;
+  params.samples_per_burst = 1;
+
+  CallStackProfiles profiles;
+  CaptureProfilesWithDefaultCallback(params, &profiles);
+
+  EXPECT_EQ(1u, profiles.size());
+  EXPECT_EQ(1u, profiles[0].samples.size());
+}
+
+// Checks that profiles are queued until a default callback is set, then
+// delivered.
+#if defined(_WIN64)
+#define MAYBE_ProfilesQueuedWithNoCallback ProfilesQueuedWithNoCallback
+#else
+#define MAYBE_ProfilesQueuedWithNoCallback DISABLED_ProfilesQueuedWithNoCallback
+#endif
+TEST(StackSamplingProfilerTest, MAYBE_ProfilesQueuedWithNoCallback) {
+  SamplingParams params;
+  params.samples_per_burst = 1;
+
+  RunProfilerWithNoCallback(params, TimeDelta::FromMilliseconds(50));
+
+  CallStackProfiles profiles;
+  // This should immediately call SaveProfiles on this thread.
+  StackSamplingProfiler::SetDefaultCompletedCallback(
+      Bind(&SaveProfiles, Unretained(&profiles)));
+  EXPECT_EQ(1u, profiles.size());
+  EXPECT_EQ(1u, profiles[0].samples.size());
+  StackSamplingProfiler::SetDefaultCompletedCallback(
+      StackSamplingProfiler::CompletedCallback());
+}
+
+// Checks that we can destroy the profiler while profiling.
+#if defined(_WIN64)
+#define MAYBE_DestroyProfilerWhileProfiling DestroyProfilerWhileProfiling
+#else
+#define MAYBE_DestroyProfilerWhileProfiling \
+  DISABLED_DestroyProfilerWhileProfiling
+#endif
+TEST(StackSamplingProfilerTest, MAYBE_DestroyProfilerWhileProfiling) {
+  SamplingParams params;
+  params.sampling_interval = TimeDelta::FromMilliseconds(10);
+
+  CallStackProfiles profiles;
+  WithTargetThread([&params, &profiles](PlatformThreadId target_thread_id) {
+    scoped_ptr<StackSamplingProfiler> profiler;
+    profiler.reset(new StackSamplingProfiler(
+        target_thread_id, params, Bind(&SaveProfiles, Unretained(&profiles))));
+    profiler->Start();
+    profiler.reset();
+
+    // Wait longer than a sample interval to catch any use-after-free actions by
+    // the profiler thread.
+    PlatformThread::Sleep(TimeDelta::FromMilliseconds(50));
+  });
+}
+
+}  // namespace base
diff --git a/base/profiler/stack_sampling_profiler_win.cc b/base/profiler/stack_sampling_profiler_win.cc
new file mode 100644
index 0000000..1ccd134
--- /dev/null
+++ b/base/profiler/stack_sampling_profiler_win.cc
@@ -0,0 +1,357 @@
+// 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 <objbase.h>
+#include <windows.h>
+
+#include <map>
+#include <utility>
+
+#include "base/logging.h"
+#include "base/profiler/native_stack_sampler.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/time/time.h"
+#include "base/win/pe_image.h"
+#include "base/win/scoped_handle.h"
+
+namespace base {
+
+namespace {
+
+// Walks the stack represented by |context| from the current frame downwards,
+// recording the instruction pointers for each frame in |instruction_pointers|.
+int RecordStack(CONTEXT* context,
+                int max_stack_size,
+                const void* instruction_pointers[],
+                bool* last_frame_is_unknown_function) {
+#ifdef _WIN64
+  *last_frame_is_unknown_function = false;
+
+  int i = 0;
+  for (; (i < max_stack_size) && context->Rip; ++i) {
+    // Try to look up unwind metadata for the current function.
+    ULONG64 image_base;
+    PRUNTIME_FUNCTION runtime_function =
+        RtlLookupFunctionEntry(context->Rip, &image_base, nullptr);
+
+    instruction_pointers[i] = reinterpret_cast<const void*>(context->Rip);
+
+    if (runtime_function) {
+      KNONVOLATILE_CONTEXT_POINTERS nvcontext = {0};
+      void* handler_data;
+      ULONG64 establisher_frame;
+      RtlVirtualUnwind(0, image_base, context->Rip, runtime_function, context,
+                       &handler_data, &establisher_frame, &nvcontext);
+    } else {
+      // If we don't have a RUNTIME_FUNCTION, then in theory this should be a
+      // leaf function whose frame contains only a return address, at
+      // RSP. However, crash data also indicates that some third party libraries
+      // do not provide RUNTIME_FUNCTION information for non-leaf functions. We
+      // could manually unwind the stack in the former case, but attempting to
+      // do so in the latter case would produce wrong results and likely crash,
+      // so just bail out.
+      //
+      // Ad hoc runs with instrumentation show that ~5% of stack traces end with
+      // a valid leaf function. To avoid selectively omitting these traces it
+      // makes sense to ultimately try to distinguish these two cases and
+      // selectively unwind the stack for legitimate leaf functions. For the
+      // purposes of avoiding crashes though, just ignore them all for now.
+      return i;
+    }
+  }
+  return i;
+#else
+  return 0;
+#endif
+}
+
+// Fills in |module_handles| corresponding to the pointers to code in
+// |addresses|. The module handles are returned with reference counts
+// incremented and should be freed with FreeModuleHandles. See note in
+// SuspendThreadAndRecordStack for why |addresses| and |module_handles| are
+// arrays.
+void FindModuleHandlesForAddresses(const void* const addresses[],
+                             HMODULE module_handles[], int stack_depth,
+                             bool last_frame_is_unknown_function) {
+  const int module_frames =
+      last_frame_is_unknown_function ? stack_depth - 1 : stack_depth;
+  for (int i = 0; i < module_frames; ++i) {
+    HMODULE module_handle = NULL;
+    if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
+                          reinterpret_cast<LPCTSTR>(addresses[i]),
+                          &module_handle)) {
+      // HMODULE actually represents the base address of the module, so we can
+      // use it directly as an address.
+      DCHECK_LE(reinterpret_cast<const void*>(module_handle), addresses[i]);
+      module_handles[i] = module_handle;
+    }
+  }
+}
+
+// Frees the modules handles returned by FindModuleHandlesForAddresses. See note
+// in SuspendThreadAndRecordStack for why |module_handles| is an array.
+void FreeModuleHandles(int stack_depth, HMODULE module_handles[]) {
+  for (int i = 0; i < stack_depth; ++i) {
+    if (module_handles[i])
+      ::FreeLibrary(module_handles[i]);
+  }
+}
+
+// Gets the unique build ID for a module. Windows build IDs are created by a
+// concatenation of a GUID and AGE fields found in the headers of a module. The
+// GUID is stored in the first 16 bytes and the AGE is stored in the last 4
+// bytes. Returns the empty string if the function fails to get the build ID.
+//
+// Example:
+// dumpbin chrome.exe /headers | find "Format:"
+//   ... Format: RSDS, {16B2A428-1DED-442E-9A36-FCE8CBD29726}, 10, ...
+//
+// The resulting buildID string of this instance of chrome.exe is
+// "16B2A4281DED442E9A36FCE8CBD2972610".
+//
+// Note that the AGE field is encoded in decimal, not hex.
+std::string GetBuildIDForModule(HMODULE module_handle) {
+  GUID guid;
+  DWORD age;
+  win::PEImage(module_handle).GetDebugId(&guid, &age);
+  const int kGUIDSize = 39;
+  std::wstring build_id;
+  int result =
+      ::StringFromGUID2(guid, WriteInto(&build_id, kGUIDSize), kGUIDSize);
+  if (result != kGUIDSize)
+    return std::string();
+  RemoveChars(build_id, L"{}-", &build_id);
+  build_id += StringPrintf(L"%d", age);
+  return WideToUTF8(build_id);
+}
+
+// Disables priority boost on a thread for the lifetime of the object.
+class ScopedDisablePriorityBoost {
+ public:
+  ScopedDisablePriorityBoost(HANDLE thread_handle);
+  ~ScopedDisablePriorityBoost();
+
+ private:
+  HANDLE thread_handle_;
+  BOOL got_previous_boost_state_;
+  BOOL boost_state_was_disabled_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedDisablePriorityBoost);
+};
+
+ScopedDisablePriorityBoost::ScopedDisablePriorityBoost(HANDLE thread_handle)
+    : thread_handle_(thread_handle),
+      got_previous_boost_state_(false),
+      boost_state_was_disabled_(false) {
+  got_previous_boost_state_ =
+      ::GetThreadPriorityBoost(thread_handle_, &boost_state_was_disabled_);
+  if (got_previous_boost_state_) {
+    // Confusingly, TRUE disables priority boost.
+    ::SetThreadPriorityBoost(thread_handle_, TRUE);
+  }
+}
+
+ScopedDisablePriorityBoost::~ScopedDisablePriorityBoost() {
+  if (got_previous_boost_state_)
+    ::SetThreadPriorityBoost(thread_handle_, boost_state_was_disabled_);
+}
+
+// Suspends the thread with |thread_handle|, records the stack into
+// |instruction_pointers|, then resumes the thread. Returns the size of the
+// stack.
+//
+// IMPORTANT NOTE: No heap allocations may occur between SuspendThread and
+// ResumeThread. Otherwise this code can deadlock on heap locks acquired by the
+// target thread before it was suspended. This is why we pass instruction
+// pointers and module handles as preallocated arrays rather than vectors, since
+// vectors make it too easy to subtly allocate memory.
+int SuspendThreadAndRecordStack(HANDLE thread_handle, int max_stack_size,
+                                const void* instruction_pointers[],
+                                bool* last_frame_is_unknown_function) {
+  if (::SuspendThread(thread_handle) == -1)
+    return 0;
+
+  int stack_depth = 0;
+  CONTEXT thread_context = {0};
+  thread_context.ContextFlags = CONTEXT_FULL;
+  if (::GetThreadContext(thread_handle, &thread_context)) {
+    stack_depth = RecordStack(&thread_context, max_stack_size,
+                              instruction_pointers,
+                              last_frame_is_unknown_function);
+  }
+
+  // Disable the priority boost that the thread would otherwise receive on
+  // resume. We do this to avoid artificially altering the dynamics of the
+  // executing application any more than we already are by suspending and
+  // resuming the thread.
+  //
+  // Note that this can racily disable a priority boost that otherwise would
+  // have been given to the thread, if the thread is waiting on other wait
+  // conditions at the time of SuspendThread and those conditions are satisfied
+  // before priority boost is reenabled. The measured length of this window is
+  // ~100us, so this should occur fairly rarely.
+  ScopedDisablePriorityBoost disable_priority_boost(thread_handle);
+  bool resume_thread_succeeded = ::ResumeThread(thread_handle) != -1;
+  CHECK(resume_thread_succeeded) << "ResumeThread failed: " << GetLastError();
+
+  return stack_depth;
+}
+
+class NativeStackSamplerWin : public NativeStackSampler {
+ public:
+  explicit NativeStackSamplerWin(win::ScopedHandle thread_handle);
+  ~NativeStackSamplerWin() override;
+
+  // StackSamplingProfiler::NativeStackSampler:
+  void ProfileRecordingStarting(
+      std::vector<StackSamplingProfiler::Module>* modules) override;
+  void RecordStackSample(StackSamplingProfiler::Sample* sample) override;
+  void ProfileRecordingStopped() override;
+
+ private:
+  // Attempts to query the module filename, base address, and id for
+  // |module_handle|, and store them in |module|. Returns true if it succeeded.
+  static bool GetModuleForHandle(HMODULE module_handle,
+                                 StackSamplingProfiler::Module* module);
+
+  // Gets the index for the Module corresponding to |module_handle| in
+  // |modules|, adding it if it's not already present. Returns
+  // StackSamplingProfiler::Frame::kUnknownModuleIndex if no Module can be
+  // determined for |module|.
+  size_t GetModuleIndex(HMODULE module_handle,
+                        std::vector<StackSamplingProfiler::Module>* modules);
+
+  // Copies the stack information represented by |instruction_pointers| into
+  // |sample| and |modules|.
+  void CopyToSample(const void* const instruction_pointers[],
+                    const HMODULE module_handles[],
+                    int stack_depth,
+                    StackSamplingProfiler::Sample* sample,
+                    std::vector<StackSamplingProfiler::Module>* modules);
+
+  win::ScopedHandle thread_handle_;
+  // Weak. Points to the modules associated with the profile being recorded
+  // between ProfileRecordingStarting() and ProfileRecordingStopped().
+  std::vector<StackSamplingProfiler::Module>* current_modules_;
+  // Maps a module handle to the corresponding Module's index within
+  // current_modules_.
+  std::map<HMODULE, size_t> profile_module_index_;
+
+  DISALLOW_COPY_AND_ASSIGN(NativeStackSamplerWin);
+};
+
+NativeStackSamplerWin::NativeStackSamplerWin(win::ScopedHandle thread_handle)
+    : thread_handle_(thread_handle.Take()) {
+}
+
+NativeStackSamplerWin::~NativeStackSamplerWin() {
+}
+
+void NativeStackSamplerWin::ProfileRecordingStarting(
+    std::vector<StackSamplingProfiler::Module>* modules) {
+  current_modules_ = modules;
+  profile_module_index_.clear();
+}
+
+void NativeStackSamplerWin::RecordStackSample(
+    StackSamplingProfiler::Sample* sample) {
+  DCHECK(current_modules_);
+
+  const int max_stack_size = 64;
+  const void* instruction_pointers[max_stack_size] = {0};
+  HMODULE module_handles[max_stack_size] = {0};
+
+  bool last_frame_is_unknown_function = false;
+  int stack_depth = SuspendThreadAndRecordStack(
+      thread_handle_.Get(), max_stack_size, instruction_pointers,
+      &last_frame_is_unknown_function);
+  FindModuleHandlesForAddresses(instruction_pointers, module_handles,
+                                stack_depth, last_frame_is_unknown_function);
+  CopyToSample(instruction_pointers, module_handles, stack_depth, sample,
+               current_modules_);
+  FreeModuleHandles(stack_depth, module_handles);
+}
+
+void NativeStackSamplerWin::ProfileRecordingStopped() {
+  current_modules_ = nullptr;
+}
+
+// static
+bool NativeStackSamplerWin::GetModuleForHandle(
+    HMODULE module_handle,
+    StackSamplingProfiler::Module* module) {
+  wchar_t module_name[MAX_PATH];
+  DWORD result_length =
+      GetModuleFileName(module_handle, module_name, arraysize(module_name));
+  if (result_length == 0)
+    return false;
+
+  module->filename = base::FilePath(module_name);
+
+  module->base_address = reinterpret_cast<const void*>(module_handle);
+
+  module->id = GetBuildIDForModule(module_handle);
+  if (module->id.empty())
+    return false;
+
+  return true;
+}
+
+size_t NativeStackSamplerWin::GetModuleIndex(
+    HMODULE module_handle,
+    std::vector<StackSamplingProfiler::Module>* modules) {
+  if (!module_handle)
+    return StackSamplingProfiler::Frame::kUnknownModuleIndex;
+
+  auto loc = profile_module_index_.find(module_handle);
+  if (loc == profile_module_index_.end()) {
+    StackSamplingProfiler::Module module;
+    if (!GetModuleForHandle(module_handle, &module))
+      return StackSamplingProfiler::Frame::kUnknownModuleIndex;
+    modules->push_back(module);
+    loc = profile_module_index_.insert(std::make_pair(
+        module_handle, modules->size() - 1)).first;
+  }
+
+  return loc->second;
+}
+
+void NativeStackSamplerWin::CopyToSample(
+    const void* const instruction_pointers[],
+    const HMODULE module_handles[],
+    int stack_depth,
+    StackSamplingProfiler::Sample* sample,
+    std::vector<StackSamplingProfiler::Module>* module) {
+  sample->clear();
+  sample->reserve(stack_depth);
+
+  for (int i = 0; i < stack_depth; ++i) {
+    sample->push_back(StackSamplingProfiler::Frame(
+        instruction_pointers[i],
+        GetModuleIndex(module_handles[i], module)));
+  }
+}
+
+}  // namespace
+
+scoped_ptr<NativeStackSampler> NativeStackSampler::Create(
+    PlatformThreadId thread_id) {
+#if _WIN64
+  // Get the thread's handle.
+  HANDLE thread_handle = ::OpenThread(
+      THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME | THREAD_QUERY_INFORMATION,
+      FALSE,
+      thread_id);
+
+  if (thread_handle) {
+    return scoped_ptr<NativeStackSampler>(new NativeStackSamplerWin(
+        win::ScopedHandle(thread_handle)));
+  }
+#endif
+  return scoped_ptr<NativeStackSampler>();
+}
+
+}  // namespace base
diff --git a/base/profiler/tracked_time.cc b/base/profiler/tracked_time.cc
new file mode 100644
index 0000000..e5da68f
--- /dev/null
+++ b/base/profiler/tracked_time.cc
@@ -0,0 +1,67 @@
+// Copyright (c) 2012 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/profiler/tracked_time.h"
+
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <mmsystem.h>  // Declare timeGetTime()... after including build_config.
+#endif
+
+namespace tracked_objects {
+
+Duration::Duration() : ms_(0) {}
+Duration::Duration(int32 duration) : ms_(duration) {}
+
+Duration& Duration::operator+=(const Duration& other) {
+  ms_ += other.ms_;
+  return *this;
+}
+
+Duration Duration::operator+(const Duration& other) const {
+  return Duration(ms_ + other.ms_);
+}
+
+bool Duration::operator==(const Duration& other) const {
+  return ms_ == other.ms_;
+}
+
+bool Duration::operator!=(const Duration& other) const {
+  return ms_ != other.ms_;
+}
+
+bool Duration::operator>(const Duration& other) const {
+  return ms_ > other.ms_;
+}
+
+// static
+Duration Duration::FromMilliseconds(int ms) { return Duration(ms); }
+
+int32 Duration::InMilliseconds() const { return ms_; }
+
+//------------------------------------------------------------------------------
+
+TrackedTime::TrackedTime() : ms_(0) {}
+TrackedTime::TrackedTime(int32 ms) : ms_(ms) {}
+TrackedTime::TrackedTime(const base::TimeTicks& time)
+    : ms_(static_cast<int32>((time - base::TimeTicks()).InMilliseconds())) {
+}
+
+// static
+TrackedTime TrackedTime::Now() {
+  return TrackedTime(base::TimeTicks::Now());
+}
+
+Duration TrackedTime::operator-(const TrackedTime& other) const {
+  return Duration(ms_ - other.ms_);
+}
+
+TrackedTime TrackedTime::operator+(const Duration& other) const {
+  return TrackedTime(ms_ + other.ms_);
+}
+
+bool TrackedTime::is_null() const { return ms_ == 0; }
+
+}  // namespace tracked_objects
diff --git a/base/profiler/tracked_time.h b/base/profiler/tracked_time.h
new file mode 100644
index 0000000..2363274
--- /dev/null
+++ b/base/profiler/tracked_time.h
@@ -0,0 +1,71 @@
+// Copyright (c) 2012 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_PROFILER_TRACKED_TIME_H_
+#define BASE_PROFILER_TRACKED_TIME_H_
+
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/time/time.h"
+
+namespace tracked_objects {
+
+//------------------------------------------------------------------------------
+
+// TimeTicks maintains a wasteful 64 bits of data (we need less than 32), and on
+// windows, a 64 bit timer is expensive to even obtain. We use a simple
+// millisecond counter for most of our time values, as well as millisecond units
+// of duration between those values.  This means we can only handle durations
+// up to 49 days (range), or 24 days (non-negative time durations).
+// We only define enough methods to service the needs of the tracking classes,
+// and our interfaces are modeled after what TimeTicks and TimeDelta use (so we
+// can swap them into place if we want to use the "real" classes).
+
+class BASE_EXPORT Duration {  // Similar to base::TimeDelta.
+ public:
+  Duration();
+
+  Duration& operator+=(const Duration& other);
+  Duration operator+(const Duration& other) const;
+
+  bool operator==(const Duration& other) const;
+  bool operator!=(const Duration& other) const;
+  bool operator>(const Duration& other) const;
+
+  static Duration FromMilliseconds(int ms);
+
+  int32 InMilliseconds() const;
+
+ private:
+  friend class TrackedTime;
+  explicit Duration(int32 duration);
+
+  // Internal time is stored directly in milliseconds.
+  int32 ms_;
+};
+
+class BASE_EXPORT TrackedTime {  // Similar to base::TimeTicks.
+ public:
+  TrackedTime();
+  explicit TrackedTime(const base::TimeTicks& time);
+
+  static TrackedTime Now();
+  Duration operator-(const TrackedTime& other) const;
+  TrackedTime operator+(const Duration& other) const;
+  bool is_null() const;
+
+  static TrackedTime FromMilliseconds(int32 ms) { return TrackedTime(ms); }
+
+ private:
+  friend class Duration;
+  explicit TrackedTime(int32 ms);
+
+  // Internal duration is stored directly in milliseconds.
+  uint32 ms_;
+};
+
+}  // namespace tracked_objects
+
+#endif  // BASE_PROFILER_TRACKED_TIME_H_
diff --git a/base/profiler/tracked_time_unittest.cc b/base/profiler/tracked_time_unittest.cc
new file mode 100644
index 0000000..c105688
--- /dev/null
+++ b/base/profiler/tracked_time_unittest.cc
@@ -0,0 +1,103 @@
+// Copyright (c) 2012 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.
+
+// Test of classes in tracked_time.cc
+
+#include "base/profiler/tracked_time.h"
+#include "base/time/time.h"
+#include "base/tracked_objects.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace tracked_objects {
+
+TEST(TrackedTimeTest, TrackedTimerMilliseconds) {
+  // First make sure we basicallly transfer simple milliseconds values as
+  // expected.  Most critically, things should not become null.
+  int32 kSomeMilliseconds = 243;  // Some example times.
+  int64 kReallyBigMilliseconds = (1LL << 35) + kSomeMilliseconds;
+
+  TrackedTime some = TrackedTime() +
+      Duration::FromMilliseconds(kSomeMilliseconds);
+  EXPECT_EQ(kSomeMilliseconds, (some - TrackedTime()).InMilliseconds());
+  EXPECT_FALSE(some.is_null());
+
+  // Now create a big time, to check that it is wrapped modulo 2^32.
+  base::TimeTicks big = base::TimeTicks() +
+      base::TimeDelta::FromMilliseconds(kReallyBigMilliseconds);
+  EXPECT_EQ(kReallyBigMilliseconds, (big - base::TimeTicks()).InMilliseconds());
+
+  TrackedTime wrapped_big(big);
+  // Expect wrapping at 32 bits.
+  EXPECT_EQ(kSomeMilliseconds, (wrapped_big - TrackedTime()).InMilliseconds());
+}
+
+TEST(TrackedTimeTest, TrackedTimerDuration) {
+  int kFirstMilliseconds = 793;
+  int kSecondMilliseconds = 14889;
+
+  Duration first = Duration::FromMilliseconds(kFirstMilliseconds);
+  Duration second = Duration::FromMilliseconds(kSecondMilliseconds);
+
+  EXPECT_EQ(kFirstMilliseconds, first.InMilliseconds());
+  EXPECT_EQ(kSecondMilliseconds, second.InMilliseconds());
+
+  Duration sum = first + second;
+  EXPECT_EQ(kFirstMilliseconds + kSecondMilliseconds, sum.InMilliseconds());
+}
+
+TEST(TrackedTimeTest, TrackedTimerVsTimeTicks) {
+  // Make sure that our 32 bit timer is aligned with the TimeTicks() timer.
+
+  // First get a 64 bit timer (which should not be null).
+  base::TimeTicks ticks_before = base::TimeTicks::Now();
+  EXPECT_FALSE(ticks_before.is_null());
+
+  // Then get a 32 bit timer that can be be null when it wraps.
+  TrackedTime now = TrackedTime::Now();
+
+  // Then get a bracketing time.
+  base::TimeTicks ticks_after = base::TimeTicks::Now();
+  EXPECT_FALSE(ticks_after.is_null());
+
+  // Now make sure that we bracketed our tracked time nicely.
+  Duration before = now - TrackedTime(ticks_before);
+  EXPECT_LE(0, before.InMilliseconds());
+  Duration after = now - TrackedTime(ticks_after);
+  EXPECT_GE(0, after.InMilliseconds());
+}
+
+TEST(TrackedTimeTest, TrackedTimerDisabled) {
+  // Check to be sure disabling the collection of data induces a null time
+  // (which we know will return much faster).
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::DEACTIVATED);
+  // Since we disabled tracking, we should get a null response.
+  TrackedTime track_now = ThreadData::Now();
+  EXPECT_TRUE(track_now.is_null());
+}
+
+TEST(TrackedTimeTest, TrackedTimerEnabled) {
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+  // Make sure that when we enable tracking, we get a real timer result.
+
+  // First get a 64 bit timer (which should not be null).
+  base::TimeTicks ticks_before = base::TimeTicks::Now();
+  EXPECT_FALSE(ticks_before.is_null());
+
+  // Then get a 32 bit timer that can be null when it wraps.
+  // Crtical difference from  the TrackedTimerVsTimeTicks test, is that we use
+  // ThreadData::Now().  It can sometimes return the null time.
+  TrackedTime now = ThreadData::Now();
+
+  // Then get a bracketing time.
+  base::TimeTicks ticks_after = base::TimeTicks::Now();
+  EXPECT_FALSE(ticks_after.is_null());
+
+  // Now make sure that we bracketed our tracked time nicely.
+  Duration before = now - TrackedTime(ticks_before);
+  EXPECT_LE(0, before.InMilliseconds());
+  Duration after = now - TrackedTime(ticks_after);
+  EXPECT_GE(0, after.InMilliseconds());
+}
+
+}  // namespace tracked_objects
diff --git a/base/rand_util.cc b/base/rand_util.cc
new file mode 100644
index 0000000..931eb4e
--- /dev/null
+++ b/base/rand_util.cc
@@ -0,0 +1,72 @@
+// Copyright (c) 2011 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/rand_util.h"
+
+#include <math.h>
+#include <stdint.h>
+
+#include <algorithm>
+#include <limits>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+
+namespace base {
+
+int RandInt(int min, int max) {
+  DCHECK_LE(min, max);
+
+  uint64 range = static_cast<uint64>(max) - min + 1;
+  int result = min + static_cast<int>(base::RandGenerator(range));
+  DCHECK_GE(result, min);
+  DCHECK_LE(result, max);
+  return result;
+}
+
+double RandDouble() {
+  return BitsToOpenEndedUnitInterval(base::RandUint64());
+}
+
+double BitsToOpenEndedUnitInterval(uint64 bits) {
+  // We try to get maximum precision by masking out as many bits as will fit
+  // in the target type's mantissa, and raising it to an appropriate power to
+  // produce output in the range [0, 1).  For IEEE 754 doubles, the mantissa
+  // is expected to accommodate 53 bits.
+
+  COMPILE_ASSERT(std::numeric_limits<double>::radix == 2, otherwise_use_scalbn);
+  static const int kBits = std::numeric_limits<double>::digits;
+  uint64 random_bits = bits & ((UINT64_C(1) << kBits) - 1);
+  double result = ldexp(static_cast<double>(random_bits), -1 * kBits);
+  DCHECK_GE(result, 0.0);
+  DCHECK_LT(result, 1.0);
+  return result;
+}
+
+uint64 RandGenerator(uint64 range) {
+  DCHECK_GT(range, 0u);
+  // We must discard random results above this number, as they would
+  // make the random generator non-uniform (consider e.g. if
+  // MAX_UINT64 was 7 and |range| was 5, then a result of 1 would be twice
+  // as likely as a result of 3 or 4).
+  uint64 max_acceptable_value =
+      (std::numeric_limits<uint64>::max() / range) * range - 1;
+
+  uint64 value;
+  do {
+    value = base::RandUint64();
+  } while (value > max_acceptable_value);
+
+  return value % range;
+}
+
+std::string RandBytesAsString(size_t length) {
+  DCHECK_GT(length, 0u);
+  std::string result;
+  RandBytes(WriteInto(&result, length + 1), length);
+  return result;
+}
+
+}  // namespace base
diff --git a/base/rand_util.h b/base/rand_util.h
new file mode 100644
index 0000000..6130c12
--- /dev/null
+++ b/base/rand_util.h
@@ -0,0 +1,59 @@
+// Copyright (c) 2012 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_RAND_UTIL_H_
+#define BASE_RAND_UTIL_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+
+// Returns a random number in range [0, kuint64max]. Thread-safe.
+BASE_EXPORT uint64 RandUint64();
+
+// Returns a random number between min and max (inclusive). Thread-safe.
+BASE_EXPORT int RandInt(int min, int max);
+
+// Returns a random number in range [0, range).  Thread-safe.
+//
+// Note that this can be used as an adapter for std::random_shuffle():
+// Given a pre-populated |std::vector<int> myvector|, shuffle it as
+//   std::random_shuffle(myvector.begin(), myvector.end(), base::RandGenerator);
+BASE_EXPORT uint64 RandGenerator(uint64 range);
+
+// Returns a random double in range [0, 1). Thread-safe.
+BASE_EXPORT double RandDouble();
+
+// Given input |bits|, convert with maximum precision to a double in
+// the range [0, 1). Thread-safe.
+BASE_EXPORT double BitsToOpenEndedUnitInterval(uint64 bits);
+
+// Fills |output_length| bytes of |output| with random data.
+//
+// WARNING:
+// Do not use for security-sensitive purposes.
+// See crypto/ for cryptographically secure random number generation APIs.
+BASE_EXPORT void RandBytes(void* output, size_t output_length);
+
+// Fills a string of length |length| with random data and returns it.
+// |length| should be nonzero.
+//
+// Note that this is a variation of |RandBytes| with a different return type.
+// The returned string is likely not ASCII/UTF-8. Use with care.
+//
+// WARNING:
+// Do not use for security-sensitive purposes.
+// See crypto/ for cryptographically secure random number generation APIs.
+BASE_EXPORT std::string RandBytesAsString(size_t length);
+
+#if defined(OS_POSIX)
+BASE_EXPORT int GetUrandomFD();
+#endif
+
+}  // namespace base
+
+#endif  // BASE_RAND_UTIL_H_
diff --git a/base/rand_util_nacl.cc b/base/rand_util_nacl.cc
new file mode 100644
index 0000000..b771dc4
--- /dev/null
+++ b/base/rand_util_nacl.cc
@@ -0,0 +1,41 @@
+// Copyright (c) 2012 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/rand_util.h"
+
+#include <nacl/nacl_random.h>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+namespace {
+
+void GetRandomBytes(void* output, size_t num_bytes) {
+  char* output_ptr = static_cast<char*>(output);
+  while (num_bytes > 0) {
+    size_t nread;
+    const int error = nacl_secure_random(output_ptr, num_bytes, &nread);
+    CHECK_EQ(error, 0);
+    CHECK_LE(nread, num_bytes);
+    output_ptr += nread;
+    num_bytes -= nread;
+  }
+}
+
+}  // namespace
+
+namespace base {
+
+// NOTE: This function must be cryptographically secure. http://crbug.com/140076
+uint64 RandUint64() {
+  uint64 result;
+  GetRandomBytes(&result, sizeof(result));
+  return result;
+}
+
+void RandBytes(void* output, size_t output_length) {
+  GetRandomBytes(output, output_length);
+}
+
+}  // namespace base
diff --git a/base/rand_util_posix.cc b/base/rand_util_posix.cc
new file mode 100644
index 0000000..fe73b96
--- /dev/null
+++ b/base/rand_util_posix.cc
@@ -0,0 +1,59 @@
+// Copyright (c) 2012 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/rand_util.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "base/files/file_util.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+
+namespace {
+
+// We keep the file descriptor for /dev/urandom around so we don't need to
+// reopen it (which is expensive), and since we may not even be able to reopen
+// it if we are later put in a sandbox. This class wraps the file descriptor so
+// we can use LazyInstance to handle opening it on the first access.
+class URandomFd {
+ public:
+  URandomFd() : fd_(open("/dev/urandom", O_RDONLY)) {
+    DCHECK_GE(fd_, 0) << "Cannot open /dev/urandom: " << errno;
+  }
+
+  ~URandomFd() { close(fd_); }
+
+  int fd() const { return fd_; }
+
+ private:
+  const int fd_;
+};
+
+base::LazyInstance<URandomFd>::Leaky g_urandom_fd = LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+namespace base {
+
+// NOTE: This function must be cryptographically secure. http://crbug.com/140076
+uint64 RandUint64() {
+  uint64 number;
+  RandBytes(&number, sizeof(number));
+  return number;
+}
+
+void RandBytes(void* output, size_t output_length) {
+  const int urandom_fd = g_urandom_fd.Pointer()->fd();
+  const bool success =
+      ReadFromFD(urandom_fd, static_cast<char*>(output), output_length);
+  CHECK(success);
+}
+
+int GetUrandomFD(void) {
+  return g_urandom_fd.Pointer()->fd();
+}
+
+}  // namespace base
diff --git a/base/rand_util_unittest.cc b/base/rand_util_unittest.cc
new file mode 100644
index 0000000..90690ec
--- /dev/null
+++ b/base/rand_util_unittest.cc
@@ -0,0 +1,144 @@
+// Copyright (c) 2011 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/rand_util.h"
+
+#include <algorithm>
+#include <limits>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const int kIntMin = std::numeric_limits<int>::min();
+const int kIntMax = std::numeric_limits<int>::max();
+
+}  // namespace
+
+TEST(RandUtilTest, SameMinAndMax) {
+  EXPECT_EQ(base::RandInt(0, 0), 0);
+  EXPECT_EQ(base::RandInt(kIntMin, kIntMin), kIntMin);
+  EXPECT_EQ(base::RandInt(kIntMax, kIntMax), kIntMax);
+}
+
+TEST(RandUtilTest, RandDouble) {
+  // Force 64-bit precision, making sure we're not in a 80-bit FPU register.
+  volatile double number = base::RandDouble();
+  EXPECT_GT(1.0, number);
+  EXPECT_LE(0.0, number);
+}
+
+TEST(RandUtilTest, RandBytes) {
+  const size_t buffer_size = 50;
+  char buffer[buffer_size];
+  memset(buffer, 0, buffer_size);
+  base::RandBytes(buffer, buffer_size);
+  std::sort(buffer, buffer + buffer_size);
+  // Probability of occurrence of less than 25 unique bytes in 50 random bytes
+  // is below 10^-25.
+  EXPECT_GT(std::unique(buffer, buffer + buffer_size) - buffer, 25);
+}
+
+TEST(RandUtilTest, RandBytesAsString) {
+  std::string random_string = base::RandBytesAsString(1);
+  EXPECT_EQ(1U, random_string.size());
+  random_string = base::RandBytesAsString(145);
+  EXPECT_EQ(145U, random_string.size());
+  char accumulator = 0;
+  for (size_t i = 0; i < random_string.size(); ++i)
+    accumulator |= random_string[i];
+  // In theory this test can fail, but it won't before the universe dies of
+  // heat death.
+  EXPECT_NE(0, accumulator);
+}
+
+// Make sure that it is still appropriate to use RandGenerator in conjunction
+// with std::random_shuffle().
+TEST(RandUtilTest, RandGeneratorForRandomShuffle) {
+  EXPECT_EQ(base::RandGenerator(1), 0U);
+  EXPECT_LE(std::numeric_limits<ptrdiff_t>::max(),
+            std::numeric_limits<int64>::max());
+}
+
+TEST(RandUtilTest, RandGeneratorIsUniform) {
+  // Verify that RandGenerator has a uniform distribution. This is a
+  // regression test that consistently failed when RandGenerator was
+  // implemented this way:
+  //
+  //   return base::RandUint64() % max;
+  //
+  // A degenerate case for such an implementation is e.g. a top of
+  // range that is 2/3rds of the way to MAX_UINT64, in which case the
+  // bottom half of the range would be twice as likely to occur as the
+  // top half. A bit of calculus care of jar@ shows that the largest
+  // measurable delta is when the top of the range is 3/4ths of the
+  // way, so that's what we use in the test.
+  const uint64 kTopOfRange = (std::numeric_limits<uint64>::max() / 4ULL) * 3ULL;
+  const uint64 kExpectedAverage = kTopOfRange / 2ULL;
+  const uint64 kAllowedVariance = kExpectedAverage / 50ULL;  // +/- 2%
+  const int kMinAttempts = 1000;
+  const int kMaxAttempts = 1000000;
+
+  double cumulative_average = 0.0;
+  int count = 0;
+  while (count < kMaxAttempts) {
+    uint64 value = base::RandGenerator(kTopOfRange);
+    cumulative_average = (count * cumulative_average + value) / (count + 1);
+
+    // Don't quit too quickly for things to start converging, or we may have
+    // a false positive.
+    if (count > kMinAttempts &&
+        kExpectedAverage - kAllowedVariance < cumulative_average &&
+        cumulative_average < kExpectedAverage + kAllowedVariance) {
+      break;
+    }
+
+    ++count;
+  }
+
+  ASSERT_LT(count, kMaxAttempts) << "Expected average was " <<
+      kExpectedAverage << ", average ended at " << cumulative_average;
+}
+
+TEST(RandUtilTest, RandUint64ProducesBothValuesOfAllBits) {
+  // This tests to see that our underlying random generator is good
+  // enough, for some value of good enough.
+  uint64 kAllZeros = 0ULL;
+  uint64 kAllOnes = ~kAllZeros;
+  uint64 found_ones = kAllZeros;
+  uint64 found_zeros = kAllOnes;
+
+  for (size_t i = 0; i < 1000; ++i) {
+    uint64 value = base::RandUint64();
+    found_ones |= value;
+    found_zeros &= value;
+
+    if (found_zeros == kAllZeros && found_ones == kAllOnes)
+      return;
+  }
+
+  FAIL() << "Didn't achieve all bit values in maximum number of tries.";
+}
+
+// Benchmark test for RandBytes().  Disabled since it's intentionally slow and
+// does not test anything that isn't already tested by the existing RandBytes()
+// tests.
+TEST(RandUtilTest, DISABLED_RandBytesPerf) {
+  // Benchmark the performance of |kTestIterations| of RandBytes() using a
+  // buffer size of |kTestBufferSize|.
+  const int kTestIterations = 10;
+  const size_t kTestBufferSize = 1 * 1024 * 1024;
+
+  scoped_ptr<uint8[]> buffer(new uint8[kTestBufferSize]);
+  const base::TimeTicks now = base::TimeTicks::Now();
+  for (int i = 0; i < kTestIterations; ++i)
+    base::RandBytes(buffer.get(), kTestBufferSize);
+  const base::TimeTicks end = base::TimeTicks::Now();
+
+  LOG(INFO) << "RandBytes(" << kTestBufferSize << ") took: "
+            << (end - now).InMicroseconds() << "µs";
+}
diff --git a/base/rand_util_win.cc b/base/rand_util_win.cc
new file mode 100644
index 0000000..8573b6b
--- /dev/null
+++ b/base/rand_util_win.cc
@@ -0,0 +1,43 @@
+// Copyright (c) 2012 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/rand_util.h"
+
+#include <windows.h>
+
+// #define needed to link in RtlGenRandom(), a.k.a. SystemFunction036.  See the
+// "Community Additions" comment on MSDN here:
+// http://msdn.microsoft.com/en-us/library/windows/desktop/aa387694.aspx
+#define SystemFunction036 NTAPI SystemFunction036
+#include <NTSecAPI.h>
+#undef SystemFunction036
+
+#include <algorithm>
+#include <limits>
+
+#include "base/logging.h"
+
+namespace base {
+
+// NOTE: This function must be cryptographically secure. http://crbug.com/140076
+uint64 RandUint64() {
+  uint64 number;
+  RandBytes(&number, sizeof(number));
+  return number;
+}
+
+void RandBytes(void* output, size_t output_length) {
+  char* output_ptr = static_cast<char*>(output);
+  while (output_length > 0) {
+    const ULONG output_bytes_this_pass = static_cast<ULONG>(std::min(
+        output_length, static_cast<size_t>(std::numeric_limits<ULONG>::max())));
+    const bool success =
+        RtlGenRandom(output_ptr, output_bytes_this_pass) != FALSE;
+    CHECK(success);
+    output_length -= output_bytes_this_pass;
+    output_ptr += output_bytes_this_pass;
+  }
+}
+
+}  // namespace base
diff --git a/base/run_loop.cc b/base/run_loop.cc
new file mode 100644
index 0000000..2aa4def
--- /dev/null
+++ b/base/run_loop.cc
@@ -0,0 +1,106 @@
+// Copyright (c) 2012 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/run_loop.h"
+
+#include "base/bind.h"
+#include "base/tracked_objects.h"
+
+#if defined(OS_WIN)
+#include "base/message_loop/message_pump_dispatcher.h"
+#endif
+
+namespace base {
+
+RunLoop::RunLoop()
+    : loop_(MessageLoop::current()),
+      previous_run_loop_(NULL),
+      run_depth_(0),
+      run_called_(false),
+      quit_called_(false),
+      running_(false),
+      quit_when_idle_received_(false),
+      weak_factory_(this) {
+#if defined(OS_WIN)
+   dispatcher_ = NULL;
+#endif
+}
+
+#if defined(OS_WIN)
+RunLoop::RunLoop(MessagePumpDispatcher* dispatcher)
+    : loop_(MessageLoop::current()),
+      previous_run_loop_(NULL),
+      dispatcher_(dispatcher),
+      run_depth_(0),
+      run_called_(false),
+      quit_called_(false),
+      running_(false),
+      quit_when_idle_received_(false),
+      weak_factory_(this) {
+}
+#endif
+
+RunLoop::~RunLoop() {
+}
+
+void RunLoop::Run() {
+  if (!BeforeRun())
+    return;
+
+  // Use task stopwatch to exclude the loop run time from the current task, if
+  // any.
+  tracked_objects::TaskStopwatch stopwatch;
+  stopwatch.Start();
+  loop_->RunHandler();
+  stopwatch.Stop();
+
+  AfterRun();
+}
+
+void RunLoop::RunUntilIdle() {
+  quit_when_idle_received_ = true;
+  Run();
+}
+
+void RunLoop::Quit() {
+  quit_called_ = true;
+  if (running_ && loop_->run_loop_ == this) {
+    // This is the inner-most RunLoop, so quit now.
+    loop_->QuitNow();
+  }
+}
+
+base::Closure RunLoop::QuitClosure() {
+  return base::Bind(&RunLoop::Quit, weak_factory_.GetWeakPtr());
+}
+
+bool RunLoop::BeforeRun() {
+  DCHECK(!run_called_);
+  run_called_ = true;
+
+  // Allow Quit to be called before Run.
+  if (quit_called_)
+    return false;
+
+  // Push RunLoop stack:
+  previous_run_loop_ = loop_->run_loop_;
+  run_depth_ = previous_run_loop_? previous_run_loop_->run_depth_ + 1 : 1;
+  loop_->run_loop_ = this;
+
+  running_ = true;
+  return true;
+}
+
+void RunLoop::AfterRun() {
+  running_ = false;
+
+  // Pop RunLoop stack:
+  loop_->run_loop_ = previous_run_loop_;
+
+  // Execute deferred QuitNow, if any:
+  if (previous_run_loop_ && previous_run_loop_->quit_called_)
+    loop_->QuitNow();
+}
+
+}  // namespace base
diff --git a/base/run_loop.h b/base/run_loop.h
new file mode 100644
index 0000000..0024108
--- /dev/null
+++ b/base/run_loop.h
@@ -0,0 +1,119 @@
+// Copyright (c) 2012 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_RUN_LOOP_H_
+#define BASE_RUN_LOOP_H_
+
+#include "base/base_export.h"
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_loop.h"
+
+namespace base {
+#if defined(OS_ANDROID)
+class MessagePumpForUI;
+#endif
+
+#if defined(OS_WIN)
+class MessagePumpDispatcher;
+#endif
+
+#if defined(OS_IOS)
+class MessagePumpUIApplication;
+#endif
+
+// Helper class to Run a nested MessageLoop. Please do not use nested
+// MessageLoops in production code! If you must, use this class instead of
+// calling MessageLoop::Run/Quit directly. RunLoop::Run can only be called once
+// per RunLoop lifetime. Create a RunLoop on the stack and call Run/Quit to run
+// a nested MessageLoop.
+class BASE_EXPORT RunLoop {
+ public:
+  RunLoop();
+#if defined(OS_WIN)
+  explicit RunLoop(MessagePumpDispatcher* dispatcher);
+#endif
+  ~RunLoop();
+
+  // Run the current MessageLoop. This blocks until Quit is called. Before
+  // calling Run, be sure to grab an AsWeakPtr or the QuitClosure in order to
+  // stop the MessageLoop asynchronously. MessageLoop::Quit and QuitNow will
+  // also trigger a return from Run, but those are deprecated.
+  void Run();
+
+  // Run the current MessageLoop until it doesn't find any tasks or messages in
+  // the queue (it goes idle). WARNING: This may never return! Only use this
+  // when repeating tasks such as animated web pages have been shut down.
+  void RunUntilIdle();
+
+  bool running() const { return running_; }
+
+  // Quit an earlier call to Run(). There can be other nested RunLoops servicing
+  // the same task queue (MessageLoop); Quitting one RunLoop has no bearing on
+  // the others. Quit can be called before, during or after Run. If called
+  // before Run, Run will return immediately when called. Calling Quit after the
+  // RunLoop has already finished running has no effect.
+  //
+  // WARNING: You must NEVER assume that a call to Quit will terminate the
+  // targetted message loop. If a nested message loop continues running, the
+  // target may NEVER terminate. It is very easy to livelock (run forever) in
+  // such a case.
+  void Quit();
+
+  // Convenience method to get a closure that safely calls Quit (has no effect
+  // if the RunLoop instance is gone).
+  //
+  // Example:
+  //   RunLoop run_loop;
+  //   PostTask(run_loop.QuitClosure());
+  //   run_loop.Run();
+  base::Closure QuitClosure();
+
+ private:
+  friend class MessageLoop;
+#if defined(OS_ANDROID)
+  // Android doesn't support the blocking MessageLoop::Run, so it calls
+  // BeforeRun and AfterRun directly.
+  friend class base::MessagePumpForUI;
+#endif
+
+#if defined(OS_IOS)
+  // iOS doesn't support the blocking MessageLoop::Run, so it calls
+  // BeforeRun directly.
+  friend class base::MessagePumpUIApplication;
+#endif
+
+  // Return false to abort the Run.
+  bool BeforeRun();
+  void AfterRun();
+
+  MessageLoop* loop_;
+
+  // Parent RunLoop or NULL if this is the top-most RunLoop.
+  RunLoop* previous_run_loop_;
+
+#if defined(OS_WIN)
+  MessagePumpDispatcher* dispatcher_;
+#endif
+
+  // Used to count how many nested Run() invocations are on the stack.
+  int run_depth_;
+
+  bool run_called_;
+  bool quit_called_;
+  bool running_;
+
+  // Used to record that QuitWhenIdle() was called on the MessageLoop, meaning
+  // that we should quit Run once it becomes idle.
+  bool quit_when_idle_received_;
+
+  // WeakPtrFactory for QuitClosure safety.
+  base::WeakPtrFactory<RunLoop> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(RunLoop);
+};
+
+}  // namespace base
+
+#endif  // BASE_RUN_LOOP_H_
diff --git a/base/scoped_clear_errno.h b/base/scoped_clear_errno.h
new file mode 100644
index 0000000..7b972fc
--- /dev/null
+++ b/base/scoped_clear_errno.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SCOPED_CLEAR_ERRNO_H_
+#define BASE_SCOPED_CLEAR_ERRNO_H_
+
+#include <errno.h>
+
+#include "base/basictypes.h"
+
+namespace base {
+
+// Simple scoper that saves the current value of errno, resets it to 0, and on
+// destruction puts the old value back.
+class ScopedClearErrno {
+ public:
+  ScopedClearErrno() : old_errno_(errno) {
+    errno = 0;
+  }
+  ~ScopedClearErrno() {
+    if (errno == 0)
+      errno = old_errno_;
+  }
+
+ private:
+  const int old_errno_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedClearErrno);
+};
+
+}  // namespace base
+
+#endif  // BASE_SCOPED_CLEAR_ERRNO_H_
diff --git a/base/scoped_clear_errno_unittest.cc b/base/scoped_clear_errno_unittest.cc
new file mode 100644
index 0000000..8afb33e
--- /dev/null
+++ b/base/scoped_clear_errno_unittest.cc
@@ -0,0 +1,30 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <errno.h>
+
+#include "base/scoped_clear_errno.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(ScopedClearErrno, TestNoError) {
+  errno = 1;
+  {
+    ScopedClearErrno clear_error;
+    EXPECT_EQ(0, errno);
+  }
+  EXPECT_EQ(1, errno);
+}
+
+TEST(ScopedClearErrno, TestError) {
+  errno = 1;
+  {
+    ScopedClearErrno clear_error;
+    errno = 2;
+  }
+  EXPECT_EQ(2, errno);
+}
+
+}  // namespace base
diff --git a/base/scoped_generic.h b/base/scoped_generic.h
new file mode 100644
index 0000000..f6807e2
--- /dev/null
+++ b/base/scoped_generic.h
@@ -0,0 +1,182 @@
+// 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.
+
+#ifndef BASE_SCOPED_GENERIC_H_
+#define BASE_SCOPED_GENERIC_H_
+
+#include <stdlib.h>
+
+#include <algorithm>
+
+#include "base/compiler_specific.h"
+#include "base/move.h"
+
+namespace base {
+
+// This class acts like ScopedPtr with a custom deleter (although is slightly
+// less fancy in some of the more escoteric respects) except that it keeps a
+// copy of the object rather than a pointer, and we require that the contained
+// object has some kind of "invalid" value.
+//
+// Defining a scoper based on this class allows you to get a scoper for
+// non-pointer types without having to write custom code for set, reset, and
+// move, etc. and get almost identical semantics that people are used to from
+// scoped_ptr.
+//
+// It is intended that you will typedef this class with an appropriate deleter
+// to implement clean up tasks for objects that act like pointers from a
+// resource management standpoint but aren't, such as file descriptors and
+// various types of operating system handles. Using scoped_ptr for these
+// things requires that you keep a pointer to the handle valid for the lifetime
+// of the scoper (which is easy to mess up).
+//
+// For an object to be able to be put into a ScopedGeneric, it must support
+// standard copyable semantics and have a specific "invalid" value. The traits
+// must define a free function and also the invalid value to assign for
+// default-constructed and released objects.
+//
+//   struct FooScopedTraits {
+//     // It's assumed that this is a fast inline function with little-to-no
+//     // penalty for duplicate calls. This must be a static function even
+//     // for stateful traits.
+//     static int InvalidValue() {
+//       return 0;
+//     }
+//
+//     // This free function will not be called if f == InvalidValue()!
+//     static void Free(int f) {
+//       ::FreeFoo(f);
+//     }
+//   };
+//
+//   typedef ScopedGeneric<int, FooScopedTraits> ScopedFoo;
+template<typename T, typename Traits>
+class ScopedGeneric {
+  MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(ScopedGeneric)
+
+ private:
+  // This must be first since it's used inline below.
+  //
+  // Use the empty base class optimization to allow us to have a D
+  // member, while avoiding any space overhead for it when D is an
+  // empty class.  See e.g. http://www.cantrip.org/emptyopt.html for a good
+  // discussion of this technique.
+  struct Data : public Traits {
+    explicit Data(const T& in) : generic(in) {}
+    Data(const T& in, const Traits& other) : Traits(other), generic(in) {}
+    T generic;
+  };
+
+ public:
+  typedef T element_type;
+  typedef Traits traits_type;
+
+  ScopedGeneric() : data_(traits_type::InvalidValue()) {}
+
+  // Constructor. Takes responsibility for freeing the resource associated with
+  // the object T.
+  explicit ScopedGeneric(const element_type& value) : data_(value) {}
+
+  // Constructor. Allows initialization of a stateful traits object.
+  ScopedGeneric(const element_type& value, const traits_type& traits)
+      : data_(value, traits) {
+  }
+
+  // Move constructor. Allows initialization from a ScopedGeneric rvalue.
+  ScopedGeneric(ScopedGeneric<T, Traits>&& rvalue)
+      : data_(rvalue.release(), rvalue.get_traits()) {
+  }
+
+  ~ScopedGeneric() {
+    FreeIfNecessary();
+  }
+
+  // operator=. Allows assignment from a ScopedGeneric rvalue.
+  ScopedGeneric& operator=(ScopedGeneric<T, Traits>&& rvalue) {
+    reset(rvalue.release());
+    return *this;
+  }
+
+  // Frees the currently owned object, if any. Then takes ownership of a new
+  // object, if given. Self-resets are not allowd as on scoped_ptr. See
+  // http://crbug.com/162971
+  void reset(const element_type& value = traits_type::InvalidValue()) {
+    if (data_.generic != traits_type::InvalidValue() && data_.generic == value)
+      abort();
+    FreeIfNecessary();
+    data_.generic = value;
+  }
+
+  void swap(ScopedGeneric& other) {
+    // Standard swap idiom: 'using std::swap' ensures that std::swap is
+    // present in the overload set, but we call swap unqualified so that
+    // any more-specific overloads can be used, if available.
+    using std::swap;
+    swap(static_cast<Traits&>(data_), static_cast<Traits&>(other.data_));
+    swap(data_.generic, other.data_.generic);
+  }
+
+  // Release the object. The return value is the current object held by this
+  // object. After this operation, this object will hold a null value, and
+  // will not own the object any more.
+  element_type release() WARN_UNUSED_RESULT {
+    element_type old_generic = data_.generic;
+    data_.generic = traits_type::InvalidValue();
+    return old_generic;
+  }
+
+  const element_type& get() const { return data_.generic; }
+
+  // Returns true if this object doesn't hold the special null value for the
+  // associated data type.
+  bool is_valid() const { return data_.generic != traits_type::InvalidValue(); }
+
+  bool operator==(const element_type& value) const {
+    return data_.generic == value;
+  }
+  bool operator!=(const element_type& value) const {
+    return data_.generic != value;
+  }
+
+  Traits& get_traits() { return data_; }
+  const Traits& get_traits() const { return data_; }
+
+ private:
+  void FreeIfNecessary() {
+    if (data_.generic != traits_type::InvalidValue()) {
+      data_.Free(data_.generic);
+      data_.generic = traits_type::InvalidValue();
+    }
+  }
+
+  // Forbid comparison. If U != T, it totally doesn't make sense, and if U ==
+  // T, it still doesn't make sense because you should never have the same
+  // object owned by two different ScopedGenerics.
+  template <typename T2, typename Traits2> bool operator==(
+      const ScopedGeneric<T2, Traits2>& p2) const;
+  template <typename T2, typename Traits2> bool operator!=(
+      const ScopedGeneric<T2, Traits2>& p2) const;
+
+  Data data_;
+};
+
+template<class T, class Traits>
+void swap(const ScopedGeneric<T, Traits>& a,
+          const ScopedGeneric<T, Traits>& b) {
+  a.swap(b);
+}
+
+template<class T, class Traits>
+bool operator==(const T& value, const ScopedGeneric<T, Traits>& scoped) {
+  return value == scoped.get();
+}
+
+template<class T, class Traits>
+bool operator!=(const T& value, const ScopedGeneric<T, Traits>& scoped) {
+  return value != scoped.get();
+}
+
+}  // namespace base
+
+#endif  // BASE_SCOPED_GENERIC_H_
diff --git a/base/scoped_generic_unittest.cc b/base/scoped_generic_unittest.cc
new file mode 100644
index 0000000..b28e154
--- /dev/null
+++ b/base/scoped_generic_unittest.cc
@@ -0,0 +1,170 @@
+// 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.
+
+#include <vector>
+
+#include "base/scoped_generic.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+struct IntTraits {
+  IntTraits(std::vector<int>* freed) : freed_ints(freed) {}
+
+  static int InvalidValue() {
+    return -1;
+  }
+  void Free(int value) {
+    freed_ints->push_back(value);
+  }
+
+  std::vector<int>* freed_ints;
+};
+
+typedef ScopedGeneric<int, IntTraits> ScopedInt;
+
+}  // namespace
+
+TEST(ScopedGenericTest, ScopedGeneric) {
+  std::vector<int> values_freed;
+  IntTraits traits(&values_freed);
+
+  // Invalid case, delete should not be called.
+  {
+    ScopedInt a(IntTraits::InvalidValue(), traits);
+  }
+  EXPECT_TRUE(values_freed.empty());
+
+  // Simple deleting case.
+  static const int kFirst = 0;
+  {
+    ScopedInt a(kFirst, traits);
+  }
+  ASSERT_EQ(1u, values_freed.size());
+  ASSERT_EQ(kFirst, values_freed[0]);
+  values_freed.clear();
+
+  // Release should return the right value and leave the object empty.
+  {
+    ScopedInt a(kFirst, traits);
+    EXPECT_EQ(kFirst, a.release());
+
+    ScopedInt b(IntTraits::InvalidValue(), traits);
+    EXPECT_EQ(IntTraits::InvalidValue(), b.release());
+  }
+  ASSERT_TRUE(values_freed.empty());
+
+  // Reset should free the old value, then the new one should go away when
+  // it goes out of scope.
+  static const int kSecond = 1;
+  {
+    ScopedInt b(kFirst, traits);
+    b.reset(kSecond);
+    ASSERT_EQ(1u, values_freed.size());
+    ASSERT_EQ(kFirst, values_freed[0]);
+  }
+  ASSERT_EQ(2u, values_freed.size());
+  ASSERT_EQ(kSecond, values_freed[1]);
+  values_freed.clear();
+
+  // Swap.
+  {
+    ScopedInt a(kFirst, traits);
+    ScopedInt b(kSecond, traits);
+    a.swap(b);
+    EXPECT_TRUE(values_freed.empty());  // Nothing should be freed.
+    EXPECT_EQ(kSecond, a.get());
+    EXPECT_EQ(kFirst, b.get());
+  }
+  // Values should be deleted in the opposite order.
+  ASSERT_EQ(2u, values_freed.size());
+  EXPECT_EQ(kFirst, values_freed[0]);
+  EXPECT_EQ(kSecond, values_freed[1]);
+  values_freed.clear();
+
+  // Pass constructor.
+  {
+    ScopedInt a(kFirst, traits);
+    ScopedInt b(a.Pass());
+    EXPECT_TRUE(values_freed.empty());  // Nothing should be freed.
+    ASSERT_EQ(IntTraits::InvalidValue(), a.get());
+    ASSERT_EQ(kFirst, b.get());
+  }
+
+  ASSERT_EQ(1u, values_freed.size());
+  ASSERT_EQ(kFirst, values_freed[0]);
+  values_freed.clear();
+
+  // Pass assign.
+  {
+    ScopedInt a(kFirst, traits);
+    ScopedInt b(kSecond, traits);
+    b = a.Pass();
+    ASSERT_EQ(1u, values_freed.size());
+    EXPECT_EQ(kSecond, values_freed[0]);
+    ASSERT_EQ(IntTraits::InvalidValue(), a.get());
+    ASSERT_EQ(kFirst, b.get());
+  }
+
+  ASSERT_EQ(2u, values_freed.size());
+  EXPECT_EQ(kFirst, values_freed[1]);
+  values_freed.clear();
+}
+
+TEST(ScopedGenericTest, Operators) {
+  std::vector<int> values_freed;
+  IntTraits traits(&values_freed);
+
+  static const int kFirst = 0;
+  static const int kSecond = 1;
+  {
+    ScopedInt a(kFirst, traits);
+    EXPECT_TRUE(a == kFirst);
+    EXPECT_FALSE(a != kFirst);
+    EXPECT_FALSE(a == kSecond);
+    EXPECT_TRUE(a != kSecond);
+
+    EXPECT_TRUE(kFirst == a);
+    EXPECT_FALSE(kFirst != a);
+    EXPECT_FALSE(kSecond == a);
+    EXPECT_TRUE(kSecond != a);
+  }
+
+  // is_valid().
+  {
+    ScopedInt a(kFirst, traits);
+    EXPECT_TRUE(a.is_valid());
+    a.reset();
+    EXPECT_FALSE(a.is_valid());
+  }
+}
+
+// Cheesy manual "no compile" test for manually validating changes.
+#if 0
+TEST(ScopedGenericTest, NoCompile) {
+  // Assignment shouldn't work.
+  /*{
+    ScopedInt a(kFirst, traits);
+    ScopedInt b(a);
+  }*/
+
+  // Comparison shouldn't work.
+  /*{
+    ScopedInt a(kFirst, traits);
+    ScopedInt b(kFirst, traits);
+    if (a == b) {
+    }
+  }*/
+
+  // Implicit conversion to bool shouldn't work.
+  /*{
+    ScopedInt a(kFirst, traits);
+    bool result = a;
+  }*/
+}
+#endif
+
+}  // namespace base
diff --git a/base/scoped_native_library.cc b/base/scoped_native_library.cc
new file mode 100644
index 0000000..7290d29
--- /dev/null
+++ b/base/scoped_native_library.cc
@@ -0,0 +1,44 @@
+// Copyright (c) 2011 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/scoped_native_library.h"
+
+namespace base {
+
+ScopedNativeLibrary::ScopedNativeLibrary() : library_(NULL) {
+}
+
+ScopedNativeLibrary::ScopedNativeLibrary(NativeLibrary library)
+    : library_(library) {
+}
+
+ScopedNativeLibrary::ScopedNativeLibrary(const FilePath& library_path) {
+  library_ = base::LoadNativeLibrary(library_path, NULL);
+}
+
+ScopedNativeLibrary::~ScopedNativeLibrary() {
+  if (library_)
+    base::UnloadNativeLibrary(library_);
+}
+
+void* ScopedNativeLibrary::GetFunctionPointer(
+    const char* function_name) const {
+  if (!library_)
+    return NULL;
+  return base::GetFunctionPointerFromNativeLibrary(library_, function_name);
+}
+
+void ScopedNativeLibrary::Reset(NativeLibrary library) {
+  if (library_)
+    base::UnloadNativeLibrary(library_);
+  library_ = library;
+}
+
+NativeLibrary ScopedNativeLibrary::Release() {
+  NativeLibrary result = library_;
+  library_ = NULL;
+  return result;
+}
+
+}  // namespace base
diff --git a/base/scoped_native_library.h b/base/scoped_native_library.h
new file mode 100644
index 0000000..c0e93f3
--- /dev/null
+++ b/base/scoped_native_library.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2011 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_SCOPED_NATIVE_LIBRARY_H_
+#define BASE_SCOPED_NATIVE_LIBRARY_H_
+
+#include "base/base_export.h"
+#include "base/native_library.h"
+
+namespace base {
+
+class FilePath;
+
+// A class which encapsulates a base::NativeLibrary object available only in a
+// scope.
+// This class automatically unloads the loaded library in its destructor.
+class BASE_EXPORT ScopedNativeLibrary {
+ public:
+  // Initializes with a NULL library.
+  ScopedNativeLibrary();
+
+  // Takes ownership of the given library handle.
+  explicit ScopedNativeLibrary(NativeLibrary library);
+
+  // Opens the given library and manages its lifetime.
+  explicit ScopedNativeLibrary(const FilePath& library_path);
+
+  ~ScopedNativeLibrary();
+
+  // Returns true if there's a valid library loaded.
+  bool is_valid() const { return !!library_; }
+
+  void* GetFunctionPointer(const char* function_name) const;
+
+  // Takes ownership of the given library handle. Any existing handle will
+  // be freed.
+  void Reset(NativeLibrary library);
+
+  // Returns the native library handle and removes it from this object. The
+  // caller must manage the lifetime of the handle.
+  NativeLibrary Release();
+
+ private:
+  NativeLibrary library_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedNativeLibrary);
+};
+
+}  // namespace base
+
+#endif  // BASE_SCOPED_NATIVE_LIBRARY_H_
diff --git a/base/scoped_native_library_unittest.cc b/base/scoped_native_library_unittest.cc
new file mode 100644
index 0000000..035faa0
--- /dev/null
+++ b/base/scoped_native_library_unittest.cc
@@ -0,0 +1,43 @@
+// Copyright (c) 2011 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/scoped_native_library.h"
+#if defined(OS_WIN)
+#include "base/files/file_path.h"
+#endif
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+// Tests whether or not a function pointer retrieved via ScopedNativeLibrary
+// is available only in a scope.
+TEST(ScopedNativeLibrary, Basic) {
+#if defined(OS_WIN)
+  // Get the pointer to DirectDrawCreate() from "ddraw.dll" and verify it
+  // is valid only in this scope.
+  // FreeLibrary() doesn't actually unload a DLL until its reference count
+  // becomes zero, i.e. function pointer is still valid if the DLL used
+  // in this test is also used by another part of this executable.
+  // So, this test uses "ddraw.dll", which is not used by Chrome at all but
+  // installed on all versions of Windows.
+  const char kFunctionName[] = "DirectDrawCreate";
+  NativeLibrary native_library;
+  {
+    FilePath path(GetNativeLibraryName(L"ddraw"));
+    native_library = LoadNativeLibrary(path, NULL);
+    ScopedNativeLibrary library(native_library);
+    FARPROC test_function =
+        reinterpret_cast<FARPROC>(library.GetFunctionPointer(kFunctionName));
+    EXPECT_EQ(0, IsBadCodePtr(test_function));
+    EXPECT_EQ(
+        GetFunctionPointerFromNativeLibrary(native_library, kFunctionName),
+        test_function);
+  }
+  EXPECT_EQ(NULL,
+            GetFunctionPointerFromNativeLibrary(native_library, kFunctionName));
+#endif
+}
+
+}  // namespace base
diff --git a/base/scoped_observer.h b/base/scoped_observer.h
new file mode 100644
index 0000000..422701b
--- /dev/null
+++ b/base/scoped_observer.h
@@ -0,0 +1,61 @@
+// Copyright (c) 2012 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_SCOPED_OBSERVER_H_
+#define BASE_SCOPED_OBSERVER_H_
+
+#include <algorithm>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+// ScopedObserver is used to keep track of the set of sources an object has
+// attached itself to as an observer. When ScopedObserver is destroyed it
+// removes the object as an observer from all sources it has been added to.
+template <class Source, class Observer>
+class ScopedObserver {
+ public:
+  explicit ScopedObserver(Observer* observer) : observer_(observer) {}
+
+  ~ScopedObserver() {
+    RemoveAll();
+  }
+
+  // Adds the object passed to the constructor as an observer on |source|.
+  void Add(Source* source) {
+    sources_.push_back(source);
+    source->AddObserver(observer_);
+  }
+
+  // Remove the object passed to the constructor as an observer from |source|.
+  void Remove(Source* source) {
+    auto it = std::find(sources_.begin(), sources_.end(), source);
+    DCHECK(it != sources_.end());
+    sources_.erase(it);
+    source->RemoveObserver(observer_);
+  }
+
+  void RemoveAll() {
+    for (size_t i = 0; i < sources_.size(); ++i)
+      sources_[i]->RemoveObserver(observer_);
+    sources_.clear();
+  }
+
+  bool IsObserving(Source* source) const {
+    return std::find(sources_.begin(), sources_.end(), source) !=
+        sources_.end();
+  }
+
+  bool IsObservingSources() const { return !sources_.empty(); }
+
+ private:
+  Observer* observer_;
+
+  std::vector<Source*> sources_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedObserver);
+};
+
+#endif  // BASE_SCOPED_OBSERVER_H_
diff --git a/base/security_unittest.cc b/base/security_unittest.cc
new file mode 100644
index 0000000..07ba6f5
--- /dev/null
+++ b/base/security_unittest.cc
@@ -0,0 +1,376 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <algorithm>
+#include <limits>
+
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_POSIX)
+#include <sys/mman.h>
+#include <unistd.h>
+#endif
+
+#if defined(OS_WIN)
+#include <new.h>
+#endif
+
+using std::nothrow;
+using std::numeric_limits;
+
+namespace {
+
+#if defined(OS_WIN)
+// This is a permitted size but exhausts memory pretty quickly.
+const size_t kLargePermittedAllocation = 0x7FFFE000;
+
+int OnNoMemory(size_t) {
+  _exit(1);
+}
+
+void ExhaustMemoryWithMalloc() {
+  for (;;) {
+    // Without the |volatile|, clang optimizes away the allocation.
+    void* volatile buf = malloc(kLargePermittedAllocation);
+    if (!buf)
+      break;
+  }
+}
+
+void ExhaustMemoryWithRealloc() {
+  size_t size = kLargePermittedAllocation;
+  void* buf = malloc(size);
+  if (!buf)
+    return;
+  for (;;) {
+    size += kLargePermittedAllocation;
+    void* new_buf = realloc(buf, size);
+    if (!buf)
+      break;
+    buf = new_buf;
+  }
+}
+#endif
+
+// This function acts as a compiler optimization barrier. We use it to
+// prevent the compiler from making an expression a compile-time constant.
+// We also use it so that the compiler doesn't discard certain return values
+// as something we don't need (see the comment with calloc below).
+template <typename Type>
+NOINLINE Type HideValueFromCompiler(volatile Type value) {
+#if defined(__GNUC__)
+  // In a GCC compatible compiler (GCC or Clang), make this compiler barrier
+  // more robust than merely using "volatile".
+  __asm__ volatile ("" : "+r" (value));
+#endif  // __GNUC__
+  return value;
+}
+
+// Tcmalloc and Windows allocator shim support setting malloc limits.
+// - NO_TCMALLOC (should be defined if compiled with use_allocator!="tcmalloc")
+// - ADDRESS_SANITIZER and SYZYASAN because they have their own memory allocator
+// - IOS does not use tcmalloc
+// - OS_MACOSX does not use tcmalloc
+// - Windows allocator shim defines ALLOCATOR_SHIM
+#if (!defined(NO_TCMALLOC) || defined(ALLOCATOR_SHIM)) &&                     \
+    !defined(ADDRESS_SANITIZER) && !defined(OS_IOS) && !defined(OS_MACOSX) && \
+    !defined(SYZYASAN)
+#define MALLOC_OVERFLOW_TEST(function) function
+#else
+#define MALLOC_OVERFLOW_TEST(function) DISABLED_##function
+#endif
+
+// TODO(jln): switch to std::numeric_limits<int>::max() when we switch to
+// C++11.
+const size_t kTooBigAllocSize = INT_MAX;
+
+// Detect runtime TCMalloc bypasses.
+bool IsTcMallocBypassed() {
+#if defined(OS_LINUX)
+  // This should detect a TCMalloc bypass from Valgrind.
+  char* g_slice = getenv("G_SLICE");
+  if (g_slice && !strcmp(g_slice, "always-malloc"))
+    return true;
+#endif
+  return false;
+}
+
+bool CallocDiesOnOOM() {
+// The sanitizers' calloc dies on OOM instead of returning NULL.
+// The wrapper function in base/process_util_linux.cc that is used when we
+// compile without TCMalloc will just die on OOM instead of returning NULL.
+#if defined(ADDRESS_SANITIZER) || \
+    defined(MEMORY_SANITIZER) || \
+    defined(THREAD_SANITIZER) || \
+    (defined(OS_LINUX) && defined(NO_TCMALLOC))
+  return true;
+#else
+  return false;
+#endif
+}
+
+// Fake test that allow to know the state of TCMalloc by looking at bots.
+TEST(SecurityTest, MALLOC_OVERFLOW_TEST(IsTCMallocDynamicallyBypassed)) {
+  printf("Malloc is dynamically bypassed: %s\n",
+         IsTcMallocBypassed() ? "yes." : "no.");
+}
+
+// The MemoryAllocationRestrictions* tests test that we can not allocate a
+// memory range that cannot be indexed via an int. This is used to mitigate
+// vulnerabilities in libraries that use int instead of size_t.  See
+// crbug.com/169327.
+
+TEST(SecurityTest, MALLOC_OVERFLOW_TEST(MemoryAllocationRestrictionsMalloc)) {
+  if (!IsTcMallocBypassed()) {
+    scoped_ptr<char, base::FreeDeleter> ptr(static_cast<char*>(
+        HideValueFromCompiler(malloc(kTooBigAllocSize))));
+    ASSERT_TRUE(!ptr);
+  }
+}
+
+#if defined(GTEST_HAS_DEATH_TEST) && defined(OS_WIN)
+TEST(SecurityTest, MALLOC_OVERFLOW_TEST(MemoryAllocationMallocDeathTest)) {
+  _set_new_handler(&OnNoMemory);
+  _set_new_mode(1);
+  {
+    scoped_ptr<char, base::FreeDeleter> ptr;
+    EXPECT_DEATH(ptr.reset(static_cast<char*>(
+                      HideValueFromCompiler(malloc(kTooBigAllocSize)))),
+                  "");
+    ASSERT_TRUE(!ptr);
+  }
+  _set_new_handler(NULL);
+  _set_new_mode(0);
+}
+
+TEST(SecurityTest, MALLOC_OVERFLOW_TEST(MemoryAllocationExhaustDeathTest)) {
+  _set_new_handler(&OnNoMemory);
+  _set_new_mode(1);
+  {
+    ASSERT_DEATH(ExhaustMemoryWithMalloc(), "");
+  }
+  _set_new_handler(NULL);
+  _set_new_mode(0);
+}
+
+TEST(SecurityTest, MALLOC_OVERFLOW_TEST(MemoryReallocationExhaustDeathTest)) {
+  _set_new_handler(&OnNoMemory);
+  _set_new_mode(1);
+  {
+    ASSERT_DEATH(ExhaustMemoryWithRealloc(), "");
+  }
+  _set_new_handler(NULL);
+  _set_new_mode(0);
+}
+#endif
+
+TEST(SecurityTest, MALLOC_OVERFLOW_TEST(MemoryAllocationRestrictionsCalloc)) {
+  if (!IsTcMallocBypassed()) {
+    scoped_ptr<char, base::FreeDeleter> ptr(static_cast<char*>(
+        HideValueFromCompiler(calloc(kTooBigAllocSize, 1))));
+    ASSERT_TRUE(!ptr);
+  }
+}
+
+TEST(SecurityTest, MALLOC_OVERFLOW_TEST(MemoryAllocationRestrictionsRealloc)) {
+  if (!IsTcMallocBypassed()) {
+    char* orig_ptr = static_cast<char*>(malloc(1));
+    ASSERT_TRUE(orig_ptr);
+    scoped_ptr<char, base::FreeDeleter> ptr(static_cast<char*>(
+        HideValueFromCompiler(realloc(orig_ptr, kTooBigAllocSize))));
+    ASSERT_TRUE(!ptr);
+    // If realloc() did not succeed, we need to free orig_ptr.
+    free(orig_ptr);
+  }
+}
+
+typedef struct {
+  char large_array[kTooBigAllocSize];
+} VeryLargeStruct;
+
+TEST(SecurityTest, MALLOC_OVERFLOW_TEST(MemoryAllocationRestrictionsNew)) {
+  if (!IsTcMallocBypassed()) {
+    scoped_ptr<VeryLargeStruct> ptr(
+        HideValueFromCompiler(new (nothrow) VeryLargeStruct));
+    ASSERT_TRUE(!ptr);
+  }
+}
+
+#if defined(GTEST_HAS_DEATH_TEST) && defined(OS_WIN)
+TEST(SecurityTest, MALLOC_OVERFLOW_TEST(MemoryAllocationNewDeathTest)) {
+  _set_new_handler(&OnNoMemory);
+  {
+    scoped_ptr<VeryLargeStruct> ptr;
+    EXPECT_DEATH(
+        ptr.reset(HideValueFromCompiler(new (nothrow) VeryLargeStruct)), "");
+    ASSERT_TRUE(!ptr);
+  }
+  _set_new_handler(NULL);
+}
+#endif
+
+TEST(SecurityTest, MALLOC_OVERFLOW_TEST(MemoryAllocationRestrictionsNewArray)) {
+  if (!IsTcMallocBypassed()) {
+    scoped_ptr<char[]> ptr(
+        HideValueFromCompiler(new (nothrow) char[kTooBigAllocSize]));
+    ASSERT_TRUE(!ptr);
+  }
+}
+
+// The tests bellow check for overflows in new[] and calloc().
+
+// There are platforms where these tests are known to fail. We would like to
+// be able to easily check the status on the bots, but marking tests as
+// FAILS_ is too clunky.
+void OverflowTestsSoftExpectTrue(bool overflow_detected) {
+  if (!overflow_detected) {
+#if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_MACOSX)
+    // Sadly, on Linux, Android, and OSX we don't have a good story yet. Don't
+    // fail the test, but report.
+    printf("Platform has overflow: %s\n",
+           !overflow_detected ? "yes." : "no.");
+#else
+    // Otherwise, fail the test. (Note: EXPECT are ok in subfunctions, ASSERT
+    // aren't).
+    EXPECT_TRUE(overflow_detected);
+#endif
+  }
+}
+
+#if defined(OS_IOS) || defined(OS_WIN) || defined(THREAD_SANITIZER) || defined(OS_MACOSX)
+#define MAYBE_NewOverflow DISABLED_NewOverflow
+#else
+#define MAYBE_NewOverflow NewOverflow
+#endif
+// Test array[TooBig][X] and array[X][TooBig] allocations for int overflows.
+// IOS doesn't honor nothrow, so disable the test there.
+// Crashes on Windows Dbg builds, disable there as well.
+// Fails on Mac 10.8 http://crbug.com/227092
+TEST(SecurityTest, MAYBE_NewOverflow) {
+  const size_t kArraySize = 4096;
+  // We want something "dynamic" here, so that the compiler doesn't
+  // immediately reject crazy arrays.
+  const size_t kDynamicArraySize = HideValueFromCompiler(kArraySize);
+  // numeric_limits are still not constexpr until we switch to C++11, so we
+  // use an ugly cast.
+  const size_t kMaxSizeT = ~static_cast<size_t>(0);
+  ASSERT_EQ(numeric_limits<size_t>::max(), kMaxSizeT);
+  const size_t kArraySize2 = kMaxSizeT / kArraySize + 10;
+  const size_t kDynamicArraySize2 = HideValueFromCompiler(kArraySize2);
+  {
+    scoped_ptr<char[][kArraySize]> array_pointer(new (nothrow)
+        char[kDynamicArraySize2][kArraySize]);
+    OverflowTestsSoftExpectTrue(!array_pointer);
+  }
+  // On windows, the compiler prevents static array sizes of more than
+  // 0x7fffffff (error C2148).
+#if defined(OS_WIN) && defined(ARCH_CPU_64_BITS)
+  ALLOW_UNUSED_LOCAL(kDynamicArraySize);
+#else
+  {
+    scoped_ptr<char[][kArraySize2]> array_pointer(new (nothrow)
+        char[kDynamicArraySize][kArraySize2]);
+    OverflowTestsSoftExpectTrue(!array_pointer);
+  }
+#endif  // !defined(OS_WIN) || !defined(ARCH_CPU_64_BITS)
+}
+
+// Call calloc(), eventually free the memory and return whether or not
+// calloc() did succeed.
+bool CallocReturnsNull(size_t nmemb, size_t size) {
+  scoped_ptr<char, base::FreeDeleter> array_pointer(
+      static_cast<char*>(calloc(nmemb, size)));
+  // We need the call to HideValueFromCompiler(): we have seen LLVM
+  // optimize away the call to calloc() entirely and assume the pointer to not
+  // be NULL.
+  return HideValueFromCompiler(array_pointer.get()) == NULL;
+}
+
+// Test if calloc() can overflow.
+TEST(SecurityTest, CallocOverflow) {
+  const size_t kArraySize = 4096;
+  const size_t kMaxSizeT = numeric_limits<size_t>::max();
+  const size_t kArraySize2 = kMaxSizeT / kArraySize + 10;
+  if (!CallocDiesOnOOM()) {
+    EXPECT_TRUE(CallocReturnsNull(kArraySize, kArraySize2));
+    EXPECT_TRUE(CallocReturnsNull(kArraySize2, kArraySize));
+  } else {
+    // It's also ok for calloc to just terminate the process.
+#if defined(GTEST_HAS_DEATH_TEST)
+    EXPECT_DEATH(CallocReturnsNull(kArraySize, kArraySize2), "");
+    EXPECT_DEATH(CallocReturnsNull(kArraySize2, kArraySize), "");
+#endif  // GTEST_HAS_DEATH_TEST
+  }
+}
+
+#if defined(OS_LINUX) && defined(__x86_64__)
+// Check if ptr1 and ptr2 are separated by less than size chars.
+bool ArePointersToSameArea(void* ptr1, void* ptr2, size_t size) {
+  ptrdiff_t ptr_diff = reinterpret_cast<char*>(std::max(ptr1, ptr2)) -
+                       reinterpret_cast<char*>(std::min(ptr1, ptr2));
+  return static_cast<size_t>(ptr_diff) <= size;
+}
+
+// Check if TCMalloc uses an underlying random memory allocator.
+TEST(SecurityTest, MALLOC_OVERFLOW_TEST(RandomMemoryAllocations)) {
+  if (IsTcMallocBypassed())
+    return;
+  size_t kPageSize = 4096;  // We support x86_64 only.
+  // Check that malloc() returns an address that is neither the kernel's
+  // un-hinted mmap area, nor the current brk() area. The first malloc() may
+  // not be at a random address because TCMalloc will first exhaust any memory
+  // that it has allocated early on, before starting the sophisticated
+  // allocators.
+  void* default_mmap_heap_address =
+      mmap(0, kPageSize, PROT_READ|PROT_WRITE,
+           MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+  ASSERT_NE(default_mmap_heap_address,
+            static_cast<void*>(MAP_FAILED));
+  ASSERT_EQ(munmap(default_mmap_heap_address, kPageSize), 0);
+  void* brk_heap_address = sbrk(0);
+  ASSERT_NE(brk_heap_address, reinterpret_cast<void*>(-1));
+  ASSERT_TRUE(brk_heap_address != NULL);
+  // 1 MB should get us past what TCMalloc pre-allocated before initializing
+  // the sophisticated allocators.
+  size_t kAllocSize = 1<<20;
+  scoped_ptr<char, base::FreeDeleter> ptr(
+      static_cast<char*>(malloc(kAllocSize)));
+  ASSERT_TRUE(ptr != NULL);
+  // If two pointers are separated by less than 512MB, they are considered
+  // to be in the same area.
+  // Our random pointer could be anywhere within 0x3fffffffffff (46bits),
+  // and we are checking that it's not withing 1GB (30 bits) from two
+  // addresses (brk and mmap heap). We have roughly one chance out of
+  // 2^15 to flake.
+  const size_t kAreaRadius = 1<<29;
+  bool in_default_mmap_heap = ArePointersToSameArea(
+      ptr.get(), default_mmap_heap_address, kAreaRadius);
+  EXPECT_FALSE(in_default_mmap_heap);
+
+  bool in_default_brk_heap = ArePointersToSameArea(
+      ptr.get(), brk_heap_address, kAreaRadius);
+  EXPECT_FALSE(in_default_brk_heap);
+
+  // In the implementation, we always mask our random addresses with
+  // kRandomMask, so we use it as an additional detection mechanism.
+  const uintptr_t kRandomMask = 0x3fffffffffffULL;
+  bool impossible_random_address =
+      reinterpret_cast<uintptr_t>(ptr.get()) & ~kRandomMask;
+  EXPECT_FALSE(impossible_random_address);
+}
+
+#endif  // defined(OS_LINUX) && defined(__x86_64__)
+
+}  // namespace
diff --git a/base/sequence_checker.h b/base/sequence_checker.h
new file mode 100644
index 0000000..ad01828
--- /dev/null
+++ b/base/sequence_checker.h
@@ -0,0 +1,62 @@
+// Copyright (c) 2012 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_SEQUENCE_CHECKER_H_
+#define BASE_SEQUENCE_CHECKER_H_
+
+// See comments for the similar block in thread_checker.h.
+#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON))
+#define ENABLE_SEQUENCE_CHECKER 1
+#else
+#define ENABLE_SEQUENCE_CHECKER 0
+#endif
+
+#include "base/sequence_checker_impl.h"
+
+namespace base {
+
+// Do nothing implementation, for use in release mode.
+//
+// Note: You should almost always use the SequenceChecker class to get
+// the right version for your build configuration.
+class SequenceCheckerDoNothing {
+ public:
+  bool CalledOnValidSequencedThread() const {
+    return true;
+  }
+
+  void DetachFromSequence() {}
+};
+
+// SequenceChecker is a helper class used to help verify that some
+// methods of a class are called in sequence -- that is, called from
+// the same SequencedTaskRunner. It is a generalization of
+// ThreadChecker; see comments in sequence_checker_impl.h for details.
+//
+// Example:
+// class MyClass {
+//  public:
+//   void Foo() {
+//     DCHECK(sequence_checker_.CalledOnValidSequencedThread());
+//     ... (do stuff) ...
+//   }
+//
+//  private:
+//   SequenceChecker sequence_checker_;
+// }
+//
+// In Release mode, CalledOnValidSequencedThread() will always return true.
+#if ENABLE_SEQUENCE_CHECKER
+class SequenceChecker : public SequenceCheckerImpl {
+};
+#else
+class SequenceChecker : public SequenceCheckerDoNothing {
+};
+#endif  // ENABLE_SEQUENCE_CHECKER
+
+#undef ENABLE_SEQUENCE_CHECKER
+
+}  // namespace base
+
+#endif  // BASE_SEQUENCE_CHECKER_H_
diff --git a/base/sequence_checker_impl.cc b/base/sequence_checker_impl.cc
new file mode 100644
index 0000000..e95b8ee
--- /dev/null
+++ b/base/sequence_checker_impl.cc
@@ -0,0 +1,46 @@
+// Copyright (c) 2012 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/sequence_checker_impl.h"
+
+namespace base {
+
+SequenceCheckerImpl::SequenceCheckerImpl()
+    : sequence_token_assigned_(false) {
+  AutoLock auto_lock(lock_);
+  EnsureSequenceTokenAssigned();
+}
+
+SequenceCheckerImpl::~SequenceCheckerImpl() {}
+
+bool SequenceCheckerImpl::CalledOnValidSequencedThread() const {
+  AutoLock auto_lock(lock_);
+  EnsureSequenceTokenAssigned();
+
+  // If this thread is not associated with a SequencedWorkerPool,
+  // SequenceChecker behaves as a ThreadChecker. See header for details.
+  if (!sequence_token_.IsValid())
+    return thread_checker_.CalledOnValidThread();
+
+  return sequence_token_.Equals(
+      SequencedWorkerPool::GetSequenceTokenForCurrentThread());
+}
+
+void SequenceCheckerImpl::DetachFromSequence() {
+  AutoLock auto_lock(lock_);
+  thread_checker_.DetachFromThread();
+  sequence_token_assigned_ = false;
+  sequence_token_ = SequencedWorkerPool::SequenceToken();
+}
+
+void SequenceCheckerImpl::EnsureSequenceTokenAssigned() const {
+  lock_.AssertAcquired();
+  if (sequence_token_assigned_)
+    return;
+
+  sequence_token_assigned_ = true;
+  sequence_token_ = SequencedWorkerPool::GetSequenceTokenForCurrentThread();
+}
+
+}  // namespace base
diff --git a/base/sequence_checker_impl.h b/base/sequence_checker_impl.h
new file mode 100644
index 0000000..741aafe
--- /dev/null
+++ b/base/sequence_checker_impl.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2012 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_SEQUENCE_CHECKER_IMPL_H_
+#define BASE_SEQUENCE_CHECKER_IMPL_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "base/threading/thread_checker_impl.h"
+
+namespace base {
+
+// SequenceCheckerImpl is used to help verify that some methods of a
+// class are called in sequence -- that is, called from the same
+// SequencedTaskRunner. It is a generalization of ThreadChecker; in
+// particular, it behaves exactly like ThreadChecker if constructed
+// on a thread that is not part of a SequencedWorkerPool.
+class BASE_EXPORT SequenceCheckerImpl {
+ public:
+  SequenceCheckerImpl();
+  ~SequenceCheckerImpl();
+
+  // Returns whether the we are being called on the same sequence token
+  // as previous calls. If there is no associated sequence, then returns
+  // whether we are being called on the underlying ThreadChecker's thread.
+  bool CalledOnValidSequencedThread() const;
+
+  // Unbinds the checker from the currently associated sequence. The
+  // checker will be re-bound on the next call to CalledOnValidSequence().
+  void DetachFromSequence();
+
+ private:
+  void EnsureSequenceTokenAssigned() const;
+
+  // Guards all variables below.
+  mutable Lock lock_;
+
+  // Used if |sequence_token_| is not valid.
+  ThreadCheckerImpl thread_checker_;
+  mutable bool sequence_token_assigned_;
+
+  mutable SequencedWorkerPool::SequenceToken sequence_token_;
+
+  DISALLOW_COPY_AND_ASSIGN(SequenceCheckerImpl);
+};
+
+}  // namespace base
+
+#endif  // BASE_SEQUENCE_CHECKER_IMPL_H_
diff --git a/base/sequence_checker_unittest.cc b/base/sequence_checker_unittest.cc
new file mode 100644
index 0000000..0aa0f9c
--- /dev/null
+++ b/base/sequence_checker_unittest.cc
@@ -0,0 +1,333 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/sequence_checker.h"
+#include "base/single_thread_task_runner.h"
+#include "base/test/sequenced_worker_pool_owner.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Duplicated from base/sequence_checker.h so that we can be good citizens
+// there and undef the macro.
+#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON))
+#define ENABLE_SEQUENCE_CHECKER 1
+#else
+#define ENABLE_SEQUENCE_CHECKER 0
+#endif
+
+namespace base {
+
+namespace {
+
+const size_t kNumWorkerThreads = 3;
+
+// Simple class to exercise the basics of SequenceChecker.
+// DoStuff should verify that it's called on a valid sequenced thread.
+// SequenceCheckedObject can be destroyed on any thread (like WeakPtr).
+class SequenceCheckedObject {
+ public:
+  SequenceCheckedObject() {}
+  ~SequenceCheckedObject() {}
+
+  // Verifies that it was called on the same thread as the constructor.
+  void DoStuff() {
+    DCHECK(sequence_checker_.CalledOnValidSequencedThread());
+  }
+
+  void DetachFromSequence() {
+    sequence_checker_.DetachFromSequence();
+  }
+
+ private:
+  SequenceChecker sequence_checker_;
+
+  DISALLOW_COPY_AND_ASSIGN(SequenceCheckedObject);
+};
+
+class SequenceCheckerTest : public testing::Test {
+ public:
+  SequenceCheckerTest() : other_thread_("sequence_checker_test_other_thread") {}
+
+  void SetUp() override {
+    other_thread_.Start();
+    ResetPool();
+  }
+
+  void TearDown() override {
+    other_thread_.Stop();
+    pool()->Shutdown();
+  }
+
+ protected:
+  base::Thread* other_thread() { return &other_thread_; }
+
+  const scoped_refptr<SequencedWorkerPool>& pool() {
+    return pool_owner_->pool();
+  }
+
+  void PostDoStuffToWorkerPool(SequenceCheckedObject* sequence_checked_object,
+                               const std::string& token_name) {
+    pool()->PostNamedSequencedWorkerTask(
+        token_name,
+        FROM_HERE,
+        base::Bind(&SequenceCheckedObject::DoStuff,
+                   base::Unretained(sequence_checked_object)));
+  }
+
+  void PostDoStuffToOtherThread(
+      SequenceCheckedObject* sequence_checked_object) {
+    other_thread()->task_runner()->PostTask(
+        FROM_HERE, base::Bind(&SequenceCheckedObject::DoStuff,
+                              base::Unretained(sequence_checked_object)));
+  }
+
+  void PostDeleteToOtherThread(
+      scoped_ptr<SequenceCheckedObject> sequence_checked_object) {
+    other_thread()->message_loop()->DeleteSoon(
+        FROM_HERE,
+        sequence_checked_object.release());
+  }
+
+  // Destroys the SequencedWorkerPool instance, blocking until it is fully shut
+  // down, and creates a new instance.
+  void ResetPool() {
+    pool_owner_.reset(new SequencedWorkerPoolOwner(kNumWorkerThreads, "test"));
+  }
+
+  void MethodOnDifferentThreadDeathTest();
+  void DetachThenCallFromDifferentThreadDeathTest();
+  void DifferentSequenceTokensDeathTest();
+  void WorkerPoolAndSimpleThreadDeathTest();
+  void TwoDifferentWorkerPoolsDeathTest();
+
+ private:
+  MessageLoop message_loop_;  // Needed by SequencedWorkerPool to function.
+  base::Thread other_thread_;
+  scoped_ptr<SequencedWorkerPoolOwner> pool_owner_;
+};
+
+TEST_F(SequenceCheckerTest, CallsAllowedOnSameThread) {
+  scoped_ptr<SequenceCheckedObject> sequence_checked_object(
+      new SequenceCheckedObject);
+
+  // Verify that DoStuff doesn't assert.
+  sequence_checked_object->DoStuff();
+
+  // Verify that the destructor doesn't assert.
+  sequence_checked_object.reset();
+}
+
+TEST_F(SequenceCheckerTest, DestructorAllowedOnDifferentThread) {
+  scoped_ptr<SequenceCheckedObject> sequence_checked_object(
+      new SequenceCheckedObject);
+
+  // Verify the destructor doesn't assert when called on a different thread.
+  PostDeleteToOtherThread(sequence_checked_object.Pass());
+  other_thread()->Stop();
+}
+
+TEST_F(SequenceCheckerTest, DetachFromSequence) {
+  scoped_ptr<SequenceCheckedObject> sequence_checked_object(
+      new SequenceCheckedObject);
+
+  // Verify that DoStuff doesn't assert when called on a different thread after
+  // a call to DetachFromSequence.
+  sequence_checked_object->DetachFromSequence();
+
+  PostDoStuffToOtherThread(sequence_checked_object.get());
+  other_thread()->Stop();
+}
+
+TEST_F(SequenceCheckerTest, SameSequenceTokenValid) {
+  scoped_ptr<SequenceCheckedObject> sequence_checked_object(
+      new SequenceCheckedObject);
+
+  sequence_checked_object->DetachFromSequence();
+  PostDoStuffToWorkerPool(sequence_checked_object.get(), "A");
+  PostDoStuffToWorkerPool(sequence_checked_object.get(), "A");
+  PostDoStuffToWorkerPool(sequence_checked_object.get(), "A");
+  PostDoStuffToWorkerPool(sequence_checked_object.get(), "A");
+  pool()->FlushForTesting();
+
+  PostDeleteToOtherThread(sequence_checked_object.Pass());
+  other_thread()->Stop();
+}
+
+TEST_F(SequenceCheckerTest, DetachSequenceTokenValid) {
+  scoped_ptr<SequenceCheckedObject> sequence_checked_object(
+      new SequenceCheckedObject);
+
+  sequence_checked_object->DetachFromSequence();
+  PostDoStuffToWorkerPool(sequence_checked_object.get(), "A");
+  PostDoStuffToWorkerPool(sequence_checked_object.get(), "A");
+  pool()->FlushForTesting();
+
+  sequence_checked_object->DetachFromSequence();
+  PostDoStuffToWorkerPool(sequence_checked_object.get(), "B");
+  PostDoStuffToWorkerPool(sequence_checked_object.get(), "B");
+  pool()->FlushForTesting();
+
+  PostDeleteToOtherThread(sequence_checked_object.Pass());
+  other_thread()->Stop();
+}
+
+#if GTEST_HAS_DEATH_TEST || !ENABLE_SEQUENCE_CHECKER
+
+void SequenceCheckerTest::MethodOnDifferentThreadDeathTest() {
+  scoped_ptr<SequenceCheckedObject> sequence_checked_object(
+      new SequenceCheckedObject);
+
+  // DoStuff should assert in debug builds only when called on a
+  // different thread.
+  PostDoStuffToOtherThread(sequence_checked_object.get());
+  other_thread()->Stop();
+}
+
+#if ENABLE_SEQUENCE_CHECKER
+TEST_F(SequenceCheckerTest, MethodNotAllowedOnDifferentThreadDeathTestInDebug) {
+  // The default style "fast" does not support multi-threaded tests.
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  ASSERT_DEATH({
+    MethodOnDifferentThreadDeathTest();
+  }, "");
+}
+#else
+TEST_F(SequenceCheckerTest, MethodAllowedOnDifferentThreadDeathTestInRelease) {
+  MethodOnDifferentThreadDeathTest();
+}
+#endif  // ENABLE_SEQUENCE_CHECKER
+
+void SequenceCheckerTest::DetachThenCallFromDifferentThreadDeathTest() {
+  scoped_ptr<SequenceCheckedObject> sequence_checked_object(
+      new SequenceCheckedObject);
+
+  // DoStuff doesn't assert when called on a different thread
+  // after a call to DetachFromSequence.
+  sequence_checked_object->DetachFromSequence();
+  PostDoStuffToOtherThread(sequence_checked_object.get());
+  other_thread()->Stop();
+
+  // DoStuff should assert in debug builds only after moving to
+  // another thread.
+  sequence_checked_object->DoStuff();
+}
+
+#if ENABLE_SEQUENCE_CHECKER
+TEST_F(SequenceCheckerTest, DetachFromSequenceDeathTestInDebug) {
+  // The default style "fast" does not support multi-threaded tests.
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  ASSERT_DEATH({
+    DetachThenCallFromDifferentThreadDeathTest();
+  }, "");
+}
+#else
+TEST_F(SequenceCheckerTest, DetachFromThreadDeathTestInRelease) {
+  DetachThenCallFromDifferentThreadDeathTest();
+}
+#endif  // ENABLE_SEQUENCE_CHECKER
+
+void SequenceCheckerTest::DifferentSequenceTokensDeathTest() {
+  scoped_ptr<SequenceCheckedObject> sequence_checked_object(
+      new SequenceCheckedObject);
+
+  sequence_checked_object->DetachFromSequence();
+  PostDoStuffToWorkerPool(sequence_checked_object.get(), "A");
+  PostDoStuffToWorkerPool(sequence_checked_object.get(), "A");
+  PostDoStuffToWorkerPool(sequence_checked_object.get(), "B");
+  PostDoStuffToWorkerPool(sequence_checked_object.get(), "B");
+  pool()->FlushForTesting();
+
+  PostDeleteToOtherThread(sequence_checked_object.Pass());
+  other_thread()->Stop();
+}
+
+#if ENABLE_SEQUENCE_CHECKER
+TEST_F(SequenceCheckerTest, DifferentSequenceTokensDeathTestInDebug) {
+  // The default style "fast" does not support multi-threaded tests.
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  ASSERT_DEATH({
+    DifferentSequenceTokensDeathTest();
+  }, "");
+}
+#else
+TEST_F(SequenceCheckerTest, DifferentSequenceTokensDeathTestInRelease) {
+  DifferentSequenceTokensDeathTest();
+}
+#endif  // ENABLE_SEQUENCE_CHECKER
+
+void SequenceCheckerTest::WorkerPoolAndSimpleThreadDeathTest() {
+  scoped_ptr<SequenceCheckedObject> sequence_checked_object(
+      new SequenceCheckedObject);
+
+  sequence_checked_object->DetachFromSequence();
+  PostDoStuffToWorkerPool(sequence_checked_object.get(), "A");
+  PostDoStuffToWorkerPool(sequence_checked_object.get(), "A");
+  pool()->FlushForTesting();
+
+  PostDoStuffToOtherThread(sequence_checked_object.get());
+  other_thread()->Stop();
+}
+
+#if ENABLE_SEQUENCE_CHECKER
+TEST_F(SequenceCheckerTest, WorkerPoolAndSimpleThreadDeathTestInDebug) {
+  // The default style "fast" does not support multi-threaded tests.
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  ASSERT_DEATH({
+    WorkerPoolAndSimpleThreadDeathTest();
+  }, "");
+}
+#else
+TEST_F(SequenceCheckerTest, WorkerPoolAndSimpleThreadDeathTestInRelease) {
+  WorkerPoolAndSimpleThreadDeathTest();
+}
+#endif  // ENABLE_SEQUENCE_CHECKER
+
+void SequenceCheckerTest::TwoDifferentWorkerPoolsDeathTest() {
+  scoped_ptr<SequenceCheckedObject> sequence_checked_object(
+      new SequenceCheckedObject);
+
+  sequence_checked_object->DetachFromSequence();
+  PostDoStuffToWorkerPool(sequence_checked_object.get(), "A");
+  PostDoStuffToWorkerPool(sequence_checked_object.get(), "A");
+  pool()->FlushForTesting();
+
+  SequencedWorkerPoolOwner second_pool_owner(kNumWorkerThreads, "test2");
+  second_pool_owner.pool()->PostNamedSequencedWorkerTask(
+      "A",
+      FROM_HERE,
+      base::Bind(&SequenceCheckedObject::DoStuff,
+                 base::Unretained(sequence_checked_object.get())));
+  second_pool_owner.pool()->FlushForTesting();
+  second_pool_owner.pool()->Shutdown();
+}
+
+#if ENABLE_SEQUENCE_CHECKER
+TEST_F(SequenceCheckerTest, TwoDifferentWorkerPoolsDeathTestInDebug) {
+  // The default style "fast" does not support multi-threaded tests.
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  ASSERT_DEATH({
+    TwoDifferentWorkerPoolsDeathTest();
+  }, "");
+}
+#else
+TEST_F(SequenceCheckerTest, TwoDifferentWorkerPoolsDeathTestInRelease) {
+  TwoDifferentWorkerPoolsDeathTest();
+}
+#endif  // ENABLE_SEQUENCE_CHECKER
+
+#endif  // GTEST_HAS_DEATH_TEST || !ENABLE_SEQUENCE_CHECKER
+
+}  // namespace
+
+}  // namespace base
+
+// Just in case we ever get lumped together with other compilation units.
+#undef ENABLE_SEQUENCE_CHECKER
diff --git a/base/sequenced_task_runner.cc b/base/sequenced_task_runner.cc
new file mode 100644
index 0000000..00d4048
--- /dev/null
+++ b/base/sequenced_task_runner.cc
@@ -0,0 +1,31 @@
+// Copyright (c) 2012 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/sequenced_task_runner.h"
+
+#include "base/bind.h"
+
+namespace base {
+
+bool SequencedTaskRunner::PostNonNestableTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task) {
+  return PostNonNestableDelayedTask(from_here, task, base::TimeDelta());
+}
+
+bool SequencedTaskRunner::DeleteSoonInternal(
+    const tracked_objects::Location& from_here,
+    void(*deleter)(const void*),
+    const void* object) {
+  return PostNonNestableTask(from_here, Bind(deleter, object));
+}
+
+bool SequencedTaskRunner::ReleaseSoonInternal(
+    const tracked_objects::Location& from_here,
+    void(*releaser)(const void*),
+    const void* object) {
+  return PostNonNestableTask(from_here, Bind(releaser, object));
+}
+
+}  // namespace base
diff --git a/base/sequenced_task_runner.h b/base/sequenced_task_runner.h
new file mode 100644
index 0000000..6bb3f2b
--- /dev/null
+++ b/base/sequenced_task_runner.h
@@ -0,0 +1,159 @@
+// Copyright (c) 2012 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_SEQUENCED_TASK_RUNNER_H_
+#define BASE_SEQUENCED_TASK_RUNNER_H_
+
+#include "base/base_export.h"
+#include "base/sequenced_task_runner_helpers.h"
+#include "base/task_runner.h"
+
+namespace base {
+
+// A SequencedTaskRunner is a subclass of TaskRunner that provides
+// additional guarantees on the order that tasks are started, as well
+// as guarantees on when tasks are in sequence, i.e. one task finishes
+// before the other one starts.
+//
+// Summary
+// -------
+// Non-nested tasks with the same delay will run one by one in FIFO
+// order.
+//
+// Detailed guarantees
+// -------------------
+//
+// SequencedTaskRunner also adds additional methods for posting
+// non-nestable tasks.  In general, an implementation of TaskRunner
+// may expose task-running methods which are themselves callable from
+// within tasks.  A non-nestable task is one that is guaranteed to not
+// be run from within an already-running task.  Conversely, a nestable
+// task (the default) is a task that can be run from within an
+// already-running task.
+//
+// The guarantees of SequencedTaskRunner are as follows:
+//
+//   - Given two tasks T2 and T1, T2 will start after T1 starts if:
+//
+//       * T2 is posted after T1; and
+//       * T2 has equal or higher delay than T1; and
+//       * T2 is non-nestable or T1 is nestable.
+//
+//   - If T2 will start after T1 starts by the above guarantee, then
+//     T2 will start after T1 finishes and is destroyed if:
+//
+//       * T2 is non-nestable, or
+//       * T1 doesn't call any task-running methods.
+//
+//   - If T2 will start after T1 finishes by the above guarantee, then
+//     all memory changes in T1 and T1's destruction will be visible
+//     to T2.
+//
+//   - If T2 runs nested within T1 via a call to the task-running
+//     method M, then all memory changes in T1 up to the call to M
+//     will be visible to T2, and all memory changes in T2 will be
+//     visible to T1 from the return from M.
+//
+// Note that SequencedTaskRunner does not guarantee that tasks are run
+// on a single dedicated thread, although the above guarantees provide
+// most (but not all) of the same guarantees.  If you do need to
+// guarantee that tasks are run on a single dedicated thread, see
+// SingleThreadTaskRunner (in single_thread_task_runner.h).
+//
+// Some corollaries to the above guarantees, assuming the tasks in
+// question don't call any task-running methods:
+//
+//   - Tasks posted via PostTask are run in FIFO order.
+//
+//   - Tasks posted via PostNonNestableTask are run in FIFO order.
+//
+//   - Tasks posted with the same delay and the same nestable state
+//     are run in FIFO order.
+//
+//   - A list of tasks with the same nestable state posted in order of
+//     non-decreasing delay is run in FIFO order.
+//
+//   - A list of tasks posted in order of non-decreasing delay with at
+//     most a single change in nestable state from nestable to
+//     non-nestable is run in FIFO order. (This is equivalent to the
+//     statement of the first guarantee above.)
+//
+// Some theoretical implementations of SequencedTaskRunner:
+//
+//   - A SequencedTaskRunner that wraps a regular TaskRunner but makes
+//     sure that only one task at a time is posted to the TaskRunner,
+//     with appropriate memory barriers in between tasks.
+//
+//   - A SequencedTaskRunner that, for each task, spawns a joinable
+//     thread to run that task and immediately quit, and then
+//     immediately joins that thread.
+//
+//   - A SequencedTaskRunner that stores the list of posted tasks and
+//     has a method Run() that runs each runnable task in FIFO order
+//     that can be called from any thread, but only if another
+//     (non-nested) Run() call isn't already happening.
+class BASE_EXPORT SequencedTaskRunner : public TaskRunner {
+ public:
+  // The two PostNonNestable*Task methods below are like their
+  // nestable equivalents in TaskRunner, but they guarantee that the
+  // posted task will not run nested within an already-running task.
+  //
+  // A simple corollary is that posting a task as non-nestable can
+  // only delay when the task gets run.  That is, posting a task as
+  // non-nestable may not affect when the task gets run, or it could
+  // make it run later than it normally would, but it won't make it
+  // run earlier than it normally would.
+
+  // TODO(akalin): Get rid of the boolean return value for the methods
+  // below.
+
+  bool PostNonNestableTask(const tracked_objects::Location& from_here,
+                           const Closure& task);
+
+  virtual bool PostNonNestableDelayedTask(
+      const tracked_objects::Location& from_here,
+      const Closure& task,
+      base::TimeDelta delay) = 0;
+
+  // Submits a non-nestable task to delete the given object.  Returns
+  // true if the object may be deleted at some point in the future,
+  // and false if the object definitely will not be deleted.
+  template <class T>
+  bool DeleteSoon(const tracked_objects::Location& from_here,
+                  const T* object) {
+    return
+        subtle::DeleteHelperInternal<T, bool>::DeleteViaSequencedTaskRunner(
+            this, from_here, object);
+  }
+
+  // Submits a non-nestable task to release the given object.  Returns
+  // true if the object may be released at some point in the future,
+  // and false if the object definitely will not be released.
+  template <class T>
+  bool ReleaseSoon(const tracked_objects::Location& from_here,
+                   T* object) {
+    return
+        subtle::ReleaseHelperInternal<T, bool>::ReleaseViaSequencedTaskRunner(
+            this, from_here, object);
+  }
+
+ protected:
+  ~SequencedTaskRunner() override {}
+
+ private:
+  template <class T, class R> friend class subtle::DeleteHelperInternal;
+  template <class T, class R> friend class subtle::ReleaseHelperInternal;
+
+  bool DeleteSoonInternal(const tracked_objects::Location& from_here,
+                          void(*deleter)(const void*),
+                          const void* object);
+
+  bool ReleaseSoonInternal(const tracked_objects::Location& from_here,
+                           void(*releaser)(const void*),
+                           const void* object);
+};
+
+}  // namespace base
+
+#endif  // BASE_SEQUENCED_TASK_RUNNER_H_
diff --git a/base/sequenced_task_runner_helpers.h b/base/sequenced_task_runner_helpers.h
new file mode 100644
index 0000000..da519bf
--- /dev/null
+++ b/base/sequenced_task_runner_helpers.h
@@ -0,0 +1,113 @@
+// Copyright (c) 2012 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_SEQUENCED_TASK_RUNNER_HELPERS_H_
+#define BASE_SEQUENCED_TASK_RUNNER_HELPERS_H_
+
+#include "base/basictypes.h"
+#include "base/debug/alias.h"
+
+// TODO(akalin): Investigate whether it's possible to just have
+// SequencedTaskRunner use these helpers (instead of MessageLoop).
+// Then we can just move these to sequenced_task_runner.h.
+
+namespace tracked_objects {
+class Location;
+}
+
+namespace base {
+
+namespace subtle {
+template <class T, class R> class DeleteHelperInternal;
+template <class T, class R> class ReleaseHelperInternal;
+}
+
+// Template helpers which use function indirection to erase T from the
+// function signature while still remembering it so we can call the
+// correct destructor/release function.
+//
+// We use this trick so we don't need to include bind.h in a header
+// file like sequenced_task_runner.h. We also wrap the helpers in a
+// templated class to make it easier for users of DeleteSoon to
+// declare the helper as a friend.
+template <class T>
+class DeleteHelper {
+ private:
+  template <class T2, class R> friend class subtle::DeleteHelperInternal;
+
+  static void DoDelete(const void* object) {
+    delete reinterpret_cast<const T*>(object);
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(DeleteHelper);
+};
+
+template <class T>
+class ReleaseHelper {
+ private:
+  template <class T2, class R> friend class subtle::ReleaseHelperInternal;
+
+  static void DoRelease(const void* object) {
+    reinterpret_cast<const T*>(object)->Release();
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(ReleaseHelper);
+};
+
+namespace subtle {
+
+// An internal SequencedTaskRunner-like class helper for DeleteHelper
+// and ReleaseHelper.  We don't want to expose the Do*() functions
+// directly directly since the void* argument makes it possible to
+// pass/ an object of the wrong type to delete.  Instead, we force
+// callers to go through these internal helpers for type
+// safety. SequencedTaskRunner-like classes which expose DeleteSoon or
+// ReleaseSoon methods should friend the appropriate helper and
+// implement a corresponding *Internal method with the following
+// signature:
+//
+// bool(const tracked_objects::Location&,
+//      void(*function)(const void*),
+//      void* object)
+//
+// An implementation of this function should simply create a
+// base::Closure from (function, object) and return the result of
+// posting the task.
+template <class T, class ReturnType>
+class DeleteHelperInternal {
+ public:
+  template <class SequencedTaskRunnerType>
+  static ReturnType DeleteViaSequencedTaskRunner(
+      SequencedTaskRunnerType* sequenced_task_runner,
+      const tracked_objects::Location& from_here,
+      const T* object) {
+    return sequenced_task_runner->DeleteSoonInternal(
+        from_here, &DeleteHelper<T>::DoDelete, object);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DeleteHelperInternal);
+};
+
+template <class T, class ReturnType>
+class ReleaseHelperInternal {
+ public:
+  template <class SequencedTaskRunnerType>
+  static ReturnType ReleaseViaSequencedTaskRunner(
+      SequencedTaskRunnerType* sequenced_task_runner,
+      const tracked_objects::Location& from_here,
+      const T* object) {
+    return sequenced_task_runner->ReleaseSoonInternal(
+        from_here, &ReleaseHelper<T>::DoRelease, object);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ReleaseHelperInternal);
+};
+
+}  // namespace subtle
+
+}  // namespace base
+
+#endif  // BASE_SEQUENCED_TASK_RUNNER_HELPERS_H_
diff --git a/base/sha1.h b/base/sha1.h
new file mode 100644
index 0000000..998cccb
--- /dev/null
+++ b/base/sha1.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2011 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_SHA1_H_
+#define BASE_SHA1_H_
+
+#include <string>
+
+#include "base/base_export.h"
+
+namespace base {
+
+// These functions perform SHA-1 operations.
+
+static const size_t kSHA1Length = 20;  // Length in bytes of a SHA-1 hash.
+
+// Computes the SHA-1 hash of the input string |str| and returns the full
+// hash.
+BASE_EXPORT std::string SHA1HashString(const std::string& str);
+
+// Computes the SHA-1 hash of the |len| bytes in |data| and puts the hash
+// in |hash|. |hash| must be kSHA1Length bytes long.
+BASE_EXPORT void SHA1HashBytes(const unsigned char* data, size_t len,
+                               unsigned char* hash);
+
+}  // namespace base
+
+#endif  // BASE_SHA1_H_
diff --git a/base/sha1_portable.cc b/base/sha1_portable.cc
new file mode 100644
index 0000000..0b9df83
--- /dev/null
+++ b/base/sha1_portable.cc
@@ -0,0 +1,216 @@
+// Copyright (c) 2011 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/sha1.h"
+
+#include <string.h>
+
+#include "base/basictypes.h"
+
+namespace base {
+
+// Implementation of SHA-1. Only handles data in byte-sized blocks,
+// which simplifies the code a fair bit.
+
+// Identifier names follow notation in FIPS PUB 180-3, where you'll
+// also find a description of the algorithm:
+// http://csrc.nist.gov/publications/fips/fips180-3/fips180-3_final.pdf
+
+// Usage example:
+//
+// SecureHashAlgorithm sha;
+// while(there is data to hash)
+//   sha.Update(moredata, size of data);
+// sha.Final();
+// memcpy(somewhere, sha.Digest(), 20);
+//
+// to reuse the instance of sha, call sha.Init();
+
+// TODO(jhawkins): Replace this implementation with a per-platform
+// implementation using each platform's crypto library.  See
+// http://crbug.com/47218
+
+class SecureHashAlgorithm {
+ public:
+  SecureHashAlgorithm() { Init(); }
+
+  static const int kDigestSizeBytes;
+
+  void Init();
+  void Update(const void* data, size_t nbytes);
+  void Final();
+
+  // 20 bytes of message digest.
+  const unsigned char* Digest() const {
+    return reinterpret_cast<const unsigned char*>(H);
+  }
+
+ private:
+  void Pad();
+  void Process();
+
+  uint32 A, B, C, D, E;
+
+  uint32 H[5];
+
+  union {
+    uint32 W[80];
+    uint8 M[64];
+  };
+
+  uint32 cursor;
+  uint64 l;
+};
+
+static inline uint32 f(uint32 t, uint32 B, uint32 C, uint32 D) {
+  if (t < 20) {
+    return (B & C) | ((~B) & D);
+  } else if (t < 40) {
+    return B ^ C ^ D;
+  } else if (t < 60) {
+    return (B & C) | (B & D) | (C & D);
+  } else {
+    return B ^ C ^ D;
+  }
+}
+
+static inline uint32 S(uint32 n, uint32 X) {
+  return (X << n) | (X >> (32-n));
+}
+
+static inline uint32 K(uint32 t) {
+  if (t < 20) {
+    return 0x5a827999;
+  } else if (t < 40) {
+    return 0x6ed9eba1;
+  } else if (t < 60) {
+    return 0x8f1bbcdc;
+  } else {
+    return 0xca62c1d6;
+  }
+}
+
+static inline void swapends(uint32* t) {
+  *t = (*t >> 24) | ((*t >> 8) & 0xff00) | ((*t & 0xff00) << 8) | (*t << 24);
+}
+
+const int SecureHashAlgorithm::kDigestSizeBytes = 20;
+
+void SecureHashAlgorithm::Init() {
+  A = 0;
+  B = 0;
+  C = 0;
+  D = 0;
+  E = 0;
+  cursor = 0;
+  l = 0;
+  H[0] = 0x67452301;
+  H[1] = 0xefcdab89;
+  H[2] = 0x98badcfe;
+  H[3] = 0x10325476;
+  H[4] = 0xc3d2e1f0;
+}
+
+void SecureHashAlgorithm::Final() {
+  Pad();
+  Process();
+
+  for (int t = 0; t < 5; ++t)
+    swapends(&H[t]);
+}
+
+void SecureHashAlgorithm::Update(const void* data, size_t nbytes) {
+  const uint8* d = reinterpret_cast<const uint8*>(data);
+  while (nbytes--) {
+    M[cursor++] = *d++;
+    if (cursor >= 64)
+      Process();
+    l += 8;
+  }
+}
+
+void SecureHashAlgorithm::Pad() {
+  M[cursor++] = 0x80;
+
+  if (cursor > 64-8) {
+    // pad out to next block
+    while (cursor < 64)
+      M[cursor++] = 0;
+
+    Process();
+  }
+
+  while (cursor < 64-8)
+    M[cursor++] = 0;
+
+  M[cursor++] = (l >> 56) & 0xff;
+  M[cursor++] = (l >> 48) & 0xff;
+  M[cursor++] = (l >> 40) & 0xff;
+  M[cursor++] = (l >> 32) & 0xff;
+  M[cursor++] = (l >> 24) & 0xff;
+  M[cursor++] = (l >> 16) & 0xff;
+  M[cursor++] = (l >> 8) & 0xff;
+  M[cursor++] = l & 0xff;
+}
+
+void SecureHashAlgorithm::Process() {
+  uint32 t;
+
+  // Each a...e corresponds to a section in the FIPS 180-3 algorithm.
+
+  // a.
+  //
+  // W and M are in a union, so no need to memcpy.
+  // memcpy(W, M, sizeof(M));
+  for (t = 0; t < 16; ++t)
+    swapends(&W[t]);
+
+  // b.
+  for (t = 16; t < 80; ++t)
+    W[t] = S(1, W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]);
+
+  // c.
+  A = H[0];
+  B = H[1];
+  C = H[2];
+  D = H[3];
+  E = H[4];
+
+  // d.
+  for (t = 0; t < 80; ++t) {
+    uint32 TEMP = S(5, A) + f(t, B, C, D) + E + W[t] + K(t);
+    E = D;
+    D = C;
+    C = S(30, B);
+    B = A;
+    A = TEMP;
+  }
+
+  // e.
+  H[0] += A;
+  H[1] += B;
+  H[2] += C;
+  H[3] += D;
+  H[4] += E;
+
+  cursor = 0;
+}
+
+std::string SHA1HashString(const std::string& str) {
+  char hash[SecureHashAlgorithm::kDigestSizeBytes];
+  SHA1HashBytes(reinterpret_cast<const unsigned char*>(str.c_str()),
+                str.length(), reinterpret_cast<unsigned char*>(hash));
+  return std::string(hash, SecureHashAlgorithm::kDigestSizeBytes);
+}
+
+void SHA1HashBytes(const unsigned char* data, size_t len,
+                   unsigned char* hash) {
+  SecureHashAlgorithm sha;
+  sha.Update(data, len);
+  sha.Final();
+
+  memcpy(hash, sha.Digest(), SecureHashAlgorithm::kDigestSizeBytes);
+}
+
+}  // namespace base
diff --git a/base/sha1_unittest.cc b/base/sha1_unittest.cc
new file mode 100644
index 0000000..b29fe46
--- /dev/null
+++ b/base/sha1_unittest.cc
@@ -0,0 +1,108 @@
+// Copyright (c) 2011 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/sha1.h"
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(SHA1Test, Test1) {
+  // Example A.1 from FIPS 180-2: one-block message.
+  std::string input = "abc";
+
+  int expected[] = { 0xa9, 0x99, 0x3e, 0x36,
+                     0x47, 0x06, 0x81, 0x6a,
+                     0xba, 0x3e, 0x25, 0x71,
+                     0x78, 0x50, 0xc2, 0x6c,
+                     0x9c, 0xd0, 0xd8, 0x9d };
+
+  std::string output = base::SHA1HashString(input);
+  for (size_t i = 0; i < base::kSHA1Length; i++)
+    EXPECT_EQ(expected[i], output[i] & 0xFF);
+}
+
+TEST(SHA1Test, Test2) {
+  // Example A.2 from FIPS 180-2: multi-block message.
+  std::string input =
+      "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
+
+  int expected[] = { 0x84, 0x98, 0x3e, 0x44,
+                     0x1c, 0x3b, 0xd2, 0x6e,
+                     0xba, 0xae, 0x4a, 0xa1,
+                     0xf9, 0x51, 0x29, 0xe5,
+                     0xe5, 0x46, 0x70, 0xf1 };
+
+  std::string output = base::SHA1HashString(input);
+  for (size_t i = 0; i < base::kSHA1Length; i++)
+    EXPECT_EQ(expected[i], output[i] & 0xFF);
+}
+
+TEST(SHA1Test, Test3) {
+  // Example A.3 from FIPS 180-2: long message.
+  std::string input(1000000, 'a');
+
+  int expected[] = { 0x34, 0xaa, 0x97, 0x3c,
+                     0xd4, 0xc4, 0xda, 0xa4,
+                     0xf6, 0x1e, 0xeb, 0x2b,
+                     0xdb, 0xad, 0x27, 0x31,
+                     0x65, 0x34, 0x01, 0x6f };
+
+  std::string output = base::SHA1HashString(input);
+  for (size_t i = 0; i < base::kSHA1Length; i++)
+    EXPECT_EQ(expected[i], output[i] & 0xFF);
+}
+
+TEST(SHA1Test, Test1Bytes) {
+  // Example A.1 from FIPS 180-2: one-block message.
+  std::string input = "abc";
+  unsigned char output[base::kSHA1Length];
+
+  unsigned char expected[] = { 0xa9, 0x99, 0x3e, 0x36,
+                               0x47, 0x06, 0x81, 0x6a,
+                               0xba, 0x3e, 0x25, 0x71,
+                               0x78, 0x50, 0xc2, 0x6c,
+                               0x9c, 0xd0, 0xd8, 0x9d };
+
+  base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(input.c_str()),
+                      input.length(), output);
+  for (size_t i = 0; i < base::kSHA1Length; i++)
+    EXPECT_EQ(expected[i], output[i]);
+}
+
+TEST(SHA1Test, Test2Bytes) {
+  // Example A.2 from FIPS 180-2: multi-block message.
+  std::string input =
+      "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
+  unsigned char output[base::kSHA1Length];
+
+  unsigned char expected[] = { 0x84, 0x98, 0x3e, 0x44,
+                               0x1c, 0x3b, 0xd2, 0x6e,
+                               0xba, 0xae, 0x4a, 0xa1,
+                               0xf9, 0x51, 0x29, 0xe5,
+                               0xe5, 0x46, 0x70, 0xf1 };
+
+  base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(input.c_str()),
+                      input.length(), output);
+  for (size_t i = 0; i < base::kSHA1Length; i++)
+    EXPECT_EQ(expected[i], output[i]);
+}
+
+TEST(SHA1Test, Test3Bytes) {
+  // Example A.3 from FIPS 180-2: long message.
+  std::string input(1000000, 'a');
+  unsigned char output[base::kSHA1Length];
+
+  unsigned char expected[] = { 0x34, 0xaa, 0x97, 0x3c,
+                               0xd4, 0xc4, 0xda, 0xa4,
+                               0xf6, 0x1e, 0xeb, 0x2b,
+                               0xdb, 0xad, 0x27, 0x31,
+                               0x65, 0x34, 0x01, 0x6f };
+
+  base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(input.c_str()),
+                      input.length(), output);
+  for (size_t i = 0; i < base::kSHA1Length; i++)
+    EXPECT_EQ(expected[i], output[i]);
+}
diff --git a/base/sha1_win.cc b/base/sha1_win.cc
new file mode 100644
index 0000000..b64c9eb
--- /dev/null
+++ b/base/sha1_win.cc
@@ -0,0 +1,67 @@
+// Copyright (c) 2011 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/sha1.h"
+
+#include <windows.h>
+#include <wincrypt.h>
+
+// This file is not being compiled at the moment (see bug 47218). If we keep
+// sha1 inside base, we cannot depend on src/crypto.
+// #include "crypto/scoped_capi_types.h"
+#include "base/logging.h"
+
+namespace base {
+
+std::string SHA1HashString(const std::string& str) {
+  ScopedHCRYPTPROV provider;
+  if (!CryptAcquireContext(provider.receive(), NULL, NULL, PROV_RSA_FULL,
+                           CRYPT_VERIFYCONTEXT)) {
+    DPLOG(ERROR) << "CryptAcquireContext failed";
+    return std::string(kSHA1Length, '\0');
+  }
+
+  {
+    ScopedHCRYPTHASH hash;
+    if (!CryptCreateHash(provider, CALG_SHA1, 0, 0, hash.receive())) {
+      DPLOG(ERROR) << "CryptCreateHash failed";
+      return std::string(kSHA1Length, '\0');
+    }
+
+    if (!CryptHashData(hash, reinterpret_cast<CONST BYTE*>(str.data()),
+                       static_cast<DWORD>(str.length()), 0)) {
+      DPLOG(ERROR) << "CryptHashData failed";
+      return std::string(kSHA1Length, '\0');
+    }
+
+    DWORD hash_len = 0;
+    DWORD buffer_size = sizeof hash_len;
+    if (!CryptGetHashParam(hash, HP_HASHSIZE,
+                           reinterpret_cast<unsigned char*>(&hash_len),
+                           &buffer_size, 0)) {
+      DPLOG(ERROR) << "CryptGetHashParam(HP_HASHSIZE) failed";
+      return std::string(kSHA1Length, '\0');
+    }
+
+    std::string result;
+    if (!CryptGetHashParam(hash, HP_HASHVAL,
+        // We need the + 1 here not because the call will write a trailing \0,
+        // but so that result.length() is correctly set to |hash_len|.
+        reinterpret_cast<BYTE*>(WriteInto(&result, hash_len + 1)), &hash_len,
+        0))) {
+      DPLOG(ERROR) << "CryptGetHashParam(HP_HASHVAL) failed";
+      return std::string(kSHA1Length, '\0');
+    }
+
+    if (hash_len != kSHA1Length) {
+      DLOG(ERROR) << "Returned hash value is wrong length: " << hash_len
+                  << " should be " << kSHA1Length;
+      return std::string(kSHA1Length, '\0');
+    }
+
+    return result;
+  }
+}
+
+}  // namespace base
diff --git a/base/single_thread_task_runner.h b/base/single_thread_task_runner.h
new file mode 100644
index 0000000..6e93193
--- /dev/null
+++ b/base/single_thread_task_runner.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2012 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_SINGLE_THREAD_TASK_RUNNER_H_
+#define BASE_SINGLE_THREAD_TASK_RUNNER_H_
+
+#include "base/base_export.h"
+#include "base/sequenced_task_runner.h"
+
+namespace base {
+
+// A SingleThreadTaskRunner is a SequencedTaskRunner with one more
+// guarantee; namely, that all tasks are run on a single dedicated
+// thread.  Most use cases require only a SequencedTaskRunner, unless
+// there is a specific need to run tasks on only a single thread.
+//
+// SingleThreadTaskRunner implementations might:
+//   - Post tasks to an existing thread's MessageLoop (see
+//     MessageLoop::task_runner()).
+//   - Create their own worker thread and MessageLoop to post tasks to.
+//   - Add tasks to a FIFO and signal to a non-MessageLoop thread for them to
+//     be processed. This allows TaskRunner-oriented code run on threads
+//     running other kinds of message loop, e.g. Jingle threads.
+class BASE_EXPORT SingleThreadTaskRunner : public SequencedTaskRunner {
+ public:
+  // A more explicit alias to RunsTasksOnCurrentThread().
+  bool BelongsToCurrentThread() const {
+    return RunsTasksOnCurrentThread();
+  }
+
+ protected:
+  ~SingleThreadTaskRunner() override {}
+};
+
+}  // namespace base
+
+#endif  // BASE_SINGLE_THREAD_TASK_RUNNER_H_
diff --git a/base/stl_util.h b/base/stl_util.h
new file mode 100644
index 0000000..e937d2f
--- /dev/null
+++ b/base/stl_util.h
@@ -0,0 +1,275 @@
+// Copyright (c) 2011 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.
+
+// Derived from google3/util/gtl/stl_util.h
+
+#ifndef BASE_STL_UTIL_H_
+#define BASE_STL_UTIL_H_
+
+#include <algorithm>
+#include <functional>
+#include <iterator>
+#include <string>
+#include <vector>
+
+#include "base/logging.h"
+
+// Clears internal memory of an STL object.
+// STL clear()/reserve(0) does not always free internal memory allocated
+// This function uses swap/destructor to ensure the internal memory is freed.
+template<class T>
+void STLClearObject(T* obj) {
+  T tmp;
+  tmp.swap(*obj);
+  // Sometimes "T tmp" allocates objects with memory (arena implementation?).
+  // Hence using additional reserve(0) even if it doesn't always work.
+  obj->reserve(0);
+}
+
+// For a range within a container of pointers, calls delete (non-array version)
+// on these pointers.
+// NOTE: for these three functions, we could just implement a DeleteObject
+// functor and then call for_each() on the range and functor, but this
+// requires us to pull in all of algorithm.h, which seems expensive.
+// For hash_[multi]set, it is important that this deletes behind the iterator
+// because the hash_set may call the hash function on the iterator when it is
+// advanced, which could result in the hash function trying to deference a
+// stale pointer.
+template <class ForwardIterator>
+void STLDeleteContainerPointers(ForwardIterator begin, ForwardIterator end) {
+  while (begin != end) {
+    ForwardIterator temp = begin;
+    ++begin;
+    delete *temp;
+  }
+}
+
+// For a range within a container of pairs, calls delete (non-array version) on
+// BOTH items in the pairs.
+// NOTE: Like STLDeleteContainerPointers, it is important that this deletes
+// behind the iterator because if both the key and value are deleted, the
+// container may call the hash function on the iterator when it is advanced,
+// which could result in the hash function trying to dereference a stale
+// pointer.
+template <class ForwardIterator>
+void STLDeleteContainerPairPointers(ForwardIterator begin,
+                                    ForwardIterator end) {
+  while (begin != end) {
+    ForwardIterator temp = begin;
+    ++begin;
+    delete temp->first;
+    delete temp->second;
+  }
+}
+
+// For a range within a container of pairs, calls delete (non-array version) on
+// the FIRST item in the pairs.
+// NOTE: Like STLDeleteContainerPointers, deleting behind the iterator.
+template <class ForwardIterator>
+void STLDeleteContainerPairFirstPointers(ForwardIterator begin,
+                                         ForwardIterator end) {
+  while (begin != end) {
+    ForwardIterator temp = begin;
+    ++begin;
+    delete temp->first;
+  }
+}
+
+// For a range within a container of pairs, calls delete.
+// NOTE: Like STLDeleteContainerPointers, deleting behind the iterator.
+// Deleting the value does not always invalidate the iterator, but it may
+// do so if the key is a pointer into the value object.
+template <class ForwardIterator>
+void STLDeleteContainerPairSecondPointers(ForwardIterator begin,
+                                          ForwardIterator end) {
+  while (begin != end) {
+    ForwardIterator temp = begin;
+    ++begin;
+    delete temp->second;
+  }
+}
+
+// Counts the number of instances of val in a container.
+template <typename Container, typename T>
+typename std::iterator_traits<
+    typename Container::const_iterator>::difference_type
+STLCount(const Container& container, const T& val) {
+  return std::count(container.begin(), container.end(), val);
+}
+
+// To treat a possibly-empty vector as an array, use these functions.
+// If you know the array will never be empty, you can use &*v.begin()
+// directly, but that is undefined behaviour if |v| is empty.
+template<typename T>
+inline T* vector_as_array(std::vector<T>* v) {
+  return v->empty() ? NULL : &*v->begin();
+}
+
+template<typename T>
+inline const T* vector_as_array(const std::vector<T>* v) {
+  return v->empty() ? NULL : &*v->begin();
+}
+
+// Return a mutable char* pointing to a string's internal buffer,
+// which may not be null-terminated. Writing through this pointer will
+// modify the string.
+//
+// string_as_array(&str)[i] is valid for 0 <= i < str.size() until the
+// next call to a string method that invalidates iterators.
+//
+// As of 2006-04, there is no standard-blessed way of getting a
+// mutable reference to a string's internal buffer. However, issue 530
+// (http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-active.html#530)
+// proposes this as the method. According to Matt Austern, this should
+// already work on all current implementations.
+inline char* string_as_array(std::string* str) {
+  // DO NOT USE const_cast<char*>(str->data())
+  return str->empty() ? NULL : &*str->begin();
+}
+
+// The following functions are useful for cleaning up STL containers whose
+// elements point to allocated memory.
+
+// STLDeleteElements() deletes all the elements in an STL container and clears
+// the container.  This function is suitable for use with a vector, set,
+// hash_set, or any other STL container which defines sensible begin(), end(),
+// and clear() methods.
+//
+// If container is NULL, this function is a no-op.
+//
+// As an alternative to calling STLDeleteElements() directly, consider
+// STLElementDeleter (defined below), which ensures that your container's
+// elements are deleted when the STLElementDeleter goes out of scope.
+template <class T>
+void STLDeleteElements(T* container) {
+  if (!container)
+    return;
+  STLDeleteContainerPointers(container->begin(), container->end());
+  container->clear();
+}
+
+// Given an STL container consisting of (key, value) pairs, STLDeleteValues
+// deletes all the "value" components and clears the container.  Does nothing
+// in the case it's given a NULL pointer.
+template <class T>
+void STLDeleteValues(T* container) {
+  if (!container)
+    return;
+  STLDeleteContainerPairSecondPointers(container->begin(), container->end());
+  container->clear();
+}
+
+
+// The following classes provide a convenient way to delete all elements or
+// values from STL containers when they goes out of scope.  This greatly
+// simplifies code that creates temporary objects and has multiple return
+// statements.  Example:
+//
+// vector<MyProto *> tmp_proto;
+// STLElementDeleter<vector<MyProto *> > d(&tmp_proto);
+// if (...) return false;
+// ...
+// return success;
+
+// Given a pointer to an STL container this class will delete all the element
+// pointers when it goes out of scope.
+template<class T>
+class STLElementDeleter {
+ public:
+  STLElementDeleter<T>(T* container) : container_(container) {}
+  ~STLElementDeleter<T>() { STLDeleteElements(container_); }
+
+ private:
+  T* container_;
+};
+
+// Given a pointer to an STL container this class will delete all the value
+// pointers when it goes out of scope.
+template<class T>
+class STLValueDeleter {
+ public:
+  STLValueDeleter<T>(T* container) : container_(container) {}
+  ~STLValueDeleter<T>() { STLDeleteValues(container_); }
+
+ private:
+  T* container_;
+};
+
+// Test to see if a set, map, hash_set or hash_map contains a particular key.
+// Returns true if the key is in the collection.
+template <typename Collection, typename Key>
+bool ContainsKey(const Collection& collection, const Key& key) {
+  return collection.find(key) != collection.end();
+}
+
+// Test to see if a collection like a vector contains a particular value.
+// Returns true if the value is in the collection.
+template <typename Collection, typename Value>
+bool ContainsValue(const Collection& collection, const Value& value) {
+  return std::find(collection.begin(), collection.end(), value) !=
+      collection.end();
+}
+
+namespace base {
+
+// Returns true if the container is sorted.
+template <typename Container>
+bool STLIsSorted(const Container& cont) {
+  // Note: Use reverse iterator on container to ensure we only require
+  // value_type to implement operator<.
+  return std::adjacent_find(cont.rbegin(), cont.rend(),
+                            std::less<typename Container::value_type>())
+      == cont.rend();
+}
+
+// Returns a new ResultType containing the difference of two sorted containers.
+template <typename ResultType, typename Arg1, typename Arg2>
+ResultType STLSetDifference(const Arg1& a1, const Arg2& a2) {
+  DCHECK(STLIsSorted(a1));
+  DCHECK(STLIsSorted(a2));
+  ResultType difference;
+  std::set_difference(a1.begin(), a1.end(),
+                      a2.begin(), a2.end(),
+                      std::inserter(difference, difference.end()));
+  return difference;
+}
+
+// Returns a new ResultType containing the union of two sorted containers.
+template <typename ResultType, typename Arg1, typename Arg2>
+ResultType STLSetUnion(const Arg1& a1, const Arg2& a2) {
+  DCHECK(STLIsSorted(a1));
+  DCHECK(STLIsSorted(a2));
+  ResultType result;
+  std::set_union(a1.begin(), a1.end(),
+                 a2.begin(), a2.end(),
+                 std::inserter(result, result.end()));
+  return result;
+}
+
+// Returns a new ResultType containing the intersection of two sorted
+// containers.
+template <typename ResultType, typename Arg1, typename Arg2>
+ResultType STLSetIntersection(const Arg1& a1, const Arg2& a2) {
+  DCHECK(STLIsSorted(a1));
+  DCHECK(STLIsSorted(a2));
+  ResultType result;
+  std::set_intersection(a1.begin(), a1.end(),
+                        a2.begin(), a2.end(),
+                        std::inserter(result, result.end()));
+  return result;
+}
+
+// Returns true if the sorted container |a1| contains all elements of the sorted
+// container |a2|.
+template <typename Arg1, typename Arg2>
+bool STLIncludes(const Arg1& a1, const Arg2& a2) {
+  DCHECK(STLIsSorted(a1));
+  DCHECK(STLIsSorted(a2));
+  return std::includes(a1.begin(), a1.end(),
+                       a2.begin(), a2.end());
+}
+
+}  // namespace base
+
+#endif  // BASE_STL_UTIL_H_
diff --git a/base/stl_util_unittest.cc b/base/stl_util_unittest.cc
new file mode 100644
index 0000000..42004eb
--- /dev/null
+++ b/base/stl_util_unittest.cc
@@ -0,0 +1,267 @@
+// Copyright 2012 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/stl_util.h"
+
+#include <set>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// Used as test case to ensure the various base::STLXxx functions don't require
+// more than operators "<" and "==" on values stored in containers.
+class ComparableValue {
+ public:
+  explicit ComparableValue(int value) : value_(value) {}
+
+  bool operator==(const ComparableValue& rhs) const {
+    return value_ == rhs.value_;
+  }
+
+  bool operator<(const ComparableValue& rhs) const {
+    return value_ < rhs.value_;
+  }
+
+ private:
+  int value_;
+};
+
+}  // namespace
+
+namespace base {
+namespace {
+
+TEST(STLUtilTest, STLIsSorted) {
+  {
+    std::set<int> set;
+    set.insert(24);
+    set.insert(1);
+    set.insert(12);
+    EXPECT_TRUE(STLIsSorted(set));
+  }
+
+  {
+    std::set<ComparableValue> set;
+    set.insert(ComparableValue(24));
+    set.insert(ComparableValue(1));
+    set.insert(ComparableValue(12));
+    EXPECT_TRUE(STLIsSorted(set));
+  }
+
+  {
+    std::vector<int> vector;
+    vector.push_back(1);
+    vector.push_back(1);
+    vector.push_back(4);
+    vector.push_back(64);
+    vector.push_back(12432);
+    EXPECT_TRUE(STLIsSorted(vector));
+    vector.back() = 1;
+    EXPECT_FALSE(STLIsSorted(vector));
+  }
+}
+
+TEST(STLUtilTest, STLSetDifference) {
+  std::set<int> a1;
+  a1.insert(1);
+  a1.insert(2);
+  a1.insert(3);
+  a1.insert(4);
+
+  std::set<int> a2;
+  a2.insert(3);
+  a2.insert(4);
+  a2.insert(5);
+  a2.insert(6);
+  a2.insert(7);
+
+  {
+    std::set<int> difference;
+    difference.insert(1);
+    difference.insert(2);
+    EXPECT_EQ(difference, STLSetDifference<std::set<int> >(a1, a2));
+  }
+
+  {
+    std::set<int> difference;
+    difference.insert(5);
+    difference.insert(6);
+    difference.insert(7);
+    EXPECT_EQ(difference, STLSetDifference<std::set<int> >(a2, a1));
+  }
+
+  {
+    std::vector<int> difference;
+    difference.push_back(1);
+    difference.push_back(2);
+    EXPECT_EQ(difference, STLSetDifference<std::vector<int> >(a1, a2));
+  }
+
+  {
+    std::vector<int> difference;
+    difference.push_back(5);
+    difference.push_back(6);
+    difference.push_back(7);
+    EXPECT_EQ(difference, STLSetDifference<std::vector<int> >(a2, a1));
+  }
+}
+
+TEST(STLUtilTest, STLSetUnion) {
+  std::set<int> a1;
+  a1.insert(1);
+  a1.insert(2);
+  a1.insert(3);
+  a1.insert(4);
+
+  std::set<int> a2;
+  a2.insert(3);
+  a2.insert(4);
+  a2.insert(5);
+  a2.insert(6);
+  a2.insert(7);
+
+  {
+    std::set<int> result;
+    result.insert(1);
+    result.insert(2);
+    result.insert(3);
+    result.insert(4);
+    result.insert(5);
+    result.insert(6);
+    result.insert(7);
+    EXPECT_EQ(result, STLSetUnion<std::set<int> >(a1, a2));
+  }
+
+  {
+    std::set<int> result;
+    result.insert(1);
+    result.insert(2);
+    result.insert(3);
+    result.insert(4);
+    result.insert(5);
+    result.insert(6);
+    result.insert(7);
+    EXPECT_EQ(result, STLSetUnion<std::set<int> >(a2, a1));
+  }
+
+  {
+    std::vector<int> result;
+    result.push_back(1);
+    result.push_back(2);
+    result.push_back(3);
+    result.push_back(4);
+    result.push_back(5);
+    result.push_back(6);
+    result.push_back(7);
+    EXPECT_EQ(result, STLSetUnion<std::vector<int> >(a1, a2));
+  }
+
+  {
+    std::vector<int> result;
+    result.push_back(1);
+    result.push_back(2);
+    result.push_back(3);
+    result.push_back(4);
+    result.push_back(5);
+    result.push_back(6);
+    result.push_back(7);
+    EXPECT_EQ(result, STLSetUnion<std::vector<int> >(a2, a1));
+  }
+}
+
+TEST(STLUtilTest, STLSetIntersection) {
+  std::set<int> a1;
+  a1.insert(1);
+  a1.insert(2);
+  a1.insert(3);
+  a1.insert(4);
+
+  std::set<int> a2;
+  a2.insert(3);
+  a2.insert(4);
+  a2.insert(5);
+  a2.insert(6);
+  a2.insert(7);
+
+  {
+    std::set<int> result;
+    result.insert(3);
+    result.insert(4);
+    EXPECT_EQ(result, STLSetIntersection<std::set<int> >(a1, a2));
+  }
+
+  {
+    std::set<int> result;
+    result.insert(3);
+    result.insert(4);
+    EXPECT_EQ(result, STLSetIntersection<std::set<int> >(a2, a1));
+  }
+
+  {
+    std::vector<int> result;
+    result.push_back(3);
+    result.push_back(4);
+    EXPECT_EQ(result, STLSetIntersection<std::vector<int> >(a1, a2));
+  }
+
+  {
+    std::vector<int> result;
+    result.push_back(3);
+    result.push_back(4);
+    EXPECT_EQ(result, STLSetIntersection<std::vector<int> >(a2, a1));
+  }
+}
+
+TEST(STLUtilTest, STLIncludes) {
+  std::set<int> a1;
+  a1.insert(1);
+  a1.insert(2);
+  a1.insert(3);
+  a1.insert(4);
+
+  std::set<int> a2;
+  a2.insert(3);
+  a2.insert(4);
+
+  std::set<int> a3;
+  a3.insert(3);
+  a3.insert(4);
+  a3.insert(5);
+
+  EXPECT_TRUE(STLIncludes<std::set<int> >(a1, a2));
+  EXPECT_FALSE(STLIncludes<std::set<int> >(a1, a3));
+  EXPECT_FALSE(STLIncludes<std::set<int> >(a2, a1));
+  EXPECT_FALSE(STLIncludes<std::set<int> >(a2, a3));
+  EXPECT_FALSE(STLIncludes<std::set<int> >(a3, a1));
+  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/base/strings/OWNERS b/base/strings/OWNERS
new file mode 100644
index 0000000..5381872
--- /dev/null
+++ b/base/strings/OWNERS
@@ -0,0 +1,2 @@
+per-file safe_sprintf*=jln@chromium.org
+per-file safe_sprintf*=mdempsky@chromium.org
diff --git a/base/strings/latin1_string_conversions.cc b/base/strings/latin1_string_conversions.cc
new file mode 100644
index 0000000..dca62ce
--- /dev/null
+++ b/base/strings/latin1_string_conversions.cc
@@ -0,0 +1,19 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/latin1_string_conversions.h"
+
+namespace base {
+
+string16 Latin1OrUTF16ToUTF16(size_t length,
+                              const Latin1Char* latin1,
+                              const char16* utf16) {
+  if (!length)
+    return string16();
+  if (latin1)
+    return string16(latin1, latin1 + length);
+  return string16(utf16, utf16 + length);
+}
+
+}  // namespace base
diff --git a/base/strings/latin1_string_conversions.h b/base/strings/latin1_string_conversions.h
new file mode 100644
index 0000000..387cb65
--- /dev/null
+++ b/base/strings/latin1_string_conversions.h
@@ -0,0 +1,32 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_STRINGS_LATIN1_STRING_CONVERSIONS_H_
+#define BASE_STRINGS_LATIN1_STRING_CONVERSIONS_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/strings/string16.h"
+
+namespace base {
+
+// This definition of Latin1Char matches the definition of LChar in Blink. We
+// use unsigned char rather than char to make less tempting to mix and match
+// Latin-1 and UTF-8 characters..
+typedef unsigned char Latin1Char;
+
+// This somewhat odd function is designed to help us convert from Blink Strings
+// to string16. A Blink string is either backed by an array of Latin-1
+// characters or an array of UTF-16 characters. This function is called by
+// WebString::operator string16() to convert one or the other character array
+// to string16. This function is defined here rather than in WebString.h to
+// avoid binary bloat in all the callers of the conversion operator.
+BASE_EXPORT string16 Latin1OrUTF16ToUTF16(size_t length,
+                                          const Latin1Char* latin1,
+                                          const char16* utf16);
+
+}  // namespace base
+
+#endif  // BASE_STRINGS_LATIN1_STRING_CONVERSIONS_H_
diff --git a/base/strings/nullable_string16.cc b/base/strings/nullable_string16.cc
new file mode 100644
index 0000000..07f81d4
--- /dev/null
+++ b/base/strings/nullable_string16.cc
@@ -0,0 +1,17 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/nullable_string16.h"
+
+#include <ostream>
+
+#include "base/strings/utf_string_conversions.h"
+
+namespace base {
+
+std::ostream& operator<<(std::ostream& out, const NullableString16& value) {
+  return value.is_null() ? out << "(null)" : out << UTF16ToUTF8(value.string());
+}
+
+}  // namespace base
diff --git a/base/strings/nullable_string16.h b/base/strings/nullable_string16.h
new file mode 100644
index 0000000..016c25c
--- /dev/null
+++ b/base/strings/nullable_string16.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2010 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_STRINGS_NULLABLE_STRING16_H_
+#define BASE_STRINGS_NULLABLE_STRING16_H_
+
+#include <iosfwd>
+
+#include "base/base_export.h"
+#include "base/strings/string16.h"
+
+namespace base {
+
+// This class is a simple wrapper for string16 which also contains a null
+// state.  This should be used only where the difference between null and
+// empty is meaningful.
+class NullableString16 {
+ public:
+  NullableString16() : is_null_(true) { }
+  NullableString16(const string16& string, bool is_null)
+      : string_(string), is_null_(is_null) {
+  }
+
+  const string16& string() const { return string_; }
+  bool is_null() const { return is_null_; }
+
+ private:
+  string16 string_;
+  bool is_null_;
+};
+
+inline bool operator==(const NullableString16& a, const NullableString16& b) {
+  return a.is_null() == b.is_null() && a.string() == b.string();
+}
+
+inline bool operator!=(const NullableString16& a, const NullableString16& b) {
+  return !(a == b);
+}
+
+BASE_EXPORT std::ostream& operator<<(std::ostream& out,
+                                     const NullableString16& value);
+
+}  // namespace base
+
+#endif  // BASE_STRINGS_NULLABLE_STRING16_H_
diff --git a/base/strings/nullable_string16_unittest.cc b/base/strings/nullable_string16_unittest.cc
new file mode 100644
index 0000000..f02fdce
--- /dev/null
+++ b/base/strings/nullable_string16_unittest.cc
@@ -0,0 +1,35 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/nullable_string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(NullableString16Test, DefaultConstructor) {
+  NullableString16 s;
+  EXPECT_TRUE(s.is_null());
+  EXPECT_EQ(string16(), s.string());
+}
+
+TEST(NullableString16Test, Equals) {
+  NullableString16 a(ASCIIToUTF16("hello"), false);
+  NullableString16 b(ASCIIToUTF16("hello"), false);
+  EXPECT_EQ(a, b);
+}
+
+TEST(NullableString16Test, NotEquals) {
+  NullableString16 a(ASCIIToUTF16("hello"), false);
+  NullableString16 b(ASCIIToUTF16("world"), false);
+  EXPECT_NE(a, b);
+}
+
+TEST(NullableString16Test, NotEqualsNull) {
+  NullableString16 a(ASCIIToUTF16("hello"), false);
+  NullableString16 b;
+  EXPECT_NE(a, b);
+}
+
+}  // namespace base
diff --git a/base/strings/safe_sprintf.cc b/base/strings/safe_sprintf.cc
new file mode 100644
index 0000000..b1fcf45
--- /dev/null
+++ b/base/strings/safe_sprintf.cc
@@ -0,0 +1,685 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/safe_sprintf.h"
+
+#include <limits>
+
+#if !defined(NDEBUG)
+// In debug builds, we use RAW_CHECK() to print useful error messages, if
+// SafeSPrintf() is called with broken arguments.
+// As our contract promises that SafeSPrintf() can be called from any
+// restricted run-time context, it is not actually safe to call logging
+// functions from it; and we only ever do so for debug builds and hope for the
+// best. We should _never_ call any logging function other than RAW_CHECK(),
+// and we should _never_ include any logging code that is active in production
+// builds. Most notably, we should not include these logging functions in
+// unofficial release builds, even though those builds would otherwise have
+// DCHECKS() enabled.
+// In other words; please do not remove the #ifdef around this #include.
+// Instead, in production builds we opt for returning a degraded result,
+// whenever an error is encountered.
+// E.g. The broken function call
+//        SafeSPrintf("errno = %d (%x)", errno, strerror(errno))
+//      will print something like
+//        errno = 13, (%x)
+//      instead of
+//        errno = 13 (Access denied)
+//      In most of the anticipated use cases, that's probably the preferred
+//      behavior.
+#include "base/logging.h"
+#define DEBUG_CHECK RAW_CHECK
+#else
+#define DEBUG_CHECK(x) do { if (x) { } } while (0)
+#endif
+
+namespace base {
+namespace strings {
+
+// The code in this file is extremely careful to be async-signal-safe.
+//
+// Most obviously, we avoid calling any code that could dynamically allocate
+// memory. Doing so would almost certainly result in bugs and dead-locks.
+// We also avoid calling any other STL functions that could have unintended
+// side-effects involving memory allocation or access to other shared
+// resources.
+//
+// But on top of that, we also avoid calling other library functions, as many
+// of them have the side-effect of calling getenv() (in order to deal with
+// localization) or accessing errno. The latter sounds benign, but there are
+// several execution contexts where it isn't even possible to safely read let
+// alone write errno.
+//
+// The stated design goal of the SafeSPrintf() function is that it can be
+// called from any context that can safely call C or C++ code (i.e. anything
+// that doesn't require assembly code).
+//
+// For a brief overview of some but not all of the issues with async-signal-
+// safety, refer to:
+// http://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html
+
+namespace {
+const size_t kSSizeMaxConst = ((size_t)(ssize_t)-1) >> 1;
+
+const char kUpCaseHexDigits[]   = "0123456789ABCDEF";
+const char kDownCaseHexDigits[] = "0123456789abcdef";
+}
+
+#if defined(NDEBUG)
+// We would like to define kSSizeMax as std::numeric_limits<ssize_t>::max(),
+// but C++ doesn't allow us to do that for constants. Instead, we have to
+// use careful casting and shifting. We later use a COMPILE_ASSERT to
+// verify that this worked correctly.
+namespace {
+const size_t kSSizeMax = kSSizeMaxConst;
+}
+#else  // defined(NDEBUG)
+// For efficiency, we really need kSSizeMax to be a constant. But for unit
+// tests, it should be adjustable. This allows us to verify edge cases without
+// having to fill the entire available address space. As a compromise, we make
+// kSSizeMax adjustable in debug builds, and then only compile that particular
+// part of the unit test in debug builds.
+namespace {
+static size_t kSSizeMax = kSSizeMaxConst;
+}
+
+namespace internal {
+void SetSafeSPrintfSSizeMaxForTest(size_t max) {
+  kSSizeMax = max;
+}
+
+size_t GetSafeSPrintfSSizeMaxForTest() {
+  return kSSizeMax;
+}
+}
+#endif  // defined(NDEBUG)
+
+namespace {
+class Buffer {
+ public:
+  // |buffer| is caller-allocated storage that SafeSPrintf() writes to. It
+  // has |size| bytes of writable storage. It is the caller's responsibility
+  // to ensure that the buffer is at least one byte in size, so that it fits
+  // the trailing NUL that will be added by the destructor. The buffer also
+  // must be smaller or equal to kSSizeMax in size.
+  Buffer(char* buffer, size_t size)
+      : buffer_(buffer),
+        size_(size - 1),  // Account for trailing NUL byte
+        count_(0) {
+// The following assertion does not build on Mac and Android. This is because
+// static_assert only works with compile-time constants, but mac uses
+// libstdc++4.2 and android uses stlport, which both don't mark
+// numeric_limits::max() as constexp.  Likewise, MSVS2013's standard library
+// also doesn't mark max() as constexpr yet. cl.exe supports static_cast but
+// doesn't really implement constexpr yet so it doesn't complain, but clang
+// does.
+#if __cplusplus >= 201103 && !defined(OS_ANDROID) && !defined(OS_MACOSX) && \
+    !defined(OS_IOS) && !(defined(__clang__) && defined(OS_WIN))
+    COMPILE_ASSERT(kSSizeMaxConst == \
+                   static_cast<size_t>(std::numeric_limits<ssize_t>::max()),
+                   kSSizeMax_is_the_max_value_of_an_ssize_t);
+#endif
+    DEBUG_CHECK(size > 0);
+    DEBUG_CHECK(size <= kSSizeMax);
+  }
+
+  ~Buffer() {
+    // The code calling the constructor guaranteed that there was enough space
+    // to store a trailing NUL -- and in debug builds, we are actually
+    // verifying this with DEBUG_CHECK()s in the constructor. So, we can
+    // always unconditionally write the NUL byte in the destructor.  We do not
+    // need to adjust the count_, as SafeSPrintf() copies snprintf() in not
+    // including the NUL byte in its return code.
+    *GetInsertionPoint() = '\000';
+  }
+
+  // Returns true, iff the buffer is filled all the way to |kSSizeMax-1|. The
+  // caller can now stop adding more data, as GetCount() has reached its
+  // maximum possible value.
+  inline bool OutOfAddressableSpace() const {
+    return count_ == static_cast<size_t>(kSSizeMax - 1);
+  }
+
+  // Returns the number of bytes that would have been emitted to |buffer_|
+  // if it was sized sufficiently large. This number can be larger than
+  // |size_|, if the caller provided an insufficiently large output buffer.
+  // But it will never be bigger than |kSSizeMax-1|.
+  inline ssize_t GetCount() const {
+    DEBUG_CHECK(count_ < kSSizeMax);
+    return static_cast<ssize_t>(count_);
+  }
+
+  // Emits one |ch| character into the |buffer_| and updates the |count_| of
+  // characters that are currently supposed to be in the buffer.
+  // Returns "false", iff the buffer was already full.
+  // N.B. |count_| increases even if no characters have been written. This is
+  // needed so that GetCount() can return the number of bytes that should
+  // have been allocated for the |buffer_|.
+  inline bool Out(char ch) {
+    if (size_ >= 1 && count_ < size_) {
+      buffer_[count_] = ch;
+      return IncrementCountByOne();
+    }
+    // |count_| still needs to be updated, even if the buffer has been
+    // filled completely. This allows SafeSPrintf() to return the number of
+    // bytes that should have been emitted.
+    IncrementCountByOne();
+    return false;
+  }
+
+  // Inserts |padding|-|len| bytes worth of padding into the |buffer_|.
+  // |count_| will also be incremented by the number of bytes that were meant
+  // to be emitted. The |pad| character is typically either a ' ' space
+  // or a '0' zero, but other non-NUL values are legal.
+  // Returns "false", iff the the |buffer_| filled up (i.e. |count_|
+  // overflowed |size_|) at any time during padding.
+  inline bool Pad(char pad, size_t padding, size_t len) {
+    DEBUG_CHECK(pad);
+    DEBUG_CHECK(padding <= kSSizeMax);
+    for (; padding > len; --padding) {
+      if (!Out(pad)) {
+        if (--padding) {
+          IncrementCount(padding-len);
+        }
+        return false;
+      }
+    }
+    return true;
+  }
+
+  // POSIX doesn't define any async-signal-safe function for converting
+  // an integer to ASCII. Define our own version.
+  //
+  // This also gives us the ability to make the function a little more
+  // powerful and have it deal with |padding|, with truncation, and with
+  // predicting the length of the untruncated output.
+  //
+  // IToASCII() converts an integer |i| to ASCII.
+  //
+  // Unlike similar functions in the standard C library, it never appends a
+  // NUL character. This is left for the caller to do.
+  //
+  // While the function signature takes a signed int64_t, the code decides at
+  // run-time whether to treat the argument as signed (int64_t) or as unsigned
+  // (uint64_t) based on the value of |sign|.
+  //
+  // It supports |base|s 2 through 16. Only a |base| of 10 is allowed to have
+  // a |sign|. Otherwise, |i| is treated as unsigned.
+  //
+  // For bases larger than 10, |upcase| decides whether lower-case or upper-
+  // case letters should be used to designate digits greater than 10.
+  //
+  // Padding can be done with either '0' zeros or ' ' spaces. Padding has to
+  // be positive and will always be applied to the left of the output.
+  //
+  // Prepends a |prefix| to the number (e.g. "0x"). This prefix goes to
+  // the left of |padding|, if |pad| is '0'; and to the right of |padding|
+  // if |pad| is ' '.
+  //
+  // Returns "false", if the |buffer_| overflowed at any time.
+  bool IToASCII(bool sign, bool upcase, int64_t i, int base,
+                char pad, size_t padding, const char* prefix);
+
+ private:
+  // Increments |count_| by |inc| unless this would cause |count_| to
+  // overflow |kSSizeMax-1|. Returns "false", iff an overflow was detected;
+  // it then clamps |count_| to |kSSizeMax-1|.
+  inline bool IncrementCount(size_t inc) {
+    // "inc" is either 1 or a "padding" value. Padding is clamped at
+    // run-time to at most kSSizeMax-1. So, we know that "inc" is always in
+    // the range 1..kSSizeMax-1.
+    // This allows us to compute "kSSizeMax - 1 - inc" without incurring any
+    // integer overflows.
+    DEBUG_CHECK(inc <= kSSizeMax - 1);
+    if (count_ > kSSizeMax - 1 - inc) {
+      count_ = kSSizeMax - 1;
+      return false;
+    } else {
+      count_ += inc;
+      return true;
+    }
+  }
+
+  // Convenience method for the common case of incrementing |count_| by one.
+  inline bool IncrementCountByOne() {
+    return IncrementCount(1);
+  }
+
+  // Return the current insertion point into the buffer. This is typically
+  // at |buffer_| + |count_|, but could be before that if truncation
+  // happened. It always points to one byte past the last byte that was
+  // successfully placed into the |buffer_|.
+  inline char* GetInsertionPoint() const {
+    size_t idx = count_;
+    if (idx > size_) {
+      idx = size_;
+    }
+    return buffer_ + idx;
+  }
+
+  // User-provided buffer that will receive the fully formatted output string.
+  char* buffer_;
+
+  // Number of bytes that are available in the buffer excluding the trailing
+  // NUL byte that will be added by the destructor.
+  const size_t size_;
+
+  // Number of bytes that would have been emitted to the buffer, if the buffer
+  // was sufficiently big. This number always excludes the trailing NUL byte
+  // and it is guaranteed to never grow bigger than kSSizeMax-1.
+  size_t count_;
+
+  DISALLOW_COPY_AND_ASSIGN(Buffer);
+};
+
+
+bool Buffer::IToASCII(bool sign, bool upcase, int64_t i, int base,
+                      char pad, size_t padding, const char* prefix) {
+  // Sanity check for parameters. None of these should ever fail, but see
+  // above for the rationale why we can't call CHECK().
+  DEBUG_CHECK(base >= 2);
+  DEBUG_CHECK(base <= 16);
+  DEBUG_CHECK(!sign || base == 10);
+  DEBUG_CHECK(pad == '0' || pad == ' ');
+  DEBUG_CHECK(padding <= kSSizeMax);
+  DEBUG_CHECK(!(sign && prefix && *prefix));
+
+  // Handle negative numbers, if the caller indicated that |i| should be
+  // treated as a signed number; otherwise treat |i| as unsigned (even if the
+  // MSB is set!)
+  // Details are tricky, because of limited data-types, but equivalent pseudo-
+  // code would look like:
+  //   if (sign && i < 0)
+  //     prefix = "-";
+  //   num = abs(i);
+  int minint = 0;
+  uint64_t num;
+  if (sign && i < 0) {
+    prefix = "-";
+
+    // Turn our number positive.
+    if (i == std::numeric_limits<int64_t>::min()) {
+      // The most negative integer needs special treatment.
+      minint = 1;
+      num = static_cast<uint64_t>(-(i + 1));
+    } else {
+      // "Normal" negative numbers are easy.
+      num = static_cast<uint64_t>(-i);
+    }
+  } else {
+    num = static_cast<uint64_t>(i);
+  }
+
+  // If padding with '0' zero, emit the prefix or '-' character now. Otherwise,
+  // make the prefix accessible in reverse order, so that we can later output
+  // it right between padding and the number.
+  // We cannot choose the easier approach of just reversing the number, as that
+  // fails in situations where we need to truncate numbers that have padding
+  // and/or prefixes.
+  const char* reverse_prefix = NULL;
+  if (prefix && *prefix) {
+    if (pad == '0') {
+      while (*prefix) {
+        if (padding) {
+          --padding;
+        }
+        Out(*prefix++);
+      }
+      prefix = NULL;
+    } else {
+      for (reverse_prefix = prefix; *reverse_prefix; ++reverse_prefix) {
+      }
+    }
+  } else
+    prefix = NULL;
+  const size_t prefix_length = reverse_prefix - prefix;
+
+  // Loop until we have converted the entire number. Output at least one
+  // character (i.e. '0').
+  size_t start = count_;
+  size_t discarded = 0;
+  bool started = false;
+  do {
+    // Make sure there is still enough space left in our output buffer.
+    if (count_ >= size_) {
+      if (start < size_) {
+        // It is rare that we need to output a partial number. But if asked
+        // to do so, we will still make sure we output the correct number of
+        // leading digits.
+        // Since we are generating the digits in reverse order, we actually
+        // have to discard digits in the order that we have already emitted
+        // them. This is essentially equivalent to:
+        //   memmove(buffer_ + start, buffer_ + start + 1, size_ - start - 1)
+        for (char* move = buffer_ + start, *end = buffer_ + size_ - 1;
+             move < end;
+             ++move) {
+          *move = move[1];
+        }
+        ++discarded;
+        --count_;
+      } else if (count_ - size_ > 1) {
+        // Need to increment either |count_| or |discarded| to make progress.
+        // The latter is more efficient, as it eventually triggers fast
+        // handling of padding. But we have to ensure we don't accidentally
+        // change the overall state (i.e. switch the state-machine from
+        // discarding to non-discarding). |count_| needs to always stay
+        // bigger than |size_|.
+        --count_;
+        ++discarded;
+      }
+    }
+
+    // Output the next digit and (if necessary) compensate for the most
+    // negative integer needing special treatment. This works because,
+    // no matter the bit width of the integer, the lowest-most decimal
+    // integer always ends in 2, 4, 6, or 8.
+    if (!num && started) {
+      if (reverse_prefix > prefix) {
+        Out(*--reverse_prefix);
+      } else {
+        Out(pad);
+      }
+    } else {
+      started = true;
+      Out((upcase ? kUpCaseHexDigits : kDownCaseHexDigits)[num%base + minint]);
+    }
+
+    minint = 0;
+    num /= base;
+
+    // Add padding, if requested.
+    if (padding > 0) {
+      --padding;
+
+      // Performance optimization for when we are asked to output excessive
+      // padding, but our output buffer is limited in size.  Even if we output
+      // a 64bit number in binary, we would never write more than 64 plus
+      // prefix non-padding characters. So, once this limit has been passed,
+      // any further state change can be computed arithmetically; we know that
+      // by this time, our entire final output consists of padding characters
+      // that have all already been output.
+      if (discarded > 8*sizeof(num) + prefix_length) {
+        IncrementCount(padding);
+        padding = 0;
+      }
+    }
+  } while (num || padding || (reverse_prefix > prefix));
+
+  // Conversion to ASCII actually resulted in the digits being in reverse
+  // order. We can't easily generate them in forward order, as we can't tell
+  // the number of characters needed until we are done converting.
+  // So, now, we reverse the string (except for the possible '-' sign).
+  char* front = buffer_ + start;
+  char* back = GetInsertionPoint();
+  while (--back > front) {
+    char ch = *back;
+    *back = *front;
+    *front++ = ch;
+  }
+
+  IncrementCount(discarded);
+  return !discarded;
+}
+
+}  // anonymous namespace
+
+namespace internal {
+
+ssize_t SafeSNPrintf(char* buf, size_t sz, const char* fmt, const Arg* args,
+                     const size_t max_args) {
+  // Make sure that at least one NUL byte can be written, and that the buffer
+  // never overflows kSSizeMax. Not only does that use up most or all of the
+  // address space, it also would result in a return code that cannot be
+  // represented.
+  if (static_cast<ssize_t>(sz) < 1) {
+    return -1;
+  } else if (sz > kSSizeMax) {
+    sz = kSSizeMax;
+  }
+
+  // Iterate over format string and interpret '%' arguments as they are
+  // encountered.
+  Buffer buffer(buf, sz);
+  size_t padding;
+  char pad;
+  for (unsigned int cur_arg = 0; *fmt && !buffer.OutOfAddressableSpace(); ) {
+    if (*fmt++ == '%') {
+      padding = 0;
+      pad = ' ';
+      char ch = *fmt++;
+    format_character_found:
+      switch (ch) {
+      case '0': case '1': case '2': case '3': case '4':
+      case '5': case '6': case '7': case '8': case '9':
+        // Found a width parameter. Convert to an integer value and store in
+        // "padding". If the leading digit is a zero, change the padding
+        // character from a space ' ' to a zero '0'.
+        pad = ch == '0' ? '0' : ' ';
+        for (;;) {
+          // The maximum allowed padding fills all the available address
+          // space and leaves just enough space to insert the trailing NUL.
+          const size_t max_padding = kSSizeMax - 1;
+          if (padding > max_padding/10 ||
+              10*padding > max_padding - (ch - '0')) {
+            DEBUG_CHECK(padding <= max_padding/10 &&
+                        10*padding <= max_padding - (ch - '0'));
+            // Integer overflow detected. Skip the rest of the width until
+            // we find the format character, then do the normal error handling.
+          padding_overflow:
+            padding = max_padding;
+            while ((ch = *fmt++) >= '0' && ch <= '9') {
+            }
+            if (cur_arg < max_args) {
+              ++cur_arg;
+            }
+            goto fail_to_expand;
+          }
+          padding = 10*padding + ch - '0';
+          if (padding > max_padding) {
+            // This doesn't happen for "sane" values of kSSizeMax. But once
+            // kSSizeMax gets smaller than about 10, our earlier range checks
+            // are incomplete. Unittests do trigger this artificial corner
+            // case.
+            DEBUG_CHECK(padding <= max_padding);
+            goto padding_overflow;
+          }
+          ch = *fmt++;
+          if (ch < '0' || ch > '9') {
+            // Reached the end of the width parameter. This is where the format
+            // character is found.
+            goto format_character_found;
+          }
+        }
+        break;
+      case 'c': {  // Output an ASCII character.
+        // Check that there are arguments left to be inserted.
+        if (cur_arg >= max_args) {
+          DEBUG_CHECK(cur_arg < max_args);
+          goto fail_to_expand;
+        }
+
+        // Check that the argument has the expected type.
+        const Arg& arg = args[cur_arg++];
+        if (arg.type != Arg::INT && arg.type != Arg::UINT) {
+          DEBUG_CHECK(arg.type == Arg::INT || arg.type == Arg::UINT);
+          goto fail_to_expand;
+        }
+
+        // Apply padding, if needed.
+        buffer.Pad(' ', padding, 1);
+
+        // Convert the argument to an ASCII character and output it.
+        char as_char = static_cast<char>(arg.integer.i);
+        if (!as_char) {
+          goto end_of_output_buffer;
+        }
+        buffer.Out(as_char);
+        break; }
+      case 'd':    // Output a possibly signed decimal value.
+      case 'o':    // Output an unsigned octal value.
+      case 'x':    // Output an unsigned hexadecimal value.
+      case 'X':
+      case 'p': {  // Output a pointer value.
+        // Check that there are arguments left to be inserted.
+        if (cur_arg >= max_args) {
+          DEBUG_CHECK(cur_arg < max_args);
+          goto fail_to_expand;
+        }
+
+        const Arg& arg = args[cur_arg++];
+        int64_t i;
+        const char* prefix = NULL;
+        if (ch != 'p') {
+          // Check that the argument has the expected type.
+          if (arg.type != Arg::INT && arg.type != Arg::UINT) {
+            DEBUG_CHECK(arg.type == Arg::INT || arg.type == Arg::UINT);
+            goto fail_to_expand;
+          }
+          i = arg.integer.i;
+
+          if (ch != 'd') {
+            // The Arg() constructor automatically performed sign expansion on
+            // signed parameters. This is great when outputting a %d decimal
+            // number, but can result in unexpected leading 0xFF bytes when
+            // outputting a %x hexadecimal number. Mask bits, if necessary.
+            // We have to do this here, instead of in the Arg() constructor, as
+            // the Arg() constructor cannot tell whether we will output a %d
+            // or a %x. Only the latter should experience masking.
+            if (arg.integer.width < sizeof(int64_t)) {
+              i &= (1LL << (8*arg.integer.width)) - 1;
+            }
+          }
+        } else {
+          // Pointer values require an actual pointer or a string.
+          if (arg.type == Arg::POINTER) {
+            i = reinterpret_cast<uintptr_t>(arg.ptr);
+          } else if (arg.type == Arg::STRING) {
+            i = reinterpret_cast<uintptr_t>(arg.str);
+          } else if (arg.type == Arg::INT &&
+                     arg.integer.width == sizeof(NULL) &&
+                     arg.integer.i == 0) {  // Allow C++'s version of NULL
+            i = 0;
+          } else {
+            DEBUG_CHECK(arg.type == Arg::POINTER || arg.type == Arg::STRING);
+            goto fail_to_expand;
+          }
+
+          // Pointers always include the "0x" prefix.
+          prefix = "0x";
+        }
+
+        // Use IToASCII() to convert to ASCII representation. For decimal
+        // numbers, optionally print a sign. For hexadecimal numbers,
+        // distinguish between upper and lower case. %p addresses are always
+        // printed as upcase. Supports base 8, 10, and 16. Prints padding
+        // and/or prefixes, if so requested.
+        buffer.IToASCII(ch == 'd' && arg.type == Arg::INT,
+                        ch != 'x', i,
+                        ch == 'o' ? 8 : ch == 'd' ? 10 : 16,
+                        pad, padding, prefix);
+        break; }
+      case 's': {
+        // Check that there are arguments left to be inserted.
+        if (cur_arg >= max_args) {
+          DEBUG_CHECK(cur_arg < max_args);
+          goto fail_to_expand;
+        }
+
+        // Check that the argument has the expected type.
+        const Arg& arg = args[cur_arg++];
+        const char *s;
+        if (arg.type == Arg::STRING) {
+          s = arg.str ? arg.str : "<NULL>";
+        } else if (arg.type == Arg::INT && arg.integer.width == sizeof(NULL) &&
+                   arg.integer.i == 0) {  // Allow C++'s version of NULL
+          s = "<NULL>";
+        } else {
+          DEBUG_CHECK(arg.type == Arg::STRING);
+          goto fail_to_expand;
+        }
+
+        // Apply padding, if needed. This requires us to first check the
+        // length of the string that we are outputting.
+        if (padding) {
+          size_t len = 0;
+          for (const char* src = s; *src++; ) {
+            ++len;
+          }
+          buffer.Pad(' ', padding, len);
+        }
+
+        // Printing a string involves nothing more than copying it into the
+        // output buffer and making sure we don't output more bytes than
+        // available space; Out() takes care of doing that.
+        for (const char* src = s; *src; ) {
+          buffer.Out(*src++);
+        }
+        break; }
+      case '%':
+        // Quoted percent '%' character.
+        goto copy_verbatim;
+      fail_to_expand:
+        // C++ gives us tools to do type checking -- something that snprintf()
+        // could never really do. So, whenever we see arguments that don't
+        // match up with the format string, we refuse to output them. But
+        // since we have to be extremely conservative about being async-
+        // signal-safe, we are limited in the type of error handling that we
+        // can do in production builds (in debug builds we can use
+        // DEBUG_CHECK() and hope for the best). So, all we do is pass the
+        // format string unchanged. That should eventually get the user's
+        // attention; and in the meantime, it hopefully doesn't lose too much
+        // data.
+      default:
+        // Unknown or unsupported format character. Just copy verbatim to
+        // output.
+        buffer.Out('%');
+        DEBUG_CHECK(ch);
+        if (!ch) {
+          goto end_of_format_string;
+        }
+        buffer.Out(ch);
+        break;
+      }
+    } else {
+  copy_verbatim:
+    buffer.Out(fmt[-1]);
+    }
+  }
+ end_of_format_string:
+ end_of_output_buffer:
+  return buffer.GetCount();
+}
+
+}  // namespace internal
+
+ssize_t SafeSNPrintf(char* buf, size_t sz, const char* fmt) {
+  // Make sure that at least one NUL byte can be written, and that the buffer
+  // never overflows kSSizeMax. Not only does that use up most or all of the
+  // address space, it also would result in a return code that cannot be
+  // represented.
+  if (static_cast<ssize_t>(sz) < 1) {
+    return -1;
+  } else if (sz > kSSizeMax) {
+    sz = kSSizeMax;
+  }
+
+  Buffer buffer(buf, sz);
+
+  // In the slow-path, we deal with errors by copying the contents of
+  // "fmt" unexpanded. This means, if there are no arguments passed, the
+  // SafeSPrintf() function always degenerates to a version of strncpy() that
+  // de-duplicates '%' characters.
+  const char* src = fmt;
+  for (; *src; ++src) {
+    buffer.Out(*src);
+    DEBUG_CHECK(src[0] != '%' || src[1] == '%');
+    if (src[0] == '%' && src[1] == '%') {
+      ++src;
+    }
+  }
+  return buffer.GetCount();
+}
+
+}  // namespace strings
+}  // namespace base
diff --git a/base/strings/safe_sprintf.h b/base/strings/safe_sprintf.h
new file mode 100644
index 0000000..2d17320
--- /dev/null
+++ b/base/strings/safe_sprintf.h
@@ -0,0 +1,247 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_STRINGS_SAFE_SPRINTF_H_
+#define BASE_STRINGS_SAFE_SPRINTF_H_
+
+#include "build/build_config.h"
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#if defined(OS_POSIX)
+// For ssize_t
+#include <unistd.h>
+#endif
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace strings {
+
+#if defined(_MSC_VER)
+// Define ssize_t inside of our namespace.
+#if defined(_WIN64)
+typedef __int64 ssize_t;
+#else
+typedef long ssize_t;
+#endif
+#endif
+
+// SafeSPrintf() is a type-safe and completely self-contained version of
+// snprintf().
+//
+// SafeSNPrintf() is an alternative function signature that can be used when
+// not dealing with fixed-sized buffers. When possible, SafeSPrintf() should
+// always be used instead of SafeSNPrintf()
+//
+// These functions allow for formatting complicated messages from contexts that
+// require strict async-signal-safety. In fact, it is safe to call them from
+// any low-level execution context, as they are guaranteed to make no library
+// or system calls. It deliberately never touches "errno", either.
+//
+// The only exception to this rule is that in debug builds the code calls
+// RAW_CHECK() to help diagnose problems when the format string does not
+// match the rest of the arguments. In release builds, no CHECK()s are used,
+// and SafeSPrintf() instead returns an output string that expands only
+// those arguments that match their format characters. Mismatched arguments
+// are ignored.
+//
+// The code currently only supports a subset of format characters:
+//   %c, %o, %d, %x, %X, %p, and %s.
+//
+// SafeSPrintf() aims to be as liberal as reasonably possible. Integer-like
+// values of arbitrary width can be passed to all of the format characters
+// that expect integers. Thus, it is explicitly legal to pass an "int" to
+// "%c", and output will automatically look at the LSB only. It is also
+// explicitly legal to pass either signed or unsigned values, and the format
+// characters will automatically interpret the arguments accordingly.
+//
+// It is still not legal to mix-and-match integer-like values with pointer
+// values. For instance, you cannot pass a pointer to %x, nor can you pass an
+// integer to %p.
+//
+// The one exception is "0" zero being accepted by "%p". This works-around
+// the problem of C++ defining NULL as an integer-like value.
+//
+// All format characters take an optional width parameter. This must be a
+// positive integer. For %d, %o, %x, %X and %p, if the width starts with
+// a leading '0', padding is done with '0' instead of ' ' characters.
+//
+// There are a few features of snprintf()-style format strings, that
+// SafeSPrintf() does not support at this time.
+//
+// If an actual user showed up, there is no particularly strong reason they
+// couldn't be added. But that assumes that the trade-offs between complexity
+// and utility are favorable.
+//
+// For example, adding support for negative padding widths, and for %n are all
+// likely to be viewed positively. They are all clearly useful, low-risk, easy
+// to test, don't jeopardize the async-signal-safety of the code, and overall
+// have little impact on other parts of SafeSPrintf() function.
+//
+// On the other hands, adding support for alternate forms, positional
+// arguments, grouping, wide characters, localization or floating point numbers
+// are all unlikely to ever be added.
+//
+// SafeSPrintf() and SafeSNPrintf() mimic the behavior of snprintf() and they
+// return the number of bytes needed to store the untruncated output. This
+// does *not* include the terminating NUL byte.
+//
+// They return -1, iff a fatal error happened. This typically can only happen,
+// if the buffer size is a) negative, or b) zero (i.e. not even the NUL byte
+// can be written). The return value can never be larger than SSIZE_MAX-1.
+// This ensures that the caller can always add one to the signed return code
+// in order to determine the amount of storage that needs to be allocated.
+//
+// While the code supports type checking and while it is generally very careful
+// to avoid printing incorrect values, it tends to be conservative in printing
+// as much as possible, even when given incorrect parameters. Typically, in
+// case of an error, the format string will not be expanded. (i.e. something
+// like SafeSPrintf(buf, "%p %d", 1, 2) results in "%p 2"). See above for
+// the use of RAW_CHECK() in debug builds, though.
+//
+// Basic example:
+//   char buf[20];
+//   base::strings::SafeSPrintf(buf, "The answer: %2d", 42);
+//
+// Example with dynamically sized buffer (async-signal-safe). This code won't
+// work on Visual studio, as it requires dynamically allocating arrays on the
+// stack. Consider picking a smaller value for |kMaxSize| if stack size is
+// limited and known. On the other hand, if the parameters to SafeSNPrintf()
+// are trusted and not controllable by the user, you can consider eliminating
+// the check for |kMaxSize| altogether. The current value of SSIZE_MAX is
+// essentially a no-op that just illustrates how to implement an upper bound:
+//   const size_t kInitialSize = 128;
+//   const size_t kMaxSize = std::numeric_limits<ssize_t>::max();
+//   size_t size = kInitialSize;
+//   for (;;) {
+//     char buf[size];
+//     size = SafeSNPrintf(buf, size, "Error message \"%s\"\n", err) + 1;
+//     if (sizeof(buf) < kMaxSize && size > kMaxSize) {
+//       size = kMaxSize;
+//       continue;
+//     } else if (size > sizeof(buf))
+//       continue;
+//     write(2, buf, size-1);
+//     break;
+//   }
+
+namespace internal {
+// Helpers that use C++ overloading, templates, and specializations to deduce
+// and record type information from function arguments. This allows us to
+// later write a type-safe version of snprintf().
+
+struct Arg {
+  enum Type { INT, UINT, STRING, POINTER };
+
+  // Any integer-like value.
+  Arg(signed char c) : type(INT) {
+    integer.i = c;
+    integer.width = sizeof(char);
+  }
+  Arg(unsigned char c) : type(UINT) {
+    integer.i = c;
+    integer.width = sizeof(char);
+  }
+  Arg(signed short j) : type(INT) {
+    integer.i = j;
+    integer.width = sizeof(short);
+  }
+  Arg(unsigned short j) : type(UINT) {
+    integer.i = j;
+    integer.width = sizeof(short);
+  }
+  Arg(signed int j) : type(INT) {
+    integer.i = j;
+    integer.width = sizeof(int);
+  }
+  Arg(unsigned int j) : type(UINT) {
+    integer.i = j;
+    integer.width = sizeof(int);
+  }
+  Arg(signed long j) : type(INT) {
+    integer.i = j;
+    integer.width = sizeof(long);
+  }
+  Arg(unsigned long j) : type(UINT) {
+    integer.i = j;
+    integer.width = sizeof(long);
+  }
+  Arg(signed long long j) : type(INT) {
+    integer.i = j;
+    integer.width = sizeof(long long);
+  }
+  Arg(unsigned long long j) : type(UINT) {
+    integer.i = j;
+    integer.width = sizeof(long long);
+  }
+
+  // A C-style text string.
+  Arg(const char* s) : str(s), type(STRING) { }
+  Arg(char* s)       : str(s), type(STRING) { }
+
+  // Any pointer value that can be cast to a "void*".
+  template<class T> Arg(T* p) : ptr((void*)p), type(POINTER) { }
+
+  union {
+    // An integer-like value.
+    struct {
+      int64_t       i;
+      unsigned char width;
+    } integer;
+
+    // A C-style text string.
+    const char* str;
+
+    // A pointer to an arbitrary object.
+    const void* ptr;
+  };
+  const enum Type type;
+};
+
+// This is the internal function that performs the actual formatting of
+// an snprintf()-style format string.
+BASE_EXPORT ssize_t SafeSNPrintf(char* buf, size_t sz, const char* fmt,
+                                 const Arg* args, size_t max_args);
+
+#if !defined(NDEBUG)
+// In debug builds, allow unit tests to artificially lower the kSSizeMax
+// constant that is used as a hard upper-bound for all buffers. In normal
+// use, this constant should always be std::numeric_limits<ssize_t>::max().
+BASE_EXPORT void SetSafeSPrintfSSizeMaxForTest(size_t max);
+BASE_EXPORT size_t GetSafeSPrintfSSizeMaxForTest();
+#endif
+
+}  // namespace internal
+
+template<typename... Args>
+ssize_t SafeSNPrintf(char* buf, size_t N, const char* fmt, Args... args) {
+  // Use Arg() object to record type information and then copy arguments to an
+  // array to make it easier to iterate over them.
+  const internal::Arg arg_array[] = { args... };
+  return internal::SafeSNPrintf(buf, N, fmt, arg_array, sizeof...(args));
+}
+
+template<size_t N, typename... Args>
+ssize_t SafeSPrintf(char (&buf)[N], const char* fmt, Args... args) {
+  // Use Arg() object to record type information and then copy arguments to an
+  // array to make it easier to iterate over them.
+  const internal::Arg arg_array[] = { args... };
+  return internal::SafeSNPrintf(buf, N, fmt, arg_array, sizeof...(args));
+}
+
+// Fast-path when we don't actually need to substitute any arguments.
+BASE_EXPORT ssize_t SafeSNPrintf(char* buf, size_t N, const char* fmt);
+template<size_t N>
+inline ssize_t SafeSPrintf(char (&buf)[N], const char* fmt) {
+  return SafeSNPrintf(buf, N, fmt);
+}
+
+}  // namespace strings
+}  // namespace base
+
+#endif  // BASE_STRINGS_SAFE_SPRINTF_H_
diff --git a/base/strings/safe_sprintf_unittest.cc b/base/strings/safe_sprintf_unittest.cc
new file mode 100644
index 0000000..ff05c6e
--- /dev/null
+++ b/base/strings/safe_sprintf_unittest.cc
@@ -0,0 +1,759 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/safe_sprintf.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <limits>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Death tests on Android are currently very flaky. No need to add more flaky
+// tests, as they just make it hard to spot real problems.
+// TODO(markus): See if the restrictions on Android can eventually be lifted.
+#if defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
+#define ALLOW_DEATH_TEST
+#endif
+
+namespace base {
+namespace strings {
+
+TEST(SafeSPrintfTest, Empty) {
+  char buf[2] = { 'X', 'X' };
+
+  // Negative buffer size should always result in an error.
+  EXPECT_EQ(-1, SafeSNPrintf(buf, static_cast<size_t>(-1), ""));
+  EXPECT_EQ('X', buf[0]);
+  EXPECT_EQ('X', buf[1]);
+
+  // Zero buffer size should always result in an error.
+  EXPECT_EQ(-1, SafeSNPrintf(buf, 0, ""));
+  EXPECT_EQ('X', buf[0]);
+  EXPECT_EQ('X', buf[1]);
+
+  // A one-byte buffer should always print a single NUL byte.
+  EXPECT_EQ(0, SafeSNPrintf(buf, 1, ""));
+  EXPECT_EQ(0, buf[0]);
+  EXPECT_EQ('X', buf[1]);
+  buf[0] = 'X';
+
+  // A larger buffer should leave the trailing bytes unchanged.
+  EXPECT_EQ(0, SafeSNPrintf(buf, 2, ""));
+  EXPECT_EQ(0, buf[0]);
+  EXPECT_EQ('X', buf[1]);
+  buf[0] = 'X';
+
+  // The same test using SafeSPrintf() instead of SafeSNPrintf().
+  EXPECT_EQ(0, SafeSPrintf(buf, ""));
+  EXPECT_EQ(0, buf[0]);
+  EXPECT_EQ('X', buf[1]);
+  buf[0] = 'X';
+}
+
+TEST(SafeSPrintfTest, NoArguments) {
+  // Output a text message that doesn't require any substitutions. This
+  // is roughly equivalent to calling strncpy() (but unlike strncpy(), it does
+  // always add a trailing NUL; it always deduplicates '%' characters).
+  static const char text[] = "hello world";
+  char ref[20], buf[20];
+  memset(ref, 'X', sizeof(ref));
+  memcpy(buf, ref, sizeof(buf));
+
+  // A negative buffer size should always result in an error.
+  EXPECT_EQ(-1, SafeSNPrintf(buf, static_cast<size_t>(-1), text));
+  EXPECT_TRUE(!memcmp(buf, ref, sizeof(buf)));
+
+  // Zero buffer size should always result in an error.
+  EXPECT_EQ(-1, SafeSNPrintf(buf, 0, text));
+  EXPECT_TRUE(!memcmp(buf, ref, sizeof(buf)));
+
+  // A one-byte buffer should always print a single NUL byte.
+  EXPECT_EQ(static_cast<ssize_t>(sizeof(text))-1, SafeSNPrintf(buf, 1, text));
+  EXPECT_EQ(0, buf[0]);
+  EXPECT_TRUE(!memcmp(buf+1, ref+1, sizeof(buf)-1));
+  memcpy(buf, ref, sizeof(buf));
+
+  // A larger (but limited) buffer should always leave the trailing bytes
+  // unchanged.
+  EXPECT_EQ(static_cast<ssize_t>(sizeof(text))-1, SafeSNPrintf(buf, 2, text));
+  EXPECT_EQ(text[0], buf[0]);
+  EXPECT_EQ(0, buf[1]);
+  EXPECT_TRUE(!memcmp(buf+2, ref+2, sizeof(buf)-2));
+  memcpy(buf, ref, sizeof(buf));
+
+  // A unrestricted buffer length should always leave the trailing bytes
+  // unchanged.
+  EXPECT_EQ(static_cast<ssize_t>(sizeof(text))-1,
+            SafeSNPrintf(buf, sizeof(buf), text));
+  EXPECT_EQ(std::string(text), std::string(buf));
+  EXPECT_TRUE(!memcmp(buf + sizeof(text), ref + sizeof(text),
+                      sizeof(buf) - sizeof(text)));
+  memcpy(buf, ref, sizeof(buf));
+
+  // The same test using SafeSPrintf() instead of SafeSNPrintf().
+  EXPECT_EQ(static_cast<ssize_t>(sizeof(text))-1, SafeSPrintf(buf, text));
+  EXPECT_EQ(std::string(text), std::string(buf));
+  EXPECT_TRUE(!memcmp(buf + sizeof(text), ref + sizeof(text),
+                      sizeof(buf) - sizeof(text)));
+  memcpy(buf, ref, sizeof(buf));
+
+  // Check for deduplication of '%' percent characters.
+  EXPECT_EQ(1, SafeSPrintf(buf, "%%"));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%%%%"));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%%X"));
+  EXPECT_EQ(3, SafeSPrintf(buf, "%%%%X"));
+#if defined(NDEBUG)
+  EXPECT_EQ(1, SafeSPrintf(buf, "%"));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%%%"));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%X"));
+  EXPECT_EQ(3, SafeSPrintf(buf, "%%%X"));
+#elif defined(ALLOW_DEATH_TEST)
+  EXPECT_DEATH(SafeSPrintf(buf, "%"), "src.1. == '%'");
+  EXPECT_DEATH(SafeSPrintf(buf, "%%%"), "src.1. == '%'");
+  EXPECT_DEATH(SafeSPrintf(buf, "%X"), "src.1. == '%'");
+  EXPECT_DEATH(SafeSPrintf(buf, "%%%X"), "src.1. == '%'");
+#endif
+}
+
+TEST(SafeSPrintfTest, OneArgument) {
+  // Test basic single-argument single-character substitution.
+  const char text[] = "hello world";
+  const char fmt[]  = "hello%cworld";
+  char ref[20], buf[20];
+  memset(ref, 'X', sizeof(buf));
+  memcpy(buf, ref, sizeof(buf));
+
+  // A negative buffer size should always result in an error.
+  EXPECT_EQ(-1, SafeSNPrintf(buf, static_cast<size_t>(-1), fmt, ' '));
+  EXPECT_TRUE(!memcmp(buf, ref, sizeof(buf)));
+
+  // Zero buffer size should always result in an error.
+  EXPECT_EQ(-1, SafeSNPrintf(buf, 0, fmt, ' '));
+  EXPECT_TRUE(!memcmp(buf, ref, sizeof(buf)));
+
+  // A one-byte buffer should always print a single NUL byte.
+  EXPECT_EQ(static_cast<ssize_t>(sizeof(text))-1,
+            SafeSNPrintf(buf, 1, fmt, ' '));
+  EXPECT_EQ(0, buf[0]);
+  EXPECT_TRUE(!memcmp(buf+1, ref+1, sizeof(buf)-1));
+  memcpy(buf, ref, sizeof(buf));
+
+  // A larger (but limited) buffer should always leave the trailing bytes
+  // unchanged.
+  EXPECT_EQ(static_cast<ssize_t>(sizeof(text))-1,
+            SafeSNPrintf(buf, 2, fmt, ' '));
+  EXPECT_EQ(text[0], buf[0]);
+  EXPECT_EQ(0, buf[1]);
+  EXPECT_TRUE(!memcmp(buf+2, ref+2, sizeof(buf)-2));
+  memcpy(buf, ref, sizeof(buf));
+
+  // A unrestricted buffer length should always leave the trailing bytes
+  // unchanged.
+  EXPECT_EQ(static_cast<ssize_t>(sizeof(text))-1,
+            SafeSNPrintf(buf, sizeof(buf), fmt, ' '));
+  EXPECT_EQ(std::string(text), std::string(buf));
+  EXPECT_TRUE(!memcmp(buf + sizeof(text), ref + sizeof(text),
+                      sizeof(buf) - sizeof(text)));
+  memcpy(buf, ref, sizeof(buf));
+
+  // The same test using SafeSPrintf() instead of SafeSNPrintf().
+  EXPECT_EQ(static_cast<ssize_t>(sizeof(text))-1, SafeSPrintf(buf, fmt, ' '));
+  EXPECT_EQ(std::string(text), std::string(buf));
+  EXPECT_TRUE(!memcmp(buf + sizeof(text), ref + sizeof(text),
+                      sizeof(buf) - sizeof(text)));
+  memcpy(buf, ref, sizeof(buf));
+
+  // Check for deduplication of '%' percent characters.
+  EXPECT_EQ(1, SafeSPrintf(buf, "%%", 0));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%%%%", 0));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%Y", 0));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%%Y", 0));
+  EXPECT_EQ(3, SafeSPrintf(buf, "%%%Y", 0));
+  EXPECT_EQ(3, SafeSPrintf(buf, "%%%%Y", 0));
+#if defined(NDEBUG)
+  EXPECT_EQ(1, SafeSPrintf(buf, "%", 0));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%%%", 0));
+#elif defined(ALLOW_DEATH_TEST)
+  EXPECT_DEATH(SafeSPrintf(buf, "%", 0), "ch");
+  EXPECT_DEATH(SafeSPrintf(buf, "%%%", 0), "ch");
+#endif
+}
+
+TEST(SafeSPrintfTest, MissingArg) {
+#if defined(NDEBUG)
+  char buf[20];
+  EXPECT_EQ(3, SafeSPrintf(buf, "%c%c", 'A'));
+  EXPECT_EQ("A%c", std::string(buf));
+#elif defined(ALLOW_DEATH_TEST)
+  char buf[20];
+  EXPECT_DEATH(SafeSPrintf(buf, "%c%c", 'A'), "cur_arg < max_args");
+#endif
+}
+
+TEST(SafeSPrintfTest, ASANFriendlyBufferTest) {
+  // Print into a buffer that is sized exactly to size. ASAN can verify that
+  // nobody attempts to write past the end of the buffer.
+  // There is a more complicated test in PrintLongString() that covers a lot
+  // more edge case, but it is also harder to debug in case of a failure.
+  const char kTestString[] = "This is a test";
+  scoped_ptr<char[]> buf(new char[sizeof(kTestString)]);
+  EXPECT_EQ(static_cast<ssize_t>(sizeof(kTestString) - 1),
+            SafeSNPrintf(buf.get(), sizeof(kTestString), kTestString));
+  EXPECT_EQ(std::string(kTestString), std::string(buf.get()));
+  EXPECT_EQ(static_cast<ssize_t>(sizeof(kTestString) - 1),
+            SafeSNPrintf(buf.get(), sizeof(kTestString), "%s", kTestString));
+  EXPECT_EQ(std::string(kTestString), std::string(buf.get()));
+}
+
+TEST(SafeSPrintfTest, NArgs) {
+  // Pre-C++11 compilers have a different code path, that can only print
+  // up to ten distinct arguments.
+  // We test both SafeSPrintf() and SafeSNPrintf(). This makes sure we don't
+  // have typos in the copy-n-pasted code that is needed to deal with various
+  // numbers of arguments.
+  char buf[12];
+  EXPECT_EQ(1, SafeSPrintf(buf, "%c", 1));
+  EXPECT_EQ("\1", std::string(buf));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%c%c", 1, 2));
+  EXPECT_EQ("\1\2", std::string(buf));
+  EXPECT_EQ(3, SafeSPrintf(buf, "%c%c%c", 1, 2, 3));
+  EXPECT_EQ("\1\2\3", std::string(buf));
+  EXPECT_EQ(4, SafeSPrintf(buf, "%c%c%c%c", 1, 2, 3, 4));
+  EXPECT_EQ("\1\2\3\4", std::string(buf));
+  EXPECT_EQ(5, SafeSPrintf(buf, "%c%c%c%c%c", 1, 2, 3, 4, 5));
+  EXPECT_EQ("\1\2\3\4\5", std::string(buf));
+  EXPECT_EQ(6, SafeSPrintf(buf, "%c%c%c%c%c%c", 1, 2, 3, 4, 5, 6));
+  EXPECT_EQ("\1\2\3\4\5\6", std::string(buf));
+  EXPECT_EQ(7, SafeSPrintf(buf, "%c%c%c%c%c%c%c", 1, 2, 3, 4, 5, 6, 7));
+  EXPECT_EQ("\1\2\3\4\5\6\7", std::string(buf));
+  EXPECT_EQ(8, SafeSPrintf(buf, "%c%c%c%c%c%c%c%c", 1, 2, 3, 4, 5, 6, 7, 8));
+  EXPECT_EQ("\1\2\3\4\5\6\7\10", std::string(buf));
+  EXPECT_EQ(9, SafeSPrintf(buf, "%c%c%c%c%c%c%c%c%c",
+                           1, 2, 3, 4, 5, 6, 7, 8, 9));
+  EXPECT_EQ("\1\2\3\4\5\6\7\10\11", std::string(buf));
+  EXPECT_EQ(10, SafeSPrintf(buf, "%c%c%c%c%c%c%c%c%c%c",
+                            1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
+
+  // Repeat all the tests with SafeSNPrintf() instead of SafeSPrintf().
+  EXPECT_EQ("\1\2\3\4\5\6\7\10\11\12", std::string(buf));
+  EXPECT_EQ(1, SafeSNPrintf(buf, 11, "%c", 1));
+  EXPECT_EQ("\1", std::string(buf));
+  EXPECT_EQ(2, SafeSNPrintf(buf, 11, "%c%c", 1, 2));
+  EXPECT_EQ("\1\2", std::string(buf));
+  EXPECT_EQ(3, SafeSNPrintf(buf, 11, "%c%c%c", 1, 2, 3));
+  EXPECT_EQ("\1\2\3", std::string(buf));
+  EXPECT_EQ(4, SafeSNPrintf(buf, 11, "%c%c%c%c", 1, 2, 3, 4));
+  EXPECT_EQ("\1\2\3\4", std::string(buf));
+  EXPECT_EQ(5, SafeSNPrintf(buf, 11, "%c%c%c%c%c", 1, 2, 3, 4, 5));
+  EXPECT_EQ("\1\2\3\4\5", std::string(buf));
+  EXPECT_EQ(6, SafeSNPrintf(buf, 11, "%c%c%c%c%c%c", 1, 2, 3, 4, 5, 6));
+  EXPECT_EQ("\1\2\3\4\5\6", std::string(buf));
+  EXPECT_EQ(7, SafeSNPrintf(buf, 11, "%c%c%c%c%c%c%c", 1, 2, 3, 4, 5, 6, 7));
+  EXPECT_EQ("\1\2\3\4\5\6\7", std::string(buf));
+  EXPECT_EQ(8, SafeSNPrintf(buf, 11, "%c%c%c%c%c%c%c%c",
+                            1, 2, 3, 4, 5, 6, 7, 8));
+  EXPECT_EQ("\1\2\3\4\5\6\7\10", std::string(buf));
+  EXPECT_EQ(9, SafeSNPrintf(buf, 11, "%c%c%c%c%c%c%c%c%c",
+                            1, 2, 3, 4, 5, 6, 7, 8, 9));
+  EXPECT_EQ("\1\2\3\4\5\6\7\10\11", std::string(buf));
+  EXPECT_EQ(10, SafeSNPrintf(buf, 11, "%c%c%c%c%c%c%c%c%c%c",
+                             1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
+  EXPECT_EQ("\1\2\3\4\5\6\7\10\11\12", std::string(buf));
+
+  EXPECT_EQ(11, SafeSPrintf(buf, "%c%c%c%c%c%c%c%c%c%c%c",
+                            1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11));
+  EXPECT_EQ("\1\2\3\4\5\6\7\10\11\12\13", std::string(buf));
+  EXPECT_EQ(11, SafeSNPrintf(buf, 12, "%c%c%c%c%c%c%c%c%c%c%c",
+                             1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11));
+  EXPECT_EQ("\1\2\3\4\5\6\7\10\11\12\13", std::string(buf));
+}
+
+TEST(SafeSPrintfTest, DataTypes) {
+  char buf[40];
+
+  // Bytes
+  EXPECT_EQ(1, SafeSPrintf(buf, "%d", (uint8_t)1));
+  EXPECT_EQ("1", std::string(buf));
+  EXPECT_EQ(3, SafeSPrintf(buf, "%d", (uint8_t)-1));
+  EXPECT_EQ("255", std::string(buf));
+  EXPECT_EQ(1, SafeSPrintf(buf, "%d", (int8_t)1));
+  EXPECT_EQ("1", std::string(buf));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%d", (int8_t)-1));
+  EXPECT_EQ("-1", std::string(buf));
+  EXPECT_EQ(4, SafeSPrintf(buf, "%d", (int8_t)-128));
+  EXPECT_EQ("-128", std::string(buf));
+
+  // Half-words
+  EXPECT_EQ(1, SafeSPrintf(buf, "%d", (uint16_t)1));
+  EXPECT_EQ("1", std::string(buf));
+  EXPECT_EQ(5, SafeSPrintf(buf, "%d", (uint16_t)-1));
+  EXPECT_EQ("65535", std::string(buf));
+  EXPECT_EQ(1, SafeSPrintf(buf, "%d", (int16_t)1));
+  EXPECT_EQ("1", std::string(buf));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%d", (int16_t)-1));
+  EXPECT_EQ("-1", std::string(buf));
+  EXPECT_EQ(6, SafeSPrintf(buf, "%d", (int16_t)-32768));
+  EXPECT_EQ("-32768", std::string(buf));
+
+  // Words
+  EXPECT_EQ(1, SafeSPrintf(buf, "%d", (uint32_t)1));
+  EXPECT_EQ("1", std::string(buf));
+  EXPECT_EQ(10, SafeSPrintf(buf, "%d", (uint32_t)-1));
+  EXPECT_EQ("4294967295", std::string(buf));
+  EXPECT_EQ(1, SafeSPrintf(buf, "%d", (int32_t)1));
+  EXPECT_EQ("1", std::string(buf));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%d", (int32_t)-1));
+  EXPECT_EQ("-1", std::string(buf));
+  // Work-around for an limitation of C90
+  EXPECT_EQ(11, SafeSPrintf(buf, "%d", (int32_t)-2147483647-1));
+  EXPECT_EQ("-2147483648", std::string(buf));
+
+  // Quads
+  EXPECT_EQ(1, SafeSPrintf(buf, "%d", (uint64_t)1));
+  EXPECT_EQ("1", std::string(buf));
+  EXPECT_EQ(20, SafeSPrintf(buf, "%d", (uint64_t)-1));
+  EXPECT_EQ("18446744073709551615", std::string(buf));
+  EXPECT_EQ(1, SafeSPrintf(buf, "%d", (int64_t)1));
+  EXPECT_EQ("1", std::string(buf));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%d", (int64_t)-1));
+  EXPECT_EQ("-1", std::string(buf));
+  // Work-around for an limitation of C90
+  EXPECT_EQ(20, SafeSPrintf(buf, "%d", (int64_t)-9223372036854775807LL-1));
+  EXPECT_EQ("-9223372036854775808", std::string(buf));
+
+  // Strings (both const and mutable).
+  EXPECT_EQ(4, SafeSPrintf(buf, "test"));
+  EXPECT_EQ("test", std::string(buf));
+  EXPECT_EQ(4, SafeSPrintf(buf, buf));
+  EXPECT_EQ("test", std::string(buf));
+
+  // Pointer
+  char addr[20];
+  sprintf(addr, "0x%llX", (unsigned long long)(uintptr_t)buf);
+  SafeSPrintf(buf, "%p", buf);
+  EXPECT_EQ(std::string(addr), std::string(buf));
+  SafeSPrintf(buf, "%p", (const char *)buf);
+  EXPECT_EQ(std::string(addr), std::string(buf));
+  sprintf(addr, "0x%llX", (unsigned long long)(uintptr_t)sprintf);
+  SafeSPrintf(buf, "%p", sprintf);
+  EXPECT_EQ(std::string(addr), std::string(buf));
+
+  // Padding for pointers is a little more complicated because of the "0x"
+  // prefix. Padding with '0' zeros is relatively straight-forward, but
+  // padding with ' ' spaces requires more effort.
+  sprintf(addr, "0x%017llX", (unsigned long long)(uintptr_t)buf);
+  SafeSPrintf(buf, "%019p", buf);
+  EXPECT_EQ(std::string(addr), std::string(buf));
+  sprintf(addr, "0x%llX", (unsigned long long)(uintptr_t)buf);
+  memset(addr, ' ',
+         (char*)memmove(addr + sizeof(addr) - strlen(addr) - 1,
+                        addr, strlen(addr)+1) - addr);
+  SafeSPrintf(buf, "%19p", buf);
+  EXPECT_EQ(std::string(addr), std::string(buf));
+}
+
+namespace {
+void PrintLongString(char* buf, size_t sz) {
+  // Output a reasonably complex expression into a limited-size buffer.
+  // At least one byte is available for writing the NUL character.
+  CHECK_GT(sz, static_cast<size_t>(0));
+
+  // Allocate slightly more space, so that we can verify that SafeSPrintf()
+  // never writes past the end of the buffer.
+  scoped_ptr<char[]> tmp(new char[sz+2]);
+  memset(tmp.get(), 'X', sz+2);
+
+  // Use SafeSPrintf() to output a complex list of arguments:
+  // - test padding and truncating %c single characters.
+  // - test truncating %s simple strings.
+  // - test mismatching arguments and truncating (for %d != %s).
+  // - test zero-padding and truncating %x hexadecimal numbers.
+  // - test outputting and truncating %d MININT.
+  // - test outputting and truncating %p arbitrary pointer values.
+  // - test outputting, padding and truncating NULL-pointer %s strings.
+  char* out = tmp.get();
+  size_t out_sz = sz;
+  size_t len;
+  for (scoped_ptr<char[]> perfect_buf;;) {
+    size_t needed = SafeSNPrintf(out, out_sz,
+#if defined(NDEBUG)
+                            "A%2cong %s: %d %010X %d %p%7s", 'l', "string", "",
+#else
+                            "A%2cong %s: %%d %010X %d %p%7s", 'l', "string",
+#endif
+                            0xDEADBEEF, std::numeric_limits<intptr_t>::min(),
+                            PrintLongString, static_cast<char*>(NULL)) + 1;
+
+    // Various sanity checks:
+    // The numbered of characters needed to print the full string should always
+    // be bigger or equal to the bytes that have actually been output.
+    len = strlen(tmp.get());
+    CHECK_GE(needed, len+1);
+
+    // The number of characters output should always fit into the buffer that
+    // was passed into SafeSPrintf().
+    CHECK_LT(len, out_sz);
+
+    // The output is always terminated with a NUL byte (actually, this test is
+    // always going to pass, as strlen() already verified this)
+    EXPECT_FALSE(tmp[len]);
+
+    // ASAN can check that we are not overwriting buffers, iff we make sure the
+    // buffer is exactly the size that we are expecting to be written. After
+    // running SafeSNPrintf() the first time, it is possible to compute the
+    // correct buffer size for this test. So, allocate a second buffer and run
+    // the exact same SafeSNPrintf() command again.
+    if (!perfect_buf.get()) {
+      out_sz = std::min(needed, sz);
+      out = new char[out_sz];
+      perfect_buf.reset(out);
+    } else {
+      break;
+    }
+  }
+
+  // All trailing bytes are unchanged.
+  for (size_t i = len+1; i < sz+2; ++i)
+    EXPECT_EQ('X', tmp[i]);
+
+  // The text that was generated by SafeSPrintf() should always match the
+  // equivalent text generated by sprintf(). Please note that the format
+  // string for sprintf() is not complicated, as it does not have the
+  // benefit of getting type information from the C++ compiler.
+  //
+  // N.B.: It would be so much cleaner to use snprintf(). But unfortunately,
+  //       Visual Studio doesn't support this function, and the work-arounds
+  //       are all really awkward.
+  char ref[256];
+  CHECK_LE(sz, sizeof(ref));
+  sprintf(ref, "A long string: %%d 00DEADBEEF %lld 0x%llX <NULL>",
+          static_cast<long long>(std::numeric_limits<intptr_t>::min()),
+          static_cast<unsigned long long>(
+            reinterpret_cast<uintptr_t>(PrintLongString)));
+  ref[sz-1] = '\000';
+
+#if defined(NDEBUG)
+  const size_t kSSizeMax = std::numeric_limits<ssize_t>::max();
+#else
+  const size_t kSSizeMax = internal::GetSafeSPrintfSSizeMaxForTest();
+#endif
+
+  // Compare the output from SafeSPrintf() to the one from sprintf().
+  EXPECT_EQ(std::string(ref).substr(0, kSSizeMax-1), std::string(tmp.get()));
+
+  // We allocated a slightly larger buffer, so that we could perform some
+  // extra sanity checks. Now that the tests have all passed, we copy the
+  // data to the output buffer that the caller provided.
+  memcpy(buf, tmp.get(), len+1);
+}
+
+#if !defined(NDEBUG)
+class ScopedSafeSPrintfSSizeMaxSetter {
+ public:
+  ScopedSafeSPrintfSSizeMaxSetter(size_t sz) {
+    old_ssize_max_ = internal::GetSafeSPrintfSSizeMaxForTest();
+    internal::SetSafeSPrintfSSizeMaxForTest(sz);
+  }
+
+  ~ScopedSafeSPrintfSSizeMaxSetter() {
+    internal::SetSafeSPrintfSSizeMaxForTest(old_ssize_max_);
+  }
+
+ private:
+  size_t old_ssize_max_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedSafeSPrintfSSizeMaxSetter);
+};
+#endif
+
+}  // anonymous namespace
+
+TEST(SafeSPrintfTest, Truncation) {
+  // We use PrintLongString() to print a complex long string and then
+  // truncate to all possible lengths. This ends up exercising a lot of
+  // different code paths in SafeSPrintf() and IToASCII(), as truncation can
+  // happen in a lot of different states.
+  char ref[256];
+  PrintLongString(ref, sizeof(ref));
+  for (size_t i = strlen(ref)+1; i; --i) {
+    char buf[sizeof(ref)];
+    PrintLongString(buf, i);
+    EXPECT_EQ(std::string(ref, i - 1), std::string(buf));
+  }
+
+  // When compiling in debug mode, we have the ability to fake a small
+  // upper limit for the maximum value that can be stored in an ssize_t.
+  // SafeSPrintf() uses this upper limit to determine how many bytes it will
+  // write to the buffer, even if the caller claimed a bigger buffer size.
+  // Repeat the truncation test and verify that this other code path in
+  // SafeSPrintf() works correctly, too.
+#if !defined(NDEBUG)
+  for (size_t i = strlen(ref)+1; i > 1; --i) {
+    ScopedSafeSPrintfSSizeMaxSetter ssize_max_setter(i);
+    char buf[sizeof(ref)];
+    PrintLongString(buf, sizeof(buf));
+    EXPECT_EQ(std::string(ref, i - 1), std::string(buf));
+  }
+
+  // kSSizeMax is also used to constrain the maximum amount of padding, before
+  // SafeSPrintf() detects an error in the format string.
+  ScopedSafeSPrintfSSizeMaxSetter ssize_max_setter(100);
+  char buf[256];
+  EXPECT_EQ(99, SafeSPrintf(buf, "%99c", ' '));
+  EXPECT_EQ(std::string(99, ' '), std::string(buf));
+  *buf = '\000';
+#if defined(ALLOW_DEATH_TEST)
+  EXPECT_DEATH(SafeSPrintf(buf, "%100c", ' '), "padding <= max_padding");
+#endif
+  EXPECT_EQ(0, *buf);
+#endif
+}
+
+TEST(SafeSPrintfTest, Padding) {
+  char buf[40], fmt[40];
+
+  // Chars %c
+  EXPECT_EQ(1, SafeSPrintf(buf, "%c", 'A'));
+  EXPECT_EQ("A", std::string(buf));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%2c", 'A'));
+  EXPECT_EQ(" A", std::string(buf));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%02c", 'A'));
+  EXPECT_EQ(" A", std::string(buf));
+  EXPECT_EQ(4, SafeSPrintf(buf, "%-2c", 'A'));
+  EXPECT_EQ("%-2c", std::string(buf));
+  SafeSPrintf(fmt, "%%%dc", std::numeric_limits<ssize_t>::max() - 1);
+  EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1, SafeSPrintf(buf, fmt, 'A'));
+  SafeSPrintf(fmt, "%%%dc",
+              static_cast<size_t>(std::numeric_limits<ssize_t>::max()));
+#if defined(NDEBUG)
+  EXPECT_EQ(2, SafeSPrintf(buf, fmt, 'A'));
+  EXPECT_EQ("%c", std::string(buf));
+#elif defined(ALLOW_DEATH_TEST)
+  EXPECT_DEATH(SafeSPrintf(buf, fmt, 'A'), "padding <= max_padding");
+#endif
+
+  // Octal %o
+  EXPECT_EQ(1, SafeSPrintf(buf, "%o", 1));
+  EXPECT_EQ("1", std::string(buf));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%2o", 1));
+  EXPECT_EQ(" 1", std::string(buf));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%02o", 1));
+  EXPECT_EQ("01", std::string(buf));
+  EXPECT_EQ(12, SafeSPrintf(buf, "%12o", -1));
+  EXPECT_EQ(" 37777777777", std::string(buf));
+  EXPECT_EQ(12, SafeSPrintf(buf, "%012o", -1));
+  EXPECT_EQ("037777777777", std::string(buf));
+  EXPECT_EQ(23, SafeSPrintf(buf, "%23o", -1LL));
+  EXPECT_EQ(" 1777777777777777777777", std::string(buf));
+  EXPECT_EQ(23, SafeSPrintf(buf, "%023o", -1LL));
+  EXPECT_EQ("01777777777777777777777", std::string(buf));
+  EXPECT_EQ(3, SafeSPrintf(buf, "%2o", 0111));
+  EXPECT_EQ("111", std::string(buf));
+  EXPECT_EQ(4, SafeSPrintf(buf, "%-2o", 1));
+  EXPECT_EQ("%-2o", std::string(buf));
+  SafeSPrintf(fmt, "%%%do", std::numeric_limits<ssize_t>::max()-1);
+  EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1,
+            SafeSNPrintf(buf, 4, fmt, 1));
+  EXPECT_EQ("   ", std::string(buf));
+  SafeSPrintf(fmt, "%%0%do", std::numeric_limits<ssize_t>::max()-1);
+  EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1,
+            SafeSNPrintf(buf, 4, fmt, 1));
+  EXPECT_EQ("000", std::string(buf));
+  SafeSPrintf(fmt, "%%%do",
+              static_cast<size_t>(std::numeric_limits<ssize_t>::max()));
+#if defined(NDEBUG)
+  EXPECT_EQ(2, SafeSPrintf(buf, fmt, 1));
+  EXPECT_EQ("%o", std::string(buf));
+#elif defined(ALLOW_DEATH_TEST)
+  EXPECT_DEATH(SafeSPrintf(buf, fmt, 1), "padding <= max_padding");
+#endif
+
+  // Decimals %d
+  EXPECT_EQ(1, SafeSPrintf(buf, "%d", 1));
+  EXPECT_EQ("1", std::string(buf));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%2d", 1));
+  EXPECT_EQ(" 1", std::string(buf));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%02d", 1));
+  EXPECT_EQ("01", std::string(buf));
+  EXPECT_EQ(3, SafeSPrintf(buf, "%3d", -1));
+  EXPECT_EQ(" -1", std::string(buf));
+  EXPECT_EQ(3, SafeSPrintf(buf, "%03d", -1));
+  EXPECT_EQ("-01", std::string(buf));
+  EXPECT_EQ(3, SafeSPrintf(buf, "%2d", 111));
+  EXPECT_EQ("111", std::string(buf));
+  EXPECT_EQ(4, SafeSPrintf(buf, "%2d", -111));
+  EXPECT_EQ("-111", std::string(buf));
+  EXPECT_EQ(4, SafeSPrintf(buf, "%-2d", 1));
+  EXPECT_EQ("%-2d", std::string(buf));
+  SafeSPrintf(fmt, "%%%dd", std::numeric_limits<ssize_t>::max()-1);
+  EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1,
+            SafeSNPrintf(buf, 4, fmt, 1));
+  EXPECT_EQ("   ", std::string(buf));
+  SafeSPrintf(fmt, "%%0%dd", std::numeric_limits<ssize_t>::max()-1);
+  EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1,
+            SafeSNPrintf(buf, 4, fmt, 1));
+  EXPECT_EQ("000", std::string(buf));
+  SafeSPrintf(fmt, "%%%dd",
+              static_cast<size_t>(std::numeric_limits<ssize_t>::max()));
+#if defined(NDEBUG)
+  EXPECT_EQ(2, SafeSPrintf(buf, fmt, 1));
+  EXPECT_EQ("%d", std::string(buf));
+#elif defined(ALLOW_DEATH_TEST)
+  EXPECT_DEATH(SafeSPrintf(buf, fmt, 1), "padding <= max_padding");
+#endif
+
+  // Hex %X
+  EXPECT_EQ(1, SafeSPrintf(buf, "%X", 1));
+  EXPECT_EQ("1", std::string(buf));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%2X", 1));
+  EXPECT_EQ(" 1", std::string(buf));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%02X", 1));
+  EXPECT_EQ("01", std::string(buf));
+  EXPECT_EQ(9, SafeSPrintf(buf, "%9X", -1));
+  EXPECT_EQ(" FFFFFFFF", std::string(buf));
+  EXPECT_EQ(9, SafeSPrintf(buf, "%09X", -1));
+  EXPECT_EQ("0FFFFFFFF", std::string(buf));
+  EXPECT_EQ(17, SafeSPrintf(buf, "%17X", -1LL));
+  EXPECT_EQ(" FFFFFFFFFFFFFFFF", std::string(buf));
+  EXPECT_EQ(17, SafeSPrintf(buf, "%017X", -1LL));
+  EXPECT_EQ("0FFFFFFFFFFFFFFFF", std::string(buf));
+  EXPECT_EQ(3, SafeSPrintf(buf, "%2X", 0x111));
+  EXPECT_EQ("111", std::string(buf));
+  EXPECT_EQ(4, SafeSPrintf(buf, "%-2X", 1));
+  EXPECT_EQ("%-2X", std::string(buf));
+  SafeSPrintf(fmt, "%%%dX", std::numeric_limits<ssize_t>::max()-1);
+  EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1,
+            SafeSNPrintf(buf, 4, fmt, 1));
+  EXPECT_EQ("   ", std::string(buf));
+  SafeSPrintf(fmt, "%%0%dX", std::numeric_limits<ssize_t>::max()-1);
+  EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1,
+            SafeSNPrintf(buf, 4, fmt, 1));
+  EXPECT_EQ("000", std::string(buf));
+  SafeSPrintf(fmt, "%%%dX",
+              static_cast<size_t>(std::numeric_limits<ssize_t>::max()));
+#if defined(NDEBUG)
+  EXPECT_EQ(2, SafeSPrintf(buf, fmt, 1));
+  EXPECT_EQ("%X", std::string(buf));
+#elif defined(ALLOW_DEATH_TEST)
+  EXPECT_DEATH(SafeSPrintf(buf, fmt, 1), "padding <= max_padding");
+#endif
+
+  // Pointer %p
+  EXPECT_EQ(3, SafeSPrintf(buf, "%p", (void*)1));
+  EXPECT_EQ("0x1", std::string(buf));
+  EXPECT_EQ(4, SafeSPrintf(buf, "%4p", (void*)1));
+  EXPECT_EQ(" 0x1", std::string(buf));
+  EXPECT_EQ(4, SafeSPrintf(buf, "%04p", (void*)1));
+  EXPECT_EQ("0x01", std::string(buf));
+  EXPECT_EQ(5, SafeSPrintf(buf, "%4p", (void*)0x111));
+  EXPECT_EQ("0x111", std::string(buf));
+  EXPECT_EQ(4, SafeSPrintf(buf, "%-2p", (void*)1));
+  EXPECT_EQ("%-2p", std::string(buf));
+  SafeSPrintf(fmt, "%%%dp", std::numeric_limits<ssize_t>::max()-1);
+  EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1,
+            SafeSNPrintf(buf, 4, fmt, (void*)1));
+  EXPECT_EQ("   ", std::string(buf));
+  SafeSPrintf(fmt, "%%0%dp", std::numeric_limits<ssize_t>::max()-1);
+  EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1,
+            SafeSNPrintf(buf, 4, fmt, (void*)1));
+  EXPECT_EQ("0x0", std::string(buf));
+  SafeSPrintf(fmt, "%%%dp",
+              static_cast<size_t>(std::numeric_limits<ssize_t>::max()));
+#if defined(NDEBUG)
+  EXPECT_EQ(2, SafeSPrintf(buf, fmt, 1));
+  EXPECT_EQ("%p", std::string(buf));
+#elif defined(ALLOW_DEATH_TEST)
+  EXPECT_DEATH(SafeSPrintf(buf, fmt, 1), "padding <= max_padding");
+#endif
+
+  // String
+  EXPECT_EQ(1, SafeSPrintf(buf, "%s", "A"));
+  EXPECT_EQ("A", std::string(buf));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%2s", "A"));
+  EXPECT_EQ(" A", std::string(buf));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%02s", "A"));
+  EXPECT_EQ(" A", std::string(buf));
+  EXPECT_EQ(3, SafeSPrintf(buf, "%2s", "AAA"));
+  EXPECT_EQ("AAA", std::string(buf));
+  EXPECT_EQ(4, SafeSPrintf(buf, "%-2s", "A"));
+  EXPECT_EQ("%-2s", std::string(buf));
+  SafeSPrintf(fmt, "%%%ds", std::numeric_limits<ssize_t>::max()-1);
+  EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1,
+            SafeSNPrintf(buf, 4, fmt, "A"));
+  EXPECT_EQ("   ", std::string(buf));
+  SafeSPrintf(fmt, "%%0%ds", std::numeric_limits<ssize_t>::max()-1);
+  EXPECT_EQ(std::numeric_limits<ssize_t>::max()-1,
+            SafeSNPrintf(buf, 4, fmt, "A"));
+  EXPECT_EQ("   ", std::string(buf));
+  SafeSPrintf(fmt, "%%%ds",
+              static_cast<size_t>(std::numeric_limits<ssize_t>::max()));
+#if defined(NDEBUG)
+  EXPECT_EQ(2, SafeSPrintf(buf, fmt, "A"));
+  EXPECT_EQ("%s", std::string(buf));
+#elif defined(ALLOW_DEATH_TEST)
+  EXPECT_DEATH(SafeSPrintf(buf, fmt, "A"), "padding <= max_padding");
+#endif
+}
+
+TEST(SafeSPrintfTest, EmbeddedNul) {
+  char buf[] = { 'X', 'X', 'X', 'X' };
+  EXPECT_EQ(2, SafeSPrintf(buf, "%3c", 0));
+  EXPECT_EQ(' ', buf[0]);
+  EXPECT_EQ(' ', buf[1]);
+  EXPECT_EQ(0,   buf[2]);
+  EXPECT_EQ('X', buf[3]);
+
+  // Check handling of a NUL format character. N.B. this takes two different
+  // code paths depending on whether we are actually passing arguments. If
+  // we don't have any arguments, we are running in the fast-path code, that
+  // looks (almost) like a strncpy().
+#if defined(NDEBUG)
+  EXPECT_EQ(2, SafeSPrintf(buf, "%%%"));
+  EXPECT_EQ("%%", std::string(buf));
+  EXPECT_EQ(2, SafeSPrintf(buf, "%%%", 0));
+  EXPECT_EQ("%%", std::string(buf));
+#elif defined(ALLOW_DEATH_TEST)
+  EXPECT_DEATH(SafeSPrintf(buf, "%%%"), "src.1. == '%'");
+  EXPECT_DEATH(SafeSPrintf(buf, "%%%", 0), "ch");
+#endif
+}
+
+TEST(SafeSPrintfTest, EmitNULL) {
+  char buf[40];
+#if defined(__GNUC__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wconversion-null"
+#endif
+  EXPECT_EQ(1, SafeSPrintf(buf, "%d", NULL));
+  EXPECT_EQ("0", std::string(buf));
+  EXPECT_EQ(3, SafeSPrintf(buf, "%p", NULL));
+  EXPECT_EQ("0x0", std::string(buf));
+  EXPECT_EQ(6, SafeSPrintf(buf, "%s", NULL));
+  EXPECT_EQ("<NULL>", std::string(buf));
+#if defined(__GCC__)
+#pragma GCC diagnostic pop
+#endif
+}
+
+TEST(SafeSPrintfTest, PointerSize) {
+  // The internal data representation is a 64bit value, independent of the
+  // native word size. We want to perform sign-extension for signed integers,
+  // but we want to avoid doing so for pointer types. This could be a
+  // problem on systems, where pointers are only 32bit. This tests verifies
+  // that there is no such problem.
+  char *str = reinterpret_cast<char *>(0x80000000u);
+  void *ptr = str;
+  char buf[40];
+  EXPECT_EQ(10, SafeSPrintf(buf, "%p", str));
+  EXPECT_EQ("0x80000000", std::string(buf));
+  EXPECT_EQ(10, SafeSPrintf(buf, "%p", ptr));
+  EXPECT_EQ("0x80000000", std::string(buf));
+}
+
+}  // namespace strings
+}  // namespace base
diff --git a/base/strings/string16.cc b/base/strings/string16.cc
new file mode 100644
index 0000000..f4c8cf7
--- /dev/null
+++ b/base/strings/string16.cc
@@ -0,0 +1,82 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/string16.h"
+
+#if defined(WCHAR_T_IS_UTF16)
+
+#error This file should not be used on 2-byte wchar_t systems
+// If this winds up being needed on 2-byte wchar_t systems, either the
+// definitions below can be used, or the host system's wide character
+// functions like wmemcmp can be wrapped.
+
+#elif defined(WCHAR_T_IS_UTF32)
+
+#include <ostream>
+
+#include "base/strings/utf_string_conversions.h"
+
+namespace base {
+
+int c16memcmp(const char16* s1, const char16* s2, size_t n) {
+  // We cannot call memcmp because that changes the semantics.
+  while (n-- > 0) {
+    if (*s1 != *s2) {
+      // We cannot use (*s1 - *s2) because char16 is unsigned.
+      return ((*s1 < *s2) ? -1 : 1);
+    }
+    ++s1;
+    ++s2;
+  }
+  return 0;
+}
+
+size_t c16len(const char16* s) {
+  const char16 *s_orig = s;
+  while (*s) {
+    ++s;
+  }
+  return s - s_orig;
+}
+
+const char16* c16memchr(const char16* s, char16 c, size_t n) {
+  while (n-- > 0) {
+    if (*s == c) {
+      return s;
+    }
+    ++s;
+  }
+  return 0;
+}
+
+char16* c16memmove(char16* s1, const char16* s2, size_t n) {
+  return static_cast<char16*>(memmove(s1, s2, n * sizeof(char16)));
+}
+
+char16* c16memcpy(char16* s1, const char16* s2, size_t n) {
+  return static_cast<char16*>(memcpy(s1, s2, n * sizeof(char16)));
+}
+
+char16* c16memset(char16* s, char16 c, size_t n) {
+  char16 *s_orig = s;
+  while (n-- > 0) {
+    *s = c;
+    ++s;
+  }
+  return s_orig;
+}
+
+std::ostream& operator<<(std::ostream& out, const string16& str) {
+  return out << UTF16ToUTF8(str);
+}
+
+void PrintTo(const string16& str, std::ostream* out) {
+  *out << str;
+}
+
+}  // namespace base
+
+template class std::basic_string<base::char16, base::string16_char_traits>;
+
+#endif  // WCHAR_T_IS_UTF32
diff --git a/base/strings/string16.h b/base/strings/string16.h
new file mode 100644
index 0000000..1a01a96
--- /dev/null
+++ b/base/strings/string16.h
@@ -0,0 +1,184 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_STRINGS_STRING16_H_
+#define BASE_STRINGS_STRING16_H_
+
+// WHAT:
+// A version of std::basic_string that provides 2-byte characters even when
+// wchar_t is not implemented as a 2-byte type. You can access this class as
+// string16. We also define char16, which string16 is based upon.
+//
+// WHY:
+// On Windows, wchar_t is 2 bytes, and it can conveniently handle UTF-16/UCS-2
+// data. Plenty of existing code operates on strings encoded as UTF-16.
+//
+// On many other platforms, sizeof(wchar_t) is 4 bytes by default. We can make
+// it 2 bytes by using the GCC flag -fshort-wchar. But then std::wstring fails
+// at run time, because it calls some functions (like wcslen) that come from
+// the system's native C library -- which was built with a 4-byte wchar_t!
+// It's wasteful to use 4-byte wchar_t strings to carry UTF-16 data, and it's
+// entirely improper on those systems where the encoding of wchar_t is defined
+// as UTF-32.
+//
+// Here, we define string16, which is similar to std::wstring but replaces all
+// libc functions with custom, 2-byte-char compatible routines. It is capable
+// of carrying UTF-16-encoded data.
+
+#include <stdio.h>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+#if defined(WCHAR_T_IS_UTF16)
+
+namespace base {
+
+typedef wchar_t char16;
+typedef std::wstring string16;
+typedef std::char_traits<wchar_t> string16_char_traits;
+
+}  // namespace base
+
+#elif defined(WCHAR_T_IS_UTF32)
+
+namespace base {
+
+typedef uint16 char16;
+
+// char16 versions of the functions required by string16_char_traits; these
+// are based on the wide character functions of similar names ("w" or "wcs"
+// instead of "c16").
+BASE_EXPORT int c16memcmp(const char16* s1, const char16* s2, size_t n);
+BASE_EXPORT size_t c16len(const char16* s);
+BASE_EXPORT const char16* c16memchr(const char16* s, char16 c, size_t n);
+BASE_EXPORT char16* c16memmove(char16* s1, const char16* s2, size_t n);
+BASE_EXPORT char16* c16memcpy(char16* s1, const char16* s2, size_t n);
+BASE_EXPORT char16* c16memset(char16* s, char16 c, size_t n);
+
+struct string16_char_traits {
+  typedef char16 char_type;
+  typedef int int_type;
+
+  // int_type needs to be able to hold each possible value of char_type, and in
+  // addition, the distinct value of eof().
+  COMPILE_ASSERT(sizeof(int_type) > sizeof(char_type), unexpected_type_width);
+
+  typedef std::streamoff off_type;
+  typedef mbstate_t state_type;
+  typedef std::fpos<state_type> pos_type;
+
+  static void assign(char_type& c1, const char_type& c2) {
+    c1 = c2;
+  }
+
+  static bool eq(const char_type& c1, const char_type& c2) {
+    return c1 == c2;
+  }
+  static bool lt(const char_type& c1, const char_type& c2) {
+    return c1 < c2;
+  }
+
+  static int compare(const char_type* s1, const char_type* s2, size_t n) {
+    return c16memcmp(s1, s2, n);
+  }
+
+  static size_t length(const char_type* s) {
+    return c16len(s);
+  }
+
+  static const char_type* find(const char_type* s, size_t n,
+                               const char_type& a) {
+    return c16memchr(s, a, n);
+  }
+
+  static char_type* move(char_type* s1, const char_type* s2, size_t n) {
+    return c16memmove(s1, s2, n);
+  }
+
+  static char_type* copy(char_type* s1, const char_type* s2, size_t n) {
+    return c16memcpy(s1, s2, n);
+  }
+
+  static char_type* assign(char_type* s, size_t n, char_type a) {
+    return c16memset(s, a, n);
+  }
+
+  static int_type not_eof(const int_type& c) {
+    return eq_int_type(c, eof()) ? 0 : c;
+  }
+
+  static char_type to_char_type(const int_type& c) {
+    return char_type(c);
+  }
+
+  static int_type to_int_type(const char_type& c) {
+    return int_type(c);
+  }
+
+  static bool eq_int_type(const int_type& c1, const int_type& c2) {
+    return c1 == c2;
+  }
+
+  static int_type eof() {
+    return static_cast<int_type>(EOF);
+  }
+};
+
+typedef std::basic_string<char16, base::string16_char_traits> string16;
+
+BASE_EXPORT extern std::ostream& operator<<(std::ostream& out,
+                                            const string16& str);
+
+// This is required by googletest to print a readable output on test failures.
+BASE_EXPORT extern void PrintTo(const string16& str, std::ostream* out);
+
+}  // namespace base
+
+// The string class will be explicitly instantiated only once, in string16.cc.
+//
+// std::basic_string<> in GNU libstdc++ contains a static data member,
+// _S_empty_rep_storage, to represent empty strings.  When an operation such
+// as assignment or destruction is performed on a string, causing its existing
+// data member to be invalidated, it must not be freed if this static data
+// member is being used.  Otherwise, it counts as an attempt to free static
+// (and not allocated) data, which is a memory error.
+//
+// Generally, due to C++ template magic, _S_empty_rep_storage will be marked
+// as a coalesced symbol, meaning that the linker will combine multiple
+// instances into a single one when generating output.
+//
+// If a string class is used by multiple shared libraries, a problem occurs.
+// Each library will get its own copy of _S_empty_rep_storage.  When strings
+// are passed across a library boundary for alteration or destruction, memory
+// errors will result.  GNU libstdc++ contains a configuration option,
+// --enable-fully-dynamic-string (_GLIBCXX_FULLY_DYNAMIC_STRING), which
+// disables the static data member optimization, but it's a good optimization
+// and non-STL code is generally at the mercy of the system's STL
+// configuration.  Fully-dynamic strings are not the default for GNU libstdc++
+// libstdc++ itself or for the libstdc++ installations on the systems we care
+// about, such as Mac OS X and relevant flavors of Linux.
+//
+// See also http://gcc.gnu.org/bugzilla/show_bug.cgi?id=24196 .
+//
+// To avoid problems, string classes need to be explicitly instantiated only
+// once, in exactly one library.  All other string users see it via an "extern"
+// declaration.  This is precisely how GNU libstdc++ handles
+// std::basic_string<char> (string) and std::basic_string<wchar_t> (wstring).
+//
+// This also works around a Mac OS X linker bug in ld64-85.2.1 (Xcode 3.1.2),
+// in which the linker does not fully coalesce symbols when dead code
+// stripping is enabled.  This bug causes the memory errors described above
+// to occur even when a std::basic_string<> does not cross shared library
+// boundaries, such as in statically-linked executables.
+//
+// TODO(mark): File this bug with Apple and update this note with a bug number.
+
+extern template
+class BASE_EXPORT std::basic_string<base::char16, base::string16_char_traits>;
+
+#endif  // WCHAR_T_IS_UTF32
+
+#endif  // BASE_STRINGS_STRING16_H_
diff --git a/base/strings/string16_unittest.cc b/base/strings/string16_unittest.cc
new file mode 100644
index 0000000..4e58218
--- /dev/null
+++ b/base/strings/string16_unittest.cc
@@ -0,0 +1,58 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <sstream>
+
+#include "base/strings/string16.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+#if defined(WCHAR_T_IS_UTF32)
+
+// We define a custom operator<< for string16 so we can use it with logging.
+// This tests that conversion.
+TEST(String16Test, OutputStream) {
+  // Basic stream test.
+  {
+    std::ostringstream stream;
+    stream << "Empty '" << string16() << "' standard '"
+           << string16(ASCIIToUTF16("Hello, world")) << "'";
+    EXPECT_STREQ("Empty '' standard 'Hello, world'",
+                 stream.str().c_str());
+  }
+
+  // Interesting edge cases.
+  {
+    // These should each get converted to the invalid character: EF BF BD.
+    string16 initial_surrogate;
+    initial_surrogate.push_back(0xd800);
+    string16 final_surrogate;
+    final_surrogate.push_back(0xdc00);
+
+    // Old italic A = U+10300, will get converted to: F0 90 8C 80 'z'.
+    string16 surrogate_pair;
+    surrogate_pair.push_back(0xd800);
+    surrogate_pair.push_back(0xdf00);
+    surrogate_pair.push_back('z');
+
+    // Will get converted to the invalid char + 's': EF BF BD 's'.
+    string16 unterminated_surrogate;
+    unterminated_surrogate.push_back(0xd800);
+    unterminated_surrogate.push_back('s');
+
+    std::ostringstream stream;
+    stream << initial_surrogate << "," << final_surrogate << ","
+           << surrogate_pair << "," << unterminated_surrogate;
+
+    EXPECT_STREQ("\xef\xbf\xbd,\xef\xbf\xbd,\xf0\x90\x8c\x80z,\xef\xbf\xbds",
+                 stream.str().c_str());
+  }
+}
+
+#endif
+
+}  // namespace base
diff --git a/base/strings/string_number_conversions.cc b/base/strings/string_number_conversions.cc
new file mode 100644
index 0000000..642d24e
--- /dev/null
+++ b/base/strings/string_number_conversions.cc
@@ -0,0 +1,529 @@
+// Copyright (c) 2012 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/strings/string_number_conversions.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <wctype.h>
+
+#include <limits>
+
+#include "base/logging.h"
+#include "base/scoped_clear_errno.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/third_party/dmg_fp/dmg_fp.h"
+
+namespace base {
+
+namespace {
+
+template <typename STR, typename INT, typename UINT, bool NEG>
+struct IntToStringT {
+  // This is to avoid a compiler warning about unary minus on unsigned type.
+  // For example, say you had the following code:
+  //   template <typename INT>
+  //   INT abs(INT value) { return value < 0 ? -value : value; }
+  // Even though if INT is unsigned, it's impossible for value < 0, so the
+  // unary minus will never be taken, the compiler will still generate a
+  // warning.  We do a little specialization dance...
+  template <typename INT2, typename UINT2, bool NEG2>
+  struct ToUnsignedT {};
+
+  template <typename INT2, typename UINT2>
+  struct ToUnsignedT<INT2, UINT2, false> {
+    static UINT2 ToUnsigned(INT2 value) {
+      return static_cast<UINT2>(value);
+    }
+  };
+
+  template <typename INT2, typename UINT2>
+  struct ToUnsignedT<INT2, UINT2, true> {
+    static UINT2 ToUnsigned(INT2 value) {
+      return static_cast<UINT2>(value < 0 ? -value : value);
+    }
+  };
+
+  // This set of templates is very similar to the above templates, but
+  // for testing whether an integer is negative.
+  template <typename INT2, bool NEG2>
+  struct TestNegT {};
+  template <typename INT2>
+  struct TestNegT<INT2, false> {
+    static bool TestNeg(INT2 value) {
+      // value is unsigned, and can never be negative.
+      return false;
+    }
+  };
+  template <typename INT2>
+  struct TestNegT<INT2, true> {
+    static bool TestNeg(INT2 value) {
+      return value < 0;
+    }
+  };
+
+  static STR IntToString(INT value) {
+    // log10(2) ~= 0.3 bytes needed per bit or per byte log10(2**8) ~= 2.4.
+    // So round up to allocate 3 output characters per byte, plus 1 for '-'.
+    const int kOutputBufSize = 3 * sizeof(INT) + 1;
+
+    // Allocate the whole string right away, we will right back to front, and
+    // then return the substr of what we ended up using.
+    STR outbuf(kOutputBufSize, 0);
+
+    bool is_neg = TestNegT<INT, NEG>::TestNeg(value);
+    // Even though is_neg will never be true when INT is parameterized as
+    // unsigned, even the presence of the unary operation causes a warning.
+    UINT res = ToUnsignedT<INT, UINT, NEG>::ToUnsigned(value);
+
+    typename STR::iterator it(outbuf.end());
+    do {
+      --it;
+      DCHECK(it != outbuf.begin());
+      *it = static_cast<typename STR::value_type>((res % 10) + '0');
+      res /= 10;
+    } while (res != 0);
+    if (is_neg) {
+      --it;
+      DCHECK(it != outbuf.begin());
+      *it = static_cast<typename STR::value_type>('-');
+    }
+    return STR(it, outbuf.end());
+  }
+};
+
+// Utility to convert a character to a digit in a given base
+template<typename CHAR, int BASE, bool BASE_LTE_10> class BaseCharToDigit {
+};
+
+// Faster specialization for bases <= 10
+template<typename CHAR, int BASE> class BaseCharToDigit<CHAR, BASE, true> {
+ public:
+  static bool Convert(CHAR c, uint8* digit) {
+    if (c >= '0' && c < '0' + BASE) {
+      *digit = static_cast<uint8>(c - '0');
+      return true;
+    }
+    return false;
+  }
+};
+
+// Specialization for bases where 10 < base <= 36
+template<typename CHAR, int BASE> class BaseCharToDigit<CHAR, BASE, false> {
+ public:
+  static bool Convert(CHAR c, uint8* digit) {
+    if (c >= '0' && c <= '9') {
+      *digit = c - '0';
+    } else if (c >= 'a' && c < 'a' + BASE - 10) {
+      *digit = c - 'a' + 10;
+    } else if (c >= 'A' && c < 'A' + BASE - 10) {
+      *digit = c - 'A' + 10;
+    } else {
+      return false;
+    }
+    return true;
+  }
+};
+
+template<int BASE, typename CHAR> bool CharToDigit(CHAR c, uint8* digit) {
+  return BaseCharToDigit<CHAR, BASE, BASE <= 10>::Convert(c, digit);
+}
+
+// There is an IsWhitespace for wchars defined in string_util.h, but it is
+// locale independent, whereas the functions we are replacing were
+// locale-dependent. TBD what is desired, but for the moment let's not introduce
+// a change in behaviour.
+template<typename CHAR> class WhitespaceHelper {
+};
+
+template<> class WhitespaceHelper<char> {
+ public:
+  static bool Invoke(char c) {
+    return 0 != isspace(static_cast<unsigned char>(c));
+  }
+};
+
+template<> class WhitespaceHelper<char16> {
+ public:
+  static bool Invoke(char16 c) {
+    return 0 != iswspace(c);
+  }
+};
+
+template<typename CHAR> bool LocalIsWhitespace(CHAR c) {
+  return WhitespaceHelper<CHAR>::Invoke(c);
+}
+
+// IteratorRangeToNumberTraits should provide:
+//  - a typedef for iterator_type, the iterator type used as input.
+//  - a typedef for value_type, the target numeric type.
+//  - static functions min, max (returning the minimum and maximum permitted
+//    values)
+//  - constant kBase, the base in which to interpret the input
+template<typename IteratorRangeToNumberTraits>
+class IteratorRangeToNumber {
+ public:
+  typedef IteratorRangeToNumberTraits traits;
+  typedef typename traits::iterator_type const_iterator;
+  typedef typename traits::value_type value_type;
+
+  // Generalized iterator-range-to-number conversion.
+  //
+  static bool Invoke(const_iterator begin,
+                     const_iterator end,
+                     value_type* output) {
+    bool valid = true;
+
+    while (begin != end && LocalIsWhitespace(*begin)) {
+      valid = false;
+      ++begin;
+    }
+
+    if (begin != end && *begin == '-') {
+      if (!std::numeric_limits<value_type>::is_signed) {
+        valid = false;
+      } else if (!Negative::Invoke(begin + 1, end, output)) {
+        valid = false;
+      }
+    } else {
+      if (begin != end && *begin == '+') {
+        ++begin;
+      }
+      if (!Positive::Invoke(begin, end, output)) {
+        valid = false;
+      }
+    }
+
+    return valid;
+  }
+
+ private:
+  // Sign provides:
+  //  - a static function, CheckBounds, that determines whether the next digit
+  //    causes an overflow/underflow
+  //  - a static function, Increment, that appends the next digit appropriately
+  //    according to the sign of the number being parsed.
+  template<typename Sign>
+  class Base {
+   public:
+    static bool Invoke(const_iterator begin, const_iterator end,
+                       typename traits::value_type* output) {
+      *output = 0;
+
+      if (begin == end) {
+        return false;
+      }
+
+      // Note: no performance difference was found when using template
+      // specialization to remove this check in bases other than 16
+      if (traits::kBase == 16 && end - begin > 2 && *begin == '0' &&
+          (*(begin + 1) == 'x' || *(begin + 1) == 'X')) {
+        begin += 2;
+      }
+
+      for (const_iterator current = begin; current != end; ++current) {
+        uint8 new_digit = 0;
+
+        if (!CharToDigit<traits::kBase>(*current, &new_digit)) {
+          return false;
+        }
+
+        if (current != begin) {
+          if (!Sign::CheckBounds(output, new_digit)) {
+            return false;
+          }
+          *output *= traits::kBase;
+        }
+
+        Sign::Increment(new_digit, output);
+      }
+      return true;
+    }
+  };
+
+  class Positive : public Base<Positive> {
+   public:
+    static bool CheckBounds(value_type* output, uint8 new_digit) {
+      if (*output > static_cast<value_type>(traits::max() / traits::kBase) ||
+          (*output == static_cast<value_type>(traits::max() / traits::kBase) &&
+           new_digit > traits::max() % traits::kBase)) {
+        *output = traits::max();
+        return false;
+      }
+      return true;
+    }
+    static void Increment(uint8 increment, value_type* output) {
+      *output += increment;
+    }
+  };
+
+  class Negative : public Base<Negative> {
+   public:
+    static bool CheckBounds(value_type* output, uint8 new_digit) {
+      if (*output < traits::min() / traits::kBase ||
+          (*output == traits::min() / traits::kBase &&
+           new_digit > 0 - traits::min() % traits::kBase)) {
+        *output = traits::min();
+        return false;
+      }
+      return true;
+    }
+    static void Increment(uint8 increment, value_type* output) {
+      *output -= increment;
+    }
+  };
+};
+
+template<typename ITERATOR, typename VALUE, int BASE>
+class BaseIteratorRangeToNumberTraits {
+ public:
+  typedef ITERATOR iterator_type;
+  typedef VALUE value_type;
+  static value_type min() {
+    return std::numeric_limits<value_type>::min();
+  }
+  static value_type max() {
+    return std::numeric_limits<value_type>::max();
+  }
+  static const int kBase = BASE;
+};
+
+template<typename ITERATOR>
+class BaseHexIteratorRangeToIntTraits
+    : public BaseIteratorRangeToNumberTraits<ITERATOR, int, 16> {
+};
+
+template<typename ITERATOR>
+class BaseHexIteratorRangeToUIntTraits
+    : public BaseIteratorRangeToNumberTraits<ITERATOR, uint32, 16> {
+};
+
+template<typename ITERATOR>
+class BaseHexIteratorRangeToInt64Traits
+    : public BaseIteratorRangeToNumberTraits<ITERATOR, int64, 16> {
+};
+
+template<typename ITERATOR>
+class BaseHexIteratorRangeToUInt64Traits
+    : public BaseIteratorRangeToNumberTraits<ITERATOR, uint64, 16> {
+};
+
+typedef BaseHexIteratorRangeToIntTraits<StringPiece::const_iterator>
+    HexIteratorRangeToIntTraits;
+
+typedef BaseHexIteratorRangeToUIntTraits<StringPiece::const_iterator>
+    HexIteratorRangeToUIntTraits;
+
+typedef BaseHexIteratorRangeToInt64Traits<StringPiece::const_iterator>
+    HexIteratorRangeToInt64Traits;
+
+typedef BaseHexIteratorRangeToUInt64Traits<StringPiece::const_iterator>
+    HexIteratorRangeToUInt64Traits;
+
+template<typename STR>
+bool HexStringToBytesT(const STR& input, std::vector<uint8>* output) {
+  DCHECK_EQ(output->size(), 0u);
+  size_t count = input.size();
+  if (count == 0 || (count % 2) != 0)
+    return false;
+  for (uintptr_t i = 0; i < count / 2; ++i) {
+    uint8 msb = 0;  // most significant 4 bits
+    uint8 lsb = 0;  // least significant 4 bits
+    if (!CharToDigit<16>(input[i * 2], &msb) ||
+        !CharToDigit<16>(input[i * 2 + 1], &lsb))
+      return false;
+    output->push_back((msb << 4) | lsb);
+  }
+  return true;
+}
+
+template <typename VALUE, int BASE>
+class StringPieceToNumberTraits
+    : public BaseIteratorRangeToNumberTraits<StringPiece::const_iterator,
+                                             VALUE,
+                                             BASE> {
+};
+
+template <typename VALUE>
+bool StringToIntImpl(const StringPiece& input, VALUE* output) {
+  return IteratorRangeToNumber<StringPieceToNumberTraits<VALUE, 10> >::Invoke(
+      input.begin(), input.end(), output);
+}
+
+template <typename VALUE, int BASE>
+class StringPiece16ToNumberTraits
+    : public BaseIteratorRangeToNumberTraits<StringPiece16::const_iterator,
+                                             VALUE,
+                                             BASE> {
+};
+
+template <typename VALUE>
+bool String16ToIntImpl(const StringPiece16& input, VALUE* output) {
+  return IteratorRangeToNumber<StringPiece16ToNumberTraits<VALUE, 10> >::Invoke(
+      input.begin(), input.end(), output);
+}
+
+}  // namespace
+
+std::string IntToString(int value) {
+  return IntToStringT<std::string, int, unsigned int, true>::
+      IntToString(value);
+}
+
+string16 IntToString16(int value) {
+  return IntToStringT<string16, int, unsigned int, true>::
+      IntToString(value);
+}
+
+std::string UintToString(unsigned int value) {
+  return IntToStringT<std::string, unsigned int, unsigned int, false>::
+      IntToString(value);
+}
+
+string16 UintToString16(unsigned int value) {
+  return IntToStringT<string16, unsigned int, unsigned int, false>::
+      IntToString(value);
+}
+
+std::string Int64ToString(int64 value) {
+  return IntToStringT<std::string, int64, uint64, true>::IntToString(value);
+}
+
+string16 Int64ToString16(int64 value) {
+  return IntToStringT<string16, int64, uint64, true>::IntToString(value);
+}
+
+std::string Uint64ToString(uint64 value) {
+  return IntToStringT<std::string, uint64, uint64, false>::IntToString(value);
+}
+
+string16 Uint64ToString16(uint64 value) {
+  return IntToStringT<string16, uint64, uint64, false>::IntToString(value);
+}
+
+std::string SizeTToString(size_t value) {
+  return IntToStringT<std::string, size_t, size_t, false>::IntToString(value);
+}
+
+string16 SizeTToString16(size_t value) {
+  return IntToStringT<string16, size_t, size_t, false>::IntToString(value);
+}
+
+std::string DoubleToString(double value) {
+  // According to g_fmt.cc, it is sufficient to declare a buffer of size 32.
+  char buffer[32];
+  dmg_fp::g_fmt(buffer, value);
+  return std::string(buffer);
+}
+
+bool StringToInt(const StringPiece& input, int* output) {
+  return StringToIntImpl(input, output);
+}
+
+bool StringToInt(const StringPiece16& input, int* output) {
+  return String16ToIntImpl(input, output);
+}
+
+bool StringToUint(const StringPiece& input, unsigned* output) {
+  return StringToIntImpl(input, output);
+}
+
+bool StringToUint(const StringPiece16& input, unsigned* output) {
+  return String16ToIntImpl(input, output);
+}
+
+bool StringToInt64(const StringPiece& input, int64* output) {
+  return StringToIntImpl(input, output);
+}
+
+bool StringToInt64(const StringPiece16& input, int64* output) {
+  return String16ToIntImpl(input, output);
+}
+
+bool StringToUint64(const StringPiece& input, uint64* output) {
+  return StringToIntImpl(input, output);
+}
+
+bool StringToUint64(const StringPiece16& input, uint64* output) {
+  return String16ToIntImpl(input, output);
+}
+
+bool StringToSizeT(const StringPiece& input, size_t* output) {
+  return StringToIntImpl(input, output);
+}
+
+bool StringToSizeT(const StringPiece16& input, size_t* output) {
+  return String16ToIntImpl(input, output);
+}
+
+bool StringToDouble(const std::string& input, double* output) {
+  // Thread-safe?  It is on at least Mac, Linux, and Windows.
+  ScopedClearErrno clear_errno;
+
+  char* endptr = NULL;
+  *output = dmg_fp::strtod(input.c_str(), &endptr);
+
+  // Cases to return false:
+  //  - If errno is ERANGE, there was an overflow or underflow.
+  //  - If the input string is empty, there was nothing to parse.
+  //  - If endptr does not point to the end of the string, there are either
+  //    characters remaining in the string after a parsed number, or the string
+  //    does not begin with a parseable number.  endptr is compared to the
+  //    expected end given the string's stated length to correctly catch cases
+  //    where the string contains embedded NUL characters.
+  //  - If the first character is a space, there was leading whitespace
+  return errno == 0 &&
+         !input.empty() &&
+         input.c_str() + input.length() == endptr &&
+         !isspace(input[0]);
+}
+
+// Note: if you need to add String16ToDouble, first ask yourself if it's
+// really necessary. If it is, probably the best implementation here is to
+// convert to 8-bit and then use the 8-bit version.
+
+// Note: if you need to add an iterator range version of StringToDouble, first
+// ask yourself if it's really necessary. If it is, probably the best
+// implementation here is to instantiate a string and use the string version.
+
+std::string HexEncode(const void* bytes, size_t size) {
+  static const char kHexChars[] = "0123456789ABCDEF";
+
+  // Each input byte creates two output hex characters.
+  std::string ret(size * 2, '\0');
+
+  for (size_t i = 0; i < size; ++i) {
+    char b = reinterpret_cast<const char*>(bytes)[i];
+    ret[(i * 2)] = kHexChars[(b >> 4) & 0xf];
+    ret[(i * 2) + 1] = kHexChars[b & 0xf];
+  }
+  return ret;
+}
+
+bool HexStringToInt(const StringPiece& input, int* output) {
+  return IteratorRangeToNumber<HexIteratorRangeToIntTraits>::Invoke(
+    input.begin(), input.end(), output);
+}
+
+bool HexStringToUInt(const StringPiece& input, uint32* output) {
+  return IteratorRangeToNumber<HexIteratorRangeToUIntTraits>::Invoke(
+      input.begin(), input.end(), output);
+}
+
+bool HexStringToInt64(const StringPiece& input, int64* output) {
+  return IteratorRangeToNumber<HexIteratorRangeToInt64Traits>::Invoke(
+    input.begin(), input.end(), output);
+}
+
+bool HexStringToUInt64(const StringPiece& input, uint64* output) {
+  return IteratorRangeToNumber<HexIteratorRangeToUInt64Traits>::Invoke(
+      input.begin(), input.end(), output);
+}
+
+bool HexStringToBytes(const std::string& input, std::vector<uint8>* output) {
+  return HexStringToBytesT(input, output);
+}
+
+}  // namespace base
diff --git a/base/strings/string_number_conversions.h b/base/strings/string_number_conversions.h
new file mode 100644
index 0000000..050e627
--- /dev/null
+++ b/base/strings/string_number_conversions.h
@@ -0,0 +1,131 @@
+// Copyright (c) 2012 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_STRINGS_STRING_NUMBER_CONVERSIONS_H_
+#define BASE_STRINGS_STRING_NUMBER_CONVERSIONS_H_
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
+
+// ----------------------------------------------------------------------------
+// IMPORTANT MESSAGE FROM YOUR SPONSOR
+//
+// This file contains no "wstring" variants. New code should use string16. If
+// you need to make old code work, use the UTF8 version and convert. Please do
+// not add wstring variants.
+//
+// Please do not add "convenience" functions for converting strings to integers
+// that return the value and ignore success/failure. That encourages people to
+// write code that doesn't properly handle the error conditions.
+// ----------------------------------------------------------------------------
+
+namespace base {
+
+// Number -> string conversions ------------------------------------------------
+
+BASE_EXPORT std::string IntToString(int value);
+BASE_EXPORT string16 IntToString16(int value);
+
+BASE_EXPORT std::string UintToString(unsigned value);
+BASE_EXPORT string16 UintToString16(unsigned value);
+
+BASE_EXPORT std::string Int64ToString(int64 value);
+BASE_EXPORT string16 Int64ToString16(int64 value);
+
+BASE_EXPORT std::string Uint64ToString(uint64 value);
+BASE_EXPORT string16 Uint64ToString16(uint64 value);
+
+BASE_EXPORT std::string SizeTToString(size_t value);
+BASE_EXPORT string16 SizeTToString16(size_t value);
+
+// DoubleToString converts the double to a string format that ignores the
+// locale. If you want to use locale specific formatting, use ICU.
+BASE_EXPORT std::string DoubleToString(double value);
+
+// String -> number conversions ------------------------------------------------
+
+// Perform a best-effort conversion of the input string to a numeric type,
+// setting |*output| to the result of the conversion.  Returns true for
+// "perfect" conversions; returns false in the following cases:
+//  - Overflow. |*output| will be set to the maximum value supported
+//    by the data type.
+//  - Underflow. |*output| will be set to the minimum value supported
+//    by the data type.
+//  - Trailing characters in the string after parsing the number.  |*output|
+//    will be set to the value of the number that was parsed.
+//  - Leading whitespace in the string before parsing the number. |*output| will
+//    be set to the value of the number that was parsed.
+//  - No characters parseable as a number at the beginning of the string.
+//    |*output| will be set to 0.
+//  - Empty string.  |*output| will be set to 0.
+BASE_EXPORT bool StringToInt(const StringPiece& input, int* output);
+BASE_EXPORT bool StringToInt(const StringPiece16& input, int* output);
+
+BASE_EXPORT bool StringToUint(const StringPiece& input, unsigned* output);
+BASE_EXPORT bool StringToUint(const StringPiece16& input, unsigned* output);
+
+BASE_EXPORT bool StringToInt64(const StringPiece& input, int64* output);
+BASE_EXPORT bool StringToInt64(const StringPiece16& input, int64* output);
+
+BASE_EXPORT bool StringToUint64(const StringPiece& input, uint64* output);
+BASE_EXPORT bool StringToUint64(const StringPiece16& input, uint64* output);
+
+BASE_EXPORT bool StringToSizeT(const StringPiece& input, size_t* output);
+BASE_EXPORT bool StringToSizeT(const StringPiece16& input, size_t* output);
+
+// For floating-point conversions, only conversions of input strings in decimal
+// form are defined to work.  Behavior with strings representing floating-point
+// numbers in hexadecimal, and strings representing non-fininte values (such as
+// NaN and inf) is undefined.  Otherwise, these behave the same as the integral
+// variants.  This expects the input string to NOT be specific to the locale.
+// If your input is locale specific, use ICU to read the number.
+BASE_EXPORT bool StringToDouble(const std::string& input, double* output);
+
+// Hex encoding ----------------------------------------------------------------
+
+// Returns a hex string representation of a binary buffer. The returned hex
+// string will be in upper case. This function does not check if |size| is
+// within reasonable limits since it's written with trusted data in mind.  If
+// you suspect that the data you want to format might be large, the absolute
+// max size for |size| should be is
+//   std::numeric_limits<size_t>::max() / 2
+BASE_EXPORT std::string HexEncode(const void* bytes, size_t size);
+
+// Best effort conversion, see StringToInt above for restrictions.
+// Will only successful parse hex values that will fit into |output|, i.e.
+// -0x80000000 < |input| < 0x7FFFFFFF.
+BASE_EXPORT bool HexStringToInt(const StringPiece& input, int* output);
+
+// Best effort conversion, see StringToInt above for restrictions.
+// Will only successful parse hex values that will fit into |output|, i.e.
+// 0x00000000 < |input| < 0xFFFFFFFF.
+// The string is not required to start with 0x.
+BASE_EXPORT bool HexStringToUInt(const StringPiece& input, uint32* output);
+
+// Best effort conversion, see StringToInt above for restrictions.
+// Will only successful parse hex values that will fit into |output|, i.e.
+// -0x8000000000000000 < |input| < 0x7FFFFFFFFFFFFFFF.
+BASE_EXPORT bool HexStringToInt64(const StringPiece& input, int64* output);
+
+// Best effort conversion, see StringToInt above for restrictions.
+// Will only successful parse hex values that will fit into |output|, i.e.
+// 0x0000000000000000 < |input| < 0xFFFFFFFFFFFFFFFF.
+// The string is not required to start with 0x.
+BASE_EXPORT bool HexStringToUInt64(const StringPiece& input, uint64* output);
+
+// Similar to the previous functions, except that output is a vector of bytes.
+// |*output| will contain as many bytes as were successfully parsed prior to the
+// error.  There is no overflow, but input.size() must be evenly divisible by 2.
+// Leading 0x or +/- are not allowed.
+BASE_EXPORT bool HexStringToBytes(const std::string& input,
+                                  std::vector<uint8>* output);
+
+}  // namespace base
+
+#endif  // BASE_STRINGS_STRING_NUMBER_CONVERSIONS_H_
diff --git a/base/strings/string_number_conversions_unittest.cc b/base/strings/string_number_conversions_unittest.cc
new file mode 100644
index 0000000..0bc72f1
--- /dev/null
+++ b/base/strings/string_number_conversions_unittest.cc
@@ -0,0 +1,796 @@
+// Copyright (c) 2012 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/strings/string_number_conversions.h"
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include <cmath>
+#include <limits>
+
+#include "base/format_macros.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+template <typename INT>
+struct IntToStringTest {
+  INT num;
+  const char* sexpected;
+  const char* uexpected;
+};
+
+}  // namespace
+
+TEST(StringNumberConversionsTest, IntToString) {
+  static const IntToStringTest<int> int_tests[] = {
+      { 0, "0", "0" },
+      { -1, "-1", "4294967295" },
+      { std::numeric_limits<int>::max(), "2147483647", "2147483647" },
+      { std::numeric_limits<int>::min(), "-2147483648", "2147483648" },
+  };
+  static const IntToStringTest<int64> int64_tests[] = {
+      { 0, "0", "0" },
+      { -1, "-1", "18446744073709551615" },
+      { std::numeric_limits<int64>::max(),
+        "9223372036854775807",
+        "9223372036854775807", },
+      { std::numeric_limits<int64>::min(),
+        "-9223372036854775808",
+        "9223372036854775808" },
+  };
+
+  for (size_t i = 0; i < arraysize(int_tests); ++i) {
+    const IntToStringTest<int>* test = &int_tests[i];
+    EXPECT_EQ(IntToString(test->num), test->sexpected);
+    EXPECT_EQ(IntToString16(test->num), UTF8ToUTF16(test->sexpected));
+    EXPECT_EQ(UintToString(test->num), test->uexpected);
+    EXPECT_EQ(UintToString16(test->num), UTF8ToUTF16(test->uexpected));
+  }
+  for (size_t i = 0; i < arraysize(int64_tests); ++i) {
+    const IntToStringTest<int64>* test = &int64_tests[i];
+    EXPECT_EQ(Int64ToString(test->num), test->sexpected);
+    EXPECT_EQ(Int64ToString16(test->num), UTF8ToUTF16(test->sexpected));
+    EXPECT_EQ(Uint64ToString(test->num), test->uexpected);
+    EXPECT_EQ(Uint64ToString16(test->num), UTF8ToUTF16(test->uexpected));
+  }
+}
+
+TEST(StringNumberConversionsTest, Uint64ToString) {
+  static const struct {
+    uint64 input;
+    std::string output;
+  } cases[] = {
+    {0, "0"},
+    {42, "42"},
+    {INT_MAX, "2147483647"},
+    {kuint64max, "18446744073709551615"},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i)
+    EXPECT_EQ(cases[i].output, Uint64ToString(cases[i].input));
+}
+
+TEST(StringNumberConversionsTest, SizeTToString) {
+  size_t size_t_max = std::numeric_limits<size_t>::max();
+  std::string size_t_max_string = StringPrintf("%" PRIuS, size_t_max);
+
+  static const struct {
+    size_t input;
+    std::string output;
+  } cases[] = {
+    {0, "0"},
+    {9, "9"},
+    {42, "42"},
+    {INT_MAX, "2147483647"},
+    {2147483648U, "2147483648"},
+#if SIZE_MAX > 4294967295U
+    {99999999999U, "99999999999"},
+#endif
+    {size_t_max, size_t_max_string},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i)
+    EXPECT_EQ(cases[i].output, Uint64ToString(cases[i].input));
+}
+
+TEST(StringNumberConversionsTest, StringToInt) {
+  static const struct {
+    std::string input;
+    int output;
+    bool success;
+  } cases[] = {
+    {"0", 0, true},
+    {"42", 42, true},
+    {"42\x99", 42, false},
+    {"\x99" "42\x99", 0, false},
+    {"-2147483648", INT_MIN, true},
+    {"2147483647", INT_MAX, true},
+    {"", 0, false},
+    {" 42", 42, false},
+    {"42 ", 42, false},
+    {"\t\n\v\f\r 42", 42, false},
+    {"blah42", 0, false},
+    {"42blah", 42, false},
+    {"blah42blah", 0, false},
+    {"-273.15", -273, false},
+    {"+98.6", 98, false},
+    {"--123", 0, false},
+    {"++123", 0, false},
+    {"-+123", 0, false},
+    {"+-123", 0, false},
+    {"-", 0, false},
+    {"-2147483649", INT_MIN, false},
+    {"-99999999999", INT_MIN, false},
+    {"2147483648", INT_MAX, false},
+    {"99999999999", INT_MAX, false},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    int output = 0;
+    EXPECT_EQ(cases[i].success, StringToInt(cases[i].input, &output));
+    EXPECT_EQ(cases[i].output, output);
+
+    string16 utf16_input = UTF8ToUTF16(cases[i].input);
+    output = 0;
+    EXPECT_EQ(cases[i].success, StringToInt(utf16_input, &output));
+    EXPECT_EQ(cases[i].output, output);
+  }
+
+  // One additional test to verify that conversion of numbers in strings with
+  // embedded NUL characters.  The NUL and extra data after it should be
+  // interpreted as junk after the number.
+  const char input[] = "6\06";
+  std::string input_string(input, arraysize(input) - 1);
+  int output;
+  EXPECT_FALSE(StringToInt(input_string, &output));
+  EXPECT_EQ(6, output);
+
+  string16 utf16_input = UTF8ToUTF16(input_string);
+  output = 0;
+  EXPECT_FALSE(StringToInt(utf16_input, &output));
+  EXPECT_EQ(6, output);
+
+  output = 0;
+  const char16 negative_wide_input[] = { 0xFF4D, '4', '2', 0};
+  EXPECT_FALSE(StringToInt(string16(negative_wide_input), &output));
+  EXPECT_EQ(0, output);
+}
+
+TEST(StringNumberConversionsTest, StringToUint) {
+  static const struct {
+    std::string input;
+    unsigned output;
+    bool success;
+  } cases[] = {
+    {"0", 0, true},
+    {"42", 42, true},
+    {"42\x99", 42, false},
+    {"\x99" "42\x99", 0, false},
+    {"-2147483648", 0, false},
+    {"2147483647", INT_MAX, true},
+    {"", 0, false},
+    {" 42", 42, false},
+    {"42 ", 42, false},
+    {"\t\n\v\f\r 42", 42, false},
+    {"blah42", 0, false},
+    {"42blah", 42, false},
+    {"blah42blah", 0, false},
+    {"-273.15", 0, false},
+    {"+98.6", 98, false},
+    {"--123", 0, false},
+    {"++123", 0, false},
+    {"-+123", 0, false},
+    {"+-123", 0, false},
+    {"-", 0, false},
+    {"-2147483649", 0, false},
+    {"-99999999999", 0, false},
+    {"4294967295", UINT_MAX, true},
+    {"4294967296", UINT_MAX, false},
+    {"99999999999", UINT_MAX, false},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    unsigned output = 0;
+    EXPECT_EQ(cases[i].success, StringToUint(cases[i].input, &output));
+    EXPECT_EQ(cases[i].output, output);
+
+    string16 utf16_input = UTF8ToUTF16(cases[i].input);
+    output = 0;
+    EXPECT_EQ(cases[i].success, StringToUint(utf16_input, &output));
+    EXPECT_EQ(cases[i].output, output);
+  }
+
+  // One additional test to verify that conversion of numbers in strings with
+  // embedded NUL characters.  The NUL and extra data after it should be
+  // interpreted as junk after the number.
+  const char input[] = "6\06";
+  std::string input_string(input, arraysize(input) - 1);
+  unsigned output;
+  EXPECT_FALSE(StringToUint(input_string, &output));
+  EXPECT_EQ(6U, output);
+
+  string16 utf16_input = UTF8ToUTF16(input_string);
+  output = 0;
+  EXPECT_FALSE(StringToUint(utf16_input, &output));
+  EXPECT_EQ(6U, output);
+
+  output = 0;
+  const char16 negative_wide_input[] = { 0xFF4D, '4', '2', 0};
+  EXPECT_FALSE(StringToUint(string16(negative_wide_input), &output));
+  EXPECT_EQ(0U, output);
+}
+
+TEST(StringNumberConversionsTest, StringToInt64) {
+  static const struct {
+    std::string input;
+    int64 output;
+    bool success;
+  } cases[] = {
+    {"0", 0, true},
+    {"42", 42, true},
+    {"-2147483648", INT_MIN, true},
+    {"2147483647", INT_MAX, true},
+    {"-2147483649", INT64_C(-2147483649), true},
+    {"-99999999999", INT64_C(-99999999999), true},
+    {"2147483648", INT64_C(2147483648), true},
+    {"99999999999", INT64_C(99999999999), true},
+    {"9223372036854775807", kint64max, true},
+    {"-9223372036854775808", kint64min, true},
+    {"09", 9, true},
+    {"-09", -9, true},
+    {"", 0, false},
+    {" 42", 42, false},
+    {"42 ", 42, false},
+    {"0x42", 0, false},
+    {"\t\n\v\f\r 42", 42, false},
+    {"blah42", 0, false},
+    {"42blah", 42, false},
+    {"blah42blah", 0, false},
+    {"-273.15", -273, false},
+    {"+98.6", 98, false},
+    {"--123", 0, false},
+    {"++123", 0, false},
+    {"-+123", 0, false},
+    {"+-123", 0, false},
+    {"-", 0, false},
+    {"-9223372036854775809", kint64min, false},
+    {"-99999999999999999999", kint64min, false},
+    {"9223372036854775808", kint64max, false},
+    {"99999999999999999999", kint64max, false},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    int64 output = 0;
+    EXPECT_EQ(cases[i].success, StringToInt64(cases[i].input, &output));
+    EXPECT_EQ(cases[i].output, output);
+
+    string16 utf16_input = UTF8ToUTF16(cases[i].input);
+    output = 0;
+    EXPECT_EQ(cases[i].success, StringToInt64(utf16_input, &output));
+    EXPECT_EQ(cases[i].output, output);
+  }
+
+  // One additional test to verify that conversion of numbers in strings with
+  // embedded NUL characters.  The NUL and extra data after it should be
+  // interpreted as junk after the number.
+  const char input[] = "6\06";
+  std::string input_string(input, arraysize(input) - 1);
+  int64 output;
+  EXPECT_FALSE(StringToInt64(input_string, &output));
+  EXPECT_EQ(6, output);
+
+  string16 utf16_input = UTF8ToUTF16(input_string);
+  output = 0;
+  EXPECT_FALSE(StringToInt64(utf16_input, &output));
+  EXPECT_EQ(6, output);
+}
+
+TEST(StringNumberConversionsTest, StringToUint64) {
+  static const struct {
+    std::string input;
+    uint64 output;
+    bool success;
+  } cases[] = {
+    {"0", 0, true},
+    {"42", 42, true},
+    {"-2147483648", 0, false},
+    {"2147483647", INT_MAX, true},
+    {"-2147483649", 0, false},
+    {"-99999999999", 0, false},
+    {"2147483648", UINT64_C(2147483648), true},
+    {"99999999999", UINT64_C(99999999999), true},
+    {"9223372036854775807", kint64max, true},
+    {"-9223372036854775808", 0, false},
+    {"09", 9, true},
+    {"-09", 0, false},
+    {"", 0, false},
+    {" 42", 42, false},
+    {"42 ", 42, false},
+    {"0x42", 0, false},
+    {"\t\n\v\f\r 42", 42, false},
+    {"blah42", 0, false},
+    {"42blah", 42, false},
+    {"blah42blah", 0, false},
+    {"-273.15", 0, false},
+    {"+98.6", 98, false},
+    {"--123", 0, false},
+    {"++123", 0, false},
+    {"-+123", 0, false},
+    {"+-123", 0, false},
+    {"-", 0, false},
+    {"-9223372036854775809", 0, false},
+    {"-99999999999999999999", 0, false},
+    {"9223372036854775808", UINT64_C(9223372036854775808), true},
+    {"99999999999999999999", kuint64max, false},
+    {"18446744073709551615", kuint64max, true},
+    {"18446744073709551616", kuint64max, false},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    uint64 output = 0;
+    EXPECT_EQ(cases[i].success, StringToUint64(cases[i].input, &output));
+    EXPECT_EQ(cases[i].output, output);
+
+    string16 utf16_input = UTF8ToUTF16(cases[i].input);
+    output = 0;
+    EXPECT_EQ(cases[i].success, StringToUint64(utf16_input, &output));
+    EXPECT_EQ(cases[i].output, output);
+  }
+
+  // One additional test to verify that conversion of numbers in strings with
+  // embedded NUL characters.  The NUL and extra data after it should be
+  // interpreted as junk after the number.
+  const char input[] = "6\06";
+  std::string input_string(input, arraysize(input) - 1);
+  uint64 output;
+  EXPECT_FALSE(StringToUint64(input_string, &output));
+  EXPECT_EQ(6U, output);
+
+  string16 utf16_input = UTF8ToUTF16(input_string);
+  output = 0;
+  EXPECT_FALSE(StringToUint64(utf16_input, &output));
+  EXPECT_EQ(6U, output);
+}
+
+TEST(StringNumberConversionsTest, StringToSizeT) {
+  size_t size_t_max = std::numeric_limits<size_t>::max();
+  std::string size_t_max_string = StringPrintf("%" PRIuS, size_t_max);
+
+  static const struct {
+    std::string input;
+    size_t output;
+    bool success;
+  } cases[] = {
+    {"0", 0, true},
+    {"42", 42, true},
+    {"-2147483648", 0, false},
+    {"2147483647", INT_MAX, true},
+    {"-2147483649", 0, false},
+    {"-99999999999", 0, false},
+    {"2147483648", 2147483648U, true},
+#if SIZE_MAX > 4294967295U
+    {"99999999999", 99999999999U, true},
+#endif
+    {"-9223372036854775808", 0, false},
+    {"09", 9, true},
+    {"-09", 0, false},
+    {"", 0, false},
+    {" 42", 42, false},
+    {"42 ", 42, false},
+    {"0x42", 0, false},
+    {"\t\n\v\f\r 42", 42, false},
+    {"blah42", 0, false},
+    {"42blah", 42, false},
+    {"blah42blah", 0, false},
+    {"-273.15", 0, false},
+    {"+98.6", 98, false},
+    {"--123", 0, false},
+    {"++123", 0, false},
+    {"-+123", 0, false},
+    {"+-123", 0, false},
+    {"-", 0, false},
+    {"-9223372036854775809", 0, false},
+    {"-99999999999999999999", 0, false},
+    {"999999999999999999999999", size_t_max, false},
+    {size_t_max_string, size_t_max, true},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    size_t output = 0;
+    EXPECT_EQ(cases[i].success, StringToSizeT(cases[i].input, &output));
+    EXPECT_EQ(cases[i].output, output);
+
+    string16 utf16_input = UTF8ToUTF16(cases[i].input);
+    output = 0;
+    EXPECT_EQ(cases[i].success, StringToSizeT(utf16_input, &output));
+    EXPECT_EQ(cases[i].output, output);
+  }
+
+  // One additional test to verify that conversion of numbers in strings with
+  // embedded NUL characters.  The NUL and extra data after it should be
+  // interpreted as junk after the number.
+  const char input[] = "6\06";
+  std::string input_string(input, arraysize(input) - 1);
+  size_t output;
+  EXPECT_FALSE(StringToSizeT(input_string, &output));
+  EXPECT_EQ(6U, output);
+
+  string16 utf16_input = UTF8ToUTF16(input_string);
+  output = 0;
+  EXPECT_FALSE(StringToSizeT(utf16_input, &output));
+  EXPECT_EQ(6U, output);
+}
+
+TEST(StringNumberConversionsTest, HexStringToInt) {
+  static const struct {
+    std::string input;
+    int64 output;
+    bool success;
+  } cases[] = {
+    {"0", 0, true},
+    {"42", 66, true},
+    {"-42", -66, true},
+    {"+42", 66, true},
+    {"7fffffff", INT_MAX, true},
+    {"-80000000", INT_MIN, true},
+    {"80000000", INT_MAX, false},  // Overflow test.
+    {"-80000001", INT_MIN, false},  // Underflow test.
+    {"0x42", 66, true},
+    {"-0x42", -66, true},
+    {"+0x42", 66, true},
+    {"0x7fffffff", INT_MAX, true},
+    {"-0x80000000", INT_MIN, true},
+    {"-80000000", INT_MIN, true},
+    {"80000000", INT_MAX, false},  // Overflow test.
+    {"-80000001", INT_MIN, false},  // Underflow test.
+    {"0x0f", 15, true},
+    {"0f", 15, true},
+    {" 45", 0x45, false},
+    {"\t\n\v\f\r 0x45", 0x45, false},
+    {" 45", 0x45, false},
+    {"45 ", 0x45, false},
+    {"45:", 0x45, false},
+    {"efgh", 0xef, false},
+    {"0xefgh", 0xef, false},
+    {"hgfe", 0, false},
+    {"-", 0, false},
+    {"", 0, false},
+    {"0x", 0, false},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    int output = 0;
+    EXPECT_EQ(cases[i].success, HexStringToInt(cases[i].input, &output));
+    EXPECT_EQ(cases[i].output, output);
+  }
+  // One additional test to verify that conversion of numbers in strings with
+  // embedded NUL characters.  The NUL and extra data after it should be
+  // interpreted as junk after the number.
+  const char input[] = "0xc0ffee\0" "9";
+  std::string input_string(input, arraysize(input) - 1);
+  int output;
+  EXPECT_FALSE(HexStringToInt(input_string, &output));
+  EXPECT_EQ(0xc0ffee, output);
+}
+
+TEST(StringNumberConversionsTest, HexStringToUInt) {
+  static const struct {
+    std::string input;
+    uint32 output;
+    bool success;
+  } cases[] = {
+    {"0", 0, true},
+    {"42", 0x42, true},
+    {"-42", 0, false},
+    {"+42", 0x42, true},
+    {"7fffffff", INT_MAX, true},
+    {"-80000000", 0, false},
+    {"ffffffff", 0xffffffff, true},
+    {"DeadBeef", 0xdeadbeef, true},
+    {"0x42", 0x42, true},
+    {"-0x42", 0, false},
+    {"+0x42", 0x42, true},
+    {"0x7fffffff", INT_MAX, true},
+    {"-0x80000000", 0, false},
+    {"0xffffffff", kuint32max, true},
+    {"0XDeadBeef", 0xdeadbeef, true},
+    {"0x7fffffffffffffff", kuint32max, false},  // Overflow test.
+    {"-0x8000000000000000", 0, false},
+    {"0x8000000000000000", kuint32max, false},  // Overflow test.
+    {"-0x8000000000000001", 0, false},
+    {"0xFFFFFFFFFFFFFFFF", kuint32max, false},  // Overflow test.
+    {"FFFFFFFFFFFFFFFF", kuint32max, false},  // Overflow test.
+    {"0x0000000000000000", 0, true},
+    {"0000000000000000", 0, true},
+    {"1FFFFFFFFFFFFFFFF", kuint32max, false}, // Overflow test.
+    {"0x0f", 0x0f, true},
+    {"0f", 0x0f, true},
+    {" 45", 0x45, false},
+    {"\t\n\v\f\r 0x45", 0x45, false},
+    {" 45", 0x45, false},
+    {"45 ", 0x45, false},
+    {"45:", 0x45, false},
+    {"efgh", 0xef, false},
+    {"0xefgh", 0xef, false},
+    {"hgfe", 0, false},
+    {"-", 0, false},
+    {"", 0, false},
+    {"0x", 0, false},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    uint32 output = 0;
+    EXPECT_EQ(cases[i].success, HexStringToUInt(cases[i].input, &output));
+    EXPECT_EQ(cases[i].output, output);
+  }
+  // One additional test to verify that conversion of numbers in strings with
+  // embedded NUL characters.  The NUL and extra data after it should be
+  // interpreted as junk after the number.
+  const char input[] = "0xc0ffee\0" "9";
+  std::string input_string(input, arraysize(input) - 1);
+  uint32 output;
+  EXPECT_FALSE(HexStringToUInt(input_string, &output));
+  EXPECT_EQ(0xc0ffeeU, output);
+}
+
+TEST(StringNumberConversionsTest, HexStringToInt64) {
+  static const struct {
+    std::string input;
+    int64 output;
+    bool success;
+  } cases[] = {
+    {"0", 0, true},
+    {"42", 66, true},
+    {"-42", -66, true},
+    {"+42", 66, true},
+    {"40acd88557b", INT64_C(4444444448123), true},
+    {"7fffffff", INT_MAX, true},
+    {"-80000000", INT_MIN, true},
+    {"ffffffff", 0xffffffff, true},
+    {"DeadBeef", 0xdeadbeef, true},
+    {"0x42", 66, true},
+    {"-0x42", -66, true},
+    {"+0x42", 66, true},
+    {"0x40acd88557b", INT64_C(4444444448123), true},
+    {"0x7fffffff", INT_MAX, true},
+    {"-0x80000000", INT_MIN, true},
+    {"0xffffffff", 0xffffffff, true},
+    {"0XDeadBeef", 0xdeadbeef, true},
+    {"0x7fffffffffffffff", kint64max, true},
+    {"-0x8000000000000000", kint64min, true},
+    {"0x8000000000000000", kint64max, false},  // Overflow test.
+    {"-0x8000000000000001", kint64min, false},  // Underflow test.
+    {"0x0f", 15, true},
+    {"0f", 15, true},
+    {" 45", 0x45, false},
+    {"\t\n\v\f\r 0x45", 0x45, false},
+    {" 45", 0x45, false},
+    {"45 ", 0x45, false},
+    {"45:", 0x45, false},
+    {"efgh", 0xef, false},
+    {"0xefgh", 0xef, false},
+    {"hgfe", 0, false},
+    {"-", 0, false},
+    {"", 0, false},
+    {"0x", 0, false},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    int64 output = 0;
+    EXPECT_EQ(cases[i].success, HexStringToInt64(cases[i].input, &output));
+    EXPECT_EQ(cases[i].output, output);
+  }
+  // One additional test to verify that conversion of numbers in strings with
+  // embedded NUL characters.  The NUL and extra data after it should be
+  // interpreted as junk after the number.
+  const char input[] = "0xc0ffee\0" "9";
+  std::string input_string(input, arraysize(input) - 1);
+  int64 output;
+  EXPECT_FALSE(HexStringToInt64(input_string, &output));
+  EXPECT_EQ(0xc0ffee, output);
+}
+
+TEST(StringNumberConversionsTest, HexStringToUInt64) {
+  static const struct {
+    std::string input;
+    uint64 output;
+    bool success;
+  } cases[] = {
+    {"0", 0, true},
+    {"42", 66, true},
+    {"-42", 0, false},
+    {"+42", 66, true},
+    {"40acd88557b", INT64_C(4444444448123), true},
+    {"7fffffff", INT_MAX, true},
+    {"-80000000", 0, false},
+    {"ffffffff", 0xffffffff, true},
+    {"DeadBeef", 0xdeadbeef, true},
+    {"0x42", 66, true},
+    {"-0x42", 0, false},
+    {"+0x42", 66, true},
+    {"0x40acd88557b", INT64_C(4444444448123), true},
+    {"0x7fffffff", INT_MAX, true},
+    {"-0x80000000", 0, false},
+    {"0xffffffff", 0xffffffff, true},
+    {"0XDeadBeef", 0xdeadbeef, true},
+    {"0x7fffffffffffffff", kint64max, true},
+    {"-0x8000000000000000", 0, false},
+    {"0x8000000000000000", UINT64_C(0x8000000000000000), true},
+    {"-0x8000000000000001", 0, false},
+    {"0xFFFFFFFFFFFFFFFF", kuint64max, true},
+    {"FFFFFFFFFFFFFFFF", kuint64max, true},
+    {"0x0000000000000000", 0, true},
+    {"0000000000000000", 0, true},
+    {"1FFFFFFFFFFFFFFFF", kuint64max, false}, // Overflow test.
+    {"0x0f", 15, true},
+    {"0f", 15, true},
+    {" 45", 0x45, false},
+    {"\t\n\v\f\r 0x45", 0x45, false},
+    {" 45", 0x45, false},
+    {"45 ", 0x45, false},
+    {"45:", 0x45, false},
+    {"efgh", 0xef, false},
+    {"0xefgh", 0xef, false},
+    {"hgfe", 0, false},
+    {"-", 0, false},
+    {"", 0, false},
+    {"0x", 0, false},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    uint64 output = 0;
+    EXPECT_EQ(cases[i].success, HexStringToUInt64(cases[i].input, &output));
+    EXPECT_EQ(cases[i].output, output);
+  }
+  // One additional test to verify that conversion of numbers in strings with
+  // embedded NUL characters.  The NUL and extra data after it should be
+  // interpreted as junk after the number.
+  const char input[] = "0xc0ffee\0" "9";
+  std::string input_string(input, arraysize(input) - 1);
+  uint64 output;
+  EXPECT_FALSE(HexStringToUInt64(input_string, &output));
+  EXPECT_EQ(0xc0ffeeU, output);
+}
+
+TEST(StringNumberConversionsTest, HexStringToBytes) {
+  static const struct {
+    const std::string input;
+    const char* output;
+    size_t output_len;
+    bool success;
+  } cases[] = {
+    {"0", "", 0, false},  // odd number of characters fails
+    {"00", "\0", 1, true},
+    {"42", "\x42", 1, true},
+    {"-42", "", 0, false},  // any non-hex value fails
+    {"+42", "", 0, false},
+    {"7fffffff", "\x7f\xff\xff\xff", 4, true},
+    {"80000000", "\x80\0\0\0", 4, true},
+    {"deadbeef", "\xde\xad\xbe\xef", 4, true},
+    {"DeadBeef", "\xde\xad\xbe\xef", 4, true},
+    {"0x42", "", 0, false},  // leading 0x fails (x is not hex)
+    {"0f", "\xf", 1, true},
+    {"45  ", "\x45", 1, false},
+    {"efgh", "\xef", 1, false},
+    {"", "", 0, false},
+    {"0123456789ABCDEF", "\x01\x23\x45\x67\x89\xAB\xCD\xEF", 8, true},
+    {"0123456789ABCDEF012345",
+     "\x01\x23\x45\x67\x89\xAB\xCD\xEF\x01\x23\x45", 11, true},
+  };
+
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    std::vector<uint8> output;
+    std::vector<uint8> compare;
+    EXPECT_EQ(cases[i].success, HexStringToBytes(cases[i].input, &output)) <<
+        i << ": " << cases[i].input;
+    for (size_t j = 0; j < cases[i].output_len; ++j)
+      compare.push_back(static_cast<uint8>(cases[i].output[j]));
+    ASSERT_EQ(output.size(), compare.size()) << i << ": " << cases[i].input;
+    EXPECT_TRUE(std::equal(output.begin(), output.end(), compare.begin())) <<
+        i << ": " << cases[i].input;
+  }
+}
+
+TEST(StringNumberConversionsTest, StringToDouble) {
+  static const struct {
+    std::string input;
+    double output;
+    bool success;
+  } cases[] = {
+    {"0", 0.0, true},
+    {"42", 42.0, true},
+    {"-42", -42.0, true},
+    {"123.45", 123.45, true},
+    {"-123.45", -123.45, true},
+    {"+123.45", 123.45, true},
+    {"2.99792458e8", 299792458.0, true},
+    {"149597870.691E+3", 149597870691.0, true},
+    {"6.", 6.0, true},
+    {"9e99999999999999999999", HUGE_VAL, false},
+    {"-9e99999999999999999999", -HUGE_VAL, false},
+    {"1e-2", 0.01, true},
+    {"42 ", 42.0, false},
+    {" 1e-2", 0.01, false},
+    {"1e-2 ", 0.01, false},
+    {"-1E-7", -0.0000001, true},
+    {"01e02", 100, true},
+    {"2.3e15", 2.3e15, true},
+    {"\t\n\v\f\r -123.45e2", -12345.0, false},
+    {"+123 e4", 123.0, false},
+    {"123e ", 123.0, false},
+    {"123e", 123.0, false},
+    {" 2.99", 2.99, false},
+    {"1e3.4", 1000.0, false},
+    {"nothing", 0.0, false},
+    {"-", 0.0, false},
+    {"+", 0.0, false},
+    {"", 0.0, false},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    double output;
+    errno = 1;
+    EXPECT_EQ(cases[i].success, StringToDouble(cases[i].input, &output));
+    if (cases[i].success)
+      EXPECT_EQ(1, errno) << i;  // confirm that errno is unchanged.
+    EXPECT_DOUBLE_EQ(cases[i].output, output);
+  }
+
+  // One additional test to verify that conversion of numbers in strings with
+  // embedded NUL characters.  The NUL and extra data after it should be
+  // interpreted as junk after the number.
+  const char input[] = "3.14\0" "159";
+  std::string input_string(input, arraysize(input) - 1);
+  double output;
+  EXPECT_FALSE(StringToDouble(input_string, &output));
+  EXPECT_DOUBLE_EQ(3.14, output);
+}
+
+TEST(StringNumberConversionsTest, DoubleToString) {
+  static const struct {
+    double input;
+    const char* expected;
+  } cases[] = {
+    {0.0, "0"},
+    {1.25, "1.25"},
+    {1.33518e+012, "1.33518e+12"},
+    {1.33489e+012, "1.33489e+12"},
+    {1.33505e+012, "1.33505e+12"},
+    {1.33545e+009, "1335450000"},
+    {1.33503e+009, "1335030000"},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    EXPECT_EQ(cases[i].expected, DoubleToString(cases[i].input));
+  }
+
+  // The following two values were seen in crashes in the wild.
+  const char input_bytes[8] = {0, 0, 0, 0, '\xee', '\x6d', '\x73', '\x42'};
+  double input = 0;
+  memcpy(&input, input_bytes, arraysize(input_bytes));
+  EXPECT_EQ("1335179083776", DoubleToString(input));
+  const char input_bytes2[8] =
+      {0, 0, 0, '\xa0', '\xda', '\x6c', '\x73', '\x42'};
+  input = 0;
+  memcpy(&input, input_bytes2, arraysize(input_bytes2));
+  EXPECT_EQ("1334890332160", DoubleToString(input));
+}
+
+TEST(StringNumberConversionsTest, HexEncode) {
+  std::string hex(HexEncode(NULL, 0));
+  EXPECT_EQ(hex.length(), 0U);
+  unsigned char bytes[] = {0x01, 0xff, 0x02, 0xfe, 0x03, 0x80, 0x81};
+  hex = HexEncode(bytes, sizeof(bytes));
+  EXPECT_EQ(hex.compare("01FF02FE038081"), 0);
+}
+
+}  // namespace base
diff --git a/base/strings/string_piece.cc b/base/strings/string_piece.cc
new file mode 100644
index 0000000..4c7f112
--- /dev/null
+++ b/base/strings/string_piece.cc
@@ -0,0 +1,437 @@
+// Copyright (c) 2012 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.
+// Copied from strings/stringpiece.cc with modifications
+
+#include "base/strings/string_piece.h"
+
+#include <algorithm>
+#include <ostream>
+
+namespace base {
+namespace {
+
+// For each character in characters_wanted, sets the index corresponding
+// to the ASCII code of that character to 1 in table.  This is used by
+// the find_.*_of methods below to tell whether or not a character is in
+// the lookup table in constant time.
+// The argument `table' must be an array that is large enough to hold all
+// the possible values of an unsigned char.  Thus it should be be declared
+// as follows:
+//   bool table[UCHAR_MAX + 1]
+inline void BuildLookupTable(const StringPiece& characters_wanted,
+                             bool* table) {
+  const size_t length = characters_wanted.length();
+  const char* const data = characters_wanted.data();
+  for (size_t i = 0; i < length; ++i) {
+    table[static_cast<unsigned char>(data[i])] = true;
+  }
+}
+
+}  // namespace
+
+// MSVC doesn't like complex extern templates and DLLs.
+#if !defined(COMPILER_MSVC)
+template class BasicStringPiece<std::string>;
+template class BasicStringPiece<string16>;
+#endif
+
+bool operator==(const StringPiece& x, const StringPiece& y) {
+  if (x.size() != y.size())
+    return false;
+
+  return StringPiece::wordmemcmp(x.data(), y.data(), x.size()) == 0;
+}
+
+std::ostream& operator<<(std::ostream& o, const StringPiece& piece) {
+  o.write(piece.data(), static_cast<std::streamsize>(piece.size()));
+  return o;
+}
+
+namespace internal {
+
+template<typename STR>
+void CopyToStringT(const BasicStringPiece<STR>& self, STR* target) {
+  if (self.empty())
+    target->clear();
+  else
+    target->assign(self.data(), self.size());
+}
+
+void CopyToString(const StringPiece& self, std::string* target) {
+  CopyToStringT(self, target);
+}
+
+void CopyToString(const StringPiece16& self, string16* target) {
+  CopyToStringT(self, target);
+}
+
+template<typename STR>
+void AppendToStringT(const BasicStringPiece<STR>& self, STR* target) {
+  if (!self.empty())
+    target->append(self.data(), self.size());
+}
+
+void AppendToString(const StringPiece& self, std::string* target) {
+  AppendToStringT(self, target);
+}
+
+void AppendToString(const StringPiece16& self, string16* target) {
+  AppendToStringT(self, target);
+}
+
+template<typename STR>
+size_t copyT(const BasicStringPiece<STR>& self,
+             typename STR::value_type* buf,
+             size_t n,
+             size_t pos) {
+  size_t ret = std::min(self.size() - pos, n);
+  memcpy(buf, self.data() + pos, ret * sizeof(typename STR::value_type));
+  return ret;
+}
+
+size_t copy(const StringPiece& self, char* buf, size_t n, size_t pos) {
+  return copyT(self, buf, n, pos);
+}
+
+size_t copy(const StringPiece16& self, char16* buf, size_t n, size_t pos) {
+  return copyT(self, buf, n, pos);
+}
+
+template<typename STR>
+size_t findT(const BasicStringPiece<STR>& self,
+             const BasicStringPiece<STR>& s,
+             size_t pos) {
+  if (pos > self.size())
+    return BasicStringPiece<STR>::npos;
+
+  typename BasicStringPiece<STR>::const_iterator result =
+      std::search(self.begin() + pos, self.end(), s.begin(), s.end());
+  const size_t xpos =
+    static_cast<size_t>(result - self.begin());
+  return xpos + s.size() <= self.size() ? xpos : BasicStringPiece<STR>::npos;
+}
+
+size_t find(const StringPiece& self, const StringPiece& s, size_t pos) {
+  return findT(self, s, pos);
+}
+
+size_t find(const StringPiece16& self, const StringPiece16& s, size_t pos) {
+  return findT(self, s, pos);
+}
+
+template<typename STR>
+size_t findT(const BasicStringPiece<STR>& self,
+             typename STR::value_type c,
+             size_t pos) {
+  if (pos >= self.size())
+    return BasicStringPiece<STR>::npos;
+
+  typename BasicStringPiece<STR>::const_iterator result =
+      std::find(self.begin() + pos, self.end(), c);
+  return result != self.end() ?
+      static_cast<size_t>(result - self.begin()) : BasicStringPiece<STR>::npos;
+}
+
+size_t find(const StringPiece& self, char c, size_t pos) {
+  return findT(self, c, pos);
+}
+
+size_t find(const StringPiece16& self, char16 c, size_t pos) {
+  return findT(self, c, pos);
+}
+
+template<typename STR>
+size_t rfindT(const BasicStringPiece<STR>& self,
+              const BasicStringPiece<STR>& s,
+              size_t pos) {
+  if (self.size() < s.size())
+    return BasicStringPiece<STR>::npos;
+
+  if (s.empty())
+    return std::min(self.size(), pos);
+
+  typename BasicStringPiece<STR>::const_iterator last =
+      self.begin() + std::min(self.size() - s.size(), pos) + s.size();
+  typename BasicStringPiece<STR>::const_iterator result =
+      std::find_end(self.begin(), last, s.begin(), s.end());
+  return result != last ?
+      static_cast<size_t>(result - self.begin()) : BasicStringPiece<STR>::npos;
+}
+
+size_t rfind(const StringPiece& self, const StringPiece& s, size_t pos) {
+  return rfindT(self, s, pos);
+}
+
+size_t rfind(const StringPiece16& self, const StringPiece16& s, size_t pos) {
+  return rfindT(self, s, pos);
+}
+
+template<typename STR>
+size_t rfindT(const BasicStringPiece<STR>& self,
+              typename STR::value_type c,
+              size_t pos) {
+  if (self.size() == 0)
+    return BasicStringPiece<STR>::npos;
+
+  for (size_t i = std::min(pos, self.size() - 1); ;
+       --i) {
+    if (self.data()[i] == c)
+      return i;
+    if (i == 0)
+      break;
+  }
+  return BasicStringPiece<STR>::npos;
+}
+
+size_t rfind(const StringPiece& self, char c, size_t pos) {
+  return rfindT(self, c, pos);
+}
+
+size_t rfind(const StringPiece16& self, char16 c, size_t pos) {
+  return rfindT(self, c, pos);
+}
+
+// 8-bit version using lookup table.
+size_t find_first_of(const StringPiece& self,
+                     const StringPiece& s,
+                     size_t pos) {
+  if (self.size() == 0 || s.size() == 0)
+    return StringPiece::npos;
+
+  // Avoid the cost of BuildLookupTable() for a single-character search.
+  if (s.size() == 1)
+    return find(self, s.data()[0], pos);
+
+  bool lookup[UCHAR_MAX + 1] = { false };
+  BuildLookupTable(s, lookup);
+  for (size_t i = pos; i < self.size(); ++i) {
+    if (lookup[static_cast<unsigned char>(self.data()[i])]) {
+      return i;
+    }
+  }
+  return StringPiece::npos;
+}
+
+// 16-bit brute force version.
+size_t find_first_of(const StringPiece16& self,
+                     const StringPiece16& s,
+                     size_t pos) {
+  StringPiece16::const_iterator found =
+      std::find_first_of(self.begin() + pos, self.end(), s.begin(), s.end());
+  if (found == self.end())
+    return StringPiece16::npos;
+  return found - self.begin();
+}
+
+// 8-bit version using lookup table.
+size_t find_first_not_of(const StringPiece& self,
+                         const StringPiece& s,
+                         size_t pos) {
+  if (self.size() == 0)
+    return StringPiece::npos;
+
+  if (s.size() == 0)
+    return 0;
+
+  // Avoid the cost of BuildLookupTable() for a single-character search.
+  if (s.size() == 1)
+    return find_first_not_of(self, s.data()[0], pos);
+
+  bool lookup[UCHAR_MAX + 1] = { false };
+  BuildLookupTable(s, lookup);
+  for (size_t i = pos; i < self.size(); ++i) {
+    if (!lookup[static_cast<unsigned char>(self.data()[i])]) {
+      return i;
+    }
+  }
+  return StringPiece::npos;
+}
+
+// 16-bit brute-force version.
+BASE_EXPORT size_t find_first_not_of(const StringPiece16& self,
+                                     const StringPiece16& s,
+                                     size_t pos) {
+  if (self.size() == 0)
+    return StringPiece16::npos;
+
+  for (size_t self_i = pos; self_i < self.size(); ++self_i) {
+    bool found = false;
+    for (size_t s_i = 0; s_i < s.size(); ++s_i) {
+      if (self[self_i] == s[s_i]) {
+        found = true;
+        break;
+      }
+    }
+    if (!found)
+      return self_i;
+  }
+  return StringPiece16::npos;
+}
+
+template<typename STR>
+size_t find_first_not_ofT(const BasicStringPiece<STR>& self,
+                          typename STR::value_type c,
+                          size_t pos) {
+  if (self.size() == 0)
+    return BasicStringPiece<STR>::npos;
+
+  for (; pos < self.size(); ++pos) {
+    if (self.data()[pos] != c) {
+      return pos;
+    }
+  }
+  return BasicStringPiece<STR>::npos;
+}
+
+size_t find_first_not_of(const StringPiece& self,
+                         char c,
+                         size_t pos) {
+  return find_first_not_ofT(self, c, pos);
+}
+
+size_t find_first_not_of(const StringPiece16& self,
+                         char16 c,
+                         size_t pos) {
+  return find_first_not_ofT(self, c, pos);
+}
+
+// 8-bit version using lookup table.
+size_t find_last_of(const StringPiece& self, const StringPiece& s, size_t pos) {
+  if (self.size() == 0 || s.size() == 0)
+    return StringPiece::npos;
+
+  // Avoid the cost of BuildLookupTable() for a single-character search.
+  if (s.size() == 1)
+    return rfind(self, s.data()[0], pos);
+
+  bool lookup[UCHAR_MAX + 1] = { false };
+  BuildLookupTable(s, lookup);
+  for (size_t i = std::min(pos, self.size() - 1); ; --i) {
+    if (lookup[static_cast<unsigned char>(self.data()[i])])
+      return i;
+    if (i == 0)
+      break;
+  }
+  return StringPiece::npos;
+}
+
+// 16-bit brute-force version.
+size_t find_last_of(const StringPiece16& self,
+                    const StringPiece16& s,
+                    size_t pos) {
+  if (self.size() == 0)
+    return StringPiece16::npos;
+
+  for (size_t self_i = std::min(pos, self.size() - 1); ;
+       --self_i) {
+    for (size_t s_i = 0; s_i < s.size(); s_i++) {
+      if (self.data()[self_i] == s[s_i])
+        return self_i;
+    }
+    if (self_i == 0)
+      break;
+  }
+  return StringPiece16::npos;
+}
+
+// 8-bit version using lookup table.
+size_t find_last_not_of(const StringPiece& self,
+                        const StringPiece& s,
+                        size_t pos) {
+  if (self.size() == 0)
+    return StringPiece::npos;
+
+  size_t i = std::min(pos, self.size() - 1);
+  if (s.size() == 0)
+    return i;
+
+  // Avoid the cost of BuildLookupTable() for a single-character search.
+  if (s.size() == 1)
+    return find_last_not_of(self, s.data()[0], pos);
+
+  bool lookup[UCHAR_MAX + 1] = { false };
+  BuildLookupTable(s, lookup);
+  for (; ; --i) {
+    if (!lookup[static_cast<unsigned char>(self.data()[i])])
+      return i;
+    if (i == 0)
+      break;
+  }
+  return StringPiece::npos;
+}
+
+// 16-bit brute-force version.
+size_t find_last_not_of(const StringPiece16& self,
+                        const StringPiece16& s,
+                        size_t pos) {
+  if (self.size() == 0)
+    return StringPiece::npos;
+
+  for (size_t self_i = std::min(pos, self.size() - 1); ; --self_i) {
+    bool found = false;
+    for (size_t s_i = 0; s_i < s.size(); s_i++) {
+      if (self.data()[self_i] == s[s_i]) {
+        found = true;
+        break;
+      }
+    }
+    if (!found)
+      return self_i;
+    if (self_i == 0)
+      break;
+  }
+  return StringPiece16::npos;
+}
+
+template<typename STR>
+size_t find_last_not_ofT(const BasicStringPiece<STR>& self,
+                         typename STR::value_type c,
+                         size_t pos) {
+  if (self.size() == 0)
+    return BasicStringPiece<STR>::npos;
+
+  for (size_t i = std::min(pos, self.size() - 1); ; --i) {
+    if (self.data()[i] != c)
+      return i;
+    if (i == 0)
+      break;
+  }
+  return BasicStringPiece<STR>::npos;
+}
+
+size_t find_last_not_of(const StringPiece& self,
+                        char c,
+                        size_t pos) {
+  return find_last_not_ofT(self, c, pos);
+}
+
+size_t find_last_not_of(const StringPiece16& self,
+                        char16 c,
+                        size_t pos) {
+  return find_last_not_ofT(self, c, pos);
+}
+
+template<typename STR>
+BasicStringPiece<STR> substrT(const BasicStringPiece<STR>& self,
+                              size_t pos,
+                              size_t n) {
+  if (pos > self.size()) pos = self.size();
+  if (n > self.size() - pos) n = self.size() - pos;
+  return BasicStringPiece<STR>(self.data() + pos, n);
+}
+
+StringPiece substr(const StringPiece& self,
+                   size_t pos,
+                   size_t n) {
+  return substrT(self, pos, n);
+}
+
+StringPiece16 substr(const StringPiece16& self,
+                     size_t pos,
+                     size_t n) {
+  return substrT(self, pos, n);
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/strings/string_piece.h b/base/strings/string_piece.h
new file mode 100644
index 0000000..a83b7d8
--- /dev/null
+++ b/base/strings/string_piece.h
@@ -0,0 +1,452 @@
+// Copyright (c) 2012 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.
+// Copied from strings/stringpiece.h with modifications
+//
+// A string-like object that points to a sized piece of memory.
+//
+// You can use StringPiece as a function or method parameter.  A StringPiece
+// parameter can receive a double-quoted string literal argument, a "const
+// char*" argument, a string argument, or a StringPiece argument with no data
+// copying.  Systematic use of StringPiece for arguments reduces data
+// copies and strlen() calls.
+//
+// Prefer passing StringPieces by value:
+//   void MyFunction(StringPiece arg);
+// If circumstances require, you may also pass by const reference:
+//   void MyFunction(const StringPiece& arg);  // not preferred
+// Both of these have the same lifetime semantics.  Passing by value
+// generates slightly smaller code.  For more discussion, Googlers can see
+// the thread go/stringpiecebyvalue on c-users.
+
+#ifndef BASE_STRINGS_STRING_PIECE_H_
+#define BASE_STRINGS_STRING_PIECE_H_
+
+#include <stddef.h>
+
+#include <iosfwd>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/containers/hash_tables.h"
+#include "base/strings/string16.h"
+
+namespace base {
+
+template <typename STRING_TYPE> class BasicStringPiece;
+typedef BasicStringPiece<std::string> StringPiece;
+typedef BasicStringPiece<string16> StringPiece16;
+
+// internal --------------------------------------------------------------------
+
+// Many of the StringPiece functions use different implementations for the
+// 8-bit and 16-bit versions, and we don't want lots of template expansions in
+// this (very common) header that will slow down compilation.
+//
+// So here we define overloaded functions called by the StringPiece template.
+// For those that share an implementation, the two versions will expand to a
+// template internal to the .cc file.
+namespace internal {
+
+BASE_EXPORT void CopyToString(const StringPiece& self, std::string* target);
+BASE_EXPORT void CopyToString(const StringPiece16& self, string16* target);
+
+BASE_EXPORT void AppendToString(const StringPiece& self, std::string* target);
+BASE_EXPORT void AppendToString(const StringPiece16& self, string16* target);
+
+BASE_EXPORT size_t copy(const StringPiece& self,
+                        char* buf,
+                        size_t n,
+                        size_t pos);
+BASE_EXPORT size_t copy(const StringPiece16& self,
+                        char16* buf,
+                        size_t n,
+                        size_t pos);
+
+BASE_EXPORT size_t find(const StringPiece& self,
+                        const StringPiece& s,
+                        size_t pos);
+BASE_EXPORT size_t find(const StringPiece16& self,
+                        const StringPiece16& s,
+                        size_t pos);
+BASE_EXPORT size_t find(const StringPiece& self,
+                        char c,
+                        size_t pos);
+BASE_EXPORT size_t find(const StringPiece16& self,
+                        char16 c,
+                        size_t pos);
+
+BASE_EXPORT size_t rfind(const StringPiece& self,
+                         const StringPiece& s,
+                         size_t pos);
+BASE_EXPORT size_t rfind(const StringPiece16& self,
+                         const StringPiece16& s,
+                         size_t pos);
+BASE_EXPORT size_t rfind(const StringPiece& self,
+                         char c,
+                         size_t pos);
+BASE_EXPORT size_t rfind(const StringPiece16& self,
+                         char16 c,
+                         size_t pos);
+
+BASE_EXPORT size_t find_first_of(const StringPiece& self,
+                                 const StringPiece& s,
+                                 size_t pos);
+BASE_EXPORT size_t find_first_of(const StringPiece16& self,
+                                 const StringPiece16& s,
+                                 size_t pos);
+
+BASE_EXPORT size_t find_first_not_of(const StringPiece& self,
+                                     const StringPiece& s,
+                                     size_t pos);
+BASE_EXPORT size_t find_first_not_of(const StringPiece16& self,
+                                     const StringPiece16& s,
+                                     size_t pos);
+BASE_EXPORT size_t find_first_not_of(const StringPiece& self,
+                                     char c,
+                                     size_t pos);
+BASE_EXPORT size_t find_first_not_of(const StringPiece16& self,
+                                     char16 c,
+                                     size_t pos);
+
+BASE_EXPORT size_t find_last_of(const StringPiece& self,
+                                const StringPiece& s,
+                                size_t pos);
+BASE_EXPORT size_t find_last_of(const StringPiece16& self,
+                                const StringPiece16& s,
+                                size_t pos);
+BASE_EXPORT size_t find_last_of(const StringPiece& self,
+                                char c,
+                                size_t pos);
+BASE_EXPORT size_t find_last_of(const StringPiece16& self,
+                                char16 c,
+                                size_t pos);
+
+BASE_EXPORT size_t find_last_not_of(const StringPiece& self,
+                                    const StringPiece& s,
+                                    size_t pos);
+BASE_EXPORT size_t find_last_not_of(const StringPiece16& self,
+                                    const StringPiece16& s,
+                                    size_t pos);
+BASE_EXPORT size_t find_last_not_of(const StringPiece16& self,
+                                    char16 c,
+                                    size_t pos);
+BASE_EXPORT size_t find_last_not_of(const StringPiece& self,
+                                    char c,
+                                    size_t pos);
+
+BASE_EXPORT StringPiece substr(const StringPiece& self,
+                               size_t pos,
+                               size_t n);
+BASE_EXPORT StringPiece16 substr(const StringPiece16& self,
+                                 size_t pos,
+                                 size_t n);
+
+}  // namespace internal
+
+// BasicStringPiece ------------------------------------------------------------
+
+// Defines the types, methods, operators, and data members common to both
+// StringPiece and StringPiece16. Do not refer to this class directly, but
+// rather to BasicStringPiece, StringPiece, or StringPiece16.
+//
+// This is templatized by string class type rather than character type, so
+// BasicStringPiece<std::string> or BasicStringPiece<base::string16>.
+template <typename STRING_TYPE> class BasicStringPiece {
+ public:
+  // Standard STL container boilerplate.
+  typedef size_t size_type;
+  typedef typename STRING_TYPE::value_type value_type;
+  typedef const value_type* pointer;
+  typedef const value_type& reference;
+  typedef const value_type& const_reference;
+  typedef ptrdiff_t difference_type;
+  typedef const value_type* const_iterator;
+  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+
+  static const size_type npos;
+
+ public:
+  // We provide non-explicit singleton constructors so users can pass
+  // in a "const char*" or a "string" wherever a "StringPiece" is
+  // expected (likewise for char16, string16, StringPiece16).
+  BasicStringPiece() : ptr_(NULL), length_(0) {}
+  BasicStringPiece(const value_type* str)
+      : ptr_(str),
+        length_((str == NULL) ? 0 : STRING_TYPE::traits_type::length(str)) {}
+  BasicStringPiece(const STRING_TYPE& str)
+      : ptr_(str.data()), length_(str.size()) {}
+  BasicStringPiece(const value_type* offset, size_type len)
+      : ptr_(offset), length_(len) {}
+  BasicStringPiece(const typename STRING_TYPE::const_iterator& begin,
+                    const typename STRING_TYPE::const_iterator& end)
+      : ptr_((end > begin) ? &(*begin) : NULL),
+        length_((end > begin) ? (size_type)(end - begin) : 0) {}
+
+  // data() may return a pointer to a buffer with embedded NULs, and the
+  // returned buffer may or may not be null terminated.  Therefore it is
+  // typically a mistake to pass data() to a routine that expects a NUL
+  // terminated string.
+  const value_type* data() const { return ptr_; }
+  size_type size() const { return length_; }
+  size_type length() const { return length_; }
+  bool empty() const { return length_ == 0; }
+
+  void clear() {
+    ptr_ = NULL;
+    length_ = 0;
+  }
+  void set(const value_type* data, size_type len) {
+    ptr_ = data;
+    length_ = len;
+  }
+  void set(const value_type* str) {
+    ptr_ = str;
+    length_ = str ? STRING_TYPE::traits_type::length(str) : 0;
+  }
+
+  value_type operator[](size_type i) const { return ptr_[i]; }
+
+  void remove_prefix(size_type n) {
+    ptr_ += n;
+    length_ -= n;
+  }
+
+  void remove_suffix(size_type n) {
+    length_ -= n;
+  }
+
+  int compare(const BasicStringPiece<STRING_TYPE>& x) const {
+    int r = wordmemcmp(
+        ptr_, x.ptr_, (length_ < x.length_ ? length_ : x.length_));
+    if (r == 0) {
+      if (length_ < x.length_) r = -1;
+      else if (length_ > x.length_) r = +1;
+    }
+    return r;
+  }
+
+  STRING_TYPE as_string() const {
+    // std::string doesn't like to take a NULL pointer even with a 0 size.
+    return empty() ? STRING_TYPE() : STRING_TYPE(data(), size());
+  }
+
+  const_iterator begin() const { return ptr_; }
+  const_iterator end() const { return ptr_ + length_; }
+  const_reverse_iterator rbegin() const {
+    return const_reverse_iterator(ptr_ + length_);
+  }
+  const_reverse_iterator rend() const {
+    return const_reverse_iterator(ptr_);
+  }
+
+  size_type max_size() const { return length_; }
+  size_type capacity() const { return length_; }
+
+  static int wordmemcmp(const value_type* p,
+                        const value_type* p2,
+                        size_type N) {
+    return STRING_TYPE::traits_type::compare(p, p2, N);
+  }
+
+  // Sets the value of the given string target type to be the current string.
+  // This saves a temporary over doing |a = b.as_string()|
+  void CopyToString(STRING_TYPE* target) const {
+    internal::CopyToString(*this, target);
+  }
+
+  void AppendToString(STRING_TYPE* target) const {
+    internal::AppendToString(*this, target);
+  }
+
+  size_type copy(value_type* buf, size_type n, size_type pos = 0) const {
+    return internal::copy(*this, buf, n, pos);
+  }
+
+  // Does "this" start with "x"
+  bool starts_with(const BasicStringPiece& x) const {
+    return ((this->length_ >= x.length_) &&
+            (wordmemcmp(this->ptr_, x.ptr_, x.length_) == 0));
+  }
+
+  // Does "this" end with "x"
+  bool ends_with(const BasicStringPiece& x) const {
+    return ((this->length_ >= x.length_) &&
+            (wordmemcmp(this->ptr_ + (this->length_-x.length_),
+                        x.ptr_, x.length_) == 0));
+  }
+
+  // find: Search for a character or substring at a given offset.
+  size_type find(const BasicStringPiece<STRING_TYPE>& s,
+                 size_type pos = 0) const {
+    return internal::find(*this, s, pos);
+  }
+  size_type find(value_type c, size_type pos = 0) const {
+    return internal::find(*this, c, pos);
+  }
+
+  // rfind: Reverse find.
+  size_type rfind(const BasicStringPiece& s,
+                  size_type pos = BasicStringPiece::npos) const {
+    return internal::rfind(*this, s, pos);
+  }
+  size_type rfind(value_type c, size_type pos = BasicStringPiece::npos) const {
+    return internal::rfind(*this, c, pos);
+  }
+
+  // find_first_of: Find the first occurence of one of a set of characters.
+  size_type find_first_of(const BasicStringPiece& s,
+                          size_type pos = 0) const {
+    return internal::find_first_of(*this, s, pos);
+  }
+  size_type find_first_of(value_type c, size_type pos = 0) const {
+    return find(c, pos);
+  }
+
+  // find_first_not_of: Find the first occurence not of a set of characters.
+  size_type find_first_not_of(const BasicStringPiece& s,
+                              size_type pos = 0) const {
+    return internal::find_first_not_of(*this, s, pos);
+  }
+  size_type find_first_not_of(value_type c, size_type pos = 0) const {
+    return internal::find_first_not_of(*this, c, pos);
+  }
+
+  // find_last_of: Find the last occurence of one of a set of characters.
+  size_type find_last_of(const BasicStringPiece& s,
+                         size_type pos = BasicStringPiece::npos) const {
+    return internal::find_last_of(*this, s, pos);
+  }
+  size_type find_last_of(value_type c,
+                         size_type pos = BasicStringPiece::npos) const {
+    return rfind(c, pos);
+  }
+
+  // find_last_not_of: Find the last occurence not of a set of characters.
+  size_type find_last_not_of(const BasicStringPiece& s,
+                             size_type pos = BasicStringPiece::npos) const {
+    return internal::find_last_not_of(*this, s, pos);
+  }
+  size_type find_last_not_of(value_type c,
+                             size_type pos = BasicStringPiece::npos) const {
+    return internal::find_last_not_of(*this, c, pos);
+  }
+
+  // substr.
+  BasicStringPiece substr(size_type pos,
+                          size_type n = BasicStringPiece::npos) const {
+    return internal::substr(*this, pos, n);
+  }
+
+ protected:
+  const value_type* ptr_;
+  size_type     length_;
+};
+
+template <typename STRING_TYPE>
+const typename BasicStringPiece<STRING_TYPE>::size_type
+BasicStringPiece<STRING_TYPE>::npos =
+    typename BasicStringPiece<STRING_TYPE>::size_type(-1);
+
+// MSVC doesn't like complex extern templates and DLLs.
+#if !defined(COMPILER_MSVC)
+extern template class BASE_EXPORT BasicStringPiece<std::string>;
+extern template class BASE_EXPORT BasicStringPiece<string16>;
+#endif
+
+// StingPiece operators --------------------------------------------------------
+
+BASE_EXPORT bool operator==(const StringPiece& x, const StringPiece& y);
+
+inline bool operator!=(const StringPiece& x, const StringPiece& y) {
+  return !(x == y);
+}
+
+inline bool operator<(const StringPiece& x, const StringPiece& y) {
+  const int r = StringPiece::wordmemcmp(
+      x.data(), y.data(), (x.size() < y.size() ? x.size() : y.size()));
+  return ((r < 0) || ((r == 0) && (x.size() < y.size())));
+}
+
+inline bool operator>(const StringPiece& x, const StringPiece& y) {
+  return y < x;
+}
+
+inline bool operator<=(const StringPiece& x, const StringPiece& y) {
+  return !(x > y);
+}
+
+inline bool operator>=(const StringPiece& x, const StringPiece& y) {
+  return !(x < y);
+}
+
+// StringPiece16 operators -----------------------------------------------------
+
+inline bool operator==(const StringPiece16& x, const StringPiece16& y) {
+  if (x.size() != y.size())
+    return false;
+
+  return StringPiece16::wordmemcmp(x.data(), y.data(), x.size()) == 0;
+}
+
+inline bool operator!=(const StringPiece16& x, const StringPiece16& y) {
+  return !(x == y);
+}
+
+inline bool operator<(const StringPiece16& x, const StringPiece16& y) {
+  const int r = StringPiece16::wordmemcmp(
+      x.data(), y.data(), (x.size() < y.size() ? x.size() : y.size()));
+  return ((r < 0) || ((r == 0) && (x.size() < y.size())));
+}
+
+inline bool operator>(const StringPiece16& x, const StringPiece16& y) {
+  return y < x;
+}
+
+inline bool operator<=(const StringPiece16& x, const StringPiece16& y) {
+  return !(x > y);
+}
+
+inline bool operator>=(const StringPiece16& x, const StringPiece16& y) {
+  return !(x < y);
+}
+
+BASE_EXPORT std::ostream& operator<<(std::ostream& o,
+                                     const StringPiece& piece);
+
+}  // namespace base
+
+// Hashing ---------------------------------------------------------------------
+
+// We provide appropriate hash functions so StringPiece and StringPiece16 can
+// be used as keys in hash sets and maps.
+
+// This hash function is copied from base/containers/hash_tables.h. We don't
+// use the ones already defined for string and string16 directly because it
+// would require the string constructors to be called, which we don't want.
+#define HASH_STRING_PIECE(StringPieceType, string_piece)                \
+  std::size_t result = 0;                                               \
+  for (StringPieceType::const_iterator i = string_piece.begin();        \
+       i != string_piece.end(); ++i)                                    \
+    result = (result * 131) + *i;                                       \
+  return result;                                                        \
+
+namespace BASE_HASH_NAMESPACE {
+
+template<>
+struct hash<base::StringPiece> {
+  std::size_t operator()(const base::StringPiece& sp) const {
+    HASH_STRING_PIECE(base::StringPiece, sp);
+  }
+};
+template<>
+struct hash<base::StringPiece16> {
+  std::size_t operator()(const base::StringPiece16& sp16) const {
+    HASH_STRING_PIECE(base::StringPiece16, sp16);
+  }
+};
+
+}  // namespace BASE_HASH_NAMESPACE
+
+#endif  // BASE_STRINGS_STRING_PIECE_H_
diff --git a/base/strings/string_piece_unittest.cc b/base/strings/string_piece_unittest.cc
new file mode 100644
index 0000000..5336603
--- /dev/null
+++ b/base/strings/string_piece_unittest.cc
@@ -0,0 +1,689 @@
+// Copyright (c) 2012 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 <string>
+
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+template <typename T>
+class CommonStringPieceTest : public ::testing::Test {
+ public:
+  static const T as_string(const char* input) {
+    return T(input);
+  }
+  static const T& as_string(const T& input) {
+    return input;
+  }
+};
+
+template <>
+class CommonStringPieceTest<string16> : public ::testing::Test {
+ public:
+  static const string16 as_string(const char* input) {
+    return ASCIIToUTF16(input);
+  }
+  static const string16 as_string(const std::string& input) {
+    return ASCIIToUTF16(input);
+  }
+};
+
+typedef ::testing::Types<std::string, string16> SupportedStringTypes;
+
+TYPED_TEST_CASE(CommonStringPieceTest, SupportedStringTypes);
+
+TYPED_TEST(CommonStringPieceTest, CheckComparisonOperators) {
+#define CMP_Y(op, x, y)                                                    \
+  {                                                                        \
+    TypeParam lhs(TestFixture::as_string(x));                              \
+    TypeParam rhs(TestFixture::as_string(y));                              \
+    ASSERT_TRUE( (BasicStringPiece<TypeParam>((lhs.c_str())) op            \
+                  BasicStringPiece<TypeParam>((rhs.c_str()))));            \
+    ASSERT_TRUE( (BasicStringPiece<TypeParam>((lhs.c_str())).compare(      \
+                      BasicStringPiece<TypeParam>((rhs.c_str()))) op 0));  \
+  }
+
+#define CMP_N(op, x, y)                                                    \
+  {                                                                        \
+    TypeParam lhs(TestFixture::as_string(x));                              \
+    TypeParam rhs(TestFixture::as_string(y));                              \
+    ASSERT_FALSE( (BasicStringPiece<TypeParam>((lhs.c_str())) op           \
+                  BasicStringPiece<TypeParam>((rhs.c_str()))));            \
+    ASSERT_FALSE( (BasicStringPiece<TypeParam>((lhs.c_str())).compare(     \
+                      BasicStringPiece<TypeParam>((rhs.c_str()))) op 0));  \
+  }
+
+  CMP_Y(==, "",   "");
+  CMP_Y(==, "a",  "a");
+  CMP_Y(==, "aa", "aa");
+  CMP_N(==, "a",  "");
+  CMP_N(==, "",   "a");
+  CMP_N(==, "a",  "b");
+  CMP_N(==, "a",  "aa");
+  CMP_N(==, "aa", "a");
+
+  CMP_N(!=, "",   "");
+  CMP_N(!=, "a",  "a");
+  CMP_N(!=, "aa", "aa");
+  CMP_Y(!=, "a",  "");
+  CMP_Y(!=, "",   "a");
+  CMP_Y(!=, "a",  "b");
+  CMP_Y(!=, "a",  "aa");
+  CMP_Y(!=, "aa", "a");
+
+  CMP_Y(<, "a",  "b");
+  CMP_Y(<, "a",  "aa");
+  CMP_Y(<, "aa", "b");
+  CMP_Y(<, "aa", "bb");
+  CMP_N(<, "a",  "a");
+  CMP_N(<, "b",  "a");
+  CMP_N(<, "aa", "a");
+  CMP_N(<, "b",  "aa");
+  CMP_N(<, "bb", "aa");
+
+  CMP_Y(<=, "a",  "a");
+  CMP_Y(<=, "a",  "b");
+  CMP_Y(<=, "a",  "aa");
+  CMP_Y(<=, "aa", "b");
+  CMP_Y(<=, "aa", "bb");
+  CMP_N(<=, "b",  "a");
+  CMP_N(<=, "aa", "a");
+  CMP_N(<=, "b",  "aa");
+  CMP_N(<=, "bb", "aa");
+
+  CMP_N(>=, "a",  "b");
+  CMP_N(>=, "a",  "aa");
+  CMP_N(>=, "aa", "b");
+  CMP_N(>=, "aa", "bb");
+  CMP_Y(>=, "a",  "a");
+  CMP_Y(>=, "b",  "a");
+  CMP_Y(>=, "aa", "a");
+  CMP_Y(>=, "b",  "aa");
+  CMP_Y(>=, "bb", "aa");
+
+  CMP_N(>, "a",  "a");
+  CMP_N(>, "a",  "b");
+  CMP_N(>, "a",  "aa");
+  CMP_N(>, "aa", "b");
+  CMP_N(>, "aa", "bb");
+  CMP_Y(>, "b",  "a");
+  CMP_Y(>, "aa", "a");
+  CMP_Y(>, "b",  "aa");
+  CMP_Y(>, "bb", "aa");
+
+  std::string x;
+  for (int i = 0; i < 256; i++) {
+    x += 'a';
+    std::string y = x;
+    CMP_Y(==, x, y);
+    for (int j = 0; j < i; j++) {
+      std::string z = x;
+      z[j] = 'b';       // Differs in position 'j'
+      CMP_N(==, x, z);
+    }
+  }
+
+#undef CMP_Y
+#undef CMP_N
+}
+
+TYPED_TEST(CommonStringPieceTest, CheckSTL) {
+  TypeParam alphabet(TestFixture::as_string("abcdefghijklmnopqrstuvwxyz"));
+  TypeParam abc(TestFixture::as_string("abc"));
+  TypeParam xyz(TestFixture::as_string("xyz"));
+  TypeParam foobar(TestFixture::as_string("foobar"));
+
+  BasicStringPiece<TypeParam> a(alphabet);
+  BasicStringPiece<TypeParam> b(abc);
+  BasicStringPiece<TypeParam> c(xyz);
+  BasicStringPiece<TypeParam> d(foobar);
+  BasicStringPiece<TypeParam> e;
+  TypeParam temp(TestFixture::as_string("123"));
+  temp += static_cast<typename TypeParam::value_type>(0);
+  temp += TestFixture::as_string("456");
+  BasicStringPiece<TypeParam> f(temp);
+
+  ASSERT_EQ(a[6], static_cast<typename TypeParam::value_type>('g'));
+  ASSERT_EQ(b[0], static_cast<typename TypeParam::value_type>('a'));
+  ASSERT_EQ(c[2], static_cast<typename TypeParam::value_type>('z'));
+  ASSERT_EQ(f[3], static_cast<typename TypeParam::value_type>('\0'));
+  ASSERT_EQ(f[5], static_cast<typename TypeParam::value_type>('5'));
+
+  ASSERT_EQ(*d.data(), static_cast<typename TypeParam::value_type>('f'));
+  ASSERT_EQ(d.data()[5], static_cast<typename TypeParam::value_type>('r'));
+  ASSERT_TRUE(e.data() == NULL);
+
+  ASSERT_EQ(*a.begin(), static_cast<typename TypeParam::value_type>('a'));
+  ASSERT_EQ(*(b.begin() + 2), static_cast<typename TypeParam::value_type>('c'));
+  ASSERT_EQ(*(c.end() - 1), static_cast<typename TypeParam::value_type>('z'));
+
+  ASSERT_EQ(*a.rbegin(), static_cast<typename TypeParam::value_type>('z'));
+  ASSERT_EQ(*(b.rbegin() + 2),
+            static_cast<typename TypeParam::value_type>('a'));
+  ASSERT_EQ(*(c.rend() - 1), static_cast<typename TypeParam::value_type>('x'));
+  ASSERT_TRUE(a.rbegin() + 26 == a.rend());
+
+  ASSERT_EQ(a.size(), 26U);
+  ASSERT_EQ(b.size(), 3U);
+  ASSERT_EQ(c.size(), 3U);
+  ASSERT_EQ(d.size(), 6U);
+  ASSERT_EQ(e.size(), 0U);
+  ASSERT_EQ(f.size(), 7U);
+
+  ASSERT_TRUE(!d.empty());
+  ASSERT_TRUE(d.begin() != d.end());
+  ASSERT_TRUE(d.begin() + 6 == d.end());
+
+  ASSERT_TRUE(e.empty());
+  ASSERT_TRUE(e.begin() == e.end());
+
+  d.clear();
+  ASSERT_EQ(d.size(), 0U);
+  ASSERT_TRUE(d.empty());
+  ASSERT_TRUE(d.data() == NULL);
+  ASSERT_TRUE(d.begin() == d.end());
+
+  ASSERT_GE(a.max_size(), a.capacity());
+  ASSERT_GE(a.capacity(), a.size());
+}
+
+TYPED_TEST(CommonStringPieceTest, CheckFind) {
+  typedef BasicStringPiece<TypeParam> Piece;
+
+  TypeParam alphabet(TestFixture::as_string("abcdefghijklmnopqrstuvwxyz"));
+  TypeParam abc(TestFixture::as_string("abc"));
+  TypeParam xyz(TestFixture::as_string("xyz"));
+  TypeParam foobar(TestFixture::as_string("foobar"));
+
+  BasicStringPiece<TypeParam> a(alphabet);
+  BasicStringPiece<TypeParam> b(abc);
+  BasicStringPiece<TypeParam> c(xyz);
+  BasicStringPiece<TypeParam> d(foobar);
+
+  d.clear();
+  Piece e;
+  TypeParam temp(TestFixture::as_string("123"));
+  temp.push_back('\0');
+  temp += TestFixture::as_string("456");
+  Piece f(temp);
+
+  typename TypeParam::value_type buf[4] = { '%', '%', '%', '%' };
+  ASSERT_EQ(a.copy(buf, 4), 4U);
+  ASSERT_EQ(buf[0], a[0]);
+  ASSERT_EQ(buf[1], a[1]);
+  ASSERT_EQ(buf[2], a[2]);
+  ASSERT_EQ(buf[3], a[3]);
+  ASSERT_EQ(a.copy(buf, 3, 7), 3U);
+  ASSERT_EQ(buf[0], a[7]);
+  ASSERT_EQ(buf[1], a[8]);
+  ASSERT_EQ(buf[2], a[9]);
+  ASSERT_EQ(buf[3], a[3]);
+  ASSERT_EQ(c.copy(buf, 99), 3U);
+  ASSERT_EQ(buf[0], c[0]);
+  ASSERT_EQ(buf[1], c[1]);
+  ASSERT_EQ(buf[2], c[2]);
+  ASSERT_EQ(buf[3], a[3]);
+
+  ASSERT_EQ(Piece::npos, TypeParam::npos);
+
+  ASSERT_EQ(a.find(b), 0U);
+  ASSERT_EQ(a.find(b, 1), Piece::npos);
+  ASSERT_EQ(a.find(c), 23U);
+  ASSERT_EQ(a.find(c, 9), 23U);
+  ASSERT_EQ(a.find(c, Piece::npos), Piece::npos);
+  ASSERT_EQ(b.find(c), Piece::npos);
+  ASSERT_EQ(b.find(c, Piece::npos), Piece::npos);
+  ASSERT_EQ(a.find(d), 0U);
+  ASSERT_EQ(a.find(e), 0U);
+  ASSERT_EQ(a.find(d, 12), 12U);
+  ASSERT_EQ(a.find(e, 17), 17U);
+  TypeParam not_found(TestFixture::as_string("xx not found bb"));
+  Piece g(not_found);
+  ASSERT_EQ(a.find(g), Piece::npos);
+  // empty string nonsense
+  ASSERT_EQ(d.find(b), Piece::npos);
+  ASSERT_EQ(e.find(b), Piece::npos);
+  ASSERT_EQ(d.find(b, 4), Piece::npos);
+  ASSERT_EQ(e.find(b, 7), Piece::npos);
+
+  size_t empty_search_pos = TypeParam().find(TypeParam());
+  ASSERT_EQ(d.find(d), empty_search_pos);
+  ASSERT_EQ(d.find(e), empty_search_pos);
+  ASSERT_EQ(e.find(d), empty_search_pos);
+  ASSERT_EQ(e.find(e), empty_search_pos);
+  ASSERT_EQ(d.find(d, 4), std::string().find(std::string(), 4));
+  ASSERT_EQ(d.find(e, 4), std::string().find(std::string(), 4));
+  ASSERT_EQ(e.find(d, 4), std::string().find(std::string(), 4));
+  ASSERT_EQ(e.find(e, 4), std::string().find(std::string(), 4));
+
+  ASSERT_EQ(a.find('a'), 0U);
+  ASSERT_EQ(a.find('c'), 2U);
+  ASSERT_EQ(a.find('z'), 25U);
+  ASSERT_EQ(a.find('$'), Piece::npos);
+  ASSERT_EQ(a.find('\0'), Piece::npos);
+  ASSERT_EQ(f.find('\0'), 3U);
+  ASSERT_EQ(f.find('3'), 2U);
+  ASSERT_EQ(f.find('5'), 5U);
+  ASSERT_EQ(g.find('o'), 4U);
+  ASSERT_EQ(g.find('o', 4), 4U);
+  ASSERT_EQ(g.find('o', 5), 8U);
+  ASSERT_EQ(a.find('b', 5), Piece::npos);
+  // empty string nonsense
+  ASSERT_EQ(d.find('\0'), Piece::npos);
+  ASSERT_EQ(e.find('\0'), Piece::npos);
+  ASSERT_EQ(d.find('\0', 4), Piece::npos);
+  ASSERT_EQ(e.find('\0', 7), Piece::npos);
+  ASSERT_EQ(d.find('x'), Piece::npos);
+  ASSERT_EQ(e.find('x'), Piece::npos);
+  ASSERT_EQ(d.find('x', 4), Piece::npos);
+  ASSERT_EQ(e.find('x', 7), Piece::npos);
+
+  ASSERT_EQ(a.rfind(b), 0U);
+  ASSERT_EQ(a.rfind(b, 1), 0U);
+  ASSERT_EQ(a.rfind(c), 23U);
+  ASSERT_EQ(a.rfind(c, 22U), Piece::npos);
+  ASSERT_EQ(a.rfind(c, 1U), Piece::npos);
+  ASSERT_EQ(a.rfind(c, 0U), Piece::npos);
+  ASSERT_EQ(b.rfind(c), Piece::npos);
+  ASSERT_EQ(b.rfind(c, 0U), Piece::npos);
+  ASSERT_EQ(a.rfind(d), static_cast<size_t>(a.as_string().rfind(TypeParam())));
+  ASSERT_EQ(a.rfind(e), a.as_string().rfind(TypeParam()));
+  ASSERT_EQ(a.rfind(d, 12), 12U);
+  ASSERT_EQ(a.rfind(e, 17), 17U);
+  ASSERT_EQ(a.rfind(g), Piece::npos);
+  ASSERT_EQ(d.rfind(b), Piece::npos);
+  ASSERT_EQ(e.rfind(b), Piece::npos);
+  ASSERT_EQ(d.rfind(b, 4), Piece::npos);
+  ASSERT_EQ(e.rfind(b, 7), Piece::npos);
+  // empty string nonsense
+  ASSERT_EQ(d.rfind(d, 4), std::string().rfind(std::string()));
+  ASSERT_EQ(e.rfind(d, 7), std::string().rfind(std::string()));
+  ASSERT_EQ(d.rfind(e, 4), std::string().rfind(std::string()));
+  ASSERT_EQ(e.rfind(e, 7), std::string().rfind(std::string()));
+  ASSERT_EQ(d.rfind(d), std::string().rfind(std::string()));
+  ASSERT_EQ(e.rfind(d), std::string().rfind(std::string()));
+  ASSERT_EQ(d.rfind(e), std::string().rfind(std::string()));
+  ASSERT_EQ(e.rfind(e), std::string().rfind(std::string()));
+
+  ASSERT_EQ(g.rfind('o'), 8U);
+  ASSERT_EQ(g.rfind('q'), Piece::npos);
+  ASSERT_EQ(g.rfind('o', 8), 8U);
+  ASSERT_EQ(g.rfind('o', 7), 4U);
+  ASSERT_EQ(g.rfind('o', 3), Piece::npos);
+  ASSERT_EQ(f.rfind('\0'), 3U);
+  ASSERT_EQ(f.rfind('\0', 12), 3U);
+  ASSERT_EQ(f.rfind('3'), 2U);
+  ASSERT_EQ(f.rfind('5'), 5U);
+  // empty string nonsense
+  ASSERT_EQ(d.rfind('o'), Piece::npos);
+  ASSERT_EQ(e.rfind('o'), Piece::npos);
+  ASSERT_EQ(d.rfind('o', 4), Piece::npos);
+  ASSERT_EQ(e.rfind('o', 7), Piece::npos);
+
+  TypeParam one_two_three_four(TestFixture::as_string("one,two:three;four"));
+  TypeParam comma_colon(TestFixture::as_string(",:"));
+  ASSERT_EQ(3U, Piece(one_two_three_four).find_first_of(comma_colon));
+  ASSERT_EQ(a.find_first_of(b), 0U);
+  ASSERT_EQ(a.find_first_of(b, 0), 0U);
+  ASSERT_EQ(a.find_first_of(b, 1), 1U);
+  ASSERT_EQ(a.find_first_of(b, 2), 2U);
+  ASSERT_EQ(a.find_first_of(b, 3), Piece::npos);
+  ASSERT_EQ(a.find_first_of(c), 23U);
+  ASSERT_EQ(a.find_first_of(c, 23), 23U);
+  ASSERT_EQ(a.find_first_of(c, 24), 24U);
+  ASSERT_EQ(a.find_first_of(c, 25), 25U);
+  ASSERT_EQ(a.find_first_of(c, 26), Piece::npos);
+  ASSERT_EQ(g.find_first_of(b), 13U);
+  ASSERT_EQ(g.find_first_of(c), 0U);
+  ASSERT_EQ(a.find_first_of(f), Piece::npos);
+  ASSERT_EQ(f.find_first_of(a), Piece::npos);
+  // empty string nonsense
+  ASSERT_EQ(a.find_first_of(d), Piece::npos);
+  ASSERT_EQ(a.find_first_of(e), Piece::npos);
+  ASSERT_EQ(d.find_first_of(b), Piece::npos);
+  ASSERT_EQ(e.find_first_of(b), Piece::npos);
+  ASSERT_EQ(d.find_first_of(d), Piece::npos);
+  ASSERT_EQ(e.find_first_of(d), Piece::npos);
+  ASSERT_EQ(d.find_first_of(e), Piece::npos);
+  ASSERT_EQ(e.find_first_of(e), Piece::npos);
+
+  ASSERT_EQ(a.find_first_not_of(b), 3U);
+  ASSERT_EQ(a.find_first_not_of(c), 0U);
+  ASSERT_EQ(b.find_first_not_of(a), Piece::npos);
+  ASSERT_EQ(c.find_first_not_of(a), Piece::npos);
+  ASSERT_EQ(f.find_first_not_of(a), 0U);
+  ASSERT_EQ(a.find_first_not_of(f), 0U);
+  ASSERT_EQ(a.find_first_not_of(d), 0U);
+  ASSERT_EQ(a.find_first_not_of(e), 0U);
+  // empty string nonsense
+  ASSERT_EQ(d.find_first_not_of(a), Piece::npos);
+  ASSERT_EQ(e.find_first_not_of(a), Piece::npos);
+  ASSERT_EQ(d.find_first_not_of(d), Piece::npos);
+  ASSERT_EQ(e.find_first_not_of(d), Piece::npos);
+  ASSERT_EQ(d.find_first_not_of(e), Piece::npos);
+  ASSERT_EQ(e.find_first_not_of(e), Piece::npos);
+
+  TypeParam equals(TestFixture::as_string("===="));
+  Piece h(equals);
+  ASSERT_EQ(h.find_first_not_of('='), Piece::npos);
+  ASSERT_EQ(h.find_first_not_of('=', 3), Piece::npos);
+  ASSERT_EQ(h.find_first_not_of('\0'), 0U);
+  ASSERT_EQ(g.find_first_not_of('x'), 2U);
+  ASSERT_EQ(f.find_first_not_of('\0'), 0U);
+  ASSERT_EQ(f.find_first_not_of('\0', 3), 4U);
+  ASSERT_EQ(f.find_first_not_of('\0', 2), 2U);
+  // empty string nonsense
+  ASSERT_EQ(d.find_first_not_of('x'), Piece::npos);
+  ASSERT_EQ(e.find_first_not_of('x'), Piece::npos);
+  ASSERT_EQ(d.find_first_not_of('\0'), Piece::npos);
+  ASSERT_EQ(e.find_first_not_of('\0'), Piece::npos);
+
+  //  Piece g("xx not found bb");
+  TypeParam fifty_six(TestFixture::as_string("56"));
+  Piece i(fifty_six);
+  ASSERT_EQ(h.find_last_of(a), Piece::npos);
+  ASSERT_EQ(g.find_last_of(a), g.size()-1);
+  ASSERT_EQ(a.find_last_of(b), 2U);
+  ASSERT_EQ(a.find_last_of(c), a.size()-1);
+  ASSERT_EQ(f.find_last_of(i), 6U);
+  ASSERT_EQ(a.find_last_of('a'), 0U);
+  ASSERT_EQ(a.find_last_of('b'), 1U);
+  ASSERT_EQ(a.find_last_of('z'), 25U);
+  ASSERT_EQ(a.find_last_of('a', 5), 0U);
+  ASSERT_EQ(a.find_last_of('b', 5), 1U);
+  ASSERT_EQ(a.find_last_of('b', 0), Piece::npos);
+  ASSERT_EQ(a.find_last_of('z', 25), 25U);
+  ASSERT_EQ(a.find_last_of('z', 24), Piece::npos);
+  ASSERT_EQ(f.find_last_of(i, 5), 5U);
+  ASSERT_EQ(f.find_last_of(i, 6), 6U);
+  ASSERT_EQ(f.find_last_of(a, 4), Piece::npos);
+  // empty string nonsense
+  ASSERT_EQ(f.find_last_of(d), Piece::npos);
+  ASSERT_EQ(f.find_last_of(e), Piece::npos);
+  ASSERT_EQ(f.find_last_of(d, 4), Piece::npos);
+  ASSERT_EQ(f.find_last_of(e, 4), Piece::npos);
+  ASSERT_EQ(d.find_last_of(d), Piece::npos);
+  ASSERT_EQ(d.find_last_of(e), Piece::npos);
+  ASSERT_EQ(e.find_last_of(d), Piece::npos);
+  ASSERT_EQ(e.find_last_of(e), Piece::npos);
+  ASSERT_EQ(d.find_last_of(f), Piece::npos);
+  ASSERT_EQ(e.find_last_of(f), Piece::npos);
+  ASSERT_EQ(d.find_last_of(d, 4), Piece::npos);
+  ASSERT_EQ(d.find_last_of(e, 4), Piece::npos);
+  ASSERT_EQ(e.find_last_of(d, 4), Piece::npos);
+  ASSERT_EQ(e.find_last_of(e, 4), Piece::npos);
+  ASSERT_EQ(d.find_last_of(f, 4), Piece::npos);
+  ASSERT_EQ(e.find_last_of(f, 4), Piece::npos);
+
+  ASSERT_EQ(a.find_last_not_of(b), a.size()-1);
+  ASSERT_EQ(a.find_last_not_of(c), 22U);
+  ASSERT_EQ(b.find_last_not_of(a), Piece::npos);
+  ASSERT_EQ(b.find_last_not_of(b), Piece::npos);
+  ASSERT_EQ(f.find_last_not_of(i), 4U);
+  ASSERT_EQ(a.find_last_not_of(c, 24), 22U);
+  ASSERT_EQ(a.find_last_not_of(b, 3), 3U);
+  ASSERT_EQ(a.find_last_not_of(b, 2), Piece::npos);
+  // empty string nonsense
+  ASSERT_EQ(f.find_last_not_of(d), f.size()-1);
+  ASSERT_EQ(f.find_last_not_of(e), f.size()-1);
+  ASSERT_EQ(f.find_last_not_of(d, 4), 4U);
+  ASSERT_EQ(f.find_last_not_of(e, 4), 4U);
+  ASSERT_EQ(d.find_last_not_of(d), Piece::npos);
+  ASSERT_EQ(d.find_last_not_of(e), Piece::npos);
+  ASSERT_EQ(e.find_last_not_of(d), Piece::npos);
+  ASSERT_EQ(e.find_last_not_of(e), Piece::npos);
+  ASSERT_EQ(d.find_last_not_of(f), Piece::npos);
+  ASSERT_EQ(e.find_last_not_of(f), Piece::npos);
+  ASSERT_EQ(d.find_last_not_of(d, 4), Piece::npos);
+  ASSERT_EQ(d.find_last_not_of(e, 4), Piece::npos);
+  ASSERT_EQ(e.find_last_not_of(d, 4), Piece::npos);
+  ASSERT_EQ(e.find_last_not_of(e, 4), Piece::npos);
+  ASSERT_EQ(d.find_last_not_of(f, 4), Piece::npos);
+  ASSERT_EQ(e.find_last_not_of(f, 4), Piece::npos);
+
+  ASSERT_EQ(h.find_last_not_of('x'), h.size() - 1);
+  ASSERT_EQ(h.find_last_not_of('='), Piece::npos);
+  ASSERT_EQ(b.find_last_not_of('c'), 1U);
+  ASSERT_EQ(h.find_last_not_of('x', 2), 2U);
+  ASSERT_EQ(h.find_last_not_of('=', 2), Piece::npos);
+  ASSERT_EQ(b.find_last_not_of('b', 1), 0U);
+  // empty string nonsense
+  ASSERT_EQ(d.find_last_not_of('x'), Piece::npos);
+  ASSERT_EQ(e.find_last_not_of('x'), Piece::npos);
+  ASSERT_EQ(d.find_last_not_of('\0'), Piece::npos);
+  ASSERT_EQ(e.find_last_not_of('\0'), Piece::npos);
+
+  ASSERT_EQ(a.substr(0, 3), b);
+  ASSERT_EQ(a.substr(23), c);
+  ASSERT_EQ(a.substr(23, 3), c);
+  ASSERT_EQ(a.substr(23, 99), c);
+  ASSERT_EQ(a.substr(0), a);
+  ASSERT_EQ(a.substr(3, 2), TestFixture::as_string("de"));
+  // empty string nonsense
+  ASSERT_EQ(a.substr(99, 2), e);
+  ASSERT_EQ(d.substr(99), e);
+  ASSERT_EQ(d.substr(0, 99), e);
+  ASSERT_EQ(d.substr(99, 99), e);
+}
+
+TYPED_TEST(CommonStringPieceTest, CheckCustom) {
+  TypeParam foobar(TestFixture::as_string("foobar"));
+  BasicStringPiece<TypeParam> a(foobar);
+  TypeParam s1(TestFixture::as_string("123"));
+  s1 += static_cast<typename TypeParam::value_type>('\0');
+  s1 += TestFixture::as_string("456");
+  BasicStringPiece<TypeParam> b(s1);
+  BasicStringPiece<TypeParam> e;
+  TypeParam s2;
+
+  // remove_prefix
+  BasicStringPiece<TypeParam> c(a);
+  c.remove_prefix(3);
+  ASSERT_EQ(c, TestFixture::as_string("bar"));
+  c = a;
+  c.remove_prefix(0);
+  ASSERT_EQ(c, a);
+  c.remove_prefix(c.size());
+  ASSERT_EQ(c, e);
+
+  // remove_suffix
+  c = a;
+  c.remove_suffix(3);
+  ASSERT_EQ(c, TestFixture::as_string("foo"));
+  c = a;
+  c.remove_suffix(0);
+  ASSERT_EQ(c, a);
+  c.remove_suffix(c.size());
+  ASSERT_EQ(c, e);
+
+  // set
+  c.set(foobar.c_str());
+  ASSERT_EQ(c, a);
+  c.set(foobar.c_str(), 6);
+  ASSERT_EQ(c, a);
+  c.set(foobar.c_str(), 0);
+  ASSERT_EQ(c, e);
+  c.set(foobar.c_str(), 7);  // Note, has an embedded NULL
+  ASSERT_NE(c, a);
+
+  // as_string
+  TypeParam s3(a.as_string().c_str(), 7);  // Note, has an embedded NULL
+  ASSERT_TRUE(c == s3);
+  TypeParam s4(e.as_string());
+  ASSERT_TRUE(s4.empty());
+}
+
+TEST(StringPieceTest, CheckCustom) {
+  StringPiece a("foobar");
+  std::string s1("123");
+  s1 += '\0';
+  s1 += "456";
+  StringPiece b(s1);
+  StringPiece e;
+  std::string s2;
+
+  // CopyToString
+  a.CopyToString(&s2);
+  ASSERT_EQ(s2.size(), 6U);
+  ASSERT_EQ(s2, "foobar");
+  b.CopyToString(&s2);
+  ASSERT_EQ(s2.size(), 7U);
+  ASSERT_EQ(s1, s2);
+  e.CopyToString(&s2);
+  ASSERT_TRUE(s2.empty());
+
+  // AppendToString
+  s2.erase();
+  a.AppendToString(&s2);
+  ASSERT_EQ(s2.size(), 6U);
+  ASSERT_EQ(s2, "foobar");
+  a.AppendToString(&s2);
+  ASSERT_EQ(s2.size(), 12U);
+  ASSERT_EQ(s2, "foobarfoobar");
+
+  // starts_with
+  ASSERT_TRUE(a.starts_with(a));
+  ASSERT_TRUE(a.starts_with("foo"));
+  ASSERT_TRUE(a.starts_with(e));
+  ASSERT_TRUE(b.starts_with(s1));
+  ASSERT_TRUE(b.starts_with(b));
+  ASSERT_TRUE(b.starts_with(e));
+  ASSERT_TRUE(e.starts_with(""));
+  ASSERT_TRUE(!a.starts_with(b));
+  ASSERT_TRUE(!b.starts_with(a));
+  ASSERT_TRUE(!e.starts_with(a));
+
+  // ends with
+  ASSERT_TRUE(a.ends_with(a));
+  ASSERT_TRUE(a.ends_with("bar"));
+  ASSERT_TRUE(a.ends_with(e));
+  ASSERT_TRUE(b.ends_with(s1));
+  ASSERT_TRUE(b.ends_with(b));
+  ASSERT_TRUE(b.ends_with(e));
+  ASSERT_TRUE(e.ends_with(""));
+  ASSERT_TRUE(!a.ends_with(b));
+  ASSERT_TRUE(!b.ends_with(a));
+  ASSERT_TRUE(!e.ends_with(a));
+
+  StringPiece c;
+  c.set("foobar", 6);
+  ASSERT_EQ(c, a);
+  c.set("foobar", 0);
+  ASSERT_EQ(c, e);
+  c.set("foobar", 7);
+  ASSERT_NE(c, a);
+}
+
+TYPED_TEST(CommonStringPieceTest, CheckNULL) {
+  // we used to crash here, but now we don't.
+  BasicStringPiece<TypeParam> s(NULL);
+  ASSERT_EQ(s.data(), (const typename TypeParam::value_type*)NULL);
+  ASSERT_EQ(s.size(), 0U);
+
+  s.set(NULL);
+  ASSERT_EQ(s.data(), (const typename TypeParam::value_type*)NULL);
+  ASSERT_EQ(s.size(), 0U);
+
+  TypeParam str = s.as_string();
+  ASSERT_EQ(str.length(), 0U);
+  ASSERT_EQ(str, TypeParam());
+}
+
+TYPED_TEST(CommonStringPieceTest, CheckComparisons2) {
+  TypeParam alphabet(TestFixture::as_string("abcdefghijklmnopqrstuvwxyz"));
+  TypeParam alphabet_z(TestFixture::as_string("abcdefghijklmnopqrstuvwxyzz"));
+  TypeParam alphabet_y(TestFixture::as_string("abcdefghijklmnopqrstuvwxyy"));
+  BasicStringPiece<TypeParam> abc(alphabet);
+
+  // check comparison operations on strings longer than 4 bytes.
+  ASSERT_TRUE(abc == BasicStringPiece<TypeParam>(alphabet));
+  ASSERT_EQ(abc.compare(BasicStringPiece<TypeParam>(alphabet)), 0);
+
+  ASSERT_TRUE(abc < BasicStringPiece<TypeParam>(alphabet_z));
+  ASSERT_LT(abc.compare(BasicStringPiece<TypeParam>(alphabet_z)), 0);
+
+  ASSERT_TRUE(abc > BasicStringPiece<TypeParam>(alphabet_y));
+  ASSERT_GT(abc.compare(BasicStringPiece<TypeParam>(alphabet_y)), 0);
+}
+
+// Test operations only supported by std::string version.
+TEST(StringPieceTest, CheckComparisons2) {
+  StringPiece abc("abcdefghijklmnopqrstuvwxyz");
+
+  // starts_with
+  ASSERT_TRUE(abc.starts_with(abc));
+  ASSERT_TRUE(abc.starts_with("abcdefghijklm"));
+  ASSERT_TRUE(!abc.starts_with("abcdefguvwxyz"));
+
+  // ends_with
+  ASSERT_TRUE(abc.ends_with(abc));
+  ASSERT_TRUE(!abc.ends_with("abcdefguvwxyz"));
+  ASSERT_TRUE(abc.ends_with("nopqrstuvwxyz"));
+}
+
+TYPED_TEST(CommonStringPieceTest, StringCompareNotAmbiguous) {
+  ASSERT_TRUE(TestFixture::as_string("hello").c_str() ==
+              TestFixture::as_string("hello"));
+  ASSERT_TRUE(TestFixture::as_string("hello").c_str() <
+              TestFixture::as_string("world"));
+}
+
+TYPED_TEST(CommonStringPieceTest, HeterogenousStringPieceEquals) {
+  TypeParam hello(TestFixture::as_string("hello"));
+
+  ASSERT_TRUE(BasicStringPiece<TypeParam>(hello) == hello);
+  ASSERT_TRUE(hello.c_str() == BasicStringPiece<TypeParam>(hello));
+}
+
+// string16-specific stuff
+TEST(StringPiece16Test, CheckSTL) {
+  // Check some non-ascii characters.
+  string16 fifth(ASCIIToUTF16("123"));
+  fifth.push_back(0x0000);
+  fifth.push_back(0xd8c5);
+  fifth.push_back(0xdffe);
+  StringPiece16 f(fifth);
+
+  ASSERT_EQ(f[3], '\0');
+  ASSERT_EQ(f[5], static_cast<char16>(0xdffe));
+
+  ASSERT_EQ(f.size(), 6U);
+}
+
+
+
+TEST(StringPiece16Test, CheckConversion) {
+  // Make sure that we can convert from UTF8 to UTF16 and back. We use a two
+  // byte character (G clef) to test this.
+  ASSERT_EQ(
+      UTF16ToUTF8(
+          StringPiece16(UTF8ToUTF16("\xf0\x9d\x84\x9e")).as_string()),
+      "\xf0\x9d\x84\x9e");
+}
+
+TYPED_TEST(CommonStringPieceTest, CheckConstructors) {
+  TypeParam str(TestFixture::as_string("hello world"));
+  TypeParam empty;
+
+  ASSERT_TRUE(str == BasicStringPiece<TypeParam>(str));
+  ASSERT_TRUE(str == BasicStringPiece<TypeParam>(str.c_str()));
+  ASSERT_TRUE(TestFixture::as_string("hello") ==
+              BasicStringPiece<TypeParam>(str.c_str(), 5));
+  ASSERT_TRUE(empty == BasicStringPiece<TypeParam>(str.c_str(),
+      static_cast<typename BasicStringPiece<TypeParam>::size_type>(0)));
+  ASSERT_TRUE(empty == BasicStringPiece<TypeParam>(NULL));
+  ASSERT_TRUE(empty == BasicStringPiece<TypeParam>(NULL,
+      static_cast<typename BasicStringPiece<TypeParam>::size_type>(0)));
+  ASSERT_TRUE(empty == BasicStringPiece<TypeParam>());
+  ASSERT_TRUE(str == BasicStringPiece<TypeParam>(str.begin(), str.end()));
+  ASSERT_TRUE(empty == BasicStringPiece<TypeParam>(str.begin(), str.begin()));
+  ASSERT_TRUE(empty == BasicStringPiece<TypeParam>(empty));
+  ASSERT_TRUE(empty == BasicStringPiece<TypeParam>(empty.begin(), empty.end()));
+}
+
+}  // namespace base
diff --git a/base/strings/string_split.cc b/base/strings/string_split.cc
new file mode 100644
index 0000000..e23ce3f
--- /dev/null
+++ b/base/strings/string_split.cc
@@ -0,0 +1,308 @@
+// Copyright (c) 2012 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/strings/string_split.h"
+
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "base/third_party/icu/icu_utf.h"
+
+namespace base {
+
+namespace {
+
+// PieceToOutputType converts a StringPiece as needed to a given output type,
+// which is either the same type of StringPiece (a NOP) or the corresponding
+// non-piece string type.
+//
+// The default converter is a NOP, it works when the OutputType is the
+// correct StringPiece.
+template<typename Str, typename OutputType>
+OutputType PieceToOutputType(BasicStringPiece<Str> piece) {
+  return piece;
+}
+template<>  // Convert StringPiece to std::string
+std::string PieceToOutputType<std::string, std::string>(StringPiece piece) {
+  return piece.as_string();
+}
+template<>  // Convert StringPiece16 to string16.
+string16 PieceToOutputType<string16, string16>(StringPiece16 piece) {
+  return piece.as_string();
+}
+
+// Returns either the ASCII or UTF-16 whitespace.
+template<typename Str> BasicStringPiece<Str> WhitespaceForType();
+template<> StringPiece16 WhitespaceForType<string16>() {
+  return kWhitespaceUTF16;
+}
+template<> StringPiece WhitespaceForType<std::string>() {
+  return kWhitespaceASCII;
+}
+
+// Optimize the single-character case to call find() on the string instead,
+// since this is the common case and can be made faster. This could have been
+// done with template specialization too, but would have been less clear.
+//
+// There is no corresponding FindFirstNotOf because StringPiece already
+// implements these different versions that do the optimized searching.
+size_t FindFirstOf(StringPiece piece, char c, size_t pos) {
+  return piece.find(c, pos);
+}
+size_t FindFirstOf(StringPiece16 piece, char16 c, size_t pos) {
+  return piece.find(c, pos);
+}
+size_t FindFirstOf(StringPiece piece, StringPiece one_of, size_t pos) {
+  return piece.find_first_of(one_of, pos);
+}
+size_t FindFirstOf(StringPiece16 piece, StringPiece16 one_of, size_t pos) {
+  return piece.find_first_of(one_of, pos);
+}
+
+// General string splitter template. Can take 8- or 16-bit input, can produce
+// the corresponding string or StringPiece output, and can take single- or
+// multiple-character delimiters.
+//
+// DelimiterType is either a character (Str::value_type) or a string piece of
+// multiple characters (BasicStringPiece<Str>). StringPiece has a version of
+// find for both of these cases, and the single-character version is the most
+// common and can be implemented faster, which is why this is a template.
+template<typename Str, typename OutputStringType, typename DelimiterType>
+static std::vector<OutputStringType> SplitStringT(
+    BasicStringPiece<Str> str,
+    DelimiterType delimiter,
+    WhitespaceHandling whitespace,
+    SplitResult result_type) {
+  std::vector<OutputStringType> result;
+  if (str.empty())
+    return result;
+
+  size_t start = 0;
+  while (start != Str::npos) {
+    size_t end = FindFirstOf(str, delimiter, start);
+
+    BasicStringPiece<Str> piece;
+    if (end == Str::npos) {
+      piece = str.substr(start);
+      start = Str::npos;
+    } else {
+      piece = str.substr(start, end - start);
+      start = end + 1;
+    }
+
+    if (whitespace == TRIM_WHITESPACE)
+      piece = TrimString(piece, WhitespaceForType<Str>(), TRIM_ALL);
+
+    if (result_type == SPLIT_WANT_ALL || !piece.empty())
+      result.push_back(PieceToOutputType<Str, OutputStringType>(piece));
+  }
+  return result;
+}
+
+bool SplitStringIntoKeyValue(const std::string& line,
+                             char key_value_delimiter,
+                             std::string* key,
+                             std::string* value) {
+  key->clear();
+  value->clear();
+
+  // Find the delimiter.
+  size_t end_key_pos = line.find_first_of(key_value_delimiter);
+  if (end_key_pos == std::string::npos) {
+    DVLOG(1) << "cannot find delimiter in: " << line;
+    return false;    // no delimiter
+  }
+  key->assign(line, 0, end_key_pos);
+
+  // Find the value string.
+  std::string remains(line, end_key_pos, line.size() - end_key_pos);
+  size_t begin_value_pos = remains.find_first_not_of(key_value_delimiter);
+  if (begin_value_pos == std::string::npos) {
+    DVLOG(1) << "cannot parse value from line: " << line;
+    return false;   // no value
+  }
+  value->assign(remains, begin_value_pos, remains.size() - begin_value_pos);
+  return true;
+}
+
+template <typename STR>
+void SplitStringUsingSubstrT(const STR& str,
+                             const STR& s,
+                             std::vector<STR>* r) {
+  r->clear();
+  typename STR::size_type begin_index = 0;
+  while (true) {
+    const typename STR::size_type end_index = str.find(s, begin_index);
+    if (end_index == STR::npos) {
+      const STR term = str.substr(begin_index);
+      STR tmp;
+      TrimWhitespace(term, TRIM_ALL, &tmp);
+      r->push_back(tmp);
+      return;
+    }
+    const STR term = str.substr(begin_index, end_index - begin_index);
+    STR tmp;
+    TrimWhitespace(term, TRIM_ALL, &tmp);
+    r->push_back(tmp);
+    begin_index = end_index + s.size();
+  }
+}
+
+}  // namespace
+
+std::vector<std::string> SplitString(StringPiece input,
+                                     StringPiece separators,
+                                     WhitespaceHandling whitespace,
+                                     SplitResult result_type) {
+  if (separators.size() == 1) {
+    return SplitStringT<std::string, std::string, char>(
+        input, separators[0], whitespace, result_type);
+  }
+  return SplitStringT<std::string, std::string, StringPiece>(
+      input, separators, whitespace, result_type);
+}
+
+std::vector<string16> SplitString(StringPiece16 input,
+                                  StringPiece16 separators,
+                                  WhitespaceHandling whitespace,
+                                  SplitResult result_type) {
+  if (separators.size() == 1) {
+    return SplitStringT<string16, string16, char16>(
+        input, separators[0], whitespace, result_type);
+  }
+  return SplitStringT<string16, string16, StringPiece16>(
+      input, separators, whitespace, result_type);
+}
+
+std::vector<StringPiece> SplitStringPiece(StringPiece input,
+                                          StringPiece separators,
+                                          WhitespaceHandling whitespace,
+                                          SplitResult result_type) {
+  if (separators.size() == 1) {
+    return SplitStringT<std::string, StringPiece, char>(
+        input, separators[0], whitespace, result_type);
+  }
+  return SplitStringT<std::string, StringPiece, StringPiece>(
+      input, separators, whitespace, result_type);
+}
+
+std::vector<StringPiece16> SplitStringPiece(StringPiece16 input,
+                                            StringPiece16 separators,
+                                            WhitespaceHandling whitespace,
+                                            SplitResult result_type) {
+  if (separators.size() == 1) {
+    return SplitStringT<string16, StringPiece16, char16>(
+        input, separators[0], whitespace, result_type);
+  }
+  return SplitStringT<string16, StringPiece16, StringPiece16>(
+      input, separators, whitespace, result_type);
+}
+
+void SplitString(const string16& str,
+                 char16 c,
+                 std::vector<string16>* result) {
+  DCHECK(CBU16_IS_SINGLE(c));
+  *result = SplitStringT<string16, string16, char16>(
+      str, c, TRIM_WHITESPACE, SPLIT_WANT_ALL);
+
+  // Backward-compat hack: The old SplitString implementation would keep
+  // empty substrings, for example:
+  //    "a,,b" -> ["a", "", "b"]
+  //    "a, ,b" -> ["a", "", "b"]
+  // which the current code also does. But the old one would discard them when
+  // the only result was that empty string:
+  //    "  " -> []
+  // In the latter case, our new code will give [""]
+  if (result->size() == 1 && (*result)[0].empty())
+    result->clear();
+}
+
+void SplitString(const std::string& str,
+                 char c,
+                 std::vector<std::string>* result) {
+#if CHAR_MIN < 0
+  DCHECK_GE(c, 0);
+#endif
+  DCHECK_LT(c, 0x7F);
+  *result = SplitStringT<std::string, std::string, char>(
+      str, c, TRIM_WHITESPACE, SPLIT_WANT_ALL);
+
+  // Backward-compat hack, see above.
+  if (result->size() == 1 && (*result)[0].empty())
+    result->clear();
+
+}
+
+bool SplitStringIntoKeyValuePairs(const std::string& line,
+                                  char key_value_delimiter,
+                                  char key_value_pair_delimiter,
+                                  StringPairs* key_value_pairs) {
+  key_value_pairs->clear();
+
+  std::vector<std::string> pairs;
+  SplitString(line, key_value_pair_delimiter, &pairs);
+
+  bool success = true;
+  for (size_t i = 0; i < pairs.size(); ++i) {
+    // Don't add empty pairs into the result.
+    if (pairs[i].empty())
+      continue;
+
+    std::string key;
+    std::string value;
+    if (!SplitStringIntoKeyValue(pairs[i], key_value_delimiter, &key, &value)) {
+      // Don't return here, to allow for pairs without associated
+      // value or key; just record that the split failed.
+      success = false;
+    }
+    key_value_pairs->push_back(make_pair(key, value));
+  }
+  return success;
+}
+
+void SplitStringUsingSubstr(const string16& str,
+                            const string16& s,
+                            std::vector<string16>* r) {
+  SplitStringUsingSubstrT(str, s, r);
+}
+
+void SplitStringUsingSubstr(const std::string& str,
+                            const std::string& s,
+                            std::vector<std::string>* r) {
+  SplitStringUsingSubstrT(str, s, r);
+}
+
+void SplitStringDontTrim(StringPiece16 str,
+                         char16 c,
+                         std::vector<string16>* result) {
+  DCHECK(CBU16_IS_SINGLE(c));
+  *result = SplitStringT<string16, string16, char16>(
+      str, c, KEEP_WHITESPACE, SPLIT_WANT_ALL);
+}
+
+void SplitStringDontTrim(StringPiece str,
+                         char c,
+                         std::vector<std::string>* result) {
+#if CHAR_MIN < 0
+  DCHECK_GE(c, 0);
+#endif
+  DCHECK_LT(c, 0x7F);
+  *result = SplitStringT<std::string, std::string, char>(
+      str, c, KEEP_WHITESPACE, SPLIT_WANT_ALL);
+}
+
+void SplitStringAlongWhitespace(const string16& str,
+                                std::vector<string16>* result) {
+  *result = SplitStringT<string16, string16, StringPiece16>(
+      str, StringPiece16(kWhitespaceASCIIAs16),
+      TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
+}
+
+void SplitStringAlongWhitespace(const std::string& str,
+                                std::vector<std::string>* result) {
+  *result = SplitStringT<std::string, std::string, StringPiece>(
+      str, StringPiece(kWhitespaceASCII),
+      TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
+}
+
+}  // namespace base
diff --git a/base/strings/string_split.h b/base/strings/string_split.h
new file mode 100644
index 0000000..dc4108d
--- /dev/null
+++ b/base/strings/string_split.h
@@ -0,0 +1,158 @@
+// Copyright (c) 2012 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_STRINGS_STRING_SPLIT_H_
+#define BASE_STRINGS_STRING_SPLIT_H_
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+enum WhitespaceHandling {
+  KEEP_WHITESPACE,
+  TRIM_WHITESPACE,
+};
+
+enum SplitResult {
+  // Strictly return all results.
+  //
+  // If the input is ",," and the separator is ',' this will return a
+  // vector of three empty strings.
+  SPLIT_WANT_ALL,
+
+  // Only nonempty results will be added to the results. Multiple separators
+  // will be coalesced. Separators at the beginning and end of the input will
+  // be ignored. With TRIM_WHITESPACE, whitespace-only results will be dropped.
+  //
+  // If the input is ",," and the separator is ',', this will return an empty
+  // vector.
+  SPLIT_WANT_NONEMPTY,
+};
+
+// Split the given string on ANY of the given separators, returning copies of
+// the result.
+//
+// To split on either commas or semicolons, keeping all whitespace:
+//
+//   std::vector<std::string> tokens = base::SplitString(
+//       input, ",;", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
+BASE_EXPORT std::vector<std::string> SplitString(
+    StringPiece input,
+    StringPiece separators,
+    WhitespaceHandling whitespace,
+    SplitResult result_type);
+BASE_EXPORT std::vector<string16> SplitString(
+    StringPiece16 input,
+    StringPiece16 separators,
+    WhitespaceHandling whitespace,
+    SplitResult result_type);
+
+// Like SplitString above except it returns a vector of StringPieces which
+// reference the original buffer without copying. Although you have to be
+// careful to keep the original string unmodified, this provides an efficient
+// way to iterate through tokens in a string.
+//
+// To iterate through all whitespace-separated tokens in an input string:
+//
+//   for (const auto& cur :
+//        base::SplitStringPiece(input, base::kWhitespaceASCII,
+//                               base::KEEP_WHITESPACE,
+//                               base::SPLIT_WANT_NONEMPTY)) {
+//     ...
+BASE_EXPORT std::vector<StringPiece> SplitStringPiece(
+    StringPiece input,
+    StringPiece separators,
+    WhitespaceHandling whitespace,
+    SplitResult result_type);
+BASE_EXPORT std::vector<StringPiece16> SplitStringPiece(
+    StringPiece16 input,
+    StringPiece16 separators,
+    WhitespaceHandling whitespace,
+    SplitResult result_type);
+
+using StringPairs = std::vector<std::pair<std::string, std::string>>;
+
+// Splits |line| into key value pairs according to the given delimiters and
+// removes whitespace leading each key and trailing each value. Returns true
+// only if each pair has a non-empty key and value. |key_value_pairs| will
+// include ("","") pairs for entries without |key_value_delimiter|.
+BASE_EXPORT bool SplitStringIntoKeyValuePairs(const std::string& line,
+                                              char key_value_delimiter,
+                                              char key_value_pair_delimiter,
+                                              StringPairs* key_value_pairs);
+
+// Similar to SplitString, but use a substring delimiter instead of a list of
+// characters that are all possible delimiters.
+//
+// TODO(brettw) this should probably be changed and expanded to provide a
+// mirror of the SplitString[Piece] API above, just with the different
+// delimiter handling.
+BASE_EXPORT void SplitStringUsingSubstr(const string16& str,
+                                        const string16& s,
+                                        std::vector<string16>* r);
+BASE_EXPORT void SplitStringUsingSubstr(const std::string& str,
+                                        const std::string& s,
+                                        std::vector<std::string>* r);
+
+// -----------------------------------------------------------------------------
+// Backwards-compat wrappers
+//
+// New code should use one of the more general variants above.
+// TODO(brettw) remove these and convert to the versions above.
+
+// Splits |str| into a vector of strings delimited by |c|, placing the results
+// in |r|. If several instances of |c| are contiguous, or if |str| begins with
+// or ends with |c|, then an empty string is inserted.
+//
+// Every substring is trimmed of any leading or trailing white space.
+// NOTE: |c| must be in BMP (Basic Multilingual Plane)
+BASE_EXPORT void SplitString(const string16& str,
+                             char16 c,
+                             std::vector<string16>* r);
+
+// |str| should not be in a multi-byte encoding like Shift-JIS or GBK in which
+// the trailing byte of a multi-byte character can be in the ASCII range.
+// UTF-8, and other single/multi-byte ASCII-compatible encodings are OK.
+// Note: |c| must be in the ASCII range.
+BASE_EXPORT void SplitString(const std::string& str,
+                             char c,
+                             std::vector<std::string>* r);
+
+// The same as SplitString, but don't trim white space.
+// NOTE: |c| must be in BMP (Basic Multilingual Plane)
+BASE_EXPORT void SplitStringDontTrim(StringPiece16 str,
+                                     char16 c,
+                                     std::vector<string16>* r);
+// |str| should not be in a multi-byte encoding like Shift-JIS or GBK in which
+// the trailing byte of a multi-byte character can be in the ASCII range.
+// UTF-8, and other single/multi-byte ASCII-compatible encodings are OK.
+// Note: |c| must be in the ASCII range.
+BASE_EXPORT void SplitStringDontTrim(StringPiece str,
+                                     char c,
+                                     std::vector<std::string>* result);
+
+// WARNING: this uses whitespace as defined by the HTML5 spec (ASCII whitespace
+// only).
+//
+// The difference between this and calling SplitString with the whitespace
+// characters as separators is the treatment of the first element when the
+// string starts with whitespace.
+//
+// Input        SplitString      SplitStringAlongWhitespace
+// --------------------------------------------------------
+// " a "        "", "a"          "a"
+BASE_EXPORT void SplitStringAlongWhitespace(const string16& str,
+                                            std::vector<string16>* result);
+BASE_EXPORT void SplitStringAlongWhitespace(const std::string& str,
+                                            std::vector<std::string>* result);
+
+}  // namespace base
+
+#endif  // BASE_STRINGS_STRING_SPLIT_H_
diff --git a/base/strings/string_split_unittest.cc b/base/strings/string_split_unittest.cc
new file mode 100644
index 0000000..c745ab5
--- /dev/null
+++ b/base/strings/string_split_unittest.cc
@@ -0,0 +1,407 @@
+// Copyright (c) 2012 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/strings/string_split.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::ElementsAre;
+
+namespace base {
+
+namespace {
+
+#if !defined(WCHAR_T_IS_UTF16)
+// Overload SplitString with a wide-char version to make it easier to
+// test the string16 version with wide character literals.
+void SplitString(const std::wstring& str,
+                 wchar_t c,
+                 std::vector<std::wstring>* result) {
+  std::vector<string16> result16;
+  SplitString(WideToUTF16(str), c, &result16);
+  for (size_t i = 0; i < result16.size(); ++i)
+    result->push_back(UTF16ToWide(result16[i]));
+}
+#endif
+
+}  // anonymous namespace
+
+class SplitStringIntoKeyValuePairsTest : public testing::Test {
+ protected:
+  base::StringPairs kv_pairs;
+};
+
+TEST_F(SplitStringIntoKeyValuePairsTest, EmptyString) {
+  EXPECT_TRUE(SplitStringIntoKeyValuePairs(std::string(),
+                                           ':',  // Key-value delimiter
+                                           ',',  // Key-value pair delimiter
+                                           &kv_pairs));
+  EXPECT_TRUE(kv_pairs.empty());
+}
+
+TEST_F(SplitStringIntoKeyValuePairsTest, MissingKeyValueDelimiter) {
+  EXPECT_FALSE(SplitStringIntoKeyValuePairs("key1,key2:value2",
+                                            ':',  // Key-value delimiter
+                                            ',',  // Key-value pair delimiter
+                                            &kv_pairs));
+  ASSERT_EQ(2U, kv_pairs.size());
+  EXPECT_TRUE(kv_pairs[0].first.empty());
+  EXPECT_TRUE(kv_pairs[0].second.empty());
+  EXPECT_EQ("key2", kv_pairs[1].first);
+  EXPECT_EQ("value2", kv_pairs[1].second);
+}
+
+TEST_F(SplitStringIntoKeyValuePairsTest, EmptyKeyWithKeyValueDelimiter) {
+  EXPECT_TRUE(SplitStringIntoKeyValuePairs(":value1,key2:value2",
+                                           ':',  // Key-value delimiter
+                                           ',',  // Key-value pair delimiter
+                                           &kv_pairs));
+  ASSERT_EQ(2U, kv_pairs.size());
+  EXPECT_TRUE(kv_pairs[0].first.empty());
+  EXPECT_EQ("value1", kv_pairs[0].second);
+  EXPECT_EQ("key2", kv_pairs[1].first);
+  EXPECT_EQ("value2", kv_pairs[1].second);
+}
+
+TEST_F(SplitStringIntoKeyValuePairsTest, TrailingAndLeadingPairDelimiter) {
+  EXPECT_TRUE(SplitStringIntoKeyValuePairs(",key1:value1,key2:value2,",
+                                           ':',   // Key-value delimiter
+                                           ',',   // Key-value pair delimiter
+                                           &kv_pairs));
+  ASSERT_EQ(2U, kv_pairs.size());
+  EXPECT_EQ("key1", kv_pairs[0].first);
+  EXPECT_EQ("value1", kv_pairs[0].second);
+  EXPECT_EQ("key2", kv_pairs[1].first);
+  EXPECT_EQ("value2", kv_pairs[1].second);
+}
+
+TEST_F(SplitStringIntoKeyValuePairsTest, EmptyPair) {
+  EXPECT_TRUE(SplitStringIntoKeyValuePairs("key1:value1,,key3:value3",
+                                           ':',   // Key-value delimiter
+                                           ',',   // Key-value pair delimiter
+                                           &kv_pairs));
+  ASSERT_EQ(2U, kv_pairs.size());
+  EXPECT_EQ("key1", kv_pairs[0].first);
+  EXPECT_EQ("value1", kv_pairs[0].second);
+  EXPECT_EQ("key3", kv_pairs[1].first);
+  EXPECT_EQ("value3", kv_pairs[1].second);
+}
+
+TEST_F(SplitStringIntoKeyValuePairsTest, EmptyValue) {
+  EXPECT_FALSE(SplitStringIntoKeyValuePairs("key1:,key2:value2",
+                                            ':',   // Key-value delimiter
+                                            ',',   // Key-value pair delimiter
+                                            &kv_pairs));
+  ASSERT_EQ(2U, kv_pairs.size());
+  EXPECT_EQ("key1", kv_pairs[0].first);
+  EXPECT_EQ("", kv_pairs[0].second);
+  EXPECT_EQ("key2", kv_pairs[1].first);
+  EXPECT_EQ("value2", kv_pairs[1].second);
+}
+
+TEST_F(SplitStringIntoKeyValuePairsTest, UntrimmedWhitespace) {
+  EXPECT_TRUE(SplitStringIntoKeyValuePairs("key1 : value1",
+                                           ':',  // Key-value delimiter
+                                           ',',  // Key-value pair delimiter
+                                           &kv_pairs));
+  ASSERT_EQ(1U, kv_pairs.size());
+  EXPECT_EQ("key1 ", kv_pairs[0].first);
+  EXPECT_EQ(" value1", kv_pairs[0].second);
+}
+
+TEST_F(SplitStringIntoKeyValuePairsTest, TrimmedWhitespace) {
+  EXPECT_TRUE(SplitStringIntoKeyValuePairs("key1:value1 , key2:value2",
+                                           ':',   // Key-value delimiter
+                                           ',',   // Key-value pair delimiter
+                                           &kv_pairs));
+  ASSERT_EQ(2U, kv_pairs.size());
+  EXPECT_EQ("key1", kv_pairs[0].first);
+  EXPECT_EQ("value1", kv_pairs[0].second);
+  EXPECT_EQ("key2", kv_pairs[1].first);
+  EXPECT_EQ("value2", kv_pairs[1].second);
+}
+
+TEST_F(SplitStringIntoKeyValuePairsTest, MultipleKeyValueDelimiters) {
+  EXPECT_TRUE(SplitStringIntoKeyValuePairs("key1:::value1,key2:value2",
+                                           ':',   // Key-value delimiter
+                                           ',',   // Key-value pair delimiter
+                                           &kv_pairs));
+  ASSERT_EQ(2U, kv_pairs.size());
+  EXPECT_EQ("key1", kv_pairs[0].first);
+  EXPECT_EQ("value1", kv_pairs[0].second);
+  EXPECT_EQ("key2", kv_pairs[1].first);
+  EXPECT_EQ("value2", kv_pairs[1].second);
+}
+
+TEST_F(SplitStringIntoKeyValuePairsTest, OnlySplitAtGivenSeparator) {
+  std::string a("a ?!@#$%^&*()_+:/{}\\\t\nb");
+  EXPECT_TRUE(SplitStringIntoKeyValuePairs(a + "X" + a + "Y" + a + "X" + a,
+                                           'X',  // Key-value delimiter
+                                           'Y',  // Key-value pair delimiter
+                                           &kv_pairs));
+  ASSERT_EQ(2U, kv_pairs.size());
+  EXPECT_EQ(a, kv_pairs[0].first);
+  EXPECT_EQ(a, kv_pairs[0].second);
+  EXPECT_EQ(a, kv_pairs[1].first);
+  EXPECT_EQ(a, kv_pairs[1].second);
+}
+
+
+TEST_F(SplitStringIntoKeyValuePairsTest, DelimiterInValue) {
+  EXPECT_TRUE(SplitStringIntoKeyValuePairs("key1:va:ue1,key2:value2",
+                                           ':',   // Key-value delimiter
+                                           ',',   // Key-value pair delimiter
+                                           &kv_pairs));
+  ASSERT_EQ(2U, kv_pairs.size());
+  EXPECT_EQ("key1", kv_pairs[0].first);
+  EXPECT_EQ("va:ue1", kv_pairs[0].second);
+  EXPECT_EQ("key2", kv_pairs[1].first);
+  EXPECT_EQ("value2", kv_pairs[1].second);
+}
+
+TEST(SplitStringUsingSubstrTest, EmptyString) {
+  std::vector<std::string> results;
+  SplitStringUsingSubstr(std::string(), "DELIMITER", &results);
+  ASSERT_EQ(1u, results.size());
+  EXPECT_THAT(results, ElementsAre(""));
+}
+
+TEST(StringUtilTest, SplitString_Basics) {
+  std::vector<std::string> r;
+
+  r = SplitString(std::string(), ",:;", KEEP_WHITESPACE, SPLIT_WANT_ALL);
+  EXPECT_TRUE(r.empty());
+
+  // Empty separator list
+  r = SplitString("hello, world", "", KEEP_WHITESPACE, SPLIT_WANT_ALL);
+  ASSERT_EQ(1u, r.size());
+  EXPECT_EQ("hello, world", r[0]);
+
+  // Should split on any of the separators.
+  r = SplitString("::,,;;", ",:;", KEEP_WHITESPACE, SPLIT_WANT_ALL);
+  ASSERT_EQ(7u, r.size());
+  for (auto str : r)
+    ASSERT_TRUE(str.empty());
+
+  r = SplitString("red, green; blue:", ",:;", TRIM_WHITESPACE,
+                  SPLIT_WANT_NONEMPTY);
+  ASSERT_EQ(3u, r.size());
+  EXPECT_EQ("red", r[0]);
+  EXPECT_EQ("green", r[1]);
+  EXPECT_EQ("blue", r[2]);
+
+  // Want to split a string along whitespace sequences.
+  r = SplitString("  red green   \tblue\n", " \t\n", TRIM_WHITESPACE,
+                  SPLIT_WANT_NONEMPTY);
+  ASSERT_EQ(3u, r.size());
+  EXPECT_EQ("red", r[0]);
+  EXPECT_EQ("green", r[1]);
+  EXPECT_EQ("blue", r[2]);
+
+  // Weird case of splitting on spaces but not trimming.
+  r = SplitString(" red ", " ", TRIM_WHITESPACE, SPLIT_WANT_ALL);
+  ASSERT_EQ(3u, r.size());
+  EXPECT_EQ("", r[0]);  // Before the first space.
+  EXPECT_EQ("red", r[1]);
+  EXPECT_EQ("", r[2]);  // After the last space.
+}
+
+TEST(StringUtilTest, SplitString_WhitespaceAndResultType) {
+  std::vector<std::string> r;
+
+  // Empty input handling.
+  r = SplitString(std::string(), ",", KEEP_WHITESPACE, SPLIT_WANT_ALL);
+  EXPECT_TRUE(r.empty());
+  r = SplitString(std::string(), ",", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY);
+  EXPECT_TRUE(r.empty());
+
+  // Input string is space and we're trimming.
+  r = SplitString(" ", ",", TRIM_WHITESPACE, SPLIT_WANT_ALL);
+  ASSERT_EQ(1u, r.size());
+  EXPECT_EQ("", r[0]);
+  r = SplitString(" ", ",", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
+  EXPECT_TRUE(r.empty());
+
+  // Test all 4 combinations of flags on ", ,".
+  r = SplitString(", ,", ",", KEEP_WHITESPACE, SPLIT_WANT_ALL);
+  ASSERT_EQ(3u, r.size());
+  EXPECT_EQ("", r[0]);
+  EXPECT_EQ(" ", r[1]);
+  EXPECT_EQ("", r[2]);
+  r = SplitString(", ,", ",", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY);
+  ASSERT_EQ(1u, r.size());
+  ASSERT_EQ(" ", r[0]);
+  r = SplitString(", ,", ",", TRIM_WHITESPACE, SPLIT_WANT_ALL);
+  ASSERT_EQ(3u, r.size());
+  EXPECT_EQ("", r[0]);
+  EXPECT_EQ("", r[1]);
+  EXPECT_EQ("", r[2]);
+  r = SplitString(", ,", ",", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
+  ASSERT_TRUE(r.empty());
+}
+
+TEST(StringUtilTest, SplitString_Legacy) {
+  std::vector<std::wstring> r;
+
+  SplitString(std::wstring(), L',', &r);
+  EXPECT_EQ(0U, r.size());
+  r.clear();
+
+  SplitString(L"a,b,c", L',', &r);
+  ASSERT_EQ(3U, r.size());
+  EXPECT_EQ(r[0], L"a");
+  EXPECT_EQ(r[1], L"b");
+  EXPECT_EQ(r[2], L"c");
+  r.clear();
+
+  SplitString(L"a, b, c", L',', &r);
+  ASSERT_EQ(3U, r.size());
+  EXPECT_EQ(r[0], L"a");
+  EXPECT_EQ(r[1], L"b");
+  EXPECT_EQ(r[2], L"c");
+  r.clear();
+
+  SplitString(L"a,,c", L',', &r);
+  ASSERT_EQ(3U, r.size());
+  EXPECT_EQ(r[0], L"a");
+  EXPECT_EQ(r[1], L"");
+  EXPECT_EQ(r[2], L"c");
+  r.clear();
+
+  SplitString(L"a, ,c", L',', &r);
+  ASSERT_EQ(3U, r.size());
+  EXPECT_EQ(r[0], L"a");
+  EXPECT_EQ(r[1], L"");
+  EXPECT_EQ(r[2], L"c");
+  r.clear();
+
+  SplitString(L"   ", L'*', &r);
+  EXPECT_EQ(0U, r.size());
+  r.clear();
+
+  SplitString(L"foo", L'*', &r);
+  ASSERT_EQ(1U, r.size());
+  EXPECT_EQ(r[0], L"foo");
+  r.clear();
+
+  SplitString(L"foo ,", L',', &r);
+  ASSERT_EQ(2U, r.size());
+  EXPECT_EQ(r[0], L"foo");
+  EXPECT_EQ(r[1], L"");
+  r.clear();
+
+  SplitString(L",", L',', &r);
+  ASSERT_EQ(2U, r.size());
+  EXPECT_EQ(r[0], L"");
+  EXPECT_EQ(r[1], L"");
+  r.clear();
+
+  SplitString(L"\t\ta\t", L'\t', &r);
+  ASSERT_EQ(4U, r.size());
+  EXPECT_EQ(r[0], L"");
+  EXPECT_EQ(r[1], L"");
+  EXPECT_EQ(r[2], L"a");
+  EXPECT_EQ(r[3], L"");
+  r.clear();
+
+  SplitString(L"\ta\t\nb\tcc", L'\n', &r);
+  ASSERT_EQ(2U, r.size());
+  EXPECT_EQ(r[0], L"a");
+  EXPECT_EQ(r[1], L"b\tcc");
+  r.clear();
+}
+
+TEST(SplitStringUsingSubstrTest, StringWithNoDelimiter) {
+  std::vector<std::string> results;
+  SplitStringUsingSubstr("alongwordwithnodelimiter", "DELIMITER", &results);
+  ASSERT_EQ(1u, results.size());
+  EXPECT_THAT(results, ElementsAre("alongwordwithnodelimiter"));
+}
+
+TEST(SplitStringUsingSubstrTest, LeadingDelimitersSkipped) {
+  std::vector<std::string> results;
+  SplitStringUsingSubstr(
+      "DELIMITERDELIMITERDELIMITERoneDELIMITERtwoDELIMITERthree",
+      "DELIMITER",
+      &results);
+  ASSERT_EQ(6u, results.size());
+  EXPECT_THAT(results, ElementsAre("", "", "", "one", "two", "three"));
+}
+
+TEST(SplitStringUsingSubstrTest, ConsecutiveDelimitersSkipped) {
+  std::vector<std::string> results;
+  SplitStringUsingSubstr(
+      "unoDELIMITERDELIMITERDELIMITERdosDELIMITERtresDELIMITERDELIMITERcuatro",
+      "DELIMITER",
+      &results);
+  ASSERT_EQ(7u, results.size());
+  EXPECT_THAT(results, ElementsAre("uno", "", "", "dos", "tres", "", "cuatro"));
+}
+
+TEST(SplitStringUsingSubstrTest, TrailingDelimitersSkipped) {
+  std::vector<std::string> results;
+  SplitStringUsingSubstr(
+      "unDELIMITERdeuxDELIMITERtroisDELIMITERquatreDELIMITERDELIMITERDELIMITER",
+      "DELIMITER",
+      &results);
+  ASSERT_EQ(7u, results.size());
+  EXPECT_THAT(
+      results, ElementsAre("un", "deux", "trois", "quatre", "", "", ""));
+}
+
+TEST(StringSplitTest, StringSplitDontTrim) {
+  std::vector<std::string> r;
+
+  SplitStringDontTrim("   ", '*', &r);
+  ASSERT_EQ(1U, r.size());
+  EXPECT_EQ(r[0], "   ");
+
+  SplitStringDontTrim("\t  \ta\t ", '\t', &r);
+  ASSERT_EQ(4U, r.size());
+  EXPECT_EQ(r[0], "");
+  EXPECT_EQ(r[1], "  ");
+  EXPECT_EQ(r[2], "a");
+  EXPECT_EQ(r[3], " ");
+
+  SplitStringDontTrim("\ta\t\nb\tcc", '\n', &r);
+  ASSERT_EQ(2U, r.size());
+  EXPECT_EQ(r[0], "\ta\t");
+  EXPECT_EQ(r[1], "b\tcc");
+}
+
+TEST(StringSplitTest, SplitStringAlongWhitespace) {
+  struct TestData {
+    const char* input;
+    const size_t expected_result_count;
+    const char* output1;
+    const char* output2;
+  } data[] = {
+    { "a",       1, "a",  ""   },
+    { " ",       0, "",   ""   },
+    { " a",      1, "a",  ""   },
+    { " ab ",    1, "ab", ""   },
+    { " ab c",   2, "ab", "c"  },
+    { " ab c ",  2, "ab", "c"  },
+    { " ab cd",  2, "ab", "cd" },
+    { " ab cd ", 2, "ab", "cd" },
+    { " \ta\t",  1, "a",  ""   },
+    { " b\ta\t", 2, "b",  "a"  },
+    { " b\tat",  2, "b",  "at" },
+    { "b\tat",   2, "b",  "at" },
+    { "b\t at",  2, "b",  "at" },
+  };
+  for (size_t i = 0; i < arraysize(data); ++i) {
+    std::vector<std::string> results;
+    SplitStringAlongWhitespace(data[i].input, &results);
+    ASSERT_EQ(data[i].expected_result_count, results.size());
+    if (data[i].expected_result_count > 0)
+      ASSERT_EQ(data[i].output1, results[0]);
+    if (data[i].expected_result_count > 1)
+      ASSERT_EQ(data[i].output2, results[1]);
+  }
+}
+
+}  // namespace base
diff --git a/base/strings/string_tokenizer.h b/base/strings/string_tokenizer.h
new file mode 100644
index 0000000..8defbac
--- /dev/null
+++ b/base/strings/string_tokenizer.h
@@ -0,0 +1,260 @@
+// Copyright (c) 2011 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_STRINGS_STRING_TOKENIZER_H_
+#define BASE_STRINGS_STRING_TOKENIZER_H_
+
+#include <algorithm>
+#include <string>
+
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+// StringTokenizerT is a simple string tokenizer class.  It works like an
+// iterator that with each step (see the Advance method) updates members that
+// refer to the next token in the input string.  The user may optionally
+// configure the tokenizer to return delimiters.
+//
+// Warning: be careful not to pass a C string into the 2-arg constructor:
+// StringTokenizer t("this is a test", " ");  // WRONG
+// This will create a temporary std::string, save the begin() and end()
+// iterators, and then the string will be freed before we actually start
+// tokenizing it.
+// Instead, use a std::string or use the 3 arg constructor of CStringTokenizer.
+//
+//
+// EXAMPLE 1:
+//
+//   char input[] = "this is a test";
+//   CStringTokenizer t(input, input + strlen(input), " ");
+//   while (t.GetNext()) {
+//     printf("%s\n", t.token().c_str());
+//   }
+//
+// Output:
+//
+//   this
+//   is
+//   a
+//   test
+//
+//
+// EXAMPLE 2:
+//
+//   std::string input = "no-cache=\"foo, bar\", private";
+//   StringTokenizer t(input, ", ");
+//   t.set_quote_chars("\"");
+//   while (t.GetNext()) {
+//     printf("%s\n", t.token().c_str());
+//   }
+//
+// Output:
+//
+//   no-cache="foo, bar"
+//   private
+//
+//
+// EXAMPLE 3:
+//
+//   bool next_is_option = false, next_is_value = false;
+//   std::string input = "text/html; charset=UTF-8; foo=bar";
+//   StringTokenizer t(input, "; =");
+//   t.set_options(StringTokenizer::RETURN_DELIMS);
+//   while (t.GetNext()) {
+//     if (t.token_is_delim()) {
+//       switch (*t.token_begin()) {
+//         case ';':
+//           next_is_option = true;
+//           break;
+//         case '=':
+//           next_is_value = true;
+//           break;
+//       }
+//     } else {
+//       const char* label;
+//       if (next_is_option) {
+//         label = "option-name";
+//         next_is_option = false;
+//       } else if (next_is_value) {
+//         label = "option-value";
+//         next_is_value = false;
+//       } else {
+//         label = "mime-type";
+//       }
+//       printf("%s: %s\n", label, t.token().c_str());
+//     }
+//   }
+//
+//
+template <class str, class const_iterator>
+class StringTokenizerT {
+ public:
+  typedef typename str::value_type char_type;
+
+  // Options that may be pass to set_options()
+  enum {
+    // Specifies the delimiters should be returned as tokens
+    RETURN_DELIMS = 1 << 0,
+  };
+
+  // The string object must live longer than the tokenizer.  (In particular this
+  // should not be constructed with a temporary.)
+  StringTokenizerT(const str& string,
+                   const str& delims) {
+    Init(string.begin(), string.end(), delims);
+  }
+
+  StringTokenizerT(const_iterator string_begin,
+                   const_iterator string_end,
+                   const str& delims) {
+    Init(string_begin, string_end, delims);
+  }
+
+  // Set the options for this tokenizer.  By default, this is 0.
+  void set_options(int options) { options_ = options; }
+
+  // Set the characters to regard as quotes.  By default, this is empty.  When
+  // a quote char is encountered, the tokenizer will switch into a mode where
+  // it ignores delimiters that it finds.  It switches out of this mode once it
+  // finds another instance of the quote char.  If a backslash is encountered
+  // within a quoted string, then the next character is skipped.
+  void set_quote_chars(const str& quotes) { quotes_ = quotes; }
+
+  // Call this method to advance the tokenizer to the next delimiter.  This
+  // returns false if the tokenizer is complete.  This method must be called
+  // before calling any of the token* methods.
+  bool GetNext() {
+    if (quotes_.empty() && options_ == 0)
+      return QuickGetNext();
+    else
+      return FullGetNext();
+  }
+
+  // Start iterating through tokens from the beginning of the string.
+  void Reset() {
+    token_end_ = start_pos_;
+  }
+
+  // Returns true if token is a delimiter.  When the tokenizer is constructed
+  // with the RETURN_DELIMS option, this method can be used to check if the
+  // returned token is actually a delimiter.
+  bool token_is_delim() const { return token_is_delim_; }
+
+  // If GetNext() returned true, then these methods may be used to read the
+  // value of the token.
+  const_iterator token_begin() const { return token_begin_; }
+  const_iterator token_end() const { return token_end_; }
+  str token() const { return str(token_begin_, token_end_); }
+  base::StringPiece token_piece() const {
+    return base::StringPiece(&*token_begin_,
+                             std::distance(token_begin_, token_end_));
+  }
+
+ private:
+  void Init(const_iterator string_begin,
+            const_iterator string_end,
+            const str& delims) {
+    start_pos_ = string_begin;
+    token_begin_ = string_begin;
+    token_end_ = string_begin;
+    end_ = string_end;
+    delims_ = delims;
+    options_ = 0;
+    token_is_delim_ = false;
+  }
+
+  // Implementation of GetNext() for when we have no quote characters. We have
+  // two separate implementations because AdvanceOne() is a hot spot in large
+  // text files with large tokens.
+  bool QuickGetNext() {
+    token_is_delim_ = false;
+    for (;;) {
+      token_begin_ = token_end_;
+      if (token_end_ == end_)
+        return false;
+      ++token_end_;
+      if (delims_.find(*token_begin_) == str::npos)
+        break;
+      // else skip over delimiter.
+    }
+    while (token_end_ != end_ && delims_.find(*token_end_) == str::npos)
+      ++token_end_;
+    return true;
+  }
+
+  // Implementation of GetNext() for when we have to take quotes into account.
+  bool FullGetNext() {
+    AdvanceState state;
+    token_is_delim_ = false;
+    for (;;) {
+      token_begin_ = token_end_;
+      if (token_end_ == end_)
+        return false;
+      ++token_end_;
+      if (AdvanceOne(&state, *token_begin_))
+        break;
+      if (options_ & RETURN_DELIMS) {
+        token_is_delim_ = true;
+        return true;
+      }
+      // else skip over delimiter.
+    }
+    while (token_end_ != end_ && AdvanceOne(&state, *token_end_))
+      ++token_end_;
+    return true;
+  }
+
+  bool IsDelim(char_type c) const {
+    return delims_.find(c) != str::npos;
+  }
+
+  bool IsQuote(char_type c) const {
+    return quotes_.find(c) != str::npos;
+  }
+
+  struct AdvanceState {
+    bool in_quote;
+    bool in_escape;
+    char_type quote_char;
+    AdvanceState() : in_quote(false), in_escape(false), quote_char('\0') {}
+  };
+
+  // Returns true if a delimiter was not hit.
+  bool AdvanceOne(AdvanceState* state, char_type c) {
+    if (state->in_quote) {
+      if (state->in_escape) {
+        state->in_escape = false;
+      } else if (c == '\\') {
+        state->in_escape = true;
+      } else if (c == state->quote_char) {
+        state->in_quote = false;
+      }
+    } else {
+      if (IsDelim(c))
+        return false;
+      state->in_quote = IsQuote(state->quote_char = c);
+    }
+    return true;
+  }
+
+  const_iterator start_pos_;
+  const_iterator token_begin_;
+  const_iterator token_end_;
+  const_iterator end_;
+  str delims_;
+  str quotes_;
+  int options_;
+  bool token_is_delim_;
+};
+
+typedef StringTokenizerT<std::string, std::string::const_iterator>
+    StringTokenizer;
+typedef StringTokenizerT<std::wstring, std::wstring::const_iterator>
+    WStringTokenizer;
+typedef StringTokenizerT<std::string, const char*> CStringTokenizer;
+
+}  // namespace base
+
+#endif  // BASE_STRINGS_STRING_TOKENIZER_H_
diff --git a/base/strings/string_tokenizer_unittest.cc b/base/strings/string_tokenizer_unittest.cc
new file mode 100644
index 0000000..d391845
--- /dev/null
+++ b/base/strings/string_tokenizer_unittest.cc
@@ -0,0 +1,234 @@
+// Copyright (c) 2006-2008 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/strings/string_tokenizer.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+using std::string;
+
+namespace base {
+
+namespace {
+
+TEST(StringTokenizerTest, Simple) {
+  string input = "this is a test";
+  StringTokenizer t(input, " ");
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("this"), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("is"), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("a"), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("test"), t.token());
+
+  EXPECT_FALSE(t.GetNext());
+}
+
+TEST(StringTokenizerTest, Reset) {
+  string input = "this is a test";
+  StringTokenizer t(input, " ");
+
+  for (int i = 0; i < 2; ++i) {
+    EXPECT_TRUE(t.GetNext());
+    EXPECT_EQ(string("this"), t.token());
+
+    EXPECT_TRUE(t.GetNext());
+    EXPECT_EQ(string("is"), t.token());
+
+    EXPECT_TRUE(t.GetNext());
+    EXPECT_EQ(string("a"), t.token());
+
+    EXPECT_TRUE(t.GetNext());
+    EXPECT_EQ(string("test"), t.token());
+
+    EXPECT_FALSE(t.GetNext());
+    t.Reset();
+  }
+}
+
+TEST(StringTokenizerTest, RetDelims) {
+  string input = "this is a test";
+  StringTokenizer t(input, " ");
+  t.set_options(StringTokenizer::RETURN_DELIMS);
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("this"), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string(" "), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("is"), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string(" "), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("a"), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string(" "), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("test"), t.token());
+
+  EXPECT_FALSE(t.GetNext());
+}
+
+TEST(StringTokenizerTest, ManyDelims) {
+  string input = "this: is, a-test";
+  StringTokenizer t(input, ": ,-");
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("this"), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("is"), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("a"), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("test"), t.token());
+
+  EXPECT_FALSE(t.GetNext());
+}
+
+TEST(StringTokenizerTest, ParseHeader) {
+  string input = "Content-Type: text/html ; charset=UTF-8";
+  StringTokenizer t(input, ": ;=");
+  t.set_options(StringTokenizer::RETURN_DELIMS);
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_FALSE(t.token_is_delim());
+  EXPECT_EQ(string("Content-Type"), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_TRUE(t.token_is_delim());
+  EXPECT_EQ(string(":"), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_TRUE(t.token_is_delim());
+  EXPECT_EQ(string(" "), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_FALSE(t.token_is_delim());
+  EXPECT_EQ(string("text/html"), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_TRUE(t.token_is_delim());
+  EXPECT_EQ(string(" "), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_TRUE(t.token_is_delim());
+  EXPECT_EQ(string(";"), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_TRUE(t.token_is_delim());
+  EXPECT_EQ(string(" "), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_FALSE(t.token_is_delim());
+  EXPECT_EQ(string("charset"), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_TRUE(t.token_is_delim());
+  EXPECT_EQ(string("="), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_FALSE(t.token_is_delim());
+  EXPECT_EQ(string("UTF-8"), t.token());
+
+  EXPECT_FALSE(t.GetNext());
+  EXPECT_FALSE(t.token_is_delim());
+}
+
+TEST(StringTokenizerTest, ParseQuotedString) {
+  string input = "foo bar 'hello world' baz";
+  StringTokenizer t(input, " ");
+  t.set_quote_chars("'");
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("foo"), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("bar"), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("'hello world'"), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("baz"), t.token());
+
+  EXPECT_FALSE(t.GetNext());
+}
+
+TEST(StringTokenizerTest, ParseQuotedString_Malformed) {
+  string input = "bar 'hello wo";
+  StringTokenizer t(input, " ");
+  t.set_quote_chars("'");
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("bar"), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("'hello wo"), t.token());
+
+  EXPECT_FALSE(t.GetNext());
+}
+
+TEST(StringTokenizerTest, ParseQuotedString_Multiple) {
+  string input = "bar 'hel\"lo\" wo' baz\"";
+  StringTokenizer t(input, " ");
+  t.set_quote_chars("'\"");
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("bar"), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("'hel\"lo\" wo'"), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("baz\""), t.token());
+
+  EXPECT_FALSE(t.GetNext());
+}
+
+TEST(StringTokenizerTest, ParseQuotedString_EscapedQuotes) {
+  string input = "foo 'don\\'t do that'";
+  StringTokenizer t(input, " ");
+  t.set_quote_chars("'");
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("foo"), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("'don\\'t do that'"), t.token());
+
+  EXPECT_FALSE(t.GetNext());
+}
+
+TEST(StringTokenizerTest, ParseQuotedString_EscapedQuotes2) {
+  string input = "foo='a, b', bar";
+  StringTokenizer t(input, ", ");
+  t.set_quote_chars("'");
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("foo='a, b'"), t.token());
+
+  EXPECT_TRUE(t.GetNext());
+  EXPECT_EQ(string("bar"), t.token());
+
+  EXPECT_FALSE(t.GetNext());
+}
+
+}  // namespace
+
+}  // namespace base
diff --git a/base/strings/string_util.cc b/base/strings/string_util.cc
new file mode 100644
index 0000000..738d32e
--- /dev/null
+++ b/base/strings/string_util.cc
@@ -0,0 +1,1050 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/string_util.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <math.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#include <algorithm>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/memory/singleton.h"
+#include "base/strings/string_split.h"
+#include "base/strings/utf_string_conversion_utils.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/third_party/icu/icu_utf.h"
+#include "build/build_config.h"
+
+// Remove when this entire file is in the base namespace.
+using base::char16;
+using base::string16;
+
+namespace {
+
+// Force the singleton used by EmptyString[16] to be a unique type. This
+// prevents other code that might accidentally use Singleton<string> from
+// getting our internal one.
+struct EmptyStrings {
+  EmptyStrings() {}
+  const std::string s;
+  const string16 s16;
+
+  static EmptyStrings* GetInstance() {
+    return Singleton<EmptyStrings>::get();
+  }
+};
+
+// Used by ReplaceStringPlaceholders to track the position in the string of
+// replaced parameters.
+struct ReplacementOffset {
+  ReplacementOffset(uintptr_t parameter, size_t offset)
+      : parameter(parameter),
+        offset(offset) {}
+
+  // Index of the parameter.
+  uintptr_t parameter;
+
+  // Starting position in the string.
+  size_t offset;
+};
+
+static bool CompareParameter(const ReplacementOffset& elem1,
+                             const ReplacementOffset& elem2) {
+  return elem1.parameter < elem2.parameter;
+}
+
+// Assuming that a pointer is the size of a "machine word", then
+// uintptr_t is an integer type that is also a machine word.
+typedef uintptr_t MachineWord;
+const uintptr_t kMachineWordAlignmentMask = sizeof(MachineWord) - 1;
+
+inline bool IsAlignedToMachineWord(const void* pointer) {
+  return !(reinterpret_cast<MachineWord>(pointer) & kMachineWordAlignmentMask);
+}
+
+template<typename T> inline T* AlignToMachineWord(T* pointer) {
+  return reinterpret_cast<T*>(reinterpret_cast<MachineWord>(pointer) &
+                              ~kMachineWordAlignmentMask);
+}
+
+template<size_t size, typename CharacterType> struct NonASCIIMask;
+template<> struct NonASCIIMask<4, base::char16> {
+    static inline uint32_t value() { return 0xFF80FF80U; }
+};
+template<> struct NonASCIIMask<4, char> {
+    static inline uint32_t value() { return 0x80808080U; }
+};
+template<> struct NonASCIIMask<8, base::char16> {
+    static inline uint64_t value() { return 0xFF80FF80FF80FF80ULL; }
+};
+template<> struct NonASCIIMask<8, char> {
+    static inline uint64_t value() { return 0x8080808080808080ULL; }
+};
+#if defined(WCHAR_T_IS_UTF32)
+template<> struct NonASCIIMask<4, wchar_t> {
+    static inline uint32_t value() { return 0xFFFFFF80U; }
+};
+template<> struct NonASCIIMask<8, wchar_t> {
+    static inline uint64_t value() { return 0xFFFFFF80FFFFFF80ULL; }
+};
+#endif  // WCHAR_T_IS_UTF32
+
+}  // namespace
+
+namespace base {
+
+bool IsWprintfFormatPortable(const wchar_t* format) {
+  for (const wchar_t* position = format; *position != '\0'; ++position) {
+    if (*position == '%') {
+      bool in_specification = true;
+      bool modifier_l = false;
+      while (in_specification) {
+        // Eat up characters until reaching a known specifier.
+        if (*++position == '\0') {
+          // The format string ended in the middle of a specification.  Call
+          // it portable because no unportable specifications were found.  The
+          // string is equally broken on all platforms.
+          return true;
+        }
+
+        if (*position == 'l') {
+          // 'l' is the only thing that can save the 's' and 'c' specifiers.
+          modifier_l = true;
+        } else if (((*position == 's' || *position == 'c') && !modifier_l) ||
+                   *position == 'S' || *position == 'C' || *position == 'F' ||
+                   *position == 'D' || *position == 'O' || *position == 'U') {
+          // Not portable.
+          return false;
+        }
+
+        if (wcschr(L"diouxXeEfgGaAcspn%", *position)) {
+          // Portable, keep scanning the rest of the format string.
+          in_specification = false;
+        }
+      }
+    }
+  }
+
+  return true;
+}
+
+const std::string& EmptyString() {
+  return EmptyStrings::GetInstance()->s;
+}
+
+const string16& EmptyString16() {
+  return EmptyStrings::GetInstance()->s16;
+}
+
+template<typename STR>
+bool ReplaceCharsT(const STR& input,
+                   const STR& replace_chars,
+                   const STR& replace_with,
+                   STR* output) {
+  bool removed = false;
+  size_t replace_length = replace_with.length();
+
+  *output = input;
+
+  size_t found = output->find_first_of(replace_chars);
+  while (found != STR::npos) {
+    removed = true;
+    output->replace(found, 1, replace_with);
+    found = output->find_first_of(replace_chars, found + replace_length);
+  }
+
+  return removed;
+}
+
+bool ReplaceChars(const string16& input,
+                  const base::StringPiece16& replace_chars,
+                  const string16& replace_with,
+                  string16* output) {
+  return ReplaceCharsT(input, replace_chars.as_string(), replace_with, output);
+}
+
+bool ReplaceChars(const std::string& input,
+                  const base::StringPiece& replace_chars,
+                  const std::string& replace_with,
+                  std::string* output) {
+  return ReplaceCharsT(input, replace_chars.as_string(), replace_with, output);
+}
+
+bool RemoveChars(const string16& input,
+                 const base::StringPiece16& remove_chars,
+                 string16* output) {
+  return ReplaceChars(input, remove_chars.as_string(), string16(), output);
+}
+
+bool RemoveChars(const std::string& input,
+                 const base::StringPiece& remove_chars,
+                 std::string* output) {
+  return ReplaceChars(input, remove_chars.as_string(), std::string(), output);
+}
+
+template<typename Str>
+TrimPositions TrimStringT(const Str& input,
+                          BasicStringPiece<Str> trim_chars,
+                          TrimPositions positions,
+                          Str* output) {
+  // Find the edges of leading/trailing whitespace as desired. Need to use
+  // a StringPiece version of input to be able to call find* on it with the
+  // StringPiece version of trim_chars (normally the trim_chars will be a
+  // constant so avoid making a copy).
+  BasicStringPiece<Str> input_piece(input);
+  const size_t last_char = input.length() - 1;
+  const size_t first_good_char = (positions & TRIM_LEADING) ?
+      input_piece.find_first_not_of(trim_chars) : 0;
+  const size_t last_good_char = (positions & TRIM_TRAILING) ?
+      input_piece.find_last_not_of(trim_chars) : last_char;
+
+  // When the string was all trimmed, report that we stripped off characters
+  // from whichever position the caller was interested in. For empty input, we
+  // stripped no characters, but we still need to clear |output|.
+  if (input.empty() ||
+      (first_good_char == Str::npos) || (last_good_char == Str::npos)) {
+    bool input_was_empty = input.empty();  // in case output == &input
+    output->clear();
+    return input_was_empty ? TRIM_NONE : positions;
+  }
+
+  // Trim.
+  *output =
+      input.substr(first_good_char, last_good_char - first_good_char + 1);
+
+  // Return where we trimmed from.
+  return static_cast<TrimPositions>(
+      ((first_good_char == 0) ? TRIM_NONE : TRIM_LEADING) |
+      ((last_good_char == last_char) ? TRIM_NONE : TRIM_TRAILING));
+}
+
+bool TrimString(const string16& input,
+                base::StringPiece16 trim_chars,
+                string16* output) {
+  return TrimStringT(input, trim_chars, TRIM_ALL, output) != TRIM_NONE;
+}
+
+bool TrimString(const std::string& input,
+                base::StringPiece trim_chars,
+                std::string* output) {
+  return TrimStringT(input, trim_chars, TRIM_ALL, output) != TRIM_NONE;
+}
+
+template<typename Str>
+BasicStringPiece<Str> TrimStringPieceT(BasicStringPiece<Str> input,
+                                       BasicStringPiece<Str> trim_chars,
+                                       TrimPositions positions) {
+  size_t begin = (positions & TRIM_LEADING) ?
+      input.find_first_not_of(trim_chars) : 0;
+  size_t end = (positions & TRIM_TRAILING) ?
+      input.find_last_not_of(trim_chars) + 1 : input.size();
+  return input.substr(begin, end - begin);
+}
+
+StringPiece16 TrimString(StringPiece16 input,
+                         const base::StringPiece16& trim_chars,
+                         TrimPositions positions) {
+  return TrimStringPieceT(input, trim_chars, positions);
+}
+
+StringPiece TrimString(StringPiece input,
+                       const base::StringPiece& trim_chars,
+                       TrimPositions positions) {
+  return TrimStringPieceT(input, trim_chars, positions);
+}
+
+void TruncateUTF8ToByteSize(const std::string& input,
+                            const size_t byte_size,
+                            std::string* output) {
+  DCHECK(output);
+  if (byte_size > input.length()) {
+    *output = input;
+    return;
+  }
+  DCHECK_LE(byte_size, static_cast<uint32>(kint32max));
+  // Note: This cast is necessary because CBU8_NEXT uses int32s.
+  int32 truncation_length = static_cast<int32>(byte_size);
+  int32 char_index = truncation_length - 1;
+  const char* data = input.data();
+
+  // Using CBU8, we will move backwards from the truncation point
+  // to the beginning of the string looking for a valid UTF8
+  // character.  Once a full UTF8 character is found, we will
+  // truncate the string to the end of that character.
+  while (char_index >= 0) {
+    int32 prev = char_index;
+    base_icu::UChar32 code_point = 0;
+    CBU8_NEXT(data, char_index, truncation_length, code_point);
+    if (!IsValidCharacter(code_point) ||
+        !IsValidCodepoint(code_point)) {
+      char_index = prev - 1;
+    } else {
+      break;
+    }
+  }
+
+  if (char_index >= 0 )
+    *output = input.substr(0, char_index);
+  else
+    output->clear();
+}
+
+TrimPositions TrimWhitespace(const string16& input,
+                             TrimPositions positions,
+                             string16* output) {
+  return TrimStringT(input, StringPiece16(kWhitespaceUTF16), positions, output);
+}
+
+TrimPositions TrimWhitespaceASCII(const std::string& input,
+                                  TrimPositions positions,
+                                  std::string* output) {
+  return TrimStringT(input, StringPiece(kWhitespaceASCII), positions, output);
+}
+
+// This function is only for backward-compatibility.
+// To be removed when all callers are updated.
+TrimPositions TrimWhitespace(const std::string& input,
+                             TrimPositions positions,
+                             std::string* output) {
+  return TrimWhitespaceASCII(input, positions, output);
+}
+
+template<typename STR>
+STR CollapseWhitespaceT(const STR& text,
+                        bool trim_sequences_with_line_breaks) {
+  STR result;
+  result.resize(text.size());
+
+  // Set flags to pretend we're already in a trimmed whitespace sequence, so we
+  // will trim any leading whitespace.
+  bool in_whitespace = true;
+  bool already_trimmed = true;
+
+  int chars_written = 0;
+  for (typename STR::const_iterator i(text.begin()); i != text.end(); ++i) {
+    if (IsWhitespace(*i)) {
+      if (!in_whitespace) {
+        // Reduce all whitespace sequences to a single space.
+        in_whitespace = true;
+        result[chars_written++] = L' ';
+      }
+      if (trim_sequences_with_line_breaks && !already_trimmed &&
+          ((*i == '\n') || (*i == '\r'))) {
+        // Whitespace sequences containing CR or LF are eliminated entirely.
+        already_trimmed = true;
+        --chars_written;
+      }
+    } else {
+      // Non-whitespace chracters are copied straight across.
+      in_whitespace = false;
+      already_trimmed = false;
+      result[chars_written++] = *i;
+    }
+  }
+
+  if (in_whitespace && !already_trimmed) {
+    // Any trailing whitespace is eliminated.
+    --chars_written;
+  }
+
+  result.resize(chars_written);
+  return result;
+}
+
+string16 CollapseWhitespace(const string16& text,
+                            bool trim_sequences_with_line_breaks) {
+  return CollapseWhitespaceT(text, trim_sequences_with_line_breaks);
+}
+
+std::string CollapseWhitespaceASCII(const std::string& text,
+                                    bool trim_sequences_with_line_breaks) {
+  return CollapseWhitespaceT(text, trim_sequences_with_line_breaks);
+}
+
+bool ContainsOnlyChars(const StringPiece& input,
+                       const StringPiece& characters) {
+  return input.find_first_not_of(characters) == StringPiece::npos;
+}
+
+bool ContainsOnlyChars(const StringPiece16& input,
+                       const StringPiece16& characters) {
+  return input.find_first_not_of(characters) == StringPiece16::npos;
+}
+
+template <class Char>
+inline bool DoIsStringASCII(const Char* characters, size_t length) {
+  MachineWord all_char_bits = 0;
+  const Char* end = characters + length;
+
+  // Prologue: align the input.
+  while (!IsAlignedToMachineWord(characters) && characters != end) {
+    all_char_bits |= *characters;
+    ++characters;
+  }
+
+  // Compare the values of CPU word size.
+  const Char* word_end = AlignToMachineWord(end);
+  const size_t loop_increment = sizeof(MachineWord) / sizeof(Char);
+  while (characters < word_end) {
+    all_char_bits |= *(reinterpret_cast<const MachineWord*>(characters));
+    characters += loop_increment;
+  }
+
+  // Process the remaining bytes.
+  while (characters != end) {
+    all_char_bits |= *characters;
+    ++characters;
+  }
+
+  MachineWord non_ascii_bit_mask =
+      NonASCIIMask<sizeof(MachineWord), Char>::value();
+  return !(all_char_bits & non_ascii_bit_mask);
+}
+
+bool IsStringASCII(const StringPiece& str) {
+  return DoIsStringASCII(str.data(), str.length());
+}
+
+bool IsStringASCII(const StringPiece16& str) {
+  return DoIsStringASCII(str.data(), str.length());
+}
+
+bool IsStringASCII(const string16& str) {
+  return DoIsStringASCII(str.data(), str.length());
+}
+
+#if defined(WCHAR_T_IS_UTF32)
+bool IsStringASCII(const std::wstring& str) {
+  return DoIsStringASCII(str.data(), str.length());
+}
+#endif
+
+bool IsStringUTF8(const StringPiece& str) {
+  const char *src = str.data();
+  int32 src_len = static_cast<int32>(str.length());
+  int32 char_index = 0;
+
+  while (char_index < src_len) {
+    int32 code_point;
+    CBU8_NEXT(src, char_index, src_len, code_point);
+    if (!IsValidCharacter(code_point))
+      return false;
+  }
+  return true;
+}
+
+template<typename Iter>
+static inline bool DoLowerCaseEqualsASCII(Iter a_begin,
+                                          Iter a_end,
+                                          const char* b) {
+  for (Iter it = a_begin; it != a_end; ++it, ++b) {
+    if (!*b || ToLowerASCII(*it) != *b)
+      return false;
+  }
+  return *b == 0;
+}
+
+// Front-ends for LowerCaseEqualsASCII.
+bool LowerCaseEqualsASCII(const std::string& a, const char* b) {
+  return DoLowerCaseEqualsASCII(a.begin(), a.end(), b);
+}
+
+bool LowerCaseEqualsASCII(const string16& a, const char* b) {
+  return DoLowerCaseEqualsASCII(a.begin(), a.end(), b);
+}
+
+bool LowerCaseEqualsASCII(std::string::const_iterator a_begin,
+                          std::string::const_iterator a_end,
+                          const char* b) {
+  return DoLowerCaseEqualsASCII(a_begin, a_end, b);
+}
+
+bool LowerCaseEqualsASCII(string16::const_iterator a_begin,
+                          string16::const_iterator a_end,
+                          const char* b) {
+  return DoLowerCaseEqualsASCII(a_begin, a_end, b);
+}
+
+bool LowerCaseEqualsASCII(const char* a_begin,
+                          const char* a_end,
+                          const char* b) {
+  return DoLowerCaseEqualsASCII(a_begin, a_end, b);
+}
+
+bool LowerCaseEqualsASCII(const char* a_begin,
+                          const char* a_end,
+                          const char* b_begin,
+                          const char* b_end) {
+  while (a_begin != a_end && b_begin != b_end &&
+         ToLowerASCII(*a_begin) == *b_begin) {
+    a_begin++;
+    b_begin++;
+  }
+  return a_begin == a_end && b_begin == b_end;
+}
+
+bool LowerCaseEqualsASCII(const char16* a_begin,
+                          const char16* a_end,
+                          const char* b) {
+  return DoLowerCaseEqualsASCII(a_begin, a_end, b);
+}
+
+bool EqualsASCII(const string16& a, const StringPiece& b) {
+  if (a.length() != b.length())
+    return false;
+  return std::equal(b.begin(), b.end(), a.begin());
+}
+
+bool StartsWithASCII(const std::string& str,
+                     const std::string& search,
+                     bool case_sensitive) {
+  if (case_sensitive)
+    return str.compare(0, search.length(), search) == 0;
+  else
+    return base::strncasecmp(str.c_str(), search.c_str(), search.length()) == 0;
+}
+
+bool StartsWith(const string16& str,
+                const string16& search,
+                bool case_sensitive) {
+  if (case_sensitive) {
+    return str.compare(0, search.length(), search) == 0;
+  }
+  if (search.size() > str.size())
+    return false;
+  return std::equal(search.begin(), search.end(), str.begin(),
+                    CaseInsensitiveCompare<char16>());
+}
+
+template <typename STR>
+bool EndsWithT(const STR& str, const STR& search, bool case_sensitive) {
+  size_t str_length = str.length();
+  size_t search_length = search.length();
+  if (search_length > str_length)
+    return false;
+  if (case_sensitive)
+    return str.compare(str_length - search_length, search_length, search) == 0;
+  return std::equal(search.begin(), search.end(),
+                    str.begin() + (str_length - search_length),
+                    base::CaseInsensitiveCompare<typename STR::value_type>());
+}
+
+bool EndsWith(const std::string& str, const std::string& search,
+              bool case_sensitive) {
+  return EndsWithT(str, search, case_sensitive);
+}
+
+bool EndsWith(const string16& str, const string16& search,
+              bool case_sensitive) {
+  return EndsWithT(str, search, case_sensitive);
+}
+
+}  // namespace base
+
+static const char* const kByteStringsUnlocalized[] = {
+  " B",
+  " kB",
+  " MB",
+  " GB",
+  " TB",
+  " PB"
+};
+
+string16 FormatBytesUnlocalized(int64 bytes) {
+  double unit_amount = static_cast<double>(bytes);
+  size_t dimension = 0;
+  const int kKilo = 1024;
+  while (unit_amount >= kKilo &&
+         dimension < arraysize(kByteStringsUnlocalized) - 1) {
+    unit_amount /= kKilo;
+    dimension++;
+  }
+
+  char buf[64];
+  if (bytes != 0 && dimension > 0 && unit_amount < 100) {
+    base::snprintf(buf, arraysize(buf), "%.1lf%s", unit_amount,
+                   kByteStringsUnlocalized[dimension]);
+  } else {
+    base::snprintf(buf, arraysize(buf), "%.0lf%s", unit_amount,
+                   kByteStringsUnlocalized[dimension]);
+  }
+
+  return base::ASCIIToUTF16(buf);
+}
+
+// Runs in O(n) time in the length of |str|.
+template<class StringType>
+void DoReplaceSubstringsAfterOffset(StringType* str,
+                                    size_t offset,
+                                    const StringType& find_this,
+                                    const StringType& replace_with,
+                                    bool replace_all) {
+  DCHECK(!find_this.empty());
+
+  // If the find string doesn't appear, there's nothing to do.
+  offset = str->find(find_this, offset);
+  if (offset == StringType::npos)
+    return;
+
+  // If we're only replacing one instance, there's no need to do anything
+  // complicated.
+  size_t find_length = find_this.length();
+  if (!replace_all) {
+    str->replace(offset, find_length, replace_with);
+    return;
+  }
+
+  // If the find and replace strings are the same length, we can simply use
+  // replace() on each instance, and finish the entire operation in O(n) time.
+  size_t replace_length = replace_with.length();
+  if (find_length == replace_length) {
+    do {
+      str->replace(offset, find_length, replace_with);
+      offset = str->find(find_this, offset + replace_length);
+    } while (offset != StringType::npos);
+    return;
+  }
+
+  // Since the find and replace strings aren't the same length, a loop like the
+  // one above would be O(n^2) in the worst case, as replace() will shift the
+  // entire remaining string each time.  We need to be more clever to keep
+  // things O(n).
+  //
+  // If we're shortening the string, we can alternate replacements with shifting
+  // forward the intervening characters using memmove().
+  size_t str_length = str->length();
+  if (find_length > replace_length) {
+    size_t write_offset = offset;
+    do {
+      if (replace_length) {
+        str->replace(write_offset, replace_length, replace_with);
+        write_offset += replace_length;
+      }
+      size_t read_offset = offset + find_length;
+      offset = std::min(str->find(find_this, read_offset), str_length);
+      size_t length = offset - read_offset;
+      if (length) {
+        memmove(&(*str)[write_offset], &(*str)[read_offset],
+                length * sizeof(typename StringType::value_type));
+        write_offset += length;
+      }
+    } while (offset < str_length);
+    str->resize(write_offset);
+    return;
+  }
+
+  // We're lengthening the string.  We can use alternating replacements and
+  // memmove() calls like above, but we need to precalculate the final string
+  // length and then expand from back-to-front to avoid overwriting the string
+  // as we're reading it, needing to shift, or having to copy to a second string
+  // temporarily.
+  size_t first_match = offset;
+
+  // First, calculate the final length and resize the string.
+  size_t final_length = str_length;
+  size_t expansion = replace_length - find_length;
+  size_t current_match;
+  do {
+    final_length += expansion;
+    // Minor optimization: save this offset into |current_match|, so that on
+    // exit from the loop, |current_match| will point at the last instance of
+    // the find string, and we won't need to find() it again immediately.
+    current_match = offset;
+    offset = str->find(find_this, offset + find_length);
+  } while (offset != StringType::npos);
+  str->resize(final_length);
+
+  // Now do the replacement loop, working backwards through the string.
+  for (size_t prev_match = str_length, write_offset = final_length; ;
+       current_match = str->rfind(find_this, current_match - 1)) {
+    size_t read_offset = current_match + find_length;
+    size_t length = prev_match - read_offset;
+    if (length) {
+      write_offset -= length;
+      memmove(&(*str)[write_offset], &(*str)[read_offset],
+              length * sizeof(typename StringType::value_type));
+    }
+    write_offset -= replace_length;
+    str->replace(write_offset, replace_length, replace_with);
+    if (current_match == first_match)
+      return;
+    prev_match = current_match;
+  }
+}
+
+void ReplaceFirstSubstringAfterOffset(string16* str,
+                                      size_t start_offset,
+                                      const string16& find_this,
+                                      const string16& replace_with) {
+  DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with,
+                                 false);  // replace first instance
+}
+
+void ReplaceFirstSubstringAfterOffset(std::string* str,
+                                      size_t start_offset,
+                                      const std::string& find_this,
+                                      const std::string& replace_with) {
+  DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with,
+                                 false);  // replace first instance
+}
+
+void ReplaceSubstringsAfterOffset(string16* str,
+                                  size_t start_offset,
+                                  const string16& find_this,
+                                  const string16& replace_with) {
+  DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with,
+                                 true);  // replace all instances
+}
+
+void ReplaceSubstringsAfterOffset(std::string* str,
+                                  size_t start_offset,
+                                  const std::string& find_this,
+                                  const std::string& replace_with) {
+  DoReplaceSubstringsAfterOffset(str, start_offset, find_this, replace_with,
+                                 true);  // replace all instances
+}
+
+size_t Tokenize(const base::string16& str,
+                const base::string16& delimiters,
+                std::vector<base::string16>* tokens) {
+  *tokens = base::SplitString(
+      str, delimiters, base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+  return tokens->size();
+}
+
+size_t Tokenize(const std::string& str,
+                const std::string& delimiters,
+                std::vector<std::string>* tokens) {
+  *tokens = base::SplitString(
+      str, delimiters, base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+  return tokens->size();
+}
+
+size_t Tokenize(const base::StringPiece& str,
+                const base::StringPiece& delimiters,
+                std::vector<base::StringPiece>* tokens) {
+  *tokens = base::SplitStringPiece(
+      str, delimiters, base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+  return tokens->size();
+}
+
+template<typename STR>
+static STR JoinStringT(const std::vector<STR>& parts, const STR& sep) {
+  if (parts.empty())
+    return STR();
+
+  STR result(parts[0]);
+  typename std::vector<STR>::const_iterator iter = parts.begin();
+  ++iter;
+
+  for (; iter != parts.end(); ++iter) {
+    result += sep;
+    result += *iter;
+  }
+
+  return result;
+}
+
+std::string JoinString(const std::vector<std::string>& parts, char sep) {
+  return JoinStringT(parts, std::string(1, sep));
+}
+
+string16 JoinString(const std::vector<string16>& parts, char16 sep) {
+  return JoinStringT(parts, string16(1, sep));
+}
+
+std::string JoinString(const std::vector<std::string>& parts,
+                       const std::string& separator) {
+  return JoinStringT(parts, separator);
+}
+
+string16 JoinString(const std::vector<string16>& parts,
+                    const string16& separator) {
+  return JoinStringT(parts, separator);
+}
+
+template<class FormatStringType, class OutStringType>
+OutStringType DoReplaceStringPlaceholders(const FormatStringType& format_string,
+    const std::vector<OutStringType>& subst, std::vector<size_t>* offsets) {
+  size_t substitutions = subst.size();
+
+  size_t sub_length = 0;
+  for (typename std::vector<OutStringType>::const_iterator iter = subst.begin();
+       iter != subst.end(); ++iter) {
+    sub_length += iter->length();
+  }
+
+  OutStringType formatted;
+  formatted.reserve(format_string.length() + sub_length);
+
+  std::vector<ReplacementOffset> r_offsets;
+  for (typename FormatStringType::const_iterator i = format_string.begin();
+       i != format_string.end(); ++i) {
+    if ('$' == *i) {
+      if (i + 1 != format_string.end()) {
+        ++i;
+        DCHECK('$' == *i || '1' <= *i) << "Invalid placeholder: " << *i;
+        if ('$' == *i) {
+          while (i != format_string.end() && '$' == *i) {
+            formatted.push_back('$');
+            ++i;
+          }
+          --i;
+        } else {
+          uintptr_t index = 0;
+          while (i != format_string.end() && '0' <= *i && *i <= '9') {
+            index *= 10;
+            index += *i - '0';
+            ++i;
+          }
+          --i;
+          index -= 1;
+          if (offsets) {
+            ReplacementOffset r_offset(index,
+                static_cast<int>(formatted.size()));
+            r_offsets.insert(std::lower_bound(r_offsets.begin(),
+                                              r_offsets.end(),
+                                              r_offset,
+                                              &CompareParameter),
+                             r_offset);
+          }
+          if (index < substitutions)
+            formatted.append(subst.at(index));
+        }
+      }
+    } else {
+      formatted.push_back(*i);
+    }
+  }
+  if (offsets) {
+    for (std::vector<ReplacementOffset>::const_iterator i = r_offsets.begin();
+         i != r_offsets.end(); ++i) {
+      offsets->push_back(i->offset);
+    }
+  }
+  return formatted;
+}
+
+string16 ReplaceStringPlaceholders(const string16& format_string,
+                                   const std::vector<string16>& subst,
+                                   std::vector<size_t>* offsets) {
+  return DoReplaceStringPlaceholders(format_string, subst, offsets);
+}
+
+std::string ReplaceStringPlaceholders(const base::StringPiece& format_string,
+                                      const std::vector<std::string>& subst,
+                                      std::vector<size_t>* offsets) {
+  return DoReplaceStringPlaceholders(format_string, subst, offsets);
+}
+
+string16 ReplaceStringPlaceholders(const string16& format_string,
+                                   const string16& a,
+                                   size_t* offset) {
+  std::vector<size_t> offsets;
+  std::vector<string16> subst;
+  subst.push_back(a);
+  string16 result = ReplaceStringPlaceholders(format_string, subst, &offsets);
+
+  DCHECK_EQ(1U, offsets.size());
+  if (offset)
+    *offset = offsets[0];
+  return result;
+}
+
+static bool IsWildcard(base_icu::UChar32 character) {
+  return character == '*' || character == '?';
+}
+
+// Move the strings pointers to the point where they start to differ.
+template <typename CHAR, typename NEXT>
+static void EatSameChars(const CHAR** pattern, const CHAR* pattern_end,
+                         const CHAR** string, const CHAR* string_end,
+                         NEXT next) {
+  const CHAR* escape = NULL;
+  while (*pattern != pattern_end && *string != string_end) {
+    if (!escape && IsWildcard(**pattern)) {
+      // We don't want to match wildcard here, except if it's escaped.
+      return;
+    }
+
+    // Check if the escapement char is found. If so, skip it and move to the
+    // next character.
+    if (!escape && **pattern == '\\') {
+      escape = *pattern;
+      next(pattern, pattern_end);
+      continue;
+    }
+
+    // Check if the chars match, if so, increment the ptrs.
+    const CHAR* pattern_next = *pattern;
+    const CHAR* string_next = *string;
+    base_icu::UChar32 pattern_char = next(&pattern_next, pattern_end);
+    if (pattern_char == next(&string_next, string_end) &&
+        pattern_char != CBU_SENTINEL) {
+      *pattern = pattern_next;
+      *string = string_next;
+    } else {
+      // Uh oh, it did not match, we are done. If the last char was an
+      // escapement, that means that it was an error to advance the ptr here,
+      // let's put it back where it was. This also mean that the MatchPattern
+      // function will return false because if we can't match an escape char
+      // here, then no one will.
+      if (escape) {
+        *pattern = escape;
+      }
+      return;
+    }
+
+    escape = NULL;
+  }
+}
+
+template <typename CHAR, typename NEXT>
+static void EatWildcard(const CHAR** pattern, const CHAR* end, NEXT next) {
+  while (*pattern != end) {
+    if (!IsWildcard(**pattern))
+      return;
+    next(pattern, end);
+  }
+}
+
+template <typename CHAR, typename NEXT>
+static bool MatchPatternT(const CHAR* eval, const CHAR* eval_end,
+                          const CHAR* pattern, const CHAR* pattern_end,
+                          int depth,
+                          NEXT next) {
+  const int kMaxDepth = 16;
+  if (depth > kMaxDepth)
+    return false;
+
+  // Eat all the matching chars.
+  EatSameChars(&pattern, pattern_end, &eval, eval_end, next);
+
+  // If the string is empty, then the pattern must be empty too, or contains
+  // only wildcards.
+  if (eval == eval_end) {
+    EatWildcard(&pattern, pattern_end, next);
+    return pattern == pattern_end;
+  }
+
+  // Pattern is empty but not string, this is not a match.
+  if (pattern == pattern_end)
+    return false;
+
+  // If this is a question mark, then we need to compare the rest with
+  // the current string or the string with one character eaten.
+  const CHAR* next_pattern = pattern;
+  next(&next_pattern, pattern_end);
+  if (pattern[0] == '?') {
+    if (MatchPatternT(eval, eval_end, next_pattern, pattern_end,
+                      depth + 1, next))
+      return true;
+    const CHAR* next_eval = eval;
+    next(&next_eval, eval_end);
+    if (MatchPatternT(next_eval, eval_end, next_pattern, pattern_end,
+                      depth + 1, next))
+      return true;
+  }
+
+  // This is a *, try to match all the possible substrings with the remainder
+  // of the pattern.
+  if (pattern[0] == '*') {
+    // Collapse duplicate wild cards (********** into *) so that the
+    // method does not recurse unnecessarily. http://crbug.com/52839
+    EatWildcard(&next_pattern, pattern_end, next);
+
+    while (eval != eval_end) {
+      if (MatchPatternT(eval, eval_end, next_pattern, pattern_end,
+                        depth + 1, next))
+        return true;
+      eval++;
+    }
+
+    // We reached the end of the string, let see if the pattern contains only
+    // wildcards.
+    if (eval == eval_end) {
+      EatWildcard(&pattern, pattern_end, next);
+      if (pattern != pattern_end)
+        return false;
+      return true;
+    }
+  }
+
+  return false;
+}
+
+struct NextCharUTF8 {
+  base_icu::UChar32 operator()(const char** p, const char* end) {
+    base_icu::UChar32 c;
+    int offset = 0;
+    CBU8_NEXT(*p, offset, end - *p, c);
+    *p += offset;
+    return c;
+  }
+};
+
+struct NextCharUTF16 {
+  base_icu::UChar32 operator()(const char16** p, const char16* end) {
+    base_icu::UChar32 c;
+    int offset = 0;
+    CBU16_NEXT(*p, offset, end - *p, c);
+    *p += offset;
+    return c;
+  }
+};
+
+bool MatchPattern(const base::StringPiece& eval,
+                  const base::StringPiece& pattern) {
+  return MatchPatternT(eval.data(), eval.data() + eval.size(),
+                       pattern.data(), pattern.data() + pattern.size(),
+                       0, NextCharUTF8());
+}
+
+bool MatchPattern(const string16& eval, const string16& pattern) {
+  return MatchPatternT(eval.c_str(), eval.c_str() + eval.size(),
+                       pattern.c_str(), pattern.c_str() + pattern.size(),
+                       0, NextCharUTF16());
+}
+
+// The following code is compatible with the OpenBSD lcpy interface.  See:
+//   http://www.gratisoft.us/todd/papers/strlcpy.html
+//   ftp://ftp.openbsd.org/pub/OpenBSD/src/lib/libc/string/{wcs,str}lcpy.c
+
+namespace {
+
+template <typename CHAR>
+size_t lcpyT(CHAR* dst, const CHAR* src, size_t dst_size) {
+  for (size_t i = 0; i < dst_size; ++i) {
+    if ((dst[i] = src[i]) == 0)  // We hit and copied the terminating NULL.
+      return i;
+  }
+
+  // We were left off at dst_size.  We over copied 1 byte.  Null terminate.
+  if (dst_size != 0)
+    dst[dst_size - 1] = 0;
+
+  // Count the rest of the |src|, and return it's length in characters.
+  while (src[dst_size]) ++dst_size;
+  return dst_size;
+}
+
+}  // namespace
+
+size_t base::strlcpy(char* dst, const char* src, size_t dst_size) {
+  return lcpyT<char>(dst, src, dst_size);
+}
+size_t base::wcslcpy(wchar_t* dst, const wchar_t* src, size_t dst_size) {
+  return lcpyT<wchar_t>(dst, src, dst_size);
+}
diff --git a/base/strings/string_util.h b/base/strings/string_util.h
new file mode 100644
index 0000000..9628c67
--- /dev/null
+++ b/base/strings/string_util.h
@@ -0,0 +1,527 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// This file defines utility functions for working with strings.
+
+#ifndef BASE_STRINGS_STRING_UTIL_H_
+#define BASE_STRINGS_STRING_UTIL_H_
+
+#include <ctype.h>
+#include <stdarg.h>   // va_list
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"  // For implicit conversions.
+
+namespace base {
+
+// C standard-library functions like "strncasecmp" and "snprintf" that aren't
+// cross-platform are provided as "base::strncasecmp", and their prototypes
+// are listed below.  These functions are then implemented as inline calls
+// to the platform-specific equivalents in the platform-specific headers.
+
+// Compares the two strings s1 and s2 without regard to case using
+// the current locale; returns 0 if they are equal, 1 if s1 > s2, and -1 if
+// s2 > s1 according to a lexicographic comparison.
+int strcasecmp(const char* s1, const char* s2);
+
+// Compares up to count characters of s1 and s2 without regard to case using
+// the current locale; returns 0 if they are equal, 1 if s1 > s2, and -1 if
+// s2 > s1 according to a lexicographic comparison.
+int strncasecmp(const char* s1, const char* s2, size_t count);
+
+// Same as strncmp but for char16 strings.
+int strncmp16(const char16* s1, const char16* s2, size_t count);
+
+// Wrapper for vsnprintf that always null-terminates and always returns the
+// number of characters that would be in an untruncated formatted
+// string, even when truncation occurs.
+int vsnprintf(char* buffer, size_t size, const char* format, va_list arguments)
+    PRINTF_FORMAT(3, 0);
+
+// Some of these implementations need to be inlined.
+
+// We separate the declaration from the implementation of this inline
+// function just so the PRINTF_FORMAT works.
+inline int snprintf(char* buffer, size_t size, const char* format, ...)
+    PRINTF_FORMAT(3, 4);
+inline int snprintf(char* buffer, size_t size, const char* format, ...) {
+  va_list arguments;
+  va_start(arguments, format);
+  int result = vsnprintf(buffer, size, format, arguments);
+  va_end(arguments);
+  return result;
+}
+
+// BSD-style safe and consistent string copy functions.
+// Copies |src| to |dst|, where |dst_size| is the total allocated size of |dst|.
+// Copies at most |dst_size|-1 characters, and always NULL terminates |dst|, as
+// long as |dst_size| is not 0.  Returns the length of |src| in characters.
+// If the return value is >= dst_size, then the output was truncated.
+// NOTE: All sizes are in number of characters, NOT in bytes.
+BASE_EXPORT size_t strlcpy(char* dst, const char* src, size_t dst_size);
+BASE_EXPORT size_t wcslcpy(wchar_t* dst, const wchar_t* src, size_t dst_size);
+
+// Scan a wprintf format string to determine whether it's portable across a
+// variety of systems.  This function only checks that the conversion
+// specifiers used by the format string are supported and have the same meaning
+// on a variety of systems.  It doesn't check for other errors that might occur
+// within a format string.
+//
+// Nonportable conversion specifiers for wprintf are:
+//  - 's' and 'c' without an 'l' length modifier.  %s and %c operate on char
+//     data on all systems except Windows, which treat them as wchar_t data.
+//     Use %ls and %lc for wchar_t data instead.
+//  - 'S' and 'C', which operate on wchar_t data on all systems except Windows,
+//     which treat them as char data.  Use %ls and %lc for wchar_t data
+//     instead.
+//  - 'F', which is not identified by Windows wprintf documentation.
+//  - 'D', 'O', and 'U', which are deprecated and not available on all systems.
+//     Use %ld, %lo, and %lu instead.
+//
+// Note that there is no portable conversion specifier for char data when
+// working with wprintf.
+//
+// This function is intended to be called from base::vswprintf.
+BASE_EXPORT bool IsWprintfFormatPortable(const wchar_t* format);
+
+// ASCII-specific tolower.  The standard library's tolower is locale sensitive,
+// so we don't want to use it here.
+template <class Char> inline Char ToLowerASCII(Char c) {
+  return (c >= 'A' && c <= 'Z') ? (c + ('a' - 'A')) : c;
+}
+
+// ASCII-specific toupper.  The standard library's toupper is locale sensitive,
+// so we don't want to use it here.
+template <class Char> inline Char ToUpperASCII(Char c) {
+  return (c >= 'a' && c <= 'z') ? (c + ('A' - 'a')) : c;
+}
+
+// Function objects to aid in comparing/searching strings.
+
+template<typename Char> struct CaseInsensitiveCompare {
+ public:
+  bool operator()(Char x, Char y) const {
+    // TODO(darin): Do we really want to do locale sensitive comparisons here?
+    // See http://crbug.com/24917
+    return tolower(x) == tolower(y);
+  }
+};
+
+template<typename Char> struct CaseInsensitiveCompareASCII {
+ public:
+  bool operator()(Char x, Char y) const {
+    return ToLowerASCII(x) == ToLowerASCII(y);
+  }
+};
+
+// These threadsafe functions return references to globally unique empty
+// strings.
+//
+// It is likely faster to construct a new empty string object (just a few
+// instructions to set the length to 0) than to get the empty string singleton
+// returned by these functions (which requires threadsafe singleton access).
+//
+// Therefore, DO NOT USE THESE AS A GENERAL-PURPOSE SUBSTITUTE FOR DEFAULT
+// CONSTRUCTORS. There is only one case where you should use these: functions
+// which need to return a string by reference (e.g. as a class member
+// accessor), and don't have an empty string to use (e.g. in an error case).
+// These should not be used as initializers, function arguments, or return
+// values for functions which return by value or outparam.
+BASE_EXPORT const std::string& EmptyString();
+BASE_EXPORT const string16& EmptyString16();
+
+// Contains the set of characters representing whitespace in the corresponding
+// encoding. Null-terminated. The ASCII versions are the whitespaces as defined
+// by HTML5, and don't include control characters.
+BASE_EXPORT extern const wchar_t kWhitespaceWide[];  // Includes Unicode.
+BASE_EXPORT extern const char16 kWhitespaceUTF16[];  // Includes Unicode.
+BASE_EXPORT extern const char kWhitespaceASCII[];
+BASE_EXPORT extern const char16 kWhitespaceASCIIAs16[];  // No unicode.
+
+// Null-terminated string representing the UTF-8 byte order mark.
+BASE_EXPORT extern const char kUtf8ByteOrderMark[];
+
+// Removes characters in |remove_chars| from anywhere in |input|.  Returns true
+// if any characters were removed.  |remove_chars| must be null-terminated.
+// NOTE: Safe to use the same variable for both |input| and |output|.
+BASE_EXPORT bool RemoveChars(const string16& input,
+                             const base::StringPiece16& remove_chars,
+                             string16* output);
+BASE_EXPORT bool RemoveChars(const std::string& input,
+                             const base::StringPiece& remove_chars,
+                             std::string* output);
+
+// Replaces characters in |replace_chars| from anywhere in |input| with
+// |replace_with|.  Each character in |replace_chars| will be replaced with
+// the |replace_with| string.  Returns true if any characters were replaced.
+// |replace_chars| must be null-terminated.
+// NOTE: Safe to use the same variable for both |input| and |output|.
+BASE_EXPORT bool ReplaceChars(const string16& input,
+                              const base::StringPiece16& replace_chars,
+                              const string16& replace_with,
+                              string16* output);
+BASE_EXPORT bool ReplaceChars(const std::string& input,
+                              const base::StringPiece& replace_chars,
+                              const std::string& replace_with,
+                              std::string* output);
+
+enum TrimPositions {
+  TRIM_NONE     = 0,
+  TRIM_LEADING  = 1 << 0,
+  TRIM_TRAILING = 1 << 1,
+  TRIM_ALL      = TRIM_LEADING | TRIM_TRAILING,
+};
+
+// Removes characters in |trim_chars| from the beginning and end of |input|.
+// The 8-bit version only works on 8-bit characters, not UTF-8.
+//
+// It is safe to use the same variable for both |input| and |output| (this is
+// the normal usage to trim in-place).
+BASE_EXPORT bool TrimString(const string16& input,
+                            base::StringPiece16 trim_chars,
+                            string16* output);
+BASE_EXPORT bool TrimString(const std::string& input,
+                            base::StringPiece trim_chars,
+                            std::string* output);
+
+// StringPiece versions of the above. The returned pieces refer to the original
+// buffer.
+BASE_EXPORT StringPiece16 TrimString(StringPiece16 input,
+                                     const base::StringPiece16& trim_chars,
+                                     TrimPositions positions);
+BASE_EXPORT StringPiece TrimString(StringPiece input,
+                                   const base::StringPiece& trim_chars,
+                                   TrimPositions positions);
+
+// Truncates a string to the nearest UTF-8 character that will leave
+// the string less than or equal to the specified byte size.
+BASE_EXPORT void TruncateUTF8ToByteSize(const std::string& input,
+                                        const size_t byte_size,
+                                        std::string* output);
+
+// Trims any whitespace from either end of the input string.  Returns where
+// whitespace was found.
+// The non-wide version has two functions:
+// * TrimWhitespaceASCII()
+//   This function is for ASCII strings and only looks for ASCII whitespace;
+// Please choose the best one according to your usage.
+// NOTE: Safe to use the same variable for both input and output.
+BASE_EXPORT TrimPositions TrimWhitespace(const string16& input,
+                                         TrimPositions positions,
+                                         base::string16* output);
+BASE_EXPORT TrimPositions TrimWhitespaceASCII(const std::string& input,
+                                              TrimPositions positions,
+                                              std::string* output);
+
+// Deprecated. This function is only for backward compatibility and calls
+// TrimWhitespaceASCII().
+BASE_EXPORT TrimPositions TrimWhitespace(const std::string& input,
+                                         TrimPositions positions,
+                                         std::string* output);
+
+// Searches  for CR or LF characters.  Removes all contiguous whitespace
+// strings that contain them.  This is useful when trying to deal with text
+// copied from terminals.
+// Returns |text|, with the following three transformations:
+// (1) Leading and trailing whitespace is trimmed.
+// (2) If |trim_sequences_with_line_breaks| is true, any other whitespace
+//     sequences containing a CR or LF are trimmed.
+// (3) All other whitespace sequences are converted to single spaces.
+BASE_EXPORT string16 CollapseWhitespace(
+    const string16& text,
+    bool trim_sequences_with_line_breaks);
+BASE_EXPORT std::string CollapseWhitespaceASCII(
+    const std::string& text,
+    bool trim_sequences_with_line_breaks);
+
+// Returns true if |input| is empty or contains only characters found in
+// |characters|.
+BASE_EXPORT bool ContainsOnlyChars(const StringPiece& input,
+                                   const StringPiece& characters);
+BASE_EXPORT bool ContainsOnlyChars(const StringPiece16& input,
+                                   const StringPiece16& characters);
+
+// Returns true if the specified string matches the criteria. How can a wide
+// string be 8-bit or UTF8? It contains only characters that are < 256 (in the
+// first case) or characters that use only 8-bits and whose 8-bit
+// representation looks like a UTF-8 string (the second case).
+//
+// Note that IsStringUTF8 checks not only if the input is structurally
+// valid but also if it doesn't contain any non-character codepoint
+// (e.g. U+FFFE). It's done on purpose because all the existing callers want
+// to have the maximum 'discriminating' power from other encodings. If
+// there's a use case for just checking the structural validity, we have to
+// add a new function for that.
+//
+// IsStringASCII assumes the input is likely all ASCII, and does not leave early
+// if it is not the case.
+BASE_EXPORT bool IsStringUTF8(const StringPiece& str);
+BASE_EXPORT bool IsStringASCII(const StringPiece& str);
+BASE_EXPORT bool IsStringASCII(const StringPiece16& str);
+// A convenience adaptor for WebStrings, as they don't convert into
+// StringPieces directly.
+BASE_EXPORT bool IsStringASCII(const string16& str);
+#if defined(WCHAR_T_IS_UTF32)
+BASE_EXPORT bool IsStringASCII(const std::wstring& str);
+#endif
+
+// Converts the elements of the given string.  This version uses a pointer to
+// clearly differentiate it from the non-pointer variant.
+template <class str> inline void StringToLowerASCII(str* s) {
+  for (typename str::iterator i = s->begin(); i != s->end(); ++i)
+    *i = ToLowerASCII(*i);
+}
+
+template <class str> inline str StringToLowerASCII(const str& s) {
+  // for std::string and std::wstring
+  str output(s);
+  StringToLowerASCII(&output);
+  return output;
+}
+
+// Converts the elements of the given string.  This version uses a pointer to
+// clearly differentiate it from the non-pointer variant.
+template <class str> inline void StringToUpperASCII(str* s) {
+  for (typename str::iterator i = s->begin(); i != s->end(); ++i)
+    *i = ToUpperASCII(*i);
+}
+
+template <class str> inline str StringToUpperASCII(const str& s) {
+  // for std::string and std::wstring
+  str output(s);
+  StringToUpperASCII(&output);
+  return output;
+}
+//
+// Compare the lower-case form of the given string against the given ASCII
+// string.  This is useful for doing checking if an input string matches some
+// token, and it is optimized to avoid intermediate string copies.  This API is
+// borrowed from the equivalent APIs in Mozilla.
+BASE_EXPORT bool LowerCaseEqualsASCII(const std::string& a, const char* b);
+BASE_EXPORT bool LowerCaseEqualsASCII(const string16& a, const char* b);
+
+// Same thing, but with string iterators instead.
+BASE_EXPORT bool LowerCaseEqualsASCII(std::string::const_iterator a_begin,
+                                      std::string::const_iterator a_end,
+                                      const char* b);
+BASE_EXPORT bool LowerCaseEqualsASCII(string16::const_iterator a_begin,
+                                      string16::const_iterator a_end,
+                                      const char* b);
+BASE_EXPORT bool LowerCaseEqualsASCII(const char* a_begin,
+                                      const char* a_end,
+                                      const char* b);
+BASE_EXPORT bool LowerCaseEqualsASCII(const char* a_begin,
+                                      const char* a_end,
+                                      const char* b_begin,
+                                      const char* b_end);
+BASE_EXPORT bool LowerCaseEqualsASCII(const char16* a_begin,
+                                      const char16* a_end,
+                                      const char* b);
+
+// Performs a case-sensitive string compare. The behavior is undefined if both
+// strings are not ASCII.
+BASE_EXPORT bool EqualsASCII(const string16& a, const StringPiece& b);
+
+// Returns true if str starts with search, or false otherwise.
+// TODO(brettw) the case sensitive flag makes callsites difficult to read.
+// Consider splitting this out in two variants (few callers want
+// case-insensitive compares) or use an enum that makes this more explicit.
+BASE_EXPORT bool StartsWithASCII(const std::string& str,
+                                 const std::string& search,
+                                 bool case_sensitive);
+BASE_EXPORT bool StartsWith(const base::string16& str,
+                            const base::string16& search,
+                            bool case_sensitive);
+
+// Returns true if str ends with search, or false otherwise.
+// TODO(brettw) case sensitive flag confusion, see StartsWith above.
+BASE_EXPORT bool EndsWith(const std::string& str,
+                          const std::string& search,
+                          bool case_sensitive);
+BASE_EXPORT bool EndsWith(const base::string16& str,
+                          const base::string16& search,
+                          bool case_sensitive);
+
+}  // namespace base
+
+#if defined(OS_WIN)
+#include "base/strings/string_util_win.h"
+#elif defined(OS_POSIX)
+#include "base/strings/string_util_posix.h"
+#else
+#error Define string operations appropriately for your platform
+#endif
+
+// Determines the type of ASCII character, independent of locale (the C
+// library versions will change based on locale).
+template <typename Char>
+inline bool IsAsciiWhitespace(Char c) {
+  return c == ' ' || c == '\r' || c == '\n' || c == '\t';
+}
+template <typename Char>
+inline bool IsAsciiAlpha(Char c) {
+  return ((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z'));
+}
+template <typename Char>
+inline bool IsAsciiDigit(Char c) {
+  return c >= '0' && c <= '9';
+}
+
+template <typename Char>
+inline bool IsHexDigit(Char c) {
+  return (c >= '0' && c <= '9') ||
+         (c >= 'A' && c <= 'F') ||
+         (c >= 'a' && c <= 'f');
+}
+
+template <typename Char>
+inline char HexDigitToInt(Char c) {
+  DCHECK(IsHexDigit(c));
+  if (c >= '0' && c <= '9')
+    return static_cast<char>(c - '0');
+  if (c >= 'A' && c <= 'F')
+    return static_cast<char>(c - 'A' + 10);
+  if (c >= 'a' && c <= 'f')
+    return static_cast<char>(c - 'a' + 10);
+  return 0;
+}
+
+// Returns true if it's a whitespace character.
+inline bool IsWhitespace(wchar_t c) {
+  return wcschr(base::kWhitespaceWide, c) != NULL;
+}
+
+// Return a byte string in human-readable format with a unit suffix. Not
+// appropriate for use in any UI; use of FormatBytes and friends in ui/base is
+// highly recommended instead. TODO(avi): Figure out how to get callers to use
+// FormatBytes instead; remove this.
+BASE_EXPORT base::string16 FormatBytesUnlocalized(int64 bytes);
+
+// Starting at |start_offset| (usually 0), replace the first instance of
+// |find_this| with |replace_with|.
+BASE_EXPORT void ReplaceFirstSubstringAfterOffset(
+    base::string16* str,
+    size_t start_offset,
+    const base::string16& find_this,
+    const base::string16& replace_with);
+BASE_EXPORT void ReplaceFirstSubstringAfterOffset(
+    std::string* str,
+    size_t start_offset,
+    const std::string& find_this,
+    const std::string& replace_with);
+
+// Starting at |start_offset| (usually 0), look through |str| and replace all
+// instances of |find_this| with |replace_with|.
+//
+// This does entire substrings; use std::replace in <algorithm> for single
+// characters, for example:
+//   std::replace(str.begin(), str.end(), 'a', 'b');
+BASE_EXPORT void ReplaceSubstringsAfterOffset(
+    base::string16* str,
+    size_t start_offset,
+    const base::string16& find_this,
+    const base::string16& replace_with);
+BASE_EXPORT void ReplaceSubstringsAfterOffset(std::string* str,
+                                              size_t start_offset,
+                                              const std::string& find_this,
+                                              const std::string& replace_with);
+
+// Reserves enough memory in |str| to accommodate |length_with_null| characters,
+// sets the size of |str| to |length_with_null - 1| characters, and returns a
+// pointer to the underlying contiguous array of characters.  This is typically
+// used when calling a function that writes results into a character array, but
+// the caller wants the data to be managed by a string-like object.  It is
+// convenient in that is can be used inline in the call, and fast in that it
+// avoids copying the results of the call from a char* into a string.
+//
+// |length_with_null| must be at least 2, since otherwise the underlying string
+// would have size 0, and trying to access &((*str)[0]) in that case can result
+// in a number of problems.
+//
+// Internally, this takes linear time because the resize() call 0-fills the
+// underlying array for potentially all
+// (|length_with_null - 1| * sizeof(string_type::value_type)) bytes.  Ideally we
+// could avoid this aspect of the resize() call, as we expect the caller to
+// immediately write over this memory, but there is no other way to set the size
+// of the string, and not doing that will mean people who access |str| rather
+// than str.c_str() will get back a string of whatever size |str| had on entry
+// to this function (probably 0).
+template <class string_type>
+inline typename string_type::value_type* WriteInto(string_type* str,
+                                                   size_t length_with_null) {
+  DCHECK_GT(length_with_null, 1u);
+  str->reserve(length_with_null);
+  str->resize(length_with_null - 1);
+  return &((*str)[0]);
+}
+
+//-----------------------------------------------------------------------------
+
+// Splits a string into its fields delimited by any of the characters in
+// |delimiters|.  Each field is added to the |tokens| vector.  Returns the
+// number of tokens found.
+//
+// DEPRECATED. Use SplitStringUsingSet for new code (these just forward).
+// TODO(brettw) convert callers and delete these forwarders.
+BASE_EXPORT size_t Tokenize(const base::string16& str,
+                            const base::string16& delimiters,
+                            std::vector<base::string16>* tokens);
+BASE_EXPORT size_t Tokenize(const std::string& str,
+                            const std::string& delimiters,
+                            std::vector<std::string>* tokens);
+BASE_EXPORT size_t Tokenize(const base::StringPiece& str,
+                            const base::StringPiece& delimiters,
+                            std::vector<base::StringPiece>* tokens);
+
+// Does the opposite of SplitString().
+BASE_EXPORT base::string16 JoinString(const std::vector<base::string16>& parts,
+                                      base::char16 s);
+BASE_EXPORT std::string JoinString(
+    const std::vector<std::string>& parts, char s);
+
+// Join |parts| using |separator|.
+BASE_EXPORT std::string JoinString(
+    const std::vector<std::string>& parts,
+    const std::string& separator);
+BASE_EXPORT base::string16 JoinString(
+    const std::vector<base::string16>& parts,
+    const base::string16& separator);
+
+// Replace $1-$2-$3..$9 in the format string with |a|-|b|-|c|..|i| respectively.
+// Additionally, any number of consecutive '$' characters is replaced by that
+// number less one. Eg $$->$, $$$->$$, etc. The offsets parameter here can be
+// NULL. This only allows you to use up to nine replacements.
+BASE_EXPORT base::string16 ReplaceStringPlaceholders(
+    const base::string16& format_string,
+    const std::vector<base::string16>& subst,
+    std::vector<size_t>* offsets);
+
+BASE_EXPORT std::string ReplaceStringPlaceholders(
+    const base::StringPiece& format_string,
+    const std::vector<std::string>& subst,
+    std::vector<size_t>* offsets);
+
+// Single-string shortcut for ReplaceStringHolders. |offset| may be NULL.
+BASE_EXPORT base::string16 ReplaceStringPlaceholders(
+    const base::string16& format_string,
+    const base::string16& a,
+    size_t* offset);
+
+// Returns true if the string passed in matches the pattern. The pattern
+// string can contain wildcards like * and ?
+// The backslash character (\) is an escape character for * and ?
+// We limit the patterns to having a max of 16 * or ? characters.
+// ? matches 0 or 1 character, while * matches 0 or more characters.
+BASE_EXPORT bool MatchPattern(const base::StringPiece& string,
+                              const base::StringPiece& pattern);
+BASE_EXPORT bool MatchPattern(const base::string16& string,
+                              const base::string16& pattern);
+
+#endif  // BASE_STRINGS_STRING_UTIL_H_
diff --git a/base/strings/string_util_constants.cc b/base/strings/string_util_constants.cc
new file mode 100644
index 0000000..aba1b12
--- /dev/null
+++ b/base/strings/string_util_constants.cc
@@ -0,0 +1,67 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/string_util.h"
+
+namespace base {
+
+#define WHITESPACE_UNICODE \
+  0x0009, /* CHARACTER TABULATION */      \
+  0x000A, /* LINE FEED (LF) */            \
+  0x000B, /* LINE TABULATION */           \
+  0x000C, /* FORM FEED (FF) */            \
+  0x000D, /* CARRIAGE RETURN (CR) */      \
+  0x0020, /* SPACE */                     \
+  0x0085, /* NEXT LINE (NEL) */           \
+  0x00A0, /* NO-BREAK SPACE */            \
+  0x1680, /* OGHAM SPACE MARK */          \
+  0x2000, /* EN QUAD */                   \
+  0x2001, /* EM QUAD */                   \
+  0x2002, /* EN SPACE */                  \
+  0x2003, /* EM SPACE */                  \
+  0x2004, /* THREE-PER-EM SPACE */        \
+  0x2005, /* FOUR-PER-EM SPACE */         \
+  0x2006, /* SIX-PER-EM SPACE */          \
+  0x2007, /* FIGURE SPACE */              \
+  0x2008, /* PUNCTUATION SPACE */         \
+  0x2009, /* THIN SPACE */                \
+  0x200A, /* HAIR SPACE */                \
+  0x2028, /* LINE SEPARATOR */            \
+  0x2029, /* PARAGRAPH SEPARATOR */       \
+  0x202F, /* NARROW NO-BREAK SPACE */     \
+  0x205F, /* MEDIUM MATHEMATICAL SPACE */ \
+  0x3000, /* IDEOGRAPHIC SPACE */         \
+  0
+
+const wchar_t kWhitespaceWide[] = {
+  WHITESPACE_UNICODE
+};
+
+const char16 kWhitespaceUTF16[] = {
+  WHITESPACE_UNICODE
+};
+
+const char kWhitespaceASCII[] = {
+  0x09,    // CHARACTER TABULATION
+  0x0A,    // LINE FEED (LF)
+  0x0B,    // LINE TABULATION
+  0x0C,    // FORM FEED (FF)
+  0x0D,    // CARRIAGE RETURN (CR)
+  0x20,    // SPACE
+  0
+};
+
+const char16 kWhitespaceASCIIAs16[] = {
+  0x09,    // CHARACTER TABULATION
+  0x0A,    // LINE FEED (LF)
+  0x0B,    // LINE TABULATION
+  0x0C,    // FORM FEED (FF)
+  0x0D,    // CARRIAGE RETURN (CR)
+  0x20,    // SPACE
+  0
+};
+
+const char kUtf8ByteOrderMark[] = "\xEF\xBB\xBF";
+
+}  // namespace base
diff --git a/base/strings/string_util_posix.h b/base/strings/string_util_posix.h
new file mode 100644
index 0000000..f4009d4
--- /dev/null
+++ b/base/strings/string_util_posix.h
@@ -0,0 +1,52 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_STRINGS_STRING_UTIL_POSIX_H_
+#define BASE_STRINGS_STRING_UTIL_POSIX_H_
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <wchar.h>
+
+#include "base/logging.h"
+
+namespace base {
+
+// Chromium code style is to not use malloc'd strings; this is only for use
+// for interaction with APIs that require it.
+inline char* strdup(const char* str) {
+  return ::strdup(str);
+}
+
+inline int strcasecmp(const char* string1, const char* string2) {
+  return ::strcasecmp(string1, string2);
+}
+
+inline int strncasecmp(const char* string1, const char* string2, size_t count) {
+  return ::strncasecmp(string1, string2, count);
+}
+
+inline int vsnprintf(char* buffer, size_t size,
+                     const char* format, va_list arguments) {
+  return ::vsnprintf(buffer, size, format, arguments);
+}
+
+inline int strncmp16(const char16* s1, const char16* s2, size_t count) {
+#if defined(WCHAR_T_IS_UTF16)
+  return ::wcsncmp(s1, s2, count);
+#elif defined(WCHAR_T_IS_UTF32)
+  return c16memcmp(s1, s2, count);
+#endif
+}
+
+inline int vswprintf(wchar_t* buffer, size_t size,
+                     const wchar_t* format, va_list arguments) {
+  DCHECK(IsWprintfFormatPortable(format));
+  return ::vswprintf(buffer, size, format, arguments);
+}
+
+}  // namespace base
+
+#endif  // BASE_STRINGS_STRING_UTIL_POSIX_H_
diff --git a/base/strings/string_util_unittest.cc b/base/strings/string_util_unittest.cc
new file mode 100644
index 0000000..fb0bead
--- /dev/null
+++ b/base/strings/string_util_unittest.cc
@@ -0,0 +1,1235 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/string_util.h"
+
+#include <math.h>
+#include <stdarg.h>
+
+#include <algorithm>
+
+#include "base/basictypes.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::ElementsAre;
+
+namespace base {
+
+static const struct trim_case {
+  const wchar_t* input;
+  const TrimPositions positions;
+  const wchar_t* output;
+  const TrimPositions return_value;
+} trim_cases[] = {
+  {L" Google Video ", TRIM_LEADING, L"Google Video ", TRIM_LEADING},
+  {L" Google Video ", TRIM_TRAILING, L" Google Video", TRIM_TRAILING},
+  {L" Google Video ", TRIM_ALL, L"Google Video", TRIM_ALL},
+  {L"Google Video", TRIM_ALL, L"Google Video", TRIM_NONE},
+  {L"", TRIM_ALL, L"", TRIM_NONE},
+  {L"  ", TRIM_LEADING, L"", TRIM_LEADING},
+  {L"  ", TRIM_TRAILING, L"", TRIM_TRAILING},
+  {L"  ", TRIM_ALL, L"", TRIM_ALL},
+  {L"\t\rTest String\n", TRIM_ALL, L"Test String", TRIM_ALL},
+  {L"\x2002Test String\x00A0\x3000", TRIM_ALL, L"Test String", TRIM_ALL},
+};
+
+static const struct trim_case_ascii {
+  const char* input;
+  const TrimPositions positions;
+  const char* output;
+  const TrimPositions return_value;
+} trim_cases_ascii[] = {
+  {" Google Video ", TRIM_LEADING, "Google Video ", TRIM_LEADING},
+  {" Google Video ", TRIM_TRAILING, " Google Video", TRIM_TRAILING},
+  {" Google Video ", TRIM_ALL, "Google Video", TRIM_ALL},
+  {"Google Video", TRIM_ALL, "Google Video", TRIM_NONE},
+  {"", TRIM_ALL, "", TRIM_NONE},
+  {"  ", TRIM_LEADING, "", TRIM_LEADING},
+  {"  ", TRIM_TRAILING, "", TRIM_TRAILING},
+  {"  ", TRIM_ALL, "", TRIM_ALL},
+  {"\t\rTest String\n", TRIM_ALL, "Test String", TRIM_ALL},
+};
+
+namespace {
+
+// Helper used to test TruncateUTF8ToByteSize.
+bool Truncated(const std::string& input,
+               const size_t byte_size,
+               std::string* output) {
+    size_t prev = input.length();
+    TruncateUTF8ToByteSize(input, byte_size, output);
+    return prev != output->length();
+}
+
+}  // namespace
+
+TEST(StringUtilTest, TruncateUTF8ToByteSize) {
+  std::string output;
+
+  // Empty strings and invalid byte_size arguments
+  EXPECT_FALSE(Truncated(std::string(), 0, &output));
+  EXPECT_EQ(output, "");
+  EXPECT_TRUE(Truncated("\xe1\x80\xbf", 0, &output));
+  EXPECT_EQ(output, "");
+  EXPECT_FALSE(Truncated("\xe1\x80\xbf", static_cast<size_t>(-1), &output));
+  EXPECT_FALSE(Truncated("\xe1\x80\xbf", 4, &output));
+
+  // Testing the truncation of valid UTF8 correctly
+  EXPECT_TRUE(Truncated("abc", 2, &output));
+  EXPECT_EQ(output, "ab");
+  EXPECT_TRUE(Truncated("\xc2\x81\xc2\x81", 2, &output));
+  EXPECT_EQ(output.compare("\xc2\x81"), 0);
+  EXPECT_TRUE(Truncated("\xc2\x81\xc2\x81", 3, &output));
+  EXPECT_EQ(output.compare("\xc2\x81"), 0);
+  EXPECT_FALSE(Truncated("\xc2\x81\xc2\x81", 4, &output));
+  EXPECT_EQ(output.compare("\xc2\x81\xc2\x81"), 0);
+
+  {
+    const char array[] = "\x00\x00\xc2\x81\xc2\x81";
+    const std::string array_string(array, arraysize(array));
+    EXPECT_TRUE(Truncated(array_string, 4, &output));
+    EXPECT_EQ(output.compare(std::string("\x00\x00\xc2\x81", 4)), 0);
+  }
+
+  {
+    const char array[] = "\x00\xc2\x81\xc2\x81";
+    const std::string array_string(array, arraysize(array));
+    EXPECT_TRUE(Truncated(array_string, 4, &output));
+    EXPECT_EQ(output.compare(std::string("\x00\xc2\x81", 3)), 0);
+  }
+
+  // Testing invalid UTF8
+  EXPECT_TRUE(Truncated("\xed\xa0\x80\xed\xbf\xbf", 6, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xed\xa0\x8f", 3, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xed\xbf\xbf", 3, &output));
+  EXPECT_EQ(output.compare(""), 0);
+
+  // Testing invalid UTF8 mixed with valid UTF8
+  EXPECT_FALSE(Truncated("\xe1\x80\xbf", 3, &output));
+  EXPECT_EQ(output.compare("\xe1\x80\xbf"), 0);
+  EXPECT_FALSE(Truncated("\xf1\x80\xa0\xbf", 4, &output));
+  EXPECT_EQ(output.compare("\xf1\x80\xa0\xbf"), 0);
+  EXPECT_FALSE(Truncated("a\xc2\x81\xe1\x80\xbf\xf1\x80\xa0\xbf",
+              10, &output));
+  EXPECT_EQ(output.compare("a\xc2\x81\xe1\x80\xbf\xf1\x80\xa0\xbf"), 0);
+  EXPECT_TRUE(Truncated("a\xc2\x81\xe1\x80\xbf\xf1""a""\x80\xa0",
+              10, &output));
+  EXPECT_EQ(output.compare("a\xc2\x81\xe1\x80\xbf\xf1""a"), 0);
+  EXPECT_FALSE(Truncated("\xef\xbb\xbf" "abc", 6, &output));
+  EXPECT_EQ(output.compare("\xef\xbb\xbf" "abc"), 0);
+
+  // Overlong sequences
+  EXPECT_TRUE(Truncated("\xc0\x80", 2, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xc1\x80\xc1\x81", 4, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xe0\x80\x80", 3, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xe0\x82\x80", 3, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xe0\x9f\xbf", 3, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xf0\x80\x80\x8D", 4, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xf0\x80\x82\x91", 4, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xf0\x80\xa0\x80", 4, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xf0\x8f\xbb\xbf", 4, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xf8\x80\x80\x80\xbf", 5, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xfc\x80\x80\x80\xa0\xa5", 6, &output));
+  EXPECT_EQ(output.compare(""), 0);
+
+  // Beyond U+10FFFF (the upper limit of Unicode codespace)
+  EXPECT_TRUE(Truncated("\xf4\x90\x80\x80", 4, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xf8\xa0\xbf\x80\xbf", 5, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xfc\x9c\xbf\x80\xbf\x80", 6, &output));
+  EXPECT_EQ(output.compare(""), 0);
+
+  // BOMs in UTF-16(BE|LE) and UTF-32(BE|LE)
+  EXPECT_TRUE(Truncated("\xfe\xff", 2, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xff\xfe", 2, &output));
+  EXPECT_EQ(output.compare(""), 0);
+
+  {
+    const char array[] = "\x00\x00\xfe\xff";
+    const std::string array_string(array, arraysize(array));
+    EXPECT_TRUE(Truncated(array_string, 4, &output));
+    EXPECT_EQ(output.compare(std::string("\x00\x00", 2)), 0);
+  }
+
+  // Variants on the previous test
+  {
+    const char array[] = "\xff\xfe\x00\x00";
+    const std::string array_string(array, 4);
+    EXPECT_FALSE(Truncated(array_string, 4, &output));
+    EXPECT_EQ(output.compare(std::string("\xff\xfe\x00\x00", 4)), 0);
+  }
+  {
+    const char array[] = "\xff\x00\x00\xfe";
+    const std::string array_string(array, arraysize(array));
+    EXPECT_TRUE(Truncated(array_string, 4, &output));
+    EXPECT_EQ(output.compare(std::string("\xff\x00\x00", 3)), 0);
+  }
+
+  // Non-characters : U+xxFFF[EF] where xx is 0x00 through 0x10 and <FDD0,FDEF>
+  EXPECT_TRUE(Truncated("\xef\xbf\xbe", 3, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xf0\x8f\xbf\xbe", 4, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xf3\xbf\xbf\xbf", 4, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xef\xb7\x90", 3, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_TRUE(Truncated("\xef\xb7\xaf", 3, &output));
+  EXPECT_EQ(output.compare(""), 0);
+
+  // Strings in legacy encodings that are valid in UTF-8, but
+  // are invalid as UTF-8 in real data.
+  EXPECT_TRUE(Truncated("caf\xe9", 4, &output));
+  EXPECT_EQ(output.compare("caf"), 0);
+  EXPECT_TRUE(Truncated("\xb0\xa1\xb0\xa2", 4, &output));
+  EXPECT_EQ(output.compare(""), 0);
+  EXPECT_FALSE(Truncated("\xa7\x41\xa6\x6e", 4, &output));
+  EXPECT_EQ(output.compare("\xa7\x41\xa6\x6e"), 0);
+  EXPECT_TRUE(Truncated("\xa7\x41\xa6\x6e\xd9\xee\xe4\xee", 7,
+              &output));
+  EXPECT_EQ(output.compare("\xa7\x41\xa6\x6e"), 0);
+
+  // Testing using the same string as input and output.
+  EXPECT_FALSE(Truncated(output, 4, &output));
+  EXPECT_EQ(output.compare("\xa7\x41\xa6\x6e"), 0);
+  EXPECT_TRUE(Truncated(output, 3, &output));
+  EXPECT_EQ(output.compare("\xa7\x41"), 0);
+
+  // "abc" with U+201[CD] in windows-125[0-8]
+  EXPECT_TRUE(Truncated("\x93" "abc\x94", 5, &output));
+  EXPECT_EQ(output.compare("\x93" "abc"), 0);
+
+  // U+0639 U+064E U+0644 U+064E in ISO-8859-6
+  EXPECT_TRUE(Truncated("\xd9\xee\xe4\xee", 4, &output));
+  EXPECT_EQ(output.compare(""), 0);
+
+  // U+03B3 U+03B5 U+03B9 U+03AC in ISO-8859-7
+  EXPECT_TRUE(Truncated("\xe3\xe5\xe9\xdC", 4, &output));
+  EXPECT_EQ(output.compare(""), 0);
+}
+
+TEST(StringUtilTest, TrimWhitespace) {
+  string16 output;  // Allow contents to carry over to next testcase
+  for (size_t i = 0; i < arraysize(trim_cases); ++i) {
+    const trim_case& value = trim_cases[i];
+    EXPECT_EQ(value.return_value,
+              TrimWhitespace(WideToUTF16(value.input), value.positions,
+                             &output));
+    EXPECT_EQ(WideToUTF16(value.output), output);
+  }
+
+  // Test that TrimWhitespace() can take the same string for input and output
+  output = ASCIIToUTF16("  This is a test \r\n");
+  EXPECT_EQ(TRIM_ALL, TrimWhitespace(output, TRIM_ALL, &output));
+  EXPECT_EQ(ASCIIToUTF16("This is a test"), output);
+
+  // Once more, but with a string of whitespace
+  output = ASCIIToUTF16("  \r\n");
+  EXPECT_EQ(TRIM_ALL, TrimWhitespace(output, TRIM_ALL, &output));
+  EXPECT_EQ(string16(), output);
+
+  std::string output_ascii;
+  for (size_t i = 0; i < arraysize(trim_cases_ascii); ++i) {
+    const trim_case_ascii& value = trim_cases_ascii[i];
+    EXPECT_EQ(value.return_value,
+              TrimWhitespace(value.input, value.positions, &output_ascii));
+    EXPECT_EQ(value.output, output_ascii);
+  }
+}
+
+static const struct collapse_case {
+  const wchar_t* input;
+  const bool trim;
+  const wchar_t* output;
+} collapse_cases[] = {
+  {L" Google Video ", false, L"Google Video"},
+  {L"Google Video", false, L"Google Video"},
+  {L"", false, L""},
+  {L"  ", false, L""},
+  {L"\t\rTest String\n", false, L"Test String"},
+  {L"\x2002Test String\x00A0\x3000", false, L"Test String"},
+  {L"    Test     \n  \t String    ", false, L"Test String"},
+  {L"\x2002Test\x1680 \x2028 \tString\x00A0\x3000", false, L"Test String"},
+  {L"   Test String", false, L"Test String"},
+  {L"Test String    ", false, L"Test String"},
+  {L"Test String", false, L"Test String"},
+  {L"", true, L""},
+  {L"\n", true, L""},
+  {L"  \r  ", true, L""},
+  {L"\nFoo", true, L"Foo"},
+  {L"\r  Foo  ", true, L"Foo"},
+  {L" Foo bar ", true, L"Foo bar"},
+  {L"  \tFoo  bar  \n", true, L"Foo bar"},
+  {L" a \r b\n c \r\n d \t\re \t f \n ", true, L"abcde f"},
+};
+
+TEST(StringUtilTest, CollapseWhitespace) {
+  for (size_t i = 0; i < arraysize(collapse_cases); ++i) {
+    const collapse_case& value = collapse_cases[i];
+    EXPECT_EQ(WideToUTF16(value.output),
+              CollapseWhitespace(WideToUTF16(value.input), value.trim));
+  }
+}
+
+static const struct collapse_case_ascii {
+  const char* input;
+  const bool trim;
+  const char* output;
+} collapse_cases_ascii[] = {
+  {" Google Video ", false, "Google Video"},
+  {"Google Video", false, "Google Video"},
+  {"", false, ""},
+  {"  ", false, ""},
+  {"\t\rTest String\n", false, "Test String"},
+  {"    Test     \n  \t String    ", false, "Test String"},
+  {"   Test String", false, "Test String"},
+  {"Test String    ", false, "Test String"},
+  {"Test String", false, "Test String"},
+  {"", true, ""},
+  {"\n", true, ""},
+  {"  \r  ", true, ""},
+  {"\nFoo", true, "Foo"},
+  {"\r  Foo  ", true, "Foo"},
+  {" Foo bar ", true, "Foo bar"},
+  {"  \tFoo  bar  \n", true, "Foo bar"},
+  {" a \r b\n c \r\n d \t\re \t f \n ", true, "abcde f"},
+};
+
+TEST(StringUtilTest, CollapseWhitespaceASCII) {
+  for (size_t i = 0; i < arraysize(collapse_cases_ascii); ++i) {
+    const collapse_case_ascii& value = collapse_cases_ascii[i];
+    EXPECT_EQ(value.output, CollapseWhitespaceASCII(value.input, value.trim));
+  }
+}
+
+TEST(StringUtilTest, IsStringUTF8) {
+  EXPECT_TRUE(IsStringUTF8("abc"));
+  EXPECT_TRUE(IsStringUTF8("\xc2\x81"));
+  EXPECT_TRUE(IsStringUTF8("\xe1\x80\xbf"));
+  EXPECT_TRUE(IsStringUTF8("\xf1\x80\xa0\xbf"));
+  EXPECT_TRUE(IsStringUTF8("a\xc2\x81\xe1\x80\xbf\xf1\x80\xa0\xbf"));
+  EXPECT_TRUE(IsStringUTF8("\xef\xbb\xbf" "abc"));  // UTF-8 BOM
+
+  // surrogate code points
+  EXPECT_FALSE(IsStringUTF8("\xed\xa0\x80\xed\xbf\xbf"));
+  EXPECT_FALSE(IsStringUTF8("\xed\xa0\x8f"));
+  EXPECT_FALSE(IsStringUTF8("\xed\xbf\xbf"));
+
+  // overlong sequences
+  EXPECT_FALSE(IsStringUTF8("\xc0\x80"));  // U+0000
+  EXPECT_FALSE(IsStringUTF8("\xc1\x80\xc1\x81"));  // "AB"
+  EXPECT_FALSE(IsStringUTF8("\xe0\x80\x80"));  // U+0000
+  EXPECT_FALSE(IsStringUTF8("\xe0\x82\x80"));  // U+0080
+  EXPECT_FALSE(IsStringUTF8("\xe0\x9f\xbf"));  // U+07ff
+  EXPECT_FALSE(IsStringUTF8("\xf0\x80\x80\x8D"));  // U+000D
+  EXPECT_FALSE(IsStringUTF8("\xf0\x80\x82\x91"));  // U+0091
+  EXPECT_FALSE(IsStringUTF8("\xf0\x80\xa0\x80"));  // U+0800
+  EXPECT_FALSE(IsStringUTF8("\xf0\x8f\xbb\xbf"));  // U+FEFF (BOM)
+  EXPECT_FALSE(IsStringUTF8("\xf8\x80\x80\x80\xbf"));  // U+003F
+  EXPECT_FALSE(IsStringUTF8("\xfc\x80\x80\x80\xa0\xa5"));  // U+00A5
+
+  // Beyond U+10FFFF (the upper limit of Unicode codespace)
+  EXPECT_FALSE(IsStringUTF8("\xf4\x90\x80\x80"));  // U+110000
+  EXPECT_FALSE(IsStringUTF8("\xf8\xa0\xbf\x80\xbf"));  // 5 bytes
+  EXPECT_FALSE(IsStringUTF8("\xfc\x9c\xbf\x80\xbf\x80"));  // 6 bytes
+
+  // BOMs in UTF-16(BE|LE) and UTF-32(BE|LE)
+  EXPECT_FALSE(IsStringUTF8("\xfe\xff"));
+  EXPECT_FALSE(IsStringUTF8("\xff\xfe"));
+  EXPECT_FALSE(IsStringUTF8(std::string("\x00\x00\xfe\xff", 4)));
+  EXPECT_FALSE(IsStringUTF8("\xff\xfe\x00\x00"));
+
+  // Non-characters : U+xxFFF[EF] where xx is 0x00 through 0x10 and <FDD0,FDEF>
+  EXPECT_FALSE(IsStringUTF8("\xef\xbf\xbe"));  // U+FFFE)
+  EXPECT_FALSE(IsStringUTF8("\xf0\x8f\xbf\xbe"));  // U+1FFFE
+  EXPECT_FALSE(IsStringUTF8("\xf3\xbf\xbf\xbf"));  // U+10FFFF
+  EXPECT_FALSE(IsStringUTF8("\xef\xb7\x90"));  // U+FDD0
+  EXPECT_FALSE(IsStringUTF8("\xef\xb7\xaf"));  // U+FDEF
+  // Strings in legacy encodings. We can certainly make up strings
+  // in a legacy encoding that are valid in UTF-8, but in real data,
+  // most of them are invalid as UTF-8.
+  EXPECT_FALSE(IsStringUTF8("caf\xe9"));  // cafe with U+00E9 in ISO-8859-1
+  EXPECT_FALSE(IsStringUTF8("\xb0\xa1\xb0\xa2"));  // U+AC00, U+AC001 in EUC-KR
+  EXPECT_FALSE(IsStringUTF8("\xa7\x41\xa6\x6e"));  // U+4F60 U+597D in Big5
+  // "abc" with U+201[CD] in windows-125[0-8]
+  EXPECT_FALSE(IsStringUTF8("\x93" "abc\x94"));
+  // U+0639 U+064E U+0644 U+064E in ISO-8859-6
+  EXPECT_FALSE(IsStringUTF8("\xd9\xee\xe4\xee"));
+  // U+03B3 U+03B5 U+03B9 U+03AC in ISO-8859-7
+  EXPECT_FALSE(IsStringUTF8("\xe3\xe5\xe9\xdC"));
+
+  // Check that we support Embedded Nulls. The first uses the canonical UTF-8
+  // representation, and the second uses a 2-byte sequence. The second version
+  // is invalid UTF-8 since UTF-8 states that the shortest encoding for a
+  // given codepoint must be used.
+  static const char kEmbeddedNull[] = "embedded\0null";
+  EXPECT_TRUE(IsStringUTF8(
+      std::string(kEmbeddedNull, sizeof(kEmbeddedNull))));
+  EXPECT_FALSE(IsStringUTF8("embedded\xc0\x80U+0000"));
+}
+
+TEST(StringUtilTest, IsStringASCII) {
+  static char char_ascii[] =
+      "0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF";
+  static char16 char16_ascii[] = {
+      '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'A',
+      'B', 'C', 'D', 'E', 'F', '0', '1', '2', '3', '4', '5', '6',
+      '7', '8', '9', '0', 'A', 'B', 'C', 'D', 'E', 'F', 0 };
+  static std::wstring wchar_ascii(
+      L"0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF");
+
+  // Test a variety of the fragment start positions and lengths in order to make
+  // sure that bit masking in IsStringASCII works correctly.
+  // Also, test that a non-ASCII character will be detected regardless of its
+  // position inside the string.
+  {
+    const size_t string_length = arraysize(char_ascii) - 1;
+    for (size_t offset = 0; offset < 8; ++offset) {
+      for (size_t len = 0, max_len = string_length - offset; len < max_len;
+           ++len) {
+        EXPECT_TRUE(IsStringASCII(StringPiece(char_ascii + offset, len)));
+        for (size_t char_pos = offset; char_pos < len; ++char_pos) {
+          char_ascii[char_pos] |= '\x80';
+          EXPECT_FALSE(IsStringASCII(StringPiece(char_ascii + offset, len)));
+          char_ascii[char_pos] &= ~'\x80';
+        }
+      }
+    }
+  }
+
+  {
+    const size_t string_length = arraysize(char16_ascii) - 1;
+    for (size_t offset = 0; offset < 4; ++offset) {
+      for (size_t len = 0, max_len = string_length - offset; len < max_len;
+           ++len) {
+        EXPECT_TRUE(IsStringASCII(StringPiece16(char16_ascii + offset, len)));
+        for (size_t char_pos = offset; char_pos < len; ++char_pos) {
+          char16_ascii[char_pos] |= 0x80;
+          EXPECT_FALSE(
+              IsStringASCII(StringPiece16(char16_ascii + offset, len)));
+          char16_ascii[char_pos] &= ~0x80;
+          // Also test when the upper half is non-zero.
+          char16_ascii[char_pos] |= 0x100;
+          EXPECT_FALSE(
+              IsStringASCII(StringPiece16(char16_ascii + offset, len)));
+          char16_ascii[char_pos] &= ~0x100;
+        }
+      }
+    }
+  }
+
+  {
+    const size_t string_length = wchar_ascii.length();
+    for (size_t len = 0; len < string_length; ++len) {
+      EXPECT_TRUE(IsStringASCII(wchar_ascii.substr(0, len)));
+      for (size_t char_pos = 0; char_pos < len; ++char_pos) {
+        wchar_ascii[char_pos] |= 0x80;
+        EXPECT_FALSE(
+            IsStringASCII(wchar_ascii.substr(0, len)));
+        wchar_ascii[char_pos] &= ~0x80;
+        wchar_ascii[char_pos] |= 0x100;
+        EXPECT_FALSE(
+            IsStringASCII(wchar_ascii.substr(0, len)));
+        wchar_ascii[char_pos] &= ~0x100;
+#if defined(WCHAR_T_IS_UTF32)
+        wchar_ascii[char_pos] |= 0x10000;
+        EXPECT_FALSE(
+            IsStringASCII(wchar_ascii.substr(0, len)));
+        wchar_ascii[char_pos] &= ~0x10000;
+#endif  // WCHAR_T_IS_UTF32
+      }
+    }
+  }
+}
+
+TEST(StringUtilTest, ConvertASCII) {
+  static const char* const char_cases[] = {
+    "Google Video",
+    "Hello, world\n",
+    "0123ABCDwxyz \a\b\t\r\n!+,.~"
+  };
+
+  static const wchar_t* const wchar_cases[] = {
+    L"Google Video",
+    L"Hello, world\n",
+    L"0123ABCDwxyz \a\b\t\r\n!+,.~"
+  };
+
+  for (size_t i = 0; i < arraysize(char_cases); ++i) {
+    EXPECT_TRUE(IsStringASCII(char_cases[i]));
+    string16 utf16 = ASCIIToUTF16(char_cases[i]);
+    EXPECT_EQ(WideToUTF16(wchar_cases[i]), utf16);
+
+    std::string ascii = UTF16ToASCII(WideToUTF16(wchar_cases[i]));
+    EXPECT_EQ(char_cases[i], ascii);
+  }
+
+  EXPECT_FALSE(IsStringASCII("Google \x80Video"));
+
+  // Convert empty strings.
+  string16 empty16;
+  std::string empty;
+  EXPECT_EQ(empty, UTF16ToASCII(empty16));
+  EXPECT_EQ(empty16, ASCIIToUTF16(empty));
+
+  // Convert strings with an embedded NUL character.
+  const char chars_with_nul[] = "test\0string";
+  const int length_with_nul = arraysize(chars_with_nul) - 1;
+  std::string string_with_nul(chars_with_nul, length_with_nul);
+  string16 string16_with_nul = ASCIIToUTF16(string_with_nul);
+  EXPECT_EQ(static_cast<string16::size_type>(length_with_nul),
+            string16_with_nul.length());
+  std::string narrow_with_nul = UTF16ToASCII(string16_with_nul);
+  EXPECT_EQ(static_cast<std::string::size_type>(length_with_nul),
+            narrow_with_nul.length());
+  EXPECT_EQ(0, string_with_nul.compare(narrow_with_nul));
+}
+
+TEST(StringUtilTest, ToUpperASCII) {
+  EXPECT_EQ('C', ToUpperASCII('C'));
+  EXPECT_EQ('C', ToUpperASCII('c'));
+  EXPECT_EQ('2', ToUpperASCII('2'));
+
+  EXPECT_EQ(L'C', ToUpperASCII(L'C'));
+  EXPECT_EQ(L'C', ToUpperASCII(L'c'));
+  EXPECT_EQ(L'2', ToUpperASCII(L'2'));
+
+  std::string in_place_a("Cc2");
+  StringToUpperASCII(&in_place_a);
+  EXPECT_EQ("CC2", in_place_a);
+
+  std::wstring in_place_w(L"Cc2");
+  StringToUpperASCII(&in_place_w);
+  EXPECT_EQ(L"CC2", in_place_w);
+
+  std::string original_a("Cc2");
+  std::string upper_a = StringToUpperASCII(original_a);
+  EXPECT_EQ("CC2", upper_a);
+
+  std::wstring original_w(L"Cc2");
+  std::wstring upper_w = StringToUpperASCII(original_w);
+  EXPECT_EQ(L"CC2", upper_w);
+}
+
+TEST(StringUtilTest, LowerCaseEqualsASCII) {
+  static const struct {
+    const char*    src_a;
+    const char*    dst;
+  } lowercase_cases[] = {
+    { "FoO", "foo" },
+    { "foo", "foo" },
+    { "FOO", "foo" },
+  };
+
+  for (size_t i = 0; i < arraysize(lowercase_cases); ++i) {
+    EXPECT_TRUE(LowerCaseEqualsASCII(ASCIIToUTF16(lowercase_cases[i].src_a),
+                                     lowercase_cases[i].dst));
+    EXPECT_TRUE(LowerCaseEqualsASCII(lowercase_cases[i].src_a,
+                                     lowercase_cases[i].dst));
+  }
+}
+
+TEST(StringUtilTest, FormatBytesUnlocalized) {
+  static const struct {
+    int64 bytes;
+    const char* expected;
+  } cases[] = {
+    // Expected behavior: we show one post-decimal digit when we have
+    // under two pre-decimal digits, except in cases where it makes no
+    // sense (zero or bytes).
+    // Since we switch units once we cross the 1000 mark, this keeps
+    // the display of file sizes or bytes consistently around three
+    // digits.
+    {0, "0 B"},
+    {512, "512 B"},
+    {1024*1024, "1.0 MB"},
+    {1024*1024*1024, "1.0 GB"},
+    {10LL*1024*1024*1024, "10.0 GB"},
+    {99LL*1024*1024*1024, "99.0 GB"},
+    {105LL*1024*1024*1024, "105 GB"},
+    {105LL*1024*1024*1024 + 500LL*1024*1024, "105 GB"},
+    {~(1LL << 63), "8192 PB"},
+
+    {99*1024 + 103, "99.1 kB"},
+    {1024*1024 + 103, "1.0 MB"},
+    {1024*1024 + 205 * 1024, "1.2 MB"},
+    {1024*1024*1024 + (927 * 1024*1024), "1.9 GB"},
+    {10LL*1024*1024*1024, "10.0 GB"},
+    {100LL*1024*1024*1024, "100 GB"},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    EXPECT_EQ(ASCIIToUTF16(cases[i].expected),
+              FormatBytesUnlocalized(cases[i].bytes));
+  }
+}
+TEST(StringUtilTest, ReplaceSubstringsAfterOffset) {
+  static const struct {
+    const char* str;
+    string16::size_type start_offset;
+    const char* find_this;
+    const char* replace_with;
+    const char* expected;
+  } cases[] = {
+    {"aaa", 0, "a", "b", "bbb"},
+    {"abb", 0, "ab", "a", "ab"},
+    {"Removing some substrings inging", 0, "ing", "", "Remov some substrs "},
+    {"Not found", 0, "x", "0", "Not found"},
+    {"Not found again", 5, "x", "0", "Not found again"},
+    {" Making it much longer ", 0, " ", "Four score and seven years ago",
+     "Four score and seven years agoMakingFour score and seven years agoit"
+     "Four score and seven years agomuchFour score and seven years agolonger"
+     "Four score and seven years ago"},
+    {"Invalid offset", 9999, "t", "foobar", "Invalid offset"},
+    {"Replace me only me once", 9, "me ", "", "Replace me only once"},
+    {"abababab", 2, "ab", "c", "abccc"},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); i++) {
+    string16 str = ASCIIToUTF16(cases[i].str);
+    ReplaceSubstringsAfterOffset(&str, cases[i].start_offset,
+                                 ASCIIToUTF16(cases[i].find_this),
+                                 ASCIIToUTF16(cases[i].replace_with));
+    EXPECT_EQ(ASCIIToUTF16(cases[i].expected), str);
+  }
+}
+
+TEST(StringUtilTest, ReplaceFirstSubstringAfterOffset) {
+  static const struct {
+    const char* str;
+    string16::size_type start_offset;
+    const char* find_this;
+    const char* replace_with;
+    const char* expected;
+  } cases[] = {
+    {"aaa", 0, "a", "b", "baa"},
+    {"abb", 0, "ab", "a", "ab"},
+    {"Removing some substrings inging", 0, "ing", "",
+      "Remov some substrings inging"},
+    {"Not found", 0, "x", "0", "Not found"},
+    {"Not found again", 5, "x", "0", "Not found again"},
+    {" Making it much longer ", 0, " ", "Four score and seven years ago",
+     "Four score and seven years agoMaking it much longer "},
+    {"Invalid offset", 9999, "t", "foobar", "Invalid offset"},
+    {"Replace me only me once", 4, "me ", "", "Replace only me once"},
+    {"abababab", 2, "ab", "c", "abcabab"},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); i++) {
+    string16 str = ASCIIToUTF16(cases[i].str);
+    ReplaceFirstSubstringAfterOffset(&str, cases[i].start_offset,
+                                     ASCIIToUTF16(cases[i].find_this),
+                                     ASCIIToUTF16(cases[i].replace_with));
+    EXPECT_EQ(ASCIIToUTF16(cases[i].expected), str);
+  }
+}
+
+TEST(StringUtilTest, HexDigitToInt) {
+  EXPECT_EQ(0, HexDigitToInt('0'));
+  EXPECT_EQ(1, HexDigitToInt('1'));
+  EXPECT_EQ(2, HexDigitToInt('2'));
+  EXPECT_EQ(3, HexDigitToInt('3'));
+  EXPECT_EQ(4, HexDigitToInt('4'));
+  EXPECT_EQ(5, HexDigitToInt('5'));
+  EXPECT_EQ(6, HexDigitToInt('6'));
+  EXPECT_EQ(7, HexDigitToInt('7'));
+  EXPECT_EQ(8, HexDigitToInt('8'));
+  EXPECT_EQ(9, HexDigitToInt('9'));
+  EXPECT_EQ(10, HexDigitToInt('A'));
+  EXPECT_EQ(11, HexDigitToInt('B'));
+  EXPECT_EQ(12, HexDigitToInt('C'));
+  EXPECT_EQ(13, HexDigitToInt('D'));
+  EXPECT_EQ(14, HexDigitToInt('E'));
+  EXPECT_EQ(15, HexDigitToInt('F'));
+
+  // Verify the lower case as well.
+  EXPECT_EQ(10, HexDigitToInt('a'));
+  EXPECT_EQ(11, HexDigitToInt('b'));
+  EXPECT_EQ(12, HexDigitToInt('c'));
+  EXPECT_EQ(13, HexDigitToInt('d'));
+  EXPECT_EQ(14, HexDigitToInt('e'));
+  EXPECT_EQ(15, HexDigitToInt('f'));
+}
+
+// Test for Tokenize
+template <typename STR>
+void TokenizeTest() {
+  std::vector<STR> r;
+  size_t size;
+
+  size = Tokenize(STR("This is a string"), STR(" "), &r);
+  EXPECT_EQ(4U, size);
+  ASSERT_EQ(4U, r.size());
+  EXPECT_EQ(r[0], STR("This"));
+  EXPECT_EQ(r[1], STR("is"));
+  EXPECT_EQ(r[2], STR("a"));
+  EXPECT_EQ(r[3], STR("string"));
+  r.clear();
+
+  size = Tokenize(STR("one,two,three"), STR(","), &r);
+  EXPECT_EQ(3U, size);
+  ASSERT_EQ(3U, r.size());
+  EXPECT_EQ(r[0], STR("one"));
+  EXPECT_EQ(r[1], STR("two"));
+  EXPECT_EQ(r[2], STR("three"));
+  r.clear();
+
+  size = Tokenize(STR("one,two:three;four"), STR(",:"), &r);
+  EXPECT_EQ(3U, size);
+  ASSERT_EQ(3U, r.size());
+  EXPECT_EQ(r[0], STR("one"));
+  EXPECT_EQ(r[1], STR("two"));
+  EXPECT_EQ(r[2], STR("three;four"));
+  r.clear();
+
+  size = Tokenize(STR("one,two:three;four"), STR(";,:"), &r);
+  EXPECT_EQ(4U, size);
+  ASSERT_EQ(4U, r.size());
+  EXPECT_EQ(r[0], STR("one"));
+  EXPECT_EQ(r[1], STR("two"));
+  EXPECT_EQ(r[2], STR("three"));
+  EXPECT_EQ(r[3], STR("four"));
+  r.clear();
+
+  size = Tokenize(STR("one, two, three"), STR(","), &r);
+  EXPECT_EQ(3U, size);
+  ASSERT_EQ(3U, r.size());
+  EXPECT_EQ(r[0], STR("one"));
+  EXPECT_EQ(r[1], STR(" two"));
+  EXPECT_EQ(r[2], STR(" three"));
+  r.clear();
+
+  size = Tokenize(STR("one, two, three, "), STR(","), &r);
+  EXPECT_EQ(4U, size);
+  ASSERT_EQ(4U, r.size());
+  EXPECT_EQ(r[0], STR("one"));
+  EXPECT_EQ(r[1], STR(" two"));
+  EXPECT_EQ(r[2], STR(" three"));
+  EXPECT_EQ(r[3], STR(" "));
+  r.clear();
+
+  size = Tokenize(STR("one, two, three,"), STR(","), &r);
+  EXPECT_EQ(3U, size);
+  ASSERT_EQ(3U, r.size());
+  EXPECT_EQ(r[0], STR("one"));
+  EXPECT_EQ(r[1], STR(" two"));
+  EXPECT_EQ(r[2], STR(" three"));
+  r.clear();
+
+  size = Tokenize(STR(), STR(","), &r);
+  EXPECT_EQ(0U, size);
+  ASSERT_EQ(0U, r.size());
+  r.clear();
+
+  size = Tokenize(STR(","), STR(","), &r);
+  EXPECT_EQ(0U, size);
+  ASSERT_EQ(0U, r.size());
+  r.clear();
+
+  size = Tokenize(STR(",;:."), STR(".:;,"), &r);
+  EXPECT_EQ(0U, size);
+  ASSERT_EQ(0U, r.size());
+  r.clear();
+
+  size = Tokenize(STR("\t\ta\t"), STR("\t"), &r);
+  EXPECT_EQ(1U, size);
+  ASSERT_EQ(1U, r.size());
+  EXPECT_EQ(r[0], STR("a"));
+  r.clear();
+
+  size = Tokenize(STR("\ta\t\nb\tcc"), STR("\n"), &r);
+  EXPECT_EQ(2U, size);
+  ASSERT_EQ(2U, r.size());
+  EXPECT_EQ(r[0], STR("\ta\t"));
+  EXPECT_EQ(r[1], STR("b\tcc"));
+  r.clear();
+}
+
+TEST(StringUtilTest, TokenizeStdString) {
+  TokenizeTest<std::string>();
+}
+
+TEST(StringUtilTest, TokenizeStringPiece) {
+  TokenizeTest<StringPiece>();
+}
+
+// Test for JoinString
+TEST(StringUtilTest, JoinString) {
+  std::vector<std::string> in;
+  EXPECT_EQ("", JoinString(in, ','));
+
+  in.push_back("a");
+  EXPECT_EQ("a", JoinString(in, ','));
+
+  in.push_back("b");
+  in.push_back("c");
+  EXPECT_EQ("a,b,c", JoinString(in, ','));
+
+  in.push_back(std::string());
+  EXPECT_EQ("a,b,c,", JoinString(in, ','));
+  in.push_back(" ");
+  EXPECT_EQ("a|b|c|| ", JoinString(in, '|'));
+}
+
+// Test for JoinString overloaded with std::string separator
+TEST(StringUtilTest, JoinStringWithString) {
+  std::string separator(", ");
+  std::vector<std::string> parts;
+  EXPECT_EQ(std::string(), JoinString(parts, separator));
+
+  parts.push_back("a");
+  EXPECT_EQ("a", JoinString(parts, separator));
+
+  parts.push_back("b");
+  parts.push_back("c");
+  EXPECT_EQ("a, b, c", JoinString(parts, separator));
+
+  parts.push_back(std::string());
+  EXPECT_EQ("a, b, c, ", JoinString(parts, separator));
+  parts.push_back(" ");
+  EXPECT_EQ("a|b|c|| ", JoinString(parts, "|"));
+}
+
+// Test for JoinString overloaded with string16 separator
+TEST(StringUtilTest, JoinStringWithString16) {
+  string16 separator = ASCIIToUTF16(", ");
+  std::vector<string16> parts;
+  EXPECT_EQ(string16(), JoinString(parts, separator));
+
+  parts.push_back(ASCIIToUTF16("a"));
+  EXPECT_EQ(ASCIIToUTF16("a"), JoinString(parts, separator));
+
+  parts.push_back(ASCIIToUTF16("b"));
+  parts.push_back(ASCIIToUTF16("c"));
+  EXPECT_EQ(ASCIIToUTF16("a, b, c"), JoinString(parts, separator));
+
+  parts.push_back(ASCIIToUTF16(""));
+  EXPECT_EQ(ASCIIToUTF16("a, b, c, "), JoinString(parts, separator));
+  parts.push_back(ASCIIToUTF16(" "));
+  EXPECT_EQ(ASCIIToUTF16("a|b|c|| "), JoinString(parts, ASCIIToUTF16("|")));
+}
+
+TEST(StringUtilTest, StartsWith) {
+  EXPECT_TRUE(StartsWithASCII("javascript:url", "javascript", true));
+  EXPECT_FALSE(StartsWithASCII("JavaScript:url", "javascript", true));
+  EXPECT_TRUE(StartsWithASCII("javascript:url", "javascript", false));
+  EXPECT_TRUE(StartsWithASCII("JavaScript:url", "javascript", false));
+  EXPECT_FALSE(StartsWithASCII("java", "javascript", true));
+  EXPECT_FALSE(StartsWithASCII("java", "javascript", false));
+  EXPECT_FALSE(StartsWithASCII(std::string(), "javascript", false));
+  EXPECT_FALSE(StartsWithASCII(std::string(), "javascript", true));
+  EXPECT_TRUE(StartsWithASCII("java", std::string(), false));
+  EXPECT_TRUE(StartsWithASCII("java", std::string(), true));
+
+  EXPECT_TRUE(StartsWith(ASCIIToUTF16("javascript:url"),
+                         ASCIIToUTF16("javascript"), true));
+  EXPECT_FALSE(StartsWith(ASCIIToUTF16("JavaScript:url"),
+                          ASCIIToUTF16("javascript"), true));
+  EXPECT_TRUE(StartsWith(ASCIIToUTF16("javascript:url"),
+                         ASCIIToUTF16("javascript"), false));
+  EXPECT_TRUE(StartsWith(ASCIIToUTF16("JavaScript:url"),
+                         ASCIIToUTF16("javascript"), false));
+  EXPECT_FALSE(StartsWith(ASCIIToUTF16("java"),
+                          ASCIIToUTF16("javascript"), true));
+  EXPECT_FALSE(StartsWith(ASCIIToUTF16("java"),
+                          ASCIIToUTF16("javascript"), false));
+  EXPECT_FALSE(StartsWith(string16(), ASCIIToUTF16("javascript"), false));
+  EXPECT_FALSE(StartsWith(string16(), ASCIIToUTF16("javascript"), true));
+  EXPECT_TRUE(StartsWith(ASCIIToUTF16("java"), string16(), false));
+  EXPECT_TRUE(StartsWith(ASCIIToUTF16("java"), string16(), true));
+}
+
+TEST(StringUtilTest, EndsWith) {
+  EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.plugin"),
+                       ASCIIToUTF16(".plugin"), true));
+  EXPECT_FALSE(EndsWith(ASCIIToUTF16("Foo.Plugin"),
+                        ASCIIToUTF16(".plugin"), true));
+  EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.plugin"),
+                       ASCIIToUTF16(".plugin"), false));
+  EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.Plugin"),
+                       ASCIIToUTF16(".plugin"), false));
+  EXPECT_FALSE(EndsWith(ASCIIToUTF16(".plug"), ASCIIToUTF16(".plugin"), true));
+  EXPECT_FALSE(EndsWith(ASCIIToUTF16(".plug"), ASCIIToUTF16(".plugin"), false));
+  EXPECT_FALSE(EndsWith(ASCIIToUTF16("Foo.plugin Bar"),
+                        ASCIIToUTF16(".plugin"), true));
+  EXPECT_FALSE(EndsWith(ASCIIToUTF16("Foo.plugin Bar"),
+                        ASCIIToUTF16(".plugin"), false));
+  EXPECT_FALSE(EndsWith(string16(), ASCIIToUTF16(".plugin"), false));
+  EXPECT_FALSE(EndsWith(string16(), ASCIIToUTF16(".plugin"), true));
+  EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.plugin"), string16(), false));
+  EXPECT_TRUE(EndsWith(ASCIIToUTF16("Foo.plugin"), string16(), true));
+  EXPECT_TRUE(EndsWith(ASCIIToUTF16(".plugin"),
+                       ASCIIToUTF16(".plugin"), false));
+  EXPECT_TRUE(EndsWith(ASCIIToUTF16(".plugin"), ASCIIToUTF16(".plugin"), true));
+  EXPECT_TRUE(EndsWith(string16(), string16(), false));
+  EXPECT_TRUE(EndsWith(string16(), string16(), true));
+}
+
+TEST(StringUtilTest, GetStringFWithOffsets) {
+  std::vector<string16> subst;
+  subst.push_back(ASCIIToUTF16("1"));
+  subst.push_back(ASCIIToUTF16("2"));
+  std::vector<size_t> offsets;
+
+  ReplaceStringPlaceholders(ASCIIToUTF16("Hello, $1. Your number is $2."),
+                            subst,
+                            &offsets);
+  EXPECT_EQ(2U, offsets.size());
+  EXPECT_EQ(7U, offsets[0]);
+  EXPECT_EQ(25U, offsets[1]);
+  offsets.clear();
+
+  ReplaceStringPlaceholders(ASCIIToUTF16("Hello, $2. Your number is $1."),
+                            subst,
+                            &offsets);
+  EXPECT_EQ(2U, offsets.size());
+  EXPECT_EQ(25U, offsets[0]);
+  EXPECT_EQ(7U, offsets[1]);
+  offsets.clear();
+}
+
+TEST(StringUtilTest, ReplaceStringPlaceholdersTooFew) {
+  // Test whether replacestringplaceholders works as expected when there
+  // are fewer inputs than outputs.
+  std::vector<string16> subst;
+  subst.push_back(ASCIIToUTF16("9a"));
+  subst.push_back(ASCIIToUTF16("8b"));
+  subst.push_back(ASCIIToUTF16("7c"));
+
+  string16 formatted =
+      ReplaceStringPlaceholders(
+          ASCIIToUTF16("$1a,$2b,$3c,$4d,$5e,$6f,$1g,$2h,$3i"), subst, NULL);
+
+  EXPECT_EQ(formatted, ASCIIToUTF16("9aa,8bb,7cc,d,e,f,9ag,8bh,7ci"));
+}
+
+TEST(StringUtilTest, ReplaceStringPlaceholders) {
+  std::vector<string16> subst;
+  subst.push_back(ASCIIToUTF16("9a"));
+  subst.push_back(ASCIIToUTF16("8b"));
+  subst.push_back(ASCIIToUTF16("7c"));
+  subst.push_back(ASCIIToUTF16("6d"));
+  subst.push_back(ASCIIToUTF16("5e"));
+  subst.push_back(ASCIIToUTF16("4f"));
+  subst.push_back(ASCIIToUTF16("3g"));
+  subst.push_back(ASCIIToUTF16("2h"));
+  subst.push_back(ASCIIToUTF16("1i"));
+
+  string16 formatted =
+      ReplaceStringPlaceholders(
+          ASCIIToUTF16("$1a,$2b,$3c,$4d,$5e,$6f,$7g,$8h,$9i"), subst, NULL);
+
+  EXPECT_EQ(formatted, ASCIIToUTF16("9aa,8bb,7cc,6dd,5ee,4ff,3gg,2hh,1ii"));
+}
+
+TEST(StringUtilTest, ReplaceStringPlaceholdersMoreThan9Replacements) {
+  std::vector<string16> subst;
+  subst.push_back(ASCIIToUTF16("9a"));
+  subst.push_back(ASCIIToUTF16("8b"));
+  subst.push_back(ASCIIToUTF16("7c"));
+  subst.push_back(ASCIIToUTF16("6d"));
+  subst.push_back(ASCIIToUTF16("5e"));
+  subst.push_back(ASCIIToUTF16("4f"));
+  subst.push_back(ASCIIToUTF16("3g"));
+  subst.push_back(ASCIIToUTF16("2h"));
+  subst.push_back(ASCIIToUTF16("1i"));
+  subst.push_back(ASCIIToUTF16("0j"));
+  subst.push_back(ASCIIToUTF16("-1k"));
+  subst.push_back(ASCIIToUTF16("-2l"));
+  subst.push_back(ASCIIToUTF16("-3m"));
+  subst.push_back(ASCIIToUTF16("-4n"));
+
+  string16 formatted =
+      ReplaceStringPlaceholders(
+          ASCIIToUTF16("$1a,$2b,$3c,$4d,$5e,$6f,$7g,$8h,$9i,"
+                       "$10j,$11k,$12l,$13m,$14n,$1"), subst, NULL);
+
+  EXPECT_EQ(formatted, ASCIIToUTF16("9aa,8bb,7cc,6dd,5ee,4ff,3gg,2hh,"
+                                    "1ii,0jj,-1kk,-2ll,-3mm,-4nn,9a"));
+}
+
+TEST(StringUtilTest, StdStringReplaceStringPlaceholders) {
+  std::vector<std::string> subst;
+  subst.push_back("9a");
+  subst.push_back("8b");
+  subst.push_back("7c");
+  subst.push_back("6d");
+  subst.push_back("5e");
+  subst.push_back("4f");
+  subst.push_back("3g");
+  subst.push_back("2h");
+  subst.push_back("1i");
+
+  std::string formatted =
+      ReplaceStringPlaceholders(
+          "$1a,$2b,$3c,$4d,$5e,$6f,$7g,$8h,$9i", subst, NULL);
+
+  EXPECT_EQ(formatted, "9aa,8bb,7cc,6dd,5ee,4ff,3gg,2hh,1ii");
+}
+
+TEST(StringUtilTest, ReplaceStringPlaceholdersConsecutiveDollarSigns) {
+  std::vector<std::string> subst;
+  subst.push_back("a");
+  subst.push_back("b");
+  subst.push_back("c");
+  EXPECT_EQ(ReplaceStringPlaceholders("$$1 $$$2 $$$$3", subst, NULL),
+            "$1 $$2 $$$3");
+}
+
+TEST(StringUtilTest, MatchPatternTest) {
+  EXPECT_TRUE(MatchPattern("www.google.com", "*.com"));
+  EXPECT_TRUE(MatchPattern("www.google.com", "*"));
+  EXPECT_FALSE(MatchPattern("www.google.com", "www*.g*.org"));
+  EXPECT_TRUE(MatchPattern("Hello", "H?l?o"));
+  EXPECT_FALSE(MatchPattern("www.google.com", "http://*)"));
+  EXPECT_FALSE(MatchPattern("www.msn.com", "*.COM"));
+  EXPECT_TRUE(MatchPattern("Hello*1234", "He??o\\*1*"));
+  EXPECT_FALSE(MatchPattern("", "*.*"));
+  EXPECT_TRUE(MatchPattern("", "*"));
+  EXPECT_TRUE(MatchPattern("", "?"));
+  EXPECT_TRUE(MatchPattern("", ""));
+  EXPECT_FALSE(MatchPattern("Hello", ""));
+  EXPECT_TRUE(MatchPattern("Hello*", "Hello*"));
+  // Stop after a certain recursion depth.
+  EXPECT_FALSE(MatchPattern("123456789012345678", "?????????????????*"));
+
+  // Test UTF8 matching.
+  EXPECT_TRUE(MatchPattern("heart: \xe2\x99\xa0", "*\xe2\x99\xa0"));
+  EXPECT_TRUE(MatchPattern("heart: \xe2\x99\xa0.", "heart: ?."));
+  EXPECT_TRUE(MatchPattern("hearts: \xe2\x99\xa0\xe2\x99\xa0", "*"));
+  // Invalid sequences should be handled as a single invalid character.
+  EXPECT_TRUE(MatchPattern("invalid: \xef\xbf\xbe", "invalid: ?"));
+  // If the pattern has invalid characters, it shouldn't match anything.
+  EXPECT_FALSE(MatchPattern("\xf4\x90\x80\x80", "\xf4\x90\x80\x80"));
+
+  // Test UTF16 character matching.
+  EXPECT_TRUE(MatchPattern(UTF8ToUTF16("www.google.com"),
+                           UTF8ToUTF16("*.com")));
+  EXPECT_TRUE(MatchPattern(UTF8ToUTF16("Hello*1234"),
+                           UTF8ToUTF16("He??o\\*1*")));
+
+  // This test verifies that consecutive wild cards are collapsed into 1
+  // wildcard (when this doesn't occur, MatchPattern reaches it's maximum
+  // recursion depth).
+  EXPECT_TRUE(MatchPattern(UTF8ToUTF16("Hello"),
+                           UTF8ToUTF16("He********************************o")));
+}
+
+TEST(StringUtilTest, LcpyTest) {
+  // Test the normal case where we fit in our buffer.
+  {
+    char dst[10];
+    wchar_t wdst[10];
+    EXPECT_EQ(7U, strlcpy(dst, "abcdefg", arraysize(dst)));
+    EXPECT_EQ(0, memcmp(dst, "abcdefg", 8));
+    EXPECT_EQ(7U, wcslcpy(wdst, L"abcdefg", arraysize(wdst)));
+    EXPECT_EQ(0, memcmp(wdst, L"abcdefg", sizeof(wchar_t) * 8));
+  }
+
+  // Test dst_size == 0, nothing should be written to |dst| and we should
+  // have the equivalent of strlen(src).
+  {
+    char dst[2] = {1, 2};
+    wchar_t wdst[2] = {1, 2};
+    EXPECT_EQ(7U, strlcpy(dst, "abcdefg", 0));
+    EXPECT_EQ(1, dst[0]);
+    EXPECT_EQ(2, dst[1]);
+    EXPECT_EQ(7U, wcslcpy(wdst, L"abcdefg", 0));
+    EXPECT_EQ(static_cast<wchar_t>(1), wdst[0]);
+    EXPECT_EQ(static_cast<wchar_t>(2), wdst[1]);
+  }
+
+  // Test the case were we _just_ competely fit including the null.
+  {
+    char dst[8];
+    wchar_t wdst[8];
+    EXPECT_EQ(7U, strlcpy(dst, "abcdefg", arraysize(dst)));
+    EXPECT_EQ(0, memcmp(dst, "abcdefg", 8));
+    EXPECT_EQ(7U, wcslcpy(wdst, L"abcdefg", arraysize(wdst)));
+    EXPECT_EQ(0, memcmp(wdst, L"abcdefg", sizeof(wchar_t) * 8));
+  }
+
+  // Test the case were we we are one smaller, so we can't fit the null.
+  {
+    char dst[7];
+    wchar_t wdst[7];
+    EXPECT_EQ(7U, strlcpy(dst, "abcdefg", arraysize(dst)));
+    EXPECT_EQ(0, memcmp(dst, "abcdef", 7));
+    EXPECT_EQ(7U, wcslcpy(wdst, L"abcdefg", arraysize(wdst)));
+    EXPECT_EQ(0, memcmp(wdst, L"abcdef", sizeof(wchar_t) * 7));
+  }
+
+  // Test the case were we are just too small.
+  {
+    char dst[3];
+    wchar_t wdst[3];
+    EXPECT_EQ(7U, strlcpy(dst, "abcdefg", arraysize(dst)));
+    EXPECT_EQ(0, memcmp(dst, "ab", 3));
+    EXPECT_EQ(7U, wcslcpy(wdst, L"abcdefg", arraysize(wdst)));
+    EXPECT_EQ(0, memcmp(wdst, L"ab", sizeof(wchar_t) * 3));
+  }
+}
+
+TEST(StringUtilTest, WprintfFormatPortabilityTest) {
+  static const struct {
+    const wchar_t* input;
+    bool portable;
+  } cases[] = {
+    { L"%ls", true },
+    { L"%s", false },
+    { L"%S", false },
+    { L"%lS", false },
+    { L"Hello, %s", false },
+    { L"%lc", true },
+    { L"%c", false },
+    { L"%C", false },
+    { L"%lC", false },
+    { L"%ls %s", false },
+    { L"%s %ls", false },
+    { L"%s %ls %s", false },
+    { L"%f", true },
+    { L"%f %F", false },
+    { L"%d %D", false },
+    { L"%o %O", false },
+    { L"%u %U", false },
+    { L"%f %d %o %u", true },
+    { L"%-8d (%02.1f%)", true },
+    { L"% 10s", false },
+    { L"% 10ls", true }
+  };
+  for (size_t i = 0; i < arraysize(cases); ++i)
+    EXPECT_EQ(cases[i].portable, IsWprintfFormatPortable(cases[i].input));
+}
+
+TEST(StringUtilTest, RemoveChars) {
+  const char kRemoveChars[] = "-/+*";
+  std::string input = "A-+bc/d!*";
+  EXPECT_TRUE(RemoveChars(input, kRemoveChars, &input));
+  EXPECT_EQ("Abcd!", input);
+
+  // No characters match kRemoveChars.
+  EXPECT_FALSE(RemoveChars(input, kRemoveChars, &input));
+  EXPECT_EQ("Abcd!", input);
+
+  // Empty string.
+  input.clear();
+  EXPECT_FALSE(RemoveChars(input, kRemoveChars, &input));
+  EXPECT_EQ(std::string(), input);
+}
+
+TEST(StringUtilTest, ReplaceChars) {
+  struct TestData {
+    const char* input;
+    const char* replace_chars;
+    const char* replace_with;
+    const char* output;
+    bool result;
+  } cases[] = {
+    { "", "", "", "", false },
+    { "test", "", "", "test", false },
+    { "test", "", "!", "test", false },
+    { "test", "z", "!", "test", false },
+    { "test", "e", "!", "t!st", true },
+    { "test", "e", "!?", "t!?st", true },
+    { "test", "ez", "!", "t!st", true },
+    { "test", "zed", "!?", "t!?st", true },
+    { "test", "t", "!?", "!?es!?", true },
+    { "test", "et", "!>", "!>!>s!>", true },
+    { "test", "zest", "!", "!!!!", true },
+    { "test", "szt", "!", "!e!!", true },
+    { "test", "t", "test", "testestest", true },
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    std::string output;
+    bool result = ReplaceChars(cases[i].input,
+                               cases[i].replace_chars,
+                               cases[i].replace_with,
+                               &output);
+    EXPECT_EQ(cases[i].result, result);
+    EXPECT_EQ(cases[i].output, output);
+  }
+}
+
+TEST(StringUtilTest, ContainsOnlyChars) {
+  // Providing an empty list of characters should return false but for the empty
+  // string.
+  EXPECT_TRUE(ContainsOnlyChars(std::string(), std::string()));
+  EXPECT_FALSE(ContainsOnlyChars("Hello", std::string()));
+
+  EXPECT_TRUE(ContainsOnlyChars(std::string(), "1234"));
+  EXPECT_TRUE(ContainsOnlyChars("1", "1234"));
+  EXPECT_TRUE(ContainsOnlyChars("1", "4321"));
+  EXPECT_TRUE(ContainsOnlyChars("123", "4321"));
+  EXPECT_FALSE(ContainsOnlyChars("123a", "4321"));
+
+  EXPECT_TRUE(ContainsOnlyChars(std::string(), kWhitespaceASCII));
+  EXPECT_TRUE(ContainsOnlyChars(" ", kWhitespaceASCII));
+  EXPECT_TRUE(ContainsOnlyChars("\t", kWhitespaceASCII));
+  EXPECT_TRUE(ContainsOnlyChars("\t \r \n  ", kWhitespaceASCII));
+  EXPECT_FALSE(ContainsOnlyChars("a", kWhitespaceASCII));
+  EXPECT_FALSE(ContainsOnlyChars("\thello\r \n  ", kWhitespaceASCII));
+
+  EXPECT_TRUE(ContainsOnlyChars(string16(), kWhitespaceUTF16));
+  EXPECT_TRUE(ContainsOnlyChars(ASCIIToUTF16(" "), kWhitespaceUTF16));
+  EXPECT_TRUE(ContainsOnlyChars(ASCIIToUTF16("\t"), kWhitespaceUTF16));
+  EXPECT_TRUE(ContainsOnlyChars(ASCIIToUTF16("\t \r \n  "), kWhitespaceUTF16));
+  EXPECT_FALSE(ContainsOnlyChars(ASCIIToUTF16("a"), kWhitespaceUTF16));
+  EXPECT_FALSE(ContainsOnlyChars(ASCIIToUTF16("\thello\r \n  "),
+                                  kWhitespaceUTF16));
+}
+
+class WriteIntoTest : public testing::Test {
+ protected:
+  static void WritesCorrectly(size_t num_chars) {
+    std::string buffer;
+    char kOriginal[] = "supercali";
+    strncpy(WriteInto(&buffer, num_chars + 1), kOriginal, num_chars);
+    // Using std::string(buffer.c_str()) instead of |buffer| truncates the
+    // string at the first \0.
+    EXPECT_EQ(std::string(kOriginal,
+                          std::min(num_chars, arraysize(kOriginal) - 1)),
+              std::string(buffer.c_str()));
+    EXPECT_EQ(num_chars, buffer.size());
+  }
+};
+
+TEST_F(WriteIntoTest, WriteInto) {
+  // Validate that WriteInto reserves enough space and
+  // sizes a string correctly.
+  WritesCorrectly(1);
+  WritesCorrectly(2);
+  WritesCorrectly(5000);
+
+  // Validate that WriteInto doesn't modify other strings
+  // when using a Copy-on-Write implementation.
+  const char kLive[] = "live";
+  const char kDead[] = "dead";
+  const std::string live = kLive;
+  std::string dead = live;
+  strncpy(WriteInto(&dead, 5), kDead, 4);
+  EXPECT_EQ(kDead, dead);
+  EXPECT_EQ(4u, dead.size());
+  EXPECT_EQ(kLive, live);
+  EXPECT_EQ(4u, live.size());
+}
+
+}  // namespace base
diff --git a/base/strings/string_util_win.h b/base/strings/string_util_win.h
new file mode 100644
index 0000000..61eda20
--- /dev/null
+++ b/base/strings/string_util_win.h
@@ -0,0 +1,55 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_STRINGS_STRING_UTIL_WIN_H_
+#define BASE_STRINGS_STRING_UTIL_WIN_H_
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <wchar.h>
+
+#include "base/logging.h"
+
+namespace base {
+
+// Chromium code style is to not use malloc'd strings; this is only for use
+// for interaction with APIs that require it.
+inline char* strdup(const char* str) {
+  return _strdup(str);
+}
+
+inline int strcasecmp(const char* s1, const char* s2) {
+  return _stricmp(s1, s2);
+}
+
+inline int strncasecmp(const char* s1, const char* s2, size_t count) {
+  return _strnicmp(s1, s2, count);
+}
+
+inline int strncmp16(const char16* s1, const char16* s2, size_t count) {
+  return ::wcsncmp(s1, s2, count);
+}
+
+inline int vsnprintf(char* buffer, size_t size,
+                     const char* format, va_list arguments) {
+  int length = vsnprintf_s(buffer, size, size - 1, format, arguments);
+  if (length < 0)
+    return _vscprintf(format, arguments);
+  return length;
+}
+
+inline int vswprintf(wchar_t* buffer, size_t size,
+                     const wchar_t* format, va_list arguments) {
+  DCHECK(IsWprintfFormatPortable(format));
+
+  int length = _vsnwprintf_s(buffer, size, size - 1, format, arguments);
+  if (length < 0)
+    return _vscwprintf(format, arguments);
+  return length;
+}
+
+}  // namespace base
+
+#endif  // BASE_STRINGS_STRING_UTIL_WIN_H_
diff --git a/base/strings/stringize_macros.h b/base/strings/stringize_macros.h
new file mode 100644
index 0000000..d4e2707
--- /dev/null
+++ b/base/strings/stringize_macros.h
@@ -0,0 +1,31 @@
+// Copyright (c) 2010 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 defines preprocessor macros for stringizing preprocessor
+// symbols (or their output) and manipulating preprocessor symbols
+// that define strings.
+
+#ifndef BASE_STRINGS_STRINGIZE_MACROS_H_
+#define BASE_STRINGS_STRINGIZE_MACROS_H_
+
+#include "build/build_config.h"
+
+// This is not very useful as it does not expand defined symbols if
+// called directly. Use its counterpart without the _NO_EXPANSION
+// suffix, below.
+#define STRINGIZE_NO_EXPANSION(x) #x
+
+// Use this to quote the provided parameter, first expanding it if it
+// is a preprocessor symbol.
+//
+// For example, if:
+//   #define A FOO
+//   #define B(x) myobj->FunctionCall(x)
+//
+// Then:
+//   STRINGIZE(A) produces "FOO"
+//   STRINGIZE(B(y)) produces "myobj->FunctionCall(y)"
+#define STRINGIZE(x) STRINGIZE_NO_EXPANSION(x)
+
+#endif  // BASE_STRINGS_STRINGIZE_MACROS_H_
diff --git a/base/strings/stringize_macros_unittest.cc b/base/strings/stringize_macros_unittest.cc
new file mode 100644
index 0000000..d7f9e56
--- /dev/null
+++ b/base/strings/stringize_macros_unittest.cc
@@ -0,0 +1,29 @@
+// Copyright (c) 2010 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/strings/stringize_macros.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Macros as per documentation in header file.
+#define PREPROCESSOR_UTIL_UNITTEST_A FOO
+#define PREPROCESSOR_UTIL_UNITTEST_B(x) myobj->FunctionCall(x)
+#define PREPROCESSOR_UTIL_UNITTEST_C "foo"
+
+TEST(StringizeTest, Ansi) {
+  EXPECT_STREQ(
+      "PREPROCESSOR_UTIL_UNITTEST_A",
+      STRINGIZE_NO_EXPANSION(PREPROCESSOR_UTIL_UNITTEST_A));
+  EXPECT_STREQ(
+      "PREPROCESSOR_UTIL_UNITTEST_B(y)",
+      STRINGIZE_NO_EXPANSION(PREPROCESSOR_UTIL_UNITTEST_B(y)));
+  EXPECT_STREQ(
+      "PREPROCESSOR_UTIL_UNITTEST_C",
+      STRINGIZE_NO_EXPANSION(PREPROCESSOR_UTIL_UNITTEST_C));
+
+  EXPECT_STREQ("FOO", STRINGIZE(PREPROCESSOR_UTIL_UNITTEST_A));
+  EXPECT_STREQ("myobj->FunctionCall(y)",
+               STRINGIZE(PREPROCESSOR_UTIL_UNITTEST_B(y)));
+  EXPECT_STREQ("\"foo\"", STRINGIZE(PREPROCESSOR_UTIL_UNITTEST_C));
+}
diff --git a/base/strings/stringprintf.cc b/base/strings/stringprintf.cc
new file mode 100644
index 0000000..537873d
--- /dev/null
+++ b/base/strings/stringprintf.cc
@@ -0,0 +1,186 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/stringprintf.h"
+
+#include <errno.h>
+
+#include <vector>
+
+#include "base/scoped_clear_errno.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+
+namespace base {
+
+namespace {
+
+// Overloaded wrappers around vsnprintf and vswprintf. The buf_size parameter
+// is the size of the buffer. These return the number of characters in the
+// formatted string excluding the NUL terminator. If the buffer is not
+// large enough to accommodate the formatted string without truncation, they
+// return the number of characters that would be in the fully-formatted string
+// (vsnprintf, and vswprintf on Windows), or -1 (vswprintf on POSIX platforms).
+inline int vsnprintfT(char* buffer,
+                      size_t buf_size,
+                      const char* format,
+                      va_list argptr) {
+  return base::vsnprintf(buffer, buf_size, format, argptr);
+}
+
+#if defined(OS_WIN)
+inline int vsnprintfT(wchar_t* buffer,
+                      size_t buf_size,
+                      const wchar_t* format,
+                      va_list argptr) {
+  return base::vswprintf(buffer, buf_size, format, argptr);
+}
+#endif
+
+// Templatized backend for StringPrintF/StringAppendF. This does not finalize
+// the va_list, the caller is expected to do that.
+template <class StringType>
+static void StringAppendVT(StringType* dst,
+                           const typename StringType::value_type* format,
+                           va_list ap) {
+  // First try with a small fixed size buffer.
+  // This buffer size should be kept in sync with StringUtilTest.GrowBoundary
+  // and StringUtilTest.StringPrintfBounds.
+  typename StringType::value_type stack_buf[1024];
+
+  va_list ap_copy;
+  va_copy(ap_copy, ap);
+
+#if !defined(OS_WIN)
+  ScopedClearErrno clear_errno;
+#endif
+  int result = vsnprintfT(stack_buf, arraysize(stack_buf), format, ap_copy);
+  va_end(ap_copy);
+
+  if (result >= 0 && result < static_cast<int>(arraysize(stack_buf))) {
+    // It fit.
+    dst->append(stack_buf, result);
+    return;
+  }
+
+  // Repeatedly increase buffer size until it fits.
+  int mem_length = arraysize(stack_buf);
+  while (true) {
+    if (result < 0) {
+#if defined(OS_WIN)
+      // On Windows, vsnprintfT always returns the number of characters in a
+      // fully-formatted string, so if we reach this point, something else is
+      // wrong and no amount of buffer-doubling is going to fix it.
+      return;
+#else
+      if (errno != 0 && errno != EOVERFLOW)
+        return;
+      // Try doubling the buffer size.
+      mem_length *= 2;
+#endif
+    } else {
+      // We need exactly "result + 1" characters.
+      mem_length = result + 1;
+    }
+
+    if (mem_length > 32 * 1024 * 1024) {
+      // That should be plenty, don't try anything larger.  This protects
+      // against huge allocations when using vsnprintfT implementations that
+      // return -1 for reasons other than overflow without setting errno.
+      DLOG(WARNING) << "Unable to printf the requested string due to size.";
+      return;
+    }
+
+    std::vector<typename StringType::value_type> mem_buf(mem_length);
+
+    // NOTE: You can only use a va_list once.  Since we're in a while loop, we
+    // need to make a new copy each time so we don't use up the original.
+    va_copy(ap_copy, ap);
+    result = vsnprintfT(&mem_buf[0], mem_length, format, ap_copy);
+    va_end(ap_copy);
+
+    if ((result >= 0) && (result < mem_length)) {
+      // It fit.
+      dst->append(&mem_buf[0], result);
+      return;
+    }
+  }
+}
+
+}  // namespace
+
+std::string StringPrintf(const char* format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  std::string result;
+  StringAppendV(&result, format, ap);
+  va_end(ap);
+  return result;
+}
+
+#if defined(OS_WIN)
+std::wstring StringPrintf(const wchar_t* format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  std::wstring result;
+  StringAppendV(&result, format, ap);
+  va_end(ap);
+  return result;
+}
+#endif
+
+std::string StringPrintV(const char* format, va_list ap) {
+  std::string result;
+  StringAppendV(&result, format, ap);
+  return result;
+}
+
+const std::string& SStringPrintf(std::string* dst, const char* format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  dst->clear();
+  StringAppendV(dst, format, ap);
+  va_end(ap);
+  return *dst;
+}
+
+#if defined(OS_WIN)
+const std::wstring& SStringPrintf(std::wstring* dst,
+                                  const wchar_t* format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  dst->clear();
+  StringAppendV(dst, format, ap);
+  va_end(ap);
+  return *dst;
+}
+#endif
+
+void StringAppendF(std::string* dst, const char* format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  StringAppendV(dst, format, ap);
+  va_end(ap);
+}
+
+#if defined(OS_WIN)
+void StringAppendF(std::wstring* dst, const wchar_t* format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  StringAppendV(dst, format, ap);
+  va_end(ap);
+}
+#endif
+
+void StringAppendV(std::string* dst, const char* format, va_list ap) {
+  StringAppendVT(dst, format, ap);
+}
+
+#if defined(OS_WIN)
+void StringAppendV(std::wstring* dst, const wchar_t* format, va_list ap) {
+  StringAppendVT(dst, format, ap);
+}
+#endif
+
+}  // namespace base
diff --git a/base/strings/stringprintf.h b/base/strings/stringprintf.h
new file mode 100644
index 0000000..523f7ee
--- /dev/null
+++ b/base/strings/stringprintf.h
@@ -0,0 +1,59 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_STRINGS_STRINGPRINTF_H_
+#define BASE_STRINGS_STRINGPRINTF_H_
+
+#include <stdarg.h>   // va_list
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+
+namespace base {
+
+// Return a C++ string given printf-like input.
+BASE_EXPORT std::string StringPrintf(const char* format, ...)
+    PRINTF_FORMAT(1, 2) WARN_UNUSED_RESULT;
+#if defined(OS_WIN)
+BASE_EXPORT std::wstring StringPrintf(const wchar_t* format, ...)
+    WPRINTF_FORMAT(1, 2) WARN_UNUSED_RESULT;
+#endif
+
+// Return a C++ string given vprintf-like input.
+BASE_EXPORT std::string StringPrintV(const char* format, va_list ap)
+    PRINTF_FORMAT(1, 0) WARN_UNUSED_RESULT;
+
+// Store result into a supplied string and return it.
+BASE_EXPORT const std::string& SStringPrintf(std::string* dst,
+                                             const char* format, ...)
+    PRINTF_FORMAT(2, 3);
+#if defined(OS_WIN)
+BASE_EXPORT const std::wstring& SStringPrintf(std::wstring* dst,
+                                              const wchar_t* format, ...)
+    WPRINTF_FORMAT(2, 3);
+#endif
+
+// Append result to a supplied string.
+BASE_EXPORT void StringAppendF(std::string* dst, const char* format, ...)
+    PRINTF_FORMAT(2, 3);
+#if defined(OS_WIN)
+BASE_EXPORT void StringAppendF(std::wstring* dst, const wchar_t* format, ...)
+    WPRINTF_FORMAT(2, 3);
+#endif
+
+// Lower-level routine that takes a va_list and appends to a specified
+// string.  All other routines are just convenience wrappers around it.
+BASE_EXPORT void StringAppendV(std::string* dst, const char* format, va_list ap)
+    PRINTF_FORMAT(2, 0);
+#if defined(OS_WIN)
+BASE_EXPORT void StringAppendV(std::wstring* dst,
+                               const wchar_t* format, va_list ap)
+    WPRINTF_FORMAT(2, 0);
+#endif
+
+}  // namespace base
+
+#endif  // BASE_STRINGS_STRINGPRINTF_H_
diff --git a/base/strings/stringprintf_unittest.cc b/base/strings/stringprintf_unittest.cc
new file mode 100644
index 0000000..c49637c
--- /dev/null
+++ b/base/strings/stringprintf_unittest.cc
@@ -0,0 +1,176 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/strings/stringprintf.h"
+
+#include <errno.h>
+
+#include "base/basictypes.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+// A helper for the StringAppendV test that follows.
+//
+// Just forwards its args to StringAppendV.
+static void StringAppendVTestHelper(std::string* out, const char* format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  StringAppendV(out, format, ap);
+  va_end(ap);
+}
+
+}  // namespace
+
+TEST(StringPrintfTest, StringPrintfEmpty) {
+  EXPECT_EQ("", StringPrintf("%s", ""));
+}
+
+TEST(StringPrintfTest, StringPrintfMisc) {
+  EXPECT_EQ("123hello w", StringPrintf("%3d%2s %1c", 123, "hello", 'w'));
+#if defined(OS_WIN)
+  EXPECT_EQ(L"123hello w", StringPrintf(L"%3d%2ls %1lc", 123, L"hello", 'w'));
+#endif
+}
+
+TEST(StringPrintfTest, StringAppendfEmptyString) {
+  std::string value("Hello");
+  StringAppendF(&value, "%s", "");
+  EXPECT_EQ("Hello", value);
+
+#if defined(OS_WIN)
+  std::wstring valuew(L"Hello");
+  StringAppendF(&valuew, L"%ls", L"");
+  EXPECT_EQ(L"Hello", valuew);
+#endif
+}
+
+TEST(StringPrintfTest, StringAppendfString) {
+  std::string value("Hello");
+  StringAppendF(&value, " %s", "World");
+  EXPECT_EQ("Hello World", value);
+
+#if defined(OS_WIN)
+  std::wstring valuew(L"Hello");
+  StringAppendF(&valuew, L" %ls", L"World");
+  EXPECT_EQ(L"Hello World", valuew);
+#endif
+}
+
+TEST(StringPrintfTest, StringAppendfInt) {
+  std::string value("Hello");
+  StringAppendF(&value, " %d", 123);
+  EXPECT_EQ("Hello 123", value);
+
+#if defined(OS_WIN)
+  std::wstring valuew(L"Hello");
+  StringAppendF(&valuew, L" %d", 123);
+  EXPECT_EQ(L"Hello 123", valuew);
+#endif
+}
+
+// Make sure that lengths exactly around the initial buffer size are handled
+// correctly.
+TEST(StringPrintfTest, StringPrintfBounds) {
+  const int kSrcLen = 1026;
+  char src[kSrcLen];
+  for (size_t i = 0; i < arraysize(src); i++)
+    src[i] = 'A';
+
+  wchar_t srcw[kSrcLen];
+  for (size_t i = 0; i < arraysize(srcw); i++)
+    srcw[i] = 'A';
+
+  for (int i = 1; i < 3; i++) {
+    src[kSrcLen - i] = 0;
+    std::string out;
+    SStringPrintf(&out, "%s", src);
+    EXPECT_STREQ(src, out.c_str());
+
+#if defined(OS_WIN)
+    srcw[kSrcLen - i] = 0;
+    std::wstring outw;
+    SStringPrintf(&outw, L"%ls", srcw);
+    EXPECT_STREQ(srcw, outw.c_str());
+#endif
+  }
+}
+
+// Test very large sprintfs that will cause the buffer to grow.
+TEST(StringPrintfTest, Grow) {
+  char src[1026];
+  for (size_t i = 0; i < arraysize(src); i++)
+    src[i] = 'A';
+  src[1025] = 0;
+
+  const char fmt[] = "%sB%sB%sB%sB%sB%sB%s";
+
+  std::string out;
+  SStringPrintf(&out, fmt, src, src, src, src, src, src, src);
+
+  const int kRefSize = 320000;
+  char* ref = new char[kRefSize];
+#if defined(OS_WIN)
+  sprintf_s(ref, kRefSize, fmt, src, src, src, src, src, src, src);
+#elif defined(OS_POSIX)
+  snprintf(ref, kRefSize, fmt, src, src, src, src, src, src, src);
+#endif
+
+  EXPECT_STREQ(ref, out.c_str());
+  delete[] ref;
+}
+
+TEST(StringPrintfTest, StringAppendV) {
+  std::string out;
+  StringAppendVTestHelper(&out, "%d foo %s", 1, "bar");
+  EXPECT_EQ("1 foo bar", out);
+}
+
+// Test the boundary condition for the size of the string_util's
+// internal buffer.
+TEST(StringPrintfTest, GrowBoundary) {
+  const int kStringUtilBufLen = 1024;
+  // Our buffer should be one larger than the size of StringAppendVT's stack
+  // buffer.
+  // And need extra one for NULL-terminator.
+  const int kBufLen = kStringUtilBufLen + 1 + 1;
+  char src[kBufLen];
+  for (int i = 0; i < kBufLen - 1; ++i)
+    src[i] = 'a';
+  src[kBufLen - 1] = 0;
+
+  std::string out;
+  SStringPrintf(&out, "%s", src);
+
+  EXPECT_STREQ(src, out.c_str());
+}
+
+// TODO(evanm): what's the proper cross-platform test here?
+#if defined(OS_WIN)
+// sprintf in Visual Studio fails when given U+FFFF. This tests that the
+// failure case is gracefuly handled.
+TEST(StringPrintfTest, Invalid) {
+  wchar_t invalid[2];
+  invalid[0] = 0xffff;
+  invalid[1] = 0;
+
+  std::wstring out;
+  SStringPrintf(&out, L"%ls", invalid);
+  EXPECT_STREQ(L"", out.c_str());
+}
+#endif
+
+// Test that StringPrintf and StringAppendV do not change errno.
+TEST(StringPrintfTest, StringPrintfErrno) {
+  errno = 1;
+  EXPECT_EQ("", StringPrintf("%s", ""));
+  EXPECT_EQ(1, errno);
+  std::string out;
+  StringAppendVTestHelper(&out, "%d foo %s", 1, "bar");
+  EXPECT_EQ(1, errno);
+}
+
+}  // namespace base
diff --git a/base/strings/sys_string_conversions.h b/base/strings/sys_string_conversions.h
new file mode 100644
index 0000000..42f2389
--- /dev/null
+++ b/base/strings/sys_string_conversions.h
@@ -0,0 +1,83 @@
+// Copyright (c) 2012 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_STRINGS_SYS_STRING_CONVERSIONS_H_
+#define BASE_STRINGS_SYS_STRING_CONVERSIONS_H_
+
+// Provides system-dependent string type conversions for cases where it's
+// necessary to not use ICU. Generally, you should not need this in Chrome,
+// but it is used in some shared code. Dependencies should be minimal.
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
+
+#if defined(OS_MACOSX)
+#include <CoreFoundation/CoreFoundation.h>
+#ifdef __OBJC__
+@class NSString;
+#else
+class NSString;
+#endif
+#endif  // OS_MACOSX
+
+namespace base {
+
+// Converts between wide and UTF-8 representations of a string. On error, the
+// result is system-dependent.
+BASE_EXPORT std::string SysWideToUTF8(const std::wstring& wide);
+BASE_EXPORT std::wstring SysUTF8ToWide(const StringPiece& utf8);
+
+// Converts between wide and the system multi-byte representations of a string.
+// DANGER: This will lose information and can change (on Windows, this can
+// change between reboots).
+BASE_EXPORT std::string SysWideToNativeMB(const std::wstring& wide);
+BASE_EXPORT std::wstring SysNativeMBToWide(const StringPiece& native_mb);
+
+// Windows-specific ------------------------------------------------------------
+
+#if defined(OS_WIN)
+
+// Converts between 8-bit and wide strings, using the given code page. The
+// code page identifier is one accepted by the Windows function
+// MultiByteToWideChar().
+BASE_EXPORT std::wstring SysMultiByteToWide(const StringPiece& mb,
+                                            uint32 code_page);
+BASE_EXPORT std::string SysWideToMultiByte(const std::wstring& wide,
+                                           uint32 code_page);
+
+#endif  // defined(OS_WIN)
+
+// Mac-specific ----------------------------------------------------------------
+
+#if defined(OS_MACOSX)
+
+// Converts between STL strings and CFStringRefs/NSStrings.
+
+// Creates a string, and returns it with a refcount of 1. You are responsible
+// for releasing it. Returns NULL on failure.
+BASE_EXPORT CFStringRef SysUTF8ToCFStringRef(const std::string& utf8);
+BASE_EXPORT CFStringRef SysUTF16ToCFStringRef(const string16& utf16);
+
+// Same, but returns an autoreleased NSString.
+BASE_EXPORT NSString* SysUTF8ToNSString(const std::string& utf8);
+BASE_EXPORT NSString* SysUTF16ToNSString(const string16& utf16);
+
+// Converts a CFStringRef to an STL string. Returns an empty string on failure.
+BASE_EXPORT std::string SysCFStringRefToUTF8(CFStringRef ref);
+BASE_EXPORT string16 SysCFStringRefToUTF16(CFStringRef ref);
+
+// Same, but accepts NSString input. Converts nil NSString* to the appropriate
+// string type of length 0.
+BASE_EXPORT std::string SysNSStringToUTF8(NSString* ref);
+BASE_EXPORT string16 SysNSStringToUTF16(NSString* ref);
+
+#endif  // defined(OS_MACOSX)
+
+}  // namespace base
+
+#endif  // BASE_STRINGS_SYS_STRING_CONVERSIONS_H_
diff --git a/base/strings/sys_string_conversions_mac.mm b/base/strings/sys_string_conversions_mac.mm
new file mode 100644
index 0000000..9479e78
--- /dev/null
+++ b/base/strings/sys_string_conversions_mac.mm
@@ -0,0 +1,186 @@
+// Copyright (c) 2012 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/strings/sys_string_conversions.h"
+
+#import <Foundation/Foundation.h>
+
+#include <vector>
+
+#include "base/mac/foundation_util.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+namespace {
+
+// Convert the supplied CFString into the specified encoding, and return it as
+// an STL string of the template type.  Returns an empty string on failure.
+//
+// Do not assert in this function since it is used by the asssertion code!
+template<typename StringType>
+static StringType CFStringToSTLStringWithEncodingT(CFStringRef cfstring,
+                                                   CFStringEncoding encoding) {
+  CFIndex length = CFStringGetLength(cfstring);
+  if (length == 0)
+    return StringType();
+
+  CFRange whole_string = CFRangeMake(0, length);
+  CFIndex out_size;
+  CFIndex converted = CFStringGetBytes(cfstring,
+                                       whole_string,
+                                       encoding,
+                                       0,      // lossByte
+                                       false,  // isExternalRepresentation
+                                       NULL,   // buffer
+                                       0,      // maxBufLen
+                                       &out_size);
+  if (converted == 0 || out_size == 0)
+    return StringType();
+
+  // out_size is the number of UInt8-sized units needed in the destination.
+  // A buffer allocated as UInt8 units might not be properly aligned to
+  // contain elements of StringType::value_type.  Use a container for the
+  // proper value_type, and convert out_size by figuring the number of
+  // value_type elements per UInt8.  Leave room for a NUL terminator.
+  typename StringType::size_type elements =
+      out_size * sizeof(UInt8) / sizeof(typename StringType::value_type) + 1;
+
+  std::vector<typename StringType::value_type> out_buffer(elements);
+  converted = CFStringGetBytes(cfstring,
+                               whole_string,
+                               encoding,
+                               0,      // lossByte
+                               false,  // isExternalRepresentation
+                               reinterpret_cast<UInt8*>(&out_buffer[0]),
+                               out_size,
+                               NULL);  // usedBufLen
+  if (converted == 0)
+    return StringType();
+
+  out_buffer[elements - 1] = '\0';
+  return StringType(&out_buffer[0], elements - 1);
+}
+
+// Given an STL string |in| with an encoding specified by |in_encoding|,
+// convert it to |out_encoding| and return it as an STL string of the
+// |OutStringType| template type.  Returns an empty string on failure.
+//
+// Do not assert in this function since it is used by the asssertion code!
+template<typename InStringType, typename OutStringType>
+static OutStringType STLStringToSTLStringWithEncodingsT(
+    const InStringType& in,
+    CFStringEncoding in_encoding,
+    CFStringEncoding out_encoding) {
+  typename InStringType::size_type in_length = in.length();
+  if (in_length == 0)
+    return OutStringType();
+
+  base::ScopedCFTypeRef<CFStringRef> cfstring(CFStringCreateWithBytesNoCopy(
+      NULL,
+      reinterpret_cast<const UInt8*>(in.data()),
+      in_length * sizeof(typename InStringType::value_type),
+      in_encoding,
+      false,
+      kCFAllocatorNull));
+  if (!cfstring)
+    return OutStringType();
+
+  return CFStringToSTLStringWithEncodingT<OutStringType>(cfstring,
+                                                         out_encoding);
+}
+
+// Given an STL string |in| with an encoding specified by |in_encoding|,
+// return it as a CFStringRef.  Returns NULL on failure.
+template<typename StringType>
+static CFStringRef STLStringToCFStringWithEncodingsT(
+    const StringType& in,
+    CFStringEncoding in_encoding) {
+  typename StringType::size_type in_length = in.length();
+  if (in_length == 0)
+    return CFSTR("");
+
+  return CFStringCreateWithBytes(kCFAllocatorDefault,
+                                 reinterpret_cast<const UInt8*>(in.data()),
+                                 in_length *
+                                   sizeof(typename StringType::value_type),
+                                 in_encoding,
+                                 false);
+}
+
+// Specify the byte ordering explicitly, otherwise CFString will be confused
+// when strings don't carry BOMs, as they typically won't.
+static const CFStringEncoding kNarrowStringEncoding = kCFStringEncodingUTF8;
+#ifdef __BIG_ENDIAN__
+static const CFStringEncoding kMediumStringEncoding = kCFStringEncodingUTF16BE;
+static const CFStringEncoding kWideStringEncoding = kCFStringEncodingUTF32BE;
+#elif defined(__LITTLE_ENDIAN__)
+static const CFStringEncoding kMediumStringEncoding = kCFStringEncodingUTF16LE;
+static const CFStringEncoding kWideStringEncoding = kCFStringEncodingUTF32LE;
+#endif  // __LITTLE_ENDIAN__
+
+}  // namespace
+
+// Do not assert in this function since it is used by the asssertion code!
+std::string SysWideToUTF8(const std::wstring& wide) {
+  return STLStringToSTLStringWithEncodingsT<std::wstring, std::string>(
+      wide, kWideStringEncoding, kNarrowStringEncoding);
+}
+
+// Do not assert in this function since it is used by the asssertion code!
+std::wstring SysUTF8ToWide(const StringPiece& utf8) {
+  return STLStringToSTLStringWithEncodingsT<StringPiece, std::wstring>(
+      utf8, kNarrowStringEncoding, kWideStringEncoding);
+}
+
+std::string SysWideToNativeMB(const std::wstring& wide) {
+  return SysWideToUTF8(wide);
+}
+
+std::wstring SysNativeMBToWide(const StringPiece& native_mb) {
+  return SysUTF8ToWide(native_mb);
+}
+
+CFStringRef SysUTF8ToCFStringRef(const std::string& utf8) {
+  return STLStringToCFStringWithEncodingsT(utf8, kNarrowStringEncoding);
+}
+
+CFStringRef SysUTF16ToCFStringRef(const string16& utf16) {
+  return STLStringToCFStringWithEncodingsT(utf16, kMediumStringEncoding);
+}
+
+NSString* SysUTF8ToNSString(const std::string& utf8) {
+  return (NSString*)base::mac::CFTypeRefToNSObjectAutorelease(
+      SysUTF8ToCFStringRef(utf8));
+}
+
+NSString* SysUTF16ToNSString(const string16& utf16) {
+  return (NSString*)base::mac::CFTypeRefToNSObjectAutorelease(
+      SysUTF16ToCFStringRef(utf16));
+}
+
+std::string SysCFStringRefToUTF8(CFStringRef ref) {
+  return CFStringToSTLStringWithEncodingT<std::string>(ref,
+                                                       kNarrowStringEncoding);
+}
+
+string16 SysCFStringRefToUTF16(CFStringRef ref) {
+  return CFStringToSTLStringWithEncodingT<string16>(ref,
+                                                    kMediumStringEncoding);
+}
+
+std::string SysNSStringToUTF8(NSString* nsstring) {
+  if (!nsstring)
+    return std::string();
+  return SysCFStringRefToUTF8(reinterpret_cast<CFStringRef>(nsstring));
+}
+
+string16 SysNSStringToUTF16(NSString* nsstring) {
+  if (!nsstring)
+    return string16();
+  return SysCFStringRefToUTF16(reinterpret_cast<CFStringRef>(nsstring));
+}
+
+}  // namespace base
diff --git a/base/strings/sys_string_conversions_mac_unittest.mm b/base/strings/sys_string_conversions_mac_unittest.mm
new file mode 100644
index 0000000..4750a9a
--- /dev/null
+++ b/base/strings/sys_string_conversions_mac_unittest.mm
@@ -0,0 +1,21 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <Foundation/Foundation.h>
+
+#include "base/strings/string16.h"
+#include "base/strings/sys_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(SysStrings, ConversionsFromNSString) {
+  EXPECT_STREQ("Hello, world!", SysNSStringToUTF8(@"Hello, world!").c_str());
+
+  // Conversions should be able to handle a NULL value without crashing.
+  EXPECT_STREQ("", SysNSStringToUTF8(nil).c_str());
+  EXPECT_EQ(string16(), SysNSStringToUTF16(nil));
+}
+
+}  // namespace base
diff --git a/base/strings/sys_string_conversions_posix.cc b/base/strings/sys_string_conversions_posix.cc
new file mode 100644
index 0000000..3b18456
--- /dev/null
+++ b/base/strings/sys_string_conversions_posix.cc
@@ -0,0 +1,160 @@
+// Copyright (c) 2012 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/strings/sys_string_conversions.h"
+
+#include <wchar.h>
+
+#include "base/strings/string_piece.h"
+#include "base/strings/utf_string_conversions.h"
+
+namespace base {
+
+std::string SysWideToUTF8(const std::wstring& wide) {
+  // In theory this should be using the system-provided conversion rather
+  // than our ICU, but this will do for now.
+  return WideToUTF8(wide);
+}
+std::wstring SysUTF8ToWide(const StringPiece& utf8) {
+  // In theory this should be using the system-provided conversion rather
+  // than our ICU, but this will do for now.
+  std::wstring out;
+  UTF8ToWide(utf8.data(), utf8.size(), &out);
+  return out;
+}
+
+#if defined(SYSTEM_NATIVE_UTF8) || defined(OS_ANDROID)
+// TODO(port): Consider reverting the OS_ANDROID when we have wcrtomb()
+// support and a better understanding of what calls these routines.
+
+std::string SysWideToNativeMB(const std::wstring& wide) {
+  return WideToUTF8(wide);
+}
+
+std::wstring SysNativeMBToWide(const StringPiece& native_mb) {
+  return SysUTF8ToWide(native_mb);
+}
+
+#else
+
+std::string SysWideToNativeMB(const std::wstring& wide) {
+  mbstate_t ps;
+
+  // Calculate the number of multi-byte characters.  We walk through the string
+  // without writing the output, counting the number of multi-byte characters.
+  size_t num_out_chars = 0;
+  memset(&ps, 0, sizeof(ps));
+  for (size_t i = 0; i < wide.size(); ++i) {
+    const wchar_t src = wide[i];
+    // Use a temp buffer since calling wcrtomb with an output of NULL does not
+    // calculate the output length.
+    char buf[16];
+    // Skip NULLs to avoid wcrtomb's special handling of them.
+    size_t res = src ? wcrtomb(buf, src, &ps) : 0;
+    switch (res) {
+      // Handle any errors and return an empty string.
+      case static_cast<size_t>(-1):
+        return std::string();
+        break;
+      case 0:
+        // We hit an embedded null byte, keep going.
+        ++num_out_chars;
+        break;
+      default:
+        num_out_chars += res;
+        break;
+    }
+  }
+
+  if (num_out_chars == 0)
+    return std::string();
+
+  std::string out;
+  out.resize(num_out_chars);
+
+  // We walk the input string again, with |i| tracking the index of the
+  // wide input, and |j| tracking the multi-byte output.
+  memset(&ps, 0, sizeof(ps));
+  for (size_t i = 0, j = 0; i < wide.size(); ++i) {
+    const wchar_t src = wide[i];
+    // We don't want wcrtomb to do its funkiness for embedded NULLs.
+    size_t res = src ? wcrtomb(&out[j], src, &ps) : 0;
+    switch (res) {
+      // Handle any errors and return an empty string.
+      case static_cast<size_t>(-1):
+        return std::string();
+        break;
+      case 0:
+        // We hit an embedded null byte, keep going.
+        ++j;  // Output is already zeroed.
+        break;
+      default:
+        j += res;
+        break;
+    }
+  }
+
+  return out;
+}
+
+std::wstring SysNativeMBToWide(const StringPiece& native_mb) {
+  mbstate_t ps;
+
+  // Calculate the number of wide characters.  We walk through the string
+  // without writing the output, counting the number of wide characters.
+  size_t num_out_chars = 0;
+  memset(&ps, 0, sizeof(ps));
+  for (size_t i = 0; i < native_mb.size(); ) {
+    const char* src = native_mb.data() + i;
+    size_t res = mbrtowc(NULL, src, native_mb.size() - i, &ps);
+    switch (res) {
+      // Handle any errors and return an empty string.
+      case static_cast<size_t>(-2):
+      case static_cast<size_t>(-1):
+        return std::wstring();
+        break;
+      case 0:
+        // We hit an embedded null byte, keep going.
+        i += 1;  // Fall through.
+      default:
+        i += res;
+        ++num_out_chars;
+        break;
+    }
+  }
+
+  if (num_out_chars == 0)
+    return std::wstring();
+
+  std::wstring out;
+  out.resize(num_out_chars);
+
+  memset(&ps, 0, sizeof(ps));  // Clear the shift state.
+  // We walk the input string again, with |i| tracking the index of the
+  // multi-byte input, and |j| tracking the wide output.
+  for (size_t i = 0, j = 0; i < native_mb.size(); ++j) {
+    const char* src = native_mb.data() + i;
+    wchar_t* dst = &out[j];
+    size_t res = mbrtowc(dst, src, native_mb.size() - i, &ps);
+    switch (res) {
+      // Handle any errors and return an empty string.
+      case static_cast<size_t>(-2):
+      case static_cast<size_t>(-1):
+        return std::wstring();
+        break;
+      case 0:
+        i += 1;  // Skip null byte.
+        break;
+      default:
+        i += res;
+        break;
+    }
+  }
+
+  return out;
+}
+
+#endif  // OS_CHROMEOS
+
+}  // namespace base
diff --git a/base/strings/sys_string_conversions_unittest.cc b/base/strings/sys_string_conversions_unittest.cc
new file mode 100644
index 0000000..0cdd428
--- /dev/null
+++ b/base/strings/sys_string_conversions_unittest.cc
@@ -0,0 +1,193 @@
+// Copyright (c) 2011 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 <string>
+
+#include "base/basictypes.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_locale.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#ifdef WCHAR_T_IS_UTF32
+static const std::wstring kSysWideOldItalicLetterA = L"\x10300";
+#else
+static const std::wstring kSysWideOldItalicLetterA = L"\xd800\xdf00";
+#endif
+
+namespace base {
+
+TEST(SysStrings, SysWideToUTF8) {
+  EXPECT_EQ("Hello, world", SysWideToUTF8(L"Hello, world"));
+  EXPECT_EQ("\xe4\xbd\xa0\xe5\xa5\xbd", SysWideToUTF8(L"\x4f60\x597d"));
+
+  // >16 bits
+  EXPECT_EQ("\xF0\x90\x8C\x80", SysWideToUTF8(kSysWideOldItalicLetterA));
+
+  // Error case. When Windows finds a UTF-16 character going off the end of
+  // a string, it just converts that literal value to UTF-8, even though this
+  // is invalid.
+  //
+  // This is what XP does, but Vista has different behavior, so we don't bother
+  // verifying it:
+  // EXPECT_EQ("\xE4\xBD\xA0\xED\xA0\x80zyxw",
+  //           SysWideToUTF8(L"\x4f60\xd800zyxw"));
+
+  // Test embedded NULLs.
+  std::wstring wide_null(L"a");
+  wide_null.push_back(0);
+  wide_null.push_back('b');
+
+  std::string expected_null("a");
+  expected_null.push_back(0);
+  expected_null.push_back('b');
+
+  EXPECT_EQ(expected_null, SysWideToUTF8(wide_null));
+}
+
+TEST(SysStrings, SysUTF8ToWide) {
+  EXPECT_EQ(L"Hello, world", SysUTF8ToWide("Hello, world"));
+  EXPECT_EQ(L"\x4f60\x597d", SysUTF8ToWide("\xe4\xbd\xa0\xe5\xa5\xbd"));
+  // >16 bits
+  EXPECT_EQ(kSysWideOldItalicLetterA, SysUTF8ToWide("\xF0\x90\x8C\x80"));
+
+  // Error case. When Windows finds an invalid UTF-8 character, it just skips
+  // it. This seems weird because it's inconsistent with the reverse conversion.
+  //
+  // This is what XP does, but Vista has different behavior, so we don't bother
+  // verifying it:
+  // EXPECT_EQ(L"\x4f60zyxw", SysUTF8ToWide("\xe4\xbd\xa0\xe5\xa5zyxw"));
+
+  // Test embedded NULLs.
+  std::string utf8_null("a");
+  utf8_null.push_back(0);
+  utf8_null.push_back('b');
+
+  std::wstring expected_null(L"a");
+  expected_null.push_back(0);
+  expected_null.push_back('b');
+
+  EXPECT_EQ(expected_null, SysUTF8ToWide(utf8_null));
+}
+
+#if defined(OS_LINUX)  // Tests depend on setting a specific Linux locale.
+
+TEST(SysStrings, SysWideToNativeMB) {
+#if !defined(SYSTEM_NATIVE_UTF8)
+  ScopedLocale locale("en_US.utf-8");
+#endif
+  EXPECT_EQ("Hello, world", SysWideToNativeMB(L"Hello, world"));
+  EXPECT_EQ("\xe4\xbd\xa0\xe5\xa5\xbd", SysWideToNativeMB(L"\x4f60\x597d"));
+
+  // >16 bits
+  EXPECT_EQ("\xF0\x90\x8C\x80", SysWideToNativeMB(kSysWideOldItalicLetterA));
+
+  // Error case. When Windows finds a UTF-16 character going off the end of
+  // a string, it just converts that literal value to UTF-8, even though this
+  // is invalid.
+  //
+  // This is what XP does, but Vista has different behavior, so we don't bother
+  // verifying it:
+  // EXPECT_EQ("\xE4\xBD\xA0\xED\xA0\x80zyxw",
+  //           SysWideToNativeMB(L"\x4f60\xd800zyxw"));
+
+  // Test embedded NULLs.
+  std::wstring wide_null(L"a");
+  wide_null.push_back(0);
+  wide_null.push_back('b');
+
+  std::string expected_null("a");
+  expected_null.push_back(0);
+  expected_null.push_back('b');
+
+  EXPECT_EQ(expected_null, SysWideToNativeMB(wide_null));
+}
+
+// We assume the test is running in a UTF8 locale.
+TEST(SysStrings, SysNativeMBToWide) {
+#if !defined(SYSTEM_NATIVE_UTF8)
+  ScopedLocale locale("en_US.utf-8");
+#endif
+  EXPECT_EQ(L"Hello, world", SysNativeMBToWide("Hello, world"));
+  EXPECT_EQ(L"\x4f60\x597d", SysNativeMBToWide("\xe4\xbd\xa0\xe5\xa5\xbd"));
+  // >16 bits
+  EXPECT_EQ(kSysWideOldItalicLetterA, SysNativeMBToWide("\xF0\x90\x8C\x80"));
+
+  // Error case. When Windows finds an invalid UTF-8 character, it just skips
+  // it. This seems weird because it's inconsistent with the reverse conversion.
+  //
+  // This is what XP does, but Vista has different behavior, so we don't bother
+  // verifying it:
+  // EXPECT_EQ(L"\x4f60zyxw", SysNativeMBToWide("\xe4\xbd\xa0\xe5\xa5zyxw"));
+
+  // Test embedded NULLs.
+  std::string utf8_null("a");
+  utf8_null.push_back(0);
+  utf8_null.push_back('b');
+
+  std::wstring expected_null(L"a");
+  expected_null.push_back(0);
+  expected_null.push_back('b');
+
+  EXPECT_EQ(expected_null, SysNativeMBToWide(utf8_null));
+}
+
+static const wchar_t* const kConvertRoundtripCases[] = {
+  L"Google Video",
+  // "网页 图片 资讯更多 »"
+  L"\x7f51\x9875\x0020\x56fe\x7247\x0020\x8d44\x8baf\x66f4\x591a\x0020\x00bb",
+  //  "Παγκόσμιος Ιστός"
+  L"\x03a0\x03b1\x03b3\x03ba\x03cc\x03c3\x03bc\x03b9"
+  L"\x03bf\x03c2\x0020\x0399\x03c3\x03c4\x03cc\x03c2",
+  // "Поиск страниц на русском"
+  L"\x041f\x043e\x0438\x0441\x043a\x0020\x0441\x0442"
+  L"\x0440\x0430\x043d\x0438\x0446\x0020\x043d\x0430"
+  L"\x0020\x0440\x0443\x0441\x0441\x043a\x043e\x043c",
+  // "전체서비스"
+  L"\xc804\xccb4\xc11c\xbe44\xc2a4",
+
+  // Test characters that take more than 16 bits. This will depend on whether
+  // wchar_t is 16 or 32 bits.
+#if defined(WCHAR_T_IS_UTF16)
+  L"\xd800\xdf00",
+  // ?????  (Mathematical Alphanumeric Symbols (U+011d40 - U+011d44 : A,B,C,D,E)
+  L"\xd807\xdd40\xd807\xdd41\xd807\xdd42\xd807\xdd43\xd807\xdd44",
+#elif defined(WCHAR_T_IS_UTF32)
+  L"\x10300",
+  // ?????  (Mathematical Alphanumeric Symbols (U+011d40 - U+011d44 : A,B,C,D,E)
+  L"\x11d40\x11d41\x11d42\x11d43\x11d44",
+#endif
+};
+
+
+TEST(SysStrings, SysNativeMBAndWide) {
+#if !defined(SYSTEM_NATIVE_UTF8)
+  ScopedLocale locale("en_US.utf-8");
+#endif
+  for (size_t i = 0; i < arraysize(kConvertRoundtripCases); ++i) {
+    std::wstring wide = kConvertRoundtripCases[i];
+    std::wstring trip = SysNativeMBToWide(SysWideToNativeMB(wide));
+    EXPECT_EQ(wide.size(), trip.size());
+    EXPECT_EQ(wide, trip);
+  }
+
+  // We assume our test is running in UTF-8, so double check through ICU.
+  for (size_t i = 0; i < arraysize(kConvertRoundtripCases); ++i) {
+    std::wstring wide = kConvertRoundtripCases[i];
+    std::wstring trip = SysNativeMBToWide(WideToUTF8(wide));
+    EXPECT_EQ(wide.size(), trip.size());
+    EXPECT_EQ(wide, trip);
+  }
+
+  for (size_t i = 0; i < arraysize(kConvertRoundtripCases); ++i) {
+    std::wstring wide = kConvertRoundtripCases[i];
+    std::wstring trip = UTF8ToWide(SysWideToNativeMB(wide));
+    EXPECT_EQ(wide.size(), trip.size());
+    EXPECT_EQ(wide, trip);
+  }
+}
+#endif  // OS_LINUX
+
+}  // namespace base
diff --git a/base/strings/sys_string_conversions_win.cc b/base/strings/sys_string_conversions_win.cc
new file mode 100644
index 0000000..94d4466
--- /dev/null
+++ b/base/strings/sys_string_conversions_win.cc
@@ -0,0 +1,70 @@
+// Copyright (c) 2006-2008 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/strings/sys_string_conversions.h"
+
+#include <windows.h>
+
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+// Do not assert in this function since it is used by the asssertion code!
+std::string SysWideToUTF8(const std::wstring& wide) {
+  return SysWideToMultiByte(wide, CP_UTF8);
+}
+
+// Do not assert in this function since it is used by the asssertion code!
+std::wstring SysUTF8ToWide(const StringPiece& utf8) {
+  return SysMultiByteToWide(utf8, CP_UTF8);
+}
+
+std::string SysWideToNativeMB(const std::wstring& wide) {
+  return SysWideToMultiByte(wide, CP_ACP);
+}
+
+std::wstring SysNativeMBToWide(const StringPiece& native_mb) {
+  return SysMultiByteToWide(native_mb, CP_ACP);
+}
+
+// Do not assert in this function since it is used by the asssertion code!
+std::wstring SysMultiByteToWide(const StringPiece& mb, uint32 code_page) {
+  if (mb.empty())
+    return std::wstring();
+
+  int mb_length = static_cast<int>(mb.length());
+  // Compute the length of the buffer.
+  int charcount = MultiByteToWideChar(code_page, 0,
+                                      mb.data(), mb_length, NULL, 0);
+  if (charcount == 0)
+    return std::wstring();
+
+  std::wstring wide;
+  wide.resize(charcount);
+  MultiByteToWideChar(code_page, 0, mb.data(), mb_length, &wide[0], charcount);
+
+  return wide;
+}
+
+// Do not assert in this function since it is used by the asssertion code!
+std::string SysWideToMultiByte(const std::wstring& wide, uint32 code_page) {
+  int wide_length = static_cast<int>(wide.length());
+  if (wide_length == 0)
+    return std::string();
+
+  // Compute the length of the buffer we'll need.
+  int charcount = WideCharToMultiByte(code_page, 0, wide.data(), wide_length,
+                                      NULL, 0, NULL, NULL);
+  if (charcount == 0)
+    return std::string();
+
+  std::string mb;
+  mb.resize(charcount);
+  WideCharToMultiByte(code_page, 0, wide.data(), wide_length,
+                      &mb[0], charcount, NULL, NULL);
+
+  return mb;
+}
+
+}  // namespace base
diff --git a/base/strings/utf_offset_string_conversions.cc b/base/strings/utf_offset_string_conversions.cc
new file mode 100644
index 0000000..c2270bf
--- /dev/null
+++ b/base/strings/utf_offset_string_conversions.cc
@@ -0,0 +1,260 @@
+// Copyright (c) 2011 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/strings/utf_offset_string_conversions.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/utf_string_conversion_utils.h"
+
+namespace base {
+
+OffsetAdjuster::Adjustment::Adjustment(size_t original_offset,
+                                       size_t original_length,
+                                       size_t output_length)
+    : original_offset(original_offset),
+      original_length(original_length),
+      output_length(output_length) {
+}
+
+// static
+void OffsetAdjuster::AdjustOffsets(
+    const Adjustments& adjustments,
+    std::vector<size_t>* offsets_for_adjustment) {
+  if (!offsets_for_adjustment || adjustments.empty())
+    return;
+  for (std::vector<size_t>::iterator i(offsets_for_adjustment->begin());
+       i != offsets_for_adjustment->end(); ++i)
+    AdjustOffset(adjustments, &(*i));
+}
+
+// static
+void OffsetAdjuster::AdjustOffset(const Adjustments& adjustments,
+                                  size_t* offset) {
+  if (*offset == string16::npos)
+    return;
+  int adjustment = 0;
+  for (Adjustments::const_iterator i = adjustments.begin();
+       i != adjustments.end(); ++i) {
+    if (*offset <= i->original_offset)
+      break;
+    if (*offset < (i->original_offset + i->original_length)) {
+      *offset = string16::npos;
+      return;
+    }
+    adjustment += static_cast<int>(i->original_length - i->output_length);
+  }
+  *offset -= adjustment;
+}
+
+// static
+void OffsetAdjuster::UnadjustOffsets(
+    const Adjustments& adjustments,
+    std::vector<size_t>* offsets_for_unadjustment) {
+  if (!offsets_for_unadjustment || adjustments.empty())
+    return;
+  for (std::vector<size_t>::iterator i(offsets_for_unadjustment->begin());
+       i != offsets_for_unadjustment->end(); ++i)
+    UnadjustOffset(adjustments, &(*i));
+}
+
+// static
+void OffsetAdjuster::UnadjustOffset(const Adjustments& adjustments,
+                                    size_t* offset) {
+  if (*offset == string16::npos)
+    return;
+  int adjustment = 0;
+  for (Adjustments::const_iterator i = adjustments.begin();
+       i != adjustments.end(); ++i) {
+    if (*offset + adjustment <= i->original_offset)
+      break;
+    adjustment += static_cast<int>(i->original_length - i->output_length);
+    if ((*offset + adjustment) <
+        (i->original_offset + i->original_length)) {
+      *offset = string16::npos;
+      return;
+    }
+  }
+  *offset += adjustment;
+}
+
+// static
+void OffsetAdjuster::MergeSequentialAdjustments(
+    const Adjustments& first_adjustments,
+    Adjustments* adjustments_on_adjusted_string) {
+  Adjustments::iterator adjusted_iter = adjustments_on_adjusted_string->begin();
+  Adjustments::const_iterator first_iter = first_adjustments.begin();
+  // Simultaneously iterate over all |adjustments_on_adjusted_string| and
+  // |first_adjustments|, adding adjustments to or correcting the adjustments
+  // in |adjustments_on_adjusted_string| as we go.  |shift| keeps track of the
+  // current number of characters collapsed by |first_adjustments| up to this
+  // point.  |currently_collapsing| keeps track of the number of characters
+  // collapsed by |first_adjustments| into the current |adjusted_iter|'s
+  // length.  These are characters that will change |shift| as soon as we're
+  // done processing the current |adjusted_iter|; they are not yet reflected in
+  // |shift|.
+  size_t shift = 0;
+  size_t currently_collapsing = 0;
+  while (adjusted_iter != adjustments_on_adjusted_string->end()) {
+    if ((first_iter == first_adjustments.end()) ||
+        ((adjusted_iter->original_offset + shift +
+          adjusted_iter->original_length) <= first_iter->original_offset)) {
+      // Entire |adjusted_iter| (accounting for its shift and including its
+      // whole original length) comes before |first_iter|.
+      //
+      // Correct the offset at |adjusted_iter| and move onto the next
+      // adjustment that needs revising.
+      adjusted_iter->original_offset += shift;
+      shift += currently_collapsing;
+      currently_collapsing = 0;
+      ++adjusted_iter;
+    } else if ((adjusted_iter->original_offset + shift) >
+               first_iter->original_offset) {
+      // |first_iter| comes before the |adjusted_iter| (as adjusted by |shift|).
+
+      // It's not possible for the adjustments to overlap.  (It shouldn't
+      // be possible that we have an |adjusted_iter->original_offset| that,
+      // when adjusted by the computed |shift|, is in the middle of
+      // |first_iter|'s output's length.  After all, that would mean the
+      // current adjustment_on_adjusted_string somehow points to an offset
+      // that was supposed to have been eliminated by the first set of
+      // adjustments.)
+      DCHECK_LE(first_iter->original_offset + first_iter->output_length,
+                adjusted_iter->original_offset + shift);
+
+      // Add the |first_adjustment_iter| to the full set of adjustments while
+      // making sure |adjusted_iter| continues pointing to the same element.
+      // We do this by inserting the |first_adjustment_iter| right before
+      // |adjusted_iter|, then incrementing |adjusted_iter| so it points to
+      // the following element.
+      shift += first_iter->original_length - first_iter->output_length;
+      adjusted_iter = adjustments_on_adjusted_string->insert(
+          adjusted_iter, *first_iter);
+      ++adjusted_iter;
+      ++first_iter;
+    } else {
+      // The first adjustment adjusted something that then got further adjusted
+      // by the second set of adjustments.  In other words, |first_iter| points
+      // to something in the range covered by |adjusted_iter|'s length (after
+      // accounting for |shift|).  Precisely,
+      //   adjusted_iter->original_offset + shift
+      //   <=
+      //   first_iter->original_offset
+      //   <=
+      //   adjusted_iter->original_offset + shift +
+      //       adjusted_iter->original_length
+
+      // Modify the current |adjusted_iter| to include whatever collapsing
+      // happened in |first_iter|, then advance to the next |first_adjustments|
+      // because we dealt with the current one.
+      const int collapse = static_cast<int>(first_iter->original_length) -
+          static_cast<int>(first_iter->output_length);
+      // This function does not know how to deal with a string that expands and
+      // then gets modified, only strings that collapse and then get modified.
+      DCHECK_GT(collapse, 0);
+      adjusted_iter->original_length += collapse;
+      currently_collapsing += collapse;
+      ++first_iter;
+    }
+  }
+  DCHECK_EQ(0u, currently_collapsing);
+  if (first_iter != first_adjustments.end()) {
+    // Only first adjustments are left.  These do not need to be modified.
+    // (Their offsets are already correct with respect to the original string.)
+    // Append them all.
+    DCHECK(adjusted_iter == adjustments_on_adjusted_string->end());
+    adjustments_on_adjusted_string->insert(
+        adjustments_on_adjusted_string->end(), first_iter,
+        first_adjustments.end());
+  }
+}
+
+// Converts the given source Unicode character type to the given destination
+// Unicode character type as a STL string. The given input buffer and size
+// determine the source, and the given output STL string will be replaced by
+// the result.  If non-NULL, |adjustments| is set to reflect the all the
+// alterations to the string that are not one-character-to-one-character.
+// It will always be sorted by increasing offset.
+template<typename SrcChar, typename DestStdString>
+bool ConvertUnicode(const SrcChar* src,
+                    size_t src_len,
+                    DestStdString* output,
+                    OffsetAdjuster::Adjustments* adjustments) {
+  if (adjustments)
+    adjustments->clear();
+  // ICU requires 32-bit numbers.
+  bool success = true;
+  int32 src_len32 = static_cast<int32>(src_len);
+  for (int32 i = 0; i < src_len32; i++) {
+    uint32 code_point;
+    size_t original_i = i;
+    size_t chars_written = 0;
+    if (ReadUnicodeCharacter(src, src_len32, &i, &code_point)) {
+      chars_written = WriteUnicodeCharacter(code_point, output);
+    } else {
+      chars_written = WriteUnicodeCharacter(0xFFFD, output);
+      success = false;
+    }
+
+    // Only bother writing an adjustment if this modification changed the
+    // length of this character.
+    // NOTE: ReadUnicodeCharacter() adjusts |i| to point _at_ the last
+    // character read, not after it (so that incrementing it in the loop
+    // increment will place it at the right location), so we need to account
+    // for that in determining the amount that was read.
+    if (adjustments && ((i - original_i + 1) != chars_written)) {
+      adjustments->push_back(OffsetAdjuster::Adjustment(
+          original_i, i - original_i + 1, chars_written));
+    }
+  }
+  return success;
+}
+
+bool UTF8ToUTF16WithAdjustments(
+    const char* src,
+    size_t src_len,
+    string16* output,
+    base::OffsetAdjuster::Adjustments* adjustments) {
+  PrepareForUTF16Or32Output(src, src_len, output);
+  return ConvertUnicode(src, src_len, output, adjustments);
+}
+
+string16 UTF8ToUTF16WithAdjustments(
+    const base::StringPiece& utf8,
+    base::OffsetAdjuster::Adjustments* adjustments) {
+  string16 result;
+  UTF8ToUTF16WithAdjustments(utf8.data(), utf8.length(), &result, adjustments);
+  return result;
+}
+
+string16 UTF8ToUTF16AndAdjustOffsets(
+    const base::StringPiece& utf8,
+    std::vector<size_t>* offsets_for_adjustment) {
+  std::for_each(offsets_for_adjustment->begin(),
+                offsets_for_adjustment->end(),
+                LimitOffset<base::StringPiece>(utf8.length()));
+  OffsetAdjuster::Adjustments adjustments;
+  string16 result = UTF8ToUTF16WithAdjustments(utf8, &adjustments);
+  OffsetAdjuster::AdjustOffsets(adjustments, offsets_for_adjustment);
+  return result;
+}
+
+std::string UTF16ToUTF8AndAdjustOffsets(
+    const base::StringPiece16& utf16,
+    std::vector<size_t>* offsets_for_adjustment) {
+  std::for_each(offsets_for_adjustment->begin(),
+                offsets_for_adjustment->end(),
+                LimitOffset<base::StringPiece16>(utf16.length()));
+  std::string result;
+  PrepareForUTF8Output(utf16.data(), utf16.length(), &result);
+  OffsetAdjuster::Adjustments adjustments;
+  ConvertUnicode(utf16.data(), utf16.length(), &result, &adjustments);
+  OffsetAdjuster::AdjustOffsets(adjustments, offsets_for_adjustment);
+  return result;
+}
+
+}  // namespace base
diff --git a/base/strings/utf_offset_string_conversions.h b/base/strings/utf_offset_string_conversions.h
new file mode 100644
index 0000000..d449489
--- /dev/null
+++ b/base/strings/utf_offset_string_conversions.h
@@ -0,0 +1,126 @@
+// Copyright (c) 2011 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_STRINGS_UTF_OFFSET_STRING_CONVERSIONS_H_
+#define BASE_STRINGS_UTF_OFFSET_STRING_CONVERSIONS_H_
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+// A helper class and associated data structures to adjust offsets into a
+// string in response to various adjustments one might do to that string
+// (e.g., eliminating a range).  For details on offsets, see the comments by
+// the AdjustOffsets() function below.
+class BASE_EXPORT OffsetAdjuster {
+ public:
+  struct BASE_EXPORT Adjustment {
+    Adjustment(size_t original_offset,
+               size_t original_length,
+               size_t output_length);
+
+    size_t original_offset;
+    size_t original_length;
+    size_t output_length;
+  };
+  typedef std::vector<Adjustment> Adjustments;
+
+  // Adjusts all offsets in |offsets_for_adjustment| to reflect the adjustments
+  // recorded in |adjustments|.
+  //
+  // Offsets represents insertion/selection points between characters: if |src|
+  // is "abcd", then 0 is before 'a', 2 is between 'b' and 'c', and 4 is at the
+  // end of the string.  Valid input offsets range from 0 to |src_len|.  On
+  // exit, each offset will have been modified to point at the same logical
+  // position in the output string.  If an offset cannot be successfully
+  // adjusted (e.g., because it points into the middle of a multibyte sequence),
+  // it will be set to string16::npos.
+  static void AdjustOffsets(const Adjustments& adjustments,
+                            std::vector<size_t>* offsets_for_adjustment);
+
+  // Adjusts the single |offset| to reflect the adjustments recorded in
+  // |adjustments|.
+  static void AdjustOffset(const Adjustments& adjustments,
+                           size_t* offset);
+
+  // Adjusts all offsets in |offsets_for_unadjustment| to reflect the reverse
+  // of the adjustments recorded in |adjustments|.  In other words, the offsets
+  // provided represent offsets into an adjusted string and the caller wants
+  // to know the offsets they correspond to in the original string.  If an
+  // offset cannot be successfully unadjusted (e.g., because it points into
+  // the middle of a multibyte sequence), it will be set to string16::npos.
+  static void UnadjustOffsets(const Adjustments& adjustments,
+                              std::vector<size_t>* offsets_for_unadjustment);
+
+  // Adjusts the single |offset| to reflect the reverse of the adjustments
+  // recorded in |adjustments|.
+  static void UnadjustOffset(const Adjustments& adjustments,
+                             size_t* offset);
+
+  // Combines two sequential sets of adjustments, storing the combined revised
+  // adjustments in |adjustments_on_adjusted_string|.  That is, suppose a
+  // string was altered in some way, with the alterations recorded as
+  // adjustments in |first_adjustments|.  Then suppose the resulting string is
+  // further altered, with the alterations recorded as adjustments scored in
+  // |adjustments_on_adjusted_string|, with the offsets recorded in these
+  // adjustments being with respect to the intermediate string.  This function
+  // combines the two sets of adjustments into one, storing the result in
+  // |adjustments_on_adjusted_string|, whose offsets are correct with respect
+  // to the original string.
+  //
+  // Assumes both parameters are sorted by increasing offset.
+  //
+  // WARNING: Only supports |first_adjustments| that involve collapsing ranges
+  // of text, not expanding ranges.
+  static void MergeSequentialAdjustments(
+      const Adjustments& first_adjustments,
+      Adjustments* adjustments_on_adjusted_string);
+};
+
+// Like the conversions in utf_string_conversions.h, but also fills in an
+// |adjustments| parameter that reflects the alterations done to the string.
+// It may be NULL.
+BASE_EXPORT bool UTF8ToUTF16WithAdjustments(
+    const char* src,
+    size_t src_len,
+    string16* output,
+    base::OffsetAdjuster::Adjustments* adjustments);
+BASE_EXPORT string16 UTF8ToUTF16WithAdjustments(
+    const base::StringPiece& utf8,
+    base::OffsetAdjuster::Adjustments* adjustments);
+// As above, but instead internally examines the adjustments and applies them
+// to |offsets_for_adjustment|.  See comments by AdjustOffsets().
+BASE_EXPORT string16 UTF8ToUTF16AndAdjustOffsets(
+    const base::StringPiece& utf8,
+    std::vector<size_t>* offsets_for_adjustment);
+
+BASE_EXPORT std::string UTF16ToUTF8AndAdjustOffsets(
+    const base::StringPiece16& utf16,
+    std::vector<size_t>* offsets_for_adjustment);
+
+// Limiting function callable by std::for_each which will replace any value
+// which is greater than |limit| with npos.  Typically this is called with a
+// string length to clamp offsets into the string to [0, length] (as opposed to
+// [0, length); see comments above).
+template <typename T>
+struct LimitOffset {
+  explicit LimitOffset(size_t limit)
+    : limit_(limit) {}
+
+  void operator()(size_t& offset) {
+    if (offset > limit_)
+      offset = T::npos;
+  }
+
+  size_t limit_;
+};
+
+}  // namespace base
+
+#endif  // BASE_STRINGS_UTF_OFFSET_STRING_CONVERSIONS_H_
diff --git a/base/strings/utf_offset_string_conversions_unittest.cc b/base/strings/utf_offset_string_conversions_unittest.cc
new file mode 100644
index 0000000..9398a56
--- /dev/null
+++ b/base/strings/utf_offset_string_conversions_unittest.cc
@@ -0,0 +1,296 @@
+// Copyright (c) 2011 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 <algorithm>
+
+#include "base/logging.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/utf_offset_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+static const size_t kNpos = string16::npos;
+
+}  // namespace
+
+TEST(UTFOffsetStringConversionsTest, AdjustOffset) {
+  struct UTF8ToUTF16Case {
+    const char* utf8;
+    size_t input_offset;
+    size_t output_offset;
+  } utf8_to_utf16_cases[] = {
+    {"", 0, 0},
+    {"", kNpos, kNpos},
+    {"\xe4\xbd\xa0\xe5\xa5\xbd", 1, kNpos},
+    {"\xe4\xbd\xa0\xe5\xa5\xbd", 3, 1},
+    {"\xed\xb0\x80z", 3, 1},
+    {"A\xF0\x90\x8C\x80z", 1, 1},
+    {"A\xF0\x90\x8C\x80z", 2, kNpos},
+    {"A\xF0\x90\x8C\x80z", 5, 3},
+    {"A\xF0\x90\x8C\x80z", 6, 4},
+    {"A\xF0\x90\x8C\x80z", kNpos, kNpos},
+  };
+  for (size_t i = 0; i < arraysize(utf8_to_utf16_cases); ++i) {
+    const size_t offset = utf8_to_utf16_cases[i].input_offset;
+    std::vector<size_t> offsets;
+    offsets.push_back(offset);
+    UTF8ToUTF16AndAdjustOffsets(utf8_to_utf16_cases[i].utf8, &offsets);
+    EXPECT_EQ(utf8_to_utf16_cases[i].output_offset, offsets[0]);
+  }
+
+  struct UTF16ToUTF8Case {
+    char16 utf16[10];
+    size_t input_offset;
+    size_t output_offset;
+  } utf16_to_utf8_cases[] = {
+      {{}, 0, 0},
+      // Converted to 3-byte utf-8 sequences
+      {{0x5909, 0x63DB}, 3, kNpos},
+      {{0x5909, 0x63DB}, 2, 6},
+      {{0x5909, 0x63DB}, 1, 3},
+      {{0x5909, 0x63DB}, 0, 0},
+      // Converted to 2-byte utf-8 sequences
+      {{'A', 0x00bc, 0x00be, 'z'}, 1, 1},
+      {{'A', 0x00bc, 0x00be, 'z'}, 2, 3},
+      {{'A', 0x00bc, 0x00be, 'z'}, 3, 5},
+      {{'A', 0x00bc, 0x00be, 'z'}, 4, 6},
+      // Surrogate pair
+      {{'A', 0xd800, 0xdf00, 'z'}, 1, 1},
+      {{'A', 0xd800, 0xdf00, 'z'}, 2, kNpos},
+      {{'A', 0xd800, 0xdf00, 'z'}, 3, 5},
+      {{'A', 0xd800, 0xdf00, 'z'}, 4, 6},
+  };
+  for (size_t i = 0; i < arraysize(utf16_to_utf8_cases); ++i) {
+    size_t offset = utf16_to_utf8_cases[i].input_offset;
+    std::vector<size_t> offsets;
+    offsets.push_back(offset);
+    UTF16ToUTF8AndAdjustOffsets(utf16_to_utf8_cases[i].utf16, &offsets);
+    EXPECT_EQ(utf16_to_utf8_cases[i].output_offset, offsets[0]) << i;
+  }
+}
+
+TEST(UTFOffsetStringConversionsTest, LimitOffsets) {
+  const size_t kLimit = 10;
+  const size_t kItems = 20;
+  std::vector<size_t> size_ts;
+  for (size_t t = 0; t < kItems; ++t)
+    size_ts.push_back(t);
+  std::for_each(size_ts.begin(), size_ts.end(),
+                LimitOffset<string16>(kLimit));
+  size_t unlimited_count = 0;
+  for (std::vector<size_t>::iterator ti = size_ts.begin(); ti != size_ts.end();
+       ++ti) {
+    if (*ti != kNpos)
+      ++unlimited_count;
+  }
+  EXPECT_EQ(11U, unlimited_count);
+
+  // Reverse the values in the vector and try again.
+  size_ts.clear();
+  for (size_t t = kItems; t > 0; --t)
+    size_ts.push_back(t - 1);
+  std::for_each(size_ts.begin(), size_ts.end(),
+                LimitOffset<string16>(kLimit));
+  unlimited_count = 0;
+  for (std::vector<size_t>::iterator ti = size_ts.begin(); ti != size_ts.end();
+       ++ti) {
+    if (*ti != kNpos)
+      ++unlimited_count;
+  }
+  EXPECT_EQ(11U, unlimited_count);
+}
+
+TEST(UTFOffsetStringConversionsTest, AdjustOffsets) {
+  // Imagine we have strings as shown in the following cases where the
+  // X's represent encoded characters.
+  // 1: abcXXXdef ==> abcXdef
+  {
+    std::vector<size_t> offsets;
+    for (size_t t = 0; t <= 9; ++t)
+      offsets.push_back(t);
+    OffsetAdjuster::Adjustments adjustments;
+    adjustments.push_back(OffsetAdjuster::Adjustment(3, 3, 1));
+    OffsetAdjuster::AdjustOffsets(adjustments, &offsets);
+    size_t expected_1[] = {0, 1, 2, 3, kNpos, kNpos, 4, 5, 6, 7};
+    EXPECT_EQ(offsets.size(), arraysize(expected_1));
+    for (size_t i = 0; i < arraysize(expected_1); ++i)
+      EXPECT_EQ(expected_1[i], offsets[i]);
+  }
+
+  // 2: XXXaXXXXbcXXXXXXXdefXXX ==> XaXXbcXXXXdefX
+  {
+    std::vector<size_t> offsets;
+    for (size_t t = 0; t <= 23; ++t)
+      offsets.push_back(t);
+    OffsetAdjuster::Adjustments adjustments;
+    adjustments.push_back(OffsetAdjuster::Adjustment(0, 3, 1));
+    adjustments.push_back(OffsetAdjuster::Adjustment(4, 4, 2));
+    adjustments.push_back(OffsetAdjuster::Adjustment(10, 7, 4));
+    adjustments.push_back(OffsetAdjuster::Adjustment(20, 3, 1));
+    OffsetAdjuster::AdjustOffsets(adjustments, &offsets);
+    size_t expected_2[] = {
+      0, kNpos, kNpos, 1, 2, kNpos, kNpos, kNpos, 4, 5, 6, kNpos, kNpos, kNpos,
+      kNpos, kNpos, kNpos, 10, 11, 12, 13, kNpos, kNpos, 14
+    };
+    EXPECT_EQ(offsets.size(), arraysize(expected_2));
+    for (size_t i = 0; i < arraysize(expected_2); ++i)
+      EXPECT_EQ(expected_2[i], offsets[i]);
+  }
+
+  // 3: XXXaXXXXbcdXXXeXX ==> aXXXXbcdXXXe
+  {
+    std::vector<size_t> offsets;
+    for (size_t t = 0; t <= 17; ++t)
+      offsets.push_back(t);
+    OffsetAdjuster::Adjustments adjustments;
+    adjustments.push_back(OffsetAdjuster::Adjustment(0, 3, 0));
+    adjustments.push_back(OffsetAdjuster::Adjustment(4, 4, 4));
+    adjustments.push_back(OffsetAdjuster::Adjustment(11, 3, 3));
+    adjustments.push_back(OffsetAdjuster::Adjustment(15, 2, 0));
+    OffsetAdjuster::AdjustOffsets(adjustments, &offsets);
+    size_t expected_3[] = {
+      0, kNpos, kNpos, 0, 1, kNpos, kNpos, kNpos, 5, 6, 7, 8, kNpos, kNpos, 11,
+      12, kNpos, 12
+    };
+    EXPECT_EQ(offsets.size(), arraysize(expected_3));
+    for (size_t i = 0; i < arraysize(expected_3); ++i)
+      EXPECT_EQ(expected_3[i], offsets[i]);
+  }
+}
+
+TEST(UTFOffsetStringConversionsTest, UnadjustOffsets) {
+  // Imagine we have strings as shown in the following cases where the
+  // X's represent encoded characters.
+  // 1: abcXXXdef ==> abcXdef
+  {
+    std::vector<size_t> offsets;
+    for (size_t t = 0; t <= 7; ++t)
+      offsets.push_back(t);
+    OffsetAdjuster::Adjustments adjustments;
+    adjustments.push_back(OffsetAdjuster::Adjustment(3, 3, 1));
+    OffsetAdjuster::UnadjustOffsets(adjustments, &offsets);
+    size_t expected_1[] = {0, 1, 2, 3, 6, 7, 8, 9};
+    EXPECT_EQ(offsets.size(), arraysize(expected_1));
+    for (size_t i = 0; i < arraysize(expected_1); ++i)
+      EXPECT_EQ(expected_1[i], offsets[i]);
+  }
+
+  // 2: XXXaXXXXbcXXXXXXXdefXXX ==> XaXXbcXXXXdefX
+  {
+    std::vector<size_t> offsets;
+    for (size_t t = 0; t <= 14; ++t)
+      offsets.push_back(t);
+    OffsetAdjuster::Adjustments adjustments;
+    adjustments.push_back(OffsetAdjuster::Adjustment(0, 3, 1));
+    adjustments.push_back(OffsetAdjuster::Adjustment(4, 4, 2));
+    adjustments.push_back(OffsetAdjuster::Adjustment(10, 7, 4));
+    adjustments.push_back(OffsetAdjuster::Adjustment(20, 3, 1));
+    OffsetAdjuster::UnadjustOffsets(adjustments, &offsets);
+    size_t expected_2[] = {
+      0, 3, 4, kNpos, 8, 9, 10, kNpos, kNpos, kNpos, 17, 18, 19, 20, 23
+    };
+    EXPECT_EQ(offsets.size(), arraysize(expected_2));
+    for (size_t i = 0; i < arraysize(expected_2); ++i)
+      EXPECT_EQ(expected_2[i], offsets[i]);
+  }
+
+  // 3: XXXaXXXXbcdXXXeXX ==> aXXXXbcdXXXe
+  {
+    std::vector<size_t> offsets;
+    for (size_t t = 0; t <= 12; ++t)
+      offsets.push_back(t);
+    OffsetAdjuster::Adjustments adjustments;
+    adjustments.push_back(OffsetAdjuster::Adjustment(0, 3, 0));
+    adjustments.push_back(OffsetAdjuster::Adjustment(4, 4, 4));
+    adjustments.push_back(OffsetAdjuster::Adjustment(11, 3, 3));
+    adjustments.push_back(OffsetAdjuster::Adjustment(15, 2, 0));
+    OffsetAdjuster::UnadjustOffsets(adjustments, &offsets);
+    size_t expected_3[] = {
+      0,  // this could just as easily be 3
+      4, kNpos, kNpos, kNpos, 8, 9, 10, 11, kNpos, kNpos, 14,
+      15  // this could just as easily be 17
+    };
+    EXPECT_EQ(offsets.size(), arraysize(expected_3));
+    for (size_t i = 0; i < arraysize(expected_3); ++i)
+      EXPECT_EQ(expected_3[i], offsets[i]);
+  }
+}
+
+// MergeSequentialAdjustments is used by net/base/escape.{h,cc} and
+// net/base/net_util.{h,cc}.  The two tests EscapeTest.AdjustOffset and
+// NetUtilTest.FormatUrlWithOffsets test its behavior extensively.  This
+// is simply a short, additional test.
+TEST(UTFOffsetStringConversionsTest, MergeSequentialAdjustments) {
+  // Pretend the input string is "abcdefghijklmnopqrstuvwxyz".
+
+  // Set up |first_adjustments| to
+  // - remove the leading "a"
+  // - combine the "bc" into one character (call it ".")
+  // - remove the "f"
+  // - remove the "tuv"
+  // The resulting string should be ".deghijklmnopqrswxyz".
+  OffsetAdjuster::Adjustments first_adjustments;
+  first_adjustments.push_back(OffsetAdjuster::Adjustment(0, 1, 0));
+  first_adjustments.push_back(OffsetAdjuster::Adjustment(1, 2, 1));
+  first_adjustments.push_back(OffsetAdjuster::Adjustment(5, 1, 0));
+  first_adjustments.push_back(OffsetAdjuster::Adjustment(19, 3, 0));
+
+  // Set up |adjustments_on_adjusted_string| to
+  // - combine the "." character that replaced "bc" with "d" into one character
+  //   (call it "?")
+  // - remove the "egh"
+  // - expand the "i" into two characters (call them "12")
+  // - combine the "jkl" into one character (call it "@")
+  // - expand the "z" into two characters (call it "34")
+  // The resulting string should be "?12@mnopqrswxy34".
+  OffsetAdjuster::Adjustments adjustments_on_adjusted_string;
+  adjustments_on_adjusted_string.push_back(OffsetAdjuster::Adjustment(
+      0, 2, 1));
+  adjustments_on_adjusted_string.push_back(OffsetAdjuster::Adjustment(
+      2, 3, 0));
+  adjustments_on_adjusted_string.push_back(OffsetAdjuster::Adjustment(
+      5, 1, 2));
+  adjustments_on_adjusted_string.push_back(OffsetAdjuster::Adjustment(
+      6, 3, 1));
+  adjustments_on_adjusted_string.push_back(OffsetAdjuster::Adjustment(
+      19, 1, 2));
+
+  // Now merge the adjustments and check the results.
+  OffsetAdjuster::MergeSequentialAdjustments(first_adjustments,
+                                             &adjustments_on_adjusted_string);
+  // The merged adjustments should look like
+  // - combine abcd into "?"
+  //   - note: it's also reasonable for the Merge function to instead produce
+  //     two adjustments instead of this, one to remove a and another to
+  //     combine bcd into "?".  This test verifies the current behavior.
+  // - remove efgh
+  // - expand i into "12"
+  // - combine jkl into "@"
+  // - remove tuv
+  // - expand z into "34"
+  ASSERT_EQ(6u, adjustments_on_adjusted_string.size());
+  EXPECT_EQ(0u, adjustments_on_adjusted_string[0].original_offset);
+  EXPECT_EQ(4u, adjustments_on_adjusted_string[0].original_length);
+  EXPECT_EQ(1u, adjustments_on_adjusted_string[0].output_length);
+  EXPECT_EQ(4u, adjustments_on_adjusted_string[1].original_offset);
+  EXPECT_EQ(4u, adjustments_on_adjusted_string[1].original_length);
+  EXPECT_EQ(0u, adjustments_on_adjusted_string[1].output_length);
+  EXPECT_EQ(8u, adjustments_on_adjusted_string[2].original_offset);
+  EXPECT_EQ(1u, adjustments_on_adjusted_string[2].original_length);
+  EXPECT_EQ(2u, adjustments_on_adjusted_string[2].output_length);
+  EXPECT_EQ(9u, adjustments_on_adjusted_string[3].original_offset);
+  EXPECT_EQ(3u, adjustments_on_adjusted_string[3].original_length);
+  EXPECT_EQ(1u, adjustments_on_adjusted_string[3].output_length);
+  EXPECT_EQ(19u, adjustments_on_adjusted_string[4].original_offset);
+  EXPECT_EQ(3u, adjustments_on_adjusted_string[4].original_length);
+  EXPECT_EQ(0u, adjustments_on_adjusted_string[4].output_length);
+  EXPECT_EQ(25u, adjustments_on_adjusted_string[5].original_offset);
+  EXPECT_EQ(1u, adjustments_on_adjusted_string[5].original_length);
+  EXPECT_EQ(2u, adjustments_on_adjusted_string[5].output_length);
+}
+
+}  // namespace base
diff --git a/base/strings/utf_string_conversion_utils.cc b/base/strings/utf_string_conversion_utils.cc
new file mode 100644
index 0000000..022c0df
--- /dev/null
+++ b/base/strings/utf_string_conversion_utils.cc
@@ -0,0 +1,148 @@
+// Copyright (c) 2009 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/strings/utf_string_conversion_utils.h"
+
+#include "base/third_party/icu/icu_utf.h"
+
+namespace base {
+
+// ReadUnicodeCharacter --------------------------------------------------------
+
+bool ReadUnicodeCharacter(const char* src,
+                          int32 src_len,
+                          int32* char_index,
+                          uint32* code_point_out) {
+  // U8_NEXT expects to be able to use -1 to signal an error, so we must
+  // use a signed type for code_point.  But this function returns false
+  // on error anyway, so code_point_out is unsigned.
+  int32 code_point;
+  CBU8_NEXT(src, *char_index, src_len, code_point);
+  *code_point_out = static_cast<uint32>(code_point);
+
+  // The ICU macro above moves to the next char, we want to point to the last
+  // char consumed.
+  (*char_index)--;
+
+  // Validate the decoded value.
+  return IsValidCodepoint(code_point);
+}
+
+bool ReadUnicodeCharacter(const char16* src,
+                          int32 src_len,
+                          int32* char_index,
+                          uint32* code_point) {
+  if (CBU16_IS_SURROGATE(src[*char_index])) {
+    if (!CBU16_IS_SURROGATE_LEAD(src[*char_index]) ||
+        *char_index + 1 >= src_len ||
+        !CBU16_IS_TRAIL(src[*char_index + 1])) {
+      // Invalid surrogate pair.
+      return false;
+    }
+
+    // Valid surrogate pair.
+    *code_point = CBU16_GET_SUPPLEMENTARY(src[*char_index],
+                                          src[*char_index + 1]);
+    (*char_index)++;
+  } else {
+    // Not a surrogate, just one 16-bit word.
+    *code_point = src[*char_index];
+  }
+
+  return IsValidCodepoint(*code_point);
+}
+
+#if defined(WCHAR_T_IS_UTF32)
+bool ReadUnicodeCharacter(const wchar_t* src,
+                          int32 src_len,
+                          int32* char_index,
+                          uint32* code_point) {
+  // Conversion is easy since the source is 32-bit.
+  *code_point = src[*char_index];
+
+  // Validate the value.
+  return IsValidCodepoint(*code_point);
+}
+#endif  // defined(WCHAR_T_IS_UTF32)
+
+// WriteUnicodeCharacter -------------------------------------------------------
+
+size_t WriteUnicodeCharacter(uint32 code_point, std::string* output) {
+  if (code_point <= 0x7f) {
+    // Fast path the common case of one byte.
+    output->push_back(static_cast<char>(code_point));
+    return 1;
+  }
+
+
+  // CBU8_APPEND_UNSAFE can append up to 4 bytes.
+  size_t char_offset = output->length();
+  size_t original_char_offset = char_offset;
+  output->resize(char_offset + CBU8_MAX_LENGTH);
+
+  CBU8_APPEND_UNSAFE(&(*output)[0], char_offset, code_point);
+
+  // CBU8_APPEND_UNSAFE will advance our pointer past the inserted character, so
+  // it will represent the new length of the string.
+  output->resize(char_offset);
+  return char_offset - original_char_offset;
+}
+
+size_t WriteUnicodeCharacter(uint32 code_point, string16* output) {
+  if (CBU16_LENGTH(code_point) == 1) {
+    // Thie code point is in the Basic Multilingual Plane (BMP).
+    output->push_back(static_cast<char16>(code_point));
+    return 1;
+  }
+  // Non-BMP characters use a double-character encoding.
+  size_t char_offset = output->length();
+  output->resize(char_offset + CBU16_MAX_LENGTH);
+  CBU16_APPEND_UNSAFE(&(*output)[0], char_offset, code_point);
+  return CBU16_MAX_LENGTH;
+}
+
+// Generalized Unicode converter -----------------------------------------------
+
+template<typename CHAR>
+void PrepareForUTF8Output(const CHAR* src,
+                          size_t src_len,
+                          std::string* output) {
+  output->clear();
+  if (src_len == 0)
+    return;
+  if (src[0] < 0x80) {
+    // Assume that the entire input will be ASCII.
+    output->reserve(src_len);
+  } else {
+    // Assume that the entire input is non-ASCII and will have 3 bytes per char.
+    output->reserve(src_len * 3);
+  }
+}
+
+// Instantiate versions we know callers will need.
+template void PrepareForUTF8Output(const wchar_t*, size_t, std::string*);
+template void PrepareForUTF8Output(const char16*, size_t, std::string*);
+
+template<typename STRING>
+void PrepareForUTF16Or32Output(const char* src,
+                               size_t src_len,
+                               STRING* output) {
+  output->clear();
+  if (src_len == 0)
+    return;
+  if (static_cast<unsigned char>(src[0]) < 0x80) {
+    // Assume the input is all ASCII, which means 1:1 correspondence.
+    output->reserve(src_len);
+  } else {
+    // Otherwise assume that the UTF-8 sequences will have 2 bytes for each
+    // character.
+    output->reserve(src_len / 2);
+  }
+}
+
+// Instantiate versions we know callers will need.
+template void PrepareForUTF16Or32Output(const char*, size_t, std::wstring*);
+template void PrepareForUTF16Or32Output(const char*, size_t, string16*);
+
+}  // namespace base
diff --git a/base/strings/utf_string_conversion_utils.h b/base/strings/utf_string_conversion_utils.h
new file mode 100644
index 0000000..22abbbc
--- /dev/null
+++ b/base/strings/utf_string_conversion_utils.h
@@ -0,0 +1,97 @@
+// Copyright (c) 2011 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_STRINGS_UTF_STRING_CONVERSION_UTILS_H_
+#define BASE_STRINGS_UTF_STRING_CONVERSION_UTILS_H_
+
+// This should only be used by the various UTF string conversion files.
+
+#include "base/base_export.h"
+#include "base/strings/string16.h"
+
+namespace base {
+
+inline bool IsValidCodepoint(uint32 code_point) {
+  // Excludes the surrogate code points ([0xD800, 0xDFFF]) and
+  // codepoints larger than 0x10FFFF (the highest codepoint allowed).
+  // Non-characters and unassigned codepoints are allowed.
+  return code_point < 0xD800u ||
+         (code_point >= 0xE000u && code_point <= 0x10FFFFu);
+}
+
+inline bool IsValidCharacter(uint32 code_point) {
+  // Excludes non-characters (U+FDD0..U+FDEF, and all codepoints ending in
+  // 0xFFFE or 0xFFFF) from the set of valid code points.
+  return code_point < 0xD800u || (code_point >= 0xE000u &&
+      code_point < 0xFDD0u) || (code_point > 0xFDEFu &&
+      code_point <= 0x10FFFFu && (code_point & 0xFFFEu) != 0xFFFEu);
+}
+
+// ReadUnicodeCharacter --------------------------------------------------------
+
+// Reads a UTF-8 stream, placing the next code point into the given output
+// |*code_point|. |src| represents the entire string to read, and |*char_index|
+// is the character offset within the string to start reading at. |*char_index|
+// will be updated to index the last character read, such that incrementing it
+// (as in a for loop) will take the reader to the next character.
+//
+// Returns true on success. On false, |*code_point| will be invalid.
+BASE_EXPORT bool ReadUnicodeCharacter(const char* src,
+                                      int32 src_len,
+                                      int32* char_index,
+                                      uint32* code_point_out);
+
+// Reads a UTF-16 character. The usage is the same as the 8-bit version above.
+BASE_EXPORT bool ReadUnicodeCharacter(const char16* src,
+                                      int32 src_len,
+                                      int32* char_index,
+                                      uint32* code_point);
+
+#if defined(WCHAR_T_IS_UTF32)
+// Reads UTF-32 character. The usage is the same as the 8-bit version above.
+BASE_EXPORT bool ReadUnicodeCharacter(const wchar_t* src,
+                                      int32 src_len,
+                                      int32* char_index,
+                                      uint32* code_point);
+#endif  // defined(WCHAR_T_IS_UTF32)
+
+// WriteUnicodeCharacter -------------------------------------------------------
+
+// Appends a UTF-8 character to the given 8-bit string.  Returns the number of
+// bytes written.
+// TODO(brettw) Bug 79631: This function should not be exposed.
+BASE_EXPORT size_t WriteUnicodeCharacter(uint32 code_point,
+                                         std::string* output);
+
+// Appends the given code point as a UTF-16 character to the given 16-bit
+// string.  Returns the number of 16-bit values written.
+BASE_EXPORT size_t WriteUnicodeCharacter(uint32 code_point, string16* output);
+
+#if defined(WCHAR_T_IS_UTF32)
+// Appends the given UTF-32 character to the given 32-bit string.  Returns the
+// number of 32-bit values written.
+inline size_t WriteUnicodeCharacter(uint32 code_point, std::wstring* output) {
+  // This is the easy case, just append the character.
+  output->push_back(code_point);
+  return 1;
+}
+#endif  // defined(WCHAR_T_IS_UTF32)
+
+// Generalized Unicode converter -----------------------------------------------
+
+// Guesses the length of the output in UTF-8 in bytes, clears that output
+// string, and reserves that amount of space.  We assume that the input
+// character types are unsigned, which will be true for UTF-16 and -32 on our
+// systems.
+template<typename CHAR>
+void PrepareForUTF8Output(const CHAR* src, size_t src_len, std::string* output);
+
+// Prepares an output buffer (containing either UTF-16 or -32 data) given some
+// UTF-8 input that will be converted to it.  See PrepareForUTF8Output().
+template<typename STRING>
+void PrepareForUTF16Or32Output(const char* src, size_t src_len, STRING* output);
+
+}  // namespace base
+
+#endif  // BASE_STRINGS_UTF_STRING_CONVERSION_UTILS_H_
diff --git a/base/strings/utf_string_conversions.cc b/base/strings/utf_string_conversions.cc
new file mode 100644
index 0000000..1480d48
--- /dev/null
+++ b/base/strings/utf_string_conversions.cc
@@ -0,0 +1,222 @@
+// Copyright (c) 2010 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/strings/utf_string_conversions.h"
+
+#include "base/strings/string_piece.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversion_utils.h"
+
+namespace base {
+
+namespace {
+
+// Generalized Unicode converter -----------------------------------------------
+
+// Converts the given source Unicode character type to the given destination
+// Unicode character type as a STL string. The given input buffer and size
+// determine the source, and the given output STL string will be replaced by
+// the result.
+template<typename SRC_CHAR, typename DEST_STRING>
+bool ConvertUnicode(const SRC_CHAR* src,
+                    size_t src_len,
+                    DEST_STRING* output) {
+  // ICU requires 32-bit numbers.
+  bool success = true;
+  int32 src_len32 = static_cast<int32>(src_len);
+  for (int32 i = 0; i < src_len32; i++) {
+    uint32 code_point;
+    if (ReadUnicodeCharacter(src, src_len32, &i, &code_point)) {
+      WriteUnicodeCharacter(code_point, output);
+    } else {
+      WriteUnicodeCharacter(0xFFFD, output);
+      success = false;
+    }
+  }
+
+  return success;
+}
+
+}  // namespace
+
+// UTF-8 <-> Wide --------------------------------------------------------------
+
+bool WideToUTF8(const wchar_t* src, size_t src_len, std::string* output) {
+  if (IsStringASCII(std::wstring(src, src_len))) {
+    output->assign(src, src + src_len);
+    return true;
+  } else {
+    PrepareForUTF8Output(src, src_len, output);
+    return ConvertUnicode(src, src_len, output);
+  }
+}
+
+std::string WideToUTF8(const std::wstring& wide) {
+  if (IsStringASCII(wide)) {
+    return std::string(wide.data(), wide.data() + wide.length());
+  }
+
+  std::string ret;
+  PrepareForUTF8Output(wide.data(), wide.length(), &ret);
+  ConvertUnicode(wide.data(), wide.length(), &ret);
+  return ret;
+}
+
+bool UTF8ToWide(const char* src, size_t src_len, std::wstring* output) {
+  if (IsStringASCII(StringPiece(src, src_len))) {
+    output->assign(src, src + src_len);
+    return true;
+  } else {
+    PrepareForUTF16Or32Output(src, src_len, output);
+    return ConvertUnicode(src, src_len, output);
+  }
+}
+
+std::wstring UTF8ToWide(const StringPiece& utf8) {
+  if (IsStringASCII(utf8)) {
+    return std::wstring(utf8.begin(), utf8.end());
+  }
+
+  std::wstring ret;
+  PrepareForUTF16Or32Output(utf8.data(), utf8.length(), &ret);
+  ConvertUnicode(utf8.data(), utf8.length(), &ret);
+  return ret;
+}
+
+// UTF-16 <-> Wide -------------------------------------------------------------
+
+#if defined(WCHAR_T_IS_UTF16)
+
+// When wide == UTF-16, then conversions are a NOP.
+bool WideToUTF16(const wchar_t* src, size_t src_len, string16* output) {
+  output->assign(src, src_len);
+  return true;
+}
+
+string16 WideToUTF16(const std::wstring& wide) {
+  return wide;
+}
+
+bool UTF16ToWide(const char16* src, size_t src_len, std::wstring* output) {
+  output->assign(src, src_len);
+  return true;
+}
+
+std::wstring UTF16ToWide(const string16& utf16) {
+  return utf16;
+}
+
+#elif defined(WCHAR_T_IS_UTF32)
+
+bool WideToUTF16(const wchar_t* src, size_t src_len, string16* output) {
+  output->clear();
+  // Assume that normally we won't have any non-BMP characters so the counts
+  // will be the same.
+  output->reserve(src_len);
+  return ConvertUnicode(src, src_len, output);
+}
+
+string16 WideToUTF16(const std::wstring& wide) {
+  string16 ret;
+  WideToUTF16(wide.data(), wide.length(), &ret);
+  return ret;
+}
+
+bool UTF16ToWide(const char16* src, size_t src_len, std::wstring* output) {
+  output->clear();
+  // Assume that normally we won't have any non-BMP characters so the counts
+  // will be the same.
+  output->reserve(src_len);
+  return ConvertUnicode(src, src_len, output);
+}
+
+std::wstring UTF16ToWide(const string16& utf16) {
+  std::wstring ret;
+  UTF16ToWide(utf16.data(), utf16.length(), &ret);
+  return ret;
+}
+
+#endif  // defined(WCHAR_T_IS_UTF32)
+
+// UTF16 <-> UTF8 --------------------------------------------------------------
+
+#if defined(WCHAR_T_IS_UTF32)
+
+bool UTF8ToUTF16(const char* src, size_t src_len, string16* output) {
+  if (IsStringASCII(StringPiece(src, src_len))) {
+    output->assign(src, src + src_len);
+    return true;
+  } else {
+    PrepareForUTF16Or32Output(src, src_len, output);
+    return ConvertUnicode(src, src_len, output);
+  }
+}
+
+string16 UTF8ToUTF16(const StringPiece& utf8) {
+  if (IsStringASCII(utf8)) {
+    return string16(utf8.begin(), utf8.end());
+  }
+
+  string16 ret;
+  PrepareForUTF16Or32Output(utf8.data(), utf8.length(), &ret);
+  // Ignore the success flag of this call, it will do the best it can for
+  // invalid input, which is what we want here.
+  ConvertUnicode(utf8.data(), utf8.length(), &ret);
+  return ret;
+}
+
+bool UTF16ToUTF8(const char16* src, size_t src_len, std::string* output) {
+  if (IsStringASCII(StringPiece16(src, src_len))) {
+    output->assign(src, src + src_len);
+    return true;
+  } else {
+    PrepareForUTF8Output(src, src_len, output);
+    return ConvertUnicode(src, src_len, output);
+  }
+}
+
+std::string UTF16ToUTF8(const string16& utf16) {
+  if (IsStringASCII(utf16)) {
+    return std::string(utf16.begin(), utf16.end());
+  }
+
+  std::string ret;
+  // Ignore the success flag of this call, it will do the best it can for
+  // invalid input, which is what we want here.
+  UTF16ToUTF8(utf16.data(), utf16.length(), &ret);
+  return ret;
+}
+
+#elif defined(WCHAR_T_IS_UTF16)
+// Easy case since we can use the "wide" versions we already wrote above.
+
+bool UTF8ToUTF16(const char* src, size_t src_len, string16* output) {
+  return UTF8ToWide(src, src_len, output);
+}
+
+string16 UTF8ToUTF16(const StringPiece& utf8) {
+  return UTF8ToWide(utf8);
+}
+
+bool UTF16ToUTF8(const char16* src, size_t src_len, std::string* output) {
+  return WideToUTF8(src, src_len, output);
+}
+
+std::string UTF16ToUTF8(const string16& utf16) {
+  return WideToUTF8(utf16);
+}
+
+#endif
+
+string16 ASCIIToUTF16(const StringPiece& ascii) {
+  DCHECK(IsStringASCII(ascii)) << ascii;
+  return string16(ascii.begin(), ascii.end());
+}
+
+std::string UTF16ToASCII(const string16& utf16) {
+  DCHECK(IsStringASCII(utf16)) << UTF16ToUTF8(utf16);
+  return std::string(utf16.begin(), utf16.end());
+}
+
+}  // namespace base
diff --git a/base/strings/utf_string_conversions.h b/base/strings/utf_string_conversions.h
new file mode 100644
index 0000000..06a3bc6
--- /dev/null
+++ b/base/strings/utf_string_conversions.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2011 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_STRINGS_UTF_STRING_CONVERSIONS_H_
+#define BASE_STRINGS_UTF_STRING_CONVERSIONS_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+// These convert between UTF-8, -16, and -32 strings. They are potentially slow,
+// so avoid unnecessary conversions. The low-level versions return a boolean
+// indicating whether the conversion was 100% valid. In this case, it will still
+// do the best it can and put the result in the output buffer. The versions that
+// return strings ignore this error and just return the best conversion
+// possible.
+BASE_EXPORT bool WideToUTF8(const wchar_t* src, size_t src_len,
+                            std::string* output);
+BASE_EXPORT std::string WideToUTF8(const std::wstring& wide);
+BASE_EXPORT bool UTF8ToWide(const char* src, size_t src_len,
+                            std::wstring* output);
+BASE_EXPORT std::wstring UTF8ToWide(const StringPiece& utf8);
+
+BASE_EXPORT bool WideToUTF16(const wchar_t* src, size_t src_len,
+                             string16* output);
+BASE_EXPORT string16 WideToUTF16(const std::wstring& wide);
+BASE_EXPORT bool UTF16ToWide(const char16* src, size_t src_len,
+                             std::wstring* output);
+BASE_EXPORT std::wstring UTF16ToWide(const string16& utf16);
+
+BASE_EXPORT bool UTF8ToUTF16(const char* src, size_t src_len, string16* output);
+BASE_EXPORT string16 UTF8ToUTF16(const StringPiece& utf8);
+BASE_EXPORT bool UTF16ToUTF8(const char16* src, size_t src_len,
+                             std::string* output);
+BASE_EXPORT std::string UTF16ToUTF8(const string16& utf16);
+
+// This converts an ASCII string, typically a hardcoded constant, to a UTF16
+// string.
+BASE_EXPORT string16 ASCIIToUTF16(const StringPiece& ascii);
+
+// Converts to 7-bit ASCII by truncating. The result must be known to be ASCII
+// beforehand.
+BASE_EXPORT std::string UTF16ToASCII(const string16& utf16);
+
+}  // namespace base
+
+#endif  // BASE_STRINGS_UTF_STRING_CONVERSIONS_H_
diff --git a/base/strings/utf_string_conversions_unittest.cc b/base/strings/utf_string_conversions_unittest.cc
new file mode 100644
index 0000000..a7b12ff
--- /dev/null
+++ b/base/strings/utf_string_conversions_unittest.cc
@@ -0,0 +1,211 @@
+// Copyright (c) 2010 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/basictypes.h"
+#include "base/logging.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+const wchar_t* const kConvertRoundtripCases[] = {
+  L"Google Video",
+  // "网页 图片 资讯更多 »"
+  L"\x7f51\x9875\x0020\x56fe\x7247\x0020\x8d44\x8baf\x66f4\x591a\x0020\x00bb",
+  //  "Παγκόσμιος Ιστός"
+  L"\x03a0\x03b1\x03b3\x03ba\x03cc\x03c3\x03bc\x03b9"
+  L"\x03bf\x03c2\x0020\x0399\x03c3\x03c4\x03cc\x03c2",
+  // "Поиск страниц на русском"
+  L"\x041f\x043e\x0438\x0441\x043a\x0020\x0441\x0442"
+  L"\x0440\x0430\x043d\x0438\x0446\x0020\x043d\x0430"
+  L"\x0020\x0440\x0443\x0441\x0441\x043a\x043e\x043c",
+  // "전체서비스"
+  L"\xc804\xccb4\xc11c\xbe44\xc2a4",
+
+  // Test characters that take more than 16 bits. This will depend on whether
+  // wchar_t is 16 or 32 bits.
+#if defined(WCHAR_T_IS_UTF16)
+  L"\xd800\xdf00",
+  // ?????  (Mathematical Alphanumeric Symbols (U+011d40 - U+011d44 : A,B,C,D,E)
+  L"\xd807\xdd40\xd807\xdd41\xd807\xdd42\xd807\xdd43\xd807\xdd44",
+#elif defined(WCHAR_T_IS_UTF32)
+  L"\x10300",
+  // ?????  (Mathematical Alphanumeric Symbols (U+011d40 - U+011d44 : A,B,C,D,E)
+  L"\x11d40\x11d41\x11d42\x11d43\x11d44",
+#endif
+};
+
+}  // namespace
+
+TEST(UTFStringConversionsTest, ConvertUTF8AndWide) {
+  // we round-trip all the wide strings through UTF-8 to make sure everything
+  // agrees on the conversion. This uses the stream operators to test them
+  // simultaneously.
+  for (size_t i = 0; i < arraysize(kConvertRoundtripCases); ++i) {
+    std::ostringstream utf8;
+    utf8 << WideToUTF8(kConvertRoundtripCases[i]);
+    std::wostringstream wide;
+    wide << UTF8ToWide(utf8.str());
+
+    EXPECT_EQ(kConvertRoundtripCases[i], wide.str());
+  }
+}
+
+TEST(UTFStringConversionsTest, ConvertUTF8AndWideEmptyString) {
+  // An empty std::wstring should be converted to an empty std::string,
+  // and vice versa.
+  std::wstring wempty;
+  std::string empty;
+  EXPECT_EQ(empty, WideToUTF8(wempty));
+  EXPECT_EQ(wempty, UTF8ToWide(empty));
+}
+
+TEST(UTFStringConversionsTest, ConvertUTF8ToWide) {
+  struct UTF8ToWideCase {
+    const char* utf8;
+    const wchar_t* wide;
+    bool success;
+  } convert_cases[] = {
+    // Regular UTF-8 input.
+    {"\xe4\xbd\xa0\xe5\xa5\xbd", L"\x4f60\x597d", true},
+    // Non-character is passed through.
+    {"\xef\xbf\xbfHello", L"\xffffHello", true},
+    // Truncated UTF-8 sequence.
+    {"\xe4\xa0\xe5\xa5\xbd", L"\xfffd\x597d", false},
+    // Truncated off the end.
+    {"\xe5\xa5\xbd\xe4\xa0", L"\x597d\xfffd", false},
+    // Non-shortest-form UTF-8.
+    {"\xf0\x84\xbd\xa0\xe5\xa5\xbd", L"\xfffd\x597d", false},
+    // This UTF-8 character decodes to a UTF-16 surrogate, which is illegal.
+    {"\xed\xb0\x80", L"\xfffd", false},
+    // Non-BMP characters. The second is a non-character regarded as valid.
+    // The result will either be in UTF-16 or UTF-32.
+#if defined(WCHAR_T_IS_UTF16)
+    {"A\xF0\x90\x8C\x80z", L"A\xd800\xdf00z", true},
+    {"A\xF4\x8F\xBF\xBEz", L"A\xdbff\xdffez", true},
+#elif defined(WCHAR_T_IS_UTF32)
+    {"A\xF0\x90\x8C\x80z", L"A\x10300z", true},
+    {"A\xF4\x8F\xBF\xBEz", L"A\x10fffez", true},
+#endif
+  };
+
+  for (size_t i = 0; i < arraysize(convert_cases); i++) {
+    std::wstring converted;
+    EXPECT_EQ(convert_cases[i].success,
+              UTF8ToWide(convert_cases[i].utf8,
+                         strlen(convert_cases[i].utf8),
+                         &converted));
+    std::wstring expected(convert_cases[i].wide);
+    EXPECT_EQ(expected, converted);
+  }
+
+  // Manually test an embedded NULL.
+  std::wstring converted;
+  EXPECT_TRUE(UTF8ToWide("\00Z\t", 3, &converted));
+  ASSERT_EQ(3U, converted.length());
+  EXPECT_EQ(static_cast<wchar_t>(0), converted[0]);
+  EXPECT_EQ('Z', converted[1]);
+  EXPECT_EQ('\t', converted[2]);
+
+  // Make sure that conversion replaces, not appends.
+  EXPECT_TRUE(UTF8ToWide("B", 1, &converted));
+  ASSERT_EQ(1U, converted.length());
+  EXPECT_EQ('B', converted[0]);
+}
+
+#if defined(WCHAR_T_IS_UTF16)
+// This test is only valid when wchar_t == UTF-16.
+TEST(UTFStringConversionsTest, ConvertUTF16ToUTF8) {
+  struct WideToUTF8Case {
+    const wchar_t* utf16;
+    const char* utf8;
+    bool success;
+  } convert_cases[] = {
+    // Regular UTF-16 input.
+    {L"\x4f60\x597d", "\xe4\xbd\xa0\xe5\xa5\xbd", true},
+    // Test a non-BMP character.
+    {L"\xd800\xdf00", "\xF0\x90\x8C\x80", true},
+    // Non-characters are passed through.
+    {L"\xffffHello", "\xEF\xBF\xBFHello", true},
+    {L"\xdbff\xdffeHello", "\xF4\x8F\xBF\xBEHello", true},
+    // The first character is a truncated UTF-16 character.
+    {L"\xd800\x597d", "\xef\xbf\xbd\xe5\xa5\xbd", false},
+    // Truncated at the end.
+    {L"\x597d\xd800", "\xe5\xa5\xbd\xef\xbf\xbd", false},
+  };
+
+  for (int i = 0; i < arraysize(convert_cases); i++) {
+    std::string converted;
+    EXPECT_EQ(convert_cases[i].success,
+              WideToUTF8(convert_cases[i].utf16,
+                         wcslen(convert_cases[i].utf16),
+                         &converted));
+    std::string expected(convert_cases[i].utf8);
+    EXPECT_EQ(expected, converted);
+  }
+}
+
+#elif defined(WCHAR_T_IS_UTF32)
+// This test is only valid when wchar_t == UTF-32.
+TEST(UTFStringConversionsTest, ConvertUTF32ToUTF8) {
+  struct WideToUTF8Case {
+    const wchar_t* utf32;
+    const char* utf8;
+    bool success;
+  } convert_cases[] = {
+    // Regular 16-bit input.
+    {L"\x4f60\x597d", "\xe4\xbd\xa0\xe5\xa5\xbd", true},
+    // Test a non-BMP character.
+    {L"A\x10300z", "A\xF0\x90\x8C\x80z", true},
+    // Non-characters are passed through.
+    {L"\xffffHello", "\xEF\xBF\xBFHello", true},
+    {L"\x10fffeHello", "\xF4\x8F\xBF\xBEHello", true},
+    // Invalid Unicode code points.
+    {L"\xfffffffHello", "\xEF\xBF\xBDHello", false},
+    // The first character is a truncated UTF-16 character.
+    {L"\xd800\x597d", "\xef\xbf\xbd\xe5\xa5\xbd", false},
+    {L"\xdc01Hello", "\xef\xbf\xbdHello", false},
+  };
+
+  for (size_t i = 0; i < arraysize(convert_cases); i++) {
+    std::string converted;
+    EXPECT_EQ(convert_cases[i].success,
+              WideToUTF8(convert_cases[i].utf32,
+                         wcslen(convert_cases[i].utf32),
+                         &converted));
+    std::string expected(convert_cases[i].utf8);
+    EXPECT_EQ(expected, converted);
+  }
+}
+#endif  // defined(WCHAR_T_IS_UTF32)
+
+TEST(UTFStringConversionsTest, ConvertMultiString) {
+  static wchar_t wmulti[] = {
+    L'f', L'o', L'o', L'\0',
+    L'b', L'a', L'r', L'\0',
+    L'b', L'a', L'z', L'\0',
+    L'\0'
+  };
+  static char multi[] = {
+    'f', 'o', 'o', '\0',
+    'b', 'a', 'r', '\0',
+    'b', 'a', 'z', '\0',
+    '\0'
+  };
+  std::wstring wmultistring;
+  memcpy(WriteInto(&wmultistring, arraysize(wmulti)), wmulti, sizeof(wmulti));
+  EXPECT_EQ(arraysize(wmulti) - 1, wmultistring.length());
+  std::string expected;
+  memcpy(WriteInto(&expected, arraysize(multi)), multi, sizeof(multi));
+  EXPECT_EQ(arraysize(multi) - 1, expected.length());
+  const std::string& converted = WideToUTF8(wmultistring);
+  EXPECT_EQ(arraysize(multi) - 1, converted.length());
+  EXPECT_EQ(expected, converted);
+}
+
+}  // namespace base
diff --git a/base/supports_user_data.cc b/base/supports_user_data.cc
new file mode 100644
index 0000000..9689014
--- /dev/null
+++ b/base/supports_user_data.cc
@@ -0,0 +1,45 @@
+// Copyright (c) 2012 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/supports_user_data.h"
+
+namespace base {
+
+SupportsUserData::SupportsUserData() {
+  // Harmless to construct on a different thread to subsequent usage.
+  thread_checker_.DetachFromThread();
+}
+
+SupportsUserData::Data* SupportsUserData::GetUserData(const void* key) const {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DataMap::const_iterator found = user_data_.find(key);
+  if (found != user_data_.end())
+    return found->second.get();
+  return NULL;
+}
+
+void SupportsUserData::SetUserData(const void* key, Data* data) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  user_data_[key] = linked_ptr<Data>(data);
+}
+
+void SupportsUserData::RemoveUserData(const void* key) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  user_data_.erase(key);
+}
+
+void SupportsUserData::DetachUserDataThread() {
+  thread_checker_.DetachFromThread();
+}
+
+SupportsUserData::~SupportsUserData() {
+  DCHECK(thread_checker_.CalledOnValidThread() || user_data_.empty());
+  DataMap local_user_data;
+  user_data_.swap(local_user_data);
+  // Now this->user_data_ is empty, and any destructors called transitively from
+  // the destruction of |local_user_data| will see it that way instead of
+  // examining a being-destroyed object.
+}
+
+}  // namespace base
diff --git a/base/supports_user_data.h b/base/supports_user_data.h
new file mode 100644
index 0000000..711ee7d
--- /dev/null
+++ b/base/supports_user_data.h
@@ -0,0 +1,81 @@
+// Copyright (c) 2012 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_SUPPORTS_USER_DATA_H_
+#define BASE_SUPPORTS_USER_DATA_H_
+
+#include <map>
+
+#include "base/base_export.h"
+#include "base/memory/linked_ptr.h"
+#include "base/memory/ref_counted.h"
+#include "base/threading/thread_checker.h"
+
+namespace base {
+
+// This is a helper for classes that want to allow users to stash random data by
+// key. At destruction all the objects will be destructed.
+class BASE_EXPORT SupportsUserData {
+ public:
+  SupportsUserData();
+
+  // Derive from this class and add your own data members to associate extra
+  // information with this object. Alternatively, add this as a public base
+  // class to any class with a virtual destructor.
+  class BASE_EXPORT Data {
+   public:
+    virtual ~Data() {}
+  };
+
+  // The user data allows the clients to associate data with this object.
+  // Multiple user data values can be stored under different keys.
+  // This object will TAKE OWNERSHIP of the given data pointer, and will
+  // delete the object if it is changed or the object is destroyed.
+  Data* GetUserData(const void* key) const;
+  void SetUserData(const void* key, Data* data);
+  void RemoveUserData(const void* key);
+
+  // SupportsUserData is not thread-safe, and on debug build will assert it is
+  // only used on one thread. Calling this method allows the caller to hand
+  // the SupportsUserData instance across threads. Use only if you are taking
+  // full control of the synchronization of that hand over.
+  void DetachUserDataThread();
+
+ protected:
+  virtual ~SupportsUserData();
+
+ private:
+  typedef std::map<const void*, linked_ptr<Data> > DataMap;
+
+  // Externally-defined data accessible by key.
+  DataMap user_data_;
+  // Guards usage of |user_data_|
+  ThreadChecker thread_checker_;
+
+  DISALLOW_COPY_AND_ASSIGN(SupportsUserData);
+};
+
+// Adapter class that releases a refcounted object when the
+// SupportsUserData::Data object is deleted.
+template <typename T>
+class UserDataAdapter : public base::SupportsUserData::Data {
+ public:
+  static T* Get(const SupportsUserData* supports_user_data, const void* key) {
+    UserDataAdapter* data =
+      static_cast<UserDataAdapter*>(supports_user_data->GetUserData(key));
+    return data ? static_cast<T*>(data->object_.get()) : NULL;
+  }
+
+  UserDataAdapter(T* object) : object_(object) {}
+  T* release() { return object_.release(); }
+
+ private:
+  scoped_refptr<T> object_;
+
+  DISALLOW_COPY_AND_ASSIGN(UserDataAdapter);
+};
+
+}  // namespace base
+
+#endif  // BASE_SUPPORTS_USER_DATA_H_
diff --git a/base/supports_user_data_unittest.cc b/base/supports_user_data_unittest.cc
new file mode 100644
index 0000000..faa8140
--- /dev/null
+++ b/base/supports_user_data_unittest.cc
@@ -0,0 +1,39 @@
+// 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.
+
+#include "base/supports_user_data.h"
+
+#include <vector>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+struct TestSupportsUserData : public SupportsUserData {};
+
+struct UsesItself : public SupportsUserData::Data {
+  UsesItself(SupportsUserData* supports_user_data, const void* key)
+      : supports_user_data_(supports_user_data),
+        key_(key) {
+  }
+
+  ~UsesItself() override {
+    EXPECT_EQ(NULL, supports_user_data_->GetUserData(key_));
+  }
+
+  SupportsUserData* supports_user_data_;
+  const void* key_;
+};
+
+TEST(SupportsUserDataTest, ClearWorksRecursively) {
+  TestSupportsUserData supports_user_data;
+  char key = 0;
+  supports_user_data.SetUserData(&key,
+                                 new UsesItself(&supports_user_data, &key));
+  // Destruction of supports_user_data runs the actual test.
+}
+
+}  // namespace
+}  // namespace base
diff --git a/base/sync_socket.h b/base/sync_socket.h
new file mode 100644
index 0000000..36d6bc1
--- /dev/null
+++ b/base/sync_socket.h
@@ -0,0 +1,157 @@
+// Copyright (c) 2012 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_SYNC_SOCKET_H_
+#define BASE_SYNC_SOCKET_H_
+
+// A socket abstraction used for sending and receiving plain
+// data.  Because the receiving is blocking, they can be used to perform
+// rudimentary cross-process synchronization with low latency.
+
+#include "base/basictypes.h"
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+#include <sys/types.h>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/process/process_handle.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/time/time.h"
+
+#if defined(OS_POSIX)
+#include "base/file_descriptor_posix.h"
+#endif
+
+namespace base {
+
+class BASE_EXPORT SyncSocket {
+ public:
+#if defined(OS_WIN)
+  typedef HANDLE Handle;
+  typedef Handle TransitDescriptor;
+#else
+  typedef int Handle;
+  typedef FileDescriptor TransitDescriptor;
+#endif
+  static const Handle kInvalidHandle;
+
+  SyncSocket();
+
+  // Creates a SyncSocket from a Handle.  Used in transport.
+  explicit SyncSocket(Handle handle) : handle_(handle)  {}
+  virtual ~SyncSocket();
+
+  // Initializes and connects a pair of sockets.
+  // |socket_a| and |socket_b| must not hold a valid handle.  Upon successful
+  // return, the sockets will both be valid and connected.
+  static bool CreatePair(SyncSocket* socket_a, SyncSocket* socket_b);
+
+  // Returns |Handle| wrapped in a |TransitDescriptor|.
+  static Handle UnwrapHandle(const TransitDescriptor& descriptor);
+
+  // Prepares a |TransitDescriptor| which wraps |Handle| used for transit.
+  // This is used to prepare the underlying shared resource before passing back
+  // the handle to be used by the peer process.
+  bool PrepareTransitDescriptor(ProcessHandle peer_process_handle,
+                                TransitDescriptor* descriptor);
+
+  // Closes the SyncSocket.  Returns true on success, false on failure.
+  virtual bool Close();
+
+  // Sends the message to the remote peer of the SyncSocket.
+  // Note it is not safe to send messages from the same socket handle by
+  // multiple threads simultaneously.
+  // buffer is a pointer to the data to send.
+  // length is the length of the data to send (must be non-zero).
+  // Returns the number of bytes sent, or 0 upon failure.
+  virtual size_t Send(const void* buffer, size_t length);
+
+  // Receives a message from an SyncSocket.
+  // buffer is a pointer to the buffer to receive data.
+  // length is the number of bytes of data to receive (must be non-zero).
+  // Returns the number of bytes received, or 0 upon failure.
+  virtual size_t Receive(void* buffer, size_t length);
+
+  // Same as Receive() but only blocks for data until |timeout| has elapsed or
+  // |buffer| |length| is exhausted.  Currently only timeouts less than one
+  // second are allowed.  Return the amount of data read.
+  virtual size_t ReceiveWithTimeout(void* buffer,
+                                    size_t length,
+                                    TimeDelta timeout);
+
+  // Returns the number of bytes available. If non-zero, Receive() will not
+  // not block when called. NOTE: Some implementations cannot reliably
+  // determine the number of bytes available so avoid using the returned
+  // size as a promise and simply test against zero.
+  size_t Peek();
+
+  // Extracts the contained handle.  Used for transferring between
+  // processes.
+  Handle handle() const { return handle_; }
+
+ protected:
+  Handle handle_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SyncSocket);
+};
+
+// Derives from SyncSocket and adds support for shutting down the socket from
+// another thread while a blocking Receive or Send is being done from the
+// thread that owns the socket.
+class BASE_EXPORT CancelableSyncSocket : public SyncSocket {
+ public:
+  CancelableSyncSocket();
+  explicit CancelableSyncSocket(Handle handle);
+  ~CancelableSyncSocket() override {}
+
+  // Initializes a pair of cancelable sockets.  See documentation for
+  // SyncSocket::CreatePair for more details.
+  static bool CreatePair(CancelableSyncSocket* socket_a,
+                         CancelableSyncSocket* socket_b);
+
+  // A way to shut down a socket even if another thread is currently performing
+  // a blocking Receive or Send.
+  bool Shutdown();
+
+#if defined(OS_WIN)
+  // Since the Linux and Mac implementations actually use a socket, shutting
+  // them down from another thread is pretty simple - we can just call
+  // shutdown().  However, the Windows implementation relies on named pipes
+  // and there isn't a way to cancel a blocking synchronous Read that is
+  // supported on <Vista. So, for Windows only, we override these
+  // SyncSocket methods in order to support shutting down the 'socket'.
+  bool Close() override;
+  size_t Receive(void* buffer, size_t length) override;
+  size_t ReceiveWithTimeout(void* buffer,
+                            size_t length,
+                            TimeDelta timeout) override;
+#endif
+
+  // Send() is overridden to catch cases where the remote end is not responding
+  // and we fill the local socket buffer. When the buffer is full, this
+  // implementation of Send() will not block indefinitely as
+  // SyncSocket::Send will, but instead return 0, as no bytes could be sent.
+  // Note that the socket will not be closed in this case.
+  size_t Send(const void* buffer, size_t length) override;
+
+ private:
+#if defined(OS_WIN)
+  WaitableEvent shutdown_event_;
+  WaitableEvent file_operation_;
+#endif
+  DISALLOW_COPY_AND_ASSIGN(CancelableSyncSocket);
+};
+
+#if defined(OS_WIN) && !defined(COMPONENT_BUILD)
+// TODO(cpu): remove this once chrome is split in two dlls.
+__declspec(selectany)
+    const SyncSocket::Handle SyncSocket::kInvalidHandle = INVALID_HANDLE_VALUE;
+#endif
+
+}  // namespace base
+
+#endif  // BASE_SYNC_SOCKET_H_
diff --git a/base/sync_socket_nacl.cc b/base/sync_socket_nacl.cc
new file mode 100644
index 0000000..9e9243d
--- /dev/null
+++ b/base/sync_socket_nacl.cc
@@ -0,0 +1,98 @@
+// Copyright (c) 2012 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/sync_socket.h"
+
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "base/logging.h"
+
+namespace base {
+
+const SyncSocket::Handle SyncSocket::kInvalidHandle = -1;
+
+SyncSocket::SyncSocket() : handle_(kInvalidHandle) {
+}
+
+SyncSocket::~SyncSocket() {
+  Close();
+}
+
+// static
+bool SyncSocket::CreatePair(SyncSocket* socket_a, SyncSocket* socket_b) {
+  return false;
+}
+
+// static
+SyncSocket::Handle SyncSocket::UnwrapHandle(
+    const SyncSocket::TransitDescriptor& descriptor) {
+  // TODO(xians): Still unclear how NaCl uses SyncSocket.
+  // See http://crbug.com/409656
+  NOTIMPLEMENTED();
+  return SyncSocket::kInvalidHandle;
+}
+
+bool SyncSocket::PrepareTransitDescriptor(
+    ProcessHandle peer_process_handle,
+    SyncSocket::TransitDescriptor* descriptor) {
+  // TODO(xians): Still unclear how NaCl uses SyncSocket.
+  // See http://crbug.com/409656
+  NOTIMPLEMENTED();
+  return false;
+}
+
+bool SyncSocket::Close() {
+  if (handle_ != kInvalidHandle) {
+    if (close(handle_) < 0)
+      DPLOG(ERROR) << "close";
+    handle_ = kInvalidHandle;
+  }
+  return true;
+}
+
+size_t SyncSocket::Send(const void* buffer, size_t length) {
+  const ssize_t bytes_written = write(handle_, buffer, length);
+  return bytes_written > 0 ? bytes_written : 0;
+}
+
+size_t SyncSocket::Receive(void* buffer, size_t length) {
+  const ssize_t bytes_read = read(handle_, buffer, length);
+  return bytes_read > 0 ? bytes_read : 0;
+}
+
+size_t SyncSocket::ReceiveWithTimeout(void* buffer, size_t length, TimeDelta) {
+  NOTIMPLEMENTED();
+  return 0;
+}
+
+size_t SyncSocket::Peek() {
+  NOTIMPLEMENTED();
+  return 0;
+}
+
+CancelableSyncSocket::CancelableSyncSocket() {
+}
+
+CancelableSyncSocket::CancelableSyncSocket(Handle handle)
+    : SyncSocket(handle) {
+}
+
+size_t CancelableSyncSocket::Send(const void* buffer, size_t length) {
+  return SyncSocket::Send(buffer, length);
+}
+
+bool CancelableSyncSocket::Shutdown() {
+  return SyncSocket::Close();
+}
+
+// static
+bool CancelableSyncSocket::CreatePair(CancelableSyncSocket* socket_a,
+                                      CancelableSyncSocket* socket_b) {
+  return SyncSocket::CreatePair(socket_a, socket_b);
+}
+
+}  // namespace base
diff --git a/base/sync_socket_posix.cc b/base/sync_socket_posix.cc
new file mode 100644
index 0000000..51b38a5
--- /dev/null
+++ b/base/sync_socket_posix.cc
@@ -0,0 +1,246 @@
+// Copyright (c) 2012 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/sync_socket.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#if defined(OS_SOLARIS)
+#include <sys/filio.h>
+#endif
+
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace base {
+
+namespace {
+// To avoid users sending negative message lengths to Send/Receive
+// we clamp message lengths, which are size_t, to no more than INT_MAX.
+const size_t kMaxMessageLength = static_cast<size_t>(INT_MAX);
+
+// Writes |length| of |buffer| into |handle|.  Returns the number of bytes
+// written or zero on error.  |length| must be greater than 0.
+size_t SendHelper(SyncSocket::Handle handle,
+                  const void* buffer,
+                  size_t length) {
+  DCHECK_GT(length, 0u);
+  DCHECK_LE(length, kMaxMessageLength);
+  DCHECK_NE(handle, SyncSocket::kInvalidHandle);
+  const char* charbuffer = static_cast<const char*>(buffer);
+  return WriteFileDescriptor(handle, charbuffer, length)
+             ? static_cast<size_t>(length)
+             : 0;
+}
+
+bool CloseHandle(SyncSocket::Handle handle) {
+  if (handle != SyncSocket::kInvalidHandle && close(handle) < 0) {
+    DPLOG(ERROR) << "close";
+    return false;
+  }
+
+  return true;
+}
+
+}  // namespace
+
+const SyncSocket::Handle SyncSocket::kInvalidHandle = -1;
+
+SyncSocket::SyncSocket() : handle_(kInvalidHandle) {}
+
+SyncSocket::~SyncSocket() {
+  Close();
+}
+
+// static
+bool SyncSocket::CreatePair(SyncSocket* socket_a, SyncSocket* socket_b) {
+  DCHECK_NE(socket_a, socket_b);
+  DCHECK_EQ(socket_a->handle_, kInvalidHandle);
+  DCHECK_EQ(socket_b->handle_, kInvalidHandle);
+
+#if defined(OS_MACOSX)
+  int nosigpipe = 1;
+#endif  // defined(OS_MACOSX)
+
+  Handle handles[2] = { kInvalidHandle, kInvalidHandle };
+  if (socketpair(AF_UNIX, SOCK_STREAM, 0, handles) != 0) {
+    CloseHandle(handles[0]);
+    CloseHandle(handles[1]);
+    return false;
+  }
+
+#if defined(OS_MACOSX)
+  // On OSX an attempt to read or write to a closed socket may generate a
+  // SIGPIPE rather than returning -1.  setsockopt will shut this off.
+  if (0 != setsockopt(handles[0], SOL_SOCKET, SO_NOSIGPIPE,
+                      &nosigpipe, sizeof nosigpipe) ||
+      0 != setsockopt(handles[1], SOL_SOCKET, SO_NOSIGPIPE,
+                      &nosigpipe, sizeof nosigpipe)) {
+    CloseHandle(handles[0]);
+    CloseHandle(handles[1]);
+    return false;
+  }
+#endif
+
+  // Copy the handles out for successful return.
+  socket_a->handle_ = handles[0];
+  socket_b->handle_ = handles[1];
+
+  return true;
+}
+
+// static
+SyncSocket::Handle SyncSocket::UnwrapHandle(
+    const TransitDescriptor& descriptor) {
+  return descriptor.fd;
+}
+
+bool SyncSocket::PrepareTransitDescriptor(ProcessHandle peer_process_handle,
+                                          TransitDescriptor* descriptor) {
+  descriptor->fd = handle();
+  descriptor->auto_close = false;
+  return descriptor->fd != kInvalidHandle;
+}
+
+bool SyncSocket::Close() {
+  const bool retval = CloseHandle(handle_);
+  handle_ = kInvalidHandle;
+  return retval;
+}
+
+size_t SyncSocket::Send(const void* buffer, size_t length) {
+  ThreadRestrictions::AssertIOAllowed();
+  return SendHelper(handle_, buffer, length);
+}
+
+size_t SyncSocket::Receive(void* buffer, size_t length) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK_GT(length, 0u);
+  DCHECK_LE(length, kMaxMessageLength);
+  DCHECK_NE(handle_, kInvalidHandle);
+  char* charbuffer = static_cast<char*>(buffer);
+  if (ReadFromFD(handle_, charbuffer, length))
+    return length;
+  return 0;
+}
+
+size_t SyncSocket::ReceiveWithTimeout(void* buffer,
+                                      size_t length,
+                                      TimeDelta timeout) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK_GT(length, 0u);
+  DCHECK_LE(length, kMaxMessageLength);
+  DCHECK_NE(handle_, kInvalidHandle);
+
+  // TODO(dalecurtis): There's an undiagnosed issue on OSX where we're seeing
+  // large numbers of open files which prevents select() from being used.  In
+  // this case, the best we can do is Peek() to see if we can Receive() now or
+  // return a timeout error (0) if not.  See http://crbug.com/314364.
+  if (handle_ >= FD_SETSIZE)
+    return Peek() < length ? 0 : Receive(buffer, length);
+
+  // Only timeouts greater than zero and less than one second are allowed.
+  DCHECK_GT(timeout.InMicroseconds(), 0);
+  DCHECK_LT(timeout.InMicroseconds(),
+            base::TimeDelta::FromSeconds(1).InMicroseconds());
+
+  // Track the start time so we can reduce the timeout as data is read.
+  TimeTicks start_time = TimeTicks::Now();
+  const TimeTicks finish_time = start_time + timeout;
+
+  fd_set read_fds;
+  size_t bytes_read_total;
+  for (bytes_read_total = 0;
+       bytes_read_total < length && timeout.InMicroseconds() > 0;
+       timeout = finish_time - base::TimeTicks::Now()) {
+    FD_ZERO(&read_fds);
+    FD_SET(handle_, &read_fds);
+
+    // Wait for data to become available.
+    struct timeval timeout_struct =
+        { 0, static_cast<suseconds_t>(timeout.InMicroseconds()) };
+    const int select_result =
+        select(handle_ + 1, &read_fds, NULL, NULL, &timeout_struct);
+    // Handle EINTR manually since we need to update the timeout value.
+    if (select_result == -1 && errno == EINTR)
+      continue;
+    if (select_result <= 0)
+      return bytes_read_total;
+
+    // select() only tells us that data is ready for reading, not how much.  We
+    // must Peek() for the amount ready for reading to avoid blocking.
+    DCHECK(FD_ISSET(handle_, &read_fds));
+    const size_t bytes_to_read = std::min(Peek(), length - bytes_read_total);
+
+    // There may be zero bytes to read if the socket at the other end closed.
+    if (!bytes_to_read)
+      return bytes_read_total;
+
+    const size_t bytes_received =
+        Receive(static_cast<char*>(buffer) + bytes_read_total, bytes_to_read);
+    bytes_read_total += bytes_received;
+    if (bytes_received != bytes_to_read)
+      return bytes_read_total;
+  }
+
+  return bytes_read_total;
+}
+
+size_t SyncSocket::Peek() {
+  DCHECK_NE(handle_, kInvalidHandle);
+  int number_chars = 0;
+  if (ioctl(handle_, FIONREAD, &number_chars) == -1) {
+    // If there is an error in ioctl, signal that the channel would block.
+    return 0;
+  }
+  DCHECK_GE(number_chars, 0);
+  return number_chars;
+}
+
+CancelableSyncSocket::CancelableSyncSocket() {}
+CancelableSyncSocket::CancelableSyncSocket(Handle handle)
+    : SyncSocket(handle) {
+}
+
+bool CancelableSyncSocket::Shutdown() {
+  DCHECK_NE(handle_, kInvalidHandle);
+  return HANDLE_EINTR(shutdown(handle_, SHUT_RDWR)) >= 0;
+}
+
+size_t CancelableSyncSocket::Send(const void* buffer, size_t length) {
+  DCHECK_GT(length, 0u);
+  DCHECK_LE(length, kMaxMessageLength);
+  DCHECK_NE(handle_, kInvalidHandle);
+
+  const long flags = fcntl(handle_, F_GETFL, NULL);
+  if (flags != -1 && (flags & O_NONBLOCK) == 0) {
+    // Set the socket to non-blocking mode for sending if its original mode
+    // is blocking.
+    fcntl(handle_, F_SETFL, flags | O_NONBLOCK);
+  }
+
+  const size_t len = SendHelper(handle_, buffer, length);
+
+  if (flags != -1 && (flags & O_NONBLOCK) == 0) {
+    // Restore the original flags.
+    fcntl(handle_, F_SETFL, flags);
+  }
+
+  return len;
+}
+
+// static
+bool CancelableSyncSocket::CreatePair(CancelableSyncSocket* socket_a,
+                                      CancelableSyncSocket* socket_b) {
+  return SyncSocket::CreatePair(socket_a, socket_b);
+}
+
+}  // namespace base
diff --git a/base/sync_socket_unittest.cc b/base/sync_socket_unittest.cc
new file mode 100644
index 0000000..7c8c97c
--- /dev/null
+++ b/base/sync_socket_unittest.cc
@@ -0,0 +1,131 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/basictypes.h"
+#include "base/sync_socket.h"
+#include "base/threading/simple_thread.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const int kReceiveTimeoutInMilliseconds = 750;
+
+class HangingReceiveThread : public base::DelegateSimpleThread::Delegate {
+ public:
+  explicit HangingReceiveThread(base::SyncSocket* socket)
+      : socket_(socket),
+        thread_(this, "HangingReceiveThread") {
+    thread_.Start();
+  }
+
+  ~HangingReceiveThread() override {}
+
+  void Run() override {
+    int data = 0;
+    ASSERT_EQ(socket_->Peek(), 0u);
+
+    // Use receive with timeout so we don't hang the test harness indefinitely.
+    ASSERT_EQ(0u, socket_->ReceiveWithTimeout(
+        &data, sizeof(data), base::TimeDelta::FromMilliseconds(
+            kReceiveTimeoutInMilliseconds)));
+  }
+
+  void Stop() {
+    thread_.Join();
+  }
+
+ private:
+  base::SyncSocket* socket_;
+  base::DelegateSimpleThread thread_;
+
+  DISALLOW_COPY_AND_ASSIGN(HangingReceiveThread);
+};
+
+// Tests sending data between two SyncSockets.  Uses ASSERT() and thus will exit
+// early upon failure.  Callers should use ASSERT_NO_FATAL_FAILURE() if testing
+// continues after return.
+void SendReceivePeek(base::SyncSocket* socket_a, base::SyncSocket* socket_b) {
+  int received = 0;
+  const int kSending = 123;
+  COMPILE_ASSERT(sizeof(kSending) == sizeof(received), Invalid_Data_Size);
+
+  ASSERT_EQ(0u, socket_a->Peek());
+  ASSERT_EQ(0u, socket_b->Peek());
+
+  // Verify |socket_a| can send to |socket_a| and |socket_a| can Receive from
+  // |socket_a|.
+  ASSERT_EQ(sizeof(kSending), socket_a->Send(&kSending, sizeof(kSending)));
+  ASSERT_EQ(sizeof(kSending), socket_b->Peek());
+  ASSERT_EQ(sizeof(kSending), socket_b->Receive(&received, sizeof(kSending)));
+  ASSERT_EQ(kSending, received);
+
+  ASSERT_EQ(0u, socket_a->Peek());
+  ASSERT_EQ(0u, socket_b->Peek());
+
+  // Now verify the reverse.
+  received = 0;
+  ASSERT_EQ(sizeof(kSending), socket_b->Send(&kSending, sizeof(kSending)));
+  ASSERT_EQ(sizeof(kSending), socket_a->Peek());
+  ASSERT_EQ(sizeof(kSending), socket_a->Receive(&received, sizeof(kSending)));
+  ASSERT_EQ(kSending, received);
+
+  ASSERT_EQ(0u, socket_a->Peek());
+  ASSERT_EQ(0u, socket_b->Peek());
+
+  ASSERT_TRUE(socket_a->Close());
+  ASSERT_TRUE(socket_b->Close());
+}
+
+template <class SocketType>
+void NormalSendReceivePeek() {
+  SocketType socket_a, socket_b;
+  ASSERT_TRUE(SocketType::CreatePair(&socket_a, &socket_b));
+  SendReceivePeek(&socket_a, &socket_b);
+}
+
+template <class SocketType>
+void ClonedSendReceivePeek() {
+  SocketType socket_a, socket_b;
+  ASSERT_TRUE(SocketType::CreatePair(&socket_a, &socket_b));
+
+  // Create new SyncSockets from the paired handles.
+  SocketType socket_c(socket_a.handle()), socket_d(socket_b.handle());
+  SendReceivePeek(&socket_c, &socket_d);
+}
+
+}  // namespace
+
+TEST(SyncSocket, NormalSendReceivePeek) {
+  NormalSendReceivePeek<base::SyncSocket>();
+}
+
+TEST(SyncSocket, ClonedSendReceivePeek) {
+  ClonedSendReceivePeek<base::SyncSocket>();
+}
+
+TEST(CancelableSyncSocket, NormalSendReceivePeek) {
+  NormalSendReceivePeek<base::CancelableSyncSocket>();
+}
+
+TEST(CancelableSyncSocket, ClonedSendReceivePeek) {
+  ClonedSendReceivePeek<base::CancelableSyncSocket>();
+}
+
+TEST(CancelableSyncSocket, CancelReceiveShutdown) {
+  base::CancelableSyncSocket socket_a, socket_b;
+  ASSERT_TRUE(base::CancelableSyncSocket::CreatePair(&socket_a, &socket_b));
+
+  base::TimeTicks start = base::TimeTicks::Now();
+  HangingReceiveThread thread(&socket_b);
+  ASSERT_TRUE(socket_b.Shutdown());
+  thread.Stop();
+
+  // Ensure the receive didn't just timeout.
+  ASSERT_LT((base::TimeTicks::Now() - start).InMilliseconds(),
+            kReceiveTimeoutInMilliseconds);
+
+  ASSERT_TRUE(socket_a.Close());
+  ASSERT_TRUE(socket_b.Close());
+}
diff --git a/base/sync_socket_win.cc b/base/sync_socket_win.cc
new file mode 100644
index 0000000..e508816
--- /dev/null
+++ b/base/sync_socket_win.cc
@@ -0,0 +1,342 @@
+// Copyright (c) 2012 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/sync_socket.h"
+
+#include "base/logging.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/win/scoped_handle.h"
+
+namespace base {
+
+using win::ScopedHandle;
+
+namespace {
+// IMPORTANT: do not change how this name is generated because it will break
+// in sandboxed scenarios as we might have by-name policies that allow pipe
+// creation. Also keep the secure random number generation.
+const wchar_t kPipeNameFormat[] = L"\\\\.\\pipe\\chrome.sync.%u.%u.%lu";
+const size_t kPipePathMax =  arraysize(kPipeNameFormat) + (3 * 10) + 1;
+
+// To avoid users sending negative message lengths to Send/Receive
+// we clamp message lengths, which are size_t, to no more than INT_MAX.
+const size_t kMaxMessageLength = static_cast<size_t>(INT_MAX);
+
+const int kOutBufferSize = 4096;
+const int kInBufferSize = 4096;
+const int kDefaultTimeoutMilliSeconds = 1000;
+
+bool CreatePairImpl(HANDLE* socket_a, HANDLE* socket_b, bool overlapped) {
+  DCHECK_NE(socket_a, socket_b);
+  DCHECK_EQ(*socket_a, SyncSocket::kInvalidHandle);
+  DCHECK_EQ(*socket_b, SyncSocket::kInvalidHandle);
+
+  wchar_t name[kPipePathMax];
+  ScopedHandle handle_a;
+  DWORD flags = PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE;
+  if (overlapped)
+    flags |= FILE_FLAG_OVERLAPPED;
+
+  do {
+    unsigned int rnd_name;
+    if (rand_s(&rnd_name) != 0)
+      return false;
+
+    swprintf(name, kPipePathMax,
+             kPipeNameFormat,
+             GetCurrentProcessId(),
+             GetCurrentThreadId(),
+             rnd_name);
+
+    handle_a.Set(CreateNamedPipeW(
+        name,
+        flags,
+        PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
+        1,
+        kOutBufferSize,
+        kInBufferSize,
+        kDefaultTimeoutMilliSeconds,
+        NULL));
+  } while (!handle_a.IsValid() &&
+           (GetLastError() == ERROR_PIPE_BUSY));
+
+  if (!handle_a.IsValid()) {
+    NOTREACHED();
+    return false;
+  }
+
+  // The SECURITY_ANONYMOUS flag means that the server side (handle_a) cannot
+  // impersonate the client (handle_b). This allows us not to care which side
+  // ends up in which side of a privilege boundary.
+  flags = SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS;
+  if (overlapped)
+    flags |= FILE_FLAG_OVERLAPPED;
+
+  ScopedHandle handle_b(CreateFileW(name,
+                                    GENERIC_READ | GENERIC_WRITE,
+                                    0,          // no sharing.
+                                    NULL,       // default security attributes.
+                                    OPEN_EXISTING,  // opens existing pipe.
+                                    flags,
+                                    NULL));     // no template file.
+  if (!handle_b.IsValid()) {
+    DPLOG(ERROR) << "CreateFileW failed";
+    return false;
+  }
+
+  if (!ConnectNamedPipe(handle_a.Get(), NULL)) {
+    DWORD error = GetLastError();
+    if (error != ERROR_PIPE_CONNECTED) {
+      DPLOG(ERROR) << "ConnectNamedPipe failed";
+      return false;
+    }
+  }
+
+  *socket_a = handle_a.Take();
+  *socket_b = handle_b.Take();
+
+  return true;
+}
+
+// Inline helper to avoid having the cast everywhere.
+DWORD GetNextChunkSize(size_t current_pos, size_t max_size) {
+  // The following statement is for 64 bit portability.
+  return static_cast<DWORD>(((max_size - current_pos) <= UINT_MAX) ?
+      (max_size - current_pos) : UINT_MAX);
+}
+
+// Template function that supports calling ReadFile or WriteFile in an
+// overlapped fashion and waits for IO completion.  The function also waits
+// on an event that can be used to cancel the operation.  If the operation
+// is cancelled, the function returns and closes the relevant socket object.
+template <typename BufferType, typename Function>
+size_t CancelableFileOperation(Function operation,
+                               HANDLE file,
+                               BufferType* buffer,
+                               size_t length,
+                               WaitableEvent* io_event,
+                               WaitableEvent* cancel_event,
+                               CancelableSyncSocket* socket,
+                               DWORD timeout_in_ms) {
+  ThreadRestrictions::AssertIOAllowed();
+  // The buffer must be byte size or the length check won't make much sense.
+  COMPILE_ASSERT(sizeof(buffer[0]) == sizeof(char), incorrect_buffer_type);
+  DCHECK_GT(length, 0u);
+  DCHECK_LE(length, kMaxMessageLength);
+  DCHECK_NE(file, SyncSocket::kInvalidHandle);
+
+  // Track the finish time so we can calculate the timeout as data is read.
+  TimeTicks current_time, finish_time;
+  if (timeout_in_ms != INFINITE) {
+    current_time = TimeTicks::Now();
+    finish_time =
+        current_time + base::TimeDelta::FromMilliseconds(timeout_in_ms);
+  }
+
+  size_t count = 0;
+  do {
+    // The OVERLAPPED structure will be modified by ReadFile or WriteFile.
+    OVERLAPPED ol = { 0 };
+    ol.hEvent = io_event->handle();
+
+    const DWORD chunk = GetNextChunkSize(count, length);
+    // This is either the ReadFile or WriteFile call depending on whether
+    // we're receiving or sending data.
+    DWORD len = 0;
+    const BOOL operation_ok = operation(
+        file, static_cast<BufferType*>(buffer) + count, chunk, &len, &ol);
+    if (!operation_ok) {
+      if (::GetLastError() == ERROR_IO_PENDING) {
+        HANDLE events[] = { io_event->handle(), cancel_event->handle() };
+        const int wait_result = WaitForMultipleObjects(
+            arraysize(events), events, FALSE,
+            timeout_in_ms == INFINITE ?
+                timeout_in_ms :
+                static_cast<DWORD>(
+                    (finish_time - current_time).InMilliseconds()));
+        if (wait_result != WAIT_OBJECT_0 + 0) {
+          // CancelIo() doesn't synchronously cancel outstanding IO, only marks
+          // outstanding IO for cancellation. We must call GetOverlappedResult()
+          // below to ensure in flight writes complete before returning.
+          CancelIo(file);
+        }
+
+        // We set the |bWait| parameter to TRUE for GetOverlappedResult() to
+        // ensure writes are complete before returning.
+        if (!GetOverlappedResult(file, &ol, &len, TRUE))
+          len = 0;
+
+        if (wait_result == WAIT_OBJECT_0 + 1) {
+          DVLOG(1) << "Shutdown was signaled. Closing socket.";
+          socket->Close();
+          return count;
+        }
+
+        // Timeouts will be handled by the while() condition below since
+        // GetOverlappedResult() may complete successfully after CancelIo().
+        DCHECK(wait_result == WAIT_OBJECT_0 + 0 || wait_result == WAIT_TIMEOUT);
+      } else {
+        break;
+      }
+    }
+
+    count += len;
+
+    // Quit the operation if we can't write/read anymore.
+    if (len != chunk)
+      break;
+
+    // Since TimeTicks::Now() is expensive, only bother updating the time if we
+    // have more work to do.
+    if (timeout_in_ms != INFINITE && count < length)
+      current_time = base::TimeTicks::Now();
+  } while (count < length &&
+           (timeout_in_ms == INFINITE || current_time < finish_time));
+
+  return count;
+}
+
+}  // namespace
+
+#if defined(COMPONENT_BUILD)
+const SyncSocket::Handle SyncSocket::kInvalidHandle = INVALID_HANDLE_VALUE;
+#endif
+
+SyncSocket::SyncSocket() : handle_(kInvalidHandle) {}
+
+SyncSocket::~SyncSocket() {
+  Close();
+}
+
+// static
+bool SyncSocket::CreatePair(SyncSocket* socket_a, SyncSocket* socket_b) {
+  return CreatePairImpl(&socket_a->handle_, &socket_b->handle_, false);
+}
+
+// static
+SyncSocket::Handle SyncSocket::UnwrapHandle(
+    const TransitDescriptor& descriptor) {
+  return descriptor;
+}
+
+bool SyncSocket::PrepareTransitDescriptor(ProcessHandle peer_process_handle,
+                                          TransitDescriptor* descriptor) {
+  DCHECK(descriptor);
+  if (!::DuplicateHandle(GetCurrentProcess(), handle(), peer_process_handle,
+                         descriptor, 0, FALSE, DUPLICATE_SAME_ACCESS)) {
+    DPLOG(ERROR) << "Cannot duplicate socket handle for peer process.";
+    return false;
+  }
+  return true;
+}
+
+bool SyncSocket::Close() {
+  if (handle_ == kInvalidHandle)
+    return true;
+
+  const BOOL result = CloseHandle(handle_);
+  handle_ = kInvalidHandle;
+  return result == TRUE;
+}
+
+size_t SyncSocket::Send(const void* buffer, size_t length) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK_GT(length, 0u);
+  DCHECK_LE(length, kMaxMessageLength);
+  DCHECK_NE(handle_, kInvalidHandle);
+  size_t count = 0;
+  while (count < length) {
+    DWORD len;
+    DWORD chunk = GetNextChunkSize(count, length);
+    if (WriteFile(handle_, static_cast<const char*>(buffer) + count,
+                  chunk, &len, NULL) == FALSE) {
+      return count;
+    }
+    count += len;
+  }
+  return count;
+}
+
+size_t SyncSocket::ReceiveWithTimeout(void* buffer,
+                                      size_t length,
+                                      TimeDelta timeout) {
+  NOTIMPLEMENTED();
+  return 0;
+}
+
+size_t SyncSocket::Receive(void* buffer, size_t length) {
+  ThreadRestrictions::AssertIOAllowed();
+  DCHECK_GT(length, 0u);
+  DCHECK_LE(length, kMaxMessageLength);
+  DCHECK_NE(handle_, kInvalidHandle);
+  size_t count = 0;
+  while (count < length) {
+    DWORD len;
+    DWORD chunk = GetNextChunkSize(count, length);
+    if (ReadFile(handle_, static_cast<char*>(buffer) + count,
+                 chunk, &len, NULL) == FALSE) {
+      return count;
+    }
+    count += len;
+  }
+  return count;
+}
+
+size_t SyncSocket::Peek() {
+  DWORD available = 0;
+  PeekNamedPipe(handle_, NULL, 0, NULL, &available, NULL);
+  return available;
+}
+
+CancelableSyncSocket::CancelableSyncSocket()
+    : shutdown_event_(true, false), file_operation_(true, false) {
+}
+
+CancelableSyncSocket::CancelableSyncSocket(Handle handle)
+    : SyncSocket(handle), shutdown_event_(true, false),
+      file_operation_(true, false) {
+}
+
+bool CancelableSyncSocket::Shutdown() {
+  // This doesn't shut down the pipe immediately, but subsequent Receive or Send
+  // methods will fail straight away.
+  shutdown_event_.Signal();
+  return true;
+}
+
+bool CancelableSyncSocket::Close() {
+  const bool result = SyncSocket::Close();
+  shutdown_event_.Reset();
+  return result;
+}
+
+size_t CancelableSyncSocket::Send(const void* buffer, size_t length) {
+  static const DWORD kWaitTimeOutInMs = 500;
+  return CancelableFileOperation(
+      &WriteFile, handle_, reinterpret_cast<const char*>(buffer),
+      length, &file_operation_, &shutdown_event_, this, kWaitTimeOutInMs);
+}
+
+size_t CancelableSyncSocket::Receive(void* buffer, size_t length) {
+  return CancelableFileOperation(
+      &ReadFile, handle_, reinterpret_cast<char*>(buffer), length,
+      &file_operation_, &shutdown_event_, this, INFINITE);
+}
+
+size_t CancelableSyncSocket::ReceiveWithTimeout(void* buffer,
+                                                size_t length,
+                                                TimeDelta timeout) {
+  return CancelableFileOperation(
+      &ReadFile, handle_, reinterpret_cast<char*>(buffer), length,
+      &file_operation_, &shutdown_event_, this,
+      static_cast<DWORD>(timeout.InMilliseconds()));
+}
+
+// static
+bool CancelableSyncSocket::CreatePair(CancelableSyncSocket* socket_a,
+                                      CancelableSyncSocket* socket_b) {
+  return CreatePairImpl(&socket_a->handle_, &socket_b->handle_, true);
+}
+
+}  // namespace base
diff --git a/base/synchronization/cancellation_flag.cc b/base/synchronization/cancellation_flag.cc
new file mode 100644
index 0000000..ca5c0a8
--- /dev/null
+++ b/base/synchronization/cancellation_flag.cc
@@ -0,0 +1,26 @@
+// Copyright (c) 2011 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/synchronization/cancellation_flag.h"
+
+#include "base/logging.h"
+
+namespace base {
+
+void CancellationFlag::Set() {
+#if !defined(NDEBUG)
+  DCHECK_EQ(set_on_, PlatformThread::CurrentId());
+#endif
+  base::subtle::Release_Store(&flag_, 1);
+}
+
+bool CancellationFlag::IsSet() const {
+  return base::subtle::Acquire_Load(&flag_) != 0;
+}
+
+void CancellationFlag::UnsafeResetForTesting() {
+  base::subtle::Release_Store(&flag_, 0);
+}
+
+}  // namespace base
diff --git a/base/synchronization/cancellation_flag.h b/base/synchronization/cancellation_flag.h
new file mode 100644
index 0000000..0f0f08e
--- /dev/null
+++ b/base/synchronization/cancellation_flag.h
@@ -0,0 +1,48 @@
+// Copyright (c) 2011 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_SYNCHRONIZATION_CANCELLATION_FLAG_H_
+#define BASE_SYNCHRONIZATION_CANCELLATION_FLAG_H_
+
+#include "base/base_export.h"
+#include "base/atomicops.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+// CancellationFlag allows one thread to cancel jobs executed on some worker
+// thread. Calling Set() from one thread and IsSet() from a number of threads
+// is thread-safe.
+//
+// This class IS NOT intended for synchronization between threads.
+class BASE_EXPORT CancellationFlag {
+ public:
+  CancellationFlag() : flag_(false) {
+#if !defined(NDEBUG)
+    set_on_ = PlatformThread::CurrentId();
+#endif
+  }
+  ~CancellationFlag() {}
+
+  // Set the flag. May only be called on the thread which owns the object.
+  void Set();
+  bool IsSet() const;  // Returns true iff the flag was set.
+
+  // For subtle reasons that may be different on different architectures,
+  // a different thread testing IsSet() may erroneously read 'true' after
+  // this method has been called.
+  void UnsafeResetForTesting();
+
+ private:
+  base::subtle::Atomic32 flag_;
+#if !defined(NDEBUG)
+  PlatformThreadId set_on_;
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(CancellationFlag);
+};
+
+}  // namespace base
+
+#endif  // BASE_SYNCHRONIZATION_CANCELLATION_FLAG_H_
diff --git a/base/synchronization/cancellation_flag_unittest.cc b/base/synchronization/cancellation_flag_unittest.cc
new file mode 100644
index 0000000..13c74bc
--- /dev/null
+++ b/base/synchronization/cancellation_flag_unittest.cc
@@ -0,0 +1,65 @@
+// Copyright (c) 2011 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.
+
+// Tests of CancellationFlag class.
+
+#include "base/synchronization/cancellation_flag.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/spin_wait.h"
+#include "base/threading/thread.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace base {
+
+namespace {
+
+//------------------------------------------------------------------------------
+// Define our test class.
+//------------------------------------------------------------------------------
+
+void CancelHelper(CancellationFlag* flag) {
+#if GTEST_HAS_DEATH_TEST
+  ASSERT_DEBUG_DEATH(flag->Set(), "");
+#endif
+}
+
+TEST(CancellationFlagTest, SimpleSingleThreadedTest) {
+  CancellationFlag flag;
+  ASSERT_FALSE(flag.IsSet());
+  flag.Set();
+  ASSERT_TRUE(flag.IsSet());
+}
+
+TEST(CancellationFlagTest, DoubleSetTest) {
+  CancellationFlag flag;
+  ASSERT_FALSE(flag.IsSet());
+  flag.Set();
+  ASSERT_TRUE(flag.IsSet());
+  flag.Set();
+  ASSERT_TRUE(flag.IsSet());
+}
+
+TEST(CancellationFlagTest, SetOnDifferentThreadDeathTest) {
+  // Checks that Set() can't be called from any other thread.
+  // CancellationFlag should die on a DCHECK if Set() is called from
+  // other thread.
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  Thread t("CancellationFlagTest.SetOnDifferentThreadDeathTest");
+  ASSERT_TRUE(t.Start());
+  ASSERT_TRUE(t.message_loop());
+  ASSERT_TRUE(t.IsRunning());
+
+  CancellationFlag flag;
+  t.task_runner()->PostTask(FROM_HERE, base::Bind(&CancelHelper, &flag));
+}
+
+}  // namespace
+
+}  // namespace base
diff --git a/base/synchronization/condition_variable.h b/base/synchronization/condition_variable.h
new file mode 100644
index 0000000..5d8507d
--- /dev/null
+++ b/base/synchronization/condition_variable.h
@@ -0,0 +1,118 @@
+// Copyright (c) 2011 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.
+
+// ConditionVariable wraps pthreads condition variable synchronization or, on
+// Windows, simulates it.  This functionality is very helpful for having
+// several threads wait for an event, as is common with a thread pool managed
+// by a master.  The meaning of such an event in the (worker) thread pool
+// scenario is that additional tasks are now available for processing.  It is
+// used in Chrome in the DNS prefetching system to notify worker threads that
+// a queue now has items (tasks) which need to be tended to.  A related use
+// would have a pool manager waiting on a ConditionVariable, waiting for a
+// thread in the pool to announce (signal) that there is now more room in a
+// (bounded size) communications queue for the manager to deposit tasks, or,
+// as a second example, that the queue of tasks is completely empty and all
+// workers are waiting.
+//
+// USAGE NOTE 1: spurious signal events are possible with this and
+// most implementations of condition variables.  As a result, be
+// *sure* to retest your condition before proceeding.  The following
+// is a good example of doing this correctly:
+//
+// while (!work_to_be_done()) Wait(...);
+//
+// In contrast do NOT do the following:
+//
+// if (!work_to_be_done()) Wait(...);  // Don't do this.
+//
+// Especially avoid the above if you are relying on some other thread only
+// issuing a signal up *if* there is work-to-do.  There can/will
+// be spurious signals.  Recheck state on waiting thread before
+// assuming the signal was intentional. Caveat caller ;-).
+//
+// USAGE NOTE 2: Broadcast() frees up all waiting threads at once,
+// which leads to contention for the locks they all held when they
+// called Wait().  This results in POOR performance.  A much better
+// approach to getting a lot of threads out of Wait() is to have each
+// thread (upon exiting Wait()) call Signal() to free up another
+// Wait'ing thread.  Look at condition_variable_unittest.cc for
+// both examples.
+//
+// Broadcast() can be used nicely during teardown, as it gets the job
+// done, and leaves no sleeping threads... and performance is less
+// critical at that point.
+//
+// The semantics of Broadcast() are carefully crafted so that *all*
+// threads that were waiting when the request was made will indeed
+// get signaled.  Some implementations mess up, and don't signal them
+// all, while others allow the wait to be effectively turned off (for
+// a while while waiting threads come around).  This implementation
+// appears correct, as it will not "lose" any signals, and will guarantee
+// that all threads get signaled by Broadcast().
+//
+// This implementation offers support for "performance" in its selection of
+// which thread to revive.  Performance, in direct contrast with "fairness,"
+// assures that the thread that most recently began to Wait() is selected by
+// Signal to revive.  Fairness would (if publicly supported) assure that the
+// thread that has Wait()ed the longest is selected. The default policy
+// may improve performance, as the selected thread may have a greater chance of
+// having some of its stack data in various CPU caches.
+//
+// For a discussion of the many very subtle implementation details, see the FAQ
+// at the end of condition_variable_win.cc.
+
+#ifndef BASE_SYNCHRONIZATION_CONDITION_VARIABLE_H_
+#define BASE_SYNCHRONIZATION_CONDITION_VARIABLE_H_
+
+#include "build/build_config.h"
+
+#if defined(OS_POSIX)
+#include <pthread.h>
+#endif
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/synchronization/lock.h"
+
+namespace base {
+
+class ConditionVarImpl;
+class TimeDelta;
+
+class BASE_EXPORT ConditionVariable {
+ public:
+  // Construct a cv for use with ONLY one user lock.
+  explicit ConditionVariable(Lock* user_lock);
+
+  ~ConditionVariable();
+
+  // Wait() releases the caller's critical section atomically as it starts to
+  // sleep, and the reacquires it when it is signaled.
+  void Wait();
+  void TimedWait(const TimeDelta& max_time);
+
+  // Broadcast() revives all waiting threads.
+  void Broadcast();
+  // Signal() revives one waiting thread.
+  void Signal();
+
+ private:
+
+#if defined(OS_WIN)
+  ConditionVarImpl* impl_;
+#elif defined(OS_POSIX)
+  pthread_cond_t condition_;
+  pthread_mutex_t* user_mutex_;
+#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+  base::Lock* user_lock_;     // Needed to adjust shadow lock state on wait.
+#endif
+
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(ConditionVariable);
+};
+
+}  // namespace base
+
+#endif  // BASE_SYNCHRONIZATION_CONDITION_VARIABLE_H_
diff --git a/base/synchronization/condition_variable_posix.cc b/base/synchronization/condition_variable_posix.cc
new file mode 100644
index 0000000..013284c
--- /dev/null
+++ b/base/synchronization/condition_variable_posix.cc
@@ -0,0 +1,122 @@
+// Copyright (c) 2011 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/synchronization/condition_variable.h"
+
+#include <errno.h>
+#include <sys/time.h>
+
+#include "base/logging.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/time/time.h"
+
+namespace base {
+
+ConditionVariable::ConditionVariable(Lock* user_lock)
+    : user_mutex_(user_lock->lock_.native_handle())
+#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+    , user_lock_(user_lock)
+#endif
+{
+  int rv = 0;
+  // http://crbug.com/293736
+  // NaCl doesn't support monotonic clock based absolute deadlines.
+  // On older Android platform versions, it's supported through the
+  // non-standard pthread_cond_timedwait_monotonic_np. Newer platform
+  // versions have pthread_condattr_setclock.
+  // Mac can use relative time deadlines.
+#if !defined(OS_MACOSX) && !defined(OS_NACL) && \
+      !(defined(OS_ANDROID) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC))
+  pthread_condattr_t attrs;
+  rv = pthread_condattr_init(&attrs);
+  DCHECK_EQ(0, rv);
+  pthread_condattr_setclock(&attrs, CLOCK_MONOTONIC);
+  rv = pthread_cond_init(&condition_, &attrs);
+  pthread_condattr_destroy(&attrs);
+#else
+  rv = pthread_cond_init(&condition_, NULL);
+#endif
+  DCHECK_EQ(0, rv);
+}
+
+ConditionVariable::~ConditionVariable() {
+  int rv = pthread_cond_destroy(&condition_);
+  DCHECK_EQ(0, rv);
+}
+
+void ConditionVariable::Wait() {
+  base::ThreadRestrictions::AssertWaitAllowed();
+#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+  user_lock_->CheckHeldAndUnmark();
+#endif
+  int rv = pthread_cond_wait(&condition_, user_mutex_);
+  DCHECK_EQ(0, rv);
+#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+  user_lock_->CheckUnheldAndMark();
+#endif
+}
+
+void ConditionVariable::TimedWait(const TimeDelta& max_time) {
+  base::ThreadRestrictions::AssertWaitAllowed();
+  int64 usecs = max_time.InMicroseconds();
+  struct timespec relative_time;
+  relative_time.tv_sec = usecs / Time::kMicrosecondsPerSecond;
+  relative_time.tv_nsec =
+      (usecs % Time::kMicrosecondsPerSecond) * Time::kNanosecondsPerMicrosecond;
+
+#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+  user_lock_->CheckHeldAndUnmark();
+#endif
+
+#if defined(OS_MACOSX)
+  int rv = pthread_cond_timedwait_relative_np(
+      &condition_, user_mutex_, &relative_time);
+#else
+  // The timeout argument to pthread_cond_timedwait is in absolute time.
+  struct timespec absolute_time;
+#if defined(OS_NACL)
+  // See comment in constructor for why this is different in NaCl.
+  struct timeval now;
+  gettimeofday(&now, NULL);
+  absolute_time.tv_sec = now.tv_sec;
+  absolute_time.tv_nsec = now.tv_usec * Time::kNanosecondsPerMicrosecond;
+#else
+  struct timespec now;
+  clock_gettime(CLOCK_MONOTONIC, &now);
+  absolute_time.tv_sec = now.tv_sec;
+  absolute_time.tv_nsec = now.tv_nsec;
+#endif
+
+  absolute_time.tv_sec += relative_time.tv_sec;
+  absolute_time.tv_nsec += relative_time.tv_nsec;
+  absolute_time.tv_sec += absolute_time.tv_nsec / Time::kNanosecondsPerSecond;
+  absolute_time.tv_nsec %= Time::kNanosecondsPerSecond;
+  DCHECK_GE(absolute_time.tv_sec, now.tv_sec);  // Overflow paranoia
+
+#if defined(OS_ANDROID) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC)
+  int rv = pthread_cond_timedwait_monotonic_np(
+      &condition_, user_mutex_, &absolute_time);
+#else
+  int rv = pthread_cond_timedwait(&condition_, user_mutex_, &absolute_time);
+#endif  // OS_ANDROID && HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC
+#endif  // OS_MACOSX
+
+  DCHECK(rv == 0 || rv == ETIMEDOUT);
+#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+  user_lock_->CheckUnheldAndMark();
+#endif
+}
+
+void ConditionVariable::Broadcast() {
+  int rv = pthread_cond_broadcast(&condition_);
+  DCHECK_EQ(0, rv);
+}
+
+void ConditionVariable::Signal() {
+  int rv = pthread_cond_signal(&condition_);
+  DCHECK_EQ(0, rv);
+}
+
+}  // namespace base
diff --git a/base/synchronization/condition_variable_unittest.cc b/base/synchronization/condition_variable_unittest.cc
new file mode 100644
index 0000000..e63a723
--- /dev/null
+++ b/base/synchronization/condition_variable_unittest.cc
@@ -0,0 +1,765 @@
+// Copyright (c) 2012 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.
+
+// Multi-threaded tests of ConditionVariable class.
+
+#include <time.h>
+#include <algorithm>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
+#include "base/synchronization/spin_wait.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread.h"
+#include "base/threading/thread_collision_warner.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace base {
+
+namespace {
+//------------------------------------------------------------------------------
+// Define our test class, with several common variables.
+//------------------------------------------------------------------------------
+
+class ConditionVariableTest : public PlatformTest {
+ public:
+  const TimeDelta kZeroMs;
+  const TimeDelta kTenMs;
+  const TimeDelta kThirtyMs;
+  const TimeDelta kFortyFiveMs;
+  const TimeDelta kSixtyMs;
+  const TimeDelta kOneHundredMs;
+
+  ConditionVariableTest()
+      : kZeroMs(TimeDelta::FromMilliseconds(0)),
+        kTenMs(TimeDelta::FromMilliseconds(10)),
+        kThirtyMs(TimeDelta::FromMilliseconds(30)),
+        kFortyFiveMs(TimeDelta::FromMilliseconds(45)),
+        kSixtyMs(TimeDelta::FromMilliseconds(60)),
+        kOneHundredMs(TimeDelta::FromMilliseconds(100)) {
+  }
+};
+
+//------------------------------------------------------------------------------
+// Define a class that will control activities an several multi-threaded tests.
+// The general structure of multi-threaded tests is that a test case will
+// construct an instance of a WorkQueue.  The WorkQueue will spin up some
+// threads and control them throughout their lifetime, as well as maintaining
+// a central repository of the work thread's activity.  Finally, the WorkQueue
+// will command the the worker threads to terminate.  At that point, the test
+// cases will validate that the WorkQueue has records showing that the desired
+// activities were performed.
+//------------------------------------------------------------------------------
+
+// Callers are responsible for synchronizing access to the following class.
+// The WorkQueue::lock_, as accessed via WorkQueue::lock(), should be used for
+// all synchronized access.
+class WorkQueue : public PlatformThread::Delegate {
+ public:
+  explicit WorkQueue(int thread_count);
+  ~WorkQueue() override;
+
+  // PlatformThread::Delegate interface.
+  void ThreadMain() override;
+
+  //----------------------------------------------------------------------------
+  // Worker threads only call the following methods.
+  // They should use the lock to get exclusive access.
+  int GetThreadId();  // Get an ID assigned to a thread..
+  bool EveryIdWasAllocated() const;  // Indicates that all IDs were handed out.
+  TimeDelta GetAnAssignment(int thread_id);  // Get a work task duration.
+  void WorkIsCompleted(int thread_id);
+
+  int task_count() const;
+  bool allow_help_requests() const;  // Workers can signal more workers.
+  bool shutdown() const;  // Check if shutdown has been requested.
+
+  void thread_shutting_down();
+
+
+  //----------------------------------------------------------------------------
+  // Worker threads can call them but not needed to acquire a lock.
+  Lock* lock();
+
+  ConditionVariable* work_is_available();
+  ConditionVariable* all_threads_have_ids();
+  ConditionVariable* no_more_tasks();
+
+  //----------------------------------------------------------------------------
+  // The rest of the methods are for use by the controlling master thread (the
+  // test case code).
+  void ResetHistory();
+  int GetMinCompletionsByWorkerThread() const;
+  int GetMaxCompletionsByWorkerThread() const;
+  int GetNumThreadsTakingAssignments() const;
+  int GetNumThreadsCompletingTasks() const;
+  int GetNumberOfCompletedTasks() const;
+
+  void SetWorkTime(TimeDelta delay);
+  void SetTaskCount(int count);
+  void SetAllowHelp(bool allow);
+
+  // The following must be called without locking, and will spin wait until the
+  // threads are all in a wait state.
+  void SpinUntilAllThreadsAreWaiting();
+  void SpinUntilTaskCountLessThan(int task_count);
+
+  // Caller must acquire lock before calling.
+  void SetShutdown();
+
+  // Compares the |shutdown_task_count_| to the |thread_count| and returns true
+  // if they are equal.  This check will acquire the |lock_| so the caller
+  // should not hold the lock when calling this method.
+  bool ThreadSafeCheckShutdown(int thread_count);
+
+ private:
+  // Both worker threads and controller use the following to synchronize.
+  Lock lock_;
+  ConditionVariable work_is_available_;  // To tell threads there is work.
+
+  // Conditions to notify the controlling process (if it is interested).
+  ConditionVariable all_threads_have_ids_;  // All threads are running.
+  ConditionVariable no_more_tasks_;  // Task count is zero.
+
+  const int thread_count_;
+  int waiting_thread_count_;
+  scoped_ptr<PlatformThreadHandle[]> thread_handles_;
+  std::vector<int> assignment_history_;  // Number of assignment per worker.
+  std::vector<int> completion_history_;  // Number of completions per worker.
+  int thread_started_counter_;  // Used to issue unique id to workers.
+  int shutdown_task_count_;  // Number of tasks told to shutdown
+  int task_count_;  // Number of assignment tasks waiting to be processed.
+  TimeDelta worker_delay_;  // Time each task takes to complete.
+  bool allow_help_requests_;  // Workers can signal more workers.
+  bool shutdown_;  // Set when threads need to terminate.
+
+  DFAKE_MUTEX(locked_methods_);
+};
+
+//------------------------------------------------------------------------------
+// The next section contains the actual tests.
+//------------------------------------------------------------------------------
+
+TEST_F(ConditionVariableTest, StartupShutdownTest) {
+  Lock lock;
+
+  // First try trivial startup/shutdown.
+  {
+    ConditionVariable cv1(&lock);
+  }  // Call for cv1 destruction.
+
+  // Exercise with at least a few waits.
+  ConditionVariable cv(&lock);
+
+  lock.Acquire();
+  cv.TimedWait(kTenMs);  // Wait for 10 ms.
+  cv.TimedWait(kTenMs);  // Wait for 10 ms.
+  lock.Release();
+
+  lock.Acquire();
+  cv.TimedWait(kTenMs);  // Wait for 10 ms.
+  cv.TimedWait(kTenMs);  // Wait for 10 ms.
+  cv.TimedWait(kTenMs);  // Wait for 10 ms.
+  lock.Release();
+}  // Call for cv destruction.
+
+TEST_F(ConditionVariableTest, TimeoutTest) {
+  Lock lock;
+  ConditionVariable cv(&lock);
+  lock.Acquire();
+
+  TimeTicks start = TimeTicks::Now();
+  const TimeDelta WAIT_TIME = TimeDelta::FromMilliseconds(300);
+  // Allow for clocking rate granularity.
+  const TimeDelta FUDGE_TIME = TimeDelta::FromMilliseconds(50);
+
+  cv.TimedWait(WAIT_TIME + FUDGE_TIME);
+  TimeDelta duration = TimeTicks::Now() - start;
+  // We can't use EXPECT_GE here as the TimeDelta class does not support the
+  // required stream conversion.
+  EXPECT_TRUE(duration >= WAIT_TIME);
+
+  lock.Release();
+}
+
+#if defined(OS_POSIX)
+const int kDiscontinuitySeconds = 2;
+
+void BackInTime(Lock* lock) {
+  AutoLock auto_lock(*lock);
+
+  timeval tv;
+  gettimeofday(&tv, NULL);
+  tv.tv_sec -= kDiscontinuitySeconds;
+  settimeofday(&tv, NULL);
+}
+
+// Tests that TimedWait ignores changes to the system clock.
+// Test is disabled by default, because it needs to run as root to muck with the
+// system clock.
+// http://crbug.com/293736
+TEST_F(ConditionVariableTest, DISABLED_TimeoutAcrossSetTimeOfDay) {
+  timeval tv;
+  gettimeofday(&tv, NULL);
+  tv.tv_sec += kDiscontinuitySeconds;
+  if (settimeofday(&tv, NULL) < 0) {
+    PLOG(ERROR) << "Could not set time of day. Run as root?";
+    return;
+  }
+
+  Lock lock;
+  ConditionVariable cv(&lock);
+  lock.Acquire();
+
+  Thread thread("Helper");
+  thread.Start();
+  thread.task_runner()->PostTask(FROM_HERE, base::Bind(&BackInTime, &lock));
+
+  TimeTicks start = TimeTicks::Now();
+  const TimeDelta kWaitTime = TimeDelta::FromMilliseconds(300);
+  // Allow for clocking rate granularity.
+  const TimeDelta kFudgeTime = TimeDelta::FromMilliseconds(50);
+
+  cv.TimedWait(kWaitTime + kFudgeTime);
+  TimeDelta duration = TimeTicks::Now() - start;
+
+  thread.Stop();
+  // We can't use EXPECT_GE here as the TimeDelta class does not support the
+  // required stream conversion.
+  EXPECT_TRUE(duration >= kWaitTime);
+  EXPECT_TRUE(duration <= TimeDelta::FromSeconds(kDiscontinuitySeconds));
+
+  lock.Release();
+}
+#endif
+
+
+// Suddenly got flaky on Win, see http://crbug.com/10607 (starting at
+// comment #15).
+#if defined(OS_WIN)
+#define MAYBE_MultiThreadConsumerTest DISABLED_MultiThreadConsumerTest
+#else
+#define MAYBE_MultiThreadConsumerTest MultiThreadConsumerTest
+#endif
+// Test serial task servicing, as well as two parallel task servicing methods.
+TEST_F(ConditionVariableTest, MAYBE_MultiThreadConsumerTest) {
+  const int kThreadCount = 10;
+  WorkQueue queue(kThreadCount);  // Start the threads.
+
+  const int kTaskCount = 10;  // Number of tasks in each mini-test here.
+
+  Time start_time;  // Used to time task processing.
+
+  {
+    base::AutoLock auto_lock(*queue.lock());
+    while (!queue.EveryIdWasAllocated())
+      queue.all_threads_have_ids()->Wait();
+  }
+
+  // If threads aren't in a wait state, they may start to gobble up tasks in
+  // parallel, short-circuiting (breaking) this test.
+  queue.SpinUntilAllThreadsAreWaiting();
+
+  {
+    // Since we have no tasks yet, all threads should be waiting by now.
+    base::AutoLock auto_lock(*queue.lock());
+    EXPECT_EQ(0, queue.GetNumThreadsTakingAssignments());
+    EXPECT_EQ(0, queue.GetNumThreadsCompletingTasks());
+    EXPECT_EQ(0, queue.task_count());
+    EXPECT_EQ(0, queue.GetMaxCompletionsByWorkerThread());
+    EXPECT_EQ(0, queue.GetMinCompletionsByWorkerThread());
+    EXPECT_EQ(0, queue.GetNumberOfCompletedTasks());
+
+    // Set up to make each task include getting help from another worker, so
+    // so that the work gets done in paralell.
+    queue.ResetHistory();
+    queue.SetTaskCount(kTaskCount);
+    queue.SetWorkTime(kThirtyMs);
+    queue.SetAllowHelp(true);
+
+    start_time = Time::Now();
+  }
+
+  queue.work_is_available()->Signal();  // But each worker can signal another.
+  // Wait till we at least start to handle tasks (and we're not all waiting).
+  queue.SpinUntilTaskCountLessThan(kTaskCount);
+  // Wait to allow the all workers to get done.
+  queue.SpinUntilAllThreadsAreWaiting();
+
+  {
+    // Wait until all work tasks have at least been assigned.
+    base::AutoLock auto_lock(*queue.lock());
+    while (queue.task_count())
+      queue.no_more_tasks()->Wait();
+
+    // To avoid racy assumptions, we'll just assert that at least 2 threads
+    // did work.  We know that the first worker should have gone to sleep, and
+    // hence a second worker should have gotten an assignment.
+    EXPECT_LE(2, queue.GetNumThreadsTakingAssignments());
+    EXPECT_EQ(kTaskCount, queue.GetNumberOfCompletedTasks());
+
+    // Try to ask all workers to help, and only a few will do the work.
+    queue.ResetHistory();
+    queue.SetTaskCount(3);
+    queue.SetWorkTime(kThirtyMs);
+    queue.SetAllowHelp(false);
+  }
+  queue.work_is_available()->Broadcast();  // Make them all try.
+  // Wait till we at least start to handle tasks (and we're not all waiting).
+  queue.SpinUntilTaskCountLessThan(3);
+  // Wait to allow the 3 workers to get done.
+  queue.SpinUntilAllThreadsAreWaiting();
+
+  {
+    base::AutoLock auto_lock(*queue.lock());
+    EXPECT_EQ(3, queue.GetNumThreadsTakingAssignments());
+    EXPECT_EQ(3, queue.GetNumThreadsCompletingTasks());
+    EXPECT_EQ(0, queue.task_count());
+    EXPECT_EQ(1, queue.GetMaxCompletionsByWorkerThread());
+    EXPECT_EQ(0, queue.GetMinCompletionsByWorkerThread());
+    EXPECT_EQ(3, queue.GetNumberOfCompletedTasks());
+
+    // Set up to make each task get help from another worker.
+    queue.ResetHistory();
+    queue.SetTaskCount(3);
+    queue.SetWorkTime(kThirtyMs);
+    queue.SetAllowHelp(true);  // Allow (unnecessary) help requests.
+  }
+  queue.work_is_available()->Broadcast();  // Signal all threads.
+  // Wait till we at least start to handle tasks (and we're not all waiting).
+  queue.SpinUntilTaskCountLessThan(3);
+  // Wait to allow the 3 workers to get done.
+  queue.SpinUntilAllThreadsAreWaiting();
+
+  {
+    base::AutoLock auto_lock(*queue.lock());
+    EXPECT_EQ(3, queue.GetNumThreadsTakingAssignments());
+    EXPECT_EQ(3, queue.GetNumThreadsCompletingTasks());
+    EXPECT_EQ(0, queue.task_count());
+    EXPECT_EQ(1, queue.GetMaxCompletionsByWorkerThread());
+    EXPECT_EQ(0, queue.GetMinCompletionsByWorkerThread());
+    EXPECT_EQ(3, queue.GetNumberOfCompletedTasks());
+
+    // Set up to make each task get help from another worker.
+    queue.ResetHistory();
+    queue.SetTaskCount(20);  // 2 tasks per thread.
+    queue.SetWorkTime(kThirtyMs);
+    queue.SetAllowHelp(true);
+  }
+  queue.work_is_available()->Signal();  // But each worker can signal another.
+  // Wait till we at least start to handle tasks (and we're not all waiting).
+  queue.SpinUntilTaskCountLessThan(20);
+  // Wait to allow the 10 workers to get done.
+  queue.SpinUntilAllThreadsAreWaiting();  // Should take about 60 ms.
+
+  {
+    base::AutoLock auto_lock(*queue.lock());
+    EXPECT_EQ(10, queue.GetNumThreadsTakingAssignments());
+    EXPECT_EQ(10, queue.GetNumThreadsCompletingTasks());
+    EXPECT_EQ(0, queue.task_count());
+    EXPECT_EQ(20, queue.GetNumberOfCompletedTasks());
+
+    // Same as last test, but with Broadcast().
+    queue.ResetHistory();
+    queue.SetTaskCount(20);  // 2 tasks per thread.
+    queue.SetWorkTime(kThirtyMs);
+    queue.SetAllowHelp(true);
+  }
+  queue.work_is_available()->Broadcast();
+  // Wait till we at least start to handle tasks (and we're not all waiting).
+  queue.SpinUntilTaskCountLessThan(20);
+  // Wait to allow the 10 workers to get done.
+  queue.SpinUntilAllThreadsAreWaiting();  // Should take about 60 ms.
+
+  {
+    base::AutoLock auto_lock(*queue.lock());
+    EXPECT_EQ(10, queue.GetNumThreadsTakingAssignments());
+    EXPECT_EQ(10, queue.GetNumThreadsCompletingTasks());
+    EXPECT_EQ(0, queue.task_count());
+    EXPECT_EQ(20, queue.GetNumberOfCompletedTasks());
+
+    queue.SetShutdown();
+  }
+  queue.work_is_available()->Broadcast();  // Force check for shutdown.
+
+  SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(1),
+                                   queue.ThreadSafeCheckShutdown(kThreadCount));
+}
+
+TEST_F(ConditionVariableTest, LargeFastTaskTest) {
+  const int kThreadCount = 200;
+  WorkQueue queue(kThreadCount);  // Start the threads.
+
+  Lock private_lock;  // Used locally for master to wait.
+  base::AutoLock private_held_lock(private_lock);
+  ConditionVariable private_cv(&private_lock);
+
+  {
+    base::AutoLock auto_lock(*queue.lock());
+    while (!queue.EveryIdWasAllocated())
+      queue.all_threads_have_ids()->Wait();
+  }
+
+  // Wait a bit more to allow threads to reach their wait state.
+  queue.SpinUntilAllThreadsAreWaiting();
+
+  {
+    // Since we have no tasks, all threads should be waiting by now.
+    base::AutoLock auto_lock(*queue.lock());
+    EXPECT_EQ(0, queue.GetNumThreadsTakingAssignments());
+    EXPECT_EQ(0, queue.GetNumThreadsCompletingTasks());
+    EXPECT_EQ(0, queue.task_count());
+    EXPECT_EQ(0, queue.GetMaxCompletionsByWorkerThread());
+    EXPECT_EQ(0, queue.GetMinCompletionsByWorkerThread());
+    EXPECT_EQ(0, queue.GetNumberOfCompletedTasks());
+
+    // Set up to make all workers do (an average of) 20 tasks.
+    queue.ResetHistory();
+    queue.SetTaskCount(20 * kThreadCount);
+    queue.SetWorkTime(kFortyFiveMs);
+    queue.SetAllowHelp(false);
+  }
+  queue.work_is_available()->Broadcast();  // Start up all threads.
+  // Wait until we've handed out all tasks.
+  {
+    base::AutoLock auto_lock(*queue.lock());
+    while (queue.task_count() != 0)
+      queue.no_more_tasks()->Wait();
+  }
+
+  // Wait till the last of the tasks complete.
+  queue.SpinUntilAllThreadsAreWaiting();
+
+  {
+    // With Broadcast(), every thread should have participated.
+    // but with racing.. they may not all have done equal numbers of tasks.
+    base::AutoLock auto_lock(*queue.lock());
+    EXPECT_EQ(kThreadCount, queue.GetNumThreadsTakingAssignments());
+    EXPECT_EQ(kThreadCount, queue.GetNumThreadsCompletingTasks());
+    EXPECT_EQ(0, queue.task_count());
+    EXPECT_LE(20, queue.GetMaxCompletionsByWorkerThread());
+    EXPECT_EQ(20 * kThreadCount, queue.GetNumberOfCompletedTasks());
+
+    // Set up to make all workers do (an average of) 4 tasks.
+    queue.ResetHistory();
+    queue.SetTaskCount(kThreadCount * 4);
+    queue.SetWorkTime(kFortyFiveMs);
+    queue.SetAllowHelp(true);  // Might outperform Broadcast().
+  }
+  queue.work_is_available()->Signal();  // Start up one thread.
+
+  // Wait until we've handed out all tasks
+  {
+    base::AutoLock auto_lock(*queue.lock());
+    while (queue.task_count() != 0)
+      queue.no_more_tasks()->Wait();
+  }
+
+  // Wait till the last of the tasks complete.
+  queue.SpinUntilAllThreadsAreWaiting();
+
+  {
+    // With Signal(), every thread should have participated.
+    // but with racing.. they may not all have done four tasks.
+    base::AutoLock auto_lock(*queue.lock());
+    EXPECT_EQ(kThreadCount, queue.GetNumThreadsTakingAssignments());
+    EXPECT_EQ(kThreadCount, queue.GetNumThreadsCompletingTasks());
+    EXPECT_EQ(0, queue.task_count());
+    EXPECT_LE(4, queue.GetMaxCompletionsByWorkerThread());
+    EXPECT_EQ(4 * kThreadCount, queue.GetNumberOfCompletedTasks());
+
+    queue.SetShutdown();
+  }
+  queue.work_is_available()->Broadcast();  // Force check for shutdown.
+
+  // Wait for shutdowns to complete.
+  SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(1),
+                                   queue.ThreadSafeCheckShutdown(kThreadCount));
+}
+
+//------------------------------------------------------------------------------
+// Finally we provide the implementation for the methods in the WorkQueue class.
+//------------------------------------------------------------------------------
+
+WorkQueue::WorkQueue(int thread_count)
+  : lock_(),
+    work_is_available_(&lock_),
+    all_threads_have_ids_(&lock_),
+    no_more_tasks_(&lock_),
+    thread_count_(thread_count),
+    waiting_thread_count_(0),
+    thread_handles_(new PlatformThreadHandle[thread_count]),
+    assignment_history_(thread_count),
+    completion_history_(thread_count),
+    thread_started_counter_(0),
+    shutdown_task_count_(0),
+    task_count_(0),
+    allow_help_requests_(false),
+    shutdown_(false) {
+  EXPECT_GE(thread_count_, 1);
+  ResetHistory();
+  SetTaskCount(0);
+  SetWorkTime(TimeDelta::FromMilliseconds(30));
+
+  for (int i = 0; i < thread_count_; ++i) {
+    PlatformThreadHandle pth;
+    EXPECT_TRUE(PlatformThread::Create(0, this, &pth));
+    thread_handles_[i] = pth;
+  }
+}
+
+WorkQueue::~WorkQueue() {
+  {
+    base::AutoLock auto_lock(lock_);
+    SetShutdown();
+  }
+  work_is_available_.Broadcast();  // Tell them all to terminate.
+
+  for (int i = 0; i < thread_count_; ++i) {
+    PlatformThread::Join(thread_handles_[i]);
+  }
+  EXPECT_EQ(0, waiting_thread_count_);
+}
+
+int WorkQueue::GetThreadId() {
+  DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_);
+  DCHECK(!EveryIdWasAllocated());
+  return thread_started_counter_++;  // Give out Unique IDs.
+}
+
+bool WorkQueue::EveryIdWasAllocated() const {
+  DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_);
+  return thread_count_ == thread_started_counter_;
+}
+
+TimeDelta WorkQueue::GetAnAssignment(int thread_id) {
+  DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_);
+  DCHECK_LT(0, task_count_);
+  assignment_history_[thread_id]++;
+  if (0 == --task_count_) {
+    no_more_tasks_.Signal();
+  }
+  return worker_delay_;
+}
+
+void WorkQueue::WorkIsCompleted(int thread_id) {
+  DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_);
+  completion_history_[thread_id]++;
+}
+
+int WorkQueue::task_count() const {
+  DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_);
+  return task_count_;
+}
+
+bool WorkQueue::allow_help_requests() const {
+  DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_);
+  return allow_help_requests_;
+}
+
+bool WorkQueue::shutdown() const {
+  lock_.AssertAcquired();
+  DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_);
+  return shutdown_;
+}
+
+// Because this method is called from the test's main thread we need to actually
+// take the lock.  Threads will call the thread_shutting_down() method with the
+// lock already acquired.
+bool WorkQueue::ThreadSafeCheckShutdown(int thread_count) {
+  bool all_shutdown;
+  base::AutoLock auto_lock(lock_);
+  {
+    // Declare in scope so DFAKE is guranteed to be destroyed before AutoLock.
+    DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_);
+    all_shutdown = (shutdown_task_count_ == thread_count);
+  }
+  return all_shutdown;
+}
+
+void WorkQueue::thread_shutting_down() {
+  lock_.AssertAcquired();
+  DFAKE_SCOPED_RECURSIVE_LOCK(locked_methods_);
+  shutdown_task_count_++;
+}
+
+Lock* WorkQueue::lock() {
+  return &lock_;
+}
+
+ConditionVariable* WorkQueue::work_is_available() {
+  return &work_is_available_;
+}
+
+ConditionVariable* WorkQueue::all_threads_have_ids() {
+  return &all_threads_have_ids_;
+}
+
+ConditionVariable* WorkQueue::no_more_tasks() {
+  return &no_more_tasks_;
+}
+
+void WorkQueue::ResetHistory() {
+  for (int i = 0; i < thread_count_; ++i) {
+    assignment_history_[i] = 0;
+    completion_history_[i] = 0;
+  }
+}
+
+int WorkQueue::GetMinCompletionsByWorkerThread() const {
+  int minumum = completion_history_[0];
+  for (int i = 0; i < thread_count_; ++i)
+    minumum = std::min(minumum, completion_history_[i]);
+  return minumum;
+}
+
+int WorkQueue::GetMaxCompletionsByWorkerThread() const {
+  int maximum = completion_history_[0];
+  for (int i = 0; i < thread_count_; ++i)
+    maximum = std::max(maximum, completion_history_[i]);
+  return maximum;
+}
+
+int WorkQueue::GetNumThreadsTakingAssignments() const {
+  int count = 0;
+  for (int i = 0; i < thread_count_; ++i)
+    if (assignment_history_[i])
+      count++;
+  return count;
+}
+
+int WorkQueue::GetNumThreadsCompletingTasks() const {
+  int count = 0;
+  for (int i = 0; i < thread_count_; ++i)
+    if (completion_history_[i])
+      count++;
+  return count;
+}
+
+int WorkQueue::GetNumberOfCompletedTasks() const {
+  int total = 0;
+  for (int i = 0; i < thread_count_; ++i)
+    total += completion_history_[i];
+  return total;
+}
+
+void WorkQueue::SetWorkTime(TimeDelta delay) {
+  worker_delay_ = delay;
+}
+
+void WorkQueue::SetTaskCount(int count) {
+  task_count_ = count;
+}
+
+void WorkQueue::SetAllowHelp(bool allow) {
+  allow_help_requests_ = allow;
+}
+
+void WorkQueue::SetShutdown() {
+  lock_.AssertAcquired();
+  shutdown_ = true;
+}
+
+void WorkQueue::SpinUntilAllThreadsAreWaiting() {
+  while (true) {
+    {
+      base::AutoLock auto_lock(lock_);
+      if (waiting_thread_count_ == thread_count_)
+        break;
+    }
+    PlatformThread::Sleep(TimeDelta::FromMilliseconds(30));
+  }
+}
+
+void WorkQueue::SpinUntilTaskCountLessThan(int task_count) {
+  while (true) {
+    {
+      base::AutoLock auto_lock(lock_);
+      if (task_count_ < task_count)
+        break;
+    }
+    PlatformThread::Sleep(TimeDelta::FromMilliseconds(30));
+  }
+}
+
+
+//------------------------------------------------------------------------------
+// Define the standard worker task. Several tests will spin out many of these
+// threads.
+//------------------------------------------------------------------------------
+
+// The multithread tests involve several threads with a task to perform as
+// directed by an instance of the class WorkQueue.
+// The task is to:
+// a) Check to see if there are more tasks (there is a task counter).
+//    a1) Wait on condition variable if there are no tasks currently.
+// b) Call a function to see what should be done.
+// c) Do some computation based on the number of milliseconds returned in (b).
+// d) go back to (a).
+
+// WorkQueue::ThreadMain() implements the above task for all threads.
+// It calls the controlling object to tell the creator about progress, and to
+// ask about tasks.
+
+void WorkQueue::ThreadMain() {
+  int thread_id;
+  {
+    base::AutoLock auto_lock(lock_);
+    thread_id = GetThreadId();
+    if (EveryIdWasAllocated())
+      all_threads_have_ids()->Signal();  // Tell creator we're ready.
+  }
+
+  Lock private_lock;  // Used to waste time on "our work".
+  while (1) {  // This is the main consumer loop.
+    TimeDelta work_time;
+    bool could_use_help;
+    {
+      base::AutoLock auto_lock(lock_);
+      while (0 == task_count() && !shutdown()) {
+        ++waiting_thread_count_;
+        work_is_available()->Wait();
+        --waiting_thread_count_;
+      }
+      if (shutdown()) {
+        // Ack the notification of a shutdown message back to the controller.
+        thread_shutting_down();
+        return;  // Terminate.
+      }
+      // Get our task duration from the queue.
+      work_time = GetAnAssignment(thread_id);
+      could_use_help = (task_count() > 0) && allow_help_requests();
+    }  // Release lock
+
+    // Do work (outside of locked region.
+    if (could_use_help)
+      work_is_available()->Signal();  // Get help from other threads.
+
+    if (work_time > TimeDelta::FromMilliseconds(0)) {
+      // We could just sleep(), but we'll instead further exercise the
+      // condition variable class, and do a timed wait.
+      base::AutoLock auto_lock(private_lock);
+      ConditionVariable private_cv(&private_lock);
+      private_cv.TimedWait(work_time);  // Unsynchronized waiting.
+    }
+
+    {
+      base::AutoLock auto_lock(lock_);
+      // Send notification that we completed our "work."
+      WorkIsCompleted(thread_id);
+    }
+  }
+}
+
+}  // namespace
+
+}  // namespace base
diff --git a/base/synchronization/condition_variable_win.cc b/base/synchronization/condition_variable_win.cc
new file mode 100644
index 0000000..5f165c8
--- /dev/null
+++ b/base/synchronization/condition_variable_win.cc
@@ -0,0 +1,669 @@
+// Copyright (c) 2011 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/synchronization/condition_variable.h"
+
+#include <windows.h>
+#include <stack>
+
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/time/time.h"
+
+namespace {
+// We can't use the linker supported delay-load for kernel32 so all this
+// cruft here is to manually late-bind the needed functions.
+typedef void (WINAPI *InitializeConditionVariableFn)(PCONDITION_VARIABLE);
+typedef BOOL (WINAPI *SleepConditionVariableCSFn)(PCONDITION_VARIABLE,
+                                                  PCRITICAL_SECTION, DWORD);
+typedef void (WINAPI *WakeConditionVariableFn)(PCONDITION_VARIABLE);
+typedef void (WINAPI *WakeAllConditionVariableFn)(PCONDITION_VARIABLE);
+
+InitializeConditionVariableFn initialize_condition_variable_fn;
+SleepConditionVariableCSFn sleep_condition_variable_fn;
+WakeConditionVariableFn wake_condition_variable_fn;
+WakeAllConditionVariableFn wake_all_condition_variable_fn;
+
+bool BindVistaCondVarFunctions() {
+  HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
+  initialize_condition_variable_fn =
+      reinterpret_cast<InitializeConditionVariableFn>(
+          GetProcAddress(kernel32, "InitializeConditionVariable"));
+  if (!initialize_condition_variable_fn)
+    return false;
+  sleep_condition_variable_fn =
+      reinterpret_cast<SleepConditionVariableCSFn>(
+          GetProcAddress(kernel32, "SleepConditionVariableCS"));
+  if (!sleep_condition_variable_fn)
+    return false;
+  wake_condition_variable_fn =
+      reinterpret_cast<WakeConditionVariableFn>(
+          GetProcAddress(kernel32, "WakeConditionVariable"));
+  if (!wake_condition_variable_fn)
+    return false;
+  wake_all_condition_variable_fn =
+      reinterpret_cast<WakeAllConditionVariableFn>(
+          GetProcAddress(kernel32, "WakeAllConditionVariable"));
+  if (!wake_all_condition_variable_fn)
+    return false;
+  return true;
+}
+
+}  // namespace.
+
+namespace base {
+// Abstract base class of the pimpl idiom.
+class ConditionVarImpl {
+ public:
+  virtual ~ConditionVarImpl() {};
+  virtual void Wait() = 0;
+  virtual void TimedWait(const TimeDelta& max_time) = 0;
+  virtual void Broadcast() = 0;
+  virtual void Signal() = 0;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Windows Vista and Win7 implementation.
+///////////////////////////////////////////////////////////////////////////////
+
+class WinVistaCondVar: public ConditionVarImpl {
+ public:
+  WinVistaCondVar(Lock* user_lock);
+  ~WinVistaCondVar() override {}
+  // Overridden from ConditionVarImpl.
+  void Wait() override;
+  void TimedWait(const TimeDelta& max_time) override;
+  void Broadcast() override;
+  void Signal() override;
+
+ private:
+  base::Lock& user_lock_;
+  CONDITION_VARIABLE cv_;
+};
+
+WinVistaCondVar::WinVistaCondVar(Lock* user_lock)
+    : user_lock_(*user_lock) {
+  initialize_condition_variable_fn(&cv_);
+  DCHECK(user_lock);
+}
+
+void WinVistaCondVar::Wait() {
+  TimedWait(TimeDelta::FromMilliseconds(INFINITE));
+}
+
+void WinVistaCondVar::TimedWait(const TimeDelta& max_time) {
+  base::ThreadRestrictions::AssertWaitAllowed();
+  DWORD timeout = static_cast<DWORD>(max_time.InMilliseconds());
+  CRITICAL_SECTION* cs = user_lock_.lock_.native_handle();
+
+#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+  user_lock_.CheckHeldAndUnmark();
+#endif
+
+  if (FALSE == sleep_condition_variable_fn(&cv_, cs, timeout)) {
+    DCHECK(GetLastError() != WAIT_TIMEOUT);
+  }
+
+#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+  user_lock_.CheckUnheldAndMark();
+#endif
+}
+
+void WinVistaCondVar::Broadcast() {
+  wake_all_condition_variable_fn(&cv_);
+}
+
+void WinVistaCondVar::Signal() {
+  wake_condition_variable_fn(&cv_);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Windows XP implementation.
+///////////////////////////////////////////////////////////////////////////////
+
+class WinXPCondVar : public ConditionVarImpl {
+ public:
+  WinXPCondVar(Lock* user_lock);
+  ~WinXPCondVar() override;
+  // Overridden from ConditionVarImpl.
+  void Wait() override;
+  void TimedWait(const TimeDelta& max_time) override;
+  void Broadcast() override;
+  void Signal() override;
+
+  // Define Event class that is used to form circularly linked lists.
+  // The list container is an element with NULL as its handle_ value.
+  // The actual list elements have a non-zero handle_ value.
+  // All calls to methods MUST be done under protection of a lock so that links
+  // can be validated.  Without the lock, some links might asynchronously
+  // change, and the assertions would fail (as would list change operations).
+  class Event {
+   public:
+    // Default constructor with no arguments creates a list container.
+    Event();
+    ~Event();
+
+    // InitListElement transitions an instance from a container, to an element.
+    void InitListElement();
+
+    // Methods for use on lists.
+    bool IsEmpty() const;
+    void PushBack(Event* other);
+    Event* PopFront();
+    Event* PopBack();
+
+    // Methods for use on list elements.
+    // Accessor method.
+    HANDLE handle() const;
+    // Pull an element from a list (if it's in one).
+    Event* Extract();
+
+    // Method for use on a list element or on a list.
+    bool IsSingleton() const;
+
+   private:
+    // Provide pre/post conditions to validate correct manipulations.
+    bool ValidateAsDistinct(Event* other) const;
+    bool ValidateAsItem() const;
+    bool ValidateAsList() const;
+    bool ValidateLinks() const;
+
+    HANDLE handle_;
+    Event* next_;
+    Event* prev_;
+    DISALLOW_COPY_AND_ASSIGN(Event);
+  };
+
+  // Note that RUNNING is an unlikely number to have in RAM by accident.
+  // This helps with defensive destructor coding in the face of user error.
+  enum RunState { SHUTDOWN = 0, RUNNING = 64213 };
+
+  // Internal implementation methods supporting Wait().
+  Event* GetEventForWaiting();
+  void RecycleEvent(Event* used_event);
+
+  RunState run_state_;
+
+  // Private critical section for access to member data.
+  base::Lock internal_lock_;
+
+  // Lock that is acquired before calling Wait().
+  base::Lock& user_lock_;
+
+  // Events that threads are blocked on.
+  Event waiting_list_;
+
+  // Free list for old events.
+  Event recycling_list_;
+  int recycling_list_size_;
+
+  // The number of allocated, but not yet deleted events.
+  int allocation_counter_;
+};
+
+WinXPCondVar::WinXPCondVar(Lock* user_lock)
+    : user_lock_(*user_lock),
+      run_state_(RUNNING),
+      allocation_counter_(0),
+      recycling_list_size_(0) {
+  DCHECK(user_lock);
+}
+
+WinXPCondVar::~WinXPCondVar() {
+  AutoLock auto_lock(internal_lock_);
+  run_state_ = SHUTDOWN;  // Prevent any more waiting.
+
+  DCHECK_EQ(recycling_list_size_, allocation_counter_);
+  if (recycling_list_size_ != allocation_counter_) {  // Rare shutdown problem.
+    // There are threads of execution still in this->TimedWait() and yet the
+    // caller has instigated the destruction of this instance :-/.
+    // A common reason for such "overly hasty" destruction is that the caller
+    // was not willing to wait for all the threads to terminate.  Such hasty
+    // actions are a violation of our usage contract, but we'll give the
+    // waiting thread(s) one last chance to exit gracefully (prior to our
+    // destruction).
+    // Note: waiting_list_ *might* be empty, but recycling is still pending.
+    AutoUnlock auto_unlock(internal_lock_);
+    Broadcast();  // Make sure all waiting threads have been signaled.
+    Sleep(10);  // Give threads a chance to grab internal_lock_.
+    // All contained threads should be blocked on user_lock_ by now :-).
+  }  // Reacquire internal_lock_.
+
+  DCHECK_EQ(recycling_list_size_, allocation_counter_);
+}
+
+void WinXPCondVar::Wait() {
+  // Default to "wait forever" timing, which means have to get a Signal()
+  // or Broadcast() to come out of this wait state.
+  TimedWait(TimeDelta::FromMilliseconds(INFINITE));
+}
+
+void WinXPCondVar::TimedWait(const TimeDelta& max_time) {
+  base::ThreadRestrictions::AssertWaitAllowed();
+  Event* waiting_event;
+  HANDLE handle;
+  {
+    AutoLock auto_lock(internal_lock_);
+    if (RUNNING != run_state_) return;  // Destruction in progress.
+    waiting_event = GetEventForWaiting();
+    handle = waiting_event->handle();
+    DCHECK(handle);
+  }  // Release internal_lock.
+
+  {
+    AutoUnlock unlock(user_lock_);  // Release caller's lock
+    WaitForSingleObject(handle, static_cast<DWORD>(max_time.InMilliseconds()));
+    // Minimize spurious signal creation window by recycling asap.
+    AutoLock auto_lock(internal_lock_);
+    RecycleEvent(waiting_event);
+    // Release internal_lock_
+  }  // Reacquire callers lock to depth at entry.
+}
+
+// Broadcast() is guaranteed to signal all threads that were waiting (i.e., had
+// a cv_event internally allocated for them) before Broadcast() was called.
+void WinXPCondVar::Broadcast() {
+  std::stack<HANDLE> handles;  // See FAQ-question-10.
+  {
+    AutoLock auto_lock(internal_lock_);
+    if (waiting_list_.IsEmpty())
+      return;
+    while (!waiting_list_.IsEmpty())
+      // This is not a leak from waiting_list_.  See FAQ-question 12.
+      handles.push(waiting_list_.PopBack()->handle());
+  }  // Release internal_lock_.
+  while (!handles.empty()) {
+    SetEvent(handles.top());
+    handles.pop();
+  }
+}
+
+// Signal() will select one of the waiting threads, and signal it (signal its
+// cv_event).  For better performance we signal the thread that went to sleep
+// most recently (LIFO).  If we want fairness, then we wake the thread that has
+// been sleeping the longest (FIFO).
+void WinXPCondVar::Signal() {
+  HANDLE handle;
+  {
+    AutoLock auto_lock(internal_lock_);
+    if (waiting_list_.IsEmpty())
+      return;  // No one to signal.
+    // Only performance option should be used.
+    // This is not a leak from waiting_list.  See FAQ-question 12.
+     handle = waiting_list_.PopBack()->handle();  // LIFO.
+  }  // Release internal_lock_.
+  SetEvent(handle);
+}
+
+// GetEventForWaiting() provides a unique cv_event for any caller that needs to
+// wait.  This means that (worst case) we may over time create as many cv_event
+// objects as there are threads simultaneously using this instance's Wait()
+// functionality.
+WinXPCondVar::Event* WinXPCondVar::GetEventForWaiting() {
+  // We hold internal_lock, courtesy of Wait().
+  Event* cv_event;
+  if (0 == recycling_list_size_) {
+    DCHECK(recycling_list_.IsEmpty());
+    cv_event = new Event();
+    cv_event->InitListElement();
+    allocation_counter_++;
+    DCHECK(cv_event->handle());
+  } else {
+    cv_event = recycling_list_.PopFront();
+    recycling_list_size_--;
+  }
+  waiting_list_.PushBack(cv_event);
+  return cv_event;
+}
+
+// RecycleEvent() takes a cv_event that was previously used for Wait()ing, and
+// recycles it for use in future Wait() calls for this or other threads.
+// Note that there is a tiny chance that the cv_event is still signaled when we
+// obtain it, and that can cause spurious signals (if/when we re-use the
+// cv_event), but such is quite rare (see FAQ-question-5).
+void WinXPCondVar::RecycleEvent(Event* used_event) {
+  // We hold internal_lock, courtesy of Wait().
+  // If the cv_event timed out, then it is necessary to remove it from
+  // waiting_list_.  If it was selected by Broadcast() or Signal(), then it is
+  // already gone.
+  used_event->Extract();  // Possibly redundant
+  recycling_list_.PushBack(used_event);
+  recycling_list_size_++;
+}
+//------------------------------------------------------------------------------
+// The next section provides the implementation for the private Event class.
+//------------------------------------------------------------------------------
+
+// Event provides a doubly-linked-list of events for use exclusively by the
+// ConditionVariable class.
+
+// This custom container was crafted because no simple combination of STL
+// classes appeared to support the functionality required.  The specific
+// unusual requirement for a linked-list-class is support for the Extract()
+// method, which can remove an element from a list, potentially for insertion
+// into a second list.  Most critically, the Extract() method is idempotent,
+// turning the indicated element into an extracted singleton whether it was
+// contained in a list or not.  This functionality allows one (or more) of
+// threads to do the extraction.  The iterator that identifies this extractable
+// element (in this case, a pointer to the list element) can be used after
+// arbitrary manipulation of the (possibly) enclosing list container.  In
+// general, STL containers do not provide iterators that can be used across
+// modifications (insertions/extractions) of the enclosing containers, and
+// certainly don't provide iterators that can be used if the identified
+// element is *deleted* (removed) from the container.
+
+// It is possible to use multiple redundant containers, such as an STL list,
+// and an STL map, to achieve similar container semantics.  This container has
+// only O(1) methods, while the corresponding (multiple) STL container approach
+// would have more complex O(log(N)) methods (yeah... N isn't that large).
+// Multiple containers also makes correctness more difficult to assert, as
+// data is redundantly stored and maintained, which is generally evil.
+
+WinXPCondVar::Event::Event() : handle_(0) {
+  next_ = prev_ = this;  // Self referencing circular.
+}
+
+WinXPCondVar::Event::~Event() {
+  if (0 == handle_) {
+    // This is the list holder
+    while (!IsEmpty()) {
+      Event* cv_event = PopFront();
+      DCHECK(cv_event->ValidateAsItem());
+      delete cv_event;
+    }
+  }
+  DCHECK(IsSingleton());
+  if (0 != handle_) {
+    int ret_val = CloseHandle(handle_);
+    DCHECK(ret_val);
+  }
+}
+
+// Change a container instance permanently into an element of a list.
+void WinXPCondVar::Event::InitListElement() {
+  DCHECK(!handle_);
+  handle_ = CreateEvent(NULL, false, false, NULL);
+  DCHECK(handle_);
+}
+
+// Methods for use on lists.
+bool WinXPCondVar::Event::IsEmpty() const {
+  DCHECK(ValidateAsList());
+  return IsSingleton();
+}
+
+void WinXPCondVar::Event::PushBack(Event* other) {
+  DCHECK(ValidateAsList());
+  DCHECK(other->ValidateAsItem());
+  DCHECK(other->IsSingleton());
+  // Prepare other for insertion.
+  other->prev_ = prev_;
+  other->next_ = this;
+  // Cut into list.
+  prev_->next_ = other;
+  prev_ = other;
+  DCHECK(ValidateAsDistinct(other));
+}
+
+WinXPCondVar::Event* WinXPCondVar::Event::PopFront() {
+  DCHECK(ValidateAsList());
+  DCHECK(!IsSingleton());
+  return next_->Extract();
+}
+
+WinXPCondVar::Event* WinXPCondVar::Event::PopBack() {
+  DCHECK(ValidateAsList());
+  DCHECK(!IsSingleton());
+  return prev_->Extract();
+}
+
+// Methods for use on list elements.
+// Accessor method.
+HANDLE WinXPCondVar::Event::handle() const {
+  DCHECK(ValidateAsItem());
+  return handle_;
+}
+
+// Pull an element from a list (if it's in one).
+WinXPCondVar::Event* WinXPCondVar::Event::Extract() {
+  DCHECK(ValidateAsItem());
+  if (!IsSingleton()) {
+    // Stitch neighbors together.
+    next_->prev_ = prev_;
+    prev_->next_ = next_;
+    // Make extractee into a singleton.
+    prev_ = next_ = this;
+  }
+  DCHECK(IsSingleton());
+  return this;
+}
+
+// Method for use on a list element or on a list.
+bool WinXPCondVar::Event::IsSingleton() const {
+  DCHECK(ValidateLinks());
+  return next_ == this;
+}
+
+// Provide pre/post conditions to validate correct manipulations.
+bool WinXPCondVar::Event::ValidateAsDistinct(Event* other) const {
+  return ValidateLinks() && other->ValidateLinks() && (this != other);
+}
+
+bool WinXPCondVar::Event::ValidateAsItem() const {
+  return (0 != handle_) && ValidateLinks();
+}
+
+bool WinXPCondVar::Event::ValidateAsList() const {
+  return (0 == handle_) && ValidateLinks();
+}
+
+bool WinXPCondVar::Event::ValidateLinks() const {
+  // Make sure both of our neighbors have links that point back to us.
+  // We don't do the O(n) check and traverse the whole loop, and instead only
+  // do a local check to (and returning from) our immediate neighbors.
+  return (next_->prev_ == this) && (prev_->next_ == this);
+}
+
+
+/*
+FAQ On WinXPCondVar subtle implementation details:
+
+1) What makes this problem subtle?  Please take a look at "Strategies
+for Implementing POSIX Condition Variables on Win32" by Douglas
+C. Schmidt and Irfan Pyarali.
+http://www.cs.wustl.edu/~schmidt/win32-cv-1.html It includes
+discussions of numerous flawed strategies for implementing this
+functionality.  I'm not convinced that even the final proposed
+implementation has semantics that are as nice as this implementation
+(especially with regard to Broadcast() and the impact on threads that
+try to Wait() after a Broadcast() has been called, but before all the
+original waiting threads have been signaled).
+
+2) Why can't you use a single wait_event for all threads that call
+Wait()?  See FAQ-question-1, or consider the following: If a single
+event were used, then numerous threads calling Wait() could release
+their cs locks, and be preempted just before calling
+WaitForSingleObject().  If a call to Broadcast() was then presented on
+a second thread, it would be impossible to actually signal all
+waiting(?) threads.  Some number of SetEvent() calls *could* be made,
+but there could be no guarantee that those led to to more than one
+signaled thread (SetEvent()'s may be discarded after the first!), and
+there could be no guarantee that the SetEvent() calls didn't just
+awaken "other" threads that hadn't even started waiting yet (oops).
+Without any limit on the number of requisite SetEvent() calls, the
+system would be forced to do many such calls, allowing many new waits
+to receive spurious signals.
+
+3) How does this implementation cause spurious signal events?  The
+cause in this implementation involves a race between a signal via
+time-out and a signal via Signal() or Broadcast().  The series of
+actions leading to this are:
+
+a) Timer fires, and a waiting thread exits the line of code:
+
+    WaitForSingleObject(waiting_event, max_time.InMilliseconds());
+
+b) That thread (in (a)) is randomly pre-empted after the above line,
+leaving the waiting_event reset (unsignaled) and still in the
+waiting_list_.
+
+c) A call to Signal() (or Broadcast()) on a second thread proceeds, and
+selects the waiting cv_event (identified in step (b)) as the event to revive
+via a call to SetEvent().
+
+d) The Signal() method (step c) calls SetEvent() on waiting_event (step b).
+
+e) The waiting cv_event (step b) is now signaled, but no thread is
+waiting on it.
+
+f) When that waiting_event (step b) is reused, it will immediately
+be signaled (spuriously).
+
+
+4) Why do you recycle events, and cause spurious signals?  First off,
+the spurious events are very rare.  They can only (I think) appear
+when the race described in FAQ-question-3 takes place.  This should be
+very rare.  Most(?)  uses will involve only timer expiration, or only
+Signal/Broadcast() actions.  When both are used, it will be rare that
+the race will appear, and it would require MANY Wait() and signaling
+activities.  If this implementation did not recycle events, then it
+would have to create and destroy events for every call to Wait().
+That allocation/deallocation and associated construction/destruction
+would be costly (per wait), and would only be a rare benefit (when the
+race was "lost" and a spurious signal took place). That would be bad
+(IMO) optimization trade-off.  Finally, such spurious events are
+allowed by the specification of condition variables (such as
+implemented in Vista), and hence it is better if any user accommodates
+such spurious events (see usage note in condition_variable.h).
+
+5) Why don't you reset events when you are about to recycle them, or
+about to reuse them, so that the spurious signals don't take place?
+The thread described in FAQ-question-3 step c may be pre-empted for an
+arbitrary length of time before proceeding to step d.  As a result,
+the wait_event may actually be re-used *before* step (e) is reached.
+As a result, calling reset would not help significantly.
+
+6) How is it that the callers lock is released atomically with the
+entry into a wait state?  We commit to the wait activity when we
+allocate the wait_event for use in a given call to Wait().  This
+allocation takes place before the caller's lock is released (and
+actually before our internal_lock_ is released).  That allocation is
+the defining moment when "the wait state has been entered," as that
+thread *can* now be signaled by a call to Broadcast() or Signal().
+Hence we actually "commit to wait" before releasing the lock, making
+the pair effectively atomic.
+
+8) Why do you need to lock your data structures during waiting, as the
+caller is already in possession of a lock?  We need to Acquire() and
+Release() our internal lock during Signal() and Broadcast().  If we tried
+to use a callers lock for this purpose, we might conflict with their
+external use of the lock.  For example, the caller may use to consistently
+hold a lock on one thread while calling Signal() on another, and that would
+block Signal().
+
+9) Couldn't a more efficient implementation be provided if you
+preclude using more than one external lock in conjunction with a
+single ConditionVariable instance?  Yes, at least it could be viewed
+as a simpler API (since you don't have to reiterate the lock argument
+in each Wait() call).  One of the constructors now takes a specific
+lock as an argument, and a there are corresponding Wait() calls that
+don't specify a lock now.  It turns that the resulting implmentation
+can't be made more efficient, as the internal lock needs to be used by
+Signal() and Broadcast(), to access internal data structures.  As a
+result, I was not able to utilize the user supplied lock (which is
+being used by the user elsewhere presumably) to protect the private
+member access.
+
+9) Since you have a second lock, how can be be sure that there is no
+possible deadlock scenario?  Our internal_lock_ is always the last
+lock acquired, and the first one released, and hence a deadlock (due
+to critical section problems) is impossible as a consequence of our
+lock.
+
+10) When doing a Broadcast(), why did you copy all the events into
+an STL queue, rather than making a linked-loop, and iterating over it?
+The iterating during Broadcast() is done so outside the protection
+of the internal lock. As a result, other threads, such as the thread
+wherein a related event is waiting, could asynchronously manipulate
+the links around a cv_event.  As a result, the link structure cannot
+be used outside a lock.  Broadcast() could iterate over waiting
+events by cycling in-and-out of the protection of the internal_lock,
+but that appears more expensive than copying the list into an STL
+stack.
+
+11) Why did the lock.h file need to be modified so much for this
+change?  Central to a Condition Variable is the atomic release of a
+lock during a Wait().  This places Wait() functionality exactly
+mid-way between the two classes, Lock and Condition Variable.  Given
+that there can be nested Acquire()'s of locks, and Wait() had to
+Release() completely a held lock, it was necessary to augment the Lock
+class with a recursion counter. Even more subtle is the fact that the
+recursion counter (in a Lock) must be protected, as many threads can
+access it asynchronously.  As a positive fallout of this, there are
+now some DCHECKS to be sure no one Release()s a Lock more than they
+Acquire()ed it, and there is ifdef'ed functionality that can detect
+nested locks (legal under windows, but not under Posix).
+
+12) Why is it that the cv_events removed from list in Broadcast() and Signal()
+are not leaked?  How are they recovered??  The cv_events that appear to leak are
+taken from the waiting_list_.  For each element in that list, there is currently
+a thread in or around the WaitForSingleObject() call of Wait(), and those
+threads have references to these otherwise leaked events. They are passed as
+arguments to be recycled just aftre returning from WaitForSingleObject().
+
+13) Why did you use a custom container class (the linked list), when STL has
+perfectly good containers, such as an STL list?  The STL list, as with any
+container, does not guarantee the utility of an iterator across manipulation
+(such as insertions and deletions) of the underlying container.  The custom
+double-linked-list container provided that assurance.  I don't believe any
+combination of STL containers provided the services that were needed at the same
+O(1) efficiency as the custom linked list.  The unusual requirement
+for the container class is that a reference to an item within a container (an
+iterator) needed to be maintained across an arbitrary manipulation of the
+container.  This requirement exposes itself in the Wait() method, where a
+waiting_event must be selected prior to the WaitForSingleObject(), and then it
+must be used as part of recycling to remove the related instance from the
+waiting_list.  A hash table (STL map) could be used, but I was embarrased to
+use a complex and relatively low efficiency container when a doubly linked list
+provided O(1) performance in all required operations.  Since other operations
+to provide performance-and/or-fairness required queue (FIFO) and list (LIFO)
+containers, I would also have needed to use an STL list/queue as well as an STL
+map.  In the end I decided it would be "fun" to just do it right, and I
+put so many assertions (DCHECKs) into the container class that it is trivial to
+code review and validate its correctness.
+
+*/
+
+ConditionVariable::ConditionVariable(Lock* user_lock)
+    : impl_(NULL) {
+  static bool use_vista_native_cv = BindVistaCondVarFunctions();
+  if (use_vista_native_cv)
+    impl_= new WinVistaCondVar(user_lock);
+  else
+    impl_ = new WinXPCondVar(user_lock);
+}
+
+ConditionVariable::~ConditionVariable() {
+  delete impl_;
+}
+
+void ConditionVariable::Wait() {
+  impl_->Wait();
+}
+
+void ConditionVariable::TimedWait(const TimeDelta& max_time) {
+  impl_->TimedWait(max_time);
+}
+
+void ConditionVariable::Broadcast() {
+  impl_->Broadcast();
+}
+
+void ConditionVariable::Signal() {
+  impl_->Signal();
+}
+
+}  // namespace base
diff --git a/base/synchronization/lock.cc b/base/synchronization/lock.cc
new file mode 100644
index 0000000..b1576c5
--- /dev/null
+++ b/base/synchronization/lock.cc
@@ -0,0 +1,39 @@
+// Copyright (c) 2011 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 used for debugging assertion support.  The Lock class
+// is functionally a wrapper around the LockImpl class, so the only
+// real intelligence in the class is in the debugging logic.
+
+#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+
+#include "base/synchronization/lock.h"
+#include "base/logging.h"
+
+namespace base {
+
+Lock::Lock() : lock_() {
+}
+
+Lock::~Lock() {
+  DCHECK(owning_thread_ref_.is_null());
+}
+
+void Lock::AssertAcquired() const {
+  DCHECK(owning_thread_ref_ == PlatformThread::CurrentRef());
+}
+
+void Lock::CheckHeldAndUnmark() {
+  DCHECK(owning_thread_ref_ == PlatformThread::CurrentRef());
+  owning_thread_ref_ = PlatformThreadRef();
+}
+
+void Lock::CheckUnheldAndMark() {
+  DCHECK(owning_thread_ref_.is_null());
+  owning_thread_ref_ = PlatformThread::CurrentRef();
+}
+
+}  // namespace base
+
+#endif  // !NDEBUG || DCHECK_ALWAYS_ON
diff --git a/base/synchronization/lock.h b/base/synchronization/lock.h
new file mode 100644
index 0000000..f384e41
--- /dev/null
+++ b/base/synchronization/lock.h
@@ -0,0 +1,137 @@
+// Copyright (c) 2011 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_SYNCHRONIZATION_LOCK_H_
+#define BASE_SYNCHRONIZATION_LOCK_H_
+
+#include "base/base_export.h"
+#include "base/synchronization/lock_impl.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+// A convenient wrapper for an OS specific critical section.  The only real
+// intelligence in this class is in debug mode for the support for the
+// AssertAcquired() method.
+class BASE_EXPORT Lock {
+ public:
+#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
+   // Optimized wrapper implementation
+  Lock() : lock_() {}
+  ~Lock() {}
+  void Acquire() { lock_.Lock(); }
+  void Release() { lock_.Unlock(); }
+
+  // If the lock is not held, take it and return true. If the lock is already
+  // held by another thread, immediately return false. This must not be called
+  // by a thread already holding the lock (what happens is undefined and an
+  // assertion may fail).
+  bool Try() { return lock_.Try(); }
+
+  // Null implementation if not debug.
+  void AssertAcquired() const {}
+#else
+  Lock();
+  ~Lock();
+
+  // NOTE: Although windows critical sections support recursive locks, we do not
+  // allow this, and we will commonly fire a DCHECK() if a thread attempts to
+  // acquire the lock a second time (while already holding it).
+  void Acquire() {
+    lock_.Lock();
+    CheckUnheldAndMark();
+  }
+  void Release() {
+    CheckHeldAndUnmark();
+    lock_.Unlock();
+  }
+
+  bool Try() {
+    bool rv = lock_.Try();
+    if (rv) {
+      CheckUnheldAndMark();
+    }
+    return rv;
+  }
+
+  void AssertAcquired() const;
+#endif  // NDEBUG && !DCHECK_ALWAYS_ON
+
+#if defined(OS_POSIX)
+  // The posix implementation of ConditionVariable needs to be able
+  // to see our lock and tweak our debugging counters, as it releases
+  // and acquires locks inside of pthread_cond_{timed,}wait.
+  friend class ConditionVariable;
+#elif defined(OS_WIN)
+  // The Windows Vista implementation of ConditionVariable needs the
+  // native handle of the critical section.
+  friend class WinVistaCondVar;
+#endif
+
+ private:
+#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+  // Members and routines taking care of locks assertions.
+  // Note that this checks for recursive locks and allows them
+  // if the variable is set.  This is allowed by the underlying implementation
+  // on windows but not on Posix, so we're doing unneeded checks on Posix.
+  // It's worth it to share the code.
+  void CheckHeldAndUnmark();
+  void CheckUnheldAndMark();
+
+  // All private data is implicitly protected by lock_.
+  // Be VERY careful to only access members under that lock.
+  base::PlatformThreadRef owning_thread_ref_;
+#endif  // !NDEBUG || DCHECK_ALWAYS_ON
+
+  // Platform specific underlying lock implementation.
+  internal::LockImpl lock_;
+
+  DISALLOW_COPY_AND_ASSIGN(Lock);
+};
+
+// A helper class that acquires the given Lock while the AutoLock is in scope.
+class AutoLock {
+ public:
+  struct AlreadyAcquired {};
+
+  explicit AutoLock(Lock& lock) : lock_(lock) {
+    lock_.Acquire();
+  }
+
+  AutoLock(Lock& lock, const AlreadyAcquired&) : lock_(lock) {
+    lock_.AssertAcquired();
+  }
+
+  ~AutoLock() {
+    lock_.AssertAcquired();
+    lock_.Release();
+  }
+
+ private:
+  Lock& lock_;
+  DISALLOW_COPY_AND_ASSIGN(AutoLock);
+};
+
+// AutoUnlock is a helper that will Release() the |lock| argument in the
+// constructor, and re-Acquire() it in the destructor.
+class AutoUnlock {
+ public:
+  explicit AutoUnlock(Lock& lock) : lock_(lock) {
+    // We require our caller to have the lock.
+    lock_.AssertAcquired();
+    lock_.Release();
+  }
+
+  ~AutoUnlock() {
+    lock_.Acquire();
+  }
+
+ private:
+  Lock& lock_;
+  DISALLOW_COPY_AND_ASSIGN(AutoUnlock);
+};
+
+}  // namespace base
+
+#endif  // BASE_SYNCHRONIZATION_LOCK_H_
diff --git a/base/synchronization/lock_impl.h b/base/synchronization/lock_impl.h
new file mode 100644
index 0000000..42e2f99
--- /dev/null
+++ b/base/synchronization/lock_impl.h
@@ -0,0 +1,61 @@
+// Copyright (c) 2011 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_SYNCHRONIZATION_LOCK_IMPL_H_
+#define BASE_SYNCHRONIZATION_LOCK_IMPL_H_
+
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#elif defined(OS_POSIX)
+#include <pthread.h>
+#endif
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace internal {
+
+// This class implements the underlying platform-specific spin-lock mechanism
+// used for the Lock class.  Most users should not use LockImpl directly, but
+// should instead use Lock.
+class BASE_EXPORT LockImpl {
+ public:
+#if defined(OS_WIN)
+  typedef CRITICAL_SECTION NativeHandle;
+#elif defined(OS_POSIX)
+  typedef pthread_mutex_t NativeHandle;
+#endif
+
+  LockImpl();
+  ~LockImpl();
+
+  // If the lock is not held, take it and return true.  If the lock is already
+  // held by something else, immediately return false.
+  bool Try();
+
+  // Take the lock, blocking until it is available if necessary.
+  void Lock();
+
+  // Release the lock.  This must only be called by the lock's holder: after
+  // a successful call to Try, or a call to Lock.
+  void Unlock();
+
+  // Return the native underlying lock.
+  // TODO(awalker): refactor lock and condition variables so that this is
+  // unnecessary.
+  NativeHandle* native_handle() { return &native_handle_; }
+
+ private:
+  NativeHandle native_handle_;
+
+  DISALLOW_COPY_AND_ASSIGN(LockImpl);
+};
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_SYNCHRONIZATION_LOCK_IMPL_H_
diff --git a/base/synchronization/lock_impl_posix.cc b/base/synchronization/lock_impl_posix.cc
new file mode 100644
index 0000000..5619ada
--- /dev/null
+++ b/base/synchronization/lock_impl_posix.cc
@@ -0,0 +1,55 @@
+// Copyright (c) 2011 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/synchronization/lock_impl.h"
+
+#include <errno.h>
+#include <string.h>
+
+#include "base/logging.h"
+
+namespace base {
+namespace internal {
+
+LockImpl::LockImpl() {
+#ifndef NDEBUG
+  // In debug, setup attributes for lock error checking.
+  pthread_mutexattr_t mta;
+  int rv = pthread_mutexattr_init(&mta);
+  DCHECK_EQ(rv, 0) << ". " << strerror(rv);
+  rv = pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_ERRORCHECK);
+  DCHECK_EQ(rv, 0) << ". " << strerror(rv);
+  rv = pthread_mutex_init(&native_handle_, &mta);
+  DCHECK_EQ(rv, 0) << ". " << strerror(rv);
+  rv = pthread_mutexattr_destroy(&mta);
+  DCHECK_EQ(rv, 0) << ". " << strerror(rv);
+#else
+  // In release, go with the default lock attributes.
+  pthread_mutex_init(&native_handle_, NULL);
+#endif
+}
+
+LockImpl::~LockImpl() {
+  int rv = pthread_mutex_destroy(&native_handle_);
+  DCHECK_EQ(rv, 0) << ". " << strerror(rv);
+}
+
+bool LockImpl::Try() {
+  int rv = pthread_mutex_trylock(&native_handle_);
+  DCHECK(rv == 0 || rv == EBUSY) << ". " << strerror(rv);
+  return rv == 0;
+}
+
+void LockImpl::Lock() {
+  int rv = pthread_mutex_lock(&native_handle_);
+  DCHECK_EQ(rv, 0) << ". " << strerror(rv);
+}
+
+void LockImpl::Unlock() {
+  int rv = pthread_mutex_unlock(&native_handle_);
+  DCHECK_EQ(rv, 0) << ". " << strerror(rv);
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/synchronization/lock_impl_win.cc b/base/synchronization/lock_impl_win.cc
new file mode 100644
index 0000000..fbc1bdd
--- /dev/null
+++ b/base/synchronization/lock_impl_win.cc
@@ -0,0 +1,36 @@
+// Copyright (c) 2011 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/synchronization/lock_impl.h"
+
+namespace base {
+namespace internal {
+
+LockImpl::LockImpl() {
+  // The second parameter is the spin count, for short-held locks it avoid the
+  // contending thread from going to sleep which helps performance greatly.
+  ::InitializeCriticalSectionAndSpinCount(&native_handle_, 2000);
+}
+
+LockImpl::~LockImpl() {
+  ::DeleteCriticalSection(&native_handle_);
+}
+
+bool LockImpl::Try() {
+  if (::TryEnterCriticalSection(&native_handle_) != FALSE) {
+    return true;
+  }
+  return false;
+}
+
+void LockImpl::Lock() {
+  ::EnterCriticalSection(&native_handle_);
+}
+
+void LockImpl::Unlock() {
+  ::LeaveCriticalSection(&native_handle_);
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/synchronization/lock_unittest.cc b/base/synchronization/lock_unittest.cc
new file mode 100644
index 0000000..967efb8
--- /dev/null
+++ b/base/synchronization/lock_unittest.cc
@@ -0,0 +1,214 @@
+// Copyright (c) 2012 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/synchronization/lock.h"
+
+#include <stdlib.h>
+
+#include "base/compiler_specific.h"
+#include "base/threading/platform_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+// Basic test to make sure that Acquire()/Release()/Try() don't crash ----------
+
+class BasicLockTestThread : public PlatformThread::Delegate {
+ public:
+  explicit BasicLockTestThread(Lock* lock) : lock_(lock), acquired_(0) {}
+
+  void ThreadMain() override {
+    for (int i = 0; i < 10; i++) {
+      lock_->Acquire();
+      acquired_++;
+      lock_->Release();
+    }
+    for (int i = 0; i < 10; i++) {
+      lock_->Acquire();
+      acquired_++;
+      PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20));
+      lock_->Release();
+    }
+    for (int i = 0; i < 10; i++) {
+      if (lock_->Try()) {
+        acquired_++;
+        PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20));
+        lock_->Release();
+      }
+    }
+  }
+
+  int acquired() const { return acquired_; }
+
+ private:
+  Lock* lock_;
+  int acquired_;
+
+  DISALLOW_COPY_AND_ASSIGN(BasicLockTestThread);
+};
+
+TEST(LockTest, Basic) {
+  Lock lock;
+  BasicLockTestThread thread(&lock);
+  PlatformThreadHandle handle;
+
+  ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
+
+  int acquired = 0;
+  for (int i = 0; i < 5; i++) {
+    lock.Acquire();
+    acquired++;
+    lock.Release();
+  }
+  for (int i = 0; i < 10; i++) {
+    lock.Acquire();
+    acquired++;
+    PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20));
+    lock.Release();
+  }
+  for (int i = 0; i < 10; i++) {
+    if (lock.Try()) {
+      acquired++;
+      PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20));
+      lock.Release();
+    }
+  }
+  for (int i = 0; i < 5; i++) {
+    lock.Acquire();
+    acquired++;
+    PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 20));
+    lock.Release();
+  }
+
+  PlatformThread::Join(handle);
+
+  EXPECT_GE(acquired, 20);
+  EXPECT_GE(thread.acquired(), 20);
+}
+
+// Test that Try() works as expected -------------------------------------------
+
+class TryLockTestThread : public PlatformThread::Delegate {
+ public:
+  explicit TryLockTestThread(Lock* lock) : lock_(lock), got_lock_(false) {}
+
+  void ThreadMain() override {
+    got_lock_ = lock_->Try();
+    if (got_lock_)
+      lock_->Release();
+  }
+
+  bool got_lock() const { return got_lock_; }
+
+ private:
+  Lock* lock_;
+  bool got_lock_;
+
+  DISALLOW_COPY_AND_ASSIGN(TryLockTestThread);
+};
+
+TEST(LockTest, TryLock) {
+  Lock lock;
+
+  ASSERT_TRUE(lock.Try());
+  // We now have the lock....
+
+  // This thread will not be able to get the lock.
+  {
+    TryLockTestThread thread(&lock);
+    PlatformThreadHandle handle;
+
+    ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
+
+    PlatformThread::Join(handle);
+
+    ASSERT_FALSE(thread.got_lock());
+  }
+
+  lock.Release();
+
+  // This thread will....
+  {
+    TryLockTestThread thread(&lock);
+    PlatformThreadHandle handle;
+
+    ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
+
+    PlatformThread::Join(handle);
+
+    ASSERT_TRUE(thread.got_lock());
+    // But it released it....
+    ASSERT_TRUE(lock.Try());
+  }
+
+  lock.Release();
+}
+
+// Tests that locks actually exclude -------------------------------------------
+
+class MutexLockTestThread : public PlatformThread::Delegate {
+ public:
+  MutexLockTestThread(Lock* lock, int* value) : lock_(lock), value_(value) {}
+
+  // Static helper which can also be called from the main thread.
+  static void DoStuff(Lock* lock, int* value) {
+    for (int i = 0; i < 40; i++) {
+      lock->Acquire();
+      int v = *value;
+      PlatformThread::Sleep(TimeDelta::FromMilliseconds(rand() % 10));
+      *value = v + 1;
+      lock->Release();
+    }
+  }
+
+  void ThreadMain() override { DoStuff(lock_, value_); }
+
+ private:
+  Lock* lock_;
+  int* value_;
+
+  DISALLOW_COPY_AND_ASSIGN(MutexLockTestThread);
+};
+
+TEST(LockTest, MutexTwoThreads) {
+  Lock lock;
+  int value = 0;
+
+  MutexLockTestThread thread(&lock, &value);
+  PlatformThreadHandle handle;
+
+  ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
+
+  MutexLockTestThread::DoStuff(&lock, &value);
+
+  PlatformThread::Join(handle);
+
+  EXPECT_EQ(2 * 40, value);
+}
+
+TEST(LockTest, MutexFourThreads) {
+  Lock lock;
+  int value = 0;
+
+  MutexLockTestThread thread1(&lock, &value);
+  MutexLockTestThread thread2(&lock, &value);
+  MutexLockTestThread thread3(&lock, &value);
+  PlatformThreadHandle handle1;
+  PlatformThreadHandle handle2;
+  PlatformThreadHandle handle3;
+
+  ASSERT_TRUE(PlatformThread::Create(0, &thread1, &handle1));
+  ASSERT_TRUE(PlatformThread::Create(0, &thread2, &handle2));
+  ASSERT_TRUE(PlatformThread::Create(0, &thread3, &handle3));
+
+  MutexLockTestThread::DoStuff(&lock, &value);
+
+  PlatformThread::Join(handle1);
+  PlatformThread::Join(handle2);
+  PlatformThread::Join(handle3);
+
+  EXPECT_EQ(4 * 40, value);
+}
+
+}  // namespace base
diff --git a/base/synchronization/spin_wait.h b/base/synchronization/spin_wait.h
new file mode 100644
index 0000000..9b147cd
--- /dev/null
+++ b/base/synchronization/spin_wait.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2012 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 provides a macro ONLY for use in testing.
+// DO NOT USE IN PRODUCTION CODE.  There are much better ways to wait.
+
+// This code is very helpful in testing multi-threaded code, without depending
+// on almost any primitives.  This is especially helpful if you are testing
+// those primitive multi-threaded constructs.
+
+// We provide a simple one argument spin wait (for 1 second), and a generic
+// spin wait (for longer periods of time).
+
+#ifndef BASE_SYNCHRONIZATION_SPIN_WAIT_H_
+#define BASE_SYNCHRONIZATION_SPIN_WAIT_H_
+
+#include "base/threading/platform_thread.h"
+#include "base/time/time.h"
+
+// Provide a macro that will wait no longer than 1 second for an asynchronous
+// change is the value of an expression.
+// A typical use would be:
+//
+//   SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(0 == f(x));
+//
+// The expression will be evaluated repeatedly until it is true, or until
+// the time (1 second) expires.
+// Since tests generally have a 5 second watch dog timer, this spin loop is
+// typically used to get the padding needed on a given test platform to assure
+// that the test passes, even if load varies, and external events vary.
+
+#define SPIN_FOR_1_SECOND_OR_UNTIL_TRUE(expression) \
+    SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(base::TimeDelta::FromSeconds(1), \
+                                     (expression))
+
+#define SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(delta, expression) do { \
+  base::TimeTicks start = base::TimeTicks::Now(); \
+  const base::TimeDelta kTimeout = delta; \
+    while (!(expression)) { \
+      if (kTimeout < base::TimeTicks::Now() - start) { \
+      EXPECT_LE((base::TimeTicks::Now() - start).InMilliseconds(), \
+                kTimeout.InMilliseconds()) << "Timed out"; \
+        break; \
+      } \
+      base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(50)); \
+    } \
+  } while (0)
+
+#endif  // BASE_SYNCHRONIZATION_SPIN_WAIT_H_
diff --git a/base/synchronization/waitable_event.h b/base/synchronization/waitable_event.h
new file mode 100644
index 0000000..c35af54
--- /dev/null
+++ b/base/synchronization/waitable_event.h
@@ -0,0 +1,186 @@
+// Copyright (c) 2012 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_SYNCHRONIZATION_WAITABLE_EVENT_H_
+#define BASE_SYNCHRONIZATION_WAITABLE_EVENT_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+#if defined(OS_WIN)
+#include "base/win/scoped_handle.h"
+#endif
+
+#if defined(OS_POSIX)
+#include <list>
+#include <utility>
+#include "base/memory/ref_counted.h"
+#include "base/synchronization/lock.h"
+#endif
+
+namespace base {
+
+class TimeDelta;
+
+// A WaitableEvent can be a useful thread synchronization tool when you want to
+// allow one thread to wait for another thread to finish some work. For
+// non-Windows systems, this can only be used from within a single address
+// space.
+//
+// Use a WaitableEvent when you would otherwise use a Lock+ConditionVariable to
+// protect a simple boolean value.  However, if you find yourself using a
+// WaitableEvent in conjunction with a Lock to wait for a more complex state
+// change (e.g., for an item to be added to a queue), then you should probably
+// be using a ConditionVariable instead of a WaitableEvent.
+//
+// NOTE: On Windows, this class provides a subset of the functionality afforded
+// by a Windows event object.  This is intentional.  If you are writing Windows
+// specific code and you need other features of a Windows event, then you might
+// be better off just using an Windows event directly.
+class BASE_EXPORT WaitableEvent {
+ public:
+  // If manual_reset is true, then to set the event state to non-signaled, a
+  // consumer must call the Reset method.  If this parameter is false, then the
+  // system automatically resets the event state to non-signaled after a single
+  // waiting thread has been released.
+  WaitableEvent(bool manual_reset, bool initially_signaled);
+
+#if defined(OS_WIN)
+  // Create a WaitableEvent from an Event HANDLE which has already been
+  // created. This objects takes ownership of the HANDLE and will close it when
+  // deleted.
+  explicit WaitableEvent(win::ScopedHandle event_handle);
+#endif
+
+  ~WaitableEvent();
+
+  // Put the event in the un-signaled state.
+  void Reset();
+
+  // Put the event in the signaled state.  Causing any thread blocked on Wait
+  // to be woken up.
+  void Signal();
+
+  // Returns true if the event is in the signaled state, else false.  If this
+  // is not a manual reset event, then this test will cause a reset.
+  bool IsSignaled();
+
+  // Wait indefinitely for the event to be signaled. Wait's return "happens
+  // after" |Signal| has completed. This means that it's safe for a
+  // WaitableEvent to synchronise its own destruction, like this:
+  //
+  //   WaitableEvent *e = new WaitableEvent;
+  //   SendToOtherThread(e);
+  //   e->Wait();
+  //   delete e;
+  void Wait();
+
+  // Wait up until max_time has passed for the event to be signaled.  Returns
+  // true if the event was signaled.  If this method returns false, then it
+  // does not necessarily mean that max_time was exceeded.
+  //
+  // TimedWait can synchronise its own destruction like |Wait|.
+  bool TimedWait(const TimeDelta& max_time);
+
+#if defined(OS_WIN)
+  HANDLE handle() const { return handle_.Get(); }
+#endif
+
+  // Wait, synchronously, on multiple events.
+  //   waitables: an array of WaitableEvent pointers
+  //   count: the number of elements in @waitables
+  //
+  // returns: the index of a WaitableEvent which has been signaled.
+  //
+  // You MUST NOT delete any of the WaitableEvent objects while this wait is
+  // happening, however WaitMany's return "happens after" the |Signal| call
+  // that caused it has completed, like |Wait|.
+  static size_t WaitMany(WaitableEvent** waitables, size_t count);
+
+  // For asynchronous waiting, see WaitableEventWatcher
+
+  // This is a private helper class. It's here because it's used by friends of
+  // this class (such as WaitableEventWatcher) to be able to enqueue elements
+  // of the wait-list
+  class Waiter {
+   public:
+    // Signal the waiter to wake up.
+    //
+    // Consider the case of a Waiter which is in multiple WaitableEvent's
+    // wait-lists. Each WaitableEvent is automatic-reset and two of them are
+    // signaled at the same time. Now, each will wake only the first waiter in
+    // the wake-list before resetting. However, if those two waiters happen to
+    // be the same object (as can happen if another thread didn't have a chance
+    // to dequeue the waiter from the other wait-list in time), two auto-resets
+    // will have happened, but only one waiter has been signaled!
+    //
+    // Because of this, a Waiter may "reject" a wake by returning false. In
+    // this case, the auto-reset WaitableEvent shouldn't act as if anything has
+    // been notified.
+    virtual bool Fire(WaitableEvent* signaling_event) = 0;
+
+    // Waiters may implement this in order to provide an extra condition for
+    // two Waiters to be considered equal. In WaitableEvent::Dequeue, if the
+    // pointers match then this function is called as a final check. See the
+    // comments in ~Handle for why.
+    virtual bool Compare(void* tag) = 0;
+
+   protected:
+    virtual ~Waiter() {}
+  };
+
+ private:
+  friend class WaitableEventWatcher;
+
+#if defined(OS_WIN)
+  win::ScopedHandle handle_;
+#else
+  // On Windows, one can close a HANDLE which is currently being waited on. The
+  // MSDN documentation says that the resulting behaviour is 'undefined', but
+  // it doesn't crash. However, if we were to include the following members
+  // directly then, on POSIX, one couldn't use WaitableEventWatcher to watch an
+  // event which gets deleted. This mismatch has bitten us several times now,
+  // so we have a kernel of the WaitableEvent, which is reference counted.
+  // WaitableEventWatchers may then take a reference and thus match the Windows
+  // behaviour.
+  struct WaitableEventKernel :
+      public RefCountedThreadSafe<WaitableEventKernel> {
+   public:
+    WaitableEventKernel(bool manual_reset, bool initially_signaled);
+
+    bool Dequeue(Waiter* waiter, void* tag);
+
+    base::Lock lock_;
+    const bool manual_reset_;
+    bool signaled_;
+    std::list<Waiter*> waiters_;
+
+   private:
+    friend class RefCountedThreadSafe<WaitableEventKernel>;
+    ~WaitableEventKernel();
+  };
+
+  typedef std::pair<WaitableEvent*, size_t> WaiterAndIndex;
+
+  // When dealing with arrays of WaitableEvent*, we want to sort by the address
+  // of the WaitableEvent in order to have a globally consistent locking order.
+  // In that case we keep them, in sorted order, in an array of pairs where the
+  // second element is the index of the WaitableEvent in the original,
+  // unsorted, array.
+  static size_t EnqueueMany(WaiterAndIndex* waitables,
+                            size_t count, Waiter* waiter);
+
+  bool SignalAll();
+  bool SignalOne();
+  void Enqueue(Waiter* waiter);
+
+  scoped_refptr<WaitableEventKernel> kernel_;
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(WaitableEvent);
+};
+
+}  // namespace base
+
+#endif  // BASE_SYNCHRONIZATION_WAITABLE_EVENT_H_
diff --git a/base/synchronization/waitable_event_posix.cc b/base/synchronization/waitable_event_posix.cc
new file mode 100644
index 0000000..696ffc7
--- /dev/null
+++ b/base/synchronization/waitable_event_posix.cc
@@ -0,0 +1,415 @@
+// Copyright (c) 2012 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 <algorithm>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/thread_restrictions.h"
+
+// -----------------------------------------------------------------------------
+// A WaitableEvent on POSIX is implemented as a wait-list. Currently we don't
+// support cross-process events (where one process can signal an event which
+// others are waiting on). Because of this, we can avoid having one thread per
+// listener in several cases.
+//
+// The WaitableEvent maintains a list of waiters, protected by a lock. Each
+// waiter is either an async wait, in which case we have a Task and the
+// MessageLoop to run it on, or a blocking wait, in which case we have the
+// condition variable to signal.
+//
+// Waiting involves grabbing the lock and adding oneself to the wait list. Async
+// waits can be canceled, which means grabbing the lock and removing oneself
+// from the list.
+//
+// Waiting on multiple events is handled by adding a single, synchronous wait to
+// the wait-list of many events. An event passes a pointer to itself when
+// firing a waiter and so we can store that pointer to find out which event
+// triggered.
+// -----------------------------------------------------------------------------
+
+namespace base {
+
+// -----------------------------------------------------------------------------
+// This is just an abstract base class for waking the two types of waiters
+// -----------------------------------------------------------------------------
+WaitableEvent::WaitableEvent(bool manual_reset, bool initially_signaled)
+    : kernel_(new WaitableEventKernel(manual_reset, initially_signaled)) {
+}
+
+WaitableEvent::~WaitableEvent() {
+}
+
+void WaitableEvent::Reset() {
+  base::AutoLock locked(kernel_->lock_);
+  kernel_->signaled_ = false;
+}
+
+void WaitableEvent::Signal() {
+  base::AutoLock locked(kernel_->lock_);
+
+  if (kernel_->signaled_)
+    return;
+
+  if (kernel_->manual_reset_) {
+    SignalAll();
+    kernel_->signaled_ = true;
+  } else {
+    // In the case of auto reset, if no waiters were woken, we remain
+    // signaled.
+    if (!SignalOne())
+      kernel_->signaled_ = true;
+  }
+}
+
+bool WaitableEvent::IsSignaled() {
+  base::AutoLock locked(kernel_->lock_);
+
+  const bool result = kernel_->signaled_;
+  if (result && !kernel_->manual_reset_)
+    kernel_->signaled_ = false;
+  return result;
+}
+
+// -----------------------------------------------------------------------------
+// Synchronous waits
+
+// -----------------------------------------------------------------------------
+// This is a synchronous waiter. The thread is waiting on the given condition
+// variable and the fired flag in this object.
+// -----------------------------------------------------------------------------
+class SyncWaiter : public WaitableEvent::Waiter {
+ public:
+  SyncWaiter()
+      : fired_(false),
+        signaling_event_(NULL),
+        lock_(),
+        cv_(&lock_) {
+  }
+
+  bool Fire(WaitableEvent* signaling_event) override {
+    base::AutoLock locked(lock_);
+
+    if (fired_)
+      return false;
+
+    fired_ = true;
+    signaling_event_ = signaling_event;
+
+    cv_.Broadcast();
+
+    // Unlike AsyncWaiter objects, SyncWaiter objects are stack-allocated on
+    // the blocking thread's stack.  There is no |delete this;| in Fire.  The
+    // SyncWaiter object is destroyed when it goes out of scope.
+
+    return true;
+  }
+
+  WaitableEvent* signaling_event() const {
+    return signaling_event_;
+  }
+
+  // ---------------------------------------------------------------------------
+  // These waiters are always stack allocated and don't delete themselves. Thus
+  // there's no problem and the ABA tag is the same as the object pointer.
+  // ---------------------------------------------------------------------------
+  bool Compare(void* tag) override { return this == tag; }
+
+  // ---------------------------------------------------------------------------
+  // Called with lock held.
+  // ---------------------------------------------------------------------------
+  bool fired() const {
+    return fired_;
+  }
+
+  // ---------------------------------------------------------------------------
+  // During a TimedWait, we need a way to make sure that an auto-reset
+  // WaitableEvent doesn't think that this event has been signaled between
+  // unlocking it and removing it from the wait-list. Called with lock held.
+  // ---------------------------------------------------------------------------
+  void Disable() {
+    fired_ = true;
+  }
+
+  base::Lock* lock() {
+    return &lock_;
+  }
+
+  base::ConditionVariable* cv() {
+    return &cv_;
+  }
+
+ private:
+  bool fired_;
+  WaitableEvent* signaling_event_;  // The WaitableEvent which woke us
+  base::Lock lock_;
+  base::ConditionVariable cv_;
+};
+
+void WaitableEvent::Wait() {
+  bool result = TimedWait(TimeDelta::FromSeconds(-1));
+  DCHECK(result) << "TimedWait() should never fail with infinite timeout";
+}
+
+bool WaitableEvent::TimedWait(const TimeDelta& max_time) {
+  base::ThreadRestrictions::AssertWaitAllowed();
+  const TimeTicks end_time(TimeTicks::Now() + max_time);
+  const bool finite_time = max_time.ToInternalValue() >= 0;
+
+  kernel_->lock_.Acquire();
+  if (kernel_->signaled_) {
+    if (!kernel_->manual_reset_) {
+      // In this case we were signaled when we had no waiters. Now that
+      // someone has waited upon us, we can automatically reset.
+      kernel_->signaled_ = false;
+    }
+
+    kernel_->lock_.Release();
+    return true;
+  }
+
+  SyncWaiter sw;
+  sw.lock()->Acquire();
+
+  Enqueue(&sw);
+  kernel_->lock_.Release();
+  // We are violating locking order here by holding the SyncWaiter lock but not
+  // the WaitableEvent lock. However, this is safe because we don't lock @lock_
+  // again before unlocking it.
+
+  for (;;) {
+    const TimeTicks current_time(TimeTicks::Now());
+
+    if (sw.fired() || (finite_time && current_time >= end_time)) {
+      const bool return_value = sw.fired();
+
+      // We can't acquire @lock_ before releasing the SyncWaiter lock (because
+      // of locking order), however, in between the two a signal could be fired
+      // and @sw would accept it, however we will still return false, so the
+      // signal would be lost on an auto-reset WaitableEvent. Thus we call
+      // Disable which makes sw::Fire return false.
+      sw.Disable();
+      sw.lock()->Release();
+
+      // This is a bug that has been enshrined in the interface of
+      // WaitableEvent now: |Dequeue| is called even when |sw.fired()| is true,
+      // even though it'll always return false in that case. However, taking
+      // the lock ensures that |Signal| has completed before we return and
+      // means that a WaitableEvent can synchronise its own destruction.
+      kernel_->lock_.Acquire();
+      kernel_->Dequeue(&sw, &sw);
+      kernel_->lock_.Release();
+
+      return return_value;
+    }
+
+    if (finite_time) {
+      const TimeDelta max_wait(end_time - current_time);
+      sw.cv()->TimedWait(max_wait);
+    } else {
+      sw.cv()->Wait();
+    }
+  }
+}
+
+// -----------------------------------------------------------------------------
+// Synchronous waiting on multiple objects.
+
+static bool  // StrictWeakOrdering
+cmp_fst_addr(const std::pair<WaitableEvent*, unsigned> &a,
+             const std::pair<WaitableEvent*, unsigned> &b) {
+  return a.first < b.first;
+}
+
+// static
+size_t WaitableEvent::WaitMany(WaitableEvent** raw_waitables,
+                               size_t count) {
+  base::ThreadRestrictions::AssertWaitAllowed();
+  DCHECK(count) << "Cannot wait on no events";
+
+  // We need to acquire the locks in a globally consistent order. Thus we sort
+  // the array of waitables by address. We actually sort a pairs so that we can
+  // map back to the original index values later.
+  std::vector<std::pair<WaitableEvent*, size_t> > waitables;
+  waitables.reserve(count);
+  for (size_t i = 0; i < count; ++i)
+    waitables.push_back(std::make_pair(raw_waitables[i], i));
+
+  DCHECK_EQ(count, waitables.size());
+
+  sort(waitables.begin(), waitables.end(), cmp_fst_addr);
+
+  // The set of waitables must be distinct. Since we have just sorted by
+  // address, we can check this cheaply by comparing pairs of consecutive
+  // elements.
+  for (size_t i = 0; i < waitables.size() - 1; ++i) {
+    DCHECK(waitables[i].first != waitables[i+1].first);
+  }
+
+  SyncWaiter sw;
+
+  const size_t r = EnqueueMany(&waitables[0], count, &sw);
+  if (r) {
+    // One of the events is already signaled. The SyncWaiter has not been
+    // enqueued anywhere. EnqueueMany returns the count of remaining waitables
+    // when the signaled one was seen, so the index of the signaled event is
+    // @count - @r.
+    return waitables[count - r].second;
+  }
+
+  // At this point, we hold the locks on all the WaitableEvents and we have
+  // enqueued our waiter in them all.
+  sw.lock()->Acquire();
+    // Release the WaitableEvent locks in the reverse order
+    for (size_t i = 0; i < count; ++i) {
+      waitables[count - (1 + i)].first->kernel_->lock_.Release();
+    }
+
+    for (;;) {
+      if (sw.fired())
+        break;
+
+      sw.cv()->Wait();
+    }
+  sw.lock()->Release();
+
+  // The address of the WaitableEvent which fired is stored in the SyncWaiter.
+  WaitableEvent *const signaled_event = sw.signaling_event();
+  // This will store the index of the raw_waitables which fired.
+  size_t signaled_index = 0;
+
+  // Take the locks of each WaitableEvent in turn (except the signaled one) and
+  // remove our SyncWaiter from the wait-list
+  for (size_t i = 0; i < count; ++i) {
+    if (raw_waitables[i] != signaled_event) {
+      raw_waitables[i]->kernel_->lock_.Acquire();
+        // There's no possible ABA issue with the address of the SyncWaiter here
+        // because it lives on the stack. Thus the tag value is just the pointer
+        // value again.
+        raw_waitables[i]->kernel_->Dequeue(&sw, &sw);
+      raw_waitables[i]->kernel_->lock_.Release();
+    } else {
+      // By taking this lock here we ensure that |Signal| has completed by the
+      // time we return, because |Signal| holds this lock. This matches the
+      // behaviour of |Wait| and |TimedWait|.
+      raw_waitables[i]->kernel_->lock_.Acquire();
+      raw_waitables[i]->kernel_->lock_.Release();
+      signaled_index = i;
+    }
+  }
+
+  return signaled_index;
+}
+
+// -----------------------------------------------------------------------------
+// If return value == 0:
+//   The locks of the WaitableEvents have been taken in order and the Waiter has
+//   been enqueued in the wait-list of each. None of the WaitableEvents are
+//   currently signaled
+// else:
+//   None of the WaitableEvent locks are held. The Waiter has not been enqueued
+//   in any of them and the return value is the index of the first WaitableEvent
+//   which was signaled, from the end of the array.
+// -----------------------------------------------------------------------------
+// static
+size_t WaitableEvent::EnqueueMany
+    (std::pair<WaitableEvent*, size_t>* waitables,
+     size_t count, Waiter* waiter) {
+  if (!count)
+    return 0;
+
+  waitables[0].first->kernel_->lock_.Acquire();
+    if (waitables[0].first->kernel_->signaled_) {
+      if (!waitables[0].first->kernel_->manual_reset_)
+        waitables[0].first->kernel_->signaled_ = false;
+      waitables[0].first->kernel_->lock_.Release();
+      return count;
+    }
+
+    const size_t r = EnqueueMany(waitables + 1, count - 1, waiter);
+    if (r) {
+      waitables[0].first->kernel_->lock_.Release();
+    } else {
+      waitables[0].first->Enqueue(waiter);
+    }
+
+    return r;
+}
+
+// -----------------------------------------------------------------------------
+
+
+// -----------------------------------------------------------------------------
+// Private functions...
+
+WaitableEvent::WaitableEventKernel::WaitableEventKernel(bool manual_reset,
+                                                        bool initially_signaled)
+    : manual_reset_(manual_reset),
+      signaled_(initially_signaled) {
+}
+
+WaitableEvent::WaitableEventKernel::~WaitableEventKernel() {
+}
+
+// -----------------------------------------------------------------------------
+// Wake all waiting waiters. Called with lock held.
+// -----------------------------------------------------------------------------
+bool WaitableEvent::SignalAll() {
+  bool signaled_at_least_one = false;
+
+  for (std::list<Waiter*>::iterator
+       i = kernel_->waiters_.begin(); i != kernel_->waiters_.end(); ++i) {
+    if ((*i)->Fire(this))
+      signaled_at_least_one = true;
+  }
+
+  kernel_->waiters_.clear();
+  return signaled_at_least_one;
+}
+
+// ---------------------------------------------------------------------------
+// Try to wake a single waiter. Return true if one was woken. Called with lock
+// held.
+// ---------------------------------------------------------------------------
+bool WaitableEvent::SignalOne() {
+  for (;;) {
+    if (kernel_->waiters_.empty())
+      return false;
+
+    const bool r = (*kernel_->waiters_.begin())->Fire(this);
+    kernel_->waiters_.pop_front();
+    if (r)
+      return true;
+  }
+}
+
+// -----------------------------------------------------------------------------
+// Add a waiter to the list of those waiting. Called with lock held.
+// -----------------------------------------------------------------------------
+void WaitableEvent::Enqueue(Waiter* waiter) {
+  kernel_->waiters_.push_back(waiter);
+}
+
+// -----------------------------------------------------------------------------
+// Remove a waiter from the list of those waiting. Return true if the waiter was
+// actually removed. Called with lock held.
+// -----------------------------------------------------------------------------
+bool WaitableEvent::WaitableEventKernel::Dequeue(Waiter* waiter, void* tag) {
+  for (std::list<Waiter*>::iterator
+       i = waiters_.begin(); i != waiters_.end(); ++i) {
+    if (*i == waiter && (*i)->Compare(tag)) {
+      waiters_.erase(i);
+      return true;
+    }
+  }
+
+  return false;
+}
+
+// -----------------------------------------------------------------------------
+
+}  // namespace base
diff --git a/base/synchronization/waitable_event_unittest.cc b/base/synchronization/waitable_event_unittest.cc
new file mode 100644
index 0000000..be56cf1
--- /dev/null
+++ b/base/synchronization/waitable_event_unittest.cc
@@ -0,0 +1,150 @@
+// Copyright (c) 2012 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/synchronization/waitable_event.h"
+
+#include "base/compiler_specific.h"
+#include "base/threading/platform_thread.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(WaitableEventTest, ManualBasics) {
+  WaitableEvent event(true, false);
+
+  EXPECT_FALSE(event.IsSignaled());
+
+  event.Signal();
+  EXPECT_TRUE(event.IsSignaled());
+  EXPECT_TRUE(event.IsSignaled());
+
+  event.Reset();
+  EXPECT_FALSE(event.IsSignaled());
+  EXPECT_FALSE(event.TimedWait(TimeDelta::FromMilliseconds(10)));
+
+  event.Signal();
+  event.Wait();
+  EXPECT_TRUE(event.TimedWait(TimeDelta::FromMilliseconds(10)));
+}
+
+TEST(WaitableEventTest, AutoBasics) {
+  WaitableEvent event(false, false);
+
+  EXPECT_FALSE(event.IsSignaled());
+
+  event.Signal();
+  EXPECT_TRUE(event.IsSignaled());
+  EXPECT_FALSE(event.IsSignaled());
+
+  event.Reset();
+  EXPECT_FALSE(event.IsSignaled());
+  EXPECT_FALSE(event.TimedWait(TimeDelta::FromMilliseconds(10)));
+
+  event.Signal();
+  event.Wait();
+  EXPECT_FALSE(event.TimedWait(TimeDelta::FromMilliseconds(10)));
+
+  event.Signal();
+  EXPECT_TRUE(event.TimedWait(TimeDelta::FromMilliseconds(10)));
+}
+
+TEST(WaitableEventTest, WaitManyShortcut) {
+  WaitableEvent* ev[5];
+  for (unsigned i = 0; i < 5; ++i)
+    ev[i] = new WaitableEvent(false, false);
+
+  ev[3]->Signal();
+  EXPECT_EQ(WaitableEvent::WaitMany(ev, 5), 3u);
+
+  ev[3]->Signal();
+  EXPECT_EQ(WaitableEvent::WaitMany(ev, 5), 3u);
+
+  ev[4]->Signal();
+  EXPECT_EQ(WaitableEvent::WaitMany(ev, 5), 4u);
+
+  ev[0]->Signal();
+  EXPECT_EQ(WaitableEvent::WaitMany(ev, 5), 0u);
+
+  for (unsigned i = 0; i < 5; ++i)
+    delete ev[i];
+}
+
+class WaitableEventSignaler : public PlatformThread::Delegate {
+ public:
+  WaitableEventSignaler(TimeDelta delay, WaitableEvent* event)
+      : delay_(delay),
+        event_(event) {
+  }
+
+  void ThreadMain() override {
+    PlatformThread::Sleep(delay_);
+    event_->Signal();
+  }
+
+ private:
+  const TimeDelta delay_;
+  WaitableEvent* event_;
+};
+
+// Tests that a WaitableEvent can be safely deleted when |Wait| is done without
+// additional synchronization.
+TEST(WaitableEventTest, WaitAndDelete) {
+  WaitableEvent* ev = new WaitableEvent(false, false);
+
+  WaitableEventSignaler signaler(TimeDelta::FromMilliseconds(10), ev);
+  PlatformThreadHandle thread;
+  PlatformThread::Create(0, &signaler, &thread);
+
+  ev->Wait();
+  delete ev;
+
+  PlatformThread::Join(thread);
+}
+
+// Tests that a WaitableEvent can be safely deleted when |WaitMany| is done
+// without additional synchronization.
+TEST(WaitableEventTest, WaitMany) {
+  WaitableEvent* ev[5];
+  for (unsigned i = 0; i < 5; ++i)
+    ev[i] = new WaitableEvent(false, false);
+
+  WaitableEventSignaler signaler(TimeDelta::FromMilliseconds(10), ev[2]);
+  PlatformThreadHandle thread;
+  PlatformThread::Create(0, &signaler, &thread);
+
+  size_t index = WaitableEvent::WaitMany(ev, 5);
+
+  for (unsigned i = 0; i < 5; ++i)
+    delete ev[i];
+
+  PlatformThread::Join(thread);
+  EXPECT_EQ(2u, index);
+}
+
+// Tests that using TimeDelta::Max() on TimedWait() is not the same as passing
+// a timeout of 0. (crbug.com/465948)
+#if defined(OS_POSIX)
+// crbug.com/465948 not fixed yet.
+#define MAYBE_TimedWait DISABLED_TimedWait
+#else
+#define MAYBE_TimedWait TimedWait
+#endif
+TEST(WaitableEventTest, MAYBE_TimedWait) {
+  WaitableEvent* ev = new WaitableEvent(false, false);
+
+  TimeDelta thread_delay = TimeDelta::FromMilliseconds(10);
+  WaitableEventSignaler signaler(thread_delay, ev);
+  PlatformThreadHandle thread;
+  TimeTicks start = TimeTicks::Now();
+  PlatformThread::Create(0, &signaler, &thread);
+
+  ev->TimedWait(TimeDelta::Max());
+  EXPECT_GE(TimeTicks::Now() - start, thread_delay);
+  delete ev;
+
+  PlatformThread::Join(thread);
+}
+
+}  // namespace base
diff --git a/base/synchronization/waitable_event_watcher.h b/base/synchronization/waitable_event_watcher.h
new file mode 100644
index 0000000..eb51eff
--- /dev/null
+++ b/base/synchronization/waitable_event_watcher.h
@@ -0,0 +1,114 @@
+// Copyright (c) 2012 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_SYNCHRONIZATION_WAITABLE_EVENT_WATCHER_H_
+#define BASE_SYNCHRONIZATION_WAITABLE_EVENT_WATCHER_H_
+
+#include "base/base_export.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include "base/win/object_watcher.h"
+#else
+#include "base/callback.h"
+#include "base/message_loop/message_loop.h"
+#include "base/synchronization/waitable_event.h"
+#endif
+
+namespace base {
+
+class Flag;
+class AsyncWaiter;
+class AsyncCallbackTask;
+class WaitableEvent;
+
+// This class provides a way to wait on a WaitableEvent asynchronously.
+//
+// Each instance of this object can be waiting on a single WaitableEvent. When
+// the waitable event is signaled, a callback is made in the thread of a given
+// MessageLoop. This callback can be deleted by deleting the waiter.
+//
+// Typical usage:
+//
+//   class MyClass {
+//    public:
+//     void DoStuffWhenSignaled(WaitableEvent *waitable_event) {
+//       watcher_.StartWatching(waitable_event,
+//           base::Bind(&MyClass::OnWaitableEventSignaled, this);
+//     }
+//    private:
+//     void OnWaitableEventSignaled(WaitableEvent* waitable_event) {
+//       // OK, time to do stuff!
+//     }
+//     base::WaitableEventWatcher watcher_;
+//   };
+//
+// In the above example, MyClass wants to "do stuff" when waitable_event
+// becomes signaled. WaitableEventWatcher makes this task easy. When MyClass
+// goes out of scope, the watcher_ will be destroyed, and there is no need to
+// worry about OnWaitableEventSignaled being called on a deleted MyClass
+// pointer.
+//
+// BEWARE: With automatically reset WaitableEvents, a signal may be lost if it
+// occurs just before a WaitableEventWatcher is deleted. There is currently no
+// safe way to stop watching an automatic reset WaitableEvent without possibly
+// missing a signal.
+//
+// NOTE: you /are/ allowed to delete the WaitableEvent while still waiting on
+// it with a Watcher. It will act as if the event was never signaled.
+
+class BASE_EXPORT WaitableEventWatcher
+#if defined(OS_WIN)
+    : public win::ObjectWatcher::Delegate {
+#else
+    : public MessageLoop::DestructionObserver {
+#endif
+ public:
+  typedef Callback<void(WaitableEvent*)> EventCallback;
+  WaitableEventWatcher();
+  ~WaitableEventWatcher() override;
+
+  // When @event is signaled, the given callback is called on the thread of the
+  // current message loop when StartWatching is called.
+  bool StartWatching(WaitableEvent* event, const EventCallback& callback);
+
+  // Cancel the current watch. Must be called from the same thread which
+  // started the watch.
+  //
+  // Does nothing if no event is being watched, nor if the watch has completed.
+  // The callback will *not* be called for the current watch after this
+  // function returns. Since the callback runs on the same thread as this
+  // function, it cannot be called during this function either.
+  void StopWatching();
+
+  // Return the currently watched event, or NULL if no object is currently being
+  // watched.
+  WaitableEvent* GetWatchedEvent();
+
+  // Return the callback that will be invoked when the event is
+  // signaled.
+  const EventCallback& callback() const { return callback_; }
+
+ private:
+#if defined(OS_WIN)
+  void OnObjectSignaled(HANDLE h) override;
+  win::ObjectWatcher watcher_;
+#else
+  // Implementation of MessageLoop::DestructionObserver
+  void WillDestroyCurrentMessageLoop() override;
+
+  MessageLoop* message_loop_;
+  scoped_refptr<Flag> cancel_flag_;
+  AsyncWaiter* waiter_;
+  base::Closure internal_callback_;
+  scoped_refptr<WaitableEvent::WaitableEventKernel> kernel_;
+#endif
+
+  WaitableEvent* event_;
+  EventCallback callback_;
+};
+
+}  // namespace base
+
+#endif  // BASE_SYNCHRONIZATION_WAITABLE_EVENT_WATCHER_H_
diff --git a/base/synchronization/waitable_event_watcher_posix.cc b/base/synchronization/waitable_event_watcher_posix.cc
new file mode 100644
index 0000000..ad66a4c
--- /dev/null
+++ b/base/synchronization/waitable_event_watcher_posix.cc
@@ -0,0 +1,269 @@
+// Copyright (c) 2012 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/synchronization/waitable_event_watcher.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event.h"
+
+namespace base {
+
+// -----------------------------------------------------------------------------
+// WaitableEventWatcher (async waits).
+//
+// The basic design is that we add an AsyncWaiter to the wait-list of the event.
+// That AsyncWaiter has a pointer to MessageLoop, and a Task to be posted to it.
+// The MessageLoop ends up running the task, which calls the delegate.
+//
+// Since the wait can be canceled, we have a thread-safe Flag object which is
+// set when the wait has been canceled. At each stage in the above, we check the
+// flag before going onto the next stage. Since the wait may only be canceled in
+// the MessageLoop which runs the Task, we are assured that the delegate cannot
+// be called after canceling...
+
+// -----------------------------------------------------------------------------
+// A thread-safe, reference-counted, write-once flag.
+// -----------------------------------------------------------------------------
+class Flag : public RefCountedThreadSafe<Flag> {
+ public:
+  Flag() { flag_ = false; }
+
+  void Set() {
+    AutoLock locked(lock_);
+    flag_ = true;
+  }
+
+  bool value() const {
+    AutoLock locked(lock_);
+    return flag_;
+  }
+
+ private:
+  friend class RefCountedThreadSafe<Flag>;
+  ~Flag() {}
+
+  mutable Lock lock_;
+  bool flag_;
+
+  DISALLOW_COPY_AND_ASSIGN(Flag);
+};
+
+// -----------------------------------------------------------------------------
+// This is an asynchronous waiter which posts a task to a MessageLoop when
+// fired. An AsyncWaiter may only be in a single wait-list.
+// -----------------------------------------------------------------------------
+class AsyncWaiter : public WaitableEvent::Waiter {
+ public:
+  AsyncWaiter(MessageLoop* message_loop,
+              const base::Closure& callback,
+              Flag* flag)
+      : message_loop_(message_loop),
+        callback_(callback),
+        flag_(flag) { }
+
+  bool Fire(WaitableEvent* event) override {
+    // Post the callback if we haven't been cancelled.
+    if (!flag_->value()) {
+      message_loop_->task_runner()->PostTask(FROM_HERE, callback_);
+    }
+
+    // We are removed from the wait-list by the WaitableEvent itself. It only
+    // remains to delete ourselves.
+    delete this;
+
+    // We can always return true because an AsyncWaiter is never in two
+    // different wait-lists at the same time.
+    return true;
+  }
+
+  // See StopWatching for discussion
+  bool Compare(void* tag) override { return tag == flag_.get(); }
+
+ private:
+  MessageLoop *const message_loop_;
+  base::Closure callback_;
+  scoped_refptr<Flag> flag_;
+};
+
+// -----------------------------------------------------------------------------
+// For async waits we need to make a callback in a MessageLoop thread. We do
+// this by posting a callback, which calls the delegate and keeps track of when
+// the event is canceled.
+// -----------------------------------------------------------------------------
+void AsyncCallbackHelper(Flag* flag,
+                         const WaitableEventWatcher::EventCallback& callback,
+                         WaitableEvent* event) {
+  // Runs in MessageLoop thread.
+  if (!flag->value()) {
+    // This is to let the WaitableEventWatcher know that the event has occured
+    // because it needs to be able to return NULL from GetWatchedObject
+    flag->Set();
+    callback.Run(event);
+  }
+}
+
+WaitableEventWatcher::WaitableEventWatcher()
+    : message_loop_(NULL),
+      cancel_flag_(NULL),
+      waiter_(NULL),
+      event_(NULL) {
+}
+
+WaitableEventWatcher::~WaitableEventWatcher() {
+  StopWatching();
+}
+
+// -----------------------------------------------------------------------------
+// The Handle is how the user cancels a wait. After deleting the Handle we
+// insure that the delegate cannot be called.
+// -----------------------------------------------------------------------------
+bool WaitableEventWatcher::StartWatching(
+    WaitableEvent* event,
+    const EventCallback& callback) {
+  MessageLoop *const current_ml = MessageLoop::current();
+  DCHECK(current_ml) << "Cannot create WaitableEventWatcher without a "
+                        "current MessageLoop";
+
+  // A user may call StartWatching from within the callback function. In this
+  // case, we won't know that we have finished watching, expect that the Flag
+  // will have been set in AsyncCallbackHelper().
+  if (cancel_flag_.get() && cancel_flag_->value()) {
+    if (message_loop_) {
+      message_loop_->RemoveDestructionObserver(this);
+      message_loop_ = NULL;
+    }
+
+    cancel_flag_ = NULL;
+  }
+
+  DCHECK(!cancel_flag_.get()) << "StartWatching called while still watching";
+
+  cancel_flag_ = new Flag;
+  callback_ = callback;
+  internal_callback_ =
+      base::Bind(&AsyncCallbackHelper, cancel_flag_, callback_, event);
+  WaitableEvent::WaitableEventKernel* kernel = event->kernel_.get();
+
+  AutoLock locked(kernel->lock_);
+
+  event_ = event;
+
+  if (kernel->signaled_) {
+    if (!kernel->manual_reset_)
+      kernel->signaled_ = false;
+
+    // No hairpinning - we can't call the delegate directly here. We have to
+    // enqueue a task on the MessageLoop as normal.
+    current_ml->task_runner()->PostTask(FROM_HERE, internal_callback_);
+    return true;
+  }
+
+  message_loop_ = current_ml;
+  current_ml->AddDestructionObserver(this);
+
+  kernel_ = kernel;
+  waiter_ = new AsyncWaiter(current_ml, internal_callback_, cancel_flag_.get());
+  event->Enqueue(waiter_);
+
+  return true;
+}
+
+void WaitableEventWatcher::StopWatching() {
+  callback_.Reset();
+
+  if (message_loop_) {
+    message_loop_->RemoveDestructionObserver(this);
+    message_loop_ = NULL;
+  }
+
+  if (!cancel_flag_.get())  // if not currently watching...
+    return;
+
+  if (cancel_flag_->value()) {
+    // In this case, the event has fired, but we haven't figured that out yet.
+    // The WaitableEvent may have been deleted too.
+    cancel_flag_ = NULL;
+    return;
+  }
+
+  if (!kernel_.get()) {
+    // We have no kernel. This means that we never enqueued a Waiter on an
+    // event because the event was already signaled when StartWatching was
+    // called.
+    //
+    // In this case, a task was enqueued on the MessageLoop and will run.
+    // We set the flag in case the task hasn't yet run. The flag will stop the
+    // delegate getting called. If the task has run then we have the last
+    // reference to the flag and it will be deleted immedately after.
+    cancel_flag_->Set();
+    cancel_flag_ = NULL;
+    return;
+  }
+
+  AutoLock locked(kernel_->lock_);
+  // We have a lock on the kernel. No one else can signal the event while we
+  // have it.
+
+  // We have a possible ABA issue here. If Dequeue was to compare only the
+  // pointer values then it's possible that the AsyncWaiter could have been
+  // fired, freed and the memory reused for a different Waiter which was
+  // enqueued in the same wait-list. We would think that that waiter was our
+  // AsyncWaiter and remove it.
+  //
+  // To stop this, Dequeue also takes a tag argument which is passed to the
+  // virtual Compare function before the two are considered a match. So we need
+  // a tag which is good for the lifetime of this handle: the Flag. Since we
+  // have a reference to the Flag, its memory cannot be reused while this object
+  // still exists. So if we find a waiter with the correct pointer value, and
+  // which shares a Flag pointer, we have a real match.
+  if (kernel_->Dequeue(waiter_, cancel_flag_.get())) {
+    // Case 2: the waiter hasn't been signaled yet; it was still on the wait
+    // list. We've removed it, thus we can delete it and the task (which cannot
+    // have been enqueued with the MessageLoop because the waiter was never
+    // signaled)
+    delete waiter_;
+    internal_callback_.Reset();
+    cancel_flag_ = NULL;
+    return;
+  }
+
+  // Case 3: the waiter isn't on the wait-list, thus it was signaled. It may
+  // not have run yet, so we set the flag to tell it not to bother enqueuing the
+  // task on the MessageLoop, but to delete it instead. The Waiter deletes
+  // itself once run.
+  cancel_flag_->Set();
+  cancel_flag_ = NULL;
+
+  // If the waiter has already run then the task has been enqueued. If the Task
+  // hasn't yet run, the flag will stop the delegate from getting called. (This
+  // is thread safe because one may only delete a Handle from the MessageLoop
+  // thread.)
+  //
+  // If the delegate has already been called then we have nothing to do. The
+  // task has been deleted by the MessageLoop.
+}
+
+WaitableEvent* WaitableEventWatcher::GetWatchedEvent() {
+  if (!cancel_flag_.get())
+    return NULL;
+
+  if (cancel_flag_->value())
+    return NULL;
+
+  return event_;
+}
+
+// -----------------------------------------------------------------------------
+// This is called when the MessageLoop which the callback will be run it is
+// deleted. We need to cancel the callback as if we had been deleted, but we
+// will still be deleted at some point in the future.
+// -----------------------------------------------------------------------------
+void WaitableEventWatcher::WillDestroyCurrentMessageLoop() {
+  StopWatching();
+}
+
+}  // namespace base
diff --git a/base/synchronization/waitable_event_watcher_unittest.cc b/base/synchronization/waitable_event_watcher_unittest.cc
new file mode 100644
index 0000000..5319d1e
--- /dev/null
+++ b/base/synchronization/waitable_event_watcher_unittest.cc
@@ -0,0 +1,176 @@
+// Copyright (c) 2012 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/synchronization/waitable_event_watcher.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/platform_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+// The message loops on which each waitable event timer should be tested.
+const MessageLoop::Type testing_message_loops[] = {
+  MessageLoop::TYPE_DEFAULT,
+  MessageLoop::TYPE_IO,
+#if !defined(OS_IOS)  // iOS does not allow direct running of the UI loop.
+  MessageLoop::TYPE_UI,
+#endif
+};
+
+const int kNumTestingMessageLoops = arraysize(testing_message_loops);
+
+void QuitWhenSignaled(WaitableEvent* event) {
+  MessageLoop::current()->QuitWhenIdle();
+}
+
+class DecrementCountContainer {
+ public:
+  explicit DecrementCountContainer(int* counter) : counter_(counter) {
+  }
+  void OnWaitableEventSignaled(WaitableEvent* object) {
+    --(*counter_);
+  }
+ private:
+  int* counter_;
+};
+
+void RunTest_BasicSignal(MessageLoop::Type message_loop_type) {
+  MessageLoop message_loop(message_loop_type);
+
+  // A manual-reset event that is not yet signaled.
+  WaitableEvent event(true, false);
+
+  WaitableEventWatcher watcher;
+  EXPECT_TRUE(watcher.GetWatchedEvent() == NULL);
+
+  watcher.StartWatching(&event, Bind(&QuitWhenSignaled));
+  EXPECT_EQ(&event, watcher.GetWatchedEvent());
+
+  event.Signal();
+
+  MessageLoop::current()->Run();
+
+  EXPECT_TRUE(watcher.GetWatchedEvent() == NULL);
+}
+
+void RunTest_BasicCancel(MessageLoop::Type message_loop_type) {
+  MessageLoop message_loop(message_loop_type);
+
+  // A manual-reset event that is not yet signaled.
+  WaitableEvent event(true, false);
+
+  WaitableEventWatcher watcher;
+
+  watcher.StartWatching(&event, Bind(&QuitWhenSignaled));
+
+  watcher.StopWatching();
+}
+
+void RunTest_CancelAfterSet(MessageLoop::Type message_loop_type) {
+  MessageLoop message_loop(message_loop_type);
+
+  // A manual-reset event that is not yet signaled.
+  WaitableEvent event(true, false);
+
+  WaitableEventWatcher watcher;
+
+  int counter = 1;
+  DecrementCountContainer delegate(&counter);
+  WaitableEventWatcher::EventCallback callback =
+      Bind(&DecrementCountContainer::OnWaitableEventSignaled,
+           Unretained(&delegate));
+  watcher.StartWatching(&event, callback);
+
+  event.Signal();
+
+  // Let the background thread do its business
+  base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(30));
+
+  watcher.StopWatching();
+
+  RunLoop().RunUntilIdle();
+
+  // Our delegate should not have fired.
+  EXPECT_EQ(1, counter);
+}
+
+void RunTest_OutlivesMessageLoop(MessageLoop::Type message_loop_type) {
+  // Simulate a MessageLoop that dies before an WaitableEventWatcher.  This
+  // ordinarily doesn't happen when people use the Thread class, but it can
+  // happen when people use the Singleton pattern or atexit.
+  WaitableEvent event(true, false);
+  {
+    WaitableEventWatcher watcher;
+    {
+      MessageLoop message_loop(message_loop_type);
+
+      watcher.StartWatching(&event, Bind(&QuitWhenSignaled));
+    }
+  }
+}
+
+void RunTest_DeleteUnder(MessageLoop::Type message_loop_type) {
+  // Delete the WaitableEvent out from under the Watcher. This is explictly
+  // allowed by the interface.
+
+  MessageLoop message_loop(message_loop_type);
+
+  {
+    WaitableEventWatcher watcher;
+
+    WaitableEvent* event = new WaitableEvent(false, false);
+
+    watcher.StartWatching(event, Bind(&QuitWhenSignaled));
+    delete event;
+  }
+}
+
+}  // namespace
+
+//-----------------------------------------------------------------------------
+
+TEST(WaitableEventWatcherTest, BasicSignal) {
+  for (int i = 0; i < kNumTestingMessageLoops; i++) {
+    RunTest_BasicSignal(testing_message_loops[i]);
+  }
+}
+
+TEST(WaitableEventWatcherTest, BasicCancel) {
+  for (int i = 0; i < kNumTestingMessageLoops; i++) {
+    RunTest_BasicCancel(testing_message_loops[i]);
+  }
+}
+
+TEST(WaitableEventWatcherTest, CancelAfterSet) {
+  for (int i = 0; i < kNumTestingMessageLoops; i++) {
+    RunTest_CancelAfterSet(testing_message_loops[i]);
+  }
+}
+
+TEST(WaitableEventWatcherTest, OutlivesMessageLoop) {
+  for (int i = 0; i < kNumTestingMessageLoops; i++) {
+    RunTest_OutlivesMessageLoop(testing_message_loops[i]);
+  }
+}
+
+#if defined(OS_WIN)
+// Crashes sometimes on vista.  http://crbug.com/62119
+#define MAYBE_DeleteUnder DISABLED_DeleteUnder
+#else
+#define MAYBE_DeleteUnder DeleteUnder
+#endif
+TEST(WaitableEventWatcherTest, MAYBE_DeleteUnder) {
+  for (int i = 0; i < kNumTestingMessageLoops; i++) {
+    RunTest_DeleteUnder(testing_message_loops[i]);
+  }
+}
+
+}  // namespace base
diff --git a/base/synchronization/waitable_event_watcher_win.cc b/base/synchronization/waitable_event_watcher_win.cc
new file mode 100644
index 0000000..46d47ac
--- /dev/null
+++ b/base/synchronization/waitable_event_watcher_win.cc
@@ -0,0 +1,48 @@
+// Copyright (c) 2011 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/synchronization/waitable_event_watcher.h"
+
+#include "base/compiler_specific.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/win/object_watcher.h"
+
+namespace base {
+
+WaitableEventWatcher::WaitableEventWatcher()
+    : event_(NULL) {
+}
+
+WaitableEventWatcher::~WaitableEventWatcher() {
+}
+
+bool WaitableEventWatcher::StartWatching(
+    WaitableEvent* event,
+    const EventCallback& callback) {
+  callback_ = callback;
+  event_ = event;
+  return watcher_.StartWatching(event->handle(), this);
+}
+
+void WaitableEventWatcher::StopWatching() {
+  callback_.Reset();
+  event_ = NULL;
+  watcher_.StopWatching();
+}
+
+WaitableEvent* WaitableEventWatcher::GetWatchedEvent() {
+  return event_;
+}
+
+void WaitableEventWatcher::OnObjectSignaled(HANDLE h) {
+  WaitableEvent* event = event_;
+  EventCallback callback = callback_;
+  event_ = NULL;
+  callback_.Reset();
+  DCHECK(event);
+
+  callback.Run(event);
+}
+
+}  // namespace base
diff --git a/base/synchronization/waitable_event_win.cc b/base/synchronization/waitable_event_win.cc
new file mode 100644
index 0000000..4db5627
--- /dev/null
+++ b/base/synchronization/waitable_event_win.cc
@@ -0,0 +1,96 @@
+// Copyright (c) 2011 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/synchronization/waitable_event.h"
+
+#include <windows.h>
+
+#include "base/logging.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/time/time.h"
+
+namespace base {
+
+WaitableEvent::WaitableEvent(bool manual_reset, bool signaled)
+    : handle_(CreateEvent(NULL, manual_reset, signaled, NULL)) {
+  // We're probably going to crash anyways if this is ever NULL, so we might as
+  // well make our stack reports more informative by crashing here.
+  CHECK(handle_.IsValid());
+}
+
+WaitableEvent::WaitableEvent(win::ScopedHandle handle)
+    : handle_(handle.Pass()) {
+  CHECK(handle_.IsValid()) << "Tried to create WaitableEvent from NULL handle";
+}
+
+WaitableEvent::~WaitableEvent() {
+}
+
+void WaitableEvent::Reset() {
+  ResetEvent(handle_.Get());
+}
+
+void WaitableEvent::Signal() {
+  SetEvent(handle_.Get());
+}
+
+bool WaitableEvent::IsSignaled() {
+  return TimedWait(TimeDelta());
+}
+
+void WaitableEvent::Wait() {
+  base::ThreadRestrictions::AssertWaitAllowed();
+  DWORD result = WaitForSingleObject(handle_.Get(), INFINITE);
+  // It is most unexpected that this should ever fail.  Help consumers learn
+  // about it if it should ever fail.
+  DCHECK_EQ(WAIT_OBJECT_0, result) << "WaitForSingleObject failed";
+}
+
+bool WaitableEvent::TimedWait(const TimeDelta& max_time) {
+  base::ThreadRestrictions::AssertWaitAllowed();
+  DCHECK_GE(max_time, TimeDelta());
+  // Truncate the timeout to milliseconds. The API specifies that this method
+  // can return in less than |max_time| (when returning false), as the argument
+  // is the maximum time that a caller is willing to wait.
+  DWORD timeout = saturated_cast<DWORD>(max_time.InMilliseconds());
+
+  DWORD result = WaitForSingleObject(handle_.Get(), timeout);
+  switch (result) {
+    case WAIT_OBJECT_0:
+      return true;
+    case WAIT_TIMEOUT:
+      return false;
+  }
+  // It is most unexpected that this should ever fail.  Help consumers learn
+  // about it if it should ever fail.
+  NOTREACHED() << "WaitForSingleObject failed";
+  return false;
+}
+
+// static
+size_t WaitableEvent::WaitMany(WaitableEvent** events, size_t count) {
+  base::ThreadRestrictions::AssertWaitAllowed();
+  HANDLE handles[MAXIMUM_WAIT_OBJECTS];
+  CHECK_LE(count, MAXIMUM_WAIT_OBJECTS)
+      << "Can only wait on " << MAXIMUM_WAIT_OBJECTS << " with WaitMany";
+
+  for (size_t i = 0; i < count; ++i)
+    handles[i] = events[i]->handle();
+
+  // The cast is safe because count is small - see the CHECK above.
+  DWORD result =
+      WaitForMultipleObjects(static_cast<DWORD>(count),
+                             handles,
+                             FALSE,      // don't wait for all the objects
+                             INFINITE);  // no timeout
+  if (result >= WAIT_OBJECT_0 + count) {
+    DPLOG(FATAL) << "WaitForMultipleObjects failed";
+    return 0;
+  }
+
+  return result - WAIT_OBJECT_0;
+}
+
+}  // namespace base
diff --git a/base/sys_byteorder.h b/base/sys_byteorder.h
new file mode 100644
index 0000000..704ed56
--- /dev/null
+++ b/base/sys_byteorder.h
@@ -0,0 +1,120 @@
+// Copyright (c) 2012 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 header defines cross-platform ByteSwap() implementations for 16, 32 and
+// 64-bit values, and NetToHostXX() / HostToNextXX() functions equivalent to
+// the traditional ntohX() and htonX() functions.
+// Use the functions defined here rather than using the platform-specific
+// functions directly.
+
+#ifndef BASE_SYS_BYTEORDER_H_
+#define BASE_SYS_BYTEORDER_H_
+
+#include "base/basictypes.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <winsock2.h>
+#else
+#include <arpa/inet.h>
+#endif
+
+namespace base {
+
+// Returns a value with all bytes in |x| swapped, i.e. reverses the endianness.
+inline uint16 ByteSwap(uint16 x) {
+  return ((x & 0x00ff) << 8) | ((x & 0xff00) >> 8);
+}
+
+inline uint32 ByteSwap(uint32 x) {
+  return ((x & 0x000000fful) << 24) | ((x & 0x0000ff00ul) << 8) |
+      ((x & 0x00ff0000ul) >> 8) | ((x & 0xff000000ul) >> 24);
+}
+
+inline uint64 ByteSwap(uint64 x) {
+  return ((x & 0x00000000000000ffull) << 56) |
+      ((x & 0x000000000000ff00ull) << 40) |
+      ((x & 0x0000000000ff0000ull) << 24) |
+      ((x & 0x00000000ff000000ull) << 8) |
+      ((x & 0x000000ff00000000ull) >> 8) |
+      ((x & 0x0000ff0000000000ull) >> 24) |
+      ((x & 0x00ff000000000000ull) >> 40) |
+      ((x & 0xff00000000000000ull) >> 56);
+}
+
+// Converts the bytes in |x| from host order (endianness) to little endian, and
+// returns the result.
+inline uint16 ByteSwapToLE16(uint16 x) {
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+  return x;
+#else
+  return ByteSwap(x);
+#endif
+}
+inline uint32 ByteSwapToLE32(uint32 x) {
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+  return x;
+#else
+  return ByteSwap(x);
+#endif
+}
+inline uint64 ByteSwapToLE64(uint64 x) {
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+  return x;
+#else
+  return ByteSwap(x);
+#endif
+}
+
+// Converts the bytes in |x| from network to host order (endianness), and
+// returns the result.
+inline uint16 NetToHost16(uint16 x) {
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+  return ByteSwap(x);
+#else
+  return x;
+#endif
+}
+inline uint32 NetToHost32(uint32 x) {
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+  return ByteSwap(x);
+#else
+  return x;
+#endif
+}
+inline uint64 NetToHost64(uint64 x) {
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+  return ByteSwap(x);
+#else
+  return x;
+#endif
+}
+
+// Converts the bytes in |x| from host to network order (endianness), and
+// returns the result.
+inline uint16 HostToNet16(uint16 x) {
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+  return ByteSwap(x);
+#else
+  return x;
+#endif
+}
+inline uint32 HostToNet32(uint32 x) {
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+  return ByteSwap(x);
+#else
+  return x;
+#endif
+}
+inline uint64 HostToNet64(uint64 x) {
+#if defined(ARCH_CPU_LITTLE_ENDIAN)
+  return ByteSwap(x);
+#else
+  return x;
+#endif
+}
+
+}  // namespace base
+
+#endif  // BASE_SYS_BYTEORDER_H_
diff --git a/base/sys_info.cc b/base/sys_info.cc
new file mode 100644
index 0000000..8640dc1
--- /dev/null
+++ b/base/sys_info.cc
@@ -0,0 +1,66 @@
+// Copyright (c) 2012 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/sys_info.h"
+
+#include "base/base_switches.h"
+#include "base/command_line.h"
+#include "base/lazy_instance.h"
+#include "base/metrics/field_trial.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/sys_info_internal.h"
+#include "base/time/time.h"
+
+namespace base {
+
+#if !defined(OS_ANDROID)
+
+static const int kLowMemoryDeviceThresholdMB = 512;
+
+bool DetectLowEndDevice() {
+  CommandLine* command_line = CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(switches::kEnableLowEndDeviceMode))
+    return true;
+  if (command_line->HasSwitch(switches::kDisableLowEndDeviceMode))
+    return false;
+
+  int ram_size_mb = SysInfo::AmountOfPhysicalMemoryMB();
+  return (ram_size_mb > 0 && ram_size_mb < kLowMemoryDeviceThresholdMB);
+}
+
+static LazyInstance<
+  internal::LazySysInfoValue<bool, DetectLowEndDevice> >::Leaky
+  g_lazy_low_end_device = LAZY_INSTANCE_INITIALIZER;
+
+// static
+bool SysInfo::IsLowEndDevice() {
+  const std::string group_name =
+      base::FieldTrialList::FindFullName("MemoryReduction");
+
+  // Low End Device Mode will be enabled if this client is assigned to
+  // one of those EnabledXXX groups.
+  if (StartsWithASCII(group_name, "Enabled", true))
+    return true;
+
+  return g_lazy_low_end_device.Get().value();
+}
+#endif
+
+#if !defined(OS_MACOSX) || defined(OS_IOS)
+std::string SysInfo::HardwareModelName() {
+  return std::string();
+}
+#endif
+
+// static
+int64 SysInfo::Uptime() {
+  // This code relies on an implementation detail of TimeTicks::Now() - that
+  // its return value happens to coincide with the system uptime value in
+  // microseconds, on Win/Mac/iOS/Linux/ChromeOS and Android.
+  int64 uptime_in_microseconds = TimeTicks::Now().ToInternalValue();
+  return uptime_in_microseconds / 1000;
+}
+
+}  // namespace base
diff --git a/base/sys_info.h b/base/sys_info.h
new file mode 100644
index 0000000..654d694
--- /dev/null
+++ b/base/sys_info.h
@@ -0,0 +1,147 @@
+// Copyright (c) 2012 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_SYS_INFO_H_
+#define BASE_SYS_INFO_H_
+
+#include <map>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/files/file_path.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+
+namespace base {
+
+class BASE_EXPORT SysInfo {
+ public:
+  // Return the number of logical processors/cores on the current machine.
+  static int NumberOfProcessors();
+
+  // Return the number of bytes of physical memory on the current machine.
+  static int64 AmountOfPhysicalMemory();
+
+  // Return the number of bytes of current available physical memory on the
+  // machine.
+  static int64 AmountOfAvailablePhysicalMemory();
+
+  // Return the number of bytes of virtual memory of this process. A return
+  // value of zero means that there is no limit on the available virtual
+  // memory.
+  static int64 AmountOfVirtualMemory();
+
+  // Return the number of megabytes of physical memory on the current machine.
+  static int AmountOfPhysicalMemoryMB() {
+    return static_cast<int>(AmountOfPhysicalMemory() / 1024 / 1024);
+  }
+
+  // Return the number of megabytes of available virtual memory, or zero if it
+  // is unlimited.
+  static int AmountOfVirtualMemoryMB() {
+    return static_cast<int>(AmountOfVirtualMemory() / 1024 / 1024);
+  }
+
+  // Return the available disk space in bytes on the volume containing |path|,
+  // or -1 on failure.
+  static int64 AmountOfFreeDiskSpace(const FilePath& path);
+
+  // Returns system uptime in milliseconds.
+  static int64 Uptime();
+
+  // Returns a descriptive string for the current machine model or an empty
+  // string if machime model is unknown or an error occured.
+  // e.g. MacPro1,1 on Mac.
+  // Only implemented on OS X, will return an empty string on other platforms.
+  static std::string HardwareModelName();
+
+  // Returns the name of the host operating system.
+  static std::string OperatingSystemName();
+
+  // Returns the version of the host operating system.
+  static std::string OperatingSystemVersion();
+
+  // Retrieves detailed numeric values for the OS version.
+  // TODO(port): Implement a Linux version of this method and enable the
+  // corresponding unit test.
+  // DON'T USE THIS ON THE MAC OR WINDOWS to determine the current OS release
+  // for OS version-specific feature checks and workarounds. If you must use
+  // an OS version check instead of a feature check, use the base::mac::IsOS*
+  // family from base/mac/mac_util.h, or base::win::GetVersion from
+  // base/win/windows_version.h.
+  static void OperatingSystemVersionNumbers(int32* major_version,
+                                            int32* minor_version,
+                                            int32* bugfix_version);
+
+  // Returns the architecture of the running operating system.
+  // Exact return value may differ across platforms.
+  // e.g. a 32-bit x86 kernel on a 64-bit capable CPU will return "x86",
+  //      whereas a x86-64 kernel on the same CPU will return "x86_64"
+  static std::string OperatingSystemArchitecture();
+
+  // Avoid using this. Use base/cpu.h to get information about the CPU instead.
+  // http://crbug.com/148884
+  // Returns the CPU model name of the system. If it can not be figured out,
+  // an empty string is returned.
+  static std::string CPUModelName();
+
+  // Return the smallest amount of memory (in bytes) which the VM system will
+  // allocate.
+  static size_t VMAllocationGranularity();
+
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
+  // Returns the maximum SysV shared memory segment size, or zero if there is no
+  // limit.
+  static uint64 MaxSharedMemorySize();
+#endif  // defined(OS_POSIX) && !defined(OS_MACOSX)
+
+#if defined(OS_CHROMEOS)
+  typedef std::map<std::string, std::string> LsbReleaseMap;
+
+  // Returns the contents of /etc/lsb-release as a map.
+  static const LsbReleaseMap& GetLsbReleaseMap();
+
+  // If |key| is present in the LsbReleaseMap, sets |value| and returns true.
+  static bool GetLsbReleaseValue(const std::string& key, std::string* value);
+
+  // Convenience function for GetLsbReleaseValue("CHROMEOS_RELEASE_BOARD",...).
+  // Returns "unknown" if CHROMEOS_RELEASE_BOARD is not set.
+  static std::string GetLsbReleaseBoard();
+
+  // Returns the creation time of /etc/lsb-release. (Used to get the date and
+  // time of the Chrome OS build).
+  static Time GetLsbReleaseTime();
+
+  // Returns true when actually running in a Chrome OS environment.
+  static bool IsRunningOnChromeOS();
+
+  // Test method to force re-parsing of lsb-release.
+  static void SetChromeOSVersionInfoForTest(const std::string& lsb_release,
+                                            const Time& lsb_release_time);
+#endif  // defined(OS_CHROMEOS)
+
+#if defined(OS_ANDROID)
+  // Returns the Android build's codename.
+  static std::string GetAndroidBuildCodename();
+
+  // Returns the Android build ID.
+  static std::string GetAndroidBuildID();
+
+  // Returns the device's name.
+  static std::string GetDeviceName();
+
+  static int DalvikHeapSizeMB();
+  static int DalvikHeapGrowthLimitMB();
+#endif  // defined(OS_ANDROID)
+
+  // Returns true if this is a low-end device.
+  // Low-end device refers to devices having less than 512M memory in the
+  // current implementation.
+  static bool IsLowEndDevice();
+};
+
+}  // namespace base
+
+#endif  // BASE_SYS_INFO_H_
diff --git a/base/sys_info_android.cc b/base/sys_info_android.cc
new file mode 100644
index 0000000..245097f
--- /dev/null
+++ b/base/sys_info_android.cc
@@ -0,0 +1,218 @@
+// Copyright (c) 2012 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/sys_info.h"
+
+#include <dlfcn.h>
+#include <sys/system_properties.h>
+
+#include "base/android/sys_utils.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/stringprintf.h"
+#include "base/sys_info_internal.h"
+
+#if (__ANDROID_API__ >= 21 /* 5.0 - Lollipop */)
+
+namespace {
+
+typedef int (SystemPropertyGetFunction)(const char*, char*);
+
+SystemPropertyGetFunction* DynamicallyLoadRealSystemPropertyGet() {
+  // libc.so should already be open, get a handle to it.
+  void* handle = dlopen("libc.so", RTLD_NOLOAD);
+  if (!handle) {
+    LOG(FATAL) << "Cannot dlopen libc.so: " << dlerror();
+  }
+  SystemPropertyGetFunction* real_system_property_get =
+      reinterpret_cast<SystemPropertyGetFunction*>(
+          dlsym(handle, "__system_property_get"));
+  if (!real_system_property_get) {
+    LOG(FATAL) << "Cannot resolve __system_property_get(): " << dlerror();
+  }
+  return real_system_property_get;
+}
+
+static base::LazyInstance<base::internal::LazySysInfoValue<
+    SystemPropertyGetFunction*, DynamicallyLoadRealSystemPropertyGet> >::Leaky
+    g_lazy_real_system_property_get = LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+// Android 'L' removes __system_property_get from the NDK, however it is still
+// a hidden symbol in libc. Until we remove all calls of __system_property_get
+// from Chrome we work around this by defining a weak stub here, which uses
+// dlsym to but ensures that Chrome uses the real system
+// implementatation when loaded.  http://crbug.com/392191.
+BASE_EXPORT int __system_property_get(const char* name, char* value) {
+  return g_lazy_real_system_property_get.Get().value()(name, value);
+}
+
+#endif
+
+namespace {
+
+// Default version of Android to fall back to when actual version numbers
+// cannot be acquired. Use the latest Android release with a higher bug fix
+// version to avoid unnecessarily comparison errors with the latest release.
+// This should be manually kept up-to-date on each Android release.
+const int kDefaultAndroidMajorVersion = 5;
+const int kDefaultAndroidMinorVersion = 1;
+const int kDefaultAndroidBugfixVersion = 99;
+
+// Parse out the OS version numbers from the system properties.
+void ParseOSVersionNumbers(const char* os_version_str,
+                           int32 *major_version,
+                           int32 *minor_version,
+                           int32 *bugfix_version) {
+  if (os_version_str[0]) {
+    // Try to parse out the version numbers from the string.
+    int num_read = sscanf(os_version_str, "%d.%d.%d", major_version,
+                          minor_version, bugfix_version);
+
+    if (num_read > 0) {
+      // If we don't have a full set of version numbers, make the extras 0.
+      if (num_read < 2) *minor_version = 0;
+      if (num_read < 3) *bugfix_version = 0;
+      return;
+    }
+  }
+
+  // For some reason, we couldn't parse the version number string.
+  *major_version = kDefaultAndroidMajorVersion;
+  *minor_version = kDefaultAndroidMinorVersion;
+  *bugfix_version = kDefaultAndroidBugfixVersion;
+}
+
+// Parses a system property (specified with unit 'k','m' or 'g').
+// Returns a value in bytes.
+// Returns -1 if the string could not be parsed.
+int64 ParseSystemPropertyBytes(const base::StringPiece& str) {
+  const int64 KB = 1024;
+  const int64 MB = 1024 * KB;
+  const int64 GB = 1024 * MB;
+  if (str.size() == 0u)
+    return -1;
+  int64 unit_multiplier = 1;
+  size_t length = str.size();
+  if (str[length - 1] == 'k') {
+    unit_multiplier = KB;
+    length--;
+  } else if (str[length - 1] == 'm') {
+    unit_multiplier = MB;
+    length--;
+  } else if (str[length - 1] == 'g') {
+    unit_multiplier = GB;
+    length--;
+  }
+  int64 result = 0;
+  bool parsed = base::StringToInt64(str.substr(0, length), &result);
+  bool negative = result <= 0;
+  bool overflow = result >= std::numeric_limits<int64>::max() / unit_multiplier;
+  if (!parsed || negative || overflow)
+    return -1;
+  return result * unit_multiplier;
+}
+
+int GetDalvikHeapSizeMB() {
+  char heap_size_str[PROP_VALUE_MAX];
+  __system_property_get("dalvik.vm.heapsize", heap_size_str);
+  // dalvik.vm.heapsize property is writable by a root user.
+  // Clamp it to reasonable range as a sanity check,
+  // a typical android device will never have less than 48MB.
+  const int64 MB = 1024 * 1024;
+  int64 result = ParseSystemPropertyBytes(heap_size_str);
+  if (result == -1) {
+     // We should consider not exposing these values if they are not reliable.
+     LOG(ERROR) << "Can't parse dalvik.vm.heapsize: " << heap_size_str;
+     result = base::SysInfo::AmountOfPhysicalMemoryMB() / 3;
+  }
+  result = std::min<int64>(std::max<int64>(32 * MB, result), 1024 * MB) / MB;
+  return static_cast<int>(result);
+}
+
+int GetDalvikHeapGrowthLimitMB() {
+  char heap_size_str[PROP_VALUE_MAX];
+  __system_property_get("dalvik.vm.heapgrowthlimit", heap_size_str);
+  // dalvik.vm.heapgrowthlimit property is writable by a root user.
+  // Clamp it to reasonable range as a sanity check,
+  // a typical android device will never have less than 24MB.
+  const int64 MB = 1024 * 1024;
+  int64 result = ParseSystemPropertyBytes(heap_size_str);
+  if (result == -1) {
+     // We should consider not exposing these values if they are not reliable.
+     LOG(ERROR) << "Can't parse dalvik.vm.heapgrowthlimit: " << heap_size_str;
+     result = base::SysInfo::AmountOfPhysicalMemoryMB() / 6;
+  }
+  result = std::min<int64>(std::max<int64>(16 * MB, result), 512 * MB) / MB;
+  return static_cast<int>(result);
+}
+
+}  // anonymous namespace
+
+namespace base {
+
+std::string SysInfo::OperatingSystemName() {
+  return "Android";
+}
+
+std::string SysInfo::GetAndroidBuildCodename() {
+  char os_version_codename_str[PROP_VALUE_MAX];
+  __system_property_get("ro.build.version.codename", os_version_codename_str);
+  return std::string(os_version_codename_str);
+}
+
+std::string SysInfo::GetAndroidBuildID() {
+  char os_build_id_str[PROP_VALUE_MAX];
+  __system_property_get("ro.build.id", os_build_id_str);
+  return std::string(os_build_id_str);
+}
+
+std::string SysInfo::GetDeviceName() {
+  char device_model_str[PROP_VALUE_MAX];
+  __system_property_get("ro.product.model", device_model_str);
+  return std::string(device_model_str);
+}
+
+std::string SysInfo::OperatingSystemVersion() {
+  int32 major, minor, bugfix;
+  OperatingSystemVersionNumbers(&major, &minor, &bugfix);
+  return StringPrintf("%d.%d.%d", major, minor, bugfix);
+}
+
+void SysInfo::OperatingSystemVersionNumbers(int32* major_version,
+                                            int32* minor_version,
+                                            int32* bugfix_version) {
+  // Read the version number string out from the properties.
+  char os_version_str[PROP_VALUE_MAX];
+  __system_property_get("ro.build.version.release", os_version_str);
+
+  // Parse out the numbers.
+  ParseOSVersionNumbers(os_version_str, major_version, minor_version,
+                        bugfix_version);
+}
+
+int SysInfo::DalvikHeapSizeMB() {
+  static int heap_size = GetDalvikHeapSizeMB();
+  return heap_size;
+}
+
+int SysInfo::DalvikHeapGrowthLimitMB() {
+  static int heap_growth_limit = GetDalvikHeapGrowthLimitMB();
+  return heap_growth_limit;
+}
+
+static base::LazyInstance<
+    base::internal::LazySysInfoValue<bool,
+        android::SysUtils::IsLowEndDeviceFromJni> >::Leaky
+    g_lazy_low_end_device = LAZY_INSTANCE_INITIALIZER;
+
+bool SysInfo::IsLowEndDevice() {
+  return g_lazy_low_end_device.Get().value();
+}
+
+
+}  // namespace base
diff --git a/base/sys_info_chromeos.cc b/base/sys_info_chromeos.cc
new file mode 100644
index 0000000..9915055
--- /dev/null
+++ b/base/sys_info_chromeos.cc
@@ -0,0 +1,219 @@
+// Copyright (c) 2012 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/sys_info.h"
+
+#include "base/basictypes.h"
+#include "base/environment.h"
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/lazy_instance.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_tokenizer.h"
+#include "base/strings/string_util.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace base {
+
+namespace {
+
+const char* const kLinuxStandardBaseVersionKeys[] = {
+  "CHROMEOS_RELEASE_VERSION",
+  "GOOGLE_RELEASE",
+  "DISTRIB_RELEASE",
+};
+
+const char kChromeOsReleaseNameKey[] = "CHROMEOS_RELEASE_NAME";
+
+const char* const kChromeOsReleaseNames[] = {
+  "Chrome OS",
+  "Chromium OS",
+};
+
+const char kLinuxStandardBaseReleaseFile[] = "/etc/lsb-release";
+
+const char kLsbReleaseKey[] = "LSB_RELEASE";
+const char kLsbReleaseTimeKey[] = "LSB_RELEASE_TIME";  // Seconds since epoch
+
+const char kLsbReleaseSourceKey[] = "lsb-release";
+const char kLsbReleaseSourceEnv[] = "env";
+const char kLsbReleaseSourceFile[] = "file";
+
+class ChromeOSVersionInfo {
+ public:
+  ChromeOSVersionInfo() {
+    Parse();
+  }
+
+  void Parse() {
+    lsb_release_map_.clear();
+    major_version_ = 0;
+    minor_version_ = 0;
+    bugfix_version_ = 0;
+    is_running_on_chromeos_ = false;
+
+    std::string lsb_release, lsb_release_time_str;
+    scoped_ptr<Environment> env(Environment::Create());
+    bool parsed_from_env =
+        env->GetVar(kLsbReleaseKey, &lsb_release) &&
+        env->GetVar(kLsbReleaseTimeKey, &lsb_release_time_str);
+    if (parsed_from_env) {
+      double us = 0;
+      if (StringToDouble(lsb_release_time_str, &us))
+        lsb_release_time_ = Time::FromDoubleT(us);
+    } else {
+      // If the LSB_RELEASE and LSB_RELEASE_TIME environment variables are not
+      // set, fall back to a blocking read of the lsb_release file. This should
+      // only happen in non Chrome OS environments.
+      ThreadRestrictions::ScopedAllowIO allow_io;
+      FilePath path(kLinuxStandardBaseReleaseFile);
+      ReadFileToString(path, &lsb_release);
+      File::Info fileinfo;
+      if (GetFileInfo(path, &fileinfo))
+        lsb_release_time_ = fileinfo.creation_time;
+    }
+    ParseLsbRelease(lsb_release);
+    // For debugging:
+    lsb_release_map_[kLsbReleaseSourceKey] =
+        parsed_from_env ? kLsbReleaseSourceEnv : kLsbReleaseSourceFile;
+  }
+
+  bool GetLsbReleaseValue(const std::string& key, std::string* value) {
+    SysInfo::LsbReleaseMap::const_iterator iter = lsb_release_map_.find(key);
+    if (iter == lsb_release_map_.end())
+      return false;
+    *value = iter->second;
+    return true;
+  }
+
+  void GetVersionNumbers(int32* major_version,
+                         int32* minor_version,
+                         int32* bugfix_version) {
+    *major_version = major_version_;
+    *minor_version = minor_version_;
+    *bugfix_version = bugfix_version_;
+  }
+
+  const Time& lsb_release_time() const { return lsb_release_time_; }
+  const SysInfo::LsbReleaseMap& lsb_release_map() const {
+    return lsb_release_map_;
+  }
+  bool is_running_on_chromeos() const { return is_running_on_chromeos_; }
+
+ private:
+  void ParseLsbRelease(const std::string& lsb_release) {
+    // Parse and cache lsb_release key pairs. There should only be a handful
+    // of entries so the overhead for this will be small, and it can be
+    // useful for debugging.
+    base::StringPairs pairs;
+    SplitStringIntoKeyValuePairs(lsb_release, '=', '\n', &pairs);
+    for (size_t i = 0; i < pairs.size(); ++i) {
+      std::string key, value;
+      TrimWhitespaceASCII(pairs[i].first, TRIM_ALL, &key);
+      TrimWhitespaceASCII(pairs[i].second, TRIM_ALL, &value);
+      if (key.empty())
+        continue;
+      lsb_release_map_[key] = value;
+    }
+    // Parse the version from the first matching recognized version key.
+    std::string version;
+    for (size_t i = 0; i < arraysize(kLinuxStandardBaseVersionKeys); ++i) {
+      std::string key = kLinuxStandardBaseVersionKeys[i];
+      if (GetLsbReleaseValue(key, &version) && !version.empty())
+        break;
+    }
+    StringTokenizer tokenizer(version, ".");
+    if (tokenizer.GetNext()) {
+      StringToInt(StringPiece(tokenizer.token_begin(), tokenizer.token_end()),
+                  &major_version_);
+    }
+    if (tokenizer.GetNext()) {
+      StringToInt(StringPiece(tokenizer.token_begin(), tokenizer.token_end()),
+                  &minor_version_);
+    }
+    if (tokenizer.GetNext()) {
+      StringToInt(StringPiece(tokenizer.token_begin(), tokenizer.token_end()),
+                  &bugfix_version_);
+    }
+
+    // Check release name for Chrome OS.
+    std::string release_name;
+    if (GetLsbReleaseValue(kChromeOsReleaseNameKey, &release_name)) {
+      for (size_t i = 0; i < arraysize(kChromeOsReleaseNames); ++i) {
+        if (release_name == kChromeOsReleaseNames[i]) {
+          is_running_on_chromeos_ = true;
+          break;
+        }
+      }
+    }
+  }
+
+  Time lsb_release_time_;
+  SysInfo::LsbReleaseMap lsb_release_map_;
+  int32 major_version_;
+  int32 minor_version_;
+  int32 bugfix_version_;
+  bool is_running_on_chromeos_;
+};
+
+static LazyInstance<ChromeOSVersionInfo>
+    g_chrome_os_version_info = LAZY_INSTANCE_INITIALIZER;
+
+ChromeOSVersionInfo& GetChromeOSVersionInfo() {
+  return g_chrome_os_version_info.Get();
+}
+
+}  // namespace
+
+// static
+void SysInfo::OperatingSystemVersionNumbers(int32* major_version,
+                                            int32* minor_version,
+                                            int32* bugfix_version) {
+  return GetChromeOSVersionInfo().GetVersionNumbers(
+      major_version, minor_version, bugfix_version);
+}
+
+// static
+const SysInfo::LsbReleaseMap& SysInfo::GetLsbReleaseMap() {
+  return GetChromeOSVersionInfo().lsb_release_map();
+}
+
+// static
+bool SysInfo::GetLsbReleaseValue(const std::string& key, std::string* value) {
+  return GetChromeOSVersionInfo().GetLsbReleaseValue(key, value);
+}
+
+// static
+std::string SysInfo::GetLsbReleaseBoard() {
+  const char kMachineInfoBoard[] = "CHROMEOS_RELEASE_BOARD";
+  std::string board;
+  if (!GetLsbReleaseValue(kMachineInfoBoard, &board))
+    board = "unknown";
+  return board;
+}
+
+// static
+Time SysInfo::GetLsbReleaseTime() {
+  return GetChromeOSVersionInfo().lsb_release_time();
+}
+
+// static
+bool SysInfo::IsRunningOnChromeOS() {
+  return GetChromeOSVersionInfo().is_running_on_chromeos();
+}
+
+// static
+void SysInfo::SetChromeOSVersionInfoForTest(const std::string& lsb_release,
+                                            const Time& lsb_release_time) {
+  scoped_ptr<Environment> env(Environment::Create());
+  env->SetVar(kLsbReleaseKey, lsb_release);
+  env->SetVar(kLsbReleaseTimeKey,
+              DoubleToString(lsb_release_time.ToDoubleT()));
+  g_chrome_os_version_info.Get().Parse();
+}
+
+}  // namespace base
diff --git a/base/sys_info_freebsd.cc b/base/sys_info_freebsd.cc
new file mode 100644
index 0000000..515b59d
--- /dev/null
+++ b/base/sys_info_freebsd.cc
@@ -0,0 +1,36 @@
+// Copyright (c) 2011 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/sys_info.h"
+
+#include <sys/sysctl.h>
+
+#include "base/logging.h"
+
+namespace base {
+
+int64 SysInfo::AmountOfPhysicalMemory() {
+  int pages, page_size;
+  size_t size = sizeof(pages);
+  sysctlbyname("vm.stats.vm.v_page_count", &pages, &size, NULL, 0);
+  sysctlbyname("vm.stats.vm.v_page_size", &page_size, &size, NULL, 0);
+  if (pages == -1 || page_size == -1) {
+    NOTREACHED();
+    return 0;
+  }
+  return static_cast<int64>(pages) * page_size;
+}
+
+// static
+uint64 SysInfo::MaxSharedMemorySize() {
+  size_t limit;
+  size_t size = sizeof(limit);
+  if (sysctlbyname("kern.ipc.shmmax", &limit, &size, NULL, 0) < 0) {
+    NOTREACHED();
+    return 0;
+  }
+  return static_cast<uint64>(limit);
+}
+
+}  // namespace base
diff --git a/base/sys_info_internal.h b/base/sys_info_internal.h
new file mode 100644
index 0000000..e7674d5
--- /dev/null
+++ b/base/sys_info_internal.h
@@ -0,0 +1,34 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SYS_INFO_INTERNAL_H_
+#define BASE_SYS_INFO_INTERNAL_H_
+
+#include "base/basictypes.h"
+
+namespace base {
+
+namespace internal {
+
+template<typename T, T (*F)(void)>
+class LazySysInfoValue {
+ public:
+  LazySysInfoValue()
+      : value_(F()) { }
+
+  ~LazySysInfoValue() { }
+
+  T value() { return value_; }
+
+ private:
+  const T value_;
+
+  DISALLOW_COPY_AND_ASSIGN(LazySysInfoValue);
+};
+
+}  // namespace internal
+
+}  // namespace base
+
+#endif  // BASE_SYS_INFO_INTERNAL_H_
diff --git a/base/sys_info_ios.mm b/base/sys_info_ios.mm
new file mode 100644
index 0000000..0e24a2a
--- /dev/null
+++ b/base/sys_info_ios.mm
@@ -0,0 +1,107 @@
+// Copyright (c) 2012 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/sys_info.h"
+
+#include <mach/mach.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+#import <UIKit/UIKit.h>
+
+#include "base/logging.h"
+#include "base/mac/scoped_mach_port.h"
+#include "base/mac/scoped_nsautorelease_pool.h"
+#include "base/strings/sys_string_conversions.h"
+
+namespace base {
+
+// static
+std::string SysInfo::OperatingSystemName() {
+  static dispatch_once_t get_system_name_once;
+  static std::string* system_name;
+  dispatch_once(&get_system_name_once, ^{
+      base::mac::ScopedNSAutoreleasePool pool;
+      system_name = new std::string(
+          SysNSStringToUTF8([[UIDevice currentDevice] systemName]));
+  });
+  // Examples of returned value: 'iPhone OS' on iPad 5.1.1
+  // and iPhone 5.1.1.
+  return *system_name;
+}
+
+// static
+std::string SysInfo::OperatingSystemVersion() {
+  static dispatch_once_t get_system_version_once;
+  static std::string* system_version;
+  dispatch_once(&get_system_version_once, ^{
+      base::mac::ScopedNSAutoreleasePool pool;
+      system_version = new std::string(
+          SysNSStringToUTF8([[UIDevice currentDevice] systemVersion]));
+  });
+  return *system_version;
+}
+
+// static
+void SysInfo::OperatingSystemVersionNumbers(int32* major_version,
+                                            int32* minor_version,
+                                            int32* bugfix_version) {
+  base::mac::ScopedNSAutoreleasePool pool;
+  std::string system_version = OperatingSystemVersion();
+  if (!system_version.empty()) {
+    // Try to parse out the version numbers from the string.
+    int num_read = sscanf(system_version.c_str(), "%d.%d.%d", major_version,
+                          minor_version, bugfix_version);
+    if (num_read < 1)
+      *major_version = 0;
+    if (num_read < 2)
+      *minor_version = 0;
+    if (num_read < 3)
+      *bugfix_version = 0;
+  }
+}
+
+// static
+int64 SysInfo::AmountOfPhysicalMemory() {
+  struct host_basic_info hostinfo;
+  mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT;
+  base::mac::ScopedMachSendRight host(mach_host_self());
+  int result = host_info(host,
+                         HOST_BASIC_INFO,
+                         reinterpret_cast<host_info_t>(&hostinfo),
+                         &count);
+  if (result != KERN_SUCCESS) {
+    NOTREACHED();
+    return 0;
+  }
+  DCHECK_EQ(HOST_BASIC_INFO_COUNT, count);
+  return static_cast<int64>(hostinfo.max_mem);
+}
+
+// static
+int64 SysInfo::AmountOfAvailablePhysicalMemory() {
+  base::mac::ScopedMachSendRight host(mach_host_self());
+  vm_statistics_data_t vm_info;
+  mach_msg_type_number_t count = HOST_VM_INFO_COUNT;
+  if (host_statistics(host.get(),
+                      HOST_VM_INFO,
+                      reinterpret_cast<host_info_t>(&vm_info),
+                      &count) != KERN_SUCCESS) {
+    NOTREACHED();
+    return 0;
+  }
+
+  return static_cast<int64>(
+      vm_info.free_count - vm_info.speculative_count) * PAGE_SIZE;
+}
+
+// static
+std::string SysInfo::CPUModelName() {
+  char name[256];
+  size_t len = arraysize(name);
+  if (sysctlbyname("machdep.cpu.brand_string", &name, &len, NULL, 0) == 0)
+    return name;
+  return std::string();
+}
+
+}  // namespace base
diff --git a/base/sys_info_linux.cc b/base/sys_info_linux.cc
new file mode 100644
index 0000000..1bbfe9c
--- /dev/null
+++ b/base/sys_info_linux.cc
@@ -0,0 +1,97 @@
+// Copyright (c) 2011 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/sys_info.h"
+
+#include <limits>
+
+#include "base/files/file_util.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/sys_info_internal.h"
+
+namespace {
+
+int64 AmountOfMemory(int pages_name) {
+  long pages = sysconf(pages_name);
+  long page_size = sysconf(_SC_PAGESIZE);
+  if (pages == -1 || page_size == -1) {
+    NOTREACHED();
+    return 0;
+  }
+  return static_cast<int64>(pages) * page_size;
+}
+
+int64 AmountOfPhysicalMemory() {
+  return AmountOfMemory(_SC_PHYS_PAGES);
+}
+
+uint64 MaxSharedMemorySize() {
+  std::string contents;
+  base::ReadFileToString(base::FilePath("/proc/sys/kernel/shmmax"), &contents);
+  DCHECK(!contents.empty());
+  if (!contents.empty() && contents[contents.length() - 1] == '\n') {
+    contents.erase(contents.length() - 1);
+  }
+
+  uint64 limit;
+  if (!base::StringToUint64(contents, &limit)) {
+    limit = 0;
+  }
+  DCHECK_GT(limit, 0u);
+  return limit;
+}
+
+base::LazyInstance<
+    base::internal::LazySysInfoValue<int64, AmountOfPhysicalMemory> >::Leaky
+    g_lazy_physical_memory = LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<
+    base::internal::LazySysInfoValue<uint64, MaxSharedMemorySize> >::Leaky
+    g_lazy_max_shared_memory = LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+namespace base {
+
+// static
+int64 SysInfo::AmountOfAvailablePhysicalMemory() {
+  return AmountOfMemory(_SC_AVPHYS_PAGES);
+}
+
+// static
+int64 SysInfo::AmountOfPhysicalMemory() {
+  return g_lazy_physical_memory.Get().value();
+}
+
+// static
+uint64 SysInfo::MaxSharedMemorySize() {
+  return g_lazy_max_shared_memory.Get().value();
+}
+
+// static
+std::string SysInfo::CPUModelName() {
+#if defined(OS_CHROMEOS) && defined(ARCH_CPU_ARMEL)
+  const char kCpuModelPrefix[] = "Hardware";
+#else
+  const char kCpuModelPrefix[] = "model name";
+#endif
+  std::string contents;
+  ReadFileToString(FilePath("/proc/cpuinfo"), &contents);
+  DCHECK(!contents.empty());
+  if (!contents.empty()) {
+    std::istringstream iss(contents);
+    std::string line;
+    while (std::getline(iss, line)) {
+      if (line.compare(0, strlen(kCpuModelPrefix), kCpuModelPrefix) == 0) {
+        size_t pos = line.find(": ");
+        return line.substr(pos + 2);
+      }
+    }
+  }
+  return std::string();
+}
+
+}  // namespace base
diff --git a/base/sys_info_mac.cc b/base/sys_info_mac.cc
new file mode 100644
index 0000000..18df624
--- /dev/null
+++ b/base/sys_info_mac.cc
@@ -0,0 +1,96 @@
+// Copyright (c) 2012 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/sys_info.h"
+
+#include <ApplicationServices/ApplicationServices.h>
+#include <CoreServices/CoreServices.h>
+#include <mach/mach_host.h>
+#include <mach/mach_init.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+
+#include "base/logging.h"
+#include "base/mac/scoped_mach_port.h"
+#include "base/strings/stringprintf.h"
+
+namespace base {
+
+// static
+std::string SysInfo::OperatingSystemName() {
+  return "Mac OS X";
+}
+
+// static
+std::string SysInfo::OperatingSystemVersion() {
+  int32 major, minor, bugfix;
+  OperatingSystemVersionNumbers(&major, &minor, &bugfix);
+  return base::StringPrintf("%d.%d.%d", major, minor, bugfix);
+}
+
+// static
+void SysInfo::OperatingSystemVersionNumbers(int32* major_version,
+                                            int32* minor_version,
+                                            int32* bugfix_version) {
+  Gestalt(gestaltSystemVersionMajor,
+      reinterpret_cast<SInt32*>(major_version));
+  Gestalt(gestaltSystemVersionMinor,
+      reinterpret_cast<SInt32*>(minor_version));
+  Gestalt(gestaltSystemVersionBugFix,
+      reinterpret_cast<SInt32*>(bugfix_version));
+}
+
+// static
+int64 SysInfo::AmountOfPhysicalMemory() {
+  struct host_basic_info hostinfo;
+  mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT;
+  base::mac::ScopedMachSendRight host(mach_host_self());
+  int result = host_info(host,
+                         HOST_BASIC_INFO,
+                         reinterpret_cast<host_info_t>(&hostinfo),
+                         &count);
+  if (result != KERN_SUCCESS) {
+    NOTREACHED();
+    return 0;
+  }
+  DCHECK_EQ(HOST_BASIC_INFO_COUNT, count);
+  return static_cast<int64>(hostinfo.max_mem);
+}
+
+// static
+int64 SysInfo::AmountOfAvailablePhysicalMemory() {
+  base::mac::ScopedMachSendRight host(mach_host_self());
+  vm_statistics_data_t vm_info;
+  mach_msg_type_number_t count = HOST_VM_INFO_COUNT;
+
+  if (host_statistics(host.get(),
+                      HOST_VM_INFO,
+                      reinterpret_cast<host_info_t>(&vm_info),
+                      &count) != KERN_SUCCESS) {
+    NOTREACHED();
+    return 0;
+  }
+
+  return static_cast<int64>(
+      vm_info.free_count - vm_info.speculative_count) * PAGE_SIZE;
+}
+
+// static
+std::string SysInfo::CPUModelName() {
+  char name[256];
+  size_t len = arraysize(name);
+  if (sysctlbyname("machdep.cpu.brand_string", &name, &len, NULL, 0) == 0)
+    return name;
+  return std::string();
+}
+
+std::string SysInfo::HardwareModelName() {
+  char model[256];
+  size_t len = sizeof(model);
+  if (sysctlbyname("hw.model", model, &len, NULL, 0) == 0)
+    return std::string(model, 0, len);
+  return std::string();
+}
+
+}  // namespace base
diff --git a/base/sys_info_openbsd.cc b/base/sys_info_openbsd.cc
new file mode 100644
index 0000000..595291b
--- /dev/null
+++ b/base/sys_info_openbsd.cc
@@ -0,0 +1,75 @@
+// Copyright (c) 2011 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/sys_info.h"
+
+#include <sys/param.h>
+#include <sys/shm.h>
+#include <sys/sysctl.h>
+
+#include "base/logging.h"
+
+namespace {
+
+int64 AmountOfMemory(int pages_name) {
+  long pages = sysconf(pages_name);
+  long page_size = sysconf(_SC_PAGESIZE);
+  if (pages == -1 || page_size == -1) {
+    NOTREACHED();
+    return 0;
+  }
+  return static_cast<int64>(pages) * page_size;
+}
+
+}  // namespace
+
+namespace base {
+
+// static
+int SysInfo::NumberOfProcessors() {
+  int mib[] = { CTL_HW, HW_NCPU };
+  int ncpu;
+  size_t size = sizeof(ncpu);
+  if (sysctl(mib, arraysize(mib), &ncpu, &size, NULL, 0) < 0) {
+    NOTREACHED();
+    return 1;
+  }
+  return ncpu;
+}
+
+// static
+int64 SysInfo::AmountOfPhysicalMemory() {
+  return AmountOfMemory(_SC_PHYS_PAGES);
+}
+
+// static
+int64 SysInfo::AmountOfAvailablePhysicalMemory() {
+  return AmountOfMemory(_SC_AVPHYS_PAGES);
+}
+
+// static
+uint64 SysInfo::MaxSharedMemorySize() {
+  int mib[] = { CTL_KERN, KERN_SHMINFO, KERN_SHMINFO_SHMMAX };
+  size_t limit;
+  size_t size = sizeof(limit);
+  if (sysctl(mib, arraysize(mib), &limit, &size, NULL, 0) < 0) {
+    NOTREACHED();
+    return 0;
+  }
+  return static_cast<uint64>(limit);
+}
+
+// static
+std::string SysInfo::CPUModelName() {
+  int mib[] = { CTL_HW, HW_MODEL };
+  char name[256];
+  size_t len = arraysize(name);
+  if (sysctl(mib, arraysize(mib), name, &len, NULL, 0) < 0) {
+    NOTREACHED();
+    return std::string();
+  }
+  return name;
+}
+
+}  // namespace base
diff --git a/base/sys_info_posix.cc b/base/sys_info_posix.cc
new file mode 100644
index 0000000..3d49bf9
--- /dev/null
+++ b/base/sys_info_posix.cc
@@ -0,0 +1,144 @@
+// Copyright (c) 2011 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/sys_info.h"
+
+#include <errno.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/resource.h>
+#include <sys/utsname.h>
+#include <unistd.h>
+
+#include "base/basictypes.h"
+#include "base/files/file_util.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/sys_info_internal.h"
+#include "base/threading/thread_restrictions.h"
+
+#if defined(OS_ANDROID)
+#include <sys/vfs.h>
+#define statvfs statfs  // Android uses a statvfs-like statfs struct and call.
+#else
+#include <sys/statvfs.h>
+#endif
+
+namespace {
+
+#if !defined(OS_OPENBSD)
+int NumberOfProcessors() {
+  // sysconf returns the number of "logical" (not "physical") processors on both
+  // Mac and Linux.  So we get the number of max available "logical" processors.
+  //
+  // Note that the number of "currently online" processors may be fewer than the
+  // returned value of NumberOfProcessors(). On some platforms, the kernel may
+  // make some processors offline intermittently, to save power when system
+  // loading is low.
+  //
+  // One common use case that needs to know the processor count is to create
+  // optimal number of threads for optimization. It should make plan according
+  // to the number of "max available" processors instead of "currently online"
+  // ones. The kernel should be smart enough to make all processors online when
+  // it has sufficient number of threads waiting to run.
+  long res = sysconf(_SC_NPROCESSORS_CONF);
+  if (res == -1) {
+    NOTREACHED();
+    return 1;
+  }
+
+  return static_cast<int>(res);
+}
+
+base::LazyInstance<
+    base::internal::LazySysInfoValue<int, NumberOfProcessors> >::Leaky
+    g_lazy_number_of_processors = LAZY_INSTANCE_INITIALIZER;
+#endif
+
+int64 AmountOfVirtualMemory() {
+  struct rlimit limit;
+  int result = getrlimit(RLIMIT_DATA, &limit);
+  if (result != 0) {
+    NOTREACHED();
+    return 0;
+  }
+  return limit.rlim_cur == RLIM_INFINITY ? 0 : limit.rlim_cur;
+}
+
+base::LazyInstance<
+    base::internal::LazySysInfoValue<int64, AmountOfVirtualMemory> >::Leaky
+    g_lazy_virtual_memory = LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+namespace base {
+
+#if !defined(OS_OPENBSD)
+int SysInfo::NumberOfProcessors() {
+  return g_lazy_number_of_processors.Get().value();
+}
+#endif
+
+// static
+int64 SysInfo::AmountOfVirtualMemory() {
+  return g_lazy_virtual_memory.Get().value();
+}
+
+// static
+int64 SysInfo::AmountOfFreeDiskSpace(const FilePath& path) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  struct statvfs stats;
+  if (HANDLE_EINTR(statvfs(path.value().c_str(), &stats)) != 0)
+    return -1;
+  return static_cast<int64>(stats.f_bavail) * stats.f_frsize;
+}
+
+#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
+// static
+std::string SysInfo::OperatingSystemName() {
+  struct utsname info;
+  if (uname(&info) < 0) {
+    NOTREACHED();
+    return std::string();
+  }
+  return std::string(info.sysname);
+}
+#endif
+
+#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
+// static
+std::string SysInfo::OperatingSystemVersion() {
+  struct utsname info;
+  if (uname(&info) < 0) {
+    NOTREACHED();
+    return std::string();
+  }
+  return std::string(info.release);
+}
+#endif
+
+// static
+std::string SysInfo::OperatingSystemArchitecture() {
+  struct utsname info;
+  if (uname(&info) < 0) {
+    NOTREACHED();
+    return std::string();
+  }
+  std::string arch(info.machine);
+  if (arch == "i386" || arch == "i486" || arch == "i586" || arch == "i686") {
+    arch = "x86";
+  } else if (arch == "amd64") {
+    arch = "x86_64";
+  }
+  return arch;
+}
+
+// static
+size_t SysInfo::VMAllocationGranularity() {
+  return getpagesize();
+}
+
+}  // namespace base
diff --git a/base/sys_info_unittest.cc b/base/sys_info_unittest.cc
new file mode 100644
index 0000000..15ae098
--- /dev/null
+++ b/base/sys_info_unittest.cc
@@ -0,0 +1,155 @@
+// Copyright (c) 2012 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/environment.h"
+#include "base/files/file_util.h"
+#include "base/sys_info.h"
+#include "base/threading/platform_thread.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+typedef PlatformTest SysInfoTest;
+using base::FilePath;
+
+#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
+TEST_F(SysInfoTest, MaxSharedMemorySize) {
+  // We aren't actually testing that it's correct, just that it's sane.
+  EXPECT_GT(base::SysInfo::MaxSharedMemorySize(), 0u);
+}
+#endif
+
+TEST_F(SysInfoTest, NumProcs) {
+  // We aren't actually testing that it's correct, just that it's sane.
+  EXPECT_GE(base::SysInfo::NumberOfProcessors(), 1);
+}
+
+TEST_F(SysInfoTest, AmountOfMem) {
+  // We aren't actually testing that it's correct, just that it's sane.
+  EXPECT_GT(base::SysInfo::AmountOfPhysicalMemory(), 0);
+  EXPECT_GT(base::SysInfo::AmountOfPhysicalMemoryMB(), 0);
+  // The maxmimal amount of virtual memory can be zero which means unlimited.
+  EXPECT_GE(base::SysInfo::AmountOfVirtualMemory(), 0);
+}
+
+TEST_F(SysInfoTest, AmountOfFreeDiskSpace) {
+  // We aren't actually testing that it's correct, just that it's sane.
+  FilePath tmp_path;
+  ASSERT_TRUE(base::GetTempDir(&tmp_path));
+  EXPECT_GT(base::SysInfo::AmountOfFreeDiskSpace(tmp_path), 0)
+            << tmp_path.value();
+}
+
+#if defined(OS_WIN) || defined(OS_MACOSX)
+TEST_F(SysInfoTest, OperatingSystemVersionNumbers) {
+  int32 os_major_version = -1;
+  int32 os_minor_version = -1;
+  int32 os_bugfix_version = -1;
+  base::SysInfo::OperatingSystemVersionNumbers(&os_major_version,
+                                               &os_minor_version,
+                                               &os_bugfix_version);
+  EXPECT_GT(os_major_version, -1);
+  EXPECT_GT(os_minor_version, -1);
+  EXPECT_GT(os_bugfix_version, -1);
+}
+#endif
+
+TEST_F(SysInfoTest, Uptime) {
+  int64 up_time_1 = base::SysInfo::Uptime();
+  // UpTime() is implemented internally using TimeTicks::Now(), which documents
+  // system resolution as being 1-15ms. Sleep a little longer than that.
+  base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(20));
+  int64 up_time_2 = base::SysInfo::Uptime();
+  EXPECT_GT(up_time_1, 0);
+  EXPECT_GT(up_time_2, up_time_1);
+}
+
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+TEST_F(SysInfoTest, HardwareModelName) {
+  std::string hardware_model = base::SysInfo::HardwareModelName();
+  EXPECT_FALSE(hardware_model.empty());
+}
+#endif
+
+#if defined(OS_CHROMEOS)
+
+TEST_F(SysInfoTest, GoogleChromeOSVersionNumbers) {
+  int32 os_major_version = -1;
+  int32 os_minor_version = -1;
+  int32 os_bugfix_version = -1;
+  const char kLsbRelease[] =
+      "FOO=1234123.34.5\n"
+      "CHROMEOS_RELEASE_VERSION=1.2.3.4\n";
+  base::SysInfo::SetChromeOSVersionInfoForTest(kLsbRelease, base::Time());
+  base::SysInfo::OperatingSystemVersionNumbers(&os_major_version,
+                                               &os_minor_version,
+                                               &os_bugfix_version);
+  EXPECT_EQ(1, os_major_version);
+  EXPECT_EQ(2, os_minor_version);
+  EXPECT_EQ(3, os_bugfix_version);
+}
+
+TEST_F(SysInfoTest, GoogleChromeOSVersionNumbersFirst) {
+  int32 os_major_version = -1;
+  int32 os_minor_version = -1;
+  int32 os_bugfix_version = -1;
+  const char kLsbRelease[] =
+      "CHROMEOS_RELEASE_VERSION=1.2.3.4\n"
+      "FOO=1234123.34.5\n";
+  base::SysInfo::SetChromeOSVersionInfoForTest(kLsbRelease, base::Time());
+  base::SysInfo::OperatingSystemVersionNumbers(&os_major_version,
+                                               &os_minor_version,
+                                               &os_bugfix_version);
+  EXPECT_EQ(1, os_major_version);
+  EXPECT_EQ(2, os_minor_version);
+  EXPECT_EQ(3, os_bugfix_version);
+}
+
+TEST_F(SysInfoTest, GoogleChromeOSNoVersionNumbers) {
+  int32 os_major_version = -1;
+  int32 os_minor_version = -1;
+  int32 os_bugfix_version = -1;
+  const char kLsbRelease[] = "FOO=1234123.34.5\n";
+  base::SysInfo::SetChromeOSVersionInfoForTest(kLsbRelease, base::Time());
+  base::SysInfo::OperatingSystemVersionNumbers(&os_major_version,
+                                               &os_minor_version,
+                                               &os_bugfix_version);
+  EXPECT_EQ(0, os_major_version);
+  EXPECT_EQ(0, os_minor_version);
+  EXPECT_EQ(0, os_bugfix_version);
+}
+
+TEST_F(SysInfoTest, GoogleChromeOSLsbReleaseTime) {
+  const char kLsbRelease[] = "CHROMEOS_RELEASE_VERSION=1.2.3.4";
+  // Use a fake time that can be safely displayed as a string.
+  const base::Time lsb_release_time(base::Time::FromDoubleT(12345.6));
+  base::SysInfo::SetChromeOSVersionInfoForTest(kLsbRelease, lsb_release_time);
+  base::Time parsed_lsb_release_time = base::SysInfo::GetLsbReleaseTime();
+  EXPECT_DOUBLE_EQ(lsb_release_time.ToDoubleT(),
+                   parsed_lsb_release_time.ToDoubleT());
+}
+
+TEST_F(SysInfoTest, IsRunningOnChromeOS) {
+  base::SysInfo::SetChromeOSVersionInfoForTest("", base::Time());
+  EXPECT_FALSE(base::SysInfo::IsRunningOnChromeOS());
+
+  const char kLsbRelease1[] =
+      "CHROMEOS_RELEASE_NAME=Non Chrome OS\n"
+      "CHROMEOS_RELEASE_VERSION=1.2.3.4\n";
+  base::SysInfo::SetChromeOSVersionInfoForTest(kLsbRelease1, base::Time());
+  EXPECT_FALSE(base::SysInfo::IsRunningOnChromeOS());
+
+  const char kLsbRelease2[] =
+      "CHROMEOS_RELEASE_NAME=Chrome OS\n"
+      "CHROMEOS_RELEASE_VERSION=1.2.3.4\n";
+  base::SysInfo::SetChromeOSVersionInfoForTest(kLsbRelease2, base::Time());
+  EXPECT_TRUE(base::SysInfo::IsRunningOnChromeOS());
+
+  const char kLsbRelease3[] =
+      "CHROMEOS_RELEASE_NAME=Chromium OS\n";
+  base::SysInfo::SetChromeOSVersionInfoForTest(kLsbRelease3, base::Time());
+  EXPECT_TRUE(base::SysInfo::IsRunningOnChromeOS());
+}
+
+#endif  // OS_CHROMEOS
diff --git a/base/sys_info_win.cc b/base/sys_info_win.cc
new file mode 100644
index 0000000..c8314c7
--- /dev/null
+++ b/base/sys_info_win.cc
@@ -0,0 +1,125 @@
+// 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/sys_info.h"
+
+#include <windows.h>
+
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/stringprintf.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/win/windows_version.h"
+
+namespace {
+
+int64 AmountOfMemory(DWORDLONG MEMORYSTATUSEX::* memory_field) {
+  MEMORYSTATUSEX memory_info;
+  memory_info.dwLength = sizeof(memory_info);
+  if (!GlobalMemoryStatusEx(&memory_info)) {
+    NOTREACHED();
+    return 0;
+  }
+
+  int64 rv = static_cast<int64>(memory_info.*memory_field);
+  return rv < 0 ? kint64max : rv;
+}
+
+}  // namespace
+
+namespace base {
+
+// static
+int SysInfo::NumberOfProcessors() {
+  return win::OSInfo::GetInstance()->processors();
+}
+
+// static
+int64 SysInfo::AmountOfPhysicalMemory() {
+  return AmountOfMemory(&MEMORYSTATUSEX::ullTotalPhys);
+}
+
+// static
+int64 SysInfo::AmountOfAvailablePhysicalMemory() {
+  return AmountOfMemory(&MEMORYSTATUSEX::ullAvailPhys);
+}
+
+// static
+int64 SysInfo::AmountOfVirtualMemory() {
+  return 0;
+}
+
+// static
+int64 SysInfo::AmountOfFreeDiskSpace(const FilePath& path) {
+  ThreadRestrictions::AssertIOAllowed();
+
+  ULARGE_INTEGER available, total, free;
+  if (!GetDiskFreeSpaceExW(path.value().c_str(), &available, &total, &free))
+    return -1;
+
+  int64 rv = static_cast<int64>(available.QuadPart);
+  return rv < 0 ? kint64max : rv;
+}
+
+std::string SysInfo::OperatingSystemName() {
+  return "Windows NT";
+}
+
+// static
+std::string SysInfo::OperatingSystemVersion() {
+  win::OSInfo* os_info = win::OSInfo::GetInstance();
+  win::OSInfo::VersionNumber version_number = os_info->version_number();
+  std::string version(StringPrintf("%d.%d", version_number.major,
+                                   version_number.minor));
+  win::OSInfo::ServicePack service_pack = os_info->service_pack();
+  if (service_pack.major != 0) {
+    version += StringPrintf(" SP%d", service_pack.major);
+    if (service_pack.minor != 0)
+      version += StringPrintf(".%d", service_pack.minor);
+  }
+  return version;
+}
+
+// TODO: Implement OperatingSystemVersionComplete, which would include
+// patchlevel/service pack number.
+// See chrome/browser/feedback/feedback_util.h, FeedbackUtil::SetOSVersion.
+
+// static
+std::string SysInfo::OperatingSystemArchitecture() {
+  win::OSInfo::WindowsArchitecture arch =
+      win::OSInfo::GetInstance()->architecture();
+  switch (arch) {
+    case win::OSInfo::X86_ARCHITECTURE:
+      return "x86";
+    case win::OSInfo::X64_ARCHITECTURE:
+      return "x86_64";
+    case win::OSInfo::IA64_ARCHITECTURE:
+      return "ia64";
+    default:
+      return "";
+  }
+}
+
+// static
+std::string SysInfo::CPUModelName() {
+  return win::OSInfo::GetInstance()->processor_model_name();
+}
+
+// static
+size_t SysInfo::VMAllocationGranularity() {
+  return win::OSInfo::GetInstance()->allocation_granularity();
+}
+
+// static
+void SysInfo::OperatingSystemVersionNumbers(int32* major_version,
+                                            int32* minor_version,
+                                            int32* bugfix_version) {
+  win::OSInfo* os_info = win::OSInfo::GetInstance();
+  *major_version = os_info->version_number().major;
+  *minor_version = os_info->version_number().minor;
+  *bugfix_version = 0;
+}
+
+}  // namespace base
diff --git a/base/system_monitor/system_monitor.cc b/base/system_monitor/system_monitor.cc
new file mode 100644
index 0000000..99152ab
--- /dev/null
+++ b/base/system_monitor/system_monitor.cc
@@ -0,0 +1,52 @@
+// Copyright (c) 2012 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/system_monitor/system_monitor.h"
+
+#include <utility>
+
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "base/time/time.h"
+
+namespace base {
+
+static SystemMonitor* g_system_monitor = NULL;
+
+SystemMonitor::SystemMonitor()
+    :  devices_changed_observer_list_(
+          new ObserverListThreadSafe<DevicesChangedObserver>()) {
+  DCHECK(!g_system_monitor);
+  g_system_monitor = this;
+}
+
+SystemMonitor::~SystemMonitor() {
+  DCHECK_EQ(this, g_system_monitor);
+  g_system_monitor = NULL;
+}
+
+// static
+SystemMonitor* SystemMonitor::Get() {
+  return g_system_monitor;
+}
+
+void SystemMonitor::ProcessDevicesChanged(DeviceType device_type) {
+  NotifyDevicesChanged(device_type);
+}
+
+void SystemMonitor::AddDevicesChangedObserver(DevicesChangedObserver* obs) {
+  devices_changed_observer_list_->AddObserver(obs);
+}
+
+void SystemMonitor::RemoveDevicesChangedObserver(DevicesChangedObserver* obs) {
+  devices_changed_observer_list_->RemoveObserver(obs);
+}
+
+void SystemMonitor::NotifyDevicesChanged(DeviceType device_type) {
+  DVLOG(1) << "DevicesChanged with device type " << device_type;
+  devices_changed_observer_list_->Notify(
+      FROM_HERE, &DevicesChangedObserver::OnDevicesChanged, device_type);
+}
+
+}  // namespace base
diff --git a/base/system_monitor/system_monitor.h b/base/system_monitor/system_monitor.h
new file mode 100644
index 0000000..5dd849f
--- /dev/null
+++ b/base/system_monitor/system_monitor.h
@@ -0,0 +1,75 @@
+// Copyright (c) 2012 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_SYSTEM_MONITOR_SYSTEM_MONITOR_H_
+#define BASE_SYSTEM_MONITOR_SYSTEM_MONITOR_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/observer_list_threadsafe.h"
+#include "build/build_config.h"
+
+namespace base {
+
+// Class for monitoring various system-related subsystems
+// such as power management, network status, etc.
+// TODO(mbelshe):  Add support beyond just power management.
+class BASE_EXPORT SystemMonitor {
+ public:
+  // Type of devices whose change need to be monitored, such as add/remove.
+  enum DeviceType {
+    DEVTYPE_AUDIO_CAPTURE,  // Audio capture device, e.g., microphone.
+    DEVTYPE_VIDEO_CAPTURE,  // Video capture device, e.g., webcam.
+    DEVTYPE_UNKNOWN,  // Other devices.
+  };
+
+  // Create SystemMonitor. Only one SystemMonitor instance per application
+  // is allowed.
+  SystemMonitor();
+  ~SystemMonitor();
+
+  // Get the application-wide SystemMonitor (if not present, returns NULL).
+  static SystemMonitor* Get();
+
+  class BASE_EXPORT DevicesChangedObserver {
+   public:
+    // Notification that the devices connected to the system have changed.
+    // This is only implemented on Windows currently.
+    virtual void OnDevicesChanged(DeviceType device_type) {}
+
+   protected:
+    virtual ~DevicesChangedObserver() {}
+  };
+
+  // Add a new observer.
+  // Can be called from any thread.
+  // Must not be called from within a notification callback.
+  void AddDevicesChangedObserver(DevicesChangedObserver* obs);
+
+  // Remove an existing observer.
+  // Can be called from any thread.
+  // Must not be called from within a notification callback.
+  void RemoveDevicesChangedObserver(DevicesChangedObserver* obs);
+
+  // The ProcessFoo() style methods are a broken pattern and should not
+  // be copied. Any significant addition to this class is blocked on
+  // refactoring to improve the state of affairs. See http://crbug.com/149059
+
+  // Cross-platform handling of a device change event.
+  void ProcessDevicesChanged(DeviceType device_type);
+
+ private:
+  // Functions to trigger notifications.
+  void NotifyDevicesChanged(DeviceType device_type);
+
+  scoped_refptr<ObserverListThreadSafe<DevicesChangedObserver> >
+      devices_changed_observer_list_;
+
+  DISALLOW_COPY_AND_ASSIGN(SystemMonitor);
+};
+
+}  // namespace base
+
+#endif  // BASE_SYSTEM_MONITOR_SYSTEM_MONITOR_H_
diff --git a/base/system_monitor/system_monitor_unittest.cc b/base/system_monitor/system_monitor_unittest.cc
new file mode 100644
index 0000000..f3db4c7
--- /dev/null
+++ b/base/system_monitor/system_monitor_unittest.cc
@@ -0,0 +1,54 @@
+// Copyright (c) 2012 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/system_monitor/system_monitor.h"
+
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/test/mock_devices_changed_observer.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+class SystemMonitorTest : public testing::Test {
+ protected:
+  SystemMonitorTest() {
+    system_monitor_.reset(new SystemMonitor);
+  }
+
+  MessageLoop message_loop_;
+  scoped_ptr<SystemMonitor> system_monitor_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SystemMonitorTest);
+};
+
+TEST_F(SystemMonitorTest, DeviceChangeNotifications) {
+  const int kObservers = 5;
+
+  testing::Sequence mock_sequencer[kObservers];
+  MockDevicesChangedObserver observers[kObservers];
+  for (int index = 0; index < kObservers; ++index) {
+    system_monitor_->AddDevicesChangedObserver(&observers[index]);
+
+    EXPECT_CALL(observers[index],
+                OnDevicesChanged(SystemMonitor::DEVTYPE_UNKNOWN))
+        .Times(3)
+        .InSequence(mock_sequencer[index]);
+  }
+
+  system_monitor_->ProcessDevicesChanged(SystemMonitor::DEVTYPE_UNKNOWN);
+  RunLoop().RunUntilIdle();
+
+  system_monitor_->ProcessDevicesChanged(SystemMonitor::DEVTYPE_UNKNOWN);
+  system_monitor_->ProcessDevicesChanged(SystemMonitor::DEVTYPE_UNKNOWN);
+  RunLoop().RunUntilIdle();
+}
+
+}  // namespace
+
+}  // namespace base
diff --git a/base/task/cancelable_task_tracker.cc b/base/task/cancelable_task_tracker.cc
new file mode 100644
index 0000000..a2e4799
--- /dev/null
+++ b/base/task/cancelable_task_tracker.cc
@@ -0,0 +1,188 @@
+// 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.
+
+#include "base/task/cancelable_task_tracker.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+#include "base/compiler_specific.h"
+#include "base/location.h"
+#include "base/memory/ref_counted.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/cancellation_flag.h"
+#include "base/task_runner.h"
+#include "base/thread_task_runner_handle.h"
+
+using base::Bind;
+using base::CancellationFlag;
+using base::Closure;
+using base::hash_map;
+using base::TaskRunner;
+
+namespace {
+
+void RunIfNotCanceled(const CancellationFlag* flag, const Closure& task) {
+  if (!flag->IsSet())
+    task.Run();
+}
+
+void RunIfNotCanceledThenUntrack(const CancellationFlag* flag,
+                                 const Closure& task,
+                                 const Closure& untrack) {
+  RunIfNotCanceled(flag, task);
+  untrack.Run();
+}
+
+bool IsCanceled(const CancellationFlag* flag,
+                base::ScopedClosureRunner* cleanup_runner) {
+  return flag->IsSet();
+}
+
+void RunAndDeleteFlag(const Closure& closure, const CancellationFlag* flag) {
+  closure.Run();
+  delete flag;
+}
+
+void RunOrPostToTaskRunner(TaskRunner* task_runner, const Closure& closure) {
+  if (task_runner->RunsTasksOnCurrentThread())
+    closure.Run();
+  else
+    task_runner->PostTask(FROM_HERE, closure);
+}
+
+}  // namespace
+
+namespace base {
+
+// static
+const CancelableTaskTracker::TaskId CancelableTaskTracker::kBadTaskId = 0;
+
+CancelableTaskTracker::CancelableTaskTracker()
+    : next_id_(1),weak_factory_(this) {}
+
+CancelableTaskTracker::~CancelableTaskTracker() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  TryCancelAll();
+}
+
+CancelableTaskTracker::TaskId CancelableTaskTracker::PostTask(
+    TaskRunner* task_runner,
+    const tracked_objects::Location& from_here,
+    const Closure& task) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  return PostTaskAndReply(task_runner, from_here, task, Bind(&base::DoNothing));
+}
+
+CancelableTaskTracker::TaskId CancelableTaskTracker::PostTaskAndReply(
+    TaskRunner* task_runner,
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    const Closure& reply) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  // We need a MessageLoop to run reply.
+  DCHECK(base::ThreadTaskRunnerHandle::IsSet());
+
+  // Owned by reply callback below.
+  CancellationFlag* flag = new CancellationFlag();
+
+  TaskId id = next_id_;
+  next_id_++;  // int64 is big enough that we ignore the potential overflow.
+
+  const Closure& untrack_closure =
+      Bind(&CancelableTaskTracker::Untrack, weak_factory_.GetWeakPtr(), id);
+  bool success =
+      task_runner->PostTaskAndReply(from_here,
+                                    Bind(&RunIfNotCanceled, flag, task),
+                                    Bind(&RunIfNotCanceledThenUntrack,
+                                         base::Owned(flag),
+                                         reply,
+                                         untrack_closure));
+
+  if (!success)
+    return kBadTaskId;
+
+  Track(id, flag);
+  return id;
+}
+
+CancelableTaskTracker::TaskId CancelableTaskTracker::NewTrackedTaskId(
+    IsCanceledCallback* is_canceled_cb) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK(base::ThreadTaskRunnerHandle::IsSet());
+
+  TaskId id = next_id_;
+  next_id_++;  // int64 is big enough that we ignore the potential overflow.
+
+  // Will be deleted by |untrack_and_delete_flag| after Untrack().
+  CancellationFlag* flag = new CancellationFlag();
+
+  Closure untrack_and_delete_flag = Bind(
+      &RunAndDeleteFlag,
+      Bind(&CancelableTaskTracker::Untrack, weak_factory_.GetWeakPtr(), id),
+      flag);
+
+  // Will always run |untrack_and_delete_flag| on current MessageLoop.
+  base::ScopedClosureRunner* untrack_and_delete_flag_runner =
+      new base::ScopedClosureRunner(Bind(&RunOrPostToTaskRunner,
+                                         base::ThreadTaskRunnerHandle::Get(),
+                                         untrack_and_delete_flag));
+
+  *is_canceled_cb =
+      Bind(&IsCanceled, flag, base::Owned(untrack_and_delete_flag_runner));
+
+  Track(id, flag);
+  return id;
+}
+
+void CancelableTaskTracker::TryCancel(TaskId id) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  hash_map<TaskId, CancellationFlag*>::const_iterator it = task_flags_.find(id);
+  if (it == task_flags_.end()) {
+    // Two possibilities:
+    //
+    //   1. The task has already been untracked.
+    //   2. The TaskId is bad or unknown.
+    //
+    // Since this function is best-effort, it's OK to ignore these.
+    return;
+  }
+  it->second->Set();
+}
+
+void CancelableTaskTracker::TryCancelAll() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  for (hash_map<TaskId, CancellationFlag*>::const_iterator it =
+           task_flags_.begin();
+       it != task_flags_.end();
+       ++it) {
+    it->second->Set();
+  }
+}
+
+bool CancelableTaskTracker::HasTrackedTasks() const {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  return !task_flags_.empty();
+}
+
+void CancelableTaskTracker::Track(TaskId id, CancellationFlag* flag) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  bool success = task_flags_.insert(std::make_pair(id, flag)).second;
+  DCHECK(success);
+}
+
+void CancelableTaskTracker::Untrack(TaskId id) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  size_t num = task_flags_.erase(id);
+  DCHECK_EQ(1u, num);
+}
+
+}  // namespace base
diff --git a/base/task/cancelable_task_tracker.h b/base/task/cancelable_task_tracker.h
new file mode 100644
index 0000000..b8a8b70
--- /dev/null
+++ b/base/task/cancelable_task_tracker.h
@@ -0,0 +1,140 @@
+// 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.
+
+// CancelableTaskTracker posts tasks (in the form of a Closure) to a
+// TaskRunner, and is able to cancel the task later if it's not needed
+// anymore.  On destruction, CancelableTaskTracker will cancel all
+// tracked tasks.
+//
+// Each cancelable task can be associated with a reply (also a Closure). After
+// the task is run on the TaskRunner, |reply| will be posted back to
+// originating TaskRunner.
+//
+// NOTE:
+//
+// CancelableCallback (base/cancelable_callback.h) and WeakPtr binding are
+// preferred solutions for canceling a task. However, they don't support
+// cancelation from another thread. This is sometimes a performance critical
+// requirement. E.g. We need to cancel database lookup task on DB thread when
+// user changes inputed text. If it is performance critical to do a best effort
+// cancelation of a task, then CancelableTaskTracker is appropriate,
+// otherwise use one of the other mechanisms.
+//
+// THREAD-SAFETY:
+//
+// 1. CancelableTaskTracker objects are not thread safe. They must
+// be created, used, and destroyed on the originating thread that posts the
+// task. It's safe to destroy a CancelableTaskTracker while there
+// are outstanding tasks. This is commonly used to cancel all outstanding
+// tasks.
+//
+// 2. Both task and reply are deleted on the originating thread.
+//
+// 3. IsCanceledCallback is thread safe and can be run or deleted on any
+// thread.
+#ifndef BASE_TASK_CANCELABLE_TASK_TRACKER_H_
+#define BASE_TASK_CANCELABLE_TASK_TRACKER_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/containers/hash_tables.h"
+#include "base/memory/weak_ptr.h"
+#include "base/task_runner_util.h"
+#include "base/threading/thread_checker.h"
+
+namespace tracked_objects {
+class Location;
+}  // namespace tracked_objects
+
+namespace base {
+
+class CancellationFlag;
+class TaskRunner;
+
+class BASE_EXPORT CancelableTaskTracker {
+ public:
+  // All values except kBadTaskId are valid.
+  typedef int64 TaskId;
+  static const TaskId kBadTaskId;
+
+  typedef base::Callback<bool()> IsCanceledCallback;
+
+  CancelableTaskTracker();
+
+  // Cancels all tracked tasks.
+  ~CancelableTaskTracker();
+
+  TaskId PostTask(base::TaskRunner* task_runner,
+                  const tracked_objects::Location& from_here,
+                  const base::Closure& task);
+
+  TaskId PostTaskAndReply(base::TaskRunner* task_runner,
+                          const tracked_objects::Location& from_here,
+                          const base::Closure& task,
+                          const base::Closure& reply);
+
+  template <typename TaskReturnType, typename ReplyArgType>
+  TaskId PostTaskAndReplyWithResult(
+      base::TaskRunner* task_runner,
+      const tracked_objects::Location& from_here,
+      const base::Callback<TaskReturnType(void)>& task,
+      const base::Callback<void(ReplyArgType)>& reply) {
+    TaskReturnType* result = new TaskReturnType();
+    return PostTaskAndReply(
+        task_runner,
+        from_here,
+        base::Bind(&base::internal::ReturnAsParamAdapter<TaskReturnType>,
+                   task,
+                   base::Unretained(result)),
+        base::Bind(&base::internal::ReplyAdapter<TaskReturnType, ReplyArgType>,
+                   reply,
+                   base::Owned(result)));
+  }
+
+  // Creates a tracked TaskId and an associated IsCanceledCallback. Client can
+  // later call TryCancel() with the returned TaskId, and run |is_canceled_cb|
+  // from any thread to check whether the TaskId is canceled.
+  //
+  // The returned task ID is tracked until the last copy of
+  // |is_canceled_cb| is destroyed.
+  //
+  // Note. This function is used to address some special cancelation requirement
+  // in existing code. You SHOULD NOT need this function in new code.
+  TaskId NewTrackedTaskId(IsCanceledCallback* is_canceled_cb);
+
+  // After calling this function, |task| and |reply| will not run. If the
+  // cancelation happens when |task| is running or has finished running, |reply|
+  // will not run. If |reply| is running or has finished running, cancellation
+  // is a noop.
+  //
+  // Note. It's OK to cancel a |task| for more than once. The later calls are
+  // noops.
+  void TryCancel(TaskId id);
+
+  // It's OK to call this function for more than once. The later calls are
+  // noops.
+  void TryCancelAll();
+
+  // Returns true iff there are in-flight tasks that are still being
+  // tracked.
+  bool HasTrackedTasks() const;
+
+ private:
+  void Track(TaskId id, base::CancellationFlag* flag);
+  void Untrack(TaskId id);
+
+  base::hash_map<TaskId, base::CancellationFlag*> task_flags_;
+
+  TaskId next_id_;
+  base::ThreadChecker thread_checker_;
+
+  base::WeakPtrFactory<CancelableTaskTracker> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(CancelableTaskTracker);
+};
+
+}  // namespace base
+
+#endif  // BASE_TASK_CANCELABLE_TASK_TRACKER_H_
diff --git a/base/task/cancelable_task_tracker_unittest.cc b/base/task/cancelable_task_tracker_unittest.cc
new file mode 100644
index 0000000..ff9e40b
--- /dev/null
+++ b/base/task/cancelable_task_tracker_unittest.cc
@@ -0,0 +1,424 @@
+// 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.
+
+#include "base/task/cancelable_task_tracker.h"
+
+#include <cstddef>
+#include <deque>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/test/test_simple_task_runner.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+class CancelableTaskTrackerTest : public testing::Test {
+ protected:
+  ~CancelableTaskTrackerTest() override { RunCurrentLoopUntilIdle(); }
+
+  void RunCurrentLoopUntilIdle() {
+    RunLoop run_loop;
+    run_loop.RunUntilIdle();
+  }
+
+  CancelableTaskTracker task_tracker_;
+
+ private:
+  // Needed by CancelableTaskTracker methods.
+  MessageLoop message_loop_;
+};
+
+void AddFailureAt(const tracked_objects::Location& location) {
+  ADD_FAILURE_AT(location.file_name(), location.line_number());
+}
+
+// Returns a closure that fails if run.
+Closure MakeExpectedNotRunClosure(const tracked_objects::Location& location) {
+  return Bind(&AddFailureAt, location);
+}
+
+// A helper class for MakeExpectedRunClosure() that fails if it is
+// destroyed without Run() having been called.  This class may be used
+// from multiple threads as long as Run() is called at most once
+// before destruction.
+class RunChecker {
+ public:
+  explicit RunChecker(const tracked_objects::Location& location)
+      : location_(location), called_(false) {}
+
+  ~RunChecker() {
+    if (!called_) {
+      ADD_FAILURE_AT(location_.file_name(), location_.line_number());
+    }
+  }
+
+  void Run() { called_ = true; }
+
+ private:
+  tracked_objects::Location location_;
+  bool called_;
+};
+
+// Returns a closure that fails on destruction if it hasn't been run.
+Closure MakeExpectedRunClosure(const tracked_objects::Location& location) {
+  return Bind(&RunChecker::Run, Owned(new RunChecker(location)));
+}
+
+}  // namespace
+
+// With the task tracker, post a task, a task with a reply, and get a
+// new task id without canceling any of them.  The tasks and the reply
+// should run and the "is canceled" callback should return false.
+TEST_F(CancelableTaskTrackerTest, NoCancel) {
+  Thread worker_thread("worker thread");
+  ASSERT_TRUE(worker_thread.Start());
+
+  ignore_result(task_tracker_.PostTask(worker_thread.task_runner().get(),
+                                       FROM_HERE,
+                                       MakeExpectedRunClosure(FROM_HERE)));
+
+  ignore_result(task_tracker_.PostTaskAndReply(
+      worker_thread.task_runner().get(), FROM_HERE,
+      MakeExpectedRunClosure(FROM_HERE), MakeExpectedRunClosure(FROM_HERE)));
+
+  CancelableTaskTracker::IsCanceledCallback is_canceled;
+  ignore_result(task_tracker_.NewTrackedTaskId(&is_canceled));
+
+  worker_thread.Stop();
+
+  RunCurrentLoopUntilIdle();
+
+  EXPECT_FALSE(is_canceled.Run());
+}
+
+// Post a task with the task tracker but cancel it before running the
+// task runner.  The task should not run.
+TEST_F(CancelableTaskTrackerTest, CancelPostedTask) {
+  scoped_refptr<TestSimpleTaskRunner> test_task_runner(
+      new TestSimpleTaskRunner());
+
+  CancelableTaskTracker::TaskId task_id = task_tracker_.PostTask(
+      test_task_runner.get(), FROM_HERE, MakeExpectedNotRunClosure(FROM_HERE));
+  EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
+
+  EXPECT_EQ(1U, test_task_runner->GetPendingTasks().size());
+
+  task_tracker_.TryCancel(task_id);
+
+  test_task_runner->RunUntilIdle();
+}
+
+// Post a task with reply with the task tracker and cancel it before
+// running the task runner.  Neither the task nor the reply should
+// run.
+TEST_F(CancelableTaskTrackerTest, CancelPostedTaskAndReply) {
+  scoped_refptr<TestSimpleTaskRunner> test_task_runner(
+      new TestSimpleTaskRunner());
+
+  CancelableTaskTracker::TaskId task_id =
+      task_tracker_.PostTaskAndReply(test_task_runner.get(),
+                                     FROM_HERE,
+                                     MakeExpectedNotRunClosure(FROM_HERE),
+                                     MakeExpectedNotRunClosure(FROM_HERE));
+  EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
+
+  task_tracker_.TryCancel(task_id);
+
+  test_task_runner->RunUntilIdle();
+}
+
+// Post a task with reply with the task tracker and cancel it after
+// running the task runner but before running the current message
+// loop.  The task should run but the reply should not.
+TEST_F(CancelableTaskTrackerTest, CancelReply) {
+  scoped_refptr<TestSimpleTaskRunner> test_task_runner(
+      new TestSimpleTaskRunner());
+
+  CancelableTaskTracker::TaskId task_id =
+      task_tracker_.PostTaskAndReply(test_task_runner.get(),
+                                     FROM_HERE,
+                                     MakeExpectedRunClosure(FROM_HERE),
+                                     MakeExpectedNotRunClosure(FROM_HERE));
+  EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
+
+  test_task_runner->RunUntilIdle();
+
+  task_tracker_.TryCancel(task_id);
+}
+
+// Post a task with reply with the task tracker on a worker thread and
+// cancel it before running the current message loop.  The task should
+// run but the reply should not.
+TEST_F(CancelableTaskTrackerTest, CancelReplyDifferentThread) {
+  Thread worker_thread("worker thread");
+  ASSERT_TRUE(worker_thread.Start());
+
+  CancelableTaskTracker::TaskId task_id = task_tracker_.PostTaskAndReply(
+      worker_thread.task_runner().get(), FROM_HERE, Bind(&DoNothing),
+      MakeExpectedNotRunClosure(FROM_HERE));
+  EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
+
+  task_tracker_.TryCancel(task_id);
+
+  worker_thread.Stop();
+}
+
+void ExpectIsCanceled(
+    const CancelableTaskTracker::IsCanceledCallback& is_canceled,
+    bool expected_is_canceled) {
+  EXPECT_EQ(expected_is_canceled, is_canceled.Run());
+}
+
+// Create a new task ID and check its status on a separate thread
+// before and after canceling.  The is-canceled callback should be
+// thread-safe (i.e., nothing should blow up).
+TEST_F(CancelableTaskTrackerTest, NewTrackedTaskIdDifferentThread) {
+  CancelableTaskTracker::IsCanceledCallback is_canceled;
+  CancelableTaskTracker::TaskId task_id =
+      task_tracker_.NewTrackedTaskId(&is_canceled);
+
+  EXPECT_FALSE(is_canceled.Run());
+
+  Thread other_thread("other thread");
+  ASSERT_TRUE(other_thread.Start());
+  other_thread.task_runner()->PostTask(
+      FROM_HERE, Bind(&ExpectIsCanceled, is_canceled, false));
+  other_thread.Stop();
+
+  task_tracker_.TryCancel(task_id);
+
+  ASSERT_TRUE(other_thread.Start());
+  other_thread.task_runner()->PostTask(
+      FROM_HERE, Bind(&ExpectIsCanceled, is_canceled, true));
+  other_thread.Stop();
+}
+
+// With the task tracker, post a task, a task with a reply, get a new
+// task id, and then cancel all of them.  None of the tasks nor the
+// reply should run and the "is canceled" callback should return
+// true.
+TEST_F(CancelableTaskTrackerTest, CancelAll) {
+  scoped_refptr<TestSimpleTaskRunner> test_task_runner(
+      new TestSimpleTaskRunner());
+
+  ignore_result(task_tracker_.PostTask(
+      test_task_runner.get(), FROM_HERE, MakeExpectedNotRunClosure(FROM_HERE)));
+
+  ignore_result(
+      task_tracker_.PostTaskAndReply(test_task_runner.get(),
+                                     FROM_HERE,
+                                     MakeExpectedNotRunClosure(FROM_HERE),
+                                     MakeExpectedNotRunClosure(FROM_HERE)));
+
+  CancelableTaskTracker::IsCanceledCallback is_canceled;
+  ignore_result(task_tracker_.NewTrackedTaskId(&is_canceled));
+
+  task_tracker_.TryCancelAll();
+
+  test_task_runner->RunUntilIdle();
+
+  RunCurrentLoopUntilIdle();
+
+  EXPECT_TRUE(is_canceled.Run());
+}
+
+// With the task tracker, post a task, a task with a reply, get a new
+// task id, and then cancel all of them.  None of the tasks nor the
+// reply should run and the "is canceled" callback should return
+// true.
+TEST_F(CancelableTaskTrackerTest, DestructionCancelsAll) {
+  scoped_refptr<TestSimpleTaskRunner> test_task_runner(
+      new TestSimpleTaskRunner());
+
+  CancelableTaskTracker::IsCanceledCallback is_canceled;
+
+  {
+    // Create another task tracker with a smaller scope.
+    CancelableTaskTracker task_tracker;
+
+    ignore_result(task_tracker.PostTask(test_task_runner.get(),
+                                        FROM_HERE,
+                                        MakeExpectedNotRunClosure(FROM_HERE)));
+
+    ignore_result(
+        task_tracker.PostTaskAndReply(test_task_runner.get(),
+                                      FROM_HERE,
+                                      MakeExpectedNotRunClosure(FROM_HERE),
+                                      MakeExpectedNotRunClosure(FROM_HERE)));
+
+    ignore_result(task_tracker_.NewTrackedTaskId(&is_canceled));
+  }
+
+  test_task_runner->RunUntilIdle();
+
+  RunCurrentLoopUntilIdle();
+
+  EXPECT_FALSE(is_canceled.Run());
+}
+
+// Post a task and cancel it.  HasTrackedTasks() should return true
+// from when the task is posted until the (do-nothing) reply task is
+// flushed.
+TEST_F(CancelableTaskTrackerTest, HasTrackedTasksPost) {
+  scoped_refptr<TestSimpleTaskRunner> test_task_runner(
+      new TestSimpleTaskRunner());
+
+  EXPECT_FALSE(task_tracker_.HasTrackedTasks());
+
+  ignore_result(task_tracker_.PostTask(
+      test_task_runner.get(), FROM_HERE, MakeExpectedNotRunClosure(FROM_HERE)));
+
+  task_tracker_.TryCancelAll();
+
+  test_task_runner->RunUntilIdle();
+
+  EXPECT_TRUE(task_tracker_.HasTrackedTasks());
+
+  RunCurrentLoopUntilIdle();
+
+  EXPECT_FALSE(task_tracker_.HasTrackedTasks());
+}
+
+// Post a task with a reply and cancel it.  HasTrackedTasks() should
+// return true from when the task is posted until it is canceled.
+TEST_F(CancelableTaskTrackerTest, HasTrackedTasksPostWithReply) {
+  scoped_refptr<TestSimpleTaskRunner> test_task_runner(
+      new TestSimpleTaskRunner());
+
+  EXPECT_FALSE(task_tracker_.HasTrackedTasks());
+
+  ignore_result(
+      task_tracker_.PostTaskAndReply(test_task_runner.get(),
+                                     FROM_HERE,
+                                     MakeExpectedNotRunClosure(FROM_HERE),
+                                     MakeExpectedNotRunClosure(FROM_HERE)));
+
+  task_tracker_.TryCancelAll();
+
+  test_task_runner->RunUntilIdle();
+
+  EXPECT_TRUE(task_tracker_.HasTrackedTasks());
+
+  RunCurrentLoopUntilIdle();
+
+  EXPECT_FALSE(task_tracker_.HasTrackedTasks());
+}
+
+// Create a new tracked task ID.  HasTrackedTasks() should return true
+// until the IsCanceledCallback is destroyed.
+TEST_F(CancelableTaskTrackerTest, HasTrackedTasksIsCancelled) {
+  EXPECT_FALSE(task_tracker_.HasTrackedTasks());
+
+  CancelableTaskTracker::IsCanceledCallback is_canceled;
+  ignore_result(task_tracker_.NewTrackedTaskId(&is_canceled));
+
+  task_tracker_.TryCancelAll();
+
+  EXPECT_TRUE(task_tracker_.HasTrackedTasks());
+
+  is_canceled.Reset();
+
+  EXPECT_FALSE(task_tracker_.HasTrackedTasks());
+}
+
+// The death tests below make sure that calling task tracker member
+// functions from a thread different from its owner thread DCHECKs in
+// debug mode.
+
+class CancelableTaskTrackerDeathTest : public CancelableTaskTrackerTest {
+ protected:
+  CancelableTaskTrackerDeathTest() {
+    // The default style "fast" does not support multi-threaded tests.
+    ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+  }
+};
+
+// Duplicated from base/threading/thread_checker.h so that we can be
+// good citizens there and undef the macro.
+#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+#define ENABLE_THREAD_CHECKER 1
+#else
+#define ENABLE_THREAD_CHECKER 0
+#endif
+
+// Runs |fn| with |task_tracker|, expecting it to crash in debug mode.
+void MaybeRunDeadlyTaskTrackerMemberFunction(
+    CancelableTaskTracker* task_tracker,
+    const Callback<void(CancelableTaskTracker*)>& fn) {
+// CancelableTask uses DCHECKs with its ThreadChecker (itself only
+// enabled in debug mode).
+#if ENABLE_THREAD_CHECKER
+  EXPECT_DEATH_IF_SUPPORTED(fn.Run(task_tracker), "");
+#endif
+}
+
+void PostDoNothingTask(CancelableTaskTracker* task_tracker) {
+  ignore_result(task_tracker->PostTask(
+      scoped_refptr<TestSimpleTaskRunner>(new TestSimpleTaskRunner()).get(),
+      FROM_HERE,
+      Bind(&DoNothing)));
+}
+
+TEST_F(CancelableTaskTrackerDeathTest, PostFromDifferentThread) {
+  Thread bad_thread("bad thread");
+  ASSERT_TRUE(bad_thread.Start());
+
+  bad_thread.task_runner()->PostTask(
+      FROM_HERE, Bind(&MaybeRunDeadlyTaskTrackerMemberFunction,
+                      Unretained(&task_tracker_), Bind(&PostDoNothingTask)));
+}
+
+void TryCancel(CancelableTaskTracker::TaskId task_id,
+               CancelableTaskTracker* task_tracker) {
+  task_tracker->TryCancel(task_id);
+}
+
+TEST_F(CancelableTaskTrackerDeathTest, CancelOnDifferentThread) {
+  scoped_refptr<TestSimpleTaskRunner> test_task_runner(
+      new TestSimpleTaskRunner());
+
+  Thread bad_thread("bad thread");
+  ASSERT_TRUE(bad_thread.Start());
+
+  CancelableTaskTracker::TaskId task_id = task_tracker_.PostTask(
+      test_task_runner.get(), FROM_HERE, Bind(&DoNothing));
+  EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
+
+  bad_thread.task_runner()->PostTask(
+      FROM_HERE, Bind(&MaybeRunDeadlyTaskTrackerMemberFunction,
+                      Unretained(&task_tracker_), Bind(&TryCancel, task_id)));
+
+  test_task_runner->RunUntilIdle();
+}
+
+TEST_F(CancelableTaskTrackerDeathTest, CancelAllOnDifferentThread) {
+  scoped_refptr<TestSimpleTaskRunner> test_task_runner(
+      new TestSimpleTaskRunner());
+
+  Thread bad_thread("bad thread");
+  ASSERT_TRUE(bad_thread.Start());
+
+  CancelableTaskTracker::TaskId task_id = task_tracker_.PostTask(
+      test_task_runner.get(), FROM_HERE, Bind(&DoNothing));
+  EXPECT_NE(CancelableTaskTracker::kBadTaskId, task_id);
+
+  bad_thread.task_runner()->PostTask(
+      FROM_HERE,
+      Bind(&MaybeRunDeadlyTaskTrackerMemberFunction, Unretained(&task_tracker_),
+           Bind(&CancelableTaskTracker::TryCancelAll)));
+
+  test_task_runner->RunUntilIdle();
+}
+
+}  // namespace base
diff --git a/base/task_runner.cc b/base/task_runner.cc
new file mode 100644
index 0000000..262e1f8
--- /dev/null
+++ b/base/task_runner.cc
@@ -0,0 +1,68 @@
+// Copyright (c) 2012 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/task_runner.h"
+
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/threading/post_task_and_reply_impl.h"
+
+namespace base {
+
+namespace {
+
+// TODO(akalin): There's only one other implementation of
+// PostTaskAndReplyImpl in WorkerPool.  Investigate whether it'll be
+// possible to merge the two.
+class PostTaskAndReplyTaskRunner : public internal::PostTaskAndReplyImpl {
+ public:
+  explicit PostTaskAndReplyTaskRunner(TaskRunner* destination);
+
+ private:
+  bool PostTask(const tracked_objects::Location& from_here,
+                const Closure& task) override;
+
+  // Non-owning.
+  TaskRunner* destination_;
+};
+
+PostTaskAndReplyTaskRunner::PostTaskAndReplyTaskRunner(
+    TaskRunner* destination) : destination_(destination) {
+  DCHECK(destination_);
+}
+
+bool PostTaskAndReplyTaskRunner::PostTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task) {
+  return destination_->PostTask(from_here, task);
+}
+
+}  // namespace
+
+bool TaskRunner::PostTask(const tracked_objects::Location& from_here,
+                          const Closure& task) {
+  return PostDelayedTask(from_here, task, base::TimeDelta());
+}
+
+bool TaskRunner::PostTaskAndReply(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    const Closure& reply) {
+  return PostTaskAndReplyTaskRunner(this).PostTaskAndReply(
+      from_here, task, reply);
+}
+
+TaskRunner::TaskRunner() {}
+
+TaskRunner::~TaskRunner() {}
+
+void TaskRunner::OnDestruct() const {
+  delete this;
+}
+
+void TaskRunnerTraits::Destruct(const TaskRunner* task_runner) {
+  task_runner->OnDestruct();
+}
+
+}  // namespace base
diff --git a/base/task_runner.h b/base/task_runner.h
new file mode 100644
index 0000000..7d07b8c
--- /dev/null
+++ b/base/task_runner.h
@@ -0,0 +1,153 @@
+// Copyright (c) 2012 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_TASK_RUNNER_H_
+#define BASE_TASK_RUNNER_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/callback_forward.h"
+#include "base/memory/ref_counted.h"
+#include "base/time/time.h"
+
+namespace tracked_objects {
+class Location;
+} // namespace tracked_objects
+
+namespace base {
+
+struct TaskRunnerTraits;
+
+// A TaskRunner is an object that runs posted tasks (in the form of
+// Closure objects).  The TaskRunner interface provides a way of
+// decoupling task posting from the mechanics of how each task will be
+// run.  TaskRunner provides very weak guarantees as to how posted
+// tasks are run (or if they're run at all).  In particular, it only
+// guarantees:
+//
+//   - Posting a task will not run it synchronously.  That is, no
+//     Post*Task method will call task.Run() directly.
+//
+//   - Increasing the delay can only delay when the task gets run.
+//     That is, increasing the delay may not affect when the task gets
+//     run, or it could make it run later than it normally would, but
+//     it won't make it run earlier than it normally would.
+//
+// TaskRunner does not guarantee the order in which posted tasks are
+// run, whether tasks overlap, or whether they're run on a particular
+// thread.  Also it does not guarantee a memory model for shared data
+// between tasks.  (In other words, you should use your own
+// synchronization/locking primitives if you need to share data
+// between tasks.)
+//
+// Implementations of TaskRunner should be thread-safe in that all
+// methods must be safe to call on any thread.  Ownership semantics
+// for TaskRunners are in general not clear, which is why the
+// interface itself is RefCountedThreadSafe.
+//
+// Some theoretical implementations of TaskRunner:
+//
+//   - A TaskRunner that uses a thread pool to run posted tasks.
+//
+//   - A TaskRunner that, for each task, spawns a non-joinable thread
+//     to run that task and immediately quit.
+//
+//   - A TaskRunner that stores the list of posted tasks and has a
+//     method Run() that runs each runnable task in random order.
+class BASE_EXPORT TaskRunner
+    : public RefCountedThreadSafe<TaskRunner, TaskRunnerTraits> {
+ public:
+  // Posts the given task to be run.  Returns true if the task may be
+  // run at some point in the future, and false if the task definitely
+  // will not be run.
+  //
+  // Equivalent to PostDelayedTask(from_here, task, 0).
+  bool PostTask(const tracked_objects::Location& from_here,
+                const Closure& task);
+
+  // Like PostTask, but tries to run the posted task only after
+  // |delay_ms| has passed.
+  //
+  // It is valid for an implementation to ignore |delay_ms|; that is,
+  // to have PostDelayedTask behave the same as PostTask.
+  virtual bool PostDelayedTask(const tracked_objects::Location& from_here,
+                               const Closure& task,
+                               base::TimeDelta delay) = 0;
+
+  // Returns true if the current thread is a thread on which a task
+  // may be run, and false if no task will be run on the current
+  // thread.
+  //
+  // It is valid for an implementation to always return true, or in
+  // general to use 'true' as a default value.
+  virtual bool RunsTasksOnCurrentThread() const = 0;
+
+  // Posts |task| on the current TaskRunner.  On completion, |reply|
+  // is posted to the thread that called PostTaskAndReply().  Both
+  // |task| and |reply| are guaranteed to be deleted on the thread
+  // from which PostTaskAndReply() is invoked.  This allows objects
+  // that must be deleted on the originating thread to be bound into
+  // the |task| and |reply| Closures.  In particular, it can be useful
+  // to use WeakPtr<> in the |reply| Closure so that the reply
+  // operation can be canceled. See the following pseudo-code:
+  //
+  // class DataBuffer : public RefCountedThreadSafe<DataBuffer> {
+  //  public:
+  //   // Called to add data into a buffer.
+  //   void AddData(void* buf, size_t length);
+  //   ...
+  // };
+  //
+  //
+  // class DataLoader : public SupportsWeakPtr<DataLoader> {
+  //  public:
+  //    void GetData() {
+  //      scoped_refptr<DataBuffer> buffer = new DataBuffer();
+  //      target_thread_.message_loop_proxy()->PostTaskAndReply(
+  //          FROM_HERE,
+  //          base::Bind(&DataBuffer::AddData, buffer),
+  //          base::Bind(&DataLoader::OnDataReceived, AsWeakPtr(), buffer));
+  //    }
+  //
+  //  private:
+  //    void OnDataReceived(scoped_refptr<DataBuffer> buffer) {
+  //      // Do something with buffer.
+  //    }
+  // };
+  //
+  //
+  // Things to notice:
+  //   * Results of |task| are shared with |reply| by binding a shared argument
+  //     (a DataBuffer instance).
+  //   * The DataLoader object has no special thread safety.
+  //   * The DataLoader object can be deleted while |task| is still running,
+  //     and the reply will cancel itself safely because it is bound to a
+  //     WeakPtr<>.
+  bool PostTaskAndReply(const tracked_objects::Location& from_here,
+                        const Closure& task,
+                        const Closure& reply);
+
+ protected:
+  friend struct TaskRunnerTraits;
+
+  // Only the Windows debug build seems to need this: see
+  // http://crbug.com/112250.
+  friend class RefCountedThreadSafe<TaskRunner, TaskRunnerTraits>;
+
+  TaskRunner();
+  virtual ~TaskRunner();
+
+  // Called when this object should be destroyed.  By default simply
+  // deletes |this|, but can be overridden to do something else, like
+  // delete on a certain thread.
+  virtual void OnDestruct() const;
+};
+
+struct BASE_EXPORT TaskRunnerTraits {
+  static void Destruct(const TaskRunner* task_runner);
+};
+
+}  // namespace base
+
+#endif  // BASE_TASK_RUNNER_H_
diff --git a/base/task_runner_util.h b/base/task_runner_util.h
new file mode 100644
index 0000000..b6dd0f3
--- /dev/null
+++ b/base/task_runner_util.h
@@ -0,0 +1,71 @@
+// Copyright (c) 2012 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_TASK_RUNNER_UTIL_H_
+#define BASE_TASK_RUNNER_UTIL_H_
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback_internal.h"
+#include "base/logging.h"
+#include "base/task_runner.h"
+
+namespace base {
+
+namespace internal {
+
+// Adapts a function that produces a result via a return value to
+// one that returns via an output parameter.
+template <typename ReturnType>
+void ReturnAsParamAdapter(const Callback<ReturnType(void)>& func,
+                          ReturnType* result) {
+  *result = func.Run();
+}
+
+// Adapts a T* result to a callblack that expects a T.
+template <typename TaskReturnType, typename ReplyArgType>
+void ReplyAdapter(const Callback<void(ReplyArgType)>& callback,
+                  TaskReturnType* result) {
+  // TODO(ajwong): Remove this conditional and add a DCHECK to enforce that
+  // |reply| must be non-null in PostTaskAndReplyWithResult() below after
+  // current code that relies on this API softness has been removed.
+  // http://crbug.com/162712
+  if (!callback.is_null())
+    callback.Run(CallbackForward(*result));
+}
+
+}  // namespace internal
+
+// When you have these methods
+//
+//   R DoWorkAndReturn();
+//   void Callback(const R& result);
+//
+// and want to call them in a PostTaskAndReply kind of fashion where the
+// result of DoWorkAndReturn is passed to the Callback, you can use
+// PostTaskAndReplyWithResult as in this example:
+//
+// PostTaskAndReplyWithResult(
+//     target_thread_.message_loop_proxy(),
+//     FROM_HERE,
+//     Bind(&DoWorkAndReturn),
+//     Bind(&Callback));
+template <typename TaskReturnType, typename ReplyArgType>
+bool PostTaskAndReplyWithResult(
+    TaskRunner* task_runner,
+    const tracked_objects::Location& from_here,
+    const Callback<TaskReturnType(void)>& task,
+    const Callback<void(ReplyArgType)>& reply) {
+  TaskReturnType* result = new TaskReturnType();
+  return task_runner->PostTaskAndReply(
+      from_here,
+      base::Bind(&internal::ReturnAsParamAdapter<TaskReturnType>, task,
+                 result),
+      base::Bind(&internal::ReplyAdapter<TaskReturnType, ReplyArgType>, reply,
+                 base::Owned(result)));
+}
+
+}  // namespace base
+
+#endif  // BASE_TASK_RUNNER_UTIL_H_
diff --git a/base/task_runner_util_unittest.cc b/base/task_runner_util_unittest.cc
new file mode 100644
index 0000000..8245cfc
--- /dev/null
+++ b/base/task_runner_util_unittest.cc
@@ -0,0 +1,122 @@
+// Copyright (c) 2012 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/task_runner_util.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/run_loop.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+int ReturnFourtyTwo() {
+  return 42;
+}
+
+void StoreValue(int* destination, int value) {
+  *destination = value;
+}
+
+void StoreDoubleValue(double* destination, double value) {
+  *destination = value;
+}
+
+int g_foo_destruct_count = 0;
+int g_foo_free_count = 0;
+
+struct Foo {
+  ~Foo() {
+    ++g_foo_destruct_count;
+  }
+};
+
+scoped_ptr<Foo> CreateFoo() {
+  return scoped_ptr<Foo>(new Foo);
+}
+
+void ExpectFoo(scoped_ptr<Foo> foo) {
+  EXPECT_TRUE(foo.get());
+  scoped_ptr<Foo> local_foo(foo.Pass());
+  EXPECT_TRUE(local_foo.get());
+  EXPECT_FALSE(foo.get());
+}
+
+struct FooDeleter {
+  void operator()(Foo* foo) const {
+    ++g_foo_free_count;
+    delete foo;
+  };
+};
+
+scoped_ptr<Foo, FooDeleter> CreateScopedFoo() {
+  return scoped_ptr<Foo, FooDeleter>(new Foo);
+}
+
+void ExpectScopedFoo(scoped_ptr<Foo, FooDeleter> foo) {
+  EXPECT_TRUE(foo.get());
+  scoped_ptr<Foo, FooDeleter> local_foo(foo.Pass());
+  EXPECT_TRUE(local_foo.get());
+  EXPECT_FALSE(foo.get());
+}
+
+}  // namespace
+
+TEST(TaskRunnerHelpersTest, PostTaskAndReplyWithResult) {
+  int result = 0;
+
+  MessageLoop message_loop;
+  PostTaskAndReplyWithResult(message_loop.task_runner().get(), FROM_HERE,
+                             Bind(&ReturnFourtyTwo),
+                             Bind(&StoreValue, &result));
+
+  RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(42, result);
+}
+
+TEST(TaskRunnerHelpersTest, PostTaskAndReplyWithResultImplicitConvert) {
+  double result = 0;
+
+  MessageLoop message_loop;
+  PostTaskAndReplyWithResult(message_loop.task_runner().get(), FROM_HERE,
+                             Bind(&ReturnFourtyTwo),
+                             Bind(&StoreDoubleValue, &result));
+
+  RunLoop().RunUntilIdle();
+
+  EXPECT_DOUBLE_EQ(42.0, result);
+}
+
+TEST(TaskRunnerHelpersTest, PostTaskAndReplyWithResultPassed) {
+  g_foo_destruct_count = 0;
+  g_foo_free_count = 0;
+
+  MessageLoop message_loop;
+  PostTaskAndReplyWithResult(message_loop.task_runner().get(), FROM_HERE,
+                             Bind(&CreateFoo), Bind(&ExpectFoo));
+
+  RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(1, g_foo_destruct_count);
+  EXPECT_EQ(0, g_foo_free_count);
+}
+
+TEST(TaskRunnerHelpersTest, PostTaskAndReplyWithResultPassedFreeProc) {
+  g_foo_destruct_count = 0;
+  g_foo_free_count = 0;
+
+  MessageLoop message_loop;
+  PostTaskAndReplyWithResult(message_loop.task_runner().get(), FROM_HERE,
+                             Bind(&CreateScopedFoo), Bind(&ExpectScopedFoo));
+
+  RunLoop().RunUntilIdle();
+
+  EXPECT_EQ(1, g_foo_destruct_count);
+  EXPECT_EQ(1, g_foo_free_count);
+}
+
+}  // namespace base
diff --git a/base/template_util.h b/base/template_util.h
new file mode 100644
index 0000000..83fa322
--- /dev/null
+++ b/base/template_util.h
@@ -0,0 +1,128 @@
+// Copyright (c) 2011 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_TEMPLATE_UTIL_H_
+#define BASE_TEMPLATE_UTIL_H_
+
+#include <cstddef>  // For size_t.
+
+#include "build/build_config.h"
+
+namespace base {
+
+// template definitions from tr1
+
+template<class T, T v>
+struct integral_constant {
+  static const T value = v;
+  typedef T value_type;
+  typedef integral_constant<T, v> type;
+};
+
+template <class T, T v> const T integral_constant<T, v>::value;
+
+typedef integral_constant<bool, true> true_type;
+typedef integral_constant<bool, false> false_type;
+
+template <class T> struct is_pointer : false_type {};
+template <class T> struct is_pointer<T*> : true_type {};
+
+// Member function pointer detection. This is built-in to C++ 11's stdlib, and
+// we can remove this when we switch to it.
+template<typename T>
+struct is_member_function_pointer : false_type {};
+
+template <typename R, typename Z, typename... A>
+struct is_member_function_pointer<R(Z::*)(A...)> : true_type {};
+template <typename R, typename Z, typename... A>
+struct is_member_function_pointer<R(Z::*)(A...) const> : true_type {};
+
+
+template <class T, class U> struct is_same : public false_type {};
+template <class T> struct is_same<T,T> : true_type {};
+
+template<class> struct is_array : public false_type {};
+template<class T, size_t n> struct is_array<T[n]> : public true_type {};
+template<class T> struct is_array<T[]> : public true_type {};
+
+template <class T> struct is_non_const_reference : false_type {};
+template <class T> struct is_non_const_reference<T&> : true_type {};
+template <class T> struct is_non_const_reference<const T&> : false_type {};
+
+template <class T> struct is_const : false_type {};
+template <class T> struct is_const<const T> : true_type {};
+
+template <class T> struct is_void : false_type {};
+template <> struct is_void<void> : true_type {};
+
+namespace internal {
+
+// Types YesType and NoType are guaranteed such that sizeof(YesType) <
+// sizeof(NoType).
+typedef char YesType;
+
+struct NoType {
+  YesType dummy[2];
+};
+
+// This class is an implementation detail for is_convertible, and you
+// don't need to know how it works to use is_convertible. For those
+// who care: we declare two different functions, one whose argument is
+// of type To and one with a variadic argument list. We give them
+// return types of different size, so we can use sizeof to trick the
+// compiler into telling us which function it would have chosen if we
+// had called it with an argument of type From.  See Alexandrescu's
+// _Modern C++ Design_ for more details on this sort of trick.
+
+struct ConvertHelper {
+  template <typename To>
+  static YesType Test(To);
+
+  template <typename To>
+  static NoType Test(...);
+
+  template <typename From>
+  static From& Create();
+};
+
+// Used to determine if a type is a struct/union/class. Inspired by Boost's
+// is_class type_trait implementation.
+struct IsClassHelper {
+  template <typename C>
+  static YesType Test(void(C::*)(void));
+
+  template <typename C>
+  static NoType Test(...);
+};
+
+}  // namespace internal
+
+// Inherits from true_type if From is convertible to To, false_type otherwise.
+//
+// Note that if the type is convertible, this will be a true_type REGARDLESS
+// of whether or not the conversion would emit a warning.
+template <typename From, typename To>
+struct is_convertible
+    : integral_constant<bool,
+                        sizeof(internal::ConvertHelper::Test<To>(
+                                   internal::ConvertHelper::Create<From>())) ==
+                        sizeof(internal::YesType)> {
+};
+
+template <typename T>
+struct is_class
+    : integral_constant<bool,
+                        sizeof(internal::IsClassHelper::Test<T>(0)) ==
+                            sizeof(internal::YesType)> {
+};
+
+template<bool B, class T = void>
+struct enable_if {};
+
+template<class T>
+struct enable_if<true, T> { typedef T type; };
+
+}  // namespace base
+
+#endif  // BASE_TEMPLATE_UTIL_H_
diff --git a/base/template_util_unittest.cc b/base/template_util_unittest.cc
new file mode 100644
index 0000000..3ec3887
--- /dev/null
+++ b/base/template_util_unittest.cc
@@ -0,0 +1,109 @@
+// Copyright (c) 2012 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/template_util.h"
+
+#include "base/basictypes.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+struct AStruct {};
+class AClass {};
+enum AnEnum {};
+
+class Parent {};
+class Child : public Parent {};
+
+// is_pointer<Type>
+COMPILE_ASSERT(!is_pointer<int>::value, IsPointer);
+COMPILE_ASSERT(!is_pointer<int&>::value, IsPointer);
+COMPILE_ASSERT(is_pointer<int*>::value, IsPointer);
+COMPILE_ASSERT(is_pointer<const int*>::value, IsPointer);
+
+// is_array<Type>
+COMPILE_ASSERT(!is_array<int>::value, IsArray);
+COMPILE_ASSERT(!is_array<int*>::value, IsArray);
+COMPILE_ASSERT(!is_array<int(*)[3]>::value, IsArray);
+COMPILE_ASSERT(is_array<int[]>::value, IsArray);
+COMPILE_ASSERT(is_array<const int[]>::value, IsArray);
+COMPILE_ASSERT(is_array<int[3]>::value, IsArray);
+
+// is_non_const_reference<Type>
+COMPILE_ASSERT(!is_non_const_reference<int>::value, IsNonConstReference);
+COMPILE_ASSERT(!is_non_const_reference<const int&>::value, IsNonConstReference);
+COMPILE_ASSERT(is_non_const_reference<int&>::value, IsNonConstReference);
+
+// is_convertible<From, To>
+
+// Extra parens needed to make preprocessor macro parsing happy. Otherwise,
+// it sees the equivalent of:
+//
+//     (is_convertible < Child), (Parent > ::value)
+//
+// Silly C++.
+COMPILE_ASSERT( (is_convertible<Child, Parent>::value), IsConvertible);
+COMPILE_ASSERT(!(is_convertible<Parent, Child>::value), IsConvertible);
+COMPILE_ASSERT(!(is_convertible<Parent, AStruct>::value), IsConvertible);
+COMPILE_ASSERT( (is_convertible<int, double>::value), IsConvertible);
+COMPILE_ASSERT( (is_convertible<int*, void*>::value), IsConvertible);
+COMPILE_ASSERT(!(is_convertible<void*, int*>::value), IsConvertible);
+
+// Array types are an easy corner case.  Make sure to test that
+// it does indeed compile.
+COMPILE_ASSERT(!(is_convertible<int[10], double>::value), IsConvertible);
+COMPILE_ASSERT(!(is_convertible<double, int[10]>::value), IsConvertible);
+COMPILE_ASSERT( (is_convertible<int[10], int*>::value), IsConvertible);
+
+// is_same<Type1, Type2>
+COMPILE_ASSERT(!(is_same<Child, Parent>::value), IsSame);
+COMPILE_ASSERT(!(is_same<Parent, Child>::value), IsSame);
+COMPILE_ASSERT( (is_same<Parent, Parent>::value), IsSame);
+COMPILE_ASSERT( (is_same<int*, int*>::value), IsSame);
+COMPILE_ASSERT( (is_same<int, int>::value), IsSame);
+COMPILE_ASSERT( (is_same<void, void>::value), IsSame);
+COMPILE_ASSERT(!(is_same<int, double>::value), IsSame);
+
+
+// is_class<Type>
+COMPILE_ASSERT(is_class<AStruct>::value, IsClass);
+COMPILE_ASSERT(is_class<AClass>::value, IsClass);
+COMPILE_ASSERT(!is_class<AnEnum>::value, IsClass);
+COMPILE_ASSERT(!is_class<int>::value, IsClass);
+COMPILE_ASSERT(!is_class<char*>::value, IsClass);
+COMPILE_ASSERT(!is_class<int&>::value, IsClass);
+COMPILE_ASSERT(!is_class<char[3]>::value, IsClass);
+
+
+COMPILE_ASSERT(!is_member_function_pointer<int>::value,
+               IsMemberFunctionPointer);
+COMPILE_ASSERT(!is_member_function_pointer<int*>::value,
+               IsMemberFunctionPointer);
+COMPILE_ASSERT(!is_member_function_pointer<void*>::value,
+               IsMemberFunctionPointer);
+COMPILE_ASSERT(!is_member_function_pointer<AStruct>::value,
+               IsMemberFunctionPointer);
+COMPILE_ASSERT(!is_member_function_pointer<AStruct*>::value,
+               IsMemberFunctionPointer);
+COMPILE_ASSERT(!is_member_function_pointer<void(*)()>::value,
+               IsMemberFunctionPointer);
+COMPILE_ASSERT(!is_member_function_pointer<int(*)(int)>::value,
+               IsMemberFunctionPointer);
+COMPILE_ASSERT(!is_member_function_pointer<int(*)(int, int)>::value,
+               IsMemberFunctionPointer);
+
+COMPILE_ASSERT(is_member_function_pointer<void (AStruct::*)()>::value,
+               IsMemberFunctionPointer);
+COMPILE_ASSERT(is_member_function_pointer<void (AStruct::*)(int)>::value,
+               IsMemberFunctionPointer);
+COMPILE_ASSERT(is_member_function_pointer<int (AStruct::*)(int)>::value,
+               IsMemberFunctionPointer);
+COMPILE_ASSERT(is_member_function_pointer<int (AStruct::*)(int) const>::value,
+               IsMemberFunctionPointer);
+COMPILE_ASSERT(is_member_function_pointer<int (AStruct::*)(int, int)>::value,
+               IsMemberFunctionPointer);
+
+}  // namespace
+}  // namespace base
diff --git a/base/test/BUILD.gn b/base/test/BUILD.gn
new file mode 100644
index 0000000..a8ae0cf
--- /dev/null
+++ b/base/test/BUILD.gn
@@ -0,0 +1,214 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/ui.gni")
+
+if (is_android) {
+  import("//build/config/android/rules.gni")
+}
+
+source_set("test_config") {
+  # TODO http://crbug.com/412064 enable this flag all the time.
+  testonly = !is_component_build
+  sources = [
+    "test_switches.cc",
+    "test_switches.h",
+    "test_timeouts.cc",
+    "test_timeouts.h",
+  ]
+  deps = [
+    "//base",
+  ]
+}
+
+# GYP: //base/base.gyp:test_support_base
+source_set("test_support") {
+  # TODO http://crbug.com/412064 enable this flag all the time.
+  testonly = !is_component_build
+  sources = [
+    "expectations/expectation.cc",
+    "expectations/expectation.h",
+    "expectations/parser.cc",
+    "expectations/parser.h",
+    "gtest_util.cc",
+    "gtest_util.h",
+    "gtest_xml_unittest_result_printer.cc",
+    "gtest_xml_unittest_result_printer.h",
+    "gtest_xml_util.cc",
+    "gtest_xml_util.h",
+    "histogram_tester.cc",
+    "histogram_tester.h",
+    "launcher/test_launcher.cc",
+    "launcher/test_launcher.h",
+    "launcher/test_result.cc",
+    "launcher/test_result.h",
+    "launcher/test_results_tracker.cc",
+    "launcher/test_results_tracker.h",
+    "launcher/unit_test_launcher.cc",
+    "launcher/unit_test_launcher.h",
+    "launcher/unit_test_launcher_ios.cc",
+    "mock_chrome_application_mac.h",
+    "mock_chrome_application_mac.mm",
+    "mock_devices_changed_observer.cc",
+    "mock_devices_changed_observer.h",
+    "mock_entropy_provider.cc",
+    "mock_entropy_provider.h",
+    "mock_log.cc",
+    "mock_log.h",
+    "multiprocess_test.cc",
+    "multiprocess_test.h",
+    "multiprocess_test_android.cc",
+    "null_task_runner.cc",
+    "null_task_runner.h",
+    "opaque_ref_counted.cc",
+    "opaque_ref_counted.h",
+    "perf_log.cc",
+    "perf_log.h",
+    "perf_test_suite.cc",
+    "perf_test_suite.h",
+    "perf_time_logger.cc",
+    "perf_time_logger.h",
+    "power_monitor_test_base.cc",
+    "power_monitor_test_base.h",
+    "scoped_locale.cc",
+    "scoped_locale.h",
+    "scoped_path_override.cc",
+    "scoped_path_override.h",
+    "sequenced_task_runner_test_template.cc",
+    "sequenced_task_runner_test_template.h",
+    "sequenced_worker_pool_owner.cc",
+    "sequenced_worker_pool_owner.h",
+    "simple_test_clock.cc",
+    "simple_test_clock.h",
+    "simple_test_tick_clock.cc",
+    "simple_test_tick_clock.h",
+    "task_runner_test_template.cc",
+    "task_runner_test_template.h",
+    "test_discardable_memory_allocator.cc",
+    "test_discardable_memory_allocator.h",
+    "test_file_util.cc",
+    "test_file_util.h",
+    "test_file_util_android.cc",
+    "test_file_util_linux.cc",
+    "test_file_util_mac.cc",
+    "test_file_util_posix.cc",
+    "test_file_util_win.cc",
+    "test_io_thread.cc",
+    "test_io_thread.h",
+    "test_listener_ios.h",
+    "test_listener_ios.mm",
+    "test_mock_time_task_runner.cc",
+    "test_mock_time_task_runner.h",
+    "test_pending_task.cc",
+    "test_pending_task.h",
+    "test_reg_util_win.cc",
+    "test_reg_util_win.h",
+    "test_shortcut_win.cc",
+    "test_shortcut_win.h",
+    "test_simple_task_runner.cc",
+    "test_simple_task_runner.h",
+    "test_suite.cc",
+    "test_suite.h",
+    "test_support_android.cc",
+    "test_support_android.h",
+    "test_support_ios.h",
+    "test_support_ios.mm",
+    "test_ui_thread_android.cc",
+    "test_ui_thread_android.h",
+    "thread_test_helper.cc",
+    "thread_test_helper.h",
+    "trace_event_analyzer.cc",
+    "trace_event_analyzer.h",
+    "trace_to_file.cc",
+    "trace_to_file.h",
+    "user_action_tester.cc",
+    "user_action_tester.h",
+    "values_test_util.cc",
+    "values_test_util.h",
+  ]
+
+  public_deps = [
+    ":test_config",
+    "//base",
+    "//base:i18n",
+    "//base:base_static",
+  ]
+  deps = [
+    "//base/third_party/dynamic_annotations",
+    "//testing/gmock",
+    "//testing/gtest",
+    "//third_party/libxml",
+    "//third_party/icu:icuuc",
+  ]
+
+  if (!is_posix) {
+    sources -= [
+      "scoped_locale.cc",
+      "scoped_locale.h",
+    ]
+  }
+  if (is_ios) {
+    # iOS uses its own unit test launcher.
+    sources -= [ "launcher/unit_test_launcher.cc" ]
+
+    # Pull in specific Mac files for iOS (which have been filtered out
+    # by file name rules).
+    set_sources_assignment_filter([])
+    sources += [ "test_file_util_mac.cc" ]
+  }
+
+  if (is_android) {
+    deps += [ ":base_unittests_jni_headers" ]
+  }
+}
+
+config("perf_test_config") {
+  defines = [ "PERF_TEST" ]
+}
+
+source_set("test_support_perf") {
+  testonly = true
+  sources = [
+    "run_all_perftests.cc",
+  ]
+  deps = [
+    ":test_support",
+    "//base",
+    "//testing/gtest",
+  ]
+
+  public_configs = [ ":perf_test_config" ]
+}
+
+source_set("run_all_unittests") {
+  testonly = true
+  sources = [
+    "run_all_unittests.cc",
+  ]
+  deps = [
+    ":test_support",
+  ]
+}
+
+if (is_linux) {
+  shared_library("malloc_wrapper") {
+    testonly = true
+    sources = [
+      "malloc_wrapper.cc",
+    ]
+    deps = [
+      "//base",
+    ]
+  }
+}
+
+if (is_android) {
+  generate_jni("base_unittests_jni_headers") {
+    sources = [
+      "android/java/src/org/chromium/base/ContentUriTestUtils.java",
+      "android/java/src/org/chromium/base/TestUiThread.java",
+    ]
+    jni_package = "base"
+  }
+}
diff --git a/base/test/DEPS b/base/test/DEPS
new file mode 100644
index 0000000..5827c26
--- /dev/null
+++ b/base/test/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+third_party/libxml",
+]
diff --git a/base/test/OWNERS b/base/test/OWNERS
new file mode 100644
index 0000000..92ecc88
--- /dev/null
+++ b/base/test/OWNERS
@@ -0,0 +1 @@
+phajdan.jr@chromium.org
diff --git a/base/test/android/OWNERS b/base/test/android/OWNERS
new file mode 100644
index 0000000..3c9067c
--- /dev/null
+++ b/base/test/android/OWNERS
@@ -0,0 +1,3 @@
+feng@chromium.org
+nyquist@chromium.org
+yfriedman@chromium.org
diff --git a/base/test/android/java/src/org/chromium/base/ContentUriTestUtils.java b/base/test/android/java/src/org/chromium/base/ContentUriTestUtils.java
new file mode 100644
index 0000000..4a1613b
--- /dev/null
+++ b/base/test/android/java/src/org/chromium/base/ContentUriTestUtils.java
@@ -0,0 +1,48 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.MediaStore;
+
+/**
+ * Utilities for testing operations on content URI.
+ */
+public class ContentUriTestUtils {
+    /**
+     * Insert an image into the MediaStore, and return the content URI. If the
+     * image already exists in the MediaStore, just retrieve the URI.
+     *
+     * @param context Application context.
+     * @param path Path to the image file.
+     * @return Content URI of the image.
+     */
+    @CalledByNative
+    private static String insertImageIntoMediaStore(Context context, String path) {
+        // Check whether the content URI exists.
+        Cursor c = context.getContentResolver().query(
+                MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
+                new String[] { MediaStore.Video.VideoColumns._ID },
+                MediaStore.Images.Media.DATA + " LIKE ?",
+                new String[] { path },
+                null);
+        if (c != null && c.getCount() > 0) {
+            c.moveToFirst();
+            int id = c.getInt(0);
+            return Uri.withAppendedPath(
+                    MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "" + id).toString();
+        }
+
+        // Insert the content URI into MediaStore.
+        ContentValues values = new ContentValues();
+        values.put(MediaStore.MediaColumns.DATA, path);
+        Uri uri = context.getContentResolver().insert(
+                MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
+        return uri.toString();
+    }
+}
diff --git a/base/test/android/java/src/org/chromium/base/TestUiThread.java b/base/test/android/java/src/org/chromium/base/TestUiThread.java
new file mode 100644
index 0000000..77f9660
--- /dev/null
+++ b/base/test/android/java/src/org/chromium/base/TestUiThread.java
@@ -0,0 +1,49 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base;
+
+import android.os.Looper;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.annotation.concurrent.ThreadSafe;
+
+/**
+ * Set up a thread as the Chromium UI Thread, and run its looper. This is is intended for C++ unit
+ * tests (e.g. the net unit tests) that don't run with the UI thread as their main looper, but test
+ * code that, on Android, uses UI thread events, so need a running UI thread.
+ */
+@ThreadSafe
+public class TestUiThread {
+    private static final AtomicBoolean sStarted = new AtomicBoolean(false);
+    private static final String TAG = Log.makeTag("TestUiThread");
+
+    @CalledByNative
+    private static void loop() {
+        // @{link ThreadUtils#setUiThread(Looper)} can only be called once in a test run, so do this
+        // once, and leave it running.
+        if (sStarted.getAndSet(true)) return;
+
+        final CountDownLatch startLatch = new CountDownLatch(1);
+        new Thread(new Runnable() {
+
+            @Override
+            public void run() {
+                Looper.prepare();
+                ThreadUtils.setUiThread(Looper.myLooper());
+                startLatch.countDown();
+                Looper.loop();
+            }
+
+        }).start();
+
+        try {
+            startLatch.await();
+        } catch (InterruptedException e) {
+            Log.e(TAG, "Failed to set UI Thread");
+        }
+    }
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/BaseActivityInstrumentationTestCase.java b/base/test/android/javatests/src/org/chromium/base/test/BaseActivityInstrumentationTestCase.java
new file mode 100644
index 0000000..53dee4a
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/BaseActivityInstrumentationTestCase.java
@@ -0,0 +1,118 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.test;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.SystemClock;
+import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
+
+import org.chromium.base.BaseChromiumApplication;
+import org.chromium.base.CommandLine;
+import org.chromium.base.test.util.CommandLineFlags;
+
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Base class for all Activity-based Instrumentation tests.
+ *
+ * @param <T> The Activity type.
+ */
+public class BaseActivityInstrumentationTestCase<T extends Activity>
+        extends ActivityInstrumentationTestCase2<T> {
+
+    private static final String TAG = "BaseActivityInstrumentationTestCase";
+
+    private static final int SLEEP_INTERVAL = 50; // milliseconds
+    private static final int WAIT_DURATION = 5000; // milliseconds
+
+    /**
+     * Creates a instance for running tests against an Activity of the given class.
+     *
+     * @param activityClass The type of activity that will be tested.
+     */
+    public BaseActivityInstrumentationTestCase(Class<T> activityClass) {
+        super(activityClass);
+    }
+
+    /**
+     * Sets up the CommandLine with the appropriate flags.
+     *
+     * This will add the difference of the sets of flags specified by {@link CommandLineFlags.Add}
+     * and {@link CommandLineFlags.Remove} to the {@link org.chromium.base.CommandLine}. Note that
+     * trying to remove a flag set externally, i.e. by the command-line flags file, will not work.
+     */
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        CommandLine.reset();
+        Context targetContext = getTargetContext();
+        assertNotNull("Unable to get a non-null target context.", targetContext);
+
+        BaseChromiumApplication.initCommandLine(targetContext);
+        Set<String> flags = getFlags(getClass().getMethod(getName()));
+        for (String flag : flags) {
+            CommandLine.getInstance().appendSwitch(flag);
+        }
+    }
+
+    /**
+     * Gets the target context.
+     *
+     * On older versions of Android, getTargetContext() may initially return null, so we have to
+     * wait for it to become available.
+     *
+     * @return The target {@link android.content.Context} if available; null otherwise.
+     */
+    private Context getTargetContext() {
+        Context targetContext = getInstrumentation().getTargetContext();
+        try {
+            long startTime = SystemClock.uptimeMillis();
+            // TODO(jbudorick): Convert this to CriteriaHelper once that moves to base/.
+            while (targetContext == null
+                    && SystemClock.uptimeMillis() - startTime < WAIT_DURATION) {
+                Thread.sleep(SLEEP_INTERVAL);
+                targetContext = getInstrumentation().getTargetContext();
+            }
+        } catch (InterruptedException e) {
+            Log.e(TAG, "Interrupted while attempting to initialize the command line.");
+        }
+        return targetContext;
+    }
+
+    private static Set<String> getFlags(AnnotatedElement element) {
+        AnnotatedElement parent = (element instanceof Method)
+                ? ((Method) element).getDeclaringClass()
+                : ((Class) element).getSuperclass();
+        Set<String> flags = (parent == null) ? new HashSet<String>() : getFlags(parent);
+
+        if (element.isAnnotationPresent(CommandLineFlags.Add.class)) {
+            flags.addAll(
+                    Arrays.asList(element.getAnnotation(CommandLineFlags.Add.class).value()));
+        }
+
+        if (element.isAnnotationPresent(CommandLineFlags.Remove.class)) {
+            List<String> flagsToRemove =
+                    Arrays.asList(element.getAnnotation(CommandLineFlags.Remove.class).value());
+            for (String flagToRemove : flagsToRemove) {
+                // If your test fails here, you have tried to remove a command-line flag via
+                // CommandLineFlags.Remove that was loaded into CommandLine via something other
+                // than CommandLineFlags.Add (probably the command-line flag file).
+                assertFalse("Unable to remove command-line flag \"" + flagToRemove + "\".",
+                        CommandLine.getInstance().hasSwitch(flagToRemove));
+            }
+            flags.removeAll(flagsToRemove);
+        }
+
+        return flags;
+    }
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/BaseInstrumentationTestRunner.java b/base/test/android/javatests/src/org/chromium/base/test/BaseInstrumentationTestRunner.java
new file mode 100644
index 0000000..8a3395a
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/BaseInstrumentationTestRunner.java
@@ -0,0 +1,133 @@
+// 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.test;
+
+import android.os.Build;
+import android.os.Bundle;
+import android.test.AndroidTestRunner;
+import android.test.InstrumentationTestRunner;
+import android.util.Log;
+
+import junit.framework.TestCase;
+import junit.framework.TestResult;
+
+import org.chromium.base.test.util.MinAndroidSdkLevel;
+import org.chromium.test.reporter.TestStatusListener;
+
+import java.util.ArrayList;
+import java.util.List;
+
+// TODO(jbudorick): Add support for on-device handling of timeouts.
+/**
+ *  An Instrumentation test runner that checks SDK level for tests with specific requirements.
+ */
+public class BaseInstrumentationTestRunner extends InstrumentationTestRunner {
+
+    private static final String TAG = "BaseInstrumentationTestRunner";
+
+    /**
+     * 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);
+    }
+
+    /**
+     * A test result that can skip tests.
+     */
+    public class SkippingTestResult extends TestResult {
+
+        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
+        protected void run(final TestCase test) {
+            if (shouldSkip(test)) {
+                startTest(test);
+
+                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() {
+        AndroidTestRunner runner = new AndroidTestRunner() {
+            @Override
+            protected TestResult createTestResult() {
+                SkippingTestResult r = new SkippingTestResult();
+                r.addSkipCheck(new MinAndroidSdkLevelSkipCheck());
+                return r;
+            }
+        };
+        runner.addTestListener(new TestStatusListener(getContext()));
+        return runner;
+    }
+
+    /**
+     * 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()) {
+                    Log.i(TAG, "Test " + testClass.getName() + "#" + testCase.getName()
+                            + " is not enabled at SDK level " + Build.VERSION.SDK_INT
+                            + ".");
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/AdvancedMockContext.java b/base/test/android/javatests/src/org/chromium/base/test/util/AdvancedMockContext.java
new file mode 100644
index 0000000..c8117f7
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/AdvancedMockContext.java
@@ -0,0 +1,118 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.test.util;
+
+import android.content.ComponentCallbacks;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.SharedPreferences;
+import android.test.mock.MockContentResolver;
+import android.test.mock.MockContext;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * ContextWrapper that adds functionality for SharedPreferences and a way to set and retrieve flags.
+ */
+public class AdvancedMockContext extends ContextWrapper {
+
+    private final MockContentResolver mMockContentResolver = new MockContentResolver();
+
+    private final Map<String, SharedPreferences> mSharedPreferences =
+            new HashMap<String, SharedPreferences>();
+
+    private final Map<String, Boolean> mFlags = new HashMap<String, Boolean>();
+
+    public AdvancedMockContext(Context base) {
+        super(base);
+    }
+
+    public AdvancedMockContext() {
+        super(new MockContext());
+    }
+
+    @Override
+    public String getPackageName() {
+        return getBaseContext().getPackageName();
+    }
+
+    @Override
+    public Context getApplicationContext() {
+        return this;
+    }
+
+    @Override
+    public ContentResolver getContentResolver() {
+        return mMockContentResolver;
+    }
+
+    public MockContentResolver getMockContentResolver() {
+        return mMockContentResolver;
+    }
+
+    @Override
+    public SharedPreferences getSharedPreferences(String name, int mode) {
+        synchronized (mSharedPreferences) {
+            if (!mSharedPreferences.containsKey(name)) {
+                // Auto-create shared preferences to mimic Android Context behavior
+                mSharedPreferences.put(name, new InMemorySharedPreferences());
+            }
+            return mSharedPreferences.get(name);
+        }
+    }
+
+    @Override
+    public void registerComponentCallbacks(ComponentCallbacks callback) {
+        getBaseContext().registerComponentCallbacks(callback);
+    }
+
+    @Override
+    public void unregisterComponentCallbacks(ComponentCallbacks callback) {
+        getBaseContext().unregisterComponentCallbacks(callback);
+    }
+
+    public void addSharedPreferences(String name, Map<String, Object> data) {
+        synchronized (mSharedPreferences) {
+            mSharedPreferences.put(name, new InMemorySharedPreferences(data));
+        }
+    }
+
+    public void setFlag(String key) {
+        mFlags.put(key, true);
+    }
+
+    public void clearFlag(String key) {
+        mFlags.remove(key);
+    }
+
+    public boolean isFlagSet(String key) {
+        return mFlags.containsKey(key) && mFlags.get(key);
+    }
+
+    /**
+     * Builder for maps of type Map<String, Object> to be used with
+     * {@link #addSharedPreferences(String, java.util.Map)}.
+     */
+    public static class MapBuilder {
+
+        private final Map<String, Object> mData = new HashMap<String, Object>();
+
+        public static MapBuilder create() {
+            return new MapBuilder();
+        }
+
+        public MapBuilder add(String key, Object value) {
+            mData.put(key, value);
+            return this;
+        }
+
+        public Map<String, Object> build() {
+            return mData;
+        }
+
+    }
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/CommandLineFlags.java b/base/test/android/javatests/src/org/chromium/base/test/util/CommandLineFlags.java
new file mode 100644
index 0000000..2feb83d
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/CommandLineFlags.java
@@ -0,0 +1,48 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.test.util;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Provides annotations related to command-line flag handling.
+ *
+ * Uses of these annotations on a derived class will take precedence over uses on its base classes,
+ * so a derived class can add a command-line flag that a base class has removed (or vice versa).
+ * Similarly, uses of these annotations on a test method will take precedence over uses on the
+ * containing class.
+ *
+ * Note that this class should never be instantiated.
+ */
+public final class CommandLineFlags {
+
+    /**
+     * Adds command-line flags to the {@link org.chromium.base.CommandLine} for this test.
+     */
+    @Inherited
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target({ElementType.METHOD, ElementType.TYPE})
+    public @interface Add {
+        String[] value();
+    }
+
+    /**
+     * Removes command-line flags from the {@link org.chromium.base.CommandLine} from this test.
+     *
+     * Note that this can only remove flags added via {@link Add} above.
+     */
+    @Inherited
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target({ElementType.METHOD, ElementType.TYPE})
+    public @interface Remove {
+        String[] value();
+    }
+
+    private CommandLineFlags() {}
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/DisabledTest.java b/base/test/android/javatests/src/org/chromium/base/test/util/DisabledTest.java
new file mode 100644
index 0000000..0dfb4be
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/DisabledTest.java
@@ -0,0 +1,21 @@
+// Copyright 2012 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.test.util;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation is for disabled tests.
+ * <p>
+ * Tests with this annotation will not be run on any of the normal bots.
+ * Please note that they might eventually run on a special bot.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface DisabledTest {
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/EnormousTest.java b/base/test/android/javatests/src/org/chromium/base/test/util/EnormousTest.java
new file mode 100644
index 0000000..af483ec
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/EnormousTest.java
@@ -0,0 +1,24 @@
+// Copyright 2012 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.test.util;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation is for enormous tests.
+ * <p>
+ * Examples of enormous tests are tests that depend on external web sites or
+ * tests that are long running.
+ * <p>
+ * Such tests are likely NOT reliable enough to run on tree closing bots and
+ * should only be run on FYI bots.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface EnormousTest {
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/Feature.java b/base/test/android/javatests/src/org/chromium/base/test/util/Feature.java
new file mode 100644
index 0000000..1bc9226
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/Feature.java
@@ -0,0 +1,29 @@
+// Copyright 2012 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.test.util;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * The java instrumentation tests are normally fairly large (in terms of
+ * dependencies), and the test suite ends up containing a large amount of
+ * tests that are not trivial to filter / group just by their names.
+ * Instead, we use this annotation: each test should be annotated as:
+ *     @Feature({"Foo", "Bar"})
+ * in order for the test runner scripts to be able to filter and group
+ * them accordingly (for instance, this enable us to run all tests that exercise
+ * feature Foo).
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Feature {
+    /**
+     * @return A list of feature names.
+     */
+    public String[] value();
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/HostDrivenTest.java b/base/test/android/javatests/src/org/chromium/base/test/util/HostDrivenTest.java
new file mode 100644
index 0000000..b52fb2c
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/HostDrivenTest.java
@@ -0,0 +1,22 @@
+// Copyright 2012 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.test.util;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation is for host-driven tests.
+ * <p>
+ * Tests with these annotations are run explicitly by HostDrivenTestCase-derived
+ * python tests on the host and are excluded from regular instrumentation test runs.
+ * <p>
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface HostDrivenTest {
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/InMemorySharedPreferences.java b/base/test/android/javatests/src/org/chromium/base/test/util/InMemorySharedPreferences.java
new file mode 100644
index 0000000..2587d72
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/InMemorySharedPreferences.java
@@ -0,0 +1,238 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.test.util;
+
+import android.content.SharedPreferences;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * An implementation of SharedPreferences that can be used in tests.
+ * <p/>
+ * It keeps all state in memory, and there is no difference between apply() and commit().
+ */
+public class InMemorySharedPreferences implements SharedPreferences {
+
+    // Guarded on its own monitor.
+    private final Map<String, Object> mData;
+
+    public InMemorySharedPreferences() {
+        mData = new HashMap<String, Object>();
+    }
+
+    public InMemorySharedPreferences(Map<String, Object> data) {
+        mData = data;
+    }
+
+    @Override
+    public Map<String, ?> getAll() {
+        synchronized (mData) {
+            return Collections.unmodifiableMap(mData);
+        }
+    }
+
+    @Override
+    public String getString(String key, String defValue) {
+        synchronized (mData) {
+            if (mData.containsKey(key)) {
+                return (String) mData.get(key);
+            }
+        }
+        return defValue;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public Set<String> getStringSet(String key, Set<String> defValues) {
+        synchronized (mData) {
+            if (mData.containsKey(key)) {
+                return Collections.unmodifiableSet((Set<String>) mData.get(key));
+            }
+        }
+        return defValues;
+    }
+
+    @Override
+    public int getInt(String key, int defValue) {
+        synchronized (mData) {
+            if (mData.containsKey(key)) {
+                return (Integer) mData.get(key);
+            }
+        }
+        return defValue;
+    }
+
+    @Override
+    public long getLong(String key, long defValue) {
+        synchronized (mData) {
+            if (mData.containsKey(key)) {
+                return (Long) mData.get(key);
+            }
+        }
+        return defValue;
+    }
+
+    @Override
+    public float getFloat(String key, float defValue) {
+        synchronized (mData) {
+            if (mData.containsKey(key)) {
+                return (Float) mData.get(key);
+            }
+        }
+        return defValue;
+    }
+
+    @Override
+    public boolean getBoolean(String key, boolean defValue) {
+        synchronized (mData) {
+            if (mData.containsKey(key)) {
+                return (Boolean) mData.get(key);
+            }
+        }
+        return defValue;
+    }
+
+    @Override
+    public boolean contains(String key) {
+        synchronized (mData) {
+            return mData.containsKey(key);
+        }
+    }
+
+    @Override
+    public SharedPreferences.Editor edit() {
+        return new InMemoryEditor();
+    }
+
+    @Override
+    public void registerOnSharedPreferenceChangeListener(
+            SharedPreferences.OnSharedPreferenceChangeListener
+                    listener) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void unregisterOnSharedPreferenceChangeListener(
+            SharedPreferences.OnSharedPreferenceChangeListener listener) {
+        throw new UnsupportedOperationException();
+    }
+
+    private class InMemoryEditor implements SharedPreferences.Editor {
+
+        // All guarded by |mChanges|
+        private boolean mClearCalled;
+        private volatile boolean mApplyCalled;
+        private final Map<String, Object> mChanges = new HashMap<String, Object>();
+
+        @Override
+        public SharedPreferences.Editor putString(String key, String value) {
+            synchronized (mChanges) {
+                if (mApplyCalled) throw new IllegalStateException();
+                mChanges.put(key, value);
+                return this;
+            }
+        }
+
+        @Override
+        public SharedPreferences.Editor putStringSet(String key, Set<String> values) {
+            synchronized (mChanges) {
+                if (mApplyCalled) throw new IllegalStateException();
+                mChanges.put(key, values);
+                return this;
+            }
+        }
+
+        @Override
+        public SharedPreferences.Editor putInt(String key, int value) {
+            synchronized (mChanges) {
+                if (mApplyCalled) throw new IllegalStateException();
+                mChanges.put(key, value);
+                return this;
+            }
+        }
+
+        @Override
+        public SharedPreferences.Editor putLong(String key, long value) {
+            synchronized (mChanges) {
+                if (mApplyCalled) throw new IllegalStateException();
+                mChanges.put(key, value);
+                return this;
+            }
+        }
+
+        @Override
+        public SharedPreferences.Editor putFloat(String key, float value) {
+            synchronized (mChanges) {
+                if (mApplyCalled) throw new IllegalStateException();
+                mChanges.put(key, value);
+                return this;
+            }
+        }
+
+        @Override
+        public SharedPreferences.Editor putBoolean(String key, boolean value) {
+            synchronized (mChanges) {
+                if (mApplyCalled) throw new IllegalStateException();
+                mChanges.put(key, value);
+                return this;
+            }
+        }
+
+        @Override
+        public SharedPreferences.Editor remove(String key) {
+            synchronized (mChanges) {
+                if (mApplyCalled) throw new IllegalStateException();
+                // Magic value for removes
+                mChanges.put(key, this);
+                return this;
+            }
+        }
+
+        @Override
+        public SharedPreferences.Editor clear() {
+            synchronized (mChanges) {
+                if (mApplyCalled) throw new IllegalStateException();
+                mClearCalled = true;
+                return this;
+            }
+        }
+
+        @Override
+        public boolean commit() {
+            apply();
+            return true;
+        }
+
+        @Override
+        public void apply() {
+            synchronized (mData) {
+                synchronized (mChanges) {
+                    if (mApplyCalled) throw new IllegalStateException();
+                    if (mClearCalled) {
+                        mData.clear();
+                    }
+                    for (Map.Entry<String, Object> entry : mChanges.entrySet()) {
+                        String key = entry.getKey();
+                        Object value = entry.getValue();
+                        if (value == this) {
+                            // Special value for removal
+                            mData.remove(key);
+                        } else {
+                            mData.put(key, value);
+                        }
+                    }
+                    // The real shared prefs clears out the temporaries allowing the caller to
+                    // reuse the Editor instance, however this is undocumented behavior and subtle
+                    // to read, so instead we just ban any future use of this instance.
+                    mApplyCalled = true;
+                }
+            }
+        }
+    }
+
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/InstrumentationUtils.java b/base/test/android/javatests/src/org/chromium/base/test/util/InstrumentationUtils.java
new file mode 100644
index 0000000..20cfd9d
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/InstrumentationUtils.java
@@ -0,0 +1,32 @@
+// Copyright 2012 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.test.util;
+
+import android.app.Instrumentation;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.FutureTask;
+
+/**
+ * Utility methods built around the android.app.Instrumentation class.
+ */
+public final class InstrumentationUtils {
+
+    private InstrumentationUtils() {
+    }
+
+    public static <R> R runOnMainSyncAndGetResult(Instrumentation instrumentation,
+            Callable<R> callable) throws Throwable {
+        FutureTask<R> task = new FutureTask<R>(callable);
+        instrumentation.runOnMainSync(task);
+        try {
+            return task.get();
+        } catch (ExecutionException e) {
+            // Unwrap the cause of the exception and re-throw it.
+            throw e.getCause();
+        }
+    }
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/IntegrationTest.java b/base/test/android/javatests/src/org/chromium/base/test/util/IntegrationTest.java
new file mode 100644
index 0000000..8b6550d
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/IntegrationTest.java
@@ -0,0 +1,26 @@
+// 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.test.util;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation is for integration tests.
+ * <p>
+ * Examples of integration tests are tests that rely on real instances of the
+ * application's services and components (e.g. Search) to test the system as
+ * a whole. These tests may use additional command-line flags to configure the
+ * existing backends to use.
+ * <p>
+ * Such tests are likely NOT reliable enough to run on tree closing bots and
+ * should only be run on FYI bots.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface IntegrationTest {
+}
\ No newline at end of file
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/Manual.java b/base/test/android/javatests/src/org/chromium/base/test/util/Manual.java
new file mode 100644
index 0000000..31f3977
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/Manual.java
@@ -0,0 +1,21 @@
+// Copyright 2012 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.test.util;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation can be used to mark a test that should only be run manually.
+ * <p>
+ * Tests with this annotation will not be run on bots, because they take too long
+ * or need manual monitoring.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Manual {
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/MetricsUtils.java b/base/test/android/javatests/src/org/chromium/base/test/util/MetricsUtils.java
new file mode 100644
index 0000000..c4664d6
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/MetricsUtils.java
@@ -0,0 +1,43 @@
+// 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.test.util;
+
+import org.chromium.base.metrics.RecordHistogram;
+
+/**
+ * Helpers for testing UMA metrics.
+ */
+public class MetricsUtils {
+    /**
+     * Helper class that snapshots the given bucket of the given UMA histogram on its creation,
+     * allowing to inspect the number of samples recorded during its lifetime.
+     */
+    public static class HistogramDelta {
+        private final String mHistogram;
+        private final int mSampleValue;
+
+        private final int mInitialCount;
+
+        private int get() {
+            return RecordHistogram.getHistogramValueCountForTesting(mHistogram, mSampleValue);
+        }
+
+        /**
+         * Snapshots the given bucket of the given histogram.
+         * @param histogram name of the histogram to snapshot
+         * @param sampleValue the bucket that contains this value will be snapshot
+         */
+        public HistogramDelta(String histogram, int sampleValue) {
+            mHistogram = histogram;
+            mSampleValue = sampleValue;
+            mInitialCount = get();
+        }
+
+        /** Returns the number of samples of the snapshot bucket recorded since creation */
+        public int getDelta() {
+            return get() - mInitialCount;
+        }
+    }
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/MinAndroidSdkLevel.java b/base/test/android/javatests/src/org/chromium/base/test/util/MinAndroidSdkLevel.java
new file mode 100644
index 0000000..d7c45e7
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/MinAndroidSdkLevel.java
@@ -0,0 +1,19 @@
+// 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.test.util;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Inherited
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE})
+public @interface MinAndroidSdkLevel {
+    int value() default 0;
+}
+
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/PerfTest.java b/base/test/android/javatests/src/org/chromium/base/test/util/PerfTest.java
new file mode 100644
index 0000000..9b3495c
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/PerfTest.java
@@ -0,0 +1,88 @@
+// 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.test.util;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation tells the test harness that this method will be used in a performance test.
+ * This means that the test harness will use the parameters here to figure out which trace calls
+ * to track specifically for this test.
+ * <p>
+ * Each of the lists ({@link #traceNames()}, {@link #graphNames()},
+ * and {@link #seriesNames()}) should have the same number of
+ * elements.
+ * <p>
+ * To write a performance test, you need to do the following:
+ * <p><ol>
+ * <li>Add TraceEvent calls to the code that you want to track.
+ *   <ul>
+ *   <li> For FPS, add a TraceEvent.instant call where you want to time and detect calls.
+ *   <li> For code segment timing, add {@link org.chromium.base.TraceEvent#begin()}/
+ * {@link org.chromium.base.TraceEvent#end()} calls around the code
+ * segment (does not have to be in the same method).
+ *   </ul>
+ * <li> Write a Java Automated UI Test that instruments this code.
+ * <li> Add this PerfTest annotation to the test method.
+ *   <ul>
+ *   <li> traceNames must be a list of the names of all of the TraceEvent calls you want to track.
+ *   <li> graphNames must be a list, one for each traceName, of which graph the trace data should be
+ *   placed in (does not have to be unique).
+ *   <li> seriesNames must be a list, one for each traceName, of what the series should be called
+ *   for this trace data (has to be unique per graphName).
+ * <li> When checked in, the buildbots will automatically run this test and the results will show up
+ * under the Java Automation UI Performance graph, where there will be tabs for each graphName
+ * specified.
+ * <li> To test your performance test, run the following command and you should see the performance
+ * numbers printed to the console.
+ * </ol>
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD})
+public @interface PerfTest {
+    /**
+     * @return A list of the trace calls to track.
+     */
+    public String[] traceNames();
+
+    /**
+     * @return A list, one for each traceName, that represents which graph this trace call should
+     *         be output on.  This does not have to be unique if there are multiple series per
+     *         graph.
+     */
+    public String[] graphNames();
+
+    /**
+     * @return A list, one for each traceName, that represents the series this trace call should be
+     *         on the corresponding graph.  This should be unique.
+     */
+    public String[] seriesNames();
+
+    /**
+     * @return Whether or not we should automatically start and stop tracing for the test.  This
+     *         makes it easier to run some tests where tracing is started and stopped at the
+     *         beginning and end of that particular test.
+     */
+    public boolean autoTrace() default false;
+
+    /**
+     * @return Whether this performance test should track memory usage in addition to time.  If
+     *         true, this will track memory usage when tracking time deltas or instants.  With each
+     *         graph defined in the annotation for tracking time, this will add an additional graph
+     *         suffixed with a memory identifier containing the same series as those tracking the
+     *         timing performance but instead will be tracking memory consumption.
+     */
+    public boolean traceMemory() default true;
+
+    /**
+     * @return Whether this performance test should track time or (optionally) only memory.  If
+     *         false, this will not automatically track time deltas or instants when logging
+     *         memory info.
+     */
+    public boolean traceTiming() default true;
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/Restriction.java b/base/test/android/javatests/src/org/chromium/base/test/util/Restriction.java
new file mode 100644
index 0000000..11026ef
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/Restriction.java
@@ -0,0 +1,37 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.test.util;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * An annotation for listing restrictions for a test method. For example, if a test method is only
+ * applicable on a phone with small memory:
+ *     @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_SMALL_MEMORY})
+ * Test classes are free to define restrictions and enforce them using reflection at runtime.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Restriction {
+    /** Specifies the test is only valid on phone form factors. */
+    public static final String RESTRICTION_TYPE_PHONE = "Phone";
+
+    /** Specifies the test is only valid on tablet form factors. */
+    public static final String RESTRICTION_TYPE_TABLET = "Tablet";
+
+    /** Specifies the test is only valid on low end devices that have less memory. */
+    public static final String RESTRICTION_TYPE_LOW_END_DEVICE = "Low_End_Device";
+
+    /** Specifies the test is only valid on non-low end devices. */
+    public static final String RESTRICTION_TYPE_NON_LOW_END_DEVICE = "Non_Low_End_Device";
+
+    /**
+     * @return A list of restrictions.
+     */
+    public String[] value();
+}
\ No newline at end of file
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/ScalableTimeout.java b/base/test/android/javatests/src/org/chromium/base/test/util/ScalableTimeout.java
new file mode 100644
index 0000000..c21bff9
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/ScalableTimeout.java
@@ -0,0 +1,28 @@
+// Copyright 2012 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.test.util;
+
+/**
+ * Utility class for scaling various timeouts by a common factor.
+ * For example, to run tests under Valgrind, you might want the following:
+ *   adb shell "echo 20.0 > /data/local/tmp/chrome_timeout_scale"
+ */
+public class ScalableTimeout {
+    private static Double sTimeoutScale = null;
+    private static final String PROPERTY_FILE = "/data/local/tmp/chrome_timeout_scale";
+
+    public static long scaleTimeout(long timeout) {
+        if (sTimeoutScale == null) {
+            try {
+                char[] data = TestFileUtil.readUtf8File(PROPERTY_FILE, 32);
+                sTimeoutScale = Double.parseDouble(new String(data));
+            } catch (Exception e) {
+                // NumberFormatException, FileNotFoundException, IOException
+                sTimeoutScale = 1.0;
+            }
+        }
+        return (long) (timeout * sTimeoutScale);
+    }
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/TestFileUtil.java b/base/test/android/javatests/src/org/chromium/base/test/util/TestFileUtil.java
new file mode 100644
index 0000000..8765def
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/TestFileUtil.java
@@ -0,0 +1,78 @@
+// Copyright 2012 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.test.util;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.util.Arrays;
+
+/**
+ * Utility class for dealing with files for test.
+ */
+public class TestFileUtil {
+    public static void createNewHtmlFile(String name, String title, String body)
+            throws IOException {
+        File file = new File(name);
+        if (!file.createNewFile()) {
+            throw new IOException("File \"" + name + "\" already exists");
+        }
+
+        Writer writer = null;
+        try {
+            writer = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");
+            writer.write("<html><meta charset=\"UTF-8\" />"
+                    + "     <head><title>" + title + "</title></head>"
+                    + "     <body>"
+                    + (body != null ? body : "")
+                    + "     </body>"
+                    + "   </html>");
+        } finally {
+            if (writer != null) {
+                writer.close();
+            }
+        }
+    }
+
+    public static void deleteFile(String name) {
+        File file = new File(name);
+        boolean deleted = file.delete();
+        assert (deleted || !file.exists());
+    }
+
+    /**
+     * @param fileName the file to read in.
+     * @param sizeLimit cap on the file size: will throw an exception if exceeded
+     * @return Array of chars read from the file
+     * @throws FileNotFoundException file does not exceed
+     * @throws IOException error encountered accessing the file
+     */
+    public static char[] readUtf8File(String fileName, int sizeLimit) throws
+            FileNotFoundException, IOException {
+        Reader reader = null;
+        try {
+            File f = new File(fileName);
+            if (f.length() > sizeLimit) {
+                throw new IOException("File " + fileName + " length " + f.length()
+                        + " exceeds limit " + sizeLimit);
+            }
+            char[] buffer = new char[(int) f.length()];
+            reader = new InputStreamReader(new FileInputStream(f), "UTF-8");
+            int charsRead = reader.read(buffer);
+            // Debug check that we've exhausted the input stream (will fail e.g. if the
+            // file grew after we inspected its length).
+            assert !reader.ready();
+            return charsRead < buffer.length ? Arrays.copyOfRange(buffer, 0, charsRead) : buffer;
+        } finally {
+            if (reader != null) reader.close();
+        }
+    }
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/TestThread.java b/base/test/android/javatests/src/org/chromium/base/test/util/TestThread.java
new file mode 100644
index 0000000..93c23f7
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/TestThread.java
@@ -0,0 +1,143 @@
+// Copyright 2012 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.test.util;
+
+import android.os.Handler;
+import android.os.Looper;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * This class is usefull when writing instrumentation tests that exercise code that posts tasks
+ * (to the same thread).
+ * Since the test code is run in a single thread, the posted tasks are never executed.
+ * The TestThread class lets you run that code on a specific thread synchronously and flush the
+ * message loop on that thread.
+ *
+ * Example of test using this:
+ *
+ * public void testMyAwesomeClass() {
+ *   TestThread testThread = new TestThread();
+ *   testThread.startAndWaitForReadyState();
+ *
+ *   testThread.runOnTestThreadSyncAndProcessPendingTasks(new Runnable() {
+ *       @Override
+ *       public void run() {
+ *           MyAwesomeClass.doStuffAsync();
+ *       }
+ *   });
+ *   // Once we get there we know doStuffAsync has been executed and all the tasks it posted.
+ *   assertTrue(MyAwesomeClass.stuffWasDone());
+ * }
+ *
+ * Notes:
+ * - this is only for tasks posted to the same thread. Anyway if you were posting to a different
+ *   thread, you'd probably need to set that other thread up.
+ * - this only supports tasks posted using Handler.post(), it won't work with postDelayed and
+ *   postAtTime.
+ * - if your test instanciates an object and that object is the one doing the posting of tasks, you
+ *   probably want to instanciate it on the test thread as it might create the Handler it posts
+ *   tasks to in the constructor.
+ */
+
+public class TestThread extends Thread {
+    private Object mThreadReadyLock;
+    private AtomicBoolean mThreadReady;
+    private Handler mMainThreadHandler;
+    private Handler mTestThreadHandler;
+
+    public TestThread() {
+        mMainThreadHandler = new Handler();
+        // We can't use the AtomicBoolean as the lock or findbugs will freak out...
+        mThreadReadyLock = new Object();
+        mThreadReady = new AtomicBoolean();
+    }
+
+    @Override
+    public void run() {
+        Looper.prepare();
+        mTestThreadHandler = new Handler();
+        mTestThreadHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                synchronized (mThreadReadyLock) {
+                    mThreadReady.set(true);
+                    mThreadReadyLock.notify();
+                }
+            }
+        });
+        Looper.loop();
+    }
+
+    /**
+     * Starts this TestThread and blocks until it's ready to accept calls.
+     */
+    public void startAndWaitForReadyState() {
+        checkOnMainThread();
+        start();
+        synchronized (mThreadReadyLock) {
+            try {
+                // Note the mThreadReady and while are not really needed.
+                // There are there so findbugs don't report warnings.
+                while (!mThreadReady.get()) {
+                    mThreadReadyLock.wait();
+                }
+            } catch (InterruptedException ie) {
+                System.err.println("Error starting TestThread.");
+                ie.printStackTrace();
+            }
+        }
+    }
+
+    /**
+     * Runs the passed Runnable synchronously on the TestThread and returns when all pending
+     * runnables have been excuted.
+     * Should be called from the main thread.
+     */
+    public void runOnTestThreadSyncAndProcessPendingTasks(Runnable r) {
+        checkOnMainThread();
+
+        runOnTestThreadSync(r);
+
+        // Run another task, when it's done it means all pendings tasks have executed.
+        runOnTestThreadSync(null);
+    }
+
+    /**
+     * Runs the passed Runnable on the test thread and blocks until it has finished executing.
+     * Should be called from the main thread.
+     * @param r The runnable to be executed.
+     */
+    public void runOnTestThreadSync(final Runnable r) {
+        checkOnMainThread();
+        final Object lock = new Object();
+        // Task executed is not really needed since we are only on one thread, it is here to appease
+        // findbugs.
+        final AtomicBoolean taskExecuted = new AtomicBoolean();
+        mTestThreadHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                if (r != null) r.run();
+                synchronized (lock) {
+                    taskExecuted.set(true);
+                    lock.notify();
+                }
+            }
+        });
+        synchronized (lock) {
+            try {
+                while (!taskExecuted.get()) {
+                    lock.wait();
+                }
+            } catch (InterruptedException ie) {
+                ie.printStackTrace();
+            }
+        }
+    }
+
+    private void checkOnMainThread() {
+        assert Looper.myLooper() == mMainThreadHandler.getLooper();
+    }
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/TimeoutScale.java b/base/test/android/javatests/src/org/chromium/base/test/util/TimeoutScale.java
new file mode 100644
index 0000000..5aee05e
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/TimeoutScale.java
@@ -0,0 +1,22 @@
+// Copyright 2012 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.test.util;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation can be used to scale a specific test timeout.
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface TimeoutScale {
+    /**
+     * @return A number to scale the test timeout.
+     */
+    public int value();
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/UrlUtils.java b/base/test/android/javatests/src/org/chromium/base/test/util/UrlUtils.java
new file mode 100644
index 0000000..797585f
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/UrlUtils.java
@@ -0,0 +1,73 @@
+// Copyright 2012 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.test.util;
+
+import junit.framework.Assert;
+
+import org.chromium.base.PathUtils;
+
+/**
+ * Collection of URL utilities.
+ */
+public class UrlUtils {
+    private static final String DATA_DIR = "/chrome/test/data/";
+
+    /**
+     * Construct the full path of a test data file.
+     * @param path Pathname relative to external/chrome/test/data
+     */
+    public static String getTestFilePath(String path) {
+        // TODO(jbudorick): Remove DATA_DIR once everything has been isolated. crbug/400499
+        return PathUtils.getExternalStorageDirectory() + DATA_DIR + path;
+    }
+
+    // TODO(jbudorick): Remove this function once everything has been isolated and switched back
+    // to getTestFilePath. crbug/400499
+    /**
+     * Construct the full path of a test data file.
+     * @param path Pathname relative to external/
+     */
+    public static String getIsolatedTestFilePath(String path) {
+        return PathUtils.getExternalStorageDirectory() + "/" + path;
+    }
+
+    /**
+     * Construct a suitable URL for loading a test data file.
+     * @param path Pathname relative to external/chrome/test/data
+     */
+    public static String getTestFileUrl(String path) {
+        return "file://" + getTestFilePath(path);
+    }
+
+    // TODO(jbudorick): Remove this function once everything has been isolated and switched back
+    // to getTestFileUrl. crbug/400499
+    /**
+     * Construct a suitable URL for loading a test data file.
+     * @param path Pathname relative to external/
+     */
+    public static String getIsolatedTestFileUrl(String path) {
+        return "file://" + getIsolatedTestFilePath(path);
+    }
+
+    /**
+     * Construct a data:text/html URI for loading from an inline HTML.
+     * @param html An unencoded HTML
+     * @return String An URI that contains the given HTML
+     */
+    public static String encodeHtmlDataUri(String html) {
+        try {
+            // URLEncoder encodes into application/x-www-form-encoded, so
+            // ' '->'+' needs to be undone and replaced with ' '->'%20'
+            // to match the Data URI requirements.
+            String encoded =
+                    "data:text/html;utf-8," + java.net.URLEncoder.encode(html, "UTF-8");
+            encoded = encoded.replace("+", "%20");
+            return encoded;
+        } catch (java.io.UnsupportedEncodingException e) {
+            Assert.fail("Unsupported encoding: " + e.getMessage());
+            return null;
+        }
+    }
+}
diff --git a/base/test/data/file_util/binary_file.bin b/base/test/data/file_util/binary_file.bin
new file mode 100644
index 0000000..f53cc82
--- /dev/null
+++ b/base/test/data/file_util/binary_file.bin
Binary files differ
diff --git a/base/test/data/file_util/binary_file_diff.bin b/base/test/data/file_util/binary_file_diff.bin
new file mode 100644
index 0000000..103b26d
--- /dev/null
+++ b/base/test/data/file_util/binary_file_diff.bin
Binary files differ
diff --git a/base/test/data/file_util/binary_file_same.bin b/base/test/data/file_util/binary_file_same.bin
new file mode 100644
index 0000000..f53cc82
--- /dev/null
+++ b/base/test/data/file_util/binary_file_same.bin
Binary files differ
diff --git a/base/test/data/file_util/blank_line.txt b/base/test/data/file_util/blank_line.txt
new file mode 100644
index 0000000..8892069
--- /dev/null
+++ b/base/test/data/file_util/blank_line.txt
@@ -0,0 +1,3 @@
+The next line is blank.
+
+But this one isn't.
diff --git a/base/test/data/file_util/blank_line_crlf.txt b/base/test/data/file_util/blank_line_crlf.txt
new file mode 100644
index 0000000..3aefe52
--- /dev/null
+++ b/base/test/data/file_util/blank_line_crlf.txt
@@ -0,0 +1,3 @@
+The next line is blank.

+

+But this one isn't.

diff --git a/base/test/data/file_util/crlf.txt b/base/test/data/file_util/crlf.txt
new file mode 100644
index 0000000..0e62728
--- /dev/null
+++ b/base/test/data/file_util/crlf.txt
@@ -0,0 +1 @@
+This file is the same.

diff --git a/base/test/data/file_util/different.txt b/base/test/data/file_util/different.txt
new file mode 100644
index 0000000..5b9f9c4
--- /dev/null
+++ b/base/test/data/file_util/different.txt
@@ -0,0 +1 @@
+This file is different.
diff --git a/base/test/data/file_util/different_first.txt b/base/test/data/file_util/different_first.txt
new file mode 100644
index 0000000..8661d66
--- /dev/null
+++ b/base/test/data/file_util/different_first.txt
@@ -0,0 +1 @@
+this file is the same.
diff --git a/base/test/data/file_util/different_last.txt b/base/test/data/file_util/different_last.txt
new file mode 100644
index 0000000..e8b3e5a
--- /dev/null
+++ b/base/test/data/file_util/different_last.txt
@@ -0,0 +1 @@
+This file is the same. 
\ No newline at end of file
diff --git a/base/test/data/file_util/empty1.txt b/base/test/data/file_util/empty1.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/base/test/data/file_util/empty1.txt
diff --git a/base/test/data/file_util/empty2.txt b/base/test/data/file_util/empty2.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/base/test/data/file_util/empty2.txt
diff --git a/base/test/data/file_util/first1.txt b/base/test/data/file_util/first1.txt
new file mode 100644
index 0000000..2c6e300
--- /dev/null
+++ b/base/test/data/file_util/first1.txt
@@ -0,0 +1,2 @@
+The first line is the same.
+The second line is different.
diff --git a/base/test/data/file_util/first2.txt b/base/test/data/file_util/first2.txt
new file mode 100644
index 0000000..e39b5ec
--- /dev/null
+++ b/base/test/data/file_util/first2.txt
@@ -0,0 +1,2 @@
+The first line is the same.
+The second line is not.
diff --git a/base/test/data/file_util/original.txt b/base/test/data/file_util/original.txt
new file mode 100644
index 0000000..4422f57
--- /dev/null
+++ b/base/test/data/file_util/original.txt
@@ -0,0 +1 @@
+This file is the same.
diff --git a/base/test/data/file_util/red.png b/base/test/data/file_util/red.png
new file mode 100644
index 0000000..0806141
--- /dev/null
+++ b/base/test/data/file_util/red.png
Binary files differ
diff --git a/base/test/data/file_util/same.txt b/base/test/data/file_util/same.txt
new file mode 100644
index 0000000..4422f57
--- /dev/null
+++ b/base/test/data/file_util/same.txt
@@ -0,0 +1 @@
+This file is the same.
diff --git a/base/test/data/file_util/same_length.txt b/base/test/data/file_util/same_length.txt
new file mode 100644
index 0000000..157405c
--- /dev/null
+++ b/base/test/data/file_util/same_length.txt
@@ -0,0 +1 @@
+This file is not same.
diff --git a/base/test/data/file_util/shortened.txt b/base/test/data/file_util/shortened.txt
new file mode 100644
index 0000000..2bee82c
--- /dev/null
+++ b/base/test/data/file_util/shortened.txt
@@ -0,0 +1 @@
+This file is the
\ No newline at end of file
diff --git a/base/test/data/file_version_info_unittest/FileVersionInfoTest1.dll b/base/test/data/file_version_info_unittest/FileVersionInfoTest1.dll
new file mode 100755
index 0000000..bdf8dc0
--- /dev/null
+++ b/base/test/data/file_version_info_unittest/FileVersionInfoTest1.dll
Binary files differ
diff --git a/base/test/data/file_version_info_unittest/FileVersionInfoTest2.dll b/base/test/data/file_version_info_unittest/FileVersionInfoTest2.dll
new file mode 100755
index 0000000..51e7966
--- /dev/null
+++ b/base/test/data/file_version_info_unittest/FileVersionInfoTest2.dll
Binary files differ
diff --git a/base/test/data/json/bom_feff.json b/base/test/data/json/bom_feff.json
new file mode 100644
index 0000000..b05ae50
--- /dev/null
+++ b/base/test/data/json/bom_feff.json
@@ -0,0 +1,10 @@
+{

+  "appName": {

+    "message": "Gmail",

+    "description": "App name."

+  },

+  "appDesc": {

+    "message": "بريد إلكتروني يوفر إمكانية البحث مع مقدار أقل من الرسائل غير المرغوب فيها.", 

+    "description":"App description."

+  }

+}
\ No newline at end of file
diff --git a/base/test/data/pe_image/pe_image_test_32.dll b/base/test/data/pe_image/pe_image_test_32.dll
new file mode 100755
index 0000000..118ce11
--- /dev/null
+++ b/base/test/data/pe_image/pe_image_test_32.dll
Binary files differ
diff --git a/base/test/data/pe_image/pe_image_test_64.dll b/base/test/data/pe_image/pe_image_test_64.dll
new file mode 100755
index 0000000..70f8ea4
--- /dev/null
+++ b/base/test/data/pe_image/pe_image_test_64.dll
Binary files differ
diff --git a/base/test/data/prefs/invalid.json b/base/test/data/prefs/invalid.json
new file mode 100644
index 0000000..43392a9
--- /dev/null
+++ b/base/test/data/prefs/invalid.json
@@ -0,0 +1 @@
+!@#$%^&
\ No newline at end of file
diff --git a/base/test/data/prefs/read.json b/base/test/data/prefs/read.json
new file mode 100644
index 0000000..ea578a4
--- /dev/null
+++ b/base/test/data/prefs/read.json
@@ -0,0 +1,8 @@
+{
+  "homepage": "http://www.cnn.com",
+  "some_directory": "/usr/local/",
+  "tabs": {
+    "new_windows_in_tabs": true,
+    "max_tabs": 20
+  }
+}
diff --git a/base/test/data/prefs/write.golden.json b/base/test/data/prefs/write.golden.json
new file mode 100644
index 0000000..fb1fff1
--- /dev/null
+++ b/base/test/data/prefs/write.golden.json
@@ -0,0 +1 @@
+{"homepage":"http://www.cnn.com","long_int":{"pref":"214748364842"},"some_directory":"/usr/sbin/","tabs":{"max_tabs":10,"new_windows_in_tabs":false}}
\ No newline at end of file
diff --git a/base/test/data/serializer_nested_test.json b/base/test/data/serializer_nested_test.json
new file mode 100644
index 0000000..cfea8e8
--- /dev/null
+++ b/base/test/data/serializer_nested_test.json
@@ -0,0 +1,17 @@
+{
+   "bool": true,
+   "dict": {
+      "bool": true,
+      "dict": {
+         "bees": "knees",
+         "cats": "meow"
+      },
+      "foos": "bar",
+      "list": [ 3.4, "second", null ]
+   },
+   "int": 42,
+   "list": [ 1, 2 ],
+   "null": null,
+   "real": 3.14,
+   "string": "hello"
+}
diff --git a/base/test/data/serializer_test.json b/base/test/data/serializer_test.json
new file mode 100644
index 0000000..446925e
--- /dev/null
+++ b/base/test/data/serializer_test.json
@@ -0,0 +1,8 @@
+{
+   "bool": true,
+   "int": 42,
+   "list": [ 1, 2 ],
+   "null": null,
+   "real": 3.14,
+   "string": "hello"
+}
diff --git a/base/test/data/serializer_test_nowhitespace.json b/base/test/data/serializer_test_nowhitespace.json
new file mode 100644
index 0000000..a1afdc5
--- /dev/null
+++ b/base/test/data/serializer_test_nowhitespace.json
@@ -0,0 +1 @@
+{"bool":true,"int":42,"list":[1,2],"null":null,"real":3.14,"string":"hello"}
\ No newline at end of file
diff --git a/base/test/expectations/OWNERS b/base/test/expectations/OWNERS
new file mode 100644
index 0000000..14fce2a
--- /dev/null
+++ b/base/test/expectations/OWNERS
@@ -0,0 +1 @@
+rsesek@chromium.org
diff --git a/base/test/expectations/expectation.cc b/base/test/expectations/expectation.cc
new file mode 100644
index 0000000..3081779
--- /dev/null
+++ b/base/test/expectations/expectation.cc
@@ -0,0 +1,161 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/expectations/expectation.h"
+
+#include "base/logging.h"
+
+#if defined(OS_WIN)
+#include "base/win/windows_version.h"
+#elif defined(OS_MACOSX) && !defined(OS_IOS)
+#include "base/mac/mac_util.h"
+#elif defined(OS_LINUX)
+#include "base/sys_info.h"
+#endif
+
+namespace test_expectations {
+
+bool ResultFromString(const base::StringPiece& result, Result* out_result) {
+  if (result == "Failure")
+    *out_result = RESULT_FAILURE;
+  else if (result == "Timeout")
+    *out_result = RESULT_TIMEOUT;
+  else if (result == "Crash")
+    *out_result = RESULT_CRASH;
+  else if (result == "Skip")
+    *out_result = RESULT_SKIP;
+  else if (result == "Pass")
+    *out_result = RESULT_PASS;
+  else
+    return false;
+
+  return true;
+}
+
+static bool IsValidPlatform(const Platform* platform) {
+  const std::string& name = platform->name;
+  const std::string& variant = platform->variant;
+
+  if (name == "Win") {
+    if (!variant.empty() &&
+        variant != "XP" &&
+        variant != "Vista" &&
+        variant != "7" &&
+        variant != "8") {
+      return false;
+    }
+  } else if (name == "Mac") {
+    if (!variant.empty() &&
+        variant != "10.6" &&
+        variant != "10.7" &&
+        variant != "10.8" &&
+        variant != "10.9" &&
+        variant != "10.10") {
+      return false;
+    }
+  } else if (name == "Linux") {
+    if (!variant.empty() &&
+        variant != "32" &&
+        variant != "64") {
+      return false;
+    }
+  } else if (name == "ChromeOS") {
+    // TODO(rsesek): Figure out what ChromeOS needs.
+  } else if (name == "iOS") {
+    // TODO(rsesek): Figure out what iOS needs. Probably Device and Simulator.
+  } else if (name == "Android") {
+    // TODO(rsesek): Figure out what Android needs.
+  } else {
+    return false;
+  }
+
+  return true;
+}
+
+bool PlatformFromString(const base::StringPiece& modifier,
+                        Platform* out_platform) {
+  size_t sep = modifier.find('-');
+  if (sep == std::string::npos) {
+    out_platform->name = modifier.as_string();
+    out_platform->variant.clear();
+  } else {
+    out_platform->name = modifier.substr(0, sep).as_string();
+    out_platform->variant = modifier.substr(sep + 1).as_string();
+  }
+
+  return IsValidPlatform(out_platform);
+}
+
+Platform GetCurrentPlatform() {
+  Platform platform;
+#if defined(OS_WIN)
+  platform.name = "Win";
+  base::win::Version version = base::win::GetVersion();
+  if (version == base::win::VERSION_XP)
+    platform.variant = "XP";
+  else if (version == base::win::VERSION_VISTA)
+    platform.variant = "Vista";
+  else if (version == base::win::VERSION_WIN7)
+    platform.variant = "7";
+  else if (version == base::win::VERSION_WIN8)
+    platform.variant = "8";
+#elif defined(OS_IOS)
+  platform.name = "iOS";
+#elif defined(OS_MACOSX)
+  platform.name = "Mac";
+  if (base::mac::IsOSSnowLeopard())
+    platform.variant = "10.6";
+  else if (base::mac::IsOSLion())
+    platform.variant = "10.7";
+  else if (base::mac::IsOSMountainLion())
+    platform.variant = "10.8";
+  else if (base::mac::IsOSMavericks())
+    platform.variant = "10.9";
+  else if (base::mac::IsOSYosemite())
+    platform.variant = "10.10";
+#elif defined(OS_CHROMEOS)
+  platform.name = "ChromeOS";
+#elif defined(OS_ANDROID)
+  platform.name = "Android";
+#elif defined(OS_LINUX)
+  platform.name = "Linux";
+  std::string arch = base::SysInfo::OperatingSystemArchitecture();
+  if (arch == "x86")
+    platform.variant = "32";
+  else if (arch == "x86_64")
+    platform.variant = "64";
+#else
+  NOTREACHED();
+#endif
+  return platform;
+}
+
+bool ConfigurationFromString(const base::StringPiece& modifier,
+                             Configuration* out_configuration) {
+  if (modifier == "Debug")
+    *out_configuration = CONFIGURATION_DEBUG;
+  else if (modifier == "Release")
+    *out_configuration = CONFIGURATION_RELEASE;
+  else
+    return false;
+
+  return true;
+}
+
+Configuration GetCurrentConfiguration() {
+#if NDEBUG
+  return CONFIGURATION_RELEASE;
+#else
+  return CONFIGURATION_DEBUG;
+#endif
+}
+
+Expectation::Expectation()
+    : configuration(CONFIGURATION_UNSPECIFIED),
+      result(RESULT_PASS) {
+}
+
+Expectation::~Expectation() {}
+
+}  // namespace test_expectations
diff --git a/base/test/expectations/expectation.h b/base/test/expectations/expectation.h
new file mode 100644
index 0000000..be5a9d7
--- /dev/null
+++ b/base/test/expectations/expectation.h
@@ -0,0 +1,94 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_EXPECTATIONS_EXPECTATION_H_
+#define BASE_TEST_EXPECTATIONS_EXPECTATION_H_
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/strings/string_piece.h"
+
+namespace test_expectations {
+
+// A Result is the expectation of a test's behavior.
+enum Result {
+  // The test has a failing assertion.
+  RESULT_FAILURE,
+
+  // The test does not complete within the test runner's alloted duration.
+  RESULT_TIMEOUT,
+
+  // The test crashes during the course of its execution.
+  RESULT_CRASH,
+
+  // The test should not be run ever.
+  RESULT_SKIP,
+
+  // The test passes, used to override a more general expectation.
+  RESULT_PASS,
+};
+
+// Converts a text string form of a |result| to its enum value, written to
+// |out_result|. Returns true on success and false on error.
+bool ResultFromString(const base::StringPiece& result,
+                      Result* out_result) WARN_UNUSED_RESULT;
+
+// A Platform stores information about the OS environment.
+struct Platform {
+  // The name of the platform. E.g., "Win", or "Mac".
+  std::string name;
+
+  // The variant of the platform, either an OS version like "XP" or "10.8", or
+  // "Device" or "Simulator" in the case of mobile.
+  std::string variant;
+};
+
+// Converts a text string |modifier| to a Platform struct, written to
+// |out_platform|. Returns true on success and false on failure.
+bool PlatformFromString(const base::StringPiece& modifier,
+                        Platform* out_platform) WARN_UNUSED_RESULT;
+
+// Returns the Platform for the currently running binary.
+Platform GetCurrentPlatform();
+
+// The build configuration.
+enum Configuration {
+  CONFIGURATION_UNSPECIFIED,
+  CONFIGURATION_DEBUG,
+  CONFIGURATION_RELEASE,
+};
+
+// Converts the |modifier| to a Configuration constant, writing the value to
+// |out_configuration|. Returns true on success or false on failure.
+bool ConfigurationFromString(const base::StringPiece& modifier,
+    Configuration* out_configuration) WARN_UNUSED_RESULT;
+
+// Returns the Configuration for the currently running binary.
+Configuration GetCurrentConfiguration();
+
+// An Expectation is records what the result for a given test name should be on
+// the specified platforms and configuration.
+struct Expectation {
+  Expectation();
+  ~Expectation();
+
+  // The name of the test, like FooBarTest.BarIsBaz.
+  std::string test_name;
+
+  // The set of platforms for which this expectation is applicable.
+  std::vector<Platform> platforms;
+
+  // The build configuration.
+  Configuration configuration;
+
+  // The expected result of this test.
+  Result result;
+};
+
+}  // namespace test_expectations
+
+#endif  // BASE_TEST_EXPECTATIONS_EXPECTATION_H_
diff --git a/base/test/expectations/expectation_unittest.cc b/base/test/expectations/expectation_unittest.cc
new file mode 100644
index 0000000..c0f55a1
--- /dev/null
+++ b/base/test/expectations/expectation_unittest.cc
@@ -0,0 +1,120 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/expectations/expectation.h"
+
+#include "base/basictypes.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(TestExpectationsFunctionsTest, ResultFromString) {
+  test_expectations::Result result = test_expectations::RESULT_PASS;
+
+  EXPECT_TRUE(ResultFromString("Failure", &result));
+  EXPECT_EQ(test_expectations::RESULT_FAILURE, result);
+
+  EXPECT_TRUE(ResultFromString("Timeout", &result));
+  EXPECT_EQ(test_expectations::RESULT_TIMEOUT, result);
+
+  EXPECT_TRUE(ResultFromString("Crash", &result));
+  EXPECT_EQ(test_expectations::RESULT_CRASH, result);
+
+  EXPECT_TRUE(ResultFromString("Skip", &result));
+  EXPECT_EQ(test_expectations::RESULT_SKIP, result);
+
+  EXPECT_TRUE(ResultFromString("Pass", &result));
+  EXPECT_EQ(test_expectations::RESULT_PASS, result);
+
+  // Case sensitive.
+  EXPECT_FALSE(ResultFromString("failure", &result));
+  EXPECT_EQ(test_expectations::RESULT_PASS, result);
+}
+
+TEST(TestExpectationsFunctionsTest, ConfigurationFromString) {
+  test_expectations::Configuration config =
+      test_expectations::CONFIGURATION_UNSPECIFIED;
+
+  EXPECT_TRUE(ConfigurationFromString("Debug", &config));
+  EXPECT_EQ(test_expectations::CONFIGURATION_DEBUG, config);
+
+  EXPECT_TRUE(ConfigurationFromString("Release", &config));
+  EXPECT_EQ(test_expectations::CONFIGURATION_RELEASE, config);
+
+  EXPECT_FALSE(ConfigurationFromString("NotAConfig", &config));
+  EXPECT_EQ(test_expectations::CONFIGURATION_RELEASE, config);
+
+  // Case sensitive.
+  EXPECT_FALSE(ConfigurationFromString("debug", &config));
+  EXPECT_EQ(test_expectations::CONFIGURATION_RELEASE, config);
+}
+
+TEST(TestExpectationsFunctionsTest, PlatformFromString) {
+  test_expectations::Platform platform;
+
+  EXPECT_TRUE(PlatformFromString("Win", &platform));
+  EXPECT_EQ("Win", platform.name);
+  EXPECT_EQ("", platform.variant);
+
+  EXPECT_TRUE(PlatformFromString("Mac-10.6", &platform));
+  EXPECT_EQ("Mac", platform.name);
+  EXPECT_EQ("10.6", platform.variant);
+
+  EXPECT_TRUE(PlatformFromString("ChromeOS", &platform));
+  EXPECT_EQ("ChromeOS", platform.name);
+  EXPECT_EQ("", platform.variant);
+
+  EXPECT_TRUE(PlatformFromString("Linux-", &platform));
+  EXPECT_EQ("Linux", platform.name);
+  EXPECT_EQ("", platform.variant);
+
+  EXPECT_FALSE(PlatformFromString("", &platform));
+}
+
+TEST(TestExpectationsFunctionsTest, IsValidPlatform) {
+  const char* const kValidPlatforms[] = {
+    "Win",
+    "Win-XP",
+    "Win-Vista",
+    "Win-7",
+    "Win-8",
+    "Mac",
+    "Mac-10.6",
+    "Mac-10.7",
+    "Mac-10.8",
+    "Linux",
+    "Linux-32",
+    "Linux-64",
+    "ChromeOS",
+    "iOS",
+    "Android",
+  };
+
+  const char* const kInvalidPlatforms[] = {
+    "Solaris",
+    "Plan9",
+  };
+
+  for (size_t i = 0; i < arraysize(kValidPlatforms); ++i) {
+    test_expectations::Platform platform;
+    EXPECT_TRUE(test_expectations::PlatformFromString(
+        kValidPlatforms[i], &platform)) << kValidPlatforms[i];
+  }
+
+  for (size_t i = 0; i < arraysize(kInvalidPlatforms); ++i) {
+    test_expectations::Platform platform;
+    EXPECT_FALSE(test_expectations::PlatformFromString(
+        kInvalidPlatforms[i], &platform)) << kInvalidPlatforms[i];
+  }
+}
+
+TEST(TestExpectationsFunctionsTest, CurrentPlatform) {
+  test_expectations::Platform current =
+      test_expectations::GetCurrentPlatform();
+  EXPECT_FALSE(current.name.empty());
+}
+
+TEST(TestExpectationsFunctionsTest, CurrentConfiguration) {
+  test_expectations::Configuration current =
+      test_expectations::GetCurrentConfiguration();
+  EXPECT_NE(test_expectations::CONFIGURATION_UNSPECIFIED, current);
+}
diff --git a/base/test/expectations/parser.cc b/base/test/expectations/parser.cc
new file mode 100644
index 0000000..c7132e5
--- /dev/null
+++ b/base/test/expectations/parser.cc
@@ -0,0 +1,201 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/expectations/parser.h"
+
+#include "base/strings/string_util.h"
+
+namespace test_expectations {
+
+Parser::Parser(Delegate* delegate, const std::string& input)
+    : delegate_(delegate),
+      input_(input),
+      pos_(NULL),
+      end_(NULL),
+      line_number_(0),
+      data_error_(false) {
+}
+
+Parser::~Parser() {
+}
+
+void Parser::Parse() {
+  pos_ = &input_[0];
+  end_ = pos_ + input_.length();
+
+  line_number_ = 1;
+
+  StateFuncPtr state = &Parser::Start;
+  while (state) {
+    state = (this->*state)();
+  }
+}
+
+inline bool Parser::HasNext() {
+  return pos_ < end_;
+}
+
+Parser::StateFunc Parser::Start() {
+  // If at the start of a line is whitespace, skip it and arrange to come back
+  // here.
+  if (IsAsciiWhitespace(*pos_))
+    return SkipWhitespaceAndNewLines(&Parser::Start);
+
+  // Handle comments at the start of lines.
+  if (*pos_ == '#')
+    return &Parser::ParseComment;
+
+  // After arranging to come back here from skipping whitespace and comments,
+  // the parser may be at the end of the input.
+  if (pos_ >= end_)
+    return NULL;
+
+  current_ = Expectation();
+  data_error_ = false;
+
+  return &Parser::ParseBugURL;
+}
+
+Parser::StateFunc Parser::ParseComment() {
+  if (*pos_ != '#')
+    return SyntaxError("Invalid start of comment");
+
+  do {
+    ++pos_;
+  } while (HasNext() && *pos_ != '\n');
+
+  return &Parser::Start;
+}
+
+Parser::StateFunc Parser::ParseBugURL() {
+  return SkipWhitespace(ExtractString(
+      &Parser::BeginModifiers));
+}
+
+Parser::StateFunc Parser::BeginModifiers() {
+  if (*pos_ != '[' || !HasNext())
+    return SyntaxError("Expected '[' for start of modifiers");
+
+  ++pos_;
+  return SkipWhitespace(&Parser::InModifiers);
+}
+
+Parser::StateFunc Parser::InModifiers() {
+  if (*pos_ == ']')
+    return &Parser::EndModifiers;
+
+  return ExtractString(SkipWhitespace(
+      &Parser::SaveModifier));
+}
+
+Parser::StateFunc Parser::SaveModifier() {
+  if (extracted_string_.empty())
+    return SyntaxError("Invalid modifier list");
+
+  Configuration config;
+  if (ConfigurationFromString(extracted_string_, &config)) {
+    if (current_.configuration != CONFIGURATION_UNSPECIFIED)
+      DataError("Cannot use more than one configuration modifier");
+    else
+      current_.configuration = config;
+  } else {
+    Platform platform;
+    if (PlatformFromString(extracted_string_, &platform))
+      current_.platforms.push_back(platform);
+    else
+      DataError("Invalid modifier string");
+  }
+
+  return SkipWhitespace(&Parser::InModifiers);
+}
+
+Parser::StateFunc Parser::EndModifiers() {
+ if (*pos_ != ']' || !HasNext())
+    return SyntaxError("Expected ']' for end of modifiers list");
+
+  ++pos_;
+  return SkipWhitespace(&Parser::ParseTestName);
+}
+
+Parser::StateFunc Parser::ParseTestName() {
+  return ExtractString(&Parser::SaveTestName);
+}
+
+Parser::StateFunc Parser::SaveTestName() {
+  if (extracted_string_.empty())
+    return SyntaxError("Invalid test name");
+
+  current_.test_name = extracted_string_.as_string();
+  return SkipWhitespace(&Parser::ParseExpectation);
+}
+
+Parser::StateFunc Parser::ParseExpectation() {
+  if (*pos_ != '=' || !HasNext())
+    return SyntaxError("Expected '=' for expectation result");
+
+  ++pos_;
+  return SkipWhitespace(&Parser::ParseExpectationType);
+}
+
+Parser::StateFunc Parser::ParseExpectationType() {
+  return ExtractString(&Parser::SaveExpectationType);
+}
+
+Parser::StateFunc Parser::SaveExpectationType() {
+  if (!ResultFromString(extracted_string_, &current_.result))
+    DataError("Unknown expectation type");
+
+  return SkipWhitespace(&Parser::End);
+}
+
+Parser::StateFunc Parser::End() {
+  if (!data_error_)
+    delegate_->EmitExpectation(current_);
+
+  if (HasNext())
+    return SkipWhitespaceAndNewLines(&Parser::Start);
+
+  return NULL;
+}
+
+Parser::StateFunc Parser::ExtractString(StateFunc success) {
+  const char* start = pos_;
+  while (!IsAsciiWhitespace(*pos_) && *pos_ != ']' && HasNext()) {
+    ++pos_;
+    if (*pos_ == '#') {
+      return SyntaxError("Unexpected start of comment");
+    }
+  }
+  extracted_string_ = base::StringPiece(start, pos_ - start);
+  return success;
+}
+
+Parser::StateFunc Parser::SkipWhitespace(Parser::StateFunc next) {
+  while ((*pos_ == ' ' || *pos_ == '\t') && HasNext()) {
+    ++pos_;
+  }
+  return next;
+}
+
+Parser::StateFunc Parser::SkipWhitespaceAndNewLines(Parser::StateFunc next) {
+  while (IsAsciiWhitespace(*pos_) && HasNext()) {
+    if (*pos_ == '\n') {
+      ++line_number_;
+    }
+    ++pos_;
+  }
+  return next;
+}
+
+Parser::StateFunc Parser::SyntaxError(const std::string& message) {
+  delegate_->OnSyntaxError(message);
+  return NULL;
+}
+
+void Parser::DataError(const std::string& error) {
+  data_error_ = true;
+  delegate_->OnDataError(error);
+}
+
+}  // namespace test_expectations
diff --git a/base/test/expectations/parser.h b/base/test/expectations/parser.h
new file mode 100644
index 0000000..69a741a
--- /dev/null
+++ b/base/test/expectations/parser.h
@@ -0,0 +1,143 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_EXPECTATIONS_PARSER_H_
+#define BASE_TEST_EXPECTATIONS_PARSER_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/strings/string_piece.h"
+#include "base/test/expectations/expectation.h"
+
+namespace test_expectations {
+
+// This is the internal parser for test expectations. It parses an input
+// string and reports information to its Delegate as it's processing the
+// input.
+//
+// The input format is documented here:
+// https://docs.google.com/a/chromium.org/document/d/1edhMJ5doY_dzfbKNCzeJJ-8XxPrexTbNL2Y_jVvLB8Q/view
+//
+// Basic format:
+// "http://bug/1234 [ OS-Version ] Test.Name = Result"
+//
+// The parser is implemented as a state machine, with each state returning a
+// function pointer to the next state.
+class Parser {
+ public:
+  // The parser will call these methods on its delegate during a Parse()
+  // operation.
+  class Delegate {
+   public:
+    // When a well-formed and valid Expectation has been parsed from the input,
+    // it is reported to the delegate via this method.
+    virtual void EmitExpectation(const Expectation& expectation) = 0;
+
+    // Called when the input string is not well-formed. Parsing will stop after
+    // this method is called.
+    virtual void OnSyntaxError(const std::string& message) = 0;
+
+    // Called when an Expectation has been parsed because it is well-formed but
+    // contains invalid data (i.e. the modifiers or result are not valid
+    // keywords). This Expectation will not be reported via EmitExpectation.
+    virtual void OnDataError(const std::string& message) = 0;
+  };
+
+  // Creates a new parser for |input| that will send data to |delegate|.
+  Parser(Delegate* delegate, const std::string& input);
+  ~Parser();
+
+  // Runs the parser of the input string.
+  void Parse();
+
+ private:
+  // This bit of hackery is used to implement a function pointer type that
+  // returns a pointer to a function of the same signature. Since a definition
+  // like that is inherently recursive, it's impossible to do:
+  //     type StateFunc(*StateFunc)(StateData*);
+  // However, this approach works without the need to use void*. Inspired by
+  // <http://www.gotw.ca/gotw/057.htm>.
+  struct StateFunc;
+  typedef StateFunc(Parser::*StateFuncPtr)();
+  struct StateFunc {
+    StateFunc(StateFuncPtr pf) : pf_(pf) {}
+    operator StateFuncPtr() {
+      return pf_;
+    }
+    StateFuncPtr pf_;
+  };
+
+  // Tests whether there is at least one more character at pos_ before end_.
+  bool HasNext();
+
+  // The parser state functions. On entry, the parser state is at the beginning
+  // of the token. Each returns a function pointer to the next state function,
+  // or NULL to end parsing. On return, the parser is at the beginning of the
+  // next token.
+  StateFunc Start();
+  StateFunc ParseComment();
+  StateFunc ParseBugURL();
+  StateFunc BeginModifiers();
+  StateFunc InModifiers();
+  StateFunc SaveModifier();
+  StateFunc EndModifiers();
+  StateFunc ParseTestName();
+  StateFunc SaveTestName();
+  StateFunc ParseExpectation();
+  StateFunc ParseExpectationType();
+  StateFunc SaveExpectationType();
+  StateFunc End();
+
+  // A state function that collects character data from the current position
+  // to the next whitespace character. Returns the |success| function when at
+  // the end of the string, with the data stored in |extracted_string_|.
+  StateFunc ExtractString(StateFunc success);
+
+  // Function that skips over horizontal whitespace characters and then returns
+  // the |next| state.
+  StateFunc SkipWhitespace(StateFunc next);
+
+  // Does the same as SkipWhitespace but includes newlines.
+  StateFunc SkipWhitespaceAndNewLines(StateFunc next);
+
+  // State function that reports the given syntax error |message| to the
+  // delegate and then returns NULL, ending the parse loop.
+  StateFunc SyntaxError(const std::string& message);
+
+  // Function that reports the data |error| to the delegate without stopping
+  // parsing.
+  void DataError(const std::string& error);
+
+  // Parser delegate.
+  Delegate* delegate_;
+
+  // The input string.
+  std::string input_;
+
+  // Current location in the |input_|.
+  const char* pos_;
+
+  // Pointer to the end of the |input_|.
+  const char* end_;
+
+  // Current line number, as updated by SkipWhitespace().
+  int line_number_;
+
+  // The character data extracted from |input_| as a result of the
+  // ExtractString() state.
+  base::StringPiece extracted_string_;
+
+  // The Expectation object that is currently being processed by the parser.
+  // Reset in Start().
+  Expectation current_;
+
+  // If DataError() has been called during the course of parsing |current_|.
+  // If true, then |current_| will not be emitted to the Delegate.
+  bool data_error_;
+};
+
+}  // namespace test_expectations
+
+#endif  // BASE_TEST_EXPECTATIONS_PARSER_H_
diff --git a/base/test/expectations/parser_unittest.cc b/base/test/expectations/parser_unittest.cc
new file mode 100644
index 0000000..074d634
--- /dev/null
+++ b/base/test/expectations/parser_unittest.cc
@@ -0,0 +1,209 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/expectations/parser.h"
+
+#include <string>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using test_expectations::Parser;
+
+class TestExpectationParserTest : public testing::Test,
+                                  public Parser::Delegate {
+ public:
+  void EmitExpectation(
+      const test_expectations::Expectation& expectation) override {
+    expectations_.push_back(expectation);
+  }
+
+  void OnSyntaxError(const std::string& message) override {
+    syntax_error_ = message;
+  }
+
+  void OnDataError(const std::string& error) override {
+    data_errors_.push_back(error);
+  }
+
+ protected:
+  std::vector<test_expectations::Expectation> expectations_;
+  std::string syntax_error_;
+  std::vector<std::string> data_errors_;
+};
+
+TEST_F(TestExpectationParserTest, Basic) {
+  Parser(this,
+      "http://crbug.com/1234 [ Win-8 ] DouglasTest.PoopsOk = Timeout").
+          Parse();
+  EXPECT_TRUE(syntax_error_.empty());
+  EXPECT_EQ(0u, data_errors_.size());
+
+  ASSERT_EQ(1u, expectations_.size());
+  EXPECT_EQ("DouglasTest.PoopsOk", expectations_[0].test_name);
+  EXPECT_EQ(test_expectations::RESULT_TIMEOUT, expectations_[0].result);
+  EXPECT_EQ(test_expectations::CONFIGURATION_UNSPECIFIED,
+            expectations_[0].configuration);
+
+  ASSERT_EQ(1u, expectations_[0].platforms.size());
+  EXPECT_EQ("Win", expectations_[0].platforms[0].name);
+  EXPECT_EQ("8", expectations_[0].platforms[0].variant);
+}
+
+TEST_F(TestExpectationParserTest, MultiModifier) {
+  Parser(this, "BUG [ Win-XP Mac ] OhMy.MeOhMy = Failure").Parse();
+  EXPECT_TRUE(syntax_error_.empty());
+  EXPECT_EQ(0u, data_errors_.size());
+
+  ASSERT_EQ(1u, expectations_.size());
+  EXPECT_EQ("OhMy.MeOhMy", expectations_[0].test_name);
+  EXPECT_EQ(test_expectations::RESULT_FAILURE,
+            expectations_[0].result);
+  EXPECT_EQ(test_expectations::CONFIGURATION_UNSPECIFIED,
+            expectations_[0].configuration);
+
+  ASSERT_EQ(2u, expectations_[0].platforms.size());
+
+  EXPECT_EQ("Win", expectations_[0].platforms[0].name);
+  EXPECT_EQ("XP", expectations_[0].platforms[0].variant);
+
+  EXPECT_EQ("Mac", expectations_[0].platforms[1].name);
+  EXPECT_EQ("", expectations_[0].platforms[1].variant);
+}
+
+TEST_F(TestExpectationParserTest, EmptyModifier) {
+  Parser(this,
+      "BUG [] First.Test = Failure\n"
+      "BUG2 [   ] Second.Test = Crash").Parse();
+  EXPECT_EQ(0u, data_errors_.size());
+
+  ASSERT_EQ(2u, expectations_.size());
+
+  EXPECT_EQ("First.Test", expectations_[0].test_name);
+  EXPECT_EQ(test_expectations::RESULT_FAILURE,
+            expectations_[0].result);
+  EXPECT_EQ(test_expectations::CONFIGURATION_UNSPECIFIED,
+            expectations_[0].configuration);
+  EXPECT_EQ(0u, expectations_[0].platforms.size());
+
+  EXPECT_EQ("Second.Test", expectations_[1].test_name);
+  EXPECT_EQ(test_expectations::RESULT_CRASH,
+            expectations_[1].result);
+  EXPECT_EQ(test_expectations::CONFIGURATION_UNSPECIFIED,
+            expectations_[1].configuration);
+  EXPECT_EQ(0u, expectations_[1].platforms.size());
+}
+
+TEST_F(TestExpectationParserTest, MultiLine) {
+  Parser(this,
+      "BUG [ Linux ] Line.First = Failure\n"
+      "\n"
+      "# A test comment.\n"
+      "BUG2 [ Release ] Line.Second = Skip").Parse();
+  EXPECT_TRUE(syntax_error_.empty());
+  EXPECT_EQ(0u, data_errors_.size());
+
+  ASSERT_EQ(2u, expectations_.size());
+  EXPECT_EQ("Line.First", expectations_[0].test_name);
+  EXPECT_EQ(test_expectations::RESULT_FAILURE, expectations_[0].result);
+  EXPECT_EQ(test_expectations::CONFIGURATION_UNSPECIFIED,
+            expectations_[0].configuration);
+
+  ASSERT_EQ(1u, expectations_[0].platforms.size());
+  EXPECT_EQ("Linux", expectations_[0].platforms[0].name);
+  EXPECT_EQ("", expectations_[0].platforms[0].variant);
+
+  EXPECT_EQ("Line.Second", expectations_[1].test_name);
+  EXPECT_EQ(test_expectations::RESULT_SKIP, expectations_[1].result);
+  EXPECT_EQ(test_expectations::CONFIGURATION_RELEASE,
+            expectations_[1].configuration);
+  EXPECT_EQ(0u, expectations_[1].platforms.size());
+}
+
+TEST_F(TestExpectationParserTest, MultiLineWithComments) {
+  Parser(this,
+      "  # Comment for your thoughts\n"
+      "  \t \n"
+      "BUG [ Mac-10.8 Debug] Foo=Bar =Skip   # Why not another comment?\n"
+      "BUG2 [Win-XP\tWin-Vista ] Cow.GoesMoo   =\tTimeout\n\n").Parse();
+  EXPECT_TRUE(syntax_error_.empty()) << syntax_error_;
+  EXPECT_EQ(0u, data_errors_.size());
+
+  ASSERT_EQ(2u, expectations_.size());
+  EXPECT_EQ("Foo=Bar", expectations_[0].test_name);
+  EXPECT_EQ(test_expectations::RESULT_SKIP, expectations_[0].result);
+  EXPECT_EQ(test_expectations::CONFIGURATION_DEBUG,
+            expectations_[0].configuration);
+
+  ASSERT_EQ(1u, expectations_[0].platforms.size());
+  EXPECT_EQ("Mac", expectations_[0].platforms[0].name);
+  EXPECT_EQ("10.8", expectations_[0].platforms[0].variant);
+
+  EXPECT_EQ("Cow.GoesMoo", expectations_[1].test_name);
+  EXPECT_EQ(test_expectations::RESULT_TIMEOUT, expectations_[1].result);
+  EXPECT_EQ(test_expectations::CONFIGURATION_UNSPECIFIED,
+            expectations_[1].configuration);
+
+  ASSERT_EQ(2u, expectations_[1].platforms.size());
+  EXPECT_EQ("Win", expectations_[1].platforms[0].name);
+  EXPECT_EQ("XP", expectations_[1].platforms[0].variant);
+  EXPECT_EQ("Win", expectations_[1].platforms[0].name);
+  EXPECT_EQ("Vista", expectations_[1].platforms[1].variant);
+}
+
+TEST_F(TestExpectationParserTest, WeirdSpaces) {
+  Parser(this, "   BUG       [Linux]        Weird  = Skip    ").Parse();
+  EXPECT_EQ(1u, expectations_.size());
+  EXPECT_TRUE(syntax_error_.empty());
+  EXPECT_EQ(0u, data_errors_.size());
+}
+
+TEST_F(TestExpectationParserTest, SyntaxErrors) {
+  const char* const kErrors[] = {
+    "Foo [ dfasd",
+    "Foo [Linux] # This is an illegal comment",
+    "Foo [Linux] Bar # Another illegal comment.",
+    "Foo [Linux] Bar = # Another illegal comment.",
+    "Foo[Linux]Bar=Failure",
+    "Foo\n[Linux] Bar = Failure",
+    "Foo [\nLinux] Bar = Failure",
+    "Foo [Linux\n] Bar = Failure",
+    "Foo [ Linux ] \n Bar = Failure",
+    "Foo [ Linux ] Bar =\nFailure",
+    "Foo [ Linux \n ] Bar =\nFailure",
+  };
+
+  for (size_t i = 0; i < arraysize(kErrors); ++i) {
+    Parser(this, kErrors[i]).Parse();
+    EXPECT_FALSE(syntax_error_.empty())
+        << "Should have error for #" << i << ": " << kErrors[i];
+    syntax_error_.clear();
+  }
+}
+
+TEST_F(TestExpectationParserTest, DataErrors) {
+  const char* const kOneError[] = {
+    "http://crbug.com/1234 [MagicBrowzR] BadModifier = Timeout",
+    "________ [Linux] BadResult = WhatNow",
+    "http://wkb.ug/1234 [Debug Release Win-7] MultipleConfigs = Skip",
+  };
+
+  for (size_t i = 0; i < arraysize(kOneError); ++i) {
+    Parser(this, kOneError[i]).Parse();
+    EXPECT_EQ(1u, data_errors_.size()) << kOneError[i];
+    data_errors_.clear();
+  }
+
+  const char* const kTwoErrors[] = {
+    ". [Mac-TurningIntoiOS] BadModifierVariant.BadResult = Foobar",
+    "1234 [ Debug Release OS/2 ] MultipleConfigs.BadModifier = Pass",
+  };
+
+  for (size_t i = 0; i < arraysize(kTwoErrors); ++i) {
+    Parser(this, kTwoErrors[i]).Parse();
+    EXPECT_EQ(2u, data_errors_.size()) << kTwoErrors[i];
+    data_errors_.clear();
+  }
+}
diff --git a/base/test/gtest_util.cc b/base/test/gtest_util.cc
new file mode 100644
index 0000000..b811194
--- /dev/null
+++ b/base/test/gtest_util.cc
@@ -0,0 +1,83 @@
+// 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.
+
+#include "base/test/gtest_util.h"
+
+#include "base/files/file_path.h"
+#include "base/json/json_file_value_serializer.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+std::string FormatFullTestName(const std::string& test_case_name,
+                               const std::string& test_name) {
+  return test_case_name + "." + test_name;
+}
+
+std::vector<SplitTestName> GetCompiledInTests() {
+  testing::UnitTest* const unit_test = testing::UnitTest::GetInstance();
+
+  std::vector<SplitTestName> tests;
+  for (int i = 0; i < unit_test->total_test_case_count(); ++i) {
+    const testing::TestCase* test_case = unit_test->GetTestCase(i);
+    for (int j = 0; j < test_case->total_test_count(); ++j) {
+      const testing::TestInfo* test_info = test_case->GetTestInfo(j);
+      tests.push_back(std::make_pair(test_case->name(), test_info->name()));
+    }
+  }
+  return tests;
+}
+
+bool WriteCompiledInTestsToFile(const FilePath& path) {
+  std::vector<SplitTestName> tests(GetCompiledInTests());
+
+  ListValue root;
+  for (size_t i = 0; i < tests.size(); ++i) {
+    DictionaryValue* test_info = new DictionaryValue;
+    test_info->SetString("test_case_name", tests[i].first);
+    test_info->SetString("test_name", tests[i].second);
+    root.Append(test_info);
+  }
+
+  JSONFileValueSerializer serializer(path);
+  return serializer.Serialize(root);
+}
+
+bool ReadTestNamesFromFile(const FilePath& path,
+                           std::vector<SplitTestName>* output) {
+  JSONFileValueDeserializer 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 base
diff --git a/base/test/gtest_util.h b/base/test/gtest_util.h
new file mode 100644
index 0000000..77cc924
--- /dev/null
+++ b/base/test/gtest_util.h
@@ -0,0 +1,42 @@
+// 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.
+
+#ifndef BASE_TEST_GTEST_UTIL_H_
+#define BASE_TEST_GTEST_UTIL_H_
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/compiler_specific.h"
+
+namespace base {
+
+class FilePath;
+
+// First value is test case name, second one is test name.
+typedef std::pair<std::string, std::string> SplitTestName;
+
+// Constructs a full test name given a test case name and a test name,
+// e.g. for test case "A" and test name "B" returns "A.B".
+std::string FormatFullTestName(const std::string& test_case_name,
+                               const std::string& test_name);
+
+// Returns a vector of gtest-based tests compiled into
+// current executable.
+std::vector<SplitTestName> GetCompiledInTests();
+
+// Writes the list of gtest-based tests compiled into
+// 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/base/test/gtest_xml_unittest_result_printer.cc b/base/test/gtest_xml_unittest_result_printer.cc
new file mode 100644
index 0000000..192c228
--- /dev/null
+++ b/base/test/gtest_xml_unittest_result_printer.cc
@@ -0,0 +1,77 @@
+// 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/test/gtest_xml_unittest_result_printer.h"
+
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/time/time.h"
+
+namespace base {
+
+XmlUnitTestResultPrinter::XmlUnitTestResultPrinter() : output_file_(NULL) {
+}
+
+XmlUnitTestResultPrinter::~XmlUnitTestResultPrinter() {
+  if (output_file_) {
+    fprintf(output_file_, "</testsuites>\n");
+    fflush(output_file_);
+    CloseFile(output_file_);
+  }
+}
+
+bool XmlUnitTestResultPrinter::Initialize(const FilePath& output_file_path) {
+  DCHECK(!output_file_);
+  output_file_ = OpenFile(output_file_path, "w");
+  if (!output_file_)
+    return false;
+
+  fprintf(output_file_,
+          "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<testsuites>\n");
+  fflush(output_file_);
+
+  return true;
+}
+
+void XmlUnitTestResultPrinter::OnTestCaseStart(
+    const testing::TestCase& test_case) {
+  fprintf(output_file_, "  <testsuite>\n");
+  fflush(output_file_);
+}
+
+void XmlUnitTestResultPrinter::OnTestStart(
+    const testing::TestInfo& test_info) {
+  // This is our custom extension - it helps to recognize which test was
+  // running when the test binary crashed. Note that we cannot even open the
+  // <testcase> tag here - it requires e.g. run time of the test to be known.
+  fprintf(output_file_,
+          "    <x-teststart name=\"%s\" classname=\"%s\" />\n",
+          test_info.name(),
+          test_info.test_case_name());
+  fflush(output_file_);
+}
+
+void XmlUnitTestResultPrinter::OnTestEnd(const testing::TestInfo& test_info) {
+  fprintf(output_file_,
+          "    <testcase name=\"%s\" status=\"run\" time=\"%.3f\""
+          " classname=\"%s\">\n",
+          test_info.name(),
+          static_cast<double>(test_info.result()->elapsed_time()) /
+              Time::kMillisecondsPerSecond,
+          test_info.test_case_name());
+  if (test_info.result()->Failed()) {
+    fprintf(output_file_,
+            "      <failure message=\"\" type=\"\"></failure>\n");
+  }
+  fprintf(output_file_, "    </testcase>\n");
+  fflush(output_file_);
+}
+
+void XmlUnitTestResultPrinter::OnTestCaseEnd(
+    const testing::TestCase& test_case) {
+  fprintf(output_file_, "  </testsuite>\n");
+  fflush(output_file_);
+}
+
+}  // namespace base
diff --git a/base/test/gtest_xml_unittest_result_printer.h b/base/test/gtest_xml_unittest_result_printer.h
new file mode 100644
index 0000000..3b06b85
--- /dev/null
+++ b/base/test/gtest_xml_unittest_result_printer.h
@@ -0,0 +1,42 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_GTEST_XML_UNITTEST_RESULT_PRINTER_H_
+#define BASE_TEST_GTEST_XML_UNITTEST_RESULT_PRINTER_H_
+
+#include <stdio.h>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+class FilePath;
+
+// Generates an XML output file. Format is very close to GTest, but has
+// extensions needed by the test launcher.
+class XmlUnitTestResultPrinter : public testing::EmptyTestEventListener {
+ public:
+  XmlUnitTestResultPrinter();
+  ~XmlUnitTestResultPrinter() override;
+
+  // Must be called before adding as a listener. Returns true on success.
+  bool Initialize(const FilePath& output_file_path) WARN_UNUSED_RESULT;
+
+ private:
+  // testing::EmptyTestEventListener:
+  void OnTestCaseStart(const testing::TestCase& test_case) override;
+  void OnTestStart(const testing::TestInfo& test_info) override;
+  void OnTestEnd(const testing::TestInfo& test_info) override;
+  void OnTestCaseEnd(const testing::TestCase& test_case) override;
+
+  FILE* output_file_;
+
+  DISALLOW_COPY_AND_ASSIGN(XmlUnitTestResultPrinter);
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_GTEST_XML_UNITTEST_RESULT_PRINTER_H_
diff --git a/base/test/gtest_xml_util.cc b/base/test/gtest_xml_util.cc
new file mode 100644
index 0000000..e24d522
--- /dev/null
+++ b/base/test/gtest_xml_util.cc
@@ -0,0 +1,168 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/gtest_xml_util.h"
+
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/gtest_util.h"
+#include "base/test/launcher/test_launcher.h"
+#include "third_party/libxml/chromium/libxml_utils.h"
+
+namespace base {
+
+namespace {
+
+// This is used for the xml parser to report errors. This assumes the context
+// is a pointer to a std::string where the error message should be appended.
+static void XmlErrorFunc(void *context, const char *message, ...) {
+  va_list args;
+  va_start(args, message);
+  std::string* error = static_cast<std::string*>(context);
+  StringAppendV(error, message, args);
+  va_end(args);
+}
+
+}  // namespace
+
+bool ProcessGTestOutput(const base::FilePath& output_file,
+                        std::vector<TestResult>* results,
+                        bool* crashed) {
+  DCHECK(results);
+
+  std::string xml_contents;
+  if (!ReadFileToString(output_file, &xml_contents))
+    return false;
+
+  // Silence XML errors - otherwise they go to stderr.
+  std::string xml_errors;
+  ScopedXmlErrorFunc error_func(&xml_errors, &XmlErrorFunc);
+
+  XmlReader xml_reader;
+  if (!xml_reader.Load(xml_contents))
+    return false;
+
+  enum {
+    STATE_INIT,
+    STATE_TESTSUITE,
+    STATE_TESTCASE,
+    STATE_FAILURE,
+    STATE_END,
+  } state = STATE_INIT;
+
+  while (xml_reader.Read()) {
+    xml_reader.SkipToElement();
+    std::string node_name(xml_reader.NodeName());
+
+    switch (state) {
+      case STATE_INIT:
+        if (node_name == "testsuites" && !xml_reader.IsClosingElement())
+          state = STATE_TESTSUITE;
+        else
+          return false;
+        break;
+      case STATE_TESTSUITE:
+        if (node_name == "testsuites" && xml_reader.IsClosingElement())
+          state = STATE_END;
+        else if (node_name == "testsuite" && !xml_reader.IsClosingElement())
+          state = STATE_TESTCASE;
+        else
+          return false;
+        break;
+      case STATE_TESTCASE:
+        if (node_name == "testsuite" && xml_reader.IsClosingElement()) {
+          state = STATE_TESTSUITE;
+        } else if (node_name == "x-teststart" &&
+                   !xml_reader.IsClosingElement()) {
+          // This is our custom extension that helps recognize which test was
+          // running when the test binary crashed.
+          TestResult result;
+
+          std::string test_case_name;
+          if (!xml_reader.NodeAttribute("classname", &test_case_name))
+            return false;
+          std::string test_name;
+          if (!xml_reader.NodeAttribute("name", &test_name))
+            return false;
+          result.full_name = FormatFullTestName(test_case_name, test_name);
+
+          result.elapsed_time = TimeDelta();
+
+          // Assume the test crashed - we can correct that later.
+          result.status = TestResult::TEST_CRASH;
+
+          results->push_back(result);
+        } else if (node_name == "testcase" && !xml_reader.IsClosingElement()) {
+          std::string test_status;
+          if (!xml_reader.NodeAttribute("status", &test_status))
+            return false;
+
+          if (test_status != "run" && test_status != "notrun")
+            return false;
+          if (test_status != "run")
+            break;
+
+          TestResult result;
+
+          std::string test_case_name;
+          if (!xml_reader.NodeAttribute("classname", &test_case_name))
+            return false;
+          std::string test_name;
+          if (!xml_reader.NodeAttribute("name", &test_name))
+            return false;
+          result.full_name = test_case_name + "." + test_name;
+
+          std::string test_time_str;
+          if (!xml_reader.NodeAttribute("time", &test_time_str))
+            return false;
+          result.elapsed_time = TimeDelta::FromMicroseconds(
+              static_cast<int64>(strtod(test_time_str.c_str(), NULL) *
+                  Time::kMicrosecondsPerSecond));
+
+          result.status = TestResult::TEST_SUCCESS;
+
+          if (!results->empty() &&
+              results->at(results->size() - 1).full_name == result.full_name &&
+              results->at(results->size() - 1).status ==
+                  TestResult::TEST_CRASH) {
+            // Erase the fail-safe "crashed" result - now we know the test did
+            // not crash.
+            results->pop_back();
+          }
+
+          results->push_back(result);
+        } else if (node_name == "failure" && !xml_reader.IsClosingElement()) {
+          std::string failure_message;
+          if (!xml_reader.NodeAttribute("message", &failure_message))
+            return false;
+
+          DCHECK(!results->empty());
+          results->at(results->size() - 1).status = TestResult::TEST_FAILURE;
+
+          state = STATE_FAILURE;
+        } else if (node_name == "testcase" && xml_reader.IsClosingElement()) {
+          // Deliberately empty.
+        } else {
+          return false;
+        }
+        break;
+      case STATE_FAILURE:
+        if (node_name == "failure" && xml_reader.IsClosingElement())
+          state = STATE_TESTCASE;
+        else
+          return false;
+        break;
+      case STATE_END:
+        // If we are here and there are still XML elements, the file has wrong
+        // format.
+        return false;
+    }
+  }
+
+  *crashed = (state != STATE_END);
+  return true;
+}
+
+}  // namespace base
diff --git a/base/test/gtest_xml_util.h b/base/test/gtest_xml_util.h
new file mode 100644
index 0000000..b023f80
--- /dev/null
+++ b/base/test/gtest_xml_util.h
@@ -0,0 +1,27 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_GTEST_XML_UTIL_H_
+#define BASE_TEST_GTEST_XML_UTIL_H_
+
+#include <vector>
+
+#include "base/compiler_specific.h"
+
+namespace base {
+
+class FilePath;
+struct TestResult;
+
+// Produces a vector of test results based on GTest output file.
+// Returns true iff the output file exists and has been successfully parsed.
+// On successful return |crashed| is set to true if the test results
+// are valid but incomplete.
+bool ProcessGTestOutput(const base::FilePath& output_file,
+                        std::vector<TestResult>* results,
+                        bool* crashed) WARN_UNUSED_RESULT;
+
+}  // namespace base
+
+#endif  // BASE_TEST_GTEST_XML_UTIL_H_
diff --git a/base/test/histogram_tester.cc b/base/test/histogram_tester.cc
new file mode 100644
index 0000000..ea738b0
--- /dev/null
+++ b/base/test/histogram_tester.cc
@@ -0,0 +1,123 @@
+// 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.
+
+#include "base/test/histogram_tester.h"
+
+#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_samples.h"
+#include "base/metrics/statistics_recorder.h"
+#include "base/stl_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+HistogramTester::HistogramTester() {
+  StatisticsRecorder::Initialize();  // Safe to call multiple times.
+
+  // Record any histogram data that exists when the object is created so it can
+  // be subtracted later.
+  StatisticsRecorder::Histograms histograms;
+  StatisticsRecorder::GetSnapshot(std::string(), &histograms);
+  for (size_t i = 0; i < histograms.size(); ++i) {
+    histograms_snapshot_[histograms[i]->histogram_name()] =
+        histograms[i]->SnapshotSamples().release();
+  }
+}
+
+HistogramTester::~HistogramTester() {
+  STLDeleteValues(&histograms_snapshot_);
+}
+
+void HistogramTester::ExpectUniqueSample(
+    const std::string& name,
+    base::HistogramBase::Sample sample,
+    base::HistogramBase::Count expected_count) const {
+  base::HistogramBase* histogram =
+      base::StatisticsRecorder::FindHistogram(name);
+  EXPECT_NE(static_cast<base::HistogramBase*>(NULL), histogram)
+      << "Histogram \"" << name << "\" does not exist.";
+
+  if (histogram) {
+    scoped_ptr<base::HistogramSamples> samples(histogram->SnapshotSamples());
+    CheckBucketCount(name, sample, expected_count, *samples);
+    CheckTotalCount(name, expected_count, *samples);
+  }
+}
+
+void HistogramTester::ExpectBucketCount(
+    const std::string& name,
+    base::HistogramBase::Sample sample,
+    base::HistogramBase::Count expected_count) const {
+  base::HistogramBase* histogram =
+      base::StatisticsRecorder::FindHistogram(name);
+  EXPECT_NE(static_cast<base::HistogramBase*>(NULL), histogram)
+      << "Histogram \"" << name << "\" does not exist.";
+
+  if (histogram) {
+    scoped_ptr<base::HistogramSamples> samples(histogram->SnapshotSamples());
+    CheckBucketCount(name, sample, expected_count, *samples);
+  }
+}
+
+void HistogramTester::ExpectTotalCount(const std::string& name,
+                                       base::HistogramBase::Count count) const {
+  base::HistogramBase* histogram =
+      base::StatisticsRecorder::FindHistogram(name);
+  if (histogram) {
+    scoped_ptr<base::HistogramSamples> samples(histogram->SnapshotSamples());
+    CheckTotalCount(name, count, *samples);
+  } else {
+    // No histogram means there were zero samples.
+    EXPECT_EQ(count, 0) << "Histogram \"" << name << "\" does not exist.";
+  }
+}
+
+scoped_ptr<HistogramSamples> HistogramTester::GetHistogramSamplesSinceCreation(
+    const std::string& histogram_name) {
+  HistogramBase* histogram = StatisticsRecorder::FindHistogram(histogram_name);
+  if (!histogram)
+    return scoped_ptr<HistogramSamples>();
+  scoped_ptr<HistogramSamples> named_samples(histogram->SnapshotSamples());
+  HistogramSamples* named_original_samples =
+      histograms_snapshot_[histogram_name];
+  if (named_original_samples)
+    named_samples->Subtract(*named_original_samples);
+  return named_samples.Pass();
+}
+
+void HistogramTester::CheckBucketCount(
+    const std::string& name,
+    base::HistogramBase::Sample sample,
+    base::HistogramBase::Count expected_count,
+    const base::HistogramSamples& samples) const {
+  int actual_count = samples.GetCount(sample);
+  std::map<std::string, HistogramSamples*>::const_iterator histogram_data;
+  histogram_data = histograms_snapshot_.find(name);
+  if (histogram_data != histograms_snapshot_.end())
+    actual_count -= histogram_data->second->GetCount(sample);
+
+  EXPECT_EQ(expected_count, actual_count)
+      << "Histogram \"" << name
+      << "\" does not have the right number of samples (" << expected_count
+      << ") in the expected bucket (" << sample << "). It has (" << actual_count
+      << ").";
+}
+
+void HistogramTester::CheckTotalCount(
+    const std::string& name,
+    base::HistogramBase::Count expected_count,
+    const base::HistogramSamples& samples) const {
+  int actual_count = samples.TotalCount();
+  std::map<std::string, HistogramSamples*>::const_iterator histogram_data;
+  histogram_data = histograms_snapshot_.find(name);
+  if (histogram_data != histograms_snapshot_.end())
+    actual_count -= histogram_data->second->TotalCount();
+
+  EXPECT_EQ(expected_count, actual_count)
+      << "Histogram \"" << name
+      << "\" does not have the right total number of samples ("
+      << expected_count << "). It has (" << actual_count << ").";
+}
+
+}  // namespace base
diff --git a/base/test/histogram_tester.h b/base/test/histogram_tester.h
new file mode 100644
index 0000000..96317f9
--- /dev/null
+++ b/base/test/histogram_tester.h
@@ -0,0 +1,81 @@
+// 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.
+
+#ifndef BASE_TEST_HISTOGRAM_TESTER_H_
+#define BASE_TEST_HISTOGRAM_TESTER_H_
+
+#include <map>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_base.h"
+
+namespace base {
+
+class HistogramSamples;
+
+// HistogramTester provides a simple interface for examining histograms, UMA
+// or otherwise. Tests can use this interface to verify that histogram data is
+// getting logged as intended.
+class HistogramTester {
+ public:
+  // The constructor will call StatisticsRecorder::Initialize() for you. Also,
+  // this takes a snapshot of all current histograms counts.
+  HistogramTester();
+  ~HistogramTester();
+
+  // We know the exact number of samples in a bucket, and that no other bucket
+  // should have samples. Measures the diff from the snapshot taken when this
+  // object was constructed.
+  void ExpectUniqueSample(const std::string& name,
+                          base::HistogramBase::Sample sample,
+                          base::HistogramBase::Count expected_count) const;
+
+  // We know the exact number of samples in a bucket, but other buckets may
+  // have samples as well. Measures the diff from the snapshot taken when this
+  // object was constructed.
+  void ExpectBucketCount(const std::string& name,
+                         base::HistogramBase::Sample sample,
+                         base::HistogramBase::Count expected_count) const;
+
+  // We don't know the values of the samples, but we know how many there are.
+  // This measures the diff from the snapshot taken when this object was
+  // constructed.
+  void ExpectTotalCount(const std::string& name,
+                        base::HistogramBase::Count count) const;
+
+  // Access a modified HistogramSamples containing only what has been logged
+  // to the histogram since the creation of this object.
+  scoped_ptr<HistogramSamples> GetHistogramSamplesSinceCreation(
+      const std::string& histogram_name);
+
+ private:
+  // Verifies and asserts that value in the |sample| bucket matches the
+  // |expected_count|. The bucket's current value is determined from |samples|
+  // and is modified based on the snapshot stored for histogram |name|.
+  void CheckBucketCount(const std::string& name,
+                        base::HistogramBase::Sample sample,
+                        base::Histogram::Count expected_count,
+                        const base::HistogramSamples& samples) const;
+
+  // Verifies that the total number of values recorded for the histogram |name|
+  // is |expected_count|. This is checked against |samples| minus the snapshot
+  // that was taken for |name|.
+  void CheckTotalCount(const std::string& name,
+                       base::Histogram::Count expected_count,
+                       const base::HistogramSamples& samples) const;
+
+  // Used to determine the histogram changes made during this instance's
+  // lifecycle. This instance takes ownership of the samples, which are deleted
+  // when the instance is destroyed.
+  std::map<std::string, HistogramSamples*> histograms_snapshot_;
+
+  DISALLOW_COPY_AND_ASSIGN(HistogramTester);
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_HISTOGRAM_TESTER_H_
diff --git a/base/test/histogram_tester_unittest.cc b/base/test/histogram_tester_unittest.cc
new file mode 100644
index 0000000..a03ee13
--- /dev/null
+++ b/base/test/histogram_tester_unittest.cc
@@ -0,0 +1,81 @@
+// 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.
+
+#include "base/test/histogram_tester.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_samples.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+const std::string kHistogram1 = "Test1";
+const std::string kHistogram2 = "Test2";
+const std::string kHistogram3 = "Test3";
+const std::string kHistogram4 = "Test4";
+
+typedef testing::Test HistogramTesterTest;
+
+TEST_F(HistogramTesterTest, Scope) {
+  // Record a histogram before the creation of the recorder.
+  UMA_HISTOGRAM_BOOLEAN(kHistogram1, true);
+
+  HistogramTester tester;
+
+  // Verify that no histogram is recorded.
+  scoped_ptr<HistogramSamples> samples(
+      tester.GetHistogramSamplesSinceCreation(kHistogram1));
+  EXPECT_FALSE(samples);
+
+  // Record a histogram after the creation of the recorder.
+  UMA_HISTOGRAM_BOOLEAN(kHistogram1, true);
+
+  // Verify that one histogram is recorded.
+  samples = tester.GetHistogramSamplesSinceCreation(kHistogram1);
+  EXPECT_TRUE(samples);
+  EXPECT_EQ(1, samples->TotalCount());
+}
+
+TEST_F(HistogramTesterTest, TestUniqueSample) {
+  HistogramTester tester;
+
+  // Record into a sample thrice
+  UMA_HISTOGRAM_COUNTS_100(kHistogram2, 2);
+  UMA_HISTOGRAM_COUNTS_100(kHistogram2, 2);
+  UMA_HISTOGRAM_COUNTS_100(kHistogram2, 2);
+
+  tester.ExpectUniqueSample(kHistogram2, 2, 3);
+}
+
+TEST_F(HistogramTesterTest, TestBucketsSample) {
+  HistogramTester tester;
+
+  // Record into a sample twice
+  UMA_HISTOGRAM_COUNTS_100(kHistogram3, 2);
+  UMA_HISTOGRAM_COUNTS_100(kHistogram3, 2);
+  UMA_HISTOGRAM_COUNTS_100(kHistogram3, 2);
+  UMA_HISTOGRAM_COUNTS_100(kHistogram3, 2);
+  UMA_HISTOGRAM_COUNTS_100(kHistogram3, 3);
+
+  tester.ExpectBucketCount(kHistogram3, 2, 4);
+  tester.ExpectBucketCount(kHistogram3, 3, 1);
+
+  tester.ExpectTotalCount(kHistogram3, 5);
+}
+
+TEST_F(HistogramTesterTest, TestBucketsSampleWithScope) {
+  // Record into a sample twice, once before the tester creation and once after.
+  UMA_HISTOGRAM_COUNTS_100(kHistogram4, 2);
+
+  HistogramTester tester;
+  UMA_HISTOGRAM_COUNTS_100(kHistogram4, 3);
+
+  tester.ExpectBucketCount(kHistogram4, 2, 0);
+  tester.ExpectBucketCount(kHistogram4, 3, 1);
+
+  tester.ExpectTotalCount(kHistogram4, 1);
+}
+
+}  // namespace base
diff --git a/base/test/ios/OWNERS b/base/test/ios/OWNERS
new file mode 100644
index 0000000..1b3348e
--- /dev/null
+++ b/base/test/ios/OWNERS
@@ -0,0 +1,2 @@
+rohitrao@chromium.org
+stuartmorgan@chromium.org
diff --git a/base/test/ios/wait_util.h b/base/test/ios/wait_util.h
new file mode 100644
index 0000000..01c6fe7
--- /dev/null
+++ b/base/test/ios/wait_util.h
@@ -0,0 +1,49 @@
+// 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.
+
+#ifndef BASE_TEST_IOS_WAIT_UTIL_H_
+#define BASE_TEST_IOS_WAIT_UTIL_H_
+
+#include "base/ios/block_types.h"
+#include "base/time/time.h"
+
+namespace base {
+
+class MessageLoop;
+
+namespace test {
+namespace ios {
+
+// Returns the time spent in running |action| plus waiting until |condition| is
+// met.
+// Performs |action| and then spins run loop and runs the |message_loop| until
+// |condition| block returns true.
+// |action| may be nil if no action needs to be performed before the wait loop.
+// |message_loop| can be null if there is no need to spin the message loop.
+// |condition| may be nil if there is no condition to wait for: the run loop
+// will spin until timeout is reached.
+// |timeout| parameter sets the maximum wait time. If |timeout| is zero,
+// a reasonable default will be used.
+TimeDelta TimeUntilCondition(ProceduralBlock action,
+                             ConditionBlock condition,
+                             MessageLoop* message_loop,
+                             TimeDelta timeout);
+
+// Waits until |condition| is met. A |message_loop| to spin and a |timeout| can
+// be optionally passed; if |timeout| is zero, a reasonable default will be
+// used.
+void WaitUntilCondition(ConditionBlock condition,
+                        MessageLoop* message_loop,
+                        TimeDelta timeout);
+void WaitUntilCondition(ConditionBlock condition);
+
+// Lets the run loop of the current thread process other messages
+// within the given maximum delay.
+void SpinRunLoopWithMaxDelay(TimeDelta max_delay);
+
+}  // namespace ios
+}  // namespace test
+}  // namespace base
+
+#endif  // BASE_TEST_IOS_WAIT_UTIL_H_
diff --git a/base/test/ios/wait_util.mm b/base/test/ios/wait_util.mm
new file mode 100644
index 0000000..e8b3a0f
--- /dev/null
+++ b/base/test/ios/wait_util.mm
@@ -0,0 +1,62 @@
+// 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.
+
+#import "base/test/ios/wait_util.h"
+
+#import <Foundation/Foundation.h>
+
+#include "base/logging.h"
+#include "base/mac/scoped_nsobject.h"
+#include "base/message_loop/message_loop.h"
+#include "base/test/test_timeouts.h"
+#include "base/timer/elapsed_timer.h"
+
+namespace base {
+namespace test {
+namespace ios {
+
+TimeDelta TimeUntilCondition(ProceduralBlock action,
+                             ConditionBlock condition,
+                             MessageLoop* message_loop,
+                             TimeDelta timeout) {
+  ElapsedTimer timer;
+  if (action)
+    action();
+  if (timeout == TimeDelta())
+    timeout = TestTimeouts::action_timeout();
+  const TimeDelta spin_delay(TimeDelta::FromMilliseconds(10));
+  while (timer.Elapsed() < timeout && (!condition || !condition())) {
+    SpinRunLoopWithMaxDelay(spin_delay);
+    if (message_loop) {
+      message_loop->RunUntilIdle();
+    }
+  }
+  TimeDelta elapsed = timer.Elapsed();
+  // If DCHECK is ever hit, check if |action| is doing something that is
+  // taking an unreasonably long time, or if |condition| does not come
+  // true quickly enough. Increase |timeout| only if necessary.
+  DCHECK(!condition || condition());
+  return elapsed;
+}
+
+void WaitUntilCondition(ConditionBlock condition,
+                        MessageLoop* message_loop,
+                        TimeDelta timeout) {
+  TimeUntilCondition(nil, condition, message_loop, timeout);
+}
+
+void WaitUntilCondition(ConditionBlock condition) {
+  WaitUntilCondition(condition, nullptr, TimeDelta());
+}
+
+void SpinRunLoopWithMaxDelay(TimeDelta max_delay) {
+  scoped_nsobject<NSDate> beforeDate(
+      [[NSDate alloc] initWithTimeIntervalSinceNow:max_delay.InSecondsF()]);
+  [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
+                           beforeDate:beforeDate];
+}
+
+}  // namespace ios
+}  // namespace test
+}  // namespace base
diff --git a/base/test/launcher/test_launcher.cc b/base/test/launcher/test_launcher.cc
new file mode 100644
index 0000000..7f258f5
--- /dev/null
+++ b/base/test/launcher/test_launcher.cc
@@ -0,0 +1,1079 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/launcher/test_launcher.h"
+
+#if defined(OS_POSIX)
+#include <fcntl.h>
+#endif
+
+#include "base/at_exit.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/environment.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_file.h"
+#include "base/format_macros.h"
+#include "base/hash.h"
+#include "base/lazy_instance.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/process/kill.h"
+#include "base/process/launch.h"
+#include "base/single_thread_task_runner.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringize_macros.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/gtest_util.h"
+#include "base/test/launcher/test_results_tracker.h"
+#include "base/test/sequenced_worker_pool_owner.h"
+#include "base/test/test_switches.h"
+#include "base/test/test_timeouts.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/thread_checker.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_MACOSX)
+#include "base/mac/scoped_nsautorelease_pool.h"
+#endif
+
+#if defined(OS_WIN)
+#include "base/win/windows_version.h"
+#endif
+
+namespace base {
+
+// See https://groups.google.com/a/chromium.org/d/msg/chromium-dev/nkdTP7sstSc/uT3FaE_sgkAJ .
+using ::operator<<;
+
+// The environment variable name for the total number of test shards.
+const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS";
+// The environment variable name for the test shard index.
+const char kTestShardIndex[] = "GTEST_SHARD_INDEX";
+
+namespace {
+
+// Global tag for test runs where the results are incomplete or unreliable
+// for any reason, e.g. early exit because of too many broken tests.
+const char kUnreliableResultsTag[] = "UNRELIABLE_RESULTS";
+
+// Maximum time of no output after which we print list of processes still
+// running. This deliberately doesn't use TestTimeouts (which is otherwise
+// a recommended solution), because they can be increased. This would defeat
+// the purpose of this timeout, which is 1) to avoid buildbot "no output for
+// X seconds" timeout killing the process 2) help communicate status of
+// the test launcher to people looking at the output (no output for a long
+// time is mysterious and gives no info about what is happening) 3) help
+// debugging in case the process hangs anyway.
+const int kOutputTimeoutSeconds = 15;
+
+// Limit of output snippet lines when printing to stdout.
+// Avoids flooding the logs with amount of output that gums up
+// the infrastructure.
+const size_t kOutputSnippetLinesLimit = 5000;
+
+// Set of live launch test processes with corresponding lock (it is allowed
+// for callers to launch processes on different threads).
+LazyInstance<std::map<ProcessHandle, CommandLine> > g_live_processes
+    = LAZY_INSTANCE_INITIALIZER;
+LazyInstance<Lock> g_live_processes_lock = LAZY_INSTANCE_INITIALIZER;
+
+#if defined(OS_POSIX)
+// Self-pipe that makes it possible to do complex shutdown handling
+// outside of the signal handler.
+int g_shutdown_pipe[2] = { -1, -1 };
+
+void ShutdownPipeSignalHandler(int signal) {
+  HANDLE_EINTR(write(g_shutdown_pipe[1], "q", 1));
+}
+
+void KillSpawnedTestProcesses() {
+  // Keep the lock until exiting the process to prevent further processes
+  // from being spawned.
+  AutoLock lock(g_live_processes_lock.Get());
+
+  fprintf(stdout,
+          "Sending SIGTERM to %" PRIuS " child processes... ",
+          g_live_processes.Get().size());
+  fflush(stdout);
+
+  for (std::map<ProcessHandle, CommandLine>::iterator i =
+           g_live_processes.Get().begin();
+       i != g_live_processes.Get().end();
+       ++i) {
+    // Send the signal to entire process group.
+    kill((-1) * (i->first), SIGTERM);
+  }
+
+  fprintf(stdout,
+          "done.\nGiving processes a chance to terminate cleanly... ");
+  fflush(stdout);
+
+  PlatformThread::Sleep(TimeDelta::FromMilliseconds(500));
+
+  fprintf(stdout, "done.\n");
+  fflush(stdout);
+
+  fprintf(stdout,
+          "Sending SIGKILL to %" PRIuS " child processes... ",
+          g_live_processes.Get().size());
+  fflush(stdout);
+
+  for (std::map<ProcessHandle, CommandLine>::iterator i =
+           g_live_processes.Get().begin();
+       i != g_live_processes.Get().end();
+       ++i) {
+    // Send the signal to entire process group.
+    kill((-1) * (i->first), SIGKILL);
+  }
+
+  fprintf(stdout, "done.\n");
+  fflush(stdout);
+}
+
+// I/O watcher for the reading end of the self-pipe above.
+// Terminates any launched child processes and exits the process.
+class SignalFDWatcher : public MessageLoopForIO::Watcher {
+ public:
+  SignalFDWatcher() {
+  }
+
+  void OnFileCanReadWithoutBlocking(int fd) override {
+    fprintf(stdout, "\nCaught signal. Killing spawned test processes...\n");
+    fflush(stdout);
+
+    KillSpawnedTestProcesses();
+
+    // The signal would normally kill the process, so exit now.
+    _exit(1);
+  }
+
+  void OnFileCanWriteWithoutBlocking(int fd) override { NOTREACHED(); }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SignalFDWatcher);
+};
+#endif  // defined(OS_POSIX)
+
+// Parses the environment variable var as an Int32.  If it is unset, returns
+// true.  If it is set, unsets it then converts it to Int32 before
+// returning it in |result|.  Returns true on success.
+bool TakeInt32FromEnvironment(const char* const var, int32* result) {
+  scoped_ptr<Environment> env(Environment::Create());
+  std::string str_val;
+
+  if (!env->GetVar(var, &str_val))
+    return true;
+
+  if (!env->UnSetVar(var)) {
+    LOG(ERROR) << "Invalid environment: we could not unset " << var << ".\n";
+    return false;
+  }
+
+  if (!StringToInt(str_val, result)) {
+    LOG(ERROR) << "Invalid environment: " << var << " is not an integer.\n";
+    return false;
+  }
+
+  return true;
+}
+
+// Unsets the environment variable |name| and returns true on success.
+// Also returns true if the variable just doesn't exist.
+bool UnsetEnvironmentVariableIfExists(const std::string& name) {
+  scoped_ptr<Environment> env(Environment::Create());
+  std::string str_val;
+
+  if (!env->GetVar(name.c_str(), &str_val))
+    return true;
+
+  return env->UnSetVar(name.c_str());
+}
+
+// Returns true if bot mode has been requested, i.e. defaults optimized
+// for continuous integration bots. This way developers don't have to remember
+// special command-line flags.
+bool BotModeEnabled() {
+  scoped_ptr<Environment> env(Environment::Create());
+  return CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kTestLauncherBotMode) ||
+      env->HasVar("CHROMIUM_TEST_LAUNCHER_BOT_MODE");
+}
+
+// Returns command line command line after gtest-specific processing
+// and applying |wrapper|.
+CommandLine PrepareCommandLineForGTest(const CommandLine& command_line,
+                                       const std::string& wrapper) {
+  CommandLine new_command_line(command_line.GetProgram());
+  CommandLine::SwitchMap switches = command_line.GetSwitches();
+
+  // Strip out gtest_repeat flag - this is handled by the launcher process.
+  switches.erase(kGTestRepeatFlag);
+
+  // Don't try to write the final XML report in child processes.
+  switches.erase(kGTestOutputFlag);
+
+  for (CommandLine::SwitchMap::const_iterator iter = switches.begin();
+       iter != switches.end(); ++iter) {
+    new_command_line.AppendSwitchNative((*iter).first, (*iter).second);
+  }
+
+  // Prepend wrapper after last CommandLine quasi-copy operation. CommandLine
+  // does not really support removing switches well, and trying to do that
+  // on a CommandLine with a wrapper is known to break.
+  // TODO(phajdan.jr): Give it a try to support CommandLine removing switches.
+#if defined(OS_WIN)
+  new_command_line.PrependWrapper(ASCIIToUTF16(wrapper));
+#elif defined(OS_POSIX)
+  new_command_line.PrependWrapper(wrapper);
+#endif
+
+  return new_command_line;
+}
+
+// Launches a child process using |command_line|. If the child process is still
+// running after |timeout|, it is terminated and |*was_timeout| is set to true.
+// Returns exit code of the process.
+int LaunchChildTestProcessWithOptions(const CommandLine& command_line,
+                                      const LaunchOptions& options,
+                                      int flags,
+                                      TimeDelta timeout,
+                                      bool* was_timeout) {
+#if defined(OS_POSIX)
+  // Make sure an option we rely on is present - see LaunchChildGTestProcess.
+  DCHECK(options.new_process_group);
+#endif
+
+  LaunchOptions new_options(options);
+
+#if defined(OS_WIN)
+  DCHECK(!new_options.job_handle);
+
+  win::ScopedHandle job_handle;
+  if (flags & TestLauncher::USE_JOB_OBJECTS) {
+    job_handle.Set(CreateJobObject(NULL, NULL));
+    if (!job_handle.IsValid()) {
+      LOG(ERROR) << "Could not create JobObject.";
+      return -1;
+    }
+
+    DWORD job_flags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
+
+    // Allow break-away from job since sandbox and few other places rely on it
+    // on Windows versions prior to Windows 8 (which supports nested jobs).
+    if (win::GetVersion() < win::VERSION_WIN8 &&
+        flags & TestLauncher::ALLOW_BREAKAWAY_FROM_JOB) {
+      job_flags |= JOB_OBJECT_LIMIT_BREAKAWAY_OK;
+    }
+
+    if (!SetJobObjectLimitFlags(job_handle.Get(), job_flags)) {
+      LOG(ERROR) << "Could not SetJobObjectLimitFlags.";
+      return -1;
+    }
+
+    new_options.job_handle = job_handle.Get();
+  }
+#endif  // defined(OS_WIN)
+
+#if defined(OS_LINUX)
+  // To prevent accidental privilege sharing to an untrusted child, processes
+  // are started with PR_SET_NO_NEW_PRIVS. Do not set that here, since this
+  // new child will be privileged and trusted.
+  new_options.allow_new_privs = true;
+#endif
+
+  Process process;
+
+  {
+    // Note how we grab the lock before the process possibly gets created.
+    // This ensures that when the lock is held, ALL the processes are registered
+    // in the set.
+    AutoLock lock(g_live_processes_lock.Get());
+
+    process = LaunchProcess(command_line, new_options);
+    if (!process.IsValid())
+      return -1;
+
+    // TODO(rvargas) crbug.com/417532: Don't store process handles.
+    g_live_processes.Get().insert(std::make_pair(process.Handle(),
+                                                 command_line));
+  }
+
+  int exit_code = 0;
+  if (!process.WaitForExitWithTimeout(timeout, &exit_code)) {
+    *was_timeout = true;
+    exit_code = -1;  // Set a non-zero exit code to signal a failure.
+
+    // Ensure that the process terminates.
+    process.Terminate(-1, true);
+  }
+
+  {
+    // Note how we grab the log before issuing a possibly broad process kill.
+    // Other code parts that grab the log kill processes, so avoid trying
+    // to do that twice and trigger all kinds of log messages.
+    AutoLock lock(g_live_processes_lock.Get());
+
+#if defined(OS_POSIX)
+    if (exit_code != 0) {
+      // On POSIX, in case the test does not exit cleanly, either due to a crash
+      // or due to it timing out, we need to clean up any child processes that
+      // it might have created. On Windows, child processes are automatically
+      // cleaned up using JobObjects.
+      KillProcessGroup(process.Handle());
+    }
+#endif
+
+    g_live_processes.Get().erase(process.Handle());
+  }
+
+  return exit_code;
+}
+
+void RunCallback(
+    const TestLauncher::LaunchChildGTestProcessCallback& callback,
+    int exit_code,
+    const TimeDelta& elapsed_time,
+    bool was_timeout,
+    const std::string& output) {
+  callback.Run(exit_code, elapsed_time, was_timeout, output);
+}
+
+void DoLaunchChildTestProcess(
+    const CommandLine& command_line,
+    TimeDelta timeout,
+    int flags,
+    bool redirect_stdio,
+    SingleThreadTaskRunner* task_runner,
+    const TestLauncher::LaunchChildGTestProcessCallback& callback) {
+  TimeTicks start_time = TimeTicks::Now();
+
+  // Redirect child process output to a file.
+  FilePath output_file;
+  CHECK(CreateTemporaryFile(&output_file));
+
+  LaunchOptions options;
+#if defined(OS_WIN)
+  win::ScopedHandle handle;
+
+  if (redirect_stdio) {
+    // Make the file handle inheritable by the child.
+    SECURITY_ATTRIBUTES sa_attr;
+    sa_attr.nLength = sizeof(SECURITY_ATTRIBUTES);
+    sa_attr.lpSecurityDescriptor = NULL;
+    sa_attr.bInheritHandle = TRUE;
+
+    handle.Set(CreateFile(output_file.value().c_str(),
+                          GENERIC_WRITE,
+                          FILE_SHARE_READ | FILE_SHARE_DELETE,
+                          &sa_attr,
+                          OPEN_EXISTING,
+                          FILE_ATTRIBUTE_TEMPORARY,
+                          NULL));
+    CHECK(handle.IsValid());
+    options.inherit_handles = true;
+    options.stdin_handle = INVALID_HANDLE_VALUE;
+    options.stdout_handle = handle.Get();
+    options.stderr_handle = handle.Get();
+  }
+#elif defined(OS_POSIX)
+  options.new_process_group = true;
+#if defined(OS_LINUX)
+  options.kill_on_parent_death = true;
+#endif  // defined(OS_LINUX)
+
+  FileHandleMappingVector fds_mapping;
+  ScopedFD output_file_fd;
+
+  if (redirect_stdio) {
+    output_file_fd.reset(open(output_file.value().c_str(), O_RDWR));
+    CHECK(output_file_fd.is_valid());
+
+    fds_mapping.push_back(std::make_pair(output_file_fd.get(), STDOUT_FILENO));
+    fds_mapping.push_back(std::make_pair(output_file_fd.get(), STDERR_FILENO));
+    options.fds_to_remap = &fds_mapping;
+  }
+#endif
+
+  bool was_timeout = false;
+  int exit_code = LaunchChildTestProcessWithOptions(
+      command_line, options, flags, timeout, &was_timeout);
+
+  if (redirect_stdio) {
+#if defined(OS_WIN)
+    FlushFileBuffers(handle.Get());
+    handle.Close();
+#elif defined(OS_POSIX)
+    output_file_fd.reset();
+#endif
+  }
+
+  std::string output_file_contents;
+  CHECK(ReadFileToString(output_file, &output_file_contents));
+
+  if (!DeleteFile(output_file, false)) {
+    // This needs to be non-fatal at least for Windows.
+    LOG(WARNING) << "Failed to delete " << output_file.AsUTF8Unsafe();
+  }
+
+  // Run target callback on the thread it was originating from, not on
+  // a worker pool thread.
+  task_runner->PostTask(FROM_HERE, Bind(&RunCallback, callback, exit_code,
+                                        TimeTicks::Now() - start_time,
+                                        was_timeout, output_file_contents));
+}
+
+}  // namespace
+
+const char kGTestFilterFlag[] = "gtest_filter";
+const char kGTestHelpFlag[]   = "gtest_help";
+const char kGTestListTestsFlag[] = "gtest_list_tests";
+const char kGTestRepeatFlag[] = "gtest_repeat";
+const char kGTestRunDisabledTestsFlag[] = "gtest_also_run_disabled_tests";
+const char kGTestOutputFlag[] = "gtest_output";
+
+TestLauncherDelegate::~TestLauncherDelegate() {
+}
+
+TestLauncher::TestLauncher(TestLauncherDelegate* launcher_delegate,
+                           size_t parallel_jobs)
+    : launcher_delegate_(launcher_delegate),
+      total_shards_(1),
+      shard_index_(0),
+      cycles_(1),
+      test_started_count_(0),
+      test_finished_count_(0),
+      test_success_count_(0),
+      test_broken_count_(0),
+      retry_count_(0),
+      retry_limit_(0),
+      run_result_(true),
+      watchdog_timer_(FROM_HERE,
+                      TimeDelta::FromSeconds(kOutputTimeoutSeconds),
+                      this,
+                      &TestLauncher::OnOutputTimeout),
+      parallel_jobs_(parallel_jobs) {
+}
+
+TestLauncher::~TestLauncher() {
+  if (worker_pool_owner_)
+    worker_pool_owner_->pool()->Shutdown();
+}
+
+bool TestLauncher::Run() {
+  if (!Init())
+    return false;
+
+  // Value of |cycles_| changes after each iteration. Keep track of the
+  // original value.
+  int requested_cycles = cycles_;
+
+#if defined(OS_POSIX)
+  CHECK_EQ(0, pipe(g_shutdown_pipe));
+
+  struct sigaction action;
+  memset(&action, 0, sizeof(action));
+  sigemptyset(&action.sa_mask);
+  action.sa_handler = &ShutdownPipeSignalHandler;
+
+  CHECK_EQ(0, sigaction(SIGINT, &action, NULL));
+  CHECK_EQ(0, sigaction(SIGQUIT, &action, NULL));
+  CHECK_EQ(0, sigaction(SIGTERM, &action, NULL));
+
+  MessageLoopForIO::FileDescriptorWatcher controller;
+  SignalFDWatcher watcher;
+
+  CHECK(MessageLoopForIO::current()->WatchFileDescriptor(
+            g_shutdown_pipe[0],
+            true,
+            MessageLoopForIO::WATCH_READ,
+            &controller,
+            &watcher));
+#endif  // defined(OS_POSIX)
+
+  // Start the watchdog timer.
+  watchdog_timer_.Reset();
+
+  ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, Bind(&TestLauncher::RunTestIteration, Unretained(this)));
+
+  MessageLoop::current()->Run();
+
+  if (requested_cycles != 1)
+    results_tracker_.PrintSummaryOfAllIterations();
+
+  MaybeSaveSummaryAsJSON();
+
+  return run_result_;
+}
+
+void TestLauncher::LaunchChildGTestProcess(
+    const CommandLine& command_line,
+    const std::string& wrapper,
+    TimeDelta timeout,
+    int flags,
+    const LaunchChildGTestProcessCallback& callback) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  // Record the exact command line used to launch the child.
+  CommandLine new_command_line(
+      PrepareCommandLineForGTest(command_line, wrapper));
+
+  // When running in parallel mode we need to redirect stdio to avoid mixed-up
+  // output. We also always redirect on the bots to get the test output into
+  // JSON summary.
+  bool redirect_stdio = (parallel_jobs_ > 1) || BotModeEnabled();
+
+  worker_pool_owner_->pool()->PostWorkerTask(
+      FROM_HERE, Bind(&DoLaunchChildTestProcess, new_command_line, timeout,
+                      flags, redirect_stdio, ThreadTaskRunnerHandle::Get(),
+                      Bind(&TestLauncher::OnLaunchTestProcessFinished,
+                           Unretained(this), callback)));
+}
+
+void TestLauncher::OnTestFinished(const TestResult& result) {
+  ++test_finished_count_;
+
+  bool print_snippet = false;
+  std::string print_test_stdio("auto");
+  if (CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kTestLauncherPrintTestStdio)) {
+    print_test_stdio = CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+        switches::kTestLauncherPrintTestStdio);
+  }
+  if (print_test_stdio == "auto") {
+    print_snippet = (result.status != TestResult::TEST_SUCCESS);
+  } else if (print_test_stdio == "always") {
+    print_snippet = true;
+  } else if (print_test_stdio == "never") {
+    print_snippet = false;
+  } else {
+    LOG(WARNING) << "Invalid value of " << switches::kTestLauncherPrintTestStdio
+                 << ": " << print_test_stdio;
+  }
+  if (print_snippet) {
+    std::vector<std::string> snippet_lines;
+    SplitStringDontTrim(result.output_snippet, '\n', &snippet_lines);
+    if (snippet_lines.size() > kOutputSnippetLinesLimit) {
+      size_t truncated_size = snippet_lines.size() - kOutputSnippetLinesLimit;
+      snippet_lines.erase(
+          snippet_lines.begin(),
+          snippet_lines.begin() + truncated_size);
+      snippet_lines.insert(snippet_lines.begin(), "<truncated>");
+    }
+    fprintf(stdout, "%s", JoinString(snippet_lines, "\n").c_str());
+    fflush(stdout);
+  }
+
+  if (result.status == TestResult::TEST_SUCCESS) {
+    ++test_success_count_;
+  } else {
+    tests_to_retry_.insert(result.full_name);
+  }
+
+  results_tracker_.AddTestResult(result);
+
+  // TODO(phajdan.jr): Align counter (padding).
+  std::string status_line(
+      StringPrintf("[%" PRIuS "/%" PRIuS "] %s ",
+                   test_finished_count_,
+                   test_started_count_,
+                   result.full_name.c_str()));
+  if (result.completed()) {
+    status_line.append(StringPrintf("(%" PRId64 " ms)",
+                                    result.elapsed_time.InMilliseconds()));
+  } else if (result.status == TestResult::TEST_TIMEOUT) {
+    status_line.append("(TIMED OUT)");
+  } else if (result.status == TestResult::TEST_CRASH) {
+    status_line.append("(CRASHED)");
+  } else if (result.status == TestResult::TEST_SKIPPED) {
+    status_line.append("(SKIPPED)");
+  } else if (result.status == TestResult::TEST_UNKNOWN) {
+    status_line.append("(UNKNOWN)");
+  } else {
+    // Fail very loudly so it's not ignored.
+    CHECK(false) << "Unhandled test result status: " << result.status;
+  }
+  fprintf(stdout, "%s\n", status_line.c_str());
+  fflush(stdout);
+
+  // We just printed a status line, reset the watchdog timer.
+  watchdog_timer_.Reset();
+
+  // Do not waste time on timeouts. We include tests with unknown results here
+  // because sometimes (e.g. hang in between unit tests) that's how a timeout
+  // gets reported.
+  if (result.status == TestResult::TEST_TIMEOUT ||
+      result.status == TestResult::TEST_UNKNOWN) {
+    test_broken_count_++;
+  }
+  size_t broken_threshold =
+      std::max(static_cast<size_t>(20), test_started_count_ / 10);
+  if (test_broken_count_ >= broken_threshold) {
+    fprintf(stdout, "Too many badly broken tests (%" PRIuS "), exiting now.\n",
+            test_broken_count_);
+    fflush(stdout);
+
+#if defined(OS_POSIX)
+    KillSpawnedTestProcesses();
+#endif  // defined(OS_POSIX)
+
+    results_tracker_.AddGlobalTag("BROKEN_TEST_EARLY_EXIT");
+    results_tracker_.AddGlobalTag(kUnreliableResultsTag);
+    MaybeSaveSummaryAsJSON();
+
+    exit(1);
+  }
+
+  if (test_finished_count_ != test_started_count_)
+    return;
+
+  if (tests_to_retry_.empty() || retry_count_ >= retry_limit_) {
+    OnTestIterationFinished();
+    return;
+  }
+
+  if (tests_to_retry_.size() >= broken_threshold) {
+    fprintf(stdout,
+            "Too many failing tests (%" PRIuS "), skipping retries.\n",
+            tests_to_retry_.size());
+    fflush(stdout);
+
+    results_tracker_.AddGlobalTag("BROKEN_TEST_SKIPPED_RETRIES");
+    results_tracker_.AddGlobalTag(kUnreliableResultsTag);
+
+    OnTestIterationFinished();
+    return;
+  }
+
+  retry_count_++;
+
+  std::vector<std::string> test_names(tests_to_retry_.begin(),
+                                      tests_to_retry_.end());
+
+  tests_to_retry_.clear();
+
+  size_t retry_started_count = launcher_delegate_->RetryTests(this, test_names);
+  if (retry_started_count == 0) {
+    // Signal failure, but continue to run all requested test iterations.
+    // With the summary of all iterations at the end this is a good default.
+    run_result_ = false;
+
+    OnTestIterationFinished();
+    return;
+  }
+
+  fprintf(stdout, "Retrying %" PRIuS " test%s (retry #%" PRIuS ")\n",
+          retry_started_count,
+          retry_started_count > 1 ? "s" : "",
+          retry_count_);
+  fflush(stdout);
+
+  test_started_count_ += retry_started_count;
+}
+
+bool TestLauncher::Init() {
+  const CommandLine* command_line = CommandLine::ForCurrentProcess();
+
+  // Initialize sharding. Command line takes precedence over legacy environment
+  // variables.
+  if (command_line->HasSwitch(switches::kTestLauncherTotalShards) &&
+      command_line->HasSwitch(switches::kTestLauncherShardIndex)) {
+    if (!StringToInt(
+            command_line->GetSwitchValueASCII(
+                switches::kTestLauncherTotalShards),
+            &total_shards_)) {
+      LOG(ERROR) << "Invalid value for " << switches::kTestLauncherTotalShards;
+      return false;
+    }
+    if (!StringToInt(
+            command_line->GetSwitchValueASCII(
+                switches::kTestLauncherShardIndex),
+            &shard_index_)) {
+      LOG(ERROR) << "Invalid value for " << switches::kTestLauncherShardIndex;
+      return false;
+    }
+    fprintf(stdout,
+            "Using sharding settings from command line. This is shard %d/%d\n",
+            shard_index_, total_shards_);
+    fflush(stdout);
+  } else {
+    if (!TakeInt32FromEnvironment(kTestTotalShards, &total_shards_))
+      return false;
+    if (!TakeInt32FromEnvironment(kTestShardIndex, &shard_index_))
+      return false;
+    fprintf(stdout,
+            "Using sharding settings from environment. This is shard %d/%d\n",
+            shard_index_, total_shards_);
+    fflush(stdout);
+  }
+  if (shard_index_ < 0 ||
+      total_shards_ < 0 ||
+      shard_index_ >= total_shards_) {
+    LOG(ERROR) << "Invalid sharding settings: we require 0 <= "
+               << kTestShardIndex << " < " << kTestTotalShards
+               << ", but you have " << kTestShardIndex << "=" << shard_index_
+               << ", " << kTestTotalShards << "=" << total_shards_ << ".\n";
+    return false;
+  }
+
+  // Make sure we don't pass any sharding-related environment to the child
+  // processes. This test launcher implements the sharding completely.
+  CHECK(UnsetEnvironmentVariableIfExists("GTEST_TOTAL_SHARDS"));
+  CHECK(UnsetEnvironmentVariableIfExists("GTEST_SHARD_INDEX"));
+
+  if (command_line->HasSwitch(kGTestRepeatFlag) &&
+      !StringToInt(command_line->GetSwitchValueASCII(kGTestRepeatFlag),
+                   &cycles_)) {
+    LOG(ERROR) << "Invalid value for " << kGTestRepeatFlag;
+    return false;
+  }
+
+  if (command_line->HasSwitch(switches::kTestLauncherRetryLimit)) {
+    int retry_limit = -1;
+    if (!StringToInt(command_line->GetSwitchValueASCII(
+                         switches::kTestLauncherRetryLimit), &retry_limit) ||
+        retry_limit < 0) {
+      LOG(ERROR) << "Invalid value for " << switches::kTestLauncherRetryLimit;
+      return false;
+    }
+
+    retry_limit_ = retry_limit;
+  } else if (!command_line->HasSwitch(kGTestFilterFlag) || BotModeEnabled()) {
+    // Retry failures 3 times by default if we are running all of the tests or
+    // in bot mode.
+    retry_limit_ = 3;
+  }
+
+  if (command_line->HasSwitch(switches::kTestLauncherJobs)) {
+    int jobs = -1;
+    if (!StringToInt(command_line->GetSwitchValueASCII(
+                         switches::kTestLauncherJobs), &jobs) ||
+        jobs < 0) {
+      LOG(ERROR) << "Invalid value for " << switches::kTestLauncherJobs;
+      return false;
+    }
+
+    parallel_jobs_ = jobs;
+  } else if (command_line->HasSwitch(kGTestFilterFlag) && !BotModeEnabled()) {
+    // Do not run jobs in parallel by default if we are running a subset of
+    // the tests and if bot mode is off.
+    parallel_jobs_ = 1;
+  }
+
+  fprintf(stdout, "Using %" PRIuS " parallel jobs.\n", parallel_jobs_);
+  fflush(stdout);
+  worker_pool_owner_.reset(
+      new SequencedWorkerPoolOwner(parallel_jobs_, "test_launcher"));
+
+  if (command_line->HasSwitch(switches::kTestLauncherFilterFile) &&
+      command_line->HasSwitch(kGTestFilterFlag)) {
+    LOG(ERROR) << "Only one of --test-launcher-filter-file and --gtest_filter "
+               << "at a time is allowed.";
+    return false;
+  }
+
+  if (command_line->HasSwitch(switches::kTestLauncherFilterFile)) {
+    std::string filter;
+    if (!ReadFileToString(
+            command_line->GetSwitchValuePath(switches::kTestLauncherFilterFile),
+            &filter)) {
+      LOG(ERROR) << "Failed to read the filter file.";
+      return false;
+    }
+
+    std::vector<std::string> filter_lines;
+    SplitString(filter, '\n', &filter_lines);
+    for (size_t i = 0; i < filter_lines.size(); i++) {
+      if (filter_lines[i].empty())
+        continue;
+
+      if (filter_lines[i][0] == '-')
+        negative_test_filter_.push_back(filter_lines[i].substr(1));
+      else
+        positive_test_filter_.push_back(filter_lines[i]);
+    }
+  } else {
+    // Split --gtest_filter at '-', if there is one, to separate into
+    // positive filter and negative filter portions.
+    std::string filter = command_line->GetSwitchValueASCII(kGTestFilterFlag);
+    size_t dash_pos = filter.find('-');
+    if (dash_pos == std::string::npos) {
+      SplitString(filter, ':', &positive_test_filter_);
+    } else {
+      // Everything up to the dash.
+      SplitString(filter.substr(0, dash_pos), ':', &positive_test_filter_);
+
+      // Everything after the dash.
+      SplitString(filter.substr(dash_pos + 1), ':', &negative_test_filter_);
+    }
+  }
+
+  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;
+  }
+
+#if defined(NDEBUG)
+  results_tracker_.AddGlobalTag("MODE_RELEASE");
+#else
+  results_tracker_.AddGlobalTag("MODE_DEBUG");
+#endif
+
+  // Operating systems (sorted alphabetically).
+  // Note that they can deliberately overlap, e.g. OS_LINUX is a subset
+  // of OS_POSIX.
+#if defined(OS_ANDROID)
+  results_tracker_.AddGlobalTag("OS_ANDROID");
+#endif
+
+#if defined(OS_BSD)
+  results_tracker_.AddGlobalTag("OS_BSD");
+#endif
+
+#if defined(OS_FREEBSD)
+  results_tracker_.AddGlobalTag("OS_FREEBSD");
+#endif
+
+#if defined(OS_IOS)
+  results_tracker_.AddGlobalTag("OS_IOS");
+#endif
+
+#if defined(OS_LINUX)
+  results_tracker_.AddGlobalTag("OS_LINUX");
+#endif
+
+#if defined(OS_MACOSX)
+  results_tracker_.AddGlobalTag("OS_MACOSX");
+#endif
+
+#if defined(OS_NACL)
+  results_tracker_.AddGlobalTag("OS_NACL");
+#endif
+
+#if defined(OS_OPENBSD)
+  results_tracker_.AddGlobalTag("OS_OPENBSD");
+#endif
+
+#if defined(OS_POSIX)
+  results_tracker_.AddGlobalTag("OS_POSIX");
+#endif
+
+#if defined(OS_SOLARIS)
+  results_tracker_.AddGlobalTag("OS_SOLARIS");
+#endif
+
+#if defined(OS_WIN)
+  results_tracker_.AddGlobalTag("OS_WIN");
+#endif
+
+  // CPU-related tags.
+#if defined(ARCH_CPU_32_BITS)
+  results_tracker_.AddGlobalTag("CPU_32_BITS");
+#endif
+
+#if defined(ARCH_CPU_64_BITS)
+  results_tracker_.AddGlobalTag("CPU_64_BITS");
+#endif
+
+  return true;
+}
+
+void TestLauncher::RunTests() {
+  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);
+
+    results_tracker_.AddTest(test_name);
+
+    const CommandLine* command_line = CommandLine::ForCurrentProcess();
+    if (test_name.find("DISABLED") != std::string::npos) {
+      results_tracker_.AddDisabledTest(test_name);
+
+      // Skip disabled tests unless explicitly requested.
+      if (!command_line->HasSwitch(kGTestRunDisabledTestsFlag))
+        continue;
+    }
+
+    if (!launcher_delegate_->ShouldRunTest(tests_[i].first, tests_[i].second))
+      continue;
+
+    // Skip the test that doesn't match the filter (if given).
+    if (!positive_test_filter_.empty()) {
+      bool found = false;
+      for (size_t k = 0; k < positive_test_filter_.size(); ++k) {
+        if (MatchPattern(test_name, positive_test_filter_[k])) {
+          found = true;
+          break;
+        }
+      }
+
+      if (!found)
+        continue;
+    }
+    bool excluded = false;
+    for (size_t k = 0; k < negative_test_filter_.size(); ++k) {
+      if (MatchPattern(test_name, negative_test_filter_[k])) {
+        excluded = true;
+        break;
+      }
+    }
+    if (excluded)
+      continue;
+
+    if (Hash(test_name) % total_shards_ != static_cast<uint32>(shard_index_))
+      continue;
+
+    test_names.push_back(test_name);
+  }
+
+  test_started_count_ = launcher_delegate_->RunTests(this, test_names);
+
+  if (test_started_count_ == 0) {
+    fprintf(stdout, "0 tests run\n");
+    fflush(stdout);
+
+    // No tests have actually been started, so kick off the next iteration.
+    ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, Bind(&TestLauncher::RunTestIteration, Unretained(this)));
+  }
+}
+
+void TestLauncher::RunTestIteration() {
+  if (cycles_ == 0) {
+    MessageLoop::current()->Quit();
+    return;
+  }
+
+  // Special value "-1" means "repeat indefinitely".
+  cycles_ = (cycles_ == -1) ? cycles_ : cycles_ - 1;
+
+  test_started_count_ = 0;
+  test_finished_count_ = 0;
+  test_success_count_ = 0;
+  test_broken_count_ = 0;
+  retry_count_ = 0;
+  tests_to_retry_.clear();
+  results_tracker_.OnTestIterationStarting();
+
+  ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, Bind(&TestLauncher::RunTests, Unretained(this)));
+}
+
+void TestLauncher::MaybeSaveSummaryAsJSON() {
+  const CommandLine* command_line = CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(switches::kTestLauncherSummaryOutput)) {
+    FilePath summary_path(command_line->GetSwitchValuePath(
+                              switches::kTestLauncherSummaryOutput));
+    if (!results_tracker_.SaveSummaryAsJSON(summary_path)) {
+      LOG(ERROR) << "Failed to save test launcher output summary.";
+    }
+  }
+}
+
+void TestLauncher::OnLaunchTestProcessFinished(
+    const LaunchChildGTestProcessCallback& callback,
+    int exit_code,
+    const TimeDelta& elapsed_time,
+    bool was_timeout,
+    const std::string& output) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  callback.Run(exit_code, elapsed_time, was_timeout, output);
+}
+
+void TestLauncher::OnTestIterationFinished() {
+  TestResultsTracker::TestStatusMap tests_by_status(
+      results_tracker_.GetTestStatusMapForCurrentIteration());
+  if (!tests_by_status[TestResult::TEST_UNKNOWN].empty())
+    results_tracker_.AddGlobalTag(kUnreliableResultsTag);
+
+  // When we retry tests, success is determined by having nothing more
+  // to retry (everything eventually passed), as opposed to having
+  // no failures at all.
+  if (tests_to_retry_.empty()) {
+    fprintf(stdout, "SUCCESS: all tests passed.\n");
+    fflush(stdout);
+  } else {
+    // Signal failure, but continue to run all requested test iterations.
+    // With the summary of all iterations at the end this is a good default.
+    run_result_ = false;
+  }
+
+  results_tracker_.PrintSummaryOfCurrentIteration();
+
+  // Kick off the next iteration.
+  ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, Bind(&TestLauncher::RunTestIteration, Unretained(this)));
+}
+
+void TestLauncher::OnOutputTimeout() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  AutoLock lock(g_live_processes_lock.Get());
+
+  fprintf(stdout, "Still waiting for the following processes to finish:\n");
+
+  for (std::map<ProcessHandle, CommandLine>::iterator i =
+           g_live_processes.Get().begin();
+       i != g_live_processes.Get().end();
+       ++i) {
+#if defined(OS_WIN)
+    fwprintf(stdout, L"\t%s\n", i->second.GetCommandLineString().c_str());
+#else
+    fprintf(stdout, "\t%s\n", i->second.GetCommandLineString().c_str());
+#endif
+  }
+
+  fflush(stdout);
+
+  // Arm the timer again - otherwise it would fire only once.
+  watchdog_timer_.Reset();
+}
+
+std::string GetTestOutputSnippet(const TestResult& result,
+                                 const std::string& full_output) {
+  size_t run_pos = full_output.find(std::string("[ RUN      ] ") +
+                                    result.full_name);
+  if (run_pos == std::string::npos)
+    return std::string();
+
+  size_t end_pos = full_output.find(std::string("[  FAILED  ] ") +
+                                    result.full_name,
+                                    run_pos);
+  // Only clip the snippet to the "OK" message if the test really
+  // succeeded. It still might have e.g. crashed after printing it.
+  if (end_pos == std::string::npos &&
+      result.status == TestResult::TEST_SUCCESS) {
+    end_pos = full_output.find(std::string("[       OK ] ") +
+                               result.full_name,
+                               run_pos);
+  }
+  if (end_pos != std::string::npos) {
+    size_t newline_pos = full_output.find("\n", end_pos);
+    if (newline_pos != std::string::npos)
+      end_pos = newline_pos + 1;
+  }
+
+  std::string snippet(full_output.substr(run_pos));
+  if (end_pos != std::string::npos)
+    snippet = full_output.substr(run_pos, end_pos - run_pos);
+
+  return snippet;
+}
+
+}  // namespace base
diff --git a/base/test/launcher/test_launcher.h b/base/test/launcher/test_launcher.h
new file mode 100644
index 0000000..544df63
--- /dev/null
+++ b/base/test/launcher/test_launcher.h
@@ -0,0 +1,210 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_LAUNCHER_TEST_LAUNCHER_H_
+#define BASE_TEST_LAUNCHER_TEST_LAUNCHER_H_
+
+#include <set>
+#include <string>
+
+#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"
+#include "base/timer/timer.h"
+
+namespace testing {
+class TestCase;
+class TestInfo;
+}
+
+namespace base {
+
+class CommandLine;
+struct LaunchOptions;
+class SequencedWorkerPoolOwner;
+class TestLauncher;
+
+// Constants for GTest command-line flags.
+extern const char kGTestFilterFlag[];
+extern const char kGTestHelpFlag[];
+extern const char kGTestListTestsFlag[];
+extern const char kGTestRepeatFlag[];
+extern const char kGTestRunDisabledTestsFlag[];
+extern const char kGTestOutputFlag[];
+
+// Interface for use with LaunchTests that abstracts away exact details
+// 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.
+  virtual bool ShouldRunTest(const std::string& test_case_name,
+                             const std::string& test_name) = 0;
+
+  // Called to make the delegate run the specified tests. The delegate must
+  // return the number of actual tests it's going to run (can be smaller,
+  // equal to, or larger than size of |test_names|). It must also call
+  // |test_launcher|'s OnTestFinished method once per every run test,
+  // regardless of its success.
+  virtual size_t RunTests(TestLauncher* test_launcher,
+                          const std::vector<std::string>& test_names) = 0;
+
+  // Called to make the delegate retry the specified tests. The delegate must
+  // return the number of actual tests it's going to retry (can be smaller,
+  // equal to, or larger than size of |test_names|). It must also call
+  // |test_launcher|'s OnTestFinished method once per every retried test,
+  // regardless of its success.
+  virtual size_t RetryTests(TestLauncher* test_launcher,
+                            const std::vector<std::string>& test_names) = 0;
+
+ protected:
+  virtual ~TestLauncherDelegate();
+};
+
+// Launches tests using a TestLauncherDelegate.
+class TestLauncher {
+ public:
+  // Flags controlling behavior of LaunchChildGTestProcess.
+  enum LaunchChildGTestProcessFlags {
+    // Allows usage of job objects on Windows. Helps properly clean up child
+    // processes.
+    USE_JOB_OBJECTS = (1 << 0),
+
+    // Allows breakaway from job on Windows. May result in some child processes
+    // not being properly terminated after launcher dies if these processes
+    // fail to cooperate.
+    ALLOW_BREAKAWAY_FROM_JOB = (1 << 1),
+  };
+
+  // Constructor. |parallel_jobs| is the limit of simultaneous parallel test
+  // jobs.
+  TestLauncher(TestLauncherDelegate* launcher_delegate, size_t parallel_jobs);
+  ~TestLauncher();
+
+  // Runs the launcher. Must be called at most once.
+  bool Run() WARN_UNUSED_RESULT;
+
+  // Callback called after a child process finishes. First argument is the exit
+  // code, second one is child process elapsed time, third one is true if
+  // the child process was terminated because of a timeout, and fourth one
+  // contains output of the child (stdout and stderr together).
+  typedef Callback<void(int, const TimeDelta&, bool, const std::string&)>
+      LaunchChildGTestProcessCallback;
+
+  // Launches a child process (assumed to be gtest-based binary) using
+  // |command_line|. If |wrapper| is not empty, it is prepended to the final
+  // command line. If the child process is still running after |timeout|, it
+  // is terminated. After the child process finishes |callback| is called
+  // on the same thread this method was called.
+  void LaunchChildGTestProcess(const CommandLine& command_line,
+                               const std::string& wrapper,
+                               base::TimeDelta timeout,
+                               int flags,
+                               const LaunchChildGTestProcessCallback& callback);
+
+  // Called when a test has finished running.
+  void OnTestFinished(const TestResult& result);
+
+ private:
+  bool Init() WARN_UNUSED_RESULT;
+
+  // Runs all tests in current iteration. Uses callbacks to communicate success.
+  void RunTests();
+
+  void RunTestIteration();
+
+  // Saves test results summary as JSON if requested from command line.
+  void MaybeSaveSummaryAsJSON();
+
+  // Called on a worker thread after a child process finishes.
+  void OnLaunchTestProcessFinished(
+      const LaunchChildGTestProcessCallback& callback,
+      int exit_code,
+      const TimeDelta& elapsed_time,
+      bool was_timeout,
+      const std::string& output);
+
+  // Called when a test iteration is finished.
+  void OnTestIterationFinished();
+
+  // Called by the delay timer when no output was made for a while.
+  void OnOutputTimeout();
+
+  // Make sure we don't accidentally call the wrong methods e.g. on the worker
+  // pool thread. With lots of callbacks used this is non-trivial.
+  // Should be the first member so that it's destroyed last: when destroying
+  // other members, especially the worker pool, we may check the code is running
+  // on the correct thread.
+  ThreadChecker thread_checker_;
+
+  TestLauncherDelegate* launcher_delegate_;
+
+  // Support for outer sharding, just like gtest does.
+  int32 total_shards_;  // Total number of outer shards, at least one.
+  int32 shard_index_;   // Index of shard the launcher is to run.
+
+  int cycles_;  // Number of remaining test itreations, or -1 for infinite.
+
+  // Test filters (empty means no filter).
+  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_;
+
+  // Number of tests finished in this iteration.
+  size_t test_finished_count_;
+
+  // Number of tests successfully finished in this iteration.
+  size_t test_success_count_;
+
+  // Number of tests either timing out or having an unknown result,
+  // likely indicating a more systemic problem if widespread.
+  size_t test_broken_count_;
+
+  // Number of retries in this iteration.
+  size_t retry_count_;
+
+  // Maximum number of retries per iteration.
+  size_t retry_limit_;
+
+  // Tests to retry in this iteration.
+  std::set<std::string> tests_to_retry_;
+
+  // Result to be returned from Run.
+  bool run_result_;
+
+  TestResultsTracker results_tracker_;
+
+  // Watchdog timer to make sure we do not go without output for too long.
+  DelayTimer<TestLauncher> watchdog_timer_;
+
+  // Number of jobs to run in parallel.
+  size_t parallel_jobs_;
+
+  // Worker pool used to launch processes in parallel.
+  scoped_ptr<SequencedWorkerPoolOwner> worker_pool_owner_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestLauncher);
+};
+
+// Extract part from |full_output| that applies to |result|.
+std::string GetTestOutputSnippet(const TestResult& result,
+                                 const std::string& full_output);
+
+}  // namespace base
+
+#endif  // BASE_TEST_LAUNCHER_TEST_LAUNCHER_H_
diff --git a/base/test/launcher/test_launcher_ios.cc b/base/test/launcher/test_launcher_ios.cc
new file mode 100644
index 0000000..ecd31ae
--- /dev/null
+++ b/base/test/launcher/test_launcher_ios.cc
@@ -0,0 +1,187 @@
+// 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.
+
+#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/strings/string_util.h"
+#include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/test_switches.h"
+#include "base/test/test_timeouts.h"
+
+namespace {
+
+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 IOSUnitTestPlatformDelegate : public base::UnitTestPlatformDelegate {
+ public:
+  IOSUnitTestPlatformDelegate() {
+  }
+
+  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);
+  }
+
+  bool CreateTemporaryFile(base::FilePath* path) override {
+    if (!CreateTemporaryDirInDir(writable_path_, std::string(), path))
+      return false;
+    *path = path->AppendASCII("test_results.xml");
+    return true;
+  }
+
+  base::CommandLine GetCommandLineForChildGTestProcess(
+      const std::vector<std::string>& test_names,
+      const base::FilePath& output_file) override {
+    base::CommandLine cmd_line(dir_exe_.AppendASCII(test_name_ + ".app"));
+    cmd_line.AppendSwitchPath(switches::kTestLauncherOutput, output_file);
+    cmd_line.AppendSwitchASCII(base::kGTestFilterFlag,
+                               JoinString(test_names, ":"));
+    return cmd_line;
+  }
+
+  std::string GetWrapperForChildGTestProcess() override {
+    return dir_exe_.AppendASCII("iossim").value();
+  }
+
+  void RelaunchTests(base::TestLauncher* test_launcher,
+                     const std::vector<std::string>& test_names,
+                     int launch_flags) override {
+    // Relaunch all tests in one big batch, since overhead of smaller batches
+    // is too big for serialized runs inside ios simulator.
+    RunUnitTestsBatch(test_launcher, this, test_names, launch_flags);
+  }
+
+ 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(IOSUnitTestPlatformDelegate);
+};
+
+}  // namespace
+
+int main(int argc, char** argv) {
+  base::AtExitManager at_exit;
+
+  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;
+
+  IOSUnitTestPlatformDelegate platform_delegate;
+  if (!platform_delegate.Init()) {
+    fprintf(stderr, "Failed to intialize test launcher platform delegate.\n");
+    fflush(stderr);
+    return 1;
+  }
+  base::UnitTestLauncherDelegate delegate(&platform_delegate, 0, false);
+  // 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/base/test/launcher/test_launcher_nacl_nonsfi.cc b/base/test/launcher/test_launcher_nacl_nonsfi.cc
new file mode 100644
index 0000000..fa52604
--- /dev/null
+++ b/base/test/launcher/test_launcher_nacl_nonsfi.cc
@@ -0,0 +1,160 @@
+// 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 <inttypes.h>
+#include <stdio.h>
+
+#include <string>
+
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/message_loop/message_loop.h"
+#include "base/path_service.h"
+#include "base/process/launch.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_tokenizer.h"
+#include "base/strings/string_util.h"
+#include "base/sys_info.h"
+#include "base/test/launcher/test_launcher.h"
+#include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/test_switches.h"
+#include "base/test/test_timeouts.h"
+
+namespace base {
+
+namespace {
+
+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 NonSfiUnitTestPlatformDelegate : public base::UnitTestPlatformDelegate {
+ public:
+  NonSfiUnitTestPlatformDelegate() {
+  }
+
+  bool Init(const std::string& test_binary) {
+    base::FilePath dir_exe;
+    if (!PathService::Get(base::DIR_EXE, &dir_exe)) {
+      LOG(ERROR) << "Failed to get directory of the current executable.";
+      return false;
+    }
+
+    test_path_ = dir_exe.AppendASCII(test_binary);
+    return true;
+  }
+
+ private:
+  bool CreateTemporaryFile(base::FilePath* path) override {
+    if (!base::CreateNewTempDirectory(base::FilePath::StringType(), path))
+      return false;
+    *path = path->AppendASCII("test_results.xml");
+    return true;
+  }
+
+  bool GetTests(std::vector<base::SplitTestName>* output) override {
+    base::FilePath output_file;
+    if (!base::CreateTemporaryFile(&output_file)) {
+      LOG(ERROR) << "Failed to create a temp file.";
+      return false;
+    }
+
+    base::CommandLine cmd_line(test_path_);
+    cmd_line.AppendSwitchPath(switches::kTestLauncherListTests, output_file);
+
+    base::LaunchOptions launch_options;
+    launch_options.wait = true;
+
+    if (!base::LaunchProcess(cmd_line, launch_options).IsValid())
+      return false;
+
+    return base::ReadTestNamesFromFile(output_file, output);
+  }
+
+  std::string GetWrapperForChildGTestProcess() override {
+    return std::string();
+  }
+
+  base::CommandLine GetCommandLineForChildGTestProcess(
+      const std::vector<std::string>& test_names,
+      const base::FilePath& output_file) override {
+    base::CommandLine cmd_line(test_path_);
+    cmd_line.AppendSwitchPath(
+        switches::kTestLauncherOutput, output_file);
+    cmd_line.AppendSwitchASCII(
+        base::kGTestFilterFlag, JoinString(test_names, ":"));
+    return cmd_line;
+  }
+
+  void RelaunchTests(base::TestLauncher* test_launcher,
+                     const std::vector<std::string>& test_names,
+                     int launch_flags) override {
+    RunUnitTestsBatch(test_launcher, this, test_names, launch_flags);
+  }
+
+  base::FilePath test_path_;
+};
+
+}  // namespace
+
+int TestLauncherNonSfiMain(const std::string& test_binary) {
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(kHelpFlag)) {
+    PrintUsage();
+    return 0;
+  }
+
+  base::TimeTicks start_time(base::TimeTicks::Now());
+
+  TestTimeouts::Initialize();
+
+  base::MessageLoopForIO message_loop;
+
+  NonSfiUnitTestPlatformDelegate platform_delegate;
+  if (!platform_delegate.Init(test_binary)) {
+    fprintf(stderr, "Failed to initialize test launcher.\n");
+    fflush(stderr);
+    return 1;
+  }
+
+  base::UnitTestLauncherDelegate delegate(&platform_delegate, 10, true);
+  base::TestLauncher launcher(&delegate, base::SysInfo::NumberOfProcessors());
+  bool success = launcher.Run();
+
+  fprintf(stdout, "Tests took %" PRId64 " seconds.\n",
+          (base::TimeTicks::Now() - start_time).InSeconds());
+  fflush(stdout);
+  return success ? 0 : 1;
+}
+
+}  // namespace base
diff --git a/base/test/launcher/test_launcher_nacl_nonsfi.h b/base/test/launcher/test_launcher_nacl_nonsfi.h
new file mode 100644
index 0000000..6cb3785
--- /dev/null
+++ b/base/test/launcher/test_launcher_nacl_nonsfi.h
@@ -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.
+
+#ifndef BASE_TEST_LAUNCHER_TEST_LAUNCHER_NACL_NONSFI_H_
+#define BASE_TEST_LAUNCHER_TEST_LAUNCHER_NACL_NONSFI_H_
+
+#include <string>
+
+namespace base {
+
+// Launches the NaCl Non-SFI test binary |test_binary|.
+int TestLauncherNonSfiMain(const std::string& test_binary);
+
+}  // namespace base
+
+#endif  // BASE_TEST_LAUNCHER_TEST_LAUNCHER_NACL_NONSFI_H_
diff --git a/base/test/launcher/test_result.cc b/base/test/launcher/test_result.cc
new file mode 100644
index 0000000..70d7a80
--- /dev/null
+++ b/base/test/launcher/test_result.cc
@@ -0,0 +1,52 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/launcher/test_result.h"
+
+#include "base/logging.h"
+
+namespace base {
+
+TestResult::TestResult() : status(TEST_UNKNOWN) {
+}
+
+TestResult::~TestResult() {
+}
+
+std::string TestResult::StatusAsString() const {
+  switch (status) {
+    case TEST_UNKNOWN:
+      return "UNKNOWN";
+    case TEST_SUCCESS:
+      return "SUCCESS";
+    case TEST_FAILURE:
+      return "FAILURE";
+    case TEST_FAILURE_ON_EXIT:
+      return "FAILURE_ON_EXIT";
+    case TEST_CRASH:
+      return "CRASH";
+    case TEST_TIMEOUT:
+      return "TIMEOUT";
+    case TEST_SKIPPED:
+      return "SKIPPED";
+     // Rely on compiler warnings to ensure all possible values are handled.
+  }
+
+  NOTREACHED();
+  return std::string();
+}
+
+std::string TestResult::GetTestName() const {
+  size_t dot_pos = full_name.find('.');
+  CHECK_NE(dot_pos, std::string::npos);
+  return full_name.substr(dot_pos + 1);
+}
+
+std::string TestResult::GetTestCaseName() const {
+  size_t dot_pos = full_name.find('.');
+  CHECK_NE(dot_pos, std::string::npos);
+  return full_name.substr(0, dot_pos);
+}
+
+}  // namespace base
diff --git a/base/test/launcher/test_result.h b/base/test/launcher/test_result.h
new file mode 100644
index 0000000..b61cdd4
--- /dev/null
+++ b/base/test/launcher/test_result.h
@@ -0,0 +1,61 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_LAUNCHER_TEST_RESULT_H_
+#define BASE_TEST_LAUNCHER_TEST_RESULT_H_
+
+#include <string>
+
+#include "base/time/time.h"
+
+namespace base {
+
+// Structure containing result of a single test.
+struct TestResult {
+  enum Status {
+    TEST_UNKNOWN,          // Status not set.
+    TEST_SUCCESS,          // Test passed.
+    TEST_FAILURE,          // Assertion failure (think EXPECT_TRUE, not DCHECK).
+    TEST_FAILURE_ON_EXIT,  // Test passed but executable exit code was non-zero.
+    TEST_TIMEOUT,          // Test timed out and was killed.
+    TEST_CRASH,            // Test crashed (includes CHECK/DCHECK failures).
+    TEST_SKIPPED,          // Test skipped (not run at all).
+  };
+
+  TestResult();
+  ~TestResult();
+
+  // Returns the test status as string (e.g. for display).
+  std::string StatusAsString() const;
+
+  // Returns the test name (e.g. "B" for "A.B").
+  std::string GetTestName() const;
+
+  // Returns the test case name (e.g. "A" for "A.B").
+  std::string GetTestCaseName() const;
+
+  // Returns true if the test has completed (i.e. the test binary exited
+  // normally, possibly with an exit code indicating failure, but didn't crash
+  // or time out in the middle of the test).
+  bool completed() const {
+    return status == TEST_SUCCESS ||
+        status == TEST_FAILURE ||
+        status == TEST_FAILURE_ON_EXIT;
+  }
+
+  // Full name of the test (e.g. "A.B").
+  std::string full_name;
+
+  Status status;
+
+  // Time it took to run the test.
+  base::TimeDelta elapsed_time;
+
+  // Output of just this test (optional).
+  std::string output_snippet;
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_LAUNCHER_TEST_RESULT_H_
diff --git a/base/test/launcher/test_results_tracker.cc b/base/test/launcher/test_results_tracker.cc
new file mode 100644
index 0000000..c4cb233
--- /dev/null
+++ b/base/test/launcher/test_results_tracker.cc
@@ -0,0 +1,353 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/launcher/test_results_tracker.h"
+
+#include "base/base64.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/format_macros.h"
+#include "base/json/json_file_value_serializer.h"
+#include "base/json/string_escape.h"
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/launcher/test_launcher.h"
+#include "base/values.h"
+
+namespace base {
+
+namespace {
+
+// The default output file for XML output.
+const FilePath::CharType kDefaultOutputFile[] = FILE_PATH_LITERAL(
+    "test_detail.xml");
+
+// Utility function to print a list of test names. Uses iterator to be
+// compatible with different containers, like vector and set.
+template<typename InputIterator>
+void PrintTests(InputIterator first,
+                InputIterator last,
+                const std::string& description) {
+  size_t count = std::distance(first, last);
+  if (count == 0)
+    return;
+
+  fprintf(stdout,
+          "%" PRIuS " test%s %s:\n",
+          count,
+          count != 1 ? "s" : "",
+          description.c_str());
+  for (InputIterator i = first; i != last; ++i)
+    fprintf(stdout, "    %s\n", (*i).c_str());
+  fflush(stdout);
+}
+
+std::string TestNameWithoutDisabledPrefix(const std::string& test_name) {
+  std::string test_name_no_disabled(test_name);
+  ReplaceSubstringsAfterOffset(&test_name_no_disabled, 0, "DISABLED_", "");
+  return test_name_no_disabled;
+}
+
+}  // namespace
+
+TestResultsTracker::TestResultsTracker() : iteration_(-1), out_(NULL) {
+}
+
+TestResultsTracker::~TestResultsTracker() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  if (!out_)
+    return;
+  fprintf(out_, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+  fprintf(out_, "<testsuites name=\"AllTests\" tests=\"\" failures=\"\""
+          " disabled=\"\" errors=\"\" time=\"\">\n");
+
+  // Maps test case names to test results.
+  typedef std::map<std::string, std::vector<TestResult> > TestCaseMap;
+  TestCaseMap test_case_map;
+
+  for (PerIterationData::ResultsMap::iterator i =
+           per_iteration_data_[iteration_].results.begin();
+       i != per_iteration_data_[iteration_].results.end();
+       ++i) {
+    // Use the last test result as the final one.
+    TestResult result = i->second.test_results.back();
+    test_case_map[result.GetTestCaseName()].push_back(result);
+  }
+  for (TestCaseMap::iterator i = test_case_map.begin();
+       i != test_case_map.end();
+       ++i) {
+    fprintf(out_, "  <testsuite name=\"%s\" tests=\"%" PRIuS "\" failures=\"\""
+            " disabled=\"\" errors=\"\" time=\"\">\n",
+            i->first.c_str(), i->second.size());
+    for (size_t j = 0; j < i->second.size(); ++j) {
+      const TestResult& result = i->second[j];
+      fprintf(out_, "    <testcase name=\"%s\" status=\"run\" time=\"%.3f\""
+              " classname=\"%s\">\n",
+              result.GetTestName().c_str(),
+              result.elapsed_time.InSecondsF(),
+              result.GetTestCaseName().c_str());
+      if (result.status != TestResult::TEST_SUCCESS)
+        fprintf(out_, "      <failure message=\"\" type=\"\"></failure>\n");
+      fprintf(out_, "    </testcase>\n");
+    }
+    fprintf(out_, "  </testsuite>\n");
+  }
+  fprintf(out_, "</testsuites>\n");
+  fclose(out_);
+}
+
+bool TestResultsTracker::Init(const CommandLine& command_line) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  // Prevent initializing twice.
+  if (out_) {
+    NOTREACHED();
+    return false;
+  }
+
+  if (!command_line.HasSwitch(kGTestOutputFlag))
+    return true;
+
+  std::string flag = command_line.GetSwitchValueASCII(kGTestOutputFlag);
+  size_t colon_pos = flag.find(':');
+  FilePath path;
+  if (colon_pos != std::string::npos) {
+    FilePath flag_path =
+        command_line.GetSwitchValuePath(kGTestOutputFlag);
+    FilePath::StringType path_string = flag_path.value();
+    path = FilePath(path_string.substr(colon_pos + 1));
+    // If the given path ends with '/', consider it is a directory.
+    // Note: This does NOT check that a directory (or file) actually exists
+    // (the behavior is same as what gtest does).
+    if (path.EndsWithSeparator()) {
+      FilePath executable = command_line.GetProgram().BaseName();
+      path = path.Append(executable.ReplaceExtension(
+                             FilePath::StringType(FILE_PATH_LITERAL("xml"))));
+    }
+  }
+  if (path.value().empty())
+    path = FilePath(kDefaultOutputFile);
+  FilePath dir_name = path.DirName();
+  if (!DirectoryExists(dir_name)) {
+    LOG(WARNING) << "The output directory does not exist. "
+                 << "Creating the directory: " << dir_name.value();
+    // Create the directory if necessary (because the gtest does the same).
+    if (!base::CreateDirectory(dir_name)) {
+      LOG(ERROR) << "Failed to created directory " << dir_name.value();
+      return false;
+    }
+  }
+  out_ = OpenFile(path, "w");
+  if (!out_) {
+    LOG(ERROR) << "Cannot open output file: "
+               << path.value() << ".";
+    return false;
+  }
+
+  return true;
+}
+
+void TestResultsTracker::OnTestIterationStarting() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  // Start with a fresh state for new iteration.
+  iteration_++;
+  per_iteration_data_.push_back(PerIterationData());
+}
+
+void TestResultsTracker::AddTest(const std::string& test_name) {
+  // Record disabled test names without DISABLED_ prefix so that they are easy
+  // to compare with regular test names, e.g. before or after disabling.
+  all_tests_.insert(TestNameWithoutDisabledPrefix(test_name));
+}
+
+void TestResultsTracker::AddDisabledTest(const std::string& test_name) {
+  // Record disabled test names without DISABLED_ prefix so that they are easy
+  // to compare with regular test names, e.g. before or after disabling.
+  disabled_tests_.insert(TestNameWithoutDisabledPrefix(test_name));
+}
+
+void TestResultsTracker::AddTestResult(const TestResult& result) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  per_iteration_data_[iteration_].results[
+      result.full_name].test_results.push_back(result);
+}
+
+void TestResultsTracker::PrintSummaryOfCurrentIteration() const {
+  TestStatusMap tests_by_status(GetTestStatusMapForCurrentIteration());
+
+  PrintTests(tests_by_status[TestResult::TEST_FAILURE].begin(),
+             tests_by_status[TestResult::TEST_FAILURE].end(),
+             "failed");
+  PrintTests(tests_by_status[TestResult::TEST_FAILURE_ON_EXIT].begin(),
+             tests_by_status[TestResult::TEST_FAILURE_ON_EXIT].end(),
+             "failed on exit");
+  PrintTests(tests_by_status[TestResult::TEST_TIMEOUT].begin(),
+             tests_by_status[TestResult::TEST_TIMEOUT].end(),
+             "timed out");
+  PrintTests(tests_by_status[TestResult::TEST_CRASH].begin(),
+             tests_by_status[TestResult::TEST_CRASH].end(),
+             "crashed");
+  PrintTests(tests_by_status[TestResult::TEST_SKIPPED].begin(),
+             tests_by_status[TestResult::TEST_SKIPPED].end(),
+             "skipped");
+  PrintTests(tests_by_status[TestResult::TEST_UNKNOWN].begin(),
+             tests_by_status[TestResult::TEST_UNKNOWN].end(),
+             "had unknown result");
+}
+
+void TestResultsTracker::PrintSummaryOfAllIterations() const {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  TestStatusMap tests_by_status(GetTestStatusMapForAllIterations());
+
+  fprintf(stdout, "Summary of all test iterations:\n");
+  fflush(stdout);
+
+  PrintTests(tests_by_status[TestResult::TEST_FAILURE].begin(),
+             tests_by_status[TestResult::TEST_FAILURE].end(),
+             "failed");
+  PrintTests(tests_by_status[TestResult::TEST_FAILURE_ON_EXIT].begin(),
+             tests_by_status[TestResult::TEST_FAILURE_ON_EXIT].end(),
+             "failed on exit");
+  PrintTests(tests_by_status[TestResult::TEST_TIMEOUT].begin(),
+             tests_by_status[TestResult::TEST_TIMEOUT].end(),
+             "timed out");
+  PrintTests(tests_by_status[TestResult::TEST_CRASH].begin(),
+             tests_by_status[TestResult::TEST_CRASH].end(),
+             "crashed");
+  PrintTests(tests_by_status[TestResult::TEST_SKIPPED].begin(),
+             tests_by_status[TestResult::TEST_SKIPPED].end(),
+             "skipped");
+  PrintTests(tests_by_status[TestResult::TEST_UNKNOWN].begin(),
+             tests_by_status[TestResult::TEST_UNKNOWN].end(),
+             "had unknown result");
+
+  fprintf(stdout, "End of the summary.\n");
+  fflush(stdout);
+}
+
+void TestResultsTracker::AddGlobalTag(const std::string& tag) {
+  global_tags_.insert(tag);
+}
+
+bool TestResultsTracker::SaveSummaryAsJSON(const FilePath& path) const {
+  scoped_ptr<DictionaryValue> summary_root(new DictionaryValue);
+
+  scoped_ptr<ListValue> global_tags(new ListValue);
+  for (const auto& global_tag : global_tags_) {
+    global_tags->AppendString(global_tag);
+  }
+  summary_root->Set("global_tags", global_tags.Pass());
+
+  scoped_ptr<ListValue> all_tests(new ListValue);
+  for (const auto& test : all_tests_) {
+    all_tests->AppendString(test);
+  }
+  summary_root->Set("all_tests", all_tests.Pass());
+
+  scoped_ptr<ListValue> disabled_tests(new ListValue);
+  for (const auto& disabled_test : disabled_tests_) {
+    disabled_tests->AppendString(disabled_test);
+  }
+  summary_root->Set("disabled_tests", disabled_tests.Pass());
+
+  scoped_ptr<ListValue> per_iteration_data(new ListValue);
+
+  for (int i = 0; i <= iteration_; i++) {
+    scoped_ptr<DictionaryValue> current_iteration_data(new DictionaryValue);
+
+    for (PerIterationData::ResultsMap::const_iterator j =
+             per_iteration_data_[i].results.begin();
+         j != per_iteration_data_[i].results.end();
+         ++j) {
+      scoped_ptr<ListValue> test_results(new ListValue);
+
+      for (size_t k = 0; k < j->second.test_results.size(); k++) {
+        const TestResult& test_result = j->second.test_results[k];
+
+        scoped_ptr<DictionaryValue> test_result_value(new DictionaryValue);
+
+        test_result_value->SetString("status", test_result.StatusAsString());
+        test_result_value->SetInteger(
+            "elapsed_time_ms",
+            static_cast<int>(test_result.elapsed_time.InMilliseconds()));
+
+        // There are no guarantees about character encoding of the output
+        // snippet. Escape it and record whether it was losless.
+        // It's useful to have the output snippet as string in the summary
+        // for easy viewing.
+        std::string escaped_output_snippet;
+        bool losless_snippet = EscapeJSONString(
+            test_result.output_snippet, false, &escaped_output_snippet);
+        test_result_value->SetString("output_snippet",
+                                     escaped_output_snippet);
+        test_result_value->SetBoolean("losless_snippet", losless_snippet);
+
+        // Also include the raw version (base64-encoded so that it can be safely
+        // JSON-serialized - there are no guarantees about character encoding
+        // of the snippet). This can be very useful piece of information when
+        // debugging a test failure related to character encoding.
+        std::string base64_output_snippet;
+        Base64Encode(test_result.output_snippet, &base64_output_snippet);
+        test_result_value->SetString("output_snippet_base64",
+                                     base64_output_snippet);
+        test_results->Append(test_result_value.Pass());
+      }
+
+      current_iteration_data->SetWithoutPathExpansion(j->first,
+                                                      test_results.Pass());
+    }
+    per_iteration_data->Append(current_iteration_data.Pass());
+    summary_root->Set("per_iteration_data", per_iteration_data.Pass());
+  }
+
+  JSONFileValueSerializer serializer(path);
+  return serializer.Serialize(*summary_root);
+}
+
+TestResultsTracker::TestStatusMap
+    TestResultsTracker::GetTestStatusMapForCurrentIteration() const {
+  TestStatusMap tests_by_status;
+  GetTestStatusForIteration(iteration_, &tests_by_status);
+  return tests_by_status;
+}
+
+TestResultsTracker::TestStatusMap
+    TestResultsTracker::GetTestStatusMapForAllIterations() const {
+  TestStatusMap tests_by_status;
+  for (int i = 0; i <= iteration_; i++)
+    GetTestStatusForIteration(i, &tests_by_status);
+  return tests_by_status;
+}
+
+void TestResultsTracker::GetTestStatusForIteration(
+    int iteration, TestStatusMap* map) const {
+  for (PerIterationData::ResultsMap::const_iterator j =
+           per_iteration_data_[iteration].results.begin();
+       j != per_iteration_data_[iteration].results.end();
+       ++j) {
+    // Use the last test result as the final one.
+    const TestResult& result = j->second.test_results.back();
+    (*map)[result.status].insert(result.full_name);
+  }
+}
+
+TestResultsTracker::AggregateTestResult::AggregateTestResult() {
+}
+
+TestResultsTracker::AggregateTestResult::~AggregateTestResult() {
+}
+
+TestResultsTracker::PerIterationData::PerIterationData() {
+}
+
+TestResultsTracker::PerIterationData::~PerIterationData() {
+}
+
+}  // namespace base
diff --git a/base/test/launcher/test_results_tracker.h b/base/test/launcher/test_results_tracker.h
new file mode 100644
index 0000000..2bddebc
--- /dev/null
+++ b/base/test/launcher/test_results_tracker.h
@@ -0,0 +1,123 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_LAUNCHER_TEST_RESULTS_TRACKER_H_
+#define BASE_TEST_LAUNCHER_TEST_RESULTS_TRACKER_H_
+
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/test/launcher/test_result.h"
+#include "base/threading/thread_checker.h"
+
+namespace base {
+
+class CommandLine;
+class FilePath;
+
+// A helper class to output results.
+// Note: as currently XML is the only supported format by gtest, we don't
+// check output format (e.g. "xml:" prefix) here and output an XML file
+// unconditionally.
+// Note: we don't output per-test-case or total summary info like
+// total failed_test_count, disabled_test_count, elapsed_time and so on.
+// Only each test (testcase element in the XML) will have the correct
+// failed/disabled/elapsed_time information. Each test won't include
+// detailed failure messages either.
+class TestResultsTracker {
+ public:
+  TestResultsTracker();
+  ~TestResultsTracker();
+
+  // Initialize the result tracker. Must be called exactly once before
+  // calling any other methods. Returns true on success.
+  bool Init(const CommandLine& command_line) WARN_UNUSED_RESULT;
+
+  // Called when a test iteration is starting.
+  void OnTestIterationStarting();
+
+  // Adds |test_name| to the set of discovered tests (this includes all tests
+  // present in the executable, not necessarily run).
+  void AddTest(const std::string& test_name);
+
+  // Adds |test_name| to the set of disabled tests.
+  void AddDisabledTest(const std::string& test_name);
+
+  // Adds |result| to the stored test results.
+  void AddTestResult(const TestResult& result);
+
+  // Prints a summary of current test iteration to stdout.
+  void PrintSummaryOfCurrentIteration() const;
+
+  // Prints a summary of all test iterations (not just the last one) to stdout.
+  void PrintSummaryOfAllIterations() const;
+
+  // Adds a string tag to the JSON summary. This is intended to indicate
+  // conditions that affect the entire test run, as opposed to individual tests.
+  void AddGlobalTag(const std::string& tag);
+
+  // Saves a JSON summary of all test iterations results to |path|. Returns
+  // true on success.
+  bool SaveSummaryAsJSON(const FilePath& path) const WARN_UNUSED_RESULT;
+
+  // Map where keys are test result statuses, and values are sets of tests
+  // which finished with that status.
+  typedef std::map<TestResult::Status, std::set<std::string> > TestStatusMap;
+
+  // Returns a test status map (see above) for current test iteration.
+  TestStatusMap GetTestStatusMapForCurrentIteration() const;
+
+  // Returns a test status map (see above) for all test iterations.
+  TestStatusMap GetTestStatusMapForAllIterations() const;
+
+ private:
+  void GetTestStatusForIteration(int iteration, TestStatusMap* map) const;
+
+  struct AggregateTestResult {
+    AggregateTestResult();
+    ~AggregateTestResult();
+
+    std::vector<TestResult> test_results;
+  };
+
+  struct PerIterationData {
+    PerIterationData();
+    ~PerIterationData();
+
+    // Aggregate test results grouped by full test name.
+    typedef std::map<std::string, AggregateTestResult> ResultsMap;
+    ResultsMap results;
+  };
+
+  ThreadChecker thread_checker_;
+
+  // Set of global tags, i.e. strings indicating conditions that apply to
+  // the entire test run.
+  std::set<std::string> global_tags_;
+
+  // Set of all test names discovered in the current executable.
+  std::set<std::string> all_tests_;
+
+  // Set of all disabled tests in the current executable.
+  std::set<std::string> disabled_tests_;
+
+  // Store test results for each iteration.
+  std::vector<PerIterationData> per_iteration_data_;
+
+  // Index of current iteration (starting from 0). -1 before the first
+  // iteration.
+  int iteration_;
+
+  // File handle of output file (can be NULL if no file).
+  FILE* out_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestResultsTracker);
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_LAUNCHER_TEST_RESULTS_TRACKER_H_
diff --git a/base/test/launcher/unit_test_launcher.cc b/base/test/launcher/unit_test_launcher.cc
new file mode 100644
index 0000000..ab6fa72
--- /dev/null
+++ b/base/test/launcher/unit_test_launcher.cc
@@ -0,0 +1,586 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/launcher/unit_test_launcher.h"
+
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+#include "base/command_line.h"
+#include "base/compiler_specific.h"
+#include "base/debug/debugger.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/format_macros.h"
+#include "base/location.h"
+#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/sys_info.h"
+#include "base/test/gtest_xml_util.h"
+#include "base/test/launcher/test_launcher.h"
+#include "base/test/test_switches.h"
+#include "base/test/test_timeouts.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/thread_checker.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+// This constant controls how many tests are run in a single batch by default.
+const size_t kDefaultTestBatchLimit = 10;
+
+const char kHelpFlag[] = "help";
+
+// Flag to run all tests in a single process.
+const char kSingleProcessTestsFlag[] = "single-process-tests";
+
+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"
+          "  --gtest_help\n"
+          "    Shows the gtest help message.\n"
+          "\n"
+          "  --test-launcher-jobs=N\n"
+          "    Sets the number of parallel test jobs to N.\n"
+          "\n"
+          "  --single-process-tests\n"
+          "    Runs the tests and the launcher in the same process. Useful\n"
+          "    for debugging a specific test in a debugger.\n"
+          "\n"
+          " Other flags:\n"
+          "  --test-launcher-batch-limit=N\n"
+          "    Sets the limit of test batch to run in a single process to N.\n"
+          "\n"
+          "  --test-launcher-debug-launcher\n"
+          "    Disables autodetection of debuggers and similar tools,\n"
+          "    making it possible to use them to debug launcher itself.\n"
+          "\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 DefaultUnitTestPlatformDelegate : public UnitTestPlatformDelegate {
+ public:
+  DefaultUnitTestPlatformDelegate() {
+  }
+
+ private:
+  // UnitTestPlatformDelegate:
+  bool GetTests(std::vector<SplitTestName>* output) override {
+    *output = GetCompiledInTests();
+    return true;
+  }
+
+  bool CreateTemporaryFile(base::FilePath* path) override {
+    if (!CreateNewTempDirectory(FilePath::StringType(), path))
+      return false;
+    *path = path->AppendASCII("test_results.xml");
+    return true;
+  }
+
+  CommandLine GetCommandLineForChildGTestProcess(
+      const std::vector<std::string>& test_names,
+      const base::FilePath& output_file) override {
+    CommandLine new_cmd_line(*CommandLine::ForCurrentProcess());
+
+    new_cmd_line.AppendSwitchPath(switches::kTestLauncherOutput, output_file);
+    new_cmd_line.AppendSwitchASCII(kGTestFilterFlag,
+                                   JoinString(test_names, ":"));
+    new_cmd_line.AppendSwitch(kSingleProcessTestsFlag);
+
+    return new_cmd_line;
+  }
+
+  std::string GetWrapperForChildGTestProcess() override {
+    return std::string();
+  }
+
+  void RelaunchTests(TestLauncher* test_launcher,
+                     const std::vector<std::string>& test_names,
+                     int launch_flags) override {
+    // Relaunch requested tests in parallel, but only use single
+    // test per batch for more precise results (crashes, etc).
+    for (const std::string& test_name : test_names) {
+      std::vector<std::string> batch;
+      batch.push_back(test_name);
+      RunUnitTestsBatch(test_launcher, this, batch, launch_flags);
+    }
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(DefaultUnitTestPlatformDelegate);
+};
+
+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;
+
+  DefaultUnitTestPlatformDelegate platform_delegate;
+  UnitTestLauncherDelegate delegate(
+      &platform_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)
+
+// Interprets test results and reports to the test launcher. Returns true
+// on success.
+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) {
+  std::vector<TestResult> test_results;
+  bool crashed = false;
+  bool have_test_results =
+      ProcessGTestOutput(output_file, &test_results, &crashed);
+
+  bool called_any_callback = false;
+
+  if (have_test_results) {
+    // TODO(phajdan.jr): Check for duplicates and mismatches between
+    // the results we got from XML file and tests we intended to run.
+    std::map<std::string, TestResult> results_map;
+    for (size_t i = 0; i < test_results.size(); i++)
+      results_map[test_results[i].full_name] = test_results[i];
+
+    bool had_interrupted_test = false;
+
+    // Results to be reported back to the test launcher.
+    std::vector<TestResult> final_results;
+
+    for (size_t i = 0; i < test_names.size(); i++) {
+      if (ContainsKey(results_map, test_names[i])) {
+        TestResult test_result = results_map[test_names[i]];
+        if (test_result.status == TestResult::TEST_CRASH) {
+          had_interrupted_test = true;
+
+          if (was_timeout) {
+            // Fix up the test status: we forcibly kill the child process
+            // after the timeout, so from XML results it looks just like
+            // a crash.
+            test_result.status = TestResult::TEST_TIMEOUT;
+          }
+        } else if (test_result.status == TestResult::TEST_SUCCESS ||
+                   test_result.status == TestResult::TEST_FAILURE) {
+          // We run multiple tests in a batch with a timeout applied
+          // to the entire batch. It is possible that with other tests
+          // running quickly some tests take longer than the per-test timeout.
+          // For consistent handling of tests independent of order and other
+          // factors, mark them as timing out.
+          if (test_result.elapsed_time >
+              TestTimeouts::test_launcher_timeout()) {
+            test_result.status = TestResult::TEST_TIMEOUT;
+          }
+        }
+        test_result.output_snippet = GetTestOutputSnippet(test_result, output);
+        final_results.push_back(test_result);
+      } else if (had_interrupted_test) {
+        tests_to_relaunch->push_back(test_names[i]);
+      } else {
+        // TODO(phajdan.jr): Explicitly pass the info that the test didn't
+        // run for a mysterious reason.
+        LOG(ERROR) << "no test result for " << test_names[i];
+        TestResult test_result;
+        test_result.full_name = test_names[i];
+        test_result.status = TestResult::TEST_UNKNOWN;
+        test_result.output_snippet = GetTestOutputSnippet(test_result, output);
+        final_results.push_back(test_result);
+      }
+    }
+
+    // TODO(phajdan.jr): Handle the case where processing XML output
+    // indicates a crash but none of the test results is marked as crashing.
+
+    if (final_results.empty())
+      return false;
+
+    bool has_non_success_test = false;
+    for (size_t i = 0; i < final_results.size(); i++) {
+      if (final_results[i].status != TestResult::TEST_SUCCESS) {
+        has_non_success_test = true;
+        break;
+      }
+    }
+
+    if (!has_non_success_test && exit_code != 0) {
+      // This is a bit surprising case: all tests are marked as successful,
+      // but the exit code was not zero. This can happen e.g. under memory
+      // tools that report leaks this way. Mark all tests as a failure on exit,
+      // and for more precise info they'd need to be retried serially.
+      for (size_t i = 0; i < final_results.size(); i++)
+        final_results[i].status = TestResult::TEST_FAILURE_ON_EXIT;
+    }
+
+    for (size_t i = 0; i < final_results.size(); i++) {
+      // Fix the output snippet after possible changes to the test result.
+      final_results[i].output_snippet =
+          GetTestOutputSnippet(final_results[i], output);
+      test_launcher->OnTestFinished(final_results[i]);
+      called_any_callback = true;
+    }
+  } else {
+    fprintf(stdout,
+            "Failed to get out-of-band test success data, "
+            "dumping full stdio below:\n%s\n",
+            output.c_str());
+    fflush(stdout);
+
+    // We do not have reliable details about test results (parsing test
+    // stdout is known to be unreliable), apply the executable exit code
+    // to all tests.
+    // TODO(phajdan.jr): Be smarter about this, e.g. retry each test
+    // individually.
+    for (size_t i = 0; i < test_names.size(); i++) {
+      TestResult test_result;
+      test_result.full_name = test_names[i];
+      test_result.status = TestResult::TEST_UNKNOWN;
+      test_launcher->OnTestFinished(test_result);
+      called_any_callback = true;
+    }
+  }
+
+  return called_any_callback;
+}
+
+// TODO(phajdan.jr): Pass parameters directly with C++11 variadic templates.
+struct GTestCallbackState {
+  TestLauncher* test_launcher;
+  UnitTestPlatformDelegate* platform_delegate;
+  std::vector<std::string> test_names;
+  int launch_flags;
+  FilePath output_file;
+};
+
+void GTestCallback(
+    const GTestCallbackState& callback_state,
+    int exit_code,
+    const TimeDelta& elapsed_time,
+    bool was_timeout,
+    const std::string& output) {
+  std::vector<std::string> tests_to_relaunch;
+  ProcessTestResults(callback_state.test_launcher, callback_state.test_names,
+                     callback_state.output_file, output, exit_code, was_timeout,
+                     &tests_to_relaunch);
+
+  if (!tests_to_relaunch.empty()) {
+    callback_state.platform_delegate->RelaunchTests(
+        callback_state.test_launcher,
+        tests_to_relaunch,
+        callback_state.launch_flags);
+  }
+
+  // The temporary file's directory is also temporary.
+  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) {
+  std::vector<std::string> tests_to_relaunch;
+  bool called_any_callbacks =
+      ProcessTestResults(callback_state.test_launcher,
+                         callback_state.test_names, callback_state.output_file,
+                         output, exit_code, was_timeout, &tests_to_relaunch);
+
+  // There is only one test, there cannot be other tests to relaunch
+  // due to a crash.
+  DCHECK(tests_to_relaunch.empty());
+
+  // There is only one test, we should have called back with its result.
+  DCHECK(called_any_callbacks);
+
+  // The temporary file's directory is also temporary.
+  DeleteFile(callback_state.output_file.DirName(), true);
+
+  ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, Bind(&RunUnitTestsSerially, callback_state.test_launcher,
+                      callback_state.platform_delegate, test_names,
+                      callback_state.launch_flags));
+}
+
+}  // 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)
+
+void RunUnitTestsSerially(
+    TestLauncher* test_launcher,
+    UnitTestPlatformDelegate* platform_delegate,
+    const std::vector<std::string>& test_names,
+    int launch_flags) {
+  if (test_names.empty())
+    return;
+
+  std::vector<std::string> new_test_names(test_names);
+  std::string test_name(new_test_names.back());
+  new_test_names.pop_back();
+
+  // Create a dedicated temporary directory to store the xml result data
+  // per run to ensure clean state and make it possible to launch multiple
+  // processes in parallel.
+  base::FilePath output_file;
+  CHECK(platform_delegate->CreateTemporaryFile(&output_file));
+
+  std::vector<std::string> current_test_names;
+  current_test_names.push_back(test_name);
+  CommandLine cmd_line(platform_delegate->GetCommandLineForChildGTestProcess(
+      current_test_names, output_file));
+
+  GTestCallbackState callback_state;
+  callback_state.test_launcher = test_launcher;
+  callback_state.platform_delegate = platform_delegate;
+  callback_state.test_names = current_test_names;
+  callback_state.launch_flags = launch_flags;
+  callback_state.output_file = output_file;
+
+  test_launcher->LaunchChildGTestProcess(
+      cmd_line,
+      platform_delegate->GetWrapperForChildGTestProcess(),
+      TestTimeouts::test_launcher_timeout(),
+      launch_flags,
+      Bind(&SerialGTestCallback, callback_state, new_test_names));
+}
+
+void RunUnitTestsBatch(
+    TestLauncher* test_launcher,
+    UnitTestPlatformDelegate* platform_delegate,
+    const std::vector<std::string>& test_names,
+    int launch_flags) {
+  if (test_names.empty())
+    return;
+
+  // Create a dedicated temporary directory to store the xml result data
+  // per run to ensure clean state and make it possible to launch multiple
+  // processes in parallel.
+  base::FilePath output_file;
+  CHECK(platform_delegate->CreateTemporaryFile(&output_file));
+
+  CommandLine cmd_line(platform_delegate->GetCommandLineForChildGTestProcess(
+      test_names, output_file));
+
+  // Adjust the timeout depending on how many tests we're running
+  // (note that e.g. the last batch of tests will be smaller).
+  // TODO(phajdan.jr): Consider an adaptive timeout, which can change
+  // depending on how many tests ran and how many remain.
+  // Note: do NOT parse child's stdout to do that, it's known to be
+  // unreliable (e.g. buffering issues can mix up the output).
+  base::TimeDelta timeout =
+      test_names.size() * TestTimeouts::test_launcher_timeout();
+
+  GTestCallbackState callback_state;
+  callback_state.test_launcher = test_launcher;
+  callback_state.platform_delegate = platform_delegate;
+  callback_state.test_names = test_names;
+  callback_state.launch_flags = launch_flags;
+  callback_state.output_file = output_file;
+
+  test_launcher->LaunchChildGTestProcess(
+      cmd_line,
+      platform_delegate->GetWrapperForChildGTestProcess(),
+      timeout,
+      launch_flags,
+      Bind(&GTestCallback, callback_state));
+}
+
+UnitTestLauncherDelegate::UnitTestLauncherDelegate(
+    UnitTestPlatformDelegate* platform_delegate,
+    size_t batch_limit,
+    bool use_job_objects)
+    : platform_delegate_(platform_delegate),
+      batch_limit_(batch_limit),
+      use_job_objects_(use_job_objects) {
+}
+
+UnitTestLauncherDelegate::~UnitTestLauncherDelegate() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+}
+
+bool UnitTestLauncherDelegate::GetTests(std::vector<SplitTestName>* output) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  return platform_delegate_->GetTests(output);
+}
+
+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 UnitTestLauncherDelegate::RunTests(
+    TestLauncher* test_launcher,
+    const std::vector<std::string>& test_names) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  int launch_flags = use_job_objects_ ? TestLauncher::USE_JOB_OBJECTS : 0;
+
+  std::vector<std::string> batch;
+  for (size_t i = 0; i < test_names.size(); i++) {
+    batch.push_back(test_names[i]);
+
+    // Use 0 to indicate unlimited batch size.
+    if (batch.size() >= batch_limit_ && batch_limit_ != 0) {
+      RunUnitTestsBatch(test_launcher, platform_delegate_, batch, launch_flags);
+      batch.clear();
+    }
+  }
+
+  RunUnitTestsBatch(test_launcher, platform_delegate_, batch, launch_flags);
+
+  return test_names.size();
+}
+
+size_t UnitTestLauncherDelegate::RetryTests(
+    TestLauncher* test_launcher,
+    const std::vector<std::string>& test_names) {
+  ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      Bind(&RunUnitTestsSerially, test_launcher, platform_delegate_, test_names,
+           use_job_objects_ ? TestLauncher::USE_JOB_OBJECTS : 0));
+  return test_names.size();
+}
+
+}  // namespace base
diff --git a/base/test/launcher/unit_test_launcher.h b/base/test/launcher/unit_test_launcher.h
new file mode 100644
index 0000000..ca00f10
--- /dev/null
+++ b/base/test/launcher/unit_test_launcher.h
@@ -0,0 +1,112 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_LAUNCHER_UNIT_TEST_LAUNCHER_H_
+#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 {
+
+// Callback that runs a test suite and returns exit code.
+typedef base::Callback<int(void)> RunTestSuiteCallback;
+
+// Launches unit tests in given test suite. Returns exit code.
+int LaunchUnitTests(int argc,
+                    char** argv,
+                    const RunTestSuiteCallback& run_test_suite);
+
+// Same as above, but always runs tests serially.
+int LaunchUnitTestsSerially(int argc,
+                            char** argv,
+                            const RunTestSuiteCallback& run_test_suite);
+
+#if defined(OS_WIN)
+// Launches unit tests in given test suite. Returns exit code.
+// |use_job_objects| determines whether to use job objects.
+int LaunchUnitTests(int argc,
+                    wchar_t** argv,
+                    bool use_job_objects,
+                    const RunTestSuiteCallback& run_test_suite);
+#endif  // defined(OS_WIN)
+
+// Delegate to abstract away platform differences for unit tests.
+class UnitTestPlatformDelegate {
+ 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 to create a temporary file. The delegate must put the resulting
+  // path in |path| and return true on success.
+  virtual bool CreateTemporaryFile(base::FilePath* path) = 0;
+
+  // Returns command line for child GTest process based on the command line
+  // of current process. |test_names| is a vector of test full names
+  // (e.g. "A.B"), |output_file| is path to the GTest XML output file.
+  virtual CommandLine GetCommandLineForChildGTestProcess(
+      const std::vector<std::string>& test_names,
+      const base::FilePath& output_file) = 0;
+
+  // Returns wrapper to use for child GTest process. Empty string means
+  // no wrapper.
+  virtual std::string GetWrapperForChildGTestProcess() = 0;
+
+  // Relaunch tests, e.g. after a crash.
+  virtual void RelaunchTests(TestLauncher* test_launcher,
+                             const std::vector<std::string>& test_names,
+                             int launch_flags) = 0;
+
+ protected:
+  ~UnitTestPlatformDelegate() {}
+};
+
+// Runs tests serially, each in its own process.
+void RunUnitTestsSerially(TestLauncher* test_launcher,
+                          UnitTestPlatformDelegate* platform_delegate,
+                          const std::vector<std::string>& test_names,
+                          int launch_flags);
+
+// Runs tests in batches (each batch in its own process).
+void RunUnitTestsBatch(TestLauncher* test_launcher,
+                       UnitTestPlatformDelegate* platform_delegate,
+                       const std::vector<std::string>& test_names,
+                       int launch_flags);
+
+// Test launcher delegate for unit tests (mostly to support batching).
+class UnitTestLauncherDelegate : public TestLauncherDelegate {
+ public:
+  UnitTestLauncherDelegate(UnitTestPlatformDelegate* delegate,
+                           size_t batch_limit,
+                           bool use_job_objects);
+  ~UnitTestLauncherDelegate() override;
+
+ private:
+  // 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;
+
+  ThreadChecker thread_checker_;
+
+  UnitTestPlatformDelegate* platform_delegate_;
+
+  // 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/base/test/launcher/unit_test_launcher_ios.cc b/base/test/launcher/unit_test_launcher_ios.cc
new file mode 100644
index 0000000..acb6c71
--- /dev/null
+++ b/base/test/launcher/unit_test_launcher_ios.cc
@@ -0,0 +1,42 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/launcher/unit_test_launcher.h"
+
+#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"
+
+namespace base {
+
+int LaunchUnitTests(int argc,
+                    char** argv,
+                    const RunTestSuiteCallback& run_test_suite) {
+  CHECK(CommandLine::InitializedForCurrentProcess() ||
+        CommandLine::Init(argc, argv));
+  const CommandLine* command_line = CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(switches::kTestLauncherListTests)) {
+    FilePath list_path(command_line->GetSwitchValuePath(
+        switches::kTestLauncherListTests));
+    if (WriteCompiledInTestsToFile(list_path)) {
+      return 0;
+    } else {
+      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();
+}
+
+}  // namespace base
diff --git a/base/test/launcher/unit_test_launcher_nacl_nonsfi.cc b/base/test/launcher/unit_test_launcher_nacl_nonsfi.cc
new file mode 100644
index 0000000..b2cf14a
--- /dev/null
+++ b/base/test/launcher/unit_test_launcher_nacl_nonsfi.cc
@@ -0,0 +1,51 @@
+// 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/test/launcher/unit_test_launcher.h"
+
+#include "base/command_line.h"
+#include "base/files/file_util.h"
+#include "base/test/gtest_util.h"
+#include "base/test/gtest_xml_unittest_result_printer.h"
+#include "base/test/test_switches.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+int LaunchUnitTests(int argc,
+                    char** argv,
+                    const RunTestSuiteCallback& run_test_suite) {
+  CHECK(CommandLine::InitializedForCurrentProcess() ||
+        CommandLine::Init(argc, argv));
+  const CommandLine* command_line = CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(switches::kTestLauncherListTests)) {
+    // Dump all test list into a file.
+    FilePath list_path(
+        command_line->GetSwitchValuePath(switches::kTestLauncherListTests));
+    if (!WriteCompiledInTestsToFile(list_path)) {
+      LOG(ERROR) << "Failed to write list of tests.";
+      return 1;
+    }
+
+    // Successfully done.
+    return 0;
+  }
+
+  // Register XML output printer, if --test-launcher-output flag is set.
+  if (command_line->HasSwitch(switches::kTestLauncherOutput)) {
+    FilePath output_path = command_line->GetSwitchValuePath(
+        switches::kTestLauncherOutput);
+    if (PathExists(output_path)) {
+      LOG(WARNING) << "Test launcher output path exists. Do not override";
+    } else {
+      XmlUnitTestResultPrinter* printer = new XmlUnitTestResultPrinter;
+      CHECK(printer->Initialize(output_path));
+      testing::UnitTest::GetInstance()->listeners().Append(printer);
+    }
+  }
+
+  return run_test_suite.Run();
+}
+
+}  // namespace base
diff --git a/base/test/malloc_wrapper.cc b/base/test/malloc_wrapper.cc
new file mode 100644
index 0000000..eb280a3
--- /dev/null
+++ b/base/test/malloc_wrapper.cc
@@ -0,0 +1,11 @@
+// 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 "malloc_wrapper.h"
+
+#include <stdlib.h>
+
+void* MallocWrapper(size_t size) {
+  return malloc(size);
+}
diff --git a/base/test/malloc_wrapper.h b/base/test/malloc_wrapper.h
new file mode 100644
index 0000000..0fa7dbb
--- /dev/null
+++ b/base/test/malloc_wrapper.h
@@ -0,0 +1,21 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_MALLOC_WRAPPER_H_
+#define BASE_TEST_MALLOC_WRAPPER_H_
+
+#include "base/basictypes.h"
+
+// BASE_EXPORT depends on COMPONENT_BUILD.
+// This will always be a separate shared library, so don't use BASE_EXPORT here.
+#if defined(WIN32)
+#define MALLOC_WRAPPER_EXPORT __declspec(dllexport)
+#else
+#define MALLOC_WRAPPER_EXPORT __attribute__((visibility("default")))
+#endif  // defined(WIN32)
+
+// Calls malloc directly.
+MALLOC_WRAPPER_EXPORT void* MallocWrapper(size_t size);
+
+#endif  // BASE_TEST_MALLOC_WRAPPER_H_
diff --git a/base/test/mock_chrome_application_mac.h b/base/test/mock_chrome_application_mac.h
new file mode 100644
index 0000000..ffa3080
--- /dev/null
+++ b/base/test/mock_chrome_application_mac.h
@@ -0,0 +1,33 @@
+// Copyright (c) 2011 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_TEST_MOCK_CHROME_APPLICATION_MAC_H_
+#define BASE_TEST_MOCK_CHROME_APPLICATION_MAC_H_
+
+#if defined(__OBJC__)
+
+#import <AppKit/AppKit.h>
+
+#include "base/mac/scoped_sending_event.h"
+#include "base/message_loop/message_pump_mac.h"
+
+// A basic implementation of CrAppProtocol and
+// CrAppControlProtocol. This can be used in tests that need an
+// NSApplication and use a runloop, or which need a ScopedSendingEvent
+// when handling a nested event loop.
+@interface MockCrApp : NSApplication<CrAppProtocol,
+                                     CrAppControlProtocol> {
+ @private
+  BOOL handlingSendEvent_;
+}
+@end
+
+#endif
+
+// To be used to instantiate MockCrApp from C++ code.
+namespace mock_cr_app {
+void RegisterMockCrApp();
+}  // namespace mock_cr_app
+
+#endif  // BASE_TEST_MOCK_CHROME_APPLICATION_MAC_H_
diff --git a/base/test/mock_chrome_application_mac.mm b/base/test/mock_chrome_application_mac.mm
new file mode 100644
index 0000000..0890553
--- /dev/null
+++ b/base/test/mock_chrome_application_mac.mm
@@ -0,0 +1,44 @@
+// Copyright (c) 2011 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/test/mock_chrome_application_mac.h"
+
+#include "base/auto_reset.h"
+#include "base/logging.h"
+
+@implementation MockCrApp
+
++ (NSApplication*)sharedApplication {
+  NSApplication* app = [super sharedApplication];
+  DCHECK([app conformsToProtocol:@protocol(CrAppControlProtocol)])
+      << "Existing NSApp (class " << [[app className] UTF8String]
+      << ") does not conform to required protocol.";
+  DCHECK(base::MessagePumpMac::UsingCrApp())
+      << "MessagePumpMac::Create() was called before "
+      << "+[MockCrApp sharedApplication]";
+  return app;
+}
+
+- (void)sendEvent:(NSEvent*)event {
+  base::AutoReset<BOOL> scoper(&handlingSendEvent_, YES);
+  [super sendEvent:event];
+}
+
+- (void)setHandlingSendEvent:(BOOL)handlingSendEvent {
+  handlingSendEvent_ = handlingSendEvent;
+}
+
+- (BOOL)isHandlingSendEvent {
+  return handlingSendEvent_;
+}
+
+@end
+
+namespace mock_cr_app {
+
+void RegisterMockCrApp() {
+  [MockCrApp sharedApplication];
+}
+
+}  // namespace mock_cr_app
diff --git a/base/test/mock_devices_changed_observer.cc b/base/test/mock_devices_changed_observer.cc
new file mode 100644
index 0000000..c05f26a
--- /dev/null
+++ b/base/test/mock_devices_changed_observer.cc
@@ -0,0 +1,15 @@
+// Copyright (c) 2012 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/test/mock_devices_changed_observer.h"
+
+namespace base {
+
+MockDevicesChangedObserver::MockDevicesChangedObserver() {
+}
+
+MockDevicesChangedObserver::~MockDevicesChangedObserver() {
+}
+
+}  // namespace base
diff --git a/base/test/mock_devices_changed_observer.h b/base/test/mock_devices_changed_observer.h
new file mode 100644
index 0000000..3255002
--- /dev/null
+++ b/base/test/mock_devices_changed_observer.h
@@ -0,0 +1,30 @@
+// Copyright (c) 2012 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_TEST_MOCK_DEVICES_CHANGED_OBSERVER_H_
+#define BASE_TEST_MOCK_DEVICES_CHANGED_OBSERVER_H_
+
+#include <string>
+
+#include "base/system_monitor/system_monitor.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace base {
+
+class MockDevicesChangedObserver
+    : public base::SystemMonitor::DevicesChangedObserver {
+ public:
+  MockDevicesChangedObserver();
+  ~MockDevicesChangedObserver();
+
+  MOCK_METHOD1(OnDevicesChanged,
+               void(base::SystemMonitor::DeviceType device_type));
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MockDevicesChangedObserver);
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_MOCK_DEVICES_CHANGED_OBSERVER_H_
diff --git a/base/test/mock_entropy_provider.cc b/base/test/mock_entropy_provider.cc
new file mode 100644
index 0000000..75186a5
--- /dev/null
+++ b/base/test/mock_entropy_provider.cc
@@ -0,0 +1,16 @@
+// 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/test/mock_entropy_provider.h"
+
+namespace base {
+
+MockEntropyProvider::~MockEntropyProvider() {}
+
+double MockEntropyProvider::GetEntropyForTrial(
+    const std::string& trial_name, uint32 randomization_seed) const {
+  return 0.5;
+}
+
+}  // namespace base
diff --git a/base/test/mock_entropy_provider.h b/base/test/mock_entropy_provider.h
new file mode 100644
index 0000000..c55bea6
--- /dev/null
+++ b/base/test/mock_entropy_provider.h
@@ -0,0 +1,23 @@
+// 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_TEST_MOCK_ENTROPY_PROVIDER_H_
+#define BASE_TEST_MOCK_ENTROPY_PROVIDER_H_
+
+#include "base/metrics/field_trial.h"
+
+namespace base {
+
+class MockEntropyProvider : public base::FieldTrial::EntropyProvider {
+ public:
+  ~MockEntropyProvider() override;
+
+  // base::FieldTrial::EntropyProvider:
+  double GetEntropyForTrial(const std::string& trial_name,
+                            uint32 randomization_seed) const override;
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_MOCK_ENTROPY_PROVIDER_H_
diff --git a/base/test/mock_log.cc b/base/test/mock_log.cc
new file mode 100644
index 0000000..fa511d4
--- /dev/null
+++ b/base/test/mock_log.cc
@@ -0,0 +1,68 @@
+// 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/test/mock_log.h"
+
+namespace base {
+namespace test {
+
+// static
+MockLog* MockLog::g_instance_ = nullptr;
+Lock MockLog::g_lock;
+
+MockLog::MockLog() : is_capturing_logs_(false) {
+}
+
+MockLog::~MockLog() {
+  if (is_capturing_logs_) {
+    StopCapturingLogs();
+  }
+}
+
+void MockLog::StartCapturingLogs() {
+  AutoLock scoped_lock(g_lock);
+
+  // We don't use CHECK(), which can generate a new LOG message, and
+  // thus can confuse MockLog objects or other registered
+  // LogSinks.
+  RAW_CHECK(!is_capturing_logs_);
+  RAW_CHECK(!g_instance_);
+
+  is_capturing_logs_ = true;
+  g_instance_ = this;
+  previous_handler_ = logging::GetLogMessageHandler();
+  logging::SetLogMessageHandler(LogMessageHandler);
+}
+
+void MockLog::StopCapturingLogs() {
+  AutoLock scoped_lock(g_lock);
+
+  // We don't use CHECK(), which can generate a new LOG message, and
+  // thus can confuse MockLog objects or other registered
+  // LogSinks.
+  RAW_CHECK(is_capturing_logs_);
+  RAW_CHECK(g_instance_ == this);
+
+  is_capturing_logs_ = false;
+  logging::SetLogMessageHandler(previous_handler_);
+  g_instance_ = nullptr;
+}
+
+// static
+bool MockLog::LogMessageHandler(int severity,
+                                const char* file,
+                                int line,
+                                size_t message_start,
+                                const std::string& str) {
+  // gMock guarantees thread-safety for calling a mocked method
+  // (https://code.google.com/p/googlemock/wiki/CookBook#Using_Google_Mock_and_Threads)
+  // but we also need to make sure that Start/StopCapturingLogs are synchronized
+  // with LogMessageHandler.
+  AutoLock scoped_lock(g_lock);
+
+  return g_instance_->Log(severity, file, line, message_start, str);
+}
+
+}  // namespace test
+}  // namespace base
diff --git a/base/test/mock_log.h b/base/test/mock_log.h
new file mode 100644
index 0000000..315ef1f
--- /dev/null
+++ b/base/test/mock_log.h
@@ -0,0 +1,98 @@
+// 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_TEST_MOCK_LOG_H_
+#define BASE_TEST_MOCK_LOG_H_
+
+#include <string>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/synchronization/lock.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace base {
+namespace test {
+
+// A MockLog object intercepts LOG() messages issued during its lifespan.  Using
+// this together with gMock, it's very easy to test how a piece of code calls
+// LOG().  The typical usage:
+//
+//   TEST(FooTest, LogsCorrectly) {
+//     MockLog log;
+//
+//     // We expect the WARNING "Something bad!" exactly twice.
+//     EXPECT_CALL(log, Log(WARNING, _, "Something bad!"))
+//         .Times(2);
+//
+//     // We allow foo.cc to call LOG(INFO) any number of times.
+//     EXPECT_CALL(log, Log(INFO, HasSubstr("/foo.cc"), _))
+//         .Times(AnyNumber());
+//
+//     log.StartCapturingLogs();  // Call this after done setting expectations.
+//     Foo();  // Exercises the code under test.
+//   }
+//
+// CAVEAT: base/logging does not allow a thread to call LOG() again when it's
+// already inside a LOG() call.  Doing so will cause a deadlock.  Therefore,
+// it's the user's responsibility to not call LOG() in an action triggered by
+// MockLog::Log().  You may call RAW_LOG() instead.
+class MockLog {
+ public:
+  // Creates a MockLog object that is not capturing logs.  If it were to start
+  // to capture logs, it could be a problem if some other threads already exist
+  // and are logging, as the user hasn't had a chance to set up expectation on
+  // this object yet (calling a mock method before setting the expectation is
+  // UNDEFINED behavior).
+  MockLog();
+
+  // When the object is destructed, it stops intercepting logs.
+  ~MockLog();
+
+  // Starts log capturing if the object isn't already doing so.
+  // Otherwise crashes.
+  void StartCapturingLogs();
+
+  // Stops log capturing if the object is capturing logs.  Otherwise crashes.
+  void StopCapturingLogs();
+
+  // Log method is invoked for every log message before it's sent to other log
+  // destinations (if any).  The method should return true to signal that it
+  // handled the message and the message should not be sent to other log
+  // destinations.
+  MOCK_METHOD5(Log,
+               bool(int severity,
+                    const char* file,
+                    int line,
+                    size_t message_start,
+                    const std::string& str));
+
+ private:
+  // The currently active mock log.
+  static MockLog* g_instance_;
+
+  // Lock protecting access to g_instance_.
+  static Lock g_lock;
+
+  // Static function which is set as the logging message handler.
+  // Called once for each message.
+  static bool LogMessageHandler(int severity,
+                                const char* file,
+                                int line,
+                                size_t message_start,
+                                const std::string& str);
+
+  // True if this object is currently capturing logs.
+  bool is_capturing_logs_;
+
+  // The previous handler to restore when the MockLog is destroyed.
+  logging::LogMessageHandlerFunction previous_handler_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockLog);
+};
+
+}  // namespace test
+}  // namespace base
+
+#endif  // BASE_TEST_MOCK_LOG_H_
diff --git a/base/test/multiprocess_test.cc b/base/test/multiprocess_test.cc
new file mode 100644
index 0000000..2cd6d8c
--- /dev/null
+++ b/base/test/multiprocess_test.cc
@@ -0,0 +1,61 @@
+// Copyright (c) 2012 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/test/multiprocess_test.h"
+
+#include "base/base_switches.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+
+namespace base {
+
+#if !defined(OS_ANDROID)
+Process SpawnMultiProcessTestChild(
+    const std::string& procname,
+    const CommandLine& base_command_line,
+    const LaunchOptions& options) {
+  CommandLine command_line(base_command_line);
+  // TODO(viettrungluu): See comment above |MakeCmdLine()| in the header file.
+  // This is a temporary hack, since |MakeCmdLine()| has to provide a full
+  // command line.
+  if (!command_line.HasSwitch(switches::kTestChildProcess))
+    command_line.AppendSwitchASCII(switches::kTestChildProcess, procname);
+
+  return LaunchProcess(command_line, options);
+}
+#endif  // !defined(OS_ANDROID)
+
+CommandLine GetMultiProcessTestChildBaseCommandLine() {
+  CommandLine cmd_line = *CommandLine::ForCurrentProcess();
+  cmd_line.SetProgram(MakeAbsoluteFilePath(cmd_line.GetProgram()));
+  return cmd_line;
+}
+
+// MultiProcessTest ------------------------------------------------------------
+
+MultiProcessTest::MultiProcessTest() {
+}
+
+Process MultiProcessTest::SpawnChild(const std::string& procname) {
+  LaunchOptions options;
+#if defined(OS_WIN)
+  options.start_hidden = true;
+#endif
+  return SpawnChildWithOptions(procname, options);
+}
+
+Process MultiProcessTest::SpawnChildWithOptions(
+    const std::string& procname,
+    const LaunchOptions& options) {
+  return SpawnMultiProcessTestChild(procname, MakeCmdLine(procname), options);
+}
+
+CommandLine MultiProcessTest::MakeCmdLine(const std::string& procname) {
+  CommandLine command_line = GetMultiProcessTestChildBaseCommandLine();
+  command_line.AppendSwitchASCII(switches::kTestChildProcess, procname);
+  return command_line;
+}
+
+}  // namespace base
diff --git a/base/test/multiprocess_test.h b/base/test/multiprocess_test.h
new file mode 100644
index 0000000..b1c73df
--- /dev/null
+++ b/base/test/multiprocess_test.h
@@ -0,0 +1,131 @@
+// Copyright (c) 2012 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_TEST_MULTIPROCESS_TEST_H_
+#define BASE_TEST_MULTIPROCESS_TEST_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/process/launch.h"
+#include "base/process/process.h"
+#include "build/build_config.h"
+#include "testing/platform_test.h"
+
+namespace base {
+
+class CommandLine;
+
+// Helpers to spawn a child for a multiprocess test and execute a designated
+// function. Use these when you already have another base class for your test
+// fixture, but you want (some) of your tests to be multiprocess (otherwise you
+// may just want to derive your fixture from |MultiProcessTest|, below).
+//
+// Use these helpers as follows:
+//
+//   TEST_F(MyTest, ATest) {
+//     CommandLine command_line(
+//         base::GetMultiProcessTestChildBaseCommandLine());
+//     // Maybe add our own switches to |command_line|....
+//
+//     LaunchOptions options;
+//     // Maybe set some options (e.g., |start_hidden| on Windows)....
+//
+//     // Start a child process and run |a_test_func|.
+//     base::Process test_child_process =
+//         base::SpawnMultiProcessTestChild("a_test_func", command_line,
+//                                          options);
+//
+//     // Do stuff involving |test_child_process| and the child process....
+//
+//     int rv = -1;
+//     ASSERT_TRUE(test_child_process.WaitForExitWithTimeout(
+//         TestTimeouts::action_timeout(), &rv));
+//     EXPECT_EQ(0, rv);
+//   }
+//
+//   // Note: |MULTIPROCESS_TEST_MAIN()| is defined in
+//   // testing/multi_process_function_list.h.
+//   MULTIPROCESS_TEST_MAIN(a_test_func) {
+//     // Code here runs in a child process....
+//     return 0;
+//   }
+
+// Spawns a child process and executes the function |procname| declared using
+// |MULTIPROCESS_TEST_MAIN()| or |MULTIPROCESS_TEST_MAIN_WITH_SETUP()|.
+// |command_line| should be as provided by
+// |GetMultiProcessTestChildBaseCommandLine()| (below), possibly with arguments
+// added. Note: On Windows, you probably want to set |options.start_hidden|.
+Process SpawnMultiProcessTestChild(
+    const std::string& procname,
+    const CommandLine& command_line,
+    const LaunchOptions& options);
+
+// Gets the base command line for |SpawnMultiProcessTestChild()|. To this, you
+// may add any flags needed for your child process.
+CommandLine GetMultiProcessTestChildBaseCommandLine();
+
+// MultiProcessTest ------------------------------------------------------------
+
+// A MultiProcessTest is a test class which makes it easier to
+// write a test which requires code running out of process.
+//
+// To create a multiprocess test simply follow these steps:
+//
+// 1) Derive your test from MultiProcessTest. Example:
+//
+//    class MyTest : public MultiProcessTest {
+//    };
+//
+//    TEST_F(MyTest, TestCaseName) {
+//      ...
+//    }
+//
+// 2) Create a mainline function for the child processes and include
+//    testing/multiprocess_func_list.h.
+//    See the declaration of the MULTIPROCESS_TEST_MAIN macro
+//    in that file for an example.
+// 3) Call SpawnChild("foo"), where "foo" is the name of
+//    the function you wish to run in the child processes.
+// That's it!
+class MultiProcessTest : public PlatformTest {
+ public:
+  MultiProcessTest();
+
+ protected:
+  // Run a child process.
+  // 'procname' is the name of a function which the child will
+  // execute.  It must be exported from this library in order to
+  // run.
+  //
+  // Example signature:
+  //    extern "C" int __declspec(dllexport) FooBar() {
+  //         // do client work here
+  //    }
+  //
+  // Returns the child process.
+  Process SpawnChild(const std::string& procname);
+
+  // Run a child process using the given launch options.
+  //
+  // Note: On Windows, you probably want to set |options.start_hidden|.
+  Process SpawnChildWithOptions(const std::string& procname,
+                                const LaunchOptions& options);
+
+  // Set up the command line used to spawn the child process.
+  // Override this to add things to the command line (calling this first in the
+  // override).
+  // Note that currently some tests rely on this providing a full command line,
+  // which they then use directly with |LaunchProcess()|.
+  // TODO(viettrungluu): Remove this and add a virtual
+  // |ModifyChildCommandLine()|; make the two divergent uses more sane.
+  virtual CommandLine MakeCmdLine(const std::string& procname);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MultiProcessTest);
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_MULTIPROCESS_TEST_H_
diff --git a/base/test/multiprocess_test_android.cc b/base/test/multiprocess_test_android.cc
new file mode 100644
index 0000000..dc489d1
--- /dev/null
+++ b/base/test/multiprocess_test_android.cc
@@ -0,0 +1,75 @@
+// Copyright (c) 2012 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/test/multiprocess_test.h"
+
+#include <unistd.h>
+
+#include "base/base_switches.h"
+#include "base/command_line.h"
+#include "base/containers/hash_tables.h"
+#include "base/logging.h"
+#include "base/posix/global_descriptors.h"
+#include "testing/multiprocess_func_list.h"
+
+namespace base {
+
+// A very basic implementation for Android. On Android tests can run in an APK
+// and we don't have an executable to exec*. This implementation does the bare
+// minimum to execute the method specified by procname (in the child process).
+//  - All options except |fds_to_remap| are ignored.
+Process SpawnMultiProcessTestChild(const std::string& procname,
+                                   const CommandLine& base_command_line,
+                                   const LaunchOptions& options) {
+  // TODO(viettrungluu): The FD-remapping done below is wrong in the presence of
+  // cycles (e.g., fd1 -> fd2, fd2 -> fd1). crbug.com/326576
+  FileHandleMappingVector empty;
+  const FileHandleMappingVector* fds_to_remap =
+      options.fds_to_remap ? options.fds_to_remap : &empty;
+
+  pid_t pid = fork();
+
+  if (pid < 0) {
+    PLOG(ERROR) << "fork";
+    return Process();
+  }
+  if (pid > 0) {
+    // Parent process.
+    return Process(pid);
+  }
+  // Child process.
+  base::hash_set<int> fds_to_keep_open;
+  for (FileHandleMappingVector::const_iterator it = fds_to_remap->begin();
+       it != fds_to_remap->end(); ++it) {
+    fds_to_keep_open.insert(it->first);
+  }
+  // Keep standard FDs (stdin, stdout, stderr, etc.) open since this
+  // is not meant to spawn a daemon.
+  int base = GlobalDescriptors::kBaseDescriptor;
+  for (int fd = base; fd < sysconf(_SC_OPEN_MAX); ++fd) {
+    if (fds_to_keep_open.find(fd) == fds_to_keep_open.end()) {
+      close(fd);
+    }
+  }
+  for (FileHandleMappingVector::const_iterator it = fds_to_remap->begin();
+       it != fds_to_remap->end(); ++it) {
+    int old_fd = it->first;
+    int new_fd = it->second;
+    if (dup2(old_fd, new_fd) < 0) {
+      PLOG(FATAL) << "dup2";
+    }
+    close(old_fd);
+  }
+  CommandLine::Reset();
+  CommandLine::Init(0, nullptr);
+  CommandLine* command_line = CommandLine::ForCurrentProcess();
+  command_line->InitFromArgv(base_command_line.argv());
+  if (!command_line->HasSwitch(switches::kTestChildProcess))
+    command_line->AppendSwitchASCII(switches::kTestChildProcess, procname);
+
+  _exit(multi_process_function_list::InvokeChildProcessTest(procname));
+  return Process();
+}
+
+}  // namespace base
diff --git a/base/test/null_task_runner.cc b/base/test/null_task_runner.cc
new file mode 100644
index 0000000..ffa6bdf
--- /dev/null
+++ b/base/test/null_task_runner.cc
@@ -0,0 +1,31 @@
+// Copyright (c) 2012 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/test/null_task_runner.h"
+
+namespace base {
+
+NullTaskRunner::NullTaskRunner() {}
+
+NullTaskRunner::~NullTaskRunner() {}
+
+bool NullTaskRunner::PostDelayedTask(
+    const tracked_objects::Location& from_here,
+    const base::Closure& task,
+    base::TimeDelta delay) {
+  return false;
+}
+
+bool NullTaskRunner::PostNonNestableDelayedTask(
+    const tracked_objects::Location& from_here,
+    const base::Closure& task,
+    base::TimeDelta delay) {
+  return false;
+}
+
+bool NullTaskRunner::RunsTasksOnCurrentThread() const {
+  return true;
+}
+
+}  // namespace base
diff --git a/base/test/null_task_runner.h b/base/test/null_task_runner.h
new file mode 100644
index 0000000..0f44751
--- /dev/null
+++ b/base/test/null_task_runner.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2012 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_TEST_NULL_TASK_RUNNER_H_
+#define BASE_TEST_NULL_TASK_RUNNER_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/single_thread_task_runner.h"
+
+namespace base {
+
+// Helper class for tests that need to provide an implementation of a
+// *TaskRunner class but don't actually care about tasks being run.
+
+class NullTaskRunner : public base::SingleThreadTaskRunner {
+ public:
+  NullTaskRunner();
+
+  bool PostDelayedTask(const tracked_objects::Location& from_here,
+                       const base::Closure& task,
+                       base::TimeDelta delay) override;
+  bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
+                                  const base::Closure& task,
+                                  base::TimeDelta delay) override;
+  // Always returns true to avoid triggering DCHECKs.
+  bool RunsTasksOnCurrentThread() const override;
+
+ protected:
+  ~NullTaskRunner() override;
+
+  DISALLOW_COPY_AND_ASSIGN(NullTaskRunner);
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_NULL_TASK_RUNNER_H_
diff --git a/base/test/opaque_ref_counted.cc b/base/test/opaque_ref_counted.cc
new file mode 100644
index 0000000..ed6c36f
--- /dev/null
+++ b/base/test/opaque_ref_counted.cc
@@ -0,0 +1,35 @@
+// 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.
+
+#include "base/test/opaque_ref_counted.h"
+
+#include "base/macros.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+class OpaqueRefCounted : public RefCounted<OpaqueRefCounted> {
+ public:
+  OpaqueRefCounted() {}
+
+  int Return42() { return 42; }
+
+ private:
+  virtual ~OpaqueRefCounted() {}
+
+  friend RefCounted<OpaqueRefCounted>;
+  DISALLOW_COPY_AND_ASSIGN(OpaqueRefCounted);
+};
+
+scoped_refptr<OpaqueRefCounted> MakeOpaqueRefCounted() {
+  return new OpaqueRefCounted();
+}
+
+void TestOpaqueRefCounted(scoped_refptr<OpaqueRefCounted> p) {
+  EXPECT_EQ(42, p->Return42());
+}
+
+}  // namespace base
+
+template class scoped_refptr<base::OpaqueRefCounted>;
diff --git a/base/test/opaque_ref_counted.h b/base/test/opaque_ref_counted.h
new file mode 100644
index 0000000..faf6a65
--- /dev/null
+++ b/base/test/opaque_ref_counted.h
@@ -0,0 +1,24 @@
+// 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.
+
+#ifndef BASE_TEST_OPAQUE_REF_COUNTED_H_
+#define BASE_TEST_OPAQUE_REF_COUNTED_H_
+
+#include "base/memory/ref_counted.h"
+
+namespace base {
+
+// OpaqueRefCounted is a test class for scoped_refptr to ensure it still works
+// when the pointed-to type is opaque (i.e., incomplete).
+class OpaqueRefCounted;
+
+// Test functions that return and accept scoped_refptr<OpaqueRefCounted> values.
+scoped_refptr<OpaqueRefCounted> MakeOpaqueRefCounted();
+void TestOpaqueRefCounted(scoped_refptr<OpaqueRefCounted> p);
+
+}  // namespace base
+
+extern template class scoped_refptr<base::OpaqueRefCounted>;
+
+#endif  // BASE_TEST_OPAQUE_REF_COUNTED_H_
diff --git a/base/test/perf_log.cc b/base/test/perf_log.cc
new file mode 100644
index 0000000..22884b8
--- /dev/null
+++ b/base/test/perf_log.cc
@@ -0,0 +1,45 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/perf_log.h"
+
+#include "base/files/file_util.h"
+#include "base/logging.h"
+
+namespace base {
+
+static FILE* perf_log_file = NULL;
+
+bool InitPerfLog(const FilePath& log_file) {
+  if (perf_log_file) {
+    // trying to initialize twice
+    NOTREACHED();
+    return false;
+  }
+
+  perf_log_file = OpenFile(log_file, "w");
+  return perf_log_file != NULL;
+}
+
+void FinalizePerfLog() {
+  if (!perf_log_file) {
+    // trying to cleanup without initializing
+    NOTREACHED();
+    return;
+  }
+  base::CloseFile(perf_log_file);
+}
+
+void LogPerfResult(const char* test_name, double value, const char* units) {
+  if (!perf_log_file) {
+    NOTREACHED();
+    return;
+  }
+
+  fprintf(perf_log_file, "%s\t%g\t%s\n", test_name, value, units);
+  printf("%s\t%g\t%s\n", test_name, value, units);
+  fflush(stdout);
+}
+
+}  // namespace base
diff --git a/base/test/perf_log.h b/base/test/perf_log.h
new file mode 100644
index 0000000..5d6ed9f
--- /dev/null
+++ b/base/test/perf_log.h
@@ -0,0 +1,24 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_PERF_LOG_H_
+#define BASE_TEST_PERF_LOG_H_
+
+namespace base {
+
+class FilePath;
+
+// Initializes and finalizes the perf log. These functions should be
+// called at the beginning and end (respectively) of running all the
+// performance tests. The init function returns true on success.
+bool InitPerfLog(const FilePath& log_path);
+void FinalizePerfLog();
+
+// Writes to the perf result log the given 'value' resulting from the
+// named 'test'. The units are to aid in reading the log by people.
+void LogPerfResult(const char* test_name, double value, const char* units);
+
+}  // namespace base
+
+#endif  // BASE_TEST_PERF_LOG_H_
diff --git a/base/test/perf_test_suite.cc b/base/test/perf_test_suite.cc
new file mode 100644
index 0000000..415aaef
--- /dev/null
+++ b/base/test/perf_test_suite.cc
@@ -0,0 +1,49 @@
+// Copyright (c) 2010 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/test/perf_test_suite.h"
+
+#include "base/command_line.h"
+#include "base/debug/debugger.h"
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "base/process/launch.h"
+#include "base/strings/string_util.h"
+#include "base/test/perf_log.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+PerfTestSuite::PerfTestSuite(int argc, char** argv) : TestSuite(argc, argv) {}
+
+void PerfTestSuite::Initialize() {
+  TestSuite::Initialize();
+
+  // Initialize the perf timer log
+  FilePath log_path =
+      CommandLine::ForCurrentProcess()->GetSwitchValuePath("log-file");
+  if (log_path.empty()) {
+    PathService::Get(FILE_EXE, &log_path);
+#if defined(OS_ANDROID)
+    base::FilePath tmp_dir;
+    PathService::Get(base::DIR_CACHE, &tmp_dir);
+    log_path = tmp_dir.Append(log_path.BaseName());
+#endif
+    log_path = log_path.ReplaceExtension(FILE_PATH_LITERAL("log"));
+    log_path = log_path.InsertBeforeExtension(FILE_PATH_LITERAL("_perf"));
+  }
+  ASSERT_TRUE(InitPerfLog(log_path));
+
+  // Raise to high priority to have more precise measurements. Since we don't
+  // aim at 1% precision, it is not necessary to run at realtime level.
+  if (!debug::BeingDebugged())
+    RaiseProcessToHighPriority();
+}
+
+void PerfTestSuite::Shutdown() {
+  TestSuite::Shutdown();
+  FinalizePerfLog();
+}
+
+}  // namespace base
diff --git a/base/test/perf_test_suite.h b/base/test/perf_test_suite.h
new file mode 100644
index 0000000..52528f0
--- /dev/null
+++ b/base/test/perf_test_suite.h
@@ -0,0 +1,22 @@
+// Copyright (c) 2011 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_TEST_PERF_TEST_SUITE_H_
+#define BASE_TEST_PERF_TEST_SUITE_H_
+
+#include "base/test/test_suite.h"
+
+namespace base {
+
+class PerfTestSuite : public TestSuite {
+ public:
+  PerfTestSuite(int argc, char** argv);
+
+  void Initialize() override;
+  void Shutdown() override;
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_PERF_TEST_SUITE_H_
diff --git a/base/test/perf_time_logger.cc b/base/test/perf_time_logger.cc
new file mode 100644
index 0000000..c05ba51
--- /dev/null
+++ b/base/test/perf_time_logger.cc
@@ -0,0 +1,27 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/perf_time_logger.h"
+
+#include "base/test/perf_log.h"
+
+namespace base {
+
+PerfTimeLogger::PerfTimeLogger(const char* test_name)
+    : logged_(false), test_name_(test_name) {}
+
+PerfTimeLogger::~PerfTimeLogger() {
+  if (!logged_)
+    Done();
+}
+
+void PerfTimeLogger::Done() {
+  // we use a floating-point millisecond value because it is more
+  // intuitive than microseconds and we want more precision than
+  // integer milliseconds
+  LogPerfResult(test_name_.c_str(), timer_.Elapsed().InMillisecondsF(), "ms");
+  logged_ = true;
+}
+
+}  // namespace base
diff --git a/base/test/perf_time_logger.h b/base/test/perf_time_logger.h
new file mode 100644
index 0000000..403b272
--- /dev/null
+++ b/base/test/perf_time_logger.h
@@ -0,0 +1,37 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_PERF_TIME_LOGGER_H_
+#define BASE_TEST_PERF_TIME_LOGGER_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/timer/elapsed_timer.h"
+
+namespace base {
+
+// Automates calling LogPerfResult for the common case where you want
+// to measure the time that something took. Call Done() when the test
+// is complete if you do extra work after the test or there are stack
+// objects with potentially expensive constructors. Otherwise, this
+// class with automatically log on destruction.
+class PerfTimeLogger {
+ public:
+  explicit PerfTimeLogger(const char* test_name);
+  ~PerfTimeLogger();
+
+  void Done();
+
+ private:
+  bool logged_;
+  std::string test_name_;
+  ElapsedTimer timer_;
+
+  DISALLOW_COPY_AND_ASSIGN(PerfTimeLogger);
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_PERF_TIME_LOGGER_H_
diff --git a/base/test/power_monitor_test_base.cc b/base/test/power_monitor_test_base.cc
new file mode 100644
index 0000000..73438ea
--- /dev/null
+++ b/base/test/power_monitor_test_base.cc
@@ -0,0 +1,64 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/power_monitor_test_base.h"
+
+#include "base/message_loop/message_loop.h"
+#include "base/power_monitor/power_monitor.h"
+#include "base/power_monitor/power_monitor_source.h"
+
+namespace base {
+
+PowerMonitorTestSource::PowerMonitorTestSource()
+    : test_on_battery_power_(false) {
+}
+
+PowerMonitorTestSource::~PowerMonitorTestSource() {
+}
+
+void PowerMonitorTestSource::GeneratePowerStateEvent(bool on_battery_power) {
+  test_on_battery_power_ = on_battery_power;
+  ProcessPowerEvent(POWER_STATE_EVENT);
+  message_loop_.RunUntilIdle();
+}
+
+void PowerMonitorTestSource::GenerateSuspendEvent() {
+  ProcessPowerEvent(SUSPEND_EVENT);
+  message_loop_.RunUntilIdle();
+}
+
+void PowerMonitorTestSource::GenerateResumeEvent() {
+  ProcessPowerEvent(RESUME_EVENT);
+  message_loop_.RunUntilIdle();
+}
+
+bool PowerMonitorTestSource::IsOnBatteryPowerImpl() {
+  return test_on_battery_power_;
+};
+
+PowerMonitorTestObserver::PowerMonitorTestObserver()
+    : last_power_state_(false),
+      power_state_changes_(0),
+      suspends_(0),
+      resumes_(0) {
+}
+
+PowerMonitorTestObserver::~PowerMonitorTestObserver() {
+}
+
+// PowerObserver callbacks.
+void PowerMonitorTestObserver::OnPowerStateChange(bool on_battery_power) {
+  last_power_state_ = on_battery_power;
+  power_state_changes_++;
+}
+
+void PowerMonitorTestObserver::OnSuspend() {
+  suspends_++;
+}
+
+void PowerMonitorTestObserver::OnResume() {
+  resumes_++;
+}
+
+}  // namespace base
diff --git a/base/test/power_monitor_test_base.h b/base/test/power_monitor_test_base.h
new file mode 100644
index 0000000..4655eae
--- /dev/null
+++ b/base/test/power_monitor_test_base.h
@@ -0,0 +1,55 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_POWER_MONITOR_TEST_BASE_H_
+#define BASE_TEST_POWER_MONITOR_TEST_BASE_H_
+
+#include "base/message_loop/message_loop.h"
+#include "base/power_monitor/power_monitor.h"
+#include "base/power_monitor/power_monitor_source.h"
+
+namespace base {
+
+class PowerMonitorTestSource : public PowerMonitorSource {
+ public:
+  PowerMonitorTestSource();
+  ~PowerMonitorTestSource() override;
+
+  void GeneratePowerStateEvent(bool on_battery_power);
+  void GenerateSuspendEvent();
+  void GenerateResumeEvent();
+
+ protected:
+  bool IsOnBatteryPowerImpl() override;
+
+  bool test_on_battery_power_;
+  MessageLoop message_loop_;
+};
+
+class PowerMonitorTestObserver : public PowerObserver {
+ public:
+  PowerMonitorTestObserver();
+  ~PowerMonitorTestObserver() override;
+
+  // PowerObserver callbacks.
+  void OnPowerStateChange(bool on_battery_power) override;
+  void OnSuspend() override;
+  void OnResume() override;
+
+  // Test status counts.
+  bool last_power_state() { return last_power_state_; }
+  int power_state_changes() { return power_state_changes_; }
+  int suspends() { return suspends_; }
+  int resumes() { return resumes_; }
+
+ private:
+  bool last_power_state_; // Last power state we were notified of.
+  int power_state_changes_;  // Count of OnPowerStateChange notifications.
+  int suspends_;  // Count of OnSuspend notifications.
+  int resumes_;  // Count of OnResume notifications.
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_POWER_MONITOR_TEST_BASE_H_
diff --git a/base/test/run_all_perftests.cc b/base/test/run_all_perftests.cc
new file mode 100644
index 0000000..6e38109
--- /dev/null
+++ b/base/test/run_all_perftests.cc
@@ -0,0 +1,9 @@
+// Copyright (c) 2012 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/test/perf_test_suite.h"
+
+int main(int argc, char** argv) {
+  return base::PerfTestSuite(argc, argv).Run();
+}
diff --git a/base/test/run_all_unittests.cc b/base/test/run_all_unittests.cc
new file mode 100644
index 0000000..93cb8cb
--- /dev/null
+++ b/base/test/run_all_unittests.cc
@@ -0,0 +1,40 @@
+// Copyright (c) 2012 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/at_exit.h"
+#include "base/bind.h"
+#include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/test_suite.h"
+
+#if defined(OS_ANDROID)
+#include "base/android/jni_android.h"
+#include "base/test/test_file_util.h"
+#endif
+
+namespace {
+
+class NoAtExitBaseTestSuite : public base::TestSuite {
+ public:
+  NoAtExitBaseTestSuite(int argc, char** argv)
+      : base::TestSuite(argc, argv, false) {
+  }
+};
+
+int RunTestSuite(int argc, char** argv) {
+  return NoAtExitBaseTestSuite(argc, argv).Run();
+}
+
+}  // namespace
+
+int main(int argc, char** argv) {
+#if defined(OS_ANDROID)
+  JNIEnv* env = base::android::AttachCurrentThread();
+  base::RegisterContentUriTestUtils(env);
+#else
+  base::AtExitManager at_exit;
+#endif
+  return base::LaunchUnitTests(argc,
+                               argv,
+                               base::Bind(&RunTestSuite, argc, argv));
+}
diff --git a/base/test/scoped_locale.cc b/base/test/scoped_locale.cc
new file mode 100644
index 0000000..35b3fbe
--- /dev/null
+++ b/base/test/scoped_locale.cc
@@ -0,0 +1,23 @@
+// Copyright (c) 2011 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/test/scoped_locale.h"
+
+#include <locale.h>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+ScopedLocale::ScopedLocale(const std::string& locale) {
+  prev_locale_ = setlocale(LC_ALL, NULL);
+  EXPECT_TRUE(setlocale(LC_ALL, locale.c_str()) != NULL) <<
+      "Failed to set locale: " << locale;
+}
+
+ScopedLocale::~ScopedLocale() {
+  EXPECT_STREQ(prev_locale_.c_str(), setlocale(LC_ALL, prev_locale_.c_str()));
+}
+
+}  // namespace base
diff --git a/base/test/scoped_locale.h b/base/test/scoped_locale.h
new file mode 100644
index 0000000..a9f9348
--- /dev/null
+++ b/base/test/scoped_locale.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2011 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_TEST_SCOPED_LOCALE_H_
+#define BASE_TEST_SCOPED_LOCALE_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+
+namespace base {
+
+// Sets the given |locale| on construction, and restores the previous locale
+// on destruction.
+class ScopedLocale {
+ public:
+  explicit ScopedLocale(const std::string& locale);
+  ~ScopedLocale();
+
+ private:
+  std::string prev_locale_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedLocale);
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_SCOPED_LOCALE_H_
diff --git a/base/test/scoped_path_override.cc b/base/test/scoped_path_override.cc
new file mode 100644
index 0000000..9a77611
--- /dev/null
+++ b/base/test/scoped_path_override.cc
@@ -0,0 +1,40 @@
+// Copyright (c) 2012 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/test/scoped_path_override.h"
+
+#include "base/logging.h"
+#include "base/path_service.h"
+
+namespace base {
+
+ScopedPathOverride::ScopedPathOverride(int key) : key_(key) {
+  bool result = temp_dir_.CreateUniqueTempDir();
+  CHECK(result);
+  result = PathService::Override(key, temp_dir_.path());
+  CHECK(result);
+}
+
+ScopedPathOverride::ScopedPathOverride(int key, const base::FilePath& dir)
+    : key_(key) {
+  bool result = PathService::Override(key, dir);
+  CHECK(result);
+}
+
+ScopedPathOverride::ScopedPathOverride(int key,
+                                       const FilePath& path,
+                                       bool is_absolute,
+                                       bool create)
+    : key_(key) {
+  bool result =
+      PathService::OverrideAndCreateIfNeeded(key, path, is_absolute, create);
+  CHECK(result);
+}
+
+ScopedPathOverride::~ScopedPathOverride() {
+   bool result = PathService::RemoveOverride(key_);
+   CHECK(result) << "The override seems to have been removed already!";
+}
+
+}  // namespace base
diff --git a/base/test/scoped_path_override.h b/base/test/scoped_path_override.h
new file mode 100644
index 0000000..c6cffe2
--- /dev/null
+++ b/base/test/scoped_path_override.h
@@ -0,0 +1,43 @@
+// Copyright (c) 2012 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_TEST_SCOPED_PATH_OVERRIDE_H_
+#define BASE_TEST_SCOPED_PATH_OVERRIDE_H_
+
+#include "base/basictypes.h"
+#include "base/files/scoped_temp_dir.h"
+
+namespace base {
+
+class FilePath;
+
+// Sets a path override on construction, and removes it when the object goes out
+// of scope. This class is intended to be used by tests that need to override
+// paths to ensure their overrides are properly handled and reverted when the
+// scope of the test is left.
+class ScopedPathOverride {
+ public:
+  // Contructor that initializes the override to a scoped temp directory.
+  explicit ScopedPathOverride(int key);
+
+  // Constructor that would use a path provided by the user.
+  ScopedPathOverride(int key, const FilePath& dir);
+
+  // See PathService::OverrideAndCreateIfNeeded.
+  ScopedPathOverride(int key,
+                     const FilePath& path,
+                     bool is_absolute,
+                     bool create);
+  ~ScopedPathOverride();
+
+ private:
+  int key_;
+  ScopedTempDir temp_dir_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedPathOverride);
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_SCOPED_PATH_OVERRIDE_H_
diff --git a/base/test/sequenced_task_runner_test_template.cc b/base/test/sequenced_task_runner_test_template.cc
new file mode 100644
index 0000000..010f439
--- /dev/null
+++ b/base/test/sequenced_task_runner_test_template.cc
@@ -0,0 +1,270 @@
+// Copyright (c) 2012 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/test/sequenced_task_runner_test_template.h"
+
+#include <ostream>
+
+#include "base/location.h"
+
+namespace base {
+
+namespace internal {
+
+TaskEvent::TaskEvent(int i, Type type)
+  : i(i), type(type) {
+}
+
+SequencedTaskTracker::SequencedTaskTracker()
+    : next_post_i_(0),
+      task_end_count_(0),
+      task_end_cv_(&lock_) {
+}
+
+void SequencedTaskTracker::PostWrappedNonNestableTask(
+    const scoped_refptr<SequencedTaskRunner>& task_runner,
+    const Closure& task) {
+  AutoLock event_lock(lock_);
+  const int post_i = next_post_i_++;
+  Closure wrapped_task = Bind(&SequencedTaskTracker::RunTask, this,
+                              task, post_i);
+  task_runner->PostNonNestableTask(FROM_HERE, wrapped_task);
+  TaskPosted(post_i);
+}
+
+void SequencedTaskTracker::PostWrappedNestableTask(
+    const scoped_refptr<SequencedTaskRunner>& task_runner,
+    const Closure& task) {
+  AutoLock event_lock(lock_);
+  const int post_i = next_post_i_++;
+  Closure wrapped_task = Bind(&SequencedTaskTracker::RunTask, this,
+                              task, post_i);
+  task_runner->PostTask(FROM_HERE, wrapped_task);
+  TaskPosted(post_i);
+}
+
+void SequencedTaskTracker::PostWrappedDelayedNonNestableTask(
+    const scoped_refptr<SequencedTaskRunner>& task_runner,
+    const Closure& task,
+    TimeDelta delay) {
+  AutoLock event_lock(lock_);
+  const int post_i = next_post_i_++;
+  Closure wrapped_task = Bind(&SequencedTaskTracker::RunTask, this,
+                              task, post_i);
+  task_runner->PostNonNestableDelayedTask(FROM_HERE, wrapped_task, delay);
+  TaskPosted(post_i);
+}
+
+void SequencedTaskTracker::PostNonNestableTasks(
+    const scoped_refptr<SequencedTaskRunner>& task_runner,
+    int task_count) {
+  for (int i = 0; i < task_count; ++i) {
+    PostWrappedNonNestableTask(task_runner, Closure());
+  }
+}
+
+void SequencedTaskTracker::RunTask(const Closure& task, int task_i) {
+  TaskStarted(task_i);
+  if (!task.is_null())
+    task.Run();
+  TaskEnded(task_i);
+}
+
+void SequencedTaskTracker::TaskPosted(int i) {
+  // Caller must own |lock_|.
+  events_.push_back(TaskEvent(i, TaskEvent::POST));
+}
+
+void SequencedTaskTracker::TaskStarted(int i) {
+  AutoLock lock(lock_);
+  events_.push_back(TaskEvent(i, TaskEvent::START));
+}
+
+void SequencedTaskTracker::TaskEnded(int i) {
+  AutoLock lock(lock_);
+  events_.push_back(TaskEvent(i, TaskEvent::END));
+  ++task_end_count_;
+  task_end_cv_.Signal();
+}
+
+const std::vector<TaskEvent>&
+SequencedTaskTracker::GetTaskEvents() const {
+  return events_;
+}
+
+void SequencedTaskTracker::WaitForCompletedTasks(int count) {
+  AutoLock lock(lock_);
+  while (task_end_count_ < count)
+    task_end_cv_.Wait();
+}
+
+SequencedTaskTracker::~SequencedTaskTracker() {
+}
+
+void PrintTo(const TaskEvent& event, std::ostream* os) {
+  *os << "(i=" << event.i << ", type=";
+  switch (event.type) {
+    case TaskEvent::POST: *os << "POST"; break;
+    case TaskEvent::START: *os << "START"; break;
+    case TaskEvent::END: *os << "END"; break;
+  }
+  *os << ")";
+}
+
+namespace {
+
+// Returns the task ordinals for the task event type |type| in the order that
+// they were recorded.
+std::vector<int> GetEventTypeOrder(const std::vector<TaskEvent>& events,
+                                   TaskEvent::Type type) {
+  std::vector<int> tasks;
+  std::vector<TaskEvent>::const_iterator event;
+  for (event = events.begin(); event != events.end(); ++event) {
+    if (event->type == type)
+      tasks.push_back(event->i);
+  }
+  return tasks;
+}
+
+// Returns all task events for task |task_i|.
+std::vector<TaskEvent::Type> GetEventsForTask(
+    const std::vector<TaskEvent>& events,
+    int task_i) {
+  std::vector<TaskEvent::Type> task_event_orders;
+  std::vector<TaskEvent>::const_iterator event;
+  for (event = events.begin(); event != events.end(); ++event) {
+    if (event->i == task_i)
+      task_event_orders.push_back(event->type);
+  }
+  return task_event_orders;
+}
+
+// Checks that the task events for each task in |events| occur in the order
+// {POST, START, END}, and that there is only one instance of each event type
+// per task.
+::testing::AssertionResult CheckEventOrdersForEachTask(
+    const std::vector<TaskEvent>& events,
+    int task_count) {
+  std::vector<TaskEvent::Type> expected_order;
+  expected_order.push_back(TaskEvent::POST);
+  expected_order.push_back(TaskEvent::START);
+  expected_order.push_back(TaskEvent::END);
+
+  // This is O(n^2), but it runs fast enough currently so is not worth
+  // optimizing.
+  for (int i = 0; i < task_count; ++i) {
+    const std::vector<TaskEvent::Type> task_events =
+        GetEventsForTask(events, i);
+    if (task_events != expected_order) {
+      return ::testing::AssertionFailure()
+          << "Events for task " << i << " are out of order; expected: "
+          << ::testing::PrintToString(expected_order) << "; actual: "
+          << ::testing::PrintToString(task_events);
+    }
+  }
+  return ::testing::AssertionSuccess();
+}
+
+// Checks that no two tasks were running at the same time. I.e. the only
+// events allowed between the START and END of a task are the POSTs of other
+// tasks.
+::testing::AssertionResult CheckNoTaskRunsOverlap(
+    const std::vector<TaskEvent>& events) {
+  // If > -1, we're currently inside a START, END pair.
+  int current_task_i = -1;
+
+  std::vector<TaskEvent>::const_iterator event;
+  for (event = events.begin(); event != events.end(); ++event) {
+    bool spurious_event_found = false;
+
+    if (current_task_i == -1) {  // Not inside a START, END pair.
+      switch (event->type) {
+        case TaskEvent::POST:
+          break;
+        case TaskEvent::START:
+          current_task_i = event->i;
+          break;
+        case TaskEvent::END:
+          spurious_event_found = true;
+          break;
+      }
+
+    } else {  // Inside a START, END pair.
+      bool interleaved_task_detected = false;
+
+      switch (event->type) {
+        case TaskEvent::POST:
+          if (event->i == current_task_i)
+            spurious_event_found = true;
+          break;
+        case TaskEvent::START:
+          interleaved_task_detected = true;
+          break;
+        case TaskEvent::END:
+          if (event->i != current_task_i)
+            interleaved_task_detected = true;
+          else
+            current_task_i = -1;
+          break;
+      }
+
+      if (interleaved_task_detected) {
+        return ::testing::AssertionFailure()
+            << "Found event " << ::testing::PrintToString(*event)
+            << " between START and END events for task " << current_task_i
+            << "; event dump: " << ::testing::PrintToString(events);
+      }
+    }
+
+    if (spurious_event_found) {
+      const int event_i = event - events.begin();
+      return ::testing::AssertionFailure()
+          << "Spurious event " << ::testing::PrintToString(*event)
+          << " at position " << event_i << "; event dump: "
+          << ::testing::PrintToString(events);
+    }
+  }
+
+  return ::testing::AssertionSuccess();
+}
+
+}  // namespace
+
+::testing::AssertionResult CheckNonNestableInvariants(
+    const std::vector<TaskEvent>& events,
+    int task_count) {
+  const std::vector<int> post_order =
+      GetEventTypeOrder(events, TaskEvent::POST);
+  const std::vector<int> start_order =
+      GetEventTypeOrder(events, TaskEvent::START);
+  const std::vector<int> end_order =
+      GetEventTypeOrder(events, TaskEvent::END);
+
+  if (start_order != post_order) {
+    return ::testing::AssertionFailure()
+        << "Expected START order (which equals actual POST order): \n"
+        << ::testing::PrintToString(post_order)
+        << "\n Actual START order:\n"
+        << ::testing::PrintToString(start_order);
+  }
+
+  if (end_order != post_order) {
+    return ::testing::AssertionFailure()
+        << "Expected END order (which equals actual POST order): \n"
+        << ::testing::PrintToString(post_order)
+        << "\n Actual END order:\n"
+        << ::testing::PrintToString(end_order);
+  }
+
+  const ::testing::AssertionResult result =
+      CheckEventOrdersForEachTask(events, task_count);
+  if (!result)
+    return result;
+
+  return CheckNoTaskRunsOverlap(events);
+}
+
+}  // namespace internal
+
+}  // namespace base
diff --git a/base/test/sequenced_task_runner_test_template.h b/base/test/sequenced_task_runner_test_template.h
new file mode 100644
index 0000000..c208d3c
--- /dev/null
+++ b/base/test/sequenced_task_runner_test_template.h
@@ -0,0 +1,341 @@
+// Copyright (c) 2012 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 class defines tests that implementations of SequencedTaskRunner should
+// pass in order to be conformant. See task_runner_test_template.h for a
+// description of how to use the constructs in this file; these work the same.
+
+#ifndef BASE_TEST_SEQUENCED_TASK_RUNNER_TEST_TEMPLATE_H_
+#define BASE_TEST_SEQUENCED_TASK_RUNNER_TEST_TEMPLATE_H_
+
+#include <cstddef>
+#include <iosfwd>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "base/sequenced_task_runner.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace internal {
+
+struct TaskEvent {
+  enum Type { POST, START, END };
+  TaskEvent(int i, Type type);
+  int i;
+  Type type;
+};
+
+// Utility class used in the tests below.
+class SequencedTaskTracker : public RefCountedThreadSafe<SequencedTaskTracker> {
+ public:
+  SequencedTaskTracker();
+
+  // Posts the non-nestable task |task|, and records its post event.
+  void PostWrappedNonNestableTask(
+      const scoped_refptr<SequencedTaskRunner>& task_runner,
+      const Closure& task);
+
+  // Posts the nestable task |task|, and records its post event.
+  void PostWrappedNestableTask(
+      const scoped_refptr<SequencedTaskRunner>& task_runner,
+      const Closure& task);
+
+  // Posts the delayed non-nestable task |task|, and records its post event.
+  void PostWrappedDelayedNonNestableTask(
+      const scoped_refptr<SequencedTaskRunner>& task_runner,
+      const Closure& task,
+      TimeDelta delay);
+
+  // Posts |task_count| non-nestable tasks.
+  void PostNonNestableTasks(
+      const scoped_refptr<SequencedTaskRunner>& task_runner,
+      int task_count);
+
+  const std::vector<TaskEvent>& GetTaskEvents() const;
+
+  // Returns after the tracker observes a total of |count| task completions.
+  void WaitForCompletedTasks(int count);
+
+ private:
+  friend class RefCountedThreadSafe<SequencedTaskTracker>;
+
+  ~SequencedTaskTracker();
+
+  // A task which runs |task|, recording the start and end events.
+  void RunTask(const Closure& task, int task_i);
+
+  // Records a post event for task |i|. The owner is expected to be holding
+  // |lock_| (unlike |TaskStarted| and |TaskEnded|).
+  void TaskPosted(int i);
+
+  // Records a start event for task |i|.
+  void TaskStarted(int i);
+
+  // Records a end event for task |i|.
+  void TaskEnded(int i);
+
+  // Protects events_, next_post_i_, task_end_count_ and task_end_cv_.
+  Lock lock_;
+
+  // The events as they occurred for each task (protected by lock_).
+  std::vector<TaskEvent> events_;
+
+  // The ordinal to be used for the next task-posting task (protected by
+  // lock_).
+  int next_post_i_;
+
+  // The number of task end events we've received.
+  int task_end_count_;
+  ConditionVariable task_end_cv_;
+
+  DISALLOW_COPY_AND_ASSIGN(SequencedTaskTracker);
+};
+
+void PrintTo(const TaskEvent& event, std::ostream* os);
+
+// Checks the non-nestable task invariants for all tasks in |events|.
+//
+// The invariants are:
+// 1) Events started and ended in the same order that they were posted.
+// 2) Events for an individual tasks occur in the order {POST, START, END},
+//    and there is only one instance of each event type for a task.
+// 3) The only events between a task's START and END events are the POSTs of
+//    other tasks. I.e. tasks were run sequentially, not interleaved.
+::testing::AssertionResult CheckNonNestableInvariants(
+    const std::vector<TaskEvent>& events,
+    int task_count);
+
+}  // namespace internal
+
+template <typename TaskRunnerTestDelegate>
+class SequencedTaskRunnerTest : public testing::Test {
+ protected:
+  SequencedTaskRunnerTest()
+      : task_tracker_(new internal::SequencedTaskTracker()) {}
+
+  const scoped_refptr<internal::SequencedTaskTracker> task_tracker_;
+  TaskRunnerTestDelegate delegate_;
+};
+
+TYPED_TEST_CASE_P(SequencedTaskRunnerTest);
+
+// This test posts N non-nestable tasks in sequence, and expects them to run
+// in FIFO order, with no part of any two tasks' execution
+// overlapping. I.e. that each task starts only after the previously-posted
+// one has finished.
+TYPED_TEST_P(SequencedTaskRunnerTest, SequentialNonNestable) {
+  const int kTaskCount = 1000;
+
+  this->delegate_.StartTaskRunner();
+  const scoped_refptr<SequencedTaskRunner> task_runner =
+      this->delegate_.GetTaskRunner();
+
+  this->task_tracker_->PostWrappedNonNestableTask(
+      task_runner, Bind(&PlatformThread::Sleep, TimeDelta::FromSeconds(1)));
+  for (int i = 1; i < kTaskCount; ++i) {
+    this->task_tracker_->PostWrappedNonNestableTask(task_runner, Closure());
+  }
+
+  this->delegate_.StopTaskRunner();
+
+  EXPECT_TRUE(CheckNonNestableInvariants(this->task_tracker_->GetTaskEvents(),
+                                         kTaskCount));
+}
+
+// This test posts N nestable tasks in sequence. It has the same expectations
+// as SequentialNonNestable because even though the tasks are nestable, they
+// will not be run nestedly in this case.
+TYPED_TEST_P(SequencedTaskRunnerTest, SequentialNestable) {
+  const int kTaskCount = 1000;
+
+  this->delegate_.StartTaskRunner();
+  const scoped_refptr<SequencedTaskRunner> task_runner =
+      this->delegate_.GetTaskRunner();
+
+  this->task_tracker_->PostWrappedNestableTask(
+      task_runner,
+      Bind(&PlatformThread::Sleep, TimeDelta::FromSeconds(1)));
+  for (int i = 1; i < kTaskCount; ++i) {
+    this->task_tracker_->PostWrappedNestableTask(task_runner, Closure());
+  }
+
+  this->delegate_.StopTaskRunner();
+
+  EXPECT_TRUE(CheckNonNestableInvariants(this->task_tracker_->GetTaskEvents(),
+                                         kTaskCount));
+}
+
+// This test posts non-nestable tasks in order of increasing delay, and checks
+// that that the tasks are run in FIFO order and that there is no execution
+// overlap whatsoever between any two tasks.
+TYPED_TEST_P(SequencedTaskRunnerTest, SequentialDelayedNonNestable) {
+  const int kTaskCount = 20;
+  const int kDelayIncrementMs = 50;
+
+  this->delegate_.StartTaskRunner();
+  const scoped_refptr<SequencedTaskRunner> task_runner =
+      this->delegate_.GetTaskRunner();
+
+  for (int i = 0; i < kTaskCount; ++i) {
+    this->task_tracker_->PostWrappedDelayedNonNestableTask(
+        task_runner,
+        Closure(),
+        TimeDelta::FromMilliseconds(kDelayIncrementMs * i));
+  }
+
+  this->task_tracker_->WaitForCompletedTasks(kTaskCount);
+  this->delegate_.StopTaskRunner();
+
+  EXPECT_TRUE(CheckNonNestableInvariants(this->task_tracker_->GetTaskEvents(),
+                                         kTaskCount));
+}
+
+// This test posts a fast, non-nestable task from within each of a number of
+// slow, non-nestable tasks and checks that they all run in the sequence they
+// were posted in and that there is no execution overlap whatsoever.
+TYPED_TEST_P(SequencedTaskRunnerTest, NonNestablePostFromNonNestableTask) {
+  const int kParentCount = 10;
+  const int kChildrenPerParent = 10;
+
+  this->delegate_.StartTaskRunner();
+  const scoped_refptr<SequencedTaskRunner> task_runner =
+      this->delegate_.GetTaskRunner();
+
+  for (int i = 0; i < kParentCount; ++i) {
+    Closure task = Bind(
+        &internal::SequencedTaskTracker::PostNonNestableTasks,
+        this->task_tracker_,
+        task_runner,
+        kChildrenPerParent);
+    this->task_tracker_->PostWrappedNonNestableTask(task_runner, task);
+  }
+
+  this->delegate_.StopTaskRunner();
+
+  EXPECT_TRUE(CheckNonNestableInvariants(
+      this->task_tracker_->GetTaskEvents(),
+      kParentCount * (kChildrenPerParent + 1)));
+}
+
+// This test posts a delayed task, and checks that the task is run later than
+// the specified time.
+TYPED_TEST_P(SequencedTaskRunnerTest, DelayedTaskBasic) {
+  const int kTaskCount = 1;
+  const TimeDelta kDelay = TimeDelta::FromMilliseconds(100);
+
+  this->delegate_.StartTaskRunner();
+  const scoped_refptr<SequencedTaskRunner> task_runner =
+      this->delegate_.GetTaskRunner();
+
+  Time time_before_run = Time::Now();
+  this->task_tracker_->PostWrappedDelayedNonNestableTask(
+      task_runner, Closure(), kDelay);
+  this->task_tracker_->WaitForCompletedTasks(kTaskCount);
+  this->delegate_.StopTaskRunner();
+  Time time_after_run = Time::Now();
+
+  EXPECT_TRUE(CheckNonNestableInvariants(this->task_tracker_->GetTaskEvents(),
+                                         kTaskCount));
+  EXPECT_LE(kDelay, time_after_run - time_before_run);
+}
+
+// This test posts two tasks with the same delay, and checks that the tasks are
+// run in the order in which they were posted.
+//
+// NOTE: This is actually an approximate test since the API only takes a
+// "delay" parameter, so we are not exactly simulating two tasks that get
+// posted at the exact same time. It would be nice if the API allowed us to
+// specify the desired run time.
+TYPED_TEST_P(SequencedTaskRunnerTest, DelayedTasksSameDelay) {
+  const int kTaskCount = 2;
+  const TimeDelta kDelay = TimeDelta::FromMilliseconds(100);
+
+  this->delegate_.StartTaskRunner();
+  const scoped_refptr<SequencedTaskRunner> task_runner =
+      this->delegate_.GetTaskRunner();
+
+  this->task_tracker_->PostWrappedDelayedNonNestableTask(
+      task_runner, Closure(), kDelay);
+  this->task_tracker_->PostWrappedDelayedNonNestableTask(
+      task_runner, Closure(), kDelay);
+  this->task_tracker_->WaitForCompletedTasks(kTaskCount);
+  this->delegate_.StopTaskRunner();
+
+  EXPECT_TRUE(CheckNonNestableInvariants(this->task_tracker_->GetTaskEvents(),
+                                         kTaskCount));
+}
+
+// This test posts a normal task and a delayed task, and checks that the
+// delayed task runs after the normal task even if the normal task takes
+// a long time to run.
+TYPED_TEST_P(SequencedTaskRunnerTest, DelayedTaskAfterLongTask) {
+  const int kTaskCount = 2;
+
+  this->delegate_.StartTaskRunner();
+  const scoped_refptr<SequencedTaskRunner> task_runner =
+      this->delegate_.GetTaskRunner();
+
+  this->task_tracker_->PostWrappedNonNestableTask(
+      task_runner, base::Bind(&PlatformThread::Sleep,
+                              TimeDelta::FromMilliseconds(50)));
+  this->task_tracker_->PostWrappedDelayedNonNestableTask(
+      task_runner, Closure(), TimeDelta::FromMilliseconds(10));
+  this->task_tracker_->WaitForCompletedTasks(kTaskCount);
+  this->delegate_.StopTaskRunner();
+
+  EXPECT_TRUE(CheckNonNestableInvariants(this->task_tracker_->GetTaskEvents(),
+                                         kTaskCount));
+}
+
+// Test that a pile of normal tasks and a delayed task run in the
+// time-to-run order.
+TYPED_TEST_P(SequencedTaskRunnerTest, DelayedTaskAfterManyLongTasks) {
+  const int kTaskCount = 11;
+
+  this->delegate_.StartTaskRunner();
+  const scoped_refptr<SequencedTaskRunner> task_runner =
+      this->delegate_.GetTaskRunner();
+
+  for (int i = 0; i < kTaskCount - 1; i++) {
+    this->task_tracker_->PostWrappedNonNestableTask(
+        task_runner, base::Bind(&PlatformThread::Sleep,
+                                TimeDelta::FromMilliseconds(50)));
+  }
+  this->task_tracker_->PostWrappedDelayedNonNestableTask(
+      task_runner, Closure(), TimeDelta::FromMilliseconds(10));
+  this->task_tracker_->WaitForCompletedTasks(kTaskCount);
+  this->delegate_.StopTaskRunner();
+
+  EXPECT_TRUE(CheckNonNestableInvariants(this->task_tracker_->GetTaskEvents(),
+                                         kTaskCount));
+}
+
+
+// TODO(francoisk777@gmail.com) Add a test, similiar to the above, which runs
+// some tasked nestedly (which should be implemented in the test
+// delegate). Also add, to the the test delegate, a predicate which checks
+// whether the implementation supports nested tasks.
+//
+
+REGISTER_TYPED_TEST_CASE_P(SequencedTaskRunnerTest,
+                           SequentialNonNestable,
+                           SequentialNestable,
+                           SequentialDelayedNonNestable,
+                           NonNestablePostFromNonNestableTask,
+                           DelayedTaskBasic,
+                           DelayedTasksSameDelay,
+                           DelayedTaskAfterLongTask,
+                           DelayedTaskAfterManyLongTasks);
+
+}  // namespace base
+
+#endif  // BASE_TEST_SEQUENCED_TASK_RUNNER_TEST_TEMPLATE_H_
diff --git a/base/test/sequenced_worker_pool_owner.cc b/base/test/sequenced_worker_pool_owner.cc
new file mode 100644
index 0000000..b0d8b7a
--- /dev/null
+++ b/base/test/sequenced_worker_pool_owner.cc
@@ -0,0 +1,58 @@
+// Copyright (c) 2012 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/test/sequenced_worker_pool_owner.h"
+
+#include "base/location.h"
+#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
+
+namespace base {
+
+SequencedWorkerPoolOwner::SequencedWorkerPoolOwner(
+    size_t max_threads,
+    const std::string& thread_name_prefix)
+    : constructor_message_loop_(MessageLoop::current()),
+      pool_(new SequencedWorkerPool(max_threads, thread_name_prefix, this)),
+      has_work_call_count_(0) {}
+
+SequencedWorkerPoolOwner::~SequencedWorkerPoolOwner() {
+  pool_ = NULL;
+  MessageLoop::current()->Run();
+}
+
+const scoped_refptr<SequencedWorkerPool>& SequencedWorkerPoolOwner::pool() {
+  return pool_;
+}
+
+void SequencedWorkerPoolOwner::SetWillWaitForShutdownCallback(
+    const Closure& callback) {
+  will_wait_for_shutdown_callback_ = callback;
+}
+
+int SequencedWorkerPoolOwner::has_work_call_count() const {
+  AutoLock lock(has_work_lock_);
+  return has_work_call_count_;
+}
+
+void SequencedWorkerPoolOwner::OnHasWork() {
+  AutoLock lock(has_work_lock_);
+  ++has_work_call_count_;
+}
+
+void SequencedWorkerPoolOwner::WillWaitForShutdown() {
+  if (!will_wait_for_shutdown_callback_.is_null()) {
+    will_wait_for_shutdown_callback_.Run();
+
+    // Release the reference to the callback to prevent retain cycles.
+    will_wait_for_shutdown_callback_ = Closure();
+  }
+}
+
+void SequencedWorkerPoolOwner::OnDestruct() {
+  constructor_message_loop_->task_runner()->PostTask(
+      FROM_HERE, constructor_message_loop_->QuitWhenIdleClosure());
+}
+
+}  // namespace base
diff --git a/base/test/sequenced_worker_pool_owner.h b/base/test/sequenced_worker_pool_owner.h
new file mode 100644
index 0000000..bf5f2f7
--- /dev/null
+++ b/base/test/sequenced_worker_pool_owner.h
@@ -0,0 +1,61 @@
+// Copyright (c) 2012 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_TEST_SEQUENCED_WORKER_POOL_OWNER_H_
+#define BASE_TEST_SEQUENCED_WORKER_POOL_OWNER_H_
+
+#include <cstddef>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/sequenced_worker_pool.h"
+
+namespace base {
+
+class MessageLoop;
+
+// Wrapper around SequencedWorkerPool for testing that blocks destruction
+// until the pool is actually destroyed.  This is so that a
+// SequencedWorkerPool from one test doesn't outlive its test and cause
+// strange races with other tests that touch global stuff (like histograms and
+// logging).  However, this requires that nothing else on this thread holds a
+// ref to the pool when the SequencedWorkerPoolOwner is destroyed.
+class SequencedWorkerPoolOwner : public SequencedWorkerPool::TestingObserver {
+ public:
+  SequencedWorkerPoolOwner(size_t max_threads,
+                           const std::string& thread_name_prefix);
+
+  ~SequencedWorkerPoolOwner() override;
+
+  // Don't change the returned pool's testing observer.
+  const scoped_refptr<SequencedWorkerPool>& pool();
+
+  // The given callback will be called on WillWaitForShutdown().
+  void SetWillWaitForShutdownCallback(const Closure& callback);
+
+  int has_work_call_count() const;
+
+ private:
+  // SequencedWorkerPool::TestingObserver implementation.
+  void OnHasWork() override;
+  void WillWaitForShutdown() override;
+  void OnDestruct() override;
+
+  MessageLoop* const constructor_message_loop_;
+  scoped_refptr<SequencedWorkerPool> pool_;
+  Closure will_wait_for_shutdown_callback_;
+
+  mutable Lock has_work_lock_;
+  int has_work_call_count_;
+
+  DISALLOW_COPY_AND_ASSIGN(SequencedWorkerPoolOwner);
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_SEQUENCED_WORKER_POOL_OWNER_H_
diff --git a/base/test/simple_test_clock.cc b/base/test/simple_test_clock.cc
new file mode 100644
index 0000000..a2bdc2a
--- /dev/null
+++ b/base/test/simple_test_clock.cc
@@ -0,0 +1,28 @@
+// Copyright (c) 2012 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/test/simple_test_clock.h"
+
+namespace base {
+
+SimpleTestClock::SimpleTestClock() {}
+
+SimpleTestClock::~SimpleTestClock() {}
+
+Time SimpleTestClock::Now() {
+  AutoLock lock(lock_);
+  return now_;
+}
+
+void SimpleTestClock::Advance(TimeDelta delta) {
+  AutoLock lock(lock_);
+  now_ += delta;
+}
+
+void SimpleTestClock::SetNow(Time now) {
+  AutoLock lock(lock_);
+  now_ = now;
+}
+
+}  // namespace base
diff --git a/base/test/simple_test_clock.h b/base/test/simple_test_clock.h
new file mode 100644
index 0000000..a70f99c
--- /dev/null
+++ b/base/test/simple_test_clock.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2012 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_TEST_SIMPLE_TEST_CLOCK_H_
+#define BASE_TEST_SIMPLE_TEST_CLOCK_H_
+
+#include "base/compiler_specific.h"
+#include "base/synchronization/lock.h"
+#include "base/time/clock.h"
+#include "base/time/time.h"
+
+namespace base {
+
+// SimpleTestClock is a Clock implementation that gives control over
+// the returned Time objects.  All methods may be called from any
+// thread.
+class SimpleTestClock : public Clock {
+ public:
+  // Starts off with a clock set to Time().
+  SimpleTestClock();
+  ~SimpleTestClock() override;
+
+  Time Now() override;
+
+  // Advances the clock by |delta|.
+  void Advance(TimeDelta delta);
+
+  // Sets the clock to the given time.
+  void SetNow(Time now);
+
+ private:
+  // Protects |now_|.
+  Lock lock_;
+
+  Time now_;
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_SIMPLE_TEST_CLOCK_H_
diff --git a/base/test/simple_test_tick_clock.cc b/base/test/simple_test_tick_clock.cc
new file mode 100644
index 0000000..1b4696f
--- /dev/null
+++ b/base/test/simple_test_tick_clock.cc
@@ -0,0 +1,26 @@
+// Copyright (c) 2012 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/test/simple_test_tick_clock.h"
+
+#include "base/logging.h"
+
+namespace base {
+
+SimpleTestTickClock::SimpleTestTickClock() {}
+
+SimpleTestTickClock::~SimpleTestTickClock() {}
+
+TimeTicks SimpleTestTickClock::NowTicks() {
+  AutoLock lock(lock_);
+  return now_ticks_;
+}
+
+void SimpleTestTickClock::Advance(TimeDelta delta) {
+  AutoLock lock(lock_);
+  DCHECK(delta >= TimeDelta());
+  now_ticks_ += delta;
+}
+
+}  // namespace base
diff --git a/base/test/simple_test_tick_clock.h b/base/test/simple_test_tick_clock.h
new file mode 100644
index 0000000..aebdebc
--- /dev/null
+++ b/base/test/simple_test_tick_clock.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2012 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_TEST_SIMPLE_TEST_TICK_CLOCK_H_
+#define BASE_TEST_SIMPLE_TEST_TICK_CLOCK_H_
+
+#include "base/compiler_specific.h"
+#include "base/synchronization/lock.h"
+#include "base/time/tick_clock.h"
+#include "base/time/time.h"
+
+namespace base {
+
+// SimpleTestTickClock is a TickClock implementation that gives
+// control over the returned TimeTicks objects.  All methods may be
+// called from any thread.
+class SimpleTestTickClock : public TickClock {
+ public:
+  // Starts off with a clock set to TimeTicks().
+  SimpleTestTickClock();
+  ~SimpleTestTickClock() override;
+
+  TimeTicks NowTicks() override;
+
+  // Advances the clock by |delta|, which must not be negative.
+  void Advance(TimeDelta delta);
+
+ private:
+  // Protects |now_ticks_|.
+  Lock lock_;
+
+  TimeTicks now_ticks_;
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_SIMPLE_TEST_TICK_CLOCK_H_
diff --git a/base/test/task_runner_test_template.cc b/base/test/task_runner_test_template.cc
new file mode 100644
index 0000000..b756203
--- /dev/null
+++ b/base/test/task_runner_test_template.cc
@@ -0,0 +1,48 @@
+// Copyright (c) 2012 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/test/task_runner_test_template.h"
+
+namespace base {
+
+namespace internal {
+
+TaskTracker::TaskTracker() : task_runs_(0), task_runs_cv_(&lock_) {}
+
+TaskTracker::~TaskTracker() {}
+
+Closure TaskTracker::WrapTask(const Closure& task, int i) {
+  return Bind(&TaskTracker::RunTask, this, task, i);
+}
+
+void TaskTracker::RunTask(const Closure& task, int i) {
+  AutoLock lock(lock_);
+  if (!task.is_null()) {
+    task.Run();
+  }
+  ++task_run_counts_[i];
+  ++task_runs_;
+  task_runs_cv_.Signal();
+}
+
+std::map<int, int> TaskTracker::GetTaskRunCounts() const {
+  AutoLock lock(lock_);
+  return task_run_counts_;
+}
+
+void TaskTracker::WaitForCompletedTasks(int count) {
+  AutoLock lock(lock_);
+  while (task_runs_ < count)
+    task_runs_cv_.Wait();
+}
+
+void ExpectRunsTasksOnCurrentThread(
+    bool expected_value,
+    const scoped_refptr<TaskRunner>& task_runner) {
+  EXPECT_EQ(expected_value, task_runner->RunsTasksOnCurrentThread());
+}
+
+}  // namespace internal
+
+}  // namespace base
diff --git a/base/test/task_runner_test_template.h b/base/test/task_runner_test_template.h
new file mode 100644
index 0000000..ee2b876
--- /dev/null
+++ b/base/test/task_runner_test_template.h
@@ -0,0 +1,217 @@
+// Copyright (c) 2012 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 class defines tests that implementations of TaskRunner should
+// pass in order to be conformant.  Here's how you use it to test your
+// implementation.
+//
+// Say your class is called MyTaskRunner.  Then you need to define a
+// class called MyTaskRunnerTestDelegate in my_task_runner_unittest.cc
+// like this:
+//
+//   class MyTaskRunnerTestDelegate {
+//    public:
+//     // Tasks posted to the task runner after this and before
+//     // StopTaskRunner() is called is called should run successfully.
+//     void StartTaskRunner() {
+//       ...
+//     }
+//
+//     // Should return the task runner implementation.  Only called
+//     // after StartTaskRunner and before StopTaskRunner.
+//     scoped_refptr<MyTaskRunner> GetTaskRunner() {
+//       ...
+//     }
+//
+//     // Stop the task runner and make sure all tasks posted before
+//     // this is called are run. Caveat: delayed tasks are not run,
+       // they're simply deleted.
+//     void StopTaskRunner() {
+//       ...
+//     }
+//   };
+//
+// The TaskRunnerTest test harness will have a member variable of
+// this delegate type and will call its functions in the various
+// tests.
+//
+// Then you simply #include this file as well as gtest.h and add the
+// following statement to my_task_runner_unittest.cc:
+//
+//   INSTANTIATE_TYPED_TEST_CASE_P(
+//       MyTaskRunner, TaskRunnerTest, MyTaskRunnerTestDelegate);
+//
+// Easy!
+
+#ifndef BASE_TEST_TASK_RUNNER_TEST_TEMPLATE_H_
+#define BASE_TEST_TASK_RUNNER_TEST_TEMPLATE_H_
+
+#include <cstddef>
+#include <map>
+
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/location.h"
+#include "base/memory/ref_counted.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
+#include "base/task_runner.h"
+#include "base/threading/thread.h"
+#include "base/tracked_objects.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace internal {
+
+// Utility class that keeps track of how many times particular tasks
+// are run.
+class TaskTracker : public RefCountedThreadSafe<TaskTracker> {
+ public:
+  TaskTracker();
+
+  // Returns a closure that runs the given task and increments the run
+  // count of |i| by one.  |task| may be null.  It is guaranteed that
+  // only one task wrapped by a given tracker will be run at a time.
+  Closure WrapTask(const Closure& task, int i);
+
+  std::map<int, int> GetTaskRunCounts() const;
+
+  // Returns after the tracker observes a total of |count| task completions.
+  void WaitForCompletedTasks(int count);
+
+ private:
+  friend class RefCountedThreadSafe<TaskTracker>;
+
+  ~TaskTracker();
+
+  void RunTask(const Closure& task, int i);
+
+  mutable Lock lock_;
+  std::map<int, int> task_run_counts_;
+  int task_runs_;
+  ConditionVariable task_runs_cv_;
+
+  DISALLOW_COPY_AND_ASSIGN(TaskTracker);
+};
+
+}  // namespace internal
+
+template <typename TaskRunnerTestDelegate>
+class TaskRunnerTest : public testing::Test {
+ protected:
+  TaskRunnerTest() : task_tracker_(new internal::TaskTracker()) {}
+
+  const scoped_refptr<internal::TaskTracker> task_tracker_;
+  TaskRunnerTestDelegate delegate_;
+};
+
+TYPED_TEST_CASE_P(TaskRunnerTest);
+
+// We can't really test much, since TaskRunner provides very few
+// guarantees.
+
+// Post a bunch of tasks to the task runner.  They should all
+// complete.
+TYPED_TEST_P(TaskRunnerTest, Basic) {
+  std::map<int, int> expected_task_run_counts;
+
+  this->delegate_.StartTaskRunner();
+  scoped_refptr<TaskRunner> task_runner = this->delegate_.GetTaskRunner();
+  // Post each ith task i+1 times.
+  for (int i = 0; i < 20; ++i) {
+    const Closure& ith_task = this->task_tracker_->WrapTask(Closure(), i);
+    for (int j = 0; j < i + 1; ++j) {
+      task_runner->PostTask(FROM_HERE, ith_task);
+      ++expected_task_run_counts[i];
+    }
+  }
+  this->delegate_.StopTaskRunner();
+
+  EXPECT_EQ(expected_task_run_counts,
+            this->task_tracker_->GetTaskRunCounts());
+}
+
+// Post a bunch of delayed tasks to the task runner.  They should all
+// complete.
+TYPED_TEST_P(TaskRunnerTest, Delayed) {
+  std::map<int, int> expected_task_run_counts;
+  int expected_total_tasks = 0;
+
+  this->delegate_.StartTaskRunner();
+  scoped_refptr<TaskRunner> task_runner = this->delegate_.GetTaskRunner();
+  // Post each ith task i+1 times with delays from 0-i.
+  for (int i = 0; i < 20; ++i) {
+    const Closure& ith_task = this->task_tracker_->WrapTask(Closure(), i);
+    for (int j = 0; j < i + 1; ++j) {
+      task_runner->PostDelayedTask(
+          FROM_HERE, ith_task, base::TimeDelta::FromMilliseconds(j));
+      ++expected_task_run_counts[i];
+      ++expected_total_tasks;
+    }
+  }
+  this->task_tracker_->WaitForCompletedTasks(expected_total_tasks);
+  this->delegate_.StopTaskRunner();
+
+  EXPECT_EQ(expected_task_run_counts,
+            this->task_tracker_->GetTaskRunCounts());
+}
+
+namespace internal {
+
+// Calls RunsTasksOnCurrentThread() on |task_runner| and expects it to
+// equal |expected_value|.
+void ExpectRunsTasksOnCurrentThread(
+    bool expected_value,
+    const scoped_refptr<TaskRunner>& task_runner);
+
+}  // namespace internal
+
+// Post a bunch of tasks to the task runner as well as to a separate
+// thread, each checking the value of RunsTasksOnCurrentThread(),
+// which should return true for the tasks posted on the task runner
+// and false for the tasks posted on the separate thread.
+TYPED_TEST_P(TaskRunnerTest, RunsTasksOnCurrentThread) {
+  std::map<int, int> expected_task_run_counts;
+
+  Thread thread("Non-task-runner thread");
+  ASSERT_TRUE(thread.Start());
+  this->delegate_.StartTaskRunner();
+
+  scoped_refptr<TaskRunner> task_runner = this->delegate_.GetTaskRunner();
+  // Post each ith task i+1 times on the task runner and i+1 times on
+  // the non-task-runner thread.
+  for (int i = 0; i < 20; ++i) {
+    const Closure& ith_task_runner_task =
+        this->task_tracker_->WrapTask(
+            Bind(&internal::ExpectRunsTasksOnCurrentThread,
+                 true, task_runner),
+            i);
+    const Closure& ith_non_task_runner_task =
+        this->task_tracker_->WrapTask(
+            Bind(&internal::ExpectRunsTasksOnCurrentThread,
+                 false, task_runner),
+            i);
+    for (int j = 0; j < i + 1; ++j) {
+      task_runner->PostTask(FROM_HERE, ith_task_runner_task);
+      thread.task_runner()->PostTask(FROM_HERE, ith_non_task_runner_task);
+      expected_task_run_counts[i] += 2;
+    }
+  }
+
+  this->delegate_.StopTaskRunner();
+  thread.Stop();
+
+  EXPECT_EQ(expected_task_run_counts,
+            this->task_tracker_->GetTaskRunCounts());
+}
+
+REGISTER_TYPED_TEST_CASE_P(
+    TaskRunnerTest, Basic, Delayed, RunsTasksOnCurrentThread);
+
+}  // namespace base
+
+#endif  // BASE_TEST_TASK_RUNNER_TEST_TEMPLATE_H_
diff --git a/base/test/test_discardable_memory_allocator.cc b/base/test/test_discardable_memory_allocator.cc
new file mode 100644
index 0000000..23d529c
--- /dev/null
+++ b/base/test/test_discardable_memory_allocator.cc
@@ -0,0 +1,40 @@
+// 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/test/test_discardable_memory_allocator.h"
+
+#include <stdint.h>
+
+#include "base/memory/discardable_memory.h"
+
+namespace base {
+namespace {
+
+class DiscardableMemoryImpl : public DiscardableMemory {
+ public:
+  explicit DiscardableMemoryImpl(size_t size) : data_(new uint8_t[size]) {}
+
+  // Overridden from DiscardableMemory:
+  bool Lock() override { return false; }
+  void Unlock() override {}
+  void* data() const override { return data_.get(); }
+
+ private:
+  scoped_ptr<uint8_t[]> data_;
+};
+
+}  // namespace
+
+TestDiscardableMemoryAllocator::TestDiscardableMemoryAllocator() {
+}
+
+TestDiscardableMemoryAllocator::~TestDiscardableMemoryAllocator() {
+}
+
+scoped_ptr<DiscardableMemory>
+TestDiscardableMemoryAllocator::AllocateLockedDiscardableMemory(size_t size) {
+  return make_scoped_ptr(new DiscardableMemoryImpl(size));
+}
+
+}  // namespace base
diff --git a/base/test/test_discardable_memory_allocator.h b/base/test/test_discardable_memory_allocator.h
new file mode 100644
index 0000000..df9d469
--- /dev/null
+++ b/base/test/test_discardable_memory_allocator.h
@@ -0,0 +1,30 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_TEST_DISCARDABLE_MEMORY_ALLOCATOR_H_
+#define BASE_TEST_TEST_DISCARDABLE_MEMORY_ALLOCATOR_H_
+
+#include "base/memory/discardable_memory_allocator.h"
+
+namespace base {
+
+// TestDiscardableMemoryAllocator is a simple DiscardableMemoryAllocator
+// implementation that can be used for testing. It allocates one-shot
+// DiscardableMemory instances backed by heap memory.
+class TestDiscardableMemoryAllocator : public DiscardableMemoryAllocator {
+ public:
+  TestDiscardableMemoryAllocator();
+  ~TestDiscardableMemoryAllocator() override;
+
+  // Overridden from DiscardableMemoryAllocator:
+  scoped_ptr<DiscardableMemory> AllocateLockedDiscardableMemory(
+      size_t size) override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestDiscardableMemoryAllocator);
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_TEST_DISCARDABLE_MEMORY_ALLOCATOR_H_
diff --git a/base/test/test_file_util.cc b/base/test/test_file_util.cc
new file mode 100644
index 0000000..40b25f0
--- /dev/null
+++ b/base/test/test_file_util.cc
@@ -0,0 +1,28 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_file_util.h"
+
+#include "base/test/test_timeouts.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+bool EvictFileFromSystemCacheWithRetry(const FilePath& path) {
+  const int kCycles = 10;
+  const TimeDelta kDelay = TestTimeouts::action_timeout() / kCycles;
+  for (int i = 0; i < kCycles; i++) {
+    if (EvictFileFromSystemCache(path))
+      return true;
+    PlatformThread::Sleep(kDelay);
+  }
+  return false;
+}
+
+// Declared in base/files/file_path.h.
+void PrintTo(const FilePath& path, std::ostream* out) {
+  *out << path.value();
+}
+
+}  // namespace base
diff --git a/base/test/test_file_util.h b/base/test/test_file_util.h
new file mode 100644
index 0000000..27197f2
--- /dev/null
+++ b/base/test/test_file_util.h
@@ -0,0 +1,80 @@
+// Copyright (c) 2012 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_TEST_TEST_FILE_UTIL_H_
+#define BASE_TEST_TEST_FILE_UTIL_H_
+
+// File utility functions used only by tests.
+
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "base/files/file_path.h"
+
+#if defined(OS_ANDROID)
+#include <jni.h>
+#include "base/basictypes.h"
+#endif
+
+namespace base {
+
+class FilePath;
+
+// Clear a specific file from the system cache like EvictFileFromSystemCache,
+// but on failure it will sleep and retry. On the Windows buildbots, eviction
+// can fail if the file is marked in use, and this will throw off timings that
+// rely on uncached files.
+bool EvictFileFromSystemCacheWithRetry(const FilePath& file);
+
+// Wrapper over base::Delete. On Windows repeatedly invokes Delete in case
+// of failure to workaround Windows file locking semantics. Returns true on
+// success.
+bool DieFileDie(const FilePath& file, bool recurse);
+
+// Clear a specific file from the system cache. After this call, trying
+// to access this file will result in a cold load from the hard drive.
+bool EvictFileFromSystemCache(const FilePath& file);
+
+#if defined(OS_WIN)
+// Returns true if the volume supports Alternate Data Streams.
+bool VolumeSupportsADS(const FilePath& path);
+
+// Returns true if the ZoneIdentifier is correctly set to "Internet" (3).
+// Note that this function must be called from the same process as
+// the one that set the zone identifier.  I.e. don't use it in UI/automation
+// based tests.
+bool HasInternetZoneIdentifier(const FilePath& full_path);
+#endif  // defined(OS_WIN)
+
+// For testing, make the file unreadable or unwritable.
+// In POSIX, this does not apply to the root user.
+bool MakeFileUnreadable(const FilePath& path) WARN_UNUSED_RESULT;
+bool MakeFileUnwritable(const FilePath& path) WARN_UNUSED_RESULT;
+
+// Saves the current permissions for a path, and restores it on destruction.
+class FilePermissionRestorer {
+ public:
+  explicit FilePermissionRestorer(const FilePath& path);
+  ~FilePermissionRestorer();
+
+ private:
+  const FilePath path_;
+  void* info_;  // The opaque stored permission information.
+  size_t length_;  // The length of the stored permission information.
+
+  DISALLOW_COPY_AND_ASSIGN(FilePermissionRestorer);
+};
+
+#if defined(OS_ANDROID)
+// Register the ContentUriTestUrils JNI bindings.
+bool RegisterContentUriTestUtils(JNIEnv* env);
+
+// Insert an image file into the MediaStore, and retrieve the content URI for
+// testing purpose.
+FilePath InsertImageIntoMediaStore(const FilePath& path);
+#endif  // defined(OS_ANDROID)
+
+}  // namespace base
+
+#endif  // BASE_TEST_TEST_FILE_UTIL_H_
diff --git a/base/test/test_file_util_android.cc b/base/test/test_file_util_android.cc
new file mode 100644
index 0000000..b8fd50c
--- /dev/null
+++ b/base/test/test_file_util_android.cc
@@ -0,0 +1,29 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_file_util.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/files/file_path.h"
+#include "jni/ContentUriTestUtils_jni.h"
+
+namespace base {
+
+bool RegisterContentUriTestUtils(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+FilePath InsertImageIntoMediaStore(const FilePath& path) {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  ScopedJavaLocalRef<jstring> j_path =
+      base::android::ConvertUTF8ToJavaString(env, path.value());
+  ScopedJavaLocalRef<jstring> j_uri =
+      Java_ContentUriTestUtils_insertImageIntoMediaStore(
+          env, base::android::GetApplicationContext(), j_path.obj());
+  std::string uri = base::android::ConvertJavaStringToUTF8(j_uri);
+  return FilePath(uri);
+}
+
+}  // namespace base
diff --git a/base/test/test_file_util_linux.cc b/base/test/test_file_util_linux.cc
new file mode 100644
index 0000000..0ef5c0a
--- /dev/null
+++ b/base/test/test_file_util_linux.cc
@@ -0,0 +1,28 @@
+// Copyright (c) 2011 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/test/test_file_util.h"
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "base/files/file_path.h"
+#include "base/files/scoped_file.h"
+
+namespace base {
+
+bool EvictFileFromSystemCache(const FilePath& file) {
+  ScopedFD fd(open(file.value().c_str(), O_RDONLY));
+  if (!fd.is_valid())
+    return false;
+  if (fdatasync(fd.get()) != 0)
+    return false;
+  if (posix_fadvise(fd.get(), 0, 0, POSIX_FADV_DONTNEED) != 0)
+    return false;
+  return true;
+}
+
+}  // namespace base
diff --git a/base/test/test_file_util_mac.cc b/base/test/test_file_util_mac.cc
new file mode 100644
index 0000000..11592c3
--- /dev/null
+++ b/base/test/test_file_util_mac.cc
@@ -0,0 +1,51 @@
+// Copyright (c) 2011 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/test/test_file_util.h"
+
+#include <sys/mman.h>
+#include <errno.h>
+
+#include "base/files/file_util.h"
+#include "base/files/memory_mapped_file.h"
+#include "base/logging.h"
+
+namespace base {
+
+bool EvictFileFromSystemCache(const FilePath& file) {
+  // There aren't any really direct ways to purge a file from the UBC.  From
+  // talking with Amit Singh, the safest is to mmap the file with MAP_FILE (the
+  // default) + MAP_SHARED, then do an msync to invalidate the memory.  The next
+  // open should then have to load the file from disk.
+
+  int64 length;
+  if (!GetFileSize(file, &length)) {
+    DLOG(ERROR) << "failed to get size of " << file.value();
+    return false;
+  }
+
+  // When a file is empty, we do not need to evict it from cache.
+  // In fact, an attempt to map it to memory will result in error.
+  if (length == 0) {
+    DLOG(WARNING) << "file size is zero, will not attempt to map to memory";
+    return true;
+  }
+
+  MemoryMappedFile mapped_file;
+  if (!mapped_file.Initialize(file)) {
+    DLOG(WARNING) << "failed to memory map " << file.value();
+    return false;
+  }
+
+  if (msync(const_cast<uint8*>(mapped_file.data()), mapped_file.length(),
+            MS_INVALIDATE) != 0) {
+    DLOG(WARNING) << "failed to invalidate memory map of " << file.value()
+                  << ", errno: " << errno;
+    return false;
+  }
+
+  return true;
+}
+
+}  // namespace base
diff --git a/base/test/test_file_util_posix.cc b/base/test/test_file_util_posix.cc
new file mode 100644
index 0000000..12b892c
--- /dev/null
+++ b/base/test/test_file_util_posix.cc
@@ -0,0 +1,108 @@
+// Copyright (c) 2012 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/test/test_file_util.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <string>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+
+namespace base {
+
+namespace {
+
+// Deny |permission| on the file |path|.
+bool DenyFilePermission(const FilePath& path, mode_t permission) {
+  struct stat stat_buf;
+  if (stat(path.value().c_str(), &stat_buf) != 0)
+    return false;
+  stat_buf.st_mode &= ~permission;
+
+  int rv = HANDLE_EINTR(chmod(path.value().c_str(), stat_buf.st_mode));
+  return rv == 0;
+}
+
+// Gets a blob indicating the permission information for |path|.
+// |length| is the length of the blob.  Zero on failure.
+// Returns the blob pointer, or NULL on failure.
+void* GetPermissionInfo(const FilePath& path, size_t* length) {
+  DCHECK(length);
+  *length = 0;
+
+  struct stat stat_buf;
+  if (stat(path.value().c_str(), &stat_buf) != 0)
+    return NULL;
+
+  *length = sizeof(mode_t);
+  mode_t* mode = new mode_t;
+  *mode = stat_buf.st_mode & ~S_IFMT;  // Filter out file/path kind.
+
+  return mode;
+}
+
+// Restores the permission information for |path|, given the blob retrieved
+// using |GetPermissionInfo()|.
+// |info| is the pointer to the blob.
+// |length| is the length of the blob.
+// Either |info| or |length| may be NULL/0, in which case nothing happens.
+bool RestorePermissionInfo(const FilePath& path, void* info, size_t length) {
+  if (!info || (length == 0))
+    return false;
+
+  DCHECK_EQ(sizeof(mode_t), length);
+  mode_t* mode = reinterpret_cast<mode_t*>(info);
+
+  int rv = HANDLE_EINTR(chmod(path.value().c_str(), *mode));
+
+  delete mode;
+
+  return rv == 0;
+}
+
+}  // namespace
+
+bool DieFileDie(const FilePath& file, bool recurse) {
+  // There is no need to workaround Windows problems on POSIX.
+  // Just pass-through.
+  return DeleteFile(file, recurse);
+}
+
+#if !defined(OS_LINUX) && !defined(OS_MACOSX)
+bool EvictFileFromSystemCache(const FilePath& file) {
+  // There doesn't seem to be a POSIX way to cool the disk cache.
+  NOTIMPLEMENTED();
+  return false;
+}
+#endif
+
+bool MakeFileUnreadable(const FilePath& path) {
+  return DenyFilePermission(path, S_IRUSR | S_IRGRP | S_IROTH);
+}
+
+bool MakeFileUnwritable(const FilePath& path) {
+  return DenyFilePermission(path, S_IWUSR | S_IWGRP | S_IWOTH);
+}
+
+FilePermissionRestorer::FilePermissionRestorer(const FilePath& path)
+    : path_(path), info_(NULL), length_(0) {
+  info_ = GetPermissionInfo(path_, &length_);
+  DCHECK(info_ != NULL);
+  DCHECK_NE(0u, length_);
+}
+
+FilePermissionRestorer::~FilePermissionRestorer() {
+  if (!RestorePermissionInfo(path_, info_, length_))
+    NOTREACHED();
+}
+
+}  // namespace base
diff --git a/base/test/test_file_util_win.cc b/base/test/test_file_util_win.cc
new file mode 100644
index 0000000..5496a55
--- /dev/null
+++ b/base/test/test_file_util_win.cc
@@ -0,0 +1,282 @@
+// Copyright (c) 2012 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/test/test_file_util.h"
+
+#include <windows.h>
+#include <aclapi.h>
+#include <shlwapi.h>
+
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/strings/string_split.h"
+#include "base/threading/platform_thread.h"
+#include "base/win/scoped_handle.h"
+
+namespace base {
+
+static const ptrdiff_t kOneMB = 1024 * 1024;
+
+namespace {
+
+struct PermissionInfo {
+  PSECURITY_DESCRIPTOR security_descriptor;
+  ACL dacl;
+};
+
+// Deny |permission| on the file |path|, for the current user.
+bool DenyFilePermission(const FilePath& path, DWORD permission) {
+  PACL old_dacl;
+  PSECURITY_DESCRIPTOR security_descriptor;
+  if (GetNamedSecurityInfo(const_cast<wchar_t*>(path.value().c_str()),
+                           SE_FILE_OBJECT,
+                           DACL_SECURITY_INFORMATION, NULL, NULL, &old_dacl,
+                           NULL, &security_descriptor) != ERROR_SUCCESS) {
+    return false;
+  }
+
+  EXPLICIT_ACCESS change;
+  change.grfAccessPermissions = permission;
+  change.grfAccessMode = DENY_ACCESS;
+  change.grfInheritance = 0;
+  change.Trustee.pMultipleTrustee = NULL;
+  change.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
+  change.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
+  change.Trustee.TrusteeType = TRUSTEE_IS_USER;
+  change.Trustee.ptstrName = const_cast<wchar_t*>(L"CURRENT_USER");
+
+  PACL new_dacl;
+  if (SetEntriesInAcl(1, &change, old_dacl, &new_dacl) != ERROR_SUCCESS) {
+    LocalFree(security_descriptor);
+    return false;
+  }
+
+  DWORD rc = SetNamedSecurityInfo(const_cast<wchar_t*>(path.value().c_str()),
+                                  SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
+                                  NULL, NULL, new_dacl, NULL);
+  LocalFree(security_descriptor);
+  LocalFree(new_dacl);
+
+  return rc == ERROR_SUCCESS;
+}
+
+// Gets a blob indicating the permission information for |path|.
+// |length| is the length of the blob.  Zero on failure.
+// Returns the blob pointer, or NULL on failure.
+void* GetPermissionInfo(const FilePath& path, size_t* length) {
+  DCHECK(length != NULL);
+  *length = 0;
+  PACL dacl = NULL;
+  PSECURITY_DESCRIPTOR security_descriptor;
+  if (GetNamedSecurityInfo(const_cast<wchar_t*>(path.value().c_str()),
+                           SE_FILE_OBJECT,
+                           DACL_SECURITY_INFORMATION, NULL, NULL, &dacl,
+                           NULL, &security_descriptor) != ERROR_SUCCESS) {
+    return NULL;
+  }
+  DCHECK(dacl != NULL);
+
+  *length = sizeof(PSECURITY_DESCRIPTOR) + dacl->AclSize;
+  PermissionInfo* info = reinterpret_cast<PermissionInfo*>(new char[*length]);
+  info->security_descriptor = security_descriptor;
+  memcpy(&info->dacl, dacl, dacl->AclSize);
+
+  return info;
+}
+
+// Restores the permission information for |path|, given the blob retrieved
+// using |GetPermissionInfo()|.
+// |info| is the pointer to the blob.
+// |length| is the length of the blob.
+// Either |info| or |length| may be NULL/0, in which case nothing happens.
+bool RestorePermissionInfo(const FilePath& path, void* info, size_t length) {
+  if (!info || !length)
+    return false;
+
+  PermissionInfo* perm = reinterpret_cast<PermissionInfo*>(info);
+
+  DWORD rc = SetNamedSecurityInfo(const_cast<wchar_t*>(path.value().c_str()),
+                                  SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
+                                  NULL, NULL, &perm->dacl, NULL);
+  LocalFree(perm->security_descriptor);
+
+  char* char_array = reinterpret_cast<char*>(info);
+  delete [] char_array;
+
+  return rc == ERROR_SUCCESS;
+}
+
+}  // namespace
+
+bool DieFileDie(const FilePath& file, bool recurse) {
+  // It turns out that to not induce flakiness a long timeout is needed.
+  const int kIterations = 25;
+  const TimeDelta kTimeout = TimeDelta::FromSeconds(10) / kIterations;
+
+  if (!PathExists(file))
+    return true;
+
+  // Sometimes Delete fails, so try a few more times. Divide the timeout
+  // into short chunks, so that if a try succeeds, we won't delay the test
+  // for too long.
+  for (int i = 0; i < kIterations; ++i) {
+    if (DeleteFile(file, recurse))
+      return true;
+    PlatformThread::Sleep(kTimeout);
+  }
+  return false;
+}
+
+bool EvictFileFromSystemCache(const FilePath& file) {
+  // Request exclusive access to the file and overwrite it with no buffering.
+  base::win::ScopedHandle file_handle(
+      CreateFile(file.value().c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL,
+                 OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, NULL));
+  if (!file_handle.IsValid())
+    return false;
+
+  // Get some attributes to restore later.
+  BY_HANDLE_FILE_INFORMATION bhi = {0};
+  CHECK(::GetFileInformationByHandle(file_handle.Get(), &bhi));
+
+  // Execute in chunks. It could be optimized. We want to do few of these since
+  // these operations will be slow without the cache.
+
+  // Allocate a buffer for the reads and the writes.
+  char* buffer = reinterpret_cast<char*>(VirtualAlloc(NULL,
+                                                      kOneMB,
+                                                      MEM_COMMIT | MEM_RESERVE,
+                                                      PAGE_READWRITE));
+
+  // If the file size isn't a multiple of kOneMB, we'll need special
+  // processing.
+  bool file_is_aligned = true;
+  int total_bytes = 0;
+  DWORD bytes_read, bytes_written;
+  for (;;) {
+    bytes_read = 0;
+    ::ReadFile(file_handle.Get(), buffer, kOneMB, &bytes_read, NULL);
+    if (bytes_read == 0)
+      break;
+
+    if (bytes_read < kOneMB) {
+      // Zero out the remaining part of the buffer.
+      // WriteFile will fail if we provide a buffer size that isn't a
+      // sector multiple, so we'll have to write the entire buffer with
+      // padded zeros and then use SetEndOfFile to truncate the file.
+      ZeroMemory(buffer + bytes_read, kOneMB - bytes_read);
+      file_is_aligned = false;
+    }
+
+    // Move back to the position we just read from.
+    // Note that SetFilePointer will also fail if total_bytes isn't sector
+    // aligned, but that shouldn't happen here.
+    DCHECK_EQ(total_bytes % kOneMB, 0);
+    SetFilePointer(file_handle.Get(), total_bytes, NULL, FILE_BEGIN);
+    if (!::WriteFile(file_handle.Get(), buffer, kOneMB, &bytes_written, NULL) ||
+        bytes_written != kOneMB) {
+      BOOL freed = VirtualFree(buffer, 0, MEM_RELEASE);
+      DCHECK(freed);
+      NOTREACHED();
+      return false;
+    }
+
+    total_bytes += bytes_read;
+
+    // If this is false, then we just processed the last portion of the file.
+    if (!file_is_aligned)
+      break;
+  }
+
+  BOOL freed = VirtualFree(buffer, 0, MEM_RELEASE);
+  DCHECK(freed);
+
+  if (!file_is_aligned) {
+    // The size of the file isn't a multiple of 1 MB, so we'll have
+    // to open the file again, this time without the FILE_FLAG_NO_BUFFERING
+    // flag and use SetEndOfFile to mark EOF.
+    file_handle.Set(NULL);
+    file_handle.Set(CreateFile(file.value().c_str(), GENERIC_WRITE, 0, NULL,
+                               OPEN_EXISTING, 0, NULL));
+    CHECK_NE(SetFilePointer(file_handle.Get(), total_bytes, NULL, FILE_BEGIN),
+             INVALID_SET_FILE_POINTER);
+    CHECK(::SetEndOfFile(file_handle.Get()));
+  }
+
+  // Restore the file attributes.
+  CHECK(::SetFileTime(file_handle.Get(), &bhi.ftCreationTime,
+                      &bhi.ftLastAccessTime, &bhi.ftLastWriteTime));
+
+  return true;
+}
+
+// Checks if the volume supports Alternate Data Streams. This is required for
+// the Zone Identifier implementation.
+bool VolumeSupportsADS(const FilePath& path) {
+  wchar_t drive[MAX_PATH] = {0};
+  wcscpy_s(drive, MAX_PATH, path.value().c_str());
+
+  if (!PathStripToRootW(drive))
+    return false;
+
+  DWORD fs_flags = 0;
+  if (!GetVolumeInformationW(drive, NULL, 0, 0, NULL, &fs_flags, NULL, 0))
+    return false;
+
+  if (fs_flags & FILE_NAMED_STREAMS)
+    return true;
+
+  return false;
+}
+
+// Return whether the ZoneIdentifier is correctly set to "Internet" (3)
+// Only returns a valid result when called from same process as the
+// one that (was supposed to have) set the zone identifier.
+bool HasInternetZoneIdentifier(const FilePath& full_path) {
+  FilePath zone_path(full_path.value() + L":Zone.Identifier");
+  std::string zone_path_contents;
+  if (!ReadFileToString(zone_path, &zone_path_contents))
+    return false;
+
+  std::vector<std::string> lines;
+  // This call also trims whitespaces, including carriage-returns (\r).
+  SplitString(zone_path_contents, '\n', &lines);
+
+  switch (lines.size()) {
+    case 3:
+      // optional empty line at end of file:
+      if (!lines[2].empty())
+        return false;
+      // fall through:
+    case 2:
+      return lines[0] == "[ZoneTransfer]" && lines[1] == "ZoneId=3";
+    default:
+      return false;
+  }
+}
+
+bool MakeFileUnreadable(const FilePath& path) {
+  return DenyFilePermission(path, GENERIC_READ);
+}
+
+bool MakeFileUnwritable(const FilePath& path) {
+  return DenyFilePermission(path, GENERIC_WRITE);
+}
+
+FilePermissionRestorer::FilePermissionRestorer(const FilePath& path)
+    : path_(path), info_(NULL), length_(0) {
+  info_ = GetPermissionInfo(path_, &length_);
+  DCHECK(info_ != NULL);
+  DCHECK_NE(0u, length_);
+}
+
+FilePermissionRestorer::~FilePermissionRestorer() {
+  if (!RestorePermissionInfo(path_, info_, length_))
+    NOTREACHED();
+}
+
+}  // namespace base
diff --git a/base/test/test_io_thread.cc b/base/test/test_io_thread.cc
new file mode 100644
index 0000000..48c1e16
--- /dev/null
+++ b/base/test/test_io_thread.cc
@@ -0,0 +1,65 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_io_thread.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/synchronization/waitable_event.h"
+
+namespace {
+
+void PostTaskAndWaitHelper(base::WaitableEvent* event,
+                           const base::Closure& task) {
+  task.Run();
+  event->Signal();
+}
+
+}  // namespace
+
+namespace base {
+
+TestIOThread::TestIOThread(Mode mode)
+    : io_thread_("test_io_thread"), io_thread_started_(false) {
+  switch (mode) {
+    case kAutoStart:
+      Start();
+      return;
+    case kManualStart:
+      return;
+  }
+  CHECK(false) << "Invalid mode";
+}
+
+TestIOThread::~TestIOThread() {
+  Stop();
+}
+
+void TestIOThread::Start() {
+  CHECK(!io_thread_started_);
+  io_thread_started_ = true;
+  CHECK(io_thread_.StartWithOptions(
+      base::Thread::Options(base::MessageLoop::TYPE_IO, 0)));
+}
+
+void TestIOThread::Stop() {
+  // Note: It's okay to call |Stop()| even if the thread isn't running.
+  io_thread_.Stop();
+  io_thread_started_ = false;
+}
+
+void TestIOThread::PostTask(const tracked_objects::Location& from_here,
+                            const base::Closure& task) {
+  task_runner()->PostTask(from_here, task);
+}
+
+void TestIOThread::PostTaskAndWait(const tracked_objects::Location& from_here,
+                                   const base::Closure& task) {
+  base::WaitableEvent event(false, false);
+  task_runner()->PostTask(from_here,
+                          base::Bind(&PostTaskAndWaitHelper, &event, task));
+  event.Wait();
+}
+
+}  // namespace base
diff --git a/base/test/test_io_thread.h b/base/test/test_io_thread.h
new file mode 100644
index 0000000..c2ed187
--- /dev/null
+++ b/base/test/test_io_thread.h
@@ -0,0 +1,59 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_TEST_IO_THREAD_H_
+#define BASE_TEST_TEST_IO_THREAD_H_
+
+#include "base/callback_forward.h"
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/task_runner.h"
+#include "base/threading/thread.h"
+#include "base/time/time.h"
+
+namespace base {
+
+// Create and run an IO thread with a MessageLoop, and
+// making the MessageLoop accessible from its client.
+// It also provides some ideomatic API like PostTaskAndWait().
+class TestIOThread {
+ public:
+  enum Mode { kAutoStart, kManualStart };
+  explicit TestIOThread(Mode mode);
+  // Stops the I/O thread if necessary.
+  ~TestIOThread();
+
+  // |Start()|/|Stop()| should only be called from the main (creation) thread.
+  // After |Stop()|, |Start()| may be called again to start a new I/O thread.
+  // |Stop()| may be called even when the I/O thread is not started.
+  void Start();
+  void Stop();
+
+  // Post |task| to the IO thread.
+  void PostTask(const tracked_objects::Location& from_here,
+                const base::Closure& task);
+  // Posts |task| to the IO-thread with an WaitableEvent associated blocks on
+  // it until the posted |task| is executed, then returns.
+  void PostTaskAndWait(const tracked_objects::Location& from_here,
+                       const base::Closure& task);
+
+  base::MessageLoopForIO* message_loop() {
+    return static_cast<base::MessageLoopForIO*>(io_thread_.message_loop());
+  }
+
+  scoped_refptr<SingleThreadTaskRunner> task_runner() {
+    return message_loop()->task_runner();
+  }
+
+ private:
+  base::Thread io_thread_;
+  bool io_thread_started_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestIOThread);
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_TEST_IO_THREAD_H_
diff --git a/base/test/test_listener_ios.h b/base/test/test_listener_ios.h
new file mode 100644
index 0000000..c312250
--- /dev/null
+++ b/base/test/test_listener_ios.h
@@ -0,0 +1,17 @@
+// Copyright (c) 2012 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_TEST_TEST_LISTENER_IOS_H_
+#define BASE_TEST_TEST_LISTENER_IOS_H_
+
+namespace base {
+namespace test_listener_ios {
+
+// Register an IOSRunLoopListener.
+void RegisterTestEndListener();
+
+}  // namespace test_listener_ios
+}  // namespace base
+
+#endif  // BASE_TEST_TEST_LISTENER_IOS_H_
diff --git a/base/test/test_listener_ios.mm b/base/test/test_listener_ios.mm
new file mode 100644
index 0000000..12cf5bb
--- /dev/null
+++ b/base/test/test_listener_ios.mm
@@ -0,0 +1,45 @@
+// Copyright (c) 2012 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/test/test_listener_ios.h"
+
+#import <Foundation/Foundation.h>
+
+#include "base/mac/scoped_nsautorelease_pool.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// The iOS watchdog timer will kill an app that doesn't spin the main event
+// loop often enough. This uses a Gtest TestEventListener to spin the current
+// loop after each test finishes. However, if any individual test takes too
+// long, it is still possible that the app will get killed.
+
+namespace {
+
+class IOSRunLoopListener : public testing::EmptyTestEventListener {
+ public:
+  virtual void OnTestEnd(const testing::TestInfo& test_info);
+};
+
+void IOSRunLoopListener::OnTestEnd(const testing::TestInfo& test_info) {
+  base::mac::ScopedNSAutoreleasePool scoped_pool;
+
+  // At the end of the test, spin the default loop for a moment.
+  NSDate* stop_date = [NSDate dateWithTimeIntervalSinceNow:0.001];
+  [[NSRunLoop currentRunLoop] runUntilDate:stop_date];
+}
+
+}  // namespace
+
+
+namespace base {
+namespace test_listener_ios {
+
+void RegisterTestEndListener() {
+  testing::TestEventListeners& listeners =
+      testing::UnitTest::GetInstance()->listeners();
+  listeners.Append(new IOSRunLoopListener);
+}
+
+}  // namespace test_listener_ios
+}  // namespace base
diff --git a/base/test/test_mock_time_task_runner.cc b/base/test/test_mock_time_task_runner.cc
new file mode 100644
index 0000000..f2e18a3
--- /dev/null
+++ b/base/test/test_mock_time_task_runner.cc
@@ -0,0 +1,263 @@
+// 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/test/test_mock_time_task_runner.h"
+
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/time/clock.h"
+#include "base/time/tick_clock.h"
+
+namespace base {
+
+namespace {
+
+// MockTickClock --------------------------------------------------------------
+
+// TickClock that always returns the then-current mock time ticks of
+// |task_runner| as the current time ticks.
+class MockTickClock : public TickClock {
+ public:
+  explicit MockTickClock(
+      scoped_refptr<const TestMockTimeTaskRunner> task_runner);
+
+  // TickClock:
+  TimeTicks NowTicks() override;
+
+ private:
+  scoped_refptr<const TestMockTimeTaskRunner> task_runner_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockTickClock);
+};
+
+MockTickClock::MockTickClock(
+    scoped_refptr<const TestMockTimeTaskRunner> task_runner)
+    : task_runner_(task_runner) {
+}
+
+TimeTicks MockTickClock::NowTicks() {
+  return task_runner_->NowTicks();
+}
+
+// MockClock ------------------------------------------------------------------
+
+// Clock that always returns the then-current mock time of |task_runner| as the
+// current time.
+class MockClock : public Clock {
+ public:
+  explicit MockClock(scoped_refptr<const TestMockTimeTaskRunner> task_runner);
+
+  // Clock:
+  Time Now() override;
+
+ private:
+  scoped_refptr<const TestMockTimeTaskRunner> task_runner_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockClock);
+};
+
+MockClock::MockClock(scoped_refptr<const TestMockTimeTaskRunner> task_runner)
+    : task_runner_(task_runner) {
+}
+
+Time MockClock::Now() {
+  return task_runner_->Now();
+}
+
+}  // namespace
+
+// TestMockTimeTaskRunner::TestOrderedPendingTask -----------------------------
+
+// Subclass of TestPendingTask which has a strictly monotonically increasing ID
+// for every task, so that tasks posted with the same 'time to run' can be run
+// in the order of being posted.
+struct TestMockTimeTaskRunner::TestOrderedPendingTask
+    : public base::TestPendingTask {
+  TestOrderedPendingTask();
+  TestOrderedPendingTask(const tracked_objects::Location& location,
+                         const Closure& task,
+                         TimeTicks post_time,
+                         TimeDelta delay,
+                         size_t ordinal,
+                         TestNestability nestability);
+  ~TestOrderedPendingTask();
+
+  size_t ordinal;
+};
+
+TestMockTimeTaskRunner::TestOrderedPendingTask::TestOrderedPendingTask()
+    : ordinal(0) {
+}
+
+TestMockTimeTaskRunner::TestOrderedPendingTask::TestOrderedPendingTask(
+    const tracked_objects::Location& location,
+    const Closure& task,
+    TimeTicks post_time,
+    TimeDelta delay,
+    size_t ordinal,
+    TestNestability nestability)
+    : base::TestPendingTask(location, task, post_time, delay, nestability),
+      ordinal(ordinal) {
+}
+
+TestMockTimeTaskRunner::TestOrderedPendingTask::~TestOrderedPendingTask() {
+}
+
+// TestMockTimeTaskRunner -----------------------------------------------------
+
+bool TestMockTimeTaskRunner::TemporalOrder::operator()(
+    const TestOrderedPendingTask& first_task,
+    const TestOrderedPendingTask& second_task) const {
+  if (first_task.GetTimeToRun() == second_task.GetTimeToRun())
+    return first_task.ordinal > second_task.ordinal;
+  return first_task.GetTimeToRun() > second_task.GetTimeToRun();
+}
+
+TestMockTimeTaskRunner::TestMockTimeTaskRunner()
+    : now_(Time::UnixEpoch()), next_task_ordinal_(0) {
+}
+
+TestMockTimeTaskRunner::~TestMockTimeTaskRunner() {
+}
+
+void TestMockTimeTaskRunner::FastForwardBy(TimeDelta delta) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_GE(delta, TimeDelta());
+
+  const TimeTicks original_now_ticks = now_ticks_;
+  ProcessAllTasksNoLaterThan(delta);
+  ForwardClocksUntilTickTime(original_now_ticks + delta);
+}
+
+void TestMockTimeTaskRunner::RunUntilIdle() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  ProcessAllTasksNoLaterThan(TimeDelta());
+}
+
+void TestMockTimeTaskRunner::FastForwardUntilNoTasksRemain() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  ProcessAllTasksNoLaterThan(TimeDelta::Max());
+}
+
+void TestMockTimeTaskRunner::ClearPendingTasks() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  AutoLock scoped_lock(tasks_lock_);
+  while (!tasks_.empty())
+    tasks_.pop();
+}
+
+Time TestMockTimeTaskRunner::Now() const {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  return now_;
+}
+
+TimeTicks TestMockTimeTaskRunner::NowTicks() const {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  return now_ticks_;
+}
+
+scoped_ptr<Clock> TestMockTimeTaskRunner::GetMockClock() const {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  return make_scoped_ptr(new MockClock(this));
+}
+
+scoped_ptr<TickClock> TestMockTimeTaskRunner::GetMockTickClock() const {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  return make_scoped_ptr(new MockTickClock(this));
+}
+
+bool TestMockTimeTaskRunner::HasPendingTask() const {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  return !tasks_.empty();
+}
+
+size_t TestMockTimeTaskRunner::GetPendingTaskCount() const {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  return tasks_.size();
+}
+
+TimeDelta TestMockTimeTaskRunner::NextPendingTaskDelay() const {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  return tasks_.empty() ? TimeDelta::Max()
+                        : tasks_.top().GetTimeToRun() - now_ticks_;
+}
+
+bool TestMockTimeTaskRunner::RunsTasksOnCurrentThread() const {
+  return thread_checker_.CalledOnValidThread();
+}
+
+bool TestMockTimeTaskRunner::PostDelayedTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay) {
+  AutoLock scoped_lock(tasks_lock_);
+  tasks_.push(TestOrderedPendingTask(from_here, task, now_ticks_, delay,
+                                     next_task_ordinal_++,
+                                     TestPendingTask::NESTABLE));
+  return true;
+}
+
+bool TestMockTimeTaskRunner::PostNonNestableDelayedTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay) {
+  return PostDelayedTask(from_here, task, delay);
+}
+
+bool TestMockTimeTaskRunner::IsElapsingStopped() {
+  return false;
+}
+
+void TestMockTimeTaskRunner::OnBeforeSelectingTask() {
+  // Empty default implementation.
+}
+
+void TestMockTimeTaskRunner::OnAfterTimePassed() {
+  // Empty default implementation.
+}
+
+void TestMockTimeTaskRunner::OnAfterTaskRun() {
+  // Empty default implementation.
+}
+
+void TestMockTimeTaskRunner::ProcessAllTasksNoLaterThan(TimeDelta max_delta) {
+  DCHECK_GE(max_delta, TimeDelta());
+  const TimeTicks original_now_ticks = now_ticks_;
+  while (!IsElapsingStopped()) {
+    OnBeforeSelectingTask();
+    TestPendingTask task_info;
+    if (!DequeueNextTask(original_now_ticks, max_delta, &task_info))
+      break;
+    // If tasks were posted with a negative delay, task_info.GetTimeToRun() will
+    // be less than |now_ticks_|. ForwardClocksUntilTickTime() takes care of not
+    // moving the clock backwards in this case.
+    ForwardClocksUntilTickTime(task_info.GetTimeToRun());
+    task_info.task.Run();
+    OnAfterTaskRun();
+  }
+}
+
+void TestMockTimeTaskRunner::ForwardClocksUntilTickTime(TimeTicks later_ticks) {
+  if (later_ticks <= now_ticks_)
+    return;
+
+  now_ += later_ticks - now_ticks_;
+  now_ticks_ = later_ticks;
+  OnAfterTimePassed();
+}
+
+bool TestMockTimeTaskRunner::DequeueNextTask(const TimeTicks& reference,
+                                             const TimeDelta& max_delta,
+                                             TestPendingTask* next_task) {
+  AutoLock scoped_lock(tasks_lock_);
+  if (!tasks_.empty() &&
+      (tasks_.top().GetTimeToRun() - reference) <= max_delta) {
+    *next_task = tasks_.top();
+    tasks_.pop();
+    return true;
+  }
+  return false;
+}
+
+}  // namespace base
diff --git a/base/test/test_mock_time_task_runner.h b/base/test/test_mock_time_task_runner.h
new file mode 100644
index 0000000..6319e0c
--- /dev/null
+++ b/base/test/test_mock_time_task_runner.h
@@ -0,0 +1,165 @@
+// 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_TEST_TEST_MOCK_TIME_TASK_RUNNER_H_
+#define BASE_TEST_TEST_MOCK_TIME_TASK_RUNNER_H_
+
+#include <queue>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/lock.h"
+#include "base/test/test_pending_task.h"
+#include "base/threading/thread_checker.h"
+#include "base/time/time.h"
+
+namespace base {
+
+class Clock;
+class TickClock;
+
+// Runs pending tasks in the order of the tasks' post time + delay, and keeps
+// track of a mock (virtual) tick clock time that can be fast-forwarded.
+//
+// TestMockTimeTaskRunner has the following properties:
+//
+//   - Methods RunsTasksOnCurrentThread() and Post[Delayed]Task() can be called
+//     from any thread, but the rest of the methods must be called on the same
+//     thread the TaskRunner was created on.
+//   - It allows for reentrancy, in that it handles the running of tasks that in
+//     turn call back into it (e.g., to post more tasks).
+//   - Tasks are stored in a priority queue, and executed in the increasing
+//     order of post time + delay, but ignoring nestability.
+//   - It does not check for overflow when doing time arithmetic. A sufficient
+//     condition for preventing overflows is to make sure that the sum of all
+//     posted task delays and fast-forward increments is still representable by
+//     a TimeDelta, and that adding this delta to the starting values of Time
+//     and TickTime is still within their respective range.
+//   - Tasks aren't guaranteed to be destroyed immediately after they're run.
+//
+// This is a slightly more sophisticated version of TestSimpleTaskRunner, in
+// that it supports running delayed tasks in the correct temporal order.
+class TestMockTimeTaskRunner : public SingleThreadTaskRunner {
+ public:
+  // Constructs an instance whose virtual time will start at the Unix epoch, and
+  // whose time ticks will start at zero.
+  TestMockTimeTaskRunner();
+
+  // Fast-forwards virtual time by |delta|, causing all tasks with a remaining
+  // delay less than or equal to |delta| to be executed. |delta| must be
+  // non-negative.
+  void FastForwardBy(TimeDelta delta);
+
+  // Fast-forwards virtual time just until all tasks are executed.
+  void FastForwardUntilNoTasksRemain();
+
+  // Executes all tasks that have no remaining delay. Tasks with a remaining
+  // delay greater than zero will remain enqueued, and no virtual time will
+  // elapse.
+  void RunUntilIdle();
+
+  // Clears the queue of pending tasks without running them.
+  void ClearPendingTasks();
+
+  // Returns the current virtual time (initially starting at the Unix epoch).
+  Time Now() const;
+
+  // Returns the current virtual tick time (initially starting at 0).
+  TimeTicks NowTicks() const;
+
+  // Returns a Clock that uses the virtual time of |this| as its time source.
+  // The returned Clock will hold a reference to |this|.
+  scoped_ptr<Clock> GetMockClock() const;
+
+  // Returns a TickClock that uses the virtual time ticks of |this| as its tick
+  // source. The returned TickClock will hold a reference to |this|.
+  scoped_ptr<TickClock> GetMockTickClock() const;
+
+  bool HasPendingTask() const;
+  size_t GetPendingTaskCount() const;
+  TimeDelta NextPendingTaskDelay() const;
+
+  // SingleThreadTaskRunner:
+  bool RunsTasksOnCurrentThread() const override;
+  bool PostDelayedTask(const tracked_objects::Location& from_here,
+                       const Closure& task,
+                       TimeDelta delay) override;
+  bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
+                                  const Closure& task,
+                                  TimeDelta delay) override;
+
+ protected:
+  ~TestMockTimeTaskRunner() override;
+
+  // Whether the elapsing of virtual time is stopped or not. Subclasses can
+  // override this method to perform early exits from a running task runner.
+  // Defaults to always return false.
+  virtual bool IsElapsingStopped();
+
+  // Called before the next task to run is selected, so that subclasses have a
+  // last chance to make sure all tasks are posted.
+  virtual void OnBeforeSelectingTask();
+
+  // Called after the current mock time has been incremented so that subclasses
+  // can react to the passing of time.
+  virtual void OnAfterTimePassed();
+
+  // Called after each task is run so that subclasses may perform additional
+  // activities, e.g., pump additional task runners.
+  virtual void OnAfterTaskRun();
+
+ private:
+  struct TestOrderedPendingTask;
+
+  // Predicate that defines a strict weak temporal ordering of tasks.
+  class TemporalOrder {
+   public:
+    bool operator()(const TestOrderedPendingTask& first_task,
+                    const TestOrderedPendingTask& second_task) const;
+  };
+
+  typedef std::priority_queue<TestOrderedPendingTask,
+                              std::vector<TestOrderedPendingTask>,
+                              TemporalOrder> TaskPriorityQueue;
+
+  // Core of the implementation for all flavors of fast-forward methods. Given a
+  // non-negative |max_delta|, runs all tasks with a remaining delay less than
+  // or equal to |max_delta|, and moves virtual time forward as needed for each
+  // processed task. Pass in TimeDelta::Max() as |max_delta| to run all tasks.
+  void ProcessAllTasksNoLaterThan(TimeDelta max_delta);
+
+  // Forwards |now_ticks_| until it equals |later_ticks|, and forwards |now_| by
+  // the same amount. Calls OnAfterTimePassed() if |later_ticks| > |now_ticks_|.
+  // Does nothing if |later_ticks| <= |now_ticks_|.
+  void ForwardClocksUntilTickTime(TimeTicks later_ticks);
+
+  // Returns the |next_task| to run if there is any with a running time that is
+  // at most |reference| + |max_delta|. This additional complexity is required
+  // so that |max_delta| == TimeDelta::Max() can be supported.
+  bool DequeueNextTask(const TimeTicks& reference,
+                       const TimeDelta& max_delta,
+                       TestPendingTask* next_task);
+
+  ThreadChecker thread_checker_;
+  Time now_;
+  TimeTicks now_ticks_;
+
+  // Temporally ordered heap of pending tasks. Must only be accessed while the
+  // |tasks_lock_| is held.
+  TaskPriorityQueue tasks_;
+
+  // The ordinal to use for the next task. Must only be accessed while the
+  // |tasks_lock_| is held.
+  size_t next_task_ordinal_;
+
+  Lock tasks_lock_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestMockTimeTaskRunner);
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_TEST_MOCK_TIME_TASK_RUNNER_H_
diff --git a/base/test/test_pending_task.cc b/base/test/test_pending_task.cc
new file mode 100644
index 0000000..3f2c79d
--- /dev/null
+++ b/base/test/test_pending_task.cc
@@ -0,0 +1,77 @@
+// Copyright (c) 2012 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 <string>
+
+#include "base/test/test_pending_task.h"
+
+namespace base {
+
+TestPendingTask::TestPendingTask() : nestability(NESTABLE) {}
+
+TestPendingTask::TestPendingTask(
+    const tracked_objects::Location& location,
+    const Closure& task,
+    TimeTicks post_time,
+    TimeDelta delay,
+    TestNestability nestability)
+    : location(location),
+      task(task),
+      post_time(post_time),
+      delay(delay),
+      nestability(nestability) {}
+
+TimeTicks TestPendingTask::GetTimeToRun() const {
+  return post_time + delay;
+}
+
+bool TestPendingTask::ShouldRunBefore(const TestPendingTask& other) const {
+  if (nestability != other.nestability)
+    return (nestability == NESTABLE);
+  return GetTimeToRun() < other.GetTimeToRun();
+}
+
+TestPendingTask::~TestPendingTask() {}
+
+void TestPendingTask::AsValueInto(base::trace_event::TracedValue* state) const {
+  state->SetInteger("run_at", GetTimeToRun().ToInternalValue());
+  state->SetString("posting_function", location.ToString());
+  state->SetInteger("post_time", post_time.ToInternalValue());
+  state->SetInteger("delay", delay.ToInternalValue());
+  switch (nestability) {
+    case NESTABLE:
+      state->SetString("nestability", "NESTABLE");
+      break;
+    case NON_NESTABLE:
+      state->SetString("nestability", "NON_NESTABLE");
+      break;
+  }
+  state->SetInteger("delay", delay.ToInternalValue());
+}
+
+scoped_refptr<base::trace_event::ConvertableToTraceFormat>
+TestPendingTask::AsValue() const {
+  scoped_refptr<base::trace_event::TracedValue> state =
+      new base::trace_event::TracedValue();
+  AsValueInto(state.get());
+  return state;
+}
+
+std::string TestPendingTask::ToString() const {
+  std::string output("TestPendingTask(");
+  AsValue()->AppendAsTraceFormat(&output);
+  output += ")";
+  return output;
+}
+
+std::ostream& operator<<(std::ostream& os, const TestPendingTask& task) {
+  PrintTo(task, &os);
+  return os;
+}
+
+void PrintTo(const TestPendingTask& task, std::ostream* os) {
+  *os << task.ToString();
+}
+
+}  // namespace base
diff --git a/base/test/test_pending_task.h b/base/test/test_pending_task.h
new file mode 100644
index 0000000..829baa6
--- /dev/null
+++ b/base/test/test_pending_task.h
@@ -0,0 +1,72 @@
+// Copyright (c) 2012 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_TEST_TEST_PENDING_TASK_H_
+#define BASE_TEST_TEST_PENDING_TASK_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/location.h"
+#include "base/time/time.h"
+#include "base/trace_event/trace_event_argument.h"
+
+namespace base {
+
+// TestPendingTask is a helper class for test TaskRunner
+// implementations.  See test_simple_task_runner.h for example usage.
+
+struct TestPendingTask {
+  enum TestNestability { NESTABLE, NON_NESTABLE };
+
+  TestPendingTask();
+  TestPendingTask(const tracked_objects::Location& location,
+                  const Closure& task,
+                  TimeTicks post_time,
+                  TimeDelta delay,
+                  TestNestability nestability);
+  ~TestPendingTask();
+
+  // Returns post_time + delay.
+  TimeTicks GetTimeToRun() const;
+
+  // Returns true if this task is nestable and |other| isn't, or if
+  // this task's time to run is strictly earlier than |other|'s time
+  // to run.
+  //
+  // Note that two tasks may both have the same nestability and delay.
+  // In that case, the caller must use some other criterion (probably
+  // the position in some queue) to break the tie.  Conveniently, the
+  // following STL functions already do so:
+  //
+  //   - std::min_element
+  //   - std::stable_sort
+  //
+  // but the following STL functions don't:
+  //
+  //   - std::max_element
+  //   - std::sort.
+  bool ShouldRunBefore(const TestPendingTask& other) const;
+
+  tracked_objects::Location location;
+  Closure task;
+  TimeTicks post_time;
+  TimeDelta delay;
+  TestNestability nestability;
+
+  // Functions for using test pending task with tracing, useful in unit
+  // testing.
+  void AsValueInto(base::trace_event::TracedValue* state) const;
+  scoped_refptr<base::trace_event::ConvertableToTraceFormat> AsValue() const;
+  std::string ToString() const;
+};
+
+// gtest helpers which allow pretty printing of the tasks, very useful in unit
+// testing.
+std::ostream& operator<<(std::ostream& os, const TestPendingTask& task);
+void PrintTo(const TestPendingTask& task, std::ostream* os);
+
+}  // namespace base
+
+#endif  // BASE_TEST_TEST_PENDING_TASK_H_
diff --git a/base/test/test_pending_task_unittest.cc b/base/test/test_pending_task_unittest.cc
new file mode 100644
index 0000000..7623ce4
--- /dev/null
+++ b/base/test/test_pending_task_unittest.cc
@@ -0,0 +1,55 @@
+// Copyright (c) 2012 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/test/test_pending_task.h"
+
+#include "base/bind.h"
+#include "base/trace_event/trace_event.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest-spi.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(TestPendingTaskTest, TraceSupport) {
+  base::TestPendingTask task;
+
+  // Check that TestPendingTask can be sent to the trace subsystem.
+  TRACE_EVENT1("test", "TestPendingTask::TraceSupport", "task", task.AsValue());
+
+  // Just a basic check that the trace output has *something* in it.
+  EXPECT_THAT(task.AsValue()->ToString(), ::testing::HasSubstr("post_time"));
+}
+
+TEST(TestPendingTaskTest, ToString) {
+  base::TestPendingTask task;
+
+  // Just a basic check that ToString has *something* in it.
+  EXPECT_THAT(task.ToString(), ::testing::StartsWith("TestPendingTask("));
+}
+
+TEST(TestPendingTaskTest, GTestPrettyPrint) {
+  base::TestPendingTask task;
+
+  // Check that gtest is calling the TestPendingTask's PrintTo method.
+  EXPECT_THAT(::testing::PrintToString(task),
+              ::testing::StartsWith("TestPendingTask("));
+
+  // Check that pretty printing works with the gtest iostreams operator.
+  EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(false) << task, "TestPendingTask(");
+}
+
+TEST(TestPendingTaskTest, ShouldRunBefore) {
+  base::TestPendingTask task_first;
+  task_first.delay = base::TimeDelta::FromMilliseconds(1);
+  base::TestPendingTask task_after;
+  task_after.delay = base::TimeDelta::FromMilliseconds(2);
+
+  EXPECT_FALSE(task_after.ShouldRunBefore(task_first))
+      << task_after << ".ShouldRunBefore(" << task_first << ")\n";
+  EXPECT_TRUE(task_first.ShouldRunBefore(task_after))
+      << task_first << ".ShouldRunBefore(" << task_after << ")\n";
+}
+
+}  // namespace base
diff --git a/base/test/test_reg_util_win.cc b/base/test/test_reg_util_win.cc
new file mode 100644
index 0000000..e3b1ffc
--- /dev/null
+++ b/base/test/test_reg_util_win.cc
@@ -0,0 +1,105 @@
+// Copyright (c) 2011 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/test/test_reg_util_win.h"
+
+#include "base/guid.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace registry_util {
+
+namespace {
+
+const wchar_t kTimestampDelimiter[] = L"$";
+const wchar_t kTempTestKeyPath[] = L"Software\\Chromium\\TempTestKeys";
+
+void DeleteStaleTestKeys(const base::Time& now,
+                         const base::string16& test_key_root) {
+  base::win::RegKey test_root_key;
+  if (test_root_key.Open(HKEY_CURRENT_USER,
+                         test_key_root.c_str(),
+                         KEY_ALL_ACCESS) != ERROR_SUCCESS) {
+    // This will occur on first-run, but is harmless.
+    return;
+  }
+
+  base::win::RegistryKeyIterator iterator_test_root_key(HKEY_CURRENT_USER,
+                                                        test_key_root.c_str());
+  for (; iterator_test_root_key.Valid(); ++iterator_test_root_key) {
+    base::string16 key_name = iterator_test_root_key.Name();
+    std::vector<base::string16> tokens;
+    if (!Tokenize(key_name, base::string16(kTimestampDelimiter), &tokens))
+      continue;
+    int64 key_name_as_number = 0;
+
+    if (!base::StringToInt64(tokens[0], &key_name_as_number)) {
+      test_root_key.DeleteKey(key_name.c_str());
+      continue;
+    }
+
+    base::Time key_time = base::Time::FromInternalValue(key_name_as_number);
+    base::TimeDelta age = now - key_time;
+
+    if (age > base::TimeDelta::FromHours(24))
+      test_root_key.DeleteKey(key_name.c_str());
+  }
+}
+
+base::string16 GenerateTempKeyPath(const base::string16& test_key_root,
+                                   const base::Time& timestamp) {
+  base::string16 key_path = test_key_root;
+  key_path += L"\\" + base::Int64ToString16(timestamp.ToInternalValue());
+  key_path += kTimestampDelimiter + base::ASCIIToUTF16(base::GenerateGUID());
+
+  return key_path;
+}
+
+}  // namespace
+
+RegistryOverrideManager::ScopedRegistryKeyOverride::ScopedRegistryKeyOverride(
+    HKEY override,
+    const base::string16& key_path)
+    : override_(override) {
+  EXPECT_EQ(
+      ERROR_SUCCESS,
+      temp_key_.Create(HKEY_CURRENT_USER, key_path.c_str(), KEY_ALL_ACCESS));
+  EXPECT_EQ(ERROR_SUCCESS,
+            ::RegOverridePredefKey(override_, temp_key_.Handle()));
+}
+
+RegistryOverrideManager::
+    ScopedRegistryKeyOverride::~ScopedRegistryKeyOverride() {
+  ::RegOverridePredefKey(override_, NULL);
+  temp_key_.DeleteKey(L"");
+}
+
+RegistryOverrideManager::RegistryOverrideManager()
+    : timestamp_(base::Time::Now()), test_key_root_(kTempTestKeyPath) {
+  DeleteStaleTestKeys(timestamp_, test_key_root_);
+}
+
+RegistryOverrideManager::RegistryOverrideManager(
+    const base::Time& timestamp,
+    const base::string16& test_key_root)
+    : timestamp_(timestamp), test_key_root_(test_key_root) {
+  DeleteStaleTestKeys(timestamp_, test_key_root_);
+}
+
+RegistryOverrideManager::~RegistryOverrideManager() {}
+
+void RegistryOverrideManager::OverrideRegistry(HKEY override) {
+  base::string16 key_path = GenerateTempKeyPath(test_key_root_, timestamp_);
+  overrides_.push_back(new ScopedRegistryKeyOverride(override, key_path));
+}
+
+base::string16 GenerateTempKeyPath() {
+  return GenerateTempKeyPath(base::string16(kTempTestKeyPath),
+                             base::Time::Now());
+}
+
+}  // namespace registry_util
diff --git a/base/test/test_reg_util_win.h b/base/test/test_reg_util_win.h
new file mode 100644
index 0000000..5f23b7f
--- /dev/null
+++ b/base/test/test_reg_util_win.h
@@ -0,0 +1,77 @@
+// Copyright (c) 2011 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_TEST_TEST_REG_UTIL_WIN_H_
+#define BASE_TEST_TEST_REG_UTIL_WIN_H_
+
+// Registry utility functions used only by tests.
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_vector.h"
+#include "base/strings/string16.h"
+#include "base/time/time.h"
+#include "base/win/registry.h"
+
+namespace registry_util {
+
+// Allows a test to easily override registry hives so that it can start from a
+// known good state, or make sure to not leave any side effects once the test
+// completes. This supports parallel tests. All the overrides are scoped to the
+// lifetime of the override manager. Destroy the manager to undo the overrides.
+//
+// Overridden hives use keys stored at, for instance:
+//   HKCU\Software\Chromium\TempTestKeys\
+//       13028145911617809$02AB211C-CF73-478D-8D91-618E11998AED
+// The key path are comprises of:
+//   - The test key root, HKCU\Software\Chromium\TempTestKeys\
+//   - The base::Time::ToInternalValue of the creation time. This is used to
+//     delete stale keys left over from crashed tests.
+//   - A GUID used for preventing name collisions (although unlikely) between
+//     two RegistryOverrideManagers created with the same timestamp.
+class RegistryOverrideManager {
+ public:
+  RegistryOverrideManager();
+  ~RegistryOverrideManager();
+
+  // Override the given registry hive using a randomly generated temporary key.
+  // Multiple overrides to the same hive are not supported and lead to undefined
+  // behavior.
+  void OverrideRegistry(HKEY override);
+
+ private:
+  friend class RegistryOverrideManagerTest;
+
+  // Keeps track of one override.
+  class ScopedRegistryKeyOverride {
+   public:
+    ScopedRegistryKeyOverride(HKEY override, const base::string16& key_path);
+    ~ScopedRegistryKeyOverride();
+
+   private:
+    HKEY override_;
+    base::win::RegKey temp_key_;
+
+    DISALLOW_COPY_AND_ASSIGN(ScopedRegistryKeyOverride);
+  };
+
+  // Used for testing only.
+  RegistryOverrideManager(const base::Time& timestamp,
+                          const base::string16& test_key_root);
+
+  base::Time timestamp_;
+  base::string16 guid_;
+
+  base::string16 test_key_root_;
+  ScopedVector<ScopedRegistryKeyOverride> overrides_;
+
+  DISALLOW_COPY_AND_ASSIGN(RegistryOverrideManager);
+};
+
+// Generates a temporary key path that will be eventually deleted
+// automatically if the process crashes.
+base::string16 GenerateTempKeyPath();
+
+}  // namespace registry_util
+
+#endif  // BASE_TEST_TEST_REG_UTIL_WIN_H_
diff --git a/base/test/test_reg_util_win_unittest.cc b/base/test/test_reg_util_win_unittest.cc
new file mode 100644
index 0000000..216d58e
--- /dev/null
+++ b/base/test/test_reg_util_win_unittest.cc
@@ -0,0 +1,130 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/test_reg_util_win.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace registry_util {
+
+namespace {
+const wchar_t kTestKeyPath[] = L"Software\\Chromium\\Foo\\Baz\\TestKey";
+const wchar_t kTestValueName[] = L"TestValue";
+}  // namespace
+
+class RegistryOverrideManagerTest : public testing::Test {
+ protected:
+  RegistryOverrideManagerTest() {
+    // We assign a fake test key path to our test RegistryOverrideManager
+    // so we don't interfere with any actual RegistryOverrideManagers running
+    // on the system. This fake path will be auto-deleted by other
+    // RegistryOverrideManagers in case we crash.
+    fake_test_key_root_ = registry_util::GenerateTempKeyPath();
+
+    // Ensure a clean test environment.
+    base::win::RegKey key(HKEY_CURRENT_USER);
+    key.DeleteKey(fake_test_key_root_.c_str());
+    key.DeleteKey(kTestKeyPath);
+  }
+
+  ~RegistryOverrideManagerTest() override {
+    base::win::RegKey key(HKEY_CURRENT_USER);
+    key.DeleteKey(fake_test_key_root_.c_str());
+  }
+
+  void AssertKeyExists(const base::string16& key_path) {
+    base::win::RegKey key;
+    ASSERT_EQ(ERROR_SUCCESS,
+              key.Open(HKEY_CURRENT_USER, key_path.c_str(), KEY_READ))
+        << key_path << " does not exist.";
+  }
+
+  void AssertKeyAbsent(const base::string16& key_path) {
+    base::win::RegKey key;
+    ASSERT_NE(ERROR_SUCCESS,
+              key.Open(HKEY_CURRENT_USER, key_path.c_str(), KEY_READ))
+        << key_path << " exists but it should not.";
+  }
+
+  void CreateKey(const base::string16& key_path) {
+    base::win::RegKey key;
+    EXPECT_EQ(ERROR_SUCCESS,
+              key.Create(HKEY_CURRENT_USER, key_path.c_str(), KEY_ALL_ACCESS));
+  }
+
+  base::string16 FakeOverrideManagerPath(const base::Time& time) {
+    return fake_test_key_root_ + L"\\" +
+           base::Int64ToString16(time.ToInternalValue());
+  }
+
+  void CreateManager(const base::Time& timestamp) {
+    manager_.reset(new RegistryOverrideManager(timestamp, fake_test_key_root_));
+    manager_->OverrideRegistry(HKEY_CURRENT_USER);
+  }
+
+  base::string16 fake_test_key_root_;
+  scoped_ptr<RegistryOverrideManager> manager_;
+};
+
+TEST_F(RegistryOverrideManagerTest, Basic) {
+  CreateManager(base::Time::Now());
+
+  base::win::RegKey create_key;
+  EXPECT_EQ(ERROR_SUCCESS,
+            create_key.Create(HKEY_CURRENT_USER, kTestKeyPath, KEY_ALL_ACCESS));
+  EXPECT_TRUE(create_key.Valid());
+  EXPECT_EQ(ERROR_SUCCESS, create_key.WriteValue(kTestValueName, 42));
+  create_key.Close();
+
+  AssertKeyExists(kTestKeyPath);
+
+  DWORD value;
+  base::win::RegKey read_key;
+  EXPECT_EQ(ERROR_SUCCESS,
+            read_key.Open(HKEY_CURRENT_USER, kTestKeyPath, KEY_READ));
+  EXPECT_TRUE(read_key.Valid());
+  EXPECT_EQ(ERROR_SUCCESS, read_key.ReadValueDW(kTestValueName, &value));
+  EXPECT_EQ(42, value);
+  read_key.Close();
+
+  manager_.reset();
+
+  AssertKeyAbsent(kTestKeyPath);
+}
+
+TEST_F(RegistryOverrideManagerTest, DeleteStaleKeys) {
+  base::Time::Exploded kTestTimeExploded = {2013, 11, 1, 4, 0, 0, 0, 0};
+  base::Time kTestTime = base::Time::FromUTCExploded(kTestTimeExploded);
+
+  base::string16 path_garbage = fake_test_key_root_ + L"\\Blah";
+  base::string16 path_very_stale =
+      FakeOverrideManagerPath(kTestTime - base::TimeDelta::FromDays(100));
+  base::string16 path_stale =
+      FakeOverrideManagerPath(kTestTime - base::TimeDelta::FromDays(5));
+  base::string16 path_current =
+      FakeOverrideManagerPath(kTestTime - base::TimeDelta::FromMinutes(1));
+  base::string16 path_future =
+      FakeOverrideManagerPath(kTestTime + base::TimeDelta::FromMinutes(1));
+
+  CreateKey(path_garbage);
+  CreateKey(path_very_stale);
+  CreateKey(path_stale);
+  CreateKey(path_current);
+  CreateKey(path_future);
+
+  CreateManager(kTestTime);
+  manager_.reset();
+
+  AssertKeyAbsent(path_garbage);
+  AssertKeyAbsent(path_very_stale);
+  AssertKeyAbsent(path_stale);
+  AssertKeyExists(path_current);
+  AssertKeyExists(path_future);
+}
+
+}  // namespace registry_util
diff --git a/base/test/test_shortcut_win.cc b/base/test/test_shortcut_win.cc
new file mode 100644
index 0000000..eb074a3
--- /dev/null
+++ b/base/test/test_shortcut_win.cc
@@ -0,0 +1,155 @@
+// Copyright (c) 2012 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/test/test_shortcut_win.h"
+
+#include <windows.h>
+#include <shlobj.h>
+#include <propkey.h>
+
+#include "base/files/file_path.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/win/scoped_comptr.h"
+#include "base/win/scoped_propvariant.h"
+#include "base/win/windows_version.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace win {
+
+void ValidatePathsAreEqual(const base::FilePath& expected_path,
+                           const base::FilePath& actual_path) {
+  wchar_t long_expected_path_chars[MAX_PATH] = {0};
+  wchar_t long_actual_path_chars[MAX_PATH] = {0};
+
+  // If |expected_path| is empty confirm immediately that |actual_path| is also
+  // empty.
+  if (expected_path.empty()) {
+    EXPECT_TRUE(actual_path.empty());
+    return;
+  }
+
+  // Proceed with LongPathName matching which will also confirm the paths exist.
+  EXPECT_NE(0U, ::GetLongPathName(
+      expected_path.value().c_str(), long_expected_path_chars, MAX_PATH))
+          << "Failed to get LongPathName of " << expected_path.value();
+  EXPECT_NE(0U, ::GetLongPathName(
+      actual_path.value().c_str(), long_actual_path_chars, MAX_PATH))
+          << "Failed to get LongPathName of " << actual_path.value();
+
+  base::FilePath long_expected_path(long_expected_path_chars);
+  base::FilePath long_actual_path(long_actual_path_chars);
+  EXPECT_FALSE(long_expected_path.empty());
+  EXPECT_FALSE(long_actual_path.empty());
+
+  EXPECT_EQ(long_expected_path, long_actual_path);
+}
+
+void ValidateShortcut(const base::FilePath& shortcut_path,
+                      const ShortcutProperties& properties) {
+  ScopedComPtr<IShellLink> i_shell_link;
+  ScopedComPtr<IPersistFile> i_persist_file;
+
+  wchar_t read_target[MAX_PATH] = {0};
+  wchar_t read_working_dir[MAX_PATH] = {0};
+  wchar_t read_arguments[MAX_PATH] = {0};
+  wchar_t read_description[MAX_PATH] = {0};
+  wchar_t read_icon[MAX_PATH] = {0};
+  int read_icon_index = 0;
+
+  HRESULT hr;
+
+  // Initialize the shell interfaces.
+  EXPECT_TRUE(SUCCEEDED(hr = i_shell_link.CreateInstance(
+      CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER)));
+  if (FAILED(hr))
+    return;
+
+  EXPECT_TRUE(SUCCEEDED(hr = i_persist_file.QueryFrom(i_shell_link.get())));
+  if (FAILED(hr))
+    return;
+
+  // Load the shortcut.
+  EXPECT_TRUE(SUCCEEDED(hr = i_persist_file->Load(
+      shortcut_path.value().c_str(), 0))) << "Failed to load shortcut at "
+                                          << shortcut_path.value();
+  if (FAILED(hr))
+    return;
+
+  if (properties.options & ShortcutProperties::PROPERTIES_TARGET) {
+    EXPECT_TRUE(SUCCEEDED(
+        i_shell_link->GetPath(read_target, MAX_PATH, NULL, SLGP_SHORTPATH)));
+    ValidatePathsAreEqual(properties.target, base::FilePath(read_target));
+  }
+
+  if (properties.options & ShortcutProperties::PROPERTIES_WORKING_DIR) {
+    EXPECT_TRUE(SUCCEEDED(
+        i_shell_link->GetWorkingDirectory(read_working_dir, MAX_PATH)));
+    ValidatePathsAreEqual(properties.working_dir,
+                          base::FilePath(read_working_dir));
+  }
+
+  if (properties.options & ShortcutProperties::PROPERTIES_ARGUMENTS) {
+    EXPECT_TRUE(SUCCEEDED(
+        i_shell_link->GetArguments(read_arguments, MAX_PATH)));
+    EXPECT_EQ(properties.arguments, read_arguments);
+  }
+
+  if (properties.options & ShortcutProperties::PROPERTIES_DESCRIPTION) {
+    EXPECT_TRUE(SUCCEEDED(
+        i_shell_link->GetDescription(read_description, MAX_PATH)));
+    EXPECT_EQ(properties.description, read_description);
+  }
+
+  if (properties.options & ShortcutProperties::PROPERTIES_ICON) {
+    EXPECT_TRUE(SUCCEEDED(
+        i_shell_link->GetIconLocation(read_icon, MAX_PATH, &read_icon_index)));
+    ValidatePathsAreEqual(properties.icon, base::FilePath(read_icon));
+    EXPECT_EQ(properties.icon_index, read_icon_index);
+  }
+
+  if (GetVersion() >= VERSION_WIN7) {
+    ScopedComPtr<IPropertyStore> property_store;
+    EXPECT_TRUE(SUCCEEDED(hr = property_store.QueryFrom(i_shell_link.get())));
+    if (FAILED(hr))
+      return;
+
+    if (properties.options & ShortcutProperties::PROPERTIES_APP_ID) {
+      ScopedPropVariant pv_app_id;
+      EXPECT_EQ(S_OK, property_store->GetValue(PKEY_AppUserModel_ID,
+                                               pv_app_id.Receive()));
+      switch (pv_app_id.get().vt) {
+        case VT_EMPTY:
+          EXPECT_TRUE(properties.app_id.empty());
+          break;
+        case VT_LPWSTR:
+          EXPECT_EQ(properties.app_id, pv_app_id.get().pwszVal);
+          break;
+        default:
+          ADD_FAILURE() << "Unexpected variant type: " << pv_app_id.get().vt;
+      }
+    }
+
+    if (properties.options & ShortcutProperties::PROPERTIES_DUAL_MODE) {
+      ScopedPropVariant pv_dual_mode;
+      EXPECT_EQ(S_OK, property_store->GetValue(PKEY_AppUserModel_IsDualMode,
+                                               pv_dual_mode.Receive()));
+      switch (pv_dual_mode.get().vt) {
+        case VT_EMPTY:
+          EXPECT_FALSE(properties.dual_mode);
+          break;
+        case VT_BOOL:
+          EXPECT_EQ(properties.dual_mode,
+                    static_cast<bool>(pv_dual_mode.get().boolVal));
+          break;
+        default:
+          ADD_FAILURE() << "Unexpected variant type: " << pv_dual_mode.get().vt;
+      }
+    }
+  }
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/test/test_shortcut_win.h b/base/test/test_shortcut_win.h
new file mode 100644
index 0000000..b828e8b
--- /dev/null
+++ b/base/test/test_shortcut_win.h
@@ -0,0 +1,30 @@
+// Copyright (c) 2012 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_TEST_TEST_SHORTCUT_WIN_H_
+#define BASE_TEST_TEST_SHORTCUT_WIN_H_
+
+#include "base/files/file_path.h"
+#include "base/win/shortcut.h"
+
+// Windows shortcut functions used only by tests.
+
+namespace base {
+namespace win {
+
+// Validates |actual_path|'s LongPathName case-insensitively matches
+// |expected_path|'s LongPathName.
+void ValidatePathsAreEqual(const base::FilePath& expected_path,
+                           const base::FilePath& actual_path);
+
+// Validates that a shortcut exists at |shortcut_path| with the expected
+// |properties|.
+// Logs gtest failures on failed verifications.
+void ValidateShortcut(const FilePath& shortcut_path,
+                      const ShortcutProperties& properties);
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_TEST_TEST_SHORTCUT_WIN_H_
diff --git a/base/test/test_simple_task_runner.cc b/base/test/test_simple_task_runner.cc
new file mode 100644
index 0000000..cc39fab
--- /dev/null
+++ b/base/test/test_simple_task_runner.cc
@@ -0,0 +1,82 @@
+// Copyright (c) 2012 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/test/test_simple_task_runner.h"
+
+#include "base/logging.h"
+
+namespace base {
+
+TestSimpleTaskRunner::TestSimpleTaskRunner() {}
+
+TestSimpleTaskRunner::~TestSimpleTaskRunner() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+}
+
+bool TestSimpleTaskRunner::PostDelayedTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  pending_tasks_.push_back(
+      TestPendingTask(from_here, task, TimeTicks(), delay,
+                      TestPendingTask::NESTABLE));
+  return true;
+}
+
+bool TestSimpleTaskRunner::PostNonNestableDelayedTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  pending_tasks_.push_back(
+      TestPendingTask(from_here, task, TimeTicks(), delay,
+                      TestPendingTask::NON_NESTABLE));
+  return true;
+}
+
+bool TestSimpleTaskRunner::RunsTasksOnCurrentThread() const {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  return true;
+}
+
+const std::deque<TestPendingTask>&
+TestSimpleTaskRunner::GetPendingTasks() const {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  return pending_tasks_;
+}
+
+bool TestSimpleTaskRunner::HasPendingTask() const {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  return !pending_tasks_.empty();
+}
+
+base::TimeDelta TestSimpleTaskRunner::NextPendingTaskDelay() const {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  return pending_tasks_.front().GetTimeToRun() - base::TimeTicks();
+}
+
+void TestSimpleTaskRunner::ClearPendingTasks() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  pending_tasks_.clear();
+}
+
+void TestSimpleTaskRunner::RunPendingTasks() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  // Swap with a local variable to avoid re-entrancy problems.
+  std::deque<TestPendingTask> tasks_to_run;
+  tasks_to_run.swap(pending_tasks_);
+  for (std::deque<TestPendingTask>::iterator it = tasks_to_run.begin();
+       it != tasks_to_run.end(); ++it) {
+    it->task.Run();
+  }
+}
+
+void TestSimpleTaskRunner::RunUntilIdle() {
+  while (!pending_tasks_.empty()) {
+    RunPendingTasks();
+  }
+}
+
+}  // namespace base
diff --git a/base/test/test_simple_task_runner.h b/base/test/test_simple_task_runner.h
new file mode 100644
index 0000000..7481b6d
--- /dev/null
+++ b/base/test/test_simple_task_runner.h
@@ -0,0 +1,85 @@
+// Copyright (c) 2012 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_TEST_TEST_SIMPLE_TASK_RUNNER_H_
+#define BASE_TEST_TEST_SIMPLE_TASK_RUNNER_H_
+
+#include <deque>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/single_thread_task_runner.h"
+#include "base/test/test_pending_task.h"
+#include "base/threading/thread_checker.h"
+
+namespace base {
+
+class TimeDelta;
+
+// TestSimpleTaskRunner is a simple TaskRunner implementation that can
+// be used for testing.  It implements SingleThreadTaskRunner as that
+// interface implements SequencedTaskRunner, which in turn implements
+// TaskRunner, so TestSimpleTaskRunner can be passed in to a function
+// that accepts any *TaskRunner object.
+//
+// TestSimpleTaskRunner has the following properties which make it simple:
+//
+//   - It is non-thread safe; all member functions must be called on
+//     the same thread.
+//   - Tasks are simply stored in a queue in FIFO order, ignoring delay
+//     and nestability.
+//   - Tasks aren't guaranteed to be destroyed immediately after
+//     they're run.
+//
+// However, TestSimpleTaskRunner allows for reentrancy, in that it
+// handles the running of tasks that in turn call back into itself
+// (e.g., to post more tasks).
+//
+// If you need more complicated properties, consider using this class
+// as a template for writing a test TaskRunner implementation using
+// TestPendingTask.
+//
+// Note that, like any TaskRunner, TestSimpleTaskRunner is
+// ref-counted.
+class TestSimpleTaskRunner : public SingleThreadTaskRunner {
+ public:
+  TestSimpleTaskRunner();
+
+  // SingleThreadTaskRunner implementation.
+  bool PostDelayedTask(const tracked_objects::Location& from_here,
+                       const Closure& task,
+                       TimeDelta delay) override;
+  bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
+                                  const Closure& task,
+                                  TimeDelta delay) override;
+
+  bool RunsTasksOnCurrentThread() const override;
+
+  const std::deque<TestPendingTask>& GetPendingTasks() const;
+  bool HasPendingTask() const;
+  base::TimeDelta NextPendingTaskDelay() const;
+
+  // Clears the queue of pending tasks without running them.
+  void ClearPendingTasks();
+
+  // Runs each current pending task in order and clears the queue.
+  // Any tasks posted by the tasks are not run.
+  virtual void RunPendingTasks();
+
+  // Runs pending tasks until the queue is empty.
+  void RunUntilIdle();
+
+ protected:
+  ~TestSimpleTaskRunner() override;
+
+  std::deque<TestPendingTask> pending_tasks_;
+  ThreadChecker thread_checker_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestSimpleTaskRunner);
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_TEST_SIMPLE_TASK_RUNNER_H_
diff --git a/base/test/test_suite.cc b/base/test/test_suite.cc
new file mode 100644
index 0000000..e281cff
--- /dev/null
+++ b/base/test/test_suite.cc
@@ -0,0 +1,358 @@
+// Copyright (c) 2012 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/test/test_suite.h"
+
+#include "base/at_exit.h"
+#include "base/base_paths.h"
+#include "base/base_switches.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/debug/debugger.h"
+#include "base/debug/stack_trace.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/i18n/icu_util.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/path_service.h"
+#include "base/process/memory.h"
+#include "base/test/gtest_xml_unittest_result_printer.h"
+#include "base/test/gtest_xml_util.h"
+#include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/multiprocess_test.h"
+#include "base/test/test_switches.h"
+#include "base/test/test_timeouts.h"
+#include "base/time/time.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/multiprocess_func_list.h"
+
+#if defined(OS_MACOSX)
+#include "base/mac/scoped_nsautorelease_pool.h"
+#if defined(OS_IOS)
+#include "base/test/test_listener_ios.h"
+#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
+
+#if defined(OS_IOS)
+#include "base/test/test_support_ios.h"
+#endif
+
+namespace base {
+
+namespace {
+
+class MaybeTestDisabler : public testing::EmptyTestEventListener {
+ public:
+  void OnTestStart(const testing::TestInfo& test_info) override {
+    ASSERT_FALSE(TestSuite::IsMarkedMaybe(test_info))
+        << "Probably the OS #ifdefs don't include all of the necessary "
+           "platforms.\nPlease ensure that no tests have the MAYBE_ prefix "
+           "after the code is preprocessed.";
+  }
+};
+
+class TestClientInitializer : public testing::EmptyTestEventListener {
+ public:
+  TestClientInitializer()
+      : old_command_line_(CommandLine::NO_PROGRAM) {
+  }
+
+  void OnTestStart(const testing::TestInfo& test_info) override {
+    old_command_line_ = *CommandLine::ForCurrentProcess();
+  }
+
+  void OnTestEnd(const testing::TestInfo& test_info) override {
+    *CommandLine::ForCurrentProcess() = old_command_line_;
+  }
+
+ private:
+  CommandLine old_command_line_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestClientInitializer);
+};
+
+}  // namespace
+
+int RunUnitTestsUsingBaseTestSuite(int argc, char **argv) {
+  TestSuite test_suite(argc, argv);
+  return LaunchUnitTests(argc, argv,
+                         Bind(&TestSuite::Run, Unretained(&test_suite)));
+}
+
+TestSuite::TestSuite(int argc, char** argv) : initialized_command_line_(false) {
+  PreInitialize(true);
+  InitializeFromCommandLine(argc, argv);
+}
+
+#if defined(OS_WIN)
+TestSuite::TestSuite(int argc, wchar_t** argv)
+    : initialized_command_line_(false) {
+  PreInitialize(true);
+  InitializeFromCommandLine(argc, argv);
+}
+#endif  // defined(OS_WIN)
+
+TestSuite::TestSuite(int argc, char** argv, bool create_at_exit_manager)
+    : initialized_command_line_(false) {
+  PreInitialize(create_at_exit_manager);
+  InitializeFromCommandLine(argc, argv);
+}
+
+TestSuite::~TestSuite() {
+  if (initialized_command_line_)
+    CommandLine::Reset();
+}
+
+void TestSuite::InitializeFromCommandLine(int argc, char** argv) {
+  initialized_command_line_ = CommandLine::Init(argc, argv);
+  testing::InitGoogleTest(&argc, argv);
+  testing::InitGoogleMock(&argc, argv);
+
+#if defined(OS_IOS)
+  InitIOSRunHook(this, argc, argv);
+#endif
+}
+
+#if defined(OS_WIN)
+void TestSuite::InitializeFromCommandLine(int argc, wchar_t** argv) {
+  // Windows CommandLine::Init ignores argv anyway.
+  initialized_command_line_ = CommandLine::Init(argc, NULL);
+  testing::InitGoogleTest(&argc, argv);
+  testing::InitGoogleMock(&argc, argv);
+}
+#endif  // defined(OS_WIN)
+
+void TestSuite::PreInitialize(bool create_at_exit_manager) {
+#if defined(OS_WIN)
+  testing::GTEST_FLAG(catch_exceptions) = false;
+#endif
+  EnableTerminationOnHeapCorruption();
+#if defined(OS_LINUX) && defined(USE_AURA)
+  // When calling native char conversion functions (e.g wrctomb) we need to
+  // have the locale set. In the absence of such a call the "C" locale is the
+  // default. In the gtk code (below) gtk_init() implicitly sets a locale.
+  setlocale(LC_ALL, "");
+#endif  // defined(OS_LINUX) && defined(USE_AURA)
+
+  // On Android, AtExitManager is created in
+  // testing/android/native_test_wrapper.cc before main() is called.
+#if !defined(OS_ANDROID)
+  if (create_at_exit_manager)
+    at_exit_manager_.reset(new AtExitManager);
+#endif
+
+  // Don't add additional code to this function.  Instead add it to
+  // Initialize().  See bug 6436.
+}
+
+
+// static
+bool TestSuite::IsMarkedMaybe(const testing::TestInfo& test) {
+  return strncmp(test.name(), "MAYBE_", 6) == 0;
+}
+
+void TestSuite::CatchMaybeTests() {
+  testing::TestEventListeners& listeners =
+      testing::UnitTest::GetInstance()->listeners();
+  listeners.Append(new MaybeTestDisabler);
+}
+
+void TestSuite::ResetCommandLine() {
+  testing::TestEventListeners& listeners =
+      testing::UnitTest::GetInstance()->listeners();
+  listeners.Append(new TestClientInitializer);
+}
+
+void TestSuite::AddTestLauncherResultPrinter() {
+  // Only add the custom printer if requested.
+  if (!CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kTestLauncherOutput)) {
+    return;
+  }
+
+  FilePath output_path(CommandLine::ForCurrentProcess()->GetSwitchValuePath(
+      switches::kTestLauncherOutput));
+
+  // Do not add the result printer if output path already exists. It's an
+  // indicator there is a process printing to that file, and we're likely
+  // its child. Do not clobber the results in that case.
+  if (PathExists(output_path)) {
+    LOG(WARNING) << "Test launcher output path " << output_path.AsUTF8Unsafe()
+                 << " exists. Not adding test launcher result printer.";
+    return;
+  }
+
+  XmlUnitTestResultPrinter* printer = new XmlUnitTestResultPrinter;
+  CHECK(printer->Initialize(output_path));
+  testing::TestEventListeners& listeners =
+      testing::UnitTest::GetInstance()->listeners();
+  listeners.Append(printer);
+}
+
+// Don't add additional code to this method.  Instead add it to
+// Initialize().  See bug 6436.
+int TestSuite::Run() {
+#if defined(OS_IOS)
+  RunTestsFromIOSApp();
+#endif
+
+#if defined(OS_MACOSX)
+  mac::ScopedNSAutoreleasePool scoped_pool;
+#endif
+
+  Initialize();
+  std::string client_func =
+      CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+          switches::kTestChildProcess);
+
+  // Check to see if we are being run as a client process.
+  if (!client_func.empty())
+    return multi_process_function_list::InvokeChildProcessTest(client_func);
+#if defined(OS_IOS)
+  test_listener_ios::RegisterTestEndListener();
+#endif
+  int result = RUN_ALL_TESTS();
+
+#if defined(OS_MACOSX)
+  // This MUST happen before Shutdown() since Shutdown() tears down
+  // objects (such as NotificationService::current()) that Cocoa
+  // objects use to remove themselves as observers.
+  scoped_pool.Recycle();
+#endif
+
+  Shutdown();
+
+  return result;
+}
+
+// static
+void TestSuite::UnitTestAssertHandler(const std::string& str) {
+#if defined(OS_ANDROID)
+  // Correlating test stdio with logcat can be difficult, so we emit this
+  // helpful little hint about what was running.  Only do this for Android
+  // because other platforms don't separate out the relevant logs in the same
+  // way.
+  const ::testing::TestInfo* const test_info =
+      ::testing::UnitTest::GetInstance()->current_test_info();
+  if (test_info) {
+    LOG(ERROR) << "Currently running: " << test_info->test_case_name() << "."
+               << test_info->name();
+    fflush(stderr);
+  }
+#endif  // defined(OS_ANDROID)
+
+  // The logging system actually prints the message before calling the assert
+  // handler. Just exit now to avoid printing too many stack traces.
+  _exit(1);
+}
+
+void TestSuite::SuppressErrorDialogs() {
+#if defined(OS_WIN)
+  UINT new_flags = SEM_FAILCRITICALERRORS |
+                   SEM_NOGPFAULTERRORBOX |
+                   SEM_NOOPENFILEERRORBOX;
+
+  // Preserve existing error mode, as discussed at
+  // http://blogs.msdn.com/oldnewthing/archive/2004/07/27/198410.aspx
+  UINT existing_flags = SetErrorMode(new_flags);
+  SetErrorMode(existing_flags | new_flags);
+
+#if defined(_DEBUG) && defined(_HAS_EXCEPTIONS) && (_HAS_EXCEPTIONS == 1)
+  // Suppress the "Debug Assertion Failed" dialog.
+  // TODO(hbono): remove this code when gtest has it.
+  // http://groups.google.com/d/topic/googletestframework/OjuwNlXy5ac/discussion
+  _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
+  _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
+#endif  // defined(_DEBUG) && defined(_HAS_EXCEPTIONS) && (_HAS_EXCEPTIONS == 1)
+#endif  // defined(OS_WIN)
+}
+
+void TestSuite::Initialize() {
+#if !defined(OS_IOS)
+  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kWaitForDebugger)) {
+    debug::WaitForDebugger(60, true);
+  }
+#endif
+
+#if defined(OS_IOS)
+  InitIOSTestMessageLoop();
+#endif  // OS_IOS
+
+#if defined(OS_ANDROID)
+  InitAndroidTest();
+#else
+  // Initialize logging.
+  FilePath exe;
+  PathService::Get(FILE_EXE, &exe);
+  FilePath log_filename = exe.ReplaceExtension(FILE_PATH_LITERAL("log"));
+  logging::LoggingSettings settings;
+  settings.logging_dest = logging::LOG_TO_ALL;
+  settings.log_file = log_filename.value().c_str();
+  settings.delete_old = logging::DELETE_OLD_LOG_FILE;
+  logging::InitLogging(settings);
+  // We want process and thread IDs because we may have multiple processes.
+  // Note: temporarily enabled timestamps in an effort to catch bug 6361.
+  logging::SetLogItems(true, true, true, true);
+#endif  // else defined(OS_ANDROID)
+
+  CHECK(debug::EnableInProcessStackDumping());
+#if defined(OS_WIN)
+  // Make sure we run with high resolution timer to minimize differences
+  // between production code and test code.
+  Time::EnableHighResolutionTimer(true);
+#endif  // defined(OS_WIN)
+
+  // In some cases, we do not want to see standard error dialogs.
+  if (!debug::BeingDebugged() &&
+      !CommandLine::ForCurrentProcess()->HasSwitch("show-error-dialogs")) {
+    SuppressErrorDialogs();
+    debug::SetSuppressDebugUI(true);
+    logging::SetLogAssertHandler(UnitTestAssertHandler);
+  }
+
+  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)
+  i18n::SetICUDefaultLocale("en_US");
+#else
+  std::string default_locale(uloc_getDefault());
+  if (EndsWith(default_locale, "POSIX", false))
+    i18n::SetICUDefaultLocale("en_US");
+#endif
+#endif
+
+  CatchMaybeTests();
+  ResetCommandLine();
+  AddTestLauncherResultPrinter();
+
+  TestTimeouts::Initialize();
+
+  trace_to_file_.BeginTracingFromCommandLineOptions();
+}
+
+void TestSuite::Shutdown() {
+}
+
+}  // namespace base
diff --git a/base/test/test_suite.h b/base/test/test_suite.h
new file mode 100644
index 0000000..cf0dd3a
--- /dev/null
+++ b/base/test/test_suite.h
@@ -0,0 +1,93 @@
+// Copyright (c) 2012 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_TEST_TEST_SUITE_H_
+#define BASE_TEST_TEST_SUITE_H_
+
+// Defines a basic test suite framework for running gtest based tests.  You can
+// instantiate this class in your main function and call its Run method to run
+// any gtest based tests that are linked into your executable.
+
+#include <string>
+
+#include "base/at_exit.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/test/trace_to_file.h"
+
+namespace testing {
+class TestInfo;
+}
+
+namespace base {
+
+// Instantiates TestSuite, runs it and returns exit code.
+int RunUnitTestsUsingBaseTestSuite(int argc, char **argv);
+
+class TestSuite {
+ public:
+  // Match function used by the GetTestCount method.
+  typedef bool (*TestMatch)(const testing::TestInfo&);
+
+  TestSuite(int argc, char** argv);
+#if defined(OS_WIN)
+  TestSuite(int argc, wchar_t** argv);
+#endif  // defined(OS_WIN)
+  virtual ~TestSuite();
+
+  // Returns true if the test is marked as "MAYBE_".
+  // When using different prefixes depending on platform, we use MAYBE_ and
+  // preprocessor directives to replace MAYBE_ with the target prefix.
+  static bool IsMarkedMaybe(const testing::TestInfo& test);
+
+  void CatchMaybeTests();
+
+  void ResetCommandLine();
+
+  void AddTestLauncherResultPrinter();
+
+  int Run();
+
+ protected:
+  // This constructor is only accessible to specialized test suite
+  // implementations which need to control the creation of an AtExitManager
+  // instance for the duration of the test.
+  TestSuite(int argc, char** argv, bool create_at_exit_manager);
+
+  // By default fatal log messages (e.g. from DCHECKs) result in error dialogs
+  // which gum up buildbots. Use a minimalistic assert handler which just
+  // terminates the process.
+  static void UnitTestAssertHandler(const std::string& str);
+
+  // Disable crash dialogs so that it doesn't gum up the buildbot
+  virtual void SuppressErrorDialogs();
+
+  // Override these for custom initialization and shutdown handling.  Use these
+  // instead of putting complex code in your constructor/destructor.
+
+  virtual void Initialize();
+  virtual void Shutdown();
+
+  // Make sure that we setup an AtExitManager so Singleton objects will be
+  // destroyed.
+  scoped_ptr<base::AtExitManager> at_exit_manager_;
+
+ private:
+  void InitializeFromCommandLine(int argc, char** argv);
+#if defined(OS_WIN)
+  void InitializeFromCommandLine(int argc, wchar_t** argv);
+#endif  // defined(OS_WIN)
+
+  // Basic initialization for the test suite happens here.
+  void PreInitialize(bool create_at_exit_manager);
+
+  test::TraceToFile trace_to_file_;
+
+  bool initialized_command_line_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestSuite);
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_TEST_SUITE_H_
diff --git a/base/test/test_support_android.cc b/base/test/test_support_android.cc
new file mode 100644
index 0000000..11a0871
--- /dev/null
+++ b/base/test/test_support_android.cc
@@ -0,0 +1,184 @@
+// Copyright (c) 2012 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 <stdarg.h>
+#include <string.h>
+
+#include "base/android/path_utils.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/memory/singleton.h"
+#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_pump_android.h"
+#include "base/path_service.h"
+#include "base/synchronization/waitable_event.h"
+
+namespace {
+
+struct RunState {
+  RunState(base::MessagePump::Delegate* delegate, int run_depth)
+      : delegate(delegate),
+        run_depth(run_depth),
+        should_quit(false) {
+  }
+
+  base::MessagePump::Delegate* delegate;
+
+  // Used to count how many Run() invocations are on the stack.
+  int run_depth;
+
+  // Used to flag that the current Run() invocation should return ASAP.
+  bool should_quit;
+};
+
+RunState* g_state = NULL;
+
+// A singleton WaitableEvent wrapper so we avoid a busy loop in
+// MessagePumpForUIStub. Other platforms use the native event loop which blocks
+// when there are no pending messages.
+class Waitable {
+ public:
+   static Waitable* GetInstance() {
+     return Singleton<Waitable>::get();
+   }
+
+   // Signals that there are more work to do.
+   void Signal() {
+     waitable_event_.Signal();
+   }
+
+   // Blocks until more work is scheduled.
+   void Block() {
+     waitable_event_.Wait();
+   }
+
+   void Quit() {
+     g_state->should_quit = true;
+     Signal();
+   }
+
+ private:
+  friend struct DefaultSingletonTraits<Waitable>;
+
+  Waitable()
+      : waitable_event_(false, false) {
+  }
+
+  base::WaitableEvent waitable_event_;
+
+  DISALLOW_COPY_AND_ASSIGN(Waitable);
+};
+
+// The MessagePumpForUI implementation for test purpose.
+class MessagePumpForUIStub : public base::MessagePumpForUI {
+  ~MessagePumpForUIStub() override {}
+
+  void Start(base::MessagePump::Delegate* delegate) override {
+    NOTREACHED() << "The Start() method shouldn't be called in test, using"
+        " Run() method should be used.";
+  }
+
+  void Run(base::MessagePump::Delegate* delegate) override {
+    // The following was based on message_pump_glib.cc, except we're using a
+    // WaitableEvent since there are no native message loop to use.
+    RunState state(delegate, g_state ? g_state->run_depth + 1 : 1);
+
+    RunState* previous_state = g_state;
+    g_state = &state;
+
+    bool more_work_is_plausible = true;
+
+    for (;;) {
+      if (!more_work_is_plausible) {
+        Waitable::GetInstance()->Block();
+        if (g_state->should_quit)
+          break;
+      }
+
+      more_work_is_plausible = g_state->delegate->DoWork();
+      if (g_state->should_quit)
+        break;
+
+      base::TimeTicks delayed_work_time;
+      more_work_is_plausible |=
+          g_state->delegate->DoDelayedWork(&delayed_work_time);
+      if (g_state->should_quit)
+        break;
+
+      if (more_work_is_plausible)
+        continue;
+
+      more_work_is_plausible = g_state->delegate->DoIdleWork();
+      if (g_state->should_quit)
+        break;
+
+      more_work_is_plausible |= !delayed_work_time.is_null();
+    }
+
+    g_state = previous_state;
+  }
+
+  void Quit() override { Waitable::GetInstance()->Quit(); }
+
+  void ScheduleWork() override { Waitable::GetInstance()->Signal(); }
+
+  void ScheduleDelayedWork(const base::TimeTicks& delayed_work_time) override {
+    Waitable::GetInstance()->Signal();
+  }
+};
+
+scoped_ptr<base::MessagePump> CreateMessagePumpForUIStub() {
+  return scoped_ptr<base::MessagePump>(new MessagePumpForUIStub());
+};
+
+// Provides the test path for DIR_MODULE and DIR_ANDROID_APP_DATA.
+bool GetTestProviderPath(int key, base::FilePath* result) {
+  switch (key) {
+    case base::DIR_ANDROID_APP_DATA: {
+      // For tests, app data is put in external storage.
+      return base::android::GetExternalStorageDirectory(result);
+    }
+    default:
+      return false;
+  }
+}
+
+void InitPathProvider(int key) {
+  base::FilePath path;
+  // If failed to override the key, that means the way has not been registered.
+  if (GetTestProviderPath(key, &path) && !PathService::Override(key, path))
+    PathService::RegisterProvider(&GetTestProviderPath, key, key + 1);
+}
+
+}  // namespace
+
+namespace base {
+
+void InitAndroidTestLogging() {
+  logging::LoggingSettings settings;
+  settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
+  logging::InitLogging(settings);
+  // To view log output with IDs and timestamps use "adb logcat -v threadtime".
+  logging::SetLogItems(false,    // Process ID
+                       false,    // Thread ID
+                       false,    // Timestamp
+                       false);   // Tick count
+}
+
+void InitAndroidTestPaths() {
+  InitPathProvider(DIR_MODULE);
+  InitPathProvider(DIR_ANDROID_APP_DATA);
+}
+
+void InitAndroidTestMessageLoop() {
+  if (!MessageLoop::InitMessagePumpForUIFactory(&CreateMessagePumpForUIStub))
+    LOG(INFO) << "MessagePumpForUIFactory already set, unable to override.";
+}
+
+void InitAndroidTest() {
+  InitAndroidTestLogging();
+  InitAndroidTestPaths();
+  InitAndroidTestMessageLoop();
+}
+}  // namespace base
diff --git a/base/test/test_support_android.h b/base/test/test_support_android.h
new file mode 100644
index 0000000..062785e
--- /dev/null
+++ b/base/test/test_support_android.h
@@ -0,0 +1,26 @@
+// Copyright (c) 2012 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_TEST_TEST_SUPPORT_ANDROID_H_
+#define BASE_TEST_TEST_SUPPORT_ANDROID_H_
+
+#include "base/base_export.h"
+
+namespace base {
+
+// Init logging for tests on Android. Logs will be output into Android's logcat.
+BASE_EXPORT void InitAndroidTestLogging();
+
+// Init path providers for tests on Android.
+BASE_EXPORT void InitAndroidTestPaths();
+
+// Init the message loop for tests on Android.
+BASE_EXPORT void InitAndroidTestMessageLoop();
+
+// Do all of the initializations above.
+BASE_EXPORT void InitAndroidTest();
+
+}  // namespace base
+
+#endif  // BASE_TEST_TEST_SUPPORT_ANDROID_H_
diff --git a/base/test/test_support_ios.h b/base/test/test_support_ios.h
new file mode 100644
index 0000000..c71cf0d
--- /dev/null
+++ b/base/test/test_support_ios.h
@@ -0,0 +1,24 @@
+// Copyright (c) 2012 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_TEST_TEST_SUPPORT_IOS_H_
+#define BASE_TEST_TEST_SUPPORT_IOS_H_
+
+#include "base/test/test_suite.h"
+
+namespace base {
+
+// Inits the message loop for tests on iOS.
+void InitIOSTestMessageLoop();
+
+// Inits the run hook for tests on iOS.
+void InitIOSRunHook(TestSuite* suite, int argc, char* argv[]);
+
+// Launches an iOS app that runs the tests in the suite passed to
+// InitIOSRunHook.
+void RunTestsFromIOSApp();
+
+}  // namespace base
+
+#endif  // BASE_TEST_TEST_SUPPORT_IOS_H_
diff --git a/base/test/test_support_ios.mm b/base/test/test_support_ios.mm
new file mode 100644
index 0000000..3b31da6
--- /dev/null
+++ b/base/test/test_support_ios.mm
@@ -0,0 +1,216 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <UIKit/UIKit.h>
+
+#include "base/debug/debugger.h"
+#include "base/logging.h"
+#include "base/mac/scoped_nsautorelease_pool.h"
+#include "base/mac/scoped_nsobject.h"
+#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_pump_default.h"
+#include "base/test/test_suite.h"
+#include "testing/coverage_util_ios.h"
+
+// Springboard will kill any iOS app that fails to check in after launch within
+// a given time. Starting a UIApplication before invoking TestSuite::Run
+// prevents this from happening.
+
+// InitIOSRunHook saves the TestSuite and argc/argv, then invoking
+// RunTestsFromIOSApp calls UIApplicationMain(), providing an application
+// delegate class: ChromeUnitTestDelegate. The delegate implements
+// application:didFinishLaunchingWithOptions: to invoke the TestSuite's Run
+// method.
+
+// Since the executable isn't likely to be a real iOS UI, the delegate puts up a
+// window displaying the app name. If a bunch of apps using MainHook are being
+// run in a row, this provides an indication of which one is currently running.
+
+static base::TestSuite* g_test_suite = NULL;
+static int g_argc;
+static char** g_argv;
+
+@interface UIApplication (Testing)
+- (void) _terminateWithStatus:(int)status;
+@end
+
+#if TARGET_IPHONE_SIMULATOR
+// Xcode 6 introduced behavior in the iOS Simulator where the software
+// keyboard does not appear if a hardware keyboard is connected. The following
+// declaration allows this behavior to be overriden when the app starts up.
+@interface UIKeyboardImpl
++ (instancetype)sharedInstance;
+- (void)setAutomaticMinimizationEnabled:(BOOL)enabled;
+- (void)setSoftwareKeyboardShownByTouch:(BOOL)enabled;
+@end
+#endif  // TARGET_IPHONE_SIMULATOR
+
+@interface ChromeUnitTestDelegate : NSObject {
+ @private
+  base::scoped_nsobject<UIWindow> window_;
+}
+- (void)runTests;
+@end
+
+@implementation ChromeUnitTestDelegate
+
+- (BOOL)application:(UIApplication *)application
+    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
+
+#if TARGET_IPHONE_SIMULATOR
+  // Xcode 6 introduced behavior in the iOS Simulator where the software
+  // keyboard does not appear if a hardware keyboard is connected. The following
+  // calls override this behavior by ensuring that the software keyboard is
+  // always shown.
+  [[UIKeyboardImpl sharedInstance] setAutomaticMinimizationEnabled:NO];
+  [[UIKeyboardImpl sharedInstance] setSoftwareKeyboardShownByTouch:YES];
+#endif  // TARGET_IPHONE_SIMULATOR
+
+  CGRect bounds = [[UIScreen mainScreen] bounds];
+
+  // Yes, this is leaked, it's just to make what's running visible.
+  window_.reset([[UIWindow alloc] initWithFrame:bounds]);
+  [window_ setBackgroundColor:[UIColor whiteColor]];
+  [window_ makeKeyAndVisible];
+
+  // Add a label with the app name.
+  UILabel* label = [[[UILabel alloc] initWithFrame:bounds] autorelease];
+  label.text = [[NSProcessInfo processInfo] processName];
+  label.textAlignment = NSTextAlignmentCenter;
+  [window_ addSubview:label];
+
+  if ([self shouldRedirectOutputToFile])
+    [self redirectOutput];
+
+  // Queue up the test run.
+  [self performSelector:@selector(runTests)
+             withObject:nil
+             afterDelay:0.1];
+  return YES;
+}
+
+// Returns true if the gtest output should be redirected to a file, then sent
+// to NSLog when compleete. This redirection is used because gtest only writes
+// output to stdout, but results must be written to NSLog in order to show up in
+// the device log that is retrieved from the device by the host.
+- (BOOL)shouldRedirectOutputToFile {
+#if !TARGET_IPHONE_SIMULATOR
+  return !base::debug::BeingDebugged();
+#endif  // TARGET_IPHONE_SIMULATOR
+  return NO;
+}
+
+// Returns the path to the directory to store gtest output files.
+- (NSString*)outputPath {
+  NSArray* searchPath =
+      NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
+                                          NSUserDomainMask,
+                                          YES);
+  CHECK([searchPath count] > 0) << "Failed to get the Documents folder";
+  return [searchPath objectAtIndex:0];
+}
+
+// Returns the path to file that stdout is redirected to.
+- (NSString*)stdoutPath {
+  return [[self outputPath] stringByAppendingPathComponent:@"stdout.log"];
+}
+
+// Returns the path to file that stderr is redirected to.
+- (NSString*)stderrPath {
+  return [[self outputPath] stringByAppendingPathComponent:@"stderr.log"];
+}
+
+// Redirects stdout and stderr to files in the Documents folder in the app's
+// sandbox.
+- (void)redirectOutput {
+  freopen([[self stdoutPath] UTF8String], "w+", stdout);
+  freopen([[self stderrPath] UTF8String], "w+", stderr);
+}
+
+// Reads the redirected gtest output from a file and writes it to NSLog.
+- (void)writeOutputToNSLog {
+  // Close the redirected stdout and stderr files so that the content written to
+  // NSLog doesn't end up in these files.
+  fclose(stdout);
+  fclose(stderr);
+  for (NSString* path in @[ [self stdoutPath], [self stderrPath]]) {
+    NSString* content = [NSString stringWithContentsOfFile:path
+                                                  encoding:NSUTF8StringEncoding
+                                                     error:NULL];
+    NSArray* lines = [content componentsSeparatedByCharactersInSet:
+        [NSCharacterSet newlineCharacterSet]];
+
+    NSLog(@"Writing contents of %@ to NSLog", path);
+    for (NSString* line in lines) {
+      NSLog(@"%@", line);
+    }
+  }
+}
+
+- (void)runTests {
+  int exitStatus = g_test_suite->Run();
+
+  if ([self shouldRedirectOutputToFile])
+    [self writeOutputToNSLog];
+
+  // If a test app is too fast, it will exit before Instruments has has a
+  // a chance to initialize and no test results will be seen.
+  // TODO(ios): crbug.com/137010 Figure out how much time is actually needed,
+  // and sleep only to make sure that much time has elapsed since launch.
+  [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:2.0]];
+  window_.reset();
+
+  // Use the hidden selector to try and cleanly take down the app (otherwise
+  // things can think the app crashed even on a zero exit status).
+  UIApplication* application = [UIApplication sharedApplication];
+  [application _terminateWithStatus:exitStatus];
+
+  coverage_util::FlushCoverageDataIfNecessary();
+
+  exit(exitStatus);
+}
+
+@end
+
+namespace {
+
+scoped_ptr<base::MessagePump> CreateMessagePumpForUIForTests() {
+  // A default MessagePump will do quite nicely in tests.
+  return scoped_ptr<base::MessagePump>(new base::MessagePumpDefault());
+}
+
+}  // namespace
+
+namespace base {
+
+void InitIOSTestMessageLoop() {
+  MessageLoop::InitMessagePumpForUIFactory(&CreateMessagePumpForUIForTests);
+}
+
+void InitIOSRunHook(TestSuite* suite, int argc, char* argv[]) {
+  g_test_suite = suite;
+  g_argc = argc;
+  g_argv = argv;
+}
+
+void RunTestsFromIOSApp() {
+  // When TestSuite::Run is invoked it calls RunTestsFromIOSApp(). On the first
+  // invocation, this method fires up an iOS app via UIApplicationMain. Since
+  // UIApplicationMain does not return until the app exits, control does not
+  // return to the initial TestSuite::Run invocation, so the app invokes
+  // TestSuite::Run a second time and since |ran_hook| is true at this point,
+  // this method is a no-op and control returns to TestSuite:Run so that test
+  // are executed. Once the app exits, RunTestsFromIOSApp calls exit() so that
+  // control is not returned to the initial invocation of TestSuite::Run.
+  static bool ran_hook = false;
+  if (!ran_hook) {
+    ran_hook = true;
+    mac::ScopedNSAutoreleasePool pool;
+    int exit_status = UIApplicationMain(g_argc, g_argv, nil,
+                                        @"ChromeUnitTestDelegate");
+    exit(exit_status);
+  }
+}
+
+}  // namespace base
diff --git a/base/test/test_switches.cc b/base/test/test_switches.cc
new file mode 100644
index 0000000..84aa53c
--- /dev/null
+++ b/base/test/test_switches.cc
@@ -0,0 +1,63 @@
+// Copyright (c) 2012 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/test/test_switches.h"
+
+// Maximum number of tests to run in a single batch.
+const char switches::kTestLauncherBatchLimit[] = "test-launcher-batch-limit";
+
+// Sets defaults desirable for the continuous integration bots, e.g. parallel
+// test execution and test retries.
+const char switches::kTestLauncherBotMode[] =
+    "test-launcher-bot-mode";
+
+// Makes it possible to debug the launcher itself. By default the launcher
+// automatically switches to single process mode when it detects presence
+// of debugger.
+const char switches::kTestLauncherDebugLauncher[] =
+    "test-launcher-debug-launcher";
+
+// Path to file containing test filter (one pattern per line).
+const char switches::kTestLauncherFilterFile[] = "test-launcher-filter-file";
+
+// Number of parallel test launcher jobs.
+const char switches::kTestLauncherJobs[] = "test-launcher-jobs";
+
+// Path to list of compiled in tests.
+const char switches::kTestLauncherListTests[] = "test-launcher-list-tests";
+
+// Path to test results file in our custom test launcher format.
+const char switches::kTestLauncherOutput[] = "test-launcher-output";
+
+// Maximum number of times to retry a test after failure.
+const char switches::kTestLauncherRetryLimit[] = "test-launcher-retry-limit";
+
+// Path to test results file with all the info from the test launcher.
+const char switches::kTestLauncherSummaryOutput[] =
+    "test-launcher-summary-output";
+
+// Flag controlling when test stdio is displayed as part of the launcher's
+// standard output.
+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[] =
+    "test-launcher-shard-index";
+
+// Total number of shards. Must be the same for all shards.
+const char switches::kTestLauncherTotalShards[] =
+    "test-launcher-total-shards";
+
+// Time (in milliseconds) that the tests should wait before timing out.
+const char switches::kTestLauncherTimeout[] = "test-launcher-timeout";
+// TODO(phajdan.jr): Clean up the switch names.
+const char switches::kTestTinyTimeout[] = "test-tiny-timeout";
+const char switches::kUiTestActionTimeout[] = "ui-test-action-timeout";
+const char switches::kUiTestActionMaxTimeout[] = "ui-test-action-max-timeout";
diff --git a/base/test/test_switches.h b/base/test/test_switches.h
new file mode 100644
index 0000000..f145f1e
--- /dev/null
+++ b/base/test/test_switches.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2012 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_TEST_TEST_SWITCHES_H_
+#define BASE_TEST_TEST_SWITCHES_H_
+
+namespace switches {
+
+// All switches in alphabetical order. The switches should be documented
+// alongside the definition of their values in the .cc file.
+extern const char kTestLauncherBatchLimit[];
+extern const char kTestLauncherBotMode[];
+extern const char kTestLauncherDebugLauncher[];
+extern const char kTestLauncherFilterFile[];
+extern const char kTestLauncherJobs[];
+extern const char kTestLauncherListTests[];
+extern const char kTestLauncherOutput[];
+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[];
+extern const char kTestTinyTimeout[];
+extern const char kUiTestActionTimeout[];
+extern const char kUiTestActionMaxTimeout[];
+
+}  // namespace switches
+
+#endif  // BASE_TEST_TEST_SWITCHES_H_
diff --git a/base/test/test_timeouts.cc b/base/test/test_timeouts.cc
new file mode 100644
index 0000000..b30d6c3
--- /dev/null
+++ b/base/test/test_timeouts.cc
@@ -0,0 +1,113 @@
+// Copyright (c) 2011 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/test/test_timeouts.h"
+
+#include <algorithm>
+
+#include "base/command_line.h"
+#include "base/debug/debugger.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/test/test_switches.h"
+
+namespace {
+
+// ASan/TSan/MSan instrument each memory access. This may slow the execution
+// down significantly.
+#if defined(MEMORY_SANITIZER)
+// For MSan the slowdown depends heavily on the value of msan_track_origins GYP
+// flag. The multiplier below corresponds to msan_track_origins=1.
+static const int kTimeoutMultiplier = 6;
+#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 = 3;
+#elif defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) || \
+    defined(SYZYASAN)
+static const int kTimeoutMultiplier = 2;
+#else
+static const int kTimeoutMultiplier = 1;
+#endif
+
+const int kAlmostInfiniteTimeoutMs = 100000000;
+
+// Sets value to the greatest of:
+// 1) value's current value multiplied by kTimeoutMultiplier (assuming
+// InitializeTimeout is called only once per value).
+// 2) min_value.
+// 3) the numerical value given by switch_name on the command line multiplied
+// by kTimeoutMultiplier.
+void InitializeTimeout(const char* switch_name, int min_value, int* value) {
+  DCHECK(value);
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(switch_name)) {
+    std::string string_value(base::CommandLine::ForCurrentProcess()->
+         GetSwitchValueASCII(switch_name));
+    int timeout;
+    base::StringToInt(string_value, &timeout);
+    *value = std::max(*value, timeout);
+  }
+  *value *= kTimeoutMultiplier;
+  *value = std::max(*value, min_value);
+}
+
+// Sets value to the greatest of:
+// 1) value's current value multiplied by kTimeoutMultiplier.
+// 2) 0
+// 3) the numerical value given by switch_name on the command line multiplied
+// by kTimeoutMultiplier.
+void InitializeTimeout(const char* switch_name, int* value) {
+  InitializeTimeout(switch_name, 0, value);
+}
+
+}  // namespace
+
+// static
+bool TestTimeouts::initialized_ = false;
+
+// The timeout values should increase in the order they appear in this block.
+// static
+int TestTimeouts::tiny_timeout_ms_ = 100;
+int TestTimeouts::action_timeout_ms_ = 10000;
+#ifndef NDEBUG
+int TestTimeouts::action_max_timeout_ms_ = 45000;
+#else
+int TestTimeouts::action_max_timeout_ms_ = 30000;
+#endif  // NDEBUG
+
+int TestTimeouts::test_launcher_timeout_ms_ = 45000;
+
+// static
+void TestTimeouts::Initialize() {
+  if (initialized_) {
+    NOTREACHED();
+    return;
+  }
+  initialized_ = true;
+
+  if (base::debug::BeingDebugged()) {
+    fprintf(stdout,
+        "Detected presence of a debugger, running without test timeouts.\n");
+  }
+
+  // Note that these timeouts MUST be initialized in the correct order as
+  // per the CHECKS below.
+  InitializeTimeout(switches::kTestTinyTimeout, &tiny_timeout_ms_);
+  InitializeTimeout(switches::kUiTestActionTimeout,
+                    base::debug::BeingDebugged() ? kAlmostInfiniteTimeoutMs
+                                                 : tiny_timeout_ms_,
+                    &action_timeout_ms_);
+  InitializeTimeout(switches::kUiTestActionMaxTimeout, action_timeout_ms_,
+                    &action_max_timeout_ms_);
+
+  // Test launcher timeout is independent from anything above action timeout.
+  InitializeTimeout(switches::kTestLauncherTimeout, action_timeout_ms_,
+                    &test_launcher_timeout_ms_);
+
+  // The timeout values should be increasing in the right order.
+  CHECK(tiny_timeout_ms_ <= action_timeout_ms_);
+  CHECK(action_timeout_ms_ <= action_max_timeout_ms_);
+
+  CHECK(action_timeout_ms_ <= test_launcher_timeout_ms_);
+}
diff --git a/base/test/test_timeouts.h b/base/test/test_timeouts.h
new file mode 100644
index 0000000..2819e4a
--- /dev/null
+++ b/base/test/test_timeouts.h
@@ -0,0 +1,59 @@
+// Copyright (c) 2012 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_TEST_TEST_TIMEOUTS_H_
+#define BASE_TEST_TEST_TIMEOUTS_H_
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/time/time.h"
+
+// Returns common timeouts to use in tests. Makes it possible to adjust
+// the timeouts for different environments (like Valgrind).
+class TestTimeouts {
+ public:
+  // Initializes the timeouts. Non thread-safe. Should be called exactly once
+  // by the test suite.
+  static void Initialize();
+
+  // Timeout for actions that are expected to finish "almost instantly".
+  static base::TimeDelta tiny_timeout() {
+    DCHECK(initialized_);
+    return base::TimeDelta::FromMilliseconds(tiny_timeout_ms_);
+  }
+
+  // Timeout to wait for something to happen. If you are not sure
+  // which timeout to use, this is the one you want.
+  static base::TimeDelta action_timeout() {
+    DCHECK(initialized_);
+    return base::TimeDelta::FromMilliseconds(action_timeout_ms_);
+  }
+
+  // Timeout longer than the above, but still suitable to use
+  // multiple times in a single test. Use if the timeout above
+  // is not sufficient.
+  static base::TimeDelta action_max_timeout() {
+    DCHECK(initialized_);
+    return base::TimeDelta::FromMilliseconds(action_max_timeout_ms_);
+  }
+
+  // Timeout for a single test launched used built-in test launcher.
+  // Do not use outside of the test launcher.
+  static base::TimeDelta test_launcher_timeout() {
+    DCHECK(initialized_);
+    return base::TimeDelta::FromMilliseconds(test_launcher_timeout_ms_);
+  }
+
+ private:
+  static bool initialized_;
+
+  static int tiny_timeout_ms_;
+  static int action_timeout_ms_;
+  static int action_max_timeout_ms_;
+  static int test_launcher_timeout_ms_;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(TestTimeouts);
+};
+
+#endif  // BASE_TEST_TEST_TIMEOUTS_H_
diff --git a/base/test/test_ui_thread_android.cc b/base/test/test_ui_thread_android.cc
new file mode 100644
index 0000000..6f19974
--- /dev/null
+++ b/base/test/test_ui_thread_android.cc
@@ -0,0 +1,18 @@
+// 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/test/test_ui_thread_android.h"
+
+#include "jni/TestUiThread_jni.h"
+
+namespace base {
+
+void StartTestUiThreadLooper() {
+  Java_TestUiThread_loop(base::android::AttachCurrentThread());
+}
+
+bool RegisterTestUiThreadAndroid(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace base
diff --git a/base/test/test_ui_thread_android.h b/base/test/test_ui_thread_android.h
new file mode 100644
index 0000000..dfecbfe
--- /dev/null
+++ b/base/test/test_ui_thread_android.h
@@ -0,0 +1,21 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_TEST_UI_THREAD_ANDROID_
+#define BASE_TEST_TEST_UI_THREAD_ANDROID_
+
+#include <jni.h>
+
+namespace base {
+
+// Set up a thread as the Chromium UI Thread, and run its looper. This is is
+// intended for C++ unit tests (e.g. the net unit tests) that don't run with the
+// UI thread as their main looper, but test code that, on Android, uses UI
+// thread events, so need a running UI thread.
+void StartTestUiThreadLooper();
+
+bool RegisterTestUiThreadAndroid(JNIEnv* env);
+}  // namespace base
+
+#endif  //  BASE_TEST_TEST_UI_THREAD_ANDROID_
diff --git a/base/test/thread_test_helper.cc b/base/test/thread_test_helper.cc
new file mode 100644
index 0000000..6a12190
--- /dev/null
+++ b/base/test/thread_test_helper.cc
@@ -0,0 +1,39 @@
+// Copyright (c) 2011 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/test/thread_test_helper.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace base {
+
+ThreadTestHelper::ThreadTestHelper(
+    scoped_refptr<SingleThreadTaskRunner> target_thread)
+    : test_result_(false),
+      target_thread_(target_thread.Pass()),
+      done_event_(false, false) {
+}
+
+bool ThreadTestHelper::Run() {
+  if (!target_thread_->PostTask(
+          FROM_HERE, base::Bind(&ThreadTestHelper::RunInThread, this))) {
+    return false;
+  }
+  base::ThreadRestrictions::ScopedAllowWait allow_wait;
+  done_event_.Wait();
+  return test_result_;
+}
+
+void ThreadTestHelper::RunTest() { set_test_result(true); }
+
+ThreadTestHelper::~ThreadTestHelper() {}
+
+void ThreadTestHelper::RunInThread() {
+  RunTest();
+  done_event_.Signal();
+}
+
+}  // namespace base
diff --git a/base/test/thread_test_helper.h b/base/test/thread_test_helper.h
new file mode 100644
index 0000000..926da73
--- /dev/null
+++ b/base/test/thread_test_helper.h
@@ -0,0 +1,49 @@
+// Copyright (c) 2011 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_TEST_THREAD_TEST_HELPER_H_
+#define BASE_TEST_THREAD_TEST_HELPER_H_
+
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/waitable_event.h"
+
+namespace base {
+
+// Helper class that executes code on a given thread while blocking on the
+// invoking thread. To use, derive from this class and overwrite RunTest. An
+// alternative use of this class is to use it directly.  It will then block
+// until all pending tasks on a given thread have been executed.
+class ThreadTestHelper : public RefCountedThreadSafe<ThreadTestHelper> {
+ public:
+  explicit ThreadTestHelper(
+      scoped_refptr<SingleThreadTaskRunner> target_thread);
+
+  // True if RunTest() was successfully executed on the target thread.
+  bool Run() WARN_UNUSED_RESULT;
+
+  virtual void RunTest();
+
+ protected:
+  friend class RefCountedThreadSafe<ThreadTestHelper>;
+
+  virtual ~ThreadTestHelper();
+
+  // Use this method to store the result of RunTest().
+  void set_test_result(bool test_result) { test_result_ = test_result; }
+
+ private:
+  void RunInThread();
+
+  bool test_result_;
+  scoped_refptr<SingleThreadTaskRunner> target_thread_;
+  WaitableEvent done_event_;
+
+  DISALLOW_COPY_AND_ASSIGN(ThreadTestHelper);
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_THREAD_TEST_HELPER_H_
diff --git a/base/test/trace_event_analyzer.cc b/base/test/trace_event_analyzer.cc
new file mode 100644
index 0000000..e46c2a5
--- /dev/null
+++ b/base/test/trace_event_analyzer.cc
@@ -0,0 +1,968 @@
+// Copyright (c) 2012 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/test/trace_event_analyzer.h"
+
+#include <algorithm>
+#include <math.h>
+#include <set>
+
+#include "base/json/json_reader.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/values.h"
+
+namespace trace_analyzer {
+
+// TraceEvent
+
+TraceEvent::TraceEvent()
+    : thread(0, 0),
+      timestamp(0),
+      duration(0),
+      phase(TRACE_EVENT_PHASE_BEGIN),
+      other_event(NULL) {
+}
+
+TraceEvent::~TraceEvent() {
+}
+
+bool TraceEvent::SetFromJSON(const base::Value* event_value) {
+  if (event_value->GetType() != base::Value::TYPE_DICTIONARY) {
+    LOG(ERROR) << "Value must be TYPE_DICTIONARY";
+    return false;
+  }
+  const base::DictionaryValue* dictionary =
+      static_cast<const base::DictionaryValue*>(event_value);
+
+  std::string phase_str;
+  const base::DictionaryValue* args = NULL;
+
+  if (!dictionary->GetString("ph", &phase_str)) {
+    LOG(ERROR) << "ph is missing from TraceEvent JSON";
+    return false;
+  }
+
+  phase = *phase_str.data();
+
+  bool may_have_duration = (phase == TRACE_EVENT_PHASE_COMPLETE);
+  bool require_origin = (phase != TRACE_EVENT_PHASE_METADATA);
+  bool require_id = (phase == TRACE_EVENT_PHASE_ASYNC_BEGIN ||
+                     phase == TRACE_EVENT_PHASE_ASYNC_STEP_INTO ||
+                     phase == TRACE_EVENT_PHASE_ASYNC_STEP_PAST ||
+                     phase == TRACE_EVENT_PHASE_ASYNC_END);
+
+  if (require_origin && !dictionary->GetInteger("pid", &thread.process_id)) {
+    LOG(ERROR) << "pid is missing from TraceEvent JSON";
+    return false;
+  }
+  if (require_origin && !dictionary->GetInteger("tid", &thread.thread_id)) {
+    LOG(ERROR) << "tid is missing from TraceEvent JSON";
+    return false;
+  }
+  if (require_origin && !dictionary->GetDouble("ts", &timestamp)) {
+    LOG(ERROR) << "ts is missing from TraceEvent JSON";
+    return false;
+  }
+  if (may_have_duration) {
+    dictionary->GetDouble("dur", &duration);
+  }
+  if (!dictionary->GetString("cat", &category)) {
+    LOG(ERROR) << "cat is missing from TraceEvent JSON";
+    return false;
+  }
+  if (!dictionary->GetString("name", &name)) {
+    LOG(ERROR) << "name is missing from TraceEvent JSON";
+    return false;
+  }
+  if (!dictionary->GetDictionary("args", &args)) {
+    LOG(ERROR) << "args is missing from TraceEvent JSON";
+    return false;
+  }
+  if (require_id && !dictionary->GetString("id", &id)) {
+    LOG(ERROR) << "id is missing from ASYNC_BEGIN/ASYNC_END TraceEvent JSON";
+    return false;
+  }
+
+  // For each argument, copy the type and create a trace_analyzer::TraceValue.
+  for (base::DictionaryValue::Iterator it(*args); !it.IsAtEnd();
+       it.Advance()) {
+    std::string str;
+    bool boolean = false;
+    int int_num = 0;
+    double double_num = 0.0;
+    if (it.value().GetAsString(&str)) {
+      arg_strings[it.key()] = str;
+    } else if (it.value().GetAsInteger(&int_num)) {
+      arg_numbers[it.key()] = static_cast<double>(int_num);
+    } else if (it.value().GetAsBoolean(&boolean)) {
+      arg_numbers[it.key()] = static_cast<double>(boolean ? 1 : 0);
+    } else if (it.value().GetAsDouble(&double_num)) {
+      arg_numbers[it.key()] = double_num;
+    } else {
+      LOG(WARNING) << "Value type of argument is not supported: " <<
+          static_cast<int>(it.value().GetType());
+      continue;  // Skip non-supported arguments.
+    }
+  }
+
+  return true;
+}
+
+double TraceEvent::GetAbsTimeToOtherEvent() const {
+  return fabs(other_event->timestamp - timestamp);
+}
+
+bool TraceEvent::GetArgAsString(const std::string& name,
+                                std::string* arg) const {
+  std::map<std::string, std::string>::const_iterator i = arg_strings.find(name);
+  if (i != arg_strings.end()) {
+    *arg = i->second;
+    return true;
+  }
+  return false;
+}
+
+bool TraceEvent::GetArgAsNumber(const std::string& name,
+                                double* arg) const {
+  std::map<std::string, double>::const_iterator i = arg_numbers.find(name);
+  if (i != arg_numbers.end()) {
+    *arg = i->second;
+    return true;
+  }
+  return false;
+}
+
+bool TraceEvent::HasStringArg(const std::string& name) const {
+  return (arg_strings.find(name) != arg_strings.end());
+}
+
+bool TraceEvent::HasNumberArg(const std::string& name) const {
+  return (arg_numbers.find(name) != arg_numbers.end());
+}
+
+std::string TraceEvent::GetKnownArgAsString(const std::string& name) const {
+  std::string arg_string;
+  bool result = GetArgAsString(name, &arg_string);
+  DCHECK(result);
+  return arg_string;
+}
+
+double TraceEvent::GetKnownArgAsDouble(const std::string& name) const {
+  double arg_double = 0;
+  bool result = GetArgAsNumber(name, &arg_double);
+  DCHECK(result);
+  return arg_double;
+}
+
+int TraceEvent::GetKnownArgAsInt(const std::string& name) const {
+  double arg_double = 0;
+  bool result = GetArgAsNumber(name, &arg_double);
+  DCHECK(result);
+  return static_cast<int>(arg_double);
+}
+
+bool TraceEvent::GetKnownArgAsBool(const std::string& name) const {
+  double arg_double = 0;
+  bool result = GetArgAsNumber(name, &arg_double);
+  DCHECK(result);
+  return (arg_double != 0.0);
+}
+
+// QueryNode
+
+QueryNode::QueryNode(const Query& query) : query_(query) {
+}
+
+QueryNode::~QueryNode() {
+}
+
+// Query
+
+Query::Query(TraceEventMember member)
+    : type_(QUERY_EVENT_MEMBER),
+      operator_(OP_INVALID),
+      member_(member),
+      number_(0),
+      is_pattern_(false) {
+}
+
+Query::Query(TraceEventMember member, const std::string& arg_name)
+    : type_(QUERY_EVENT_MEMBER),
+      operator_(OP_INVALID),
+      member_(member),
+      number_(0),
+      string_(arg_name),
+      is_pattern_(false) {
+}
+
+Query::Query(const Query& query)
+    : type_(query.type_),
+      operator_(query.operator_),
+      left_(query.left_),
+      right_(query.right_),
+      member_(query.member_),
+      number_(query.number_),
+      string_(query.string_),
+      is_pattern_(query.is_pattern_) {
+}
+
+Query::~Query() {
+}
+
+Query Query::String(const std::string& str) {
+  return Query(str);
+}
+
+Query Query::Double(double num) {
+  return Query(num);
+}
+
+Query Query::Int(int32 num) {
+  return Query(static_cast<double>(num));
+}
+
+Query Query::Uint(uint32 num) {
+  return Query(static_cast<double>(num));
+}
+
+Query Query::Bool(bool boolean) {
+  return Query(boolean ? 1.0 : 0.0);
+}
+
+Query Query::Phase(char phase) {
+  return Query(static_cast<double>(phase));
+}
+
+Query Query::Pattern(const std::string& pattern) {
+  Query query(pattern);
+  query.is_pattern_ = true;
+  return query;
+}
+
+bool Query::Evaluate(const TraceEvent& event) const {
+  // First check for values that can convert to bool.
+
+  // double is true if != 0:
+  double bool_value = 0.0;
+  bool is_bool = GetAsDouble(event, &bool_value);
+  if (is_bool)
+    return (bool_value != 0.0);
+
+  // string is true if it is non-empty:
+  std::string str_value;
+  bool is_str = GetAsString(event, &str_value);
+  if (is_str)
+    return !str_value.empty();
+
+  DCHECK_EQ(QUERY_BOOLEAN_OPERATOR, type_)
+      << "Invalid query: missing boolean expression";
+  DCHECK(left_.get());
+  DCHECK(right_.get() || is_unary_operator());
+
+  if (is_comparison_operator()) {
+    DCHECK(left().is_value() && right().is_value())
+        << "Invalid query: comparison operator used between event member and "
+           "value.";
+    bool compare_result = false;
+    if (CompareAsDouble(event, &compare_result))
+      return compare_result;
+    if (CompareAsString(event, &compare_result))
+      return compare_result;
+    return false;
+  }
+  // It's a logical operator.
+  switch (operator_) {
+    case OP_AND:
+      return left().Evaluate(event) && right().Evaluate(event);
+    case OP_OR:
+      return left().Evaluate(event) || right().Evaluate(event);
+    case OP_NOT:
+      return !left().Evaluate(event);
+    default:
+      NOTREACHED();
+      return false;
+  }
+}
+
+bool Query::CompareAsDouble(const TraceEvent& event, bool* result) const {
+  double lhs, rhs;
+  if (!left().GetAsDouble(event, &lhs) || !right().GetAsDouble(event, &rhs))
+    return false;
+  switch (operator_) {
+    case OP_EQ:
+      *result = (lhs == rhs);
+      return true;
+    case OP_NE:
+      *result = (lhs != rhs);
+      return true;
+    case OP_LT:
+      *result = (lhs < rhs);
+      return true;
+    case OP_LE:
+      *result = (lhs <= rhs);
+      return true;
+    case OP_GT:
+      *result = (lhs > rhs);
+      return true;
+    case OP_GE:
+      *result = (lhs >= rhs);
+      return true;
+    default:
+      NOTREACHED();
+      return false;
+  }
+}
+
+bool Query::CompareAsString(const TraceEvent& event, bool* result) const {
+  std::string lhs, rhs;
+  if (!left().GetAsString(event, &lhs) || !right().GetAsString(event, &rhs))
+    return false;
+  switch (operator_) {
+    case OP_EQ:
+      if (right().is_pattern_)
+        *result = MatchPattern(lhs, rhs);
+      else if (left().is_pattern_)
+        *result = MatchPattern(rhs, lhs);
+      else
+        *result = (lhs == rhs);
+      return true;
+    case OP_NE:
+      if (right().is_pattern_)
+        *result = !MatchPattern(lhs, rhs);
+      else if (left().is_pattern_)
+        *result = !MatchPattern(rhs, lhs);
+      else
+        *result = (lhs != rhs);
+      return true;
+    case OP_LT:
+      *result = (lhs < rhs);
+      return true;
+    case OP_LE:
+      *result = (lhs <= rhs);
+      return true;
+    case OP_GT:
+      *result = (lhs > rhs);
+      return true;
+    case OP_GE:
+      *result = (lhs >= rhs);
+      return true;
+    default:
+      NOTREACHED();
+      return false;
+  }
+}
+
+bool Query::EvaluateArithmeticOperator(const TraceEvent& event,
+                                       double* num) const {
+  DCHECK_EQ(QUERY_ARITHMETIC_OPERATOR, type_);
+  DCHECK(left_.get());
+  DCHECK(right_.get() || is_unary_operator());
+
+  double lhs = 0, rhs = 0;
+  if (!left().GetAsDouble(event, &lhs))
+    return false;
+  if (!is_unary_operator() && !right().GetAsDouble(event, &rhs))
+    return false;
+
+  switch (operator_) {
+    case OP_ADD:
+      *num = lhs + rhs;
+      return true;
+    case OP_SUB:
+      *num = lhs - rhs;
+      return true;
+    case OP_MUL:
+      *num = lhs * rhs;
+      return true;
+    case OP_DIV:
+      *num = lhs / rhs;
+      return true;
+    case OP_MOD:
+      *num = static_cast<double>(static_cast<int64>(lhs) %
+                                 static_cast<int64>(rhs));
+      return true;
+    case OP_NEGATE:
+      *num = -lhs;
+      return true;
+    default:
+      NOTREACHED();
+      return false;
+  }
+}
+
+bool Query::GetAsDouble(const TraceEvent& event, double* num) const {
+  switch (type_) {
+    case QUERY_ARITHMETIC_OPERATOR:
+      return EvaluateArithmeticOperator(event, num);
+    case QUERY_EVENT_MEMBER:
+      return GetMemberValueAsDouble(event, num);
+    case QUERY_NUMBER:
+      *num = number_;
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool Query::GetAsString(const TraceEvent& event, std::string* str) const {
+  switch (type_) {
+    case QUERY_EVENT_MEMBER:
+      return GetMemberValueAsString(event, str);
+    case QUERY_STRING:
+      *str = string_;
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool Query::GetMemberValueAsDouble(const TraceEvent& event,
+                                   double* num) const {
+  DCHECK_EQ(QUERY_EVENT_MEMBER, type_);
+
+  // This could be a request for a member of |event| or a member of |event|'s
+  // associated event. Store the target event in the_event:
+  const TraceEvent* the_event = (member_ < OTHER_PID) ?
+      &event : event.other_event;
+
+  // Request for member of associated event, but there is no associated event.
+  if (!the_event)
+    return false;
+
+  switch (member_) {
+    case EVENT_PID:
+    case OTHER_PID:
+      *num = static_cast<double>(the_event->thread.process_id);
+      return true;
+    case EVENT_TID:
+    case OTHER_TID:
+      *num = static_cast<double>(the_event->thread.thread_id);
+      return true;
+    case EVENT_TIME:
+    case OTHER_TIME:
+      *num = the_event->timestamp;
+      return true;
+    case EVENT_DURATION:
+      if (!the_event->has_other_event())
+        return false;
+      *num = the_event->GetAbsTimeToOtherEvent();
+      return true;
+    case EVENT_COMPLETE_DURATION:
+      if (the_event->phase != TRACE_EVENT_PHASE_COMPLETE)
+        return false;
+      *num = the_event->duration;
+      return true;
+    case EVENT_PHASE:
+    case OTHER_PHASE:
+      *num = static_cast<double>(the_event->phase);
+      return true;
+    case EVENT_HAS_STRING_ARG:
+    case OTHER_HAS_STRING_ARG:
+      *num = (the_event->HasStringArg(string_) ? 1.0 : 0.0);
+      return true;
+    case EVENT_HAS_NUMBER_ARG:
+    case OTHER_HAS_NUMBER_ARG:
+      *num = (the_event->HasNumberArg(string_) ? 1.0 : 0.0);
+      return true;
+    case EVENT_ARG:
+    case OTHER_ARG: {
+      // Search for the argument name and return its value if found.
+      std::map<std::string, double>::const_iterator num_i =
+          the_event->arg_numbers.find(string_);
+      if (num_i == the_event->arg_numbers.end())
+        return false;
+      *num = num_i->second;
+      return true;
+    }
+    case EVENT_HAS_OTHER:
+      // return 1.0 (true) if the other event exists
+      *num = event.other_event ? 1.0 : 0.0;
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool Query::GetMemberValueAsString(const TraceEvent& event,
+                                   std::string* str) const {
+  DCHECK_EQ(QUERY_EVENT_MEMBER, type_);
+
+  // This could be a request for a member of |event| or a member of |event|'s
+  // associated event. Store the target event in the_event:
+  const TraceEvent* the_event = (member_ < OTHER_PID) ?
+      &event : event.other_event;
+
+  // Request for member of associated event, but there is no associated event.
+  if (!the_event)
+    return false;
+
+  switch (member_) {
+    case EVENT_CATEGORY:
+    case OTHER_CATEGORY:
+      *str = the_event->category;
+      return true;
+    case EVENT_NAME:
+    case OTHER_NAME:
+      *str = the_event->name;
+      return true;
+    case EVENT_ID:
+    case OTHER_ID:
+      *str = the_event->id;
+      return true;
+    case EVENT_ARG:
+    case OTHER_ARG: {
+      // Search for the argument name and return its value if found.
+      std::map<std::string, std::string>::const_iterator str_i =
+          the_event->arg_strings.find(string_);
+      if (str_i == the_event->arg_strings.end())
+        return false;
+      *str = str_i->second;
+      return true;
+    }
+    default:
+      return false;
+  }
+}
+
+Query::Query(const std::string& str)
+    : type_(QUERY_STRING),
+      operator_(OP_INVALID),
+      member_(EVENT_INVALID),
+      number_(0),
+      string_(str),
+      is_pattern_(false) {
+}
+
+Query::Query(double num)
+    : type_(QUERY_NUMBER),
+      operator_(OP_INVALID),
+      member_(EVENT_INVALID),
+      number_(num),
+      is_pattern_(false) {
+}
+const Query& Query::left() const {
+  return left_->query();
+}
+
+const Query& Query::right() const {
+  return right_->query();
+}
+
+Query Query::operator==(const Query& rhs) const {
+  return Query(*this, rhs, OP_EQ);
+}
+
+Query Query::operator!=(const Query& rhs) const {
+  return Query(*this, rhs, OP_NE);
+}
+
+Query Query::operator<(const Query& rhs) const {
+  return Query(*this, rhs, OP_LT);
+}
+
+Query Query::operator<=(const Query& rhs) const {
+  return Query(*this, rhs, OP_LE);
+}
+
+Query Query::operator>(const Query& rhs) const {
+  return Query(*this, rhs, OP_GT);
+}
+
+Query Query::operator>=(const Query& rhs) const {
+  return Query(*this, rhs, OP_GE);
+}
+
+Query Query::operator&&(const Query& rhs) const {
+  return Query(*this, rhs, OP_AND);
+}
+
+Query Query::operator||(const Query& rhs) const {
+  return Query(*this, rhs, OP_OR);
+}
+
+Query Query::operator!() const {
+  return Query(*this, OP_NOT);
+}
+
+Query Query::operator+(const Query& rhs) const {
+  return Query(*this, rhs, OP_ADD);
+}
+
+Query Query::operator-(const Query& rhs) const {
+  return Query(*this, rhs, OP_SUB);
+}
+
+Query Query::operator*(const Query& rhs) const {
+  return Query(*this, rhs, OP_MUL);
+}
+
+Query Query::operator/(const Query& rhs) const {
+  return Query(*this, rhs, OP_DIV);
+}
+
+Query Query::operator%(const Query& rhs) const {
+  return Query(*this, rhs, OP_MOD);
+}
+
+Query Query::operator-() const {
+  return Query(*this, OP_NEGATE);
+}
+
+
+Query::Query(const Query& left, const Query& right, Operator binary_op)
+    : operator_(binary_op),
+      left_(new QueryNode(left)),
+      right_(new QueryNode(right)),
+      member_(EVENT_INVALID),
+      number_(0) {
+  type_ = (binary_op < OP_ADD ?
+           QUERY_BOOLEAN_OPERATOR : QUERY_ARITHMETIC_OPERATOR);
+}
+
+Query::Query(const Query& left, Operator unary_op)
+    : operator_(unary_op),
+      left_(new QueryNode(left)),
+      member_(EVENT_INVALID),
+      number_(0) {
+  type_ = (unary_op < OP_ADD ?
+           QUERY_BOOLEAN_OPERATOR : QUERY_ARITHMETIC_OPERATOR);
+}
+
+namespace {
+
+// Search |events| for |query| and add matches to |output|.
+size_t FindMatchingEvents(const std::vector<TraceEvent>& events,
+                          const Query& query,
+                          TraceEventVector* output,
+                          bool ignore_metadata_events) {
+  for (size_t i = 0; i < events.size(); ++i) {
+    if (ignore_metadata_events && events[i].phase == TRACE_EVENT_PHASE_METADATA)
+      continue;
+    if (query.Evaluate(events[i]))
+      output->push_back(&events[i]);
+  }
+  return output->size();
+}
+
+bool ParseEventsFromJson(const std::string& json,
+                         std::vector<TraceEvent>* output) {
+  scoped_ptr<base::Value> root;
+  root.reset(base::JSONReader::DeprecatedRead(json));
+
+  base::ListValue* root_list = NULL;
+  if (!root.get() || !root->GetAsList(&root_list))
+    return false;
+
+  for (size_t i = 0; i < root_list->GetSize(); ++i) {
+    base::Value* item = NULL;
+    if (root_list->Get(i, &item)) {
+      TraceEvent event;
+      if (event.SetFromJSON(item))
+        output->push_back(event);
+      else
+        return false;
+    }
+  }
+
+  return true;
+}
+
+}  // namespace
+
+// TraceAnalyzer
+
+TraceAnalyzer::TraceAnalyzer()
+    : ignore_metadata_events_(false),
+      allow_assocation_changes_(true) {}
+
+TraceAnalyzer::~TraceAnalyzer() {
+}
+
+// static
+TraceAnalyzer* TraceAnalyzer::Create(const std::string& json_events) {
+  scoped_ptr<TraceAnalyzer> analyzer(new TraceAnalyzer());
+  if (analyzer->SetEvents(json_events))
+    return analyzer.release();
+  return NULL;
+}
+
+bool TraceAnalyzer::SetEvents(const std::string& json_events) {
+  raw_events_.clear();
+  if (!ParseEventsFromJson(json_events, &raw_events_))
+    return false;
+  std::stable_sort(raw_events_.begin(), raw_events_.end());
+  ParseMetadata();
+  return true;
+}
+
+void TraceAnalyzer::AssociateBeginEndEvents() {
+  using trace_analyzer::Query;
+
+  Query begin(Query::EventPhaseIs(TRACE_EVENT_PHASE_BEGIN));
+  Query end(Query::EventPhaseIs(TRACE_EVENT_PHASE_END));
+  Query match(Query::EventName() == Query::OtherName() &&
+              Query::EventCategory() == Query::OtherCategory() &&
+              Query::EventTid() == Query::OtherTid() &&
+              Query::EventPid() == Query::OtherPid());
+
+  AssociateEvents(begin, end, match);
+}
+
+void TraceAnalyzer::AssociateAsyncBeginEndEvents() {
+  using trace_analyzer::Query;
+
+  Query begin(
+      Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_BEGIN) ||
+      Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_STEP_INTO) ||
+      Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_STEP_PAST));
+  Query end(Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_END) ||
+            Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_STEP_INTO) ||
+            Query::EventPhaseIs(TRACE_EVENT_PHASE_ASYNC_STEP_PAST));
+  Query match(Query::EventName() == Query::OtherName() &&
+              Query::EventCategory() == Query::OtherCategory() &&
+              Query::EventId() == Query::OtherId());
+
+  AssociateEvents(begin, end, match);
+}
+
+void TraceAnalyzer::AssociateEvents(const Query& first,
+                                    const Query& second,
+                                    const Query& match) {
+  DCHECK(allow_assocation_changes_)
+      << "AssociateEvents not allowed after FindEvents";
+
+  // Search for matching begin/end event pairs. When a matching end is found,
+  // it is associated with the begin event.
+  std::vector<TraceEvent*> begin_stack;
+  for (size_t event_index = 0; event_index < raw_events_.size();
+       ++event_index) {
+
+    TraceEvent& this_event = raw_events_[event_index];
+
+    if (second.Evaluate(this_event)) {
+      // Search stack for matching begin, starting from end.
+      for (int stack_index = static_cast<int>(begin_stack.size()) - 1;
+           stack_index >= 0; --stack_index) {
+        TraceEvent& begin_event = *begin_stack[stack_index];
+
+        // Temporarily set other to test against the match query.
+        const TraceEvent* other_backup = begin_event.other_event;
+        begin_event.other_event = &this_event;
+        if (match.Evaluate(begin_event)) {
+          // Found a matching begin/end pair.
+          // Erase the matching begin event index from the stack.
+          begin_stack.erase(begin_stack.begin() + stack_index);
+          break;
+        }
+
+        // Not a match, restore original other and continue.
+        begin_event.other_event = other_backup;
+      }
+    }
+    // Even if this_event is a |second| event that has matched an earlier
+    // |first| event, it can still also be a |first| event and be associated
+    // with a later |second| event.
+    if (first.Evaluate(this_event)) {
+      begin_stack.push_back(&this_event);
+    }
+  }
+}
+
+void TraceAnalyzer::MergeAssociatedEventArgs() {
+  for (size_t i = 0; i < raw_events_.size(); ++i) {
+    // Merge all associated events with the first event.
+    const TraceEvent* other = raw_events_[i].other_event;
+    // Avoid looping by keeping set of encountered TraceEvents.
+    std::set<const TraceEvent*> encounters;
+    encounters.insert(&raw_events_[i]);
+    while (other && encounters.find(other) == encounters.end()) {
+      encounters.insert(other);
+      raw_events_[i].arg_numbers.insert(
+          other->arg_numbers.begin(),
+          other->arg_numbers.end());
+      raw_events_[i].arg_strings.insert(
+          other->arg_strings.begin(),
+          other->arg_strings.end());
+      other = other->other_event;
+    }
+  }
+}
+
+size_t TraceAnalyzer::FindEvents(const Query& query, TraceEventVector* output) {
+  allow_assocation_changes_ = false;
+  output->clear();
+  return FindMatchingEvents(
+      raw_events_, query, output, ignore_metadata_events_);
+}
+
+const TraceEvent* TraceAnalyzer::FindFirstOf(const Query& query) {
+  TraceEventVector output;
+  if (FindEvents(query, &output) > 0)
+    return output.front();
+  return NULL;
+}
+
+const TraceEvent* TraceAnalyzer::FindLastOf(const Query& query) {
+  TraceEventVector output;
+  if (FindEvents(query, &output) > 0)
+    return output.back();
+  return NULL;
+}
+
+const std::string& TraceAnalyzer::GetThreadName(
+    const TraceEvent::ProcessThreadID& thread) {
+  // If thread is not found, just add and return empty string.
+  return thread_names_[thread];
+}
+
+void TraceAnalyzer::ParseMetadata() {
+  for (size_t i = 0; i < raw_events_.size(); ++i) {
+    TraceEvent& this_event = raw_events_[i];
+    // Check for thread name metadata.
+    if (this_event.phase != TRACE_EVENT_PHASE_METADATA ||
+        this_event.name != "thread_name")
+      continue;
+    std::map<std::string, std::string>::const_iterator string_it =
+        this_event.arg_strings.find("name");
+    if (string_it != this_event.arg_strings.end())
+      thread_names_[this_event.thread] = string_it->second;
+  }
+}
+
+// TraceEventVector utility functions.
+
+bool GetRateStats(const TraceEventVector& events,
+                  RateStats* stats,
+                  const RateStatsOptions* options) {
+  DCHECK(stats);
+  // Need at least 3 events to calculate rate stats.
+  const size_t kMinEvents = 3;
+  if (events.size() < kMinEvents) {
+    LOG(ERROR) << "Not enough events: " << events.size();
+    return false;
+  }
+
+  std::vector<double> deltas;
+  size_t num_deltas = events.size() - 1;
+  for (size_t i = 0; i < num_deltas; ++i) {
+    double delta = events.at(i + 1)->timestamp - events.at(i)->timestamp;
+    if (delta < 0.0) {
+      LOG(ERROR) << "Events are out of order";
+      return false;
+    }
+    deltas.push_back(delta);
+  }
+
+  std::sort(deltas.begin(), deltas.end());
+
+  if (options) {
+    if (options->trim_min + options->trim_max > events.size() - kMinEvents) {
+      LOG(ERROR) << "Attempt to trim too many events";
+      return false;
+    }
+    deltas.erase(deltas.begin(), deltas.begin() + options->trim_min);
+    deltas.erase(deltas.end() - options->trim_max, deltas.end());
+  }
+
+  num_deltas = deltas.size();
+  double delta_sum = 0.0;
+  for (size_t i = 0; i < num_deltas; ++i)
+    delta_sum += deltas[i];
+
+  stats->min_us = *std::min_element(deltas.begin(), deltas.end());
+  stats->max_us = *std::max_element(deltas.begin(), deltas.end());
+  stats->mean_us = delta_sum / static_cast<double>(num_deltas);
+
+  double sum_mean_offsets_squared = 0.0;
+  for (size_t i = 0; i < num_deltas; ++i) {
+    double offset = fabs(deltas[i] - stats->mean_us);
+    sum_mean_offsets_squared += offset * offset;
+  }
+  stats->standard_deviation_us =
+      sqrt(sum_mean_offsets_squared / static_cast<double>(num_deltas - 1));
+
+  return true;
+}
+
+bool FindFirstOf(const TraceEventVector& events,
+                 const Query& query,
+                 size_t position,
+                 size_t* return_index) {
+  DCHECK(return_index);
+  for (size_t i = position; i < events.size(); ++i) {
+    if (query.Evaluate(*events[i])) {
+      *return_index = i;
+      return true;
+    }
+  }
+  return false;
+}
+
+bool FindLastOf(const TraceEventVector& events,
+                const Query& query,
+                size_t position,
+                size_t* return_index) {
+  DCHECK(return_index);
+  for (size_t i = std::min(position + 1, events.size()); i != 0; --i) {
+    if (query.Evaluate(*events[i - 1])) {
+      *return_index = i - 1;
+      return true;
+    }
+  }
+  return false;
+}
+
+bool FindClosest(const TraceEventVector& events,
+                 const Query& query,
+                 size_t position,
+                 size_t* return_closest,
+                 size_t* return_second_closest) {
+  DCHECK(return_closest);
+  if (events.empty() || position >= events.size())
+    return false;
+  size_t closest = events.size();
+  size_t second_closest = events.size();
+  for (size_t i = 0; i < events.size(); ++i) {
+    if (!query.Evaluate(*events.at(i)))
+      continue;
+    if (closest == events.size()) {
+      closest = i;
+      continue;
+    }
+    if (fabs(events.at(i)->timestamp - events.at(position)->timestamp) <
+        fabs(events.at(closest)->timestamp - events.at(position)->timestamp)) {
+      second_closest = closest;
+      closest = i;
+    } else if (second_closest == events.size()) {
+      second_closest = i;
+    }
+  }
+
+  if (closest < events.size() &&
+      (!return_second_closest || second_closest < events.size())) {
+    *return_closest = closest;
+    if (return_second_closest)
+      *return_second_closest = second_closest;
+    return true;
+  }
+
+  return false;
+}
+
+size_t CountMatches(const TraceEventVector& events,
+                    const Query& query,
+                    size_t begin_position,
+                    size_t end_position) {
+  if (begin_position >= events.size())
+    return 0u;
+  end_position = (end_position < events.size()) ? end_position : events.size();
+  size_t count = 0u;
+  for (size_t i = begin_position; i < end_position; ++i) {
+    if (query.Evaluate(*events.at(i)))
+      ++count;
+  }
+  return count;
+}
+
+}  // namespace trace_analyzer
diff --git a/base/test/trace_event_analyzer.h b/base/test/trace_event_analyzer.h
new file mode 100644
index 0000000..57ff2b5
--- /dev/null
+++ b/base/test/trace_event_analyzer.h
@@ -0,0 +1,706 @@
+// Copyright (c) 2012 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.
+
+// Use trace_analyzer::Query and trace_analyzer::TraceAnalyzer to search for
+// specific trace events that were generated by the trace_event.h API.
+//
+// Basic procedure:
+// - Get trace events JSON string from base::trace_event::TraceLog.
+// - Create TraceAnalyzer with JSON string.
+// - Call TraceAnalyzer::AssociateBeginEndEvents (optional).
+// - Call TraceAnalyzer::AssociateEvents (zero or more times).
+// - Call TraceAnalyzer::FindEvents with queries to find specific events.
+//
+// A Query is a boolean expression tree that evaluates to true or false for a
+// given trace event. Queries can be combined into a tree using boolean,
+// arithmetic and comparison operators that refer to data of an individual trace
+// event.
+//
+// The events are returned as trace_analyzer::TraceEvent objects.
+// TraceEvent contains a single trace event's data, as well as a pointer to
+// a related trace event. The related trace event is typically the matching end
+// of a begin event or the matching begin of an end event.
+//
+// The following examples use this basic setup code to construct TraceAnalyzer
+// with the json trace string retrieved from TraceLog and construct an event
+// vector for retrieving events:
+//
+// TraceAnalyzer analyzer(json_events);
+// TraceEventVector events;
+//
+// EXAMPLE 1: Find events named "my_event".
+//
+// analyzer.FindEvents(Query(EVENT_NAME) == "my_event", &events);
+//
+// EXAMPLE 2: Find begin events named "my_event" with duration > 1 second.
+//
+// Query q = (Query(EVENT_NAME) == Query::String("my_event") &&
+//            Query(EVENT_PHASE) == Query::Phase(TRACE_EVENT_PHASE_BEGIN) &&
+//            Query(EVENT_DURATION) > Query::Double(1000000.0));
+// analyzer.FindEvents(q, &events);
+//
+// EXAMPLE 3: Associating event pairs across threads.
+//
+// If the test needs to analyze something that starts and ends on different
+// threads, the test needs to use INSTANT events. The typical procedure is to
+// specify the same unique ID as a TRACE_EVENT argument on both the start and
+// finish INSTANT events. Then use the following procedure to associate those
+// events.
+//
+// Step 1: instrument code with custom begin/end trace events.
+//   [Thread 1 tracing code]
+//   TRACE_EVENT_INSTANT1("test_latency", "timing1_begin", "id", 3);
+//   [Thread 2 tracing code]
+//   TRACE_EVENT_INSTANT1("test_latency", "timing1_end", "id", 3);
+//
+// Step 2: associate these custom begin/end pairs.
+//   Query begin(Query(EVENT_NAME) == Query::String("timing1_begin"));
+//   Query end(Query(EVENT_NAME) == Query::String("timing1_end"));
+//   Query match(Query(EVENT_ARG, "id") == Query(OTHER_ARG, "id"));
+//   analyzer.AssociateEvents(begin, end, match);
+//
+// Step 3: search for "timing1_begin" events with existing other event.
+//   Query q = (Query(EVENT_NAME) == Query::String("timing1_begin") &&
+//              Query(EVENT_HAS_OTHER));
+//   analyzer.FindEvents(q, &events);
+//
+// Step 4: analyze events, such as checking durations.
+//   for (size_t i = 0; i < events.size(); ++i) {
+//     double duration;
+//     EXPECT_TRUE(events[i].GetAbsTimeToOtherEvent(&duration));
+//     EXPECT_LT(duration, 1000000.0/60.0); // expect less than 1/60 second.
+//   }
+
+
+#ifndef BASE_TEST_TRACE_EVENT_ANALYZER_H_
+#define BASE_TEST_TRACE_EVENT_ANALYZER_H_
+
+#include <map>
+
+#include "base/memory/ref_counted.h"
+#include "base/trace_event/trace_event.h"
+
+namespace base {
+class Value;
+}
+
+namespace trace_analyzer {
+class QueryNode;
+
+// trace_analyzer::TraceEvent is a more convenient form of the
+// base::trace_event::TraceEvent class to make tracing-based tests easier to
+// write.
+struct TraceEvent {
+  // ProcessThreadID contains a Process ID and Thread ID.
+  struct ProcessThreadID {
+    ProcessThreadID() : process_id(0), thread_id(0) {}
+    ProcessThreadID(int process_id, int thread_id)
+        : process_id(process_id), thread_id(thread_id) {}
+    bool operator< (const ProcessThreadID& rhs) const {
+      if (process_id != rhs.process_id)
+        return process_id < rhs.process_id;
+      return thread_id < rhs.thread_id;
+    }
+    int process_id;
+    int thread_id;
+  };
+
+  TraceEvent();
+  ~TraceEvent();
+
+  bool SetFromJSON(const base::Value* event_value) WARN_UNUSED_RESULT;
+
+  bool operator< (const TraceEvent& rhs) const {
+    return timestamp < rhs.timestamp;
+  }
+
+  bool has_other_event() const { return other_event; }
+
+  // Returns absolute duration in microseconds between this event and other
+  // event. Must have already verified that other_event exists by
+  // Query(EVENT_HAS_OTHER) or by calling has_other_event().
+  double GetAbsTimeToOtherEvent() const;
+
+  // Return the argument value if it exists and it is a string.
+  bool GetArgAsString(const std::string& name, std::string* arg) const;
+  // Return the argument value if it exists and it is a number.
+  bool GetArgAsNumber(const std::string& name, double* arg) const;
+
+  // Check if argument exists and is string.
+  bool HasStringArg(const std::string& name) const;
+  // Check if argument exists and is number (double, int or bool).
+  bool HasNumberArg(const std::string& name) const;
+
+  // Get known existing arguments as specific types.
+  // Useful when you have already queried the argument with
+  // Query(HAS_NUMBER_ARG) or Query(HAS_STRING_ARG).
+  std::string GetKnownArgAsString(const std::string& name) const;
+  double GetKnownArgAsDouble(const std::string& name) const;
+  int GetKnownArgAsInt(const std::string& name) const;
+  bool GetKnownArgAsBool(const std::string& name) const;
+
+  // Process ID and Thread ID.
+  ProcessThreadID thread;
+
+  // Time since epoch in microseconds.
+  // Stored as double to match its JSON representation.
+  double timestamp;
+
+  double duration;
+
+  char phase;
+
+  std::string category;
+
+  std::string name;
+
+  std::string id;
+
+  // All numbers and bool values from TraceEvent args are cast to double.
+  // bool becomes 1.0 (true) or 0.0 (false).
+  std::map<std::string, double> arg_numbers;
+
+  std::map<std::string, std::string> arg_strings;
+
+  // The other event associated with this event (or NULL).
+  const TraceEvent* other_event;
+};
+
+typedef std::vector<const TraceEvent*> TraceEventVector;
+
+class Query {
+ public:
+  Query(const Query& query);
+
+  ~Query();
+
+  ////////////////////////////////////////////////////////////////
+  // Query literal values
+
+  // Compare with the given string.
+  static Query String(const std::string& str);
+
+  // Compare with the given number.
+  static Query Double(double num);
+  static Query Int(int32 num);
+  static Query Uint(uint32 num);
+
+  // Compare with the given bool.
+  static Query Bool(bool boolean);
+
+  // Compare with the given phase.
+  static Query Phase(char phase);
+
+  // Compare with the given string pattern. Only works with == and != operators.
+  // Example: Query(EVENT_NAME) == Query::Pattern("MyEvent*")
+  static Query Pattern(const std::string& pattern);
+
+  ////////////////////////////////////////////////////////////////
+  // Query event members
+
+  static Query EventPid() { return Query(EVENT_PID); }
+
+  static Query EventTid() { return Query(EVENT_TID); }
+
+  // Return the timestamp of the event in microseconds since epoch.
+  static Query EventTime() { return Query(EVENT_TIME); }
+
+  // Return the absolute time between event and other event in microseconds.
+  // Only works if Query::EventHasOther() == true.
+  static Query EventDuration() { return Query(EVENT_DURATION); }
+
+  // Return the duration of a COMPLETE event.
+  static Query EventCompleteDuration() {
+    return Query(EVENT_COMPLETE_DURATION);
+  }
+
+  static Query EventPhase() { return Query(EVENT_PHASE); }
+
+  static Query EventCategory() { return Query(EVENT_CATEGORY); }
+
+  static Query EventName() { return Query(EVENT_NAME); }
+
+  static Query EventId() { return Query(EVENT_ID); }
+
+  static Query EventPidIs(int process_id) {
+    return Query(EVENT_PID) == Query::Int(process_id);
+  }
+
+  static Query EventTidIs(int thread_id) {
+    return Query(EVENT_TID) == Query::Int(thread_id);
+  }
+
+  static Query EventThreadIs(const TraceEvent::ProcessThreadID& thread) {
+    return EventPidIs(thread.process_id) && EventTidIs(thread.thread_id);
+  }
+
+  static Query EventTimeIs(double timestamp) {
+    return Query(EVENT_TIME) == Query::Double(timestamp);
+  }
+
+  static Query EventDurationIs(double duration) {
+    return Query(EVENT_DURATION) == Query::Double(duration);
+  }
+
+  static Query EventPhaseIs(char phase) {
+    return Query(EVENT_PHASE) == Query::Phase(phase);
+  }
+
+  static Query EventCategoryIs(const std::string& category) {
+    return Query(EVENT_CATEGORY) == Query::String(category);
+  }
+
+  static Query EventNameIs(const std::string& name) {
+    return Query(EVENT_NAME) == Query::String(name);
+  }
+
+  static Query EventIdIs(const std::string& id) {
+    return Query(EVENT_ID) == Query::String(id);
+  }
+
+  // Evaluates to true if arg exists and is a string.
+  static Query EventHasStringArg(const std::string& arg_name) {
+    return Query(EVENT_HAS_STRING_ARG, arg_name);
+  }
+
+  // Evaluates to true if arg exists and is a number.
+  // Number arguments include types double, int and bool.
+  static Query EventHasNumberArg(const std::string& arg_name) {
+    return Query(EVENT_HAS_NUMBER_ARG, arg_name);
+  }
+
+  // Evaluates to arg value (string or number).
+  static Query EventArg(const std::string& arg_name) {
+    return Query(EVENT_ARG, arg_name);
+  }
+
+  // Return true if associated event exists.
+  static Query EventHasOther() { return Query(EVENT_HAS_OTHER); }
+
+  // Access the associated other_event's members:
+
+  static Query OtherPid() { return Query(OTHER_PID); }
+
+  static Query OtherTid() { return Query(OTHER_TID); }
+
+  static Query OtherTime() { return Query(OTHER_TIME); }
+
+  static Query OtherPhase() { return Query(OTHER_PHASE); }
+
+  static Query OtherCategory() { return Query(OTHER_CATEGORY); }
+
+  static Query OtherName() { return Query(OTHER_NAME); }
+
+  static Query OtherId() { return Query(OTHER_ID); }
+
+  static Query OtherPidIs(int process_id) {
+    return Query(OTHER_PID) == Query::Int(process_id);
+  }
+
+  static Query OtherTidIs(int thread_id) {
+    return Query(OTHER_TID) == Query::Int(thread_id);
+  }
+
+  static Query OtherThreadIs(const TraceEvent::ProcessThreadID& thread) {
+    return OtherPidIs(thread.process_id) && OtherTidIs(thread.thread_id);
+  }
+
+  static Query OtherTimeIs(double timestamp) {
+    return Query(OTHER_TIME) == Query::Double(timestamp);
+  }
+
+  static Query OtherPhaseIs(char phase) {
+    return Query(OTHER_PHASE) == Query::Phase(phase);
+  }
+
+  static Query OtherCategoryIs(const std::string& category) {
+    return Query(OTHER_CATEGORY) == Query::String(category);
+  }
+
+  static Query OtherNameIs(const std::string& name) {
+    return Query(OTHER_NAME) == Query::String(name);
+  }
+
+  static Query OtherIdIs(const std::string& id) {
+    return Query(OTHER_ID) == Query::String(id);
+  }
+
+  // Evaluates to true if arg exists and is a string.
+  static Query OtherHasStringArg(const std::string& arg_name) {
+    return Query(OTHER_HAS_STRING_ARG, arg_name);
+  }
+
+  // Evaluates to true if arg exists and is a number.
+  // Number arguments include types double, int and bool.
+  static Query OtherHasNumberArg(const std::string& arg_name) {
+    return Query(OTHER_HAS_NUMBER_ARG, arg_name);
+  }
+
+  // Evaluates to arg value (string or number).
+  static Query OtherArg(const std::string& arg_name) {
+    return Query(OTHER_ARG, arg_name);
+  }
+
+  ////////////////////////////////////////////////////////////////
+  // Common queries:
+
+  // Find BEGIN events that have a corresponding END event.
+  static Query MatchBeginWithEnd() {
+    return (Query(EVENT_PHASE) == Query::Phase(TRACE_EVENT_PHASE_BEGIN)) &&
+           Query(EVENT_HAS_OTHER);
+  }
+
+  // Find COMPLETE events.
+  static Query MatchComplete() {
+    return (Query(EVENT_PHASE) == Query::Phase(TRACE_EVENT_PHASE_COMPLETE));
+  }
+
+  // Find ASYNC_BEGIN events that have a corresponding ASYNC_END event.
+  static Query MatchAsyncBeginWithNext() {
+    return (Query(EVENT_PHASE) ==
+            Query::Phase(TRACE_EVENT_PHASE_ASYNC_BEGIN)) &&
+           Query(EVENT_HAS_OTHER);
+  }
+
+  // Find BEGIN events of given |name| which also have associated END events.
+  static Query MatchBeginName(const std::string& name) {
+    return (Query(EVENT_NAME) == Query(name)) && MatchBeginWithEnd();
+  }
+
+  // Find COMPLETE events of given |name|.
+  static Query MatchCompleteName(const std::string& name) {
+    return (Query(EVENT_NAME) == Query(name)) && MatchComplete();
+  }
+
+  // Match given Process ID and Thread ID.
+  static Query MatchThread(const TraceEvent::ProcessThreadID& thread) {
+    return (Query(EVENT_PID) == Query::Int(thread.process_id)) &&
+           (Query(EVENT_TID) == Query::Int(thread.thread_id));
+  }
+
+  // Match event pair that spans multiple threads.
+  static Query MatchCrossThread() {
+    return (Query(EVENT_PID) != Query(OTHER_PID)) ||
+           (Query(EVENT_TID) != Query(OTHER_TID));
+  }
+
+  ////////////////////////////////////////////////////////////////
+  // Operators:
+
+  // Boolean operators:
+  Query operator==(const Query& rhs) const;
+  Query operator!=(const Query& rhs) const;
+  Query operator< (const Query& rhs) const;
+  Query operator<=(const Query& rhs) const;
+  Query operator> (const Query& rhs) const;
+  Query operator>=(const Query& rhs) const;
+  Query operator&&(const Query& rhs) const;
+  Query operator||(const Query& rhs) const;
+  Query operator!() const;
+
+  // Arithmetic operators:
+  // Following operators are applied to double arguments:
+  Query operator+(const Query& rhs) const;
+  Query operator-(const Query& rhs) const;
+  Query operator*(const Query& rhs) const;
+  Query operator/(const Query& rhs) const;
+  Query operator-() const;
+  // Mod operates on int64 args (doubles are casted to int64 beforehand):
+  Query operator%(const Query& rhs) const;
+
+  // Return true if the given event matches this query tree.
+  // This is a recursive method that walks the query tree.
+  bool Evaluate(const TraceEvent& event) const;
+
+ private:
+  enum TraceEventMember {
+    EVENT_INVALID,
+    EVENT_PID,
+    EVENT_TID,
+    EVENT_TIME,
+    EVENT_DURATION,
+    EVENT_COMPLETE_DURATION,
+    EVENT_PHASE,
+    EVENT_CATEGORY,
+    EVENT_NAME,
+    EVENT_ID,
+    EVENT_HAS_STRING_ARG,
+    EVENT_HAS_NUMBER_ARG,
+    EVENT_ARG,
+    EVENT_HAS_OTHER,
+    OTHER_PID,
+    OTHER_TID,
+    OTHER_TIME,
+    OTHER_PHASE,
+    OTHER_CATEGORY,
+    OTHER_NAME,
+    OTHER_ID,
+    OTHER_HAS_STRING_ARG,
+    OTHER_HAS_NUMBER_ARG,
+    OTHER_ARG,
+  };
+
+  enum Operator {
+    OP_INVALID,
+    // Boolean operators:
+    OP_EQ,
+    OP_NE,
+    OP_LT,
+    OP_LE,
+    OP_GT,
+    OP_GE,
+    OP_AND,
+    OP_OR,
+    OP_NOT,
+    // Arithmetic operators:
+    OP_ADD,
+    OP_SUB,
+    OP_MUL,
+    OP_DIV,
+    OP_MOD,
+    OP_NEGATE
+  };
+
+  enum QueryType {
+    QUERY_BOOLEAN_OPERATOR,
+    QUERY_ARITHMETIC_OPERATOR,
+    QUERY_EVENT_MEMBER,
+    QUERY_NUMBER,
+    QUERY_STRING
+  };
+
+  // Compare with the given member.
+  explicit Query(TraceEventMember member);
+
+  // Compare with the given member argument value.
+  Query(TraceEventMember member, const std::string& arg_name);
+
+  // Compare with the given string.
+  explicit Query(const std::string& str);
+
+  // Compare with the given number.
+  explicit Query(double num);
+
+  // Construct a boolean Query that returns (left <binary_op> right).
+  Query(const Query& left, const Query& right, Operator binary_op);
+
+  // Construct a boolean Query that returns (<binary_op> left).
+  Query(const Query& left, Operator unary_op);
+
+  // Try to compare left_ against right_ based on operator_.
+  // If either left or right does not convert to double, false is returned.
+  // Otherwise, true is returned and |result| is set to the comparison result.
+  bool CompareAsDouble(const TraceEvent& event, bool* result) const;
+
+  // Try to compare left_ against right_ based on operator_.
+  // If either left or right does not convert to string, false is returned.
+  // Otherwise, true is returned and |result| is set to the comparison result.
+  bool CompareAsString(const TraceEvent& event, bool* result) const;
+
+  // Attempt to convert this Query to a double. On success, true is returned
+  // and the double value is stored in |num|.
+  bool GetAsDouble(const TraceEvent& event, double* num) const;
+
+  // Attempt to convert this Query to a string. On success, true is returned
+  // and the string value is stored in |str|.
+  bool GetAsString(const TraceEvent& event, std::string* str) const;
+
+  // Evaluate this Query as an arithmetic operator on left_ and right_.
+  bool EvaluateArithmeticOperator(const TraceEvent& event,
+                                  double* num) const;
+
+  // For QUERY_EVENT_MEMBER Query: attempt to get the double value of the Query.
+  bool GetMemberValueAsDouble(const TraceEvent& event, double* num) const;
+
+  // For QUERY_EVENT_MEMBER Query: attempt to get the string value of the Query.
+  bool GetMemberValueAsString(const TraceEvent& event, std::string* num) const;
+
+  // Does this Query represent a value?
+  bool is_value() const { return type_ != QUERY_BOOLEAN_OPERATOR; }
+
+  bool is_unary_operator() const {
+    return operator_ == OP_NOT || operator_ == OP_NEGATE;
+  }
+
+  bool is_comparison_operator() const {
+    return operator_ != OP_INVALID && operator_ < OP_AND;
+  }
+
+  const Query& left() const;
+  const Query& right() const;
+
+  QueryType type_;
+  Operator operator_;
+  scoped_refptr<QueryNode> left_;
+  scoped_refptr<QueryNode> right_;
+  TraceEventMember member_;
+  double number_;
+  std::string string_;
+  bool is_pattern_;
+};
+
+// Implementation detail:
+// QueryNode allows Query to store a ref-counted query tree.
+class QueryNode : public base::RefCounted<QueryNode> {
+ public:
+  explicit QueryNode(const Query& query);
+  const Query& query() const { return query_; }
+
+ private:
+  friend class base::RefCounted<QueryNode>;
+  ~QueryNode();
+
+  Query query_;
+};
+
+// TraceAnalyzer helps tests search for trace events.
+class TraceAnalyzer {
+ public:
+  ~TraceAnalyzer();
+
+  // Use trace events from JSON string generated by tracing API.
+  // Returns non-NULL if the JSON is successfully parsed.
+  static TraceAnalyzer* Create(const std::string& json_events)
+                               WARN_UNUSED_RESULT;
+
+  void SetIgnoreMetadataEvents(bool ignore) { ignore_metadata_events_ = true; }
+
+  // Associate BEGIN and END events with each other. This allows Query(OTHER_*)
+  // to access the associated event and enables Query(EVENT_DURATION).
+  // An end event will match the most recent begin event with the same name,
+  // category, process ID and thread ID. This matches what is shown in
+  // about:tracing. After association, the BEGIN event will point to the
+  // matching END event, but the END event will not point to the BEGIN event.
+  void AssociateBeginEndEvents();
+
+  // Associate ASYNC_BEGIN, ASYNC_STEP and ASYNC_END events with each other.
+  // An ASYNC_END event will match the most recent ASYNC_BEGIN or ASYNC_STEP
+  // event with the same name, category, and ID. This creates a singly linked
+  // list of ASYNC_BEGIN->ASYNC_STEP...->ASYNC_END.
+  void AssociateAsyncBeginEndEvents();
+
+  // AssociateEvents can be used to customize event associations by setting the
+  // other_event member of TraceEvent. This should be used to associate two
+  // INSTANT events.
+  //
+  // The assumptions are:
+  // - |first| events occur before |second| events.
+  // - the closest matching |second| event is the correct match.
+  //
+  // |first|  - Eligible |first| events match this query.
+  // |second| - Eligible |second| events match this query.
+  // |match|  - This query is run on the |first| event. The OTHER_* EventMember
+  //            queries will point to an eligible |second| event. The query
+  //            should evaluate to true if the |first|/|second| pair is a match.
+  //
+  // When a match is found, the pair will be associated by having the first
+  // event's other_event member point to the other. AssociateEvents does not
+  // clear previous associations, so it is possible to associate multiple pairs
+  // of events by calling AssociateEvents more than once with different queries.
+  //
+  // NOTE: AssociateEvents will overwrite existing other_event associations if
+  // the queries pass for events that already had a previous association.
+  //
+  // After calling any Find* method, it is not allowed to call AssociateEvents
+  // again.
+  void AssociateEvents(const Query& first,
+                       const Query& second,
+                       const Query& match);
+
+  // For each event, copy its arguments to the other_event argument map. If
+  // argument name already exists, it will not be overwritten.
+  void MergeAssociatedEventArgs();
+
+  // Find all events that match query and replace output vector.
+  size_t FindEvents(const Query& query, TraceEventVector* output);
+
+  // Find first event that matches query or NULL if not found.
+  const TraceEvent* FindFirstOf(const Query& query);
+
+  // Find last event that matches query or NULL if not found.
+  const TraceEvent* FindLastOf(const Query& query);
+
+  const std::string& GetThreadName(const TraceEvent::ProcessThreadID& thread);
+
+ private:
+  TraceAnalyzer();
+
+  bool SetEvents(const std::string& json_events) WARN_UNUSED_RESULT;
+
+  // Read metadata (thread names, etc) from events.
+  void ParseMetadata();
+
+  std::map<TraceEvent::ProcessThreadID, std::string> thread_names_;
+  std::vector<TraceEvent> raw_events_;
+  bool ignore_metadata_events_;
+  bool allow_assocation_changes_;
+
+  DISALLOW_COPY_AND_ASSIGN(TraceAnalyzer);
+};
+
+// Utility functions for TraceEventVector.
+
+struct RateStats {
+  double min_us;
+  double max_us;
+  double mean_us;
+  double standard_deviation_us;
+};
+
+struct RateStatsOptions {
+  RateStatsOptions() : trim_min(0u), trim_max(0u) {}
+  // After the times between events are sorted, the number of specified elements
+  // will be trimmed before calculating the RateStats. This is useful in cases
+  // where extreme outliers are tolerable and should not skew the overall
+  // average.
+  size_t trim_min;  // Trim this many minimum times.
+  size_t trim_max;  // Trim this many maximum times.
+};
+
+// Calculate min/max/mean and standard deviation from the times between
+// adjacent events.
+bool GetRateStats(const TraceEventVector& events,
+                  RateStats* stats,
+                  const RateStatsOptions* options);
+
+// Starting from |position|, find the first event that matches |query|.
+// Returns true if found, false otherwise.
+bool FindFirstOf(const TraceEventVector& events,
+                 const Query& query,
+                 size_t position,
+                 size_t* return_index);
+
+// Starting from |position|, find the last event that matches |query|.
+// Returns true if found, false otherwise.
+bool FindLastOf(const TraceEventVector& events,
+                const Query& query,
+                size_t position,
+                size_t* return_index);
+
+// Find the closest events to |position| in time that match |query|.
+// return_second_closest may be NULL. Closeness is determined by comparing
+// with the event timestamp.
+// Returns true if found, false otherwise. If both return parameters are
+// requested, both must be found for a successful result.
+bool FindClosest(const TraceEventVector& events,
+                 const Query& query,
+                 size_t position,
+                 size_t* return_closest,
+                 size_t* return_second_closest);
+
+// Count matches, inclusive of |begin_position|, exclusive of |end_position|.
+size_t CountMatches(const TraceEventVector& events,
+                    const Query& query,
+                    size_t begin_position,
+                    size_t end_position);
+
+// Count all matches.
+static inline size_t CountMatches(const TraceEventVector& events,
+                                  const Query& query) {
+  return CountMatches(events, query, 0u, events.size());
+}
+
+}  // namespace trace_analyzer
+
+#endif  // BASE_TEST_TRACE_EVENT_ANALYZER_H_
diff --git a/base/test/trace_event_analyzer_unittest.cc b/base/test/trace_event_analyzer_unittest.cc
new file mode 100644
index 0000000..278709f
--- /dev/null
+++ b/base/test/trace_event_analyzer_unittest.cc
@@ -0,0 +1,894 @@
+// Copyright (c) 2012 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/bind.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/test/trace_event_analyzer.h"
+#include "base/threading/platform_thread.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace trace_analyzer {
+
+namespace {
+
+class TraceEventAnalyzerTest : public testing::Test {
+ public:
+  void ManualSetUp();
+  void OnTraceDataCollected(
+      base::WaitableEvent* flush_complete_event,
+      const scoped_refptr<base::RefCountedString>& json_events_str,
+      bool has_more_events);
+  void BeginTracing();
+  void EndTracing();
+
+  base::trace_event::TraceResultBuffer::SimpleOutput output_;
+  base::trace_event::TraceResultBuffer buffer_;
+};
+
+void TraceEventAnalyzerTest::ManualSetUp() {
+  ASSERT_TRUE(base::trace_event::TraceLog::GetInstance());
+  buffer_.SetOutputCallback(output_.GetCallback());
+  output_.json_output.clear();
+}
+
+void TraceEventAnalyzerTest::OnTraceDataCollected(
+    base::WaitableEvent* flush_complete_event,
+    const scoped_refptr<base::RefCountedString>& json_events_str,
+    bool has_more_events) {
+  buffer_.AddFragment(json_events_str->data());
+  if (!has_more_events)
+    flush_complete_event->Signal();
+}
+
+void TraceEventAnalyzerTest::BeginTracing() {
+  output_.json_output.clear();
+  buffer_.Start();
+  base::trace_event::TraceLog::GetInstance()->SetEnabled(
+      base::trace_event::TraceConfig("*", ""),
+      base::trace_event::TraceLog::RECORDING_MODE);
+}
+
+void TraceEventAnalyzerTest::EndTracing() {
+  base::trace_event::TraceLog::GetInstance()->SetDisabled();
+  base::WaitableEvent flush_complete_event(false, false);
+  base::trace_event::TraceLog::GetInstance()->Flush(
+      base::Bind(&TraceEventAnalyzerTest::OnTraceDataCollected,
+                 base::Unretained(this),
+                 base::Unretained(&flush_complete_event)));
+  flush_complete_event.Wait();
+  buffer_.Finish();
+}
+
+}  // namespace
+
+TEST_F(TraceEventAnalyzerTest, NoEvents) {
+  ManualSetUp();
+
+  // Create an empty JSON event string:
+  buffer_.Start();
+  buffer_.Finish();
+
+  scoped_ptr<TraceAnalyzer>
+      analyzer(TraceAnalyzer::Create(output_.json_output));
+  ASSERT_TRUE(analyzer.get());
+
+  // Search for all events and verify that nothing is returned.
+  TraceEventVector found;
+  analyzer->FindEvents(Query::Bool(true), &found);
+  EXPECT_EQ(0u, found.size());
+}
+
+TEST_F(TraceEventAnalyzerTest, TraceEvent) {
+  ManualSetUp();
+
+  int int_num = 2;
+  double double_num = 3.5;
+  const char str[] = "the string";
+
+  TraceEvent event;
+  event.arg_numbers["false"] = 0.0;
+  event.arg_numbers["true"] = 1.0;
+  event.arg_numbers["int"] = static_cast<double>(int_num);
+  event.arg_numbers["double"] = double_num;
+  event.arg_strings["string"] = str;
+
+  ASSERT_TRUE(event.HasNumberArg("false"));
+  ASSERT_TRUE(event.HasNumberArg("true"));
+  ASSERT_TRUE(event.HasNumberArg("int"));
+  ASSERT_TRUE(event.HasNumberArg("double"));
+  ASSERT_TRUE(event.HasStringArg("string"));
+  ASSERT_FALSE(event.HasNumberArg("notfound"));
+  ASSERT_FALSE(event.HasStringArg("notfound"));
+
+  EXPECT_FALSE(event.GetKnownArgAsBool("false"));
+  EXPECT_TRUE(event.GetKnownArgAsBool("true"));
+  EXPECT_EQ(int_num, event.GetKnownArgAsInt("int"));
+  EXPECT_EQ(double_num, event.GetKnownArgAsDouble("double"));
+  EXPECT_STREQ(str, event.GetKnownArgAsString("string").c_str());
+}
+
+TEST_F(TraceEventAnalyzerTest, QueryEventMember) {
+  ManualSetUp();
+
+  TraceEvent event;
+  event.thread.process_id = 3;
+  event.thread.thread_id = 4;
+  event.timestamp = 1.5;
+  event.phase = TRACE_EVENT_PHASE_BEGIN;
+  event.category = "category";
+  event.name = "name";
+  event.id = "1";
+  event.arg_numbers["num"] = 7.0;
+  event.arg_strings["str"] = "the string";
+
+  // Other event with all different members:
+  TraceEvent other;
+  other.thread.process_id = 5;
+  other.thread.thread_id = 6;
+  other.timestamp = 2.5;
+  other.phase = TRACE_EVENT_PHASE_END;
+  other.category = "category2";
+  other.name = "name2";
+  other.id = "2";
+  other.arg_numbers["num2"] = 8.0;
+  other.arg_strings["str2"] = "the string 2";
+
+  event.other_event = &other;
+  ASSERT_TRUE(event.has_other_event());
+  double duration = event.GetAbsTimeToOtherEvent();
+
+  Query event_pid = Query::EventPidIs(event.thread.process_id);
+  Query event_tid = Query::EventTidIs(event.thread.thread_id);
+  Query event_time = Query::EventTimeIs(event.timestamp);
+  Query event_duration = Query::EventDurationIs(duration);
+  Query event_phase = Query::EventPhaseIs(event.phase);
+  Query event_category = Query::EventCategoryIs(event.category);
+  Query event_name = Query::EventNameIs(event.name);
+  Query event_id = Query::EventIdIs(event.id);
+  Query event_has_arg1 = Query::EventHasNumberArg("num");
+  Query event_has_arg2 = Query::EventHasStringArg("str");
+  Query event_arg1 =
+      (Query::EventArg("num") == Query::Double(event.arg_numbers["num"]));
+  Query event_arg2 =
+      (Query::EventArg("str") == Query::String(event.arg_strings["str"]));
+  Query event_has_other = Query::EventHasOther();
+  Query other_pid = Query::OtherPidIs(other.thread.process_id);
+  Query other_tid = Query::OtherTidIs(other.thread.thread_id);
+  Query other_time = Query::OtherTimeIs(other.timestamp);
+  Query other_phase = Query::OtherPhaseIs(other.phase);
+  Query other_category = Query::OtherCategoryIs(other.category);
+  Query other_name = Query::OtherNameIs(other.name);
+  Query other_id = Query::OtherIdIs(other.id);
+  Query other_has_arg1 = Query::OtherHasNumberArg("num2");
+  Query other_has_arg2 = Query::OtherHasStringArg("str2");
+  Query other_arg1 =
+      (Query::OtherArg("num2") == Query::Double(other.arg_numbers["num2"]));
+  Query other_arg2 =
+      (Query::OtherArg("str2") == Query::String(other.arg_strings["str2"]));
+
+  EXPECT_TRUE(event_pid.Evaluate(event));
+  EXPECT_TRUE(event_tid.Evaluate(event));
+  EXPECT_TRUE(event_time.Evaluate(event));
+  EXPECT_TRUE(event_duration.Evaluate(event));
+  EXPECT_TRUE(event_phase.Evaluate(event));
+  EXPECT_TRUE(event_category.Evaluate(event));
+  EXPECT_TRUE(event_name.Evaluate(event));
+  EXPECT_TRUE(event_id.Evaluate(event));
+  EXPECT_TRUE(event_has_arg1.Evaluate(event));
+  EXPECT_TRUE(event_has_arg2.Evaluate(event));
+  EXPECT_TRUE(event_arg1.Evaluate(event));
+  EXPECT_TRUE(event_arg2.Evaluate(event));
+  EXPECT_TRUE(event_has_other.Evaluate(event));
+  EXPECT_TRUE(other_pid.Evaluate(event));
+  EXPECT_TRUE(other_tid.Evaluate(event));
+  EXPECT_TRUE(other_time.Evaluate(event));
+  EXPECT_TRUE(other_phase.Evaluate(event));
+  EXPECT_TRUE(other_category.Evaluate(event));
+  EXPECT_TRUE(other_name.Evaluate(event));
+  EXPECT_TRUE(other_id.Evaluate(event));
+  EXPECT_TRUE(other_has_arg1.Evaluate(event));
+  EXPECT_TRUE(other_has_arg2.Evaluate(event));
+  EXPECT_TRUE(other_arg1.Evaluate(event));
+  EXPECT_TRUE(other_arg2.Evaluate(event));
+
+  // Evaluate event queries against other to verify the queries fail when the
+  // event members are wrong.
+  EXPECT_FALSE(event_pid.Evaluate(other));
+  EXPECT_FALSE(event_tid.Evaluate(other));
+  EXPECT_FALSE(event_time.Evaluate(other));
+  EXPECT_FALSE(event_duration.Evaluate(other));
+  EXPECT_FALSE(event_phase.Evaluate(other));
+  EXPECT_FALSE(event_category.Evaluate(other));
+  EXPECT_FALSE(event_name.Evaluate(other));
+  EXPECT_FALSE(event_id.Evaluate(other));
+  EXPECT_FALSE(event_has_arg1.Evaluate(other));
+  EXPECT_FALSE(event_has_arg2.Evaluate(other));
+  EXPECT_FALSE(event_arg1.Evaluate(other));
+  EXPECT_FALSE(event_arg2.Evaluate(other));
+  EXPECT_FALSE(event_has_other.Evaluate(other));
+}
+
+TEST_F(TraceEventAnalyzerTest, BooleanOperators) {
+  ManualSetUp();
+
+  BeginTracing();
+  {
+    TRACE_EVENT_INSTANT1("cat1", "name1", TRACE_EVENT_SCOPE_THREAD, "num", 1);
+    TRACE_EVENT_INSTANT1("cat1", "name2", TRACE_EVENT_SCOPE_THREAD, "num", 2);
+    TRACE_EVENT_INSTANT1("cat2", "name3", TRACE_EVENT_SCOPE_THREAD, "num", 3);
+    TRACE_EVENT_INSTANT1("cat2", "name4", TRACE_EVENT_SCOPE_THREAD, "num", 4);
+  }
+  EndTracing();
+
+  scoped_ptr<TraceAnalyzer>
+      analyzer(TraceAnalyzer::Create(output_.json_output));
+  ASSERT_TRUE(analyzer);
+  analyzer->SetIgnoreMetadataEvents(true);
+
+  TraceEventVector found;
+
+  // ==
+
+  analyzer->FindEvents(Query::EventCategory() == Query::String("cat1"), &found);
+  ASSERT_EQ(2u, found.size());
+  EXPECT_STREQ("name1", found[0]->name.c_str());
+  EXPECT_STREQ("name2", found[1]->name.c_str());
+
+  analyzer->FindEvents(Query::EventArg("num") == Query::Int(2), &found);
+  ASSERT_EQ(1u, found.size());
+  EXPECT_STREQ("name2", found[0]->name.c_str());
+
+  // !=
+
+  analyzer->FindEvents(Query::EventCategory() != Query::String("cat1"), &found);
+  ASSERT_EQ(2u, found.size());
+  EXPECT_STREQ("name3", found[0]->name.c_str());
+  EXPECT_STREQ("name4", found[1]->name.c_str());
+
+  analyzer->FindEvents(Query::EventArg("num") != Query::Int(2), &found);
+  ASSERT_EQ(3u, found.size());
+  EXPECT_STREQ("name1", found[0]->name.c_str());
+  EXPECT_STREQ("name3", found[1]->name.c_str());
+  EXPECT_STREQ("name4", found[2]->name.c_str());
+
+  // <
+  analyzer->FindEvents(Query::EventArg("num") < Query::Int(2), &found);
+  ASSERT_EQ(1u, found.size());
+  EXPECT_STREQ("name1", found[0]->name.c_str());
+
+  // <=
+  analyzer->FindEvents(Query::EventArg("num") <= Query::Int(2), &found);
+  ASSERT_EQ(2u, found.size());
+  EXPECT_STREQ("name1", found[0]->name.c_str());
+  EXPECT_STREQ("name2", found[1]->name.c_str());
+
+  // >
+  analyzer->FindEvents(Query::EventArg("num") > Query::Int(3), &found);
+  ASSERT_EQ(1u, found.size());
+  EXPECT_STREQ("name4", found[0]->name.c_str());
+
+  // >=
+  analyzer->FindEvents(Query::EventArg("num") >= Query::Int(4), &found);
+  ASSERT_EQ(1u, found.size());
+  EXPECT_STREQ("name4", found[0]->name.c_str());
+
+  // &&
+  analyzer->FindEvents(Query::EventName() != Query::String("name1") &&
+                       Query::EventArg("num") < Query::Int(3), &found);
+  ASSERT_EQ(1u, found.size());
+  EXPECT_STREQ("name2", found[0]->name.c_str());
+
+  // ||
+  analyzer->FindEvents(Query::EventName() == Query::String("name1") ||
+                       Query::EventArg("num") == Query::Int(3), &found);
+  ASSERT_EQ(2u, found.size());
+  EXPECT_STREQ("name1", found[0]->name.c_str());
+  EXPECT_STREQ("name3", found[1]->name.c_str());
+
+  // !
+  analyzer->FindEvents(!(Query::EventName() == Query::String("name1") ||
+                         Query::EventArg("num") == Query::Int(3)), &found);
+  ASSERT_EQ(2u, found.size());
+  EXPECT_STREQ("name2", found[0]->name.c_str());
+  EXPECT_STREQ("name4", found[1]->name.c_str());
+}
+
+TEST_F(TraceEventAnalyzerTest, ArithmeticOperators) {
+  ManualSetUp();
+
+  BeginTracing();
+  {
+    // These events are searched for:
+    TRACE_EVENT_INSTANT2("cat1", "math1", TRACE_EVENT_SCOPE_THREAD,
+                         "a", 10, "b", 5);
+    TRACE_EVENT_INSTANT2("cat1", "math2", TRACE_EVENT_SCOPE_THREAD,
+                         "a", 10, "b", 10);
+    // Extra events that never match, for noise:
+    TRACE_EVENT_INSTANT2("noise", "math3", TRACE_EVENT_SCOPE_THREAD,
+                         "a", 1,  "b", 3);
+    TRACE_EVENT_INSTANT2("noise", "math4", TRACE_EVENT_SCOPE_THREAD,
+                         "c", 10, "d", 5);
+  }
+  EndTracing();
+
+  scoped_ptr<TraceAnalyzer>
+      analyzer(TraceAnalyzer::Create(output_.json_output));
+  ASSERT_TRUE(analyzer.get());
+
+  TraceEventVector found;
+
+  // Verify that arithmetic operators function:
+
+  // +
+  analyzer->FindEvents(Query::EventArg("a") + Query::EventArg("b") ==
+                       Query::Int(20), &found);
+  EXPECT_EQ(1u, found.size());
+  EXPECT_STREQ("math2", found.front()->name.c_str());
+
+  // -
+  analyzer->FindEvents(Query::EventArg("a") - Query::EventArg("b") ==
+                       Query::Int(5), &found);
+  EXPECT_EQ(1u, found.size());
+  EXPECT_STREQ("math1", found.front()->name.c_str());
+
+  // *
+  analyzer->FindEvents(Query::EventArg("a") * Query::EventArg("b") ==
+                       Query::Int(50), &found);
+  EXPECT_EQ(1u, found.size());
+  EXPECT_STREQ("math1", found.front()->name.c_str());
+
+  // /
+  analyzer->FindEvents(Query::EventArg("a") / Query::EventArg("b") ==
+                       Query::Int(2), &found);
+  EXPECT_EQ(1u, found.size());
+  EXPECT_STREQ("math1", found.front()->name.c_str());
+
+  // %
+  analyzer->FindEvents(Query::EventArg("a") % Query::EventArg("b") ==
+                       Query::Int(0), &found);
+  EXPECT_EQ(2u, found.size());
+
+  // - (negate)
+  analyzer->FindEvents(-Query::EventArg("b") == Query::Int(-10), &found);
+  EXPECT_EQ(1u, found.size());
+  EXPECT_STREQ("math2", found.front()->name.c_str());
+}
+
+TEST_F(TraceEventAnalyzerTest, StringPattern) {
+  ManualSetUp();
+
+  BeginTracing();
+  {
+    TRACE_EVENT_INSTANT0("cat1", "name1", TRACE_EVENT_SCOPE_THREAD);
+    TRACE_EVENT_INSTANT0("cat1", "name2", TRACE_EVENT_SCOPE_THREAD);
+    TRACE_EVENT_INSTANT0("cat1", "no match", TRACE_EVENT_SCOPE_THREAD);
+    TRACE_EVENT_INSTANT0("cat1", "name3x", TRACE_EVENT_SCOPE_THREAD);
+  }
+  EndTracing();
+
+  scoped_ptr<TraceAnalyzer>
+      analyzer(TraceAnalyzer::Create(output_.json_output));
+  ASSERT_TRUE(analyzer.get());
+  analyzer->SetIgnoreMetadataEvents(true);
+
+  TraceEventVector found;
+
+  analyzer->FindEvents(Query::EventName() == Query::Pattern("name?"), &found);
+  ASSERT_EQ(2u, found.size());
+  EXPECT_STREQ("name1", found[0]->name.c_str());
+  EXPECT_STREQ("name2", found[1]->name.c_str());
+
+  analyzer->FindEvents(Query::EventName() == Query::Pattern("name*"), &found);
+  ASSERT_EQ(3u, found.size());
+  EXPECT_STREQ("name1", found[0]->name.c_str());
+  EXPECT_STREQ("name2", found[1]->name.c_str());
+  EXPECT_STREQ("name3x", found[2]->name.c_str());
+
+  analyzer->FindEvents(Query::EventName() != Query::Pattern("name*"), &found);
+  ASSERT_EQ(1u, found.size());
+  EXPECT_STREQ("no match", found[0]->name.c_str());
+}
+
+// Test that duration queries work.
+TEST_F(TraceEventAnalyzerTest, BeginEndDuration) {
+  ManualSetUp();
+
+  const base::TimeDelta kSleepTime = base::TimeDelta::FromMilliseconds(200);
+  // We will search for events that have a duration of greater than 90% of the
+  // sleep time, so that there is no flakiness.
+  int64 duration_cutoff_us = (kSleepTime.InMicroseconds() * 9) / 10;
+
+  BeginTracing();
+  {
+    TRACE_EVENT_BEGIN0("cat1", "name1"); // found by duration query
+    TRACE_EVENT_BEGIN0("noise", "name2"); // not searched for, just noise
+    {
+      TRACE_EVENT_BEGIN0("cat2", "name3"); // found by duration query
+      // next event not searched for, just noise
+      TRACE_EVENT_INSTANT0("noise", "name4", TRACE_EVENT_SCOPE_THREAD);
+      base::PlatformThread::Sleep(kSleepTime);
+      TRACE_EVENT_BEGIN0("cat2", "name5"); // not found (duration too short)
+      TRACE_EVENT_END0("cat2", "name5"); // not found (duration too short)
+      TRACE_EVENT_END0("cat2", "name3"); // found by duration query
+    }
+    TRACE_EVENT_END0("noise", "name2"); // not searched for, just noise
+    TRACE_EVENT_END0("cat1", "name1"); // found by duration query
+  }
+  EndTracing();
+
+  scoped_ptr<TraceAnalyzer>
+      analyzer(TraceAnalyzer::Create(output_.json_output));
+  ASSERT_TRUE(analyzer.get());
+  analyzer->AssociateBeginEndEvents();
+
+  TraceEventVector found;
+  analyzer->FindEvents(
+      Query::MatchBeginWithEnd() &&
+      Query::EventDuration() >
+          Query::Int(static_cast<int>(duration_cutoff_us)) &&
+      (Query::EventCategory() == Query::String("cat1") ||
+       Query::EventCategory() == Query::String("cat2") ||
+       Query::EventCategory() == Query::String("cat3")),
+      &found);
+  ASSERT_EQ(2u, found.size());
+  EXPECT_STREQ("name1", found[0]->name.c_str());
+  EXPECT_STREQ("name3", found[1]->name.c_str());
+}
+
+// Test that duration queries work.
+TEST_F(TraceEventAnalyzerTest, CompleteDuration) {
+  ManualSetUp();
+
+  const base::TimeDelta kSleepTime = base::TimeDelta::FromMilliseconds(200);
+  // We will search for events that have a duration of greater than 90% of the
+  // sleep time, so that there is no flakiness.
+  int64 duration_cutoff_us = (kSleepTime.InMicroseconds() * 9) / 10;
+
+  BeginTracing();
+  {
+    TRACE_EVENT0("cat1", "name1"); // found by duration query
+    TRACE_EVENT0("noise", "name2"); // not searched for, just noise
+    {
+      TRACE_EVENT0("cat2", "name3"); // found by duration query
+      // next event not searched for, just noise
+      TRACE_EVENT_INSTANT0("noise", "name4", TRACE_EVENT_SCOPE_THREAD);
+      base::PlatformThread::Sleep(kSleepTime);
+      TRACE_EVENT0("cat2", "name5"); // not found (duration too short)
+    }
+  }
+  EndTracing();
+
+  scoped_ptr<TraceAnalyzer>
+      analyzer(TraceAnalyzer::Create(output_.json_output));
+  ASSERT_TRUE(analyzer.get());
+  analyzer->AssociateBeginEndEvents();
+
+  TraceEventVector found;
+  analyzer->FindEvents(
+      Query::EventCompleteDuration() >
+          Query::Int(static_cast<int>(duration_cutoff_us)) &&
+      (Query::EventCategory() == Query::String("cat1") ||
+       Query::EventCategory() == Query::String("cat2") ||
+       Query::EventCategory() == Query::String("cat3")),
+      &found);
+  ASSERT_EQ(2u, found.size());
+  EXPECT_STREQ("name1", found[0]->name.c_str());
+  EXPECT_STREQ("name3", found[1]->name.c_str());
+}
+
+// Test AssociateBeginEndEvents
+TEST_F(TraceEventAnalyzerTest, BeginEndAssocations) {
+  ManualSetUp();
+
+  BeginTracing();
+  {
+    TRACE_EVENT_END0("cat1", "name1"); // does not match out of order begin
+    TRACE_EVENT_BEGIN0("cat1", "name2");
+    TRACE_EVENT_INSTANT0("cat1", "name3", TRACE_EVENT_SCOPE_THREAD);
+    TRACE_EVENT_BEGIN0("cat1", "name1");
+    TRACE_EVENT_END0("cat1", "name2");
+  }
+  EndTracing();
+
+  scoped_ptr<TraceAnalyzer>
+      analyzer(TraceAnalyzer::Create(output_.json_output));
+  ASSERT_TRUE(analyzer.get());
+  analyzer->AssociateBeginEndEvents();
+
+  TraceEventVector found;
+  analyzer->FindEvents(Query::MatchBeginWithEnd(), &found);
+  ASSERT_EQ(1u, found.size());
+  EXPECT_STREQ("name2", found[0]->name.c_str());
+}
+
+// Test MergeAssociatedEventArgs
+TEST_F(TraceEventAnalyzerTest, MergeAssociatedEventArgs) {
+  ManualSetUp();
+
+  const char arg_string[] = "arg_string";
+  BeginTracing();
+  {
+    TRACE_EVENT_BEGIN0("cat1", "name1");
+    TRACE_EVENT_END1("cat1", "name1", "arg", arg_string);
+  }
+  EndTracing();
+
+  scoped_ptr<TraceAnalyzer>
+      analyzer(TraceAnalyzer::Create(output_.json_output));
+  ASSERT_TRUE(analyzer.get());
+  analyzer->AssociateBeginEndEvents();
+
+  TraceEventVector found;
+  analyzer->FindEvents(Query::MatchBeginName("name1"), &found);
+  ASSERT_EQ(1u, found.size());
+  std::string arg_actual;
+  EXPECT_FALSE(found[0]->GetArgAsString("arg", &arg_actual));
+
+  analyzer->MergeAssociatedEventArgs();
+  EXPECT_TRUE(found[0]->GetArgAsString("arg", &arg_actual));
+  EXPECT_STREQ(arg_string, arg_actual.c_str());
+}
+
+// Test AssociateAsyncBeginEndEvents
+TEST_F(TraceEventAnalyzerTest, AsyncBeginEndAssocations) {
+  ManualSetUp();
+
+  BeginTracing();
+  {
+    TRACE_EVENT_ASYNC_END0("cat1", "name1", 0xA); // no match / out of order
+    TRACE_EVENT_ASYNC_BEGIN0("cat1", "name1", 0xB);
+    TRACE_EVENT_ASYNC_BEGIN0("cat1", "name1", 0xC);
+    TRACE_EVENT_INSTANT0("cat1", "name1", TRACE_EVENT_SCOPE_THREAD); // noise
+    TRACE_EVENT0("cat1", "name1"); // noise
+    TRACE_EVENT_ASYNC_END0("cat1", "name1", 0xB);
+    TRACE_EVENT_ASYNC_END0("cat1", "name1", 0xC);
+    TRACE_EVENT_ASYNC_BEGIN0("cat1", "name1", 0xA); // no match / out of order
+  }
+  EndTracing();
+
+  scoped_ptr<TraceAnalyzer>
+      analyzer(TraceAnalyzer::Create(output_.json_output));
+  ASSERT_TRUE(analyzer.get());
+  analyzer->AssociateAsyncBeginEndEvents();
+
+  TraceEventVector found;
+  analyzer->FindEvents(Query::MatchAsyncBeginWithNext(), &found);
+  ASSERT_EQ(2u, found.size());
+  EXPECT_STRCASEEQ("0xb", found[0]->id.c_str());
+  EXPECT_STRCASEEQ("0xc", found[1]->id.c_str());
+}
+
+// Test AssociateAsyncBeginEndEvents
+TEST_F(TraceEventAnalyzerTest, AsyncBeginEndAssocationsWithSteps) {
+  ManualSetUp();
+
+  BeginTracing();
+  {
+    TRACE_EVENT_ASYNC_STEP_INTO0("c", "n", 0xA, "s1");
+    TRACE_EVENT_ASYNC_END0("c", "n", 0xA);
+    TRACE_EVENT_ASYNC_BEGIN0("c", "n", 0xB);
+    TRACE_EVENT_ASYNC_BEGIN0("c", "n", 0xC);
+    TRACE_EVENT_ASYNC_STEP_PAST0("c", "n", 0xB, "s1");
+    TRACE_EVENT_ASYNC_STEP_INTO0("c", "n", 0xC, "s1");
+    TRACE_EVENT_ASYNC_STEP_INTO1("c", "n", 0xC, "s2", "a", 1);
+    TRACE_EVENT_ASYNC_END0("c", "n", 0xB);
+    TRACE_EVENT_ASYNC_END0("c", "n", 0xC);
+    TRACE_EVENT_ASYNC_BEGIN0("c", "n", 0xA);
+    TRACE_EVENT_ASYNC_STEP_INTO0("c", "n", 0xA, "s2");
+  }
+  EndTracing();
+
+  scoped_ptr<TraceAnalyzer>
+      analyzer(TraceAnalyzer::Create(output_.json_output));
+  ASSERT_TRUE(analyzer.get());
+  analyzer->AssociateAsyncBeginEndEvents();
+
+  TraceEventVector found;
+  analyzer->FindEvents(Query::MatchAsyncBeginWithNext(), &found);
+  ASSERT_EQ(3u, found.size());
+
+  EXPECT_STRCASEEQ("0xb", found[0]->id.c_str());
+  EXPECT_EQ(TRACE_EVENT_PHASE_ASYNC_STEP_PAST, found[0]->other_event->phase);
+  EXPECT_TRUE(found[0]->other_event->other_event);
+  EXPECT_EQ(TRACE_EVENT_PHASE_ASYNC_END,
+            found[0]->other_event->other_event->phase);
+
+  EXPECT_STRCASEEQ("0xc", found[1]->id.c_str());
+  EXPECT_EQ(TRACE_EVENT_PHASE_ASYNC_STEP_INTO, found[1]->other_event->phase);
+  EXPECT_TRUE(found[1]->other_event->other_event);
+  EXPECT_EQ(TRACE_EVENT_PHASE_ASYNC_STEP_INTO,
+            found[1]->other_event->other_event->phase);
+  double arg_actual = 0;
+  EXPECT_TRUE(found[1]->other_event->other_event->GetArgAsNumber(
+                  "a", &arg_actual));
+  EXPECT_EQ(1.0, arg_actual);
+  EXPECT_TRUE(found[1]->other_event->other_event->other_event);
+  EXPECT_EQ(TRACE_EVENT_PHASE_ASYNC_END,
+            found[1]->other_event->other_event->other_event->phase);
+
+  EXPECT_STRCASEEQ("0xa", found[2]->id.c_str());
+  EXPECT_EQ(TRACE_EVENT_PHASE_ASYNC_STEP_INTO, found[2]->other_event->phase);
+}
+
+// Test that the TraceAnalyzer custom associations work.
+TEST_F(TraceEventAnalyzerTest, CustomAssociations) {
+  ManualSetUp();
+
+  // Add events that begin/end in pipelined ordering with unique ID parameter
+  // to match up the begin/end pairs.
+  BeginTracing();
+  {
+    // no begin match
+    TRACE_EVENT_INSTANT1("cat1", "end", TRACE_EVENT_SCOPE_THREAD, "id", 1);
+    // end is cat4
+    TRACE_EVENT_INSTANT1("cat2", "begin", TRACE_EVENT_SCOPE_THREAD, "id", 2);
+    // end is cat5
+    TRACE_EVENT_INSTANT1("cat3", "begin", TRACE_EVENT_SCOPE_THREAD, "id", 3);
+    TRACE_EVENT_INSTANT1("cat4", "end", TRACE_EVENT_SCOPE_THREAD, "id", 2);
+    TRACE_EVENT_INSTANT1("cat5", "end", TRACE_EVENT_SCOPE_THREAD, "id", 3);
+    // no end match
+    TRACE_EVENT_INSTANT1("cat6", "begin", TRACE_EVENT_SCOPE_THREAD, "id", 1);
+  }
+  EndTracing();
+
+  scoped_ptr<TraceAnalyzer>
+      analyzer(TraceAnalyzer::Create(output_.json_output));
+  ASSERT_TRUE(analyzer.get());
+
+  // begin, end, and match queries to find proper begin/end pairs.
+  Query begin(Query::EventName() == Query::String("begin"));
+  Query end(Query::EventName() == Query::String("end"));
+  Query match(Query::EventArg("id") == Query::OtherArg("id"));
+  analyzer->AssociateEvents(begin, end, match);
+
+  TraceEventVector found;
+
+  // cat1 has no other_event.
+  analyzer->FindEvents(Query::EventCategory() == Query::String("cat1") &&
+                       Query::EventHasOther(), &found);
+  EXPECT_EQ(0u, found.size());
+
+  // cat1 has no other_event.
+  analyzer->FindEvents(Query::EventCategory() == Query::String("cat1") &&
+                       !Query::EventHasOther(), &found);
+  EXPECT_EQ(1u, found.size());
+
+  // cat6 has no other_event.
+  analyzer->FindEvents(Query::EventCategory() == Query::String("cat6") &&
+                       !Query::EventHasOther(), &found);
+  EXPECT_EQ(1u, found.size());
+
+  // cat2 and cat4 are associated.
+  analyzer->FindEvents(Query::EventCategory() == Query::String("cat2") &&
+                       Query::OtherCategory() == Query::String("cat4"), &found);
+  EXPECT_EQ(1u, found.size());
+
+  // cat4 and cat2 are not associated.
+  analyzer->FindEvents(Query::EventCategory() == Query::String("cat4") &&
+                       Query::OtherCategory() == Query::String("cat2"), &found);
+  EXPECT_EQ(0u, found.size());
+
+  // cat3 and cat5 are associated.
+  analyzer->FindEvents(Query::EventCategory() == Query::String("cat3") &&
+                       Query::OtherCategory() == Query::String("cat5"), &found);
+  EXPECT_EQ(1u, found.size());
+
+  // cat5 and cat3 are not associated.
+  analyzer->FindEvents(Query::EventCategory() == Query::String("cat5") &&
+                       Query::OtherCategory() == Query::String("cat3"), &found);
+  EXPECT_EQ(0u, found.size());
+}
+
+// Verify that Query literals and types are properly casted.
+TEST_F(TraceEventAnalyzerTest, Literals) {
+  ManualSetUp();
+
+  // Since these queries don't refer to the event data, the dummy event below
+  // will never be accessed.
+  TraceEvent dummy;
+  char char_num = 5;
+  short short_num = -5;
+  EXPECT_TRUE((Query::Double(5.0) == Query::Int(char_num)).Evaluate(dummy));
+  EXPECT_TRUE((Query::Double(-5.0) == Query::Int(short_num)).Evaluate(dummy));
+  EXPECT_TRUE((Query::Double(1.0) == Query::Uint(1u)).Evaluate(dummy));
+  EXPECT_TRUE((Query::Double(1.0) == Query::Int(1)).Evaluate(dummy));
+  EXPECT_TRUE((Query::Double(-1.0) == Query::Int(-1)).Evaluate(dummy));
+  EXPECT_TRUE((Query::Double(1.0) == Query::Double(1.0f)).Evaluate(dummy));
+  EXPECT_TRUE((Query::Bool(true) == Query::Int(1)).Evaluate(dummy));
+  EXPECT_TRUE((Query::Bool(false) == Query::Int(0)).Evaluate(dummy));
+  EXPECT_TRUE((Query::Bool(true) == Query::Double(1.0f)).Evaluate(dummy));
+  EXPECT_TRUE((Query::Bool(false) == Query::Double(0.0f)).Evaluate(dummy));
+}
+
+// Test GetRateStats.
+TEST_F(TraceEventAnalyzerTest, RateStats) {
+  std::vector<TraceEvent> events;
+  events.reserve(100);
+  TraceEventVector event_ptrs;
+  TraceEvent event;
+  event.timestamp = 0.0;
+  double little_delta = 1.0;
+  double big_delta = 10.0;
+  double tiny_delta = 0.1;
+  RateStats stats;
+  RateStatsOptions options;
+
+  // Insert 10 events, each apart by little_delta.
+  for (int i = 0; i < 10; ++i) {
+    event.timestamp += little_delta;
+    events.push_back(event);
+    event_ptrs.push_back(&events.back());
+  }
+
+  ASSERT_TRUE(GetRateStats(event_ptrs, &stats, NULL));
+  EXPECT_EQ(little_delta, stats.mean_us);
+  EXPECT_EQ(little_delta, stats.min_us);
+  EXPECT_EQ(little_delta, stats.max_us);
+  EXPECT_EQ(0.0, stats.standard_deviation_us);
+
+  // Add an event apart by big_delta.
+  event.timestamp += big_delta;
+  events.push_back(event);
+  event_ptrs.push_back(&events.back());
+
+  ASSERT_TRUE(GetRateStats(event_ptrs, &stats, NULL));
+  EXPECT_LT(little_delta, stats.mean_us);
+  EXPECT_EQ(little_delta, stats.min_us);
+  EXPECT_EQ(big_delta, stats.max_us);
+  EXPECT_LT(0.0, stats.standard_deviation_us);
+
+  // Trim off the biggest delta and verify stats.
+  options.trim_min = 0;
+  options.trim_max = 1;
+  ASSERT_TRUE(GetRateStats(event_ptrs, &stats, &options));
+  EXPECT_EQ(little_delta, stats.mean_us);
+  EXPECT_EQ(little_delta, stats.min_us);
+  EXPECT_EQ(little_delta, stats.max_us);
+  EXPECT_EQ(0.0, stats.standard_deviation_us);
+
+  // Add an event apart by tiny_delta.
+  event.timestamp += tiny_delta;
+  events.push_back(event);
+  event_ptrs.push_back(&events.back());
+
+  // Trim off both the biggest and tiniest delta and verify stats.
+  options.trim_min = 1;
+  options.trim_max = 1;
+  ASSERT_TRUE(GetRateStats(event_ptrs, &stats, &options));
+  EXPECT_EQ(little_delta, stats.mean_us);
+  EXPECT_EQ(little_delta, stats.min_us);
+  EXPECT_EQ(little_delta, stats.max_us);
+  EXPECT_EQ(0.0, stats.standard_deviation_us);
+
+  // Verify smallest allowed number of events.
+  TraceEventVector few_event_ptrs;
+  few_event_ptrs.push_back(&event);
+  few_event_ptrs.push_back(&event);
+  ASSERT_FALSE(GetRateStats(few_event_ptrs, &stats, NULL));
+  few_event_ptrs.push_back(&event);
+  ASSERT_TRUE(GetRateStats(few_event_ptrs, &stats, NULL));
+
+  // Trim off more than allowed and verify failure.
+  options.trim_min = 0;
+  options.trim_max = 1;
+  ASSERT_FALSE(GetRateStats(few_event_ptrs, &stats, &options));
+}
+
+// Test FindFirstOf and FindLastOf.
+TEST_F(TraceEventAnalyzerTest, FindOf) {
+  size_t num_events = 100;
+  size_t index = 0;
+  TraceEventVector event_ptrs;
+  EXPECT_FALSE(FindFirstOf(event_ptrs, Query::Bool(true), 0, &index));
+  EXPECT_FALSE(FindFirstOf(event_ptrs, Query::Bool(true), 10, &index));
+  EXPECT_FALSE(FindLastOf(event_ptrs, Query::Bool(true), 0, &index));
+  EXPECT_FALSE(FindLastOf(event_ptrs, Query::Bool(true), 10, &index));
+
+  std::vector<TraceEvent> events;
+  events.resize(num_events);
+  for (size_t i = 0; i < events.size(); ++i)
+    event_ptrs.push_back(&events[i]);
+  size_t bam_index = num_events/2;
+  events[bam_index].name = "bam";
+  Query query_bam = Query::EventName() == Query::String(events[bam_index].name);
+
+  // FindFirstOf
+  EXPECT_FALSE(FindFirstOf(event_ptrs, Query::Bool(false), 0, &index));
+  EXPECT_TRUE(FindFirstOf(event_ptrs, Query::Bool(true), 0, &index));
+  EXPECT_EQ(0u, index);
+  EXPECT_TRUE(FindFirstOf(event_ptrs, Query::Bool(true), 5, &index));
+  EXPECT_EQ(5u, index);
+
+  EXPECT_FALSE(FindFirstOf(event_ptrs, query_bam, bam_index + 1, &index));
+  EXPECT_TRUE(FindFirstOf(event_ptrs, query_bam, 0, &index));
+  EXPECT_EQ(bam_index, index);
+  EXPECT_TRUE(FindFirstOf(event_ptrs, query_bam, bam_index, &index));
+  EXPECT_EQ(bam_index, index);
+
+  // FindLastOf
+  EXPECT_FALSE(FindLastOf(event_ptrs, Query::Bool(false), 1000, &index));
+  EXPECT_TRUE(FindLastOf(event_ptrs, Query::Bool(true), 1000, &index));
+  EXPECT_EQ(num_events - 1, index);
+  EXPECT_TRUE(FindLastOf(event_ptrs, Query::Bool(true), num_events - 5,
+                         &index));
+  EXPECT_EQ(num_events - 5, index);
+
+  EXPECT_FALSE(FindLastOf(event_ptrs, query_bam, bam_index - 1, &index));
+  EXPECT_TRUE(FindLastOf(event_ptrs, query_bam, num_events, &index));
+  EXPECT_EQ(bam_index, index);
+  EXPECT_TRUE(FindLastOf(event_ptrs, query_bam, bam_index, &index));
+  EXPECT_EQ(bam_index, index);
+}
+
+// Test FindClosest.
+TEST_F(TraceEventAnalyzerTest, FindClosest) {
+  size_t index_1 = 0;
+  size_t index_2 = 0;
+  TraceEventVector event_ptrs;
+  EXPECT_FALSE(FindClosest(event_ptrs, Query::Bool(true), 0,
+                           &index_1, &index_2));
+
+  size_t num_events = 5;
+  std::vector<TraceEvent> events;
+  events.resize(num_events);
+  for (size_t i = 0; i < events.size(); ++i) {
+    // timestamps go up exponentially so the lower index is always closer in
+    // time than the higher index.
+    events[i].timestamp = static_cast<double>(i) * static_cast<double>(i);
+    event_ptrs.push_back(&events[i]);
+  }
+  events[0].name = "one";
+  events[2].name = "two";
+  events[4].name = "three";
+  Query query_named = Query::EventName() != Query::String(std::string());
+  Query query_one = Query::EventName() == Query::String("one");
+
+  // Only one event matches query_one, so two closest can't be found.
+  EXPECT_FALSE(FindClosest(event_ptrs, query_one, 0, &index_1, &index_2));
+
+  EXPECT_TRUE(FindClosest(event_ptrs, query_one, 3, &index_1, NULL));
+  EXPECT_EQ(0u, index_1);
+
+  EXPECT_TRUE(FindClosest(event_ptrs, query_named, 1, &index_1, &index_2));
+  EXPECT_EQ(0u, index_1);
+  EXPECT_EQ(2u, index_2);
+
+  EXPECT_TRUE(FindClosest(event_ptrs, query_named, 4, &index_1, &index_2));
+  EXPECT_EQ(4u, index_1);
+  EXPECT_EQ(2u, index_2);
+
+  EXPECT_TRUE(FindClosest(event_ptrs, query_named, 3, &index_1, &index_2));
+  EXPECT_EQ(2u, index_1);
+  EXPECT_EQ(0u, index_2);
+}
+
+// Test CountMatches.
+TEST_F(TraceEventAnalyzerTest, CountMatches) {
+  TraceEventVector event_ptrs;
+  EXPECT_EQ(0u, CountMatches(event_ptrs, Query::Bool(true), 0, 10));
+
+  size_t num_events = 5;
+  size_t num_named = 3;
+  std::vector<TraceEvent> events;
+  events.resize(num_events);
+  for (size_t i = 0; i < events.size(); ++i)
+    event_ptrs.push_back(&events[i]);
+  events[0].name = "one";
+  events[2].name = "two";
+  events[4].name = "three";
+  Query query_named = Query::EventName() != Query::String(std::string());
+  Query query_one = Query::EventName() == Query::String("one");
+
+  EXPECT_EQ(0u, CountMatches(event_ptrs, Query::Bool(false)));
+  EXPECT_EQ(num_events, CountMatches(event_ptrs, Query::Bool(true)));
+  EXPECT_EQ(num_events - 1, CountMatches(event_ptrs, Query::Bool(true),
+                                         1, num_events));
+  EXPECT_EQ(1u, CountMatches(event_ptrs, query_one));
+  EXPECT_EQ(num_events - 1, CountMatches(event_ptrs, !query_one));
+  EXPECT_EQ(num_named, CountMatches(event_ptrs, query_named));
+}
+
+
+}  // namespace trace_analyzer
diff --git a/base/test/trace_to_file.cc b/base/test/trace_to_file.cc
new file mode 100644
index 0000000..e00b58a
--- /dev/null
+++ b/base/test/trace_to_file.cc
@@ -0,0 +1,104 @@
+// Copyright (c) 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.
+
+#include "base/test/trace_to_file.h"
+
+#include "base/base_switches.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/files/file_util.h"
+#include "base/run_loop.h"
+#include "base/trace_event/trace_event_impl.h"
+
+namespace base {
+namespace test {
+
+TraceToFile::TraceToFile() : started_(false) {
+}
+
+TraceToFile::~TraceToFile() {
+  EndTracingIfNeeded();
+}
+
+void TraceToFile::BeginTracingFromCommandLineOptions() {
+  DCHECK(CommandLine::InitializedForCurrentProcess());
+  DCHECK(!started_);
+
+  if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kTraceToFile))
+    return;
+
+  // Empty filter (i.e. just --trace-to-file) turns into default categories in
+  // TraceEventImpl
+  std::string filter = CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+      switches::kTraceToFile);
+
+  FilePath path;
+  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kTraceToFileName)) {
+    path = FilePath(CommandLine::ForCurrentProcess()
+                        ->GetSwitchValuePath(switches::kTraceToFileName));
+  } else {
+    path = FilePath(FILE_PATH_LITERAL("trace.json"));
+  }
+
+  BeginTracing(path, filter);
+}
+
+void TraceToFile::BeginTracing(const FilePath& path,
+                               const std::string& categories) {
+  DCHECK(!started_);
+  started_ = true;
+  path_ = path;
+  WriteFileHeader();
+
+  trace_event::TraceLog::GetInstance()->SetEnabled(
+      trace_event::TraceConfig(categories, trace_event::RECORD_UNTIL_FULL),
+      trace_event::TraceLog::RECORDING_MODE);
+}
+
+void TraceToFile::WriteFileHeader() {
+  const char str[] = "{\"traceEvents\": [";
+  WriteFile(path_, str, static_cast<int>(strlen(str)));
+}
+
+void TraceToFile::AppendFileFooter() {
+  const char str[] = "]}";
+  AppendToFile(path_, str, static_cast<int>(strlen(str)));
+}
+
+void TraceToFile::TraceOutputCallback(const std::string& data) {
+  bool ret = AppendToFile(path_, data.c_str(), static_cast<int>(data.size()));
+  DCHECK(ret);
+}
+
+static void OnTraceDataCollected(
+    Closure quit_closure,
+    trace_event::TraceResultBuffer* buffer,
+    const scoped_refptr<RefCountedString>& json_events_str,
+    bool has_more_events) {
+  buffer->AddFragment(json_events_str->data());
+  if (!has_more_events)
+    quit_closure.Run();
+}
+
+void TraceToFile::EndTracingIfNeeded() {
+  if (!started_)
+    return;
+  started_ = false;
+
+  trace_event::TraceLog::GetInstance()->SetDisabled();
+
+  trace_event::TraceResultBuffer buffer;
+  buffer.SetOutputCallback(
+      Bind(&TraceToFile::TraceOutputCallback, Unretained(this)));
+
+  RunLoop run_loop;
+  trace_event::TraceLog::GetInstance()->Flush(
+      Bind(&OnTraceDataCollected, run_loop.QuitClosure(), Unretained(&buffer)));
+  run_loop.Run();
+
+  AppendFileFooter();
+}
+
+}  // namespace test
+}  // namespace base
diff --git a/base/test/trace_to_file.h b/base/test/trace_to_file.h
new file mode 100644
index 0000000..4308736
--- /dev/null
+++ b/base/test/trace_to_file.h
@@ -0,0 +1,35 @@
+// Copyright (c) 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.
+
+#ifndef BASE_TEST_TRACE_TO_FILE_H_
+#define BASE_TEST_TRACE_TO_FILE_H_
+
+#include "base/files/file_path.h"
+
+namespace base {
+namespace test {
+
+class TraceToFile {
+ public:
+  TraceToFile();
+  ~TraceToFile();
+
+  void BeginTracingFromCommandLineOptions();
+  void BeginTracing(const base::FilePath& path, const std::string& categories);
+  void EndTracingIfNeeded();
+
+ private:
+  void WriteFileHeader();
+  void AppendFileFooter();
+
+  void TraceOutputCallback(const std::string& data);
+
+  base::FilePath path_;
+  bool started_;
+};
+
+}  // namespace test
+}  // namespace base
+
+#endif  // BASE_TEST_TRACE_TO_FILE_H_
diff --git a/base/test/user_action_tester.cc b/base/test/user_action_tester.cc
new file mode 100644
index 0000000..3fdab12
--- /dev/null
+++ b/base/test/user_action_tester.cc
@@ -0,0 +1,35 @@
+// 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/test/user_action_tester.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+
+namespace base {
+
+UserActionTester::UserActionTester()
+    : action_callback_(
+          base::Bind(&UserActionTester::OnUserAction, base::Unretained(this))) {
+  base::AddActionCallback(action_callback_);
+}
+
+UserActionTester::~UserActionTester() {
+  base::RemoveActionCallback(action_callback_);
+}
+
+int UserActionTester::GetActionCount(const std::string& user_action) const {
+  UserActionCountMap::const_iterator iter = count_map_.find(user_action);
+  return iter == count_map_.end() ? 0 : iter->second;
+}
+
+void UserActionTester::ResetCounts() {
+  count_map_.clear();
+}
+
+void UserActionTester::OnUserAction(const std::string& user_action) {
+  ++(count_map_[user_action]);
+}
+
+}  // namespace base
diff --git a/base/test/user_action_tester.h b/base/test/user_action_tester.h
new file mode 100644
index 0000000..6b0efc5
--- /dev/null
+++ b/base/test/user_action_tester.h
@@ -0,0 +1,46 @@
+// 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_TEST_USER_ACTION_TESTER_H_
+#define BASE_TEST_USER_ACTION_TESTER_H_
+
+#include <map>
+#include <string>
+
+#include "base/metrics/user_metrics.h"
+
+namespace base {
+
+// This class observes and collects user action notifications that are sent
+// by the tests, so that they can be examined afterwards for correctness.
+// Note: This class is NOT thread-safe.
+class UserActionTester {
+ public:
+  UserActionTester();
+  ~UserActionTester();
+
+  // Returns the number of times the given |user_action| occurred.
+  int GetActionCount(const std::string& user_action) const;
+
+  // Resets all user action counts to 0.
+  void ResetCounts();
+
+ private:
+  typedef std::map<std::string, int> UserActionCountMap;
+
+  // The callback that is notified when a user actions occurs.
+  void OnUserAction(const std::string& user_action);
+
+  // A map that tracks the number of times a user action has occurred.
+  UserActionCountMap count_map_;
+
+  // The callback that is added to the global action callback list.
+  base::ActionCallback action_callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(UserActionTester);
+};
+
+}  // namespace base
+
+#endif  // BASE_TEST_USER_ACTION_TESTER_H_
diff --git a/base/test/user_action_tester_unittest.cc b/base/test/user_action_tester_unittest.cc
new file mode 100644
index 0000000..a51849f
--- /dev/null
+++ b/base/test/user_action_tester_unittest.cc
@@ -0,0 +1,86 @@
+// 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/test/user_action_tester.h"
+
+#include "base/metrics/user_metrics.h"
+#include "base/metrics/user_metrics_action.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+const char kUserAction1[] = "user.action.1";
+const char kUserAction2[] = "user.action.2";
+const char kUserAction3[] = "user.action.3";
+
+// Record an action and cause all ActionCallback observers to be notified.
+void RecordAction(const char user_action[]) {
+  base::RecordAction(base::UserMetricsAction(user_action));
+}
+
+}  // namespace
+
+// Verify user action counts are zero initially.
+TEST(UserActionTesterTest, GetActionCountWhenNoActionsHaveBeenRecorded) {
+  UserActionTester user_action_tester;
+  EXPECT_EQ(0, user_action_tester.GetActionCount(kUserAction1));
+}
+
+// Verify user action counts are tracked properly.
+TEST(UserActionTesterTest, GetActionCountWhenActionsHaveBeenRecorded) {
+  UserActionTester user_action_tester;
+
+  RecordAction(kUserAction1);
+  RecordAction(kUserAction2);
+  RecordAction(kUserAction2);
+
+  EXPECT_EQ(1, user_action_tester.GetActionCount(kUserAction1));
+  EXPECT_EQ(2, user_action_tester.GetActionCount(kUserAction2));
+  EXPECT_EQ(0, user_action_tester.GetActionCount(kUserAction3));
+}
+
+// Verify no seg faults occur when resetting action counts when none have been
+// recorded.
+TEST(UserActionTesterTest, ResetCountsWhenNoActionsHaveBeenRecorded) {
+  UserActionTester user_action_tester;
+  user_action_tester.ResetCounts();
+}
+
+// Verify user action counts are set to zero on a ResetCounts.
+TEST(UserActionTesterTest, ResetCountsWhenActionsHaveBeenRecorded) {
+  UserActionTester user_action_tester;
+
+  RecordAction(kUserAction1);
+  RecordAction(kUserAction1);
+  RecordAction(kUserAction2);
+  user_action_tester.ResetCounts();
+
+  EXPECT_EQ(0, user_action_tester.GetActionCount(kUserAction1));
+  EXPECT_EQ(0, user_action_tester.GetActionCount(kUserAction2));
+  EXPECT_EQ(0, user_action_tester.GetActionCount(kUserAction3));
+}
+
+// Verify the UserActionsTester is notified when base::RecordAction is called.
+TEST(UserActionTesterTest, VerifyUserActionTesterListensForUserActions) {
+  UserActionTester user_action_tester;
+
+  base::RecordAction(base::UserMetricsAction(kUserAction1));
+
+  EXPECT_EQ(1, user_action_tester.GetActionCount(kUserAction1));
+}
+
+// Verify the UserActionsTester is notified when base::RecordComputedAction is
+// called.
+TEST(UserActionTesterTest,
+     VerifyUserActionTesterListensForComputedUserActions) {
+  UserActionTester user_action_tester;
+
+  base::RecordComputedAction(kUserAction1);
+
+  EXPECT_EQ(1, user_action_tester.GetActionCount(kUserAction1));
+}
+
+}  // namespace base
diff --git a/base/test/values_test_util.cc b/base/test/values_test_util.cc
new file mode 100644
index 0000000..ebfc494
--- /dev/null
+++ b/base/test/values_test_util.cc
@@ -0,0 +1,77 @@
+// Copyright (c) 2012 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/test/values_test_util.h"
+
+#include "base/json/json_reader.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+void ExpectDictBooleanValue(bool expected_value,
+                            const DictionaryValue& value,
+                            const std::string& key) {
+  bool boolean_value = false;
+  EXPECT_TRUE(value.GetBoolean(key, &boolean_value)) << key;
+  EXPECT_EQ(expected_value, boolean_value) << key;
+}
+
+void ExpectDictDictionaryValue(const DictionaryValue& expected_value,
+                               const DictionaryValue& value,
+                               const std::string& key) {
+  const DictionaryValue* dict_value = NULL;
+  EXPECT_TRUE(value.GetDictionary(key, &dict_value)) << key;
+  EXPECT_TRUE(Value::Equals(dict_value, &expected_value)) << key;
+}
+
+void ExpectDictIntegerValue(int expected_value,
+                            const DictionaryValue& value,
+                            const std::string& key) {
+  int integer_value = 0;
+  EXPECT_TRUE(value.GetInteger(key, &integer_value)) << key;
+  EXPECT_EQ(expected_value, integer_value) << key;
+}
+
+void ExpectDictListValue(const ListValue& expected_value,
+                         const DictionaryValue& value,
+                         const std::string& key) {
+  const ListValue* list_value = NULL;
+  EXPECT_TRUE(value.GetList(key, &list_value)) << key;
+  EXPECT_TRUE(Value::Equals(list_value, &expected_value)) << key;
+}
+
+void ExpectDictStringValue(const std::string& expected_value,
+                           const DictionaryValue& value,
+                           const std::string& key) {
+  std::string string_value;
+  EXPECT_TRUE(value.GetString(key, &string_value)) << key;
+  EXPECT_EQ(expected_value, string_value) << key;
+}
+
+void ExpectStringValue(const std::string& expected_str,
+                       StringValue* actual) {
+  scoped_ptr<StringValue> scoped_actual(actual);
+  std::string actual_str;
+  EXPECT_TRUE(scoped_actual->GetAsString(&actual_str));
+  EXPECT_EQ(expected_str, actual_str);
+}
+
+namespace test {
+
+scoped_ptr<Value> ParseJson(base::StringPiece json) {
+  std::string error_msg;
+  scoped_ptr<Value> result = base::JSONReader::ReadAndReturnError(
+      json, base::JSON_ALLOW_TRAILING_COMMAS, NULL, &error_msg);
+  if (!result) {
+    ADD_FAILURE() << "Failed to parse \"" << json << "\": " << error_msg;
+    result = Value::CreateNullValue();
+  }
+  return result.Pass();
+}
+
+}  // namespace test
+}  // namespace base
diff --git a/base/test/values_test_util.h b/base/test/values_test_util.h
new file mode 100644
index 0000000..86d91c3
--- /dev/null
+++ b/base/test/values_test_util.h
@@ -0,0 +1,56 @@
+// Copyright (c) 2012 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_TEST_VALUES_TEST_UTIL_H_
+#define BASE_TEST_VALUES_TEST_UTIL_H_
+
+#include <string>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+class DictionaryValue;
+class ListValue;
+class StringValue;
+class Value;
+
+// All the functions below expect that the value for the given key in
+// the given dictionary equals the given expected value.
+
+void ExpectDictBooleanValue(bool expected_value,
+                            const DictionaryValue& value,
+                            const std::string& key);
+
+void ExpectDictDictionaryValue(const DictionaryValue& expected_value,
+                               const DictionaryValue& value,
+                               const std::string& key);
+
+void ExpectDictIntegerValue(int expected_value,
+                            const DictionaryValue& value,
+                            const std::string& key);
+
+void ExpectDictListValue(const ListValue& expected_value,
+                         const DictionaryValue& value,
+                         const std::string& key);
+
+void ExpectDictStringValue(const std::string& expected_value,
+                           const DictionaryValue& value,
+                           const std::string& key);
+
+// Takes ownership of |actual|.
+void ExpectStringValue(const std::string& expected_str,
+                       StringValue* actual);
+
+namespace test {
+
+// Parses |json| as JSON, allowing trailing commas, and returns the
+// resulting value.  If the json fails to parse, causes an EXPECT
+// failure and returns the Null Value (but never a NULL pointer).
+scoped_ptr<Value> ParseJson(base::StringPiece json);
+
+}  // namespace test
+}  // namespace base
+
+#endif  // BASE_TEST_VALUES_TEST_UTIL_H_
diff --git a/base/third_party/dmg_fp/LICENSE b/base/third_party/dmg_fp/LICENSE
new file mode 100644
index 0000000..716f1ef
--- /dev/null
+++ b/base/third_party/dmg_fp/LICENSE
@@ -0,0 +1,18 @@
+/****************************************************************
+ *
+ * The author of this software is David M. Gay.
+ *
+ * Copyright (c) 1991, 2000, 2001 by Lucent Technologies.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ ***************************************************************/
diff --git a/base/third_party/dmg_fp/README.chromium b/base/third_party/dmg_fp/README.chromium
new file mode 100644
index 0000000..4538b7e
--- /dev/null
+++ b/base/third_party/dmg_fp/README.chromium
@@ -0,0 +1,20 @@
+Name: David M. Gay's floating point routines
+URL: http://www.netlib.org/fp/
+License: MIT-like
+
+Original dtoa.c file can be found at <http://www.netlib.org/fp/dtoa.c>.
+Original g_fmt.c file can be found at <http://www.netlib.org/fp/g_fmt.c>.
+
+List of changes made to original code:
+  - wrapped functions in dmg_fp namespace
+  - renamed .c files to .cc
+  - added dmg_fp.h header
+  - added #define IEEE_8087 to dtoa.cc
+  - added #define NO_HEX_FP to dtoa.cc
+  - made some minor changes to allow clean compilation under g++ -Wall, see
+    gcc_warnings.patch.
+  - made some minor changes to build on 64-bit, see gcc_64_bit.patch.
+  - made minor changes for -Wextra for Mac build, see mac_wextra.patch
+  - crash fix for running with reduced CPU float precision, see
+    float_precision_crash.patch and crbug.com/123157
+  - fixed warnings under msvc, see msvc_warnings.patch
\ No newline at end of file
diff --git a/base/third_party/dmg_fp/dmg_fp.h b/base/third_party/dmg_fp/dmg_fp.h
new file mode 100644
index 0000000..4795397
--- /dev/null
+++ b/base/third_party/dmg_fp/dmg_fp.h
@@ -0,0 +1,30 @@
+// Copyright (c) 2008 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 THIRD_PARTY_DMG_FP_H_
+#define THIRD_PARTY_DMG_FP_H_
+
+namespace dmg_fp {
+
+// Return a nearest machine number to the input decimal
+// string (or set errno to ERANGE). With IEEE arithmetic, ties are
+// broken by the IEEE round-even rule.  Otherwise ties are broken by
+// biased rounding (add half and chop).
+double strtod(const char* s00, char** se);
+
+// Convert double to ASCII string. For meaning of parameters
+// see dtoa.cc file.
+char* dtoa(double d, int mode, int ndigits,
+           int* decpt, int* sign, char** rve);
+
+// Must be used to free values returned by dtoa.
+void freedtoa(char* s);
+
+// Store the closest decimal approximation to x in b (null terminated).
+// Returns a pointer to b.  It is sufficient for |b| to be 32 characters.
+char* g_fmt(char* b, double x);
+
+}  // namespace dmg_fp
+
+#endif  // THIRD_PARTY_DMG_FP_H_
diff --git a/base/third_party/dmg_fp/dtoa.cc b/base/third_party/dmg_fp/dtoa.cc
new file mode 100644
index 0000000..502c16c
--- /dev/null
+++ b/base/third_party/dmg_fp/dtoa.cc
@@ -0,0 +1,4234 @@
+/****************************************************************
+ *
+ * The author of this software is David M. Gay.
+ *
+ * Copyright (c) 1991, 2000, 2001 by Lucent Technologies.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ ***************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to ".").	*/
+
+/* On a machine with IEEE extended-precision registers, it is
+ * necessary to specify double-precision (53-bit) rounding precision
+ * before invoking strtod or dtoa.  If the machine uses (the equivalent
+ * of) Intel 80x87 arithmetic, the call
+ *	_control87(PC_53, MCW_PC);
+ * does this with many compilers.  Whether this or another call is
+ * appropriate depends on the compiler; for this to work, it may be
+ * necessary to #include "float.h" or another system-dependent header
+ * file.
+ */
+
+/* strtod for IEEE-, VAX-, and IBM-arithmetic machines.
+ *
+ * This strtod returns a nearest machine number to the input decimal
+ * string (or sets errno to ERANGE).  With IEEE arithmetic, ties are
+ * broken by the IEEE round-even rule.  Otherwise ties are broken by
+ * biased rounding (add half and chop).
+ *
+ * Inspired loosely by William D. Clinger's paper "How to Read Floating
+ * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 92-101].
+ *
+ * Modifications:
+ *
+ *	1. We only require IEEE, IBM, or VAX double-precision
+ *		arithmetic (not IEEE double-extended).
+ *	2. We get by with floating-point arithmetic in a case that
+ *		Clinger missed -- when we're computing d * 10^n
+ *		for a small integer d and the integer n is not too
+ *		much larger than 22 (the maximum integer k for which
+ *		we can represent 10^k exactly), we may be able to
+ *		compute (d*10^k) * 10^(e-k) with just one roundoff.
+ *	3. Rather than a bit-at-a-time adjustment of the binary
+ *		result in the hard case, we use floating-point
+ *		arithmetic to determine the adjustment to within
+ *		one bit; only in really hard cases do we need to
+ *		compute a second residual.
+ *	4. Because of 3., we don't need a large table of powers of 10
+ *		for ten-to-e (just some small tables, e.g. of 10^k
+ *		for 0 <= k <= 22).
+ */
+
+/*
+ * #define IEEE_8087 for IEEE-arithmetic machines where the least
+ *	significant byte has the lowest address.
+ * #define IEEE_MC68k for IEEE-arithmetic machines where the most
+ *	significant byte has the lowest address.
+ * #define Long int on machines with 32-bit ints and 64-bit longs.
+ * #define IBM for IBM mainframe-style floating-point arithmetic.
+ * #define VAX for VAX-style floating-point arithmetic (D_floating).
+ * #define No_leftright to omit left-right logic in fast floating-point
+ *	computation of dtoa.
+ * #define Honor_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3
+ *	and strtod and dtoa should round accordingly.  Unless Trust_FLT_ROUNDS
+ *	is also #defined, fegetround() will be queried for the rounding mode.
+ *	Note that both FLT_ROUNDS and fegetround() are specified by the C99
+ *	standard (and are specified to be consistent, with fesetround()
+ *	affecting the value of FLT_ROUNDS), but that some (Linux) systems
+ *	do not work correctly in this regard, so using fegetround() is more
+ *	portable than using FLT_FOUNDS directly.
+ * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3
+ *	and Honor_FLT_ROUNDS is not #defined.
+ * #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines
+ *	that use extended-precision instructions to compute rounded
+ *	products and quotients) with IBM.
+ * #define ROUND_BIASED for IEEE-format with biased rounding.
+ * #define Inaccurate_Divide for IEEE-format with correctly rounded
+ *	products but inaccurate quotients, e.g., for Intel i860.
+ * #define NO_LONG_LONG on machines that do not have a "long long"
+ *	integer type (of >= 64 bits).  On such machines, you can
+ *	#define Just_16 to store 16 bits per 32-bit Long when doing
+ *	high-precision integer arithmetic.  Whether this speeds things
+ *	up or slows things down depends on the machine and the number
+ *	being converted.  If long long is available and the name is
+ *	something other than "long long", #define Llong to be the name,
+ *	and if "unsigned Llong" does not work as an unsigned version of
+ *	Llong, #define #ULLong to be the corresponding unsigned type.
+ * #define KR_headers for old-style C function headers.
+ * #define Bad_float_h if your system lacks a float.h or if it does not
+ *	define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP,
+ *	FLT_RADIX, FLT_ROUNDS, and DBL_MAX.
+ * #define MALLOC your_malloc, where your_malloc(n) acts like malloc(n)
+ *	if memory is available and otherwise does something you deem
+ *	appropriate.  If MALLOC is undefined, malloc will be invoked
+ *	directly -- and assumed always to succeed.  Similarly, if you
+ *	want something other than the system's free() to be called to
+ *	recycle memory acquired from MALLOC, #define FREE to be the
+ *	name of the alternate routine.  (FREE or free is only called in
+ *	pathological cases, e.g., in a dtoa call after a dtoa return in
+ *	mode 3 with thousands of digits requested.)
+ * #define Omit_Private_Memory to omit logic (added Jan. 1998) for making
+ *	memory allocations from a private pool of memory when possible.
+ *	When used, the private pool is PRIVATE_MEM bytes long:  2304 bytes,
+ *	unless #defined to be a different length.  This default length
+ *	suffices to get rid of MALLOC calls except for unusual cases,
+ *	such as decimal-to-binary conversion of a very long string of
+ *	digits.  The longest string dtoa can return is about 751 bytes
+ *	long.  For conversions by strtod of strings of 800 digits and
+ *	all dtoa conversions in single-threaded executions with 8-byte
+ *	pointers, PRIVATE_MEM >= 7400 appears to suffice; with 4-byte
+ *	pointers, PRIVATE_MEM >= 7112 appears adequate.
+ * #define NO_INFNAN_CHECK if you do not wish to have INFNAN_CHECK
+ *	#defined automatically on IEEE systems.  On such systems,
+ *	when INFNAN_CHECK is #defined, strtod checks
+ *	for Infinity and NaN (case insensitively).  On some systems
+ *	(e.g., some HP systems), it may be necessary to #define NAN_WORD0
+ *	appropriately -- to the most significant word of a quiet NaN.
+ *	(On HP Series 700/800 machines, -DNAN_WORD0=0x7ff40000 works.)
+ *	When INFNAN_CHECK is #defined and No_Hex_NaN is not #defined,
+ *	strtod also accepts (case insensitively) strings of the form
+ *	NaN(x), where x is a string of hexadecimal digits and spaces;
+ *	if there is only one string of hexadecimal digits, it is taken
+ *	for the 52 fraction bits of the resulting NaN; if there are two
+ *	or more strings of hex digits, the first is for the high 20 bits,
+ *	the second and subsequent for the low 32 bits, with intervening
+ *	white space ignored; but if this results in none of the 52
+ *	fraction bits being on (an IEEE Infinity symbol), then NAN_WORD0
+ *	and NAN_WORD1 are used instead.
+ * #define MULTIPLE_THREADS if the system offers preemptively scheduled
+ *	multiple threads.  In this case, you must provide (or suitably
+ *	#define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed
+ *	by FREE_DTOA_LOCK(n) for n = 0 or 1.  (The second lock, accessed
+ *	in pow5mult, ensures lazy evaluation of only one copy of high
+ *	powers of 5; omitting this lock would introduce a small
+ *	probability of wasting memory, but would otherwise be harmless.)
+ *	You must also invoke freedtoa(s) to free the value s returned by
+ *	dtoa.  You may do so whether or not MULTIPLE_THREADS is #defined.
+ * #define NO_IEEE_Scale to disable new (Feb. 1997) logic in strtod that
+ *	avoids underflows on inputs whose result does not underflow.
+ *	If you #define NO_IEEE_Scale on a machine that uses IEEE-format
+ *	floating-point numbers and flushes underflows to zero rather
+ *	than implementing gradual underflow, then you must also #define
+ *	Sudden_Underflow.
+ * #define USE_LOCALE to use the current locale's decimal_point value.
+ * #define SET_INEXACT if IEEE arithmetic is being used and extra
+ *	computation should be done to set the inexact flag when the
+ *	result is inexact and avoid setting inexact when the result
+ *	is exact.  In this case, dtoa.c must be compiled in
+ *	an environment, perhaps provided by #include "dtoa.c" in a
+ *	suitable wrapper, that defines two functions,
+ *		int get_inexact(void);
+ *		void clear_inexact(void);
+ *	such that get_inexact() returns a nonzero value if the
+ *	inexact bit is already set, and clear_inexact() sets the
+ *	inexact bit to 0.  When SET_INEXACT is #defined, strtod
+ *	also does extra computations to set the underflow and overflow
+ *	flags when appropriate (i.e., when the result is tiny and
+ *	inexact or when it is a numeric value rounded to +-infinity).
+ * #define NO_ERRNO if strtod should not assign errno = ERANGE when
+ *	the result overflows to +-Infinity or underflows to 0.
+ * #define NO_HEX_FP to omit recognition of hexadecimal floating-point
+ *	values by strtod.
+ * #define NO_STRTOD_BIGCOMP (on IEEE-arithmetic systems only for now)
+ *	to disable logic for "fast" testing of very long input strings
+ *	to strtod.  This testing proceeds by initially truncating the
+ *	input string, then if necessary comparing the whole string with
+ *	a decimal expansion to decide close cases. This logic is only
+ *	used for input more than STRTOD_DIGLIM digits long (default 40).
+ */
+
+#define IEEE_8087
+#define NO_HEX_FP
+
+#ifndef Long
+#if __LP64__
+#define Long int
+#else
+#define Long long
+#endif
+#endif
+#ifndef ULong
+typedef unsigned Long ULong;
+#endif
+
+#ifdef DEBUG
+#include "stdio.h"
+#define Bug(x) {fprintf(stderr, "%s\n", x); exit(1);}
+#endif
+
+#include "stdlib.h"
+#include "string.h"
+
+#ifdef USE_LOCALE
+#include "locale.h"
+#endif
+
+#ifdef Honor_FLT_ROUNDS
+#ifndef Trust_FLT_ROUNDS
+#include <fenv.h>
+#endif
+#endif
+
+#ifdef MALLOC
+#ifdef KR_headers
+extern char *MALLOC();
+#else
+extern void *MALLOC(size_t);
+#endif
+#else
+#define MALLOC malloc
+#endif
+
+#ifndef Omit_Private_Memory
+#ifndef PRIVATE_MEM
+#define PRIVATE_MEM 2304
+#endif
+#define PRIVATE_mem ((unsigned)((PRIVATE_MEM+sizeof(double)-1)/sizeof(double)))
+static double private_mem[PRIVATE_mem], *pmem_next = private_mem;
+#endif
+
+#undef IEEE_Arith
+#undef Avoid_Underflow
+#ifdef IEEE_MC68k
+#define IEEE_Arith
+#endif
+#ifdef IEEE_8087
+#define IEEE_Arith
+#endif
+
+#ifdef IEEE_Arith
+#ifndef NO_INFNAN_CHECK
+#undef INFNAN_CHECK
+#define INFNAN_CHECK
+#endif
+#else
+#undef INFNAN_CHECK
+#define NO_STRTOD_BIGCOMP
+#endif
+
+#include "errno.h"
+
+#ifdef Bad_float_h
+
+#ifdef IEEE_Arith
+#define DBL_DIG 15
+#define DBL_MAX_10_EXP 308
+#define DBL_MAX_EXP 1024
+#define FLT_RADIX 2
+#endif /*IEEE_Arith*/
+
+#ifdef IBM
+#define DBL_DIG 16
+#define DBL_MAX_10_EXP 75
+#define DBL_MAX_EXP 63
+#define FLT_RADIX 16
+#define DBL_MAX 7.2370055773322621e+75
+#endif
+
+#ifdef VAX
+#define DBL_DIG 16
+#define DBL_MAX_10_EXP 38
+#define DBL_MAX_EXP 127
+#define FLT_RADIX 2
+#define DBL_MAX 1.7014118346046923e+38
+#endif
+
+#ifndef LONG_MAX
+#define LONG_MAX 2147483647
+#endif
+
+#else /* ifndef Bad_float_h */
+#include "float.h"
+#endif /* Bad_float_h */
+
+#ifndef __MATH_H__
+#include "math.h"
+#endif
+
+namespace dmg_fp {
+
+#ifndef CONST
+#ifdef KR_headers
+#define CONST /* blank */
+#else
+#define CONST const
+#endif
+#endif
+
+#if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(VAX) + defined(IBM) != 1
+Exactly one of IEEE_8087, IEEE_MC68k, VAX, or IBM should be defined.
+#endif
+
+typedef union { double d; ULong L[2]; } U;
+
+#ifdef IEEE_8087
+#define word0(x) (x)->L[1]
+#define word1(x) (x)->L[0]
+#else
+#define word0(x) (x)->L[0]
+#define word1(x) (x)->L[1]
+#endif
+#define dval(x) (x)->d
+
+#ifndef STRTOD_DIGLIM
+#define STRTOD_DIGLIM 40
+#endif
+
+#ifdef DIGLIM_DEBUG
+extern int strtod_diglim;
+#else
+#define strtod_diglim STRTOD_DIGLIM
+#endif
+
+/* The following definition of Storeinc is appropriate for MIPS processors.
+ * An alternative that might be better on some machines is
+ * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff)
+ */
+#if defined(IEEE_8087) + defined(VAX)
+#define Storeinc(a,b,c) (((unsigned short *)a)[1] = (unsigned short)b, \
+((unsigned short *)a)[0] = (unsigned short)c, a++)
+#else
+#define Storeinc(a,b,c) (((unsigned short *)a)[0] = (unsigned short)b, \
+((unsigned short *)a)[1] = (unsigned short)c, a++)
+#endif
+
+/* #define P DBL_MANT_DIG */
+/* Ten_pmax = floor(P*log(2)/log(5)) */
+/* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */
+/* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */
+/* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */
+
+#ifdef IEEE_Arith
+#define Exp_shift  20
+#define Exp_shift1 20
+#define Exp_msk1    0x100000
+#define Exp_msk11   0x100000
+#define Exp_mask  0x7ff00000
+#define P 53
+#define Nbits 53
+#define Bias 1023
+#define Emax 1023
+#define Emin (-1022)
+#define Exp_1  0x3ff00000
+#define Exp_11 0x3ff00000
+#define Ebits 11
+#define Frac_mask  0xfffff
+#define Frac_mask1 0xfffff
+#define Ten_pmax 22
+#define Bletch 0x10
+#define Bndry_mask  0xfffff
+#define Bndry_mask1 0xfffff
+#define LSB 1
+#define Sign_bit 0x80000000
+#define Log2P 1
+#define Tiny0 0
+#define Tiny1 1
+#define Quick_max 14
+#define Int_max 14
+#ifndef NO_IEEE_Scale
+#define Avoid_Underflow
+#ifdef Flush_Denorm	/* debugging option */
+#undef Sudden_Underflow
+#endif
+#endif
+
+#ifndef Flt_Rounds
+#ifdef FLT_ROUNDS
+#define Flt_Rounds FLT_ROUNDS
+#else
+#define Flt_Rounds 1
+#endif
+#endif /*Flt_Rounds*/
+
+#ifdef Honor_FLT_ROUNDS
+#undef Check_FLT_ROUNDS
+#define Check_FLT_ROUNDS
+#else
+#define Rounding Flt_Rounds
+#endif
+
+#else /* ifndef IEEE_Arith */
+#undef Check_FLT_ROUNDS
+#undef Honor_FLT_ROUNDS
+#undef SET_INEXACT
+#undef  Sudden_Underflow
+#define Sudden_Underflow
+#ifdef IBM
+#undef Flt_Rounds
+#define Flt_Rounds 0
+#define Exp_shift  24
+#define Exp_shift1 24
+#define Exp_msk1   0x1000000
+#define Exp_msk11  0x1000000
+#define Exp_mask  0x7f000000
+#define P 14
+#define Nbits 56
+#define Bias 65
+#define Emax 248
+#define Emin (-260)
+#define Exp_1  0x41000000
+#define Exp_11 0x41000000
+#define Ebits 8	/* exponent has 7 bits, but 8 is the right value in b2d */
+#define Frac_mask  0xffffff
+#define Frac_mask1 0xffffff
+#define Bletch 4
+#define Ten_pmax 22
+#define Bndry_mask  0xefffff
+#define Bndry_mask1 0xffffff
+#define LSB 1
+#define Sign_bit 0x80000000
+#define Log2P 4
+#define Tiny0 0x100000
+#define Tiny1 0
+#define Quick_max 14
+#define Int_max 15
+#else /* VAX */
+#undef Flt_Rounds
+#define Flt_Rounds 1
+#define Exp_shift  23
+#define Exp_shift1 7
+#define Exp_msk1    0x80
+#define Exp_msk11   0x800000
+#define Exp_mask  0x7f80
+#define P 56
+#define Nbits 56
+#define Bias 129
+#define Emax 126
+#define Emin (-129)
+#define Exp_1  0x40800000
+#define Exp_11 0x4080
+#define Ebits 8
+#define Frac_mask  0x7fffff
+#define Frac_mask1 0xffff007f
+#define Ten_pmax 24
+#define Bletch 2
+#define Bndry_mask  0xffff007f
+#define Bndry_mask1 0xffff007f
+#define LSB 0x10000
+#define Sign_bit 0x8000
+#define Log2P 1
+#define Tiny0 0x80
+#define Tiny1 0
+#define Quick_max 15
+#define Int_max 15
+#endif /* IBM, VAX */
+#endif /* IEEE_Arith */
+
+#ifndef IEEE_Arith
+#define ROUND_BIASED
+#endif
+
+#ifdef RND_PRODQUOT
+#define rounded_product(a,b) a = rnd_prod(a, b)
+#define rounded_quotient(a,b) a = rnd_quot(a, b)
+#ifdef KR_headers
+extern double rnd_prod(), rnd_quot();
+#else
+extern double rnd_prod(double, double), rnd_quot(double, double);
+#endif
+#else
+#define rounded_product(a,b) a *= b
+#define rounded_quotient(a,b) a /= b
+#endif
+
+#define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1))
+#define Big1 0xffffffff
+
+#ifndef Pack_32
+#define Pack_32
+#endif
+
+typedef struct BCinfo BCinfo;
+ struct
+BCinfo { int dp0, dp1, dplen, dsign, e0, inexact, nd, nd0, rounding, scale, uflchk; };
+
+#ifdef KR_headers
+#define FFFFFFFF ((((unsigned long)0xffff)<<16)|(unsigned long)0xffff)
+#else
+#define FFFFFFFF 0xffffffffUL
+#endif
+
+#ifdef NO_LONG_LONG
+#undef ULLong
+#ifdef Just_16
+#undef Pack_32
+/* When Pack_32 is not defined, we store 16 bits per 32-bit Long.
+ * This makes some inner loops simpler and sometimes saves work
+ * during multiplications, but it often seems to make things slightly
+ * slower.  Hence the default is now to store 32 bits per Long.
+ */
+#endif
+#else	/* long long available */
+#ifndef Llong
+#define Llong long long
+#endif
+#ifndef ULLong
+#define ULLong unsigned Llong
+#endif
+#endif /* NO_LONG_LONG */
+
+#ifndef MULTIPLE_THREADS
+#define ACQUIRE_DTOA_LOCK(n)	/*nothing*/
+#define FREE_DTOA_LOCK(n)	/*nothing*/
+#endif
+
+#define Kmax 7
+
+double strtod(const char *s00, char **se);
+char *dtoa(double d, int mode, int ndigits,
+			int *decpt, int *sign, char **rve);
+
+ struct
+Bigint {
+	struct Bigint *next;
+	int k, maxwds, sign, wds;
+	ULong x[1];
+	};
+
+ typedef struct Bigint Bigint;
+
+ static Bigint *freelist[Kmax+1];
+
+ static Bigint *
+Balloc
+#ifdef KR_headers
+	(k) int k;
+#else
+	(int k)
+#endif
+{
+	int x;
+	Bigint *rv;
+#ifndef Omit_Private_Memory
+	unsigned int len;
+#endif
+
+	ACQUIRE_DTOA_LOCK(0);
+	/* The k > Kmax case does not need ACQUIRE_DTOA_LOCK(0), */
+	/* but this case seems very unlikely. */
+	if (k <= Kmax && freelist[k]) {
+		rv = freelist[k];
+		freelist[k] = rv->next;
+		}
+	else {
+		x = 1 << k;
+#ifdef Omit_Private_Memory
+		rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong));
+#else
+		len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1)
+			/sizeof(double);
+		if (k <= Kmax && pmem_next - private_mem + len <= PRIVATE_mem) {
+			rv = (Bigint*)pmem_next;
+			pmem_next += len;
+			}
+		else
+			rv = (Bigint*)MALLOC(len*sizeof(double));
+#endif
+		rv->k = k;
+		rv->maxwds = x;
+		}
+	FREE_DTOA_LOCK(0);
+	rv->sign = rv->wds = 0;
+	return rv;
+	}
+
+ static void
+Bfree
+#ifdef KR_headers
+	(v) Bigint *v;
+#else
+	(Bigint *v)
+#endif
+{
+	if (v) {
+		if (v->k > Kmax)
+#ifdef FREE
+			FREE((void*)v);
+#else
+			free((void*)v);
+#endif
+		else {
+			ACQUIRE_DTOA_LOCK(0);
+			v->next = freelist[v->k];
+			freelist[v->k] = v;
+			FREE_DTOA_LOCK(0);
+			}
+		}
+	}
+
+#define Bcopy(x,y) memcpy((char *)&x->sign, (char *)&y->sign, \
+y->wds*sizeof(Long) + 2*sizeof(int))
+
+ static Bigint *
+multadd
+#ifdef KR_headers
+	(b, m, a) Bigint *b; int m, a;
+#else
+	(Bigint *b, int m, int a)	/* multiply by m and add a */
+#endif
+{
+	int i, wds;
+#ifdef ULLong
+	ULong *x;
+	ULLong carry, y;
+#else
+	ULong carry, *x, y;
+#ifdef Pack_32
+	ULong xi, z;
+#endif
+#endif
+	Bigint *b1;
+
+	wds = b->wds;
+	x = b->x;
+	i = 0;
+	carry = a;
+	do {
+#ifdef ULLong
+		y = *x * (ULLong)m + carry;
+		carry = y >> 32;
+		*x++ = y & FFFFFFFF;
+#else
+#ifdef Pack_32
+		xi = *x;
+		y = (xi & 0xffff) * m + carry;
+		z = (xi >> 16) * m + (y >> 16);
+		carry = z >> 16;
+		*x++ = (z << 16) + (y & 0xffff);
+#else
+		y = *x * m + carry;
+		carry = y >> 16;
+		*x++ = y & 0xffff;
+#endif
+#endif
+		}
+		while(++i < wds);
+	if (carry) {
+		if (wds >= b->maxwds) {
+			b1 = Balloc(b->k+1);
+			Bcopy(b1, b);
+			Bfree(b);
+			b = b1;
+			}
+		b->x[wds++] = (ULong)carry;
+		b->wds = wds;
+		}
+	return b;
+	}
+
+ static Bigint *
+s2b
+#ifdef KR_headers
+	(s, nd0, nd, y9, dplen) CONST char *s; int nd0, nd, dplen; ULong y9;
+#else
+	(CONST char *s, int nd0, int nd, ULong y9, int dplen)
+#endif
+{
+	Bigint *b;
+	int i, k;
+	Long x, y;
+
+	x = (nd + 8) / 9;
+	for(k = 0, y = 1; x > y; y <<= 1, k++) ;
+#ifdef Pack_32
+	b = Balloc(k);
+	b->x[0] = y9;
+	b->wds = 1;
+#else
+	b = Balloc(k+1);
+	b->x[0] = y9 & 0xffff;
+	b->wds = (b->x[1] = y9 >> 16) ? 2 : 1;
+#endif
+
+	i = 9;
+	if (9 < nd0) {
+		s += 9;
+		do b = multadd(b, 10, *s++ - '0');
+			while(++i < nd0);
+		s += dplen;
+		}
+	else
+		s += dplen + 9;
+	for(; i < nd; i++)
+		b = multadd(b, 10, *s++ - '0');
+	return b;
+	}
+
+ static int
+hi0bits
+#ifdef KR_headers
+	(x) ULong x;
+#else
+	(ULong x)
+#endif
+{
+	int k = 0;
+
+	if (!(x & 0xffff0000)) {
+		k = 16;
+		x <<= 16;
+		}
+	if (!(x & 0xff000000)) {
+		k += 8;
+		x <<= 8;
+		}
+	if (!(x & 0xf0000000)) {
+		k += 4;
+		x <<= 4;
+		}
+	if (!(x & 0xc0000000)) {
+		k += 2;
+		x <<= 2;
+		}
+	if (!(x & 0x80000000)) {
+		k++;
+		if (!(x & 0x40000000))
+			return 32;
+		}
+	return k;
+	}
+
+ static int
+lo0bits
+#ifdef KR_headers
+	(y) ULong *y;
+#else
+	(ULong *y)
+#endif
+{
+	int k;
+	ULong x = *y;
+
+	if (x & 7) {
+		if (x & 1)
+			return 0;
+		if (x & 2) {
+			*y = x >> 1;
+			return 1;
+			}
+		*y = x >> 2;
+		return 2;
+		}
+	k = 0;
+	if (!(x & 0xffff)) {
+		k = 16;
+		x >>= 16;
+		}
+	if (!(x & 0xff)) {
+		k += 8;
+		x >>= 8;
+		}
+	if (!(x & 0xf)) {
+		k += 4;
+		x >>= 4;
+		}
+	if (!(x & 0x3)) {
+		k += 2;
+		x >>= 2;
+		}
+	if (!(x & 1)) {
+		k++;
+		x >>= 1;
+		if (!x)
+			return 32;
+		}
+	*y = x;
+	return k;
+	}
+
+ static Bigint *
+i2b
+#ifdef KR_headers
+	(i) int i;
+#else
+	(int i)
+#endif
+{
+	Bigint *b;
+
+	b = Balloc(1);
+	b->x[0] = i;
+	b->wds = 1;
+	return b;
+	}
+
+ static Bigint *
+mult
+#ifdef KR_headers
+	(a, b) Bigint *a, *b;
+#else
+	(Bigint *a, Bigint *b)
+#endif
+{
+	Bigint *c;
+	int k, wa, wb, wc;
+	ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0;
+	ULong y;
+#ifdef ULLong
+	ULLong carry, z;
+#else
+	ULong carry, z;
+#ifdef Pack_32
+	ULong z2;
+#endif
+#endif
+
+	if (a->wds < b->wds) {
+		c = a;
+		a = b;
+		b = c;
+		}
+	k = a->k;
+	wa = a->wds;
+	wb = b->wds;
+	wc = wa + wb;
+	if (wc > a->maxwds)
+		k++;
+	c = Balloc(k);
+	for(x = c->x, xa = x + wc; x < xa; x++)
+		*x = 0;
+	xa = a->x;
+	xae = xa + wa;
+	xb = b->x;
+	xbe = xb + wb;
+	xc0 = c->x;
+#ifdef ULLong
+	for(; xb < xbe; xc0++) {
+		y = *xb++;
+		if (y) {
+			x = xa;
+			xc = xc0;
+			carry = 0;
+			do {
+				z = *x++ * (ULLong)y + *xc + carry;
+				carry = z >> 32;
+				*xc++ = z & FFFFFFFF;
+				}
+				while(x < xae);
+			*xc = (ULong)carry;
+			}
+		}
+#else
+#ifdef Pack_32
+	for(; xb < xbe; xb++, xc0++) {
+		if (y = *xb & 0xffff) {
+			x = xa;
+			xc = xc0;
+			carry = 0;
+			do {
+				z = (*x & 0xffff) * y + (*xc & 0xffff) + carry;
+				carry = z >> 16;
+				z2 = (*x++ >> 16) * y + (*xc >> 16) + carry;
+				carry = z2 >> 16;
+				Storeinc(xc, z2, z);
+				}
+				while(x < xae);
+			*xc = carry;
+			}
+		if (y = *xb >> 16) {
+			x = xa;
+			xc = xc0;
+			carry = 0;
+			z2 = *xc;
+			do {
+				z = (*x & 0xffff) * y + (*xc >> 16) + carry;
+				carry = z >> 16;
+				Storeinc(xc, z, z2);
+				z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry;
+				carry = z2 >> 16;
+				}
+				while(x < xae);
+			*xc = z2;
+			}
+		}
+#else
+	for(; xb < xbe; xc0++) {
+		if (y = *xb++) {
+			x = xa;
+			xc = xc0;
+			carry = 0;
+			do {
+				z = *x++ * y + *xc + carry;
+				carry = z >> 16;
+				*xc++ = z & 0xffff;
+				}
+				while(x < xae);
+			*xc = carry;
+			}
+		}
+#endif
+#endif
+	for(xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ;
+	c->wds = wc;
+	return c;
+	}
+
+ static Bigint *p5s;
+
+ static Bigint *
+pow5mult
+#ifdef KR_headers
+	(b, k) Bigint *b; int k;
+#else
+	(Bigint *b, int k)
+#endif
+{
+	Bigint *b1, *p5, *p51;
+	int i;
+	static int p05[3] = { 5, 25, 125 };
+
+	i = k & 3;
+	if (i)
+		b = multadd(b, p05[i-1], 0);
+
+	if (!(k >>= 2))
+		return b;
+	p5 = p5s;
+	if (!p5) {
+		/* first time */
+#ifdef MULTIPLE_THREADS
+		ACQUIRE_DTOA_LOCK(1);
+		p5 = p5s;
+		if (!p5) {
+			p5 = p5s = i2b(625);
+			p5->next = 0;
+			}
+		FREE_DTOA_LOCK(1);
+#else
+		p5 = p5s = i2b(625);
+		p5->next = 0;
+#endif
+		}
+	for(;;) {
+		if (k & 1) {
+			b1 = mult(b, p5);
+			Bfree(b);
+			b = b1;
+			}
+		if (!(k >>= 1))
+			break;
+		p51 = p5->next;
+		if (!p51) {
+#ifdef MULTIPLE_THREADS
+			ACQUIRE_DTOA_LOCK(1);
+			p51 = p5->next;
+			if (!p51) {
+				p51 = p5->next = mult(p5,p5);
+				p51->next = 0;
+				}
+			FREE_DTOA_LOCK(1);
+#else
+			p51 = p5->next = mult(p5,p5);
+			p51->next = 0;
+#endif
+			}
+		p5 = p51;
+		}
+	return b;
+	}
+
+ static Bigint *
+lshift
+#ifdef KR_headers
+	(b, k) Bigint *b; int k;
+#else
+	(Bigint *b, int k)
+#endif
+{
+	int i, k1, n, n1;
+	Bigint *b1;
+	ULong *x, *x1, *xe, z;
+
+#ifdef Pack_32
+	n = k >> 5;
+#else
+	n = k >> 4;
+#endif
+	k1 = b->k;
+	n1 = n + b->wds + 1;
+	for(i = b->maxwds; n1 > i; i <<= 1)
+		k1++;
+	b1 = Balloc(k1);
+	x1 = b1->x;
+	for(i = 0; i < n; i++)
+		*x1++ = 0;
+	x = b->x;
+	xe = x + b->wds;
+#ifdef Pack_32
+	if (k &= 0x1f) {
+		k1 = 32 - k;
+		z = 0;
+		do {
+			*x1++ = *x << k | z;
+			z = *x++ >> k1;
+			}
+			while(x < xe);
+		*x1 = z;
+		if (*x1)
+			++n1;
+		}
+#else
+	if (k &= 0xf) {
+		k1 = 16 - k;
+		z = 0;
+		do {
+			*x1++ = *x << k  & 0xffff | z;
+			z = *x++ >> k1;
+			}
+			while(x < xe);
+		if (*x1 = z)
+			++n1;
+		}
+#endif
+	else do
+		*x1++ = *x++;
+		while(x < xe);
+	b1->wds = n1 - 1;
+	Bfree(b);
+	return b1;
+	}
+
+ static int
+cmp
+#ifdef KR_headers
+	(a, b) Bigint *a, *b;
+#else
+	(Bigint *a, Bigint *b)
+#endif
+{
+	ULong *xa, *xa0, *xb, *xb0;
+	int i, j;
+
+	i = a->wds;
+	j = b->wds;
+#ifdef DEBUG
+	if (i > 1 && !a->x[i-1])
+		Bug("cmp called with a->x[a->wds-1] == 0");
+	if (j > 1 && !b->x[j-1])
+		Bug("cmp called with b->x[b->wds-1] == 0");
+#endif
+	if (i -= j)
+		return i;
+	xa0 = a->x;
+	xa = xa0 + j;
+	xb0 = b->x;
+	xb = xb0 + j;
+	for(;;) {
+		if (*--xa != *--xb)
+			return *xa < *xb ? -1 : 1;
+		if (xa <= xa0)
+			break;
+		}
+	return 0;
+	}
+
+ static Bigint *
+diff
+#ifdef KR_headers
+	(a, b) Bigint *a, *b;
+#else
+	(Bigint *a, Bigint *b)
+#endif
+{
+	Bigint *c;
+	int i, wa, wb;
+	ULong *xa, *xae, *xb, *xbe, *xc;
+#ifdef ULLong
+	ULLong borrow, y;
+#else
+	ULong borrow, y;
+#ifdef Pack_32
+	ULong z;
+#endif
+#endif
+
+	i = cmp(a,b);
+	if (!i) {
+		c = Balloc(0);
+		c->wds = 1;
+		c->x[0] = 0;
+		return c;
+		}
+	if (i < 0) {
+		c = a;
+		a = b;
+		b = c;
+		i = 1;
+		}
+	else
+		i = 0;
+	c = Balloc(a->k);
+	c->sign = i;
+	wa = a->wds;
+	xa = a->x;
+	xae = xa + wa;
+	wb = b->wds;
+	xb = b->x;
+	xbe = xb + wb;
+	xc = c->x;
+	borrow = 0;
+#ifdef ULLong
+	do {
+		y = (ULLong)*xa++ - *xb++ - borrow;
+		borrow = y >> 32 & (ULong)1;
+		*xc++ = y & FFFFFFFF;
+		}
+		while(xb < xbe);
+	while(xa < xae) {
+		y = *xa++ - borrow;
+		borrow = y >> 32 & (ULong)1;
+		*xc++ = y & FFFFFFFF;
+		}
+#else
+#ifdef Pack_32
+	do {
+		y = (*xa & 0xffff) - (*xb & 0xffff) - borrow;
+		borrow = (y & 0x10000) >> 16;
+		z = (*xa++ >> 16) - (*xb++ >> 16) - borrow;
+		borrow = (z & 0x10000) >> 16;
+		Storeinc(xc, z, y);
+		}
+		while(xb < xbe);
+	while(xa < xae) {
+		y = (*xa & 0xffff) - borrow;
+		borrow = (y & 0x10000) >> 16;
+		z = (*xa++ >> 16) - borrow;
+		borrow = (z & 0x10000) >> 16;
+		Storeinc(xc, z, y);
+		}
+#else
+	do {
+		y = *xa++ - *xb++ - borrow;
+		borrow = (y & 0x10000) >> 16;
+		*xc++ = y & 0xffff;
+		}
+		while(xb < xbe);
+	while(xa < xae) {
+		y = *xa++ - borrow;
+		borrow = (y & 0x10000) >> 16;
+		*xc++ = y & 0xffff;
+		}
+#endif
+#endif
+	while(!*--xc)
+		wa--;
+	c->wds = wa;
+	return c;
+	}
+
+ static double
+ulp
+#ifdef KR_headers
+	(x) U *x;
+#else
+	(U *x)
+#endif
+{
+	Long L;
+	U u;
+
+	L = (word0(x) & Exp_mask) - (P-1)*Exp_msk1;
+#ifndef Avoid_Underflow
+#ifndef Sudden_Underflow
+	if (L > 0) {
+#endif
+#endif
+#ifdef IBM
+		L |= Exp_msk1 >> 4;
+#endif
+		word0(&u) = L;
+		word1(&u) = 0;
+#ifndef Avoid_Underflow
+#ifndef Sudden_Underflow
+		}
+	else {
+		L = -L >> Exp_shift;
+		if (L < Exp_shift) {
+			word0(&u) = 0x80000 >> L;
+			word1(&u) = 0;
+			}
+		else {
+			word0(&u) = 0;
+			L -= Exp_shift;
+			word1(&u) = L >= 31 ? 1 : 1 << 31 - L;
+			}
+		}
+#endif
+#endif
+	return dval(&u);
+	}
+
+ static double
+b2d
+#ifdef KR_headers
+	(a, e) Bigint *a; int *e;
+#else
+	(Bigint *a, int *e)
+#endif
+{
+	ULong *xa, *xa0, w, y, z;
+	int k;
+	U d;
+#ifdef VAX
+	ULong d0, d1;
+#else
+#define d0 word0(&d)
+#define d1 word1(&d)
+#endif
+
+	xa0 = a->x;
+	xa = xa0 + a->wds;
+	y = *--xa;
+#ifdef DEBUG
+	if (!y) Bug("zero y in b2d");
+#endif
+	k = hi0bits(y);
+	*e = 32 - k;
+#ifdef Pack_32
+	if (k < Ebits) {
+		d0 = Exp_1 | y >> (Ebits - k);
+		w = xa > xa0 ? *--xa : 0;
+		d1 = y << ((32-Ebits) + k) | w >> (Ebits - k);
+		goto ret_d;
+		}
+	z = xa > xa0 ? *--xa : 0;
+	if (k -= Ebits) {
+		d0 = Exp_1 | y << k | z >> (32 - k);
+		y = xa > xa0 ? *--xa : 0;
+		d1 = z << k | y >> (32 - k);
+		}
+	else {
+		d0 = Exp_1 | y;
+		d1 = z;
+		}
+#else
+	if (k < Ebits + 16) {
+		z = xa > xa0 ? *--xa : 0;
+		d0 = Exp_1 | y << k - Ebits | z >> Ebits + 16 - k;
+		w = xa > xa0 ? *--xa : 0;
+		y = xa > xa0 ? *--xa : 0;
+		d1 = z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k;
+		goto ret_d;
+		}
+	z = xa > xa0 ? *--xa : 0;
+	w = xa > xa0 ? *--xa : 0;
+	k -= Ebits + 16;
+	d0 = Exp_1 | y << k + 16 | z << k | w >> 16 - k;
+	y = xa > xa0 ? *--xa : 0;
+	d1 = w << k + 16 | y << k;
+#endif
+ ret_d:
+#ifdef VAX
+	word0(&d) = d0 >> 16 | d0 << 16;
+	word1(&d) = d1 >> 16 | d1 << 16;
+#else
+#undef d0
+#undef d1
+#endif
+	return dval(&d);
+	}
+
+ static Bigint *
+d2b
+#ifdef KR_headers
+	(d, e, bits) U *d; int *e, *bits;
+#else
+	(U *d, int *e, int *bits)
+#endif
+{
+	Bigint *b;
+	int de, k;
+	ULong *x, y, z;
+#ifndef Sudden_Underflow
+	int i;
+#endif
+#ifdef VAX
+	ULong d0, d1;
+	d0 = word0(d) >> 16 | word0(d) << 16;
+	d1 = word1(d) >> 16 | word1(d) << 16;
+#else
+#define d0 word0(d)
+#define d1 word1(d)
+#endif
+
+#ifdef Pack_32
+	b = Balloc(1);
+#else
+	b = Balloc(2);
+#endif
+	x = b->x;
+
+	z = d0 & Frac_mask;
+	d0 &= 0x7fffffff;	/* clear sign bit, which we ignore */
+#ifdef Sudden_Underflow
+	de = (int)(d0 >> Exp_shift);
+#ifndef IBM
+	z |= Exp_msk11;
+#endif
+#else
+	de = (int)(d0 >> Exp_shift);
+	if (de)
+		z |= Exp_msk1;
+#endif
+#ifdef Pack_32
+	y = d1;
+	if (y) {
+		k = lo0bits(&y);
+		if (k) {
+			x[0] = y | z << (32 - k);
+			z >>= k;
+			}
+		else
+			x[0] = y;
+		x[1] = z;
+		b->wds = x[1] ? 2 : 1;
+#ifndef Sudden_Underflow
+		i = b->wds;
+#endif
+		}
+	else {
+		k = lo0bits(&z);
+		x[0] = z;
+#ifndef Sudden_Underflow
+		i =
+#endif
+		    b->wds = 1;
+		k += 32;
+		}
+#else
+	if (y = d1) {
+		if (k = lo0bits(&y))
+			if (k >= 16) {
+				x[0] = y | z << 32 - k & 0xffff;
+				x[1] = z >> k - 16 & 0xffff;
+				x[2] = z >> k;
+				i = 2;
+				}
+			else {
+				x[0] = y & 0xffff;
+				x[1] = y >> 16 | z << 16 - k & 0xffff;
+				x[2] = z >> k & 0xffff;
+				x[3] = z >> k+16;
+				i = 3;
+				}
+		else {
+			x[0] = y & 0xffff;
+			x[1] = y >> 16;
+			x[2] = z & 0xffff;
+			x[3] = z >> 16;
+			i = 3;
+			}
+		}
+	else {
+#ifdef DEBUG
+		if (!z)
+			Bug("Zero passed to d2b");
+#endif
+		k = lo0bits(&z);
+		if (k >= 16) {
+			x[0] = z;
+			i = 0;
+			}
+		else {
+			x[0] = z & 0xffff;
+			x[1] = z >> 16;
+			i = 1;
+			}
+		k += 32;
+		}
+	while(!x[i])
+		--i;
+	b->wds = i + 1;
+#endif
+#ifndef Sudden_Underflow
+	if (de) {
+#endif
+#ifdef IBM
+		*e = (de - Bias - (P-1) << 2) + k;
+		*bits = 4*P + 8 - k - hi0bits(word0(d) & Frac_mask);
+#else
+		*e = de - Bias - (P-1) + k;
+		*bits = P - k;
+#endif
+#ifndef Sudden_Underflow
+		}
+	else {
+		*e = de - Bias - (P-1) + 1 + k;
+#ifdef Pack_32
+		*bits = 32*i - hi0bits(x[i-1]);
+#else
+		*bits = (i+2)*16 - hi0bits(x[i]);
+#endif
+		}
+#endif
+	return b;
+	}
+#undef d0
+#undef d1
+
+ static double
+ratio
+#ifdef KR_headers
+	(a, b) Bigint *a, *b;
+#else
+	(Bigint *a, Bigint *b)
+#endif
+{
+	U da, db;
+	int k, ka, kb;
+
+	dval(&da) = b2d(a, &ka);
+	dval(&db) = b2d(b, &kb);
+#ifdef Pack_32
+	k = ka - kb + 32*(a->wds - b->wds);
+#else
+	k = ka - kb + 16*(a->wds - b->wds);
+#endif
+#ifdef IBM
+	if (k > 0) {
+		word0(&da) += (k >> 2)*Exp_msk1;
+		if (k &= 3)
+			dval(&da) *= 1 << k;
+		}
+	else {
+		k = -k;
+		word0(&db) += (k >> 2)*Exp_msk1;
+		if (k &= 3)
+			dval(&db) *= 1 << k;
+		}
+#else
+	if (k > 0)
+		word0(&da) += k*Exp_msk1;
+	else {
+		k = -k;
+		word0(&db) += k*Exp_msk1;
+		}
+#endif
+	return dval(&da) / dval(&db);
+	}
+
+ static CONST double
+tens[] = {
+		1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
+		1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
+		1e20, 1e21, 1e22
+#ifdef VAX
+		, 1e23, 1e24
+#endif
+		};
+
+ static CONST double
+#ifdef IEEE_Arith
+bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 };
+static CONST double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128,
+#ifdef Avoid_Underflow
+		9007199254740992.*9007199254740992.e-256
+		/* = 2^106 * 1e-256 */
+#else
+		1e-256
+#endif
+		};
+/* The factor of 2^53 in tinytens[4] helps us avoid setting the underflow */
+/* flag unnecessarily.  It leads to a song and dance at the end of strtod. */
+#define Scale_Bit 0x10
+#define n_bigtens 5
+#else
+#ifdef IBM
+bigtens[] = { 1e16, 1e32, 1e64 };
+static CONST double tinytens[] = { 1e-16, 1e-32, 1e-64 };
+#define n_bigtens 3
+#else
+bigtens[] = { 1e16, 1e32 };
+static CONST double tinytens[] = { 1e-16, 1e-32 };
+#define n_bigtens 2
+#endif
+#endif
+
+#undef Need_Hexdig
+#ifdef INFNAN_CHECK
+#ifndef No_Hex_NaN
+#define Need_Hexdig
+#endif
+#endif
+
+#ifndef Need_Hexdig
+#ifndef NO_HEX_FP
+#define Need_Hexdig
+#endif
+#endif
+
+#ifdef Need_Hexdig /*{*/
+static unsigned char hexdig[256];
+
+ static void
+#ifdef KR_headers
+htinit(h, s, inc) unsigned char *h; unsigned char *s; int inc;
+#else
+htinit(unsigned char *h, unsigned char *s, int inc)
+#endif
+{
+	int i, j;
+	for(i = 0; (j = s[i]) !=0; i++)
+		h[j] = (unsigned char)(i + inc);
+	}
+
+ static void
+#ifdef KR_headers
+hexdig_init()
+#else
+hexdig_init(void)
+#endif
+{
+#define USC (unsigned char *)
+	htinit(hexdig, USC "0123456789", 0x10);
+	htinit(hexdig, USC "abcdef", 0x10 + 10);
+	htinit(hexdig, USC "ABCDEF", 0x10 + 10);
+	}
+#endif /* } Need_Hexdig */
+
+#ifdef INFNAN_CHECK
+
+#ifndef NAN_WORD0
+#define NAN_WORD0 0x7ff80000
+#endif
+
+#ifndef NAN_WORD1
+#define NAN_WORD1 0
+#endif
+
+ static int
+match
+#ifdef KR_headers
+	(sp, t) char **sp, *t;
+#else
+	(CONST char **sp, CONST char *t)
+#endif
+{
+	int c, d;
+	CONST char *s = *sp;
+
+	for(d = *t++; d; d = *t++) {
+		if ((c = *++s) >= 'A' && c <= 'Z')
+			c += 'a' - 'A';
+		if (c != d)
+			return 0;
+		}
+	*sp = s + 1;
+	return 1;
+	}
+
+#ifndef No_Hex_NaN
+ static void
+hexnan
+#ifdef KR_headers
+	(rvp, sp) U *rvp; CONST char **sp;
+#else
+	(U *rvp, CONST char **sp)
+#endif
+{
+	ULong c, x[2];
+	CONST char *s;
+	int c1, havedig, udx0, xshift;
+
+	if (!hexdig['0'])
+		hexdig_init();
+	x[0] = x[1] = 0;
+	havedig = xshift = 0;
+	udx0 = 1;
+	s = *sp;
+	/* allow optional initial 0x or 0X */
+	for(c = *(CONST unsigned char*)(s+1); c && c <= ' '; c = *(CONST unsigned char*)(s+1))
+		++s;
+	if (s[1] == '0' && (s[2] == 'x' || s[2] == 'X'))
+		s += 2;
+	for(c = *(CONST unsigned char*)++s; c; c = *(CONST unsigned char*)++s) {
+		c1 = hexdig[c];
+		if (c1)
+			c  = c1 & 0xf;
+		else if (c <= ' ') {
+			if (udx0 && havedig) {
+				udx0 = 0;
+				xshift = 1;
+				}
+			continue;
+			}
+#ifdef GDTOA_NON_PEDANTIC_NANCHECK
+		else if (/*(*/ c == ')' && havedig) {
+			*sp = s + 1;
+			break;
+			}
+		else
+			return;	/* invalid form: don't change *sp */
+#else
+		else {
+			do {
+				if (/*(*/ c == ')') {
+					*sp = s + 1;
+					break;
+					}
+				c = *++s;
+				} while(c);
+			break;
+			}
+#endif
+		havedig = 1;
+		if (xshift) {
+			xshift = 0;
+			x[0] = x[1];
+			x[1] = 0;
+			}
+		if (udx0)
+			x[0] = (x[0] << 4) | (x[1] >> 28);
+		x[1] = (x[1] << 4) | c;
+		}
+	if ((x[0] &= 0xfffff) || x[1]) {
+		word0(rvp) = Exp_mask | x[0];
+		word1(rvp) = x[1];
+		}
+	}
+#endif /*No_Hex_NaN*/
+#endif /* INFNAN_CHECK */
+
+#ifdef Pack_32
+#define ULbits 32
+#define kshift 5
+#define kmask 31
+#else
+#define ULbits 16
+#define kshift 4
+#define kmask 15
+#endif
+#ifndef NO_HEX_FP /*{*/
+
+ static void
+#ifdef KR_headers
+rshift(b, k) Bigint *b; int k;
+#else
+rshift(Bigint *b, int k)
+#endif
+{
+	ULong *x, *x1, *xe, y;
+	int n;
+
+	x = x1 = b->x;
+	n = k >> kshift;
+	if (n < b->wds) {
+		xe = x + b->wds;
+		x += n;
+		if (k &= kmask) {
+			n = 32 - k;
+			y = *x++ >> k;
+			while(x < xe) {
+				*x1++ = (y | (*x << n)) & 0xffffffff;
+				y = *x++ >> k;
+				}
+			if ((*x1 = y) !=0)
+				x1++;
+			}
+		else
+			while(x < xe)
+				*x1++ = *x++;
+		}
+	if ((b->wds = x1 - b->x) == 0)
+		b->x[0] = 0;
+	}
+
+ static ULong
+#ifdef KR_headers
+any_on(b, k) Bigint *b; int k;
+#else
+any_on(Bigint *b, int k)
+#endif
+{
+	int n, nwds;
+	ULong *x, *x0, x1, x2;
+
+	x = b->x;
+	nwds = b->wds;
+	n = k >> kshift;
+	if (n > nwds)
+		n = nwds;
+	else if (n < nwds && (k &= kmask)) {
+		x1 = x2 = x[n];
+		x1 >>= k;
+		x1 <<= k;
+		if (x1 != x2)
+			return 1;
+		}
+	x0 = x;
+	x += n;
+	while(x > x0)
+		if (*--x)
+			return 1;
+	return 0;
+	}
+
+enum {	/* rounding values: same as FLT_ROUNDS */
+	Round_zero = 0,
+	Round_near = 1,
+	Round_up = 2,
+	Round_down = 3
+	};
+
+ static Bigint *
+#ifdef KR_headers
+increment(b) Bigint *b;
+#else
+increment(Bigint *b)
+#endif
+{
+	ULong *x, *xe;
+	Bigint *b1;
+
+	x = b->x;
+	xe = x + b->wds;
+	do {
+		if (*x < (ULong)0xffffffffL) {
+			++*x;
+			return b;
+			}
+		*x++ = 0;
+		} while(x < xe);
+	{
+		if (b->wds >= b->maxwds) {
+			b1 = Balloc(b->k+1);
+			Bcopy(b1,b);
+			Bfree(b);
+			b = b1;
+			}
+		b->x[b->wds++] = 1;
+		}
+	return b;
+	}
+
+ void
+#ifdef KR_headers
+gethex(sp, rvp, rounding, sign)
+	CONST char **sp; U *rvp; int rounding, sign;
+#else
+gethex( CONST char **sp, U *rvp, int rounding, int sign)
+#endif
+{
+	Bigint *b;
+	CONST unsigned char *decpt, *s0, *s, *s1;
+	Long e, e1;
+	ULong L, lostbits, *x;
+	int big, denorm, esign, havedig, k, n, nbits, up, zret;
+#ifdef IBM
+	int j;
+#endif
+	enum {
+#ifdef IEEE_Arith /*{{*/
+		emax = 0x7fe - Bias - P + 1,
+		emin = Emin - P + 1
+#else /*}{*/
+		emin = Emin - P,
+#ifdef VAX
+		emax = 0x7ff - Bias - P + 1
+#endif
+#ifdef IBM
+		emax = 0x7f - Bias - P
+#endif
+#endif /*}}*/
+		};
+#ifdef USE_LOCALE
+	int i;
+#ifdef NO_LOCALE_CACHE
+	const unsigned char *decimalpoint = (unsigned char*)
+		localeconv()->decimal_point;
+#else
+	const unsigned char *decimalpoint;
+	static unsigned char *decimalpoint_cache;
+	if (!(s0 = decimalpoint_cache)) {
+		s0 = (unsigned char*)localeconv()->decimal_point;
+		if ((decimalpoint_cache = (unsigned char*)
+				MALLOC(strlen((CONST char*)s0) + 1))) {
+			strcpy((char*)decimalpoint_cache, (CONST char*)s0);
+			s0 = decimalpoint_cache;
+			}
+		}
+	decimalpoint = s0;
+#endif
+#endif
+
+	if (!hexdig['0'])
+		hexdig_init();
+	havedig = 0;
+	s0 = *(CONST unsigned char **)sp + 2;
+	while(s0[havedig] == '0')
+		havedig++;
+	s0 += havedig;
+	s = s0;
+	decpt = 0;
+	zret = 0;
+	e = 0;
+	if (hexdig[*s])
+		havedig++;
+	else {
+		zret = 1;
+#ifdef USE_LOCALE
+		for(i = 0; decimalpoint[i]; ++i) {
+			if (s[i] != decimalpoint[i])
+				goto pcheck;
+			}
+		decpt = s += i;
+#else
+		if (*s != '.')
+			goto pcheck;
+		decpt = ++s;
+#endif
+		if (!hexdig[*s])
+			goto pcheck;
+		while(*s == '0')
+			s++;
+		if (hexdig[*s])
+			zret = 0;
+		havedig = 1;
+		s0 = s;
+		}
+	while(hexdig[*s])
+		s++;
+#ifdef USE_LOCALE
+	if (*s == *decimalpoint && !decpt) {
+		for(i = 1; decimalpoint[i]; ++i) {
+			if (s[i] != decimalpoint[i])
+				goto pcheck;
+			}
+		decpt = s += i;
+#else
+	if (*s == '.' && !decpt) {
+		decpt = ++s;
+#endif
+		while(hexdig[*s])
+			s++;
+		}/*}*/
+	if (decpt)
+		e = -(((Long)(s-decpt)) << 2);
+ pcheck:
+	s1 = s;
+	big = esign = 0;
+	switch(*s) {
+	  case 'p':
+	  case 'P':
+		switch(*++s) {
+		  case '-':
+			esign = 1;
+			/* no break */
+		  case '+':
+			s++;
+		  }
+		if ((n = hexdig[*s]) == 0 || n > 0x19) {
+			s = s1;
+			break;
+			}
+		e1 = n - 0x10;
+		while((n = hexdig[*++s]) !=0 && n <= 0x19) {
+			if (e1 & 0xf8000000)
+				big = 1;
+			e1 = 10*e1 + n - 0x10;
+			}
+		if (esign)
+			e1 = -e1;
+		e += e1;
+	  }
+	*sp = (char*)s;
+	if (!havedig)
+		*sp = (char*)s0 - 1;
+	if (zret)
+		goto retz1;
+	if (big) {
+		if (esign) {
+#ifdef IEEE_Arith
+			switch(rounding) {
+			  case Round_up:
+				if (sign)
+					break;
+				goto ret_tiny;
+			  case Round_down:
+				if (!sign)
+					break;
+				goto ret_tiny;
+			  }
+#endif
+			goto retz;
+#ifdef IEEE_Arith
+ ret_tiny:
+#ifndef NO_ERRNO
+			errno = ERANGE;
+#endif
+			word0(rvp) = 0;
+			word1(rvp) = 1;
+			return;
+#endif /* IEEE_Arith */
+			}
+		switch(rounding) {
+		  case Round_near:
+			goto ovfl1;
+		  case Round_up:
+			if (!sign)
+				goto ovfl1;
+			goto ret_big;
+		  case Round_down:
+			if (sign)
+				goto ovfl1;
+			goto ret_big;
+		  }
+ ret_big:
+		word0(rvp) = Big0;
+		word1(rvp) = Big1;
+		return;
+		}
+	n = s1 - s0 - 1;
+	for(k = 0; n > (1 << (kshift-2)) - 1; n >>= 1)
+		k++;
+	b = Balloc(k);
+	x = b->x;
+	n = 0;
+	L = 0;
+#ifdef USE_LOCALE
+	for(i = 0; decimalpoint[i+1]; ++i);
+#endif
+	while(s1 > s0) {
+#ifdef USE_LOCALE
+		if (*--s1 == decimalpoint[i]) {
+			s1 -= i;
+			continue;
+			}
+#else
+		if (*--s1 == '.')
+			continue;
+#endif
+		if (n == ULbits) {
+			*x++ = L;
+			L = 0;
+			n = 0;
+			}
+		L |= (hexdig[*s1] & 0x0f) << n;
+		n += 4;
+		}
+	*x++ = L;
+	b->wds = n = x - b->x;
+	n = ULbits*n - hi0bits(L);
+	nbits = Nbits;
+	lostbits = 0;
+	x = b->x;
+	if (n > nbits) {
+		n -= nbits;
+		if (any_on(b,n)) {
+			lostbits = 1;
+			k = n - 1;
+			if (x[k>>kshift] & 1 << (k & kmask)) {
+				lostbits = 2;
+				if (k > 0 && any_on(b,k))
+					lostbits = 3;
+				}
+			}
+		rshift(b, n);
+		e += n;
+		}
+	else if (n < nbits) {
+		n = nbits - n;
+		b = lshift(b, n);
+		e -= n;
+		x = b->x;
+		}
+	if (e > Emax) {
+ ovfl:
+		Bfree(b);
+ ovfl1:
+#ifndef NO_ERRNO
+		errno = ERANGE;
+#endif
+		word0(rvp) = Exp_mask;
+		word1(rvp) = 0;
+		return;
+		}
+	denorm = 0;
+	if (e < emin) {
+		denorm = 1;
+		n = emin - e;
+		if (n >= nbits) {
+#ifdef IEEE_Arith /*{*/
+			switch (rounding) {
+			  case Round_near:
+				if (n == nbits && (n < 2 || any_on(b,n-1)))
+					goto ret_tiny;
+				break;
+			  case Round_up:
+				if (!sign)
+					goto ret_tiny;
+				break;
+			  case Round_down:
+				if (sign)
+					goto ret_tiny;
+			  }
+#endif /* } IEEE_Arith */
+			Bfree(b);
+ retz:
+#ifndef NO_ERRNO
+			errno = ERANGE;
+#endif
+ retz1:
+			rvp->d = 0.;
+			return;
+			}
+		k = n - 1;
+		if (lostbits)
+			lostbits = 1;
+		else if (k > 0)
+			lostbits = any_on(b,k);
+		if (x[k>>kshift] & 1 << (k & kmask))
+			lostbits |= 2;
+		nbits -= n;
+		rshift(b,n);
+		e = emin;
+		}
+	if (lostbits) {
+		up = 0;
+		switch(rounding) {
+		  case Round_zero:
+			break;
+		  case Round_near:
+			if (lostbits & 2
+			 && (lostbits & 1) | (x[0] & 1))
+				up = 1;
+			break;
+		  case Round_up:
+			up = 1 - sign;
+			break;
+		  case Round_down:
+			up = sign;
+		  }
+		if (up) {
+			k = b->wds;
+			b = increment(b);
+			x = b->x;
+			if (denorm) {
+#if 0
+				if (nbits == Nbits - 1
+				 && x[nbits >> kshift] & 1 << (nbits & kmask))
+					denorm = 0; /* not currently used */
+#endif
+				}
+			else if (b->wds > k
+			 || ((n = nbits & kmask) !=0
+			     && hi0bits(x[k-1]) < 32-n)) {
+				rshift(b,1);
+				if (++e > Emax)
+					goto ovfl;
+				}
+			}
+		}
+#ifdef IEEE_Arith
+	if (denorm)
+		word0(rvp) = b->wds > 1 ? b->x[1] & ~0x100000 : 0;
+	else
+		word0(rvp) = (b->x[1] & ~0x100000) | ((e + 0x3ff + 52) << 20);
+	word1(rvp) = b->x[0];
+#endif
+#ifdef IBM
+	if ((j = e & 3)) {
+		k = b->x[0] & ((1 << j) - 1);
+		rshift(b,j);
+		if (k) {
+			switch(rounding) {
+			  case Round_up:
+				if (!sign)
+					increment(b);
+				break;
+			  case Round_down:
+				if (sign)
+					increment(b);
+				break;
+			  case Round_near:
+				j = 1 << (j-1);
+				if (k & j && ((k & (j-1)) | lostbits))
+					increment(b);
+			  }
+			}
+		}
+	e >>= 2;
+	word0(rvp) = b->x[1] | ((e + 65 + 13) << 24);
+	word1(rvp) = b->x[0];
+#endif
+#ifdef VAX
+	/* The next two lines ignore swap of low- and high-order 2 bytes. */
+	/* word0(rvp) = (b->x[1] & ~0x800000) | ((e + 129 + 55) << 23); */
+	/* word1(rvp) = b->x[0]; */
+	word0(rvp) = ((b->x[1] & ~0x800000) >> 16) | ((e + 129 + 55) << 7) | (b->x[1] << 16);
+	word1(rvp) = (b->x[0] >> 16) | (b->x[0] << 16);
+#endif
+	Bfree(b);
+	}
+#endif /*}!NO_HEX_FP*/
+
+ static int
+#ifdef KR_headers
+dshift(b, p2) Bigint *b; int p2;
+#else
+dshift(Bigint *b, int p2)
+#endif
+{
+	int rv = hi0bits(b->x[b->wds-1]) - 4;
+	if (p2 > 0)
+		rv -= p2;
+	return rv & kmask;
+	}
+
+ static int
+quorem
+#ifdef KR_headers
+	(b, S) Bigint *b, *S;
+#else
+	(Bigint *b, Bigint *S)
+#endif
+{
+	int n;
+	ULong *bx, *bxe, q, *sx, *sxe;
+#ifdef ULLong
+	ULLong borrow, carry, y, ys;
+#else
+	ULong borrow, carry, y, ys;
+#ifdef Pack_32
+	ULong si, z, zs;
+#endif
+#endif
+
+	n = S->wds;
+#ifdef DEBUG
+	/*debug*/ if (b->wds > n)
+	/*debug*/	Bug("oversize b in quorem");
+#endif
+	if (b->wds < n)
+		return 0;
+	sx = S->x;
+	sxe = sx + --n;
+	bx = b->x;
+	bxe = bx + n;
+	q = *bxe / (*sxe + 1);	/* ensure q <= true quotient */
+#ifdef DEBUG
+	/*debug*/ if (q > 9)
+	/*debug*/	Bug("oversized quotient in quorem");
+#endif
+	if (q) {
+		borrow = 0;
+		carry = 0;
+		do {
+#ifdef ULLong
+			ys = *sx++ * (ULLong)q + carry;
+			carry = ys >> 32;
+			y = *bx - (ys & FFFFFFFF) - borrow;
+			borrow = y >> 32 & (ULong)1;
+			*bx++ = y & FFFFFFFF;
+#else
+#ifdef Pack_32
+			si = *sx++;
+			ys = (si & 0xffff) * q + carry;
+			zs = (si >> 16) * q + (ys >> 16);
+			carry = zs >> 16;
+			y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
+			borrow = (y & 0x10000) >> 16;
+			z = (*bx >> 16) - (zs & 0xffff) - borrow;
+			borrow = (z & 0x10000) >> 16;
+			Storeinc(bx, z, y);
+#else
+			ys = *sx++ * q + carry;
+			carry = ys >> 16;
+			y = *bx - (ys & 0xffff) - borrow;
+			borrow = (y & 0x10000) >> 16;
+			*bx++ = y & 0xffff;
+#endif
+#endif
+			}
+			while(sx <= sxe);
+		if (!*bxe) {
+			bx = b->x;
+			while(--bxe > bx && !*bxe)
+				--n;
+			b->wds = n;
+			}
+		}
+	if (cmp(b, S) >= 0) {
+		q++;
+		borrow = 0;
+		carry = 0;
+		bx = b->x;
+		sx = S->x;
+		do {
+#ifdef ULLong
+			ys = *sx++ + carry;
+			carry = ys >> 32;
+			y = *bx - (ys & FFFFFFFF) - borrow;
+			borrow = y >> 32 & (ULong)1;
+			*bx++ = y & FFFFFFFF;
+#else
+#ifdef Pack_32
+			si = *sx++;
+			ys = (si & 0xffff) + carry;
+			zs = (si >> 16) + (ys >> 16);
+			carry = zs >> 16;
+			y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
+			borrow = (y & 0x10000) >> 16;
+			z = (*bx >> 16) - (zs & 0xffff) - borrow;
+			borrow = (z & 0x10000) >> 16;
+			Storeinc(bx, z, y);
+#else
+			ys = *sx++ + carry;
+			carry = ys >> 16;
+			y = *bx - (ys & 0xffff) - borrow;
+			borrow = (y & 0x10000) >> 16;
+			*bx++ = y & 0xffff;
+#endif
+#endif
+			}
+			while(sx <= sxe);
+		bx = b->x;
+		bxe = bx + n;
+		if (!*bxe) {
+			while(--bxe > bx && !*bxe)
+				--n;
+			b->wds = n;
+			}
+		}
+	return q;
+	}
+
+#ifndef NO_STRTOD_BIGCOMP
+
+ static void
+bigcomp
+#ifdef KR_headers
+	(rv, s0, bc)
+	U *rv; CONST char *s0; BCinfo *bc;
+#else
+	(U *rv, CONST char *s0, BCinfo *bc)
+#endif
+{
+	Bigint *b, *d;
+	int b2, bbits, d2, dd, dig, dsign, i, j, nd, nd0, p2, p5, speccase;
+
+	dsign = bc->dsign;
+	nd = bc->nd;
+	nd0 = bc->nd0;
+	p5 = nd + bc->e0 - 1;
+	dd = speccase = 0;
+#ifndef Sudden_Underflow
+	if (rv->d == 0.) {	/* special case: value near underflow-to-zero */
+				/* threshold was rounded to zero */
+		b = i2b(1);
+		p2 = Emin - P + 1;
+		bbits = 1;
+#ifdef Avoid_Underflow
+		word0(rv) = (P+2) << Exp_shift;
+#else
+		word1(rv) = 1;
+#endif
+		i = 0;
+#ifdef Honor_FLT_ROUNDS
+		if (bc->rounding == 1)
+#endif
+			{
+			speccase = 1;
+			--p2;
+			dsign = 0;
+			goto have_i;
+			}
+		}
+	else
+#endif
+		b = d2b(rv, &p2, &bbits);
+#ifdef Avoid_Underflow
+	p2 -= bc->scale;
+#endif
+	/* floor(log2(rv)) == bbits - 1 + p2 */
+	/* Check for denormal case. */
+	i = P - bbits;
+	if (i > (j = P - Emin - 1 + p2)) {
+#ifdef Sudden_Underflow
+		Bfree(b);
+		b = i2b(1);
+		p2 = Emin;
+		i = P - 1;
+#ifdef Avoid_Underflow
+		word0(rv) = (1 + bc->scale) << Exp_shift;
+#else
+		word0(rv) = Exp_msk1;
+#endif
+		word1(rv) = 0;
+#else
+		i = j;
+#endif
+		}
+#ifdef Honor_FLT_ROUNDS
+	if (bc->rounding != 1) {
+		if (i > 0)
+			b = lshift(b, i);
+		if (dsign)
+			b = increment(b);
+		}
+	else
+#endif
+		{
+		b = lshift(b, ++i);
+		b->x[0] |= 1;
+		}
+#ifndef Sudden_Underflow
+ have_i:
+#endif
+	p2 -= p5 + i;
+	d = i2b(1);
+	/* Arrange for convenient computation of quotients:
+	 * shift left if necessary so divisor has 4 leading 0 bits.
+	 */
+	if (p5 > 0)
+		d = pow5mult(d, p5);
+	else if (p5 < 0)
+		b = pow5mult(b, -p5);
+	if (p2 > 0) {
+		b2 = p2;
+		d2 = 0;
+		}
+	else {
+		b2 = 0;
+		d2 = -p2;
+		}
+	i = dshift(d, d2);
+	if ((b2 += i) > 0)
+		b = lshift(b, b2);
+	if ((d2 += i) > 0)
+		d = lshift(d, d2);
+
+	/* Now b/d = exactly half-way between the two floating-point values */
+	/* on either side of the input string.  Compute first digit of b/d. */
+
+	dig = quorem(b,d);
+	if (!dig) {
+		b = multadd(b, 10, 0);	/* very unlikely */
+		dig = quorem(b,d);
+		}
+
+	/* Compare b/d with s0 */
+
+	for(i = 0; i < nd0; ) {
+		dd = s0[i++] - '0' - dig;
+		if (dd)
+			goto ret;
+		if (!b->x[0] && b->wds == 1) {
+			if (i < nd)
+				dd = 1;
+			goto ret;
+			}
+		b = multadd(b, 10, 0);
+		dig = quorem(b,d);
+		}
+	for(j = bc->dp1; i++ < nd;) {
+		dd = s0[j++] - '0' - dig;
+		if (dd)
+			goto ret;
+		if (!b->x[0] && b->wds == 1) {
+			if (i < nd)
+				dd = 1;
+			goto ret;
+			}
+		b = multadd(b, 10, 0);
+		dig = quorem(b,d);
+		}
+	if (b->x[0] || b->wds > 1)
+		dd = -1;
+ ret:
+	Bfree(b);
+	Bfree(d);
+#ifdef Honor_FLT_ROUNDS
+	if (bc->rounding != 1) {
+		if (dd < 0) {
+			if (bc->rounding == 0) {
+				if (!dsign)
+					goto retlow1;
+				}
+			else if (dsign)
+				goto rethi1;
+			}
+		else if (dd > 0) {
+			if (bc->rounding == 0) {
+				if (dsign)
+					goto rethi1;
+				goto ret1;
+				}
+			if (!dsign)
+				goto rethi1;
+			dval(rv) += 2.*ulp(rv);
+			}
+		else {
+			bc->inexact = 0;
+			if (dsign)
+				goto rethi1;
+			}
+		}
+	else
+#endif
+	if (speccase) {
+		if (dd <= 0)
+			rv->d = 0.;
+		}
+	else if (dd < 0) {
+		if (!dsign)	/* does not happen for round-near */
+retlow1:
+			dval(rv) -= ulp(rv);
+		}
+	else if (dd > 0) {
+		if (dsign) {
+ rethi1:
+			dval(rv) += ulp(rv);
+			}
+		}
+	else {
+		/* Exact half-way case:  apply round-even rule. */
+		if (word1(rv) & 1) {
+			if (dsign)
+				goto rethi1;
+			goto retlow1;
+			}
+		}
+
+#ifdef Honor_FLT_ROUNDS
+ ret1:
+#endif
+	return;
+	}
+#endif /* NO_STRTOD_BIGCOMP */
+
+ double
+strtod
+#ifdef KR_headers
+	(s00, se) CONST char *s00; char **se;
+#else
+	(CONST char *s00, char **se)
+#endif
+{
+	int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, e, e1;
+	int esign, i, j, k, nd, nd0, nf, nz, nz0, sign;
+	CONST char *s, *s0, *s1;
+	double aadj, aadj1;
+	Long L;
+	U aadj2, adj, rv, rv0;
+	ULong y, z;
+	BCinfo bc;
+	Bigint *bb, *bb1, *bd, *bd0, *bs, *delta;
+#ifdef SET_INEXACT
+	int oldinexact;
+#endif
+#ifdef Honor_FLT_ROUNDS /*{*/
+#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */
+	bc.rounding = Flt_Rounds;
+#else /*}{*/
+	bc.rounding = 1;
+	switch(fegetround()) {
+	  case FE_TOWARDZERO:	bc.rounding = 0; break;
+	  case FE_UPWARD:	bc.rounding = 2; break;
+	  case FE_DOWNWARD:	bc.rounding = 3;
+	  }
+#endif /*}}*/
+#endif /*}*/
+#ifdef USE_LOCALE
+	CONST char *s2;
+#endif
+
+	sign = nz0 = nz = bc.dplen = bc.uflchk = 0;
+	dval(&rv) = 0.;
+	for(s = s00;;s++) switch(*s) {
+		case '-':
+			sign = 1;
+			/* no break */
+		case '+':
+			if (*++s)
+				goto break2;
+			/* no break */
+		case 0:
+			goto ret0;
+		case '\t':
+		case '\n':
+		case '\v':
+		case '\f':
+		case '\r':
+		case ' ':
+			continue;
+		default:
+			goto break2;
+		}
+ break2:
+	if (*s == '0') {
+#ifndef NO_HEX_FP /*{*/
+		switch(s[1]) {
+		  case 'x':
+		  case 'X':
+#ifdef Honor_FLT_ROUNDS
+			gethex(&s, &rv, bc.rounding, sign);
+#else
+			gethex(&s, &rv, 1, sign);
+#endif
+			goto ret;
+		  }
+#endif /*}*/
+		nz0 = 1;
+		while(*++s == '0') ;
+		if (!*s)
+			goto ret;
+		}
+	s0 = s;
+	y = z = 0;
+	for(nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++)
+		if (nd < 9)
+			y = 10*y + c - '0';
+		else if (nd < 16)
+			z = 10*z + c - '0';
+	nd0 = nd;
+	bc.dp0 = bc.dp1 = s - s0;
+#ifdef USE_LOCALE
+	s1 = localeconv()->decimal_point;
+	if (c == *s1) {
+		c = '.';
+		if (*++s1) {
+			s2 = s;
+			for(;;) {
+				if (*++s2 != *s1) {
+					c = 0;
+					break;
+					}
+				if (!*++s1) {
+					s = s2;
+					break;
+					}
+				}
+			}
+		}
+#endif
+	if (c == '.') {
+		c = *++s;
+		bc.dp1 = s - s0;
+		bc.dplen = bc.dp1 - bc.dp0;
+		if (!nd) {
+			for(; c == '0'; c = *++s)
+				nz++;
+			if (c > '0' && c <= '9') {
+				s0 = s;
+				nf += nz;
+				nz = 0;
+				goto have_dig;
+				}
+			goto dig_done;
+			}
+		for(; c >= '0' && c <= '9'; c = *++s) {
+ have_dig:
+			nz++;
+			if (c -= '0') {
+				nf += nz;
+				for(i = 1; i < nz; i++)
+					if (nd++ < 9)
+						y *= 10;
+					else if (nd <= DBL_DIG + 1)
+						z *= 10;
+				if (nd++ < 9)
+					y = 10*y + c;
+				else if (nd <= DBL_DIG + 1)
+					z = 10*z + c;
+				nz = 0;
+				}
+			}
+		}
+ dig_done:
+	e = 0;
+	if (c == 'e' || c == 'E') {
+		if (!nd && !nz && !nz0) {
+			goto ret0;
+			}
+		s00 = s;
+		esign = 0;
+		switch(c = *++s) {
+			case '-':
+				esign = 1;
+			case '+':
+				c = *++s;
+			}
+		if (c >= '0' && c <= '9') {
+			while(c == '0')
+				c = *++s;
+			if (c > '0' && c <= '9') {
+				L = c - '0';
+				s1 = s;
+				while((c = *++s) >= '0' && c <= '9')
+					L = 10*L + c - '0';
+				if (s - s1 > 8 || L > 19999)
+					/* Avoid confusion from exponents
+					 * so large that e might overflow.
+					 */
+					e = 19999; /* safe for 16 bit ints */
+				else
+					e = (int)L;
+				if (esign)
+					e = -e;
+				}
+			else
+				e = 0;
+			}
+		else
+			s = s00;
+		}
+	if (!nd) {
+		if (!nz && !nz0) {
+#ifdef INFNAN_CHECK
+			/* Check for Nan and Infinity */
+			if (!bc.dplen)
+			 switch(c) {
+			  case 'i':
+			  case 'I':
+				if (match(&s,"nf")) {
+					--s;
+					if (!match(&s,"inity"))
+						++s;
+					word0(&rv) = 0x7ff00000;
+					word1(&rv) = 0;
+					goto ret;
+					}
+				break;
+			  case 'n':
+			  case 'N':
+				if (match(&s, "an")) {
+					word0(&rv) = NAN_WORD0;
+					word1(&rv) = NAN_WORD1;
+#ifndef No_Hex_NaN
+					if (*s == '(') /*)*/
+						hexnan(&rv, &s);
+#endif
+					goto ret;
+					}
+			  }
+#endif /* INFNAN_CHECK */
+ ret0:
+			s = s00;
+			sign = 0;
+			}
+		goto ret;
+		}
+	bc.e0 = e1 = e -= nf;
+
+	/* Now we have nd0 digits, starting at s0, followed by a
+	 * decimal point, followed by nd-nd0 digits.  The number we're
+	 * after is the integer represented by those digits times
+	 * 10**e */
+
+	if (!nd0)
+		nd0 = nd;
+	k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1;
+	dval(&rv) = y;
+	if (k > 9) {
+#ifdef SET_INEXACT
+		if (k > DBL_DIG)
+			oldinexact = get_inexact();
+#endif
+		dval(&rv) = tens[k - 9] * dval(&rv) + z;
+		}
+	bd0 = 0;
+	if (nd <= DBL_DIG
+#ifndef RND_PRODQUOT
+#ifndef Honor_FLT_ROUNDS
+		&& Flt_Rounds == 1
+#endif
+#endif
+			) {
+		if (!e)
+			goto ret;
+		if (e > 0) {
+			if (e <= Ten_pmax) {
+#ifdef VAX
+				goto vax_ovfl_check;
+#else
+#ifdef Honor_FLT_ROUNDS
+				/* round correctly FLT_ROUNDS = 2 or 3 */
+				if (sign) {
+					rv.d = -rv.d;
+					sign = 0;
+					}
+#endif
+				/* rv = */ rounded_product(dval(&rv), tens[e]);
+				goto ret;
+#endif
+				}
+			i = DBL_DIG - nd;
+			if (e <= Ten_pmax + i) {
+				/* A fancier test would sometimes let us do
+				 * this for larger i values.
+				 */
+#ifdef Honor_FLT_ROUNDS
+				/* round correctly FLT_ROUNDS = 2 or 3 */
+				if (sign) {
+					rv.d = -rv.d;
+					sign = 0;
+					}
+#endif
+				e -= i;
+				dval(&rv) *= tens[i];
+#ifdef VAX
+				/* VAX exponent range is so narrow we must
+				 * worry about overflow here...
+				 */
+ vax_ovfl_check:
+				word0(&rv) -= P*Exp_msk1;
+				/* rv = */ rounded_product(dval(&rv), tens[e]);
+				if ((word0(&rv) & Exp_mask)
+				 > Exp_msk1*(DBL_MAX_EXP+Bias-1-P))
+					goto ovfl;
+				word0(&rv) += P*Exp_msk1;
+#else
+				/* rv = */ rounded_product(dval(&rv), tens[e]);
+#endif
+				goto ret;
+				}
+			}
+#ifndef Inaccurate_Divide
+		else if (e >= -Ten_pmax) {
+#ifdef Honor_FLT_ROUNDS
+			/* round correctly FLT_ROUNDS = 2 or 3 */
+			if (sign) {
+				rv.d = -rv.d;
+				sign = 0;
+				}
+#endif
+			/* rv = */ rounded_quotient(dval(&rv), tens[-e]);
+			goto ret;
+			}
+#endif
+		}
+	e1 += nd - k;
+
+#ifdef IEEE_Arith
+#ifdef SET_INEXACT
+	bc.inexact = 1;
+	if (k <= DBL_DIG)
+		oldinexact = get_inexact();
+#endif
+#ifdef Avoid_Underflow
+	bc.scale = 0;
+#endif
+#ifdef Honor_FLT_ROUNDS
+	if (bc.rounding >= 2) {
+		if (sign)
+			bc.rounding = bc.rounding == 2 ? 0 : 2;
+		else
+			if (bc.rounding != 2)
+				bc.rounding = 0;
+		}
+#endif
+#endif /*IEEE_Arith*/
+
+	/* Get starting approximation = rv * 10**e1 */
+
+	if (e1 > 0) {
+		i = e1 & 15;
+		if (i)
+			dval(&rv) *= tens[i];
+		if (e1 &= ~15) {
+			if (e1 > DBL_MAX_10_EXP) {
+ ovfl:
+#ifndef NO_ERRNO
+				errno = ERANGE;
+#endif
+				/* Can't trust HUGE_VAL */
+#ifdef IEEE_Arith
+#ifdef Honor_FLT_ROUNDS
+				switch(bc.rounding) {
+				  case 0: /* toward 0 */
+				  case 3: /* toward -infinity */
+					word0(&rv) = Big0;
+					word1(&rv) = Big1;
+					break;
+				  default:
+					word0(&rv) = Exp_mask;
+					word1(&rv) = 0;
+				  }
+#else /*Honor_FLT_ROUNDS*/
+				word0(&rv) = Exp_mask;
+				word1(&rv) = 0;
+#endif /*Honor_FLT_ROUNDS*/
+#ifdef SET_INEXACT
+				/* set overflow bit */
+				dval(&rv0) = 1e300;
+				dval(&rv0) *= dval(&rv0);
+#endif
+#else /*IEEE_Arith*/
+				word0(&rv) = Big0;
+				word1(&rv) = Big1;
+#endif /*IEEE_Arith*/
+				goto ret;
+				}
+			e1 >>= 4;
+			for(j = 0; e1 > 1; j++, e1 >>= 1)
+				if (e1 & 1)
+					dval(&rv) *= bigtens[j];
+		/* The last multiplication could overflow. */
+			word0(&rv) -= P*Exp_msk1;
+			dval(&rv) *= bigtens[j];
+			if ((z = word0(&rv) & Exp_mask)
+			 > Exp_msk1*(DBL_MAX_EXP+Bias-P))
+				goto ovfl;
+			if (z > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) {
+				/* set to largest number */
+				/* (Can't trust DBL_MAX) */
+				word0(&rv) = Big0;
+				word1(&rv) = Big1;
+				}
+			else
+				word0(&rv) += P*Exp_msk1;
+			}
+		}
+	else if (e1 < 0) {
+		e1 = -e1;
+		i = e1 & 15;
+		if (i)
+			dval(&rv) /= tens[i];
+		if (e1 >>= 4) {
+			if (e1 >= 1 << n_bigtens)
+				goto undfl;
+#ifdef Avoid_Underflow
+			if (e1 & Scale_Bit)
+				bc.scale = 2*P;
+			for(j = 0; e1 > 0; j++, e1 >>= 1)
+				if (e1 & 1)
+					dval(&rv) *= tinytens[j];
+			if (bc.scale && (j = 2*P + 1 - ((word0(&rv) & Exp_mask)
+						>> Exp_shift)) > 0) {
+				/* scaled rv is denormal; clear j low bits */
+				if (j >= 32) {
+					word1(&rv) = 0;
+					if (j >= 53)
+					 word0(&rv) = (P+2)*Exp_msk1;
+					else
+					 word0(&rv) &= 0xffffffff << (j-32);
+					}
+				else
+					word1(&rv) &= 0xffffffff << j;
+				}
+#else
+			for(j = 0; e1 > 1; j++, e1 >>= 1)
+				if (e1 & 1)
+					dval(&rv) *= tinytens[j];
+			/* The last multiplication could underflow. */
+			dval(&rv0) = dval(&rv);
+			dval(&rv) *= tinytens[j];
+			if (!dval(&rv)) {
+				dval(&rv) = 2.*dval(&rv0);
+				dval(&rv) *= tinytens[j];
+#endif
+				if (!dval(&rv)) {
+ undfl:
+					dval(&rv) = 0.;
+#ifndef NO_ERRNO
+					errno = ERANGE;
+#endif
+					goto ret;
+					}
+#ifndef Avoid_Underflow
+				word0(&rv) = Tiny0;
+				word1(&rv) = Tiny1;
+				/* The refinement below will clean
+				 * this approximation up.
+				 */
+				}
+#endif
+			}
+		}
+
+	/* Now the hard part -- adjusting rv to the correct value.*/
+
+	/* Put digits into bd: true value = bd * 10^e */
+
+	bc.nd = nd;
+#ifndef NO_STRTOD_BIGCOMP
+	bc.nd0 = nd0;	/* Only needed if nd > strtod_diglim, but done here */
+			/* to silence an erroneous warning about bc.nd0 */
+			/* possibly not being initialized. */
+	if (nd > strtod_diglim) {
+		/* ASSERT(strtod_diglim >= 18); 18 == one more than the */
+		/* minimum number of decimal digits to distinguish double values */
+		/* in IEEE arithmetic. */
+		i = j = 18;
+		if (i > nd0)
+			j += bc.dplen;
+		for(;;) {
+			if (--j <= bc.dp1 && j >= bc.dp0)
+				j = bc.dp0 - 1;
+			if (s0[j] != '0')
+				break;
+			--i;
+			}
+		e += nd - i;
+		nd = i;
+		if (nd0 > nd)
+			nd0 = nd;
+		if (nd < 9) { /* must recompute y */
+			y = 0;
+			for(i = 0; i < nd0; ++i)
+				y = 10*y + s0[i] - '0';
+			for(j = bc.dp1; i < nd; ++i)
+				y = 10*y + s0[j++] - '0';
+			}
+		}
+#endif
+	bd0 = s2b(s0, nd0, nd, y, bc.dplen);
+
+	for(;;) {
+		bd = Balloc(bd0->k);
+		Bcopy(bd, bd0);
+		bb = d2b(&rv, &bbe, &bbbits);	/* rv = bb * 2^bbe */
+		bs = i2b(1);
+
+		if (e >= 0) {
+			bb2 = bb5 = 0;
+			bd2 = bd5 = e;
+			}
+		else {
+			bb2 = bb5 = -e;
+			bd2 = bd5 = 0;
+			}
+		if (bbe >= 0)
+			bb2 += bbe;
+		else
+			bd2 -= bbe;
+		bs2 = bb2;
+#ifdef Honor_FLT_ROUNDS
+		if (bc.rounding != 1)
+			bs2++;
+#endif
+#ifdef Avoid_Underflow
+		j = bbe - bc.scale;
+		i = j + bbbits - 1;	/* logb(rv) */
+		if (i < Emin)	/* denormal */
+			j += P - Emin;
+		else
+			j = P + 1 - bbbits;
+#else /*Avoid_Underflow*/
+#ifdef Sudden_Underflow
+#ifdef IBM
+		j = 1 + 4*P - 3 - bbbits + ((bbe + bbbits - 1) & 3);
+#else
+		j = P + 1 - bbbits;
+#endif
+#else /*Sudden_Underflow*/
+		j = bbe;
+		i = j + bbbits - 1;	/* logb(rv) */
+		if (i < Emin)	/* denormal */
+			j += P - Emin;
+		else
+			j = P + 1 - bbbits;
+#endif /*Sudden_Underflow*/
+#endif /*Avoid_Underflow*/
+		bb2 += j;
+		bd2 += j;
+#ifdef Avoid_Underflow
+		bd2 += bc.scale;
+#endif
+		i = bb2 < bd2 ? bb2 : bd2;
+		if (i > bs2)
+			i = bs2;
+		if (i > 0) {
+			bb2 -= i;
+			bd2 -= i;
+			bs2 -= i;
+			}
+		if (bb5 > 0) {
+			bs = pow5mult(bs, bb5);
+			bb1 = mult(bs, bb);
+			Bfree(bb);
+			bb = bb1;
+			}
+		if (bb2 > 0)
+			bb = lshift(bb, bb2);
+		if (bd5 > 0)
+			bd = pow5mult(bd, bd5);
+		if (bd2 > 0)
+			bd = lshift(bd, bd2);
+		if (bs2 > 0)
+			bs = lshift(bs, bs2);
+		delta = diff(bb, bd);
+		bc.dsign = delta->sign;
+		delta->sign = 0;
+		i = cmp(delta, bs);
+#ifndef NO_STRTOD_BIGCOMP
+		if (bc.nd > nd && i <= 0) {
+			if (bc.dsign)
+				break;	/* Must use bigcomp(). */
+#ifdef Honor_FLT_ROUNDS
+			if (bc.rounding != 1) {
+				if (i < 0)
+					break;
+				}
+			else
+#endif
+				{
+				bc.nd = nd;
+				i = -1;	/* Discarded digits make delta smaller. */
+				}
+			}
+#endif
+#ifdef Honor_FLT_ROUNDS
+		if (bc.rounding != 1) {
+			if (i < 0) {
+				/* Error is less than an ulp */
+				if (!delta->x[0] && delta->wds <= 1) {
+					/* exact */
+#ifdef SET_INEXACT
+					bc.inexact = 0;
+#endif
+					break;
+					}
+				if (bc.rounding) {
+					if (bc.dsign) {
+						adj.d = 1.;
+						goto apply_adj;
+						}
+					}
+				else if (!bc.dsign) {
+					adj.d = -1.;
+					if (!word1(&rv)
+					 && !(word0(&rv) & Frac_mask)) {
+						y = word0(&rv) & Exp_mask;
+#ifdef Avoid_Underflow
+						if (!bc.scale || y > 2*P*Exp_msk1)
+#else
+						if (y)
+#endif
+						  {
+						  delta = lshift(delta,Log2P);
+						  if (cmp(delta, bs) <= 0)
+							adj.d = -0.5;
+						  }
+						}
+ apply_adj:
+#ifdef Avoid_Underflow
+					if (bc.scale && (y = word0(&rv) & Exp_mask)
+						<= 2*P*Exp_msk1)
+					  word0(&adj) += (2*P+1)*Exp_msk1 - y;
+#else
+#ifdef Sudden_Underflow
+					if ((word0(&rv) & Exp_mask) <=
+							P*Exp_msk1) {
+						word0(&rv) += P*Exp_msk1;
+						dval(&rv) += adj.d*ulp(dval(&rv));
+						word0(&rv) -= P*Exp_msk1;
+						}
+					else
+#endif /*Sudden_Underflow*/
+#endif /*Avoid_Underflow*/
+					dval(&rv) += adj.d*ulp(&rv);
+					}
+				break;
+				}
+			adj.d = ratio(delta, bs);
+			if (adj.d < 1.)
+				adj.d = 1.;
+			if (adj.d <= 0x7ffffffe) {
+				/* adj = rounding ? ceil(adj) : floor(adj); */
+				y = adj.d;
+				if (y != adj.d) {
+					if (!((bc.rounding>>1) ^ bc.dsign))
+						y++;
+					adj.d = y;
+					}
+				}
+#ifdef Avoid_Underflow
+			if (bc.scale && (y = word0(&rv) & Exp_mask) <= 2*P*Exp_msk1)
+				word0(&adj) += (2*P+1)*Exp_msk1 - y;
+#else
+#ifdef Sudden_Underflow
+			if ((word0(&rv) & Exp_mask) <= P*Exp_msk1) {
+				word0(&rv) += P*Exp_msk1;
+				adj.d *= ulp(dval(&rv));
+				if (bc.dsign)
+					dval(&rv) += adj.d;
+				else
+					dval(&rv) -= adj.d;
+				word0(&rv) -= P*Exp_msk1;
+				goto cont;
+				}
+#endif /*Sudden_Underflow*/
+#endif /*Avoid_Underflow*/
+			adj.d *= ulp(&rv);
+			if (bc.dsign) {
+				if (word0(&rv) == Big0 && word1(&rv) == Big1)
+					goto ovfl;
+				dval(&rv) += adj.d;
+				}
+			else
+				dval(&rv) -= adj.d;
+			goto cont;
+			}
+#endif /*Honor_FLT_ROUNDS*/
+
+		if (i < 0) {
+			/* Error is less than half an ulp -- check for
+			 * special case of mantissa a power of two.
+			 */
+			if (bc.dsign || word1(&rv) || word0(&rv) & Bndry_mask
+#ifdef IEEE_Arith
+#ifdef Avoid_Underflow
+			 || (word0(&rv) & Exp_mask) <= (2*P+1)*Exp_msk1
+#else
+			 || (word0(&rv) & Exp_mask) <= Exp_msk1
+#endif
+#endif
+				) {
+#ifdef SET_INEXACT
+				if (!delta->x[0] && delta->wds <= 1)
+					bc.inexact = 0;
+#endif
+				break;
+				}
+			if (!delta->x[0] && delta->wds <= 1) {
+				/* exact result */
+#ifdef SET_INEXACT
+				bc.inexact = 0;
+#endif
+				break;
+				}
+			delta = lshift(delta,Log2P);
+			if (cmp(delta, bs) > 0)
+				goto drop_down;
+			break;
+			}
+		if (i == 0) {
+			/* exactly half-way between */
+			if (bc.dsign) {
+				if ((word0(&rv) & Bndry_mask1) == Bndry_mask1
+				 &&  word1(&rv) == (
+#ifdef Avoid_Underflow
+			(bc.scale && (y = word0(&rv) & Exp_mask) <= 2*P*Exp_msk1)
+		? (0xffffffff & (0xffffffff << (2*P+1-(y>>Exp_shift)))) :
+#endif
+						   0xffffffff)) {
+					/*boundary case -- increment exponent*/
+					word0(&rv) = (word0(&rv) & Exp_mask)
+						+ Exp_msk1
+#ifdef IBM
+						| Exp_msk1 >> 4
+#endif
+						;
+					word1(&rv) = 0;
+#ifdef Avoid_Underflow
+					bc.dsign = 0;
+#endif
+					break;
+					}
+				}
+			else if (!(word0(&rv) & Bndry_mask) && !word1(&rv)) {
+ drop_down:
+				/* boundary case -- decrement exponent */
+#ifdef Sudden_Underflow /*{{*/
+				L = word0(&rv) & Exp_mask;
+#ifdef IBM
+				if (L <  Exp_msk1)
+#else
+#ifdef Avoid_Underflow
+				if (L <= (bc.scale ? (2*P+1)*Exp_msk1 : Exp_msk1))
+#else
+				if (L <= Exp_msk1)
+#endif /*Avoid_Underflow*/
+#endif /*IBM*/
+					{
+					if (bc.nd >nd) {
+						bc.uflchk = 1;
+						break;
+						}
+					goto undfl;
+					}
+				L -= Exp_msk1;
+#else /*Sudden_Underflow}{*/
+#ifdef Avoid_Underflow
+				if (bc.scale) {
+					L = word0(&rv) & Exp_mask;
+					if (L <= (2*P+1)*Exp_msk1) {
+						if (L > (P+2)*Exp_msk1)
+							/* round even ==> */
+							/* accept rv */
+							break;
+						/* rv = smallest denormal */
+						if (bc.nd >nd) {
+							bc.uflchk = 1;
+							break;
+							}
+						goto undfl;
+						}
+					}
+#endif /*Avoid_Underflow*/
+				L = (word0(&rv) & Exp_mask) - Exp_msk1;
+#endif /*Sudden_Underflow}}*/
+				word0(&rv) = L | Bndry_mask1;
+				word1(&rv) = 0xffffffff;
+#ifdef IBM
+				goto cont;
+#else
+				break;
+#endif
+				}
+#ifndef ROUND_BIASED
+			if (!(word1(&rv) & LSB))
+				break;
+#endif
+			if (bc.dsign)
+				dval(&rv) += ulp(&rv);
+#ifndef ROUND_BIASED
+			else {
+				dval(&rv) -= ulp(&rv);
+#ifndef Sudden_Underflow
+				if (!dval(&rv)) {
+					if (bc.nd >nd) {
+						bc.uflchk = 1;
+						break;
+						}
+					goto undfl;
+					}
+#endif
+				}
+#ifdef Avoid_Underflow
+			bc.dsign = 1 - bc.dsign;
+#endif
+#endif
+			break;
+			}
+		if ((aadj = ratio(delta, bs)) <= 2.) {
+			if (bc.dsign)
+				aadj = aadj1 = 1.;
+			else if (word1(&rv) || word0(&rv) & Bndry_mask) {
+#ifndef Sudden_Underflow
+				if (word1(&rv) == Tiny1 && !word0(&rv)) {
+					if (bc.nd >nd) {
+						bc.uflchk = 1;
+						break;
+						}
+					goto undfl;
+					}
+#endif
+				aadj = 1.;
+				aadj1 = -1.;
+				}
+			else {
+				/* special case -- power of FLT_RADIX to be */
+				/* rounded down... */
+
+				if (aadj < 2./FLT_RADIX)
+					aadj = 1./FLT_RADIX;
+				else
+					aadj *= 0.5;
+				aadj1 = -aadj;
+				}
+			}
+		else {
+			aadj *= 0.5;
+			aadj1 = bc.dsign ? aadj : -aadj;
+#ifdef Check_FLT_ROUNDS
+			switch(bc.rounding) {
+				case 2: /* towards +infinity */
+					aadj1 -= 0.5;
+					break;
+				case 0: /* towards 0 */
+				case 3: /* towards -infinity */
+					aadj1 += 0.5;
+				}
+#else
+			if (Flt_Rounds == 0)
+				aadj1 += 0.5;
+#endif /*Check_FLT_ROUNDS*/
+			}
+		y = word0(&rv) & Exp_mask;
+
+		/* Check for overflow */
+
+		if (y == Exp_msk1*(DBL_MAX_EXP+Bias-1)) {
+			dval(&rv0) = dval(&rv);
+			word0(&rv) -= P*Exp_msk1;
+			adj.d = aadj1 * ulp(&rv);
+			dval(&rv) += adj.d;
+			if ((word0(&rv) & Exp_mask) >=
+					Exp_msk1*(DBL_MAX_EXP+Bias-P)) {
+				if (word0(&rv0) == Big0 && word1(&rv0) == Big1)
+					goto ovfl;
+				word0(&rv) = Big0;
+				word1(&rv) = Big1;
+				goto cont;
+				}
+			else
+				word0(&rv) += P*Exp_msk1;
+			}
+		else {
+#ifdef Avoid_Underflow
+			if (bc.scale && y <= 2*P*Exp_msk1) {
+				if (aadj <= 0x7fffffff) {
+					if ((z = (ULong)aadj) <= 0)
+						z = 1;
+					aadj = z;
+					aadj1 = bc.dsign ? aadj : -aadj;
+					}
+				dval(&aadj2) = aadj1;
+				word0(&aadj2) += (2*P+1)*Exp_msk1 - y;
+				aadj1 = dval(&aadj2);
+				}
+			adj.d = aadj1 * ulp(&rv);
+			dval(&rv) += adj.d;
+#else
+#ifdef Sudden_Underflow
+			if ((word0(&rv) & Exp_mask) <= P*Exp_msk1) {
+				dval(&rv0) = dval(&rv);
+				word0(&rv) += P*Exp_msk1;
+				adj.d = aadj1 * ulp(&rv);
+				dval(&rv) += adj.d;
+#ifdef IBM
+				if ((word0(&rv) & Exp_mask) <  P*Exp_msk1)
+#else
+				if ((word0(&rv) & Exp_mask) <= P*Exp_msk1)
+#endif
+					{
+					if (word0(&rv0) == Tiny0
+					 && word1(&rv0) == Tiny1) {
+						if (bc.nd >nd) {
+							bc.uflchk = 1;
+							break;
+							}
+						goto undfl;
+						}
+					word0(&rv) = Tiny0;
+					word1(&rv) = Tiny1;
+					goto cont;
+					}
+				else
+					word0(&rv) -= P*Exp_msk1;
+				}
+			else {
+				adj.d = aadj1 * ulp(&rv);
+				dval(&rv) += adj.d;
+				}
+#else /*Sudden_Underflow*/
+			/* Compute adj so that the IEEE rounding rules will
+			 * correctly round rv + adj in some half-way cases.
+			 * If rv * ulp(rv) is denormalized (i.e.,
+			 * y <= (P-1)*Exp_msk1), we must adjust aadj to avoid
+			 * trouble from bits lost to denormalization;
+			 * example: 1.2e-307 .
+			 */
+			if (y <= (P-1)*Exp_msk1 && aadj > 1.) {
+				aadj1 = (double)(int)(aadj + 0.5);
+				if (!bc.dsign)
+					aadj1 = -aadj1;
+				}
+			adj.d = aadj1 * ulp(&rv);
+			dval(&rv) += adj.d;
+#endif /*Sudden_Underflow*/
+#endif /*Avoid_Underflow*/
+			}
+		z = word0(&rv) & Exp_mask;
+#ifndef SET_INEXACT
+		if (bc.nd == nd) {
+#ifdef Avoid_Underflow
+		if (!bc.scale)
+#endif
+		if (y == z) {
+			/* Can we stop now? */
+			L = (Long)aadj;
+			aadj -= L;
+			/* The tolerances below are conservative. */
+			if (bc.dsign || word1(&rv) || word0(&rv) & Bndry_mask) {
+				if (aadj < .4999999 || aadj > .5000001)
+					break;
+				}
+			else if (aadj < .4999999/FLT_RADIX)
+				break;
+			}
+		}
+#endif
+ cont:
+		Bfree(bb);
+		Bfree(bd);
+		Bfree(bs);
+		Bfree(delta);
+		}
+	Bfree(bb);
+	Bfree(bd);
+	Bfree(bs);
+	Bfree(bd0);
+	Bfree(delta);
+#ifndef NO_STRTOD_BIGCOMP
+	if (bc.nd > nd)
+		bigcomp(&rv, s0, &bc);
+#endif
+#ifdef SET_INEXACT
+	if (bc.inexact) {
+		if (!oldinexact) {
+			word0(&rv0) = Exp_1 + (70 << Exp_shift);
+			word1(&rv0) = 0;
+			dval(&rv0) += 1.;
+			}
+		}
+	else if (!oldinexact)
+		clear_inexact();
+#endif
+#ifdef Avoid_Underflow
+	if (bc.scale) {
+		word0(&rv0) = Exp_1 - 2*P*Exp_msk1;
+		word1(&rv0) = 0;
+		dval(&rv) *= dval(&rv0);
+#ifndef NO_ERRNO
+		/* try to avoid the bug of testing an 8087 register value */
+#ifdef IEEE_Arith
+		if (!(word0(&rv) & Exp_mask))
+#else
+		if (word0(&rv) == 0 && word1(&rv) == 0)
+#endif
+			errno = ERANGE;
+#endif
+		}
+#endif /* Avoid_Underflow */
+#ifdef SET_INEXACT
+	if (bc.inexact && !(word0(&rv) & Exp_mask)) {
+		/* set underflow bit */
+		dval(&rv0) = 1e-300;
+		dval(&rv0) *= dval(&rv0);
+		}
+#endif
+ ret:
+	if (se)
+		*se = (char *)s;
+	return sign ? -dval(&rv) : dval(&rv);
+	}
+
+#ifndef MULTIPLE_THREADS
+ static char *dtoa_result;
+#endif
+
+ static char *
+#ifdef KR_headers
+rv_alloc(i) int i;
+#else
+rv_alloc(int i)
+#endif
+{
+	int j, k, *r;
+
+	j = sizeof(ULong);
+	for(k = 0;
+		sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= (size_t)i;
+		j <<= 1)
+			k++;
+	r = (int*)Balloc(k);
+	*r = k;
+	return
+#ifndef MULTIPLE_THREADS
+	dtoa_result =
+#endif
+		(char *)(r+1);
+	}
+
+ static char *
+#ifdef KR_headers
+nrv_alloc(s, rve, n) char *s, **rve; int n;
+#else
+nrv_alloc(CONST char *s, char **rve, int n)
+#endif
+{
+	char *rv, *t;
+
+	t = rv = rv_alloc(n);
+	for(*t = *s++; *t; *t = *s++) t++;
+	if (rve)
+		*rve = t;
+	return rv;
+	}
+
+/* freedtoa(s) must be used to free values s returned by dtoa
+ * when MULTIPLE_THREADS is #defined.  It should be used in all cases,
+ * but for consistency with earlier versions of dtoa, it is optional
+ * when MULTIPLE_THREADS is not defined.
+ */
+
+ void
+#ifdef KR_headers
+freedtoa(s) char *s;
+#else
+freedtoa(char *s)
+#endif
+{
+	Bigint *b = (Bigint *)((int *)s - 1);
+	b->maxwds = 1 << (b->k = *(int*)b);
+	Bfree(b);
+#ifndef MULTIPLE_THREADS
+	if (s == dtoa_result)
+		dtoa_result = 0;
+#endif
+	}
+
+/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string.
+ *
+ * Inspired by "How to Print Floating-Point Numbers Accurately" by
+ * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126].
+ *
+ * Modifications:
+ *	1. Rather than iterating, we use a simple numeric overestimate
+ *	   to determine k = floor(log10(d)).  We scale relevant
+ *	   quantities using O(log2(k)) rather than O(k) multiplications.
+ *	2. For some modes > 2 (corresponding to ecvt and fcvt), we don't
+ *	   try to generate digits strictly left to right.  Instead, we
+ *	   compute with fewer bits and propagate the carry if necessary
+ *	   when rounding the final digit up.  This is often faster.
+ *	3. Under the assumption that input will be rounded nearest,
+ *	   mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22.
+ *	   That is, we allow equality in stopping tests when the
+ *	   round-nearest rule will give the same floating-point value
+ *	   as would satisfaction of the stopping test with strict
+ *	   inequality.
+ *	4. We remove common factors of powers of 2 from relevant
+ *	   quantities.
+ *	5. When converting floating-point integers less than 1e16,
+ *	   we use floating-point arithmetic rather than resorting
+ *	   to multiple-precision integers.
+ *	6. When asked to produce fewer than 15 digits, we first try
+ *	   to get by with floating-point arithmetic; we resort to
+ *	   multiple-precision integer arithmetic only if we cannot
+ *	   guarantee that the floating-point calculation has given
+ *	   the correctly rounded result.  For k requested digits and
+ *	   "uniformly" distributed input, the probability is
+ *	   something like 10^(k-15) that we must resort to the Long
+ *	   calculation.
+ */
+
+ char *
+dtoa
+#ifdef KR_headers
+	(dd, mode, ndigits, decpt, sign, rve)
+	double dd; int mode, ndigits, *decpt, *sign; char **rve;
+#else
+	(double dd, int mode, int ndigits, int *decpt, int *sign, char **rve)
+#endif
+{
+ /*	Arguments ndigits, decpt, sign are similar to those
+	of ecvt and fcvt; trailing zeros are suppressed from
+	the returned string.  If not null, *rve is set to point
+	to the end of the return value.  If d is +-Infinity or NaN,
+	then *decpt is set to 9999.
+
+	mode:
+		0 ==> shortest string that yields d when read in
+			and rounded to nearest.
+		1 ==> like 0, but with Steele & White stopping rule;
+			e.g. with IEEE P754 arithmetic , mode 0 gives
+			1e23 whereas mode 1 gives 9.999999999999999e22.
+		2 ==> max(1,ndigits) significant digits.  This gives a
+			return value similar to that of ecvt, except
+			that trailing zeros are suppressed.
+		3 ==> through ndigits past the decimal point.  This
+			gives a return value similar to that from fcvt,
+			except that trailing zeros are suppressed, and
+			ndigits can be negative.
+		4,5 ==> similar to 2 and 3, respectively, but (in
+			round-nearest mode) with the tests of mode 0 to
+			possibly return a shorter string that rounds to d.
+			With IEEE arithmetic and compilation with
+			-DHonor_FLT_ROUNDS, modes 4 and 5 behave the same
+			as modes 2 and 3 when FLT_ROUNDS != 1.
+		6-9 ==> Debugging modes similar to mode - 4:  don't try
+			fast floating-point estimate (if applicable).
+
+		Values of mode other than 0-9 are treated as mode 0.
+
+		Sufficient space is allocated to the return value
+		to hold the suppressed trailing zeros.
+	*/
+
+	int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1,
+		j, j1, k, k0, k_check, leftright, m2, m5, s2, s5,
+		spec_case, try_quick;
+	Long L;
+#ifndef Sudden_Underflow
+	int denorm;
+	ULong x;
+#endif
+	Bigint *b, *b1, *delta, *mlo = NULL, *mhi, *S;
+	U d2, eps, u;
+	double ds;
+	char *s, *s0;
+#ifdef SET_INEXACT
+	int inexact, oldinexact;
+#endif
+#ifdef Honor_FLT_ROUNDS /*{*/
+	int Rounding;
+#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */
+	Rounding = Flt_Rounds;
+#else /*}{*/
+	Rounding = 1;
+	switch(fegetround()) {
+	  case FE_TOWARDZERO:	Rounding = 0; break;
+	  case FE_UPWARD:	Rounding = 2; break;
+	  case FE_DOWNWARD:	Rounding = 3;
+	  }
+#endif /*}}*/
+#endif /*}*/
+
+#ifndef MULTIPLE_THREADS
+	if (dtoa_result) {
+		freedtoa(dtoa_result);
+		dtoa_result = 0;
+		}
+#endif
+
+	u.d = dd;
+	if (word0(&u) & Sign_bit) {
+		/* set sign for everything, including 0's and NaNs */
+		*sign = 1;
+		word0(&u) &= ~Sign_bit;	/* clear sign bit */
+		}
+	else
+		*sign = 0;
+
+#if defined(IEEE_Arith) + defined(VAX)
+#ifdef IEEE_Arith
+	if ((word0(&u) & Exp_mask) == Exp_mask)
+#else
+	if (word0(&u)  == 0x8000)
+#endif
+		{
+		/* Infinity or NaN */
+		*decpt = 9999;
+#ifdef IEEE_Arith
+		if (!word1(&u) && !(word0(&u) & 0xfffff))
+			return nrv_alloc("Infinity", rve, 8);
+#endif
+		return nrv_alloc("NaN", rve, 3);
+		}
+#endif
+#ifdef IBM
+	dval(&u) += 0; /* normalize */
+#endif
+	if (!dval(&u)) {
+		*decpt = 1;
+		return nrv_alloc("0", rve, 1);
+		}
+
+#ifdef SET_INEXACT
+	try_quick = oldinexact = get_inexact();
+	inexact = 1;
+#endif
+#ifdef Honor_FLT_ROUNDS
+	if (Rounding >= 2) {
+		if (*sign)
+			Rounding = Rounding == 2 ? 0 : 2;
+		else
+			if (Rounding != 2)
+				Rounding = 0;
+		}
+#endif
+
+	b = d2b(&u, &be, &bbits);
+	i = (int)(word0(&u) >> Exp_shift1 & (Exp_mask>>Exp_shift1));
+#ifndef Sudden_Underflow
+	if (i) {
+#endif
+		dval(&d2) = dval(&u);
+		word0(&d2) &= Frac_mask1;
+		word0(&d2) |= Exp_11;
+#ifdef IBM
+		if (j = 11 - hi0bits(word0(&d2) & Frac_mask))
+			dval(&d2) /= 1 << j;
+#endif
+
+		/* log(x)	~=~ log(1.5) + (x-1.5)/1.5
+		 * log10(x)	 =  log(x) / log(10)
+		 *		~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10))
+		 * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2)
+		 *
+		 * This suggests computing an approximation k to log10(d) by
+		 *
+		 * k = (i - Bias)*0.301029995663981
+		 *	+ ( (d2-1.5)*0.289529654602168 + 0.176091259055681 );
+		 *
+		 * We want k to be too large rather than too small.
+		 * The error in the first-order Taylor series approximation
+		 * is in our favor, so we just round up the constant enough
+		 * to compensate for any error in the multiplication of
+		 * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077,
+		 * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14,
+		 * adding 1e-13 to the constant term more than suffices.
+		 * Hence we adjust the constant term to 0.1760912590558.
+		 * (We could get a more accurate k by invoking log10,
+		 *  but this is probably not worthwhile.)
+		 */
+
+		i -= Bias;
+#ifdef IBM
+		i <<= 2;
+		i += j;
+#endif
+#ifndef Sudden_Underflow
+		denorm = 0;
+		}
+	else {
+		/* d is denormalized */
+
+		i = bbits + be + (Bias + (P-1) - 1);
+		x = i > 32  ? word0(&u) << (64 - i) | word1(&u) >> (i - 32)
+			    : word1(&u) << (32 - i);
+		dval(&d2) = x;
+		word0(&d2) -= 31*Exp_msk1; /* adjust exponent */
+		i -= (Bias + (P-1) - 1) + 1;
+		denorm = 1;
+		}
+#endif
+	ds = (dval(&d2)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981;
+	k = (int)ds;
+	if (ds < 0. && ds != k)
+		k--;	/* want k = floor(ds) */
+	k_check = 1;
+	if (k >= 0 && k <= Ten_pmax) {
+		if (dval(&u) < tens[k])
+			k--;
+		k_check = 0;
+		}
+	j = bbits - i - 1;
+	if (j >= 0) {
+		b2 = 0;
+		s2 = j;
+		}
+	else {
+		b2 = -j;
+		s2 = 0;
+		}
+	if (k >= 0) {
+		b5 = 0;
+		s5 = k;
+		s2 += k;
+		}
+	else {
+		b2 -= k;
+		b5 = -k;
+		s5 = 0;
+		}
+	if (mode < 0 || mode > 9)
+		mode = 0;
+
+#ifndef SET_INEXACT
+#ifdef Check_FLT_ROUNDS
+	try_quick = Rounding == 1;
+#else
+	try_quick = 1;
+#endif
+#endif /*SET_INEXACT*/
+
+	if (mode > 5) {
+		mode -= 4;
+		try_quick = 0;
+		}
+	leftright = 1;
+	ilim = ilim1 = -1;	/* Values for cases 0 and 1; done here to */
+				/* silence erroneous "gcc -Wall" warning. */
+	switch(mode) {
+		case 0:
+		case 1:
+			i = 18;
+			ndigits = 0;
+			break;
+		case 2:
+			leftright = 0;
+			/* no break */
+		case 4:
+			if (ndigits <= 0)
+				ndigits = 1;
+			ilim = ilim1 = i = ndigits;
+			break;
+		case 3:
+			leftright = 0;
+			/* no break */
+		case 5:
+			i = ndigits + k + 1;
+			ilim = i;
+			ilim1 = i - 1;
+			if (i <= 0)
+				i = 1;
+		}
+	s = s0 = rv_alloc(i);
+
+#ifdef Honor_FLT_ROUNDS
+	if (mode > 1 && Rounding != 1)
+		leftright = 0;
+#endif
+
+	if (ilim >= 0 && ilim <= Quick_max && try_quick) {
+
+		/* Try to get by with floating-point arithmetic. */
+
+		i = 0;
+		dval(&d2) = dval(&u);
+		k0 = k;
+		ilim0 = ilim;
+		ieps = 2; /* conservative */
+		if (k > 0) {
+			ds = tens[k&0xf];
+			j = k >> 4;
+			if (j & Bletch) {
+				/* prevent overflows */
+				j &= Bletch - 1;
+				dval(&u) /= bigtens[n_bigtens-1];
+				ieps++;
+				}
+			for(; j; j >>= 1, i++)
+				if (j & 1) {
+					ieps++;
+					ds *= bigtens[i];
+					}
+			dval(&u) /= ds;
+			}
+		else {
+			j1 = -k;
+			if (j1) {
+				dval(&u) *= tens[j1 & 0xf];
+				for(j = j1 >> 4; j; j >>= 1, i++)
+					if (j & 1) {
+						ieps++;
+						dval(&u) *= bigtens[i];
+						}
+				}
+			}
+		if (k_check && dval(&u) < 1. && ilim > 0) {
+			if (ilim1 <= 0)
+				goto fast_failed;
+			ilim = ilim1;
+			k--;
+			dval(&u) *= 10.;
+			ieps++;
+			}
+		dval(&eps) = ieps*dval(&u) + 7.;
+		word0(&eps) -= (P-1)*Exp_msk1;
+		if (ilim == 0) {
+			S = mhi = 0;
+			dval(&u) -= 5.;
+			if (dval(&u) > dval(&eps))
+				goto one_digit;
+			if (dval(&u) < -dval(&eps))
+				goto no_digits;
+			goto fast_failed;
+			}
+#ifndef No_leftright
+		if (leftright) {
+			/* Use Steele & White method of only
+			 * generating digits needed.
+			 */
+			dval(&eps) = 0.5/tens[ilim-1] - dval(&eps);
+			for(i = 0;;) {
+				L = (long)dval(&u);
+				dval(&u) -= L;
+				*s++ = '0' + (char)L;
+				if (dval(&u) < dval(&eps))
+					goto ret1;
+				if (1. - dval(&u) < dval(&eps))
+					goto bump_up;
+				if (++i >= ilim)
+					break;
+				dval(&eps) *= 10.;
+				dval(&u) *= 10.;
+				}
+			}
+		else {
+#endif
+			/* Generate ilim digits, then fix them up. */
+			dval(&eps) *= tens[ilim-1];
+			for(i = 1;; i++, dval(&u) *= 10.) {
+				L = (Long)(dval(&u));
+				if (!(dval(&u) -= L))
+					ilim = i;
+				*s++ = '0' + (char)L;
+				if (i == ilim) {
+					if (dval(&u) > 0.5 + dval(&eps))
+						goto bump_up;
+					else if (dval(&u) < 0.5 - dval(&eps)) {
+						while(*--s == '0') {}
+						s++;
+						goto ret1;
+						}
+					break;
+					}
+				}
+#ifndef No_leftright
+			}
+#endif
+ fast_failed:
+		s = s0;
+		dval(&u) = dval(&d2);
+		k = k0;
+		ilim = ilim0;
+		}
+
+	/* Do we have a "small" integer? */
+
+	if (be >= 0 && k <= Int_max) {
+		/* Yes. */
+		ds = tens[k];
+		if (ndigits < 0 && ilim <= 0) {
+			S = mhi = 0;
+			if (ilim < 0 || dval(&u) <= 5*ds)
+				goto no_digits;
+			goto one_digit;
+			}
+		for(i = 1; i <= k + 1; i++, dval(&u) *= 10.) {
+			L = (Long)(dval(&u) / ds);
+			dval(&u) -= L*ds;
+#ifdef Check_FLT_ROUNDS
+			/* If FLT_ROUNDS == 2, L will usually be high by 1 */
+			if (dval(&u) < 0) {
+				L--;
+				dval(&u) += ds;
+				}
+#endif
+			*s++ = '0' + (char)L;
+			if (!dval(&u)) {
+#ifdef SET_INEXACT
+				inexact = 0;
+#endif
+				break;
+				}
+			if (i == ilim) {
+#ifdef Honor_FLT_ROUNDS
+				if (mode > 1)
+				switch(Rounding) {
+				  case 0: goto ret1;
+				  case 2: goto bump_up;
+				  }
+#endif
+				dval(&u) += dval(&u);
+				if (dval(&u) > ds || (dval(&u) == ds && L & 1)) {
+ bump_up:
+					while(*--s == '9')
+						if (s == s0) {
+							k++;
+							*s = '0';
+							break;
+							}
+					++*s++;
+					}
+				break;
+				}
+			}
+		goto ret1;
+		}
+
+	m2 = b2;
+	m5 = b5;
+	mhi = mlo = 0;
+	if (leftright) {
+		i =
+#ifndef Sudden_Underflow
+			denorm ? be + (Bias + (P-1) - 1 + 1) :
+#endif
+#ifdef IBM
+			1 + 4*P - 3 - bbits + ((bbits + be - 1) & 3);
+#else
+			1 + P - bbits;
+#endif
+		b2 += i;
+		s2 += i;
+		mhi = i2b(1);
+		}
+	if (m2 > 0 && s2 > 0) {
+		i = m2 < s2 ? m2 : s2;
+		b2 -= i;
+		m2 -= i;
+		s2 -= i;
+		}
+	if (b5 > 0) {
+		if (leftright) {
+			if (m5 > 0) {
+				mhi = pow5mult(mhi, m5);
+				b1 = mult(mhi, b);
+				Bfree(b);
+				b = b1;
+				}
+			j = b5 - m5;
+			if (j)
+				b = pow5mult(b, j);
+			}
+		else
+			b = pow5mult(b, b5);
+		}
+	S = i2b(1);
+	if (s5 > 0)
+		S = pow5mult(S, s5);
+
+	/* Check for special case that d is a normalized power of 2. */
+
+	spec_case = 0;
+	if ((mode < 2 || leftright)
+#ifdef Honor_FLT_ROUNDS
+			&& Rounding == 1
+#endif
+				) {
+		if (!word1(&u) && !(word0(&u) & Bndry_mask)
+#ifndef Sudden_Underflow
+		 && word0(&u) & (Exp_mask & ~Exp_msk1)
+#endif
+				) {
+			/* The special case */
+			b2 += Log2P;
+			s2 += Log2P;
+			spec_case = 1;
+			}
+		}
+
+	/* Arrange for convenient computation of quotients:
+	 * shift left if necessary so divisor has 4 leading 0 bits.
+	 *
+	 * Perhaps we should just compute leading 28 bits of S once
+	 * and for all and pass them and a shift to quorem, so it
+	 * can do shifts and ors to compute the numerator for q.
+	 */
+#ifdef Pack_32
+	i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f;
+	if (i)
+		i = 32 - i;
+#define iInc 28
+#else
+	if (i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0xf)
+		i = 16 - i;
+#define iInc 12
+#endif
+	i = dshift(S, s2);
+	b2 += i;
+	m2 += i;
+	s2 += i;
+	if (b2 > 0)
+		b = lshift(b, b2);
+	if (s2 > 0)
+		S = lshift(S, s2);
+	if (k_check) {
+		if (cmp(b,S) < 0) {
+			k--;
+			b = multadd(b, 10, 0);	/* we botched the k estimate */
+			if (leftright)
+				mhi = multadd(mhi, 10, 0);
+			ilim = ilim1;
+			}
+		}
+	if (ilim <= 0 && (mode == 3 || mode == 5)) {
+		if (ilim < 0 || cmp(b,S = multadd(S,5,0)) <= 0) {
+			/* no digits, fcvt style */
+ no_digits:
+			k = -1 - ndigits;
+			goto ret;
+			}
+ one_digit:
+		*s++ = '1';
+		k++;
+		goto ret;
+		}
+	if (leftright) {
+		if (m2 > 0)
+			mhi = lshift(mhi, m2);
+
+		/* Compute mlo -- check for special case
+		 * that d is a normalized power of 2.
+		 */
+
+		mlo = mhi;
+		if (spec_case) {
+			mhi = Balloc(mhi->k);
+			Bcopy(mhi, mlo);
+			mhi = lshift(mhi, Log2P);
+			}
+
+		for(i = 1;;i++) {
+			dig = quorem(b,S) + '0';
+			/* Do we yet have the shortest decimal string
+			 * that will round to d?
+			 */
+			j = cmp(b, mlo);
+			delta = diff(S, mhi);
+			j1 = delta->sign ? 1 : cmp(b, delta);
+			Bfree(delta);
+#ifndef ROUND_BIASED
+			if (j1 == 0 && mode != 1 && !(word1(&u) & 1)
+#ifdef Honor_FLT_ROUNDS
+				&& Rounding >= 1
+#endif
+								   ) {
+				if (dig == '9')
+					goto round_9_up;
+				if (j > 0)
+					dig++;
+#ifdef SET_INEXACT
+				else if (!b->x[0] && b->wds <= 1)
+					inexact = 0;
+#endif
+				*s++ = (char)dig;
+				goto ret;
+				}
+#endif
+			if (j < 0 || (j == 0 && mode != 1
+#ifndef ROUND_BIASED
+							&& !(word1(&u) & 1)
+#endif
+					)) {
+				if (!b->x[0] && b->wds <= 1) {
+#ifdef SET_INEXACT
+					inexact = 0;
+#endif
+					goto accept_dig;
+					}
+#ifdef Honor_FLT_ROUNDS
+				if (mode > 1)
+				 switch(Rounding) {
+				  case 0: goto accept_dig;
+				  case 2: goto keep_dig;
+				  }
+#endif /*Honor_FLT_ROUNDS*/
+				if (j1 > 0) {
+					b = lshift(b, 1);
+					j1 = cmp(b, S);
+					if ((j1 > 0 || (j1 == 0 && dig & 1))
+					&& dig++ == '9')
+						goto round_9_up;
+					}
+ accept_dig:
+				*s++ = (char)dig;
+				goto ret;
+				}
+			if (j1 > 0) {
+#ifdef Honor_FLT_ROUNDS
+				if (!Rounding)
+					goto accept_dig;
+#endif
+				if (dig == '9') { /* possible if i == 1 */
+ round_9_up:
+					*s++ = '9';
+					goto roundoff;
+					}
+				*s++ = (char)dig + 1;
+				goto ret;
+				}
+#ifdef Honor_FLT_ROUNDS
+ keep_dig:
+#endif
+			*s++ = (char)dig;
+			if (i == ilim)
+				break;
+			b = multadd(b, 10, 0);
+			if (mlo == mhi)
+				mlo = mhi = multadd(mhi, 10, 0);
+			else {
+				mlo = multadd(mlo, 10, 0);
+				mhi = multadd(mhi, 10, 0);
+				}
+			}
+		}
+	else
+		for(i = 1;; i++) {
+			dig = quorem(b,S) + '0';
+			*s++ = (char)dig;
+			if (!b->x[0] && b->wds <= 1) {
+#ifdef SET_INEXACT
+				inexact = 0;
+#endif
+				goto ret;
+				}
+			if (i >= ilim)
+				break;
+			b = multadd(b, 10, 0);
+			}
+
+	/* Round off last digit */
+
+#ifdef Honor_FLT_ROUNDS
+	switch(Rounding) {
+	  case 0: goto trimzeros;
+	  case 2: goto roundoff;
+	  }
+#endif
+	b = lshift(b, 1);
+	j = cmp(b, S);
+	if (j > 0 || (j == 0 && dig & 1)) {
+ roundoff:
+		while(*--s == '9')
+			if (s == s0) {
+				k++;
+				*s++ = '1';
+				goto ret;
+				}
+		++*s++;
+		}
+	else {
+#ifdef Honor_FLT_ROUNDS
+ trimzeros:
+#endif
+		while(*--s == '0') {}
+		s++;
+		}
+ ret:
+	Bfree(S);
+	if (mhi) {
+		if (mlo && mlo != mhi)
+			Bfree(mlo);
+		Bfree(mhi);
+		}
+ ret1:
+#ifdef SET_INEXACT
+	if (inexact) {
+		if (!oldinexact) {
+			word0(&u) = Exp_1 + (70 << Exp_shift);
+			word1(&u) = 0;
+			dval(&u) += 1.;
+			}
+		}
+	else if (!oldinexact)
+		clear_inexact();
+#endif
+	Bfree(b);
+	*s = 0;
+	*decpt = k + 1;
+	if (rve)
+		*rve = s;
+	return s0;
+	}
+
+}  // namespace dmg_fp
diff --git a/base/third_party/dmg_fp/dtoa_wrapper.cc b/base/third_party/dmg_fp/dtoa_wrapper.cc
new file mode 100644
index 0000000..c314c59
--- /dev/null
+++ b/base/third_party/dmg_fp/dtoa_wrapper.cc
@@ -0,0 +1,46 @@
+// Copyright (c) 2012 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.
+//
+// The purpose of this file is to supply the macro definintions necessary
+// to make third_party/dmg_fp/dtoa.cc threadsafe.
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/synchronization/lock.h"
+
+// We need two locks because they're sometimes grabbed at the same time.
+// A single lock would lead to an attempted recursive grab.
+static base::LazyInstance<base::Lock>::Leaky
+    dtoa_lock_0 = LAZY_INSTANCE_INITIALIZER;
+static base::LazyInstance<base::Lock>::Leaky
+    dtoa_lock_1 = LAZY_INSTANCE_INITIALIZER;
+
+/*
+ * This define and the code below is to trigger thread-safe behavior
+ * in dtoa.cc, per this comment from the file:
+ *
+ * #define MULTIPLE_THREADS if the system offers preemptively scheduled
+ *	multiple threads.  In this case, you must provide (or suitably
+ *	#define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed
+ *	by FREE_DTOA_LOCK(n) for n = 0 or 1.  (The second lock, accessed
+ *	in pow5mult, ensures lazy evaluation of only one copy of high
+ *	powers of 5; omitting this lock would introduce a small
+ *	probability of wasting memory, but would otherwise be harmless.)
+ *	You must also invoke freedtoa(s) to free the value s returned by
+ *	dtoa.  You may do so whether or not MULTIPLE_THREADS is #defined.
+ */
+#define MULTIPLE_THREADS
+
+inline static void ACQUIRE_DTOA_LOCK(size_t n) {
+  DCHECK(n < 2);
+  base::Lock* lock = n == 0 ? dtoa_lock_0.Pointer() : dtoa_lock_1.Pointer();
+  lock->Acquire();
+}
+
+inline static void FREE_DTOA_LOCK(size_t n) {
+  DCHECK(n < 2);
+  base::Lock* lock = n == 0 ? dtoa_lock_0.Pointer() : dtoa_lock_1.Pointer();
+  lock->Release();
+}
+
+#include "base/third_party/dmg_fp/dtoa.cc"
diff --git a/base/third_party/dmg_fp/float_precision_crash.patch b/base/third_party/dmg_fp/float_precision_crash.patch
new file mode 100644
index 0000000..df64e7e
--- /dev/null
+++ b/base/third_party/dmg_fp/float_precision_crash.patch
@@ -0,0 +1,13 @@
+diff --git a/base/third_party/dmg_fp/dtoa.cc b/base/third_party/dmg_fp/dtoa.cc
+index 3f7e794..3312fa4 100644
+--- dtoa.cc
++++ dtoa.cc
+@@ -3891,7 +3891,7 @@ dtoa
+ 				goto no_digits;
+ 			goto one_digit;
+ 			}
+-		for(i = 1;; i++, dval(&u) *= 10.) {
++		for(i = 1; i <= k + 1; i++, dval(&u) *= 10.) {
+ 			L = (Long)(dval(&u) / ds);
+ 			dval(&u) -= L*ds;
+ #ifdef Check_FLT_ROUNDS
diff --git a/base/third_party/dmg_fp/g_fmt.cc b/base/third_party/dmg_fp/g_fmt.cc
new file mode 100644
index 0000000..bfa358d
--- /dev/null
+++ b/base/third_party/dmg_fp/g_fmt.cc
@@ -0,0 +1,102 @@
+/****************************************************************
+ *
+ * The author of this software is David M. Gay.
+ *
+ * Copyright (c) 1991, 1996 by Lucent Technologies.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ ***************************************************************/
+
+/* g_fmt(buf,x) stores the closest decimal approximation to x in buf;
+ * it suffices to declare buf
+ *	char buf[32];
+ */
+
+#include "dmg_fp.h"
+
+namespace dmg_fp {
+
+ char *
+g_fmt(register char *b, double x)
+{
+	register int i, k;
+	register char *s;
+	int decpt, j, sign;
+	char *b0, *s0, *se;
+
+	b0 = b;
+#ifdef IGNORE_ZERO_SIGN
+	if (!x) {
+		*b++ = '0';
+		*b = 0;
+		goto done;
+		}
+#endif
+	s = s0 = dtoa(x, 0, 0, &decpt, &sign, &se);
+	if (sign)
+		*b++ = '-';
+	if (decpt == 9999) /* Infinity or Nan */ {
+		for(*b = *s++; *b++; *b = *s++) {}
+		goto done0;
+		}
+	if (decpt <= -4 || decpt > se - s + 5) {
+		*b++ = *s++;
+		if (*s) {
+			*b++ = '.';
+			for(*b = *s++; *b; *b = *s++)
+				b++;
+			}
+		*b++ = 'e';
+		/* sprintf(b, "%+.2d", decpt - 1); */
+		if (--decpt < 0) {
+			*b++ = '-';
+			decpt = -decpt;
+			}
+		else
+			*b++ = '+';
+		for(j = 2, k = 10; 10*k <= decpt; j++, k *= 10) {}
+		for(;;) {
+			i = decpt / k;
+			*b++ = (char)i + '0';
+			if (--j <= 0)
+				break;
+			decpt -= i*k;
+			decpt *= 10;
+			}
+		*b = 0;
+		}
+	else if (decpt <= 0) {
+		*b++ = '.';
+		for(; decpt < 0; decpt++)
+			*b++ = '0';
+		for(*b = *s++; *b++; *b = *s++) {}
+		}
+	else {
+		for(*b = *s++; *b; *b = *s++) {
+			b++;
+			if (--decpt == 0 && *s)
+				*b++ = '.';
+			}
+		for(; decpt > 0; decpt--)
+			*b++ = '0';
+		*b = 0;
+		}
+ done0:
+	freedtoa(s0);
+#ifdef IGNORE_ZERO_SIGN
+ done:
+#endif
+	return b0;
+	}
+
+}  // namespace dmg_fp
diff --git a/base/third_party/dmg_fp/gcc_64_bit.patch b/base/third_party/dmg_fp/gcc_64_bit.patch
new file mode 100644
index 0000000..ab943c0
--- /dev/null
+++ b/base/third_party/dmg_fp/gcc_64_bit.patch
@@ -0,0 +1,25 @@
+Index: dtoa.cc
+--- dtoa.cc    (old copy)
++++ dtoa.cc    (working copy)
+@@ -183,8 +183,12 @@
+ #define NO_HEX_FP
+ 
+ #ifndef Long
++#if __LP64__
++#define Long int
++#else
+ #define Long long
+ #endif
++#endif
+ #ifndef ULong
+ typedef unsigned Long ULong;
+ #endif
+@@ -221,7 +225,7 @@ extern void *MALLOC(size_t);
+ #ifndef PRIVATE_MEM
+ #define PRIVATE_MEM 2304
+ #endif
+-#define PRIVATE_mem ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double))
++#define PRIVATE_mem ((unsigned)((PRIVATE_MEM+sizeof(double)-1)/sizeof(double)))
+ static double private_mem[PRIVATE_mem], *pmem_next = private_mem;
+ #endif
+ 
diff --git a/base/third_party/dmg_fp/gcc_warnings.patch b/base/third_party/dmg_fp/gcc_warnings.patch
new file mode 100644
index 0000000..4262237
--- /dev/null
+++ b/base/third_party/dmg_fp/gcc_warnings.patch
@@ -0,0 +1,126 @@
+Index: dtoa.cc
+--- dtoa.cc    (old copy)
++++ dtoa.cc    (working copy)
+@@ -179,6 +179,9 @@
+  *	used for input more than STRTOD_DIGLIM digits long (default 40).
+  */
+ 
++#define IEEE_8087
++#define NO_HEX_FP
++
+ #ifndef Long
+ #define Long long
+ #endif
+@@ -280,9 +283,7 @@
+ #include "math.h"
+ #endif
+ 
+-#ifdef __cplusplus
+-extern "C" {
+-#endif
++namespace dmg_fp {
+ 
+ #ifndef CONST
+ #ifdef KR_headers
+@@ -511,11 +512,9 @@
+ 
+ #define Kmax 7
+ 
+-#ifdef __cplusplus
+-extern "C" double strtod(const char *s00, char **se);
+-extern "C" char *dtoa(double d, int mode, int ndigits,
++double strtod(const char *s00, char **se);
++char *dtoa(double d, int mode, int ndigits,
+ 			int *decpt, int *sign, char **rve);
+-#endif
+ 
+  struct
+ Bigint {
+@@ -1527,7 +1526,7 @@
+ #ifdef KR_headers
+ 	(sp, t) char **sp, *t;
+ #else
+-	(CONST char **sp, char *t)
++	(CONST char **sp, CONST char *t)
+ #endif
+ {
+ 	int c, d;
+@@ -2234,7 +2234,7 @@ bigcomp
+ 	nd = bc->nd;
+ 	nd0 = bc->nd0;
+ 	p5 = nd + bc->e0 - 1;
+-	speccase = 0;
++	dd = speccase = 0;
+ #ifndef Sudden_Underflow
+ 	if (rv->d == 0.) {	/* special case: value near underflow-to-zero */
+ 				/* threshold was rounded to zero */
+@@ -3431,7 +3430,7 @@
+ 
+ 	j = sizeof(ULong);
+ 	for(k = 0;
+-		sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= i;
++		sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= (size_t)i;
+ 		j <<= 1)
+ 			k++;
+ 	r = (int*)Balloc(k);
+@@ -3447,7 +3446,7 @@
+ #ifdef KR_headers
+ nrv_alloc(s, rve, n) char *s, **rve; int n;
+ #else
+-nrv_alloc(char *s, char **rve, int n)
++nrv_alloc(CONST char *s, char **rve, int n)
+ #endif
+ {
+ 	char *rv, *t;
+@@ -4202,6 +4201,5 @@
+ 		*rve = s;
+ 	return s0;
+ 	}
+-#ifdef __cplusplus
+-}
+-#endif
++
++}  // namespace dmg_fp
+Index: g_fmt.cc
+--- g_fmt.cc   (old copy)
++++ g_fmt.cc   (new copy)
+@@ -46,14 +46,14 @@ g_fmt(register char *b, double x)
+ 	if (sign)
+ 		*b++ = '-';
+ 	if (decpt == 9999) /* Infinity or Nan */ {
+-		while(*b++ = *s++);
++		while((*b++ = *s++));
+ 		goto done0;
+ 		}
+ 	if (decpt <= -4 || decpt > se - s + 5) {
+ 		*b++ = *s++;
+ 		if (*s) {
+ 			*b++ = '.';
+-			while(*b = *s++)
++			while((*b = *s++))
+ 				b++;
+ 			}
+ 		*b++ = 'e';
+@@ -79,10 +79,10 @@ g_fmt(register char *b, double x)
+ 		*b++ = '.';
+ 		for(; decpt < 0; decpt++)
+ 			*b++ = '0';
+-		while(*b++ = *s++);
++		while((*b++ = *s++));
+ 		}
+ 	else {
+-		while(*b = *s++) {
++		while((*b = *s++)) {
+ 			b++;
+ 			if (--decpt == 0 && *s)
+ 				*b++ = '.';
+@@ -93,7 +93,9 @@ g_fmt(register char *b, double x)
+ 		}
+  done0:
+ 	freedtoa(s0);
++#ifdef IGNORE_ZERO_SIGN
+  done:
++#endif
+ 	return b0;
+ 	}
+ 
diff --git a/base/third_party/dmg_fp/mac_wextra.patch b/base/third_party/dmg_fp/mac_wextra.patch
new file mode 100644
index 0000000..15340f2
--- /dev/null
+++ b/base/third_party/dmg_fp/mac_wextra.patch
@@ -0,0 +1,53 @@
+Index: g_fmt.cc
+===================================================================
+--- g_fmt.cc	(revision 49784)
++++ g_fmt.cc	(working copy)
+@@ -46,7 +46,7 @@
+ 	if (sign)
+ 		*b++ = '-';
+ 	if (decpt == 9999) /* Infinity or Nan */ {
+-		while((*b++ = *s++));
++		while((*b++ = *s++)) {}
+ 		goto done0;
+ 		}
+ 	if (decpt <= -4 || decpt > se - s + 5) {
+@@ -64,7 +64,7 @@
+ 			}
+ 		else
+ 			*b++ = '+';
+-		for(j = 2, k = 10; 10*k <= decpt; j++, k *= 10);
++		for(j = 2, k = 10; 10*k <= decpt; j++, k *= 10) {}
+ 		for(;;) {
+ 			i = decpt / k;
+ 			*b++ = i + '0';
+@@ -79,7 +79,7 @@
+ 		*b++ = '.';
+ 		for(; decpt < 0; decpt++)
+ 			*b++ = '0';
+-		while((*b++ = *s++));
++		while((*b++ = *s++)) {}
+ 		}
+ 	else {
+ 		while((*b = *s++)) {
+Index: dtoa.cc
+===================================================================
+--- dtoa.cc	(revision 49784)
++++ dtoa.cc	(working copy)
+@@ -3863,7 +3863,7 @@
+ 					if (dval(&u) > 0.5 + dval(&eps))
+ 						goto bump_up;
+ 					else if (dval(&u) < 0.5 - dval(&eps)) {
+-						while(*--s == '0');
++						while(*--s == '0') {}
+ 						s++;
+ 						goto ret1;
+ 						}
+@@ -4176,7 +4176,7 @@
+ #ifdef Honor_FLT_ROUNDS
+  trimzeros:
+ #endif
+-		while(*--s == '0');
++		while(*--s == '0') {}
+ 		s++;
+ 		}
+  ret:
diff --git a/base/third_party/dmg_fp/msvc_warnings.patch b/base/third_party/dmg_fp/msvc_warnings.patch
new file mode 100644
index 0000000..22e89cd
--- /dev/null
+++ b/base/third_party/dmg_fp/msvc_warnings.patch
@@ -0,0 +1,419 @@
+diff --git a/base/third_party/dmg_fp/dtoa.cc b/base/third_party/dmg_fp/dtoa.cc
+index 3312fa4..502c16c 100644
+--- a/base/third_party/dmg_fp/dtoa.cc
++++ b/base/third_party/dmg_fp/dtoa.cc
+@@ -548,8 +548,10 @@ Balloc
+ 	ACQUIRE_DTOA_LOCK(0);
+ 	/* The k > Kmax case does not need ACQUIRE_DTOA_LOCK(0), */
+ 	/* but this case seems very unlikely. */
+-	if (k <= Kmax && (rv = freelist[k]))
++	if (k <= Kmax && freelist[k]) {
++		rv = freelist[k];
+ 		freelist[k] = rv->next;
++		}
+ 	else {
+ 		x = 1 << k;
+ #ifdef Omit_Private_Memory
+@@ -650,7 +652,7 @@ multadd
+ 			Bfree(b);
+ 			b = b1;
+ 			}
+-		b->x[wds++] = carry;
++		b->x[wds++] = (ULong)carry;
+ 		b->wds = wds;
+ 		}
+ 	return b;
+@@ -834,7 +836,8 @@ mult
+ 	xc0 = c->x;
+ #ifdef ULLong
+ 	for(; xb < xbe; xc0++) {
+-		if ((y = *xb++)) {
++		y = *xb++;
++		if (y) {
+ 			x = xa;
+ 			xc = xc0;
+ 			carry = 0;
+@@ -844,7 +847,7 @@ mult
+ 				*xc++ = z & FFFFFFFF;
+ 				}
+ 				while(x < xae);
+-			*xc = carry;
++			*xc = (ULong)carry;
+ 			}
+ 		}
+ #else
+@@ -916,16 +919,19 @@ pow5mult
+ 	int i;
+ 	static int p05[3] = { 5, 25, 125 };
+ 
+-	if ((i = k & 3))
++	i = k & 3;
++	if (i)
+ 		b = multadd(b, p05[i-1], 0);
+ 
+ 	if (!(k >>= 2))
+ 		return b;
+-	if (!(p5 = p5s)) {
++	p5 = p5s;
++	if (!p5) {
+ 		/* first time */
+ #ifdef MULTIPLE_THREADS
+ 		ACQUIRE_DTOA_LOCK(1);
+-		if (!(p5 = p5s)) {
++		p5 = p5s;
++		if (!p5) {
+ 			p5 = p5s = i2b(625);
+ 			p5->next = 0;
+ 			}
+@@ -943,10 +949,12 @@ pow5mult
+ 			}
+ 		if (!(k >>= 1))
+ 			break;
+-		if (!(p51 = p5->next)) {
++		p51 = p5->next;
++		if (!p51) {
+ #ifdef MULTIPLE_THREADS
+ 			ACQUIRE_DTOA_LOCK(1);
+-			if (!(p51 = p5->next)) {
++			p51 = p5->next;
++			if (!p51) {
+ 				p51 = p5->next = mult(p5,p5);
+ 				p51->next = 0;
+ 				}
+@@ -997,7 +1005,8 @@ lshift
+ 			z = *x++ >> k1;
+ 			}
+ 			while(x < xe);
+-		if ((*x1 = z))
++		*x1 = z;
++		if (*x1)
+ 			++n1;
+ 		}
+ #else
+@@ -1299,21 +1308,25 @@ d2b
+ 	z |= Exp_msk11;
+ #endif
+ #else
+-	if ((de = (int)(d0 >> Exp_shift)))
++	de = (int)(d0 >> Exp_shift);
++	if (de)
+ 		z |= Exp_msk1;
+ #endif
+ #ifdef Pack_32
+-	if ((y = d1)) {
+-		if ((k = lo0bits(&y))) {
++	y = d1;
++	if (y) {
++		k = lo0bits(&y);
++		if (k) {
+ 			x[0] = y | z << (32 - k);
+ 			z >>= k;
+ 			}
+ 		else
+ 			x[0] = y;
++		x[1] = z;
++		b->wds = x[1] ? 2 : 1;
+ #ifndef Sudden_Underflow
+-		i =
++		i = b->wds;
+ #endif
+-		    b->wds = (x[1] = z) ? 2 : 1;
+ 		}
+ 	else {
+ 		k = lo0bits(&z);
+@@ -1498,7 +1511,7 @@ htinit(unsigned char *h, unsigned char *s, int inc)
+ {
+ 	int i, j;
+ 	for(i = 0; (j = s[i]) !=0; i++)
+-		h[j] = i + inc;
++		h[j] = (unsigned char)(i + inc);
+ 	}
+ 
+  static void
+@@ -1536,7 +1549,7 @@ match
+ 	int c, d;
+ 	CONST char *s = *sp;
+ 
+-	while((d = *t++)) {
++	for(d = *t++; d; d = *t++) {
+ 		if ((c = *++s) >= 'A' && c <= 'Z')
+ 			c += 'a' - 'A';
+ 		if (c != d)
+@@ -1566,12 +1579,13 @@ hexnan
+ 	udx0 = 1;
+ 	s = *sp;
+ 	/* allow optional initial 0x or 0X */
+-	while((c = *(CONST unsigned char*)(s+1)) && c <= ' ')
++	for(c = *(CONST unsigned char*)(s+1); c && c <= ' '; c = *(CONST unsigned char*)(s+1))
+ 		++s;
+ 	if (s[1] == '0' && (s[2] == 'x' || s[2] == 'X'))
+ 		s += 2;
+-	while((c = *(CONST unsigned char*)++s)) {
+-		if ((c1 = hexdig[c]))
++	for(c = *(CONST unsigned char*)++s; c; c = *(CONST unsigned char*)++s) {
++		c1 = hexdig[c];
++		if (c1)
+ 			c  = c1 & 0xf;
+ 		else if (c <= ' ') {
+ 			if (udx0 && havedig) {
+@@ -1594,7 +1608,8 @@ hexnan
+ 					*sp = s + 1;
+ 					break;
+ 					}
+-				} while((c = *++s));
++				c = *++s;
++				} while(c);
+ 			break;
+ 			}
+ #endif
+@@ -2328,7 +2343,8 @@ bigcomp
+ 	/* Now b/d = exactly half-way between the two floating-point values */
+ 	/* on either side of the input string.  Compute first digit of b/d. */
+ 
+-	if (!(dig = quorem(b,d))) {
++	dig = quorem(b,d);
++	if (!dig) {
+ 		b = multadd(b, 10, 0);	/* very unlikely */
+ 		dig = quorem(b,d);
+ 		}
+@@ -2336,7 +2352,8 @@ bigcomp
+ 	/* Compare b/d with s0 */
+ 
+ 	for(i = 0; i < nd0; ) {
+-		if ((dd = s0[i++] - '0' - dig))
++		dd = s0[i++] - '0' - dig;
++		if (dd)
+ 			goto ret;
+ 		if (!b->x[0] && b->wds == 1) {
+ 			if (i < nd)
+@@ -2347,7 +2364,8 @@ bigcomp
+ 		dig = quorem(b,d);
+ 		}
+ 	for(j = bc->dp1; i++ < nd;) {
+-		if ((dd = s0[j++] - '0' - dig))
++		dd = s0[j++] - '0' - dig;
++		if (dd)
+ 			goto ret;
+ 		if (!b->x[0] && b->wds == 1) {
+ 			if (i < nd)
+@@ -2747,7 +2765,8 @@ strtod
+ 	/* Get starting approximation = rv * 10**e1 */
+ 
+ 	if (e1 > 0) {
+-		if ((i = e1 & 15))
++		i = e1 & 15;
++		if (i)
+ 			dval(&rv) *= tens[i];
+ 		if (e1 &= ~15) {
+ 			if (e1 > DBL_MAX_10_EXP) {
+@@ -2805,7 +2824,8 @@ strtod
+ 		}
+ 	else if (e1 < 0) {
+ 		e1 = -e1;
+-		if ((i = e1 & 15))
++		i = e1 & 15;
++		if (i)
+ 			dval(&rv) /= tens[i];
+ 		if (e1 >>= 4) {
+ 			if (e1 >= 1 << n_bigtens)
+@@ -3283,7 +3303,7 @@ strtod
+ #ifdef Avoid_Underflow
+ 			if (bc.scale && y <= 2*P*Exp_msk1) {
+ 				if (aadj <= 0x7fffffff) {
+-					if ((z = aadj) <= 0)
++					if ((z = (ULong)aadj) <= 0)
+ 						z = 1;
+ 					aadj = z;
+ 					aadj1 = bc.dsign ? aadj : -aadj;
+@@ -3456,7 +3476,7 @@ nrv_alloc(CONST char *s, char **rve, int n)
+ 	char *rv, *t;
+ 
+ 	t = rv = rv_alloc(n);
+-	while((*t = *s++)) t++;
++	for(*t = *s++; *t; *t = *s++) t++;
+ 	if (rve)
+ 		*rve = t;
+ 	return rv;
+@@ -3569,7 +3589,7 @@ dtoa
+ 	int denorm;
+ 	ULong x;
+ #endif
+-	Bigint *b, *b1, *delta, *mlo, *mhi, *S;
++	Bigint *b, *b1, *delta, *mlo = NULL, *mhi, *S;
+ 	U d2, eps, u;
+ 	double ds;
+ 	char *s, *s0;
+@@ -3645,10 +3665,9 @@ dtoa
+ #endif
+ 
+ 	b = d2b(&u, &be, &bbits);
+-#ifdef Sudden_Underflow
+ 	i = (int)(word0(&u) >> Exp_shift1 & (Exp_mask>>Exp_shift1));
+-#else
+-	if ((i = (int)(word0(&u) >> Exp_shift1 & (Exp_mask>>Exp_shift1)))) {
++#ifndef Sudden_Underflow
++	if (i) {
+ #endif
+ 		dval(&d2) = dval(&u);
+ 		word0(&d2) &= Frac_mask1;
+@@ -3803,13 +3822,16 @@ dtoa
+ 					}
+ 			dval(&u) /= ds;
+ 			}
+-		else if ((j1 = -k)) {
+-			dval(&u) *= tens[j1 & 0xf];
+-			for(j = j1 >> 4; j; j >>= 1, i++)
+-				if (j & 1) {
+-					ieps++;
+-					dval(&u) *= bigtens[i];
+-					}
++		else {
++			j1 = -k;
++			if (j1) {
++				dval(&u) *= tens[j1 & 0xf];
++				for(j = j1 >> 4; j; j >>= 1, i++)
++					if (j & 1) {
++						ieps++;
++						dval(&u) *= bigtens[i];
++						}
++				}
+ 			}
+ 		if (k_check && dval(&u) < 1. && ilim > 0) {
+ 			if (ilim1 <= 0)
+@@ -3837,9 +3859,9 @@ dtoa
+ 			 */
+ 			dval(&eps) = 0.5/tens[ilim-1] - dval(&eps);
+ 			for(i = 0;;) {
+-				L = dval(&u);
++				L = (long)dval(&u);
+ 				dval(&u) -= L;
+-				*s++ = '0' + (int)L;
++				*s++ = '0' + (char)L;
+ 				if (dval(&u) < dval(&eps))
+ 					goto ret1;
+ 				if (1. - dval(&u) < dval(&eps))
+@@ -3858,7 +3880,7 @@ dtoa
+ 				L = (Long)(dval(&u));
+ 				if (!(dval(&u) -= L))
+ 					ilim = i;
+-				*s++ = '0' + (int)L;
++				*s++ = '0' + (char)L;
+ 				if (i == ilim) {
+ 					if (dval(&u) > 0.5 + dval(&eps))
+ 						goto bump_up;
+@@ -3901,7 +3923,7 @@ dtoa
+ 				dval(&u) += ds;
+ 				}
+ #endif
+-			*s++ = '0' + (int)L;
++			*s++ = '0' + (char)L;
+ 			if (!dval(&u)) {
+ #ifdef SET_INEXACT
+ 				inexact = 0;
+@@ -3964,7 +3986,8 @@ dtoa
+ 				Bfree(b);
+ 				b = b1;
+ 				}
+-			if ((j = b5 - m5))
++			j = b5 - m5;
++			if (j)
+ 				b = pow5mult(b, j);
+ 			}
+ 		else
+@@ -4002,7 +4025,8 @@ dtoa
+ 	 * can do shifts and ors to compute the numerator for q.
+ 	 */
+ #ifdef Pack_32
+-	if ((i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f))
++	i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f;
++	if (i)
+ 		i = 32 - i;
+ #define iInc 28
+ #else
+@@ -4077,7 +4101,7 @@ dtoa
+ 				else if (!b->x[0] && b->wds <= 1)
+ 					inexact = 0;
+ #endif
+-				*s++ = dig;
++				*s++ = (char)dig;
+ 				goto ret;
+ 				}
+ #endif
+@@ -4107,7 +4131,7 @@ dtoa
+ 						goto round_9_up;
+ 					}
+  accept_dig:
+-				*s++ = dig;
++				*s++ = (char)dig;
+ 				goto ret;
+ 				}
+ 			if (j1 > 0) {
+@@ -4120,13 +4144,13 @@ dtoa
+ 					*s++ = '9';
+ 					goto roundoff;
+ 					}
+-				*s++ = dig + 1;
++				*s++ = (char)dig + 1;
+ 				goto ret;
+ 				}
+ #ifdef Honor_FLT_ROUNDS
+  keep_dig:
+ #endif
+-			*s++ = dig;
++			*s++ = (char)dig;
+ 			if (i == ilim)
+ 				break;
+ 			b = multadd(b, 10, 0);
+@@ -4140,7 +4164,8 @@ dtoa
+ 		}
+ 	else
+ 		for(i = 1;; i++) {
+-			*s++ = dig = quorem(b,S) + '0';
++			dig = quorem(b,S) + '0';
++			*s++ = (char)dig;
+ 			if (!b->x[0] && b->wds <= 1) {
+ #ifdef SET_INEXACT
+ 				inexact = 0;
+diff --git a/base/third_party/dmg_fp/g_fmt.cc b/base/third_party/dmg_fp/g_fmt.cc
+index d864eb7..bfa358d 100644
+--- a/base/third_party/dmg_fp/g_fmt.cc
++++ b/base/third_party/dmg_fp/g_fmt.cc
+@@ -46,14 +46,14 @@ g_fmt(register char *b, double x)
+ 	if (sign)
+ 		*b++ = '-';
+ 	if (decpt == 9999) /* Infinity or Nan */ {
+-		while((*b++ = *s++)) {}
++		for(*b = *s++; *b++; *b = *s++) {}
+ 		goto done0;
+ 		}
+ 	if (decpt <= -4 || decpt > se - s + 5) {
+ 		*b++ = *s++;
+ 		if (*s) {
+ 			*b++ = '.';
+-			while((*b = *s++))
++			for(*b = *s++; *b; *b = *s++)
+ 				b++;
+ 			}
+ 		*b++ = 'e';
+@@ -67,7 +67,7 @@ g_fmt(register char *b, double x)
+ 		for(j = 2, k = 10; 10*k <= decpt; j++, k *= 10) {}
+ 		for(;;) {
+ 			i = decpt / k;
+-			*b++ = i + '0';
++			*b++ = (char)i + '0';
+ 			if (--j <= 0)
+ 				break;
+ 			decpt -= i*k;
+@@ -79,10 +79,10 @@ g_fmt(register char *b, double x)
+ 		*b++ = '.';
+ 		for(; decpt < 0; decpt++)
+ 			*b++ = '0';
+-		while((*b++ = *s++)) {}
++		for(*b = *s++; *b++; *b = *s++) {}
+ 		}
+ 	else {
+-		while((*b = *s++)) {
++		for(*b = *s++; *b; *b = *s++) {
+ 			b++;
+ 			if (--decpt == 0 && *s)
+ 				*b++ = '.';
diff --git a/base/third_party/dynamic_annotations/BUILD.gn b/base/third_party/dynamic_annotations/BUILD.gn
new file mode 100644
index 0000000..bc324ae
--- /dev/null
+++ b/base/third_party/dynamic_annotations/BUILD.gn
@@ -0,0 +1,26 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+if (is_nacl) {
+  # Native client doesn't need dynamic annotations, so we provide a
+  # dummy target in order for clients to not have to special-case the
+  # dependency.
+  source_set("dynamic_annotations") {
+    sources = [
+      "dynamic_annotations.h",
+    ]
+  }
+} else {
+  source_set("dynamic_annotations") {
+    sources = [
+      "../valgrind/valgrind.h",
+      "dynamic_annotations.c",
+      "dynamic_annotations.h",
+    ]
+    if (is_android && !is_debug) {
+      configs -= [ "//build/config/compiler:optimize" ]
+      configs += [ "//build/config/compiler:optimize_max" ]
+    }
+  }
+}
diff --git a/base/third_party/dynamic_annotations/LICENSE b/base/third_party/dynamic_annotations/LICENSE
new file mode 100644
index 0000000..5c581a9
--- /dev/null
+++ b/base/third_party/dynamic_annotations/LICENSE
@@ -0,0 +1,28 @@
+/* Copyright (c) 2008-2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ---
+ * Author: Kostya Serebryany
+ */
diff --git a/base/third_party/dynamic_annotations/README.chromium b/base/third_party/dynamic_annotations/README.chromium
new file mode 100644
index 0000000..ff21b19
--- /dev/null
+++ b/base/third_party/dynamic_annotations/README.chromium
@@ -0,0 +1,20 @@
+Name: dynamic annotations
+URL: http://code.google.com/p/data-race-test/wiki/DynamicAnnotations
+Version: 4384
+License: BSD
+
+ATTENTION: please avoid using these annotations in Chromium code.
+They were mainly intended to instruct the Valgrind-based version of
+ThreadSanitizer to handle atomic operations. The new version of ThreadSanitizer
+based on compiler instrumentation understands atomic operations out of the box,
+so normally you don't need the annotations.
+If you still think you do, please consider writing a comment at http://crbug.com/349861
+
+One header and one source file (dynamic_annotations.h and dynamic_annotations.c)
+in this directory define runtime macros useful for annotating synchronization
+utilities and benign data races so data race detectors can handle Chromium code
+with better precision.
+
+These files were taken from
+http://code.google.com/p/data-race-test/source/browse/?#svn/trunk/dynamic_annotations
+The files are covered under BSD license as described within the files.
diff --git a/base/third_party/dynamic_annotations/dynamic_annotations.c b/base/third_party/dynamic_annotations/dynamic_annotations.c
new file mode 100644
index 0000000..f57cb12
--- /dev/null
+++ b/base/third_party/dynamic_annotations/dynamic_annotations.c
@@ -0,0 +1,269 @@
+/* Copyright (c) 2011, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef _MSC_VER
+# include <windows.h>
+#endif
+
+#ifdef __cplusplus
+# error "This file should be built as pure C to avoid name mangling"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+
+#ifdef __GNUC__
+/* valgrind.h uses gcc extensions so it won't build with other compilers */
+# include "base/third_party/valgrind/valgrind.h"
+#endif
+
+/* Compiler-based ThreadSanitizer defines
+   DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL = 1
+   and provides its own definitions of the functions. */
+
+#ifndef DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL
+# define DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL 0
+#endif
+
+/* Each function is empty and called (via a macro) only in debug mode.
+   The arguments are captured by dynamic tools at runtime. */
+
+#if DYNAMIC_ANNOTATIONS_ENABLED == 1 \
+    && DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0
+
+/* Identical code folding(-Wl,--icf=all) countermeasures.
+   This makes all Annotate* functions different, which prevents the linker from
+   folding them. */
+#ifdef __COUNTER__
+#define DYNAMIC_ANNOTATIONS_IMPL \
+  volatile short lineno = (__LINE__ << 8) + __COUNTER__; (void)lineno;
+#else
+#define DYNAMIC_ANNOTATIONS_IMPL \
+  volatile short lineno = (__LINE__ << 8); (void)lineno;
+#endif
+
+/* WARNING: always add new annotations to the end of the list.
+   Otherwise, lineno (see above) numbers for different Annotate* functions may
+   conflict. */
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockCreate)(
+    const char *file, int line, const volatile void *lock)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockDestroy)(
+    const char *file, int line, const volatile void *lock)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockAcquired)(
+    const char *file, int line, const volatile void *lock, long is_w)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockReleased)(
+    const char *file, int line, const volatile void *lock, long is_w)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierInit)(
+    const char *file, int line, const volatile void *barrier, long count,
+    long reinitialization_allowed)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierWaitBefore)(
+    const char *file, int line, const volatile void *barrier)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierWaitAfter)(
+    const char *file, int line, const volatile void *barrier)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierDestroy)(
+    const char *file, int line, const volatile void *barrier)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarWait)(
+    const char *file, int line, const volatile void *cv,
+    const volatile void *lock)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarSignal)(
+    const char *file, int line, const volatile void *cv)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarSignalAll)(
+    const char *file, int line, const volatile void *cv)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateHappensBefore)(
+    const char *file, int line, const volatile void *obj)
+{DYNAMIC_ANNOTATIONS_IMPL};
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateHappensAfter)(
+    const char *file, int line, const volatile void *obj)
+{DYNAMIC_ANNOTATIONS_IMPL};
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePublishMemoryRange)(
+    const char *file, int line, const volatile void *address, long size)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateUnpublishMemoryRange)(
+    const char *file, int line, const volatile void *address, long size)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQCreate)(
+    const char *file, int line, const volatile void *pcq)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQDestroy)(
+    const char *file, int line, const volatile void *pcq)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQPut)(
+    const char *file, int line, const volatile void *pcq)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQGet)(
+    const char *file, int line, const volatile void *pcq)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateNewMemory)(
+    const char *file, int line, const volatile void *mem, long size)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateExpectRace)(
+    const char *file, int line, const volatile void *mem,
+    const char *description)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateFlushExpectedRaces)(
+    const char *file, int line)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBenignRace)(
+    const char *file, int line, const volatile void *mem,
+    const char *description)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBenignRaceSized)(
+    const char *file, int line, const volatile void *mem, long size,
+    const char *description)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsUsedAsCondVar)(
+    const char *file, int line, const volatile void *mu)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsNotPHB)(
+    const char *file, int line, const volatile void *mu)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateTraceMemory)(
+    const char *file, int line, const volatile void *arg)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateThreadName)(
+    const char *file, int line, const char *name)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreReadsBegin)(
+    const char *file, int line)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreReadsEnd)(
+    const char *file, int line)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreWritesBegin)(
+    const char *file, int line)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreWritesEnd)(
+    const char *file, int line)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreSyncBegin)(
+    const char *file, int line)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreSyncEnd)(
+    const char *file, int line)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateEnableRaceDetection)(
+    const char *file, int line, int enable)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateNoOp)(
+    const char *file, int line, const volatile void *arg)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateFlushState)(
+    const char *file, int line)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+#endif  /* DYNAMIC_ANNOTATIONS_ENABLED == 1
+    && DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0 */
+
+#if DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND == 1 \
+    && DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0
+static int GetRunningOnValgrind(void) {
+#ifdef RUNNING_ON_VALGRIND
+  if (RUNNING_ON_VALGRIND) return 1;
+#endif
+
+#ifndef _MSC_VER
+  char *running_on_valgrind_str = getenv("RUNNING_ON_VALGRIND");
+  if (running_on_valgrind_str) {
+    return strcmp(running_on_valgrind_str, "0") != 0;
+  }
+#else
+  /* Visual Studio issues warnings if we use getenv,
+   * so we use GetEnvironmentVariableA instead.
+   */
+  char value[100] = "1";
+  int res = GetEnvironmentVariableA("RUNNING_ON_VALGRIND",
+                                    value, sizeof(value));
+  /* value will remain "1" if res == 0 or res >= sizeof(value). The latter
+   * can happen only if the given value is long, in this case it can't be "0".
+   */
+  if (res > 0 && strcmp(value, "0") != 0)
+    return 1;
+#endif
+  return 0;
+}
+
+/* See the comments in dynamic_annotations.h */
+int RunningOnValgrind(void) {
+  static volatile int running_on_valgrind = -1;
+  /* C doesn't have thread-safe initialization of statics, and we
+     don't want to depend on pthread_once here, so hack it. */
+  int local_running_on_valgrind = running_on_valgrind;
+  if (local_running_on_valgrind == -1)
+    running_on_valgrind = local_running_on_valgrind = GetRunningOnValgrind();
+  return local_running_on_valgrind;
+}
+
+#endif /* DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND == 1
+    && DYNAMIC_ANNOTATIONS_EXTERNAL_IMPL == 0 */
diff --git a/base/third_party/dynamic_annotations/dynamic_annotations.gyp b/base/third_party/dynamic_annotations/dynamic_annotations.gyp
new file mode 100644
index 0000000..8d2e9ec
--- /dev/null
+++ b/base/third_party/dynamic_annotations/dynamic_annotations.gyp
@@ -0,0 +1,50 @@
+# Copyright (c) 2011 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.
+
+{
+  'targets': [
+    {
+      'target_name': 'dynamic_annotations',
+      'type': 'static_library',
+      'toolsets': ['host', 'target'],
+      'include_dirs': [
+        '../../../',
+      ],
+      'sources': [
+        '../valgrind/valgrind.h',
+        'dynamic_annotations.c',
+        'dynamic_annotations.h',
+      ],
+      'includes': [
+        '../../../build/android/increase_size_for_speed.gypi',
+      ],
+    },
+  ],
+  'conditions': [
+    ['OS == "win" and target_arch=="ia32"', {
+      'targets': [
+        {
+          'target_name': 'dynamic_annotations_win64',
+          'type': 'static_library',
+          # We can't use dynamic_annotations target for win64 build since it is
+          # a 32-bit library.
+          # TODO(gregoryd): merge with dynamic_annotations when
+          # the win32/64 targets are merged.
+          'include_dirs': [
+              '../../../',
+          ],
+          'sources': [
+            'dynamic_annotations.c',
+            'dynamic_annotations.h',
+          ],
+          'configurations': {
+            'Common_Base': {
+              'msvs_target_platform': 'x64',
+            },
+          },
+        },
+      ],
+    }],
+  ],
+}
diff --git a/base/third_party/dynamic_annotations/dynamic_annotations.h b/base/third_party/dynamic_annotations/dynamic_annotations.h
new file mode 100644
index 0000000..8d7f052
--- /dev/null
+++ b/base/third_party/dynamic_annotations/dynamic_annotations.h
@@ -0,0 +1,595 @@
+/* Copyright (c) 2011, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* This file defines dynamic annotations for use with dynamic analysis
+   tool such as valgrind, PIN, etc.
+
+   Dynamic annotation is a source code annotation that affects
+   the generated code (that is, the annotation is not a comment).
+   Each such annotation is attached to a particular
+   instruction and/or to a particular object (address) in the program.
+
+   The annotations that should be used by users are macros in all upper-case
+   (e.g., ANNOTATE_NEW_MEMORY).
+
+   Actual implementation of these macros may differ depending on the
+   dynamic analysis tool being used.
+
+   See http://code.google.com/p/data-race-test/  for more information.
+
+   This file supports the following dynamic analysis tools:
+   - None (DYNAMIC_ANNOTATIONS_ENABLED is not defined or zero).
+      Macros are defined empty.
+   - ThreadSanitizer, Helgrind, DRD (DYNAMIC_ANNOTATIONS_ENABLED is 1).
+      Macros are defined as calls to non-inlinable empty functions
+      that are intercepted by Valgrind. */
+
+#ifndef __DYNAMIC_ANNOTATIONS_H__
+#define __DYNAMIC_ANNOTATIONS_H__
+
+#ifndef DYNAMIC_ANNOTATIONS_PREFIX
+# define DYNAMIC_ANNOTATIONS_PREFIX
+#endif
+
+#ifndef DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND
+# define DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND 1
+#endif
+
+#ifdef DYNAMIC_ANNOTATIONS_WANT_ATTRIBUTE_WEAK
+# ifdef __GNUC__
+#  define DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK __attribute__((weak))
+# else
+/* TODO(glider): for Windows support we may want to change this macro in order
+   to prepend __declspec(selectany) to the annotations' declarations. */
+#  error weak annotations are not supported for your compiler
+# endif
+#else
+# define DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK
+#endif
+
+/* The following preprocessor magic prepends the value of
+   DYNAMIC_ANNOTATIONS_PREFIX to annotation function names. */
+#define DYNAMIC_ANNOTATIONS_GLUE0(A, B) A##B
+#define DYNAMIC_ANNOTATIONS_GLUE(A, B) DYNAMIC_ANNOTATIONS_GLUE0(A, B)
+#define DYNAMIC_ANNOTATIONS_NAME(name) \
+  DYNAMIC_ANNOTATIONS_GLUE(DYNAMIC_ANNOTATIONS_PREFIX, name)
+
+#ifndef DYNAMIC_ANNOTATIONS_ENABLED
+# define DYNAMIC_ANNOTATIONS_ENABLED 0
+#endif
+
+#if DYNAMIC_ANNOTATIONS_ENABLED != 0
+
+  /* -------------------------------------------------------------
+     Annotations useful when implementing condition variables such as CondVar,
+     using conditional critical sections (Await/LockWhen) and when constructing
+     user-defined synchronization mechanisms.
+
+     The annotations ANNOTATE_HAPPENS_BEFORE() and ANNOTATE_HAPPENS_AFTER() can
+     be used to define happens-before arcs in user-defined synchronization
+     mechanisms:  the race detector will infer an arc from the former to the
+     latter when they share the same argument pointer.
+
+     Example 1 (reference counting):
+
+     void Unref() {
+       ANNOTATE_HAPPENS_BEFORE(&refcount_);
+       if (AtomicDecrementByOne(&refcount_) == 0) {
+         ANNOTATE_HAPPENS_AFTER(&refcount_);
+         delete this;
+       }
+     }
+
+     Example 2 (message queue):
+
+     void MyQueue::Put(Type *e) {
+       MutexLock lock(&mu_);
+       ANNOTATE_HAPPENS_BEFORE(e);
+       PutElementIntoMyQueue(e);
+     }
+
+     Type *MyQueue::Get() {
+       MutexLock lock(&mu_);
+       Type *e = GetElementFromMyQueue();
+       ANNOTATE_HAPPENS_AFTER(e);
+       return e;
+     }
+
+     Note: when possible, please use the existing reference counting and message
+     queue implementations instead of inventing new ones. */
+
+  /* Report that wait on the condition variable at address "cv" has succeeded
+     and the lock at address "lock" is held. */
+  #define ANNOTATE_CONDVAR_LOCK_WAIT(cv, lock) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarWait)(__FILE__, __LINE__, cv, lock)
+
+  /* Report that wait on the condition variable at "cv" has succeeded.  Variant
+     w/o lock. */
+  #define ANNOTATE_CONDVAR_WAIT(cv) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarWait)(__FILE__, __LINE__, cv, NULL)
+
+  /* Report that we are about to signal on the condition variable at address
+     "cv". */
+  #define ANNOTATE_CONDVAR_SIGNAL(cv) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarSignal)(__FILE__, __LINE__, cv)
+
+  /* Report that we are about to signal_all on the condition variable at address
+     "cv". */
+  #define ANNOTATE_CONDVAR_SIGNAL_ALL(cv) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarSignalAll)(__FILE__, __LINE__, cv)
+
+  /* Annotations for user-defined synchronization mechanisms. */
+  #define ANNOTATE_HAPPENS_BEFORE(obj) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateHappensBefore)(__FILE__, __LINE__, obj)
+  #define ANNOTATE_HAPPENS_AFTER(obj) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateHappensAfter)(__FILE__, __LINE__, obj)
+
+  /* DEPRECATED. Don't use it. */
+  #define ANNOTATE_PUBLISH_MEMORY_RANGE(pointer, size) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotatePublishMemoryRange)(__FILE__, __LINE__, \
+        pointer, size)
+
+  /* DEPRECATED. Don't use it. */
+  #define ANNOTATE_UNPUBLISH_MEMORY_RANGE(pointer, size) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateUnpublishMemoryRange)(__FILE__, __LINE__, \
+        pointer, size)
+
+  /* DEPRECATED. Don't use it. */
+  #define ANNOTATE_SWAP_MEMORY_RANGE(pointer, size)   \
+    do {                                              \
+      ANNOTATE_UNPUBLISH_MEMORY_RANGE(pointer, size); \
+      ANNOTATE_PUBLISH_MEMORY_RANGE(pointer, size);   \
+    } while (0)
+
+  /* Instruct the tool to create a happens-before arc between mu->Unlock() and
+     mu->Lock(). This annotation may slow down the race detector and hide real
+     races. Normally it is used only when it would be difficult to annotate each
+     of the mutex's critical sections individually using the annotations above.
+     This annotation makes sense only for hybrid race detectors. For pure
+     happens-before detectors this is a no-op. For more details see
+     http://code.google.com/p/data-race-test/wiki/PureHappensBeforeVsHybrid . */
+  #define ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX(mu) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsUsedAsCondVar)(__FILE__, __LINE__, \
+        mu)
+
+  /* Opposite to ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX.
+     Instruct the tool to NOT create h-b arcs between Unlock and Lock, even in
+     pure happens-before mode. For a hybrid mode this is a no-op. */
+  #define ANNOTATE_NOT_HAPPENS_BEFORE_MUTEX(mu) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsNotPHB)(__FILE__, __LINE__, mu)
+
+  /* Deprecated. Use ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX. */
+  #define ANNOTATE_MUTEX_IS_USED_AS_CONDVAR(mu) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsUsedAsCondVar)(__FILE__, __LINE__, \
+        mu)
+
+  /* -------------------------------------------------------------
+     Annotations useful when defining memory allocators, or when memory that
+     was protected in one way starts to be protected in another. */
+
+  /* Report that a new memory at "address" of size "size" has been allocated.
+     This might be used when the memory has been retrieved from a free list and
+     is about to be reused, or when a the locking discipline for a variable
+     changes. */
+  #define ANNOTATE_NEW_MEMORY(address, size) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateNewMemory)(__FILE__, __LINE__, address, \
+        size)
+
+  /* -------------------------------------------------------------
+     Annotations useful when defining FIFO queues that transfer data between
+     threads. */
+
+  /* Report that the producer-consumer queue (such as ProducerConsumerQueue) at
+     address "pcq" has been created.  The ANNOTATE_PCQ_* annotations
+     should be used only for FIFO queues.  For non-FIFO queues use
+     ANNOTATE_HAPPENS_BEFORE (for put) and ANNOTATE_HAPPENS_AFTER (for get). */
+  #define ANNOTATE_PCQ_CREATE(pcq) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQCreate)(__FILE__, __LINE__, pcq)
+
+  /* Report that the queue at address "pcq" is about to be destroyed. */
+  #define ANNOTATE_PCQ_DESTROY(pcq) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQDestroy)(__FILE__, __LINE__, pcq)
+
+  /* Report that we are about to put an element into a FIFO queue at address
+     "pcq". */
+  #define ANNOTATE_PCQ_PUT(pcq) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQPut)(__FILE__, __LINE__, pcq)
+
+  /* Report that we've just got an element from a FIFO queue at address
+     "pcq". */
+  #define ANNOTATE_PCQ_GET(pcq) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQGet)(__FILE__, __LINE__, pcq)
+
+  /* -------------------------------------------------------------
+     Annotations that suppress errors.  It is usually better to express the
+     program's synchronization using the other annotations, but these can
+     be used when all else fails. */
+
+  /* Report that we may have a benign race at "pointer", with size
+     "sizeof(*(pointer))". "pointer" must be a non-void* pointer.  Insert at the
+     point where "pointer" has been allocated, preferably close to the point
+     where the race happens.  See also ANNOTATE_BENIGN_RACE_STATIC. */
+  #define ANNOTATE_BENIGN_RACE(pointer, description) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateBenignRaceSized)(__FILE__, __LINE__, \
+        pointer, sizeof(*(pointer)), description)
+
+  /* Same as ANNOTATE_BENIGN_RACE(address, description), but applies to
+     the memory range [address, address+size). */
+  #define ANNOTATE_BENIGN_RACE_SIZED(address, size, description) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateBenignRaceSized)(__FILE__, __LINE__, \
+        address, size, description)
+
+  /* Request the analysis tool to ignore all reads in the current thread
+     until ANNOTATE_IGNORE_READS_END is called.
+     Useful to ignore intentional racey reads, while still checking
+     other reads and all writes.
+     See also ANNOTATE_UNPROTECTED_READ. */
+  #define ANNOTATE_IGNORE_READS_BEGIN() \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreReadsBegin)(__FILE__, __LINE__)
+
+  /* Stop ignoring reads. */
+  #define ANNOTATE_IGNORE_READS_END() \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreReadsEnd)(__FILE__, __LINE__)
+
+  /* Similar to ANNOTATE_IGNORE_READS_BEGIN, but ignore writes. */
+  #define ANNOTATE_IGNORE_WRITES_BEGIN() \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreWritesBegin)(__FILE__, __LINE__)
+
+  /* Stop ignoring writes. */
+  #define ANNOTATE_IGNORE_WRITES_END() \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreWritesEnd)(__FILE__, __LINE__)
+
+  /* Start ignoring all memory accesses (reads and writes). */
+  #define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \
+    do {\
+      ANNOTATE_IGNORE_READS_BEGIN();\
+      ANNOTATE_IGNORE_WRITES_BEGIN();\
+    }while(0)\
+
+  /* Stop ignoring all memory accesses. */
+  #define ANNOTATE_IGNORE_READS_AND_WRITES_END() \
+    do {\
+      ANNOTATE_IGNORE_WRITES_END();\
+      ANNOTATE_IGNORE_READS_END();\
+    }while(0)\
+
+  /* Similar to ANNOTATE_IGNORE_READS_BEGIN, but ignore synchronization events:
+     RWLOCK* and CONDVAR*. */
+  #define ANNOTATE_IGNORE_SYNC_BEGIN() \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreSyncBegin)(__FILE__, __LINE__)
+
+  /* Stop ignoring sync events. */
+  #define ANNOTATE_IGNORE_SYNC_END() \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreSyncEnd)(__FILE__, __LINE__)
+
+
+  /* Enable (enable!=0) or disable (enable==0) race detection for all threads.
+     This annotation could be useful if you want to skip expensive race analysis
+     during some period of program execution, e.g. during initialization. */
+  #define ANNOTATE_ENABLE_RACE_DETECTION(enable) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateEnableRaceDetection)(__FILE__, __LINE__, \
+        enable)
+
+  /* -------------------------------------------------------------
+     Annotations useful for debugging. */
+
+  /* Request to trace every access to "address". */
+  #define ANNOTATE_TRACE_MEMORY(address) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateTraceMemory)(__FILE__, __LINE__, address)
+
+  /* Report the current thread name to a race detector. */
+  #define ANNOTATE_THREAD_NAME(name) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateThreadName)(__FILE__, __LINE__, name)
+
+  /* -------------------------------------------------------------
+     Annotations useful when implementing locks.  They are not
+     normally needed by modules that merely use locks.
+     The "lock" argument is a pointer to the lock object. */
+
+  /* Report that a lock has been created at address "lock". */
+  #define ANNOTATE_RWLOCK_CREATE(lock) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockCreate)(__FILE__, __LINE__, lock)
+
+  /* Report that the lock at address "lock" is about to be destroyed. */
+  #define ANNOTATE_RWLOCK_DESTROY(lock) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockDestroy)(__FILE__, __LINE__, lock)
+
+  /* Report that the lock at address "lock" has been acquired.
+     is_w=1 for writer lock, is_w=0 for reader lock. */
+  #define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockAcquired)(__FILE__, __LINE__, lock, \
+        is_w)
+
+  /* Report that the lock at address "lock" is about to be released. */
+  #define ANNOTATE_RWLOCK_RELEASED(lock, is_w) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockReleased)(__FILE__, __LINE__, lock, \
+        is_w)
+
+  /* -------------------------------------------------------------
+     Annotations useful when implementing barriers.  They are not
+     normally needed by modules that merely use barriers.
+     The "barrier" argument is a pointer to the barrier object. */
+
+  /* Report that the "barrier" has been initialized with initial "count".
+   If 'reinitialization_allowed' is true, initialization is allowed to happen
+   multiple times w/o calling barrier_destroy() */
+  #define ANNOTATE_BARRIER_INIT(barrier, count, reinitialization_allowed) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierInit)(__FILE__, __LINE__, barrier, \
+        count, reinitialization_allowed)
+
+  /* Report that we are about to enter barrier_wait("barrier"). */
+  #define ANNOTATE_BARRIER_WAIT_BEFORE(barrier) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierWaitBefore)(__FILE__, __LINE__, \
+        barrier)
+
+  /* Report that we just exited barrier_wait("barrier"). */
+  #define ANNOTATE_BARRIER_WAIT_AFTER(barrier) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierWaitAfter)(__FILE__, __LINE__, \
+        barrier)
+
+  /* Report that the "barrier" has been destroyed. */
+  #define ANNOTATE_BARRIER_DESTROY(barrier) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierDestroy)(__FILE__, __LINE__, \
+        barrier)
+
+  /* -------------------------------------------------------------
+     Annotations useful for testing race detectors. */
+
+  /* Report that we expect a race on the variable at "address".
+     Use only in unit tests for a race detector. */
+  #define ANNOTATE_EXPECT_RACE(address, description) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateExpectRace)(__FILE__, __LINE__, address, \
+        description)
+
+  #define ANNOTATE_FLUSH_EXPECTED_RACES() \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateFlushExpectedRaces)(__FILE__, __LINE__)
+
+  /* A no-op. Insert where you like to test the interceptors. */
+  #define ANNOTATE_NO_OP(arg) \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateNoOp)(__FILE__, __LINE__, arg)
+
+  /* Force the race detector to flush its state. The actual effect depends on
+   * the implementation of the detector. */
+  #define ANNOTATE_FLUSH_STATE() \
+    DYNAMIC_ANNOTATIONS_NAME(AnnotateFlushState)(__FILE__, __LINE__)
+
+
+#else  /* DYNAMIC_ANNOTATIONS_ENABLED == 0 */
+
+  #define ANNOTATE_RWLOCK_CREATE(lock) /* empty */
+  #define ANNOTATE_RWLOCK_DESTROY(lock) /* empty */
+  #define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) /* empty */
+  #define ANNOTATE_RWLOCK_RELEASED(lock, is_w) /* empty */
+  #define ANNOTATE_BARRIER_INIT(barrier, count, reinitialization_allowed) /* */
+  #define ANNOTATE_BARRIER_WAIT_BEFORE(barrier) /* empty */
+  #define ANNOTATE_BARRIER_WAIT_AFTER(barrier) /* empty */
+  #define ANNOTATE_BARRIER_DESTROY(barrier) /* empty */
+  #define ANNOTATE_CONDVAR_LOCK_WAIT(cv, lock) /* empty */
+  #define ANNOTATE_CONDVAR_WAIT(cv) /* empty */
+  #define ANNOTATE_CONDVAR_SIGNAL(cv) /* empty */
+  #define ANNOTATE_CONDVAR_SIGNAL_ALL(cv) /* empty */
+  #define ANNOTATE_HAPPENS_BEFORE(obj) /* empty */
+  #define ANNOTATE_HAPPENS_AFTER(obj) /* empty */
+  #define ANNOTATE_PUBLISH_MEMORY_RANGE(address, size) /* empty */
+  #define ANNOTATE_UNPUBLISH_MEMORY_RANGE(address, size)  /* empty */
+  #define ANNOTATE_SWAP_MEMORY_RANGE(address, size)  /* empty */
+  #define ANNOTATE_PCQ_CREATE(pcq) /* empty */
+  #define ANNOTATE_PCQ_DESTROY(pcq) /* empty */
+  #define ANNOTATE_PCQ_PUT(pcq) /* empty */
+  #define ANNOTATE_PCQ_GET(pcq) /* empty */
+  #define ANNOTATE_NEW_MEMORY(address, size) /* empty */
+  #define ANNOTATE_EXPECT_RACE(address, description) /* empty */
+  #define ANNOTATE_FLUSH_EXPECTED_RACES(address, description) /* empty */
+  #define ANNOTATE_BENIGN_RACE(address, description) /* empty */
+  #define ANNOTATE_BENIGN_RACE_SIZED(address, size, description) /* empty */
+  #define ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX(mu) /* empty */
+  #define ANNOTATE_MUTEX_IS_USED_AS_CONDVAR(mu) /* empty */
+  #define ANNOTATE_TRACE_MEMORY(arg) /* empty */
+  #define ANNOTATE_THREAD_NAME(name) /* empty */
+  #define ANNOTATE_IGNORE_READS_BEGIN() /* empty */
+  #define ANNOTATE_IGNORE_READS_END() /* empty */
+  #define ANNOTATE_IGNORE_WRITES_BEGIN() /* empty */
+  #define ANNOTATE_IGNORE_WRITES_END() /* empty */
+  #define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() /* empty */
+  #define ANNOTATE_IGNORE_READS_AND_WRITES_END() /* empty */
+  #define ANNOTATE_IGNORE_SYNC_BEGIN() /* empty */
+  #define ANNOTATE_IGNORE_SYNC_END() /* empty */
+  #define ANNOTATE_ENABLE_RACE_DETECTION(enable) /* empty */
+  #define ANNOTATE_NO_OP(arg) /* empty */
+  #define ANNOTATE_FLUSH_STATE() /* empty */
+
+#endif  /* DYNAMIC_ANNOTATIONS_ENABLED */
+
+/* Use the macros above rather than using these functions directly. */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockCreate)(
+    const char *file, int line,
+    const volatile void *lock) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockDestroy)(
+    const char *file, int line,
+    const volatile void *lock) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockAcquired)(
+    const char *file, int line,
+    const volatile void *lock, long is_w) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockReleased)(
+    const char *file, int line,
+    const volatile void *lock, long is_w) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierInit)(
+    const char *file, int line, const volatile void *barrier, long count,
+    long reinitialization_allowed) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierWaitBefore)(
+    const char *file, int line,
+    const volatile void *barrier) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierWaitAfter)(
+    const char *file, int line,
+    const volatile void *barrier) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierDestroy)(
+    const char *file, int line,
+    const volatile void *barrier) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarWait)(
+    const char *file, int line, const volatile void *cv,
+    const volatile void *lock) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarSignal)(
+    const char *file, int line,
+    const volatile void *cv) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarSignalAll)(
+    const char *file, int line,
+    const volatile void *cv) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateHappensBefore)(
+    const char *file, int line,
+    const volatile void *obj) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateHappensAfter)(
+    const char *file, int line,
+    const volatile void *obj) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePublishMemoryRange)(
+    const char *file, int line,
+    const volatile void *address, long size) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateUnpublishMemoryRange)(
+    const char *file, int line,
+    const volatile void *address, long size) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQCreate)(
+    const char *file, int line,
+    const volatile void *pcq) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQDestroy)(
+    const char *file, int line,
+    const volatile void *pcq) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQPut)(
+    const char *file, int line,
+    const volatile void *pcq) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQGet)(
+    const char *file, int line,
+    const volatile void *pcq) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateNewMemory)(
+    const char *file, int line,
+    const volatile void *mem, long size) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateExpectRace)(
+    const char *file, int line, const volatile void *mem,
+    const char *description) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateFlushExpectedRaces)(
+    const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBenignRace)(
+    const char *file, int line, const volatile void *mem,
+    const char *description) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBenignRaceSized)(
+    const char *file, int line, const volatile void *mem, long size,
+    const char *description) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsUsedAsCondVar)(
+    const char *file, int line,
+    const volatile void *mu) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsNotPHB)(
+    const char *file, int line,
+    const volatile void *mu) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateTraceMemory)(
+    const char *file, int line,
+    const volatile void *arg) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateThreadName)(
+    const char *file, int line,
+    const char *name) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreReadsBegin)(
+    const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreReadsEnd)(
+    const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreWritesBegin)(
+    const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreWritesEnd)(
+    const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreSyncBegin)(
+    const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreSyncEnd)(
+    const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateEnableRaceDetection)(
+    const char *file, int line, int enable) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateNoOp)(
+    const char *file, int line,
+    const volatile void *arg) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateFlushState)(
+    const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+
+#if DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND == 1
+/* Return non-zero value if running under valgrind.
+
+  If "valgrind.h" is included into dynamic_annotations.c,
+  the regular valgrind mechanism will be used.
+  See http://valgrind.org/docs/manual/manual-core-adv.html about
+  RUNNING_ON_VALGRIND and other valgrind "client requests".
+  The file "valgrind.h" may be obtained by doing
+     svn co svn://svn.valgrind.org/valgrind/trunk/include
+
+  If for some reason you can't use "valgrind.h" or want to fake valgrind,
+  there are two ways to make this function return non-zero:
+    - Use environment variable: export RUNNING_ON_VALGRIND=1
+    - Make your tool intercept the function RunningOnValgrind() and
+      change its return value.
+ */
+int RunningOnValgrind(void) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+#endif /* DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND == 1 */
+
+#ifdef __cplusplus
+}
+#endif
+
+#if DYNAMIC_ANNOTATIONS_ENABLED != 0 && defined(__cplusplus)
+
+  /* ANNOTATE_UNPROTECTED_READ is the preferred way to annotate racey reads.
+
+     Instead of doing
+        ANNOTATE_IGNORE_READS_BEGIN();
+        ... = x;
+        ANNOTATE_IGNORE_READS_END();
+     one can use
+        ... = ANNOTATE_UNPROTECTED_READ(x); */
+  template <class T>
+  inline T ANNOTATE_UNPROTECTED_READ(const volatile T &x) {
+    ANNOTATE_IGNORE_READS_BEGIN();
+    T res = x;
+    ANNOTATE_IGNORE_READS_END();
+    return res;
+  }
+  /* Apply ANNOTATE_BENIGN_RACE_SIZED to a static variable. */
+  #define ANNOTATE_BENIGN_RACE_STATIC(static_var, description)        \
+    namespace {                                                       \
+      class static_var ## _annotator {                                \
+       public:                                                        \
+        static_var ## _annotator() {                                  \
+          ANNOTATE_BENIGN_RACE_SIZED(&static_var,                     \
+                                      sizeof(static_var),             \
+            # static_var ": " description);                           \
+        }                                                             \
+      };                                                              \
+      static static_var ## _annotator the ## static_var ## _annotator;\
+    }
+#else /* DYNAMIC_ANNOTATIONS_ENABLED == 0 */
+
+  #define ANNOTATE_UNPROTECTED_READ(x) (x)
+  #define ANNOTATE_BENIGN_RACE_STATIC(static_var, description)  /* empty */
+
+#endif /* DYNAMIC_ANNOTATIONS_ENABLED */
+
+#endif  /* __DYNAMIC_ANNOTATIONS_H__ */
diff --git a/base/third_party/icu/LICENSE b/base/third_party/icu/LICENSE
new file mode 100644
index 0000000..40282f4
--- /dev/null
+++ b/base/third_party/icu/LICENSE
@@ -0,0 +1,32 @@
+ICU License - ICU 1.8.1 and later
+
+COPYRIGHT AND PERMISSION NOTICE
+
+Copyright (c) 1995-2009 International Business Machines Corporation and others
+
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, and/or sell copies of the Software, and to permit persons
+to whom the Software is furnished to do so, provided that the above
+copyright notice(s) and this permission notice appear in all copies of
+the Software and that both the above copyright notice(s) and this
+permission notice appear in supporting documentation.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY
+SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER
+RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+Except as contained in this notice, the name of a copyright holder
+shall not be used in advertising or otherwise to promote the sale, use
+or other dealings in this Software without prior written authorization
+of the copyright holder.
diff --git a/base/third_party/icu/README.chromium b/base/third_party/icu/README.chromium
new file mode 100644
index 0000000..6a9a15a
--- /dev/null
+++ b/base/third_party/icu/README.chromium
@@ -0,0 +1,16 @@
+Name: ICU
+URL: http://site.icu-project.org/
+License: MIT
+License File: NOT_SHIPPED
+
+This file has the relevant components from ICU copied to handle basic
+UTF8/16/32 conversions. Components are copied from utf.h utf8.h utf16.h and
+utf_impl.c
+
+The same module appears in third_party/icu, so we don't repeat the license
+file here.
+
+The main change is that U_/U8_/U16_ prefixes have been replaced with
+CBU_/CBU8_/CBU16_ (for "Chrome Base") to avoid confusion with the "real" ICU
+macros should ICU be in use on the system. For the same reason, the functions
+and types have been put in the "base_icu" namespace.
diff --git a/base/third_party/icu/icu_utf.cc b/base/third_party/icu/icu_utf.cc
new file mode 100644
index 0000000..b47c8ac
--- /dev/null
+++ b/base/third_party/icu/icu_utf.cc
@@ -0,0 +1,228 @@
+/*
+******************************************************************************
+*
+*   Copyright (C) 1999-2006, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+******************************************************************************
+*   file name:  utf_impl.c
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 1999sep13
+*   created by: Markus W. Scherer
+*
+*   This file provides implementation functions for macros in the utfXX.h
+*   that would otherwise be too long as macros.
+*/
+
+#include "base/third_party/icu/icu_utf.h"
+
+namespace base_icu {
+
+/**
+ * UTF8_ERROR_VALUE_1 and UTF8_ERROR_VALUE_2 are special error values for UTF-8,
+ * which need 1 or 2 bytes in UTF-8:
+ * \code
+ * U+0015 = NAK = Negative Acknowledge, C0 control character
+ * U+009f = highest C1 control character
+ * \endcode
+ *
+ * These are used by UTF8_..._SAFE macros so that they can return an error value
+ * that needs the same number of code units (bytes) as were seen by
+ * a macro. They should be tested with UTF_IS_ERROR() or UTF_IS_VALID().
+ *
+ * @deprecated ICU 2.4. Obsolete, see utf_old.h.
+ */
+#define CBUTF8_ERROR_VALUE_1 0x15
+
+/**
+ * See documentation on UTF8_ERROR_VALUE_1 for details.
+ *
+ * @deprecated ICU 2.4. Obsolete, see utf_old.h.
+ */
+#define CBUTF8_ERROR_VALUE_2 0x9f
+
+
+/**
+ * Error value for all UTFs. This code point value will be set by macros with e>
+ * checking if an error is detected.
+ *
+ * @deprecated ICU 2.4. Obsolete, see utf_old.h.
+ */
+#define CBUTF_ERROR_VALUE 0xffff
+
+/*
+ * This table could be replaced on many machines by
+ * a few lines of assembler code using an
+ * "index of first 0-bit from msb" instruction and
+ * one or two more integer instructions.
+ *
+ * For example, on an i386, do something like
+ * - MOV AL, leadByte
+ * - NOT AL         (8-bit, leave b15..b8==0..0, reverse only b7..b0)
+ * - MOV AH, 0
+ * - BSR BX, AX     (16-bit)
+ * - MOV AX, 6      (result)
+ * - JZ finish      (ZF==1 if leadByte==0xff)
+ * - SUB AX, BX (result)
+ * -finish:
+ * (BSR: Bit Scan Reverse, scans for a 1-bit, starting from the MSB)
+ *
+ * In Unicode, all UTF-8 byte sequences with more than 4 bytes are illegal;
+ * lead bytes above 0xf4 are illegal.
+ * We keep them in this table for skipping long ISO 10646-UTF-8 sequences.
+ */
+const uint8
+utf8_countTrailBytes[256]={
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+    3, 3, 3, 3, 3,
+    3, 3, 3,    /* illegal in Unicode */
+    4, 4, 4, 4, /* illegal in Unicode */
+    5, 5,       /* illegal in Unicode */
+    0, 0        /* illegal bytes 0xfe and 0xff */
+};
+
+static const UChar32
+utf8_minLegal[4]={ 0, 0x80, 0x800, 0x10000 };
+
+static const UChar32
+utf8_errorValue[6]={
+    CBUTF8_ERROR_VALUE_1, CBUTF8_ERROR_VALUE_2, CBUTF_ERROR_VALUE, 0x10ffff,
+    0x3ffffff, 0x7fffffff
+};
+
+/*
+ * Handle the non-inline part of the U8_NEXT() macro and its obsolete sibling
+ * UTF8_NEXT_CHAR_SAFE().
+ *
+ * The "strict" parameter controls the error behavior:
+ * <0  "Safe" behavior of U8_NEXT(): All illegal byte sequences yield a negative
+ *     code point result.
+ *  0  Obsolete "safe" behavior of UTF8_NEXT_CHAR_SAFE(..., FALSE):
+ *     All illegal byte sequences yield a positive code point such that this
+ *     result code point would be encoded with the same number of bytes as
+ *     the illegal sequence.
+ * >0  Obsolete "strict" behavior of UTF8_NEXT_CHAR_SAFE(..., TRUE):
+ *     Same as the obsolete "safe" behavior, but non-characters are also treated
+ *     like illegal sequences.
+ *
+ * The special negative (<0) value -2 is used for lenient treatment of surrogate
+ * code points as legal. Some implementations use this for roundtripping of
+ * Unicode 16-bit strings that are not well-formed UTF-16, that is, they
+ * contain unpaired surrogates.
+ *
+ * Note that a UBool is the same as an int8_t.
+ */
+UChar32
+utf8_nextCharSafeBody(const uint8 *s, int32 *pi, int32 length, UChar32 c, UBool strict) {
+    int32 i=*pi;
+    uint8 count=CBU8_COUNT_TRAIL_BYTES(c);
+    if((i)+count<=(length)) {
+        uint8 trail, illegal=0;
+
+        CBU8_MASK_LEAD_BYTE((c), count);
+        /* count==0 for illegally leading trail bytes and the illegal bytes 0xfe and 0xff */
+        switch(count) {
+        /* each branch falls through to the next one */
+        case 5:
+        case 4:
+            /* count>=4 is always illegal: no more than 3 trail bytes in Unicode's UTF-8 */
+            illegal=1;
+            break;
+        case 3:
+            trail=s[(i)++];
+            (c)=((c)<<6)|(trail&0x3f);
+            if(c<0x110) {
+                illegal|=(trail&0xc0)^0x80;
+            } else {
+                /* code point>0x10ffff, outside Unicode */
+                illegal=1;
+                break;
+            }
+        case 2:
+            trail=s[(i)++];
+            (c)=((c)<<6)|(trail&0x3f);
+            illegal|=(trail&0xc0)^0x80;
+        case 1:
+            trail=s[(i)++];
+            (c)=((c)<<6)|(trail&0x3f);
+            illegal|=(trail&0xc0)^0x80;
+            break;
+        case 0:
+            if(strict>=0) {
+                return CBUTF8_ERROR_VALUE_1;
+            } else {
+                return CBU_SENTINEL;
+            }
+        /* no default branch to optimize switch()  - all values are covered */
+        }
+
+        /*
+         * All the error handling should return a value
+         * that needs count bytes so that UTF8_GET_CHAR_SAFE() works right.
+         *
+         * Starting with Unicode 3.0.1, non-shortest forms are illegal.
+         * Starting with Unicode 3.2, surrogate code points must not be
+         * encoded in UTF-8, and there are no irregular sequences any more.
+         *
+         * U8_ macros (new in ICU 2.4) return negative values for error conditions.
+         */
+
+        /* correct sequence - all trail bytes have (b7..b6)==(10)? */
+        /* illegal is also set if count>=4 */
+        if(illegal || (c)<utf8_minLegal[count] || (CBU_IS_SURROGATE(c) && strict!=-2)) {
+            /* error handling */
+            uint8 errorCount=count;
+            /* don't go beyond this sequence */
+            i=*pi;
+            while(count>0 && CBU8_IS_TRAIL(s[i])) {
+                ++(i);
+                --count;
+            }
+            if(strict>=0) {
+                c=utf8_errorValue[errorCount-count];
+            } else {
+                c=CBU_SENTINEL;
+            }
+        } else if((strict)>0 && CBU_IS_UNICODE_NONCHAR(c)) {
+            /* strict: forbid non-characters like U+fffe */
+            c=utf8_errorValue[count];
+        }
+    } else /* too few bytes left */ {
+        /* error handling */
+        int32 i0=i;
+        /* don't just set (i)=(length) in case there is an illegal sequence */
+        while((i)<(length) && CBU8_IS_TRAIL(s[i])) {
+            ++(i);
+        }
+        if(strict>=0) {
+            c=utf8_errorValue[i-i0];
+        } else {
+            c=CBU_SENTINEL;
+        }
+    }
+    *pi=i;
+    return c;
+}
+
+}  // namespace base_icu
diff --git a/base/third_party/icu/icu_utf.h b/base/third_party/icu/icu_utf.h
new file mode 100644
index 0000000..2b993b0
--- /dev/null
+++ b/base/third_party/icu/icu_utf.h
@@ -0,0 +1,391 @@
+/*
+*******************************************************************************
+*
+*   Copyright (C) 1999-2004, International Business Machines
+*   Corporation and others.  All Rights Reserved.
+*
+*******************************************************************************
+*   file name:  utf.h
+*   encoding:   US-ASCII
+*   tab size:   8 (not used)
+*   indentation:4
+*
+*   created on: 1999sep09
+*   created by: Markus W. Scherer
+*/
+
+#ifndef BASE_THIRD_PARTY_ICU_ICU_UTF_H_
+#define BASE_THIRD_PARTY_ICU_ICU_UTF_H_
+
+#include "base/basictypes.h"
+
+namespace base_icu {
+
+typedef int32 UChar32;
+typedef uint16 UChar;
+typedef int8 UBool;
+
+// General ---------------------------------------------------------------------
+// from utf.h
+
+/**
+ * This value is intended for sentinel values for APIs that
+ * (take or) return single code points (UChar32).
+ * It is outside of the Unicode code point range 0..0x10ffff.
+ *
+ * For example, a "done" or "error" value in a new API
+ * could be indicated with CBU_SENTINEL.
+ *
+ * ICU APIs designed before ICU 2.4 usually define service-specific "done"
+ * values, mostly 0xffff.
+ * Those may need to be distinguished from
+ * actual U+ffff text contents by calling functions like
+ * CharacterIterator::hasNext() or UnicodeString::length().
+ *
+ * @return -1
+ * @see UChar32
+ * @stable ICU 2.4
+ */
+#define CBU_SENTINEL (-1)
+
+/**
+ * Is this code point a Unicode noncharacter?
+ * @param c 32-bit code point
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU_IS_UNICODE_NONCHAR(c) \
+    ((c)>=0xfdd0 && \
+     ((uint32)(c)<=0xfdef || ((c)&0xfffe)==0xfffe) && \
+     (uint32)(c)<=0x10ffff)
+
+/**
+ * Is c a Unicode code point value (0..U+10ffff)
+ * that can be assigned a character?
+ *
+ * Code points that are not characters include:
+ * - single surrogate code points (U+d800..U+dfff, 2048 code points)
+ * - the last two code points on each plane (U+__fffe and U+__ffff, 34 code points)
+ * - U+fdd0..U+fdef (new with Unicode 3.1, 32 code points)
+ * - the highest Unicode code point value is U+10ffff
+ *
+ * This means that all code points below U+d800 are character code points,
+ * and that boundary is tested first for performance.
+ *
+ * @param c 32-bit code point
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU_IS_UNICODE_CHAR(c) \
+    ((uint32)(c)<0xd800 || \
+        ((uint32)(c)>0xdfff && \
+         (uint32)(c)<=0x10ffff && \
+         !CBU_IS_UNICODE_NONCHAR(c)))
+
+/**
+ * Is this code point a surrogate (U+d800..U+dfff)?
+ * @param c 32-bit code point
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU_IS_SURROGATE(c) (((c)&0xfffff800)==0xd800)
+
+/**
+ * Assuming c is a surrogate code point (U_IS_SURROGATE(c)),
+ * is it a lead surrogate?
+ * @param c 32-bit code point
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU_IS_SURROGATE_LEAD(c) (((c)&0x400)==0)
+
+
+// UTF-8 macros ----------------------------------------------------------------
+// from utf8.h
+
+extern const uint8 utf8_countTrailBytes[256];
+
+/**
+ * Count the trail bytes for a UTF-8 lead byte.
+ * @internal
+ */
+#define CBU8_COUNT_TRAIL_BYTES(leadByte) (base_icu::utf8_countTrailBytes[(uint8)leadByte])
+
+/**
+ * Mask a UTF-8 lead byte, leave only the lower bits that form part of the code point value.
+ * @internal
+ */
+#define CBU8_MASK_LEAD_BYTE(leadByte, countTrailBytes) ((leadByte)&=(1<<(6-(countTrailBytes)))-1)
+
+/**
+ * Does this code unit (byte) encode a code point by itself (US-ASCII 0..0x7f)?
+ * @param c 8-bit code unit (byte)
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU8_IS_SINGLE(c) (((c)&0x80)==0)
+
+/**
+ * Is this code unit (byte) a UTF-8 lead byte?
+ * @param c 8-bit code unit (byte)
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU8_IS_LEAD(c) ((uint8)((c)-0xc0)<0x3e)
+
+/**
+ * Is this code unit (byte) a UTF-8 trail byte?
+ * @param c 8-bit code unit (byte)
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU8_IS_TRAIL(c) (((c)&0xc0)==0x80)
+
+/**
+ * How many code units (bytes) are used for the UTF-8 encoding
+ * of this Unicode code point?
+ * @param c 32-bit code point
+ * @return 1..4, or 0 if c is a surrogate or not a Unicode code point
+ * @stable ICU 2.4
+ */
+#define CBU8_LENGTH(c) \
+    ((uint32)(c)<=0x7f ? 1 : \
+        ((uint32)(c)<=0x7ff ? 2 : \
+            ((uint32)(c)<=0xd7ff ? 3 : \
+                ((uint32)(c)<=0xdfff || (uint32)(c)>0x10ffff ? 0 : \
+                    ((uint32)(c)<=0xffff ? 3 : 4)\
+                ) \
+            ) \
+        ) \
+    )
+
+/**
+ * The maximum number of UTF-8 code units (bytes) per Unicode code point (U+0000..U+10ffff).
+ * @return 4
+ * @stable ICU 2.4
+ */
+#define CBU8_MAX_LENGTH 4
+
+/**
+ * Function for handling "next code point" with error-checking.
+ * @internal
+ */
+UChar32 utf8_nextCharSafeBody(const uint8 *s, int32 *pi, int32 length, UChar32 c, UBool strict);
+
+/**
+ * Get a code point from a string at a code point boundary offset,
+ * and advance the offset to the next code point boundary.
+ * (Post-incrementing forward iteration.)
+ * "Safe" macro, checks for illegal sequences and for string boundaries.
+ *
+ * The offset may point to the lead byte of a multi-byte sequence,
+ * in which case the macro will read the whole sequence.
+ * If the offset points to a trail byte or an illegal UTF-8 sequence, then
+ * c is set to a negative value.
+ *
+ * @param s const uint8 * string
+ * @param i string offset, i<length
+ * @param length string length
+ * @param c output UChar32 variable, set to <0 in case of an error
+ * @see CBU8_NEXT_UNSAFE
+ * @stable ICU 2.4
+ */
+#define CBU8_NEXT(s, i, length, c) { \
+    (c)=(s)[(i)++]; \
+    if(((uint8)(c))>=0x80) { \
+        if(CBU8_IS_LEAD(c)) { \
+            (c)=base_icu::utf8_nextCharSafeBody((const uint8 *)s, &(i), (int32)(length), c, -1); \
+        } else { \
+            (c)=CBU_SENTINEL; \
+        } \
+    } \
+}
+
+/**
+ * Append a code point to a string, overwriting 1 to 4 bytes.
+ * The offset points to the current end of the string contents
+ * and is advanced (post-increment).
+ * "Unsafe" macro, assumes a valid code point and sufficient space in the string.
+ * Otherwise, the result is undefined.
+ *
+ * @param s const uint8 * string buffer
+ * @param i string offset
+ * @param c code point to append
+ * @see CBU8_APPEND
+ * @stable ICU 2.4
+ */
+#define CBU8_APPEND_UNSAFE(s, i, c) { \
+    if((uint32)(c)<=0x7f) { \
+        (s)[(i)++]=(uint8)(c); \
+    } else { \
+        if((uint32)(c)<=0x7ff) { \
+            (s)[(i)++]=(uint8)(((c)>>6)|0xc0); \
+        } else { \
+            if((uint32)(c)<=0xffff) { \
+                (s)[(i)++]=(uint8)(((c)>>12)|0xe0); \
+            } else { \
+                (s)[(i)++]=(uint8)(((c)>>18)|0xf0); \
+                (s)[(i)++]=(uint8)((((c)>>12)&0x3f)|0x80); \
+            } \
+            (s)[(i)++]=(uint8)((((c)>>6)&0x3f)|0x80); \
+        } \
+        (s)[(i)++]=(uint8)(((c)&0x3f)|0x80); \
+    } \
+}
+
+// UTF-16 macros ---------------------------------------------------------------
+// from utf16.h
+
+/**
+ * Does this code unit alone encode a code point (BMP, not a surrogate)?
+ * @param c 16-bit code unit
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU16_IS_SINGLE(c) !CBU_IS_SURROGATE(c)
+
+/**
+ * Is this code unit a lead surrogate (U+d800..U+dbff)?
+ * @param c 16-bit code unit
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU16_IS_LEAD(c) (((c)&0xfffffc00)==0xd800)
+
+/**
+ * Is this code unit a trail surrogate (U+dc00..U+dfff)?
+ * @param c 16-bit code unit
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU16_IS_TRAIL(c) (((c)&0xfffffc00)==0xdc00)
+
+/**
+ * Is this code unit a surrogate (U+d800..U+dfff)?
+ * @param c 16-bit code unit
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU16_IS_SURROGATE(c) CBU_IS_SURROGATE(c)
+
+/**
+ * Assuming c is a surrogate code point (U16_IS_SURROGATE(c)),
+ * is it a lead surrogate?
+ * @param c 16-bit code unit
+ * @return TRUE or FALSE
+ * @stable ICU 2.4
+ */
+#define CBU16_IS_SURROGATE_LEAD(c) (((c)&0x400)==0)
+
+/**
+ * Helper constant for CBU16_GET_SUPPLEMENTARY.
+ * @internal
+ */
+#define CBU16_SURROGATE_OFFSET ((0xd800<<10UL)+0xdc00-0x10000)
+
+/**
+ * Get a supplementary code point value (U+10000..U+10ffff)
+ * from its lead and trail surrogates.
+ * The result is undefined if the input values are not
+ * lead and trail surrogates.
+ *
+ * @param lead lead surrogate (U+d800..U+dbff)
+ * @param trail trail surrogate (U+dc00..U+dfff)
+ * @return supplementary code point (U+10000..U+10ffff)
+ * @stable ICU 2.4
+ */
+#define CBU16_GET_SUPPLEMENTARY(lead, trail) \
+    (((base_icu::UChar32)(lead)<<10UL)+(base_icu::UChar32)(trail)-CBU16_SURROGATE_OFFSET)
+
+
+/**
+ * Get the lead surrogate (0xd800..0xdbff) for a
+ * supplementary code point (0x10000..0x10ffff).
+ * @param supplementary 32-bit code point (U+10000..U+10ffff)
+ * @return lead surrogate (U+d800..U+dbff) for supplementary
+ * @stable ICU 2.4
+ */
+#define CBU16_LEAD(supplementary) \
+    (base_icu::UChar)(((supplementary)>>10)+0xd7c0)
+
+/**
+ * Get the trail surrogate (0xdc00..0xdfff) for a
+ * supplementary code point (0x10000..0x10ffff).
+ * @param supplementary 32-bit code point (U+10000..U+10ffff)
+ * @return trail surrogate (U+dc00..U+dfff) for supplementary
+ * @stable ICU 2.4
+ */
+#define CBU16_TRAIL(supplementary) \
+    (base_icu::UChar)(((supplementary)&0x3ff)|0xdc00)
+
+/**
+ * How many 16-bit code units are used to encode this Unicode code point? (1 or 2)
+ * The result is not defined if c is not a Unicode code point (U+0000..U+10ffff).
+ * @param c 32-bit code point
+ * @return 1 or 2
+ * @stable ICU 2.4
+ */
+#define CBU16_LENGTH(c) ((uint32)(c)<=0xffff ? 1 : 2)
+
+/**
+ * The maximum number of 16-bit code units per Unicode code point (U+0000..U+10ffff).
+ * @return 2
+ * @stable ICU 2.4
+ */
+#define CBU16_MAX_LENGTH 2
+
+/**
+ * Get a code point from a string at a code point boundary offset,
+ * and advance the offset to the next code point boundary.
+ * (Post-incrementing forward iteration.)
+ * "Safe" macro, handles unpaired surrogates and checks for string boundaries.
+ *
+ * The offset may point to the lead surrogate unit
+ * for a supplementary code point, in which case the macro will read
+ * the following trail surrogate as well.
+ * If the offset points to a trail surrogate or
+ * to a single, unpaired lead surrogate, then that itself
+ * will be returned as the code point.
+ *
+ * @param s const UChar * string
+ * @param i string offset, i<length
+ * @param length string length
+ * @param c output UChar32 variable
+ * @stable ICU 2.4
+ */
+#define CBU16_NEXT(s, i, length, c) { \
+    (c)=(s)[(i)++]; \
+    if(CBU16_IS_LEAD(c)) { \
+        uint16 __c2; \
+        if((i)<(length) && CBU16_IS_TRAIL(__c2=(s)[(i)])) { \
+            ++(i); \
+            (c)=CBU16_GET_SUPPLEMENTARY((c), __c2); \
+        } \
+    } \
+}
+
+/**
+ * Append a code point to a string, overwriting 1 or 2 code units.
+ * The offset points to the current end of the string contents
+ * and is advanced (post-increment).
+ * "Unsafe" macro, assumes a valid code point and sufficient space in the string.
+ * Otherwise, the result is undefined.
+ *
+ * @param s const UChar * string buffer
+ * @param i string offset
+ * @param c code point to append
+ * @see CBU16_APPEND
+ * @stable ICU 2.4
+ */
+#define CBU16_APPEND_UNSAFE(s, i, c) { \
+    if((uint32)(c)<=0xffff) { \
+        (s)[(i)++]=(uint16)(c); \
+    } else { \
+        (s)[(i)++]=(uint16)(((c)>>10)+0xd7c0); \
+        (s)[(i)++]=(uint16)(((c)&0x3ff)|0xdc00); \
+    } \
+}
+
+}  // namesapce base_icu
+
+#endif  // BASE_THIRD_PARTY_ICU_ICU_UTF_H_
diff --git a/base/third_party/nspr/LICENSE b/base/third_party/nspr/LICENSE
new file mode 100644
index 0000000..eba7b77
--- /dev/null
+++ b/base/third_party/nspr/LICENSE
@@ -0,0 +1,35 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
diff --git a/base/third_party/nspr/OWNERS b/base/third_party/nspr/OWNERS
new file mode 100644
index 0000000..20ba660
--- /dev/null
+++ b/base/third_party/nspr/OWNERS
@@ -0,0 +1,2 @@
+rsleevi@chromium.org
+wtc@chromium.org
diff --git a/base/third_party/nspr/README.chromium b/base/third_party/nspr/README.chromium
new file mode 100644
index 0000000..3659a2c
--- /dev/null
+++ b/base/third_party/nspr/README.chromium
@@ -0,0 +1,3 @@
+Name: Netscape Portable Runtime (NSPR)
+URL: http://www.mozilla.org/projects/nspr/
+License: MPL 1.1/GPL 2.0/LGPL 2.1
diff --git a/base/third_party/nspr/prtime.cc b/base/third_party/nspr/prtime.cc
new file mode 100644
index 0000000..9335b01
--- /dev/null
+++ b/base/third_party/nspr/prtime.cc
@@ -0,0 +1,1252 @@
+/* Portions are Copyright (C) 2011 Google Inc */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * prtime.cc --
+ * NOTE: The original nspr file name is prtime.c
+ *
+ *     NSPR date and time functions
+ *
+ * CVS revision 3.37
+ */
+
+/*
+ * The following functions were copied from the NSPR prtime.c file.
+ * PR_ParseTimeString
+ *   We inlined the new PR_ParseTimeStringToExplodedTime function to avoid
+ *   copying PR_ExplodeTime and PR_LocalTimeParameters.  (The PR_ExplodeTime
+ *   and PR_ImplodeTime calls cancel each other out.)
+ * PR_NormalizeTime
+ * PR_GMTParameters
+ * PR_ImplodeTime
+ *   This was modified to use the Win32 SYSTEMTIME/FILETIME structures
+ *   and the timezone offsets are applied to the FILETIME structure.
+ * All types and macros are defined in the base/third_party/prtime.h file.
+ * These have been copied from the following nspr files. We have only copied
+ * over the types we need.
+ * 1. prtime.h
+ * 2. prtypes.h
+ * 3. prlong.h
+ *
+ * Unit tests are in base/time/pr_time_unittest.cc.
+ */
+
+#include "base/logging.h"
+#include "base/third_party/nspr/prtime.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#elif defined(OS_MACOSX)
+#include <CoreFoundation/CoreFoundation.h>
+#elif defined(OS_ANDROID)
+#include <ctype.h>
+#include "base/os_compat_android.h"  // For timegm()
+#elif defined(OS_NACL)
+#include "base/os_compat_nacl.h"  // For timegm()
+#endif
+#include <errno.h>  /* for EINVAL */
+#include <time.h>
+
+/* Implements the Unix localtime_r() function for windows */
+#if defined(OS_WIN)
+static void localtime_r(const time_t* secs, struct tm* time) {
+  (void) localtime_s(time, secs);
+}
+#endif
+
+/*
+ *------------------------------------------------------------------------
+ *
+ * PR_ImplodeTime --
+ *
+ *     Cf. time_t mktime(struct tm *tp)
+ *     Note that 1 year has < 2^25 seconds.  So an PRInt32 is large enough.
+ *
+ *------------------------------------------------------------------------
+ */
+PRTime
+PR_ImplodeTime(const PRExplodedTime *exploded)
+{
+    // This is important, we want to make sure multiplications are
+    // done with the correct precision.
+    static const PRTime kSecondsToMicroseconds = static_cast<PRTime>(1000000);
+#if defined(OS_WIN)
+   // Create the system struct representing our exploded time.
+    SYSTEMTIME st = {0};
+    FILETIME ft = {0};
+    ULARGE_INTEGER uli = {0};
+
+    st.wYear = exploded->tm_year;
+    st.wMonth = static_cast<WORD>(exploded->tm_month + 1);
+    st.wDayOfWeek = exploded->tm_wday;
+    st.wDay = static_cast<WORD>(exploded->tm_mday);
+    st.wHour = static_cast<WORD>(exploded->tm_hour);
+    st.wMinute = static_cast<WORD>(exploded->tm_min);
+    st.wSecond = static_cast<WORD>(exploded->tm_sec);
+    st.wMilliseconds = static_cast<WORD>(exploded->tm_usec/1000);
+     // Convert to FILETIME.
+    if (!SystemTimeToFileTime(&st, &ft)) {
+      NOTREACHED() << "Unable to convert time";
+      return 0;
+    }
+    // Apply offsets.
+    uli.LowPart = ft.dwLowDateTime;
+    uli.HighPart = ft.dwHighDateTime;
+    // Convert from Windows epoch to NSPR epoch, and 100-nanoseconds units
+    // to microsecond units.
+    PRTime result =
+        static_cast<PRTime>((uli.QuadPart / 10) - 11644473600000000i64);
+    // Adjust for time zone and dst.  Convert from seconds to microseconds.
+    result -= (exploded->tm_params.tp_gmt_offset +
+               exploded->tm_params.tp_dst_offset) * kSecondsToMicroseconds;
+    // Add microseconds that cannot be represented in |st|.
+    result += exploded->tm_usec % 1000;
+    return result;
+#elif defined(OS_MACOSX)
+    // Create the system struct representing our exploded time.
+    CFGregorianDate gregorian_date;
+    gregorian_date.year = exploded->tm_year;
+    gregorian_date.month = exploded->tm_month + 1;
+    gregorian_date.day = exploded->tm_mday;
+    gregorian_date.hour = exploded->tm_hour;
+    gregorian_date.minute = exploded->tm_min;
+    gregorian_date.second = exploded->tm_sec;
+
+    // Compute |absolute_time| in seconds, correct for gmt and dst
+    // (note the combined offset will be negative when we need to add it), then
+    // convert to microseconds which is what PRTime expects.
+    CFAbsoluteTime absolute_time =
+        CFGregorianDateGetAbsoluteTime(gregorian_date, NULL);
+    PRTime result = static_cast<PRTime>(absolute_time);
+    result -= exploded->tm_params.tp_gmt_offset +
+              exploded->tm_params.tp_dst_offset;
+    result += kCFAbsoluteTimeIntervalSince1970;  // PRTime epoch is 1970
+    result *= kSecondsToMicroseconds;
+    result += exploded->tm_usec;
+    return result;
+#elif defined(OS_POSIX)
+    struct tm exp_tm = {0};
+    exp_tm.tm_sec  = exploded->tm_sec;
+    exp_tm.tm_min  = exploded->tm_min;
+    exp_tm.tm_hour = exploded->tm_hour;
+    exp_tm.tm_mday = exploded->tm_mday;
+    exp_tm.tm_mon  = exploded->tm_month;
+    exp_tm.tm_year = exploded->tm_year - 1900;
+
+    time_t absolute_time = timegm(&exp_tm);
+
+    // If timegm returned -1.  Since we don't pass it a time zone, the only
+    // valid case of returning -1 is 1 second before Epoch (Dec 31, 1969).
+    if (absolute_time == -1 &&
+        !(exploded->tm_year == 1969 && exploded->tm_month == 11 &&
+        exploded->tm_mday == 31 && exploded->tm_hour == 23 &&
+        exploded->tm_min == 59 && exploded->tm_sec == 59)) {
+      // If we get here, time_t must be 32 bits.
+      // Date was possibly too far in the future and would overflow.  Return
+      // the most future date possible (year 2038).
+      if (exploded->tm_year >= 1970)
+        return INT_MAX * kSecondsToMicroseconds;
+      // Date was possibly too far in the past and would underflow.  Return
+      // the most past date possible (year 1901).
+      return INT_MIN * kSecondsToMicroseconds;
+    }
+
+    PRTime result = static_cast<PRTime>(absolute_time);
+    result -= exploded->tm_params.tp_gmt_offset +
+              exploded->tm_params.tp_dst_offset;
+    result *= kSecondsToMicroseconds;
+    result += exploded->tm_usec;
+    return result;
+#else
+#error No PR_ImplodeTime implemented on your platform.
+#endif
+}
+
+/* 
+ * The COUNT_LEAPS macro counts the number of leap years passed by
+ * till the start of the given year Y.  At the start of the year 4
+ * A.D. the number of leap years passed by is 0, while at the start of
+ * the year 5 A.D. this count is 1. The number of years divisible by
+ * 100 but not divisible by 400 (the non-leap years) is deducted from
+ * the count to get the correct number of leap years.
+ *
+ * The COUNT_DAYS macro counts the number of days since 01/01/01 till the
+ * start of the given year Y. The number of days at the start of the year
+ * 1 is 0 while the number of days at the start of the year 2 is 365
+ * (which is ((2)-1) * 365) and so on. The reference point is 01/01/01
+ * midnight 00:00:00.
+ */
+
+#define COUNT_LEAPS(Y)   ( ((Y)-1)/4 - ((Y)-1)/100 + ((Y)-1)/400 )
+#define COUNT_DAYS(Y)  ( ((Y)-1)*365 + COUNT_LEAPS(Y) )
+#define DAYS_BETWEEN_YEARS(A, B)  (COUNT_DAYS(B) - COUNT_DAYS(A))
+
+/*
+ * Static variables used by functions in this file
+ */
+
+/*
+ * The following array contains the day of year for the last day of
+ * each month, where index 1 is January, and day 0 is January 1.
+ */
+
+static const int lastDayOfMonth[2][13] = {
+    {-1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364},
+    {-1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}
+};
+
+/*
+ * The number of days in a month
+ */
+
+static const PRInt8 nDays[2][12] = {
+    {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
+    {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
+};
+
+/*
+ *-------------------------------------------------------------------------
+ *
+ * IsLeapYear --
+ *
+ *     Returns 1 if the year is a leap year, 0 otherwise.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static int IsLeapYear(PRInt16 year)
+{
+    if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
+        return 1;
+    else
+        return 0;
+}
+
+/*
+ * 'secOffset' should be less than 86400 (i.e., a day).
+ * 'time' should point to a normalized PRExplodedTime.
+ */
+
+static void
+ApplySecOffset(PRExplodedTime *time, PRInt32 secOffset)
+{
+    time->tm_sec += secOffset;
+
+    /* Note that in this implementation we do not count leap seconds */
+    if (time->tm_sec < 0 || time->tm_sec >= 60) {
+        time->tm_min += time->tm_sec / 60;
+        time->tm_sec %= 60;
+        if (time->tm_sec < 0) {
+            time->tm_sec += 60;
+            time->tm_min--;
+        }
+    }
+
+    if (time->tm_min < 0 || time->tm_min >= 60) {
+        time->tm_hour += time->tm_min / 60;
+        time->tm_min %= 60;
+        if (time->tm_min < 0) {
+            time->tm_min += 60;
+            time->tm_hour--;
+        }
+    }
+
+    if (time->tm_hour < 0) {
+        /* Decrement mday, yday, and wday */
+        time->tm_hour += 24;
+        time->tm_mday--;
+        time->tm_yday--;
+        if (time->tm_mday < 1) {
+            time->tm_month--;
+            if (time->tm_month < 0) {
+                time->tm_month = 11;
+                time->tm_year--;
+                if (IsLeapYear(time->tm_year))
+                    time->tm_yday = 365;
+                else
+                    time->tm_yday = 364;
+            }
+            time->tm_mday = nDays[IsLeapYear(time->tm_year)][time->tm_month];
+        }
+        time->tm_wday--;
+        if (time->tm_wday < 0)
+            time->tm_wday = 6;
+    } else if (time->tm_hour > 23) {
+        /* Increment mday, yday, and wday */
+        time->tm_hour -= 24;
+        time->tm_mday++;
+        time->tm_yday++;
+        if (time->tm_mday >
+                nDays[IsLeapYear(time->tm_year)][time->tm_month]) {
+            time->tm_mday = 1;
+            time->tm_month++;
+            if (time->tm_month > 11) {
+                time->tm_month = 0;
+                time->tm_year++;
+                time->tm_yday = 0;
+            }
+        }
+        time->tm_wday++;
+        if (time->tm_wday > 6)
+            time->tm_wday = 0;
+    }
+}
+
+void
+PR_NormalizeTime(PRExplodedTime *time, PRTimeParamFn params)
+{
+    int daysInMonth;
+    PRInt32 numDays;
+
+    /* Get back to GMT */
+    time->tm_sec -= time->tm_params.tp_gmt_offset
+            + time->tm_params.tp_dst_offset;
+    time->tm_params.tp_gmt_offset = 0;
+    time->tm_params.tp_dst_offset = 0;
+
+    /* Now normalize GMT */
+
+    if (time->tm_usec < 0 || time->tm_usec >= 1000000) {
+        time->tm_sec +=  time->tm_usec / 1000000;
+        time->tm_usec %= 1000000;
+        if (time->tm_usec < 0) {
+            time->tm_usec += 1000000;
+            time->tm_sec--;
+        }
+    }
+
+    /* Note that we do not count leap seconds in this implementation */
+    if (time->tm_sec < 0 || time->tm_sec >= 60) {
+        time->tm_min += time->tm_sec / 60;
+        time->tm_sec %= 60;
+        if (time->tm_sec < 0) {
+            time->tm_sec += 60;
+            time->tm_min--;
+        }
+    }
+
+    if (time->tm_min < 0 || time->tm_min >= 60) {
+        time->tm_hour += time->tm_min / 60;
+        time->tm_min %= 60;
+        if (time->tm_min < 0) {
+            time->tm_min += 60;
+            time->tm_hour--;
+        }
+    }
+
+    if (time->tm_hour < 0 || time->tm_hour >= 24) {
+        time->tm_mday += time->tm_hour / 24;
+        time->tm_hour %= 24;
+        if (time->tm_hour < 0) {
+            time->tm_hour += 24;
+            time->tm_mday--;
+        }
+    }
+
+    /* Normalize month and year before mday */
+    if (time->tm_month < 0 || time->tm_month >= 12) {
+        time->tm_year += static_cast<PRInt16>(time->tm_month / 12);
+        time->tm_month %= 12;
+        if (time->tm_month < 0) {
+            time->tm_month += 12;
+            time->tm_year--;
+        }
+    }
+
+    /* Now that month and year are in proper range, normalize mday */
+
+    if (time->tm_mday < 1) {
+        /* mday too small */
+        do {
+            /* the previous month */
+            time->tm_month--;
+            if (time->tm_month < 0) {
+                time->tm_month = 11;
+                time->tm_year--;
+            }
+            time->tm_mday += nDays[IsLeapYear(time->tm_year)][time->tm_month];
+        } while (time->tm_mday < 1);
+    } else {
+        daysInMonth = nDays[IsLeapYear(time->tm_year)][time->tm_month];
+        while (time->tm_mday > daysInMonth) {
+            /* mday too large */
+            time->tm_mday -= daysInMonth;
+            time->tm_month++;
+            if (time->tm_month > 11) {
+                time->tm_month = 0;
+                time->tm_year++;
+            }
+            daysInMonth = nDays[IsLeapYear(time->tm_year)][time->tm_month];
+        }
+    }
+
+    /* Recompute yday and wday */
+    time->tm_yday = static_cast<PRInt16>(time->tm_mday +
+            lastDayOfMonth[IsLeapYear(time->tm_year)][time->tm_month]);
+
+    numDays = DAYS_BETWEEN_YEARS(1970, time->tm_year) + time->tm_yday;
+    time->tm_wday = (numDays + 4) % 7;
+    if (time->tm_wday < 0) {
+        time->tm_wday += 7;
+    }
+
+    /* Recompute time parameters */
+
+    time->tm_params = params(time);
+
+    ApplySecOffset(time, time->tm_params.tp_gmt_offset
+            + time->tm_params.tp_dst_offset);
+}
+
+/*
+ *------------------------------------------------------------------------
+ *
+ * PR_GMTParameters --
+ *
+ *     Returns the PRTimeParameters for Greenwich Mean Time.
+ *     Trivially, both the tp_gmt_offset and tp_dst_offset fields are 0.
+ *
+ *------------------------------------------------------------------------
+ */
+
+PRTimeParameters
+PR_GMTParameters(const PRExplodedTime *gmt)
+{
+    PRTimeParameters retVal = { 0, 0 };
+    return retVal;
+}
+
+/*
+ * The following code implements PR_ParseTimeString().  It is based on
+ * ns/lib/xp/xp_time.c, revision 1.25, by Jamie Zawinski <jwz@netscape.com>.
+ */
+
+/*
+ * We only recognize the abbreviations of a small subset of time zones
+ * in North America, Europe, and Japan.
+ *
+ * PST/PDT: Pacific Standard/Daylight Time
+ * MST/MDT: Mountain Standard/Daylight Time
+ * CST/CDT: Central Standard/Daylight Time
+ * EST/EDT: Eastern Standard/Daylight Time
+ * AST: Atlantic Standard Time
+ * NST: Newfoundland Standard Time
+ * GMT: Greenwich Mean Time
+ * BST: British Summer Time
+ * MET: Middle Europe Time
+ * EET: Eastern Europe Time
+ * JST: Japan Standard Time
+ */
+
+typedef enum
+{
+  TT_UNKNOWN,
+
+  TT_SUN, TT_MON, TT_TUE, TT_WED, TT_THU, TT_FRI, TT_SAT,
+
+  TT_JAN, TT_FEB, TT_MAR, TT_APR, TT_MAY, TT_JUN,
+  TT_JUL, TT_AUG, TT_SEP, TT_OCT, TT_NOV, TT_DEC,
+
+  TT_PST, TT_PDT, TT_MST, TT_MDT, TT_CST, TT_CDT, TT_EST, TT_EDT,
+  TT_AST, TT_NST, TT_GMT, TT_BST, TT_MET, TT_EET, TT_JST
+} TIME_TOKEN;
+
+/*
+ * This parses a time/date string into a PRTime
+ * (microseconds after "1-Jan-1970 00:00:00 GMT").
+ * It returns PR_SUCCESS on success, and PR_FAILURE
+ * if the time/date string can't be parsed.
+ *
+ * Many formats are handled, including:
+ *
+ *   14 Apr 89 03:20:12
+ *   14 Apr 89 03:20 GMT
+ *   Fri, 17 Mar 89 4:01:33
+ *   Fri, 17 Mar 89 4:01 GMT
+ *   Mon Jan 16 16:12 PDT 1989
+ *   Mon Jan 16 16:12 +0130 1989
+ *   6 May 1992 16:41-JST (Wednesday)
+ *   22-AUG-1993 10:59:12.82
+ *   22-AUG-1993 10:59pm
+ *   22-AUG-1993 12:59am
+ *   22-AUG-1993 12:59 PM
+ *   Friday, August 04, 1995 3:54 PM
+ *   06/21/95 04:24:34 PM
+ *   20/06/95 21:07
+ *   95-06-08 19:32:48 EDT
+ *   1995-06-17T23:11:25.342156Z
+ *
+ * If the input string doesn't contain a description of the timezone,
+ * we consult the `default_to_gmt' to decide whether the string should
+ * be interpreted relative to the local time zone (PR_FALSE) or GMT (PR_TRUE).
+ * The correct value for this argument depends on what standard specified
+ * the time string which you are parsing.
+ */
+
+PRStatus
+PR_ParseTimeString(
+        const char *string,
+        PRBool default_to_gmt,
+        PRTime *result_imploded)
+{
+  PRExplodedTime tm;
+  PRExplodedTime *result = &tm;
+  TIME_TOKEN dotw = TT_UNKNOWN;
+  TIME_TOKEN month = TT_UNKNOWN;
+  TIME_TOKEN zone = TT_UNKNOWN;
+  int zone_offset = -1;
+  int dst_offset = 0;
+  int date = -1;
+  PRInt32 year = -1;
+  int hour = -1;
+  int min = -1;
+  int sec = -1;
+  int usec = -1;
+
+  const char *rest = string;
+
+  int iterations = 0;
+
+  PR_ASSERT(string && result);
+  if (!string || !result) return PR_FAILURE;
+
+  while (*rest)
+        {
+
+          if (iterations++ > 1000)
+                {
+                  return PR_FAILURE;
+                }
+
+          switch (*rest)
+                {
+                case 'a': case 'A':
+                  if (month == TT_UNKNOWN &&
+                          (rest[1] == 'p' || rest[1] == 'P') &&
+                          (rest[2] == 'r' || rest[2] == 'R'))
+                        month = TT_APR;
+                  else if (zone == TT_UNKNOWN &&
+                                   (rest[1] == 's' || rest[1] == 'S') &&
+                                   (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_AST;
+                  else if (month == TT_UNKNOWN &&
+                                   (rest[1] == 'u' || rest[1] == 'U') &&
+                                   (rest[2] == 'g' || rest[2] == 'G'))
+                        month = TT_AUG;
+                  break;
+                case 'b': case 'B':
+                  if (zone == TT_UNKNOWN &&
+                          (rest[1] == 's' || rest[1] == 'S') &&
+                          (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_BST;
+                  break;
+                case 'c': case 'C':
+                  if (zone == TT_UNKNOWN &&
+                          (rest[1] == 'd' || rest[1] == 'D') &&
+                          (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_CDT;
+                  else if (zone == TT_UNKNOWN &&
+                                   (rest[1] == 's' || rest[1] == 'S') &&
+                                   (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_CST;
+                  break;
+                case 'd': case 'D':
+                  if (month == TT_UNKNOWN &&
+                          (rest[1] == 'e' || rest[1] == 'E') &&
+                          (rest[2] == 'c' || rest[2] == 'C'))
+                        month = TT_DEC;
+                  break;
+                case 'e': case 'E':
+                  if (zone == TT_UNKNOWN &&
+                          (rest[1] == 'd' || rest[1] == 'D') &&
+                          (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_EDT;
+                  else if (zone == TT_UNKNOWN &&
+                                   (rest[1] == 'e' || rest[1] == 'E') &&
+                                   (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_EET;
+                  else if (zone == TT_UNKNOWN &&
+                                   (rest[1] == 's' || rest[1] == 'S') &&
+                                   (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_EST;
+                  break;
+                case 'f': case 'F':
+                  if (month == TT_UNKNOWN &&
+                          (rest[1] == 'e' || rest[1] == 'E') &&
+                          (rest[2] == 'b' || rest[2] == 'B'))
+                        month = TT_FEB;
+                  else if (dotw == TT_UNKNOWN &&
+                                   (rest[1] == 'r' || rest[1] == 'R') &&
+                                   (rest[2] == 'i' || rest[2] == 'I'))
+                        dotw = TT_FRI;
+                  break;
+                case 'g': case 'G':
+                  if (zone == TT_UNKNOWN &&
+                          (rest[1] == 'm' || rest[1] == 'M') &&
+                          (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_GMT;
+                  break;
+                case 'j': case 'J':
+                  if (month == TT_UNKNOWN &&
+                          (rest[1] == 'a' || rest[1] == 'A') &&
+                          (rest[2] == 'n' || rest[2] == 'N'))
+                        month = TT_JAN;
+                  else if (zone == TT_UNKNOWN &&
+                                   (rest[1] == 's' || rest[1] == 'S') &&
+                                   (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_JST;
+                  else if (month == TT_UNKNOWN &&
+                                   (rest[1] == 'u' || rest[1] == 'U') &&
+                                   (rest[2] == 'l' || rest[2] == 'L'))
+                        month = TT_JUL;
+                  else if (month == TT_UNKNOWN &&
+                                   (rest[1] == 'u' || rest[1] == 'U') &&
+                                   (rest[2] == 'n' || rest[2] == 'N'))
+                        month = TT_JUN;
+                  break;
+                case 'm': case 'M':
+                  if (month == TT_UNKNOWN &&
+                          (rest[1] == 'a' || rest[1] == 'A') &&
+                          (rest[2] == 'r' || rest[2] == 'R'))
+                        month = TT_MAR;
+                  else if (month == TT_UNKNOWN &&
+                                   (rest[1] == 'a' || rest[1] == 'A') &&
+                                   (rest[2] == 'y' || rest[2] == 'Y'))
+                        month = TT_MAY;
+                  else if (zone == TT_UNKNOWN &&
+                                   (rest[1] == 'd' || rest[1] == 'D') &&
+                                   (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_MDT;
+                  else if (zone == TT_UNKNOWN &&
+                                   (rest[1] == 'e' || rest[1] == 'E') &&
+                                   (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_MET;
+                  else if (dotw == TT_UNKNOWN &&
+                                   (rest[1] == 'o' || rest[1] == 'O') &&
+                                   (rest[2] == 'n' || rest[2] == 'N'))
+                        dotw = TT_MON;
+                  else if (zone == TT_UNKNOWN &&
+                                   (rest[1] == 's' || rest[1] == 'S') &&
+                                   (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_MST;
+                  break;
+                case 'n': case 'N':
+                  if (month == TT_UNKNOWN &&
+                          (rest[1] == 'o' || rest[1] == 'O') &&
+                          (rest[2] == 'v' || rest[2] == 'V'))
+                        month = TT_NOV;
+                  else if (zone == TT_UNKNOWN &&
+                                   (rest[1] == 's' || rest[1] == 'S') &&
+                                   (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_NST;
+                  break;
+                case 'o': case 'O':
+                  if (month == TT_UNKNOWN &&
+                          (rest[1] == 'c' || rest[1] == 'C') &&
+                          (rest[2] == 't' || rest[2] == 'T'))
+                        month = TT_OCT;
+                  break;
+                case 'p': case 'P':
+                  if (zone == TT_UNKNOWN &&
+                          (rest[1] == 'd' || rest[1] == 'D') &&
+                          (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_PDT;
+                  else if (zone == TT_UNKNOWN &&
+                                   (rest[1] == 's' || rest[1] == 'S') &&
+                                   (rest[2] == 't' || rest[2] == 'T'))
+                        zone = TT_PST;
+                  break;
+                case 's': case 'S':
+                  if (dotw == TT_UNKNOWN &&
+                          (rest[1] == 'a' || rest[1] == 'A') &&
+                          (rest[2] == 't' || rest[2] == 'T'))
+                        dotw = TT_SAT;
+                  else if (month == TT_UNKNOWN &&
+                                   (rest[1] == 'e' || rest[1] == 'E') &&
+                                   (rest[2] == 'p' || rest[2] == 'P'))
+                        month = TT_SEP;
+                  else if (dotw == TT_UNKNOWN &&
+                                   (rest[1] == 'u' || rest[1] == 'U') &&
+                                   (rest[2] == 'n' || rest[2] == 'N'))
+                        dotw = TT_SUN;
+                  break;
+                case 't': case 'T':
+                  if (dotw == TT_UNKNOWN &&
+                          (rest[1] == 'h' || rest[1] == 'H') &&
+                          (rest[2] == 'u' || rest[2] == 'U'))
+                        dotw = TT_THU;
+                  else if (dotw == TT_UNKNOWN &&
+                                   (rest[1] == 'u' || rest[1] == 'U') &&
+                                   (rest[2] == 'e' || rest[2] == 'E'))
+                        dotw = TT_TUE;
+                  break;
+                case 'u': case 'U':
+                  if (zone == TT_UNKNOWN &&
+                          (rest[1] == 't' || rest[1] == 'T') &&
+                          !(rest[2] >= 'A' && rest[2] <= 'Z') &&
+                          !(rest[2] >= 'a' && rest[2] <= 'z'))
+                        /* UT is the same as GMT but UTx is not. */
+                        zone = TT_GMT;
+                  break;
+                case 'w': case 'W':
+                  if (dotw == TT_UNKNOWN &&
+                          (rest[1] == 'e' || rest[1] == 'E') &&
+                          (rest[2] == 'd' || rest[2] == 'D'))
+                        dotw = TT_WED;
+                  break;
+
+                case '+': case '-':
+                  {
+                        const char *end;
+                        int sign;
+                        if (zone_offset != -1)
+                          {
+                                /* already got one... */
+                                rest++;
+                                break;
+                          }
+                        if (zone != TT_UNKNOWN && zone != TT_GMT)
+                          {
+                                /* GMT+0300 is legal, but PST+0300 is not. */
+                                rest++;
+                                break;
+                          }
+
+                        sign = ((*rest == '+') ? 1 : -1);
+                        rest++; /* move over sign */
+                        end = rest;
+                        while (*end >= '0' && *end <= '9')
+                          end++;
+                        if (rest == end) /* no digits here */
+                          break;
+
+                        if ((end - rest) == 4)
+                          /* offset in HHMM */
+                          zone_offset = (((((rest[0]-'0')*10) + (rest[1]-'0')) * 60) +
+                                                         (((rest[2]-'0')*10) + (rest[3]-'0')));
+                        else if ((end - rest) == 2)
+                          /* offset in hours */
+                          zone_offset = (((rest[0]-'0')*10) + (rest[1]-'0')) * 60;
+                        else if ((end - rest) == 1)
+                          /* offset in hours */
+                          zone_offset = (rest[0]-'0') * 60;
+                        else
+                          /* 3 or >4 */
+                          break;
+
+                        zone_offset *= sign;
+                        zone = TT_GMT;
+                        break;
+                  }
+
+                case '0': case '1': case '2': case '3': case '4':
+                case '5': case '6': case '7': case '8': case '9':
+                  {
+                        int tmp_hour = -1;
+                        int tmp_min = -1;
+                        int tmp_sec = -1;
+                        int tmp_usec = -1;
+                        const char *end = rest + 1;
+                        while (*end >= '0' && *end <= '9')
+                          end++;
+
+                        /* end is now the first character after a range of digits. */
+
+                        if (*end == ':')
+                          {
+                                if (hour >= 0 && min >= 0) /* already got it */
+                                  break;
+
+                                /* We have seen "[0-9]+:", so this is probably HH:MM[:SS] */
+                                if ((end - rest) > 2)
+                                  /* it is [0-9][0-9][0-9]+: */
+                                  break;
+                                else if ((end - rest) == 2)
+                                  tmp_hour = ((rest[0]-'0')*10 +
+                                                          (rest[1]-'0'));
+                                else
+                                  tmp_hour = (rest[0]-'0');
+
+                                /* move over the colon, and parse minutes */
+
+                                rest = ++end;
+                                while (*end >= '0' && *end <= '9')
+                                  end++;
+
+                                if (end == rest)
+                                  /* no digits after first colon? */
+                                  break;
+                                else if ((end - rest) > 2)
+                                  /* it is [0-9][0-9][0-9]+: */
+                                  break;
+                                else if ((end - rest) == 2)
+                                  tmp_min = ((rest[0]-'0')*10 +
+                                                         (rest[1]-'0'));
+                                else
+                                  tmp_min = (rest[0]-'0');
+
+                                /* now go for seconds */
+                                rest = end;
+                                if (*rest == ':')
+                                  rest++;
+                                end = rest;
+                                while (*end >= '0' && *end <= '9')
+                                  end++;
+
+                                if (end == rest)
+                                  /* no digits after second colon - that's ok. */
+                                  ;
+                                else if ((end - rest) > 2)
+                                  /* it is [0-9][0-9][0-9]+: */
+                                  break;
+                                else if ((end - rest) == 2)
+                                  tmp_sec = ((rest[0]-'0')*10 +
+                                                         (rest[1]-'0'));
+                                else
+                                  tmp_sec = (rest[0]-'0');
+
+                                /* fractional second */
+                                rest = end;
+                                if (*rest == '.')
+                                  {
+                                    rest++;
+                                    end++;
+                                    tmp_usec = 0;
+                                    /* use up to 6 digits, skip over the rest */
+                                    while (*end >= '0' && *end <= '9')
+                                      {
+                                        if (end - rest < 6)
+                                          tmp_usec = tmp_usec * 10 + *end - '0';
+                                        end++;
+                                      }
+                                    int ndigits = end - rest;
+                                    while (ndigits++ < 6)
+                                      tmp_usec *= 10;
+                                    rest = end;
+                                  }
+
+                                if (*rest == 'Z')
+                                  {
+                                    zone = TT_GMT;
+                                    rest++;
+                                  }
+                                else if (tmp_hour <= 12)
+                                  {
+                                    /* If we made it here, we've parsed hour and min,
+                                       and possibly sec, so the current token is a time.
+                                       Now skip over whitespace and see if there's an AM
+                                       or PM directly following the time.
+                                    */
+                                        const char *s = end;
+                                        while (*s && (*s == ' ' || *s == '\t'))
+                                          s++;
+                                        if ((s[0] == 'p' || s[0] == 'P') &&
+                                                (s[1] == 'm' || s[1] == 'M'))
+                                          /* 10:05pm == 22:05, and 12:05pm == 12:05 */
+                                          tmp_hour = (tmp_hour == 12 ? 12 : tmp_hour + 12);
+                                        else if (tmp_hour == 12 &&
+                                                         (s[0] == 'a' || s[0] == 'A') &&
+                                                         (s[1] == 'm' || s[1] == 'M'))
+                                          /* 12:05am == 00:05 */
+                                          tmp_hour = 0;
+                                  }
+
+                                hour = tmp_hour;
+                                min = tmp_min;
+                                sec = tmp_sec;
+                                usec = tmp_usec;
+                                rest = end;
+                                break;
+                          }
+                        else if ((*end == '/' || *end == '-') &&
+                                         end[1] >= '0' && end[1] <= '9')
+                          {
+                                /* Perhaps this is 6/16/95, 16/6/95, 6-16-95, or 16-6-95
+                                   or even 95-06-05 or 1995-06-22.
+                                 */
+                                int n1, n2, n3;
+                                const char *s;
+
+                                if (month != TT_UNKNOWN)
+                                  /* if we saw a month name, this can't be. */
+                                  break;
+
+                                s = rest;
+
+                                n1 = (*s++ - '0');                                /* first 1, 2 or 4 digits */
+                                if (*s >= '0' && *s <= '9')
+                                  {
+                                    n1 = n1*10 + (*s++ - '0');
+
+                                    if (*s >= '0' && *s <= '9')            /* optional digits 3 and 4 */
+                                      {
+                                        n1 = n1*10 + (*s++ - '0');
+                                        if (*s < '0' || *s > '9')
+                                          break;
+                                        n1 = n1*10 + (*s++ - '0');
+                                      }
+                                  }
+
+                                if (*s != '/' && *s != '-')                /* slash */
+                                  break;
+                                s++;
+
+                                if (*s < '0' || *s > '9')                /* second 1 or 2 digits */
+                                  break;
+                                n2 = (*s++ - '0');
+                                if (*s >= '0' && *s <= '9')
+                                  n2 = n2*10 + (*s++ - '0');
+
+                                if (*s != '/' && *s != '-')                /* slash */
+                                  break;
+                                s++;
+
+                                if (*s < '0' || *s > '9')                /* third 1, 2, 4, or 5 digits */
+                                  break;
+                                n3 = (*s++ - '0');
+                                if (*s >= '0' && *s <= '9')
+                                  n3 = n3*10 + (*s++ - '0');
+
+                                if (*s >= '0' && *s <= '9')            /* optional digits 3, 4, and 5 */
+                                  {
+                                        n3 = n3*10 + (*s++ - '0');
+                                        if (*s < '0' || *s > '9')
+                                          break;
+                                        n3 = n3*10 + (*s++ - '0');
+                                        if (*s >= '0' && *s <= '9')
+                                          n3 = n3*10 + (*s++ - '0');
+                                  }
+
+                                if (*s == 'T' && s[1] >= '0' && s[1] <= '9')
+                                  /* followed by ISO 8601 T delimiter and number is ok */
+                                  ;
+                                else if ((*s >= '0' && *s <= '9') ||
+                                         (*s >= 'A' && *s <= 'Z') ||
+                                         (*s >= 'a' && *s <= 'z'))
+                                  /* but other alphanumerics are not ok */
+                                  break;
+
+                                /* Ok, we parsed three multi-digit numbers, with / or -
+                                   between them.  Now decide what the hell they are
+                                   (DD/MM/YY or MM/DD/YY or [YY]YY/MM/DD.)
+                                 */
+
+                                if (n1 > 31 || n1 == 0)  /* must be [YY]YY/MM/DD */
+                                  {
+                                        if (n2 > 12) break;
+                                        if (n3 > 31) break;
+                                        year = n1;
+                                        if (year < 70)
+                                            year += 2000;
+                                        else if (year < 100)
+                                            year += 1900;
+                                        month = (TIME_TOKEN)(n2 + ((int)TT_JAN) - 1);
+                                        date = n3;
+                                        rest = s;
+                                        break;
+                                  }
+
+                                if (n1 > 12 && n2 > 12)  /* illegal */
+                                  {
+                                        rest = s;
+                                        break;
+                                  }
+
+                                if (n3 < 70)
+                                    n3 += 2000;
+                                else if (n3 < 100)
+                                    n3 += 1900;
+
+                                if (n1 > 12)  /* must be DD/MM/YY */
+                                  {
+                                        date = n1;
+                                        month = (TIME_TOKEN)(n2 + ((int)TT_JAN) - 1);
+                                        year = n3;
+                                  }
+                                else                  /* assume MM/DD/YY */
+                                  {
+                                        /* #### In the ambiguous case, should we consult the
+                                           locale to find out the local default? */
+                                        month = (TIME_TOKEN)(n1 + ((int)TT_JAN) - 1);
+                                        date = n2;
+                                        year = n3;
+                                  }
+                                rest = s;
+                          }
+                        else if ((*end >= 'A' && *end <= 'Z') ||
+                                         (*end >= 'a' && *end <= 'z'))
+                          /* Digits followed by non-punctuation - what's that? */
+                          ;
+                        else if ((end - rest) == 5)                /* five digits is a year */
+                          year = (year < 0
+                                          ? ((rest[0]-'0')*10000L +
+                                                 (rest[1]-'0')*1000L +
+                                                 (rest[2]-'0')*100L +
+                                                 (rest[3]-'0')*10L +
+                                                 (rest[4]-'0'))
+                                          : year);
+                        else if ((end - rest) == 4)                /* four digits is a year */
+                          year = (year < 0
+                                          ? ((rest[0]-'0')*1000L +
+                                                 (rest[1]-'0')*100L +
+                                                 (rest[2]-'0')*10L +
+                                                 (rest[3]-'0'))
+                                          : year);
+                        else if ((end - rest) == 2)                /* two digits - date or year */
+                          {
+                                int n = ((rest[0]-'0')*10 +
+                                                 (rest[1]-'0'));
+                                /* If we don't have a date (day of the month) and we see a number
+                                     less than 32, then assume that is the date.
+
+                                         Otherwise, if we have a date and not a year, assume this is the
+                                         year.  If it is less than 70, then assume it refers to the 21st
+                                         century.  If it is two digits (>= 70), assume it refers to this
+                                         century.  Otherwise, assume it refers to an unambiguous year.
+
+                                         The world will surely end soon.
+                                   */
+                                if (date < 0 && n < 32)
+                                  date = n;
+                                else if (year < 0)
+                                  {
+                                        if (n < 70)
+                                          year = 2000 + n;
+                                        else if (n < 100)
+                                          year = 1900 + n;
+                                        else
+                                          year = n;
+                                  }
+                                /* else what the hell is this. */
+                          }
+                        else if ((end - rest) == 1)                /* one digit - date */
+                          date = (date < 0 ? (rest[0]-'0') : date);
+                        /* else, three or more than five digits - what's that? */
+
+                        break;
+                  }   /* case '0' .. '9' */
+                }   /* switch */
+
+          /* Skip to the end of this token, whether we parsed it or not.
+             Tokens are delimited by whitespace, or ,;-+/()[] but explicitly not .:
+             'T' is also treated as delimiter when followed by a digit (ISO 8601).
+           */
+          while (*rest &&
+                         *rest != ' ' && *rest != '\t' &&
+                         *rest != ',' && *rest != ';' &&
+                         *rest != '-' && *rest != '+' &&
+                         *rest != '/' &&
+                         *rest != '(' && *rest != ')' && *rest != '[' && *rest != ']' &&
+                         !(*rest == 'T' && rest[1] >= '0' && rest[1] <= '9')
+                )
+                rest++;
+          /* skip over uninteresting chars. */
+        SKIP_MORE:
+          while (*rest == ' ' || *rest == '\t' ||
+                 *rest == ',' || *rest == ';' || *rest == '/' ||
+                 *rest == '(' || *rest == ')' || *rest == '[' || *rest == ']')
+                rest++;
+
+          /* "-" is ignored at the beginning of a token if we have not yet
+                 parsed a year (e.g., the second "-" in "30-AUG-1966"), or if
+                 the character after the dash is not a digit. */         
+          if (*rest == '-' && ((rest > string &&
+              isalpha((unsigned char)rest[-1]) && year < 0) ||
+              rest[1] < '0' || rest[1] > '9'))
+                {
+                  rest++;
+                  goto SKIP_MORE;
+                }
+
+          /* Skip T that may precede ISO 8601 time. */
+          if (*rest == 'T' && rest[1] >= '0' && rest[1] <= '9')
+            rest++;
+        }   /* while */
+
+  if (zone != TT_UNKNOWN && zone_offset == -1)
+        {
+          switch (zone)
+                {
+                case TT_PST: zone_offset = -8 * 60; break;
+                case TT_PDT: zone_offset = -8 * 60; dst_offset = 1 * 60; break;
+                case TT_MST: zone_offset = -7 * 60; break;
+                case TT_MDT: zone_offset = -7 * 60; dst_offset = 1 * 60; break;
+                case TT_CST: zone_offset = -6 * 60; break;
+                case TT_CDT: zone_offset = -6 * 60; dst_offset = 1 * 60; break;
+                case TT_EST: zone_offset = -5 * 60; break;
+                case TT_EDT: zone_offset = -5 * 60; dst_offset = 1 * 60; break;
+                case TT_AST: zone_offset = -4 * 60; break;
+                case TT_NST: zone_offset = -3 * 60 - 30; break;
+                case TT_GMT: zone_offset =  0 * 60; break;
+                case TT_BST: zone_offset =  0 * 60; dst_offset = 1 * 60; break;
+                case TT_MET: zone_offset =  1 * 60; break;
+                case TT_EET: zone_offset =  2 * 60; break;
+                case TT_JST: zone_offset =  9 * 60; break;
+                default:
+                  PR_ASSERT (0);
+                  break;
+                }
+        }
+
+  /* If we didn't find a year, month, or day-of-the-month, we can't
+         possibly parse this, and in fact, mktime() will do something random
+         (I'm seeing it return "Tue Feb  5 06:28:16 2036", which is no doubt
+         a numerologically significant date... */
+  if (month == TT_UNKNOWN || date == -1 || year == -1 || year > PR_INT16_MAX)
+      return PR_FAILURE;
+
+  memset(result, 0, sizeof(*result));
+  if (usec != -1)
+        result->tm_usec = usec;
+  if (sec != -1)
+        result->tm_sec = sec;
+  if (min != -1)
+        result->tm_min = min;
+  if (hour != -1)
+        result->tm_hour = hour;
+  if (date != -1)
+        result->tm_mday = date;
+  if (month != TT_UNKNOWN)
+        result->tm_month = (((int)month) - ((int)TT_JAN));
+  if (year != -1)
+        result->tm_year = static_cast<PRInt16>(year);
+  if (dotw != TT_UNKNOWN)
+        result->tm_wday = static_cast<PRInt8>(((int)dotw) - ((int)TT_SUN));
+  /*
+   * Mainly to compute wday and yday, but normalized time is also required
+   * by the check below that works around a Visual C++ 2005 mktime problem.
+   */
+  PR_NormalizeTime(result, PR_GMTParameters);
+  /* The remaining work is to set the gmt and dst offsets in tm_params. */
+
+  if (zone == TT_UNKNOWN && default_to_gmt)
+        {
+          /* No zone was specified, so pretend the zone was GMT. */
+          zone = TT_GMT;
+          zone_offset = 0;
+        }
+
+  if (zone_offset == -1)
+         {
+           /* no zone was specified, and we're to assume that everything
+             is local. */
+          struct tm localTime;
+          time_t secs;
+
+          PR_ASSERT(result->tm_month > -1 &&
+                    result->tm_mday > 0 &&
+                    result->tm_hour > -1 &&
+                    result->tm_min > -1 &&
+                    result->tm_sec > -1);
+
+            /*
+             * To obtain time_t from a tm structure representing the local
+             * time, we call mktime().  However, we need to see if we are
+             * on 1-Jan-1970 or before.  If we are, we can't call mktime()
+             * because mktime() will crash on win16. In that case, we
+             * calculate zone_offset based on the zone offset at
+             * 00:00:00, 2 Jan 1970 GMT, and subtract zone_offset from the
+             * date we are parsing to transform the date to GMT.  We also
+             * do so if mktime() returns (time_t) -1 (time out of range).
+           */
+
+          /* month, day, hours, mins and secs are always non-negative
+             so we dont need to worry about them. */
+          if (result->tm_year >= 1970)
+                {
+                  localTime.tm_sec = result->tm_sec;
+                  localTime.tm_min = result->tm_min;
+                  localTime.tm_hour = result->tm_hour;
+                  localTime.tm_mday = result->tm_mday;
+                  localTime.tm_mon = result->tm_month;
+                  localTime.tm_year = result->tm_year - 1900;
+                  /* Set this to -1 to tell mktime "I don't care".  If you set
+                     it to 0 or 1, you are making assertions about whether the
+                     date you are handing it is in daylight savings mode or not;
+                     and if you're wrong, it will "fix" it for you. */
+                  localTime.tm_isdst = -1;
+
+#if _MSC_VER == 1400  /* 1400 = Visual C++ 2005 (8.0) */
+                  /*
+                   * mktime will return (time_t) -1 if the input is a date
+                   * after 23:59:59, December 31, 3000, US Pacific Time (not
+                   * UTC as documented): 
+                   * http://msdn.microsoft.com/en-us/library/d1y53h2a(VS.80).aspx
+                   * But if the year is 3001, mktime also invokes the invalid
+                   * parameter handler, causing the application to crash.  This
+                   * problem has been reported in
+                   * http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=266036.
+                   * We avoid this crash by not calling mktime if the date is
+                   * out of range.  To use a simple test that works in any time
+                   * zone, we consider year 3000 out of range as well.  (See
+                   * bug 480740.)
+                   */
+                  if (result->tm_year >= 3000) {
+                      /* Emulate what mktime would have done. */
+                      errno = EINVAL;
+                      secs = (time_t) -1;
+                  } else {
+                      secs = mktime(&localTime);
+                  }
+#else
+                  secs = mktime(&localTime);
+#endif
+                  if (secs != (time_t) -1)
+                    {
+                      *result_imploded = (PRInt64)secs * PR_USEC_PER_SEC;
+                      *result_imploded += result->tm_usec;
+                      return PR_SUCCESS;
+                    }
+                }
+                
+                /* So mktime() can't handle this case.  We assume the
+                   zone_offset for the date we are parsing is the same as
+                   the zone offset on 00:00:00 2 Jan 1970 GMT. */
+                secs = 86400;
+                localtime_r(&secs, &localTime);
+                zone_offset = localTime.tm_min
+                              + 60 * localTime.tm_hour
+                              + 1440 * (localTime.tm_mday - 2);
+        }
+
+  result->tm_params.tp_gmt_offset = zone_offset * 60;
+  result->tm_params.tp_dst_offset = dst_offset * 60;
+
+  *result_imploded = PR_ImplodeTime(result);
+  return PR_SUCCESS;
+}
diff --git a/base/third_party/nspr/prtime.h b/base/third_party/nspr/prtime.h
new file mode 100644
index 0000000..01a4e54
--- /dev/null
+++ b/base/third_party/nspr/prtime.h
@@ -0,0 +1,252 @@
+/* Portions are Copyright (C) 2011 Google Inc */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape Portable Runtime (NSPR).
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * prtime.h --
+ *
+ *     NSPR date and time functions
+ * CVS revision 3.10
+ * This file contains definitions of NSPR's basic types required by
+ * prtime.cc. These types have been copied over from the following NSPR
+ * files prtime.h, prtypes.h(CVS revision 3.35), prlong.h(CVS revision 3.13)
+ *
+ *---------------------------------------------------------------------------
+ */
+
+#ifndef BASE_PRTIME_H__
+#define BASE_PRTIME_H__
+
+#include <stdint.h>
+
+#include "base/base_export.h"
+
+typedef int8_t PRInt8;
+typedef int16_t PRInt16;
+typedef int32_t PRInt32;
+typedef int64_t PRInt64;
+typedef int PRIntn;
+
+typedef PRIntn PRBool;
+#define PR_TRUE 1
+#define PR_FALSE 0
+
+typedef enum { PR_FAILURE = -1, PR_SUCCESS = 0 } PRStatus;
+
+#define PR_ASSERT DCHECK
+#define PR_CALLBACK
+#define PR_INT16_MAX 32767
+#define NSPR_API(__type) extern __type
+
+/**********************************************************************/
+/************************* TYPES AND CONSTANTS ************************/
+/**********************************************************************/
+
+#define PR_MSEC_PER_SEC		1000UL
+#define PR_USEC_PER_SEC		1000000UL
+#define PR_NSEC_PER_SEC		1000000000UL
+#define PR_USEC_PER_MSEC	1000UL
+#define PR_NSEC_PER_MSEC	1000000UL
+
+/*
+ * PRTime --
+ *
+ *     NSPR represents basic time as 64-bit signed integers relative
+ *     to midnight (00:00:00), January 1, 1970 Greenwich Mean Time (GMT).
+ *     (GMT is also known as Coordinated Universal Time, UTC.)
+ *     The units of time are in microseconds. Negative times are allowed
+ *     to represent times prior to the January 1970 epoch. Such values are
+ *     intended to be exported to other systems or converted to human
+ *     readable form.
+ *
+ *     Notes on porting: PRTime corresponds to time_t in ANSI C.  NSPR 1.0
+ *     simply uses PRInt64.
+ */
+
+typedef PRInt64 PRTime;
+
+/*
+ * Time zone and daylight saving time corrections applied to GMT to
+ * obtain the local time of some geographic location
+ */
+
+typedef struct PRTimeParameters {
+    PRInt32 tp_gmt_offset;     /* the offset from GMT in seconds */
+    PRInt32 tp_dst_offset;     /* contribution of DST in seconds */
+} PRTimeParameters;
+
+/*
+ * PRExplodedTime --
+ *
+ *     Time broken down into human-readable components such as year, month,
+ *     day, hour, minute, second, and microsecond.  Time zone and daylight
+ *     saving time corrections may be applied.  If they are applied, the
+ *     offsets from the GMT must be saved in the 'tm_params' field so that
+ *     all the information is available to reconstruct GMT.
+ *
+ *     Notes on porting: PRExplodedTime corrresponds to struct tm in
+ *     ANSI C, with the following differences:
+ *       - an additional field tm_usec;
+ *       - replacing tm_isdst by tm_params;
+ *       - the month field is spelled tm_month, not tm_mon;
+ *       - we use absolute year, AD, not the year since 1900.
+ *     The corresponding type in NSPR 1.0 is called PRTime.  Below is
+ *     a table of date/time type correspondence in the three APIs:
+ *         API          time since epoch          time in components
+ *       ANSI C             time_t                  struct tm
+ *       NSPR 1.0           PRInt64                   PRTime
+ *       NSPR 2.0           PRTime                  PRExplodedTime
+ */
+
+typedef struct PRExplodedTime {
+    PRInt32 tm_usec;		    /* microseconds past tm_sec (0-99999)  */
+    PRInt32 tm_sec;             /* seconds past tm_min (0-61, accomodating
+                                   up to two leap seconds) */	
+    PRInt32 tm_min;             /* minutes past tm_hour (0-59) */
+    PRInt32 tm_hour;            /* hours past tm_day (0-23) */
+    PRInt32 tm_mday;            /* days past tm_mon (1-31, note that it
+				                starts from 1) */
+    PRInt32 tm_month;           /* months past tm_year (0-11, Jan = 0) */
+    PRInt16 tm_year;            /* absolute year, AD (note that we do not
+				                count from 1900) */
+
+    PRInt8 tm_wday;		        /* calculated day of the week
+				                (0-6, Sun = 0) */
+    PRInt16 tm_yday;            /* calculated day of the year
+				                (0-365, Jan 1 = 0) */
+
+    PRTimeParameters tm_params;  /* time parameters used by conversion */
+} PRExplodedTime;
+
+/*
+ * PRTimeParamFn --
+ *
+ *     A function of PRTimeParamFn type returns the time zone and
+ *     daylight saving time corrections for some geographic location,
+ *     given the current time in GMT.  The input argument gmt should
+ *     point to a PRExplodedTime that is in GMT, i.e., whose
+ *     tm_params contains all 0's.
+ *
+ *     For any time zone other than GMT, the computation is intended to
+ *     consist of two steps:
+ *       - Figure out the time zone correction, tp_gmt_offset.  This number
+ *         usually depends on the geographic location only.  But it may
+ *         also depend on the current time.  For example, all of China
+ *         is one time zone right now.  But this situation may change
+ *         in the future.
+ *       - Figure out the daylight saving time correction, tp_dst_offset.
+ *         This number depends on both the geographic location and the
+ *         current time.  Most of the DST rules are expressed in local
+ *         current time.  If so, one should apply the time zone correction
+ *         to GMT before applying the DST rules.
+ */
+
+typedef PRTimeParameters (PR_CALLBACK *PRTimeParamFn)(const PRExplodedTime *gmt);
+
+/**********************************************************************/
+/****************************** FUNCTIONS *****************************/
+/**********************************************************************/
+
+NSPR_API(PRTime)
+PR_ImplodeTime(const PRExplodedTime *exploded);
+
+/*
+ * Adjust exploded time to normalize field overflows after manipulation.
+ * Note that the following fields of PRExplodedTime should not be
+ * manipulated:
+ *   - tm_month and tm_year: because the number of days in a month and
+ *     number of days in a year are not constant, it is ambiguous to
+ *     manipulate the month and year fields, although one may be tempted
+ *     to.  For example, what does "a month from January 31st" mean?
+ *   - tm_wday and tm_yday: these fields are calculated by NSPR.  Users
+ *     should treat them as "read-only".
+ */
+
+NSPR_API(void) PR_NormalizeTime(
+    PRExplodedTime *exploded, PRTimeParamFn params);
+
+/**********************************************************************/
+/*********************** TIME PARAMETER FUNCTIONS *********************/
+/**********************************************************************/
+
+/* Time parameters that represent Greenwich Mean Time */
+NSPR_API(PRTimeParameters) PR_GMTParameters(const PRExplodedTime *gmt);
+
+/*
+ * This parses a time/date string into a PRTime
+ * (microseconds after "1-Jan-1970 00:00:00 GMT").
+ * It returns PR_SUCCESS on success, and PR_FAILURE
+ * if the time/date string can't be parsed.
+ *
+ * Many formats are handled, including:
+ *
+ *   14 Apr 89 03:20:12
+ *   14 Apr 89 03:20 GMT
+ *   Fri, 17 Mar 89 4:01:33
+ *   Fri, 17 Mar 89 4:01 GMT
+ *   Mon Jan 16 16:12 PDT 1989
+ *   Mon Jan 16 16:12 +0130 1989
+ *   6 May 1992 16:41-JST (Wednesday)
+ *   22-AUG-1993 10:59:12.82
+ *   22-AUG-1993 10:59pm
+ *   22-AUG-1993 12:59am
+ *   22-AUG-1993 12:59 PM
+ *   Friday, August 04, 1995 3:54 PM
+ *   06/21/95 04:24:34 PM
+ *   20/06/95 21:07
+ *   95-06-08 19:32:48 EDT
+ *   1995-06-17T23:11:25.342156Z
+ *
+ * If the input string doesn't contain a description of the timezone,
+ * we consult the `default_to_gmt' to decide whether the string should
+ * be interpreted relative to the local time zone (PR_FALSE) or GMT (PR_TRUE).
+ * The correct value for this argument depends on what standard specified
+ * the time string which you are parsing.
+ */
+
+/*
+ * This is the only funtion that should be called from outside base, and only
+ * from the unit test.
+ */
+
+BASE_EXPORT PRStatus PR_ParseTimeString (
+	const char *string,
+	PRBool default_to_gmt,
+	PRTime *result);
+
+#endif  // BASE_PRTIME_H__
diff --git a/base/third_party/superfasthash/LICENSE b/base/third_party/superfasthash/LICENSE
new file mode 100644
index 0000000..3c40a3e
--- /dev/null
+++ b/base/third_party/superfasthash/LICENSE
@@ -0,0 +1,27 @@
+Paul Hsieh OLD BSD license
+
+Copyright (c) 2010, Paul Hsieh
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright notice, this
+  list of conditions and the following disclaimer in the documentation and/or
+  other materials provided with the distribution.
+* Neither my name, Paul Hsieh, nor the names of any other contributors to the
+  code use may not be used to endorse or promote products derived from this
+  software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/base/third_party/superfasthash/OWNERS b/base/third_party/superfasthash/OWNERS
new file mode 100644
index 0000000..f34cfb1
--- /dev/null
+++ b/base/third_party/superfasthash/OWNERS
@@ -0,0 +1,2 @@
+mgiuca@chromium.org
+rvargas@chromium.org
diff --git a/base/third_party/superfasthash/README.chromium b/base/third_party/superfasthash/README.chromium
new file mode 100644
index 0000000..d41ed77
--- /dev/null
+++ b/base/third_party/superfasthash/README.chromium
@@ -0,0 +1,29 @@
+Name: Paul Hsieh's SuperFastHash
+Short Name: SuperFastHash
+URL: http://www.azillionmonkeys.com/qed/hash.html
+Version: 0
+Date: 2012-02-21
+License: BSD
+License File: LICENSE
+Security Critical: yes
+
+Description:
+A fast string hashing algorithm.
+
+Local Modifications:
+- Added LICENSE.
+- Added license text as a comment to the top of superfasthash.c.
+- #include <stdint.h> instead of "pstdint.h".
+- #include <stdlib.h>.
+
+The license is a standard 3-clause BSD license with the following minor changes:
+
+"nor the names of its contributors may be used"
+is replaced with:
+"nor the names of any other contributors to the code use may not be used"
+
+and
+
+"IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE"
+is replaced with:
+"IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE"
diff --git a/base/third_party/superfasthash/superfasthash.c b/base/third_party/superfasthash/superfasthash.c
new file mode 100644
index 0000000..6e7687e
--- /dev/null
+++ b/base/third_party/superfasthash/superfasthash.c
@@ -0,0 +1,84 @@
+// Copyright (c) 2010, Paul Hsieh
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice, this
+//   list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+// * Neither my name, Paul Hsieh, nor the names of any other contributors to the
+//   code use may not be used to endorse or promote products derived from this
+//   software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+
+#include <stdint.h>
+#include <stdlib.h>
+#undef get16bits
+#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
+  || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
+#define get16bits(d) (*((const uint16_t *) (d)))
+#endif
+
+#if !defined (get16bits)
+#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\
+                       +(uint32_t)(((const uint8_t *)(d))[0]) )
+#endif
+
+uint32_t SuperFastHash (const char * data, int len) {
+uint32_t hash = len, tmp;
+int rem;
+
+    if (len <= 0 || data == NULL) return 0;
+
+    rem = len & 3;
+    len >>= 2;
+
+    /* Main loop */
+    for (;len > 0; len--) {
+        hash  += get16bits (data);
+        tmp    = (get16bits (data+2) << 11) ^ hash;
+        hash   = (hash << 16) ^ tmp;
+        data  += 2*sizeof (uint16_t);
+        hash  += hash >> 11;
+    }
+
+    /* Handle end cases */
+    switch (rem) {
+        case 3: hash += get16bits (data);
+                hash ^= hash << 16;
+                hash ^= ((signed char)data[sizeof (uint16_t)]) << 18;
+                hash += hash >> 11;
+                break;
+        case 2: hash += get16bits (data);
+                hash ^= hash << 11;
+                hash += hash >> 17;
+                break;
+        case 1: hash += (signed char)*data;
+                hash ^= hash << 10;
+                hash += hash >> 1;
+    }
+
+    /* Force "avalanching" of final 127 bits */
+    hash ^= hash << 3;
+    hash += hash >> 5;
+    hash ^= hash << 4;
+    hash += hash >> 17;
+    hash ^= hash << 25;
+    hash += hash >> 6;
+
+    return hash;
+}
diff --git a/base/third_party/symbolize/BUILD.gn b/base/third_party/symbolize/BUILD.gn
new file mode 100644
index 0000000..ddcb789
--- /dev/null
+++ b/base/third_party/symbolize/BUILD.gn
@@ -0,0 +1,20 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("symbolize") {
+  visibility = [ "//base/*" ]
+  sources = [
+    "config.h",
+    "demangle.cc",
+    "demangle.h",
+    "glog/logging.h",
+    "glog/raw_logging.h",
+    "symbolize.cc",
+    "symbolize.h",
+    "utilities.h",
+  ]
+
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [ "//build/config/compiler:no_chromium_code" ]
+}
diff --git a/base/third_party/symbolize/DEPS b/base/third_party/symbolize/DEPS
new file mode 100644
index 0000000..73eab50
--- /dev/null
+++ b/base/third_party/symbolize/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+glog",
+]
diff --git a/base/third_party/symbolize/LICENSE b/base/third_party/symbolize/LICENSE
new file mode 100644
index 0000000..433a3d1
--- /dev/null
+++ b/base/third_party/symbolize/LICENSE
@@ -0,0 +1,28 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/base/third_party/symbolize/README.chromium b/base/third_party/symbolize/README.chromium
new file mode 100644
index 0000000..de92794
--- /dev/null
+++ b/base/third_party/symbolize/README.chromium
@@ -0,0 +1,18 @@
+Name: google-glog's symbolization library
+URL: http://code.google.com/p/google-glog/
+License: BSD
+
+The following files are copied AS-IS from:
+http://code.google.com/p/google-glog/source/browse/#svn/trunk/src (r141)
+
+- demangle.cc
+- demangle.h
+- symbolize.cc
+- symbolize.h
+
+The following files are minimal stubs created for use in Chromium:
+
+- config.h
+- glog/logging.h
+- glog/raw_logging.h
+- utilities.h
diff --git a/base/third_party/symbolize/config.h b/base/third_party/symbolize/config.h
new file mode 100644
index 0000000..945f5a6
--- /dev/null
+++ b/base/third_party/symbolize/config.h
@@ -0,0 +1,7 @@
+// Copyright (c) 2010 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.
+
+#define GOOGLE_NAMESPACE google
+#define _END_GOOGLE_NAMESPACE_ }
+#define _START_GOOGLE_NAMESPACE_ namespace google {
diff --git a/base/third_party/symbolize/demangle.cc b/base/third_party/symbolize/demangle.cc
new file mode 100644
index 0000000..e858181
--- /dev/null
+++ b/base/third_party/symbolize/demangle.cc
@@ -0,0 +1,1304 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: Satoru Takabayashi
+//
+// For reference check out:
+// http://www.codesourcery.com/public/cxx-abi/abi.html#mangling
+//
+// Note that we only have partial C++0x support yet.
+
+#include <stdio.h>  // for NULL
+#include "demangle.h"
+
+_START_GOOGLE_NAMESPACE_
+
+typedef struct {
+  const char *abbrev;
+  const char *real_name;
+} AbbrevPair;
+
+// List of operators from Itanium C++ ABI.
+static const AbbrevPair kOperatorList[] = {
+  { "nw", "new" },
+  { "na", "new[]" },
+  { "dl", "delete" },
+  { "da", "delete[]" },
+  { "ps", "+" },
+  { "ng", "-" },
+  { "ad", "&" },
+  { "de", "*" },
+  { "co", "~" },
+  { "pl", "+" },
+  { "mi", "-" },
+  { "ml", "*" },
+  { "dv", "/" },
+  { "rm", "%" },
+  { "an", "&" },
+  { "or", "|" },
+  { "eo", "^" },
+  { "aS", "=" },
+  { "pL", "+=" },
+  { "mI", "-=" },
+  { "mL", "*=" },
+  { "dV", "/=" },
+  { "rM", "%=" },
+  { "aN", "&=" },
+  { "oR", "|=" },
+  { "eO", "^=" },
+  { "ls", "<<" },
+  { "rs", ">>" },
+  { "lS", "<<=" },
+  { "rS", ">>=" },
+  { "eq", "==" },
+  { "ne", "!=" },
+  { "lt", "<" },
+  { "gt", ">" },
+  { "le", "<=" },
+  { "ge", ">=" },
+  { "nt", "!" },
+  { "aa", "&&" },
+  { "oo", "||" },
+  { "pp", "++" },
+  { "mm", "--" },
+  { "cm", "," },
+  { "pm", "->*" },
+  { "pt", "->" },
+  { "cl", "()" },
+  { "ix", "[]" },
+  { "qu", "?" },
+  { "st", "sizeof" },
+  { "sz", "sizeof" },
+  { NULL, NULL },
+};
+
+// List of builtin types from Itanium C++ ABI.
+static const AbbrevPair kBuiltinTypeList[] = {
+  { "v", "void" },
+  { "w", "wchar_t" },
+  { "b", "bool" },
+  { "c", "char" },
+  { "a", "signed char" },
+  { "h", "unsigned char" },
+  { "s", "short" },
+  { "t", "unsigned short" },
+  { "i", "int" },
+  { "j", "unsigned int" },
+  { "l", "long" },
+  { "m", "unsigned long" },
+  { "x", "long long" },
+  { "y", "unsigned long long" },
+  { "n", "__int128" },
+  { "o", "unsigned __int128" },
+  { "f", "float" },
+  { "d", "double" },
+  { "e", "long double" },
+  { "g", "__float128" },
+  { "z", "ellipsis" },
+  { NULL, NULL }
+};
+
+// List of substitutions Itanium C++ ABI.
+static const AbbrevPair kSubstitutionList[] = {
+  { "St", "" },
+  { "Sa", "allocator" },
+  { "Sb", "basic_string" },
+  // std::basic_string<char, std::char_traits<char>,std::allocator<char> >
+  { "Ss", "string"},
+  // std::basic_istream<char, std::char_traits<char> >
+  { "Si", "istream" },
+  // std::basic_ostream<char, std::char_traits<char> >
+  { "So", "ostream" },
+  // std::basic_iostream<char, std::char_traits<char> >
+  { "Sd", "iostream" },
+  { NULL, NULL }
+};
+
+// State needed for demangling.
+typedef struct {
+  const char *mangled_cur;  // Cursor of mangled name.
+  char *out_cur;            // Cursor of output string.
+  const char *out_begin;    // Beginning of output string.
+  const char *out_end;      // End of output string.
+  const char *prev_name;    // For constructors/destructors.
+  int prev_name_length;     // For constructors/destructors.
+  short nest_level;         // For nested names.
+  bool append;              // Append flag.
+  bool overflowed;          // True if output gets overflowed.
+} State;
+
+// We don't use strlen() in libc since it's not guaranteed to be async
+// signal safe.
+static size_t StrLen(const char *str) {
+  size_t len = 0;
+  while (*str != '\0') {
+    ++str;
+    ++len;
+  }
+  return len;
+}
+
+// Returns true if "str" has at least "n" characters remaining.
+static bool AtLeastNumCharsRemaining(const char *str, int n) {
+  for (int i = 0; i < n; ++i) {
+    if (str[i] == '\0') {
+      return false;
+    }
+  }
+  return true;
+}
+
+// Returns true if "str" has "prefix" as a prefix.
+static bool StrPrefix(const char *str, const char *prefix) {
+  size_t i = 0;
+  while (str[i] != '\0' && prefix[i] != '\0' &&
+         str[i] == prefix[i]) {
+    ++i;
+  }
+  return prefix[i] == '\0';  // Consumed everything in "prefix".
+}
+
+static void InitState(State *state, const char *mangled,
+                      char *out, int out_size) {
+  state->mangled_cur = mangled;
+  state->out_cur = out;
+  state->out_begin = out;
+  state->out_end = out + out_size;
+  state->prev_name  = NULL;
+  state->prev_name_length = -1;
+  state->nest_level = -1;
+  state->append = true;
+  state->overflowed = false;
+}
+
+// Returns true and advances "mangled_cur" if we find "one_char_token"
+// at "mangled_cur" position.  It is assumed that "one_char_token" does
+// not contain '\0'.
+static bool ParseOneCharToken(State *state, const char one_char_token) {
+  if (state->mangled_cur[0] == one_char_token) {
+    ++state->mangled_cur;
+    return true;
+  }
+  return false;
+}
+
+// Returns true and advances "mangled_cur" if we find "two_char_token"
+// at "mangled_cur" position.  It is assumed that "two_char_token" does
+// not contain '\0'.
+static bool ParseTwoCharToken(State *state, const char *two_char_token) {
+  if (state->mangled_cur[0] == two_char_token[0] &&
+      state->mangled_cur[1] == two_char_token[1]) {
+    state->mangled_cur += 2;
+    return true;
+  }
+  return false;
+}
+
+// Returns true and advances "mangled_cur" if we find any character in
+// "char_class" at "mangled_cur" position.
+static bool ParseCharClass(State *state, const char *char_class) {
+  const char *p = char_class;
+  for (; *p != '\0'; ++p) {
+    if (state->mangled_cur[0] == *p) {
+      ++state->mangled_cur;
+      return true;
+    }
+  }
+  return false;
+}
+
+// This function is used for handling an optional non-terminal.
+static bool Optional(bool) {
+  return true;
+}
+
+// This function is used for handling <non-terminal>+ syntax.
+typedef bool (*ParseFunc)(State *);
+static bool OneOrMore(ParseFunc parse_func, State *state) {
+  if (parse_func(state)) {
+    while (parse_func(state)) {
+    }
+    return true;
+  }
+  return false;
+}
+
+// This function is used for handling <non-terminal>* syntax. The function
+// always returns true and must be followed by a termination token or a
+// terminating sequence not handled by parse_func (e.g.
+// ParseOneCharToken(state, 'E')).
+static bool ZeroOrMore(ParseFunc parse_func, State *state) {
+  while (parse_func(state)) {
+  }
+  return true;
+}
+
+// Append "str" at "out_cur".  If there is an overflow, "overflowed"
+// is set to true for later use.  The output string is ensured to
+// always terminate with '\0' as long as there is no overflow.
+static void Append(State *state, const char * const str, const int length) {
+  int i;
+  for (i = 0; i < length; ++i) {
+    if (state->out_cur + 1 < state->out_end) {  // +1 for '\0'
+      *state->out_cur = str[i];
+      ++state->out_cur;
+    } else {
+      state->overflowed = true;
+      break;
+    }
+  }
+  if (!state->overflowed) {
+    *state->out_cur = '\0';  // Terminate it with '\0'
+  }
+}
+
+// We don't use equivalents in libc to avoid locale issues.
+static bool IsLower(char c) {
+  return c >= 'a' && c <= 'z';
+}
+
+static bool IsAlpha(char c) {
+  return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
+}
+
+static bool IsDigit(char c) {
+  return c >= '0' && c <= '9';
+}
+
+// Returns true if "str" is a function clone suffix.  These suffixes are used
+// by GCC 4.5.x and later versions to indicate functions which have been
+// cloned during optimization.  We treat any sequence (.<alpha>+.<digit>+)+ as
+// a function clone suffix.
+static bool IsFunctionCloneSuffix(const char *str) {
+  size_t i = 0;
+  while (str[i] != '\0') {
+    // Consume a single .<alpha>+.<digit>+ sequence.
+    if (str[i] != '.' || !IsAlpha(str[i + 1])) {
+      return false;
+    }
+    i += 2;
+    while (IsAlpha(str[i])) {
+      ++i;
+    }
+    if (str[i] != '.' || !IsDigit(str[i + 1])) {
+      return false;
+    }
+    i += 2;
+    while (IsDigit(str[i])) {
+      ++i;
+    }
+  }
+  return true;  // Consumed everything in "str".
+}
+
+// Append "str" with some tweaks, iff "append" state is true.
+// Returns true so that it can be placed in "if" conditions.
+static void MaybeAppendWithLength(State *state, const char * const str,
+                                  const int length) {
+  if (state->append && length > 0) {
+    // Append a space if the output buffer ends with '<' and "str"
+    // starts with '<' to avoid <<<.
+    if (str[0] == '<' && state->out_begin < state->out_cur  &&
+        state->out_cur[-1] == '<') {
+      Append(state, " ", 1);
+    }
+    // Remember the last identifier name for ctors/dtors.
+    if (IsAlpha(str[0]) || str[0] == '_') {
+      state->prev_name = state->out_cur;
+      state->prev_name_length = length;
+    }
+    Append(state, str, length);
+  }
+}
+
+// A convenient wrapper arount MaybeAppendWithLength().
+static bool MaybeAppend(State *state, const char * const str) {
+  if (state->append) {
+    int length = StrLen(str);
+    MaybeAppendWithLength(state, str, length);
+  }
+  return true;
+}
+
+// This function is used for handling nested names.
+static bool EnterNestedName(State *state) {
+  state->nest_level = 0;
+  return true;
+}
+
+// This function is used for handling nested names.
+static bool LeaveNestedName(State *state, short prev_value) {
+  state->nest_level = prev_value;
+  return true;
+}
+
+// Disable the append mode not to print function parameters, etc.
+static bool DisableAppend(State *state) {
+  state->append = false;
+  return true;
+}
+
+// Restore the append mode to the previous state.
+static bool RestoreAppend(State *state, bool prev_value) {
+  state->append = prev_value;
+  return true;
+}
+
+// Increase the nest level for nested names.
+static void MaybeIncreaseNestLevel(State *state) {
+  if (state->nest_level > -1) {
+    ++state->nest_level;
+  }
+}
+
+// Appends :: for nested names if necessary.
+static void MaybeAppendSeparator(State *state) {
+  if (state->nest_level >= 1) {
+    MaybeAppend(state, "::");
+  }
+}
+
+// Cancel the last separator if necessary.
+static void MaybeCancelLastSeparator(State *state) {
+  if (state->nest_level >= 1 && state->append &&
+      state->out_begin <= state->out_cur - 2) {
+    state->out_cur -= 2;
+    *state->out_cur = '\0';
+  }
+}
+
+// Returns true if the identifier of the given length pointed to by
+// "mangled_cur" is anonymous namespace.
+static bool IdentifierIsAnonymousNamespace(State *state, int length) {
+  static const char anon_prefix[] = "_GLOBAL__N_";
+  return (length > (int)sizeof(anon_prefix) - 1 &&  // Should be longer.
+          StrPrefix(state->mangled_cur, anon_prefix));
+}
+
+// Forward declarations of our parsing functions.
+static bool ParseMangledName(State *state);
+static bool ParseEncoding(State *state);
+static bool ParseName(State *state);
+static bool ParseUnscopedName(State *state);
+static bool ParseUnscopedTemplateName(State *state);
+static bool ParseNestedName(State *state);
+static bool ParsePrefix(State *state);
+static bool ParseUnqualifiedName(State *state);
+static bool ParseSourceName(State *state);
+static bool ParseLocalSourceName(State *state);
+static bool ParseNumber(State *state, int *number_out);
+static bool ParseFloatNumber(State *state);
+static bool ParseSeqId(State *state);
+static bool ParseIdentifier(State *state, int length);
+static bool ParseOperatorName(State *state);
+static bool ParseSpecialName(State *state);
+static bool ParseCallOffset(State *state);
+static bool ParseNVOffset(State *state);
+static bool ParseVOffset(State *state);
+static bool ParseCtorDtorName(State *state);
+static bool ParseType(State *state);
+static bool ParseCVQualifiers(State *state);
+static bool ParseBuiltinType(State *state);
+static bool ParseFunctionType(State *state);
+static bool ParseBareFunctionType(State *state);
+static bool ParseClassEnumType(State *state);
+static bool ParseArrayType(State *state);
+static bool ParsePointerToMemberType(State *state);
+static bool ParseTemplateParam(State *state);
+static bool ParseTemplateTemplateParam(State *state);
+static bool ParseTemplateArgs(State *state);
+static bool ParseTemplateArg(State *state);
+static bool ParseExpression(State *state);
+static bool ParseExprPrimary(State *state);
+static bool ParseLocalName(State *state);
+static bool ParseDiscriminator(State *state);
+static bool ParseSubstitution(State *state);
+
+// Implementation note: the following code is a straightforward
+// translation of the Itanium C++ ABI defined in BNF with a couple of
+// exceptions.
+//
+// - Support GNU extensions not defined in the Itanium C++ ABI
+// - <prefix> and <template-prefix> are combined to avoid infinite loop
+// - Reorder patterns to shorten the code
+// - Reorder patterns to give greedier functions precedence
+//   We'll mark "Less greedy than" for these cases in the code
+//
+// Each parsing function changes the state and returns true on
+// success.  Otherwise, don't change the state and returns false.  To
+// ensure that the state isn't changed in the latter case, we save the
+// original state before we call more than one parsing functions
+// consecutively with &&, and restore the state if unsuccessful.  See
+// ParseEncoding() as an example of this convention.  We follow the
+// convention throughout the code.
+//
+// Originally we tried to do demangling without following the full ABI
+// syntax but it turned out we needed to follow the full syntax to
+// parse complicated cases like nested template arguments.  Note that
+// implementing a full-fledged demangler isn't trivial (libiberty's
+// cp-demangle.c has +4300 lines).
+//
+// Note that (foo) in <(foo) ...> is a modifier to be ignored.
+//
+// Reference:
+// - Itanium C++ ABI
+//   <http://www.codesourcery.com/cxx-abi/abi.html#mangling>
+
+// <mangled-name> ::= _Z <encoding>
+static bool ParseMangledName(State *state) {
+  return ParseTwoCharToken(state, "_Z") && ParseEncoding(state);
+}
+
+// <encoding> ::= <(function) name> <bare-function-type>
+//            ::= <(data) name>
+//            ::= <special-name>
+static bool ParseEncoding(State *state) {
+  State copy = *state;
+  if (ParseName(state) && ParseBareFunctionType(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseName(state) || ParseSpecialName(state)) {
+    return true;
+  }
+  return false;
+}
+
+// <name> ::= <nested-name>
+//        ::= <unscoped-template-name> <template-args>
+//        ::= <unscoped-name>
+//        ::= <local-name>
+static bool ParseName(State *state) {
+  if (ParseNestedName(state) || ParseLocalName(state)) {
+    return true;
+  }
+
+  State copy = *state;
+  if (ParseUnscopedTemplateName(state) &&
+      ParseTemplateArgs(state)) {
+    return true;
+  }
+  *state = copy;
+
+  // Less greedy than <unscoped-template-name> <template-args>.
+  if (ParseUnscopedName(state)) {
+    return true;
+  }
+  return false;
+}
+
+// <unscoped-name> ::= <unqualified-name>
+//                 ::= St <unqualified-name>
+static bool ParseUnscopedName(State *state) {
+  if (ParseUnqualifiedName(state)) {
+    return true;
+  }
+
+  State copy = *state;
+  if (ParseTwoCharToken(state, "St") &&
+      MaybeAppend(state, "std::") &&
+      ParseUnqualifiedName(state)) {
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <unscoped-template-name> ::= <unscoped-name>
+//                          ::= <substitution>
+static bool ParseUnscopedTemplateName(State *state) {
+  return ParseUnscopedName(state) || ParseSubstitution(state);
+}
+
+// <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E
+//               ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
+static bool ParseNestedName(State *state) {
+  State copy = *state;
+  if (ParseOneCharToken(state, 'N') &&
+      EnterNestedName(state) &&
+      Optional(ParseCVQualifiers(state)) &&
+      ParsePrefix(state) &&
+      LeaveNestedName(state, copy.nest_level) &&
+      ParseOneCharToken(state, 'E')) {
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// This part is tricky.  If we literally translate them to code, we'll
+// end up infinite loop.  Hence we merge them to avoid the case.
+//
+// <prefix> ::= <prefix> <unqualified-name>
+//          ::= <template-prefix> <template-args>
+//          ::= <template-param>
+//          ::= <substitution>
+//          ::= # empty
+// <template-prefix> ::= <prefix> <(template) unqualified-name>
+//                   ::= <template-param>
+//                   ::= <substitution>
+static bool ParsePrefix(State *state) {
+  bool has_something = false;
+  while (true) {
+    MaybeAppendSeparator(state);
+    if (ParseTemplateParam(state) ||
+        ParseSubstitution(state) ||
+        ParseUnscopedName(state)) {
+      has_something = true;
+      MaybeIncreaseNestLevel(state);
+      continue;
+    }
+    MaybeCancelLastSeparator(state);
+    if (has_something && ParseTemplateArgs(state)) {
+      return ParsePrefix(state);
+    } else {
+      break;
+    }
+  }
+  return true;
+}
+
+// <unqualified-name> ::= <operator-name>
+//                    ::= <ctor-dtor-name>
+//                    ::= <source-name>
+//                    ::= <local-source-name>
+static bool ParseUnqualifiedName(State *state) {
+  return (ParseOperatorName(state) ||
+          ParseCtorDtorName(state) ||
+          ParseSourceName(state) ||
+          ParseLocalSourceName(state));
+}
+
+// <source-name> ::= <positive length number> <identifier>
+static bool ParseSourceName(State *state) {
+  State copy = *state;
+  int length = -1;
+  if (ParseNumber(state, &length) && ParseIdentifier(state, length)) {
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <local-source-name> ::= L <source-name> [<discriminator>]
+//
+// References:
+//   http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31775
+//   http://gcc.gnu.org/viewcvs?view=rev&revision=124467
+static bool ParseLocalSourceName(State *state) {
+  State copy = *state;
+  if (ParseOneCharToken(state, 'L') && ParseSourceName(state) &&
+      Optional(ParseDiscriminator(state))) {
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <number> ::= [n] <non-negative decimal integer>
+// If "number_out" is non-null, then *number_out is set to the value of the
+// parsed number on success.
+static bool ParseNumber(State *state, int *number_out) {
+  int sign = 1;
+  if (ParseOneCharToken(state, 'n')) {
+    sign = -1;
+  }
+  const char *p = state->mangled_cur;
+  int number = 0;
+  for (;*p != '\0'; ++p) {
+    if (IsDigit(*p)) {
+      number = number * 10 + (*p - '0');
+    } else {
+      break;
+    }
+  }
+  if (p != state->mangled_cur) {  // Conversion succeeded.
+    state->mangled_cur = p;
+    if (number_out != NULL) {
+      *number_out = number * sign;
+    }
+    return true;
+  }
+  return false;
+}
+
+// Floating-point literals are encoded using a fixed-length lowercase
+// hexadecimal string.
+static bool ParseFloatNumber(State *state) {
+  const char *p = state->mangled_cur;
+  for (;*p != '\0'; ++p) {
+    if (!IsDigit(*p) && !(*p >= 'a' && *p <= 'f')) {
+      break;
+    }
+  }
+  if (p != state->mangled_cur) {  // Conversion succeeded.
+    state->mangled_cur = p;
+    return true;
+  }
+  return false;
+}
+
+// The <seq-id> is a sequence number in base 36,
+// using digits and upper case letters
+static bool ParseSeqId(State *state) {
+  const char *p = state->mangled_cur;
+  for (;*p != '\0'; ++p) {
+    if (!IsDigit(*p) && !(*p >= 'A' && *p <= 'Z')) {
+      break;
+    }
+  }
+  if (p != state->mangled_cur) {  // Conversion succeeded.
+    state->mangled_cur = p;
+    return true;
+  }
+  return false;
+}
+
+// <identifier> ::= <unqualified source code identifier> (of given length)
+static bool ParseIdentifier(State *state, int length) {
+  if (length == -1 ||
+      !AtLeastNumCharsRemaining(state->mangled_cur, length)) {
+    return false;
+  }
+  if (IdentifierIsAnonymousNamespace(state, length)) {
+    MaybeAppend(state, "(anonymous namespace)");
+  } else {
+    MaybeAppendWithLength(state, state->mangled_cur, length);
+  }
+  state->mangled_cur += length;
+  return true;
+}
+
+// <operator-name> ::= nw, and other two letters cases
+//                 ::= cv <type>  # (cast)
+//                 ::= v  <digit> <source-name> # vendor extended operator
+static bool ParseOperatorName(State *state) {
+  if (!AtLeastNumCharsRemaining(state->mangled_cur, 2)) {
+    return false;
+  }
+  // First check with "cv" (cast) case.
+  State copy = *state;
+  if (ParseTwoCharToken(state, "cv") &&
+      MaybeAppend(state, "operator ") &&
+      EnterNestedName(state) &&
+      ParseType(state) &&
+      LeaveNestedName(state, copy.nest_level)) {
+    return true;
+  }
+  *state = copy;
+
+  // Then vendor extended operators.
+  if (ParseOneCharToken(state, 'v') && ParseCharClass(state, "0123456789") &&
+      ParseSourceName(state)) {
+    return true;
+  }
+  *state = copy;
+
+  // Other operator names should start with a lower alphabet followed
+  // by a lower/upper alphabet.
+  if (!(IsLower(state->mangled_cur[0]) &&
+        IsAlpha(state->mangled_cur[1]))) {
+    return false;
+  }
+  // We may want to perform a binary search if we really need speed.
+  const AbbrevPair *p;
+  for (p = kOperatorList; p->abbrev != NULL; ++p) {
+    if (state->mangled_cur[0] == p->abbrev[0] &&
+        state->mangled_cur[1] == p->abbrev[1]) {
+      MaybeAppend(state, "operator");
+      if (IsLower(*p->real_name)) {  // new, delete, etc.
+        MaybeAppend(state, " ");
+      }
+      MaybeAppend(state, p->real_name);
+      state->mangled_cur += 2;
+      return true;
+    }
+  }
+  return false;
+}
+
+// <special-name> ::= TV <type>
+//                ::= TT <type>
+//                ::= TI <type>
+//                ::= TS <type>
+//                ::= Tc <call-offset> <call-offset> <(base) encoding>
+//                ::= GV <(object) name>
+//                ::= T <call-offset> <(base) encoding>
+// G++ extensions:
+//                ::= TC <type> <(offset) number> _ <(base) type>
+//                ::= TF <type>
+//                ::= TJ <type>
+//                ::= GR <name>
+//                ::= GA <encoding>
+//                ::= Th <call-offset> <(base) encoding>
+//                ::= Tv <call-offset> <(base) encoding>
+//
+// Note: we don't care much about them since they don't appear in
+// stack traces.  The are special data.
+static bool ParseSpecialName(State *state) {
+  State copy = *state;
+  if (ParseOneCharToken(state, 'T') &&
+      ParseCharClass(state, "VTIS") &&
+      ParseType(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseTwoCharToken(state, "Tc") && ParseCallOffset(state) &&
+      ParseCallOffset(state) && ParseEncoding(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseTwoCharToken(state, "GV") &&
+      ParseName(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseOneCharToken(state, 'T') && ParseCallOffset(state) &&
+      ParseEncoding(state)) {
+    return true;
+  }
+  *state = copy;
+
+  // G++ extensions
+  if (ParseTwoCharToken(state, "TC") && ParseType(state) &&
+      ParseNumber(state, NULL) && ParseOneCharToken(state, '_') &&
+      DisableAppend(state) &&
+      ParseType(state)) {
+    RestoreAppend(state, copy.append);
+    return true;
+  }
+  *state = copy;
+
+  if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "FJ") &&
+      ParseType(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseTwoCharToken(state, "GR") && ParseName(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseTwoCharToken(state, "GA") && ParseEncoding(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "hv") &&
+      ParseCallOffset(state) && ParseEncoding(state)) {
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <call-offset> ::= h <nv-offset> _
+//               ::= v <v-offset> _
+static bool ParseCallOffset(State *state) {
+  State copy = *state;
+  if (ParseOneCharToken(state, 'h') &&
+      ParseNVOffset(state) && ParseOneCharToken(state, '_')) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseOneCharToken(state, 'v') &&
+      ParseVOffset(state) && ParseOneCharToken(state, '_')) {
+    return true;
+  }
+  *state = copy;
+
+  return false;
+}
+
+// <nv-offset> ::= <(offset) number>
+static bool ParseNVOffset(State *state) {
+  return ParseNumber(state, NULL);
+}
+
+// <v-offset>  ::= <(offset) number> _ <(virtual offset) number>
+static bool ParseVOffset(State *state) {
+  State copy = *state;
+  if (ParseNumber(state, NULL) && ParseOneCharToken(state, '_') &&
+      ParseNumber(state, NULL)) {
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <ctor-dtor-name> ::= C1 | C2 | C3
+//                  ::= D0 | D1 | D2
+static bool ParseCtorDtorName(State *state) {
+  State copy = *state;
+  if (ParseOneCharToken(state, 'C') &&
+      ParseCharClass(state, "123")) {
+    const char * const prev_name = state->prev_name;
+    const int prev_name_length = state->prev_name_length;
+    MaybeAppendWithLength(state, prev_name, prev_name_length);
+    return true;
+  }
+  *state = copy;
+
+  if (ParseOneCharToken(state, 'D') &&
+      ParseCharClass(state, "012")) {
+    const char * const prev_name = state->prev_name;
+    const int prev_name_length = state->prev_name_length;
+    MaybeAppend(state, "~");
+    MaybeAppendWithLength(state, prev_name, prev_name_length);
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <type> ::= <CV-qualifiers> <type>
+//        ::= P <type>   # pointer-to
+//        ::= R <type>   # reference-to
+//        ::= O <type>   # rvalue reference-to (C++0x)
+//        ::= C <type>   # complex pair (C 2000)
+//        ::= G <type>   # imaginary (C 2000)
+//        ::= U <source-name> <type>  # vendor extended type qualifier
+//        ::= <builtin-type>
+//        ::= <function-type>
+//        ::= <class-enum-type>
+//        ::= <array-type>
+//        ::= <pointer-to-member-type>
+//        ::= <template-template-param> <template-args>
+//        ::= <template-param>
+//        ::= <substitution>
+//        ::= Dp <type>          # pack expansion of (C++0x)
+//        ::= Dt <expression> E  # decltype of an id-expression or class
+//                               # member access (C++0x)
+//        ::= DT <expression> E  # decltype of an expression (C++0x)
+//
+static bool ParseType(State *state) {
+  // We should check CV-qualifers, and PRGC things first.
+  State copy = *state;
+  if (ParseCVQualifiers(state) && ParseType(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseCharClass(state, "OPRCG") && ParseType(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseTwoCharToken(state, "Dp") && ParseType(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseOneCharToken(state, 'D') && ParseCharClass(state, "tT") &&
+      ParseExpression(state) && ParseOneCharToken(state, 'E')) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseOneCharToken(state, 'U') && ParseSourceName(state) &&
+      ParseType(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseBuiltinType(state) ||
+      ParseFunctionType(state) ||
+      ParseClassEnumType(state) ||
+      ParseArrayType(state) ||
+      ParsePointerToMemberType(state) ||
+      ParseSubstitution(state)) {
+    return true;
+  }
+
+  if (ParseTemplateTemplateParam(state) &&
+      ParseTemplateArgs(state)) {
+    return true;
+  }
+  *state = copy;
+
+  // Less greedy than <template-template-param> <template-args>.
+  if (ParseTemplateParam(state)) {
+    return true;
+  }
+
+  return false;
+}
+
+// <CV-qualifiers> ::= [r] [V] [K]
+// We don't allow empty <CV-qualifiers> to avoid infinite loop in
+// ParseType().
+static bool ParseCVQualifiers(State *state) {
+  int num_cv_qualifiers = 0;
+  num_cv_qualifiers += ParseOneCharToken(state, 'r');
+  num_cv_qualifiers += ParseOneCharToken(state, 'V');
+  num_cv_qualifiers += ParseOneCharToken(state, 'K');
+  return num_cv_qualifiers > 0;
+}
+
+// <builtin-type> ::= v, etc.
+//                ::= u <source-name>
+static bool ParseBuiltinType(State *state) {
+  const AbbrevPair *p;
+  for (p = kBuiltinTypeList; p->abbrev != NULL; ++p) {
+    if (state->mangled_cur[0] == p->abbrev[0]) {
+      MaybeAppend(state, p->real_name);
+      ++state->mangled_cur;
+      return true;
+    }
+  }
+
+  State copy = *state;
+  if (ParseOneCharToken(state, 'u') && ParseSourceName(state)) {
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <function-type> ::= F [Y] <bare-function-type> E
+static bool ParseFunctionType(State *state) {
+  State copy = *state;
+  if (ParseOneCharToken(state, 'F') &&
+      Optional(ParseOneCharToken(state, 'Y')) &&
+      ParseBareFunctionType(state) && ParseOneCharToken(state, 'E')) {
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <bare-function-type> ::= <(signature) type>+
+static bool ParseBareFunctionType(State *state) {
+  State copy = *state;
+  DisableAppend(state);
+  if (OneOrMore(ParseType, state)) {
+    RestoreAppend(state, copy.append);
+    MaybeAppend(state, "()");
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <class-enum-type> ::= <name>
+static bool ParseClassEnumType(State *state) {
+  return ParseName(state);
+}
+
+// <array-type> ::= A <(positive dimension) number> _ <(element) type>
+//              ::= A [<(dimension) expression>] _ <(element) type>
+static bool ParseArrayType(State *state) {
+  State copy = *state;
+  if (ParseOneCharToken(state, 'A') && ParseNumber(state, NULL) &&
+      ParseOneCharToken(state, '_') && ParseType(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseOneCharToken(state, 'A') && Optional(ParseExpression(state)) &&
+      ParseOneCharToken(state, '_') && ParseType(state)) {
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <pointer-to-member-type> ::= M <(class) type> <(member) type>
+static bool ParsePointerToMemberType(State *state) {
+  State copy = *state;
+  if (ParseOneCharToken(state, 'M') && ParseType(state) &&
+      ParseType(state)) {
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <template-param> ::= T_
+//                  ::= T <parameter-2 non-negative number> _
+static bool ParseTemplateParam(State *state) {
+  if (ParseTwoCharToken(state, "T_")) {
+    MaybeAppend(state, "?");  // We don't support template substitutions.
+    return true;
+  }
+
+  State copy = *state;
+  if (ParseOneCharToken(state, 'T') && ParseNumber(state, NULL) &&
+      ParseOneCharToken(state, '_')) {
+    MaybeAppend(state, "?");  // We don't support template substitutions.
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+
+// <template-template-param> ::= <template-param>
+//                           ::= <substitution>
+static bool ParseTemplateTemplateParam(State *state) {
+  return (ParseTemplateParam(state) ||
+          ParseSubstitution(state));
+}
+
+// <template-args> ::= I <template-arg>+ E
+static bool ParseTemplateArgs(State *state) {
+  State copy = *state;
+  DisableAppend(state);
+  if (ParseOneCharToken(state, 'I') &&
+      OneOrMore(ParseTemplateArg, state) &&
+      ParseOneCharToken(state, 'E')) {
+    RestoreAppend(state, copy.append);
+    MaybeAppend(state, "<>");
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <template-arg>  ::= <type>
+//                 ::= <expr-primary>
+//                 ::= I <template-arg>* E        # argument pack
+//                 ::= X <expression> E
+static bool ParseTemplateArg(State *state) {
+  State copy = *state;
+  if (ParseOneCharToken(state, 'I') &&
+      ZeroOrMore(ParseTemplateArg, state) &&
+      ParseOneCharToken(state, 'E')) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseType(state) ||
+      ParseExprPrimary(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseOneCharToken(state, 'X') && ParseExpression(state) &&
+      ParseOneCharToken(state, 'E')) {
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <expression> ::= <template-param>
+//              ::= <expr-primary>
+//              ::= <unary operator-name> <expression>
+//              ::= <binary operator-name> <expression> <expression>
+//              ::= <trinary operator-name> <expression> <expression>
+//                  <expression>
+//              ::= st <type>
+//              ::= sr <type> <unqualified-name> <template-args>
+//              ::= sr <type> <unqualified-name>
+static bool ParseExpression(State *state) {
+  if (ParseTemplateParam(state) || ParseExprPrimary(state)) {
+    return true;
+  }
+
+  State copy = *state;
+  if (ParseOperatorName(state) &&
+      ParseExpression(state) &&
+      ParseExpression(state) &&
+      ParseExpression(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseOperatorName(state) &&
+      ParseExpression(state) &&
+      ParseExpression(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseOperatorName(state) &&
+      ParseExpression(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseTwoCharToken(state, "st") && ParseType(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseTwoCharToken(state, "sr") && ParseType(state) &&
+      ParseUnqualifiedName(state) &&
+      ParseTemplateArgs(state)) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseTwoCharToken(state, "sr") && ParseType(state) &&
+      ParseUnqualifiedName(state)) {
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <expr-primary> ::= L <type> <(value) number> E
+//                ::= L <type> <(value) float> E
+//                ::= L <mangled-name> E
+//                // A bug in g++'s C++ ABI version 2 (-fabi-version=2).
+//                ::= LZ <encoding> E
+static bool ParseExprPrimary(State *state) {
+  State copy = *state;
+  if (ParseOneCharToken(state, 'L') && ParseType(state) &&
+      ParseNumber(state, NULL) &&
+      ParseOneCharToken(state, 'E')) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseOneCharToken(state, 'L') && ParseType(state) &&
+      ParseFloatNumber(state) &&
+      ParseOneCharToken(state, 'E')) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseOneCharToken(state, 'L') && ParseMangledName(state) &&
+      ParseOneCharToken(state, 'E')) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseTwoCharToken(state, "LZ") && ParseEncoding(state) &&
+      ParseOneCharToken(state, 'E')) {
+    return true;
+  }
+  *state = copy;
+
+  return false;
+}
+
+// <local-name> := Z <(function) encoding> E <(entity) name>
+//                 [<discriminator>]
+//              := Z <(function) encoding> E s [<discriminator>]
+static bool ParseLocalName(State *state) {
+  State copy = *state;
+  if (ParseOneCharToken(state, 'Z') && ParseEncoding(state) &&
+      ParseOneCharToken(state, 'E') && MaybeAppend(state, "::") &&
+      ParseName(state) && Optional(ParseDiscriminator(state))) {
+    return true;
+  }
+  *state = copy;
+
+  if (ParseOneCharToken(state, 'Z') && ParseEncoding(state) &&
+      ParseTwoCharToken(state, "Es") && Optional(ParseDiscriminator(state))) {
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <discriminator> := _ <(non-negative) number>
+static bool ParseDiscriminator(State *state) {
+  State copy = *state;
+  if (ParseOneCharToken(state, '_') && ParseNumber(state, NULL)) {
+    return true;
+  }
+  *state = copy;
+  return false;
+}
+
+// <substitution> ::= S_
+//                ::= S <seq-id> _
+//                ::= St, etc.
+static bool ParseSubstitution(State *state) {
+  if (ParseTwoCharToken(state, "S_")) {
+    MaybeAppend(state, "?");  // We don't support substitutions.
+    return true;
+  }
+
+  State copy = *state;
+  if (ParseOneCharToken(state, 'S') && ParseSeqId(state) &&
+      ParseOneCharToken(state, '_')) {
+    MaybeAppend(state, "?");  // We don't support substitutions.
+    return true;
+  }
+  *state = copy;
+
+  // Expand abbreviations like "St" => "std".
+  if (ParseOneCharToken(state, 'S')) {
+    const AbbrevPair *p;
+    for (p = kSubstitutionList; p->abbrev != NULL; ++p) {
+      if (state->mangled_cur[0] == p->abbrev[1]) {
+        MaybeAppend(state, "std");
+        if (p->real_name[0] != '\0') {
+          MaybeAppend(state, "::");
+          MaybeAppend(state, p->real_name);
+        }
+        ++state->mangled_cur;
+        return true;
+      }
+    }
+  }
+  *state = copy;
+  return false;
+}
+
+// Parse <mangled-name>, optionally followed by either a function-clone suffix
+// or version suffix.  Returns true only if all of "mangled_cur" was consumed.
+static bool ParseTopLevelMangledName(State *state) {
+  if (ParseMangledName(state)) {
+    if (state->mangled_cur[0] != '\0') {
+      // Drop trailing function clone suffix, if any.
+      if (IsFunctionCloneSuffix(state->mangled_cur)) {
+        return true;
+      }
+      // Append trailing version suffix if any.
+      // ex. _Z3foo@@GLIBCXX_3.4
+      if (state->mangled_cur[0] == '@') {
+        MaybeAppend(state, state->mangled_cur);
+        return true;
+      }
+      return false;  // Unconsumed suffix.
+    }
+    return true;
+  }
+  return false;
+}
+
+// The demangler entry point.
+bool Demangle(const char *mangled, char *out, int out_size) {
+  State state;
+  InitState(&state, mangled, out, out_size);
+  return ParseTopLevelMangledName(&state) && !state.overflowed;
+}
+
+_END_GOOGLE_NAMESPACE_
diff --git a/base/third_party/symbolize/demangle.h b/base/third_party/symbolize/demangle.h
new file mode 100644
index 0000000..9c75915
--- /dev/null
+++ b/base/third_party/symbolize/demangle.h
@@ -0,0 +1,84 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: Satoru Takabayashi
+//
+// An async-signal-safe and thread-safe demangler for Itanium C++ ABI
+// (aka G++ V3 ABI).
+
+// The demangler is implemented to be used in async signal handlers to
+// symbolize stack traces.  We cannot use libstdc++'s
+// abi::__cxa_demangle() in such signal handlers since it's not async
+// signal safe (it uses malloc() internally).
+//
+// Note that this demangler doesn't support full demangling.  More
+// specifically, it doesn't print types of function parameters and
+// types of template arguments.  It just skips them.  However, it's
+// still very useful to extract basic information such as class,
+// function, constructor, destructor, and operator names.
+//
+// See the implementation note in demangle.cc if you are interested.
+//
+// Example:
+//
+// | Mangled Name  | The Demangler | abi::__cxa_demangle()
+// |---------------|---------------|-----------------------
+// | _Z1fv         | f()           | f()
+// | _Z1fi         | f()           | f(int)
+// | _Z3foo3bar    | foo()         | foo(bar)
+// | _Z1fIiEvi     | f<>()         | void f<int>(int)
+// | _ZN1N1fE      | N::f          | N::f
+// | _ZN3Foo3BarEv | Foo::Bar()    | Foo::Bar()
+// | _Zrm1XS_"     | operator%()   | operator%(X, X)
+// | _ZN3FooC1Ev   | Foo::Foo()    | Foo::Foo()
+// | _Z1fSs        | f()           | f(std::basic_string<char,
+// |               |               |   std::char_traits<char>,
+// |               |               |   std::allocator<char> >)
+//
+// See the unit test for more examples.
+//
+// Note: we might want to write demanglers for ABIs other than Itanium
+// C++ ABI in the future.
+//
+
+#ifndef BASE_DEMANGLE_H_
+#define BASE_DEMANGLE_H_
+
+#include "config.h"
+
+_START_GOOGLE_NAMESPACE_
+
+// Demangle "mangled".  On success, return true and write the
+// demangled symbol name to "out".  Otherwise, return false.
+// "out" is modified even if demangling is unsuccessful.
+bool Demangle(const char *mangled, char *out, int out_size);
+
+_END_GOOGLE_NAMESPACE_
+
+#endif  // BASE_DEMANGLE_H_
diff --git a/base/third_party/symbolize/glog/logging.h b/base/third_party/symbolize/glog/logging.h
new file mode 100644
index 0000000..a42c306
--- /dev/null
+++ b/base/third_party/symbolize/glog/logging.h
@@ -0,0 +1,5 @@
+// Copyright (c) 2010 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.
+
+// Empty.
diff --git a/base/third_party/symbolize/glog/raw_logging.h b/base/third_party/symbolize/glog/raw_logging.h
new file mode 100644
index 0000000..f5515c4
--- /dev/null
+++ b/base/third_party/symbolize/glog/raw_logging.h
@@ -0,0 +1,6 @@
+// Copyright (c) 2010 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.
+
+#define WARNING 1;
+#define RAW_LOG(severity, ...);  // Do nothing.
diff --git a/base/third_party/symbolize/symbolize.cc b/base/third_party/symbolize/symbolize.cc
new file mode 100644
index 0000000..b25f747
--- /dev/null
+++ b/base/third_party/symbolize/symbolize.cc
@@ -0,0 +1,848 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: Satoru Takabayashi
+// Stack-footprint reduction work done by Raksit Ashok
+//
+// Implementation note:
+//
+// We don't use heaps but only use stacks.  We want to reduce the
+// stack consumption so that the symbolizer can run on small stacks.
+//
+// Here are some numbers collected with GCC 4.1.0 on x86:
+// - sizeof(Elf32_Sym)  = 16
+// - sizeof(Elf32_Shdr) = 40
+// - sizeof(Elf64_Sym)  = 24
+// - sizeof(Elf64_Shdr) = 64
+//
+// This implementation is intended to be async-signal-safe but uses
+// some functions which are not guaranteed to be so, such as memchr()
+// and memmove().  We assume they are async-signal-safe.
+//
+// Additional header can be specified by the GLOG_BUILD_CONFIG_INCLUDE
+// macro to add platform specific defines (e.g. OS_OPENBSD).
+
+#ifdef GLOG_BUILD_CONFIG_INCLUDE
+#include GLOG_BUILD_CONFIG_INCLUDE
+#endif  // GLOG_BUILD_CONFIG_INCLUDE
+
+#include "utilities.h"
+
+#if defined(HAVE_SYMBOLIZE)
+
+#include <limits>
+
+#include "symbolize.h"
+#include "demangle.h"
+
+_START_GOOGLE_NAMESPACE_
+
+// We don't use assert() since it's not guaranteed to be
+// async-signal-safe.  Instead we define a minimal assertion
+// macro. So far, we don't need pretty printing for __FILE__, etc.
+
+// A wrapper for abort() to make it callable in ? :.
+static int AssertFail() {
+  abort();
+  return 0;  // Should not reach.
+}
+
+#define SAFE_ASSERT(expr) ((expr) ? 0 : AssertFail())
+
+static SymbolizeCallback g_symbolize_callback = NULL;
+void InstallSymbolizeCallback(SymbolizeCallback callback) {
+  g_symbolize_callback = callback;
+}
+
+static SymbolizeOpenObjectFileCallback g_symbolize_open_object_file_callback =
+    NULL;
+void InstallSymbolizeOpenObjectFileCallback(
+    SymbolizeOpenObjectFileCallback callback) {
+  g_symbolize_open_object_file_callback = callback;
+}
+
+// This function wraps the Demangle function to provide an interface
+// where the input symbol is demangled in-place.
+// To keep stack consumption low, we would like this function to not
+// get inlined.
+static ATTRIBUTE_NOINLINE void DemangleInplace(char *out, int out_size) {
+  char demangled[256];  // Big enough for sane demangled symbols.
+  if (Demangle(out, demangled, sizeof(demangled))) {
+    // Demangling succeeded. Copy to out if the space allows.
+    size_t len = strlen(demangled);
+    if (len + 1 <= (size_t)out_size) {  // +1 for '\0'.
+      SAFE_ASSERT(len < sizeof(demangled));
+      memmove(out, demangled, len + 1);
+    }
+  }
+}
+
+_END_GOOGLE_NAMESPACE_
+
+#if defined(__ELF__)
+
+#include <dlfcn.h>
+#if defined(OS_OPENBSD)
+#include <sys/exec_elf.h>
+#else
+#include <elf.h>
+#endif
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "symbolize.h"
+#include "config.h"
+#include "glog/raw_logging.h"
+
+// Re-runs fn until it doesn't cause EINTR.
+#define NO_INTR(fn)   do {} while ((fn) < 0 && errno == EINTR)
+
+_START_GOOGLE_NAMESPACE_
+
+// Read up to "count" bytes from file descriptor "fd" into the buffer
+// starting at "buf" while handling short reads and EINTR.  On
+// success, return the number of bytes read.  Otherwise, return -1.
+static ssize_t ReadPersistent(const int fd, void *buf, const size_t count) {
+  SAFE_ASSERT(fd >= 0);
+  SAFE_ASSERT(count <= std::numeric_limits<ssize_t>::max());
+  char *buf0 = reinterpret_cast<char *>(buf);
+  ssize_t num_bytes = 0;
+  while (num_bytes < count) {
+    ssize_t len;
+    NO_INTR(len = read(fd, buf0 + num_bytes, count - num_bytes));
+    if (len < 0) {  // There was an error other than EINTR.
+      return -1;
+    }
+    if (len == 0) {  // Reached EOF.
+      break;
+    }
+    num_bytes += len;
+  }
+  SAFE_ASSERT(num_bytes <= count);
+  return num_bytes;
+}
+
+// Read up to "count" bytes from "offset" in the file pointed by file
+// descriptor "fd" into the buffer starting at "buf".  On success,
+// return the number of bytes read.  Otherwise, return -1.
+static ssize_t ReadFromOffset(const int fd, void *buf,
+                              const size_t count, const off_t offset) {
+  off_t off = lseek(fd, offset, SEEK_SET);
+  if (off == (off_t)-1) {
+    return -1;
+  }
+  return ReadPersistent(fd, buf, count);
+}
+
+// Try reading exactly "count" bytes from "offset" bytes in a file
+// pointed by "fd" into the buffer starting at "buf" while handling
+// short reads and EINTR.  On success, return true. Otherwise, return
+// false.
+static bool ReadFromOffsetExact(const int fd, void *buf,
+                                const size_t count, const off_t offset) {
+  ssize_t len = ReadFromOffset(fd, buf, count, offset);
+  return len == count;
+}
+
+// Returns elf_header.e_type if the file pointed by fd is an ELF binary.
+static int FileGetElfType(const int fd) {
+  ElfW(Ehdr) elf_header;
+  if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
+    return -1;
+  }
+  if (memcmp(elf_header.e_ident, ELFMAG, SELFMAG) != 0) {
+    return -1;
+  }
+  return elf_header.e_type;
+}
+
+// Read the section headers in the given ELF binary, and if a section
+// of the specified type is found, set the output to this section header
+// and return true.  Otherwise, return false.
+// To keep stack consumption low, we would like this function to not get
+// inlined.
+static ATTRIBUTE_NOINLINE bool
+GetSectionHeaderByType(const int fd, ElfW(Half) sh_num, const off_t sh_offset,
+                       ElfW(Word) type, ElfW(Shdr) *out) {
+  // Read at most 16 section headers at a time to save read calls.
+  ElfW(Shdr) buf[16];
+  for (int i = 0; i < sh_num;) {
+    const ssize_t num_bytes_left = (sh_num - i) * sizeof(buf[0]);
+    const ssize_t num_bytes_to_read =
+        (sizeof(buf) > num_bytes_left) ? num_bytes_left : sizeof(buf);
+    const ssize_t len = ReadFromOffset(fd, buf, num_bytes_to_read,
+                                       sh_offset + i * sizeof(buf[0]));
+    SAFE_ASSERT(len % sizeof(buf[0]) == 0);
+    const ssize_t num_headers_in_buf = len / sizeof(buf[0]);
+    SAFE_ASSERT(num_headers_in_buf <= sizeof(buf) / sizeof(buf[0]));
+    for (int j = 0; j < num_headers_in_buf; ++j) {
+      if (buf[j].sh_type == type) {
+        *out = buf[j];
+        return true;
+      }
+    }
+    i += num_headers_in_buf;
+  }
+  return false;
+}
+
+// There is no particular reason to limit section name to 63 characters,
+// but there has (as yet) been no need for anything longer either.
+const int kMaxSectionNameLen = 64;
+
+// name_len should include terminating '\0'.
+bool GetSectionHeaderByName(int fd, const char *name, size_t name_len,
+                            ElfW(Shdr) *out) {
+  ElfW(Ehdr) elf_header;
+  if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
+    return false;
+  }
+
+  ElfW(Shdr) shstrtab;
+  off_t shstrtab_offset = (elf_header.e_shoff +
+                           elf_header.e_shentsize * elf_header.e_shstrndx);
+  if (!ReadFromOffsetExact(fd, &shstrtab, sizeof(shstrtab), shstrtab_offset)) {
+    return false;
+  }
+
+  for (int i = 0; i < elf_header.e_shnum; ++i) {
+    off_t section_header_offset = (elf_header.e_shoff +
+                                   elf_header.e_shentsize * i);
+    if (!ReadFromOffsetExact(fd, out, sizeof(*out), section_header_offset)) {
+      return false;
+    }
+    char header_name[kMaxSectionNameLen];
+    if (sizeof(header_name) < name_len) {
+      RAW_LOG(WARNING, "Section name '%s' is too long (%" PRIuS "); "
+              "section will not be found (even if present).", name, name_len);
+      // No point in even trying.
+      return false;
+    }
+    off_t name_offset = shstrtab.sh_offset + out->sh_name;
+    ssize_t n_read = ReadFromOffset(fd, &header_name, name_len, name_offset);
+    if (n_read == -1) {
+      return false;
+    } else if (n_read != name_len) {
+      // Short read -- name could be at end of file.
+      continue;
+    }
+    if (memcmp(header_name, name, name_len) == 0) {
+      return true;
+    }
+  }
+  return false;
+}
+
+// Read a symbol table and look for the symbol containing the
+// pc. Iterate over symbols in a symbol table and look for the symbol
+// containing "pc".  On success, return true and write the symbol name
+// to out.  Otherwise, return false.
+// To keep stack consumption low, we would like this function to not get
+// inlined.
+static ATTRIBUTE_NOINLINE bool
+FindSymbol(uint64_t pc, const int fd, char *out, int out_size,
+           uint64_t symbol_offset, const ElfW(Shdr) *strtab,
+           const ElfW(Shdr) *symtab) {
+  if (symtab == NULL) {
+    return false;
+  }
+  const int num_symbols = symtab->sh_size / symtab->sh_entsize;
+  for (int i = 0; i < num_symbols;) {
+    off_t offset = symtab->sh_offset + i * symtab->sh_entsize;
+
+    // If we are reading Elf64_Sym's, we want to limit this array to
+    // 32 elements (to keep stack consumption low), otherwise we can
+    // have a 64 element Elf32_Sym array.
+#if __WORDSIZE == 64
+#define NUM_SYMBOLS 32
+#else
+#define NUM_SYMBOLS 64
+#endif
+
+    // Read at most NUM_SYMBOLS symbols at once to save read() calls.
+    ElfW(Sym) buf[NUM_SYMBOLS];
+    const ssize_t len = ReadFromOffset(fd, &buf, sizeof(buf), offset);
+    SAFE_ASSERT(len % sizeof(buf[0]) == 0);
+    const ssize_t num_symbols_in_buf = len / sizeof(buf[0]);
+    SAFE_ASSERT(num_symbols_in_buf <= sizeof(buf)/sizeof(buf[0]));
+    for (int j = 0; j < num_symbols_in_buf; ++j) {
+      const ElfW(Sym)& symbol = buf[j];
+      uint64_t start_address = symbol.st_value;
+      start_address += symbol_offset;
+      uint64_t end_address = start_address + symbol.st_size;
+      if (symbol.st_value != 0 &&  // Skip null value symbols.
+          symbol.st_shndx != 0 &&  // Skip undefined symbols.
+          start_address <= pc && pc < end_address) {
+        ssize_t len1 = ReadFromOffset(fd, out, out_size,
+                                      strtab->sh_offset + symbol.st_name);
+        if (len1 <= 0 || memchr(out, '\0', out_size) == NULL) {
+          return false;
+        }
+        return true;  // Obtained the symbol name.
+      }
+    }
+    i += num_symbols_in_buf;
+  }
+  return false;
+}
+
+// Get the symbol name of "pc" from the file pointed by "fd".  Process
+// both regular and dynamic symbol tables if necessary.  On success,
+// write the symbol name to "out" and return true.  Otherwise, return
+// false.
+static bool GetSymbolFromObjectFile(const int fd, uint64_t pc,
+                                    char *out, int out_size,
+                                    uint64_t map_start_address) {
+  // Read the ELF header.
+  ElfW(Ehdr) elf_header;
+  if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
+    return false;
+  }
+
+  uint64_t symbol_offset = 0;
+  if (elf_header.e_type == ET_DYN) {  // DSO needs offset adjustment.
+    symbol_offset = map_start_address;
+  }
+
+  ElfW(Shdr) symtab, strtab;
+
+  // Consult a regular symbol table first.
+  if (GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff,
+                             SHT_SYMTAB, &symtab)) {
+    if (!ReadFromOffsetExact(fd, &strtab, sizeof(strtab), elf_header.e_shoff +
+                             symtab.sh_link * sizeof(symtab))) {
+      return false;
+    }
+    if (FindSymbol(pc, fd, out, out_size, symbol_offset,
+                   &strtab, &symtab)) {
+      return true;  // Found the symbol in a regular symbol table.
+    }
+  }
+
+  // If the symbol is not found, then consult a dynamic symbol table.
+  if (GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff,
+                             SHT_DYNSYM, &symtab)) {
+    if (!ReadFromOffsetExact(fd, &strtab, sizeof(strtab), elf_header.e_shoff +
+                             symtab.sh_link * sizeof(symtab))) {
+      return false;
+    }
+    if (FindSymbol(pc, fd, out, out_size, symbol_offset,
+                   &strtab, &symtab)) {
+      return true;  // Found the symbol in a dynamic symbol table.
+    }
+  }
+
+  return false;
+}
+
+namespace {
+// Thin wrapper around a file descriptor so that the file descriptor
+// gets closed for sure.
+struct FileDescriptor {
+  const int fd_;
+  explicit FileDescriptor(int fd) : fd_(fd) {}
+  ~FileDescriptor() {
+    if (fd_ >= 0) {
+      NO_INTR(close(fd_));
+    }
+  }
+  int get() { return fd_; }
+
+ private:
+  explicit FileDescriptor(const FileDescriptor&);
+  void operator=(const FileDescriptor&);
+};
+
+// Helper class for reading lines from file.
+//
+// Note: we don't use ProcMapsIterator since the object is big (it has
+// a 5k array member) and uses async-unsafe functions such as sscanf()
+// and snprintf().
+class LineReader {
+ public:
+  explicit LineReader(int fd, char *buf, int buf_len) : fd_(fd),
+    buf_(buf), buf_len_(buf_len), bol_(buf), eol_(buf), eod_(buf) {
+  }
+
+  // Read '\n'-terminated line from file.  On success, modify "bol"
+  // and "eol", then return true.  Otherwise, return false.
+  //
+  // Note: if the last line doesn't end with '\n', the line will be
+  // dropped.  It's an intentional behavior to make the code simple.
+  bool ReadLine(const char **bol, const char **eol) {
+    if (BufferIsEmpty()) {  // First time.
+      const ssize_t num_bytes = ReadPersistent(fd_, buf_, buf_len_);
+      if (num_bytes <= 0) {  // EOF or error.
+        return false;
+      }
+      eod_ = buf_ + num_bytes;
+      bol_ = buf_;
+    } else {
+      bol_ = eol_ + 1;  // Advance to the next line in the buffer.
+      SAFE_ASSERT(bol_ <= eod_);  // "bol_" can point to "eod_".
+      if (!HasCompleteLine()) {
+        const int incomplete_line_length = eod_ - bol_;
+        // Move the trailing incomplete line to the beginning.
+        memmove(buf_, bol_, incomplete_line_length);
+        // Read text from file and append it.
+        char * const append_pos = buf_ + incomplete_line_length;
+        const int capacity_left = buf_len_ - incomplete_line_length;
+        const ssize_t num_bytes = ReadPersistent(fd_, append_pos,
+                                                 capacity_left);
+        if (num_bytes <= 0) {  // EOF or error.
+          return false;
+        }
+        eod_ = append_pos + num_bytes;
+        bol_ = buf_;
+      }
+    }
+    eol_ = FindLineFeed();
+    if (eol_ == NULL) {  // '\n' not found.  Malformed line.
+      return false;
+    }
+    *eol_ = '\0';  // Replace '\n' with '\0'.
+
+    *bol = bol_;
+    *eol = eol_;
+    return true;
+  }
+
+  // Beginning of line.
+  const char *bol() {
+    return bol_;
+  }
+
+  // End of line.
+  const char *eol() {
+    return eol_;
+  }
+
+ private:
+  explicit LineReader(const LineReader&);
+  void operator=(const LineReader&);
+
+  char *FindLineFeed() {
+    return reinterpret_cast<char *>(memchr(bol_, '\n', eod_ - bol_));
+  }
+
+  bool BufferIsEmpty() {
+    return buf_ == eod_;
+  }
+
+  bool HasCompleteLine() {
+    return !BufferIsEmpty() && FindLineFeed() != NULL;
+  }
+
+  const int fd_;
+  char * const buf_;
+  const int buf_len_;
+  char *bol_;
+  char *eol_;
+  const char *eod_;  // End of data in "buf_".
+};
+}  // namespace
+
+// Place the hex number read from "start" into "*hex".  The pointer to
+// the first non-hex character or "end" is returned.
+static char *GetHex(const char *start, const char *end, uint64_t *hex) {
+  *hex = 0;
+  const char *p;
+  for (p = start; p < end; ++p) {
+    int ch = *p;
+    if ((ch >= '0' && ch <= '9') ||
+        (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f')) {
+      *hex = (*hex << 4) | (ch < 'A' ? ch - '0' : (ch & 0xF) + 9);
+    } else {  // Encountered the first non-hex character.
+      break;
+    }
+  }
+  SAFE_ASSERT(p <= end);
+  return const_cast<char *>(p);
+}
+
+// Searches for the object file (from /proc/self/maps) that contains
+// the specified pc.  If found, sets |start_address| to the start address
+// of where this object file is mapped in memory, sets the module base
+// address into |base_address|, copies the object file name into
+// |out_file_name|, and attempts to open the object file.  If the object
+// file is opened successfully, returns the file descriptor.  Otherwise,
+// returns -1.  |out_file_name_size| is the size of the file name buffer
+// (including the null-terminator).
+static ATTRIBUTE_NOINLINE int
+OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
+                                             uint64_t &start_address,
+                                             uint64_t &base_address,
+                                             char *out_file_name,
+                                             int out_file_name_size) {
+  int object_fd;
+
+  // Open /proc/self/maps.
+  int maps_fd;
+  NO_INTR(maps_fd = open("/proc/self/maps", O_RDONLY));
+  FileDescriptor wrapped_maps_fd(maps_fd);
+  if (wrapped_maps_fd.get() < 0) {
+    return -1;
+  }
+
+  // Iterate over maps and look for the map containing the pc.  Then
+  // look into the symbol tables inside.
+  char buf[1024];  // Big enough for line of sane /proc/self/maps
+  int num_maps = 0;
+  LineReader reader(wrapped_maps_fd.get(), buf, sizeof(buf));
+  while (true) {
+    num_maps++;
+    const char *cursor;
+    const char *eol;
+    if (!reader.ReadLine(&cursor, &eol)) {  // EOF or malformed line.
+      return -1;
+    }
+
+    // Start parsing line in /proc/self/maps.  Here is an example:
+    //
+    // 08048000-0804c000 r-xp 00000000 08:01 2142121    /bin/cat
+    //
+    // We want start address (08048000), end address (0804c000), flags
+    // (r-xp) and file name (/bin/cat).
+
+    // Read start address.
+    cursor = GetHex(cursor, eol, &start_address);
+    if (cursor == eol || *cursor != '-') {
+      return -1;  // Malformed line.
+    }
+    ++cursor;  // Skip '-'.
+
+    // Read end address.
+    uint64_t end_address;
+    cursor = GetHex(cursor, eol, &end_address);
+    if (cursor == eol || *cursor != ' ') {
+      return -1;  // Malformed line.
+    }
+    ++cursor;  // Skip ' '.
+
+    // Check start and end addresses.
+    if (!(start_address <= pc && pc < end_address)) {
+      continue;  // We skip this map.  PC isn't in this map.
+    }
+
+    // Read flags.  Skip flags until we encounter a space or eol.
+    const char * const flags_start = cursor;
+    while (cursor < eol && *cursor != ' ') {
+      ++cursor;
+    }
+    // We expect at least four letters for flags (ex. "r-xp").
+    if (cursor == eol || cursor < flags_start + 4) {
+      return -1;  // Malformed line.
+    }
+
+    // Check flags.  We are only interested in "r-x" maps.
+    if (memcmp(flags_start, "r-x", 3) != 0) {  // Not a "r-x" map.
+      continue;  // We skip this map.
+    }
+    ++cursor;  // Skip ' '.
+
+    // Read file offset.
+    uint64_t file_offset;
+    cursor = GetHex(cursor, eol, &file_offset);
+    if (cursor == eol || *cursor != ' ') {
+      return -1;  // Malformed line.
+    }
+    ++cursor;  // Skip ' '.
+
+    // Don't subtract 'start_address' from the first entry:
+    // * If a binary is compiled w/o -pie, then the first entry in
+    //   process maps is likely the binary itself (all dynamic libs
+    //   are mapped higher in address space). For such a binary,
+    //   instruction offset in binary coincides with the actual
+    //   instruction address in virtual memory (as code section
+    //   is mapped to a fixed memory range).
+    // * If a binary is compiled with -pie, all the modules are
+    //   mapped high at address space (in particular, higher than
+    //   shadow memory of the tool), so the module can't be the
+    //   first entry.
+    base_address = ((num_maps == 1) ? 0U : start_address) - file_offset;
+
+    // Skip to file name.  "cursor" now points to dev.  We need to
+    // skip at least two spaces for dev and inode.
+    int num_spaces = 0;
+    while (cursor < eol) {
+      if (*cursor == ' ') {
+        ++num_spaces;
+      } else if (num_spaces >= 2) {
+        // The first non-space character after skipping two spaces
+        // is the beginning of the file name.
+        break;
+      }
+      ++cursor;
+    }
+    if (cursor == eol) {
+      return -1;  // Malformed line.
+    }
+
+    // Finally, "cursor" now points to file name of our interest.
+    NO_INTR(object_fd = open(cursor, O_RDONLY));
+    if (object_fd < 0) {
+      // Failed to open object file.  Copy the object file name to
+      // |out_file_name|.
+      strncpy(out_file_name, cursor, out_file_name_size);
+      // Making sure |out_file_name| is always null-terminated.
+      out_file_name[out_file_name_size - 1] = '\0';
+      return -1;
+    }
+    return object_fd;
+  }
+}
+
+// POSIX doesn't define any async-signal safe function for converting
+// an integer to ASCII. We'll have to define our own version.
+// itoa_r() converts a (signed) integer to ASCII. It returns "buf", if the
+// conversion was successful or NULL otherwise. It never writes more than "sz"
+// bytes. Output will be truncated as needed, and a NUL character is always
+// appended.
+// NOTE: code from sandbox/linux/seccomp-bpf/demo.cc.
+char *itoa_r(intptr_t i, char *buf, size_t sz, int base, size_t padding) {
+  // Make sure we can write at least one NUL byte.
+  size_t n = 1;
+  if (n > sz)
+    return NULL;
+
+  if (base < 2 || base > 16) {
+    buf[0] = '\000';
+    return NULL;
+  }
+
+  char *start = buf;
+
+  uintptr_t j = i;
+
+  // Handle negative numbers (only for base 10).
+  if (i < 0 && base == 10) {
+    j = -i;
+
+    // Make sure we can write the '-' character.
+    if (++n > sz) {
+      buf[0] = '\000';
+      return NULL;
+    }
+    *start++ = '-';
+  }
+
+  // Loop until we have converted the entire number. Output at least one
+  // character (i.e. '0').
+  char *ptr = start;
+  do {
+    // Make sure there is still enough space left in our output buffer.
+    if (++n > sz) {
+      buf[0] = '\000';
+      return NULL;
+    }
+
+    // Output the next digit.
+    *ptr++ = "0123456789abcdef"[j % base];
+    j /= base;
+
+    if (padding > 0)
+      padding--;
+  } while (j > 0 || padding > 0);
+
+  // Terminate the output with a NUL character.
+  *ptr = '\000';
+
+  // Conversion to ASCII actually resulted in the digits being in reverse
+  // order. We can't easily generate them in forward order, as we can't tell
+  // the number of characters needed until we are done converting.
+  // So, now, we reverse the string (except for the possible "-" sign).
+  while (--ptr > start) {
+    char ch = *ptr;
+    *ptr = *start;
+    *start++ = ch;
+  }
+  return buf;
+}
+
+// Safely appends string |source| to string |dest|.  Never writes past the
+// buffer size |dest_size| and guarantees that |dest| is null-terminated.
+void SafeAppendString(const char* source, char* dest, int dest_size) {
+  int dest_string_length = strlen(dest);
+  SAFE_ASSERT(dest_string_length < dest_size);
+  dest += dest_string_length;
+  dest_size -= dest_string_length;
+  strncpy(dest, source, dest_size);
+  // Making sure |dest| is always null-terminated.
+  dest[dest_size - 1] = '\0';
+}
+
+// Converts a 64-bit value into a hex string, and safely appends it to |dest|.
+// Never writes past the buffer size |dest_size| and guarantees that |dest| is
+// null-terminated.
+void SafeAppendHexNumber(uint64_t value, char* dest, int dest_size) {
+  // 64-bit numbers in hex can have up to 16 digits.
+  char buf[17] = {'\0'};
+  SafeAppendString(itoa_r(value, buf, sizeof(buf), 16, 0), dest, dest_size);
+}
+
+// The implementation of our symbolization routine.  If it
+// successfully finds the symbol containing "pc" and obtains the
+// symbol name, returns true and write the symbol name to "out".
+// Otherwise, returns false. If Callback function is installed via
+// InstallSymbolizeCallback(), the function is also called in this function,
+// and "out" is used as its output.
+// To keep stack consumption low, we would like this function to not
+// get inlined.
+static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
+                                                    int out_size) {
+  uint64_t pc0 = reinterpret_cast<uintptr_t>(pc);
+  uint64_t start_address = 0;
+  uint64_t base_address = 0;
+  int object_fd = -1;
+
+  if (out_size < 1) {
+    return false;
+  }
+  out[0] = '\0';
+  SafeAppendString("(", out, out_size);
+
+  if (g_symbolize_open_object_file_callback) {
+    object_fd = g_symbolize_open_object_file_callback(pc0, start_address,
+                                                      base_address, out + 1,
+                                                      out_size - 1);
+  } else {
+    object_fd = OpenObjectFileContainingPcAndGetStartAddress(pc0, start_address,
+                                                             base_address,
+                                                             out + 1,
+                                                             out_size - 1);
+  }
+
+  // Check whether a file name was returned.
+  if (object_fd < 0) {
+    if (out[1]) {
+      // The object file containing PC was determined successfully however the
+      // object file was not opened successfully.  This is still considered
+      // success because the object file name and offset are known and tools
+      // like asan_symbolize.py can be used for the symbolization.
+      out[out_size - 1] = '\0';  // Making sure |out| is always null-terminated.
+      SafeAppendString("+0x", out, out_size);
+      SafeAppendHexNumber(pc0 - base_address, out, out_size);
+      SafeAppendString(")", out, out_size);
+      return true;
+    }
+    // Failed to determine the object file containing PC.  Bail out.
+    return false;
+  }
+  FileDescriptor wrapped_object_fd(object_fd);
+  int elf_type = FileGetElfType(wrapped_object_fd.get());
+  if (elf_type == -1) {
+    return false;
+  }
+  if (g_symbolize_callback) {
+    // Run the call back if it's installed.
+    // Note: relocation (and much of the rest of this code) will be
+    // wrong for prelinked shared libraries and PIE executables.
+    uint64 relocation = (elf_type == ET_DYN) ? start_address : 0;
+    int num_bytes_written = g_symbolize_callback(wrapped_object_fd.get(),
+                                                 pc, out, out_size,
+                                                 relocation);
+    if (num_bytes_written > 0) {
+      out += num_bytes_written;
+      out_size -= num_bytes_written;
+    }
+  }
+  if (!GetSymbolFromObjectFile(wrapped_object_fd.get(), pc0,
+                               out, out_size, start_address)) {
+    return false;
+  }
+
+  // Symbolization succeeded.  Now we try to demangle the symbol.
+  DemangleInplace(out, out_size);
+  return true;
+}
+
+_END_GOOGLE_NAMESPACE_
+
+#elif defined(OS_MACOSX) && defined(HAVE_DLADDR)
+
+#include <dlfcn.h>
+#include <string.h>
+
+_START_GOOGLE_NAMESPACE_
+
+static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
+                                                    int out_size) {
+  Dl_info info;
+  if (dladdr(pc, &info)) {
+    if ((int)strlen(info.dli_sname) < out_size) {
+      strcpy(out, info.dli_sname);
+      // Symbolization succeeded.  Now we try to demangle the symbol.
+      DemangleInplace(out, out_size);
+      return true;
+    }
+  }
+  return false;
+}
+
+_END_GOOGLE_NAMESPACE_
+
+#else
+# error BUG: HAVE_SYMBOLIZE was wrongly set
+#endif
+
+_START_GOOGLE_NAMESPACE_
+
+bool Symbolize(void *pc, char *out, int out_size) {
+  SAFE_ASSERT(out_size >= 0);
+  return SymbolizeAndDemangle(pc, out, out_size);
+}
+
+_END_GOOGLE_NAMESPACE_
+
+#else  /* HAVE_SYMBOLIZE */
+
+#include <assert.h>
+
+#include "config.h"
+
+_START_GOOGLE_NAMESPACE_
+
+// TODO: Support other environments.
+bool Symbolize(void *pc, char *out, int out_size) {
+  assert(0);
+  return false;
+}
+
+_END_GOOGLE_NAMESPACE_
+
+#endif
diff --git a/base/third_party/symbolize/symbolize.h b/base/third_party/symbolize/symbolize.h
new file mode 100644
index 0000000..f617184
--- /dev/null
+++ b/base/third_party/symbolize/symbolize.h
@@ -0,0 +1,155 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: Satoru Takabayashi
+//
+// This library provides Symbolize() function that symbolizes program
+// counters to their corresponding symbol names on linux platforms.
+// This library has a minimal implementation of an ELF symbol table
+// reader (i.e. it doesn't depend on libelf, etc.).
+//
+// The algorithm used in Symbolize() is as follows.
+//
+//   1. Go through a list of maps in /proc/self/maps and find the map
+//   containing the program counter.
+//
+//   2. Open the mapped file and find a regular symbol table inside.
+//   Iterate over symbols in the symbol table and look for the symbol
+//   containing the program counter.  If such a symbol is found,
+//   obtain the symbol name, and demangle the symbol if possible.
+//   If the symbol isn't found in the regular symbol table (binary is
+//   stripped), try the same thing with a dynamic symbol table.
+//
+// Note that Symbolize() is originally implemented to be used in
+// FailureSignalHandler() in base/google.cc.  Hence it doesn't use
+// malloc() and other unsafe operations.  It should be both
+// thread-safe and async-signal-safe.
+
+#ifndef BASE_SYMBOLIZE_H_
+#define BASE_SYMBOLIZE_H_
+
+#include "utilities.h"
+#include "config.h"
+#include "glog/logging.h"
+
+#ifdef HAVE_SYMBOLIZE
+
+#if defined(__ELF__)  // defined by gcc
+#if defined(__OpenBSD__)
+#include <sys/exec_elf.h>
+#else
+#include <elf.h>
+#endif
+
+#if !defined(ANDROID)
+#include <link.h>  // For ElfW() macro.
+#endif
+
+// For systems where SIZEOF_VOID_P is not defined, determine it
+// based on __LP64__ (defined by gcc on 64-bit systems)
+#if !defined(SIZEOF_VOID_P)
+# if defined(__LP64__)
+#  define SIZEOF_VOID_P 8
+# else
+#  define SIZEOF_VOID_P 4
+# endif
+#endif
+
+// If there is no ElfW macro, let's define it by ourself.
+#ifndef ElfW
+# if SIZEOF_VOID_P == 4
+#  define ElfW(type) Elf32_##type
+# elif SIZEOF_VOID_P == 8
+#  define ElfW(type) Elf64_##type
+# else
+#  error "Unknown sizeof(void *)"
+# endif
+#endif
+
+_START_GOOGLE_NAMESPACE_
+
+// Gets the section header for the given name, if it exists. Returns true on
+// success. Otherwise, returns false.
+bool GetSectionHeaderByName(int fd, const char *name, size_t name_len,
+                            ElfW(Shdr) *out);
+
+_END_GOOGLE_NAMESPACE_
+
+#endif  /* __ELF__ */
+
+_START_GOOGLE_NAMESPACE_
+
+// Restrictions on the callbacks that follow:
+//  - The callbacks must not use heaps but only use stacks.
+//  - The callbacks must be async-signal-safe.
+
+// Installs a callback function, which will be called right before a symbol name
+// is printed. The callback is intended to be used for showing a file name and a
+// line number preceding a symbol name.
+// "fd" is a file descriptor of the object file containing the program
+// counter "pc". The callback function should write output to "out"
+// and return the size of the output written. On error, the callback
+// function should return -1.
+typedef int (*SymbolizeCallback)(int fd, void *pc, char *out, size_t out_size,
+                                 uint64 relocation);
+void InstallSymbolizeCallback(SymbolizeCallback callback);
+
+// Installs a callback function, which will be called instead of
+// OpenObjectFileContainingPcAndGetStartAddress.  The callback is expected
+// to searches for the object file (from /proc/self/maps) that contains
+// the specified pc.  If found, sets |start_address| to the start address
+// of where this object file is mapped in memory, sets the module base
+// address into |base_address|, copies the object file name into
+// |out_file_name|, and attempts to open the object file.  If the object
+// file is opened successfully, returns the file descriptor.  Otherwise,
+// returns -1.  |out_file_name_size| is the size of the file name buffer
+// (including the null-terminator).
+typedef int (*SymbolizeOpenObjectFileCallback)(uint64_t pc,
+                                               uint64_t &start_address,
+                                               uint64_t &base_address,
+                                               char *out_file_name,
+                                               int out_file_name_size);
+void InstallSymbolizeOpenObjectFileCallback(
+    SymbolizeOpenObjectFileCallback callback);
+
+_END_GOOGLE_NAMESPACE_
+
+#endif
+
+_START_GOOGLE_NAMESPACE_
+
+// Symbolizes a program counter.  On success, returns true and write the
+// symbol name to "out".  The symbol name is demangled if possible
+// (supports symbols generated by GCC 3.x or newer).  Otherwise,
+// returns false.
+bool Symbolize(void *pc, char *out, int out_size);
+
+_END_GOOGLE_NAMESPACE_
+
+#endif  // BASE_SYMBOLIZE_H_
diff --git a/base/third_party/symbolize/utilities.h b/base/third_party/symbolize/utilities.h
new file mode 100644
index 0000000..0bed526
--- /dev/null
+++ b/base/third_party/symbolize/utilities.h
@@ -0,0 +1,11 @@
+// Copyright (c) 2010 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 <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+typedef uint64_t uint64;
+#define HAVE_SYMBOLIZE 1
+#define ATTRIBUTE_NOINLINE __attribute__ ((noinline))
diff --git a/base/third_party/valgrind/LICENSE b/base/third_party/valgrind/LICENSE
new file mode 100644
index 0000000..41f677b
--- /dev/null
+++ b/base/third_party/valgrind/LICENSE
@@ -0,0 +1,39 @@
+   Notice that the following BSD-style license applies to the Valgrind header
+   files used by Chromium (valgrind.h and memcheck.h). However, the rest of
+   Valgrind is licensed under the terms of the GNU General Public License,
+   version 2, unless otherwise indicated.
+
+   ----------------------------------------------------------------
+
+   Copyright (C) 2000-2008 Julian Seward.  All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   1. Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+   2. The origin of this software must not be misrepresented; you must 
+      not claim that you wrote the original software.  If you use this 
+      software in a product, an acknowledgment in the product 
+      documentation would be appreciated but is not required.
+
+   3. Altered source versions must be plainly marked as such, and must
+      not be misrepresented as being the original software.
+
+   4. The name of the author may not be used to endorse or promote 
+      products derived from this software without specific prior written 
+      permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+   OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+   ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/base/third_party/valgrind/README.chromium b/base/third_party/valgrind/README.chromium
new file mode 100644
index 0000000..56a1cbb
--- /dev/null
+++ b/base/third_party/valgrind/README.chromium
@@ -0,0 +1,11 @@
+Name: valgrind
+URL: http://valgrind.org
+License: BSD
+
+Header files in this directory define runtime macros that determine whether the
+current process is running under Valgrind and tell Memcheck tool about custom
+memory allocators.
+
+These header files were taken from Valgrind source code
+(svn://svn.valgrind.org/valgrind/trunk@11504, dated 21 Jan 2011). The files are
+covered under BSD license as described within.
diff --git a/base/third_party/valgrind/memcheck.h b/base/third_party/valgrind/memcheck.h
new file mode 100644
index 0000000..f59c212
--- /dev/null
+++ b/base/third_party/valgrind/memcheck.h
@@ -0,0 +1,279 @@
+
+/*
+   ----------------------------------------------------------------
+
+   Notice that the following BSD-style license applies to this one
+   file (memcheck.h) only.  The rest of Valgrind is licensed under the
+   terms of the GNU General Public License, version 2, unless
+   otherwise indicated.  See the COPYING file in the source
+   distribution for details.
+
+   ----------------------------------------------------------------
+
+   This file is part of MemCheck, a heavyweight Valgrind tool for
+   detecting memory errors.
+
+   Copyright (C) 2000-2010 Julian Seward.  All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   1. Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+   2. The origin of this software must not be misrepresented; you must 
+      not claim that you wrote the original software.  If you use this 
+      software in a product, an acknowledgment in the product 
+      documentation would be appreciated but is not required.
+
+   3. Altered source versions must be plainly marked as such, and must
+      not be misrepresented as being the original software.
+
+   4. The name of the author may not be used to endorse or promote 
+      products derived from this software without specific prior written 
+      permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+   OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+   ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+   ----------------------------------------------------------------
+
+   Notice that the above BSD-style license applies to this one file
+   (memcheck.h) only.  The entire rest of Valgrind is licensed under
+   the terms of the GNU General Public License, version 2.  See the
+   COPYING file in the source distribution for details.
+
+   ---------------------------------------------------------------- 
+*/
+
+
+#ifndef __MEMCHECK_H
+#define __MEMCHECK_H
+
+
+/* This file is for inclusion into client (your!) code.
+
+   You can use these macros to manipulate and query memory permissions
+   inside your own programs.
+
+   See comment near the top of valgrind.h on how to use them.
+*/
+
+#include "valgrind.h"
+
+/* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !! 
+   This enum comprises an ABI exported by Valgrind to programs
+   which use client requests.  DO NOT CHANGE THE ORDER OF THESE
+   ENTRIES, NOR DELETE ANY -- add new ones at the end. */
+typedef
+   enum { 
+      VG_USERREQ__MAKE_MEM_NOACCESS = VG_USERREQ_TOOL_BASE('M','C'),
+      VG_USERREQ__MAKE_MEM_UNDEFINED,
+      VG_USERREQ__MAKE_MEM_DEFINED,
+      VG_USERREQ__DISCARD,
+      VG_USERREQ__CHECK_MEM_IS_ADDRESSABLE,
+      VG_USERREQ__CHECK_MEM_IS_DEFINED,
+      VG_USERREQ__DO_LEAK_CHECK,
+      VG_USERREQ__COUNT_LEAKS,
+
+      VG_USERREQ__GET_VBITS,
+      VG_USERREQ__SET_VBITS,
+
+      VG_USERREQ__CREATE_BLOCK,
+
+      VG_USERREQ__MAKE_MEM_DEFINED_IF_ADDRESSABLE,
+
+      /* Not next to VG_USERREQ__COUNT_LEAKS because it was added later. */
+      VG_USERREQ__COUNT_LEAK_BLOCKS,
+
+      /* This is just for memcheck's internal use - don't use it */
+      _VG_USERREQ__MEMCHECK_RECORD_OVERLAP_ERROR 
+         = VG_USERREQ_TOOL_BASE('M','C') + 256
+   } Vg_MemCheckClientRequest;
+
+
+
+/* Client-code macros to manipulate the state of memory. */
+
+/* Mark memory at _qzz_addr as unaddressable for _qzz_len bytes. */
+#define VALGRIND_MAKE_MEM_NOACCESS(_qzz_addr,_qzz_len)           \
+    VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */,      \
+                            VG_USERREQ__MAKE_MEM_NOACCESS,       \
+                            (_qzz_addr), (_qzz_len), 0, 0, 0)
+      
+/* Similarly, mark memory at _qzz_addr as addressable but undefined
+   for _qzz_len bytes. */
+#define VALGRIND_MAKE_MEM_UNDEFINED(_qzz_addr,_qzz_len)          \
+    VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */,      \
+                            VG_USERREQ__MAKE_MEM_UNDEFINED,      \
+                            (_qzz_addr), (_qzz_len), 0, 0, 0)
+
+/* Similarly, mark memory at _qzz_addr as addressable and defined
+   for _qzz_len bytes. */
+#define VALGRIND_MAKE_MEM_DEFINED(_qzz_addr,_qzz_len)            \
+    VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */,      \
+                            VG_USERREQ__MAKE_MEM_DEFINED,        \
+                            (_qzz_addr), (_qzz_len), 0, 0, 0)
+
+/* Similar to VALGRIND_MAKE_MEM_DEFINED except that addressability is
+   not altered: bytes which are addressable are marked as defined,
+   but those which are not addressable are left unchanged. */
+#define VALGRIND_MAKE_MEM_DEFINED_IF_ADDRESSABLE(_qzz_addr,_qzz_len)     \
+    VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */,              \
+                            VG_USERREQ__MAKE_MEM_DEFINED_IF_ADDRESSABLE, \
+                            (_qzz_addr), (_qzz_len), 0, 0, 0)
+
+/* Create a block-description handle.  The description is an ascii
+   string which is included in any messages pertaining to addresses
+   within the specified memory range.  Has no other effect on the
+   properties of the memory range. */
+#define VALGRIND_CREATE_BLOCK(_qzz_addr,_qzz_len, _qzz_desc)	   \
+    VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */,        \
+                            VG_USERREQ__CREATE_BLOCK,              \
+                            (_qzz_addr), (_qzz_len), (_qzz_desc),  \
+                            0, 0)
+
+/* Discard a block-description-handle. Returns 1 for an
+   invalid handle, 0 for a valid handle. */
+#define VALGRIND_DISCARD(_qzz_blkindex)                          \
+    VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* default return */,      \
+                            VG_USERREQ__DISCARD,                 \
+                            0, (_qzz_blkindex), 0, 0, 0)
+
+
+/* Client-code macros to check the state of memory. */
+
+/* Check that memory at _qzz_addr is addressable for _qzz_len bytes.
+   If suitable addressibility is not established, Valgrind prints an
+   error message and returns the address of the first offending byte.
+   Otherwise it returns zero. */
+#define VALGRIND_CHECK_MEM_IS_ADDRESSABLE(_qzz_addr,_qzz_len)      \
+    VALGRIND_DO_CLIENT_REQUEST_EXPR(0,                             \
+                            VG_USERREQ__CHECK_MEM_IS_ADDRESSABLE,  \
+                            (_qzz_addr), (_qzz_len), 0, 0, 0)
+
+/* Check that memory at _qzz_addr is addressable and defined for
+   _qzz_len bytes.  If suitable addressibility and definedness are not
+   established, Valgrind prints an error message and returns the
+   address of the first offending byte.  Otherwise it returns zero. */
+#define VALGRIND_CHECK_MEM_IS_DEFINED(_qzz_addr,_qzz_len)        \
+    VALGRIND_DO_CLIENT_REQUEST_EXPR(0,                           \
+                            VG_USERREQ__CHECK_MEM_IS_DEFINED,    \
+                            (_qzz_addr), (_qzz_len), 0, 0, 0)
+
+/* Use this macro to force the definedness and addressibility of an
+   lvalue to be checked.  If suitable addressibility and definedness
+   are not established, Valgrind prints an error message and returns
+   the address of the first offending byte.  Otherwise it returns
+   zero. */
+#define VALGRIND_CHECK_VALUE_IS_DEFINED(__lvalue)                \
+   VALGRIND_CHECK_MEM_IS_DEFINED(                                \
+      (volatile unsigned char *)&(__lvalue),                     \
+                      (unsigned long)(sizeof (__lvalue)))
+
+
+/* Do a full memory leak check (like --leak-check=full) mid-execution. */
+#define VALGRIND_DO_LEAK_CHECK                                   \
+   {unsigned long _qzz_res;                                      \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                      \
+                            VG_USERREQ__DO_LEAK_CHECK,           \
+                            0, 0, 0, 0, 0);                      \
+   }
+
+/* Do a summary memory leak check (like --leak-check=summary) mid-execution. */
+#define VALGRIND_DO_QUICK_LEAK_CHECK				 \
+   {unsigned long _qzz_res;                                      \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                      \
+                            VG_USERREQ__DO_LEAK_CHECK,           \
+                            1, 0, 0, 0, 0);                      \
+   }
+
+/* Return number of leaked, dubious, reachable and suppressed bytes found by
+   all previous leak checks.  They must be lvalues.  */
+#define VALGRIND_COUNT_LEAKS(leaked, dubious, reachable, suppressed)     \
+   /* For safety on 64-bit platforms we assign the results to private
+      unsigned long variables, then assign these to the lvalues the user
+      specified, which works no matter what type 'leaked', 'dubious', etc
+      are.  We also initialise '_qzz_leaked', etc because
+      VG_USERREQ__COUNT_LEAKS doesn't mark the values returned as
+      defined. */                                                        \
+   {unsigned long _qzz_res;                                              \
+    unsigned long _qzz_leaked    = 0, _qzz_dubious    = 0;               \
+    unsigned long _qzz_reachable = 0, _qzz_suppressed = 0;               \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                              \
+                               VG_USERREQ__COUNT_LEAKS,                  \
+                               &_qzz_leaked, &_qzz_dubious,              \
+                               &_qzz_reachable, &_qzz_suppressed, 0);    \
+    leaked     = _qzz_leaked;                                            \
+    dubious    = _qzz_dubious;                                           \
+    reachable  = _qzz_reachable;                                         \
+    suppressed = _qzz_suppressed;                                        \
+   }
+
+/* Return number of leaked, dubious, reachable and suppressed bytes found by
+   all previous leak checks.  They must be lvalues.  */
+#define VALGRIND_COUNT_LEAK_BLOCKS(leaked, dubious, reachable, suppressed) \
+   /* For safety on 64-bit platforms we assign the results to private
+      unsigned long variables, then assign these to the lvalues the user
+      specified, which works no matter what type 'leaked', 'dubious', etc
+      are.  We also initialise '_qzz_leaked', etc because
+      VG_USERREQ__COUNT_LEAKS doesn't mark the values returned as
+      defined. */                                                        \
+   {unsigned long _qzz_res;                                              \
+    unsigned long _qzz_leaked    = 0, _qzz_dubious    = 0;               \
+    unsigned long _qzz_reachable = 0, _qzz_suppressed = 0;               \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                              \
+                               VG_USERREQ__COUNT_LEAK_BLOCKS,            \
+                               &_qzz_leaked, &_qzz_dubious,              \
+                               &_qzz_reachable, &_qzz_suppressed, 0);    \
+    leaked     = _qzz_leaked;                                            \
+    dubious    = _qzz_dubious;                                           \
+    reachable  = _qzz_reachable;                                         \
+    suppressed = _qzz_suppressed;                                        \
+   }
+
+
+/* Get the validity data for addresses [zza..zza+zznbytes-1] and copy it
+   into the provided zzvbits array.  Return values:
+      0   if not running on valgrind
+      1   success
+      2   [previously indicated unaligned arrays;  these are now allowed]
+      3   if any parts of zzsrc/zzvbits are not addressable.
+   The metadata is not copied in cases 0, 2 or 3 so it should be
+   impossible to segfault your system by using this call.
+*/
+#define VALGRIND_GET_VBITS(zza,zzvbits,zznbytes)                \
+    VALGRIND_DO_CLIENT_REQUEST_EXPR(0,                          \
+                                    VG_USERREQ__GET_VBITS,      \
+                                    (const char*)(zza),         \
+                                    (char*)(zzvbits),           \
+                                    (zznbytes), 0, 0)
+
+/* Set the validity data for addresses [zza..zza+zznbytes-1], copying it
+   from the provided zzvbits array.  Return values:
+      0   if not running on valgrind
+      1   success
+      2   [previously indicated unaligned arrays;  these are now allowed]
+      3   if any parts of zza/zzvbits are not addressable.
+   The metadata is not copied in cases 0, 2 or 3 so it should be
+   impossible to segfault your system by using this call.
+*/
+#define VALGRIND_SET_VBITS(zza,zzvbits,zznbytes)                \
+    VALGRIND_DO_CLIENT_REQUEST_EXPR(0,                          \
+                                    VG_USERREQ__SET_VBITS,      \
+                                    (const char*)(zza),         \
+                                    (const char*)(zzvbits),     \
+                                    (zznbytes), 0, 0 )
+
+#endif
+
diff --git a/base/third_party/valgrind/valgrind.h b/base/third_party/valgrind/valgrind.h
new file mode 100644
index 0000000..0bae0aa
--- /dev/null
+++ b/base/third_party/valgrind/valgrind.h
@@ -0,0 +1,4792 @@
+/* -*- c -*-
+   ----------------------------------------------------------------
+
+   Notice that the following BSD-style license applies to this one
+   file (valgrind.h) only.  The rest of Valgrind is licensed under the
+   terms of the GNU General Public License, version 2, unless
+   otherwise indicated.  See the COPYING file in the source
+   distribution for details.
+
+   ----------------------------------------------------------------
+
+   This file is part of Valgrind, a dynamic binary instrumentation
+   framework.
+
+   Copyright (C) 2000-2010 Julian Seward.  All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   1. Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+   2. The origin of this software must not be misrepresented; you must 
+      not claim that you wrote the original software.  If you use this 
+      software in a product, an acknowledgment in the product 
+      documentation would be appreciated but is not required.
+
+   3. Altered source versions must be plainly marked as such, and must
+      not be misrepresented as being the original software.
+
+   4. The name of the author may not be used to endorse or promote 
+      products derived from this software without specific prior written 
+      permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+   OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+   ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+   ----------------------------------------------------------------
+
+   Notice that the above BSD-style license applies to this one file
+   (valgrind.h) only.  The entire rest of Valgrind is licensed under
+   the terms of the GNU General Public License, version 2.  See the
+   COPYING file in the source distribution for details.
+
+   ---------------------------------------------------------------- 
+*/
+
+
+/* This file is for inclusion into client (your!) code.
+
+   You can use these macros to manipulate and query Valgrind's 
+   execution inside your own programs.
+
+   The resulting executables will still run without Valgrind, just a
+   little bit more slowly than they otherwise would, but otherwise
+   unchanged.  When not running on valgrind, each client request
+   consumes very few (eg. 7) instructions, so the resulting performance
+   loss is negligible unless you plan to execute client requests
+   millions of times per second.  Nevertheless, if that is still a
+   problem, you can compile with the NVALGRIND symbol defined (gcc
+   -DNVALGRIND) so that client requests are not even compiled in.  */
+
+#ifndef __VALGRIND_H
+#define __VALGRIND_H
+
+
+/* ------------------------------------------------------------------ */
+/* VERSION NUMBER OF VALGRIND                                         */
+/* ------------------------------------------------------------------ */
+
+/* Specify Valgrind's version number, so that user code can
+   conditionally compile based on our version number.  Note that these
+   were introduced at version 3.6 and so do not exist in version 3.5
+   or earlier.  The recommended way to use them to check for "version
+   X.Y or later" is (eg)
+
+#if defined(__VALGRIND_MAJOR__) && defined(__VALGRIND_MINOR__)   \
+    && (__VALGRIND_MAJOR__ > 3                                   \
+        || (__VALGRIND_MAJOR__ == 3 && __VALGRIND_MINOR__ >= 6))
+*/
+#define __VALGRIND_MAJOR__    3
+#define __VALGRIND_MINOR__    6
+
+
+#include <stdarg.h>
+
+/* Nb: this file might be included in a file compiled with -ansi.  So
+   we can't use C++ style "//" comments nor the "asm" keyword (instead
+   use "__asm__"). */
+
+/* Derive some tags indicating what the target platform is.  Note
+   that in this file we're using the compiler's CPP symbols for
+   identifying architectures, which are different to the ones we use
+   within the rest of Valgrind.  Note, __powerpc__ is active for both
+   32 and 64-bit PPC, whereas __powerpc64__ is only active for the
+   latter (on Linux, that is).
+
+   Misc note: how to find out what's predefined in gcc by default:
+   gcc -Wp,-dM somefile.c
+*/
+#undef PLAT_ppc64_aix5
+#undef PLAT_ppc32_aix5
+#undef PLAT_x86_darwin
+#undef PLAT_amd64_darwin
+#undef PLAT_x86_win32
+#undef PLAT_x86_linux
+#undef PLAT_amd64_linux
+#undef PLAT_ppc32_linux
+#undef PLAT_ppc64_linux
+#undef PLAT_arm_linux
+
+#if defined(_AIX) && defined(__64BIT__)
+#  define PLAT_ppc64_aix5 1
+#elif defined(_AIX) && !defined(__64BIT__)
+#  define PLAT_ppc32_aix5 1
+#elif defined(__APPLE__) && defined(__i386__)
+#  define PLAT_x86_darwin 1
+#elif defined(__APPLE__) && defined(__x86_64__)
+#  define PLAT_amd64_darwin 1
+#elif defined(__MINGW32__) || defined(__CYGWIN32__) || defined(_WIN32) && defined(_M_IX86)
+#  define PLAT_x86_win32 1
+#elif defined(__linux__) && defined(__i386__)
+#  define PLAT_x86_linux 1
+#elif defined(__linux__) && defined(__x86_64__)
+#  define PLAT_amd64_linux 1
+#elif defined(__linux__) && defined(__powerpc__) && !defined(__powerpc64__)
+#  define PLAT_ppc32_linux 1
+#elif defined(__linux__) && defined(__powerpc__) && defined(__powerpc64__)
+#  define PLAT_ppc64_linux 1
+#elif defined(__linux__) && defined(__arm__)
+#  define PLAT_arm_linux 1
+#else
+/* If we're not compiling for our target platform, don't generate
+   any inline asms.  */
+#  if !defined(NVALGRIND)
+#    define NVALGRIND 1
+#  endif
+#endif
+
+
+/* ------------------------------------------------------------------ */
+/* ARCHITECTURE SPECIFICS for SPECIAL INSTRUCTIONS.  There is nothing */
+/* in here of use to end-users -- skip to the next section.           */
+/* ------------------------------------------------------------------ */
+
+#if defined(NVALGRIND)
+
+/* Define NVALGRIND to completely remove the Valgrind magic sequence
+   from the compiled code (analogous to NDEBUG's effects on
+   assert()) */
+#define VALGRIND_DO_CLIENT_REQUEST(                               \
+        _zzq_rlval, _zzq_default, _zzq_request,                   \
+        _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)    \
+   {                                                              \
+      (_zzq_rlval) = (_zzq_default);                              \
+   }
+
+#else  /* ! NVALGRIND */
+
+/* The following defines the magic code sequences which the JITter
+   spots and handles magically.  Don't look too closely at them as
+   they will rot your brain.
+
+   The assembly code sequences for all architectures is in this one
+   file.  This is because this file must be stand-alone, and we don't
+   want to have multiple files.
+
+   For VALGRIND_DO_CLIENT_REQUEST, we must ensure that the default
+   value gets put in the return slot, so that everything works when
+   this is executed not under Valgrind.  Args are passed in a memory
+   block, and so there's no intrinsic limit to the number that could
+   be passed, but it's currently five.
+   
+   The macro args are: 
+      _zzq_rlval    result lvalue
+      _zzq_default  default value (result returned when running on real CPU)
+      _zzq_request  request code
+      _zzq_arg1..5  request params
+
+   The other two macros are used to support function wrapping, and are
+   a lot simpler.  VALGRIND_GET_NR_CONTEXT returns the value of the
+   guest's NRADDR pseudo-register and whatever other information is
+   needed to safely run the call original from the wrapper: on
+   ppc64-linux, the R2 value at the divert point is also needed.  This
+   information is abstracted into a user-visible type, OrigFn.
+
+   VALGRIND_CALL_NOREDIR_* behaves the same as the following on the
+   guest, but guarantees that the branch instruction will not be
+   redirected: x86: call *%eax, amd64: call *%rax, ppc32/ppc64:
+   branch-and-link-to-r11.  VALGRIND_CALL_NOREDIR is just text, not a
+   complete inline asm, since it needs to be combined with more magic
+   inline asm stuff to be useful.
+*/
+
+/* ------------------------- x86-{linux,darwin} ---------------- */
+
+#if defined(PLAT_x86_linux)  ||  defined(PLAT_x86_darwin)  \
+    ||  (defined(PLAT_x86_win32) && defined(__GNUC__))
+
+typedef
+   struct { 
+      unsigned int nraddr; /* where's the code? */
+   }
+   OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE                            \
+                     "roll $3,  %%edi ; roll $13, %%edi\n\t"      \
+                     "roll $29, %%edi ; roll $19, %%edi\n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST(                               \
+        _zzq_rlval, _zzq_default, _zzq_request,                   \
+        _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)    \
+  { volatile unsigned int _zzq_args[6];                           \
+    volatile unsigned int _zzq_result;                            \
+    _zzq_args[0] = (unsigned int)(_zzq_request);                  \
+    _zzq_args[1] = (unsigned int)(_zzq_arg1);                     \
+    _zzq_args[2] = (unsigned int)(_zzq_arg2);                     \
+    _zzq_args[3] = (unsigned int)(_zzq_arg3);                     \
+    _zzq_args[4] = (unsigned int)(_zzq_arg4);                     \
+    _zzq_args[5] = (unsigned int)(_zzq_arg5);                     \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %EDX = client_request ( %EAX ) */         \
+                     "xchgl %%ebx,%%ebx"                          \
+                     : "=d" (_zzq_result)                         \
+                     : "a" (&_zzq_args[0]), "0" (_zzq_default)    \
+                     : "cc", "memory"                             \
+                    );                                            \
+    _zzq_rlval = _zzq_result;                                     \
+  }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval)                       \
+  { volatile OrigFn* _zzq_orig = &(_zzq_rlval);                   \
+    volatile unsigned int __addr;                                 \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %EAX = guest_NRADDR */                    \
+                     "xchgl %%ecx,%%ecx"                          \
+                     : "=a" (__addr)                              \
+                     :                                            \
+                     : "cc", "memory"                             \
+                    );                                            \
+    _zzq_orig->nraddr = __addr;                                   \
+  }
+
+#define VALGRIND_CALL_NOREDIR_EAX                                 \
+                     __SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* call-noredir *%EAX */                     \
+                     "xchgl %%edx,%%edx\n\t"
+#endif /* PLAT_x86_linux || PLAT_x86_darwin || (PLAT_x86_win32 && __GNUC__) */
+
+/* ------------------------- x86-Win32 ------------------------- */
+
+#if defined(PLAT_x86_win32) && !defined(__GNUC__)
+
+typedef
+   struct { 
+      unsigned int nraddr; /* where's the code? */
+   }
+   OrigFn;
+
+#if defined(_MSC_VER)
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE                            \
+                     __asm rol edi, 3  __asm rol edi, 13          \
+                     __asm rol edi, 29 __asm rol edi, 19
+
+#define VALGRIND_DO_CLIENT_REQUEST(                               \
+        _zzq_rlval, _zzq_default, _zzq_request,                   \
+        _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)    \
+  { volatile uintptr_t _zzq_args[6];                              \
+    volatile unsigned int _zzq_result;                            \
+    _zzq_args[0] = (uintptr_t)(_zzq_request);                     \
+    _zzq_args[1] = (uintptr_t)(_zzq_arg1);                        \
+    _zzq_args[2] = (uintptr_t)(_zzq_arg2);                        \
+    _zzq_args[3] = (uintptr_t)(_zzq_arg3);                        \
+    _zzq_args[4] = (uintptr_t)(_zzq_arg4);                        \
+    _zzq_args[5] = (uintptr_t)(_zzq_arg5);                        \
+    __asm { __asm lea eax, _zzq_args __asm mov edx, _zzq_default  \
+            __SPECIAL_INSTRUCTION_PREAMBLE                        \
+            /* %EDX = client_request ( %EAX ) */                  \
+            __asm xchg ebx,ebx                                    \
+            __asm mov _zzq_result, edx                            \
+    }                                                             \
+    _zzq_rlval = _zzq_result;                                     \
+  }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval)                       \
+  { volatile OrigFn* _zzq_orig = &(_zzq_rlval);                   \
+    volatile unsigned int __addr;                                 \
+    __asm { __SPECIAL_INSTRUCTION_PREAMBLE                        \
+            /* %EAX = guest_NRADDR */                             \
+            __asm xchg ecx,ecx                                    \
+            __asm mov __addr, eax                                 \
+    }                                                             \
+    _zzq_orig->nraddr = __addr;                                   \
+  }
+
+#define VALGRIND_CALL_NOREDIR_EAX ERROR
+
+#else
+#error Unsupported compiler.
+#endif
+
+#endif /* PLAT_x86_win32 */
+
+/* ------------------------ amd64-{linux,darwin} --------------- */
+
+#if defined(PLAT_amd64_linux)  ||  defined(PLAT_amd64_darwin)
+
+typedef
+   struct { 
+      unsigned long long int nraddr; /* where's the code? */
+   }
+   OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE                            \
+                     "rolq $3,  %%rdi ; rolq $13, %%rdi\n\t"      \
+                     "rolq $61, %%rdi ; rolq $51, %%rdi\n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST(                               \
+        _zzq_rlval, _zzq_default, _zzq_request,                   \
+        _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)    \
+  { volatile unsigned long long int _zzq_args[6];                 \
+    volatile unsigned long long int _zzq_result;                  \
+    _zzq_args[0] = (unsigned long long int)(_zzq_request);        \
+    _zzq_args[1] = (unsigned long long int)(_zzq_arg1);           \
+    _zzq_args[2] = (unsigned long long int)(_zzq_arg2);           \
+    _zzq_args[3] = (unsigned long long int)(_zzq_arg3);           \
+    _zzq_args[4] = (unsigned long long int)(_zzq_arg4);           \
+    _zzq_args[5] = (unsigned long long int)(_zzq_arg5);           \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %RDX = client_request ( %RAX ) */         \
+                     "xchgq %%rbx,%%rbx"                          \
+                     : "=d" (_zzq_result)                         \
+                     : "a" (&_zzq_args[0]), "0" (_zzq_default)    \
+                     : "cc", "memory"                             \
+                    );                                            \
+    _zzq_rlval = _zzq_result;                                     \
+  }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval)                       \
+  { volatile OrigFn* _zzq_orig = &(_zzq_rlval);                   \
+    volatile unsigned long long int __addr;                       \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %RAX = guest_NRADDR */                    \
+                     "xchgq %%rcx,%%rcx"                          \
+                     : "=a" (__addr)                              \
+                     :                                            \
+                     : "cc", "memory"                             \
+                    );                                            \
+    _zzq_orig->nraddr = __addr;                                   \
+  }
+
+#define VALGRIND_CALL_NOREDIR_RAX                                 \
+                     __SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* call-noredir *%RAX */                     \
+                     "xchgq %%rdx,%%rdx\n\t"
+#endif /* PLAT_amd64_linux || PLAT_amd64_darwin */
+
+/* ------------------------ ppc32-linux ------------------------ */
+
+#if defined(PLAT_ppc32_linux)
+
+typedef
+   struct { 
+      unsigned int nraddr; /* where's the code? */
+   }
+   OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE                            \
+                     "rlwinm 0,0,3,0,0  ; rlwinm 0,0,13,0,0\n\t"  \
+                     "rlwinm 0,0,29,0,0 ; rlwinm 0,0,19,0,0\n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST(                               \
+        _zzq_rlval, _zzq_default, _zzq_request,                   \
+        _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)    \
+                                                                  \
+  {          unsigned int  _zzq_args[6];                          \
+             unsigned int  _zzq_result;                           \
+             unsigned int* _zzq_ptr;                              \
+    _zzq_args[0] = (unsigned int)(_zzq_request);                  \
+    _zzq_args[1] = (unsigned int)(_zzq_arg1);                     \
+    _zzq_args[2] = (unsigned int)(_zzq_arg2);                     \
+    _zzq_args[3] = (unsigned int)(_zzq_arg3);                     \
+    _zzq_args[4] = (unsigned int)(_zzq_arg4);                     \
+    _zzq_args[5] = (unsigned int)(_zzq_arg5);                     \
+    _zzq_ptr = _zzq_args;                                         \
+    __asm__ volatile("mr 3,%1\n\t" /*default*/                    \
+                     "mr 4,%2\n\t" /*ptr*/                        \
+                     __SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %R3 = client_request ( %R4 ) */           \
+                     "or 1,1,1\n\t"                               \
+                     "mr %0,3"     /*result*/                     \
+                     : "=b" (_zzq_result)                         \
+                     : "b" (_zzq_default), "b" (_zzq_ptr)         \
+                     : "cc", "memory", "r3", "r4");               \
+    _zzq_rlval = _zzq_result;                                     \
+  }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval)                       \
+  { volatile OrigFn* _zzq_orig = &(_zzq_rlval);                   \
+    unsigned int __addr;                                          \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %R3 = guest_NRADDR */                     \
+                     "or 2,2,2\n\t"                               \
+                     "mr %0,3"                                    \
+                     : "=b" (__addr)                              \
+                     :                                            \
+                     : "cc", "memory", "r3"                       \
+                    );                                            \
+    _zzq_orig->nraddr = __addr;                                   \
+  }
+
+#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                   \
+                     __SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* branch-and-link-to-noredir *%R11 */       \
+                     "or 3,3,3\n\t"
+#endif /* PLAT_ppc32_linux */
+
+/* ------------------------ ppc64-linux ------------------------ */
+
+#if defined(PLAT_ppc64_linux)
+
+typedef
+   struct { 
+      unsigned long long int nraddr; /* where's the code? */
+      unsigned long long int r2;  /* what tocptr do we need? */
+   }
+   OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE                            \
+                     "rotldi 0,0,3  ; rotldi 0,0,13\n\t"          \
+                     "rotldi 0,0,61 ; rotldi 0,0,51\n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST(                               \
+        _zzq_rlval, _zzq_default, _zzq_request,                   \
+        _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)    \
+                                                                  \
+  {          unsigned long long int  _zzq_args[6];                \
+    register unsigned long long int  _zzq_result __asm__("r3");   \
+    register unsigned long long int* _zzq_ptr __asm__("r4");      \
+    _zzq_args[0] = (unsigned long long int)(_zzq_request);        \
+    _zzq_args[1] = (unsigned long long int)(_zzq_arg1);           \
+    _zzq_args[2] = (unsigned long long int)(_zzq_arg2);           \
+    _zzq_args[3] = (unsigned long long int)(_zzq_arg3);           \
+    _zzq_args[4] = (unsigned long long int)(_zzq_arg4);           \
+    _zzq_args[5] = (unsigned long long int)(_zzq_arg5);           \
+    _zzq_ptr = _zzq_args;                                         \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %R3 = client_request ( %R4 ) */           \
+                     "or 1,1,1"                                   \
+                     : "=r" (_zzq_result)                         \
+                     : "0" (_zzq_default), "r" (_zzq_ptr)         \
+                     : "cc", "memory");                           \
+    _zzq_rlval = _zzq_result;                                     \
+  }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval)                       \
+  { volatile OrigFn* _zzq_orig = &(_zzq_rlval);                   \
+    register unsigned long long int __addr __asm__("r3");         \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %R3 = guest_NRADDR */                     \
+                     "or 2,2,2"                                   \
+                     : "=r" (__addr)                              \
+                     :                                            \
+                     : "cc", "memory"                             \
+                    );                                            \
+    _zzq_orig->nraddr = __addr;                                   \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %R3 = guest_NRADDR_GPR2 */                \
+                     "or 4,4,4"                                   \
+                     : "=r" (__addr)                              \
+                     :                                            \
+                     : "cc", "memory"                             \
+                    );                                            \
+    _zzq_orig->r2 = __addr;                                       \
+  }
+
+#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                   \
+                     __SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* branch-and-link-to-noredir *%R11 */       \
+                     "or 3,3,3\n\t"
+
+#endif /* PLAT_ppc64_linux */
+
+/* ------------------------- arm-linux ------------------------- */
+
+#if defined(PLAT_arm_linux)
+
+typedef
+   struct { 
+      unsigned int nraddr; /* where's the code? */
+   }
+   OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE                            \
+            "mov r12, r12, ror #3  ; mov r12, r12, ror #13 \n\t"  \
+            "mov r12, r12, ror #29 ; mov r12, r12, ror #19 \n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST(                               \
+        _zzq_rlval, _zzq_default, _zzq_request,                   \
+        _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)    \
+                                                                  \
+  { volatile unsigned int  _zzq_args[6];                          \
+    volatile unsigned int  _zzq_result;                           \
+    _zzq_args[0] = (unsigned int)(_zzq_request);                  \
+    _zzq_args[1] = (unsigned int)(_zzq_arg1);                     \
+    _zzq_args[2] = (unsigned int)(_zzq_arg2);                     \
+    _zzq_args[3] = (unsigned int)(_zzq_arg3);                     \
+    _zzq_args[4] = (unsigned int)(_zzq_arg4);                     \
+    _zzq_args[5] = (unsigned int)(_zzq_arg5);                     \
+    __asm__ volatile("mov r3, %1\n\t" /*default*/                 \
+                     "mov r4, %2\n\t" /*ptr*/                     \
+                     __SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* R3 = client_request ( R4 ) */             \
+                     "orr r10, r10, r10\n\t"                      \
+                     "mov %0, r3"     /*result*/                  \
+                     : "=r" (_zzq_result)                         \
+                     : "r" (_zzq_default), "r" (&_zzq_args[0])    \
+                     : "cc","memory", "r3", "r4");                \
+    _zzq_rlval = _zzq_result;                                     \
+  }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval)                       \
+  { volatile OrigFn* _zzq_orig = &(_zzq_rlval);                   \
+    unsigned int __addr;                                          \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* R3 = guest_NRADDR */                      \
+                     "orr r11, r11, r11\n\t"                      \
+                     "mov %0, r3"                                 \
+                     : "=r" (__addr)                              \
+                     :                                            \
+                     : "cc", "memory", "r3"                       \
+                    );                                            \
+    _zzq_orig->nraddr = __addr;                                   \
+  }
+
+#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                    \
+                     __SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* branch-and-link-to-noredir *%R4 */        \
+                     "orr r12, r12, r12\n\t"
+
+#endif /* PLAT_arm_linux */
+
+/* ------------------------ ppc32-aix5 ------------------------- */
+
+#if defined(PLAT_ppc32_aix5)
+
+typedef
+   struct { 
+      unsigned int nraddr; /* where's the code? */
+      unsigned int r2;  /* what tocptr do we need? */
+   }
+   OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE                            \
+                     "rlwinm 0,0,3,0,0  ; rlwinm 0,0,13,0,0\n\t"  \
+                     "rlwinm 0,0,29,0,0 ; rlwinm 0,0,19,0,0\n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST(                               \
+        _zzq_rlval, _zzq_default, _zzq_request,                   \
+        _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)    \
+                                                                  \
+  {          unsigned int  _zzq_args[7];                          \
+    register unsigned int  _zzq_result;                           \
+    register unsigned int* _zzq_ptr;                              \
+    _zzq_args[0] = (unsigned int)(_zzq_request);                  \
+    _zzq_args[1] = (unsigned int)(_zzq_arg1);                     \
+    _zzq_args[2] = (unsigned int)(_zzq_arg2);                     \
+    _zzq_args[3] = (unsigned int)(_zzq_arg3);                     \
+    _zzq_args[4] = (unsigned int)(_zzq_arg4);                     \
+    _zzq_args[5] = (unsigned int)(_zzq_arg5);                     \
+    _zzq_args[6] = (unsigned int)(_zzq_default);                  \
+    _zzq_ptr = _zzq_args;                                         \
+    __asm__ volatile("mr 4,%1\n\t"                                \
+                     "lwz 3, 24(4)\n\t"                           \
+                     __SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %R3 = client_request ( %R4 ) */           \
+                     "or 1,1,1\n\t"                               \
+                     "mr %0,3"                                    \
+                     : "=b" (_zzq_result)                         \
+                     : "b" (_zzq_ptr)                             \
+                     : "r3", "r4", "cc", "memory");               \
+    _zzq_rlval = _zzq_result;                                     \
+  }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval)                       \
+  { volatile OrigFn* _zzq_orig = &(_zzq_rlval);                   \
+    register unsigned int __addr;                                 \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %R3 = guest_NRADDR */                     \
+                     "or 2,2,2\n\t"                               \
+                     "mr %0,3"                                    \
+                     : "=b" (__addr)                              \
+                     :                                            \
+                     : "r3", "cc", "memory"                       \
+                    );                                            \
+    _zzq_orig->nraddr = __addr;                                   \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %R3 = guest_NRADDR_GPR2 */                \
+                     "or 4,4,4\n\t"                               \
+                     "mr %0,3"                                    \
+                     : "=b" (__addr)                              \
+                     :                                            \
+                     : "r3", "cc", "memory"                       \
+                    );                                            \
+    _zzq_orig->r2 = __addr;                                       \
+  }
+
+#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                   \
+                     __SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* branch-and-link-to-noredir *%R11 */       \
+                     "or 3,3,3\n\t"
+
+#endif /* PLAT_ppc32_aix5 */
+
+/* ------------------------ ppc64-aix5 ------------------------- */
+
+#if defined(PLAT_ppc64_aix5)
+
+typedef
+   struct { 
+      unsigned long long int nraddr; /* where's the code? */
+      unsigned long long int r2;  /* what tocptr do we need? */
+   }
+   OrigFn;
+
+#define __SPECIAL_INSTRUCTION_PREAMBLE                            \
+                     "rotldi 0,0,3  ; rotldi 0,0,13\n\t"          \
+                     "rotldi 0,0,61 ; rotldi 0,0,51\n\t"
+
+#define VALGRIND_DO_CLIENT_REQUEST(                               \
+        _zzq_rlval, _zzq_default, _zzq_request,                   \
+        _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)    \
+                                                                  \
+  {          unsigned long long int  _zzq_args[7];                \
+    register unsigned long long int  _zzq_result;                 \
+    register unsigned long long int* _zzq_ptr;                    \
+    _zzq_args[0] = (unsigned int long long)(_zzq_request);        \
+    _zzq_args[1] = (unsigned int long long)(_zzq_arg1);           \
+    _zzq_args[2] = (unsigned int long long)(_zzq_arg2);           \
+    _zzq_args[3] = (unsigned int long long)(_zzq_arg3);           \
+    _zzq_args[4] = (unsigned int long long)(_zzq_arg4);           \
+    _zzq_args[5] = (unsigned int long long)(_zzq_arg5);           \
+    _zzq_args[6] = (unsigned int long long)(_zzq_default);        \
+    _zzq_ptr = _zzq_args;                                         \
+    __asm__ volatile("mr 4,%1\n\t"                                \
+                     "ld 3, 48(4)\n\t"                            \
+                     __SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %R3 = client_request ( %R4 ) */           \
+                     "or 1,1,1\n\t"                               \
+                     "mr %0,3"                                    \
+                     : "=b" (_zzq_result)                         \
+                     : "b" (_zzq_ptr)                             \
+                     : "r3", "r4", "cc", "memory");               \
+    _zzq_rlval = _zzq_result;                                     \
+  }
+
+#define VALGRIND_GET_NR_CONTEXT(_zzq_rlval)                       \
+  { volatile OrigFn* _zzq_orig = &(_zzq_rlval);                   \
+    register unsigned long long int __addr;                       \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %R3 = guest_NRADDR */                     \
+                     "or 2,2,2\n\t"                               \
+                     "mr %0,3"                                    \
+                     : "=b" (__addr)                              \
+                     :                                            \
+                     : "r3", "cc", "memory"                       \
+                    );                                            \
+    _zzq_orig->nraddr = __addr;                                   \
+    __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* %R3 = guest_NRADDR_GPR2 */                \
+                     "or 4,4,4\n\t"                               \
+                     "mr %0,3"                                    \
+                     : "=b" (__addr)                              \
+                     :                                            \
+                     : "r3", "cc", "memory"                       \
+                    );                                            \
+    _zzq_orig->r2 = __addr;                                       \
+  }
+
+#define VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                   \
+                     __SPECIAL_INSTRUCTION_PREAMBLE               \
+                     /* branch-and-link-to-noredir *%R11 */       \
+                     "or 3,3,3\n\t"
+
+#endif /* PLAT_ppc64_aix5 */
+
+/* Insert assembly code for other platforms here... */
+
+#endif /* NVALGRIND */
+
+
+/* ------------------------------------------------------------------ */
+/* PLATFORM SPECIFICS for FUNCTION WRAPPING.  This is all very        */
+/* ugly.  It's the least-worst tradeoff I can think of.               */
+/* ------------------------------------------------------------------ */
+
+/* This section defines magic (a.k.a appalling-hack) macros for doing
+   guaranteed-no-redirection macros, so as to get from function
+   wrappers to the functions they are wrapping.  The whole point is to
+   construct standard call sequences, but to do the call itself with a
+   special no-redirect call pseudo-instruction that the JIT
+   understands and handles specially.  This section is long and
+   repetitious, and I can't see a way to make it shorter.
+
+   The naming scheme is as follows:
+
+      CALL_FN_{W,v}_{v,W,WW,WWW,WWWW,5W,6W,7W,etc}
+
+   'W' stands for "word" and 'v' for "void".  Hence there are
+   different macros for calling arity 0, 1, 2, 3, 4, etc, functions,
+   and for each, the possibility of returning a word-typed result, or
+   no result.
+*/
+
+/* Use these to write the name of your wrapper.  NOTE: duplicates
+   VG_WRAP_FUNCTION_Z{U,Z} in pub_tool_redir.h. */
+
+/* Use an extra level of macroisation so as to ensure the soname/fnname
+   args are fully macro-expanded before pasting them together. */
+#define VG_CONCAT4(_aa,_bb,_cc,_dd) _aa##_bb##_cc##_dd
+
+#define I_WRAP_SONAME_FNNAME_ZU(soname,fnname)                    \
+   VG_CONCAT4(_vgwZU_,soname,_,fnname)
+
+#define I_WRAP_SONAME_FNNAME_ZZ(soname,fnname)                    \
+   VG_CONCAT4(_vgwZZ_,soname,_,fnname)
+
+/* Use this macro from within a wrapper function to collect the
+   context (address and possibly other info) of the original function.
+   Once you have that you can then use it in one of the CALL_FN_
+   macros.  The type of the argument _lval is OrigFn. */
+#define VALGRIND_GET_ORIG_FN(_lval)  VALGRIND_GET_NR_CONTEXT(_lval)
+
+/* Derivatives of the main macros below, for calling functions
+   returning void. */
+
+#define CALL_FN_v_v(fnptr)                                        \
+   do { volatile unsigned long _junk;                             \
+        CALL_FN_W_v(_junk,fnptr); } while (0)
+
+#define CALL_FN_v_W(fnptr, arg1)                                  \
+   do { volatile unsigned long _junk;                             \
+        CALL_FN_W_W(_junk,fnptr,arg1); } while (0)
+
+#define CALL_FN_v_WW(fnptr, arg1,arg2)                            \
+   do { volatile unsigned long _junk;                             \
+        CALL_FN_W_WW(_junk,fnptr,arg1,arg2); } while (0)
+
+#define CALL_FN_v_WWW(fnptr, arg1,arg2,arg3)                      \
+   do { volatile unsigned long _junk;                             \
+        CALL_FN_W_WWW(_junk,fnptr,arg1,arg2,arg3); } while (0)
+
+#define CALL_FN_v_WWWW(fnptr, arg1,arg2,arg3,arg4)                \
+   do { volatile unsigned long _junk;                             \
+        CALL_FN_W_WWWW(_junk,fnptr,arg1,arg2,arg3,arg4); } while (0)
+
+#define CALL_FN_v_5W(fnptr, arg1,arg2,arg3,arg4,arg5)             \
+   do { volatile unsigned long _junk;                             \
+        CALL_FN_W_5W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5); } while (0)
+
+#define CALL_FN_v_6W(fnptr, arg1,arg2,arg3,arg4,arg5,arg6)        \
+   do { volatile unsigned long _junk;                             \
+        CALL_FN_W_6W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5,arg6); } while (0)
+
+#define CALL_FN_v_7W(fnptr, arg1,arg2,arg3,arg4,arg5,arg6,arg7)   \
+   do { volatile unsigned long _junk;                             \
+        CALL_FN_W_7W(_junk,fnptr,arg1,arg2,arg3,arg4,arg5,arg6,arg7); } while (0)
+
+/* ------------------------- x86-{linux,darwin} ---------------- */
+
+#if defined(PLAT_x86_linux)  ||  defined(PLAT_x86_darwin)
+
+/* These regs are trashed by the hidden call.  No need to mention eax
+   as gcc can already see that, plus causes gcc to bomb. */
+#define __CALLER_SAVED_REGS /*"eax"*/ "ecx", "edx"
+
+/* These CALL_FN_ macros assume that on x86-linux, sizeof(unsigned
+   long) == 4. */
+
+#define CALL_FN_W_v(lval, orig)                                   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[1];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      __asm__ volatile(                                           \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1)                             \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[2];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      __asm__ volatile(                                           \
+         "subl $12, %%esp\n\t"                                    \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $16, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      __asm__ volatile(                                           \
+         "subl $8, %%esp\n\t"                                     \
+         "pushl 8(%%eax)\n\t"                                     \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $16, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3)                 \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[4];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      __asm__ volatile(                                           \
+         "subl $4, %%esp\n\t"                                     \
+         "pushl 12(%%eax)\n\t"                                    \
+         "pushl 8(%%eax)\n\t"                                     \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $16, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[5];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      __asm__ volatile(                                           \
+         "pushl 16(%%eax)\n\t"                                    \
+         "pushl 12(%%eax)\n\t"                                    \
+         "pushl 8(%%eax)\n\t"                                     \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $16, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5)        \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[6];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      __asm__ volatile(                                           \
+         "subl $12, %%esp\n\t"                                    \
+         "pushl 20(%%eax)\n\t"                                    \
+         "pushl 16(%%eax)\n\t"                                    \
+         "pushl 12(%%eax)\n\t"                                    \
+         "pushl 8(%%eax)\n\t"                                     \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $32, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6)   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[7];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      __asm__ volatile(                                           \
+         "subl $8, %%esp\n\t"                                     \
+         "pushl 24(%%eax)\n\t"                                    \
+         "pushl 20(%%eax)\n\t"                                    \
+         "pushl 16(%%eax)\n\t"                                    \
+         "pushl 12(%%eax)\n\t"                                    \
+         "pushl 8(%%eax)\n\t"                                     \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $32, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7)                            \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[8];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      __asm__ volatile(                                           \
+         "subl $4, %%esp\n\t"                                     \
+         "pushl 28(%%eax)\n\t"                                    \
+         "pushl 24(%%eax)\n\t"                                    \
+         "pushl 20(%%eax)\n\t"                                    \
+         "pushl 16(%%eax)\n\t"                                    \
+         "pushl 12(%%eax)\n\t"                                    \
+         "pushl 8(%%eax)\n\t"                                     \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $32, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[9];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      __asm__ volatile(                                           \
+         "pushl 32(%%eax)\n\t"                                    \
+         "pushl 28(%%eax)\n\t"                                    \
+         "pushl 24(%%eax)\n\t"                                    \
+         "pushl 20(%%eax)\n\t"                                    \
+         "pushl 16(%%eax)\n\t"                                    \
+         "pushl 12(%%eax)\n\t"                                    \
+         "pushl 8(%%eax)\n\t"                                     \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $32, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8,arg9)                  \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[10];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      __asm__ volatile(                                           \
+         "subl $12, %%esp\n\t"                                    \
+         "pushl 36(%%eax)\n\t"                                    \
+         "pushl 32(%%eax)\n\t"                                    \
+         "pushl 28(%%eax)\n\t"                                    \
+         "pushl 24(%%eax)\n\t"                                    \
+         "pushl 20(%%eax)\n\t"                                    \
+         "pushl 16(%%eax)\n\t"                                    \
+         "pushl 12(%%eax)\n\t"                                    \
+         "pushl 8(%%eax)\n\t"                                     \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $48, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[11];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      _argvec[10] = (unsigned long)(arg10);                       \
+      __asm__ volatile(                                           \
+         "subl $8, %%esp\n\t"                                     \
+         "pushl 40(%%eax)\n\t"                                    \
+         "pushl 36(%%eax)\n\t"                                    \
+         "pushl 32(%%eax)\n\t"                                    \
+         "pushl 28(%%eax)\n\t"                                    \
+         "pushl 24(%%eax)\n\t"                                    \
+         "pushl 20(%%eax)\n\t"                                    \
+         "pushl 16(%%eax)\n\t"                                    \
+         "pushl 12(%%eax)\n\t"                                    \
+         "pushl 8(%%eax)\n\t"                                     \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $48, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,       \
+                                  arg6,arg7,arg8,arg9,arg10,      \
+                                  arg11)                          \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[12];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      _argvec[10] = (unsigned long)(arg10);                       \
+      _argvec[11] = (unsigned long)(arg11);                       \
+      __asm__ volatile(                                           \
+         "subl $4, %%esp\n\t"                                     \
+         "pushl 44(%%eax)\n\t"                                    \
+         "pushl 40(%%eax)\n\t"                                    \
+         "pushl 36(%%eax)\n\t"                                    \
+         "pushl 32(%%eax)\n\t"                                    \
+         "pushl 28(%%eax)\n\t"                                    \
+         "pushl 24(%%eax)\n\t"                                    \
+         "pushl 20(%%eax)\n\t"                                    \
+         "pushl 16(%%eax)\n\t"                                    \
+         "pushl 12(%%eax)\n\t"                                    \
+         "pushl 8(%%eax)\n\t"                                     \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $48, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,       \
+                                  arg6,arg7,arg8,arg9,arg10,      \
+                                  arg11,arg12)                    \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[13];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      _argvec[10] = (unsigned long)(arg10);                       \
+      _argvec[11] = (unsigned long)(arg11);                       \
+      _argvec[12] = (unsigned long)(arg12);                       \
+      __asm__ volatile(                                           \
+         "pushl 48(%%eax)\n\t"                                    \
+         "pushl 44(%%eax)\n\t"                                    \
+         "pushl 40(%%eax)\n\t"                                    \
+         "pushl 36(%%eax)\n\t"                                    \
+         "pushl 32(%%eax)\n\t"                                    \
+         "pushl 28(%%eax)\n\t"                                    \
+         "pushl 24(%%eax)\n\t"                                    \
+         "pushl 20(%%eax)\n\t"                                    \
+         "pushl 16(%%eax)\n\t"                                    \
+         "pushl 12(%%eax)\n\t"                                    \
+         "pushl 8(%%eax)\n\t"                                     \
+         "pushl 4(%%eax)\n\t"                                     \
+         "movl (%%eax), %%eax\n\t"  /* target->%eax */            \
+         VALGRIND_CALL_NOREDIR_EAX                                \
+         "addl $48, %%esp\n"                                      \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#endif /* PLAT_x86_linux || PLAT_x86_darwin */
+
+/* ------------------------ amd64-{linux,darwin} --------------- */
+
+#if defined(PLAT_amd64_linux)  ||  defined(PLAT_amd64_darwin)
+
+/* ARGREGS: rdi rsi rdx rcx r8 r9 (the rest on stack in R-to-L order) */
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS /*"rax",*/ "rcx", "rdx", "rsi",       \
+                            "rdi", "r8", "r9", "r10", "r11"
+
+/* This is all pretty complex.  It's so as to make stack unwinding
+   work reliably.  See bug 243270.  The basic problem is the sub and
+   add of 128 of %rsp in all of the following macros.  If gcc believes
+   the CFA is in %rsp, then unwinding may fail, because what's at the
+   CFA is not what gcc "expected" when it constructs the CFIs for the
+   places where the macros are instantiated.
+
+   But we can't just add a CFI annotation to increase the CFA offset
+   by 128, to match the sub of 128 from %rsp, because we don't know
+   whether gcc has chosen %rsp as the CFA at that point, or whether it
+   has chosen some other register (eg, %rbp).  In the latter case,
+   adding a CFI annotation to change the CFA offset is simply wrong.
+
+   So the solution is to get hold of the CFA using
+   __builtin_dwarf_cfa(), put it in a known register, and add a
+   CFI annotation to say what the register is.  We choose %rbp for
+   this (perhaps perversely), because:
+
+   (1) %rbp is already subject to unwinding.  If a new register was
+       chosen then the unwinder would have to unwind it in all stack
+       traces, which is expensive, and
+
+   (2) %rbp is already subject to precise exception updates in the
+       JIT.  If a new register was chosen, we'd have to have precise
+       exceptions for it too, which reduces performance of the
+       generated code.
+
+   However .. one extra complication.  We can't just whack the result
+   of __builtin_dwarf_cfa() into %rbp and then add %rbp to the
+   list of trashed registers at the end of the inline assembly
+   fragments; gcc won't allow %rbp to appear in that list.  Hence
+   instead we need to stash %rbp in %r15 for the duration of the asm,
+   and say that %r15 is trashed instead.  gcc seems happy to go with
+   that.
+
+   Oh .. and this all needs to be conditionalised so that it is
+   unchanged from before this commit, when compiled with older gccs
+   that don't support __builtin_dwarf_cfa.  Furthermore, since
+   this header file is freestanding, it has to be independent of
+   config.h, and so the following conditionalisation cannot depend on
+   configure time checks.
+
+   Although it's not clear from
+   'defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM)',
+   this expression excludes Darwin.
+   .cfi directives in Darwin assembly appear to be completely
+   different and I haven't investigated how they work.
+
+   For even more entertainment value, note we have to use the
+   completely undocumented __builtin_dwarf_cfa(), which appears to
+   really compute the CFA, whereas __builtin_frame_address(0) claims
+   to but actually doesn't.  See
+   https://bugs.kde.org/show_bug.cgi?id=243270#c47
+*/
+#if defined(__GNUC__) && defined(__GCC_HAVE_DWARF2_CFI_ASM)
+#  define __FRAME_POINTER                                         \
+      ,"r"(__builtin_dwarf_cfa())
+#  define VALGRIND_CFI_PROLOGUE                                   \
+      "movq %%rbp, %%r15\n\t"                                     \
+      "movq %2, %%rbp\n\t"                                        \
+      ".cfi_remember_state\n\t"                                   \
+      ".cfi_def_cfa rbp, 0\n\t"
+#  define VALGRIND_CFI_EPILOGUE                                   \
+      "movq %%r15, %%rbp\n\t"                                     \
+      ".cfi_restore_state\n\t"
+#else
+#  define __FRAME_POINTER
+#  define VALGRIND_CFI_PROLOGUE
+#  define VALGRIND_CFI_EPILOGUE
+#endif
+
+
+/* These CALL_FN_ macros assume that on amd64-linux, sizeof(unsigned
+   long) == 8. */
+
+/* NB 9 Sept 07.  There is a nasty kludge here in all these CALL_FN_
+   macros.  In order not to trash the stack redzone, we need to drop
+   %rsp by 128 before the hidden call, and restore afterwards.  The
+   nastyness is that it is only by luck that the stack still appears
+   to be unwindable during the hidden call - since then the behaviour
+   of any routine using this macro does not match what the CFI data
+   says.  Sigh.
+
+   Why is this important?  Imagine that a wrapper has a stack
+   allocated local, and passes to the hidden call, a pointer to it.
+   Because gcc does not know about the hidden call, it may allocate
+   that local in the redzone.  Unfortunately the hidden call may then
+   trash it before it comes to use it.  So we must step clear of the
+   redzone, for the duration of the hidden call, to make it safe.
+
+   Probably the same problem afflicts the other redzone-style ABIs too
+   (ppc64-linux, ppc32-aix5, ppc64-aix5); but for those, the stack is
+   self describing (none of this CFI nonsense) so at least messing
+   with the stack pointer doesn't give a danger of non-unwindable
+   stack. */
+
+#define CALL_FN_W_v(lval, orig)                                   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[1];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      __asm__ volatile(                                           \
+         VALGRIND_CFI_PROLOGUE                                    \
+         "subq $128,%%rsp\n\t"                                    \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $128,%%rsp\n\t"                                    \
+         VALGRIND_CFI_EPILOGUE                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0]) __FRAME_POINTER            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15"   \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1)                             \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[2];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      __asm__ volatile(                                           \
+         VALGRIND_CFI_PROLOGUE                                    \
+         "subq $128,%%rsp\n\t"                                    \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $128,%%rsp\n\t"                                    \
+         VALGRIND_CFI_EPILOGUE                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0]) __FRAME_POINTER            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15"   \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      __asm__ volatile(                                           \
+         VALGRIND_CFI_PROLOGUE                                    \
+         "subq $128,%%rsp\n\t"                                    \
+         "movq 16(%%rax), %%rsi\n\t"                              \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $128,%%rsp\n\t"                                    \
+         VALGRIND_CFI_EPILOGUE                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0]) __FRAME_POINTER            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15"   \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3)                 \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[4];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      __asm__ volatile(                                           \
+         VALGRIND_CFI_PROLOGUE                                    \
+         "subq $128,%%rsp\n\t"                                    \
+         "movq 24(%%rax), %%rdx\n\t"                              \
+         "movq 16(%%rax), %%rsi\n\t"                              \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $128,%%rsp\n\t"                                    \
+         VALGRIND_CFI_EPILOGUE                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0]) __FRAME_POINTER            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15"   \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[5];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      __asm__ volatile(                                           \
+         VALGRIND_CFI_PROLOGUE                                    \
+         "subq $128,%%rsp\n\t"                                    \
+         "movq 32(%%rax), %%rcx\n\t"                              \
+         "movq 24(%%rax), %%rdx\n\t"                              \
+         "movq 16(%%rax), %%rsi\n\t"                              \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $128,%%rsp\n\t"                                    \
+         VALGRIND_CFI_EPILOGUE                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0]) __FRAME_POINTER            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15"   \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5)        \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[6];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      __asm__ volatile(                                           \
+         VALGRIND_CFI_PROLOGUE                                    \
+         "subq $128,%%rsp\n\t"                                    \
+         "movq 40(%%rax), %%r8\n\t"                               \
+         "movq 32(%%rax), %%rcx\n\t"                              \
+         "movq 24(%%rax), %%rdx\n\t"                              \
+         "movq 16(%%rax), %%rsi\n\t"                              \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $128,%%rsp\n\t"                                    \
+         VALGRIND_CFI_EPILOGUE                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0]) __FRAME_POINTER            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15"   \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6)   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[7];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      __asm__ volatile(                                           \
+         VALGRIND_CFI_PROLOGUE                                    \
+         "subq $128,%%rsp\n\t"                                    \
+         "movq 48(%%rax), %%r9\n\t"                               \
+         "movq 40(%%rax), %%r8\n\t"                               \
+         "movq 32(%%rax), %%rcx\n\t"                              \
+         "movq 24(%%rax), %%rdx\n\t"                              \
+         "movq 16(%%rax), %%rsi\n\t"                              \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $128,%%rsp\n\t"                                    \
+         VALGRIND_CFI_EPILOGUE                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0]) __FRAME_POINTER            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15"   \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7)                            \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[8];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      __asm__ volatile(                                           \
+         VALGRIND_CFI_PROLOGUE                                    \
+         "subq $136,%%rsp\n\t"                                    \
+         "pushq 56(%%rax)\n\t"                                    \
+         "movq 48(%%rax), %%r9\n\t"                               \
+         "movq 40(%%rax), %%r8\n\t"                               \
+         "movq 32(%%rax), %%rcx\n\t"                              \
+         "movq 24(%%rax), %%rdx\n\t"                              \
+         "movq 16(%%rax), %%rsi\n\t"                              \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $8, %%rsp\n"                                       \
+         "addq $136,%%rsp\n\t"                                    \
+         VALGRIND_CFI_EPILOGUE                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0]) __FRAME_POINTER            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15"   \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[9];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      __asm__ volatile(                                           \
+         VALGRIND_CFI_PROLOGUE                                    \
+         "subq $128,%%rsp\n\t"                                    \
+         "pushq 64(%%rax)\n\t"                                    \
+         "pushq 56(%%rax)\n\t"                                    \
+         "movq 48(%%rax), %%r9\n\t"                               \
+         "movq 40(%%rax), %%r8\n\t"                               \
+         "movq 32(%%rax), %%rcx\n\t"                              \
+         "movq 24(%%rax), %%rdx\n\t"                              \
+         "movq 16(%%rax), %%rsi\n\t"                              \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $16, %%rsp\n"                                      \
+         "addq $128,%%rsp\n\t"                                    \
+         VALGRIND_CFI_EPILOGUE                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0]) __FRAME_POINTER            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15"   \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8,arg9)                  \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[10];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      __asm__ volatile(                                           \
+         VALGRIND_CFI_PROLOGUE                                    \
+         "subq $136,%%rsp\n\t"                                    \
+         "pushq 72(%%rax)\n\t"                                    \
+         "pushq 64(%%rax)\n\t"                                    \
+         "pushq 56(%%rax)\n\t"                                    \
+         "movq 48(%%rax), %%r9\n\t"                               \
+         "movq 40(%%rax), %%r8\n\t"                               \
+         "movq 32(%%rax), %%rcx\n\t"                              \
+         "movq 24(%%rax), %%rdx\n\t"                              \
+         "movq 16(%%rax), %%rsi\n\t"                              \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $24, %%rsp\n"                                      \
+         "addq $136,%%rsp\n\t"                                    \
+         VALGRIND_CFI_EPILOGUE                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0]) __FRAME_POINTER            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15"   \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[11];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      _argvec[10] = (unsigned long)(arg10);                       \
+      __asm__ volatile(                                           \
+         VALGRIND_CFI_PROLOGUE                                    \
+         "subq $128,%%rsp\n\t"                                    \
+         "pushq 80(%%rax)\n\t"                                    \
+         "pushq 72(%%rax)\n\t"                                    \
+         "pushq 64(%%rax)\n\t"                                    \
+         "pushq 56(%%rax)\n\t"                                    \
+         "movq 48(%%rax), %%r9\n\t"                               \
+         "movq 40(%%rax), %%r8\n\t"                               \
+         "movq 32(%%rax), %%rcx\n\t"                              \
+         "movq 24(%%rax), %%rdx\n\t"                              \
+         "movq 16(%%rax), %%rsi\n\t"                              \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $32, %%rsp\n"                                      \
+         "addq $128,%%rsp\n\t"                                    \
+         VALGRIND_CFI_EPILOGUE                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0]) __FRAME_POINTER            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15"   \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10,arg11)     \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[12];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      _argvec[10] = (unsigned long)(arg10);                       \
+      _argvec[11] = (unsigned long)(arg11);                       \
+      __asm__ volatile(                                           \
+         VALGRIND_CFI_PROLOGUE                                    \
+         "subq $136,%%rsp\n\t"                                    \
+         "pushq 88(%%rax)\n\t"                                    \
+         "pushq 80(%%rax)\n\t"                                    \
+         "pushq 72(%%rax)\n\t"                                    \
+         "pushq 64(%%rax)\n\t"                                    \
+         "pushq 56(%%rax)\n\t"                                    \
+         "movq 48(%%rax), %%r9\n\t"                               \
+         "movq 40(%%rax), %%r8\n\t"                               \
+         "movq 32(%%rax), %%rcx\n\t"                              \
+         "movq 24(%%rax), %%rdx\n\t"                              \
+         "movq 16(%%rax), %%rsi\n\t"                              \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $40, %%rsp\n"                                      \
+         "addq $136,%%rsp\n\t"                                    \
+         VALGRIND_CFI_EPILOGUE                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0]) __FRAME_POINTER            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15"   \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                arg7,arg8,arg9,arg10,arg11,arg12) \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[13];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      _argvec[10] = (unsigned long)(arg10);                       \
+      _argvec[11] = (unsigned long)(arg11);                       \
+      _argvec[12] = (unsigned long)(arg12);                       \
+      __asm__ volatile(                                           \
+         VALGRIND_CFI_PROLOGUE                                    \
+         "subq $128,%%rsp\n\t"                                    \
+         "pushq 96(%%rax)\n\t"                                    \
+         "pushq 88(%%rax)\n\t"                                    \
+         "pushq 80(%%rax)\n\t"                                    \
+         "pushq 72(%%rax)\n\t"                                    \
+         "pushq 64(%%rax)\n\t"                                    \
+         "pushq 56(%%rax)\n\t"                                    \
+         "movq 48(%%rax), %%r9\n\t"                               \
+         "movq 40(%%rax), %%r8\n\t"                               \
+         "movq 32(%%rax), %%rcx\n\t"                              \
+         "movq 24(%%rax), %%rdx\n\t"                              \
+         "movq 16(%%rax), %%rsi\n\t"                              \
+         "movq 8(%%rax), %%rdi\n\t"                               \
+         "movq (%%rax), %%rax\n\t"  /* target->%rax */            \
+         VALGRIND_CALL_NOREDIR_RAX                                \
+         "addq $48, %%rsp\n"                                      \
+         "addq $128,%%rsp\n\t"                                    \
+         VALGRIND_CFI_EPILOGUE                                    \
+         : /*out*/   "=a" (_res)                                  \
+         : /*in*/    "a" (&_argvec[0]) __FRAME_POINTER            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS, "r15"   \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#endif /* PLAT_amd64_linux || PLAT_amd64_darwin */
+
+/* ------------------------ ppc32-linux ------------------------ */
+
+#if defined(PLAT_ppc32_linux)
+
+/* This is useful for finding out about the on-stack stuff:
+
+   extern int f9  ( int,int,int,int,int,int,int,int,int );
+   extern int f10 ( int,int,int,int,int,int,int,int,int,int );
+   extern int f11 ( int,int,int,int,int,int,int,int,int,int,int );
+   extern int f12 ( int,int,int,int,int,int,int,int,int,int,int,int );
+
+   int g9 ( void ) {
+      return f9(11,22,33,44,55,66,77,88,99);
+   }
+   int g10 ( void ) {
+      return f10(11,22,33,44,55,66,77,88,99,110);
+   }
+   int g11 ( void ) {
+      return f11(11,22,33,44,55,66,77,88,99,110,121);
+   }
+   int g12 ( void ) {
+      return f12(11,22,33,44,55,66,77,88,99,110,121,132);
+   }
+*/
+
+/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS                                       \
+   "lr", "ctr", "xer",                                            \
+   "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7",        \
+   "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",   \
+   "r11", "r12", "r13"
+
+/* These CALL_FN_ macros assume that on ppc32-linux, 
+   sizeof(unsigned long) == 4. */
+
+#define CALL_FN_W_v(lval, orig)                                   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[1];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1)                             \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[2];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      _argvec[2] = (unsigned long)arg2;                           \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 4,8(11)\n\t"                                        \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3)                 \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[4];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      _argvec[2] = (unsigned long)arg2;                           \
+      _argvec[3] = (unsigned long)arg3;                           \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 4,8(11)\n\t"                                        \
+         "lwz 5,12(11)\n\t"                                       \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[5];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      _argvec[2] = (unsigned long)arg2;                           \
+      _argvec[3] = (unsigned long)arg3;                           \
+      _argvec[4] = (unsigned long)arg4;                           \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 4,8(11)\n\t"                                        \
+         "lwz 5,12(11)\n\t"                                       \
+         "lwz 6,16(11)\n\t"  /* arg4->r6 */                       \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5)        \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[6];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      _argvec[2] = (unsigned long)arg2;                           \
+      _argvec[3] = (unsigned long)arg3;                           \
+      _argvec[4] = (unsigned long)arg4;                           \
+      _argvec[5] = (unsigned long)arg5;                           \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 4,8(11)\n\t"                                        \
+         "lwz 5,12(11)\n\t"                                       \
+         "lwz 6,16(11)\n\t"  /* arg4->r6 */                       \
+         "lwz 7,20(11)\n\t"                                       \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6)   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[7];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      _argvec[2] = (unsigned long)arg2;                           \
+      _argvec[3] = (unsigned long)arg3;                           \
+      _argvec[4] = (unsigned long)arg4;                           \
+      _argvec[5] = (unsigned long)arg5;                           \
+      _argvec[6] = (unsigned long)arg6;                           \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 4,8(11)\n\t"                                        \
+         "lwz 5,12(11)\n\t"                                       \
+         "lwz 6,16(11)\n\t"  /* arg4->r6 */                       \
+         "lwz 7,20(11)\n\t"                                       \
+         "lwz 8,24(11)\n\t"                                       \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7)                            \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[8];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      _argvec[2] = (unsigned long)arg2;                           \
+      _argvec[3] = (unsigned long)arg3;                           \
+      _argvec[4] = (unsigned long)arg4;                           \
+      _argvec[5] = (unsigned long)arg5;                           \
+      _argvec[6] = (unsigned long)arg6;                           \
+      _argvec[7] = (unsigned long)arg7;                           \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 4,8(11)\n\t"                                        \
+         "lwz 5,12(11)\n\t"                                       \
+         "lwz 6,16(11)\n\t"  /* arg4->r6 */                       \
+         "lwz 7,20(11)\n\t"                                       \
+         "lwz 8,24(11)\n\t"                                       \
+         "lwz 9,28(11)\n\t"                                       \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[9];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      _argvec[2] = (unsigned long)arg2;                           \
+      _argvec[3] = (unsigned long)arg3;                           \
+      _argvec[4] = (unsigned long)arg4;                           \
+      _argvec[5] = (unsigned long)arg5;                           \
+      _argvec[6] = (unsigned long)arg6;                           \
+      _argvec[7] = (unsigned long)arg7;                           \
+      _argvec[8] = (unsigned long)arg8;                           \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 4,8(11)\n\t"                                        \
+         "lwz 5,12(11)\n\t"                                       \
+         "lwz 6,16(11)\n\t"  /* arg4->r6 */                       \
+         "lwz 7,20(11)\n\t"                                       \
+         "lwz 8,24(11)\n\t"                                       \
+         "lwz 9,28(11)\n\t"                                       \
+         "lwz 10,32(11)\n\t" /* arg8->r10 */                      \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8,arg9)                  \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[10];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      _argvec[2] = (unsigned long)arg2;                           \
+      _argvec[3] = (unsigned long)arg3;                           \
+      _argvec[4] = (unsigned long)arg4;                           \
+      _argvec[5] = (unsigned long)arg5;                           \
+      _argvec[6] = (unsigned long)arg6;                           \
+      _argvec[7] = (unsigned long)arg7;                           \
+      _argvec[8] = (unsigned long)arg8;                           \
+      _argvec[9] = (unsigned long)arg9;                           \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "addi 1,1,-16\n\t"                                       \
+         /* arg9 */                                               \
+         "lwz 3,36(11)\n\t"                                       \
+         "stw 3,8(1)\n\t"                                         \
+         /* args1-8 */                                            \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 4,8(11)\n\t"                                        \
+         "lwz 5,12(11)\n\t"                                       \
+         "lwz 6,16(11)\n\t"  /* arg4->r6 */                       \
+         "lwz 7,20(11)\n\t"                                       \
+         "lwz 8,24(11)\n\t"                                       \
+         "lwz 9,28(11)\n\t"                                       \
+         "lwz 10,32(11)\n\t" /* arg8->r10 */                      \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "addi 1,1,16\n\t"                                        \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[11];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      _argvec[2] = (unsigned long)arg2;                           \
+      _argvec[3] = (unsigned long)arg3;                           \
+      _argvec[4] = (unsigned long)arg4;                           \
+      _argvec[5] = (unsigned long)arg5;                           \
+      _argvec[6] = (unsigned long)arg6;                           \
+      _argvec[7] = (unsigned long)arg7;                           \
+      _argvec[8] = (unsigned long)arg8;                           \
+      _argvec[9] = (unsigned long)arg9;                           \
+      _argvec[10] = (unsigned long)arg10;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "addi 1,1,-16\n\t"                                       \
+         /* arg10 */                                              \
+         "lwz 3,40(11)\n\t"                                       \
+         "stw 3,12(1)\n\t"                                        \
+         /* arg9 */                                               \
+         "lwz 3,36(11)\n\t"                                       \
+         "stw 3,8(1)\n\t"                                         \
+         /* args1-8 */                                            \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 4,8(11)\n\t"                                        \
+         "lwz 5,12(11)\n\t"                                       \
+         "lwz 6,16(11)\n\t"  /* arg4->r6 */                       \
+         "lwz 7,20(11)\n\t"                                       \
+         "lwz 8,24(11)\n\t"                                       \
+         "lwz 9,28(11)\n\t"                                       \
+         "lwz 10,32(11)\n\t" /* arg8->r10 */                      \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "addi 1,1,16\n\t"                                        \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10,arg11)     \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[12];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      _argvec[2] = (unsigned long)arg2;                           \
+      _argvec[3] = (unsigned long)arg3;                           \
+      _argvec[4] = (unsigned long)arg4;                           \
+      _argvec[5] = (unsigned long)arg5;                           \
+      _argvec[6] = (unsigned long)arg6;                           \
+      _argvec[7] = (unsigned long)arg7;                           \
+      _argvec[8] = (unsigned long)arg8;                           \
+      _argvec[9] = (unsigned long)arg9;                           \
+      _argvec[10] = (unsigned long)arg10;                         \
+      _argvec[11] = (unsigned long)arg11;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "addi 1,1,-32\n\t"                                       \
+         /* arg11 */                                              \
+         "lwz 3,44(11)\n\t"                                       \
+         "stw 3,16(1)\n\t"                                        \
+         /* arg10 */                                              \
+         "lwz 3,40(11)\n\t"                                       \
+         "stw 3,12(1)\n\t"                                        \
+         /* arg9 */                                               \
+         "lwz 3,36(11)\n\t"                                       \
+         "stw 3,8(1)\n\t"                                         \
+         /* args1-8 */                                            \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 4,8(11)\n\t"                                        \
+         "lwz 5,12(11)\n\t"                                       \
+         "lwz 6,16(11)\n\t"  /* arg4->r6 */                       \
+         "lwz 7,20(11)\n\t"                                       \
+         "lwz 8,24(11)\n\t"                                       \
+         "lwz 9,28(11)\n\t"                                       \
+         "lwz 10,32(11)\n\t" /* arg8->r10 */                      \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "addi 1,1,32\n\t"                                        \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                arg7,arg8,arg9,arg10,arg11,arg12) \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[13];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)arg1;                           \
+      _argvec[2] = (unsigned long)arg2;                           \
+      _argvec[3] = (unsigned long)arg3;                           \
+      _argvec[4] = (unsigned long)arg4;                           \
+      _argvec[5] = (unsigned long)arg5;                           \
+      _argvec[6] = (unsigned long)arg6;                           \
+      _argvec[7] = (unsigned long)arg7;                           \
+      _argvec[8] = (unsigned long)arg8;                           \
+      _argvec[9] = (unsigned long)arg9;                           \
+      _argvec[10] = (unsigned long)arg10;                         \
+      _argvec[11] = (unsigned long)arg11;                         \
+      _argvec[12] = (unsigned long)arg12;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "addi 1,1,-32\n\t"                                       \
+         /* arg12 */                                              \
+         "lwz 3,48(11)\n\t"                                       \
+         "stw 3,20(1)\n\t"                                        \
+         /* arg11 */                                              \
+         "lwz 3,44(11)\n\t"                                       \
+         "stw 3,16(1)\n\t"                                        \
+         /* arg10 */                                              \
+         "lwz 3,40(11)\n\t"                                       \
+         "stw 3,12(1)\n\t"                                        \
+         /* arg9 */                                               \
+         "lwz 3,36(11)\n\t"                                       \
+         "stw 3,8(1)\n\t"                                         \
+         /* args1-8 */                                            \
+         "lwz 3,4(11)\n\t"   /* arg1->r3 */                       \
+         "lwz 4,8(11)\n\t"                                        \
+         "lwz 5,12(11)\n\t"                                       \
+         "lwz 6,16(11)\n\t"  /* arg4->r6 */                       \
+         "lwz 7,20(11)\n\t"                                       \
+         "lwz 8,24(11)\n\t"                                       \
+         "lwz 9,28(11)\n\t"                                       \
+         "lwz 10,32(11)\n\t" /* arg8->r10 */                      \
+         "lwz 11,0(11)\n\t"  /* target->r11 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "addi 1,1,32\n\t"                                        \
+         "mr %0,3"                                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#endif /* PLAT_ppc32_linux */
+
+/* ------------------------ ppc64-linux ------------------------ */
+
+#if defined(PLAT_ppc64_linux)
+
+/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS                                       \
+   "lr", "ctr", "xer",                                            \
+   "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7",        \
+   "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",   \
+   "r11", "r12", "r13"
+
+/* These CALL_FN_ macros assume that on ppc64-linux, sizeof(unsigned
+   long) == 8. */
+
+#define CALL_FN_W_v(lval, orig)                                   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+0];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1] = (unsigned long)_orig.r2;                       \
+      _argvec[2] = (unsigned long)_orig.nraddr;                   \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)" /* restore tocptr */                      \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1)                             \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+1];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)" /* restore tocptr */                      \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+2];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)" /* restore tocptr */                      \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3)                 \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+3];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)" /* restore tocptr */                      \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+4];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)" /* restore tocptr */                      \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5)        \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+5];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)" /* restore tocptr */                      \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6)   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+6];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)" /* restore tocptr */                      \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7)                            \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+7];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)" /* restore tocptr */                      \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+8];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  10, 64(11)\n\t" /* arg8->r10 */                     \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)" /* restore tocptr */                      \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8,arg9)                  \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+9];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "addi 1,1,-128\n\t"  /* expand stack frame */            \
+         /* arg9 */                                               \
+         "ld  3,72(11)\n\t"                                       \
+         "std 3,112(1)\n\t"                                       \
+         /* args1-8 */                                            \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  10, 64(11)\n\t" /* arg8->r10 */                     \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)\n\t" /* restore tocptr */                  \
+         "addi 1,1,128"     /* restore frame */                   \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+10];                       \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      _argvec[2+10] = (unsigned long)arg10;                       \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "addi 1,1,-128\n\t"  /* expand stack frame */            \
+         /* arg10 */                                              \
+         "ld  3,80(11)\n\t"                                       \
+         "std 3,120(1)\n\t"                                       \
+         /* arg9 */                                               \
+         "ld  3,72(11)\n\t"                                       \
+         "std 3,112(1)\n\t"                                       \
+         /* args1-8 */                                            \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  10, 64(11)\n\t" /* arg8->r10 */                     \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)\n\t" /* restore tocptr */                  \
+         "addi 1,1,128"     /* restore frame */                   \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10,arg11)     \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+11];                       \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      _argvec[2+10] = (unsigned long)arg10;                       \
+      _argvec[2+11] = (unsigned long)arg11;                       \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "addi 1,1,-144\n\t"  /* expand stack frame */            \
+         /* arg11 */                                              \
+         "ld  3,88(11)\n\t"                                       \
+         "std 3,128(1)\n\t"                                       \
+         /* arg10 */                                              \
+         "ld  3,80(11)\n\t"                                       \
+         "std 3,120(1)\n\t"                                       \
+         /* arg9 */                                               \
+         "ld  3,72(11)\n\t"                                       \
+         "std 3,112(1)\n\t"                                       \
+         /* args1-8 */                                            \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  10, 64(11)\n\t" /* arg8->r10 */                     \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)\n\t" /* restore tocptr */                  \
+         "addi 1,1,144"     /* restore frame */                   \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                arg7,arg8,arg9,arg10,arg11,arg12) \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+12];                       \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      _argvec[2+10] = (unsigned long)arg10;                       \
+      _argvec[2+11] = (unsigned long)arg11;                       \
+      _argvec[2+12] = (unsigned long)arg12;                       \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         "std 2,-16(11)\n\t"  /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "addi 1,1,-144\n\t"  /* expand stack frame */            \
+         /* arg12 */                                              \
+         "ld  3,96(11)\n\t"                                       \
+         "std 3,136(1)\n\t"                                       \
+         /* arg11 */                                              \
+         "ld  3,88(11)\n\t"                                       \
+         "std 3,128(1)\n\t"                                       \
+         /* arg10 */                                              \
+         "ld  3,80(11)\n\t"                                       \
+         "std 3,120(1)\n\t"                                       \
+         /* arg9 */                                               \
+         "ld  3,72(11)\n\t"                                       \
+         "std 3,112(1)\n\t"                                       \
+         /* args1-8 */                                            \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  10, 64(11)\n\t" /* arg8->r10 */                     \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)\n\t" /* restore tocptr */                  \
+         "addi 1,1,144"     /* restore frame */                   \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#endif /* PLAT_ppc64_linux */
+
+/* ------------------------- arm-linux ------------------------- */
+
+#if defined(PLAT_arm_linux)
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS "r0", "r1", "r2", "r3","r4","r14"
+
+/* These CALL_FN_ macros assume that on arm-linux, sizeof(unsigned
+   long) == 4. */
+
+#define CALL_FN_W_v(lval, orig)                                   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[1];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      __asm__ volatile(                                           \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "mov %0, r0\n"                                           \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1)                             \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[2];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "mov %0, r0\n"                                           \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory",  __CALLER_SAVED_REGS         \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r1, [%1, #8] \n\t"                                  \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "mov %0, r0\n"                                           \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3)                 \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[4];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r1, [%1, #8] \n\t"                                  \
+         "ldr r2, [%1, #12] \n\t"                                 \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "mov %0, r0\n"                                           \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[5];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r1, [%1, #8] \n\t"                                  \
+         "ldr r2, [%1, #12] \n\t"                                 \
+         "ldr r3, [%1, #16] \n\t"                                 \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "mov %0, r0"                                             \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5)        \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[6];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #20] \n\t"                                 \
+         "push {r0} \n\t"                                         \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r1, [%1, #8] \n\t"                                  \
+         "ldr r2, [%1, #12] \n\t"                                 \
+         "ldr r3, [%1, #16] \n\t"                                 \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "add sp, sp, #4 \n\t"                                    \
+         "mov %0, r0"                                             \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6)   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[7];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #20] \n\t"                                 \
+         "ldr r1, [%1, #24] \n\t"                                 \
+         "push {r0, r1} \n\t"                                     \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r1, [%1, #8] \n\t"                                  \
+         "ldr r2, [%1, #12] \n\t"                                 \
+         "ldr r3, [%1, #16] \n\t"                                 \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "add sp, sp, #8 \n\t"                                    \
+         "mov %0, r0"                                             \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7)                            \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[8];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #20] \n\t"                                 \
+         "ldr r1, [%1, #24] \n\t"                                 \
+         "ldr r2, [%1, #28] \n\t"                                 \
+         "push {r0, r1, r2} \n\t"                                 \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r1, [%1, #8] \n\t"                                  \
+         "ldr r2, [%1, #12] \n\t"                                 \
+         "ldr r3, [%1, #16] \n\t"                                 \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "add sp, sp, #12 \n\t"                                   \
+         "mov %0, r0"                                             \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[9];                          \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #20] \n\t"                                 \
+         "ldr r1, [%1, #24] \n\t"                                 \
+         "ldr r2, [%1, #28] \n\t"                                 \
+         "ldr r3, [%1, #32] \n\t"                                 \
+         "push {r0, r1, r2, r3} \n\t"                             \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r1, [%1, #8] \n\t"                                  \
+         "ldr r2, [%1, #12] \n\t"                                 \
+         "ldr r3, [%1, #16] \n\t"                                 \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "add sp, sp, #16 \n\t"                                   \
+         "mov %0, r0"                                             \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8,arg9)                  \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[10];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #20] \n\t"                                 \
+         "ldr r1, [%1, #24] \n\t"                                 \
+         "ldr r2, [%1, #28] \n\t"                                 \
+         "ldr r3, [%1, #32] \n\t"                                 \
+         "ldr r4, [%1, #36] \n\t"                                 \
+         "push {r0, r1, r2, r3, r4} \n\t"                         \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r1, [%1, #8] \n\t"                                  \
+         "ldr r2, [%1, #12] \n\t"                                 \
+         "ldr r3, [%1, #16] \n\t"                                 \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "add sp, sp, #20 \n\t"                                   \
+         "mov %0, r0"                                             \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[11];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      _argvec[10] = (unsigned long)(arg10);                       \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #40] \n\t"                                 \
+         "push {r0} \n\t"                                         \
+         "ldr r0, [%1, #20] \n\t"                                 \
+         "ldr r1, [%1, #24] \n\t"                                 \
+         "ldr r2, [%1, #28] \n\t"                                 \
+         "ldr r3, [%1, #32] \n\t"                                 \
+         "ldr r4, [%1, #36] \n\t"                                 \
+         "push {r0, r1, r2, r3, r4} \n\t"                         \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r1, [%1, #8] \n\t"                                  \
+         "ldr r2, [%1, #12] \n\t"                                 \
+         "ldr r3, [%1, #16] \n\t"                                 \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "add sp, sp, #24 \n\t"                                   \
+         "mov %0, r0"                                             \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,       \
+                                  arg6,arg7,arg8,arg9,arg10,      \
+                                  arg11)                          \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[12];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      _argvec[10] = (unsigned long)(arg10);                       \
+      _argvec[11] = (unsigned long)(arg11);                       \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #40] \n\t"                                 \
+         "ldr r1, [%1, #44] \n\t"                                 \
+         "push {r0, r1} \n\t"                                     \
+         "ldr r0, [%1, #20] \n\t"                                 \
+         "ldr r1, [%1, #24] \n\t"                                 \
+         "ldr r2, [%1, #28] \n\t"                                 \
+         "ldr r3, [%1, #32] \n\t"                                 \
+         "ldr r4, [%1, #36] \n\t"                                 \
+         "push {r0, r1, r2, r3, r4} \n\t"                         \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r1, [%1, #8] \n\t"                                  \
+         "ldr r2, [%1, #12] \n\t"                                 \
+         "ldr r3, [%1, #16] \n\t"                                 \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "add sp, sp, #28 \n\t"                                   \
+         "mov %0, r0"                                             \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory",__CALLER_SAVED_REGS           \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,       \
+                                  arg6,arg7,arg8,arg9,arg10,      \
+                                  arg11,arg12)                    \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[13];                         \
+      volatile unsigned long _res;                                \
+      _argvec[0] = (unsigned long)_orig.nraddr;                   \
+      _argvec[1] = (unsigned long)(arg1);                         \
+      _argvec[2] = (unsigned long)(arg2);                         \
+      _argvec[3] = (unsigned long)(arg3);                         \
+      _argvec[4] = (unsigned long)(arg4);                         \
+      _argvec[5] = (unsigned long)(arg5);                         \
+      _argvec[6] = (unsigned long)(arg6);                         \
+      _argvec[7] = (unsigned long)(arg7);                         \
+      _argvec[8] = (unsigned long)(arg8);                         \
+      _argvec[9] = (unsigned long)(arg9);                         \
+      _argvec[10] = (unsigned long)(arg10);                       \
+      _argvec[11] = (unsigned long)(arg11);                       \
+      _argvec[12] = (unsigned long)(arg12);                       \
+      __asm__ volatile(                                           \
+         "ldr r0, [%1, #40] \n\t"                                 \
+         "ldr r1, [%1, #44] \n\t"                                 \
+         "ldr r2, [%1, #48] \n\t"                                 \
+         "push {r0, r1, r2} \n\t"                                 \
+         "ldr r0, [%1, #20] \n\t"                                 \
+         "ldr r1, [%1, #24] \n\t"                                 \
+         "ldr r2, [%1, #28] \n\t"                                 \
+         "ldr r3, [%1, #32] \n\t"                                 \
+         "ldr r4, [%1, #36] \n\t"                                 \
+         "push {r0, r1, r2, r3, r4} \n\t"                         \
+         "ldr r0, [%1, #4] \n\t"                                  \
+         "ldr r1, [%1, #8] \n\t"                                  \
+         "ldr r2, [%1, #12] \n\t"                                 \
+         "ldr r3, [%1, #16] \n\t"                                 \
+         "ldr r4, [%1] \n\t"  /* target->r4 */                    \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R4                   \
+         "add sp, sp, #32 \n\t"                                   \
+         "mov %0, r0"                                             \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "0" (&_argvec[0])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#endif /* PLAT_arm_linux */
+
+/* ------------------------ ppc32-aix5 ------------------------- */
+
+#if defined(PLAT_ppc32_aix5)
+
+/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS                                       \
+   "lr", "ctr", "xer",                                            \
+   "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7",        \
+   "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",   \
+   "r11", "r12", "r13"
+
+/* Expand the stack frame, copying enough info that unwinding
+   still works.  Trashes r3. */
+
+#define VG_EXPAND_FRAME_BY_trashes_r3(_n_fr)                      \
+         "addi 1,1,-" #_n_fr "\n\t"                               \
+         "lwz  3," #_n_fr "(1)\n\t"                               \
+         "stw  3,0(1)\n\t"
+
+#define VG_CONTRACT_FRAME_BY(_n_fr)                               \
+         "addi 1,1," #_n_fr "\n\t"
+
+/* These CALL_FN_ macros assume that on ppc32-aix5, sizeof(unsigned
+   long) == 4. */
+
+#define CALL_FN_W_v(lval, orig)                                   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+0];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1] = (unsigned long)_orig.r2;                       \
+      _argvec[2] = (unsigned long)_orig.nraddr;                   \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1)                             \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+1];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+2];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz  4, 8(11)\n\t"  /* arg2->r4 */                      \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3)                 \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+3];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz  4, 8(11)\n\t"  /* arg2->r4 */                      \
+         "lwz  5, 12(11)\n\t" /* arg3->r5 */                      \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+4];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz  4, 8(11)\n\t"  /* arg2->r4 */                      \
+         "lwz  5, 12(11)\n\t" /* arg3->r5 */                      \
+         "lwz  6, 16(11)\n\t" /* arg4->r6 */                      \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5)        \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+5];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz  4, 8(11)\n\t" /* arg2->r4 */                       \
+         "lwz  5, 12(11)\n\t" /* arg3->r5 */                      \
+         "lwz  6, 16(11)\n\t" /* arg4->r6 */                      \
+         "lwz  7, 20(11)\n\t" /* arg5->r7 */                      \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6)   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+6];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz  4, 8(11)\n\t"  /* arg2->r4 */                      \
+         "lwz  5, 12(11)\n\t" /* arg3->r5 */                      \
+         "lwz  6, 16(11)\n\t" /* arg4->r6 */                      \
+         "lwz  7, 20(11)\n\t" /* arg5->r7 */                      \
+         "lwz  8, 24(11)\n\t" /* arg6->r8 */                      \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7)                            \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+7];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz  4, 8(11)\n\t"  /* arg2->r4 */                      \
+         "lwz  5, 12(11)\n\t" /* arg3->r5 */                      \
+         "lwz  6, 16(11)\n\t" /* arg4->r6 */                      \
+         "lwz  7, 20(11)\n\t" /* arg5->r7 */                      \
+         "lwz  8, 24(11)\n\t" /* arg6->r8 */                      \
+         "lwz  9, 28(11)\n\t" /* arg7->r9 */                      \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+8];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz  4, 8(11)\n\t"  /* arg2->r4 */                      \
+         "lwz  5, 12(11)\n\t" /* arg3->r5 */                      \
+         "lwz  6, 16(11)\n\t" /* arg4->r6 */                      \
+         "lwz  7, 20(11)\n\t" /* arg5->r7 */                      \
+         "lwz  8, 24(11)\n\t" /* arg6->r8 */                      \
+         "lwz  9, 28(11)\n\t" /* arg7->r9 */                      \
+         "lwz 10, 32(11)\n\t" /* arg8->r10 */                     \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8,arg9)                  \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+9];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         VG_EXPAND_FRAME_BY_trashes_r3(64)                        \
+         /* arg9 */                                               \
+         "lwz 3,36(11)\n\t"                                       \
+         "stw 3,56(1)\n\t"                                        \
+         /* args1-8 */                                            \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz  4, 8(11)\n\t"  /* arg2->r4 */                      \
+         "lwz  5, 12(11)\n\t" /* arg3->r5 */                      \
+         "lwz  6, 16(11)\n\t" /* arg4->r6 */                      \
+         "lwz  7, 20(11)\n\t" /* arg5->r7 */                      \
+         "lwz  8, 24(11)\n\t" /* arg6->r8 */                      \
+         "lwz  9, 28(11)\n\t" /* arg7->r9 */                      \
+         "lwz 10, 32(11)\n\t" /* arg8->r10 */                     \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(64)                                 \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+10];                       \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      _argvec[2+10] = (unsigned long)arg10;                       \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         VG_EXPAND_FRAME_BY_trashes_r3(64)                        \
+         /* arg10 */                                              \
+         "lwz 3,40(11)\n\t"                                       \
+         "stw 3,60(1)\n\t"                                        \
+         /* arg9 */                                               \
+         "lwz 3,36(11)\n\t"                                       \
+         "stw 3,56(1)\n\t"                                        \
+         /* args1-8 */                                            \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz  4, 8(11)\n\t"  /* arg2->r4 */                      \
+         "lwz  5, 12(11)\n\t" /* arg3->r5 */                      \
+         "lwz  6, 16(11)\n\t" /* arg4->r6 */                      \
+         "lwz  7, 20(11)\n\t" /* arg5->r7 */                      \
+         "lwz  8, 24(11)\n\t" /* arg6->r8 */                      \
+         "lwz  9, 28(11)\n\t" /* arg7->r9 */                      \
+         "lwz 10, 32(11)\n\t" /* arg8->r10 */                     \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(64)                                 \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10,arg11)     \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+11];                       \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      _argvec[2+10] = (unsigned long)arg10;                       \
+      _argvec[2+11] = (unsigned long)arg11;                       \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         VG_EXPAND_FRAME_BY_trashes_r3(72)                        \
+         /* arg11 */                                              \
+         "lwz 3,44(11)\n\t"                                       \
+         "stw 3,64(1)\n\t"                                        \
+         /* arg10 */                                              \
+         "lwz 3,40(11)\n\t"                                       \
+         "stw 3,60(1)\n\t"                                        \
+         /* arg9 */                                               \
+         "lwz 3,36(11)\n\t"                                       \
+         "stw 3,56(1)\n\t"                                        \
+         /* args1-8 */                                            \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz  4, 8(11)\n\t"  /* arg2->r4 */                      \
+         "lwz  5, 12(11)\n\t" /* arg3->r5 */                      \
+         "lwz  6, 16(11)\n\t" /* arg4->r6 */                      \
+         "lwz  7, 20(11)\n\t" /* arg5->r7 */                      \
+         "lwz  8, 24(11)\n\t" /* arg6->r8 */                      \
+         "lwz  9, 28(11)\n\t" /* arg7->r9 */                      \
+         "lwz 10, 32(11)\n\t" /* arg8->r10 */                     \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(72)                                 \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                arg7,arg8,arg9,arg10,arg11,arg12) \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+12];                       \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      _argvec[2+10] = (unsigned long)arg10;                       \
+      _argvec[2+11] = (unsigned long)arg11;                       \
+      _argvec[2+12] = (unsigned long)arg12;                       \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "stw  2,-8(11)\n\t"  /* save tocptr */                   \
+         "lwz  2,-4(11)\n\t"  /* use nraddr's tocptr */           \
+         VG_EXPAND_FRAME_BY_trashes_r3(72)                        \
+         /* arg12 */                                              \
+         "lwz 3,48(11)\n\t"                                       \
+         "stw 3,68(1)\n\t"                                        \
+         /* arg11 */                                              \
+         "lwz 3,44(11)\n\t"                                       \
+         "stw 3,64(1)\n\t"                                        \
+         /* arg10 */                                              \
+         "lwz 3,40(11)\n\t"                                       \
+         "stw 3,60(1)\n\t"                                        \
+         /* arg9 */                                               \
+         "lwz 3,36(11)\n\t"                                       \
+         "stw 3,56(1)\n\t"                                        \
+         /* args1-8 */                                            \
+         "lwz  3, 4(11)\n\t"  /* arg1->r3 */                      \
+         "lwz  4, 8(11)\n\t"  /* arg2->r4 */                      \
+         "lwz  5, 12(11)\n\t" /* arg3->r5 */                      \
+         "lwz  6, 16(11)\n\t" /* arg4->r6 */                      \
+         "lwz  7, 20(11)\n\t" /* arg5->r7 */                      \
+         "lwz  8, 24(11)\n\t" /* arg6->r8 */                      \
+         "lwz  9, 28(11)\n\t" /* arg7->r9 */                      \
+         "lwz 10, 32(11)\n\t" /* arg8->r10 */                     \
+         "lwz 11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "lwz 2,-8(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(72)                                 \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#endif /* PLAT_ppc32_aix5 */
+
+/* ------------------------ ppc64-aix5 ------------------------- */
+
+#if defined(PLAT_ppc64_aix5)
+
+/* ARGREGS: r3 r4 r5 r6 r7 r8 r9 r10 (the rest on stack somewhere) */
+
+/* These regs are trashed by the hidden call. */
+#define __CALLER_SAVED_REGS                                       \
+   "lr", "ctr", "xer",                                            \
+   "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7",        \
+   "r0", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10",   \
+   "r11", "r12", "r13"
+
+/* Expand the stack frame, copying enough info that unwinding
+   still works.  Trashes r3. */
+
+#define VG_EXPAND_FRAME_BY_trashes_r3(_n_fr)                      \
+         "addi 1,1,-" #_n_fr "\n\t"                               \
+         "ld   3," #_n_fr "(1)\n\t"                               \
+         "std  3,0(1)\n\t"
+
+#define VG_CONTRACT_FRAME_BY(_n_fr)                               \
+         "addi 1,1," #_n_fr "\n\t"
+
+/* These CALL_FN_ macros assume that on ppc64-aix5, sizeof(unsigned
+   long) == 8. */
+
+#define CALL_FN_W_v(lval, orig)                                   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+0];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1] = (unsigned long)_orig.r2;                       \
+      _argvec[2] = (unsigned long)_orig.nraddr;                   \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_W(lval, orig, arg1)                             \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+1];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld 2,-16(11)\n\t" /* restore tocptr */                  \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WW(lval, orig, arg1,arg2)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+2];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld  2,-16(11)\n\t" /* restore tocptr */                 \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWW(lval, orig, arg1,arg2,arg3)                 \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+3];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld  2,-16(11)\n\t" /* restore tocptr */                 \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_WWWW(lval, orig, arg1,arg2,arg3,arg4)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+4];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld  2,-16(11)\n\t" /* restore tocptr */                 \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_5W(lval, orig, arg1,arg2,arg3,arg4,arg5)        \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+5];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld  2,-16(11)\n\t" /* restore tocptr */                 \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_6W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6)   \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+6];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld  2,-16(11)\n\t" /* restore tocptr */                 \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_7W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7)                            \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+7];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld  2,-16(11)\n\t" /* restore tocptr */                 \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_8W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8)                       \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+8];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  10, 64(11)\n\t" /* arg8->r10 */                     \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld  2,-16(11)\n\t" /* restore tocptr */                 \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_9W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,   \
+                                 arg7,arg8,arg9)                  \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+9];                        \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         VG_EXPAND_FRAME_BY_trashes_r3(128)                       \
+         /* arg9 */                                               \
+         "ld  3,72(11)\n\t"                                       \
+         "std 3,112(1)\n\t"                                       \
+         /* args1-8 */                                            \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  10, 64(11)\n\t" /* arg8->r10 */                     \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld  2,-16(11)\n\t" /* restore tocptr */                 \
+         VG_CONTRACT_FRAME_BY(128)                                \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_10W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10)           \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+10];                       \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      _argvec[2+10] = (unsigned long)arg10;                       \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         VG_EXPAND_FRAME_BY_trashes_r3(128)                       \
+         /* arg10 */                                              \
+         "ld  3,80(11)\n\t"                                       \
+         "std 3,120(1)\n\t"                                       \
+         /* arg9 */                                               \
+         "ld  3,72(11)\n\t"                                       \
+         "std 3,112(1)\n\t"                                       \
+         /* args1-8 */                                            \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  10, 64(11)\n\t" /* arg8->r10 */                     \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld  2,-16(11)\n\t" /* restore tocptr */                 \
+         VG_CONTRACT_FRAME_BY(128)                                \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_11W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                  arg7,arg8,arg9,arg10,arg11)     \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+11];                       \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      _argvec[2+10] = (unsigned long)arg10;                       \
+      _argvec[2+11] = (unsigned long)arg11;                       \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         VG_EXPAND_FRAME_BY_trashes_r3(144)                       \
+         /* arg11 */                                              \
+         "ld  3,88(11)\n\t"                                       \
+         "std 3,128(1)\n\t"                                       \
+         /* arg10 */                                              \
+         "ld  3,80(11)\n\t"                                       \
+         "std 3,120(1)\n\t"                                       \
+         /* arg9 */                                               \
+         "ld  3,72(11)\n\t"                                       \
+         "std 3,112(1)\n\t"                                       \
+         /* args1-8 */                                            \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  10, 64(11)\n\t" /* arg8->r10 */                     \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld  2,-16(11)\n\t" /* restore tocptr */                 \
+         VG_CONTRACT_FRAME_BY(144)                                \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#define CALL_FN_W_12W(lval, orig, arg1,arg2,arg3,arg4,arg5,arg6,  \
+                                arg7,arg8,arg9,arg10,arg11,arg12) \
+   do {                                                           \
+      volatile OrigFn        _orig = (orig);                      \
+      volatile unsigned long _argvec[3+12];                       \
+      volatile unsigned long _res;                                \
+      /* _argvec[0] holds current r2 across the call */           \
+      _argvec[1]   = (unsigned long)_orig.r2;                     \
+      _argvec[2]   = (unsigned long)_orig.nraddr;                 \
+      _argvec[2+1] = (unsigned long)arg1;                         \
+      _argvec[2+2] = (unsigned long)arg2;                         \
+      _argvec[2+3] = (unsigned long)arg3;                         \
+      _argvec[2+4] = (unsigned long)arg4;                         \
+      _argvec[2+5] = (unsigned long)arg5;                         \
+      _argvec[2+6] = (unsigned long)arg6;                         \
+      _argvec[2+7] = (unsigned long)arg7;                         \
+      _argvec[2+8] = (unsigned long)arg8;                         \
+      _argvec[2+9] = (unsigned long)arg9;                         \
+      _argvec[2+10] = (unsigned long)arg10;                       \
+      _argvec[2+11] = (unsigned long)arg11;                       \
+      _argvec[2+12] = (unsigned long)arg12;                       \
+      __asm__ volatile(                                           \
+         "mr 11,%1\n\t"                                           \
+         VG_EXPAND_FRAME_BY_trashes_r3(512)                       \
+         "std  2,-16(11)\n\t" /* save tocptr */                   \
+         "ld   2,-8(11)\n\t"  /* use nraddr's tocptr */           \
+         VG_EXPAND_FRAME_BY_trashes_r3(144)                       \
+         /* arg12 */                                              \
+         "ld  3,96(11)\n\t"                                       \
+         "std 3,136(1)\n\t"                                       \
+         /* arg11 */                                              \
+         "ld  3,88(11)\n\t"                                       \
+         "std 3,128(1)\n\t"                                       \
+         /* arg10 */                                              \
+         "ld  3,80(11)\n\t"                                       \
+         "std 3,120(1)\n\t"                                       \
+         /* arg9 */                                               \
+         "ld  3,72(11)\n\t"                                       \
+         "std 3,112(1)\n\t"                                       \
+         /* args1-8 */                                            \
+         "ld   3, 8(11)\n\t"  /* arg1->r3 */                      \
+         "ld   4, 16(11)\n\t" /* arg2->r4 */                      \
+         "ld   5, 24(11)\n\t" /* arg3->r5 */                      \
+         "ld   6, 32(11)\n\t" /* arg4->r6 */                      \
+         "ld   7, 40(11)\n\t" /* arg5->r7 */                      \
+         "ld   8, 48(11)\n\t" /* arg6->r8 */                      \
+         "ld   9, 56(11)\n\t" /* arg7->r9 */                      \
+         "ld  10, 64(11)\n\t" /* arg8->r10 */                     \
+         "ld  11, 0(11)\n\t"  /* target->r11 */                   \
+         VALGRIND_BRANCH_AND_LINK_TO_NOREDIR_R11                  \
+         "mr 11,%1\n\t"                                           \
+         "mr %0,3\n\t"                                            \
+         "ld  2,-16(11)\n\t" /* restore tocptr */                 \
+         VG_CONTRACT_FRAME_BY(144)                                \
+         VG_CONTRACT_FRAME_BY(512)                                \
+         : /*out*/   "=r" (_res)                                  \
+         : /*in*/    "r" (&_argvec[2])                            \
+         : /*trash*/ "cc", "memory", __CALLER_SAVED_REGS          \
+      );                                                          \
+      lval = (__typeof__(lval)) _res;                             \
+   } while (0)
+
+#endif /* PLAT_ppc64_aix5 */
+
+
+/* ------------------------------------------------------------------ */
+/* ARCHITECTURE INDEPENDENT MACROS for CLIENT REQUESTS.               */
+/*                                                                    */
+/* ------------------------------------------------------------------ */
+
+/* Some request codes.  There are many more of these, but most are not
+   exposed to end-user view.  These are the public ones, all of the
+   form 0x1000 + small_number.
+
+   Core ones are in the range 0x00000000--0x0000ffff.  The non-public
+   ones start at 0x2000.
+*/
+
+/* These macros are used by tools -- they must be public, but don't
+   embed them into other programs. */
+#define VG_USERREQ_TOOL_BASE(a,b) \
+   ((unsigned int)(((a)&0xff) << 24 | ((b)&0xff) << 16))
+#define VG_IS_TOOL_USERREQ(a, b, v) \
+   (VG_USERREQ_TOOL_BASE(a,b) == ((v) & 0xffff0000))
+
+/* !! ABIWARNING !! ABIWARNING !! ABIWARNING !! ABIWARNING !! 
+   This enum comprises an ABI exported by Valgrind to programs
+   which use client requests.  DO NOT CHANGE THE ORDER OF THESE
+   ENTRIES, NOR DELETE ANY -- add new ones at the end. */
+typedef
+   enum { VG_USERREQ__RUNNING_ON_VALGRIND  = 0x1001,
+          VG_USERREQ__DISCARD_TRANSLATIONS = 0x1002,
+
+          /* These allow any function to be called from the simulated
+             CPU but run on the real CPU.  Nb: the first arg passed to
+             the function is always the ThreadId of the running
+             thread!  So CLIENT_CALL0 actually requires a 1 arg
+             function, etc. */
+          VG_USERREQ__CLIENT_CALL0 = 0x1101,
+          VG_USERREQ__CLIENT_CALL1 = 0x1102,
+          VG_USERREQ__CLIENT_CALL2 = 0x1103,
+          VG_USERREQ__CLIENT_CALL3 = 0x1104,
+
+          /* Can be useful in regression testing suites -- eg. can
+             send Valgrind's output to /dev/null and still count
+             errors. */
+          VG_USERREQ__COUNT_ERRORS = 0x1201,
+
+          /* These are useful and can be interpreted by any tool that
+             tracks malloc() et al, by using vg_replace_malloc.c. */
+          VG_USERREQ__MALLOCLIKE_BLOCK = 0x1301,
+          VG_USERREQ__FREELIKE_BLOCK   = 0x1302,
+          /* Memory pool support. */
+          VG_USERREQ__CREATE_MEMPOOL   = 0x1303,
+          VG_USERREQ__DESTROY_MEMPOOL  = 0x1304,
+          VG_USERREQ__MEMPOOL_ALLOC    = 0x1305,
+          VG_USERREQ__MEMPOOL_FREE     = 0x1306,
+          VG_USERREQ__MEMPOOL_TRIM     = 0x1307,
+          VG_USERREQ__MOVE_MEMPOOL     = 0x1308,
+          VG_USERREQ__MEMPOOL_CHANGE   = 0x1309,
+          VG_USERREQ__MEMPOOL_EXISTS   = 0x130a,
+
+          /* Allow printfs to valgrind log. */
+          /* The first two pass the va_list argument by value, which
+             assumes it is the same size as or smaller than a UWord,
+             which generally isn't the case.  Hence are deprecated.
+             The second two pass the vargs by reference and so are
+             immune to this problem. */
+          /* both :: char* fmt, va_list vargs (DEPRECATED) */
+          VG_USERREQ__PRINTF           = 0x1401,
+          VG_USERREQ__PRINTF_BACKTRACE = 0x1402,
+          /* both :: char* fmt, va_list* vargs */
+          VG_USERREQ__PRINTF_VALIST_BY_REF = 0x1403,
+          VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF = 0x1404,
+
+          /* Stack support. */
+          VG_USERREQ__STACK_REGISTER   = 0x1501,
+          VG_USERREQ__STACK_DEREGISTER = 0x1502,
+          VG_USERREQ__STACK_CHANGE     = 0x1503,
+
+          /* Wine support */
+          VG_USERREQ__LOAD_PDB_DEBUGINFO = 0x1601,
+
+          /* Querying of debug info. */
+          VG_USERREQ__MAP_IP_TO_SRCLOC = 0x1701
+   } Vg_ClientRequest;
+
+#if !defined(__GNUC__)
+#  define __extension__ /* */
+#endif
+
+
+/*
+ * VALGRIND_DO_CLIENT_REQUEST_EXPR(): a C expression that invokes a Valgrind
+ * client request and whose value equals the client request result.
+ */
+
+#if defined(NVALGRIND)
+
+#define VALGRIND_DO_CLIENT_REQUEST_EXPR(                               \
+        _zzq_default, _zzq_request,                                    \
+        _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)         \
+   (_zzq_default)
+
+#else /*defined(NVALGRIND)*/
+
+#if defined(_MSC_VER)
+
+#define VALGRIND_DO_CLIENT_REQUEST_EXPR(                                \
+        _zzq_default, _zzq_request,                                     \
+        _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)          \
+   (vg_VALGRIND_DO_CLIENT_REQUEST_EXPR((uintptr_t)(_zzq_default),       \
+        (_zzq_request), (uintptr_t)(_zzq_arg1), (uintptr_t)(_zzq_arg2), \
+        (uintptr_t)(_zzq_arg3), (uintptr_t)(_zzq_arg4),                 \
+        (uintptr_t)(_zzq_arg5)))
+
+static __inline unsigned
+vg_VALGRIND_DO_CLIENT_REQUEST_EXPR(uintptr_t _zzq_default,
+                                   unsigned _zzq_request, uintptr_t _zzq_arg1,
+                                   uintptr_t _zzq_arg2, uintptr_t _zzq_arg3,
+                                   uintptr_t _zzq_arg4, uintptr_t _zzq_arg5)
+{
+    unsigned _zzq_rlval;
+    VALGRIND_DO_CLIENT_REQUEST(_zzq_rlval, _zzq_default, _zzq_request,
+                      _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5);
+    return _zzq_rlval;
+}
+
+#else /*defined(_MSC_VER)*/
+
+#define VALGRIND_DO_CLIENT_REQUEST_EXPR(                               \
+        _zzq_default, _zzq_request,                                    \
+        _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5)         \
+   (__extension__({unsigned int _zzq_rlval;                            \
+    VALGRIND_DO_CLIENT_REQUEST(_zzq_rlval, _zzq_default, _zzq_request, \
+                _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \
+    _zzq_rlval;                                                        \
+   }))
+
+#endif /*defined(_MSC_VER)*/
+
+#endif /*defined(NVALGRIND)*/
+
+
+/* Returns the number of Valgrinds this code is running under.  That
+   is, 0 if running natively, 1 if running under Valgrind, 2 if
+   running under Valgrind which is running under another Valgrind,
+   etc. */
+#define RUNNING_ON_VALGRIND                                           \
+    VALGRIND_DO_CLIENT_REQUEST_EXPR(0 /* if not */,                   \
+                                    VG_USERREQ__RUNNING_ON_VALGRIND,  \
+                                    0, 0, 0, 0, 0)                    \
+
+
+/* Discard translation of code in the range [_qzz_addr .. _qzz_addr +
+   _qzz_len - 1].  Useful if you are debugging a JITter or some such,
+   since it provides a way to make sure valgrind will retranslate the
+   invalidated area.  Returns no value. */
+#define VALGRIND_DISCARD_TRANSLATIONS(_qzz_addr,_qzz_len)         \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__DISCARD_TRANSLATIONS,  \
+                               _qzz_addr, _qzz_len, 0, 0, 0);     \
+   }
+
+
+/* These requests are for getting Valgrind itself to print something.
+   Possibly with a backtrace.  This is a really ugly hack.  The return value
+   is the number of characters printed, excluding the "**<pid>** " part at the
+   start and the backtrace (if present). */
+
+#if defined(NVALGRIND)
+
+#  define VALGRIND_PRINTF(...)
+#  define VALGRIND_PRINTF_BACKTRACE(...)
+
+#else /* NVALGRIND */
+
+#if !defined(_MSC_VER)
+/* Modern GCC will optimize the static routine out if unused,
+   and unused attribute will shut down warnings about it.  */
+static int VALGRIND_PRINTF(const char *format, ...)
+   __attribute__((format(__printf__, 1, 2), __unused__));
+#endif
+static int
+#if defined(_MSC_VER)
+__inline
+#endif
+VALGRIND_PRINTF(const char *format, ...)
+{
+   unsigned long _qzz_res;
+   va_list vargs;
+   va_start(vargs, format);
+#if defined(_MSC_VER)
+   VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,
+                              VG_USERREQ__PRINTF_VALIST_BY_REF,
+                              (uintptr_t)format,
+                              (uintptr_t)&vargs,
+                              0, 0, 0);
+#else
+   VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,
+                              VG_USERREQ__PRINTF_VALIST_BY_REF,
+                              (unsigned long)format,
+                              (unsigned long)&vargs, 
+                              0, 0, 0);
+#endif
+   va_end(vargs);
+   return (int)_qzz_res;
+}
+
+#if !defined(_MSC_VER)
+static int VALGRIND_PRINTF_BACKTRACE(const char *format, ...)
+   __attribute__((format(__printf__, 1, 2), __unused__));
+#endif
+static int
+#if defined(_MSC_VER)
+__inline
+#endif
+VALGRIND_PRINTF_BACKTRACE(const char *format, ...)
+{
+   unsigned long _qzz_res;
+   va_list vargs;
+   va_start(vargs, format);
+#if defined(_MSC_VER)
+   VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,
+                              VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF,
+                              (uintptr_t)format,
+                              (uintptr_t)&vargs,
+                              0, 0, 0);
+#else
+   VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,
+                              VG_USERREQ__PRINTF_BACKTRACE_VALIST_BY_REF,
+                              (unsigned long)format,
+                              (unsigned long)&vargs, 
+                              0, 0, 0);
+#endif
+   va_end(vargs);
+   return (int)_qzz_res;
+}
+
+#endif /* NVALGRIND */
+
+
+/* These requests allow control to move from the simulated CPU to the
+   real CPU, calling an arbitary function.
+   
+   Note that the current ThreadId is inserted as the first argument.
+   So this call:
+
+     VALGRIND_NON_SIMD_CALL2(f, arg1, arg2)
+
+   requires f to have this signature:
+
+     Word f(Word tid, Word arg1, Word arg2)
+
+   where "Word" is a word-sized type.
+
+   Note that these client requests are not entirely reliable.  For example,
+   if you call a function with them that subsequently calls printf(),
+   there's a high chance Valgrind will crash.  Generally, your prospects of
+   these working are made higher if the called function does not refer to
+   any global variables, and does not refer to any libc or other functions
+   (printf et al).  Any kind of entanglement with libc or dynamic linking is
+   likely to have a bad outcome, for tricky reasons which we've grappled
+   with a lot in the past.
+*/
+#define VALGRIND_NON_SIMD_CALL0(_qyy_fn)                          \
+   __extension__                                                  \
+   ({unsigned long _qyy_res;                                      \
+    VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */,  \
+                               VG_USERREQ__CLIENT_CALL0,          \
+                               _qyy_fn,                           \
+                               0, 0, 0, 0);                       \
+    _qyy_res;                                                     \
+   })
+
+#define VALGRIND_NON_SIMD_CALL1(_qyy_fn, _qyy_arg1)               \
+   __extension__                                                  \
+   ({unsigned long _qyy_res;                                      \
+    VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */,  \
+                               VG_USERREQ__CLIENT_CALL1,          \
+                               _qyy_fn,                           \
+                               _qyy_arg1, 0, 0, 0);               \
+    _qyy_res;                                                     \
+   })
+
+#define VALGRIND_NON_SIMD_CALL2(_qyy_fn, _qyy_arg1, _qyy_arg2)    \
+   __extension__                                                  \
+   ({unsigned long _qyy_res;                                      \
+    VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */,  \
+                               VG_USERREQ__CLIENT_CALL2,          \
+                               _qyy_fn,                           \
+                               _qyy_arg1, _qyy_arg2, 0, 0);       \
+    _qyy_res;                                                     \
+   })
+
+#define VALGRIND_NON_SIMD_CALL3(_qyy_fn, _qyy_arg1, _qyy_arg2, _qyy_arg3) \
+   __extension__                                                  \
+   ({unsigned long _qyy_res;                                      \
+    VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */,  \
+                               VG_USERREQ__CLIENT_CALL3,          \
+                               _qyy_fn,                           \
+                               _qyy_arg1, _qyy_arg2,              \
+                               _qyy_arg3, 0);                     \
+    _qyy_res;                                                     \
+   })
+
+
+/* Counts the number of errors that have been recorded by a tool.  Nb:
+   the tool must record the errors with VG_(maybe_record_error)() or
+   VG_(unique_error)() for them to be counted. */
+#define VALGRIND_COUNT_ERRORS                                     \
+   __extension__                                                  \
+   ({unsigned int _qyy_res;                                       \
+    VALGRIND_DO_CLIENT_REQUEST(_qyy_res, 0 /* default return */,  \
+                               VG_USERREQ__COUNT_ERRORS,          \
+                               0, 0, 0, 0, 0);                    \
+    _qyy_res;                                                     \
+   })
+
+/* Several Valgrind tools (Memcheck, Massif, Helgrind, DRD) rely on knowing
+   when heap blocks are allocated in order to give accurate results.  This
+   happens automatically for the standard allocator functions such as
+   malloc(), calloc(), realloc(), memalign(), new, new[], free(), delete,
+   delete[], etc.
+
+   But if your program uses a custom allocator, this doesn't automatically
+   happen, and Valgrind will not do as well.  For example, if you allocate
+   superblocks with mmap() and then allocates chunks of the superblocks, all
+   Valgrind's observations will be at the mmap() level and it won't know that
+   the chunks should be considered separate entities.  In Memcheck's case,
+   that means you probably won't get heap block overrun detection (because
+   there won't be redzones marked as unaddressable) and you definitely won't
+   get any leak detection.
+
+   The following client requests allow a custom allocator to be annotated so
+   that it can be handled accurately by Valgrind.
+
+   VALGRIND_MALLOCLIKE_BLOCK marks a region of memory as having been allocated
+   by a malloc()-like function.  For Memcheck (an illustrative case), this
+   does two things:
+
+   - It records that the block has been allocated.  This means any addresses
+     within the block mentioned in error messages will be
+     identified as belonging to the block.  It also means that if the block
+     isn't freed it will be detected by the leak checker.
+
+   - It marks the block as being addressable and undefined (if 'is_zeroed' is
+     not set), or addressable and defined (if 'is_zeroed' is set).  This
+     controls how accesses to the block by the program are handled.
+   
+   'addr' is the start of the usable block (ie. after any
+   redzone), 'sizeB' is its size.  'rzB' is the redzone size if the allocator
+   can apply redzones -- these are blocks of padding at the start and end of
+   each block.  Adding redzones is recommended as it makes it much more likely
+   Valgrind will spot block overruns.  `is_zeroed' indicates if the memory is
+   zeroed (or filled with another predictable value), as is the case for
+   calloc().
+   
+   VALGRIND_MALLOCLIKE_BLOCK should be put immediately after the point where a
+   heap block -- that will be used by the client program -- is allocated.
+   It's best to put it at the outermost level of the allocator if possible;
+   for example, if you have a function my_alloc() which calls
+   internal_alloc(), and the client request is put inside internal_alloc(),
+   stack traces relating to the heap block will contain entries for both
+   my_alloc() and internal_alloc(), which is probably not what you want.
+
+   For Memcheck users: if you use VALGRIND_MALLOCLIKE_BLOCK to carve out
+   custom blocks from within a heap block, B, that has been allocated with
+   malloc/calloc/new/etc, then block B will be *ignored* during leak-checking
+   -- the custom blocks will take precedence.
+
+   VALGRIND_FREELIKE_BLOCK is the partner to VALGRIND_MALLOCLIKE_BLOCK.  For
+   Memcheck, it does two things:
+
+   - It records that the block has been deallocated.  This assumes that the
+     block was annotated as having been allocated via
+     VALGRIND_MALLOCLIKE_BLOCK.  Otherwise, an error will be issued.
+
+   - It marks the block as being unaddressable.
+
+   VALGRIND_FREELIKE_BLOCK should be put immediately after the point where a
+   heap block is deallocated.
+
+   In many cases, these two client requests will not be enough to get your
+   allocator working well with Memcheck.  More specifically, if your allocator
+   writes to freed blocks in any way then a VALGRIND_MAKE_MEM_UNDEFINED call
+   will be necessary to mark the memory as addressable just before the zeroing
+   occurs, otherwise you'll get a lot of invalid write errors.  For example,
+   you'll need to do this if your allocator recycles freed blocks, but it
+   zeroes them before handing them back out (via VALGRIND_MALLOCLIKE_BLOCK).
+   Alternatively, if your allocator reuses freed blocks for allocator-internal
+   data structures, VALGRIND_MAKE_MEM_UNDEFINED calls will also be necessary.
+
+   Really, what's happening is a blurring of the lines between the client
+   program and the allocator... after VALGRIND_FREELIKE_BLOCK is called, the
+   memory should be considered unaddressable to the client program, but the
+   allocator knows more than the rest of the client program and so may be able
+   to safely access it.  Extra client requests are necessary for Valgrind to
+   understand the distinction between the allocator and the rest of the
+   program.
+
+   Note: there is currently no VALGRIND_REALLOCLIKE_BLOCK client request;  it
+   has to be emulated with MALLOCLIKE/FREELIKE and memory copying.
+   
+   Ignored if addr == 0.
+*/
+#define VALGRIND_MALLOCLIKE_BLOCK(addr, sizeB, rzB, is_zeroed)    \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__MALLOCLIKE_BLOCK,      \
+                               addr, sizeB, rzB, is_zeroed, 0);   \
+   }
+
+/* See the comment for VALGRIND_MALLOCLIKE_BLOCK for details.
+   Ignored if addr == 0.
+*/
+#define VALGRIND_FREELIKE_BLOCK(addr, rzB)                        \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__FREELIKE_BLOCK,        \
+                               addr, rzB, 0, 0, 0);               \
+   }
+
+/* Create a memory pool. */
+#define VALGRIND_CREATE_MEMPOOL(pool, rzB, is_zeroed)             \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__CREATE_MEMPOOL,        \
+                               pool, rzB, is_zeroed, 0, 0);       \
+   }
+
+/* Destroy a memory pool. */
+#define VALGRIND_DESTROY_MEMPOOL(pool)                            \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__DESTROY_MEMPOOL,       \
+                               pool, 0, 0, 0, 0);                 \
+   }
+
+/* Associate a piece of memory with a memory pool. */
+#define VALGRIND_MEMPOOL_ALLOC(pool, addr, size)                  \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__MEMPOOL_ALLOC,         \
+                               pool, addr, size, 0, 0);           \
+   }
+
+/* Disassociate a piece of memory from a memory pool. */
+#define VALGRIND_MEMPOOL_FREE(pool, addr)                         \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__MEMPOOL_FREE,          \
+                               pool, addr, 0, 0, 0);              \
+   }
+
+/* Disassociate any pieces outside a particular range. */
+#define VALGRIND_MEMPOOL_TRIM(pool, addr, size)                   \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__MEMPOOL_TRIM,          \
+                               pool, addr, size, 0, 0);           \
+   }
+
+/* Resize and/or move a piece associated with a memory pool. */
+#define VALGRIND_MOVE_MEMPOOL(poolA, poolB)                       \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__MOVE_MEMPOOL,          \
+                               poolA, poolB, 0, 0, 0);            \
+   }
+
+/* Resize and/or move a piece associated with a memory pool. */
+#define VALGRIND_MEMPOOL_CHANGE(pool, addrA, addrB, size)         \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__MEMPOOL_CHANGE,        \
+                               pool, addrA, addrB, size, 0);      \
+   }
+
+/* Return 1 if a mempool exists, else 0. */
+#define VALGRIND_MEMPOOL_EXISTS(pool)                             \
+   __extension__                                                  \
+   ({unsigned int _qzz_res;                                       \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__MEMPOOL_EXISTS,        \
+                               pool, 0, 0, 0, 0);                 \
+    _qzz_res;                                                     \
+   })
+
+/* Mark a piece of memory as being a stack. Returns a stack id. */
+#define VALGRIND_STACK_REGISTER(start, end)                       \
+   __extension__                                                  \
+   ({unsigned int _qzz_res;                                       \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__STACK_REGISTER,        \
+                               start, end, 0, 0, 0);              \
+    _qzz_res;                                                     \
+   })
+
+/* Unmark the piece of memory associated with a stack id as being a
+   stack. */
+#define VALGRIND_STACK_DEREGISTER(id)                             \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__STACK_DEREGISTER,      \
+                               id, 0, 0, 0, 0);                   \
+   }
+
+/* Change the start and end address of the stack id. */
+#define VALGRIND_STACK_CHANGE(id, start, end)                     \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__STACK_CHANGE,          \
+                               id, start, end, 0, 0);             \
+   }
+
+/* Load PDB debug info for Wine PE image_map. */
+#define VALGRIND_LOAD_PDB_DEBUGINFO(fd, ptr, total_size, delta)   \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__LOAD_PDB_DEBUGINFO,    \
+                               fd, ptr, total_size, delta, 0);    \
+   }
+
+/* Map a code address to a source file name and line number.  buf64
+   must point to a 64-byte buffer in the caller's address space.  The
+   result will be dumped in there and is guaranteed to be zero
+   terminated.  If no info is found, the first byte is set to zero. */
+#define VALGRIND_MAP_IP_TO_SRCLOC(addr, buf64)                    \
+   {unsigned int _qzz_res;                                        \
+    VALGRIND_DO_CLIENT_REQUEST(_qzz_res, 0,                       \
+                               VG_USERREQ__MAP_IP_TO_SRCLOC,      \
+                               addr, buf64, 0, 0, 0);             \
+   }
+
+
+#undef PLAT_x86_linux
+#undef PLAT_amd64_linux
+#undef PLAT_ppc32_linux
+#undef PLAT_ppc64_linux
+#undef PLAT_arm_linux
+#undef PLAT_ppc32_aix5
+#undef PLAT_ppc64_aix5
+
+#endif   /* __VALGRIND_H */
diff --git a/base/third_party/xdg_mime/BUILD.gn b/base/third_party/xdg_mime/BUILD.gn
new file mode 100644
index 0000000..72a3038
--- /dev/null
+++ b/base/third_party/xdg_mime/BUILD.gn
@@ -0,0 +1,28 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("xdg_mime") {
+  visibility = [ "//base/*" ]
+  sources = [
+    "xdgmime.c",
+    "xdgmime.h",
+    "xdgmimealias.c",
+    "xdgmimealias.h",
+    "xdgmimecache.c",
+    "xdgmimecache.h",
+    "xdgmimeglob.c",
+    "xdgmimeglob.h",
+    "xdgmimeicon.c",
+    "xdgmimeicon.h",
+    "xdgmimeint.c",
+    "xdgmimeint.h",
+    "xdgmimemagic.c",
+    "xdgmimemagic.h",
+    "xdgmimeparent.c",
+    "xdgmimeparent.h",
+  ]
+
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [ "//build/config/compiler:no_chromium_code" ]
+}
diff --git a/base/third_party/xdg_mime/LICENSE b/base/third_party/xdg_mime/LICENSE
new file mode 100644
index 0000000..55fedcf
--- /dev/null
+++ b/base/third_party/xdg_mime/LICENSE
@@ -0,0 +1,168 @@
+Licensed under the Academic Free License version 2.0 (below)
+Or under the following terms:
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the
+Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.
+
+
+--------------------------------------------------------------------------------
+Academic Free License v. 2.0
+--------------------------------------------------------------------------------
+
+This Academic Free License (the "License") applies to any original work of
+authorship (the "Original Work") whose owner (the "Licensor") has placed the
+following notice immediately following the copyright notice for the Original
+Work:
+
+Licensed under the Academic Free License version 2.0
+1) Grant of Copyright License. Licensor hereby grants You a world-wide,
+royalty-free, non-exclusive, perpetual, sublicenseable license to do the
+following:
+
+a) to reproduce the Original Work in copies;
+b) to prepare derivative works ("Derivative Works") based upon the Original
+   Work;
+c) to distribute copies of the Original Work and Derivative Works to the
+   public;
+d) to perform the Original Work publicly; and
+e) to display the Original Work publicly.
+
+2) Grant of Patent License. Licensor hereby grants You a world-wide,
+royalty-free, non-exclusive, perpetual, sublicenseable license, under patent
+claims owned or controlled by the Licensor that are embodied in the Original
+Work as furnished by the Licensor, to make, use, sell and offer for sale the
+Original Work and Derivative Works.
+
+3) Grant of Source Code License. The term "Source Code" means the preferred
+form of the Original Work for making modifications to it and all available
+documentation describing how to modify the Original Work. Licensor hereby
+agrees to provide a machine-readable copy of the Source Code of the Original
+Work along with each copy of the Original Work that Licensor distributes.
+Licensor reserves the right to satisfy this obligation by placing a
+machine-readable copy of the Source Code in an information repository
+reasonably calculated to permit inexpensive and convenient access by You for as
+long as Licensor continues to distribute the Original Work, and by publishing
+the address of that information repository in a notice immediately following
+the copyright notice that applies to the Original Work.
+
+4) Exclusions From License Grant. Neither the names of Licensor, nor the names
+of any contributors to the Original Work, nor any of their trademarks or
+service marks, may be used to endorse or promote products derived from this
+Original Work without express prior written permission of the Licensor. Nothing
+in this License shall be deemed to grant any rights to trademarks, copyrights,
+patents, trade secrets or any other intellectual property of Licensor except as
+expressly stated herein. No patent license is granted to make, use, sell or
+offer to sell embodiments of any patent claims other than the licensed claims
+defined in Section 2. No right is granted to the trademarks of Licensor even if
+such marks are included in the Original Work. Nothing in this License shall be
+interpreted to prohibit Licensor from licensing under different terms from this
+License any Original Work that Licensor otherwise would have a right to
+license.
+
+5) This section intentionally omitted.
+
+6) Attribution Rights. You must retain, in the Source Code of any Derivative
+Works that You create, all copyright, patent or trademark notices from the
+Source Code of the Original Work, as well as any notices of licensing and any
+descriptive text identified therein as an "Attribution Notice." You must cause
+the Source Code for any Derivative Works that You create to carry a prominent
+Attribution Notice reasonably calculated to inform recipients that You have
+modified the Original Work.
+
+7) Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that
+the copyright in and to the Original Work and the patent rights granted herein
+by Licensor are owned by the Licensor or are sublicensed to You under the terms
+of this License with the permission of the contributor(s) of those copyrights
+and patent rights. Except as expressly stated in the immediately proceeding
+sentence, the Original Work is provided under this License on an "AS IS" BASIS
+and WITHOUT WARRANTY, either express or implied, including, without limitation,
+the warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU.
+This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No
+license to Original Work is granted hereunder except under this disclaimer.
+
+8) Limitation of Liability. Under no circumstances and under no legal theory,
+whether in tort (including negligence), contract, or otherwise, shall the
+Licensor be liable to any person for any direct, indirect, special, incidental,
+or consequential damages of any character arising as a result of this License
+or the use of the Original Work including, without limitation, damages for loss
+of goodwill, work stoppage, computer failure or malfunction, or any and all
+other commercial damages or losses. This limitation of liability shall not
+apply to liability for death or personal injury resulting from Licensor's
+negligence to the extent applicable law prohibits such limitation. Some
+jurisdictions do not allow the exclusion or limitation of incidental or
+consequential damages, so this exclusion and limitation may not apply to You.
+
+9) Acceptance and Termination. If You distribute copies of the Original Work or
+a Derivative Work, You must make a reasonable effort under the circumstances to
+obtain the express assent of recipients to the terms of this License. Nothing
+else but this License (or another written agreement between Licensor and You)
+grants You permission to create Derivative Works based upon the Original Work
+or to exercise any of the rights granted in Section 1 herein, and any attempt
+to do so except under the terms of this License (or another written agreement
+between Licensor and You) is expressly prohibited by U.S. copyright law, the
+equivalent laws of other countries, and by international treaty. Therefore, by
+exercising any of the rights granted to You in Section 1 herein, You indicate
+Your acceptance of this License and all of its terms and conditions.
+
+10) Termination for Patent Action. This License shall terminate automatically
+and You may no longer exercise any of the rights granted to You by this License
+as of the date You commence an action, including a cross-claim or counterclaim,
+for patent infringement (i) against Licensor with respect to a patent
+applicable to software or (ii) against any entity with respect to a patent
+applicable to the Original Work (but excluding combinations of the Original
+Work with other software or hardware).
+
+11) Jurisdiction, Venue and Governing Law. Any action or suit relating to this
+License may be brought only in the courts of a jurisdiction wherein the
+Licensor resides or in which Licensor conducts its primary business, and under
+the laws of that jurisdiction excluding its conflict-of-law provisions. The
+application of the United Nations Convention on Contracts for the International
+Sale of Goods is expressly excluded. Any use of the Original Work outside the
+scope of this License or after its termination shall be subject to the
+requirements and penalties of the U.S. Copyright Act, 17 U.S.C. 101 et seq.,
+the equivalent laws of other countries, and international treaty. This section
+shall survive the termination of this License.
+
+12) Attorneys Fees. In any action to enforce the terms of this License or
+seeking damages relating thereto, the prevailing party shall be entitled to
+recover its costs and expenses, including, without limitation, reasonable
+attorneys' fees and costs incurred in connection with such action, including
+any appeal of such action. This section shall survive the termination of this
+License.
+
+13) Miscellaneous. This License represents the complete agreement concerning
+the subject matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent necessary to
+make it enforceable.
+
+14) Definition of "You" in This License. "You" throughout this License, whether
+in upper or lower case, means an individual or a legal entity exercising rights
+under, and complying with all of the terms of, this License. For legal
+entities, "You" includes any entity that controls, is controlled by, or is
+under common control with you. For purposes of this definition, "control" means
+(i) the power, direct or indirect, to cause the direction or management of such
+entity, whether by contract or otherwise, or (ii) ownership of fifty percent
+(50%) or more of the outstanding shares, or (iii) beneficial ownership of such
+entity.
+
+15) Right to Use. You may use the Original Work in all ways not otherwise
+restricted or conditioned by this License or by law, and Licensor promises not
+to interfere with or be responsible for such uses by You.
+
+This license is Copyright (C) 2003 Lawrence E. Rosen. All rights reserved.
+Permission is hereby granted to copy and distribute this license without
+modification. This license may not be modified without the express written
+permission of its copyright owner.
diff --git a/base/third_party/xdg_mime/README b/base/third_party/xdg_mime/README
new file mode 100644
index 0000000..e7f3f68
--- /dev/null
+++ b/base/third_party/xdg_mime/README
@@ -0,0 +1,8 @@
+This module is a simple module that parses the proposed MIME spec listed
+at http://freedesktop.org/.  It is currently targetted at version 0.12.
+There are no formal releases planned for this module, and it is not
+intended to be installed at this time.  Rather, it is meant to be used
+by other libraries or applications to add support for the MIME system.
+
+It is dual-licensed under the terms of the GNU Lesser General Public
+License, and the Academic Free License, version 2.0.
diff --git a/base/third_party/xdg_mime/README.chromium b/base/third_party/xdg_mime/README.chromium
new file mode 100644
index 0000000..95f3a96
--- /dev/null
+++ b/base/third_party/xdg_mime/README.chromium
@@ -0,0 +1,13 @@
+Name: xdg-mime
+URL: http://freedesktop.org
+License: Academic Free License version 2.0 or LGPL v2
+
+The code in this directory is synced from:
+git://anongit.freedesktop.org/xdg/xdgmime
+@ 2cdd8d36d7930d5a594587286cb1949ff62f7027 on 2012/08/06.
+
+In addition, we have the following patch(es):
+  - compile.patch: small tweaks to make the code compile.
+  - free_pointer_later.patch: small patch that fixes potential crash in
+      xdg_mime_get_mime_type_for_file() - use of pointer after being freed.
+  - Added a LICENSE file.
diff --git a/base/third_party/xdg_mime/compile.patch b/base/third_party/xdg_mime/compile.patch
new file mode 100644
index 0000000..cd055ed
--- /dev/null
+++ b/base/third_party/xdg_mime/compile.patch
@@ -0,0 +1,17 @@
+--- a/xdgmimecache.c
++++ b/xdgmimecache.c
+@@ -40,6 +40,8 @@
+ 
+ #include <netinet/in.h> /* for ntohl/ntohs */
+ 
++#define HAVE_MMAP 1
++
+ #ifdef HAVE_MMAP
+ #include <sys/mman.h>
+ #else
+@@ -1000,5 +1002,3 @@
+ 	    dump_glob_node (cache, offset + 20 * j, 0);
+   }
+ }
+-
+-
diff --git a/base/third_party/xdg_mime/free_pointer_later.patch b/base/third_party/xdg_mime/free_pointer_later.patch
new file mode 100644
index 0000000..7668761
--- /dev/null
+++ b/base/third_party/xdg_mime/free_pointer_later.patch
@@ -0,0 +1,22 @@
+diff --git a/base/third_party/xdg_mime/xdgmime.c b/base/third_party/xdg_mime/xdgmime.c
+index c7b16bb..6dc58c2 100644
+--- a/base/third_party/xdg_mime/xdgmime.c
++++ b/base/third_party/xdg_mime/xdgmime.c
+@@ -558,13 +558,13 @@ xdg_mime_get_mime_type_for_file (const char  *file_name,
+   mime_type = _xdg_mime_magic_lookup_data (global_magic, data, bytes_read, NULL,
+ 					   mime_types, n);
+ 
+-  free (data);
+   fclose (file);
+ 
+-  if (mime_type)
+-    return mime_type;
++  if (!mime_type)
++    mime_type = _xdg_binary_or_text_fallback(data, bytes_read);
+ 
+-  return _xdg_binary_or_text_fallback(data, bytes_read);
++  free (data);
++  return mime_type;
+ }
+ 
+ const char *
diff --git a/base/third_party/xdg_mime/xdgmime.c b/base/third_party/xdg_mime/xdgmime.c
new file mode 100644
index 0000000..6dc58c2
--- /dev/null
+++ b/base/third_party/xdg_mime/xdgmime.c
@@ -0,0 +1,934 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* xdgmime.c: XDG Mime Spec mime resolver.  Based on version 0.11 of the spec.
+ *
+ * More info can be found at http://www.freedesktop.org/standards/
+ * 
+ * Copyright (C) 2003,2004  Red Hat, Inc.
+ * Copyright (C) 2003,2004  Jonathan Blandford <jrb@alum.mit.edu>
+ *
+ * Licensed under the Academic Free License version 2.0
+ * Or under the following terms:
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "xdgmime.h"
+#include "xdgmimeint.h"
+#include "xdgmimeglob.h"
+#include "xdgmimemagic.h"
+#include "xdgmimealias.h"
+#include "xdgmimeicon.h"
+#include "xdgmimeparent.h"
+#include "xdgmimecache.h"
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <assert.h>
+
+typedef struct XdgDirTimeList XdgDirTimeList;
+typedef struct XdgCallbackList XdgCallbackList;
+
+static int need_reread = TRUE;
+static time_t last_stat_time = 0;
+
+static XdgGlobHash *global_hash = NULL;
+static XdgMimeMagic *global_magic = NULL;
+static XdgAliasList *alias_list = NULL;
+static XdgParentList *parent_list = NULL;
+static XdgDirTimeList *dir_time_list = NULL;
+static XdgCallbackList *callback_list = NULL;
+static XdgIconList *icon_list = NULL;
+static XdgIconList *generic_icon_list = NULL;
+
+XdgMimeCache **_caches = NULL;
+static int n_caches = 0;
+
+const char xdg_mime_type_unknown[] = "application/octet-stream";
+const char xdg_mime_type_empty[] = "application/x-zerosize";
+const char xdg_mime_type_textplain[] = "text/plain";
+
+
+enum
+{
+  XDG_CHECKED_UNCHECKED,
+  XDG_CHECKED_VALID,
+  XDG_CHECKED_INVALID
+};
+
+struct XdgDirTimeList
+{
+  time_t mtime;
+  char *directory_name;
+  int checked;
+  XdgDirTimeList *next;
+};
+
+struct XdgCallbackList
+{
+  XdgCallbackList *next;
+  XdgCallbackList *prev;
+  int              callback_id;
+  XdgMimeCallback  callback;
+  void            *data;
+  XdgMimeDestroy   destroy;
+};
+
+/* Function called by xdg_run_command_on_dirs.  If it returns TRUE, further
+ * directories aren't looked at */
+typedef int (*XdgDirectoryFunc) (const char *directory,
+				 void       *user_data);
+
+static void
+xdg_dir_time_list_add (char   *file_name, 
+		       time_t  mtime)
+{
+  XdgDirTimeList *list;
+
+  for (list = dir_time_list; list; list = list->next) 
+    {
+      if (strcmp (list->directory_name, file_name) == 0)
+        {
+          free (file_name);
+          return;
+        }
+    }
+  
+  list = calloc (1, sizeof (XdgDirTimeList));
+  list->checked = XDG_CHECKED_UNCHECKED;
+  list->directory_name = file_name;
+  list->mtime = mtime;
+  list->next = dir_time_list;
+  dir_time_list = list;
+}
+ 
+static void
+xdg_dir_time_list_free (XdgDirTimeList *list)
+{
+  XdgDirTimeList *next;
+
+  while (list)
+    {
+      next = list->next;
+      free (list->directory_name);
+      free (list);
+      list = next;
+    }
+}
+
+static int
+xdg_mime_init_from_directory (const char *directory)
+{
+  char *file_name;
+  struct stat st;
+
+  assert (directory != NULL);
+
+  file_name = malloc (strlen (directory) + strlen ("/mime/mime.cache") + 1);
+  strcpy (file_name, directory); strcat (file_name, "/mime/mime.cache");
+  if (stat (file_name, &st) == 0)
+    {
+      XdgMimeCache *cache = _xdg_mime_cache_new_from_file (file_name);
+
+      if (cache != NULL)
+	{
+	  xdg_dir_time_list_add (file_name, st.st_mtime);
+
+	  _caches = realloc (_caches, sizeof (XdgMimeCache *) * (n_caches + 2));
+	  _caches[n_caches] = cache;
+          _caches[n_caches + 1] = NULL;
+	  n_caches++;
+
+	  return FALSE;
+	}
+    }
+  free (file_name);
+
+  file_name = malloc (strlen (directory) + strlen ("/mime/globs2") + 1);
+  strcpy (file_name, directory); strcat (file_name, "/mime/globs2");
+  if (stat (file_name, &st) == 0)
+    {
+      _xdg_mime_glob_read_from_file (global_hash, file_name, TRUE);
+      xdg_dir_time_list_add (file_name, st.st_mtime);
+    }
+  else
+    {
+      free (file_name);
+      file_name = malloc (strlen (directory) + strlen ("/mime/globs") + 1);
+      strcpy (file_name, directory); strcat (file_name, "/mime/globs");
+      if (stat (file_name, &st) == 0)
+        {
+          _xdg_mime_glob_read_from_file (global_hash, file_name, FALSE);
+          xdg_dir_time_list_add (file_name, st.st_mtime);
+        }
+      else
+        {
+          free (file_name);
+        }
+    }
+
+  file_name = malloc (strlen (directory) + strlen ("/mime/magic") + 1);
+  strcpy (file_name, directory); strcat (file_name, "/mime/magic");
+  if (stat (file_name, &st) == 0)
+    {
+      _xdg_mime_magic_read_from_file (global_magic, file_name);
+      xdg_dir_time_list_add (file_name, st.st_mtime);
+    }
+  else
+    {
+      free (file_name);
+    }
+
+  file_name = malloc (strlen (directory) + strlen ("/mime/aliases") + 1);
+  strcpy (file_name, directory); strcat (file_name, "/mime/aliases");
+  _xdg_mime_alias_read_from_file (alias_list, file_name);
+  free (file_name);
+
+  file_name = malloc (strlen (directory) + strlen ("/mime/subclasses") + 1);
+  strcpy (file_name, directory); strcat (file_name, "/mime/subclasses");
+  _xdg_mime_parent_read_from_file (parent_list, file_name);
+  free (file_name);
+
+  file_name = malloc (strlen (directory) + strlen ("/mime/icons") + 1);
+  strcpy (file_name, directory); strcat (file_name, "/mime/icons");
+  _xdg_mime_icon_read_from_file (icon_list, file_name);
+  free (file_name);
+
+  file_name = malloc (strlen (directory) + strlen ("/mime/generic-icons") + 1);
+  strcpy (file_name, directory); strcat (file_name, "/mime/generic-icons");
+  _xdg_mime_icon_read_from_file (generic_icon_list, file_name);
+  free (file_name);
+
+  return FALSE; /* Keep processing */
+}
+
+/* Runs a command on all the directories in the search path */
+static void
+xdg_run_command_on_dirs (XdgDirectoryFunc  func,
+			 void             *user_data)
+{
+  const char *xdg_data_home;
+  const char *xdg_data_dirs;
+  const char *ptr;
+
+  xdg_data_home = getenv ("XDG_DATA_HOME");
+  if (xdg_data_home)
+    {
+      if ((func) (xdg_data_home, user_data))
+	return;
+    }
+  else
+    {
+      const char *home;
+
+      home = getenv ("HOME");
+      if (home != NULL)
+	{
+	  char *guessed_xdg_home;
+	  int stop_processing;
+
+	  guessed_xdg_home = malloc (strlen (home) + strlen ("/.local/share/") + 1);
+	  strcpy (guessed_xdg_home, home);
+	  strcat (guessed_xdg_home, "/.local/share/");
+	  stop_processing = (func) (guessed_xdg_home, user_data);
+	  free (guessed_xdg_home);
+
+	  if (stop_processing)
+	    return;
+	}
+    }
+
+  xdg_data_dirs = getenv ("XDG_DATA_DIRS");
+  if (xdg_data_dirs == NULL)
+    xdg_data_dirs = "/usr/local/share/:/usr/share/";
+
+  ptr = xdg_data_dirs;
+
+  while (*ptr != '\000')
+    {
+      const char *end_ptr;
+      char *dir;
+      int len;
+      int stop_processing;
+
+      end_ptr = ptr;
+      while (*end_ptr != ':' && *end_ptr != '\000')
+	end_ptr ++;
+
+      if (end_ptr == ptr)
+	{
+	  ptr++;
+	  continue;
+	}
+
+      if (*end_ptr == ':')
+	len = end_ptr - ptr;
+      else
+	len = end_ptr - ptr + 1;
+      dir = malloc (len + 1);
+      strncpy (dir, ptr, len);
+      dir[len] = '\0';
+      stop_processing = (func) (dir, user_data);
+      free (dir);
+
+      if (stop_processing)
+	return;
+
+      ptr = end_ptr;
+    }
+}
+
+/* Checks file_path to make sure it has the same mtime as last time it was
+ * checked.  If it has a different mtime, or if the file doesn't exist, it
+ * returns FALSE.
+ *
+ * FIXME: This doesn't protect against permission changes.
+ */
+static int
+xdg_check_file (const char *file_path,
+                int        *exists)
+{
+  struct stat st;
+
+  /* If the file exists */
+  if (stat (file_path, &st) == 0)
+    {
+      XdgDirTimeList *list;
+
+      if (exists)
+        *exists = TRUE;
+
+      for (list = dir_time_list; list; list = list->next)
+	{
+	  if (! strcmp (list->directory_name, file_path))
+	    {
+	      if (st.st_mtime == list->mtime)
+		list->checked = XDG_CHECKED_VALID;
+	      else 
+		list->checked = XDG_CHECKED_INVALID;
+
+	      return (list->checked != XDG_CHECKED_VALID);
+	    }
+	}
+      return TRUE;
+    }
+
+  if (exists)
+    *exists = FALSE;
+
+  return FALSE;
+}
+
+static int
+xdg_check_dir (const char *directory,
+	       int        *invalid_dir_list)
+{
+  int invalid, exists;
+  char *file_name;
+
+  assert (directory != NULL);
+
+  /* Check the mime.cache file */
+  file_name = malloc (strlen (directory) + strlen ("/mime/mime.cache") + 1);
+  strcpy (file_name, directory); strcat (file_name, "/mime/mime.cache");
+  invalid = xdg_check_file (file_name, &exists);
+  free (file_name);
+  if (invalid)
+    {
+      *invalid_dir_list = TRUE;
+      return TRUE;
+    }
+  else if (exists)
+    {
+      return FALSE;
+    }
+
+  /* Check the globs file */
+  file_name = malloc (strlen (directory) + strlen ("/mime/globs") + 1);
+  strcpy (file_name, directory); strcat (file_name, "/mime/globs");
+  invalid = xdg_check_file (file_name, NULL);
+  free (file_name);
+  if (invalid)
+    {
+      *invalid_dir_list = TRUE;
+      return TRUE;
+    }
+
+  /* Check the magic file */
+  file_name = malloc (strlen (directory) + strlen ("/mime/magic") + 1);
+  strcpy (file_name, directory); strcat (file_name, "/mime/magic");
+  invalid = xdg_check_file (file_name, NULL);
+  free (file_name);
+  if (invalid)
+    {
+      *invalid_dir_list = TRUE;
+      return TRUE;
+    }
+
+  return FALSE; /* Keep processing */
+}
+
+/* Walks through all the mime files stat()ing them to see if they've changed.
+ * Returns TRUE if they have. */
+static int
+xdg_check_dirs (void)
+{
+  XdgDirTimeList *list;
+  int invalid_dir_list = FALSE;
+
+  for (list = dir_time_list; list; list = list->next)
+    list->checked = XDG_CHECKED_UNCHECKED;
+
+  xdg_run_command_on_dirs ((XdgDirectoryFunc) xdg_check_dir,
+			   &invalid_dir_list);
+
+  if (invalid_dir_list)
+    return TRUE;
+
+  for (list = dir_time_list; list; list = list->next)
+    {
+      if (list->checked != XDG_CHECKED_VALID)
+	return TRUE;
+    }
+
+  return FALSE;
+}
+
+/* We want to avoid stat()ing on every single mime call, so we only look for
+ * newer files every 5 seconds.  This will return TRUE if we need to reread the
+ * mime data from disk.
+ */
+static int
+xdg_check_time_and_dirs (void)
+{
+  struct timeval tv;
+  time_t current_time;
+  int retval = FALSE;
+
+  gettimeofday (&tv, NULL);
+  current_time = tv.tv_sec;
+
+  if (current_time >= last_stat_time + 5)
+    {
+      retval = xdg_check_dirs ();
+      last_stat_time = current_time;
+    }
+
+  return retval;
+}
+
+/* Called in every public function.  It reloads the hash function if need be.
+ */
+static void
+xdg_mime_init (void)
+{
+  if (xdg_check_time_and_dirs ())
+    {
+      xdg_mime_shutdown ();
+    }
+
+  if (need_reread)
+    {
+      global_hash = _xdg_glob_hash_new ();
+      global_magic = _xdg_mime_magic_new ();
+      alias_list = _xdg_mime_alias_list_new ();
+      parent_list = _xdg_mime_parent_list_new ();
+      icon_list = _xdg_mime_icon_list_new ();
+      generic_icon_list = _xdg_mime_icon_list_new ();
+
+      xdg_run_command_on_dirs ((XdgDirectoryFunc) xdg_mime_init_from_directory,
+			       NULL);
+
+      need_reread = FALSE;
+    }
+}
+
+const char *
+xdg_mime_get_mime_type_for_data (const void *data,
+				 size_t      len,
+				 int        *result_prio)
+{
+  const char *mime_type;
+
+  if (len == 0)
+    {
+      *result_prio = 100;
+      return XDG_MIME_TYPE_EMPTY;
+    }
+
+  xdg_mime_init ();
+
+  if (_caches)
+    mime_type = _xdg_mime_cache_get_mime_type_for_data (data, len, result_prio);
+  else
+    mime_type = _xdg_mime_magic_lookup_data (global_magic, data, len, result_prio, NULL, 0);
+
+  if (mime_type)
+    return mime_type;
+
+  return _xdg_binary_or_text_fallback(data, len);
+}
+
+const char *
+xdg_mime_get_mime_type_for_file (const char  *file_name,
+                                 struct stat *statbuf)
+{
+  const char *mime_type;
+  /* currently, only a few globs occur twice, and none
+   * more often, so 5 seems plenty.
+   */
+  const char *mime_types[5];
+  FILE *file;
+  unsigned char *data;
+  int max_extent;
+  int bytes_read;
+  struct stat buf;
+  const char *base_name;
+  int n;
+
+  if (file_name == NULL)
+    return NULL;
+  if (! _xdg_utf8_validate (file_name))
+    return NULL;
+
+  xdg_mime_init ();
+
+  if (_caches)
+    return _xdg_mime_cache_get_mime_type_for_file (file_name, statbuf);
+
+  base_name = _xdg_get_base_name (file_name);
+  n = _xdg_glob_hash_lookup_file_name (global_hash, base_name, mime_types, 5);
+
+  if (n == 1)
+    return mime_types[0];
+
+  if (!statbuf)
+    {
+      if (stat (file_name, &buf) != 0)
+	return XDG_MIME_TYPE_UNKNOWN;
+
+      statbuf = &buf;
+    }
+
+  if (!S_ISREG (statbuf->st_mode))
+    return XDG_MIME_TYPE_UNKNOWN;
+
+  /* FIXME: Need to make sure that max_extent isn't totally broken.  This could
+   * be large and need getting from a stream instead of just reading it all
+   * in. */
+  max_extent = _xdg_mime_magic_get_buffer_extents (global_magic);
+  data = malloc (max_extent);
+  if (data == NULL)
+    return XDG_MIME_TYPE_UNKNOWN;
+        
+  file = fopen (file_name, "r");
+  if (file == NULL)
+    {
+      free (data);
+      return XDG_MIME_TYPE_UNKNOWN;
+    }
+
+  bytes_read = fread (data, 1, max_extent, file);
+  if (ferror (file))
+    {
+      free (data);
+      fclose (file);
+      return XDG_MIME_TYPE_UNKNOWN;
+    }
+
+  mime_type = _xdg_mime_magic_lookup_data (global_magic, data, bytes_read, NULL,
+					   mime_types, n);
+
+  fclose (file);
+
+  if (!mime_type)
+    mime_type = _xdg_binary_or_text_fallback(data, bytes_read);
+
+  free (data);
+  return mime_type;
+}
+
+const char *
+xdg_mime_get_mime_type_from_file_name (const char *file_name)
+{
+  const char *mime_type;
+
+  xdg_mime_init ();
+
+  if (_caches)
+    return _xdg_mime_cache_get_mime_type_from_file_name (file_name);
+
+  if (_xdg_glob_hash_lookup_file_name (global_hash, file_name, &mime_type, 1))
+    return mime_type;
+  else
+    return XDG_MIME_TYPE_UNKNOWN;
+}
+
+int
+xdg_mime_get_mime_types_from_file_name (const char *file_name,
+					const char  *mime_types[],
+					int          n_mime_types)
+{
+  xdg_mime_init ();
+  
+  if (_caches)
+    return _xdg_mime_cache_get_mime_types_from_file_name (file_name, mime_types, n_mime_types);
+  
+  return _xdg_glob_hash_lookup_file_name (global_hash, file_name, mime_types, n_mime_types);
+}
+
+int
+xdg_mime_is_valid_mime_type (const char *mime_type)
+{
+  /* FIXME: We should make this a better test
+   */
+  return _xdg_utf8_validate (mime_type);
+}
+
+void
+xdg_mime_shutdown (void)
+{
+  XdgCallbackList *list;
+
+  /* FIXME: Need to make this (and the whole library) thread safe */
+  if (dir_time_list)
+    {
+      xdg_dir_time_list_free (dir_time_list);
+      dir_time_list = NULL;
+    }
+	
+  if (global_hash)
+    {
+      _xdg_glob_hash_free (global_hash);
+      global_hash = NULL;
+    }
+  if (global_magic)
+    {
+      _xdg_mime_magic_free (global_magic);
+      global_magic = NULL;
+    }
+
+  if (alias_list)
+    {
+      _xdg_mime_alias_list_free (alias_list);
+      alias_list = NULL;
+    }
+
+  if (parent_list)
+    {
+      _xdg_mime_parent_list_free (parent_list);
+      parent_list = NULL;
+    }
+
+  if (icon_list)
+    {
+      _xdg_mime_icon_list_free (icon_list);
+      icon_list = NULL;
+    }
+
+  if (generic_icon_list)
+    {
+      _xdg_mime_icon_list_free (generic_icon_list);
+      generic_icon_list = NULL;
+    }
+  
+  if (_caches)
+    {
+      int i;
+
+      for (i = 0; i < n_caches; i++)
+        _xdg_mime_cache_unref (_caches[i]);
+      free (_caches);
+      _caches = NULL;
+      n_caches = 0;
+    }
+
+  for (list = callback_list; list; list = list->next)
+    (list->callback) (list->data);
+
+  need_reread = TRUE;
+}
+
+int
+xdg_mime_get_max_buffer_extents (void)
+{
+  xdg_mime_init ();
+  
+  if (_caches)
+    return _xdg_mime_cache_get_max_buffer_extents ();
+
+  return _xdg_mime_magic_get_buffer_extents (global_magic);
+}
+
+const char *
+_xdg_mime_unalias_mime_type (const char *mime_type)
+{
+  const char *lookup;
+
+  if (_caches)
+    return _xdg_mime_cache_unalias_mime_type (mime_type);
+
+  if ((lookup = _xdg_mime_alias_list_lookup (alias_list, mime_type)) != NULL)
+    return lookup;
+
+  return mime_type;
+}
+
+const char *
+xdg_mime_unalias_mime_type (const char *mime_type)
+{
+  xdg_mime_init ();
+
+  return _xdg_mime_unalias_mime_type (mime_type);
+}
+
+int
+_xdg_mime_mime_type_equal (const char *mime_a,
+			   const char *mime_b)
+{
+  const char *unalias_a, *unalias_b;
+
+  unalias_a = _xdg_mime_unalias_mime_type (mime_a);
+  unalias_b = _xdg_mime_unalias_mime_type (mime_b);
+
+  if (strcmp (unalias_a, unalias_b) == 0)
+    return 1;
+
+  return 0;
+}
+
+int
+xdg_mime_mime_type_equal (const char *mime_a,
+			  const char *mime_b)
+{
+  xdg_mime_init ();
+
+  return _xdg_mime_mime_type_equal (mime_a, mime_b);
+}
+
+int
+xdg_mime_media_type_equal (const char *mime_a,
+			   const char *mime_b)
+{
+  char *sep;
+
+  sep = strchr (mime_a, '/');
+  
+  if (sep && strncmp (mime_a, mime_b, sep - mime_a + 1) == 0)
+    return 1;
+
+  return 0;
+}
+
+#if 1
+static int
+xdg_mime_is_super_type (const char *mime)
+{
+  int length;
+  const char *type;
+
+  length = strlen (mime);
+  type = &(mime[length - 2]);
+
+  if (strcmp (type, "/*") == 0)
+    return 1;
+
+  return 0;
+}
+#endif
+
+int
+_xdg_mime_mime_type_subclass (const char *mime,
+			      const char *base)
+{
+  const char *umime, *ubase;
+  const char **parents;
+
+  if (_caches)
+    return _xdg_mime_cache_mime_type_subclass (mime, base);
+
+  umime = _xdg_mime_unalias_mime_type (mime);
+  ubase = _xdg_mime_unalias_mime_type (base);
+
+  if (strcmp (umime, ubase) == 0)
+    return 1;
+
+#if 1  
+  /* Handle supertypes */
+  if (xdg_mime_is_super_type (ubase) &&
+      xdg_mime_media_type_equal (umime, ubase))
+    return 1;
+#endif
+
+  /*  Handle special cases text/plain and application/octet-stream */
+  if (strcmp (ubase, "text/plain") == 0 && 
+      strncmp (umime, "text/", 5) == 0)
+    return 1;
+
+  if (strcmp (ubase, "application/octet-stream") == 0)
+    return 1;
+  
+  parents = _xdg_mime_parent_list_lookup (parent_list, umime);
+  for (; parents && *parents; parents++)
+    {
+      if (_xdg_mime_mime_type_subclass (*parents, ubase))
+	return 1;
+    }
+
+  return 0;
+}
+
+int
+xdg_mime_mime_type_subclass (const char *mime,
+			     const char *base)
+{
+  xdg_mime_init ();
+
+  return _xdg_mime_mime_type_subclass (mime, base);
+}
+
+char **
+xdg_mime_list_mime_parents (const char *mime)
+{
+  const char **parents;
+  char **result;
+  int i, n;
+
+  if (_caches)
+    return _xdg_mime_cache_list_mime_parents (mime);
+
+  parents = xdg_mime_get_mime_parents (mime);
+
+  if (!parents)
+    return NULL;
+
+  for (i = 0; parents[i]; i++) ;
+  
+  n = (i + 1) * sizeof (char *);
+  result = (char **) malloc (n);
+  memcpy (result, parents, n);
+
+  return result;
+}
+
+const char **
+xdg_mime_get_mime_parents (const char *mime)
+{
+  const char *umime;
+
+  xdg_mime_init ();
+
+  umime = _xdg_mime_unalias_mime_type (mime);
+
+  return _xdg_mime_parent_list_lookup (parent_list, umime);
+}
+
+void 
+xdg_mime_dump (void)
+{
+  xdg_mime_init();
+
+  printf ("*** ALIASES ***\n\n");
+  _xdg_mime_alias_list_dump (alias_list);
+  printf ("\n*** PARENTS ***\n\n");
+  _xdg_mime_parent_list_dump (parent_list);
+  printf ("\n*** CACHE ***\n\n");
+  _xdg_glob_hash_dump (global_hash);
+  printf ("\n*** GLOBS ***\n\n");
+  _xdg_glob_hash_dump (global_hash);
+  printf ("\n*** GLOBS REVERSE TREE ***\n\n");
+  _xdg_mime_cache_glob_dump ();
+}
+
+
+/* Registers a function to be called every time the mime database reloads its files
+ */
+int
+xdg_mime_register_reload_callback (XdgMimeCallback  callback,
+				   void            *data,
+				   XdgMimeDestroy   destroy)
+{
+  XdgCallbackList *list_el;
+  static int callback_id = 1;
+
+  /* Make a new list element */
+  list_el = calloc (1, sizeof (XdgCallbackList));
+  list_el->callback_id = callback_id;
+  list_el->callback = callback;
+  list_el->data = data;
+  list_el->destroy = destroy;
+  list_el->next = callback_list;
+  if (list_el->next)
+    list_el->next->prev = list_el;
+
+  callback_list = list_el;
+  callback_id ++;
+
+  return callback_id - 1;
+}
+
+void
+xdg_mime_remove_callback (int callback_id)
+{
+  XdgCallbackList *list;
+
+  for (list = callback_list; list; list = list->next)
+    {
+      if (list->callback_id == callback_id)
+	{
+	  if (list->next)
+	    list->next = list->prev;
+
+	  if (list->prev)
+	    list->prev->next = list->next;
+	  else
+	    callback_list = list->next;
+
+	  /* invoke the destroy handler */
+	  (list->destroy) (list->data);
+	  free (list);
+	  return;
+	}
+    }
+}
+
+const char *
+xdg_mime_get_icon (const char *mime)
+{
+  xdg_mime_init ();
+  
+  if (_caches)
+    return _xdg_mime_cache_get_icon (mime);
+
+  return _xdg_mime_icon_list_lookup (icon_list, mime);
+}
+
+const char *
+xdg_mime_get_generic_icon (const char *mime)
+{
+  xdg_mime_init ();
+  
+  if (_caches)
+    return _xdg_mime_cache_get_generic_icon (mime);
+
+  return _xdg_mime_icon_list_lookup (generic_icon_list, mime);
+}
diff --git a/base/third_party/xdg_mime/xdgmime.h b/base/third_party/xdg_mime/xdgmime.h
new file mode 100644
index 0000000..6a34edf
--- /dev/null
+++ b/base/third_party/xdg_mime/xdgmime.h
@@ -0,0 +1,133 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* xdgmime.h: XDG Mime Spec mime resolver.  Based on version 0.11 of the spec.
+ *
+ * More info can be found at http://www.freedesktop.org/standards/
+ * 
+ * Copyright (C) 2003  Red Hat, Inc.
+ * Copyright (C) 2003  Jonathan Blandford <jrb@alum.mit.edu>
+ *
+ * Licensed under the Academic Free License version 2.0
+ * Or under the following terms:
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef __XDG_MIME_H__
+#define __XDG_MIME_H__
+
+#include <stdlib.h>
+#include <sys/stat.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#ifdef XDG_PREFIX
+#define XDG_ENTRY(func) _XDG_ENTRY2(XDG_PREFIX,func)
+#define _XDG_ENTRY2(prefix,func) _XDG_ENTRY3(prefix,func)
+#define _XDG_ENTRY3(prefix,func) prefix##_##func
+
+#define XDG_RESERVED_ENTRY(func) _XDG_RESERVED_ENTRY2(XDG_PREFIX,func)
+#define _XDG_RESERVED_ENTRY2(prefix,func) _XDG_RESERVED_ENTRY3(prefix,func)
+#define _XDG_RESERVED_ENTRY3(prefix,func) _##prefix##_##func
+#endif
+
+typedef void (*XdgMimeCallback) (void *user_data);
+typedef void (*XdgMimeDestroy)  (void *user_data);
+
+  
+#ifdef XDG_PREFIX
+#define xdg_mime_get_mime_type_for_data       XDG_ENTRY(get_mime_type_for_data)
+#define xdg_mime_get_mime_type_for_file       XDG_ENTRY(get_mime_type_for_file)
+#define xdg_mime_get_mime_type_from_file_name XDG_ENTRY(get_mime_type_from_file_name)
+#define xdg_mime_get_mime_types_from_file_name XDG_ENTRY(get_mime_types_from_file_name)
+#define xdg_mime_is_valid_mime_type           XDG_ENTRY(is_valid_mime_type)
+#define xdg_mime_mime_type_equal              XDG_ENTRY(mime_type_equal)
+#define xdg_mime_media_type_equal             XDG_ENTRY(media_type_equal)
+#define xdg_mime_mime_type_subclass           XDG_ENTRY(mime_type_subclass)
+#define xdg_mime_get_mime_parents             XDG_ENTRY(get_mime_parents)
+#define xdg_mime_list_mime_parents            XDG_ENTRY(list_mime_parents)
+#define xdg_mime_unalias_mime_type            XDG_ENTRY(unalias_mime_type)
+#define xdg_mime_get_max_buffer_extents       XDG_ENTRY(get_max_buffer_extents)
+#define xdg_mime_shutdown                     XDG_ENTRY(shutdown)
+#define xdg_mime_dump                         XDG_ENTRY(dump)
+#define xdg_mime_register_reload_callback     XDG_ENTRY(register_reload_callback)
+#define xdg_mime_remove_callback              XDG_ENTRY(remove_callback)
+#define xdg_mime_type_unknown                 XDG_ENTRY(type_unknown)
+#define xdg_mime_type_empty                   XDG_ENTRY(type_empty)
+#define xdg_mime_type_textplain               XDG_ENTRY(type_textplain)
+#define xdg_mime_get_icon                     XDG_ENTRY(get_icon)
+#define xdg_mime_get_generic_icon             XDG_ENTRY(get_generic_icon)
+
+#define _xdg_mime_mime_type_equal             XDG_RESERVED_ENTRY(mime_type_equal)
+#define _xdg_mime_mime_type_subclass          XDG_RESERVED_ENTRY(mime_type_subclass)
+#define _xdg_mime_unalias_mime_type           XDG_RESERVED_ENTRY(unalias_mime_type)  
+#endif
+
+extern const char xdg_mime_type_unknown[];
+extern const char xdg_mime_type_empty[];
+extern const char xdg_mime_type_textplain[];
+#define XDG_MIME_TYPE_UNKNOWN xdg_mime_type_unknown
+#define XDG_MIME_TYPE_EMPTY xdg_mime_type_empty
+#define XDG_MIME_TYPE_TEXTPLAIN xdg_mime_type_textplain
+
+const char  *xdg_mime_get_mime_type_for_data       (const void *data,
+						    size_t      len,
+						    int        *result_prio);
+const char  *xdg_mime_get_mime_type_for_file       (const char *file_name,
+                                                    struct stat *statbuf);
+const char  *xdg_mime_get_mime_type_from_file_name (const char *file_name);
+int          xdg_mime_get_mime_types_from_file_name(const char *file_name,
+						    const char *mime_types[],
+						    int         n_mime_types);
+int          xdg_mime_is_valid_mime_type           (const char *mime_type);
+int          xdg_mime_mime_type_equal              (const char *mime_a,
+						    const char *mime_b);
+int          xdg_mime_media_type_equal             (const char *mime_a,
+						    const char *mime_b);
+int          xdg_mime_mime_type_subclass           (const char *mime_a,
+						    const char *mime_b);
+  /* xdg_mime_get_mime_parents() is deprecated since it does
+   * not work correctly with caches. Use xdg_mime_list_parents() 
+   * instead, but notice that that function expects you to free
+   * the array it returns. 
+   */
+const char **xdg_mime_get_mime_parents		   (const char *mime);
+char **      xdg_mime_list_mime_parents		   (const char *mime);
+const char  *xdg_mime_unalias_mime_type		   (const char *mime);
+const char  *xdg_mime_get_icon                     (const char *mime);
+const char  *xdg_mime_get_generic_icon             (const char *mime);
+int          xdg_mime_get_max_buffer_extents       (void);
+void         xdg_mime_shutdown                     (void);
+void         xdg_mime_dump                         (void);
+int          xdg_mime_register_reload_callback     (XdgMimeCallback  callback,
+						    void            *data,
+						    XdgMimeDestroy   destroy);
+void         xdg_mime_remove_callback              (int              callback_id);
+
+   /* Private versions of functions that don't call xdg_mime_init () */
+int          _xdg_mime_mime_type_equal             (const char *mime_a,
+						    const char *mime_b);
+int          _xdg_mime_mime_type_subclass          (const char *mime,
+						    const char *base);
+const char  *_xdg_mime_unalias_mime_type           (const char *mime);
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __XDG_MIME_H__ */
diff --git a/base/third_party/xdg_mime/xdgmimealias.c b/base/third_party/xdg_mime/xdgmimealias.c
new file mode 100644
index 0000000..07d89eb
--- /dev/null
+++ b/base/third_party/xdg_mime/xdgmimealias.c
@@ -0,0 +1,184 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* xdgmimealias.c: Private file.  Datastructure for storing the aliases.
+ *
+ * More info can be found at http://www.freedesktop.org/standards/
+ *
+ * Copyright (C) 2004  Red Hat, Inc.
+ * Copyright (C) 2004  Matthias Clasen <mclasen@redhat.com>
+ *
+ * Licensed under the Academic Free License version 2.0
+ * Or under the following terms:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "xdgmimealias.h"
+#include "xdgmimeint.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <fnmatch.h>
+
+#ifndef	FALSE
+#define	FALSE	(0)
+#endif
+
+#ifndef	TRUE
+#define	TRUE	(!FALSE)
+#endif
+
+typedef struct XdgAlias XdgAlias;
+
+struct XdgAlias 
+{
+  char *alias;
+  char *mime_type;
+};
+
+struct XdgAliasList
+{
+  struct XdgAlias *aliases;
+  int n_aliases;
+};
+
+XdgAliasList *
+_xdg_mime_alias_list_new (void)
+{
+  XdgAliasList *list;
+
+  list = malloc (sizeof (XdgAliasList));
+
+  list->aliases = NULL;
+  list->n_aliases = 0;
+
+  return list;
+}
+
+void         
+_xdg_mime_alias_list_free (XdgAliasList *list)
+{
+  int i;
+
+  if (list->aliases)
+    {
+      for (i = 0; i < list->n_aliases; i++)
+	{
+	  free (list->aliases[i].alias);
+	  free (list->aliases[i].mime_type);
+	}
+      free (list->aliases);
+    }
+  free (list);
+}
+
+static int
+alias_entry_cmp (const void *v1, const void *v2)
+{
+  return strcmp (((XdgAlias *)v1)->alias, ((XdgAlias *)v2)->alias);
+}
+
+const char  *
+_xdg_mime_alias_list_lookup (XdgAliasList *list,
+			     const char   *alias)
+{
+  XdgAlias *entry;
+  XdgAlias key;
+
+  if (list->n_aliases > 0)
+    {
+      key.alias = (char *)alias;
+      key.mime_type = NULL;
+
+      entry = bsearch (&key, list->aliases, list->n_aliases,
+		       sizeof (XdgAlias), alias_entry_cmp);
+      if (entry)
+        return entry->mime_type;
+    }
+
+  return NULL;
+}
+
+void
+_xdg_mime_alias_read_from_file (XdgAliasList *list,
+				const char   *file_name)
+{
+  FILE *file;
+  char line[255];
+  int alloc;
+
+  file = fopen (file_name, "r");
+
+  if (file == NULL)
+    return;
+
+  /* FIXME: Not UTF-8 safe.  Doesn't work if lines are greater than 255 chars.
+   * Blah */
+  alloc = list->n_aliases + 16;
+  list->aliases = realloc (list->aliases, alloc * sizeof (XdgAlias));
+  while (fgets (line, 255, file) != NULL)
+    {
+      char *sep;
+      if (line[0] == '#')
+	continue;
+
+      sep = strchr (line, ' ');
+      if (sep == NULL)
+	continue;
+      *(sep++) = '\000';
+      sep[strlen (sep) -1] = '\000';
+      if (list->n_aliases == alloc)
+	{
+	  alloc <<= 1;
+	  list->aliases = realloc (list->aliases, 
+				   alloc * sizeof (XdgAlias));
+	}
+      list->aliases[list->n_aliases].alias = strdup (line);
+      list->aliases[list->n_aliases].mime_type = strdup (sep);
+      list->n_aliases++;
+    }
+  list->aliases = realloc (list->aliases, 
+			   list->n_aliases * sizeof (XdgAlias));
+
+  fclose (file);  
+  
+  if (list->n_aliases > 1)
+    qsort (list->aliases, list->n_aliases, 
+           sizeof (XdgAlias), alias_entry_cmp);
+}
+
+
+void
+_xdg_mime_alias_list_dump (XdgAliasList *list)
+{
+  int i;
+
+  if (list->aliases)
+    {
+      for (i = 0; i < list->n_aliases; i++)
+	{
+	  printf ("%s %s\n", 
+		  list->aliases[i].alias,
+		  list->aliases[i].mime_type);
+	}
+    }
+}
+
+
diff --git a/base/third_party/xdg_mime/xdgmimealias.h b/base/third_party/xdg_mime/xdgmimealias.h
new file mode 100644
index 0000000..3c28012
--- /dev/null
+++ b/base/third_party/xdg_mime/xdgmimealias.h
@@ -0,0 +1,51 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* xdgmimealias.h: Private file.  Datastructure for storing the aliases.
+ *
+ * More info can be found at http://www.freedesktop.org/standards/
+ *
+ * Copyright (C) 2004  Red Hat, Inc.
+ * Copyright (C) 200  Matthias Clasen <mclasen@redhat.com>
+ *
+ * Licensed under the Academic Free License version 2.0
+ * Or under the following terms:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __XDG_MIME_ALIAS_H__
+#define __XDG_MIME_ALIAS_H__
+
+#include "xdgmime.h"
+
+typedef struct XdgAliasList XdgAliasList;
+
+#ifdef XDG_PREFIX
+#define _xdg_mime_alias_read_from_file        XDG_RESERVED_ENTRY(alias_read_from_file)
+#define _xdg_mime_alias_list_new              XDG_RESERVED_ENTRY(alias_list_new)
+#define _xdg_mime_alias_list_free             XDG_RESERVED_ENTRY(alias_list_free)
+#define _xdg_mime_alias_list_lookup           XDG_RESERVED_ENTRY(alias_list_lookup)
+#define _xdg_mime_alias_list_dump             XDG_RESERVED_ENTRY(alias_list_dump)
+#endif
+
+void          _xdg_mime_alias_read_from_file (XdgAliasList *list,
+					      const char   *file_name);
+XdgAliasList *_xdg_mime_alias_list_new       (void);
+void          _xdg_mime_alias_list_free      (XdgAliasList *list);
+const char   *_xdg_mime_alias_list_lookup    (XdgAliasList *list,
+					      const char  *alias);
+void          _xdg_mime_alias_list_dump      (XdgAliasList *list);
+
+#endif /* __XDG_MIME_ALIAS_H__ */
diff --git a/base/third_party/xdg_mime/xdgmimecache.c b/base/third_party/xdg_mime/xdgmimecache.c
new file mode 100644
index 0000000..ddb8754
--- /dev/null
+++ b/base/third_party/xdg_mime/xdgmimecache.c
@@ -0,0 +1,1069 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* xdgmimealias.c: Private file.  mmappable caches for mime data
+ *
+ * More info can be found at http://www.freedesktop.org/standards/
+ *
+ * Copyright (C) 2005  Matthias Clasen <mclasen@redhat.com>
+ *
+ * Licensed under the Academic Free License version 2.0
+ * Or under the following terms:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <fnmatch.h>
+#include <assert.h>
+
+#include <netinet/in.h> /* for ntohl/ntohs */
+
+#define HAVE_MMAP 1
+
+#ifdef HAVE_MMAP
+#include <sys/mman.h>
+#else
+#warning Building xdgmime without MMAP support. Binary "mime.cache" files will not be used.
+#endif
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "xdgmimecache.h"
+#include "xdgmimeint.h"
+
+#ifndef MAX
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#endif
+
+#ifndef	FALSE
+#define	FALSE	(0)
+#endif
+
+#ifndef	TRUE
+#define	TRUE	(!FALSE)
+#endif
+
+#ifndef _O_BINARY
+#define _O_BINARY 0
+#endif
+
+#ifndef MAP_FAILED
+#define MAP_FAILED ((void *) -1)
+#endif
+
+#define MAJOR_VERSION 1
+#define MINOR_VERSION_MIN 1
+#define MINOR_VERSION_MAX 2
+
+struct _XdgMimeCache
+{
+  int ref_count;
+  int minor;
+
+  size_t  size;
+  char   *buffer;
+};
+
+#define GET_UINT16(cache,offset) (ntohs(*(xdg_uint16_t*)((cache) + (offset))))
+#define GET_UINT32(cache,offset) (ntohl(*(xdg_uint32_t*)((cache) + (offset))))
+
+XdgMimeCache *
+_xdg_mime_cache_ref (XdgMimeCache *cache)
+{
+  cache->ref_count++;
+  return cache;
+}
+
+void
+_xdg_mime_cache_unref (XdgMimeCache *cache)
+{
+  cache->ref_count--;
+
+  if (cache->ref_count == 0)
+    {
+#ifdef HAVE_MMAP
+      munmap (cache->buffer, cache->size);
+#endif
+      free (cache);
+    }
+}
+
+XdgMimeCache *
+_xdg_mime_cache_new_from_file (const char *file_name)
+{
+  XdgMimeCache *cache = NULL;
+
+#ifdef HAVE_MMAP
+  int fd = -1;
+  struct stat st;
+  char *buffer = NULL;
+  int minor;
+
+  /* Open the file and map it into memory */
+  fd = open (file_name, O_RDONLY|_O_BINARY, 0);
+
+  if (fd < 0)
+    return NULL;
+  
+  if (fstat (fd, &st) < 0 || st.st_size < 4)
+    goto done;
+
+  buffer = (char *) mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
+
+  if (buffer == MAP_FAILED)
+    goto done;
+
+  minor = GET_UINT16 (buffer, 2);
+  /* Verify version */
+  if (GET_UINT16 (buffer, 0) != MAJOR_VERSION ||
+      (minor < MINOR_VERSION_MIN ||
+       minor > MINOR_VERSION_MAX))
+    {
+      munmap (buffer, st.st_size);
+
+      goto done;
+    }
+  
+  cache = (XdgMimeCache *) malloc (sizeof (XdgMimeCache));
+  cache->minor = minor;
+  cache->ref_count = 1;
+  cache->buffer = buffer;
+  cache->size = st.st_size;
+
+ done:
+  if (fd != -1)
+    close (fd);
+
+#endif  /* HAVE_MMAP */
+
+  return cache;
+}
+
+static int
+cache_magic_matchlet_compare_to_data (XdgMimeCache *cache, 
+				      xdg_uint32_t  offset,
+				      const void   *data,
+				      size_t        len)
+{
+  xdg_uint32_t range_start = GET_UINT32 (cache->buffer, offset);
+  xdg_uint32_t range_length = GET_UINT32 (cache->buffer, offset + 4);
+  xdg_uint32_t data_length = GET_UINT32 (cache->buffer, offset + 12);
+  xdg_uint32_t data_offset = GET_UINT32 (cache->buffer, offset + 16);
+  xdg_uint32_t mask_offset = GET_UINT32 (cache->buffer, offset + 20);
+  
+  int i, j;
+
+  for (i = range_start; i < range_start + range_length; i++)
+    {
+      int valid_matchlet = TRUE;
+      
+      if (i + data_length > len)
+	return FALSE;
+
+      if (mask_offset)
+	{
+	  for (j = 0; j < data_length; j++)
+	    {
+	      if ((((unsigned char *)cache->buffer)[data_offset + j] & ((unsigned char *)cache->buffer)[mask_offset + j]) !=
+		  ((((unsigned char *) data)[j + i]) & ((unsigned char *)cache->buffer)[mask_offset + j]))
+		{
+		  valid_matchlet = FALSE;
+		  break;
+		}
+	    }
+	}
+      else
+	{
+	  valid_matchlet = memcmp(cache->buffer + data_offset, data + i, data_length) == 0;
+	}
+
+      if (valid_matchlet)
+	return TRUE;
+    }
+  
+  return FALSE;  
+}
+
+static int
+cache_magic_matchlet_compare (XdgMimeCache *cache, 
+			      xdg_uint32_t  offset,
+			      const void   *data,
+			      size_t        len)
+{
+  xdg_uint32_t n_children = GET_UINT32 (cache->buffer, offset + 24);
+  xdg_uint32_t child_offset = GET_UINT32 (cache->buffer, offset + 28);
+
+  int i;
+  
+  if (cache_magic_matchlet_compare_to_data (cache, offset, data, len))
+    {
+      if (n_children == 0)
+	return TRUE;
+      
+      for (i = 0; i < n_children; i++)
+	{
+	  if (cache_magic_matchlet_compare (cache, child_offset + 32 * i,
+					    data, len))
+	    return TRUE;
+	}
+    }
+  
+  return FALSE;  
+}
+
+static const char *
+cache_magic_compare_to_data (XdgMimeCache *cache, 
+			     xdg_uint32_t  offset,
+			     const void   *data, 
+			     size_t        len, 
+			     int          *prio)
+{
+  xdg_uint32_t priority = GET_UINT32 (cache->buffer, offset);
+  xdg_uint32_t mimetype_offset = GET_UINT32 (cache->buffer, offset + 4);
+  xdg_uint32_t n_matchlets = GET_UINT32 (cache->buffer, offset + 8);
+  xdg_uint32_t matchlet_offset = GET_UINT32 (cache->buffer, offset + 12);
+
+  int i;
+
+  for (i = 0; i < n_matchlets; i++)
+    {
+      if (cache_magic_matchlet_compare (cache, matchlet_offset + i * 32, 
+					data, len))
+	{
+	  *prio = priority;
+	  
+	  return cache->buffer + mimetype_offset;
+	}
+    }
+
+  return NULL;
+}
+
+static const char *
+cache_magic_lookup_data (XdgMimeCache *cache, 
+			 const void   *data, 
+			 size_t        len, 
+			 int          *prio,
+			 const char   *mime_types[],
+			 int           n_mime_types)
+{
+  xdg_uint32_t list_offset;
+  xdg_uint32_t n_entries;
+  xdg_uint32_t offset;
+
+  int j, n;
+
+  *prio = 0;
+
+  list_offset = GET_UINT32 (cache->buffer, 24);
+  n_entries = GET_UINT32 (cache->buffer, list_offset);
+  offset = GET_UINT32 (cache->buffer, list_offset + 8);
+  
+  for (j = 0; j < n_entries; j++)
+    {
+      const char *match;
+
+      match = cache_magic_compare_to_data (cache, offset + 16 * j, 
+					   data, len, prio);
+      if (match)
+	return match;
+      else
+	{
+	  xdg_uint32_t mimetype_offset;
+	  const char *non_match;
+	  
+	  mimetype_offset = GET_UINT32 (cache->buffer, offset + 16 * j + 4);
+	  non_match = cache->buffer + mimetype_offset;
+
+	  for (n = 0; n < n_mime_types; n++)
+	    {
+	      if (mime_types[n] && 
+		  _xdg_mime_mime_type_equal (mime_types[n], non_match))
+		mime_types[n] = NULL;
+	    }
+	}
+    }
+
+  return NULL;
+}
+
+static const char *
+cache_alias_lookup (const char *alias)
+{
+  const char *ptr;
+  int i, min, max, mid, cmp;
+
+  for (i = 0; _caches[i]; i++)
+    {
+      XdgMimeCache *cache = _caches[i];
+      xdg_uint32_t list_offset = GET_UINT32 (cache->buffer, 4);
+      xdg_uint32_t n_entries = GET_UINT32 (cache->buffer, list_offset);
+      xdg_uint32_t offset;
+
+      min = 0; 
+      max = n_entries - 1;
+      while (max >= min) 
+	{
+	  mid = (min + max) / 2;
+
+	  offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * mid);
+	  ptr = cache->buffer + offset;
+	  cmp = strcmp (ptr, alias);
+	  
+	  if (cmp < 0)
+	    min = mid + 1;
+	  else if (cmp > 0)
+	    max = mid - 1;
+	  else
+	    {
+	      offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * mid + 4);
+	      return cache->buffer + offset;
+	    }
+	}
+    }
+
+  return NULL;
+}
+
+typedef struct {
+  const char *mime;
+  int weight;
+} MimeWeight;
+
+static int
+cache_glob_lookup_literal (const char *file_name,
+			   const char *mime_types[],
+			   int         n_mime_types,
+			   int         case_sensitive_check)
+{
+  const char *ptr;
+  int i, min, max, mid, cmp;
+
+  for (i = 0; _caches[i]; i++)
+    {
+      XdgMimeCache *cache = _caches[i];
+      xdg_uint32_t list_offset = GET_UINT32 (cache->buffer, 12);
+      xdg_uint32_t n_entries = GET_UINT32 (cache->buffer, list_offset);
+      xdg_uint32_t offset;
+
+      min = 0; 
+      max = n_entries - 1;
+      while (max >= min) 
+	{
+	  mid = (min + max) / 2;
+
+	  offset = GET_UINT32 (cache->buffer, list_offset + 4 + 12 * mid);
+	  ptr = cache->buffer + offset;
+	  cmp = strcmp (ptr, file_name);
+
+	  if (cmp < 0)
+	    min = mid + 1;
+	  else if (cmp > 0)
+	    max = mid - 1;
+	  else
+	    {
+	      int weight = GET_UINT32 (cache->buffer, list_offset + 4 + 12 * mid + 8);
+	      int case_sensitive = weight & 0x100;
+	      weight = weight & 0xff;
+
+	      if (case_sensitive_check || !case_sensitive)
+		{
+		  offset = GET_UINT32 (cache->buffer, list_offset + 4 + 12 * mid + 4);
+		  mime_types[0] = (const char *)(cache->buffer + offset);
+
+		  return 1;
+		}
+	      return 0;
+	    }
+	}
+    }
+
+  return 0;
+}
+
+static int
+cache_glob_lookup_fnmatch (const char *file_name,
+			   MimeWeight  mime_types[],
+			   int         n_mime_types,
+			   int         case_sensitive_check)
+{
+  const char *mime_type;
+  const char *ptr;
+
+  int i, j, n;
+
+  n = 0;
+  for (i = 0; _caches[i]; i++)
+    {
+      XdgMimeCache *cache = _caches[i];
+
+      xdg_uint32_t list_offset = GET_UINT32 (cache->buffer, 20);
+      xdg_uint32_t n_entries = GET_UINT32 (cache->buffer, list_offset);
+
+      for (j = 0; j < n_entries && n < n_mime_types; j++)
+	{
+	  xdg_uint32_t offset = GET_UINT32 (cache->buffer, list_offset + 4 + 12 * j);
+	  xdg_uint32_t mimetype_offset = GET_UINT32 (cache->buffer, list_offset + 4 + 12 * j + 4);
+	  int weight = GET_UINT32 (cache->buffer, list_offset + 4 + 12 * j + 8);
+	  int case_sensitive = weight & 0x100;
+	  weight = weight & 0xff;
+	  ptr = cache->buffer + offset;
+	  mime_type = cache->buffer + mimetype_offset;
+	  if (case_sensitive_check || !case_sensitive)
+	    {
+	      /* FIXME: Not UTF-8 safe */
+	      if (fnmatch (ptr, file_name, 0) == 0)
+	        {
+	          mime_types[n].mime = mime_type;
+	          mime_types[n].weight = weight;
+	          n++;
+	        }
+	    }
+	}
+
+      if (n > 0)
+	return n;
+    }
+  
+  return 0;
+}
+
+static int
+cache_glob_node_lookup_suffix (XdgMimeCache  *cache,
+			       xdg_uint32_t   n_entries,
+			       xdg_uint32_t   offset,
+			       const char    *file_name,
+			       int            len,
+			       int            case_sensitive_check,
+			       MimeWeight     mime_types[],
+			       int            n_mime_types)
+{
+  xdg_unichar_t character;
+  xdg_unichar_t match_char;
+  xdg_uint32_t mimetype_offset;
+  xdg_uint32_t n_children;
+  xdg_uint32_t child_offset; 
+  int weight;
+  int case_sensitive;
+
+  int min, max, mid, n, i;
+
+  character = file_name[len - 1];
+
+  assert (character != 0);
+
+  min = 0;
+  max = n_entries - 1;
+  while (max >= min)
+    {
+      mid = (min + max) /  2;
+      match_char = GET_UINT32 (cache->buffer, offset + 12 * mid);
+      if (match_char < character)
+	min = mid + 1;
+      else if (match_char > character)
+	max = mid - 1;
+      else 
+	{
+          len--;
+          n = 0;
+          n_children = GET_UINT32 (cache->buffer, offset + 12 * mid + 4);
+          child_offset = GET_UINT32 (cache->buffer, offset + 12 * mid + 8);
+      
+          if (len > 0)
+            {
+              n = cache_glob_node_lookup_suffix (cache, 
+                                                 n_children, child_offset,
+                                                 file_name, len, 
+                                                 case_sensitive_check,
+                                                 mime_types,
+                                                 n_mime_types);
+            }
+          if (n == 0)
+            {
+	      i = 0;
+	      while (n < n_mime_types && i < n_children)
+		{
+		  match_char = GET_UINT32 (cache->buffer, child_offset + 12 * i);
+		  if (match_char != 0)
+		    break;
+
+		  mimetype_offset = GET_UINT32 (cache->buffer, child_offset + 12 * i + 4);
+		  weight = GET_UINT32 (cache->buffer, child_offset + 12 * i + 8);
+		  case_sensitive = weight & 0x100;
+		  weight = weight & 0xff;
+
+		  if (case_sensitive_check || !case_sensitive)
+		    {
+		      mime_types[n].mime = cache->buffer + mimetype_offset;
+		      mime_types[n].weight = weight;
+		      n++;
+		    }
+		  i++;
+		}
+	    }
+	  return n;
+	}
+    }
+  return 0;
+}
+
+static int
+cache_glob_lookup_suffix (const char *file_name,
+			  int         len,
+			  int         ignore_case,
+			  MimeWeight  mime_types[],
+			  int         n_mime_types)
+{
+  int i, n;
+
+  for (i = 0; _caches[i]; i++)
+    {
+      XdgMimeCache *cache = _caches[i];
+
+      xdg_uint32_t list_offset = GET_UINT32 (cache->buffer, 16);
+      xdg_uint32_t n_entries = GET_UINT32 (cache->buffer, list_offset);
+      xdg_uint32_t offset = GET_UINT32 (cache->buffer, list_offset + 4);
+
+      n = cache_glob_node_lookup_suffix (cache, 
+					 n_entries, offset, 
+					 file_name, len,
+					 ignore_case,
+					 mime_types,
+					 n_mime_types);
+      if (n > 0)
+	return n;
+    }
+
+  return 0;
+}
+
+static int compare_mime_weight (const void *a, const void *b)
+{
+  const MimeWeight *aa = (const MimeWeight *)a;
+  const MimeWeight *bb = (const MimeWeight *)b;
+
+  return bb->weight - aa->weight;
+}
+
+#define ISUPPER(c)		((c) >= 'A' && (c) <= 'Z')
+static char *
+ascii_tolower (const char *str)
+{
+  char *p, *lower;
+
+  lower = strdup (str);
+  p = lower;
+  while (*p != 0)
+    {
+      char c = *p;
+      *p++ = ISUPPER (c) ? c - 'A' + 'a' : c;
+    }
+  return lower;
+}
+
+static int
+cache_glob_lookup_file_name (const char *file_name, 
+			     const char *mime_types[],
+			     int         n_mime_types)
+{
+  int n;
+  MimeWeight mimes[10];
+  int n_mimes = 10;
+  int i;
+  int len;
+  char *lower_case;
+
+  assert (file_name != NULL && n_mime_types > 0);
+
+  /* First, check the literals */
+
+  lower_case = ascii_tolower (file_name);
+
+  n = cache_glob_lookup_literal (lower_case, mime_types, n_mime_types, FALSE);
+  if (n > 0)
+    {
+      free (lower_case);
+      return n;
+    }
+
+  n = cache_glob_lookup_literal (file_name, mime_types, n_mime_types, TRUE);
+  if (n > 0)
+    {
+      free (lower_case);
+      return n;
+    }
+
+  len = strlen (file_name);
+  n = cache_glob_lookup_suffix (lower_case, len, FALSE, mimes, n_mimes);
+  if (n == 0)
+    n = cache_glob_lookup_suffix (file_name, len, TRUE, mimes, n_mimes);
+
+  /* Last, try fnmatch */
+  if (n == 0)
+    n = cache_glob_lookup_fnmatch (lower_case, mimes, n_mimes, FALSE);
+  if (n == 0)
+    n = cache_glob_lookup_fnmatch (file_name, mimes, n_mimes, TRUE);
+
+  free (lower_case);
+
+  qsort (mimes, n, sizeof (MimeWeight), compare_mime_weight);
+
+  if (n_mime_types < n)
+    n = n_mime_types;
+
+  for (i = 0; i < n; i++)
+    mime_types[i] = mimes[i].mime;
+
+  return n;
+}
+
+int
+_xdg_mime_cache_get_max_buffer_extents (void)
+{
+  xdg_uint32_t offset;
+  xdg_uint32_t max_extent;
+  int i;
+
+  max_extent = 0;
+  for (i = 0; _caches[i]; i++)
+    {
+      XdgMimeCache *cache = _caches[i];
+
+      offset = GET_UINT32 (cache->buffer, 24);
+      max_extent = MAX (max_extent, GET_UINT32 (cache->buffer, offset + 4));
+    }
+
+  return max_extent;
+}
+
+static const char *
+cache_get_mime_type_for_data (const void *data,
+			      size_t      len,
+			      int        *result_prio,
+			      const char *mime_types[],
+			      int         n_mime_types)
+{
+  const char *mime_type;
+  int i, n, priority;
+
+  priority = 0;
+  mime_type = NULL;
+  for (i = 0; _caches[i]; i++)
+    {
+      XdgMimeCache *cache = _caches[i];
+
+      int prio;
+      const char *match;
+
+      match = cache_magic_lookup_data (cache, data, len, &prio, 
+				       mime_types, n_mime_types);
+      if (prio > priority)
+	{
+	  priority = prio;
+	  mime_type = match;
+	}
+    }
+
+  if (result_prio)
+    *result_prio = priority;
+
+  if (priority > 0)
+    {
+      /* Pick glob-result R where mime_type inherits from R */
+      for (n = 0; n < n_mime_types; n++)
+        {
+          if (mime_types[n] && _xdg_mime_cache_mime_type_subclass(mime_types[n], mime_type))
+              return mime_types[n];
+        }
+
+      /* Return magic match */
+      return mime_type;
+    }
+
+  /* Pick first glob result, as fallback */
+  for (n = 0; n < n_mime_types; n++)
+    {
+      if (mime_types[n])
+        return mime_types[n];
+    }
+
+  return NULL;
+}
+
+const char *
+_xdg_mime_cache_get_mime_type_for_data (const void *data,
+					size_t      len,
+					int        *result_prio)
+{
+  return cache_get_mime_type_for_data (data, len, result_prio, NULL, 0);
+}
+
+const char *
+_xdg_mime_cache_get_mime_type_for_file (const char  *file_name,
+					struct stat *statbuf)
+{
+  const char *mime_type;
+  const char *mime_types[10];
+  FILE *file;
+  unsigned char *data;
+  int max_extent;
+  int bytes_read;
+  struct stat buf;
+  const char *base_name;
+  int n;
+
+  if (file_name == NULL)
+    return NULL;
+
+  if (! _xdg_utf8_validate (file_name))
+    return NULL;
+
+  base_name = _xdg_get_base_name (file_name);
+  n = cache_glob_lookup_file_name (base_name, mime_types, 10);
+
+  if (n == 1)
+    return mime_types[0];
+
+  if (!statbuf)
+    {
+      if (stat (file_name, &buf) != 0)
+	return XDG_MIME_TYPE_UNKNOWN;
+
+      statbuf = &buf;
+    }
+
+  if (statbuf->st_size == 0)
+    return XDG_MIME_TYPE_EMPTY;
+
+  if (!S_ISREG (statbuf->st_mode))
+    return XDG_MIME_TYPE_UNKNOWN;
+
+  /* FIXME: Need to make sure that max_extent isn't totally broken.  This could
+   * be large and need getting from a stream instead of just reading it all
+   * in. */
+  max_extent = _xdg_mime_cache_get_max_buffer_extents ();
+  data = malloc (max_extent);
+  if (data == NULL)
+    return XDG_MIME_TYPE_UNKNOWN;
+        
+  file = fopen (file_name, "r");
+  if (file == NULL)
+    {
+      free (data);
+      return XDG_MIME_TYPE_UNKNOWN;
+    }
+
+  bytes_read = fread (data, 1, max_extent, file);
+  if (ferror (file))
+    {
+      free (data);
+      fclose (file);
+      return XDG_MIME_TYPE_UNKNOWN;
+    }
+
+  mime_type = cache_get_mime_type_for_data (data, bytes_read, NULL,
+					    mime_types, n);
+
+  if (!mime_type)
+    mime_type = _xdg_binary_or_text_fallback(data, bytes_read);
+
+  free (data);
+  fclose (file);
+
+  return mime_type;
+}
+
+const char *
+_xdg_mime_cache_get_mime_type_from_file_name (const char *file_name)
+{
+  const char *mime_type;
+
+  if (cache_glob_lookup_file_name (file_name, &mime_type, 1))
+    return mime_type;
+  else
+    return XDG_MIME_TYPE_UNKNOWN;
+}
+
+int
+_xdg_mime_cache_get_mime_types_from_file_name (const char *file_name,
+					       const char  *mime_types[],
+					       int          n_mime_types)
+{
+  return cache_glob_lookup_file_name (file_name, mime_types, n_mime_types);
+}
+
+#if 1
+static int
+is_super_type (const char *mime)
+{
+  int length;
+  const char *type;
+
+  length = strlen (mime);
+  type = &(mime[length - 2]);
+
+  if (strcmp (type, "/*") == 0)
+    return 1;
+
+  return 0;
+}
+#endif
+
+int
+_xdg_mime_cache_mime_type_subclass (const char *mime,
+				    const char *base)
+{
+  const char *umime, *ubase;
+
+  int i, j, min, max, med, cmp;
+  
+  umime = _xdg_mime_cache_unalias_mime_type (mime);
+  ubase = _xdg_mime_cache_unalias_mime_type (base);
+
+  if (strcmp (umime, ubase) == 0)
+    return 1;
+
+  /* We really want to handle text/ * in GtkFileFilter, so we just
+   * turn on the supertype matching
+   */
+#if 1
+  /* Handle supertypes */
+  if (is_super_type (ubase) &&
+      xdg_mime_media_type_equal (umime, ubase))
+    return 1;
+#endif
+
+  /*  Handle special cases text/plain and application/octet-stream */
+  if (strcmp (ubase, "text/plain") == 0 && 
+      strncmp (umime, "text/", 5) == 0)
+    return 1;
+
+  if (strcmp (ubase, "application/octet-stream") == 0)
+    return 1;
+ 
+  for (i = 0; _caches[i]; i++)
+    {
+      XdgMimeCache *cache = _caches[i];
+      
+      xdg_uint32_t list_offset = GET_UINT32 (cache->buffer, 8);
+      xdg_uint32_t n_entries = GET_UINT32 (cache->buffer, list_offset);
+      xdg_uint32_t offset, n_parents, parent_offset;
+
+      min = 0; 
+      max = n_entries - 1;
+      while (max >= min)
+	{
+	  med = (min + max)/2;
+	  
+	  offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * med);
+	  cmp = strcmp (cache->buffer + offset, umime);
+	  if (cmp < 0)
+	    min = med + 1;
+	  else if (cmp > 0)
+	    max = med - 1;
+	  else
+	    {
+	      offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * med + 4);
+	      n_parents = GET_UINT32 (cache->buffer, offset);
+	      
+	      for (j = 0; j < n_parents; j++)
+		{
+		  parent_offset = GET_UINT32 (cache->buffer, offset + 4 + 4 * j);
+		  if (_xdg_mime_cache_mime_type_subclass (cache->buffer + parent_offset, ubase))
+		    return 1;
+		}
+
+	      break;
+	    }
+	}
+    }
+
+  return 0;
+}
+
+const char *
+_xdg_mime_cache_unalias_mime_type (const char *mime)
+{
+  const char *lookup;
+  
+  lookup = cache_alias_lookup (mime);
+  
+  if (lookup)
+    return lookup;
+  
+  return mime;  
+}
+
+char **
+_xdg_mime_cache_list_mime_parents (const char *mime)
+{
+  int i, j, k, l, p;
+  char *all_parents[128]; /* we'll stop at 128 */ 
+  char **result;
+
+  mime = xdg_mime_unalias_mime_type (mime);
+
+  p = 0;
+  for (i = 0; _caches[i]; i++)
+    {
+      XdgMimeCache *cache = _caches[i];
+  
+      xdg_uint32_t list_offset = GET_UINT32 (cache->buffer, 8);
+      xdg_uint32_t n_entries = GET_UINT32 (cache->buffer, list_offset);
+
+      for (j = 0; j < n_entries; j++)
+	{
+	  xdg_uint32_t mimetype_offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * j);
+	  xdg_uint32_t parents_offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * j + 4);
+
+	  if (strcmp (cache->buffer + mimetype_offset, mime) == 0)
+	    {
+	      xdg_uint32_t parent_mime_offset;
+	      xdg_uint32_t n_parents = GET_UINT32 (cache->buffer, parents_offset);
+
+	      for (k = 0; k < n_parents && p < 127; k++)
+		{
+		  parent_mime_offset = GET_UINT32 (cache->buffer, parents_offset + 4 + 4 * k);
+
+		  /* Don't add same parent multiple times.
+		   * This can happen for instance if the same type is listed in multiple directories
+		   */
+		  for (l = 0; l < p; l++)
+		    {
+		      if (strcmp (all_parents[l], cache->buffer + parent_mime_offset) == 0)
+			break;
+		    }
+
+		  if (l == p)
+		    all_parents[p++] = cache->buffer + parent_mime_offset;
+		}
+
+	      break;
+	    }
+	}
+    }
+  all_parents[p++] = NULL;
+  
+  result = (char **) malloc (p * sizeof (char *));
+  memcpy (result, all_parents, p * sizeof (char *));
+
+  return result;
+}
+
+static const char *
+cache_lookup_icon (const char *mime, int header)
+{
+  const char *ptr;
+  int i, min, max, mid, cmp;
+
+  for (i = 0; _caches[i]; i++)
+    {
+      XdgMimeCache *cache = _caches[i];
+      xdg_uint32_t list_offset = GET_UINT32 (cache->buffer, header);
+      xdg_uint32_t n_entries = GET_UINT32 (cache->buffer, list_offset);
+      xdg_uint32_t offset;
+
+      min = 0; 
+      max = n_entries - 1;
+      while (max >= min) 
+        {
+          mid = (min + max) / 2;
+
+          offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * mid);
+          ptr = cache->buffer + offset;
+          cmp = strcmp (ptr, mime);
+         
+          if (cmp < 0)
+            min = mid + 1;
+          else if (cmp > 0)
+            max = mid - 1;
+          else
+            {
+              offset = GET_UINT32 (cache->buffer, list_offset + 4 + 8 * mid + 4);
+              return cache->buffer + offset;
+            }
+        }
+    }
+
+  return NULL;
+}
+
+const char *
+_xdg_mime_cache_get_generic_icon (const char *mime)
+{
+  return cache_lookup_icon (mime, 36);
+}
+
+const char *
+_xdg_mime_cache_get_icon (const char *mime)
+{
+  return cache_lookup_icon (mime, 32);
+}
+
+static void
+dump_glob_node (XdgMimeCache *cache,
+		xdg_uint32_t  offset,
+		int           depth)
+{
+  xdg_unichar_t character;
+  xdg_uint32_t mime_offset;
+  xdg_uint32_t n_children;
+  xdg_uint32_t child_offset;
+  int i;
+
+  character = GET_UINT32 (cache->buffer, offset);
+  mime_offset = GET_UINT32 (cache->buffer, offset + 4);
+  n_children = GET_UINT32 (cache->buffer, offset + 8);
+  child_offset = GET_UINT32 (cache->buffer, offset + 12);
+  for (i = 0; i < depth; i++)
+    printf (" ");
+  printf ("%c", character);
+  if (mime_offset)
+    printf (" - %s", cache->buffer + mime_offset);
+  printf ("\n");
+  if (child_offset)
+  {
+    for (i = 0; i < n_children; i++)
+      dump_glob_node (cache, child_offset + 20 * i, depth + 1);
+  }
+}
+
+void
+_xdg_mime_cache_glob_dump (void)
+{
+  int i, j;
+  for (i = 0; _caches[i]; i++)
+  {
+    XdgMimeCache *cache = _caches[i];
+    xdg_uint32_t list_offset;
+    xdg_uint32_t n_entries;
+    xdg_uint32_t offset;
+    list_offset = GET_UINT32 (cache->buffer, 16);
+    n_entries = GET_UINT32 (cache->buffer, list_offset);
+    offset = GET_UINT32 (cache->buffer, list_offset + 4);
+    for (j = 0; j < n_entries; j++)
+	    dump_glob_node (cache, offset + 20 * j, 0);
+  }
+}
diff --git a/base/third_party/xdg_mime/xdgmimecache.h b/base/third_party/xdg_mime/xdgmimecache.h
new file mode 100644
index 0000000..27f42d0
--- /dev/null
+++ b/base/third_party/xdg_mime/xdgmimecache.h
@@ -0,0 +1,81 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* xdgmimecache.h: Private file.  Datastructure for mmapped caches.
+ *
+ * More info can be found at http://www.freedesktop.org/standards/
+ *
+ * Copyright (C) 2005  Matthias Clasen <mclasen@redhat.com>
+ *
+ * Licensed under the Academic Free License version 2.0
+ * Or under the following terms:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __XDG_MIME_CACHE_H__
+#define __XDG_MIME_CACHE_H__
+
+#include "xdgmime.h"
+
+typedef struct _XdgMimeCache XdgMimeCache;
+
+#ifdef XDG_PREFIX
+#define _xdg_mime_cache_new_from_file                 XDG_RESERVED_ENTRY(cache_new_from_file)
+#define _xdg_mime_cache_ref                           XDG_RESERVED_ENTRY(cache_ref)
+#define _xdg_mime_cache_unref                         XDG_RESERVED_ENTRY(cache_unref)
+#define _xdg_mime_cache_get_max_buffer_extents        XDG_RESERVED_ENTRY(cache_get_max_buffer_extents)
+#define _xdg_mime_cache_get_mime_type_for_data        XDG_RESERVED_ENTRY(cache_get_mime_type_for_data)
+#define _xdg_mime_cache_get_mime_type_for_file        XDG_RESERVED_ENTRY(cache_get_mime_type_for_file)
+#define _xdg_mime_cache_get_mime_type_from_file_name  XDG_RESERVED_ENTRY(cache_get_mime_type_from_file_name)
+#define _xdg_mime_cache_get_mime_types_from_file_name XDG_RESERVED_ENTRY(cache_get_mime_types_from_file_name)
+#define _xdg_mime_cache_list_mime_parents             XDG_RESERVED_ENTRY(cache_list_mime_parents)
+#define _xdg_mime_cache_mime_type_subclass            XDG_RESERVED_ENTRY(cache_mime_type_subclass)
+#define _xdg_mime_cache_unalias_mime_type             XDG_RESERVED_ENTRY(cache_unalias_mime_type)
+#define _xdg_mime_cache_get_icon                      XDG_RESERVED_ENTRY(cache_get_icon)
+#define _xdg_mime_cache_get_generic_icon              XDG_RESERVED_ENTRY(cache_get_generic_icon)
+#define _xdg_mime_cache_glob_dump                     XDG_RESERVED_ENTRY(cache_glob_dump)
+#endif
+
+extern XdgMimeCache **_caches;
+
+XdgMimeCache *_xdg_mime_cache_new_from_file (const char   *file_name);
+XdgMimeCache *_xdg_mime_cache_ref           (XdgMimeCache *cache);
+void          _xdg_mime_cache_unref         (XdgMimeCache *cache);
+
+
+const char  *_xdg_mime_cache_get_mime_type_for_data       (const void *data,
+		 				           size_t      len,
+							   int        *result_prio);
+const char  *_xdg_mime_cache_get_mime_type_for_file       (const char  *file_name,
+							   struct stat *statbuf);
+int          _xdg_mime_cache_get_mime_types_from_file_name (const char *file_name,
+							    const char  *mime_types[],
+							    int          n_mime_types);
+const char  *_xdg_mime_cache_get_mime_type_from_file_name (const char *file_name);
+int          _xdg_mime_cache_is_valid_mime_type           (const char *mime_type);
+int          _xdg_mime_cache_mime_type_equal              (const char *mime_a,
+						           const char *mime_b);
+int          _xdg_mime_cache_media_type_equal             (const char *mime_a,
+							   const char *mime_b);
+int          _xdg_mime_cache_mime_type_subclass           (const char *mime_a,
+							   const char *mime_b);
+char       **_xdg_mime_cache_list_mime_parents		  (const char *mime);
+const char  *_xdg_mime_cache_unalias_mime_type            (const char *mime);
+int          _xdg_mime_cache_get_max_buffer_extents       (void);
+const char  *_xdg_mime_cache_get_icon                     (const char *mime);
+const char  *_xdg_mime_cache_get_generic_icon             (const char *mime);
+void         _xdg_mime_cache_glob_dump                    (void);
+
+#endif /* __XDG_MIME_CACHE_H__ */
diff --git a/base/third_party/xdg_mime/xdgmimeglob.c b/base/third_party/xdg_mime/xdgmimeglob.c
new file mode 100644
index 0000000..f8434bc
--- /dev/null
+++ b/base/third_party/xdg_mime/xdgmimeglob.c
@@ -0,0 +1,691 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* xdgmimeglob.c: Private file.  Datastructure for storing the globs.
+ *
+ * More info can be found at http://www.freedesktop.org/standards/
+ *
+ * Copyright (C) 2003  Red Hat, Inc.
+ * Copyright (C) 2003  Jonathan Blandford <jrb@alum.mit.edu>
+ *
+ * Licensed under the Academic Free License version 2.0
+ * Or under the following terms:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "xdgmimeglob.h"
+#include "xdgmimeint.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <fnmatch.h>
+
+#ifndef	FALSE
+#define	FALSE	(0)
+#endif
+
+#ifndef	TRUE
+#define	TRUE	(!FALSE)
+#endif
+
+typedef struct XdgGlobHashNode XdgGlobHashNode;
+typedef struct XdgGlobList XdgGlobList;
+
+struct XdgGlobHashNode
+{
+  xdg_unichar_t character;
+  const char *mime_type;
+  int weight;
+  int case_sensitive;
+  XdgGlobHashNode *next;
+  XdgGlobHashNode *child;
+};
+struct XdgGlobList
+{
+  const char *data;
+  const char *mime_type;
+  int weight;
+  int case_sensitive;
+  XdgGlobList *next;
+};
+
+struct XdgGlobHash
+{
+  XdgGlobList *literal_list;
+  XdgGlobHashNode *simple_node;
+  XdgGlobList *full_list;
+};
+
+
+/* XdgGlobList
+ */
+static XdgGlobList *
+_xdg_glob_list_new (void)
+{
+  XdgGlobList *new_element;
+
+  new_element = calloc (1, sizeof (XdgGlobList));
+
+  return new_element;
+}
+
+/* Frees glob_list and all of it's children */
+static void
+_xdg_glob_list_free (XdgGlobList *glob_list)
+{
+  XdgGlobList *ptr, *next;
+
+  ptr = glob_list;
+
+  while (ptr != NULL)
+    {
+      next = ptr->next;
+
+      if (ptr->data)
+	free ((void *) ptr->data);
+      if (ptr->mime_type)
+	free ((void *) ptr->mime_type);
+      free (ptr);
+
+      ptr = next;
+    }
+}
+
+static XdgGlobList *
+_xdg_glob_list_append (XdgGlobList *glob_list,
+		       void        *data,
+		       const char  *mime_type,
+		       int          weight,
+		       int          case_sensitive)
+{
+  XdgGlobList *new_element;
+  XdgGlobList *tmp_element;
+
+  tmp_element = glob_list;
+  while (tmp_element != NULL)
+    {
+      if (strcmp (tmp_element->data, data) == 0 &&
+	  strcmp (tmp_element->mime_type, mime_type) == 0)
+	return glob_list;
+
+      tmp_element = tmp_element->next;
+    }
+
+  new_element = _xdg_glob_list_new ();
+  new_element->data = data;
+  new_element->mime_type = mime_type;
+  new_element->weight = weight;
+  new_element->case_sensitive = case_sensitive;
+  if (glob_list == NULL)
+    return new_element;
+
+  tmp_element = glob_list;
+  while (tmp_element->next != NULL)
+    tmp_element = tmp_element->next;
+
+  tmp_element->next = new_element;
+
+  return glob_list;
+}
+
+/* XdgGlobHashNode
+ */
+
+static XdgGlobHashNode *
+_xdg_glob_hash_node_new (void)
+{
+  XdgGlobHashNode *glob_hash_node;
+
+  glob_hash_node = calloc (1, sizeof (XdgGlobHashNode));
+
+  return glob_hash_node;
+}
+
+static void
+_xdg_glob_hash_node_dump (XdgGlobHashNode *glob_hash_node,
+			  int depth)
+{
+  int i;
+  for (i = 0; i < depth; i++)
+    printf (" ");
+
+  printf ("%c", (char)glob_hash_node->character);
+  if (glob_hash_node->mime_type)
+    printf (" - %s %d\n", glob_hash_node->mime_type, glob_hash_node->weight);
+  else
+    printf ("\n");
+  if (glob_hash_node->child)
+    _xdg_glob_hash_node_dump (glob_hash_node->child, depth + 1);
+  if (glob_hash_node->next)
+    _xdg_glob_hash_node_dump (glob_hash_node->next, depth);
+}
+
+static XdgGlobHashNode *
+_xdg_glob_hash_insert_ucs4 (XdgGlobHashNode *glob_hash_node,
+			    xdg_unichar_t   *text,
+			    const char      *mime_type,
+			    int              weight,
+			    int              case_sensitive)
+{
+  XdgGlobHashNode *node;
+  xdg_unichar_t character;
+
+  character = text[0];
+
+  if ((glob_hash_node == NULL) ||
+      (character < glob_hash_node->character))
+    {
+      node = _xdg_glob_hash_node_new ();
+      node->character = character;
+      node->next = glob_hash_node;
+      glob_hash_node = node;
+    }
+  else if (character == glob_hash_node->character)
+    {
+      node = glob_hash_node;
+    }
+  else
+    {
+      XdgGlobHashNode *prev_node;
+      int found_node = FALSE;
+
+      /* Look for the first character of text in glob_hash_node, and insert it if we
+       * have to.*/
+      prev_node = glob_hash_node;
+      node = prev_node->next;
+
+      while (node != NULL)
+	{
+	  if (character < node->character)
+	    {
+	      node = _xdg_glob_hash_node_new ();
+	      node->character = character;
+	      node->next = prev_node->next;
+	      prev_node->next = node;
+
+	      found_node = TRUE;
+	      break;
+	    }
+	  else if (character == node->character)
+	    {
+	      found_node = TRUE;
+	      break;
+	    }
+	  prev_node = node;
+	  node = node->next;
+	}
+
+      if (! found_node)
+	{
+	  node = _xdg_glob_hash_node_new ();
+	  node->character = character;
+	  node->next = prev_node->next;
+	  prev_node->next = node;
+	}
+    }
+
+  text++;
+  if (*text == 0)
+    {
+      if (node->mime_type)
+	{
+	  if (strcmp (node->mime_type, mime_type) != 0)
+	    {
+	      XdgGlobHashNode *child;
+	      int found_node = FALSE;
+
+	      child = node->child;
+	      while (child && child->character == 0)
+		{
+		  if (strcmp (child->mime_type, mime_type) == 0)
+		    {
+		      found_node = TRUE;
+		      break;
+		    }
+		  child = child->next;
+		}
+
+	      if (!found_node)
+		{
+		  child = _xdg_glob_hash_node_new ();
+		  child->character = 0;
+		  child->mime_type = strdup (mime_type);
+		  child->weight = weight;
+		  child->case_sensitive = case_sensitive;
+		  child->child = NULL;
+		  child->next = node->child;
+		  node->child = child;
+		}
+	    }
+	}
+      else
+	{
+	  node->mime_type = strdup (mime_type);
+	  node->weight = weight;
+	  node->case_sensitive = case_sensitive;
+	}
+    }
+  else
+    {
+      node->child = _xdg_glob_hash_insert_ucs4 (node->child, text, mime_type, weight, case_sensitive);
+    }
+  return glob_hash_node;
+}
+
+/* glob must be valid UTF-8 */
+static XdgGlobHashNode *
+_xdg_glob_hash_insert_text (XdgGlobHashNode *glob_hash_node,
+			    const char      *text,
+			    const char      *mime_type,
+			    int              weight,
+			    int              case_sensitive)
+{
+  XdgGlobHashNode *node;
+  xdg_unichar_t *unitext;
+  int len;
+
+  unitext = _xdg_convert_to_ucs4 (text, &len);
+  _xdg_reverse_ucs4 (unitext, len);
+  node = _xdg_glob_hash_insert_ucs4 (glob_hash_node, unitext, mime_type, weight, case_sensitive);
+  free (unitext);
+  return node;
+}
+
+typedef struct {
+  const char *mime;
+  int weight;
+} MimeWeight;
+
+static int
+_xdg_glob_hash_node_lookup_file_name (XdgGlobHashNode *glob_hash_node,
+				      const char      *file_name,
+				      int              len,
+				      int              case_sensitive_check,
+				      MimeWeight       mime_types[],
+				      int              n_mime_types)
+{
+  int n;
+  XdgGlobHashNode *node;
+  xdg_unichar_t character;
+
+  if (glob_hash_node == NULL)
+    return 0;
+
+  character = file_name[len - 1];
+
+  for (node = glob_hash_node; node && character >= node->character; node = node->next)
+    {
+      if (character == node->character)
+        {
+          len--;
+          n = 0;
+          if (len > 0) 
+	    {
+	      n = _xdg_glob_hash_node_lookup_file_name (node->child,
+							file_name,
+							len,
+							case_sensitive_check,
+							mime_types,
+							n_mime_types);
+	    }
+	  if (n == 0)
+	    {
+              if (node->mime_type &&
+		  (case_sensitive_check ||
+		   !node->case_sensitive))
+                {
+	          mime_types[n].mime = node->mime_type;
+		  mime_types[n].weight = node->weight;
+		  n++; 
+                }
+	      node = node->child;
+	      while (n < n_mime_types && node && node->character == 0)
+		{
+                  if (node->mime_type &&
+		      (case_sensitive_check ||
+		       !node->case_sensitive))
+		    {
+		      mime_types[n].mime = node->mime_type;
+		      mime_types[n].weight = node->weight;
+		      n++;
+		    }
+		  node = node->next;
+		}
+	    }
+	  return n;
+	}
+    }
+
+  return 0;
+}
+
+static int compare_mime_weight (const void *a, const void *b)
+{
+  const MimeWeight *aa = (const MimeWeight *)a;
+  const MimeWeight *bb = (const MimeWeight *)b;
+
+  return bb->weight - aa->weight;
+}
+
+#define ISUPPER(c)		((c) >= 'A' && (c) <= 'Z')
+static char *
+ascii_tolower (const char *str)
+{
+  char *p, *lower;
+
+  lower = strdup (str);
+  p = lower;
+  while (*p != 0)
+    {
+      char c = *p;
+      *p++ = ISUPPER (c) ? c - 'A' + 'a' : c;
+    }
+  return lower;
+}
+
+int
+_xdg_glob_hash_lookup_file_name (XdgGlobHash *glob_hash,
+				 const char  *file_name,
+				 const char  *mime_types[],
+				 int          n_mime_types)
+{
+  XdgGlobList *list;
+  int i, n;
+  MimeWeight mimes[10];
+  int n_mimes = 10;
+  int len;
+  char *lower_case;
+
+  /* First, check the literals */
+
+  assert (file_name != NULL && n_mime_types > 0);
+
+  n = 0;
+
+  lower_case = ascii_tolower (file_name);
+
+  for (list = glob_hash->literal_list; list; list = list->next)
+    {
+      if (strcmp ((const char *)list->data, file_name) == 0)
+	{
+	  mime_types[0] = list->mime_type;
+	  free (lower_case);
+	  return 1;
+	}
+    }
+
+  for (list = glob_hash->literal_list; list; list = list->next)
+    {
+      if (!list->case_sensitive &&
+	  strcmp ((const char *)list->data, lower_case) == 0)
+	{
+	  mime_types[0] = list->mime_type;
+	  free (lower_case);
+	  return 1;
+	}
+    }
+
+
+  len = strlen (file_name);
+  n = _xdg_glob_hash_node_lookup_file_name (glob_hash->simple_node, lower_case, len, FALSE,
+					    mimes, n_mimes);
+  if (n == 0)
+    n = _xdg_glob_hash_node_lookup_file_name (glob_hash->simple_node, file_name, len, TRUE,
+					      mimes, n_mimes);
+
+  if (n == 0)
+    {
+      for (list = glob_hash->full_list; list && n < n_mime_types; list = list->next)
+        {
+          if (fnmatch ((const char *)list->data, file_name, 0) == 0)
+	    {
+	      mimes[n].mime = list->mime_type;
+	      mimes[n].weight = list->weight;
+	      n++;
+	    }
+        }
+    }
+  free (lower_case);
+
+  qsort (mimes, n, sizeof (MimeWeight), compare_mime_weight);
+
+  if (n_mime_types < n)
+    n = n_mime_types;
+
+  for (i = 0; i < n; i++)
+    mime_types[i] = mimes[i].mime;
+
+  return n;
+}
+
+
+
+/* XdgGlobHash
+ */
+
+XdgGlobHash *
+_xdg_glob_hash_new (void)
+{
+  XdgGlobHash *glob_hash;
+
+  glob_hash = calloc (1, sizeof (XdgGlobHash));
+
+  return glob_hash;
+}
+
+
+static void
+_xdg_glob_hash_free_nodes (XdgGlobHashNode *node)
+{
+  if (node)
+    {
+      if (node->child)
+       _xdg_glob_hash_free_nodes (node->child);
+      if (node->next)
+       _xdg_glob_hash_free_nodes (node->next);
+      if (node->mime_type)
+	free ((void *) node->mime_type);
+      free (node);
+    }
+}
+
+void
+_xdg_glob_hash_free (XdgGlobHash *glob_hash)
+{
+  _xdg_glob_list_free (glob_hash->literal_list);
+  _xdg_glob_list_free (glob_hash->full_list);
+  _xdg_glob_hash_free_nodes (glob_hash->simple_node);
+  free (glob_hash);
+}
+
+XdgGlobType
+_xdg_glob_determine_type (const char *glob)
+{
+  const char *ptr;
+  int maybe_in_simple_glob = FALSE;
+  int first_char = TRUE;
+
+  ptr = glob;
+
+  while (*ptr != '\0')
+    {
+      if (*ptr == '*' && first_char)
+	maybe_in_simple_glob = TRUE;
+      else if (*ptr == '\\' || *ptr == '[' || *ptr == '?' || *ptr == '*')
+	  return XDG_GLOB_FULL;
+
+      first_char = FALSE;
+      ptr = _xdg_utf8_next_char (ptr);
+    }
+  if (maybe_in_simple_glob)
+    return XDG_GLOB_SIMPLE;
+  else
+    return XDG_GLOB_LITERAL;
+}
+
+/* glob must be valid UTF-8 */
+void
+_xdg_glob_hash_append_glob (XdgGlobHash *glob_hash,
+			    const char  *glob,
+			    const char  *mime_type,
+			    int          weight,
+			    int          case_sensitive)
+{
+  XdgGlobType type;
+
+  assert (glob_hash != NULL);
+  assert (glob != NULL);
+
+  type = _xdg_glob_determine_type (glob);
+
+  switch (type)
+    {
+    case XDG_GLOB_LITERAL:
+      glob_hash->literal_list = _xdg_glob_list_append (glob_hash->literal_list, strdup (glob), strdup (mime_type), weight, case_sensitive);
+      break;
+    case XDG_GLOB_SIMPLE:
+      glob_hash->simple_node = _xdg_glob_hash_insert_text (glob_hash->simple_node, glob + 1, mime_type, weight, case_sensitive);
+      break;
+    case XDG_GLOB_FULL:
+      glob_hash->full_list = _xdg_glob_list_append (glob_hash->full_list, strdup (glob), strdup (mime_type), weight, case_sensitive);
+      break;
+    }
+}
+
+void
+_xdg_glob_hash_dump (XdgGlobHash *glob_hash)
+{
+  XdgGlobList *list;
+  printf ("LITERAL STRINGS\n");
+  if (!glob_hash || glob_hash->literal_list == NULL)
+    {
+      printf ("    None\n");
+    }
+  else
+    {
+      for (list = glob_hash->literal_list; list; list = list->next)
+	printf ("    %s - %s %d\n", (char *)list->data, list->mime_type, list->weight);
+    }
+  printf ("\nSIMPLE GLOBS\n");
+  if (!glob_hash || glob_hash->simple_node == NULL)
+    {
+      printf ("    None\n");
+    }
+  else
+    {
+      _xdg_glob_hash_node_dump (glob_hash->simple_node, 4);
+    }
+
+  printf ("\nFULL GLOBS\n");
+  if (!glob_hash || glob_hash->full_list == NULL)
+    {
+      printf ("    None\n");
+    }
+  else
+    {
+      for (list = glob_hash->full_list; list; list = list->next)
+	printf ("    %s - %s %d\n", (char *)list->data, list->mime_type, list->weight);
+    }
+}
+
+
+void
+_xdg_mime_glob_read_from_file (XdgGlobHash *glob_hash,
+			       const char  *file_name,
+			       int          version_two)
+{
+  FILE *glob_file;
+  char line[255];
+  char *p;
+
+  glob_file = fopen (file_name, "r");
+
+  if (glob_file == NULL)
+    return;
+
+  /* FIXME: Not UTF-8 safe.  Doesn't work if lines are greater than 255 chars.
+   * Blah */
+  while (fgets (line, 255, glob_file) != NULL)
+    {
+      char *colon;
+      char *mimetype, *glob, *end;
+      int weight;
+      int case_sensitive;
+
+      if (line[0] == '#' || line[0] == 0)
+	continue;
+
+      end = line + strlen(line) - 1;
+      if (*end == '\n')
+	*end = 0;
+
+      p = line;
+      if (version_two)
+	{
+	  colon = strchr (p, ':');
+	  if (colon == NULL)
+	    continue;
+	  *colon = 0;
+          weight = atoi (p);
+	  p = colon + 1;
+	}
+      else
+	weight = 50;
+
+      colon = strchr (p, ':');
+      if (colon == NULL)
+	continue;
+      *colon = 0;
+
+      mimetype = p;
+      p = colon + 1;
+      glob = p;
+      case_sensitive = FALSE;
+
+      colon = strchr (p, ':');
+      if (version_two && colon != NULL)
+	{
+	  char *flag;
+
+	  /* We got flags */
+	  *colon = 0;
+	  p = colon + 1;
+
+	  /* Flags end at next colon */
+	  colon = strchr (p, ':');
+	  if (colon != NULL)
+	    *colon = 0;
+
+	  flag = strstr (p, "cs");
+	  if (flag != NULL &&
+	      /* Start or after comma */
+	      (flag == p ||
+	       flag[-1] == ',') &&
+	      /* ends with comma or end of string */
+	      (flag[2] == 0 ||
+	       flag[2] == ','))
+	    case_sensitive = TRUE;
+	}
+
+      _xdg_glob_hash_append_glob (glob_hash, glob, mimetype, weight, case_sensitive);
+    }
+
+  fclose (glob_file);
+}
diff --git a/base/third_party/xdg_mime/xdgmimeglob.h b/base/third_party/xdg_mime/xdgmimeglob.h
new file mode 100644
index 0000000..0018292
--- /dev/null
+++ b/base/third_party/xdg_mime/xdgmimeglob.h
@@ -0,0 +1,70 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* xdgmimeglob.h: Private file.  Datastructure for storing the globs.
+ *
+ * More info can be found at http://www.freedesktop.org/standards/
+ *
+ * Copyright (C) 2003  Red Hat, Inc.
+ * Copyright (C) 2003  Jonathan Blandford <jrb@alum.mit.edu>
+ *
+ * Licensed under the Academic Free License version 2.0
+ * Or under the following terms:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __XDG_MIME_GLOB_H__
+#define __XDG_MIME_GLOB_H__
+
+#include "xdgmime.h"
+
+typedef struct XdgGlobHash XdgGlobHash;
+
+typedef enum
+{
+  XDG_GLOB_LITERAL, /* Makefile */
+  XDG_GLOB_SIMPLE,  /* *.gif */
+  XDG_GLOB_FULL     /* x*.[ch] */
+} XdgGlobType;
+
+  
+#ifdef XDG_PREFIX
+#define _xdg_mime_glob_read_from_file         XDG_RESERVED_ENTRY(glob_read_from_file)
+#define _xdg_glob_hash_new                    XDG_RESERVED_ENTRY(hash_new)
+#define _xdg_glob_hash_free                   XDG_RESERVED_ENTRY(hash_free)
+#define _xdg_glob_hash_lookup_file_name       XDG_RESERVED_ENTRY(hash_lookup_file_name)
+#define _xdg_glob_hash_append_glob            XDG_RESERVED_ENTRY(hash_append_glob)
+#define _xdg_glob_determine_type              XDG_RESERVED_ENTRY(determine_type)
+#define _xdg_glob_hash_dump                   XDG_RESERVED_ENTRY(hash_dump)
+#endif
+
+void         _xdg_mime_glob_read_from_file   (XdgGlobHash *glob_hash,
+					      const char  *file_name,
+					      int          version_two);
+XdgGlobHash *_xdg_glob_hash_new              (void);
+void         _xdg_glob_hash_free             (XdgGlobHash *glob_hash);
+int          _xdg_glob_hash_lookup_file_name (XdgGlobHash *glob_hash,
+					      const char  *text,
+					      const char  *mime_types[],
+					      int          n_mime_types);
+void         _xdg_glob_hash_append_glob      (XdgGlobHash *glob_hash,
+					      const char  *glob,
+					      const char  *mime_type,
+					      int          weight,
+					      int          case_sensitive);
+XdgGlobType  _xdg_glob_determine_type        (const char  *glob);
+void         _xdg_glob_hash_dump             (XdgGlobHash *glob_hash);
+
+#endif /* __XDG_MIME_GLOB_H__ */
diff --git a/base/third_party/xdg_mime/xdgmimeicon.c b/base/third_party/xdg_mime/xdgmimeicon.c
new file mode 100644
index 0000000..05c9473
--- /dev/null
+++ b/base/third_party/xdg_mime/xdgmimeicon.c
@@ -0,0 +1,183 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* xdgmimeicon.c: Private file.  Datastructure for storing the aliases.
+ *
+ * More info can be found at http://www.freedesktop.org/standards/
+ *
+ * Copyright (C) 2008  Red Hat, Inc.
+ *
+ * Licensed under the Academic Free License version 2.0
+ * Or under the following terms:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "xdgmimeicon.h"
+#include "xdgmimeint.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <fnmatch.h>
+
+#ifndef	FALSE
+#define	FALSE	(0)
+#endif
+
+#ifndef	TRUE
+#define	TRUE	(!FALSE)
+#endif
+
+typedef struct XdgIcon XdgIcon;
+
+struct XdgIcon 
+{
+  char *mime_type;
+  char *icon_name;
+};
+
+struct XdgIconList
+{
+  struct XdgIcon *icons;
+  int n_icons;
+};
+
+XdgIconList *
+_xdg_mime_icon_list_new (void)
+{
+  XdgIconList *list;
+
+  list = malloc (sizeof (XdgIconList));
+
+  list->icons = NULL;
+  list->n_icons = 0;
+
+  return list;
+}
+
+void         
+_xdg_mime_icon_list_free (XdgIconList *list)
+{
+  int i;
+
+  if (list->icons)
+    {
+      for (i = 0; i < list->n_icons; i++)
+	{
+	  free (list->icons[i].mime_type);
+	  free (list->icons[i].icon_name);
+	}
+      free (list->icons);
+    }
+  free (list);
+}
+
+static int
+icon_entry_cmp (const void *v1, const void *v2)
+{
+  return strcmp (((XdgIcon *)v1)->mime_type, ((XdgIcon *)v2)->mime_type);
+}
+
+const char  *
+_xdg_mime_icon_list_lookup (XdgIconList *list,
+			    const char  *mime_type)
+{
+  XdgIcon *entry;
+  XdgIcon key;
+
+  if (list->n_icons > 0)
+    {
+      key.mime_type = (char *)mime_type;
+      key.icon_name = NULL;
+
+      entry = bsearch (&key, list->icons, list->n_icons,
+		       sizeof (XdgIcon), icon_entry_cmp);
+      if (entry)
+        return entry->icon_name;
+    }
+
+  return NULL;
+}
+
+void
+_xdg_mime_icon_read_from_file (XdgIconList *list,
+			       const char   *file_name)
+{
+  FILE *file;
+  char line[255];
+  int alloc;
+
+  file = fopen (file_name, "r");
+
+  if (file == NULL)
+    return;
+
+  /* FIXME: Not UTF-8 safe.  Doesn't work if lines are greater than 255 chars.
+   * Blah */
+  alloc = list->n_icons + 16;
+  list->icons = realloc (list->icons, alloc * sizeof (XdgIcon));
+  while (fgets (line, 255, file) != NULL)
+    {
+      char *sep;
+      if (line[0] == '#')
+	continue;
+
+      sep = strchr (line, ':');
+      if (sep == NULL)
+	continue;
+      *(sep++) = '\000';
+      sep[strlen (sep) -1] = '\000';
+      if (list->n_icons == alloc)
+	{
+	  alloc <<= 1;
+	  list->icons = realloc (list->icons, 
+				   alloc * sizeof (XdgIcon));
+	}
+      list->icons[list->n_icons].mime_type = strdup (line);
+      list->icons[list->n_icons].icon_name = strdup (sep);
+      list->n_icons++;
+    }
+  list->icons = realloc (list->icons, 
+			   list->n_icons * sizeof (XdgIcon));
+
+  fclose (file);  
+  
+  if (list->n_icons > 1)
+    qsort (list->icons, list->n_icons, 
+           sizeof (XdgIcon), icon_entry_cmp);
+}
+
+
+void
+_xdg_mime_icon_list_dump (XdgIconList *list)
+{
+  int i;
+
+  if (list->icons)
+    {
+      for (i = 0; i < list->n_icons; i++)
+	{
+	  printf ("%s %s\n", 
+		  list->icons[i].mime_type,
+		  list->icons[i].icon_name);
+	}
+    }
+}
+
+
diff --git a/base/third_party/xdg_mime/xdgmimeicon.h b/base/third_party/xdg_mime/xdgmimeicon.h
new file mode 100644
index 0000000..b5f2583
--- /dev/null
+++ b/base/third_party/xdg_mime/xdgmimeicon.h
@@ -0,0 +1,50 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* xdgmimeicon.h: Private file.  Datastructure for storing the aliases.
+ *
+ * More info can be found at http://www.freedesktop.org/standards/
+ *
+ * Copyright (C) 2008  Red Hat, Inc.
+ *
+ * Licensed under the Academic Free License version 2.0
+ * Or under the following terms:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __XDG_MIME_ICON_H__
+#define __XDG_MIME_ICON_H__
+
+#include "xdgmime.h"
+
+typedef struct XdgIconList XdgIconList;
+
+#ifdef XDG_PREFIX
+#define _xdg_mime_icon_read_from_file        XDG_ENTRY(icon_read_from_file)
+#define _xdg_mime_icon_list_new              XDG_ENTRY(icon_list_new)
+#define _xdg_mime_icon_list_free             XDG_ENTRY(icon_list_free)
+#define _xdg_mime_icon_list_lookup           XDG_ENTRY(icon_list_lookup)
+#define _xdg_mime_icon_list_dump             XDG_ENTRY(icon_list_dump)
+#endif
+
+void          _xdg_mime_icon_read_from_file (XdgIconList *list,
+					    const char   *file_name);
+XdgIconList  *_xdg_mime_icon_list_new       (void);
+void          _xdg_mime_icon_list_free      (XdgIconList *list);
+const char   *_xdg_mime_icon_list_lookup    (XdgIconList *list,
+					     const char  *mime);
+void          _xdg_mime_icon_list_dump      (XdgIconList *list);
+
+#endif /* __XDG_MIME_ICON_H__ */
diff --git a/base/third_party/xdg_mime/xdgmimeint.c b/base/third_party/xdg_mime/xdgmimeint.c
new file mode 100644
index 0000000..cf789d9
--- /dev/null
+++ b/base/third_party/xdg_mime/xdgmimeint.c
@@ -0,0 +1,206 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* xdgmimeint.c: Internal defines and functions.
+ *
+ * More info can be found at http://www.freedesktop.org/standards/
+ *
+ * Copyright (C) 2003  Red Hat, Inc.
+ * Copyright (C) 2003  Jonathan Blandford <jrb@alum.mit.edu>
+ *
+ * Licensed under the Academic Free License version 2.0
+ * Or under the following terms:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "xdgmimeint.h"
+#include <ctype.h>
+#include <string.h>
+
+#ifndef	FALSE
+#define	FALSE	(0)
+#endif
+
+#ifndef	TRUE
+#define	TRUE	(!FALSE)
+#endif
+
+static const char _xdg_utf8_skip_data[256] = {
+  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+  3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1
+};
+
+const char * const _xdg_utf8_skip = _xdg_utf8_skip_data;
+
+
+
+/* Returns the number of unprocessed characters. */
+xdg_unichar_t
+_xdg_utf8_to_ucs4(const char *source)
+{
+  xdg_unichar_t ucs32;
+  if( ! ( *source & 0x80 ) )
+    {
+      ucs32 = *source;
+    }
+  else
+    {
+      int bytelength = 0;
+      xdg_unichar_t result;
+      if ( ! (*source & 0x40) )
+	{
+	  ucs32 = *source;
+	}
+      else
+	{
+	  if ( ! (*source & 0x20) )
+	    {
+	      result = *source++ & 0x1F;
+	      bytelength = 2;
+	    }
+	  else if ( ! (*source & 0x10) )
+	    {
+	      result = *source++ & 0x0F;
+	      bytelength = 3;
+	    }
+	  else if ( ! (*source & 0x08) )
+	    {
+	      result = *source++ & 0x07;
+	      bytelength = 4;
+	    }
+	  else if ( ! (*source & 0x04) )
+	    {
+	      result = *source++ & 0x03;
+	      bytelength = 5;
+	    }
+	  else if ( ! (*source & 0x02) )
+	    {
+	      result = *source++ & 0x01;
+	      bytelength = 6;
+	    }
+	  else
+	    {
+	      result = *source++;
+	      bytelength = 1;
+	    }
+
+	  for ( bytelength --; bytelength > 0; bytelength -- )
+	    {
+	      result <<= 6;
+	      result |= *source++ & 0x3F;
+	    }
+	  ucs32 = result;
+	}
+    }
+  return ucs32;
+}
+
+
+/* hullo.  this is great code.  don't rewrite it */
+
+xdg_unichar_t
+_xdg_ucs4_to_lower (xdg_unichar_t source)
+{
+  /* FIXME: Do a real to_upper sometime */
+  /* CaseFolding-3.2.0.txt has a table of rules. */
+  if ((source & 0xFF) == source)
+    return (xdg_unichar_t) tolower ((unsigned char) source);
+  return source;
+}
+
+int
+_xdg_utf8_validate (const char *source)
+{
+  /* FIXME: actually write */
+  return TRUE;
+}
+
+const char *
+_xdg_get_base_name (const char *file_name)
+{
+  const char *base_name;
+
+  if (file_name == NULL)
+    return NULL;
+
+  base_name = strrchr (file_name, '/');
+
+  if (base_name == NULL)
+    return file_name;
+  else
+    return base_name + 1;
+}
+
+xdg_unichar_t *
+_xdg_convert_to_ucs4 (const char *source, int *len)
+{
+  xdg_unichar_t *out;
+  int i;
+  const char *p;
+
+  out = malloc (sizeof (xdg_unichar_t) * (strlen (source) + 1));
+
+  p = source;
+  i = 0;
+  while (*p) 
+    {
+      out[i++] = _xdg_utf8_to_ucs4 (p);
+      p = _xdg_utf8_next_char (p); 
+    }
+  out[i] = 0;
+  *len = i;
+ 
+  return out;
+}
+
+void
+_xdg_reverse_ucs4 (xdg_unichar_t *source, int len)
+{
+  xdg_unichar_t c;
+  int i;
+
+  for (i = 0; i < len - i - 1; i++) 
+    {
+      c = source[i]; 
+      source[i] = source[len - i - 1];
+      source[len - i - 1] = c;
+    }
+}
+
+const char *
+_xdg_binary_or_text_fallback(const void *data, size_t len)
+{
+  unsigned char *chardata;
+  int i;
+
+  chardata = (unsigned char *) data;
+  for (i = 0; i < 32 && i < len; ++i)
+    {
+       if (chardata[i] < 32 && chardata[i] != 9 && chardata[i] != 10 && chardata[i] != 13)
+         return XDG_MIME_TYPE_UNKNOWN; /* binary data */
+    }
+
+  return XDG_MIME_TYPE_TEXTPLAIN;
+}
diff --git a/base/third_party/xdg_mime/xdgmimeint.h b/base/third_party/xdg_mime/xdgmimeint.h
new file mode 100644
index 0000000..9e8b2cb
--- /dev/null
+++ b/base/third_party/xdg_mime/xdgmimeint.h
@@ -0,0 +1,78 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* xdgmimeint.h: Internal defines and functions.
+ *
+ * More info can be found at http://www.freedesktop.org/standards/
+ *
+ * Copyright (C) 2003  Red Hat, Inc.
+ * Copyright (C) 2003  Jonathan Blandford <jrb@alum.mit.edu>
+ *
+ * Licensed under the Academic Free License version 2.0
+ * Or under the following terms:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __XDG_MIME_INT_H__
+#define __XDG_MIME_INT_H__
+
+#include "xdgmime.h"
+
+
+#ifndef	FALSE
+#define	FALSE (0)
+#endif
+
+#ifndef	TRUE
+#define	TRUE (!FALSE)
+#endif
+
+/* FIXME: Needs to be configure check */
+typedef unsigned int   xdg_unichar_t;
+typedef unsigned char  xdg_uchar8_t;
+typedef unsigned short xdg_uint16_t;
+typedef unsigned int   xdg_uint32_t;
+
+#ifdef XDG_PREFIX
+#define _xdg_utf8_skip       XDG_RESERVED_ENTRY(utf8_skip)
+#define _xdg_utf8_to_ucs4    XDG_RESERVED_ENTRY(utf8_to_ucs4)
+#define _xdg_ucs4_to_lower   XDG_RESERVED_ENTRY(ucs4_to_lower)
+#define _xdg_utf8_validate   XDG_RESERVED_ENTRY(utf8_validate)
+#define _xdg_get_base_name   XDG_RESERVED_ENTRY(get_base_name)
+#define _xdg_convert_to_ucs4 XDG_RESERVED_ENTRY(convert_to_ucs4)
+#define _xdg_reverse_ucs4    XDG_RESERVED_ENTRY(reverse_ucs4)
+#endif
+
+#define SWAP_BE16_TO_LE16(val) (xdg_uint16_t)(((xdg_uint16_t)(val) << 8)|((xdg_uint16_t)(val) >> 8))
+
+#define SWAP_BE32_TO_LE32(val) (xdg_uint32_t)((((xdg_uint32_t)(val) & 0xFF000000U) >> 24) |	\
+					      (((xdg_uint32_t)(val) & 0x00FF0000U) >> 8) |	\
+					      (((xdg_uint32_t)(val) & 0x0000FF00U) << 8) |	\
+					      (((xdg_uint32_t)(val) & 0x000000FFU) << 24))
+/* UTF-8 utils
+ */
+extern const char *const _xdg_utf8_skip;
+#define _xdg_utf8_next_char(p) (char *)((p) + _xdg_utf8_skip[*(unsigned char *)(p)])
+#define _xdg_utf8_char_size(p) (int) (_xdg_utf8_skip[*(unsigned char *)(p)])
+
+xdg_unichar_t  _xdg_utf8_to_ucs4  (const char    *source);
+xdg_unichar_t  _xdg_ucs4_to_lower (xdg_unichar_t  source);
+int            _xdg_utf8_validate (const char    *source);
+xdg_unichar_t *_xdg_convert_to_ucs4 (const char *source, int *len);
+void           _xdg_reverse_ucs4 (xdg_unichar_t *source, int len);
+const char    *_xdg_get_base_name (const char    *file_name);
+const char    *_xdg_binary_or_text_fallback(const void *data, size_t len);
+
+#endif /* __XDG_MIME_INT_H__ */
diff --git a/base/third_party/xdg_mime/xdgmimemagic.c b/base/third_party/xdg_mime/xdgmimemagic.c
new file mode 100644
index 0000000..a2320f5
--- /dev/null
+++ b/base/third_party/xdg_mime/xdgmimemagic.c
@@ -0,0 +1,813 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* xdgmimemagic.: Private file.  Datastructure for storing magic files.
+ *
+ * More info can be found at http://www.freedesktop.org/standards/
+ *
+ * Copyright (C) 2003  Red Hat, Inc.
+ * Copyright (C) 2003  Jonathan Blandford <jrb@alum.mit.edu>
+ *
+ * Licensed under the Academic Free License version 2.0
+ * Or under the following terms:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <assert.h>
+#include "xdgmimemagic.h"
+#include "xdgmimeint.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+
+#ifndef	FALSE
+#define	FALSE	(0)
+#endif
+
+#ifndef	TRUE
+#define	TRUE	(!FALSE)
+#endif
+
+#if !defined getc_unlocked && !defined HAVE_GETC_UNLOCKED
+# define getc_unlocked(fp) getc (fp)
+#endif
+
+typedef struct XdgMimeMagicMatch XdgMimeMagicMatch;
+typedef struct XdgMimeMagicMatchlet XdgMimeMagicMatchlet;
+
+typedef enum
+{
+  XDG_MIME_MAGIC_SECTION,
+  XDG_MIME_MAGIC_MAGIC,
+  XDG_MIME_MAGIC_ERROR,
+  XDG_MIME_MAGIC_EOF
+} XdgMimeMagicState;
+
+struct XdgMimeMagicMatch
+{
+  const char *mime_type;
+  int priority;
+  XdgMimeMagicMatchlet *matchlet;
+  XdgMimeMagicMatch *next;
+};
+
+
+struct XdgMimeMagicMatchlet
+{
+  int indent;
+  int offset;
+  unsigned int value_length;
+  unsigned char *value;
+  unsigned char *mask;
+  unsigned int range_length;
+  unsigned int word_size;
+  XdgMimeMagicMatchlet *next;
+};
+
+
+struct XdgMimeMagic
+{
+  XdgMimeMagicMatch *match_list;
+  int max_extent;
+};
+
+static XdgMimeMagicMatch *
+_xdg_mime_magic_match_new (void)
+{
+  return calloc (1, sizeof (XdgMimeMagicMatch));
+}
+
+
+static XdgMimeMagicMatchlet *
+_xdg_mime_magic_matchlet_new (void)
+{
+  XdgMimeMagicMatchlet *matchlet;
+
+  matchlet = malloc (sizeof (XdgMimeMagicMatchlet));
+
+  matchlet->indent = 0;
+  matchlet->offset = 0;
+  matchlet->value_length = 0;
+  matchlet->value = NULL;
+  matchlet->mask = NULL;
+  matchlet->range_length = 1;
+  matchlet->word_size = 1;
+  matchlet->next = NULL;
+
+  return matchlet;
+}
+
+
+static void
+_xdg_mime_magic_matchlet_free (XdgMimeMagicMatchlet *mime_magic_matchlet)
+{
+  if (mime_magic_matchlet)
+    {
+      if (mime_magic_matchlet->next)
+	_xdg_mime_magic_matchlet_free (mime_magic_matchlet->next);
+      if (mime_magic_matchlet->value)
+	free (mime_magic_matchlet->value);
+      if (mime_magic_matchlet->mask)
+	free (mime_magic_matchlet->mask);
+      free (mime_magic_matchlet);
+    }
+}
+
+
+/* Frees mime_magic_match and the remainder of its list
+ */
+static void
+_xdg_mime_magic_match_free (XdgMimeMagicMatch *mime_magic_match)
+{
+  XdgMimeMagicMatch *ptr, *next;
+
+  ptr = mime_magic_match;
+  while (ptr)
+    {
+      next = ptr->next;
+
+      if (ptr->mime_type)
+	free ((void *) ptr->mime_type);
+      if (ptr->matchlet)
+	_xdg_mime_magic_matchlet_free (ptr->matchlet);
+      free (ptr);
+
+      ptr = next;
+    }
+}
+
+/* Reads in a hunk of data until a newline character or a '\000' is hit.  The
+ * returned string is null terminated, and doesn't include the newline.
+ */
+static unsigned char *
+_xdg_mime_magic_read_to_newline (FILE *magic_file,
+				 int  *end_of_file)
+{
+  unsigned char *retval;
+  int c;
+  int len, pos;
+
+  len = 128;
+  pos = 0;
+  retval = malloc (len);
+  *end_of_file = FALSE;
+
+  while (TRUE)
+    {
+      c = getc_unlocked (magic_file);
+      if (c == EOF)
+	{
+	  *end_of_file = TRUE;
+	  break;
+	}
+      if (c == '\n' || c == '\000')
+	break;
+      retval[pos++] = (unsigned char) c;
+      if (pos % 128 == 127)
+	{
+	  len = len + 128;
+	  retval = realloc (retval, len);
+	}
+    }
+
+  retval[pos] = '\000';
+  return retval;
+}
+
+/* Returns the number read from the file, or -1 if no number could be read.
+ */
+static int
+_xdg_mime_magic_read_a_number (FILE *magic_file,
+			       int  *end_of_file)
+{
+  /* LONG_MAX is about 20 characters on my system */
+#define MAX_NUMBER_SIZE 30
+  char number_string[MAX_NUMBER_SIZE + 1];
+  int pos = 0;
+  int c;
+  long retval = -1;
+
+  while (TRUE)
+    {
+      c = getc_unlocked (magic_file);
+
+      if (c == EOF)
+	{
+	  *end_of_file = TRUE;
+	  break;
+	}
+      if (! isdigit (c))
+	{
+	  ungetc (c, magic_file);
+	  break;
+	}
+      number_string[pos] = (char) c;
+      pos++;
+      if (pos == MAX_NUMBER_SIZE)
+	break;
+    }
+  if (pos > 0)
+    {
+      number_string[pos] = '\000';
+      errno = 0;
+      retval = strtol (number_string, NULL, 10);
+
+      if ((retval < INT_MIN) || (retval > INT_MAX) || (errno != 0))
+	return -1;
+    }
+
+  return retval;
+}
+
+/* Headers are of the format:
+ * [<priority>:<mime-type>]
+ */
+static XdgMimeMagicState
+_xdg_mime_magic_parse_header (FILE *magic_file, XdgMimeMagicMatch *match)
+{
+  int c;
+  char *buffer;
+  char *end_ptr;
+  int end_of_file = 0;
+
+  assert (magic_file != NULL);
+  assert (match != NULL);
+
+  c = getc_unlocked (magic_file);
+  if (c == EOF)
+    return XDG_MIME_MAGIC_EOF;
+  if (c != '[')
+    return XDG_MIME_MAGIC_ERROR;
+
+  match->priority = _xdg_mime_magic_read_a_number (magic_file, &end_of_file);
+  if (end_of_file)
+    return XDG_MIME_MAGIC_EOF;
+  if (match->priority == -1)
+    return XDG_MIME_MAGIC_ERROR;
+
+  c = getc_unlocked (magic_file);
+  if (c == EOF)
+    return XDG_MIME_MAGIC_EOF;
+  if (c != ':')
+    return XDG_MIME_MAGIC_ERROR;
+
+  buffer = (char *)_xdg_mime_magic_read_to_newline (magic_file, &end_of_file);
+  if (end_of_file)
+    return XDG_MIME_MAGIC_EOF;
+
+  end_ptr = buffer;
+  while (*end_ptr != ']' && *end_ptr != '\000' && *end_ptr != '\n')
+    end_ptr++;
+  if (*end_ptr != ']')
+    {
+      free (buffer);
+      return XDG_MIME_MAGIC_ERROR;
+    }
+  *end_ptr = '\000';
+
+  match->mime_type = strdup (buffer);
+  free (buffer);
+
+  return XDG_MIME_MAGIC_MAGIC;
+}
+
+static XdgMimeMagicState
+_xdg_mime_magic_parse_error (FILE *magic_file)
+{
+  int c;
+
+  while (1)
+    {
+      c = getc_unlocked (magic_file);
+      if (c == EOF)
+	return XDG_MIME_MAGIC_EOF;
+      if (c == '\n')
+	return XDG_MIME_MAGIC_SECTION;
+    }
+}
+
+/* Headers are of the format:
+ * [ indent ] ">" start-offset "=" value
+ * [ "&" mask ] [ "~" word-size ] [ "+" range-length ] "\n"
+ */
+static XdgMimeMagicState
+_xdg_mime_magic_parse_magic_line (FILE              *magic_file,
+				  XdgMimeMagicMatch *match)
+{
+  XdgMimeMagicMatchlet *matchlet;
+  int c;
+  int end_of_file;
+  int indent = 0;
+  int bytes_read;
+
+  assert (magic_file != NULL);
+
+  /* Sniff the buffer to make sure it's a valid line */
+  c = getc_unlocked (magic_file);
+  if (c == EOF)
+    return XDG_MIME_MAGIC_EOF;
+  else if (c == '[')
+    {
+      ungetc (c, magic_file);
+      return XDG_MIME_MAGIC_SECTION;
+    }
+  else if (c == '\n')
+    return XDG_MIME_MAGIC_MAGIC;
+
+  /* At this point, it must be a digit or a '>' */
+  end_of_file = FALSE;
+  if (isdigit (c))
+    {
+      ungetc (c, magic_file);
+      indent = _xdg_mime_magic_read_a_number (magic_file, &end_of_file);
+      if (end_of_file)
+	return XDG_MIME_MAGIC_EOF;
+      if (indent == -1)
+	return XDG_MIME_MAGIC_ERROR;
+      c = getc_unlocked (magic_file);
+      if (c == EOF)
+	return XDG_MIME_MAGIC_EOF;
+    }
+
+  if (c != '>')
+    return XDG_MIME_MAGIC_ERROR;
+
+  matchlet = _xdg_mime_magic_matchlet_new ();
+  matchlet->indent = indent;
+  matchlet->offset = _xdg_mime_magic_read_a_number (magic_file, &end_of_file);
+  if (end_of_file)
+    {
+      _xdg_mime_magic_matchlet_free (matchlet);
+      return XDG_MIME_MAGIC_EOF;
+    }
+  if (matchlet->offset == -1)
+    {
+      _xdg_mime_magic_matchlet_free (matchlet);
+      return XDG_MIME_MAGIC_ERROR;
+    }
+  c = getc_unlocked (magic_file);
+  if (c == EOF)
+    {
+      _xdg_mime_magic_matchlet_free (matchlet);
+      return XDG_MIME_MAGIC_EOF;
+    }
+  else if (c != '=')
+    {
+      _xdg_mime_magic_matchlet_free (matchlet);
+      return XDG_MIME_MAGIC_ERROR;
+    }
+
+  /* Next two bytes determine how long the value is */
+  matchlet->value_length = 0;
+  c = getc_unlocked (magic_file);
+  if (c == EOF)
+    {
+      _xdg_mime_magic_matchlet_free (matchlet);
+      return XDG_MIME_MAGIC_EOF;
+    }
+  matchlet->value_length = c & 0xFF;
+  matchlet->value_length = matchlet->value_length << 8;
+
+  c = getc_unlocked (magic_file);
+  if (c == EOF)
+    {
+      _xdg_mime_magic_matchlet_free (matchlet);
+      return XDG_MIME_MAGIC_EOF;
+    }
+  matchlet->value_length = matchlet->value_length + (c & 0xFF);
+
+  matchlet->value = malloc (matchlet->value_length);
+
+  /* OOM */
+  if (matchlet->value == NULL)
+    {
+      _xdg_mime_magic_matchlet_free (matchlet);
+      return XDG_MIME_MAGIC_ERROR;
+    }
+  bytes_read = fread (matchlet->value, 1, matchlet->value_length, magic_file);
+  if (bytes_read != matchlet->value_length)
+    {
+      _xdg_mime_magic_matchlet_free (matchlet);
+      if (feof (magic_file))
+	return XDG_MIME_MAGIC_EOF;
+      else
+	return XDG_MIME_MAGIC_ERROR;
+    }
+
+  c = getc_unlocked (magic_file);
+  if (c == '&')
+    {
+      matchlet->mask = malloc (matchlet->value_length);
+      /* OOM */
+      if (matchlet->mask == NULL)
+	{
+	  _xdg_mime_magic_matchlet_free (matchlet);
+	  return XDG_MIME_MAGIC_ERROR;
+	}
+      bytes_read = fread (matchlet->mask, 1, matchlet->value_length, magic_file);
+      if (bytes_read != matchlet->value_length)
+	{
+	  _xdg_mime_magic_matchlet_free (matchlet);
+	  if (feof (magic_file))
+	    return XDG_MIME_MAGIC_EOF;
+	  else
+	    return XDG_MIME_MAGIC_ERROR;
+	}
+      c = getc_unlocked (magic_file);
+    }
+
+  if (c == '~')
+    {
+      matchlet->word_size = _xdg_mime_magic_read_a_number (magic_file, &end_of_file);
+      if (end_of_file)
+	{
+	  _xdg_mime_magic_matchlet_free (matchlet);
+	  return XDG_MIME_MAGIC_EOF;
+	}
+      if (matchlet->word_size != 0 &&
+	  matchlet->word_size != 1 &&
+	  matchlet->word_size != 2 &&
+	  matchlet->word_size != 4)
+	{
+	  _xdg_mime_magic_matchlet_free (matchlet);
+	  return XDG_MIME_MAGIC_ERROR;
+	}
+      c = getc_unlocked (magic_file);
+    }
+
+  if (c == '+')
+    {
+      matchlet->range_length = _xdg_mime_magic_read_a_number (magic_file, &end_of_file);
+      if (end_of_file)
+	{
+	  _xdg_mime_magic_matchlet_free (matchlet);
+	  return XDG_MIME_MAGIC_EOF;
+	}
+      if (matchlet->range_length == -1)
+	{
+	  _xdg_mime_magic_matchlet_free (matchlet);
+	  return XDG_MIME_MAGIC_ERROR;
+	}
+      c = getc_unlocked (magic_file);
+    }
+
+
+  if (c == '\n')
+    {
+      /* We clean up the matchlet, byte swapping if needed */
+      if (matchlet->word_size > 1)
+	{
+	  int i;
+	  if (matchlet->value_length % matchlet->word_size != 0)
+	    {
+	      _xdg_mime_magic_matchlet_free (matchlet);
+	      return XDG_MIME_MAGIC_ERROR;
+	    }
+	  /* FIXME: need to get this defined in a <config.h> style file */
+#if LITTLE_ENDIAN
+	  for (i = 0; i < matchlet->value_length; i = i + matchlet->word_size)
+	    {
+	      if (matchlet->word_size == 2)
+		*((xdg_uint16_t *) matchlet->value + i) = SWAP_BE16_TO_LE16 (*((xdg_uint16_t *) (matchlet->value + i)));
+	      else if (matchlet->word_size == 4)
+		*((xdg_uint32_t *) matchlet->value + i) = SWAP_BE32_TO_LE32 (*((xdg_uint32_t *) (matchlet->value + i)));
+	      if (matchlet->mask)
+		{
+		  if (matchlet->word_size == 2)
+		    *((xdg_uint16_t *) matchlet->mask + i) = SWAP_BE16_TO_LE16 (*((xdg_uint16_t *) (matchlet->mask + i)));
+		  else if (matchlet->word_size == 4)
+		    *((xdg_uint32_t *) matchlet->mask + i) = SWAP_BE32_TO_LE32 (*((xdg_uint32_t *) (matchlet->mask + i)));
+
+		}
+	    }
+#endif
+	}
+
+      matchlet->next = match->matchlet;
+      match->matchlet = matchlet;
+
+
+      return XDG_MIME_MAGIC_MAGIC;
+    }
+
+  _xdg_mime_magic_matchlet_free (matchlet);
+  if (c == EOF)
+    return XDG_MIME_MAGIC_EOF;
+
+  return XDG_MIME_MAGIC_ERROR;
+}
+
+static int
+_xdg_mime_magic_matchlet_compare_to_data (XdgMimeMagicMatchlet *matchlet,
+					  const void           *data,
+					  size_t                len)
+{
+  int i, j;
+  for (i = matchlet->offset; i < matchlet->offset + matchlet->range_length; i++)
+    {
+      int valid_matchlet = TRUE;
+
+      if (i + matchlet->value_length > len)
+	return FALSE;
+
+      if (matchlet->mask)
+	{
+	  for (j = 0; j < matchlet->value_length; j++)
+	    {
+	      if ((matchlet->value[j] & matchlet->mask[j]) !=
+		  ((((unsigned char *) data)[j + i]) & matchlet->mask[j]))
+		{
+		  valid_matchlet = FALSE;
+		  break;
+		}
+	    }
+	}
+      else
+	{
+	  for (j = 0; j <  matchlet->value_length; j++)
+	    {
+	      if (matchlet->value[j] != ((unsigned char *) data)[j + i])
+		{
+		  valid_matchlet = FALSE;
+		  break;
+		}
+	    }
+	}
+      if (valid_matchlet)
+	return TRUE;
+    }
+  return FALSE;
+}
+
+static int
+_xdg_mime_magic_matchlet_compare_level (XdgMimeMagicMatchlet *matchlet,
+					const void           *data,
+					size_t                len,
+					int                   indent)
+{
+  while ((matchlet != NULL) && (matchlet->indent == indent))
+    {
+      if (_xdg_mime_magic_matchlet_compare_to_data (matchlet, data, len))
+	{
+	  if ((matchlet->next == NULL) ||
+	      (matchlet->next->indent <= indent))
+	    return TRUE;
+
+	  if (_xdg_mime_magic_matchlet_compare_level (matchlet->next,
+						      data,
+						      len,
+						      indent + 1))
+	    return TRUE;
+	}
+
+      do
+	{
+	  matchlet = matchlet->next;
+	}
+      while (matchlet && matchlet->indent > indent);
+    }
+
+  return FALSE;
+}
+
+static int
+_xdg_mime_magic_match_compare_to_data (XdgMimeMagicMatch *match,
+				       const void        *data,
+				       size_t             len)
+{
+  return _xdg_mime_magic_matchlet_compare_level (match->matchlet, data, len, 0);
+}
+
+static void
+_xdg_mime_magic_insert_match (XdgMimeMagic      *mime_magic,
+			      XdgMimeMagicMatch *match)
+{
+  XdgMimeMagicMatch *list;
+
+  if (mime_magic->match_list == NULL)
+    {
+      mime_magic->match_list = match;
+      return;
+    }
+
+  if (match->priority > mime_magic->match_list->priority)
+    {
+      match->next = mime_magic->match_list;
+      mime_magic->match_list = match;
+      return;
+    }
+
+  list = mime_magic->match_list;
+  while (list->next != NULL)
+    {
+      if (list->next->priority < match->priority)
+	{
+	  match->next = list->next;
+	  list->next = match;
+	  return;
+	}
+      list = list->next;
+    }
+  list->next = match;
+  match->next = NULL;
+}
+
+XdgMimeMagic *
+_xdg_mime_magic_new (void)
+{
+  return calloc (1, sizeof (XdgMimeMagic));
+}
+
+void
+_xdg_mime_magic_free (XdgMimeMagic *mime_magic)
+{
+  if (mime_magic) {
+    _xdg_mime_magic_match_free (mime_magic->match_list);
+    free (mime_magic);
+  }
+}
+
+int
+_xdg_mime_magic_get_buffer_extents (XdgMimeMagic *mime_magic)
+{
+  return mime_magic->max_extent;
+}
+
+const char *
+_xdg_mime_magic_lookup_data (XdgMimeMagic *mime_magic,
+			     const void   *data,
+			     size_t        len,
+			     int           *result_prio,
+                             const char   *mime_types[],
+                             int           n_mime_types)
+{
+  XdgMimeMagicMatch *match;
+  const char *mime_type;
+  int n;
+  int prio;
+
+  prio = 0;
+  mime_type = NULL;
+  for (match = mime_magic->match_list; match; match = match->next)
+    {
+      if (_xdg_mime_magic_match_compare_to_data (match, data, len))
+	{
+	  prio = match->priority;
+	  mime_type = match->mime_type;
+	  break;
+	}
+      else 
+	{
+	  for (n = 0; n < n_mime_types; n++)
+	    {
+	      if (mime_types[n] && 
+		  _xdg_mime_mime_type_equal (mime_types[n], match->mime_type))
+		mime_types[n] = NULL;
+	    }
+	}
+    }
+
+  if (mime_type == NULL)
+    {
+      for (n = 0; n < n_mime_types; n++)
+	{
+	  if (mime_types[n])
+	    mime_type = mime_types[n];
+	}
+    }
+  
+  if (result_prio)
+    *result_prio = prio;
+
+  return mime_type;
+}
+
+static void
+_xdg_mime_update_mime_magic_extents (XdgMimeMagic *mime_magic)
+{
+  XdgMimeMagicMatch *match;
+  int max_extent = 0;
+
+  for (match = mime_magic->match_list; match; match = match->next)
+    {
+      XdgMimeMagicMatchlet *matchlet;
+
+      for (matchlet = match->matchlet; matchlet; matchlet = matchlet->next)
+	{
+	  int extent;
+
+	  extent = matchlet->value_length + matchlet->offset + matchlet->range_length;
+	  if (max_extent < extent)
+	    max_extent = extent;
+	}
+    }
+
+  mime_magic->max_extent = max_extent;
+}
+
+static XdgMimeMagicMatchlet *
+_xdg_mime_magic_matchlet_mirror (XdgMimeMagicMatchlet *matchlets)
+{
+  XdgMimeMagicMatchlet *new_list;
+  XdgMimeMagicMatchlet *tmp;
+
+  if ((matchlets == NULL) || (matchlets->next == NULL))
+    return matchlets;
+
+  new_list = NULL;
+  tmp = matchlets;
+  while (tmp != NULL)
+    {
+      XdgMimeMagicMatchlet *matchlet;
+
+      matchlet = tmp;
+      tmp = tmp->next;
+      matchlet->next = new_list;
+      new_list = matchlet;
+    }
+
+  return new_list;
+
+}
+
+static void
+_xdg_mime_magic_read_magic_file (XdgMimeMagic *mime_magic,
+				 FILE         *magic_file)
+{
+  XdgMimeMagicState state;
+  XdgMimeMagicMatch *match = NULL; /* Quiet compiler */
+
+  state = XDG_MIME_MAGIC_SECTION;
+
+  while (state != XDG_MIME_MAGIC_EOF)
+    {
+      switch (state)
+	{
+	case XDG_MIME_MAGIC_SECTION:
+	  match = _xdg_mime_magic_match_new ();
+	  state = _xdg_mime_magic_parse_header (magic_file, match);
+	  if (state == XDG_MIME_MAGIC_EOF || state == XDG_MIME_MAGIC_ERROR)
+	    _xdg_mime_magic_match_free (match);
+	  break;
+	case XDG_MIME_MAGIC_MAGIC:
+	  state = _xdg_mime_magic_parse_magic_line (magic_file, match);
+	  if (state == XDG_MIME_MAGIC_SECTION ||
+	      (state == XDG_MIME_MAGIC_EOF && match->mime_type))
+	    {
+	      match->matchlet = _xdg_mime_magic_matchlet_mirror (match->matchlet);
+	      _xdg_mime_magic_insert_match (mime_magic, match);
+	    }
+	  else if (state == XDG_MIME_MAGIC_EOF || state == XDG_MIME_MAGIC_ERROR)
+	    _xdg_mime_magic_match_free (match);
+	  break;
+	case XDG_MIME_MAGIC_ERROR:
+	  state = _xdg_mime_magic_parse_error (magic_file);
+	  break;
+	case XDG_MIME_MAGIC_EOF:
+	default:
+	  /* Make the compiler happy */
+	  assert (0);
+	}
+    }
+  _xdg_mime_update_mime_magic_extents (mime_magic);
+}
+
+void
+_xdg_mime_magic_read_from_file (XdgMimeMagic *mime_magic,
+				const char   *file_name)
+{
+  FILE *magic_file;
+  char header[12];
+
+  magic_file = fopen (file_name, "r");
+
+  if (magic_file == NULL)
+    return;
+
+  if (fread (header, 1, 12, magic_file) == 12)
+    {
+      if (memcmp ("MIME-Magic\0\n", header, 12) == 0)
+        _xdg_mime_magic_read_magic_file (mime_magic, magic_file);
+    }
+
+  fclose (magic_file);
+}
diff --git a/base/third_party/xdg_mime/xdgmimemagic.h b/base/third_party/xdg_mime/xdgmimemagic.h
new file mode 100644
index 0000000..35c8039
--- /dev/null
+++ b/base/third_party/xdg_mime/xdgmimemagic.h
@@ -0,0 +1,57 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* xdgmimemagic.h: Private file.  Datastructure for storing the magic files.
+ *
+ * More info can be found at http://www.freedesktop.org/standards/
+ *
+ * Copyright (C) 2003  Red Hat, Inc.
+ * Copyright (C) 2003  Jonathan Blandford <jrb@alum.mit.edu>
+ *
+ * Licensed under the Academic Free License version 2.0
+ * Or under the following terms:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __XDG_MIME_MAGIC_H__
+#define __XDG_MIME_MAGIC_H__
+
+#include <unistd.h>
+#include "xdgmime.h"
+typedef struct XdgMimeMagic XdgMimeMagic;
+
+#ifdef XDG_PREFIX
+#define _xdg_mime_glob_read_from_file             XDG_RESERVED_ENTRY(glob_read_from_file)
+#define _xdg_mime_magic_new                       XDG_RESERVED_ENTRY(magic_new)
+#define _xdg_mime_magic_read_from_file            XDG_RESERVED_ENTRY(magic_read_from_file)
+#define _xdg_mime_magic_free                      XDG_RESERVED_ENTRY(magic_free)
+#define _xdg_mime_magic_get_buffer_extents        XDG_RESERVED_ENTRY(magic_get_buffer_extents)
+#define _xdg_mime_magic_lookup_data               XDG_RESERVED_ENTRY(magic_lookup_data)
+#endif
+
+
+XdgMimeMagic *_xdg_mime_magic_new                (void);
+void          _xdg_mime_magic_read_from_file     (XdgMimeMagic *mime_magic,
+						  const char   *file_name);
+void          _xdg_mime_magic_free               (XdgMimeMagic *mime_magic);
+int           _xdg_mime_magic_get_buffer_extents (XdgMimeMagic *mime_magic);
+const char   *_xdg_mime_magic_lookup_data        (XdgMimeMagic *mime_magic,
+						  const void   *data,
+						  size_t        len,
+						  int          *result_prio,
+						  const char   *mime_types[],
+						  int           n_mime_types);
+
+#endif /* __XDG_MIME_MAGIC_H__ */
diff --git a/base/third_party/xdg_mime/xdgmimeparent.c b/base/third_party/xdg_mime/xdgmimeparent.c
new file mode 100644
index 0000000..511bbac
--- /dev/null
+++ b/base/third_party/xdg_mime/xdgmimeparent.c
@@ -0,0 +1,219 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* xdgmimealias.c: Private file.  Datastructure for storing the hierarchy.
+ *
+ * More info can be found at http://www.freedesktop.org/standards/
+ *
+ * Copyright (C) 2004  Red Hat, Inc.
+ * Copyright (C) 2004  Matthias Clasen <mclasen@redhat.com>
+ *
+ * Licensed under the Academic Free License version 2.0
+ * Or under the following terms:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "xdgmimeparent.h"
+#include "xdgmimeint.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <fnmatch.h>
+
+#ifndef	FALSE
+#define	FALSE	(0)
+#endif
+
+#ifndef	TRUE
+#define	TRUE	(!FALSE)
+#endif
+
+typedef struct XdgMimeParents XdgMimeParents;
+
+struct XdgMimeParents
+{
+  char *mime;
+  char **parents;
+  int n_parents;
+};
+
+struct XdgParentList
+{
+  struct XdgMimeParents *parents;
+  int n_mimes;
+};
+
+XdgParentList *
+_xdg_mime_parent_list_new (void)
+{
+  XdgParentList *list;
+
+  list = malloc (sizeof (XdgParentList));
+
+  list->parents = NULL;
+  list->n_mimes = 0;
+
+  return list;
+}
+
+void         
+_xdg_mime_parent_list_free (XdgParentList *list)
+{
+  int i;
+  char **p;
+
+  if (list->parents)
+    {
+      for (i = 0; i < list->n_mimes; i++)
+	{
+	  for (p = list->parents[i].parents; *p; p++)
+	    free (*p);
+
+	  free (list->parents[i].parents);
+	  free (list->parents[i].mime);
+	}
+      free (list->parents);
+    }
+  free (list);
+}
+
+static int
+parent_entry_cmp (const void *v1, const void *v2)
+{
+  return strcmp (((XdgMimeParents *)v1)->mime, ((XdgMimeParents *)v2)->mime);
+}
+
+const char **
+_xdg_mime_parent_list_lookup (XdgParentList *list,
+			      const char    *mime)
+{
+  XdgMimeParents *entry;
+  XdgMimeParents key;
+
+  if (list->n_mimes > 0)
+    {
+      key.mime = (char *)mime;
+      key.parents = NULL;
+
+      entry = bsearch (&key, list->parents, list->n_mimes,
+		       sizeof (XdgMimeParents), &parent_entry_cmp);
+      if (entry)
+        return (const char **)entry->parents;
+    }
+
+  return NULL;
+}
+
+void
+_xdg_mime_parent_read_from_file (XdgParentList *list,
+				 const char    *file_name)
+{
+  FILE *file;
+  char line[255];
+  int i, alloc;
+  XdgMimeParents *entry;
+
+  file = fopen (file_name, "r");
+
+  if (file == NULL)
+    return;
+
+  /* FIXME: Not UTF-8 safe.  Doesn't work if lines are greater than 255 chars.
+   * Blah */
+  alloc = list->n_mimes + 16;
+  list->parents = realloc (list->parents, alloc * sizeof (XdgMimeParents));
+  while (fgets (line, 255, file) != NULL)
+    {
+      char *sep;
+      if (line[0] == '#')
+	continue;
+
+      sep = strchr (line, ' ');
+      if (sep == NULL)
+	continue;
+      *(sep++) = '\000';
+      sep[strlen (sep) -1] = '\000';
+      entry = NULL;
+      for (i = 0; i < list->n_mimes; i++)
+	{
+	  if (strcmp (list->parents[i].mime, line) == 0)
+	    {
+	      entry = &(list->parents[i]);
+	      break;
+	    }
+	}
+      
+      if (!entry)
+	{
+	  if (list->n_mimes == alloc)
+	    {
+	      alloc <<= 1;
+	      list->parents = realloc (list->parents, 
+				       alloc * sizeof (XdgMimeParents));
+	    }
+	  list->parents[list->n_mimes].mime = strdup (line);
+	  list->parents[list->n_mimes].parents = NULL;
+	  entry = &(list->parents[list->n_mimes]);
+	  list->n_mimes++;
+	}
+
+      if (!entry->parents)
+	{
+	  entry->n_parents = 1;
+	  entry->parents = malloc ((entry->n_parents + 1) * sizeof (char *));
+	}
+      else
+	{
+	  entry->n_parents += 1;
+	  entry->parents = realloc (entry->parents, 
+				    (entry->n_parents + 2) * sizeof (char *));
+	}
+      entry->parents[entry->n_parents - 1] = strdup (sep);
+      entry->parents[entry->n_parents] = NULL;
+    }
+
+  list->parents = realloc (list->parents, 
+			   list->n_mimes * sizeof (XdgMimeParents));
+
+  fclose (file);  
+  
+  if (list->n_mimes > 1)
+    qsort (list->parents, list->n_mimes, 
+           sizeof (XdgMimeParents), &parent_entry_cmp);
+}
+
+
+void         
+_xdg_mime_parent_list_dump (XdgParentList *list)
+{
+  int i;
+  char **p;
+
+  if (list->parents)
+    {
+      for (i = 0; i < list->n_mimes; i++)
+	{
+	  for (p = list->parents[i].parents; *p; p++)
+	    printf ("%s %s\n", list->parents[i].mime, *p);
+	}
+    }
+}
+
+
diff --git a/base/third_party/xdg_mime/xdgmimeparent.h b/base/third_party/xdg_mime/xdgmimeparent.h
new file mode 100644
index 0000000..b564f41
--- /dev/null
+++ b/base/third_party/xdg_mime/xdgmimeparent.h
@@ -0,0 +1,51 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* xdgmimeparent.h: Private file.  Datastructure for storing the hierarchy.
+ *
+ * More info can be found at http://www.freedesktop.org/standards/
+ *
+ * Copyright (C) 2004  Red Hat, Inc.
+ * Copyright (C) 200  Matthias Clasen <mclasen@redhat.com>
+ *
+ * Licensed under the Academic Free License version 2.0
+ * Or under the following terms:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __XDG_MIME_PARENT_H__
+#define __XDG_MIME_PARENT_H__
+
+#include "xdgmime.h"
+
+typedef struct XdgParentList XdgParentList;
+
+#ifdef XDG_PREFIX
+#define _xdg_mime_parent_read_from_file        XDG_RESERVED_ENTRY(parent_read_from_file)
+#define _xdg_mime_parent_list_new              XDG_RESERVED_ENTRY(parent_list_new)
+#define _xdg_mime_parent_list_free             XDG_RESERVED_ENTRY(parent_list_free)
+#define _xdg_mime_parent_list_lookup           XDG_RESERVED_ENTRY(parent_list_lookup)
+#define _xdg_mime_parent_list_dump             XDG_RESERVED_ENTRY(parent_list_dump)
+#endif
+
+void          _xdg_mime_parent_read_from_file (XdgParentList *list,
+					       const char    *file_name);
+XdgParentList *_xdg_mime_parent_list_new       (void);
+void           _xdg_mime_parent_list_free      (XdgParentList *list);
+const char   **_xdg_mime_parent_list_lookup    (XdgParentList *list,
+						const char    *mime);
+void           _xdg_mime_parent_list_dump      (XdgParentList *list);
+
+#endif /* __XDG_MIME_PARENT_H__ */
diff --git a/base/third_party/xdg_user_dirs/BUILD.gn b/base/third_party/xdg_user_dirs/BUILD.gn
new file mode 100644
index 0000000..62e7cdf
--- /dev/null
+++ b/base/third_party/xdg_user_dirs/BUILD.gn
@@ -0,0 +1,11 @@
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("xdg_user_dirs") {
+  visibility = [ "//base/*" ]
+  sources = [
+    "xdg_user_dir_lookup.cc",
+    "xdg_user_dir_lookup.h",
+  ]
+}
diff --git a/base/third_party/xdg_user_dirs/LICENSE b/base/third_party/xdg_user_dirs/LICENSE
new file mode 100644
index 0000000..540e803
--- /dev/null
+++ b/base/third_party/xdg_user_dirs/LICENSE
@@ -0,0 +1,21 @@
+  Copyright (c) 2007 Red Hat, inc
+
+  Permission is hereby granted, free of charge, to any person
+  obtaining a copy of this software and associated documentation files
+  (the "Software"), to deal in the Software without restriction,
+  including without limitation the rights to use, copy, modify, merge,
+  publish, distribute, sublicense, and/or sell copies of the Software,
+  and to permit persons to whom the Software is furnished to do so,
+  subject to the following conditions: 
+
+  The above copyright notice and this permission notice shall be
+  included in all copies or substantial portions of the Software. 
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+  SOFTWARE.
diff --git a/base/third_party/xdg_user_dirs/README.chromium b/base/third_party/xdg_user_dirs/README.chromium
new file mode 100644
index 0000000..b4cf6d7
--- /dev/null
+++ b/base/third_party/xdg_user_dirs/README.chromium
@@ -0,0 +1,7 @@
+Name: xdg-user-dirs
+URL: http://www.freedesktop.org/wiki/Software/xdg-user-dirs
+License: MIT
+
+This directory include xdg-user-dir-lookup.c renamed as xdg_user_dir_lookup.cc
+from xdg-user-dirs 0.10. We made xdg_user_dir_lookup() non-static and added a
+xdg_user_dir_lookup.h.
diff --git a/base/third_party/xdg_user_dirs/xdg_user_dir_lookup.cc b/base/third_party/xdg_user_dirs/xdg_user_dir_lookup.cc
new file mode 100644
index 0000000..343f70c
--- /dev/null
+++ b/base/third_party/xdg_user_dirs/xdg_user_dir_lookup.cc
@@ -0,0 +1,232 @@
+/*
+  This file is not licenced under the GPL like the rest of the code.
+  Its is under the MIT license, to encourage reuse by cut-and-paste.
+
+  Copyright (c) 2007 Red Hat, inc
+
+  Permission is hereby granted, free of charge, to any person
+  obtaining a copy of this software and associated documentation files
+  (the "Software"), to deal in the Software without restriction,
+  including without limitation the rights to use, copy, modify, merge,
+  publish, distribute, sublicense, and/or sell copies of the Software,
+  and to permit persons to whom the Software is furnished to do so,
+  subject to the following conditions: 
+
+  The above copyright notice and this permission notice shall be
+  included in all copies or substantial portions of the Software. 
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+  SOFTWARE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/**
+ * xdg_user_dir_lookup_with_fallback:
+ * @type: a string specifying the type of directory
+ * @fallback: value to use if the directory isn't specified by the user
+ * @returns: a newly allocated absolute pathname
+ *
+ * Looks up a XDG user directory of the specified type.
+ * Example of types are "DESKTOP" and "DOWNLOAD".
+ *
+ * In case the user hasn't specified any directory for the specified
+ * type the value returned is @fallback.
+ *
+ * The return value is newly allocated and must be freed with
+ * free(). The return value is never NULL if @fallback != NULL, unless
+ * out of memory.
+ **/
+static char *
+xdg_user_dir_lookup_with_fallback (const char *type, const char *fallback)
+{
+  FILE *file;
+  char *home_dir, *config_home, *config_file;
+  char buffer[512];
+  char *user_dir;
+  char *p, *d;
+  int len;
+  int relative;
+  
+  home_dir = getenv ("HOME");
+
+  if (home_dir == NULL)
+    goto error;
+
+  config_home = getenv ("XDG_CONFIG_HOME");
+  if (config_home == NULL || config_home[0] == 0)
+    {
+      config_file = (char*) malloc (strlen (home_dir) + strlen ("/.config/user-dirs.dirs") + 1);
+      if (config_file == NULL)
+        goto error;
+
+      strcpy (config_file, home_dir);
+      strcat (config_file, "/.config/user-dirs.dirs");
+    }
+  else
+    {
+      config_file = (char*) malloc (strlen (config_home) + strlen ("/user-dirs.dirs") + 1);
+      if (config_file == NULL)
+        goto error;
+
+      strcpy (config_file, config_home);
+      strcat (config_file, "/user-dirs.dirs");
+    }
+
+  file = fopen (config_file, "r");
+  free (config_file);
+  if (file == NULL)
+    goto error;
+
+  user_dir = NULL;
+  while (fgets (buffer, sizeof (buffer), file))
+    {
+      /* Remove newline at end */
+      len = strlen (buffer);
+      if (len > 0 && buffer[len-1] == '\n')
+	buffer[len-1] = 0;
+      
+      p = buffer;
+      while (*p == ' ' || *p == '\t')
+	p++;
+      
+      if (strncmp (p, "XDG_", 4) != 0)
+	continue;
+      p += 4;
+      if (strncmp (p, type, strlen (type)) != 0)
+	continue;
+      p += strlen (type);
+      if (strncmp (p, "_DIR", 4) != 0)
+	continue;
+      p += 4;
+
+      while (*p == ' ' || *p == '\t')
+	p++;
+
+      if (*p != '=')
+	continue;
+      p++;
+      
+      while (*p == ' ' || *p == '\t')
+	p++;
+
+      if (*p != '"')
+	continue;
+      p++;
+      
+      relative = 0;
+      if (strncmp (p, "$HOME/", 6) == 0)
+	{
+	  p += 6;
+	  relative = 1;
+	}
+      else if (*p != '/')
+	continue;
+      
+      if (relative)
+	{
+	  user_dir = (char*) malloc (strlen (home_dir) + 1 + strlen (p) + 1);
+          if (user_dir == NULL)
+            goto error2;
+
+	  strcpy (user_dir, home_dir);
+	  strcat (user_dir, "/");
+	}
+      else
+	{
+	  user_dir = (char*) malloc (strlen (p) + 1);
+          if (user_dir == NULL)
+            goto error2;
+
+	  *user_dir = 0;
+	}
+      
+      d = user_dir + strlen (user_dir);
+      while (*p && *p != '"')
+	{
+	  if ((*p == '\\') && (*(p+1) != 0))
+	    p++;
+	  *d++ = *p++;
+	}
+      *d = 0;
+    }
+error2:
+  fclose (file);
+
+  if (user_dir)
+    return user_dir;
+
+ error:
+  if (fallback)
+    return strdup (fallback);
+  return NULL;
+}
+
+/**
+ * xdg_user_dir_lookup:
+ * @type: a string specifying the type of directory
+ * @returns: a newly allocated absolute pathname
+ *
+ * Looks up a XDG user directory of the specified type.
+ * Example of types are "DESKTOP" and "DOWNLOAD".
+ *
+ * The return value is always != NULL (unless out of memory),
+ * and if a directory
+ * for the type is not specified by the user the default
+ * is the home directory. Except for DESKTOP which defaults
+ * to ~/Desktop.
+ *
+ * The return value is newly allocated and must be freed with
+ * free().
+ **/
+char *
+xdg_user_dir_lookup (const char *type)
+{
+  char *dir, *home_dir, *user_dir;
+	  
+  dir = xdg_user_dir_lookup_with_fallback (type, NULL);
+  if (dir != NULL)
+    return dir;
+  
+  home_dir = getenv ("HOME");
+  
+  if (home_dir == NULL)
+    return strdup ("/tmp");
+  
+  /* Special case desktop for historical compatibility */
+  if (strcmp (type, "DESKTOP") == 0)
+    {
+      user_dir = (char*) malloc (strlen (home_dir) + strlen ("/Desktop") + 1);
+      if (user_dir == NULL)
+        return NULL;
+
+      strcpy (user_dir, home_dir);
+      strcat (user_dir, "/Desktop");
+      return user_dir;
+    }
+  
+  return strdup (home_dir);
+}
+
+#ifdef STANDALONE_XDG_USER_DIR_LOOKUP
+int
+main (int argc, char *argv[])
+{
+  if (argc != 2)
+    {
+      fprintf (stderr, "Usage %s <dir-type>\n", argv[0]);
+      exit (1);
+    }
+  
+  printf ("%s\n", xdg_user_dir_lookup (argv[1]));
+  return 0;
+}
+#endif
diff --git a/base/third_party/xdg_user_dirs/xdg_user_dir_lookup.h b/base/third_party/xdg_user_dirs/xdg_user_dir_lookup.h
new file mode 100644
index 0000000..9e81e1b
--- /dev/null
+++ b/base/third_party/xdg_user_dirs/xdg_user_dir_lookup.h
@@ -0,0 +1,33 @@
+/*
+  This file is not licenced under the GPL like the rest of the code.
+  Its is under the MIT license, to encourage reuse by cut-and-paste.
+
+  Copyright (c) 2007 Red Hat, inc
+
+  Permission is hereby granted, free of charge, to any person
+  obtaining a copy of this software and associated documentation files
+  (the "Software"), to deal in the Software without restriction,
+  including without limitation the rights to use, copy, modify, merge,
+  publish, distribute, sublicense, and/or sell copies of the Software,
+  and to permit persons to whom the Software is furnished to do so,
+  subject to the following conditions: 
+
+  The above copyright notice and this permission notice shall be
+  included in all copies or substantial portions of the Software. 
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+  SOFTWARE.
+*/
+
+#ifndef CHROME_THIRD_PARTY_XDG_USER_DIRS_XDG_USER_DIR_LOOKUP_H_
+#define CHROME_THIRD_PARTY_XDG_USER_DIRS_XDG_USER_DIR_LOOKUP_H_
+
+char* xdg_user_dir_lookup(const char *type);
+
+#endif  // CHROME_THIRD_PARTY_XDG_USER_DIRS_XDG_USER_DIR_LOOKUP_H_
diff --git a/base/thread_task_runner_handle.cc b/base/thread_task_runner_handle.cc
new file mode 100644
index 0000000..860a0ec
--- /dev/null
+++ b/base/thread_task_runner_handle.cc
@@ -0,0 +1,46 @@
+// Copyright (c) 2012 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/thread_task_runner_handle.h"
+
+#include "base/lazy_instance.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/thread_local.h"
+
+namespace base {
+
+namespace {
+
+base::LazyInstance<base::ThreadLocalPointer<ThreadTaskRunnerHandle> >
+    lazy_tls_ptr = LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+// static
+scoped_refptr<SingleThreadTaskRunner> ThreadTaskRunnerHandle::Get() {
+  ThreadTaskRunnerHandle* current = lazy_tls_ptr.Pointer()->Get();
+  DCHECK(current);
+  return current->task_runner_;
+}
+
+// static
+bool ThreadTaskRunnerHandle::IsSet() {
+  return lazy_tls_ptr.Pointer()->Get() != NULL;
+}
+
+ThreadTaskRunnerHandle::ThreadTaskRunnerHandle(
+    const scoped_refptr<SingleThreadTaskRunner>& task_runner)
+    : task_runner_(task_runner) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+  DCHECK(!lazy_tls_ptr.Pointer()->Get());
+  lazy_tls_ptr.Pointer()->Set(this);
+}
+
+ThreadTaskRunnerHandle::~ThreadTaskRunnerHandle() {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+  DCHECK_EQ(lazy_tls_ptr.Pointer()->Get(), this);
+  lazy_tls_ptr.Pointer()->Set(NULL);
+}
+
+}  // namespace base
diff --git a/base/thread_task_runner_handle.h b/base/thread_task_runner_handle.h
new file mode 100644
index 0000000..238435f
--- /dev/null
+++ b/base/thread_task_runner_handle.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2012 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_THREAD_TASK_RUNNER_HANDLE_H_
+#define BASE_THREAD_TASK_RUNNER_HANDLE_H_
+
+#include "base/base_export.h"
+#include "base/memory/ref_counted.h"
+
+namespace base {
+
+class SingleThreadTaskRunner;
+
+// ThreadTaskRunnerHandle stores a reference to a thread's TaskRunner
+// in thread-local storage.  Callers can then retrieve the TaskRunner
+// for the current thread by calling ThreadTaskRunnerHandle::Get().
+// At most one TaskRunner may be bound to each thread at a time.
+class BASE_EXPORT ThreadTaskRunnerHandle {
+ public:
+  // Gets the SingleThreadTaskRunner for the current thread.
+  static scoped_refptr<SingleThreadTaskRunner> Get();
+
+  // Returns true if the SingleThreadTaskRunner is already created for
+  // the current thread.
+  static bool IsSet();
+
+  // Binds |task_runner| to the current thread. |task_runner| must belong
+  // to the current thread for this to succeed.
+  explicit ThreadTaskRunnerHandle(
+      const scoped_refptr<SingleThreadTaskRunner>& task_runner);
+  ~ThreadTaskRunnerHandle();
+
+ private:
+  scoped_refptr<SingleThreadTaskRunner> task_runner_;
+};
+
+}  // namespace base
+
+#endif  // BASE_THREAD_TASK_RUNNER_HANDLE_H_
diff --git a/base/threading/OWNERS b/base/threading/OWNERS
new file mode 100644
index 0000000..4198e99
--- /dev/null
+++ b/base/threading/OWNERS
@@ -0,0 +1,2 @@
+# For thread_resrictions.*
+jam@chromium.org
diff --git a/base/threading/non_thread_safe.h b/base/threading/non_thread_safe.h
new file mode 100644
index 0000000..d41c086
--- /dev/null
+++ b/base/threading/non_thread_safe.h
@@ -0,0 +1,71 @@
+// Copyright (c) 2012 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_THREADING_NON_THREAD_SAFE_H_
+#define BASE_THREADING_NON_THREAD_SAFE_H_
+
+// Classes deriving from NonThreadSafe may need to suppress MSVC warning 4275:
+// non dll-interface class 'Bar' used as base for dll-interface class 'Foo'.
+// There is a specific macro to do it: NON_EXPORTED_BASE(), defined in
+// compiler_specific.h
+#include "base/compiler_specific.h"
+
+// See comment at top of thread_checker.h
+#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON))
+#define ENABLE_NON_THREAD_SAFE 1
+#else
+#define ENABLE_NON_THREAD_SAFE 0
+#endif
+
+#include "base/threading/non_thread_safe_impl.h"
+
+namespace base {
+
+// Do nothing implementation of NonThreadSafe, for release mode.
+//
+// Note: You should almost always use the NonThreadSafe class to get
+// the right version of the class for your build configuration.
+class NonThreadSafeDoNothing {
+ public:
+  bool CalledOnValidThread() const {
+    return true;
+  }
+
+ protected:
+  ~NonThreadSafeDoNothing() {}
+  void DetachFromThread() {}
+};
+
+// NonThreadSafe is a helper class used to help verify that methods of a
+// class are called from the same thread.  One can inherit from this class
+// and use CalledOnValidThread() to verify.
+//
+// This is intended to be used with classes that appear to be thread safe, but
+// aren't.  For example, a service or a singleton like the preferences system.
+//
+// Example:
+// class MyClass : public base::NonThreadSafe {
+//  public:
+//   void Foo() {
+//     DCHECK(CalledOnValidThread());
+//     ... (do stuff) ...
+//   }
+// }
+//
+// Note that base::ThreadChecker offers identical functionality to
+// NonThreadSafe, but does not require inheritance. In general, it is preferable
+// to have a base::ThreadChecker as a member, rather than inherit from
+// NonThreadSafe. For more details about when to choose one over the other, see
+// the documentation for base::ThreadChecker.
+#if ENABLE_NON_THREAD_SAFE
+typedef NonThreadSafeImpl NonThreadSafe;
+#else
+typedef NonThreadSafeDoNothing NonThreadSafe;
+#endif  // ENABLE_NON_THREAD_SAFE
+
+#undef ENABLE_NON_THREAD_SAFE
+
+}  // namespace base
+
+#endif  // BASE_THREADING_NON_THREAD_SAFE_H_
diff --git a/base/threading/non_thread_safe_impl.cc b/base/threading/non_thread_safe_impl.cc
new file mode 100644
index 0000000..7e729d9
--- /dev/null
+++ b/base/threading/non_thread_safe_impl.cc
@@ -0,0 +1,23 @@
+// Copyright (c) 2012 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/threading/non_thread_safe_impl.h"
+
+#include "base/logging.h"
+
+namespace base {
+
+bool NonThreadSafeImpl::CalledOnValidThread() const {
+  return thread_checker_.CalledOnValidThread();
+}
+
+NonThreadSafeImpl::~NonThreadSafeImpl() {
+  DCHECK(CalledOnValidThread());
+}
+
+void NonThreadSafeImpl::DetachFromThread() {
+  thread_checker_.DetachFromThread();
+}
+
+}  // namespace base
diff --git a/base/threading/non_thread_safe_impl.h b/base/threading/non_thread_safe_impl.h
new file mode 100644
index 0000000..a3a356d
--- /dev/null
+++ b/base/threading/non_thread_safe_impl.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2012 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_THREADING_NON_THREAD_SAFE_IMPL_H_
+#define BASE_THREADING_NON_THREAD_SAFE_IMPL_H_
+
+#include "base/base_export.h"
+#include "base/threading/thread_checker_impl.h"
+
+namespace base {
+
+// Full implementation of NonThreadSafe, for debug mode or for occasional
+// temporary use in release mode e.g. when you need to CHECK on a thread
+// bug that only occurs in the wild.
+//
+// Note: You should almost always use the NonThreadSafe class to get
+// the right version of the class for your build configuration.
+class BASE_EXPORT NonThreadSafeImpl {
+ public:
+  bool CalledOnValidThread() const;
+
+ protected:
+  ~NonThreadSafeImpl();
+
+  // Changes the thread that is checked for in CalledOnValidThread. The next
+  // call to CalledOnValidThread will attach this class to a new thread. It is
+  // up to the NonThreadSafe derived class to decide to expose this or not.
+  // This may be useful when an object may be created on one thread and then
+  // used exclusively on another thread.
+  void DetachFromThread();
+
+ private:
+  ThreadCheckerImpl thread_checker_;
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_NON_THREAD_SAFE_IMPL_H_
diff --git a/base/threading/non_thread_safe_unittest.cc b/base/threading/non_thread_safe_unittest.cc
new file mode 100644
index 0000000..955c939
--- /dev/null
+++ b/base/threading/non_thread_safe_unittest.cc
@@ -0,0 +1,163 @@
+// Copyright (c) 2012 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/basictypes.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/threading/non_thread_safe.h"
+#include "base/threading/simple_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Duplicated from base/threading/non_thread_safe.h so that we can be
+// good citizens there and undef the macro.
+#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON))
+#define ENABLE_NON_THREAD_SAFE 1
+#else
+#define ENABLE_NON_THREAD_SAFE 0
+#endif
+
+namespace base {
+
+namespace {
+
+// Simple class to exersice the basics of NonThreadSafe.
+// Both the destructor and DoStuff should verify that they were
+// called on the same thread as the constructor.
+class NonThreadSafeClass : public NonThreadSafe {
+ public:
+  NonThreadSafeClass() {}
+
+  // Verifies that it was called on the same thread as the constructor.
+  void DoStuff() {
+    DCHECK(CalledOnValidThread());
+  }
+
+  void DetachFromThread() {
+    NonThreadSafe::DetachFromThread();
+  }
+
+  static void MethodOnDifferentThreadImpl();
+  static void DestructorOnDifferentThreadImpl();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(NonThreadSafeClass);
+};
+
+// Calls NonThreadSafeClass::DoStuff on another thread.
+class CallDoStuffOnThread : public SimpleThread {
+ public:
+  explicit CallDoStuffOnThread(NonThreadSafeClass* non_thread_safe_class)
+      : SimpleThread("call_do_stuff_on_thread"),
+        non_thread_safe_class_(non_thread_safe_class) {
+  }
+
+  void Run() override { non_thread_safe_class_->DoStuff(); }
+
+ private:
+  NonThreadSafeClass* non_thread_safe_class_;
+
+  DISALLOW_COPY_AND_ASSIGN(CallDoStuffOnThread);
+};
+
+// Deletes NonThreadSafeClass on a different thread.
+class DeleteNonThreadSafeClassOnThread : public SimpleThread {
+ public:
+  explicit DeleteNonThreadSafeClassOnThread(
+      NonThreadSafeClass* non_thread_safe_class)
+      : SimpleThread("delete_non_thread_safe_class_on_thread"),
+        non_thread_safe_class_(non_thread_safe_class) {
+  }
+
+  void Run() override { non_thread_safe_class_.reset(); }
+
+ private:
+  scoped_ptr<NonThreadSafeClass> non_thread_safe_class_;
+
+  DISALLOW_COPY_AND_ASSIGN(DeleteNonThreadSafeClassOnThread);
+};
+
+}  // namespace
+
+TEST(NonThreadSafeTest, CallsAllowedOnSameThread) {
+  scoped_ptr<NonThreadSafeClass> non_thread_safe_class(
+      new NonThreadSafeClass);
+
+  // Verify that DoStuff doesn't assert.
+  non_thread_safe_class->DoStuff();
+
+  // Verify that the destructor doesn't assert.
+  non_thread_safe_class.reset();
+}
+
+TEST(NonThreadSafeTest, DetachThenDestructOnDifferentThread) {
+  scoped_ptr<NonThreadSafeClass> non_thread_safe_class(
+      new NonThreadSafeClass);
+
+  // Verify that the destructor doesn't assert when called on a different thread
+  // after a detach.
+  non_thread_safe_class->DetachFromThread();
+  DeleteNonThreadSafeClassOnThread delete_on_thread(
+      non_thread_safe_class.release());
+
+  delete_on_thread.Start();
+  delete_on_thread.Join();
+}
+
+#if GTEST_HAS_DEATH_TEST || !ENABLE_NON_THREAD_SAFE
+
+void NonThreadSafeClass::MethodOnDifferentThreadImpl() {
+  scoped_ptr<NonThreadSafeClass> non_thread_safe_class(
+      new NonThreadSafeClass);
+
+  // Verify that DoStuff asserts in debug builds only when called
+  // on a different thread.
+  CallDoStuffOnThread call_on_thread(non_thread_safe_class.get());
+
+  call_on_thread.Start();
+  call_on_thread.Join();
+}
+
+#if ENABLE_NON_THREAD_SAFE
+TEST(NonThreadSafeDeathTest, MethodNotAllowedOnDifferentThreadInDebug) {
+  ASSERT_DEATH({
+      NonThreadSafeClass::MethodOnDifferentThreadImpl();
+    }, "");
+}
+#else
+TEST(NonThreadSafeTest, MethodAllowedOnDifferentThreadInRelease) {
+  NonThreadSafeClass::MethodOnDifferentThreadImpl();
+}
+#endif  // ENABLE_NON_THREAD_SAFE
+
+void NonThreadSafeClass::DestructorOnDifferentThreadImpl() {
+  scoped_ptr<NonThreadSafeClass> non_thread_safe_class(
+      new NonThreadSafeClass);
+
+  // Verify that the destructor asserts in debug builds only
+  // when called on a different thread.
+  DeleteNonThreadSafeClassOnThread delete_on_thread(
+      non_thread_safe_class.release());
+
+  delete_on_thread.Start();
+  delete_on_thread.Join();
+}
+
+#if ENABLE_NON_THREAD_SAFE
+TEST(NonThreadSafeDeathTest, DestructorNotAllowedOnDifferentThreadInDebug) {
+  ASSERT_DEATH({
+      NonThreadSafeClass::DestructorOnDifferentThreadImpl();
+    }, "");
+}
+#else
+TEST(NonThreadSafeTest, DestructorAllowedOnDifferentThreadInRelease) {
+  NonThreadSafeClass::DestructorOnDifferentThreadImpl();
+}
+#endif  // ENABLE_NON_THREAD_SAFE
+
+#endif  // GTEST_HAS_DEATH_TEST || !ENABLE_NON_THREAD_SAFE
+
+// Just in case we ever get lumped together with other compilation units.
+#undef ENABLE_NON_THREAD_SAFE
+
+}  // namespace base
diff --git a/base/threading/platform_thread.h b/base/threading/platform_thread.h
new file mode 100644
index 0000000..3468f45
--- /dev/null
+++ b/base/threading/platform_thread.h
@@ -0,0 +1,211 @@
+// Copyright (c) 2012 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.
+
+// WARNING: You should *NOT* be using this class directly.  PlatformThread is
+// the low-level platform-specific abstraction to the OS's threading interface.
+// You should instead be using a message-loop driven Thread, see thread.h.
+
+#ifndef BASE_THREADING_PLATFORM_THREAD_H_
+#define BASE_THREADING_PLATFORM_THREAD_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#elif defined(OS_POSIX)
+#include <pthread.h>
+#include <unistd.h>
+#endif
+
+namespace base {
+
+// Used for logging. Always an integer value.
+#if defined(OS_WIN)
+typedef DWORD PlatformThreadId;
+#elif defined(OS_POSIX)
+typedef pid_t PlatformThreadId;
+#endif
+
+// Used for thread checking and debugging.
+// Meant to be as fast as possible.
+// These are produced by PlatformThread::CurrentRef(), and used to later
+// check if we are on the same thread or not by using ==. These are safe
+// to copy between threads, but can't be copied to another process as they
+// have no meaning there. Also, the internal identifier can be re-used
+// after a thread dies, so a PlatformThreadRef cannot be reliably used
+// to distinguish a new thread from an old, dead thread.
+class PlatformThreadRef {
+ public:
+#if defined(OS_WIN)
+  typedef DWORD RefType;
+#elif defined(OS_POSIX)
+  typedef pthread_t RefType;
+#endif
+  PlatformThreadRef()
+      : id_(0) {
+  }
+
+  explicit PlatformThreadRef(RefType id)
+      : id_(id) {
+  }
+
+  bool operator==(PlatformThreadRef other) const {
+    return id_ == other.id_;
+  }
+
+  bool is_null() const {
+    return id_ == 0;
+  }
+ private:
+  RefType id_;
+};
+
+// Used to operate on threads.
+class PlatformThreadHandle {
+ public:
+#if defined(OS_WIN)
+  typedef void* Handle;
+#elif defined(OS_POSIX)
+  typedef pthread_t Handle;
+#endif
+
+  PlatformThreadHandle()
+      : handle_(0),
+        id_(0) {
+  }
+
+  explicit PlatformThreadHandle(Handle handle)
+      : handle_(handle),
+        id_(0) {
+  }
+
+  PlatformThreadHandle(Handle handle,
+                       PlatformThreadId id)
+      : handle_(handle),
+        id_(id) {
+  }
+
+  PlatformThreadId id() const {
+    return id_;
+  }
+
+  bool is_equal(const PlatformThreadHandle& other) const {
+    return handle_ == other.handle_;
+  }
+
+  bool is_null() const {
+    return !handle_;
+  }
+
+  Handle platform_handle() const {
+    return handle_;
+  }
+
+ private:
+  Handle handle_;
+  PlatformThreadId id_;
+};
+
+const PlatformThreadId kInvalidThreadId(0);
+
+// Valid values for SetThreadPriority(), listed in increasing order of
+// importance.
+enum class ThreadPriority {
+  // Suitable for threads that shouldn't disrupt high priority work.
+  BACKGROUND,
+  // Default priority level.
+  NORMAL,
+  // Suitable for threads which generate data for the display (at ~60Hz).
+  DISPLAY,
+  // Suitable for low-latency, glitch-resistant audio.
+  REALTIME_AUDIO,
+};
+
+// A namespace for low-level thread functions.
+class BASE_EXPORT PlatformThread {
+ public:
+  // Implement this interface to run code on a background thread.  Your
+  // ThreadMain method will be called on the newly created thread.
+  class BASE_EXPORT Delegate {
+   public:
+    virtual void ThreadMain() = 0;
+
+   protected:
+    virtual ~Delegate() {}
+  };
+
+  // Gets the current thread id, which may be useful for logging purposes.
+  static PlatformThreadId CurrentId();
+
+  // Gets the current thread reference, which can be used to check if
+  // we're on the right thread quickly.
+  static PlatformThreadRef CurrentRef();
+
+  // Get the handle representing the current thread. On Windows, this is a
+  // pseudo handle constant which will always represent the thread using it and
+  // hence should not be shared with other threads nor be used to differentiate
+  // the current thread from another.
+  static PlatformThreadHandle CurrentHandle();
+
+  // Yield the current thread so another thread can be scheduled.
+  static void YieldCurrentThread();
+
+  // Sleeps for the specified duration.
+  static void Sleep(base::TimeDelta duration);
+
+  // Sets the thread name visible to debuggers/tools. This has no effect
+  // otherwise.
+  static void SetName(const std::string& name);
+
+  // Gets the thread name, if previously set by SetName.
+  static const char* GetName();
+
+  // Creates a new thread.  The |stack_size| parameter can be 0 to indicate
+  // that the default stack size should be used.  Upon success,
+  // |*thread_handle| will be assigned a handle to the newly created thread,
+  // and |delegate|'s ThreadMain method will be executed on the newly created
+  // thread.
+  // NOTE: When you are done with the thread handle, you must call Join to
+  // release system resources associated with the thread.  You must ensure that
+  // the Delegate object outlives the thread.
+  static bool Create(size_t stack_size, Delegate* delegate,
+                     PlatformThreadHandle* thread_handle);
+
+  // CreateWithPriority() does the same thing as Create() except the priority of
+  // the thread is set based on |priority|.  Can be used in place of Create()
+  // followed by SetThreadPriority().
+  static bool CreateWithPriority(size_t stack_size, Delegate* delegate,
+                                 PlatformThreadHandle* thread_handle,
+                                 ThreadPriority priority);
+
+  // CreateNonJoinable() does the same thing as Create() except the thread
+  // cannot be Join()'d.  Therefore, it also does not output a
+  // PlatformThreadHandle.
+  static bool CreateNonJoinable(size_t stack_size, Delegate* delegate);
+
+  // Joins with a thread created via the Create function.  This function blocks
+  // the caller until the designated thread exits.  This will invalidate
+  // |thread_handle|.
+  static void Join(PlatformThreadHandle thread_handle);
+
+  // Toggles the target thread's priority at runtime.  Prefer
+  // CreateWithPriority() to set the thread's initial priority.
+  // NOTE: The call may fail if the caller thread is not the same as the
+  // target thread on POSIX.  For example, seccomp-bpf blocks it by default
+  // in the sandbox.
+  static void SetThreadPriority(PlatformThreadHandle handle,
+                                ThreadPriority priority);
+
+  static ThreadPriority GetThreadPriority(PlatformThreadHandle handle);
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(PlatformThread);
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_PLATFORM_THREAD_H_
diff --git a/base/threading/platform_thread_android.cc b/base/threading/platform_thread_android.cc
new file mode 100644
index 0000000..11e5e2e
--- /dev/null
+++ b/base/threading/platform_thread_android.cc
@@ -0,0 +1,113 @@
+// Copyright (c) 2012 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/threading/platform_thread.h"
+
+#include <errno.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/thread_utils.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/threading/platform_thread_internal_posix.h"
+#include "base/threading/thread_id_name_manager.h"
+#include "base/tracked_objects.h"
+#include "jni/ThreadUtils_jni.h"
+
+namespace base {
+
+namespace internal {
+
+// These nice values are taken from Android, which uses nice values like linux,
+// but defines some preset nice values.
+//   Process.THREAD_PRIORITY_AUDIO = -16
+//   Process.THREAD_PRIORITY_BACKGROUND = 10
+//   Process.THREAD_PRIORITY_DEFAULT = 0;
+//   Process.THREAD_PRIORITY_DISPLAY = -4;
+//   Process.THREAD_PRIORITY_FOREGROUND = -2;
+//   Process.THREAD_PRIORITY_LESS_FAVORABLE = 1;
+//   Process.THREAD_PRIORITY_LOWEST = 19;
+//   Process.THREAD_PRIORITY_MORE_FAVORABLE = -1;
+//   Process.THREAD_PRIORITY_URGENT_AUDIO = -19;
+//   Process.THREAD_PRIORITY_URGENT_DISPLAY = -8;
+// We use -6 for display, but we may want to split this into urgent (-8) and
+// non-urgent (-4).
+const ThreadPriorityToNiceValuePair kThreadPriorityToNiceValueMap[4] = {
+    {ThreadPriority::BACKGROUND, 10},
+    {ThreadPriority::NORMAL, 0},
+    {ThreadPriority::DISPLAY, -6},
+    {ThreadPriority::REALTIME_AUDIO, -16},
+};
+
+bool SetThreadPriorityForPlatform(PlatformThreadHandle handle,
+                                  ThreadPriority priority) {
+  // On Android, we set the Audio priority through JNI as Audio priority
+  // will also allow the process to run while it is backgrounded.
+  if (priority == ThreadPriority::REALTIME_AUDIO) {
+    JNIEnv* env = base::android::AttachCurrentThread();
+    Java_ThreadUtils_setThreadPriorityAudio(env, PlatformThread::CurrentId());
+    return true;
+  }
+  return false;
+}
+
+bool GetThreadPriorityForPlatform(PlatformThreadHandle handle,
+                                  ThreadPriority* priority) {
+  NOTIMPLEMENTED();
+  return false;
+}
+
+}  // namespace internal
+
+void PlatformThread::SetName(const std::string& name) {
+  ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name);
+  tracked_objects::ThreadData::InitializeThreadContext(name);
+
+  // Like linux, on android we can get the thread names to show up in the
+  // debugger by setting the process name for the LWP.
+  // We don't want to do this for the main thread because that would rename
+  // the process, causing tools like killall to stop working.
+  if (PlatformThread::CurrentId() == getpid())
+    return;
+
+  // Set the name for the LWP (which gets truncated to 15 characters).
+  int err = prctl(PR_SET_NAME, name.c_str());
+  if (err < 0 && errno != EPERM)
+    DPLOG(ERROR) << "prctl(PR_SET_NAME)";
+}
+
+
+void InitThreading() {
+}
+
+void InitOnThread() {
+  // Threads on linux/android may inherit their priority from the thread
+  // where they were created. This sets all new threads to the default.
+  PlatformThread::SetThreadPriority(PlatformThread::CurrentHandle(),
+                                    ThreadPriority::NORMAL);
+}
+
+void TerminateOnThread() {
+  base::android::DetachFromVM();
+}
+
+size_t GetDefaultThreadStackSize(const pthread_attr_t& attributes) {
+#if !defined(ADDRESS_SANITIZER)
+  return 0;
+#else
+  // AddressSanitizer bloats the stack approximately 2x. Default stack size of
+  // 1Mb is not enough for some tests (see http://crbug.com/263749 for example).
+  return 2 * (1 << 20);  // 2Mb
+#endif
+}
+
+bool RegisterThreadUtils(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+}  // namespace base
diff --git a/base/threading/platform_thread_freebsd.cc b/base/threading/platform_thread_freebsd.cc
new file mode 100644
index 0000000..f4fded0
--- /dev/null
+++ b/base/threading/platform_thread_freebsd.cc
@@ -0,0 +1,103 @@
+// 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.
+
+#include "base/threading/platform_thread.h"
+
+#include <errno.h>
+#include <sched.h>
+
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/threading/thread_id_name_manager.h"
+#include "base/tracked_objects.h"
+
+#if !defined(OS_NACL)
+#include <pthread.h>
+#include <sys/prctl.h>
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
+namespace base {
+
+namespace internal {
+
+namespace {
+#if !defined(OS_NACL)
+const struct sched_param kRealTimePrio = {8};
+#endif
+}  // namespace
+
+const ThreadPriorityToNiceValuePair kThreadPriorityToNiceValueMap[4] = {
+    {ThreadPriority::BACKGROUND, 10},
+    {ThreadPriority::NORMAL, 0},
+    {ThreadPriority::DISPLAY, -6},
+    {ThreadPriority::REALTIME_AUDIO, -10},
+}
+
+bool SetThreadPriorityForPlatform(PlatformThreadHandle handle,
+                                  ThreadPriority priority) {
+#if !defined(OS_NACL)
+  // TODO(gab): Assess the correctness of using |pthread_self()| below instead
+  // of |handle|. http://crbug.com/468793.
+  return priority == ThreadPriority::REALTIME_AUDIO &&
+         pthread_setschedparam(pthread_self(), SCHED_RR, &kRealTimePrio) == 0;
+#else
+  return false;
+#endif
+}
+
+bool GetThreadPriorityForPlatform(PlatformThreadHandle handle,
+                                  ThreadPriority* priority) {
+#if !defined(OS_NACL)
+  // TODO(gab): Assess the correctness of using |pthread_self()| below instead
+  // of |handle|. http://crbug.com/468793.
+  int maybe_sched_rr = 0;
+  struct sched_param maybe_realtime_prio = {0};
+  if (pthread_getschedparam(pthread_self(), &maybe_sched_rr,
+                            &maybe_realtime_prio) == 0 &&
+      maybe_sched_rr == SCHED_RR &&
+      maybe_realtime_prio.sched_priority == kRealTimePrio.sched_priority) {
+    *priority = ThreadPriority::REALTIME_AUDIO;
+    return true;
+  }
+#endif
+  return false;
+}
+
+}  // namespace internal
+
+// static
+void PlatformThread::SetName(const std::string& name) {
+  ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name);
+  tracked_objects::ThreadData::InitializeThreadContext(name);
+
+#if !defined(OS_NACL)
+  // On FreeBSD we can get the thread names to show up in the debugger by
+  // setting the process name for the LWP.  We don't want to do this for the
+  // main thread because that would rename the process, causing tools like
+  // killall to stop working.
+  if (PlatformThread::CurrentId() == getpid())
+    return;
+  setproctitle("%s", name.c_str());
+#endif  //  !defined(OS_NACL)
+}
+
+void InitThreading() {}
+
+void InitOnThread() {}
+
+void TerminateOnThread() {}
+
+size_t GetDefaultThreadStackSize(const pthread_attr_t& attributes) {
+#if !defined(THREAD_SANITIZER)
+  return 0;
+#else
+  // ThreadSanitizer bloats the stack heavily. Evidence has been that the
+  // default stack size isn't enough for some browser tests.
+  return 2 * (1 << 23);  // 2 times 8192K (the default stack size on Linux).
+#endif
+}
+
+}  // namespace base
diff --git a/base/threading/platform_thread_internal_posix.cc b/base/threading/platform_thread_internal_posix.cc
new file mode 100644
index 0000000..9af0204
--- /dev/null
+++ b/base/threading/platform_thread_internal_posix.cc
@@ -0,0 +1,35 @@
+// 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/threading/platform_thread_internal_posix.h"
+
+#include "base/logging.h"
+
+namespace base {
+
+namespace internal {
+
+int ThreadPriorityToNiceValue(ThreadPriority priority) {
+  for (const ThreadPriorityToNiceValuePair& pair :
+       kThreadPriorityToNiceValueMap) {
+    if (pair.priority == priority)
+      return pair.nice_value;
+  }
+  NOTREACHED() << "Unknown ThreadPriority";
+  return 0;
+}
+
+ThreadPriority NiceValueToThreadPriority(int nice_value) {
+  for (const ThreadPriorityToNiceValuePair& pair :
+       kThreadPriorityToNiceValueMap) {
+    if (pair.nice_value == nice_value)
+      return pair.priority;
+  }
+  NOTREACHED() << "Unknown nice value";
+  return ThreadPriority::NORMAL;
+}
+
+}  // namespace internal
+
+}  // namespace base
diff --git a/base/threading/platform_thread_internal_posix.h b/base/threading/platform_thread_internal_posix.h
new file mode 100644
index 0000000..62006ce
--- /dev/null
+++ b/base/threading/platform_thread_internal_posix.h
@@ -0,0 +1,45 @@
+// 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_THREADING_PLATFORM_THREAD_INTERNAL_POSIX_H_
+#define BASE_THREADING_PLATFORM_THREAD_INTERNAL_POSIX_H_
+
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+namespace internal {
+
+struct ThreadPriorityToNiceValuePair {
+  ThreadPriority priority;
+  int nice_value;
+};
+extern const ThreadPriorityToNiceValuePair kThreadPriorityToNiceValueMap[4];
+
+// Returns the nice value matching |priority| based on the platform-specific
+// implementation of kThreadPriorityToNiceValueMap.
+int ThreadPriorityToNiceValue(ThreadPriority priority);
+
+// Returns the ThreadPrioirty matching |nice_value| based on the platform-
+// specific implementation of kThreadPriorityToNiceValueMap.
+ThreadPriority NiceValueToThreadPriority(int nice_value);
+
+// Allows platform specific tweaks to the generic POSIX solution for
+// SetThreadPriority. Returns true if the platform-specific implementation
+// handled this |priority| change, false if the generic implementation should
+// instead proceed.
+bool SetThreadPriorityForPlatform(PlatformThreadHandle handle,
+                                  ThreadPriority priority);
+
+// Returns true if there is a platform-specific ThreadPriority set on |handle|
+// (and returns the actual ThreadPriority via |priority|). Returns false
+// otherwise, leaving |priority| untouched.
+bool GetThreadPriorityForPlatform(PlatformThreadHandle handle,
+                                  ThreadPriority* priority);
+
+}  // namespace internal
+
+}  // namespace base
+
+#endif  // BASE_THREADING_PLATFORM_THREAD_INTERNAL_POSIX_H_
diff --git a/base/threading/platform_thread_linux.cc b/base/threading/platform_thread_linux.cc
new file mode 100644
index 0000000..9f74374
--- /dev/null
+++ b/base/threading/platform_thread_linux.cc
@@ -0,0 +1,113 @@
+// Copyright (c) 2012 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/threading/platform_thread.h"
+
+#include <errno.h>
+#include <sched.h>
+
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/threading/platform_thread_internal_posix.h"
+#include "base/threading/thread_id_name_manager.h"
+#include "base/tracked_objects.h"
+
+#if !defined(OS_NACL)
+#include <pthread.h>
+#include <sys/prctl.h>
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
+namespace base {
+
+namespace internal {
+
+namespace {
+#if !defined(OS_NACL)
+const struct sched_param kRealTimePrio = {8};
+#endif
+}  // namespace
+
+const ThreadPriorityToNiceValuePair kThreadPriorityToNiceValueMap[4] = {
+    {ThreadPriority::BACKGROUND, 10},
+    {ThreadPriority::NORMAL, 0},
+    {ThreadPriority::DISPLAY, -6},
+    {ThreadPriority::REALTIME_AUDIO, -10},
+};
+
+bool SetThreadPriorityForPlatform(PlatformThreadHandle handle,
+                                  ThreadPriority priority) {
+#if !defined(OS_NACL)
+  // TODO(gab): Assess the correctness of using |pthread_self()| below instead
+  // of |handle|. http://crbug.com/468793.
+  return priority == ThreadPriority::REALTIME_AUDIO  &&
+         pthread_setschedparam(pthread_self(), SCHED_RR, &kRealTimePrio) == 0;
+#else
+  return false;
+#endif
+}
+
+bool GetThreadPriorityForPlatform(PlatformThreadHandle handle,
+                                  ThreadPriority* priority) {
+#if !defined(OS_NACL)
+  int maybe_sched_rr = 0;
+  struct sched_param maybe_realtime_prio = {0};
+  // TODO(gab): Assess the correctness of using |pthread_self()| below instead
+  // of |handle|. http://crbug.com/468793.
+  if (pthread_getschedparam(pthread_self(), &maybe_sched_rr,
+                            &maybe_realtime_prio) == 0 &&
+      maybe_sched_rr == SCHED_RR &&
+      maybe_realtime_prio.sched_priority == kRealTimePrio.sched_priority) {
+    *priority = ThreadPriority::REALTIME_AUDIO;
+    return true;
+  }
+#endif
+  return false;
+}
+
+}  // namespace internal
+
+// static
+void PlatformThread::SetName(const std::string& name) {
+  ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name);
+  tracked_objects::ThreadData::InitializeThreadContext(name);
+
+#if !defined(OS_NACL)
+  // On linux we can get the thread names to show up in the debugger by setting
+  // the process name for the LWP.  We don't want to do this for the main
+  // thread because that would rename the process, causing tools like killall
+  // to stop working.
+  if (PlatformThread::CurrentId() == getpid())
+    return;
+
+  // http://0pointer.de/blog/projects/name-your-threads.html
+  // Set the name for the LWP (which gets truncated to 15 characters).
+  // Note that glibc also has a 'pthread_setname_np' api, but it may not be
+  // available everywhere and it's only benefit over using prctl directly is
+  // that it can set the name of threads other than the current thread.
+  int err = prctl(PR_SET_NAME, name.c_str());
+  // We expect EPERM failures in sandboxed processes, just ignore those.
+  if (err < 0 && errno != EPERM)
+    DPLOG(ERROR) << "prctl(PR_SET_NAME)";
+#endif  //  !defined(OS_NACL)
+}
+
+void InitThreading() {}
+
+void InitOnThread() {}
+
+void TerminateOnThread() {}
+
+size_t GetDefaultThreadStackSize(const pthread_attr_t& attributes) {
+#if !defined(THREAD_SANITIZER)
+  return 0;
+#else
+  // ThreadSanitizer bloats the stack heavily. Evidence has been that the
+  // default stack size isn't enough for some browser tests.
+  return 2 * (1 << 23);  // 2 times 8192K (the default stack size on Linux).
+#endif
+}
+
+}  // namespace base
diff --git a/base/threading/platform_thread_mac.mm b/base/threading/platform_thread_mac.mm
new file mode 100644
index 0000000..813cae2
--- /dev/null
+++ b/base/threading/platform_thread_mac.mm
@@ -0,0 +1,223 @@
+// Copyright (c) 2012 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/threading/platform_thread.h"
+
+#import <Foundation/Foundation.h>
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+#include <mach/thread_policy.h>
+#include <sys/resource.h>
+
+#include <algorithm>
+
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/mac/mach_logging.h"
+#include "base/threading/thread_id_name_manager.h"
+#include "base/tracked_objects.h"
+
+namespace base {
+
+// If Cocoa is to be used on more than one thread, it must know that the
+// application is multithreaded.  Since it's possible to enter Cocoa code
+// from threads created by pthread_thread_create, Cocoa won't necessarily
+// be aware that the application is multithreaded.  Spawning an NSThread is
+// enough to get Cocoa to set up for multithreaded operation, so this is done
+// if necessary before pthread_thread_create spawns any threads.
+//
+// http://developer.apple.com/documentation/Cocoa/Conceptual/Multithreading/CreatingThreads/chapter_4_section_4.html
+void InitThreading() {
+  static BOOL multithreaded = [NSThread isMultiThreaded];
+  if (!multithreaded) {
+    // +[NSObject class] is idempotent.
+    [NSThread detachNewThreadSelector:@selector(class)
+                             toTarget:[NSObject class]
+                           withObject:nil];
+    multithreaded = YES;
+
+    DCHECK([NSThread isMultiThreaded]);
+  }
+}
+
+// static
+void PlatformThread::SetName(const std::string& name) {
+  ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name);
+  tracked_objects::ThreadData::InitializeThreadContext(name);
+
+  // Mac OS X does not expose the length limit of the name, so
+  // hardcode it.
+  const int kMaxNameLength = 63;
+  std::string shortened_name = name.substr(0, kMaxNameLength);
+  // pthread_setname() fails (harmlessly) in the sandbox, ignore when it does.
+  // See http://crbug.com/47058
+  pthread_setname_np(shortened_name.c_str());
+}
+
+namespace {
+
+void SetPriorityNormal(mach_port_t mach_thread_id) {
+  // Make thread standard policy.
+  // Please note that this call could fail in rare cases depending
+  // on runtime conditions.
+  thread_standard_policy policy;
+  kern_return_t result =
+      thread_policy_set(mach_thread_id,
+                        THREAD_STANDARD_POLICY,
+                        reinterpret_cast<thread_policy_t>(&policy),
+                        THREAD_STANDARD_POLICY_COUNT);
+
+  if (result != KERN_SUCCESS)
+    MACH_DVLOG(1, result) << "thread_policy_set";
+}
+
+// Enables time-contraint policy and priority suitable for low-latency,
+// glitch-resistant audio.
+void SetPriorityRealtimeAudio(mach_port_t mach_thread_id) {
+  // Increase thread priority to real-time.
+
+  // Please note that the thread_policy_set() calls may fail in
+  // rare cases if the kernel decides the system is under heavy load
+  // and is unable to handle boosting the thread priority.
+  // In these cases we just return early and go on with life.
+
+  // Make thread fixed priority.
+  thread_extended_policy_data_t policy;
+  policy.timeshare = 0;  // Set to 1 for a non-fixed thread.
+  kern_return_t result =
+      thread_policy_set(mach_thread_id,
+                        THREAD_EXTENDED_POLICY,
+                        reinterpret_cast<thread_policy_t>(&policy),
+                        THREAD_EXTENDED_POLICY_COUNT);
+  if (result != KERN_SUCCESS) {
+    MACH_DVLOG(1, result) << "thread_policy_set";
+    return;
+  }
+
+  // Set to relatively high priority.
+  thread_precedence_policy_data_t precedence;
+  precedence.importance = 63;
+  result = thread_policy_set(mach_thread_id,
+                             THREAD_PRECEDENCE_POLICY,
+                             reinterpret_cast<thread_policy_t>(&precedence),
+                             THREAD_PRECEDENCE_POLICY_COUNT);
+  if (result != KERN_SUCCESS) {
+    MACH_DVLOG(1, result) << "thread_policy_set";
+    return;
+  }
+
+  // Most important, set real-time constraints.
+
+  // Define the guaranteed and max fraction of time for the audio thread.
+  // These "duty cycle" values can range from 0 to 1.  A value of 0.5
+  // means the scheduler would give half the time to the thread.
+  // These values have empirically been found to yield good behavior.
+  // Good means that audio performance is high and other threads won't starve.
+  const double kGuaranteedAudioDutyCycle = 0.75;
+  const double kMaxAudioDutyCycle = 0.85;
+
+  // Define constants determining how much time the audio thread can
+  // use in a given time quantum.  All times are in milliseconds.
+
+  // About 128 frames @44.1KHz
+  const double kTimeQuantum = 2.9;
+
+  // Time guaranteed each quantum.
+  const double kAudioTimeNeeded = kGuaranteedAudioDutyCycle * kTimeQuantum;
+
+  // Maximum time each quantum.
+  const double kMaxTimeAllowed = kMaxAudioDutyCycle * kTimeQuantum;
+
+  // Get the conversion factor from milliseconds to absolute time
+  // which is what the time-constraints call needs.
+  mach_timebase_info_data_t tb_info;
+  mach_timebase_info(&tb_info);
+  double ms_to_abs_time =
+      (static_cast<double>(tb_info.denom) / tb_info.numer) * 1000000;
+
+  thread_time_constraint_policy_data_t time_constraints;
+  time_constraints.period = kTimeQuantum * ms_to_abs_time;
+  time_constraints.computation = kAudioTimeNeeded * ms_to_abs_time;
+  time_constraints.constraint = kMaxTimeAllowed * ms_to_abs_time;
+  time_constraints.preemptible = 0;
+
+  result =
+      thread_policy_set(mach_thread_id,
+                        THREAD_TIME_CONSTRAINT_POLICY,
+                        reinterpret_cast<thread_policy_t>(&time_constraints),
+                        THREAD_TIME_CONSTRAINT_POLICY_COUNT);
+  MACH_DVLOG_IF(1, result != KERN_SUCCESS, result) << "thread_policy_set";
+
+  return;
+}
+
+}  // anonymous namespace
+
+// static
+void PlatformThread::SetThreadPriority(PlatformThreadHandle handle,
+                                       ThreadPriority priority) {
+  // Convert from pthread_t to mach thread identifier.
+  mach_port_t mach_thread_id = pthread_mach_thread_np(handle.platform_handle());
+
+  switch (priority) {
+    case ThreadPriority::NORMAL:
+      SetPriorityNormal(mach_thread_id);
+      break;
+    case ThreadPriority::REALTIME_AUDIO:
+      SetPriorityRealtimeAudio(mach_thread_id);
+      break;
+    default:
+      NOTREACHED() << "Unknown priority.";
+      break;
+  }
+}
+
+// static
+ThreadPriority PlatformThread::GetThreadPriority(PlatformThreadHandle handle) {
+  NOTIMPLEMENTED();
+  return ThreadPriority::NORMAL;
+}
+
+size_t GetDefaultThreadStackSize(const pthread_attr_t& attributes) {
+#if defined(OS_IOS)
+  return 0;
+#else
+  // The Mac OS X default for a pthread stack size is 512kB.
+  // Libc-594.1.4/pthreads/pthread.c's pthread_attr_init uses
+  // DEFAULT_STACK_SIZE for this purpose.
+  //
+  // 512kB isn't quite generous enough for some deeply recursive threads that
+  // otherwise request the default stack size by specifying 0. Here, adopt
+  // glibc's behavior as on Linux, which is to use the current stack size
+  // limit (ulimit -s) as the default stack size. See
+  // glibc-2.11.1/nptl/nptl-init.c's __pthread_initialize_minimal_internal. To
+  // avoid setting the limit below the Mac OS X default or the minimum usable
+  // stack size, these values are also considered. If any of these values
+  // can't be determined, or if stack size is unlimited (ulimit -s unlimited),
+  // stack_size is left at 0 to get the system default.
+  //
+  // Mac OS X normally only applies ulimit -s to the main thread stack. On
+  // contemporary OS X and Linux systems alike, this value is generally 8MB
+  // or in that neighborhood.
+  size_t default_stack_size = 0;
+  struct rlimit stack_rlimit;
+  if (pthread_attr_getstacksize(&attributes, &default_stack_size) == 0 &&
+      getrlimit(RLIMIT_STACK, &stack_rlimit) == 0 &&
+      stack_rlimit.rlim_cur != RLIM_INFINITY) {
+    default_stack_size =
+        std::max(std::max(default_stack_size,
+                          static_cast<size_t>(PTHREAD_STACK_MIN)),
+                 static_cast<size_t>(stack_rlimit.rlim_cur));
+  }
+  return default_stack_size;
+#endif
+}
+
+void InitOnThread() {
+}
+
+void TerminateOnThread() {
+}
+
+}  // namespace base
diff --git a/base/threading/platform_thread_posix.cc b/base/threading/platform_thread_posix.cc
new file mode 100644
index 0000000..0d821a9
--- /dev/null
+++ b/base/threading/platform_thread_posix.cc
@@ -0,0 +1,294 @@
+// Copyright (c) 2012 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/threading/platform_thread.h"
+
+#include <errno.h>
+#include <pthread.h>
+#include <sched.h>
+#include <sys/resource.h>
+#include <sys/time.h>
+
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/platform_thread_internal_posix.h"
+#include "base/threading/thread_id_name_manager.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/tracked_objects.h"
+
+#if defined(OS_LINUX)
+#include <sys/syscall.h>
+#elif defined(OS_ANDROID)
+#include <sys/types.h>
+#endif
+
+namespace base {
+
+void InitThreading();
+void InitOnThread();
+void TerminateOnThread();
+size_t GetDefaultThreadStackSize(const pthread_attr_t& attributes);
+
+namespace {
+
+struct ThreadParams {
+  ThreadParams()
+      : delegate(NULL),
+        joinable(false),
+        priority(ThreadPriority::NORMAL),
+        handle(NULL),
+        handle_set(false, false) {
+  }
+
+  PlatformThread::Delegate* delegate;
+  bool joinable;
+  ThreadPriority priority;
+  PlatformThreadHandle* handle;
+  WaitableEvent handle_set;
+};
+
+void* ThreadFunc(void* params) {
+  base::InitOnThread();
+  ThreadParams* thread_params = static_cast<ThreadParams*>(params);
+
+  PlatformThread::Delegate* delegate = thread_params->delegate;
+  if (!thread_params->joinable)
+    base::ThreadRestrictions::SetSingletonAllowed(false);
+
+  if (thread_params->priority != ThreadPriority::NORMAL) {
+    PlatformThread::SetThreadPriority(PlatformThread::CurrentHandle(),
+                                      thread_params->priority);
+  }
+
+  // Stash the id in the handle so the calling thread has a complete
+  // handle, and unblock the parent thread.
+  *(thread_params->handle) = PlatformThreadHandle(pthread_self(),
+                                                  PlatformThread::CurrentId());
+  thread_params->handle_set.Signal();
+
+  ThreadIdNameManager::GetInstance()->RegisterThread(
+      PlatformThread::CurrentHandle().platform_handle(),
+      PlatformThread::CurrentId());
+
+  delegate->ThreadMain();
+
+  ThreadIdNameManager::GetInstance()->RemoveName(
+      PlatformThread::CurrentHandle().platform_handle(),
+      PlatformThread::CurrentId());
+
+  base::TerminateOnThread();
+  return NULL;
+}
+
+bool CreateThread(size_t stack_size, bool joinable,
+                  PlatformThread::Delegate* delegate,
+                  PlatformThreadHandle* thread_handle,
+                  ThreadPriority priority) {
+  base::InitThreading();
+
+  bool success = false;
+  pthread_attr_t attributes;
+  pthread_attr_init(&attributes);
+
+  // Pthreads are joinable by default, so only specify the detached
+  // attribute if the thread should be non-joinable.
+  if (!joinable) {
+    pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_DETACHED);
+  }
+
+  // Get a better default if available.
+  if (stack_size == 0)
+    stack_size = base::GetDefaultThreadStackSize(attributes);
+
+  if (stack_size > 0)
+    pthread_attr_setstacksize(&attributes, stack_size);
+
+  ThreadParams params;
+  params.delegate = delegate;
+  params.joinable = joinable;
+  params.priority = priority;
+  params.handle = thread_handle;
+
+  pthread_t handle;
+  int err = pthread_create(&handle,
+                           &attributes,
+                           ThreadFunc,
+                           &params);
+  success = !err;
+  if (!success) {
+    // Value of |handle| is undefined if pthread_create fails.
+    handle = 0;
+    errno = err;
+    PLOG(ERROR) << "pthread_create";
+  }
+
+  pthread_attr_destroy(&attributes);
+
+  // Don't let this call complete until the thread id
+  // is set in the handle.
+  if (success)
+    params.handle_set.Wait();
+  CHECK_EQ(handle, thread_handle->platform_handle());
+
+  return success;
+}
+
+}  // namespace
+
+// static
+PlatformThreadId PlatformThread::CurrentId() {
+  // Pthreads doesn't have the concept of a thread ID, so we have to reach down
+  // into the kernel.
+#if defined(OS_MACOSX)
+  return pthread_mach_thread_np(pthread_self());
+#elif defined(OS_LINUX)
+  return syscall(__NR_gettid);
+#elif defined(OS_ANDROID)
+  return gettid();
+#elif defined(OS_SOLARIS) || defined(OS_QNX)
+  return pthread_self();
+#elif defined(OS_NACL) && defined(__GLIBC__)
+  return pthread_self();
+#elif defined(OS_NACL) && !defined(__GLIBC__)
+  // Pointers are 32-bits in NaCl.
+  return reinterpret_cast<int32>(pthread_self());
+#elif defined(OS_POSIX)
+  return reinterpret_cast<int64>(pthread_self());
+#endif
+}
+
+// static
+PlatformThreadRef PlatformThread::CurrentRef() {
+  return PlatformThreadRef(pthread_self());
+}
+
+// static
+PlatformThreadHandle PlatformThread::CurrentHandle() {
+  return PlatformThreadHandle(pthread_self(), CurrentId());
+}
+
+// static
+void PlatformThread::YieldCurrentThread() {
+  sched_yield();
+}
+
+// static
+void PlatformThread::Sleep(TimeDelta duration) {
+  struct timespec sleep_time, remaining;
+
+  // Break the duration into seconds and nanoseconds.
+  // NOTE: TimeDelta's microseconds are int64s while timespec's
+  // nanoseconds are longs, so this unpacking must prevent overflow.
+  sleep_time.tv_sec = duration.InSeconds();
+  duration -= TimeDelta::FromSeconds(sleep_time.tv_sec);
+  sleep_time.tv_nsec = duration.InMicroseconds() * 1000;  // nanoseconds
+
+  while (nanosleep(&sleep_time, &remaining) == -1 && errno == EINTR)
+    sleep_time = remaining;
+}
+
+// static
+const char* PlatformThread::GetName() {
+  return ThreadIdNameManager::GetInstance()->GetName(CurrentId());
+}
+
+// static
+bool PlatformThread::Create(size_t stack_size, Delegate* delegate,
+                            PlatformThreadHandle* thread_handle) {
+  base::ThreadRestrictions::ScopedAllowWait allow_wait;
+  return CreateThread(stack_size, true /* joinable thread */,
+                      delegate, thread_handle, ThreadPriority::NORMAL);
+}
+
+// static
+bool PlatformThread::CreateWithPriority(size_t stack_size, Delegate* delegate,
+                                        PlatformThreadHandle* thread_handle,
+                                        ThreadPriority priority) {
+  base::ThreadRestrictions::ScopedAllowWait allow_wait;
+  return CreateThread(stack_size, true,  // joinable thread
+                      delegate, thread_handle, priority);
+}
+
+// static
+bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) {
+  PlatformThreadHandle unused;
+
+  base::ThreadRestrictions::ScopedAllowWait allow_wait;
+  bool result = CreateThread(stack_size, false /* non-joinable thread */,
+                             delegate, &unused, ThreadPriority::NORMAL);
+  return result;
+}
+
+// static
+void PlatformThread::Join(PlatformThreadHandle thread_handle) {
+  // Joining another thread may block the current thread for a long time, since
+  // the thread referred to by |thread_handle| may still be running long-lived /
+  // blocking tasks.
+  base::ThreadRestrictions::AssertIOAllowed();
+  CHECK_EQ(0, pthread_join(thread_handle.platform_handle(), NULL));
+}
+
+// Mac has its own Set/GetThreadPriority() implementations.
+#if !defined(OS_MACOSX)
+
+// static
+void PlatformThread::SetThreadPriority(PlatformThreadHandle handle,
+                                       ThreadPriority priority) {
+#if defined(OS_NACL)
+  NOTIMPLEMENTED();
+#else
+  if (internal::SetThreadPriorityForPlatform(handle, priority))
+    return;
+
+  // setpriority(2) should change the whole thread group's (i.e. process)
+  // priority. However, as stated in the bugs section of
+  // http://man7.org/linux/man-pages/man2/getpriority.2.html: "under the current
+  // Linux/NPTL implementation of POSIX threads, the nice value is a per-thread
+  // attribute". Also, 0 is prefered to the current thread id since it is
+  // equivalent but makes sandboxing easier (https://crbug.com/399473).
+  DCHECK_NE(handle.id(), kInvalidThreadId);
+  const int nice_setting = internal::ThreadPriorityToNiceValue(priority);
+  const PlatformThreadId current_id = PlatformThread::CurrentId();
+  if (setpriority(PRIO_PROCESS, handle.id() == current_id ? 0 : handle.id(),
+                  nice_setting)) {
+    DVPLOG(1) << "Failed to set nice value of thread (" << handle.id()
+              << ") to " << nice_setting;
+  }
+#endif  // defined(OS_NACL)
+}
+
+// static
+ThreadPriority PlatformThread::GetThreadPriority(PlatformThreadHandle handle) {
+#if defined(OS_NACL)
+  NOTIMPLEMENTED();
+  return ThreadPriority::NORMAL;
+#else
+  // Mirrors SetThreadPriority()'s implementation.
+  ThreadPriority platform_specific_priority;
+  if (internal::GetThreadPriorityForPlatform(handle,
+                                             &platform_specific_priority)) {
+    return platform_specific_priority;
+  }
+
+  DCHECK_NE(handle.id(), kInvalidThreadId);
+  const PlatformThreadId current_id = PlatformThread::CurrentId();
+  // Need to clear errno before calling getpriority():
+  // http://man7.org/linux/man-pages/man2/getpriority.2.html
+  errno = 0;
+  int nice_value =
+      getpriority(PRIO_PROCESS, handle.id() == current_id ? 0 : handle.id());
+  if (errno != 0) {
+    DVPLOG(1) << "Failed to get nice value of thread (" << handle.id() << ")";
+    return ThreadPriority::NORMAL;
+  }
+
+  return internal::NiceValueToThreadPriority(nice_value);
+#endif  // !defined(OS_NACL)
+}
+
+#endif  // !defined(OS_MACOSX)
+
+}  // namespace base
diff --git a/base/threading/platform_thread_unittest.cc b/base/threading/platform_thread_unittest.cc
new file mode 100644
index 0000000..c4b3d5d
--- /dev/null
+++ b/base/threading/platform_thread_unittest.cc
@@ -0,0 +1,275 @@
+// Copyright (c) 2012 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/compiler_specific.h"
+#include "base/macros.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/platform_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
+namespace base {
+
+// Trivial tests that thread runs and doesn't crash on create and join ---------
+
+class TrivialThread : public PlatformThread::Delegate {
+ public:
+  TrivialThread() : did_run_(false) {}
+
+  void ThreadMain() override { did_run_ = true; }
+
+  bool did_run() const { return did_run_; }
+
+ private:
+  bool did_run_;
+
+  DISALLOW_COPY_AND_ASSIGN(TrivialThread);
+};
+
+TEST(PlatformThreadTest, Trivial) {
+  TrivialThread thread;
+  PlatformThreadHandle handle;
+
+  ASSERT_FALSE(thread.did_run());
+  ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
+  PlatformThread::Join(handle);
+  ASSERT_TRUE(thread.did_run());
+}
+
+TEST(PlatformThreadTest, TrivialTimesTen) {
+  TrivialThread thread[10];
+  PlatformThreadHandle handle[arraysize(thread)];
+
+  for (size_t n = 0; n < arraysize(thread); n++)
+    ASSERT_FALSE(thread[n].did_run());
+  for (size_t n = 0; n < arraysize(thread); n++)
+    ASSERT_TRUE(PlatformThread::Create(0, &thread[n], &handle[n]));
+  for (size_t n = 0; n < arraysize(thread); n++)
+    PlatformThread::Join(handle[n]);
+  for (size_t n = 0; n < arraysize(thread); n++)
+    ASSERT_TRUE(thread[n].did_run());
+}
+
+// Tests of basic thread functions ---------------------------------------------
+
+class FunctionTestThread : public PlatformThread::Delegate {
+ public:
+  FunctionTestThread()
+      : thread_id_(kInvalidThreadId),
+        thread_started_(true, false),
+        terminate_thread_(true, false),
+        done_(false) {}
+  ~FunctionTestThread() override {
+    EXPECT_TRUE(terminate_thread_.IsSignaled())
+        << "Need to mark thread for termination and join the underlying thread "
+        << "before destroying a FunctionTestThread as it owns the "
+        << "WaitableEvent blocking the underlying thread's main.";
+  }
+
+  // Grabs |thread_id_|, signals |thread_started_|, and then waits for
+  // |terminate_thread_| to be signaled before exiting.
+  void ThreadMain() override {
+    thread_id_ = PlatformThread::CurrentId();
+    EXPECT_NE(thread_id_, kInvalidThreadId);
+
+    // Make sure that the thread ID is the same across calls.
+    EXPECT_EQ(thread_id_, PlatformThread::CurrentId());
+
+    thread_started_.Signal();
+
+    terminate_thread_.Wait();
+
+    done_ = true;
+  }
+
+  PlatformThreadId thread_id() const {
+    EXPECT_TRUE(thread_started_.IsSignaled()) << "Thread ID still unknown";
+    return thread_id_;
+  }
+
+  bool IsRunning() const {
+    return thread_started_.IsSignaled() && !done_;
+  }
+
+  // Blocks until this thread is started.
+  void WaitForThreadStart() { thread_started_.Wait(); }
+
+  // Mark this thread for termination (callers must then join this thread to be
+  // guaranteed of termination).
+  void MarkForTermination() { terminate_thread_.Signal(); }
+
+ private:
+  PlatformThreadId thread_id_;
+
+  mutable WaitableEvent thread_started_;
+  WaitableEvent terminate_thread_;
+  bool done_;
+
+  DISALLOW_COPY_AND_ASSIGN(FunctionTestThread);
+};
+
+TEST(PlatformThreadTest, Function) {
+  PlatformThreadId main_thread_id = PlatformThread::CurrentId();
+
+  FunctionTestThread thread;
+  PlatformThreadHandle handle;
+
+  ASSERT_FALSE(thread.IsRunning());
+  ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
+  thread.WaitForThreadStart();
+  ASSERT_TRUE(thread.IsRunning());
+  EXPECT_NE(thread.thread_id(), main_thread_id);
+
+  thread.MarkForTermination();
+  PlatformThread::Join(handle);
+  ASSERT_FALSE(thread.IsRunning());
+
+  // Make sure that the thread ID is the same across calls.
+  EXPECT_EQ(main_thread_id, PlatformThread::CurrentId());
+}
+
+TEST(PlatformThreadTest, FunctionTimesTen) {
+  PlatformThreadId main_thread_id = PlatformThread::CurrentId();
+
+  FunctionTestThread thread[10];
+  PlatformThreadHandle handle[arraysize(thread)];
+
+  for (size_t n = 0; n < arraysize(thread); n++)
+    ASSERT_FALSE(thread[n].IsRunning());
+
+  for (size_t n = 0; n < arraysize(thread); n++)
+    ASSERT_TRUE(PlatformThread::Create(0, &thread[n], &handle[n]));
+  for (size_t n = 0; n < arraysize(thread); n++)
+    thread[n].WaitForThreadStart();
+
+  for (size_t n = 0; n < arraysize(thread); n++) {
+    ASSERT_TRUE(thread[n].IsRunning());
+    EXPECT_NE(thread[n].thread_id(), main_thread_id);
+
+    // Make sure no two threads get the same ID.
+    for (size_t i = 0; i < n; ++i) {
+      EXPECT_NE(thread[i].thread_id(), thread[n].thread_id());
+    }
+  }
+
+  for (size_t n = 0; n < arraysize(thread); n++)
+    thread[n].MarkForTermination();
+  for (size_t n = 0; n < arraysize(thread); n++)
+    PlatformThread::Join(handle[n]);
+  for (size_t n = 0; n < arraysize(thread); n++)
+    ASSERT_FALSE(thread[n].IsRunning());
+
+  // Make sure that the thread ID is the same across calls.
+  EXPECT_EQ(main_thread_id, PlatformThread::CurrentId());
+}
+
+namespace {
+
+const ThreadPriority kThreadPriorityTestValues[] = {
+// Disable non-normal priority toggling on POSIX as it appears to be broken
+// (http://crbug.com/468793). This is prefered to disabling the tests altogether
+// on POSIX as it at least provides coverage for running this code under
+// "normal" priority.
+#if !defined(OS_POSIX)
+    ThreadPriority::DISPLAY,
+    ThreadPriority::REALTIME_AUDIO,
+    // Keep BACKGROUND second to last to test backgrounding from other
+    // priorities.
+    ThreadPriority::BACKGROUND,
+#endif  // !defined(OS_POSIX)
+    // Keep NORMAL last to test unbackgrounding.
+    ThreadPriority::NORMAL
+};
+
+}  // namespace
+
+// Test changing another thread's priority.
+// NOTE: This test is partially disabled on POSIX, see note above and
+// http://crbug.com/468793.
+TEST(PlatformThreadTest, ThreadPriorityOtherThread) {
+  PlatformThreadHandle current_handle(PlatformThread::CurrentHandle());
+
+  // Confirm that the current thread's priority is as expected.
+  EXPECT_EQ(ThreadPriority::NORMAL,
+            PlatformThread::GetThreadPriority(current_handle));
+
+  // Create a test thread.
+  FunctionTestThread thread;
+  PlatformThreadHandle handle;
+  ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
+  thread.WaitForThreadStart();
+  EXPECT_NE(thread.thread_id(), kInvalidThreadId);
+  EXPECT_NE(thread.thread_id(), PlatformThread::CurrentId());
+
+  // New threads should get normal priority by default.
+  EXPECT_EQ(ThreadPriority::NORMAL, PlatformThread::GetThreadPriority(handle));
+
+  // Toggle each supported priority on the test thread and confirm it only
+  // affects it (and not the current thread).
+  for (size_t i = 0; i < arraysize(kThreadPriorityTestValues); ++i) {
+    SCOPED_TRACE(i);
+
+    // Alter and verify the test thread's priority.
+    PlatformThread::SetThreadPriority(handle, kThreadPriorityTestValues[i]);
+    EXPECT_EQ(kThreadPriorityTestValues[i],
+              PlatformThread::GetThreadPriority(handle));
+
+    // Make sure the current thread was otherwise unaffected.
+    EXPECT_EQ(ThreadPriority::NORMAL,
+              PlatformThread::GetThreadPriority(current_handle));
+  }
+
+  thread.MarkForTermination();
+  PlatformThread::Join(handle);
+}
+
+// Test changing the current thread's priority (which has different semantics on
+// some platforms).
+// NOTE: This test is partially disabled on POSIX, see note above and
+// http://crbug.com/468793.
+TEST(PlatformThreadTest, ThreadPriorityCurrentThread) {
+  PlatformThreadHandle current_handle(PlatformThread::CurrentHandle());
+
+  // Confirm that the current thread's priority is as expected.
+  EXPECT_EQ(ThreadPriority::NORMAL,
+            PlatformThread::GetThreadPriority(current_handle));
+
+  // Create a test thread for verification purposes only.
+  FunctionTestThread thread;
+  PlatformThreadHandle handle;
+  ASSERT_TRUE(PlatformThread::Create(0, &thread, &handle));
+  thread.WaitForThreadStart();
+  EXPECT_NE(thread.thread_id(), kInvalidThreadId);
+  EXPECT_NE(thread.thread_id(), PlatformThread::CurrentId());
+
+  // Confirm that the new thread's priority is as expected.
+  EXPECT_EQ(ThreadPriority::NORMAL, PlatformThread::GetThreadPriority(handle));
+
+  // Toggle each supported priority on the current thread and confirm it only
+  // affects it (and not the test thread).
+  for (size_t i = 0; i < arraysize(kThreadPriorityTestValues); ++i) {
+    SCOPED_TRACE(i);
+
+    // Alter and verify the current thread's priority.
+    PlatformThread::SetThreadPriority(current_handle,
+                                      kThreadPriorityTestValues[i]);
+    EXPECT_EQ(kThreadPriorityTestValues[i],
+              PlatformThread::GetThreadPriority(current_handle));
+
+    // Make sure the test thread was otherwise unaffected.
+    EXPECT_EQ(ThreadPriority::NORMAL,
+              PlatformThread::GetThreadPriority(handle));
+  }
+
+  // Restore current thread priority for follow-up tests.
+  PlatformThread::SetThreadPriority(current_handle, ThreadPriority::NORMAL);
+
+  thread.MarkForTermination();
+  PlatformThread::Join(handle);
+}
+
+}  // namespace base
diff --git a/base/threading/platform_thread_win.cc b/base/threading/platform_thread_win.cc
new file mode 100644
index 0000000..395fc9e
--- /dev/null
+++ b/base/threading/platform_thread_win.cc
@@ -0,0 +1,288 @@
+// Copyright (c) 2012 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/threading/platform_thread.h"
+
+#include "base/debug/alias.h"
+#include "base/debug/profiler.h"
+#include "base/logging.h"
+#include "base/threading/thread_id_name_manager.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/tracked_objects.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/windows_version.h"
+
+namespace base {
+
+namespace {
+
+// The information on how to set the thread name comes from
+// a MSDN article: http://msdn2.microsoft.com/en-us/library/xcb2z8hs.aspx
+const DWORD kVCThreadNameException = 0x406D1388;
+
+typedef struct tagTHREADNAME_INFO {
+  DWORD dwType;  // Must be 0x1000.
+  LPCSTR szName;  // Pointer to name (in user addr space).
+  DWORD dwThreadID;  // Thread ID (-1=caller thread).
+  DWORD dwFlags;  // Reserved for future use, must be zero.
+} THREADNAME_INFO;
+
+// This function has try handling, so it is separated out of its caller.
+void SetNameInternal(PlatformThreadId thread_id, const char* name) {
+  THREADNAME_INFO info;
+  info.dwType = 0x1000;
+  info.szName = name;
+  info.dwThreadID = thread_id;
+  info.dwFlags = 0;
+
+  __try {
+    RaiseException(kVCThreadNameException, 0, sizeof(info)/sizeof(DWORD),
+                   reinterpret_cast<DWORD_PTR*>(&info));
+  } __except(EXCEPTION_CONTINUE_EXECUTION) {
+  }
+}
+
+struct ThreadParams {
+  PlatformThread::Delegate* delegate;
+  bool joinable;
+};
+
+DWORD __stdcall ThreadFunc(void* params) {
+  ThreadParams* thread_params = static_cast<ThreadParams*>(params);
+  PlatformThread::Delegate* delegate = thread_params->delegate;
+  if (!thread_params->joinable)
+    base::ThreadRestrictions::SetSingletonAllowed(false);
+
+  // Retrieve a copy of the thread handle to use as the key in the
+  // thread name mapping.
+  PlatformThreadHandle::Handle platform_handle;
+  BOOL did_dup = DuplicateHandle(GetCurrentProcess(),
+                                GetCurrentThread(),
+                                GetCurrentProcess(),
+                                &platform_handle,
+                                0,
+                                FALSE,
+                                DUPLICATE_SAME_ACCESS);
+
+  win::ScopedHandle scoped_platform_handle;
+
+  if (did_dup) {
+    scoped_platform_handle.Set(platform_handle);
+    ThreadIdNameManager::GetInstance()->RegisterThread(
+        scoped_platform_handle.Get(),
+        PlatformThread::CurrentId());
+  }
+
+  delete thread_params;
+  delegate->ThreadMain();
+
+  if (did_dup) {
+    ThreadIdNameManager::GetInstance()->RemoveName(
+        scoped_platform_handle.Get(),
+        PlatformThread::CurrentId());
+  }
+
+  return NULL;
+}
+
+// CreateThreadInternal() matches PlatformThread::Create(), except that
+// |out_thread_handle| may be NULL, in which case a non-joinable thread is
+// created.
+bool CreateThreadInternal(size_t stack_size,
+                          PlatformThread::Delegate* delegate,
+                          PlatformThreadHandle* out_thread_handle) {
+  unsigned int flags = 0;
+  if (stack_size > 0 && base::win::GetVersion() >= base::win::VERSION_XP) {
+    flags = STACK_SIZE_PARAM_IS_A_RESERVATION;
+  } else {
+    stack_size = 0;
+  }
+
+  ThreadParams* params = new ThreadParams;
+  params->delegate = delegate;
+  params->joinable = out_thread_handle != NULL;
+
+  // Using CreateThread here vs _beginthreadex makes thread creation a bit
+  // faster and doesn't require the loader lock to be available.  Our code will
+  // have to work running on CreateThread() threads anyway, since we run code
+  // on the Windows thread pool, etc.  For some background on the difference:
+  //   http://www.microsoft.com/msj/1099/win32/win321099.aspx
+  PlatformThreadId thread_id;
+  void* thread_handle = CreateThread(
+      NULL, stack_size, ThreadFunc, params, flags, &thread_id);
+  if (!thread_handle) {
+    delete params;
+    return false;
+  }
+
+  if (out_thread_handle)
+    *out_thread_handle = PlatformThreadHandle(thread_handle, thread_id);
+  else
+    CloseHandle(thread_handle);
+  return true;
+}
+
+}  // namespace
+
+// static
+PlatformThreadId PlatformThread::CurrentId() {
+  return ::GetCurrentThreadId();
+}
+
+// static
+PlatformThreadRef PlatformThread::CurrentRef() {
+  return PlatformThreadRef(::GetCurrentThreadId());
+}
+
+// static
+PlatformThreadHandle PlatformThread::CurrentHandle() {
+  return PlatformThreadHandle(::GetCurrentThread());
+}
+
+// static
+void PlatformThread::YieldCurrentThread() {
+  ::Sleep(0);
+}
+
+// static
+void PlatformThread::Sleep(TimeDelta duration) {
+  // When measured with a high resolution clock, Sleep() sometimes returns much
+  // too early. We may need to call it repeatedly to get the desired duration.
+  TimeTicks end = TimeTicks::Now() + duration;
+  for (TimeTicks now = TimeTicks::Now(); now < end; now = TimeTicks::Now())
+    ::Sleep(static_cast<DWORD>((end - now).InMillisecondsRoundedUp()));
+}
+
+// static
+void PlatformThread::SetName(const std::string& name) {
+  ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name);
+
+  // On Windows only, we don't need to tell the profiler about the "BrokerEvent"
+  // thread, as it exists only in the chrome.exe image, and never spawns or runs
+  // tasks (items which could be profiled).  This test avoids the notification,
+  // which would also (as a side effect) initialize the profiler in this unused
+  // context, including setting up thread local storage, etc.  The performance
+  // impact is not terrible, but there is no reason to do initialize it.
+  if (name != "BrokerEvent")
+    tracked_objects::ThreadData::InitializeThreadContext(name);
+
+  // The debugger needs to be around to catch the name in the exception.  If
+  // there isn't a debugger, we are just needlessly throwing an exception.
+  // If this image file is instrumented, we raise the exception anyway
+  // to provide the profiler with human-readable thread names.
+  if (!::IsDebuggerPresent() && !base::debug::IsBinaryInstrumented())
+    return;
+
+  SetNameInternal(CurrentId(), name.c_str());
+}
+
+// static
+const char* PlatformThread::GetName() {
+  return ThreadIdNameManager::GetInstance()->GetName(CurrentId());
+}
+
+// static
+bool PlatformThread::Create(size_t stack_size, Delegate* delegate,
+                            PlatformThreadHandle* thread_handle) {
+  DCHECK(thread_handle);
+  return CreateThreadInternal(stack_size, delegate, thread_handle);
+}
+
+// static
+bool PlatformThread::CreateWithPriority(size_t stack_size, Delegate* delegate,
+                                        PlatformThreadHandle* thread_handle,
+                                        ThreadPriority priority) {
+  bool result = Create(stack_size, delegate, thread_handle);
+  if (result)
+    SetThreadPriority(*thread_handle, priority);
+  return result;
+}
+
+// static
+bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) {
+  return CreateThreadInternal(stack_size, delegate, NULL);
+}
+
+// static
+void PlatformThread::Join(PlatformThreadHandle thread_handle) {
+  DCHECK(thread_handle.platform_handle());
+  // TODO(willchan): Enable this check once I can get it to work for Windows
+  // shutdown.
+  // Joining another thread may block the current thread for a long time, since
+  // the thread referred to by |thread_handle| may still be running long-lived /
+  // blocking tasks.
+#if 0
+  base::ThreadRestrictions::AssertIOAllowed();
+#endif
+
+  // Wait for the thread to exit.  It should already have terminated but make
+  // sure this assumption is valid.
+  DWORD result = WaitForSingleObject(thread_handle.platform_handle(), INFINITE);
+  if (result != WAIT_OBJECT_0) {
+    // Debug info for bug 127931.
+    DWORD error = GetLastError();
+    debug::Alias(&error);
+    debug::Alias(&result);
+    CHECK(false);
+  }
+
+  CloseHandle(thread_handle.platform_handle());
+}
+
+// static
+void PlatformThread::SetThreadPriority(PlatformThreadHandle handle,
+                                       ThreadPriority priority) {
+  DCHECK(!handle.is_null());
+
+  int desired_priority = THREAD_PRIORITY_ERROR_RETURN;
+  switch (priority) {
+    case ThreadPriority::BACKGROUND:
+      desired_priority = THREAD_PRIORITY_LOWEST;
+      break;
+    case ThreadPriority::NORMAL:
+      desired_priority = THREAD_PRIORITY_NORMAL;
+      break;
+    case ThreadPriority::DISPLAY:
+      desired_priority = THREAD_PRIORITY_ABOVE_NORMAL;
+      break;
+    case ThreadPriority::REALTIME_AUDIO:
+      desired_priority = THREAD_PRIORITY_TIME_CRITICAL;
+      break;
+    default:
+      NOTREACHED() << "Unknown priority.";
+      break;
+  }
+  DCHECK_NE(desired_priority, THREAD_PRIORITY_ERROR_RETURN);
+
+#ifndef NDEBUG
+  const BOOL success =
+#endif
+      ::SetThreadPriority(handle.platform_handle(), desired_priority);
+  DPLOG_IF(ERROR, !success) << "Failed to set thread priority to "
+                            << desired_priority;
+}
+
+// static
+ThreadPriority PlatformThread::GetThreadPriority(PlatformThreadHandle handle) {
+  DCHECK(!handle.is_null());
+
+  int priority = ::GetThreadPriority(handle.platform_handle());
+  switch (priority) {
+    case THREAD_PRIORITY_LOWEST:
+      return ThreadPriority::BACKGROUND;
+    case THREAD_PRIORITY_NORMAL:
+      return ThreadPriority::NORMAL;
+    case THREAD_PRIORITY_ABOVE_NORMAL:
+      return ThreadPriority::DISPLAY;
+    case THREAD_PRIORITY_TIME_CRITICAL:
+      return ThreadPriority::REALTIME_AUDIO;
+    case THREAD_PRIORITY_ERROR_RETURN:
+      DPCHECK(false) << "GetThreadPriority error";  // Falls through.
+    default:
+      NOTREACHED() << "Unexpected priority: " << priority;
+      return ThreadPriority::NORMAL;
+  }
+}
+
+}  // namespace base
diff --git a/base/threading/post_task_and_reply_impl.cc b/base/threading/post_task_and_reply_impl.cc
new file mode 100644
index 0000000..f3e88ab
--- /dev/null
+++ b/base/threading/post_task_and_reply_impl.cc
@@ -0,0 +1,91 @@
+// Copyright (c) 2011 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/threading/post_task_and_reply_impl.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
+
+namespace base {
+
+namespace {
+
+// This relay class remembers the MessageLoop that it was created on, and
+// ensures that both the |task| and |reply| Closures are deleted on this same
+// thread. Also, |task| is guaranteed to be deleted before |reply| is run or
+// deleted.
+//
+// If this is not possible because the originating MessageLoop is no longer
+// available, the the |task| and |reply| Closures are leaked.  Leaking is
+// considered preferable to having a thread-safetey violations caused by
+// invoking the Closure destructor on the wrong thread.
+class PostTaskAndReplyRelay {
+ public:
+  PostTaskAndReplyRelay(const tracked_objects::Location& from_here,
+                        const Closure& task,
+                        const Closure& reply)
+      : from_here_(from_here),
+        origin_task_runner_(ThreadTaskRunnerHandle::Get()) {
+    task_ = task;
+    reply_ = reply;
+  }
+
+  ~PostTaskAndReplyRelay() {
+    DCHECK(origin_task_runner_->BelongsToCurrentThread());
+    task_.Reset();
+    reply_.Reset();
+  }
+
+  void Run() {
+    task_.Run();
+    origin_task_runner_->PostTask(
+        from_here_, Bind(&PostTaskAndReplyRelay::RunReplyAndSelfDestruct,
+                         base::Unretained(this)));
+  }
+
+ private:
+  void RunReplyAndSelfDestruct() {
+    DCHECK(origin_task_runner_->BelongsToCurrentThread());
+
+    // Force |task_| to be released before |reply_| is to ensure that no one
+    // accidentally depends on |task_| keeping one of its arguments alive while
+    // |reply_| is executing.
+    task_.Reset();
+
+    reply_.Run();
+
+    // Cue mission impossible theme.
+    delete this;
+  }
+
+  tracked_objects::Location from_here_;
+  scoped_refptr<SingleThreadTaskRunner> origin_task_runner_;
+  Closure reply_;
+  Closure task_;
+};
+
+}  // namespace
+
+namespace internal {
+
+bool PostTaskAndReplyImpl::PostTaskAndReply(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    const Closure& reply) {
+  PostTaskAndReplyRelay* relay =
+      new PostTaskAndReplyRelay(from_here, task, reply);
+  if (!PostTask(from_here, Bind(&PostTaskAndReplyRelay::Run,
+                                Unretained(relay)))) {
+    delete relay;
+    return false;
+  }
+
+  return true;
+}
+
+}  // namespace internal
+
+}  // namespace base
diff --git a/base/threading/post_task_and_reply_impl.h b/base/threading/post_task_and_reply_impl.h
new file mode 100644
index 0000000..a5b9580
--- /dev/null
+++ b/base/threading/post_task_and_reply_impl.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2011 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 contains the implementation shared by
+// TaskRunner::PostTaskAndReply and WorkerPool::PostTaskAndReply.
+
+#ifndef BASE_THREADING_POST_TASK_AND_REPLY_IMPL_H_
+#define BASE_THREADING_POST_TASK_AND_REPLY_IMPL_H_
+
+#include "base/callback_forward.h"
+#include "base/location.h"
+
+namespace base {
+namespace internal {
+
+// Inherit from this in a class that implements PostTask appropriately
+// for sending to a destination thread.
+//
+// Note that 'reply' will always get posted back to your current
+// MessageLoop.
+//
+// If you're looking for a concrete implementation of
+// PostTaskAndReply, you probably want base::SingleThreadTaskRunner, or you
+// may want base::WorkerPool.
+class PostTaskAndReplyImpl {
+ public:
+  // Implementation for TaskRunner::PostTaskAndReply and
+  // WorkerPool::PostTaskAndReply.
+  bool PostTaskAndReply(const tracked_objects::Location& from_here,
+                        const Closure& task,
+                        const Closure& reply);
+
+ private:
+  virtual bool PostTask(const tracked_objects::Location& from_here,
+                        const Closure& task) = 0;
+};
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // BASE_THREADING_POST_TASK_AND_REPLY_IMPL_H_
diff --git a/base/threading/sequenced_worker_pool.cc b/base/threading/sequenced_worker_pool.cc
new file mode 100644
index 0000000..7bbca92
--- /dev/null
+++ b/base/threading/sequenced_worker_pool.cc
@@ -0,0 +1,1307 @@
+// Copyright (c) 2012 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/threading/sequenced_worker_pool.h"
+
+#include <list>
+#include <map>
+#include <set>
+#include <utility>
+#include <vector>
+
+#include "base/atomic_sequence_num.h"
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/critical_closure.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/memory/linked_ptr.h"
+#include "base/stl_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/simple_thread.h"
+#include "base/threading/thread_local.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
+#include "base/tracked_objects.h"
+
+#if defined(OS_MACOSX)
+#include "base/mac/scoped_nsautorelease_pool.h"
+#elif defined(OS_WIN)
+#include "base/win/scoped_com_initializer.h"
+#endif
+
+#if !defined(OS_NACL)
+#include "base/metrics/histogram.h"
+#endif
+
+namespace base {
+
+namespace {
+
+struct SequencedTask : public TrackingInfo  {
+  SequencedTask()
+      : sequence_token_id(0),
+        trace_id(0),
+        sequence_task_number(0),
+        shutdown_behavior(SequencedWorkerPool::BLOCK_SHUTDOWN) {}
+
+  explicit SequencedTask(const tracked_objects::Location& from_here)
+      : base::TrackingInfo(from_here, TimeTicks()),
+        sequence_token_id(0),
+        trace_id(0),
+        sequence_task_number(0),
+        shutdown_behavior(SequencedWorkerPool::BLOCK_SHUTDOWN) {}
+
+  ~SequencedTask() {}
+
+  int sequence_token_id;
+  int trace_id;
+  int64 sequence_task_number;
+  SequencedWorkerPool::WorkerShutdown shutdown_behavior;
+  tracked_objects::Location posted_from;
+  Closure task;
+
+  // Non-delayed tasks and delayed tasks are managed together by time-to-run
+  // order. We calculate the time by adding the posted time and the given delay.
+  TimeTicks time_to_run;
+};
+
+struct SequencedTaskLessThan {
+ public:
+  bool operator()(const SequencedTask& lhs, const SequencedTask& rhs) const {
+    if (lhs.time_to_run < rhs.time_to_run)
+      return true;
+
+    if (lhs.time_to_run > rhs.time_to_run)
+      return false;
+
+    // If the time happen to match, then we use the sequence number to decide.
+    return lhs.sequence_task_number < rhs.sequence_task_number;
+  }
+};
+
+// SequencedWorkerPoolTaskRunner ---------------------------------------------
+// A TaskRunner which posts tasks to a SequencedWorkerPool with a
+// fixed ShutdownBehavior.
+//
+// Note that this class is RefCountedThreadSafe (inherited from TaskRunner).
+class SequencedWorkerPoolTaskRunner : public TaskRunner {
+ public:
+  SequencedWorkerPoolTaskRunner(
+      const scoped_refptr<SequencedWorkerPool>& pool,
+      SequencedWorkerPool::WorkerShutdown shutdown_behavior);
+
+  // TaskRunner implementation
+  bool PostDelayedTask(const tracked_objects::Location& from_here,
+                       const Closure& task,
+                       TimeDelta delay) override;
+  bool RunsTasksOnCurrentThread() const override;
+
+ private:
+  ~SequencedWorkerPoolTaskRunner() override;
+
+  const scoped_refptr<SequencedWorkerPool> pool_;
+
+  const SequencedWorkerPool::WorkerShutdown shutdown_behavior_;
+
+  DISALLOW_COPY_AND_ASSIGN(SequencedWorkerPoolTaskRunner);
+};
+
+SequencedWorkerPoolTaskRunner::SequencedWorkerPoolTaskRunner(
+    const scoped_refptr<SequencedWorkerPool>& pool,
+    SequencedWorkerPool::WorkerShutdown shutdown_behavior)
+    : pool_(pool),
+      shutdown_behavior_(shutdown_behavior) {
+}
+
+SequencedWorkerPoolTaskRunner::~SequencedWorkerPoolTaskRunner() {
+}
+
+bool SequencedWorkerPoolTaskRunner::PostDelayedTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay) {
+  if (delay == TimeDelta()) {
+    return pool_->PostWorkerTaskWithShutdownBehavior(
+        from_here, task, shutdown_behavior_);
+  }
+  return pool_->PostDelayedWorkerTask(from_here, task, delay);
+}
+
+bool SequencedWorkerPoolTaskRunner::RunsTasksOnCurrentThread() const {
+  return pool_->RunsTasksOnCurrentThread();
+}
+
+// SequencedWorkerPoolSequencedTaskRunner ------------------------------------
+// A SequencedTaskRunner which posts tasks to a SequencedWorkerPool with a
+// fixed sequence token.
+//
+// Note that this class is RefCountedThreadSafe (inherited from TaskRunner).
+class SequencedWorkerPoolSequencedTaskRunner : public SequencedTaskRunner {
+ public:
+  SequencedWorkerPoolSequencedTaskRunner(
+      const scoped_refptr<SequencedWorkerPool>& pool,
+      SequencedWorkerPool::SequenceToken token,
+      SequencedWorkerPool::WorkerShutdown shutdown_behavior);
+
+  // TaskRunner implementation
+  bool PostDelayedTask(const tracked_objects::Location& from_here,
+                       const Closure& task,
+                       TimeDelta delay) override;
+  bool RunsTasksOnCurrentThread() const override;
+
+  // SequencedTaskRunner implementation
+  bool PostNonNestableDelayedTask(const tracked_objects::Location& from_here,
+                                  const Closure& task,
+                                  TimeDelta delay) override;
+
+ private:
+  ~SequencedWorkerPoolSequencedTaskRunner() override;
+
+  const scoped_refptr<SequencedWorkerPool> pool_;
+
+  const SequencedWorkerPool::SequenceToken token_;
+
+  const SequencedWorkerPool::WorkerShutdown shutdown_behavior_;
+
+  DISALLOW_COPY_AND_ASSIGN(SequencedWorkerPoolSequencedTaskRunner);
+};
+
+SequencedWorkerPoolSequencedTaskRunner::SequencedWorkerPoolSequencedTaskRunner(
+    const scoped_refptr<SequencedWorkerPool>& pool,
+    SequencedWorkerPool::SequenceToken token,
+    SequencedWorkerPool::WorkerShutdown shutdown_behavior)
+    : pool_(pool),
+      token_(token),
+      shutdown_behavior_(shutdown_behavior) {
+}
+
+SequencedWorkerPoolSequencedTaskRunner::
+~SequencedWorkerPoolSequencedTaskRunner() {
+}
+
+bool SequencedWorkerPoolSequencedTaskRunner::PostDelayedTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay) {
+  if (delay == TimeDelta()) {
+    return pool_->PostSequencedWorkerTaskWithShutdownBehavior(
+        token_, from_here, task, shutdown_behavior_);
+  }
+  return pool_->PostDelayedSequencedWorkerTask(token_, from_here, task, delay);
+}
+
+bool SequencedWorkerPoolSequencedTaskRunner::RunsTasksOnCurrentThread() const {
+  return pool_->IsRunningSequenceOnCurrentThread(token_);
+}
+
+bool SequencedWorkerPoolSequencedTaskRunner::PostNonNestableDelayedTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay) {
+  // There's no way to run nested tasks, so simply forward to
+  // PostDelayedTask.
+  return PostDelayedTask(from_here, task, delay);
+}
+
+// Create a process-wide unique ID to represent this task in trace events. This
+// will be mangled with a Process ID hash to reduce the likelyhood of colliding
+// with MessageLoop pointers on other processes.
+uint64 GetTaskTraceID(const SequencedTask& task,
+                      void* pool) {
+  return (static_cast<uint64>(task.trace_id) << 32) |
+         static_cast<uint64>(reinterpret_cast<intptr_t>(pool));
+}
+
+base::LazyInstance<base::ThreadLocalPointer<
+    SequencedWorkerPool::SequenceToken> >::Leaky g_lazy_tls_ptr =
+        LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+// Worker ---------------------------------------------------------------------
+
+class SequencedWorkerPool::Worker : public SimpleThread {
+ public:
+  // Hold a (cyclic) ref to |worker_pool|, since we want to keep it
+  // around as long as we are running.
+  Worker(const scoped_refptr<SequencedWorkerPool>& worker_pool,
+         int thread_number,
+         const std::string& thread_name_prefix);
+  ~Worker() override;
+
+  // SimpleThread implementation. This actually runs the background thread.
+  void Run() override;
+
+  // Indicates that a task is about to be run. The parameters provide
+  // additional metainformation about the task being run.
+  void set_running_task_info(SequenceToken token,
+                             WorkerShutdown shutdown_behavior) {
+    is_processing_task_ = true;
+    task_sequence_token_ = token;
+    task_shutdown_behavior_ = shutdown_behavior;
+  }
+
+  // Indicates that the task has finished running.
+  void reset_running_task_info() { is_processing_task_ = false; }
+
+  // Whether the worker is processing a task.
+  bool is_processing_task() { return is_processing_task_; }
+
+  SequenceToken task_sequence_token() const {
+    DCHECK(is_processing_task_);
+    return task_sequence_token_;
+  }
+
+  WorkerShutdown task_shutdown_behavior() const {
+    DCHECK(is_processing_task_);
+    return task_shutdown_behavior_;
+  }
+
+ private:
+  scoped_refptr<SequencedWorkerPool> worker_pool_;
+  // The sequence token of the task being processed. Only valid when
+  // is_processing_task_ is true.
+  SequenceToken task_sequence_token_;
+  // The shutdown behavior of the task being processed. Only valid when
+  // is_processing_task_ is true.
+  WorkerShutdown task_shutdown_behavior_;
+  // Whether the Worker is processing a task.
+  bool is_processing_task_;
+
+  DISALLOW_COPY_AND_ASSIGN(Worker);
+};
+
+// Inner ----------------------------------------------------------------------
+
+class SequencedWorkerPool::Inner {
+ public:
+  // Take a raw pointer to |worker| to avoid cycles (since we're owned
+  // by it).
+  Inner(SequencedWorkerPool* worker_pool, size_t max_threads,
+        const std::string& thread_name_prefix,
+        TestingObserver* observer);
+
+  ~Inner();
+
+  SequenceToken GetSequenceToken();
+
+  SequenceToken GetNamedSequenceToken(const std::string& name);
+
+  // This function accepts a name and an ID. If the name is null, the
+  // token ID is used. This allows us to implement the optional name lookup
+  // from a single function without having to enter the lock a separate time.
+  bool PostTask(const std::string* optional_token_name,
+                SequenceToken sequence_token,
+                WorkerShutdown shutdown_behavior,
+                const tracked_objects::Location& from_here,
+                const Closure& task,
+                TimeDelta delay);
+
+  bool RunsTasksOnCurrentThread() const;
+
+  bool IsRunningSequenceOnCurrentThread(SequenceToken sequence_token) const;
+
+  void CleanupForTesting();
+
+  void SignalHasWorkForTesting();
+
+  int GetWorkSignalCountForTesting() const;
+
+  void Shutdown(int max_blocking_tasks_after_shutdown);
+
+  bool IsShutdownInProgress();
+
+  // Runs the worker loop on the background thread.
+  void ThreadLoop(Worker* this_worker);
+
+ private:
+  enum GetWorkStatus {
+    GET_WORK_FOUND,
+    GET_WORK_NOT_FOUND,
+    GET_WORK_WAIT,
+  };
+
+  enum CleanupState {
+    CLEANUP_REQUESTED,
+    CLEANUP_STARTING,
+    CLEANUP_RUNNING,
+    CLEANUP_FINISHING,
+    CLEANUP_DONE,
+  };
+
+  // Called from within the lock, this converts the given token name into a
+  // token ID, creating a new one if necessary.
+  int LockedGetNamedTokenID(const std::string& name);
+
+  // Called from within the lock, this returns the next sequence task number.
+  int64 LockedGetNextSequenceTaskNumber();
+
+  // Gets new task. There are 3 cases depending on the return value:
+  //
+  // 1) If the return value is |GET_WORK_FOUND|, |task| is filled in and should
+  //    be run immediately.
+  // 2) If the return value is |GET_WORK_NOT_FOUND|, there are no tasks to run,
+  //    and |task| is not filled in. In this case, the caller should wait until
+  //    a task is posted.
+  // 3) If the return value is |GET_WORK_WAIT|, there are no tasks to run
+  //    immediately, and |task| is not filled in. Likewise, |wait_time| is
+  //    filled in the time to wait until the next task to run. In this case, the
+  //    caller should wait the time.
+  //
+  // In any case, the calling code should clear the given
+  // delete_these_outside_lock vector the next time the lock is released.
+  // See the implementation for a more detailed description.
+  GetWorkStatus GetWork(SequencedTask* task,
+                        TimeDelta* wait_time,
+                        std::vector<Closure>* delete_these_outside_lock);
+
+  void HandleCleanup();
+
+  // Peforms init and cleanup around running the given task. WillRun...
+  // returns the value from PrepareToStartAdditionalThreadIfNecessary.
+  // The calling code should call FinishStartingAdditionalThread once the
+  // lock is released if the return values is nonzero.
+  int WillRunWorkerTask(const SequencedTask& task);
+  void DidRunWorkerTask(const SequencedTask& task);
+
+  // Returns true if there are no threads currently running the given
+  // sequence token.
+  bool IsSequenceTokenRunnable(int sequence_token_id) const;
+
+  // Checks if all threads are busy and the addition of one more could run an
+  // additional task waiting in the queue. This must be called from within
+  // the lock.
+  //
+  // If another thread is helpful, this will mark the thread as being in the
+  // process of starting and returns the index of the new thread which will be
+  // 0 or more. The caller should then call FinishStartingAdditionalThread to
+  // complete initialization once the lock is released.
+  //
+  // If another thread is not necessary, returne 0;
+  //
+  // See the implementedion for more.
+  int PrepareToStartAdditionalThreadIfHelpful();
+
+  // The second part of thread creation after
+  // PrepareToStartAdditionalThreadIfHelpful with the thread number it
+  // generated. This actually creates the thread and should be called outside
+  // the lock to avoid blocking important work starting a thread in the lock.
+  void FinishStartingAdditionalThread(int thread_number);
+
+  // Signal |has_work_| and increment |has_work_signal_count_|.
+  void SignalHasWork();
+
+  // Checks whether there is work left that's blocking shutdown. Must be
+  // called inside the lock.
+  bool CanShutdown() const;
+
+  SequencedWorkerPool* const worker_pool_;
+
+  // The last sequence number used. Managed by GetSequenceToken, since this
+  // only does threadsafe increment operations, you do not need to hold the
+  // lock. This is class-static to make SequenceTokens issued by
+  // GetSequenceToken unique across SequencedWorkerPool instances.
+  static base::StaticAtomicSequenceNumber g_last_sequence_number_;
+
+  // This lock protects |everything in this class|. Do not read or modify
+  // anything without holding this lock. Do not block while holding this
+  // lock.
+  mutable Lock lock_;
+
+  // Condition variable that is waited on by worker threads until new
+  // tasks are posted or shutdown starts.
+  ConditionVariable has_work_cv_;
+
+  // Condition variable that is waited on by non-worker threads (in
+  // Shutdown()) until CanShutdown() goes to true.
+  ConditionVariable can_shutdown_cv_;
+
+  // The maximum number of worker threads we'll create.
+  const size_t max_threads_;
+
+  const std::string thread_name_prefix_;
+
+  // Associates all known sequence token names with their IDs.
+  std::map<std::string, int> named_sequence_tokens_;
+
+  // Owning pointers to all threads we've created so far, indexed by
+  // ID. Since we lazily create threads, this may be less than
+  // max_threads_ and will be initially empty.
+  typedef std::map<PlatformThreadId, linked_ptr<Worker> > ThreadMap;
+  ThreadMap threads_;
+
+  // Set to true when we're in the process of creating another thread.
+  // See PrepareToStartAdditionalThreadIfHelpful for more.
+  bool thread_being_created_;
+
+  // Number of threads currently waiting for work.
+  size_t waiting_thread_count_;
+
+  // Number of threads currently running tasks that have the BLOCK_SHUTDOWN
+  // or SKIP_ON_SHUTDOWN flag set.
+  size_t blocking_shutdown_thread_count_;
+
+  // A set of all pending tasks in time-to-run order. These are tasks that are
+  // either waiting for a thread to run on, waiting for their time to run,
+  // or blocked on a previous task in their sequence. We have to iterate over
+  // the tasks by time-to-run order, so we use the set instead of the
+  // traditional priority_queue.
+  typedef std::set<SequencedTask, SequencedTaskLessThan> PendingTaskSet;
+  PendingTaskSet pending_tasks_;
+
+  // The next sequence number for a new sequenced task.
+  int64 next_sequence_task_number_;
+
+  // Number of tasks in the pending_tasks_ list that are marked as blocking
+  // shutdown.
+  size_t blocking_shutdown_pending_task_count_;
+
+  // Lists all sequence tokens currently executing.
+  std::set<int> current_sequences_;
+
+  // An ID for each posted task to distinguish the task from others in traces.
+  int trace_id_;
+
+  // Set when Shutdown is called and no further tasks should be
+  // allowed, though we may still be running existing tasks.
+  bool shutdown_called_;
+
+  // The number of new BLOCK_SHUTDOWN tasks that may be posted after Shudown()
+  // has been called.
+  int max_blocking_tasks_after_shutdown_;
+
+  // State used to cleanup for testing, all guarded by lock_.
+  CleanupState cleanup_state_;
+  size_t cleanup_idlers_;
+  ConditionVariable cleanup_cv_;
+
+  TestingObserver* const testing_observer_;
+
+  DISALLOW_COPY_AND_ASSIGN(Inner);
+};
+
+// Worker definitions ---------------------------------------------------------
+
+SequencedWorkerPool::Worker::Worker(
+    const scoped_refptr<SequencedWorkerPool>& worker_pool,
+    int thread_number,
+    const std::string& prefix)
+    : SimpleThread(prefix + StringPrintf("Worker%d", thread_number)),
+      worker_pool_(worker_pool),
+      task_shutdown_behavior_(BLOCK_SHUTDOWN),
+      is_processing_task_(false) {
+  Start();
+}
+
+SequencedWorkerPool::Worker::~Worker() {
+}
+
+void SequencedWorkerPool::Worker::Run() {
+#if defined(OS_WIN)
+  win::ScopedCOMInitializer com_initializer;
+#endif
+
+  // Store a pointer to the running sequence in thread local storage for
+  // static function access.
+  g_lazy_tls_ptr.Get().Set(&task_sequence_token_);
+
+  // Just jump back to the Inner object to run the thread, since it has all the
+  // tracking information and queues. It might be more natural to implement
+  // using DelegateSimpleThread and have Inner implement the Delegate to avoid
+  // having these worker objects at all, but that method lacks the ability to
+  // send thread-specific information easily to the thread loop.
+  worker_pool_->inner_->ThreadLoop(this);
+  // Release our cyclic reference once we're done.
+  worker_pool_ = NULL;
+}
+
+// Inner definitions ---------------------------------------------------------
+
+SequencedWorkerPool::Inner::Inner(
+    SequencedWorkerPool* worker_pool,
+    size_t max_threads,
+    const std::string& thread_name_prefix,
+    TestingObserver* observer)
+    : worker_pool_(worker_pool),
+      lock_(),
+      has_work_cv_(&lock_),
+      can_shutdown_cv_(&lock_),
+      max_threads_(max_threads),
+      thread_name_prefix_(thread_name_prefix),
+      thread_being_created_(false),
+      waiting_thread_count_(0),
+      blocking_shutdown_thread_count_(0),
+      next_sequence_task_number_(0),
+      blocking_shutdown_pending_task_count_(0),
+      trace_id_(0),
+      shutdown_called_(false),
+      max_blocking_tasks_after_shutdown_(0),
+      cleanup_state_(CLEANUP_DONE),
+      cleanup_idlers_(0),
+      cleanup_cv_(&lock_),
+      testing_observer_(observer) {}
+
+SequencedWorkerPool::Inner::~Inner() {
+  // You must call Shutdown() before destroying the pool.
+  DCHECK(shutdown_called_);
+
+  // Need to explicitly join with the threads before they're destroyed or else
+  // they will be running when our object is half torn down.
+  for (ThreadMap::iterator it = threads_.begin(); it != threads_.end(); ++it)
+    it->second->Join();
+  threads_.clear();
+
+  if (testing_observer_)
+    testing_observer_->OnDestruct();
+}
+
+SequencedWorkerPool::SequenceToken
+SequencedWorkerPool::Inner::GetSequenceToken() {
+  // Need to add one because StaticAtomicSequenceNumber starts at zero, which
+  // is used as a sentinel value in SequenceTokens.
+  return SequenceToken(g_last_sequence_number_.GetNext() + 1);
+}
+
+SequencedWorkerPool::SequenceToken
+SequencedWorkerPool::Inner::GetNamedSequenceToken(const std::string& name) {
+  AutoLock lock(lock_);
+  return SequenceToken(LockedGetNamedTokenID(name));
+}
+
+bool SequencedWorkerPool::Inner::PostTask(
+    const std::string* optional_token_name,
+    SequenceToken sequence_token,
+    WorkerShutdown shutdown_behavior,
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay) {
+  DCHECK(delay == TimeDelta() || shutdown_behavior == SKIP_ON_SHUTDOWN);
+  SequencedTask sequenced(from_here);
+  sequenced.sequence_token_id = sequence_token.id_;
+  sequenced.shutdown_behavior = shutdown_behavior;
+  sequenced.posted_from = from_here;
+  sequenced.task =
+      shutdown_behavior == BLOCK_SHUTDOWN ?
+      base::MakeCriticalClosure(task) : task;
+  sequenced.time_to_run = TimeTicks::Now() + delay;
+
+  int create_thread_id = 0;
+  {
+    AutoLock lock(lock_);
+    if (shutdown_called_) {
+      // Don't allow a new task to be posted if it doesn't block shutdown.
+      if (shutdown_behavior != BLOCK_SHUTDOWN)
+        return false;
+
+      // If the current thread is running a task, and that task doesn't block
+      // shutdown, then it shouldn't be allowed to post any more tasks.
+      ThreadMap::const_iterator found =
+          threads_.find(PlatformThread::CurrentId());
+      if (found != threads_.end() && found->second->is_processing_task() &&
+          found->second->task_shutdown_behavior() != BLOCK_SHUTDOWN) {
+        return false;
+      }
+
+      if (max_blocking_tasks_after_shutdown_ <= 0) {
+        DLOG(WARNING) << "BLOCK_SHUTDOWN task disallowed";
+        return false;
+      }
+      max_blocking_tasks_after_shutdown_ -= 1;
+    }
+
+    // The trace_id is used for identifying the task in about:tracing.
+    sequenced.trace_id = trace_id_++;
+
+    TRACE_EVENT_FLOW_BEGIN0(TRACE_DISABLED_BY_DEFAULT("toplevel.flow"),
+        "SequencedWorkerPool::PostTask",
+        TRACE_ID_MANGLE(GetTaskTraceID(sequenced, static_cast<void*>(this))));
+
+    sequenced.sequence_task_number = LockedGetNextSequenceTaskNumber();
+
+    // Now that we have the lock, apply the named token rules.
+    if (optional_token_name)
+      sequenced.sequence_token_id = LockedGetNamedTokenID(*optional_token_name);
+
+    pending_tasks_.insert(sequenced);
+    if (shutdown_behavior == BLOCK_SHUTDOWN)
+      blocking_shutdown_pending_task_count_++;
+
+    create_thread_id = PrepareToStartAdditionalThreadIfHelpful();
+  }
+
+  // Actually start the additional thread or signal an existing one now that
+  // we're outside the lock.
+  if (create_thread_id)
+    FinishStartingAdditionalThread(create_thread_id);
+  else
+    SignalHasWork();
+
+  return true;
+}
+
+bool SequencedWorkerPool::Inner::RunsTasksOnCurrentThread() const {
+  AutoLock lock(lock_);
+  return ContainsKey(threads_, PlatformThread::CurrentId());
+}
+
+bool SequencedWorkerPool::Inner::IsRunningSequenceOnCurrentThread(
+    SequenceToken sequence_token) const {
+  AutoLock lock(lock_);
+  ThreadMap::const_iterator found = threads_.find(PlatformThread::CurrentId());
+  if (found == threads_.end())
+    return false;
+  return found->second->is_processing_task() &&
+         sequence_token.Equals(found->second->task_sequence_token());
+}
+
+// See https://code.google.com/p/chromium/issues/detail?id=168415
+void SequencedWorkerPool::Inner::CleanupForTesting() {
+  DCHECK(!RunsTasksOnCurrentThread());
+  base::ThreadRestrictions::ScopedAllowWait allow_wait;
+  AutoLock lock(lock_);
+  CHECK_EQ(CLEANUP_DONE, cleanup_state_);
+  if (shutdown_called_)
+    return;
+  if (pending_tasks_.empty() && waiting_thread_count_ == threads_.size())
+    return;
+  cleanup_state_ = CLEANUP_REQUESTED;
+  cleanup_idlers_ = 0;
+  has_work_cv_.Signal();
+  while (cleanup_state_ != CLEANUP_DONE)
+    cleanup_cv_.Wait();
+}
+
+void SequencedWorkerPool::Inner::SignalHasWorkForTesting() {
+  SignalHasWork();
+}
+
+void SequencedWorkerPool::Inner::Shutdown(
+    int max_new_blocking_tasks_after_shutdown) {
+  DCHECK_GE(max_new_blocking_tasks_after_shutdown, 0);
+  {
+    AutoLock lock(lock_);
+    // Cleanup and Shutdown should not be called concurrently.
+    CHECK_EQ(CLEANUP_DONE, cleanup_state_);
+    if (shutdown_called_)
+      return;
+    shutdown_called_ = true;
+    max_blocking_tasks_after_shutdown_ = max_new_blocking_tasks_after_shutdown;
+
+    // Tickle the threads. This will wake up a waiting one so it will know that
+    // it can exit, which in turn will wake up any other waiting ones.
+    SignalHasWork();
+
+    // There are no pending or running tasks blocking shutdown, we're done.
+    if (CanShutdown())
+      return;
+  }
+
+  // If we're here, then something is blocking shutdown.  So wait for
+  // CanShutdown() to go to true.
+
+  if (testing_observer_)
+    testing_observer_->WillWaitForShutdown();
+
+#if !defined(OS_NACL)
+  TimeTicks shutdown_wait_begin = TimeTicks::Now();
+#endif
+
+  {
+    base::ThreadRestrictions::ScopedAllowWait allow_wait;
+    AutoLock lock(lock_);
+    while (!CanShutdown())
+      can_shutdown_cv_.Wait();
+  }
+#if !defined(OS_NACL)
+  UMA_HISTOGRAM_TIMES("SequencedWorkerPool.ShutdownDelayTime",
+                      TimeTicks::Now() - shutdown_wait_begin);
+#endif
+}
+
+bool SequencedWorkerPool::Inner::IsShutdownInProgress() {
+    AutoLock lock(lock_);
+    return shutdown_called_;
+}
+
+void SequencedWorkerPool::Inner::ThreadLoop(Worker* this_worker) {
+  {
+    AutoLock lock(lock_);
+    DCHECK(thread_being_created_);
+    thread_being_created_ = false;
+    std::pair<ThreadMap::iterator, bool> result =
+        threads_.insert(
+            std::make_pair(this_worker->tid(), make_linked_ptr(this_worker)));
+    DCHECK(result.second);
+
+    while (true) {
+#if defined(OS_MACOSX)
+      base::mac::ScopedNSAutoreleasePool autorelease_pool;
+#endif
+
+      HandleCleanup();
+
+      // See GetWork for what delete_these_outside_lock is doing.
+      SequencedTask task;
+      TimeDelta wait_time;
+      std::vector<Closure> delete_these_outside_lock;
+      GetWorkStatus status =
+          GetWork(&task, &wait_time, &delete_these_outside_lock);
+      if (status == GET_WORK_FOUND) {
+        TRACE_EVENT_FLOW_END0(TRACE_DISABLED_BY_DEFAULT("toplevel.flow"),
+            "SequencedWorkerPool::PostTask",
+            TRACE_ID_MANGLE(GetTaskTraceID(task, static_cast<void*>(this))));
+        TRACE_EVENT2("toplevel", "SequencedWorkerPool::ThreadLoop",
+                     "src_file", task.posted_from.file_name(),
+                     "src_func", task.posted_from.function_name());
+        int new_thread_id = WillRunWorkerTask(task);
+        {
+          AutoUnlock unlock(lock_);
+          // There may be more work available, so wake up another
+          // worker thread. (Technically not required, since we
+          // already get a signal for each new task, but it doesn't
+          // hurt.)
+          SignalHasWork();
+          delete_these_outside_lock.clear();
+
+          // Complete thread creation outside the lock if necessary.
+          if (new_thread_id)
+            FinishStartingAdditionalThread(new_thread_id);
+
+          this_worker->set_running_task_info(
+              SequenceToken(task.sequence_token_id), task.shutdown_behavior);
+
+          tracked_objects::TaskStopwatch stopwatch;
+          stopwatch.Start();
+          task.task.Run();
+          stopwatch.Stop();
+
+          tracked_objects::ThreadData::TallyRunOnNamedThreadIfTracking(
+              task, stopwatch);
+
+          // Make sure our task is erased outside the lock for the
+          // same reason we do this with delete_these_oustide_lock.
+          // Also, do it before calling reset_running_task_info() so
+          // that sequence-checking from within the task's destructor
+          // still works.
+          task.task = Closure();
+
+          this_worker->reset_running_task_info();
+        }
+        DidRunWorkerTask(task);  // Must be done inside the lock.
+      } else if (cleanup_state_ == CLEANUP_RUNNING) {
+        switch (status) {
+          case GET_WORK_WAIT: {
+              AutoUnlock unlock(lock_);
+              delete_these_outside_lock.clear();
+            }
+            break;
+          case GET_WORK_NOT_FOUND:
+            CHECK(delete_these_outside_lock.empty());
+            cleanup_state_ = CLEANUP_FINISHING;
+            cleanup_cv_.Broadcast();
+            break;
+          default:
+            NOTREACHED();
+        }
+      } else {
+        // When we're terminating and there's no more work, we can
+        // shut down, other workers can complete any pending or new tasks.
+        // We can get additional tasks posted after shutdown_called_ is set
+        // but only worker threads are allowed to post tasks at that time, and
+        // the workers responsible for posting those tasks will be available
+        // to run them. Also, there may be some tasks stuck behind running
+        // ones with the same sequence token, but additional threads won't
+        // help this case.
+        if (shutdown_called_ && blocking_shutdown_pending_task_count_ == 0) {
+          AutoUnlock unlock(lock_);
+          delete_these_outside_lock.clear();
+          break;
+        }
+
+        // No work was found, but there are tasks that need deletion. The
+        // deletion must happen outside of the lock.
+        if (delete_these_outside_lock.size()) {
+          AutoUnlock unlock(lock_);
+          delete_these_outside_lock.clear();
+
+          // Since the lock has been released, |status| may no longer be
+          // accurate. It might read GET_WORK_WAIT even if there are tasks
+          // ready to perform work. Jump to the top of the loop to recalculate
+          // |status|.
+          continue;
+        }
+
+        waiting_thread_count_++;
+
+        switch (status) {
+          case GET_WORK_NOT_FOUND:
+            has_work_cv_.Wait();
+            break;
+          case GET_WORK_WAIT:
+            has_work_cv_.TimedWait(wait_time);
+            break;
+          default:
+            NOTREACHED();
+        }
+        waiting_thread_count_--;
+      }
+    }
+  }  // Release lock_.
+
+  // We noticed we should exit. Wake up the next worker so it knows it should
+  // exit as well (because the Shutdown() code only signals once).
+  SignalHasWork();
+
+  // Possibly unblock shutdown.
+  can_shutdown_cv_.Signal();
+}
+
+void SequencedWorkerPool::Inner::HandleCleanup() {
+  lock_.AssertAcquired();
+  if (cleanup_state_ == CLEANUP_DONE)
+    return;
+  if (cleanup_state_ == CLEANUP_REQUESTED) {
+    // We win, we get to do the cleanup as soon as the others wise up and idle.
+    cleanup_state_ = CLEANUP_STARTING;
+    while (thread_being_created_ ||
+           cleanup_idlers_ != threads_.size() - 1) {
+      has_work_cv_.Signal();
+      cleanup_cv_.Wait();
+    }
+    cleanup_state_ = CLEANUP_RUNNING;
+    return;
+  }
+  if (cleanup_state_ == CLEANUP_STARTING) {
+    // Another worker thread is cleaning up, we idle here until thats done.
+    ++cleanup_idlers_;
+    cleanup_cv_.Broadcast();
+    while (cleanup_state_ != CLEANUP_FINISHING) {
+      cleanup_cv_.Wait();
+    }
+    --cleanup_idlers_;
+    cleanup_cv_.Broadcast();
+    return;
+  }
+  if (cleanup_state_ == CLEANUP_FINISHING) {
+    // We wait for all idlers to wake up prior to being DONE.
+    while (cleanup_idlers_ != 0) {
+      cleanup_cv_.Broadcast();
+      cleanup_cv_.Wait();
+    }
+    if (cleanup_state_ == CLEANUP_FINISHING) {
+      cleanup_state_ = CLEANUP_DONE;
+      cleanup_cv_.Signal();
+    }
+    return;
+  }
+}
+
+int SequencedWorkerPool::Inner::LockedGetNamedTokenID(
+    const std::string& name) {
+  lock_.AssertAcquired();
+  DCHECK(!name.empty());
+
+  std::map<std::string, int>::const_iterator found =
+      named_sequence_tokens_.find(name);
+  if (found != named_sequence_tokens_.end())
+    return found->second;  // Got an existing one.
+
+  // Create a new one for this name.
+  SequenceToken result = GetSequenceToken();
+  named_sequence_tokens_.insert(std::make_pair(name, result.id_));
+  return result.id_;
+}
+
+int64 SequencedWorkerPool::Inner::LockedGetNextSequenceTaskNumber() {
+  lock_.AssertAcquired();
+  // We assume that we never create enough tasks to wrap around.
+  return next_sequence_task_number_++;
+}
+
+SequencedWorkerPool::Inner::GetWorkStatus SequencedWorkerPool::Inner::GetWork(
+    SequencedTask* task,
+    TimeDelta* wait_time,
+    std::vector<Closure>* delete_these_outside_lock) {
+  lock_.AssertAcquired();
+
+  // Find the next task with a sequence token that's not currently in use.
+  // If the token is in use, that means another thread is running something
+  // in that sequence, and we can't run it without going out-of-order.
+  //
+  // This algorithm is simple and fair, but inefficient in some cases. For
+  // example, say somebody schedules 1000 slow tasks with the same sequence
+  // number. We'll have to go through all those tasks each time we feel like
+  // there might be work to schedule. If this proves to be a problem, we
+  // should make this more efficient.
+  //
+  // One possible enhancement would be to keep a map from sequence ID to a
+  // list of pending but currently blocked SequencedTasks for that ID.
+  // When a worker finishes a task of one sequence token, it can pick up the
+  // next one from that token right away.
+  //
+  // This may lead to starvation if there are sufficient numbers of sequences
+  // in use. To alleviate this, we could add an incrementing priority counter
+  // to each SequencedTask. Then maintain a priority_queue of all runnable
+  // tasks, sorted by priority counter. When a sequenced task is completed
+  // we would pop the head element off of that tasks pending list and add it
+  // to the priority queue. Then we would run the first item in the priority
+  // queue.
+
+  GetWorkStatus status = GET_WORK_NOT_FOUND;
+  int unrunnable_tasks = 0;
+  PendingTaskSet::iterator i = pending_tasks_.begin();
+  // We assume that the loop below doesn't take too long and so we can just do
+  // a single call to TimeTicks::Now().
+  const TimeTicks current_time = TimeTicks::Now();
+  while (i != pending_tasks_.end()) {
+    if (!IsSequenceTokenRunnable(i->sequence_token_id)) {
+      unrunnable_tasks++;
+      ++i;
+      continue;
+    }
+
+    if (shutdown_called_ && i->shutdown_behavior != BLOCK_SHUTDOWN) {
+      // We're shutting down and the task we just found isn't blocking
+      // shutdown. Delete it and get more work.
+      //
+      // Note that we do not want to delete unrunnable tasks. Deleting a task
+      // can have side effects (like freeing some objects) and deleting a
+      // task that's supposed to run after one that's currently running could
+      // cause an obscure crash.
+      //
+      // We really want to delete these tasks outside the lock in case the
+      // closures are holding refs to objects that want to post work from
+      // their destructorss (which would deadlock). The closures are
+      // internally refcounted, so we just need to keep a copy of them alive
+      // until the lock is exited. The calling code can just clear() the
+      // vector they passed to us once the lock is exited to make this
+      // happen.
+      delete_these_outside_lock->push_back(i->task);
+      pending_tasks_.erase(i++);
+      continue;
+    }
+
+    if (i->time_to_run > current_time) {
+      // The time to run has not come yet.
+      *wait_time = i->time_to_run - current_time;
+      status = GET_WORK_WAIT;
+      if (cleanup_state_ == CLEANUP_RUNNING) {
+        // Deferred tasks are deleted when cleaning up, see Inner::ThreadLoop.
+        delete_these_outside_lock->push_back(i->task);
+        pending_tasks_.erase(i);
+      }
+      break;
+    }
+
+    // Found a runnable task.
+    *task = *i;
+    pending_tasks_.erase(i);
+    if (task->shutdown_behavior == BLOCK_SHUTDOWN) {
+      blocking_shutdown_pending_task_count_--;
+    }
+
+    status = GET_WORK_FOUND;
+    break;
+  }
+
+  return status;
+}
+
+int SequencedWorkerPool::Inner::WillRunWorkerTask(const SequencedTask& task) {
+  lock_.AssertAcquired();
+
+  // Mark the task's sequence number as in use.
+  if (task.sequence_token_id)
+    current_sequences_.insert(task.sequence_token_id);
+
+  // Ensure that threads running tasks posted with either SKIP_ON_SHUTDOWN
+  // or BLOCK_SHUTDOWN will prevent shutdown until that task or thread
+  // completes.
+  if (task.shutdown_behavior != CONTINUE_ON_SHUTDOWN)
+    blocking_shutdown_thread_count_++;
+
+  // We just picked up a task. Since StartAdditionalThreadIfHelpful only
+  // creates a new thread if there is no free one, there is a race when posting
+  // tasks that many tasks could have been posted before a thread started
+  // running them, so only one thread would have been created. So we also check
+  // whether we should create more threads after removing our task from the
+  // queue, which also has the nice side effect of creating the workers from
+  // background threads rather than the main thread of the app.
+  //
+  // If another thread wasn't created, we want to wake up an existing thread
+  // if there is one waiting to pick up the next task.
+  //
+  // Note that we really need to do this *before* running the task, not
+  // after. Otherwise, if more than one task is posted, the creation of the
+  // second thread (since we only create one at a time) will be blocked by
+  // the execution of the first task, which could be arbitrarily long.
+  return PrepareToStartAdditionalThreadIfHelpful();
+}
+
+void SequencedWorkerPool::Inner::DidRunWorkerTask(const SequencedTask& task) {
+  lock_.AssertAcquired();
+
+  if (task.shutdown_behavior != CONTINUE_ON_SHUTDOWN) {
+    DCHECK_GT(blocking_shutdown_thread_count_, 0u);
+    blocking_shutdown_thread_count_--;
+  }
+
+  if (task.sequence_token_id)
+    current_sequences_.erase(task.sequence_token_id);
+}
+
+bool SequencedWorkerPool::Inner::IsSequenceTokenRunnable(
+    int sequence_token_id) const {
+  lock_.AssertAcquired();
+  return !sequence_token_id ||
+      current_sequences_.find(sequence_token_id) ==
+          current_sequences_.end();
+}
+
+int SequencedWorkerPool::Inner::PrepareToStartAdditionalThreadIfHelpful() {
+  lock_.AssertAcquired();
+  // How thread creation works:
+  //
+  // We'de like to avoid creating threads with the lock held. However, we
+  // need to be sure that we have an accurate accounting of the threads for
+  // proper Joining and deltion on shutdown.
+  //
+  // We need to figure out if we need another thread with the lock held, which
+  // is what this function does. It then marks us as in the process of creating
+  // a thread. When we do shutdown, we wait until the thread_being_created_
+  // flag is cleared, which ensures that the new thread is properly added to
+  // all the data structures and we can't leak it. Once shutdown starts, we'll
+  // refuse to create more threads or they would be leaked.
+  //
+  // Note that this creates a mostly benign race condition on shutdown that
+  // will cause fewer workers to be created than one would expect. It isn't
+  // much of an issue in real life, but affects some tests. Since we only spawn
+  // one worker at a time, the following sequence of events can happen:
+  //
+  //  1. Main thread posts a bunch of unrelated tasks that would normally be
+  //     run on separate threads.
+  //  2. The first task post causes us to start a worker. Other tasks do not
+  //     cause a worker to start since one is pending.
+  //  3. Main thread initiates shutdown.
+  //  4. No more threads are created since the shutdown_called_ flag is set.
+  //
+  // The result is that one may expect that max_threads_ workers to be created
+  // given the workload, but in reality fewer may be created because the
+  // sequence of thread creation on the background threads is racing with the
+  // shutdown call.
+  if (!shutdown_called_ &&
+      !thread_being_created_ &&
+      cleanup_state_ == CLEANUP_DONE &&
+      threads_.size() < max_threads_ &&
+      waiting_thread_count_ == 0) {
+    // We could use an additional thread if there's work to be done.
+    for (PendingTaskSet::const_iterator i = pending_tasks_.begin();
+         i != pending_tasks_.end(); ++i) {
+      if (IsSequenceTokenRunnable(i->sequence_token_id)) {
+        // Found a runnable task, mark the thread as being started.
+        thread_being_created_ = true;
+        return static_cast<int>(threads_.size() + 1);
+      }
+    }
+  }
+  return 0;
+}
+
+void SequencedWorkerPool::Inner::FinishStartingAdditionalThread(
+    int thread_number) {
+  // Called outside of the lock.
+  DCHECK_GT(thread_number, 0);
+
+  // The worker is assigned to the list when the thread actually starts, which
+  // will manage the memory of the pointer.
+  new Worker(worker_pool_, thread_number, thread_name_prefix_);
+}
+
+void SequencedWorkerPool::Inner::SignalHasWork() {
+  has_work_cv_.Signal();
+  if (testing_observer_) {
+    testing_observer_->OnHasWork();
+  }
+}
+
+bool SequencedWorkerPool::Inner::CanShutdown() const {
+  lock_.AssertAcquired();
+  // See PrepareToStartAdditionalThreadIfHelpful for how thread creation works.
+  return !thread_being_created_ &&
+         blocking_shutdown_thread_count_ == 0 &&
+         blocking_shutdown_pending_task_count_ == 0;
+}
+
+base::StaticAtomicSequenceNumber
+SequencedWorkerPool::Inner::g_last_sequence_number_;
+
+// SequencedWorkerPool --------------------------------------------------------
+
+// static
+SequencedWorkerPool::SequenceToken
+SequencedWorkerPool::GetSequenceTokenForCurrentThread() {
+  // Don't construct lazy instance on check.
+  if (g_lazy_tls_ptr == NULL)
+    return SequenceToken();
+
+  SequencedWorkerPool::SequenceToken* token = g_lazy_tls_ptr.Get().Get();
+  if (!token)
+    return SequenceToken();
+  return *token;
+}
+
+SequencedWorkerPool::SequencedWorkerPool(size_t max_threads,
+                                         const std::string& thread_name_prefix)
+    : constructor_task_runner_(ThreadTaskRunnerHandle::Get()),
+      inner_(new Inner(this, max_threads, thread_name_prefix, NULL)) {
+}
+
+SequencedWorkerPool::SequencedWorkerPool(size_t max_threads,
+                                         const std::string& thread_name_prefix,
+                                         TestingObserver* observer)
+    : constructor_task_runner_(ThreadTaskRunnerHandle::Get()),
+      inner_(new Inner(this, max_threads, thread_name_prefix, observer)) {
+}
+
+SequencedWorkerPool::~SequencedWorkerPool() {}
+
+void SequencedWorkerPool::OnDestruct() const {
+  // Avoid deleting ourselves on a worker thread (which would
+  // deadlock).
+  if (RunsTasksOnCurrentThread()) {
+    constructor_task_runner_->DeleteSoon(FROM_HERE, this);
+  } else {
+    delete this;
+  }
+}
+
+SequencedWorkerPool::SequenceToken SequencedWorkerPool::GetSequenceToken() {
+  return inner_->GetSequenceToken();
+}
+
+SequencedWorkerPool::SequenceToken SequencedWorkerPool::GetNamedSequenceToken(
+    const std::string& name) {
+  return inner_->GetNamedSequenceToken(name);
+}
+
+scoped_refptr<SequencedTaskRunner> SequencedWorkerPool::GetSequencedTaskRunner(
+    SequenceToken token) {
+  return GetSequencedTaskRunnerWithShutdownBehavior(token, BLOCK_SHUTDOWN);
+}
+
+scoped_refptr<SequencedTaskRunner>
+SequencedWorkerPool::GetSequencedTaskRunnerWithShutdownBehavior(
+    SequenceToken token, WorkerShutdown shutdown_behavior) {
+  return new SequencedWorkerPoolSequencedTaskRunner(
+      this, token, shutdown_behavior);
+}
+
+scoped_refptr<TaskRunner>
+SequencedWorkerPool::GetTaskRunnerWithShutdownBehavior(
+    WorkerShutdown shutdown_behavior) {
+  return new SequencedWorkerPoolTaskRunner(this, shutdown_behavior);
+}
+
+bool SequencedWorkerPool::PostWorkerTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task) {
+  return inner_->PostTask(NULL, SequenceToken(), BLOCK_SHUTDOWN,
+                          from_here, task, TimeDelta());
+}
+
+bool SequencedWorkerPool::PostDelayedWorkerTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay) {
+  WorkerShutdown shutdown_behavior =
+      delay == TimeDelta() ? BLOCK_SHUTDOWN : SKIP_ON_SHUTDOWN;
+  return inner_->PostTask(NULL, SequenceToken(), shutdown_behavior,
+                          from_here, task, delay);
+}
+
+bool SequencedWorkerPool::PostWorkerTaskWithShutdownBehavior(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    WorkerShutdown shutdown_behavior) {
+  return inner_->PostTask(NULL, SequenceToken(), shutdown_behavior,
+                          from_here, task, TimeDelta());
+}
+
+bool SequencedWorkerPool::PostSequencedWorkerTask(
+    SequenceToken sequence_token,
+    const tracked_objects::Location& from_here,
+    const Closure& task) {
+  return inner_->PostTask(NULL, sequence_token, BLOCK_SHUTDOWN,
+                          from_here, task, TimeDelta());
+}
+
+bool SequencedWorkerPool::PostDelayedSequencedWorkerTask(
+    SequenceToken sequence_token,
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay) {
+  WorkerShutdown shutdown_behavior =
+      delay == TimeDelta() ? BLOCK_SHUTDOWN : SKIP_ON_SHUTDOWN;
+  return inner_->PostTask(NULL, sequence_token, shutdown_behavior,
+                          from_here, task, delay);
+}
+
+bool SequencedWorkerPool::PostNamedSequencedWorkerTask(
+    const std::string& token_name,
+    const tracked_objects::Location& from_here,
+    const Closure& task) {
+  DCHECK(!token_name.empty());
+  return inner_->PostTask(&token_name, SequenceToken(), BLOCK_SHUTDOWN,
+                          from_here, task, TimeDelta());
+}
+
+bool SequencedWorkerPool::PostSequencedWorkerTaskWithShutdownBehavior(
+    SequenceToken sequence_token,
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    WorkerShutdown shutdown_behavior) {
+  return inner_->PostTask(NULL, sequence_token, shutdown_behavior,
+                          from_here, task, TimeDelta());
+}
+
+bool SequencedWorkerPool::PostDelayedTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay) {
+  return PostDelayedWorkerTask(from_here, task, delay);
+}
+
+bool SequencedWorkerPool::RunsTasksOnCurrentThread() const {
+  return inner_->RunsTasksOnCurrentThread();
+}
+
+bool SequencedWorkerPool::IsRunningSequenceOnCurrentThread(
+    SequenceToken sequence_token) const {
+  return inner_->IsRunningSequenceOnCurrentThread(sequence_token);
+}
+
+void SequencedWorkerPool::FlushForTesting() {
+  inner_->CleanupForTesting();
+}
+
+void SequencedWorkerPool::SignalHasWorkForTesting() {
+  inner_->SignalHasWorkForTesting();
+}
+
+void SequencedWorkerPool::Shutdown(int max_new_blocking_tasks_after_shutdown) {
+  DCHECK(constructor_task_runner_->BelongsToCurrentThread());
+  inner_->Shutdown(max_new_blocking_tasks_after_shutdown);
+}
+
+bool SequencedWorkerPool::IsShutdownInProgress() {
+  return inner_->IsShutdownInProgress();
+}
+
+}  // namespace base
diff --git a/base/threading/sequenced_worker_pool.h b/base/threading/sequenced_worker_pool.h
new file mode 100644
index 0000000..ee282bc
--- /dev/null
+++ b/base/threading/sequenced_worker_pool.h
@@ -0,0 +1,360 @@
+// Copyright (c) 2012 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_THREADING_SEQUENCED_WORKER_POOL_H_
+#define BASE_THREADING_SEQUENCED_WORKER_POOL_H_
+
+#include <cstddef>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/callback_forward.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/single_thread_task_runner.h"
+#include "base/task_runner.h"
+
+namespace tracked_objects {
+class Location;
+}  // namespace tracked_objects
+
+namespace base {
+
+class SingleThreadTaskRunner;
+
+template <class T> class DeleteHelper;
+
+class SequencedTaskRunner;
+
+// A worker thread pool that enforces ordering between sets of tasks. It also
+// allows you to specify what should happen to your tasks on shutdown.
+//
+// To enforce ordering, get a unique sequence token from the pool and post all
+// tasks you want to order with the token. All tasks with the same token are
+// guaranteed to execute serially, though not necessarily on the same thread.
+// This means that:
+//
+//   - No two tasks with the same token will run at the same time.
+//
+//   - Given two tasks T1 and T2 with the same token such that T2 will
+//     run after T1, then T2 will start after T1 is destroyed.
+//
+//   - If T2 will run after T1, then all memory changes in T1 and T1's
+//     destruction will be visible to T2.
+//
+// Example:
+//   SequencedWorkerPool::SequenceToken token = pool.GetSequenceToken();
+//   pool.PostSequencedWorkerTask(token, SequencedWorkerPool::SKIP_ON_SHUTDOWN,
+//                                FROM_HERE, base::Bind(...));
+//   pool.PostSequencedWorkerTask(token, SequencedWorkerPool::SKIP_ON_SHUTDOWN,
+//                                FROM_HERE, base::Bind(...));
+//
+// You can make named sequence tokens to make it easier to share a token
+// across different components.
+//
+// You can also post tasks to the pool without ordering using PostWorkerTask.
+// These will be executed in an unspecified order. The order of execution
+// between tasks with different sequence tokens is also unspecified.
+//
+// This class may be leaked on shutdown to facilitate fast shutdown. The
+// expected usage, however, is to call Shutdown(), which correctly accounts
+// for CONTINUE_ON_SHUTDOWN behavior and is required for BLOCK_SHUTDOWN
+// behavior.
+//
+// Implementation note: This does not use a base::WorkerPool since that does
+// not enforce shutdown semantics or allow us to specify how many worker
+// threads to run. For the typical use case of random background work, we don't
+// necessarily want to be super aggressive about creating threads.
+//
+// Note that SequencedWorkerPool is RefCountedThreadSafe (inherited
+// from TaskRunner).
+//
+// Test-only code should wrap this in a base::SequencedWorkerPoolOwner to avoid
+// memory leaks. See http://crbug.com/273800
+class BASE_EXPORT SequencedWorkerPool : public TaskRunner {
+ public:
+  // Defines what should happen to a task posted to the worker pool on
+  // shutdown.
+  enum WorkerShutdown {
+    // Tasks posted with this mode which have not run at shutdown will be
+    // deleted rather than run, and any tasks with this mode running at
+    // shutdown will be ignored (the worker thread will not be joined).
+    //
+    // This option provides a nice way to post stuff you don't want blocking
+    // shutdown. For example, you might be doing a slow DNS lookup and if it's
+    // blocked on the OS, you may not want to stop shutdown, since the result
+    // doesn't really matter at that point.
+    //
+    // However, you need to be very careful what you do in your callback when
+    // you use this option. Since the thread will continue to run until the OS
+    // terminates the process, the app can be in the process of tearing down
+    // when you're running. This means any singletons or global objects you
+    // use may suddenly become invalid out from under you. For this reason,
+    // it's best to use this only for slow but simple operations like the DNS
+    // example.
+    CONTINUE_ON_SHUTDOWN,
+
+    // Tasks posted with this mode that have not started executing at
+    // shutdown will be deleted rather than executed. However, any tasks that
+    // have already begun executing when shutdown is called will be allowed
+    // to continue, and will block shutdown until completion.
+    //
+    // Note: Because Shutdown() may block while these tasks are executing,
+    // care must be taken to ensure that they do not block on the thread that
+    // called Shutdown(), as this may lead to deadlock.
+    SKIP_ON_SHUTDOWN,
+
+    // Tasks posted with this mode will block shutdown until they're
+    // executed. Since this can have significant performance implications,
+    // use sparingly.
+    //
+    // Generally, this should be used only for user data, for example, a task
+    // writing a preference file.
+    //
+    // If a task is posted during shutdown, it will not get run since the
+    // workers may already be stopped. In this case, the post operation will
+    // fail (return false) and the task will be deleted.
+    BLOCK_SHUTDOWN,
+  };
+
+  // Opaque identifier that defines sequencing of tasks posted to the worker
+  // pool.
+  class SequenceToken {
+   public:
+    SequenceToken() : id_(0) {}
+    ~SequenceToken() {}
+
+    bool Equals(const SequenceToken& other) const {
+      return id_ == other.id_;
+    }
+
+    // Returns false if current thread is executing an unsequenced task.
+    bool IsValid() const {
+      return id_ != 0;
+    }
+
+   private:
+    friend class SequencedWorkerPool;
+
+    explicit SequenceToken(int id) : id_(id) {}
+
+    int id_;
+  };
+
+  // Allows tests to perform certain actions.
+  class TestingObserver {
+   public:
+    virtual ~TestingObserver() {}
+    virtual void OnHasWork() = 0;
+    virtual void WillWaitForShutdown() = 0;
+    virtual void OnDestruct() = 0;
+  };
+
+  // Gets the SequencedToken of the current thread.
+  // If current thread is not a SequencedWorkerPool worker thread or is running
+  // an unsequenced task, returns an invalid SequenceToken.
+  static SequenceToken GetSequenceTokenForCurrentThread();
+
+  // When constructing a SequencedWorkerPool, there must be a
+  // MessageLoop on the current thread unless you plan to deliberately
+  // leak it.
+
+  // Pass the maximum number of threads (they will be lazily created as needed)
+  // and a prefix for the thread name to aid in debugging.
+  SequencedWorkerPool(size_t max_threads,
+                      const std::string& thread_name_prefix);
+
+  // Like above, but with |observer| for testing.  Does not take
+  // ownership of |observer|.
+  SequencedWorkerPool(size_t max_threads,
+                      const std::string& thread_name_prefix,
+                      TestingObserver* observer);
+
+  // Returns a unique token that can be used to sequence tasks posted to
+  // PostSequencedWorkerTask(). Valid tokens are always nonzero.
+  SequenceToken GetSequenceToken();
+
+  // Returns the sequence token associated with the given name. Calling this
+  // function multiple times with the same string will always produce the
+  // same sequence token. If the name has not been used before, a new token
+  // will be created.
+  SequenceToken GetNamedSequenceToken(const std::string& name);
+
+  // Returns a SequencedTaskRunner wrapper which posts to this
+  // SequencedWorkerPool using the given sequence token. Tasks with nonzero
+  // delay are posted with SKIP_ON_SHUTDOWN behavior and tasks with zero delay
+  // are posted with BLOCK_SHUTDOWN behavior.
+  scoped_refptr<SequencedTaskRunner> GetSequencedTaskRunner(
+      SequenceToken token);
+
+  // Returns a SequencedTaskRunner wrapper which posts to this
+  // SequencedWorkerPool using the given sequence token. Tasks with nonzero
+  // delay are posted with SKIP_ON_SHUTDOWN behavior and tasks with zero delay
+  // are posted with the given shutdown behavior.
+  scoped_refptr<SequencedTaskRunner> GetSequencedTaskRunnerWithShutdownBehavior(
+      SequenceToken token,
+      WorkerShutdown shutdown_behavior);
+
+  // Returns a TaskRunner wrapper which posts to this SequencedWorkerPool using
+  // the given shutdown behavior. Tasks with nonzero delay are posted with
+  // SKIP_ON_SHUTDOWN behavior and tasks with zero delay are posted with the
+  // given shutdown behavior.
+  scoped_refptr<TaskRunner> GetTaskRunnerWithShutdownBehavior(
+      WorkerShutdown shutdown_behavior);
+
+  // Posts the given task for execution in the worker pool. Tasks posted with
+  // this function will execute in an unspecified order on a background thread.
+  // Returns true if the task was posted. If your tasks have ordering
+  // requirements, see PostSequencedWorkerTask().
+  //
+  // This class will attempt to delete tasks that aren't run
+  // (non-block-shutdown semantics) but can't guarantee that this happens. If
+  // all worker threads are busy running CONTINUE_ON_SHUTDOWN tasks, there
+  // will be no workers available to delete these tasks. And there may be
+  // tasks with the same sequence token behind those CONTINUE_ON_SHUTDOWN
+  // tasks. Deleting those tasks before the previous one has completed could
+  // cause nondeterministic crashes because the task could be keeping some
+  // objects alive which do work in their destructor, which could voilate the
+  // assumptions of the running task.
+  //
+  // The task will be guaranteed to run to completion before shutdown
+  // (BLOCK_SHUTDOWN semantics).
+  //
+  // Returns true if the task was posted successfully. This may fail during
+  // shutdown regardless of the specified ShutdownBehavior.
+  bool PostWorkerTask(const tracked_objects::Location& from_here,
+                      const Closure& task);
+
+  // Same as PostWorkerTask but allows a delay to be specified (although doing
+  // so changes the shutdown behavior). The task will be run after the given
+  // delay has elapsed.
+  //
+  // If the delay is nonzero, the task won't be guaranteed to run to completion
+  // before shutdown (SKIP_ON_SHUTDOWN semantics) to avoid shutdown hangs.
+  // If the delay is zero, this behaves exactly like PostWorkerTask, i.e. the
+  // task will be guaranteed to run to completion before shutdown
+  // (BLOCK_SHUTDOWN semantics).
+  bool PostDelayedWorkerTask(const tracked_objects::Location& from_here,
+                             const Closure& task,
+                             TimeDelta delay);
+
+  // Same as PostWorkerTask but allows specification of the shutdown behavior.
+  bool PostWorkerTaskWithShutdownBehavior(
+      const tracked_objects::Location& from_here,
+      const Closure& task,
+      WorkerShutdown shutdown_behavior);
+
+  // Like PostWorkerTask above, but provides sequencing semantics. This means
+  // that tasks posted with the same sequence token (see GetSequenceToken())
+  // are guaranteed to execute in order. This is useful in cases where you're
+  // doing operations that may depend on previous ones, like appending to a
+  // file.
+  //
+  // The task will be guaranteed to run to completion before shutdown
+  // (BLOCK_SHUTDOWN semantics).
+  //
+  // Returns true if the task was posted successfully. This may fail during
+  // shutdown regardless of the specified ShutdownBehavior.
+  bool PostSequencedWorkerTask(SequenceToken sequence_token,
+                               const tracked_objects::Location& from_here,
+                               const Closure& task);
+
+  // Like PostSequencedWorkerTask above, but allows you to specify a named
+  // token, which saves an extra call to GetNamedSequenceToken.
+  bool PostNamedSequencedWorkerTask(const std::string& token_name,
+                                    const tracked_objects::Location& from_here,
+                                    const Closure& task);
+
+  // Same as PostSequencedWorkerTask but allows a delay to be specified
+  // (although doing so changes the shutdown behavior). The task will be run
+  // after the given delay has elapsed.
+  //
+  // If the delay is nonzero, the task won't be guaranteed to run to completion
+  // before shutdown (SKIP_ON_SHUTDOWN semantics) to avoid shutdown hangs.
+  // If the delay is zero, this behaves exactly like PostSequencedWorkerTask,
+  // i.e. the task will be guaranteed to run to completion before shutdown
+  // (BLOCK_SHUTDOWN semantics).
+  bool PostDelayedSequencedWorkerTask(
+      SequenceToken sequence_token,
+      const tracked_objects::Location& from_here,
+      const Closure& task,
+      TimeDelta delay);
+
+  // Same as PostSequencedWorkerTask but allows specification of the shutdown
+  // behavior.
+  bool PostSequencedWorkerTaskWithShutdownBehavior(
+      SequenceToken sequence_token,
+      const tracked_objects::Location& from_here,
+      const Closure& task,
+      WorkerShutdown shutdown_behavior);
+
+  // TaskRunner implementation. Forwards to PostDelayedWorkerTask().
+  bool PostDelayedTask(const tracked_objects::Location& from_here,
+                       const Closure& task,
+                       TimeDelta delay) override;
+  bool RunsTasksOnCurrentThread() const override;
+
+  // Returns true if the current thread is processing a task with the given
+  // sequence_token.
+  bool IsRunningSequenceOnCurrentThread(SequenceToken sequence_token) const;
+
+  // Blocks until all pending tasks are complete. This should only be called in
+  // unit tests when you want to validate something that should have happened.
+  // This will not flush delayed tasks; delayed tasks get deleted.
+  //
+  // Note that calling this will not prevent other threads from posting work to
+  // the queue while the calling thread is waiting on Flush(). In this case,
+  // Flush will return only when there's no more work in the queue. Normally,
+  // this doesn't come up since in a test, all the work is being posted from
+  // the main thread.
+  void FlushForTesting();
+
+  // Spuriously signal that there is work to be done.
+  void SignalHasWorkForTesting();
+
+  // Implements the worker pool shutdown. This should be called during app
+  // shutdown, and will discard/join with appropriate tasks before returning.
+  // After this call, subsequent calls to post tasks will fail.
+  //
+  // Must be called from the same thread this object was constructed on.
+  void Shutdown() { Shutdown(0); }
+
+  // A variant that allows an arbitrary number of new blocking tasks to be
+  // posted during shutdown. The tasks cannot be posted within the execution
+  // context of tasks whose shutdown behavior is not BLOCKING_SHUTDOWN. Once
+  // the limit is reached, subsequent calls to post task fail in all cases.
+  // Must be called from the same thread this object was constructed on.
+  void Shutdown(int max_new_blocking_tasks_after_shutdown);
+
+  // Check if Shutdown was called for given threading pool. This method is used
+  // for aborting time consuming operation to avoid blocking shutdown.
+  //
+  // Can be called from any thread.
+  bool IsShutdownInProgress();
+
+ protected:
+  ~SequencedWorkerPool() override;
+
+  void OnDestruct() const override;
+
+ private:
+  friend class RefCountedThreadSafe<SequencedWorkerPool>;
+  friend class DeleteHelper<SequencedWorkerPool>;
+
+  class Inner;
+  class Worker;
+
+  const scoped_refptr<SingleThreadTaskRunner> constructor_task_runner_;
+
+  // Avoid pulling in too many headers by putting (almost) everything
+  // into |inner_|.
+  const scoped_ptr<Inner> inner_;
+
+  DISALLOW_COPY_AND_ASSIGN(SequencedWorkerPool);
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_SEQUENCED_WORKER_POOL_H_
diff --git a/base/threading/sequenced_worker_pool_unittest.cc b/base/threading/sequenced_worker_pool_unittest.cc
new file mode 100644
index 0000000..05989a5
--- /dev/null
+++ b/base/threading/sequenced_worker_pool_unittest.cc
@@ -0,0 +1,1032 @@
+// Copyright (c) 2012 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/threading/sequenced_worker_pool.h"
+
+#include <algorithm>
+
+#include "base/bind.h"
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
+#include "base/test/sequenced_task_runner_test_template.h"
+#include "base/test/sequenced_worker_pool_owner.h"
+#include "base/test/task_runner_test_template.h"
+#include "base/test/test_timeouts.h"
+#include "base/threading/platform_thread.h"
+#include "base/time/time.h"
+#include "base/tracked_objects.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+// IMPORTANT NOTE:
+//
+// Many of these tests have failure modes where they'll hang forever. These
+// tests should not be flaky, and hanging indicates a type of failure. Do not
+// mark as flaky if they're hanging, it's likely an actual bug.
+
+namespace {
+
+const size_t kNumWorkerThreads = 3;
+
+// Allows a number of threads to all be blocked on the same event, and
+// provides a way to unblock a certain number of them.
+class ThreadBlocker {
+ public:
+  ThreadBlocker() : lock_(), cond_var_(&lock_), unblock_counter_(0) {}
+
+  void Block() {
+    {
+      base::AutoLock lock(lock_);
+      while (unblock_counter_ == 0)
+        cond_var_.Wait();
+      unblock_counter_--;
+    }
+    cond_var_.Signal();
+  }
+
+  void Unblock(size_t count) {
+    {
+      base::AutoLock lock(lock_);
+      DCHECK_EQ(unblock_counter_, 0u);
+      unblock_counter_ = count;
+    }
+    cond_var_.Signal();
+  }
+
+ private:
+  base::Lock lock_;
+  base::ConditionVariable cond_var_;
+
+  size_t unblock_counter_;
+};
+
+class DestructionDeadlockChecker
+    : public base::RefCountedThreadSafe<DestructionDeadlockChecker> {
+ public:
+  DestructionDeadlockChecker(const scoped_refptr<SequencedWorkerPool>& pool)
+      : pool_(pool) {}
+
+ protected:
+  virtual ~DestructionDeadlockChecker() {
+    // This method should not deadlock.
+    pool_->RunsTasksOnCurrentThread();
+  }
+
+ private:
+  scoped_refptr<SequencedWorkerPool> pool_;
+  friend class base::RefCountedThreadSafe<DestructionDeadlockChecker>;
+};
+
+class TestTracker : public base::RefCountedThreadSafe<TestTracker> {
+ public:
+  TestTracker()
+      : lock_(),
+        cond_var_(&lock_),
+        started_events_(0) {
+  }
+
+  // Each of these tasks appends the argument to the complete sequence vector
+  // so calling code can see what order they finished in.
+  void FastTask(int id) {
+    SignalWorkerDone(id);
+  }
+
+  void SlowTask(int id) {
+    base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
+    SignalWorkerDone(id);
+  }
+
+  void BlockTask(int id, ThreadBlocker* blocker) {
+    // Note that this task has started and signal anybody waiting for that
+    // to happen.
+    {
+      base::AutoLock lock(lock_);
+      started_events_++;
+    }
+    cond_var_.Signal();
+
+    blocker->Block();
+    SignalWorkerDone(id);
+  }
+
+  void PostAdditionalTasks(
+        int id, SequencedWorkerPool* pool,
+        bool expected_return_value) {
+    Closure fast_task = base::Bind(&TestTracker::FastTask, this, 100);
+    EXPECT_EQ(expected_return_value,
+              pool->PostWorkerTaskWithShutdownBehavior(
+                  FROM_HERE, fast_task,
+                  SequencedWorkerPool::CONTINUE_ON_SHUTDOWN));
+    EXPECT_EQ(expected_return_value,
+              pool->PostWorkerTaskWithShutdownBehavior(
+                  FROM_HERE, fast_task,
+                  SequencedWorkerPool::SKIP_ON_SHUTDOWN));
+    pool->PostWorkerTaskWithShutdownBehavior(
+        FROM_HERE, fast_task,
+        SequencedWorkerPool::BLOCK_SHUTDOWN);
+    SignalWorkerDone(id);
+  }
+
+  // This task posts itself back onto the SequencedWorkerPool before it
+  // finishes running. Each instance of the task maintains a strong reference
+  // to a DestructionDeadlockChecker. The DestructionDeadlockChecker is only
+  // destroyed when the task is destroyed without being run, which only happens
+  // during destruction of the SequencedWorkerPool.
+  void PostRepostingTask(
+      const scoped_refptr<SequencedWorkerPool>& pool,
+      const scoped_refptr<DestructionDeadlockChecker>& checker) {
+    Closure reposting_task =
+        base::Bind(&TestTracker::PostRepostingTask, this, pool, checker);
+    pool->PostWorkerTaskWithShutdownBehavior(
+        FROM_HERE, reposting_task, SequencedWorkerPool::SKIP_ON_SHUTDOWN);
+  }
+
+  // This task reposts itself back onto the SequencedWorkerPool before it
+  // finishes running.
+  void PostRepostingBlockingTask(
+      const scoped_refptr<SequencedWorkerPool>& pool,
+      const SequencedWorkerPool::SequenceToken& token) {
+    Closure reposting_task =
+        base::Bind(&TestTracker::PostRepostingBlockingTask, this, pool, token);
+    pool->PostSequencedWorkerTaskWithShutdownBehavior(token,
+        FROM_HERE, reposting_task, SequencedWorkerPool::BLOCK_SHUTDOWN);
+  }
+
+  void PostBlockingTaskThenUnblockThreads(
+      const scoped_refptr<SequencedWorkerPool>& pool,
+      ThreadBlocker* blocker,
+      size_t threads_to_wake) {
+    Closure arbitrary_task = base::Bind(&TestTracker::FastTask, this, 0);
+    pool->PostWorkerTaskWithShutdownBehavior(
+        FROM_HERE, arbitrary_task, SequencedWorkerPool::BLOCK_SHUTDOWN);
+    blocker->Unblock(threads_to_wake);
+  }
+
+  // Waits until the given number of tasks have started executing.
+  void WaitUntilTasksBlocked(size_t count) {
+    {
+      base::AutoLock lock(lock_);
+      while (started_events_ < count)
+        cond_var_.Wait();
+    }
+    cond_var_.Signal();
+  }
+
+  // Blocks the current thread until at least the given number of tasks are in
+  // the completed vector, and then returns a copy.
+  std::vector<int> WaitUntilTasksComplete(size_t num_tasks) {
+    std::vector<int> ret;
+    {
+      base::AutoLock lock(lock_);
+      while (complete_sequence_.size() < num_tasks)
+        cond_var_.Wait();
+      ret = complete_sequence_;
+    }
+    cond_var_.Signal();
+    return ret;
+  }
+
+  size_t GetTasksCompletedCount() {
+    base::AutoLock lock(lock_);
+    return complete_sequence_.size();
+  }
+
+  void ClearCompleteSequence() {
+    base::AutoLock lock(lock_);
+    complete_sequence_.clear();
+    started_events_ = 0;
+  }
+
+ private:
+  friend class base::RefCountedThreadSafe<TestTracker>;
+  ~TestTracker() {}
+
+  void SignalWorkerDone(int id) {
+    {
+      base::AutoLock lock(lock_);
+      complete_sequence_.push_back(id);
+    }
+    cond_var_.Signal();
+  }
+
+  // Protects the complete_sequence.
+  base::Lock lock_;
+
+  base::ConditionVariable cond_var_;
+
+  // Protected by lock_.
+  std::vector<int> complete_sequence_;
+
+  // Counter of the number of "block" workers that have started.
+  size_t started_events_;
+};
+
+class SequencedWorkerPoolTest : public testing::Test {
+ public:
+  SequencedWorkerPoolTest()
+      : tracker_(new TestTracker) {
+    ResetPool();
+  }
+
+  void TearDown() override { pool()->Shutdown(); }
+
+  const scoped_refptr<SequencedWorkerPool>& pool() {
+    return pool_owner_->pool();
+  }
+  TestTracker* tracker() { return tracker_.get(); }
+
+  // Destroys the SequencedWorkerPool instance, blocking until it is fully shut
+  // down, and creates a new instance.
+  void ResetPool() {
+    pool_owner_.reset(new SequencedWorkerPoolOwner(kNumWorkerThreads, "test"));
+  }
+
+  void SetWillWaitForShutdownCallback(const Closure& callback) {
+    pool_owner_->SetWillWaitForShutdownCallback(callback);
+  }
+
+  // Ensures that the given number of worker threads is created by adding
+  // tasks and waiting until they complete. Worker thread creation is
+  // serialized, can happen on background threads asynchronously, and doesn't
+  // happen any more at shutdown. This means that if a test posts a bunch of
+  // tasks and calls shutdown, fewer workers will be created than the test may
+  // expect.
+  //
+  // This function ensures that this condition can't happen so tests can make
+  // assumptions about the number of workers active. See the comment in
+  // PrepareToStartAdditionalThreadIfNecessary in the .cc file for more
+  // details.
+  //
+  // It will post tasks to the queue with id -1. It also assumes this is the
+  // first thing called in a test since it will clear the complete_sequence_.
+  void EnsureAllWorkersCreated() {
+    // Create a bunch of threads, all waiting. This will cause that may
+    // workers to be created.
+    ThreadBlocker blocker;
+    for (size_t i = 0; i < kNumWorkerThreads; i++) {
+      pool()->PostWorkerTask(FROM_HERE,
+                             base::Bind(&TestTracker::BlockTask,
+                                        tracker(), -1, &blocker));
+    }
+    tracker()->WaitUntilTasksBlocked(kNumWorkerThreads);
+
+    // Now wake them up and wait until they're done.
+    blocker.Unblock(kNumWorkerThreads);
+    tracker()->WaitUntilTasksComplete(kNumWorkerThreads);
+
+    // Clean up the task IDs we added.
+    tracker()->ClearCompleteSequence();
+  }
+
+  int has_work_call_count() const {
+    return pool_owner_->has_work_call_count();
+  }
+
+ private:
+  MessageLoop message_loop_;
+  scoped_ptr<SequencedWorkerPoolOwner> pool_owner_;
+  const scoped_refptr<TestTracker> tracker_;
+};
+
+// Checks that the given number of entries are in the tasks to complete of
+// the given tracker, and then signals the given event the given number of
+// times. This is used to wake up blocked background threads before blocking
+// on shutdown.
+void EnsureTasksToCompleteCountAndUnblock(scoped_refptr<TestTracker> tracker,
+                                          size_t expected_tasks_to_complete,
+                                          ThreadBlocker* blocker,
+                                          size_t threads_to_awake) {
+  EXPECT_EQ(
+      expected_tasks_to_complete,
+      tracker->WaitUntilTasksComplete(expected_tasks_to_complete).size());
+
+  blocker->Unblock(threads_to_awake);
+}
+
+class DeletionHelper : public base::RefCountedThreadSafe<DeletionHelper> {
+ public:
+  explicit DeletionHelper(
+      const scoped_refptr<base::RefCountedData<bool> >& deleted_flag)
+      : deleted_flag_(deleted_flag) {
+  }
+
+ private:
+  friend class base::RefCountedThreadSafe<DeletionHelper>;
+  virtual ~DeletionHelper() { deleted_flag_->data = true; }
+
+  const scoped_refptr<base::RefCountedData<bool> > deleted_flag_;
+  DISALLOW_COPY_AND_ASSIGN(DeletionHelper);
+};
+
+void HoldPoolReference(const scoped_refptr<base::SequencedWorkerPool>& pool,
+                       const scoped_refptr<DeletionHelper>& helper) {
+  ADD_FAILURE() << "Should never run";
+}
+
+// Tests that delayed tasks are deleted upon shutdown of the pool.
+TEST_F(SequencedWorkerPoolTest, DelayedTaskDuringShutdown) {
+  // Post something to verify the pool is started up.
+  EXPECT_TRUE(pool()->PostTask(
+      FROM_HERE, base::Bind(&TestTracker::FastTask, tracker(), 1)));
+
+  scoped_refptr<base::RefCountedData<bool> > deleted_flag(
+      new base::RefCountedData<bool>(false));
+
+  base::Time posted_at(base::Time::Now());
+  // Post something that shouldn't run.
+  EXPECT_TRUE(pool()->PostDelayedTask(
+      FROM_HERE,
+      base::Bind(&HoldPoolReference,
+                 pool(),
+                 make_scoped_refptr(new DeletionHelper(deleted_flag))),
+      TestTimeouts::action_timeout()));
+
+  std::vector<int> completion_sequence = tracker()->WaitUntilTasksComplete(1);
+  ASSERT_EQ(1u, completion_sequence.size());
+  ASSERT_EQ(1, completion_sequence[0]);
+
+  pool()->Shutdown();
+  // Shutdown is asynchronous, so use ResetPool() to block until the pool is
+  // fully destroyed (and thus shut down).
+  ResetPool();
+
+  // Verify that we didn't block until the task was due.
+  ASSERT_LT(base::Time::Now() - posted_at, TestTimeouts::action_timeout());
+
+  // Verify that the deferred task has not only not run, but has also been
+  // destroyed.
+  ASSERT_TRUE(deleted_flag->data);
+}
+
+// Tests that same-named tokens have the same ID.
+TEST_F(SequencedWorkerPoolTest, NamedTokens) {
+  const std::string name1("hello");
+  SequencedWorkerPool::SequenceToken token1 =
+      pool()->GetNamedSequenceToken(name1);
+
+  SequencedWorkerPool::SequenceToken token2 = pool()->GetSequenceToken();
+
+  const std::string name3("goodbye");
+  SequencedWorkerPool::SequenceToken token3 =
+      pool()->GetNamedSequenceToken(name3);
+
+  // All 3 tokens should be different.
+  EXPECT_FALSE(token1.Equals(token2));
+  EXPECT_FALSE(token1.Equals(token3));
+  EXPECT_FALSE(token2.Equals(token3));
+
+  // Requesting the same name again should give the same value.
+  SequencedWorkerPool::SequenceToken token1again =
+      pool()->GetNamedSequenceToken(name1);
+  EXPECT_TRUE(token1.Equals(token1again));
+
+  SequencedWorkerPool::SequenceToken token3again =
+      pool()->GetNamedSequenceToken(name3);
+  EXPECT_TRUE(token3.Equals(token3again));
+}
+
+// Tests that posting a bunch of tasks (many more than the number of worker
+// threads) runs them all.
+TEST_F(SequencedWorkerPoolTest, LotsOfTasks) {
+  pool()->PostWorkerTask(FROM_HERE,
+                         base::Bind(&TestTracker::SlowTask, tracker(), 0));
+
+  const size_t kNumTasks = 20;
+  for (size_t i = 1; i < kNumTasks; i++) {
+    pool()->PostWorkerTask(FROM_HERE,
+                           base::Bind(&TestTracker::FastTask, tracker(), i));
+  }
+
+  std::vector<int> result = tracker()->WaitUntilTasksComplete(kNumTasks);
+  EXPECT_EQ(kNumTasks, result.size());
+}
+
+// Tests that posting a bunch of tasks (many more than the number of
+// worker threads) to two pools simultaneously runs them all twice.
+// This test is meant to shake out any concurrency issues between
+// pools (like histograms).
+TEST_F(SequencedWorkerPoolTest, LotsOfTasksTwoPools) {
+  SequencedWorkerPoolOwner pool1(kNumWorkerThreads, "test1");
+  SequencedWorkerPoolOwner pool2(kNumWorkerThreads, "test2");
+
+  base::Closure slow_task = base::Bind(&TestTracker::SlowTask, tracker(), 0);
+  pool1.pool()->PostWorkerTask(FROM_HERE, slow_task);
+  pool2.pool()->PostWorkerTask(FROM_HERE, slow_task);
+
+  const size_t kNumTasks = 20;
+  for (size_t i = 1; i < kNumTasks; i++) {
+    base::Closure fast_task =
+        base::Bind(&TestTracker::FastTask, tracker(), i);
+    pool1.pool()->PostWorkerTask(FROM_HERE, fast_task);
+    pool2.pool()->PostWorkerTask(FROM_HERE, fast_task);
+  }
+
+  std::vector<int> result =
+      tracker()->WaitUntilTasksComplete(2*kNumTasks);
+  EXPECT_EQ(2 * kNumTasks, result.size());
+
+  pool2.pool()->Shutdown();
+  pool1.pool()->Shutdown();
+}
+
+// Test that tasks with the same sequence token are executed in order but don't
+// affect other tasks.
+TEST_F(SequencedWorkerPoolTest, Sequence) {
+  // Fill all the worker threads except one.
+  const size_t kNumBackgroundTasks = kNumWorkerThreads - 1;
+  ThreadBlocker background_blocker;
+  for (size_t i = 0; i < kNumBackgroundTasks; i++) {
+    pool()->PostWorkerTask(FROM_HERE,
+                           base::Bind(&TestTracker::BlockTask,
+                                      tracker(), i, &background_blocker));
+  }
+  tracker()->WaitUntilTasksBlocked(kNumBackgroundTasks);
+
+  // Create two tasks with the same sequence token, one that will block on the
+  // event, and one which will just complete quickly when it's run. Since there
+  // is one worker thread free, the first task will start and then block, and
+  // the second task should be waiting.
+  ThreadBlocker blocker;
+  SequencedWorkerPool::SequenceToken token1 = pool()->GetSequenceToken();
+  pool()->PostSequencedWorkerTask(
+      token1, FROM_HERE,
+      base::Bind(&TestTracker::BlockTask, tracker(), 100, &blocker));
+  pool()->PostSequencedWorkerTask(
+      token1, FROM_HERE,
+      base::Bind(&TestTracker::FastTask, tracker(), 101));
+  EXPECT_EQ(0u, tracker()->WaitUntilTasksComplete(0).size());
+
+  // Create another two tasks as above with a different token. These will be
+  // blocked since there are no slots to run.
+  SequencedWorkerPool::SequenceToken token2 = pool()->GetSequenceToken();
+  pool()->PostSequencedWorkerTask(
+      token2, FROM_HERE,
+      base::Bind(&TestTracker::FastTask, tracker(), 200));
+  pool()->PostSequencedWorkerTask(
+      token2, FROM_HERE,
+      base::Bind(&TestTracker::FastTask, tracker(), 201));
+  EXPECT_EQ(0u, tracker()->WaitUntilTasksComplete(0).size());
+
+  // Let one background task complete. This should then let both tasks of
+  // token2 run to completion in order. The second task of token1 should still
+  // be blocked.
+  background_blocker.Unblock(1);
+  std::vector<int> result = tracker()->WaitUntilTasksComplete(3);
+  ASSERT_EQ(3u, result.size());
+  EXPECT_EQ(200, result[1]);
+  EXPECT_EQ(201, result[2]);
+
+  // Finish the rest of the background tasks. This should leave some workers
+  // free with the second token1 task still blocked on the first.
+  background_blocker.Unblock(kNumBackgroundTasks - 1);
+  EXPECT_EQ(kNumBackgroundTasks + 2,
+            tracker()->WaitUntilTasksComplete(kNumBackgroundTasks + 2).size());
+
+  // Allow the first task of token1 to complete. This should run the second.
+  blocker.Unblock(1);
+  result = tracker()->WaitUntilTasksComplete(kNumBackgroundTasks + 4);
+  ASSERT_EQ(kNumBackgroundTasks + 4, result.size());
+  EXPECT_EQ(100, result[result.size() - 2]);
+  EXPECT_EQ(101, result[result.size() - 1]);
+}
+
+// Tests that any tasks posted after Shutdown are ignored.
+// Disabled for flakiness.  See http://crbug.com/166451.
+TEST_F(SequencedWorkerPoolTest, DISABLED_IgnoresAfterShutdown) {
+  // Start tasks to take all the threads and block them.
+  EnsureAllWorkersCreated();
+  ThreadBlocker blocker;
+  for (size_t i = 0; i < kNumWorkerThreads; i++) {
+    pool()->PostWorkerTask(FROM_HERE,
+                           base::Bind(&TestTracker::BlockTask,
+                                      tracker(), i, &blocker));
+  }
+  tracker()->WaitUntilTasksBlocked(kNumWorkerThreads);
+
+  SetWillWaitForShutdownCallback(
+      base::Bind(&EnsureTasksToCompleteCountAndUnblock,
+                 scoped_refptr<TestTracker>(tracker()), 0,
+                 &blocker, kNumWorkerThreads));
+
+  // Shutdown the worker pool. This should discard all non-blocking tasks.
+  const int kMaxNewBlockingTasksAfterShutdown = 100;
+  pool()->Shutdown(kMaxNewBlockingTasksAfterShutdown);
+
+  int old_has_work_call_count = has_work_call_count();
+
+  std::vector<int> result =
+      tracker()->WaitUntilTasksComplete(kNumWorkerThreads);
+
+  // The kNumWorkerThread items should have completed, in no particular order.
+  ASSERT_EQ(kNumWorkerThreads, result.size());
+  for (size_t i = 0; i < kNumWorkerThreads; i++) {
+    EXPECT_TRUE(std::find(result.begin(), result.end(), static_cast<int>(i)) !=
+                result.end());
+  }
+
+  // No further tasks, regardless of shutdown mode, should be allowed.
+  EXPECT_FALSE(pool()->PostWorkerTaskWithShutdownBehavior(
+      FROM_HERE,
+      base::Bind(&TestTracker::FastTask, tracker(), 100),
+      SequencedWorkerPool::CONTINUE_ON_SHUTDOWN));
+  EXPECT_FALSE(pool()->PostWorkerTaskWithShutdownBehavior(
+      FROM_HERE,
+      base::Bind(&TestTracker::FastTask, tracker(), 101),
+      SequencedWorkerPool::SKIP_ON_SHUTDOWN));
+  EXPECT_FALSE(pool()->PostWorkerTaskWithShutdownBehavior(
+      FROM_HERE,
+      base::Bind(&TestTracker::FastTask, tracker(), 102),
+      SequencedWorkerPool::BLOCK_SHUTDOWN));
+
+  ASSERT_EQ(old_has_work_call_count, has_work_call_count());
+}
+
+TEST_F(SequencedWorkerPoolTest, AllowsAfterShutdown) {
+  // Test that <n> new blocking tasks are allowed provided they're posted
+  // by a running tasks.
+  EnsureAllWorkersCreated();
+  ThreadBlocker blocker;
+
+  // Start tasks to take all the threads and block them.
+  const int kNumBlockTasks = static_cast<int>(kNumWorkerThreads);
+  for (int i = 0; i < kNumBlockTasks; ++i) {
+    EXPECT_TRUE(pool()->PostWorkerTask(
+        FROM_HERE,
+        base::Bind(&TestTracker::BlockTask, tracker(), i, &blocker)));
+  }
+  tracker()->WaitUntilTasksBlocked(kNumWorkerThreads);
+
+  // Queue up shutdown blocking tasks behind those which will attempt to post
+  // additional tasks when run, PostAdditionalTasks attemtps to post 3
+  // new FastTasks, one for each shutdown_behavior.
+  const int kNumQueuedTasks = static_cast<int>(kNumWorkerThreads);
+  for (int i = 0; i < kNumQueuedTasks; ++i) {
+    EXPECT_TRUE(pool()->PostWorkerTaskWithShutdownBehavior(
+        FROM_HERE,
+        base::Bind(&TestTracker::PostAdditionalTasks, tracker(), i, pool(),
+                   false),
+        SequencedWorkerPool::BLOCK_SHUTDOWN));
+  }
+
+  // Setup to open the floodgates from within Shutdown().
+  SetWillWaitForShutdownCallback(
+      base::Bind(&EnsureTasksToCompleteCountAndUnblock,
+                 scoped_refptr<TestTracker>(tracker()),
+                 0, &blocker, kNumBlockTasks));
+
+  // Allow half of the additional blocking tasks thru.
+  const int kNumNewBlockingTasksToAllow = kNumWorkerThreads / 2;
+  pool()->Shutdown(kNumNewBlockingTasksToAllow);
+
+  // Ensure that the correct number of tasks actually got run.
+  tracker()->WaitUntilTasksComplete(static_cast<size_t>(
+      kNumBlockTasks + kNumQueuedTasks + kNumNewBlockingTasksToAllow));
+
+  // Clean up the task IDs we added and go home.
+  tracker()->ClearCompleteSequence();
+}
+
+// Tests that blocking tasks can still be posted during shutdown, as long as
+// the task is not being posted within the context of a running task.
+TEST_F(SequencedWorkerPoolTest,
+       AllowsBlockingTasksDuringShutdownOutsideOfRunningTask) {
+  EnsureAllWorkersCreated();
+  ThreadBlocker blocker;
+
+  // Start tasks to take all the threads and block them.
+  const int kNumBlockTasks = static_cast<int>(kNumWorkerThreads);
+  for (int i = 0; i < kNumBlockTasks; ++i) {
+    EXPECT_TRUE(pool()->PostWorkerTask(
+        FROM_HERE,
+        base::Bind(&TestTracker::BlockTask, tracker(), i, &blocker)));
+  }
+  tracker()->WaitUntilTasksBlocked(kNumWorkerThreads);
+
+  // Setup to open the floodgates from within Shutdown().
+  SetWillWaitForShutdownCallback(
+      base::Bind(&TestTracker::PostBlockingTaskThenUnblockThreads,
+                 scoped_refptr<TestTracker>(tracker()), pool(), &blocker,
+                 kNumWorkerThreads));
+  pool()->Shutdown(kNumWorkerThreads + 1);
+
+  // Ensure that the correct number of tasks actually got run.
+  tracker()->WaitUntilTasksComplete(static_cast<size_t>(kNumWorkerThreads + 1));
+  tracker()->ClearCompleteSequence();
+}
+
+// Tests that unrun tasks are discarded properly according to their shutdown
+// mode.
+TEST_F(SequencedWorkerPoolTest, DiscardOnShutdown) {
+  // Start tasks to take all the threads and block them.
+  EnsureAllWorkersCreated();
+  ThreadBlocker blocker;
+  for (size_t i = 0; i < kNumWorkerThreads; i++) {
+    pool()->PostWorkerTask(FROM_HERE,
+                           base::Bind(&TestTracker::BlockTask,
+                                      tracker(), i, &blocker));
+  }
+  tracker()->WaitUntilTasksBlocked(kNumWorkerThreads);
+
+  // Create some tasks with different shutdown modes.
+  pool()->PostWorkerTaskWithShutdownBehavior(
+      FROM_HERE,
+      base::Bind(&TestTracker::FastTask, tracker(), 100),
+      SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
+  pool()->PostWorkerTaskWithShutdownBehavior(
+      FROM_HERE,
+      base::Bind(&TestTracker::FastTask, tracker(), 101),
+      SequencedWorkerPool::SKIP_ON_SHUTDOWN);
+  pool()->PostWorkerTaskWithShutdownBehavior(
+      FROM_HERE,
+      base::Bind(&TestTracker::FastTask, tracker(), 102),
+      SequencedWorkerPool::BLOCK_SHUTDOWN);
+
+  // Shutdown the worker pool. This should discard all non-blocking tasks.
+  SetWillWaitForShutdownCallback(
+      base::Bind(&EnsureTasksToCompleteCountAndUnblock,
+                 scoped_refptr<TestTracker>(tracker()), 0,
+                 &blocker, kNumWorkerThreads));
+  pool()->Shutdown();
+
+  std::vector<int> result =
+      tracker()->WaitUntilTasksComplete(kNumWorkerThreads + 1);
+
+  // The kNumWorkerThread items should have completed, plus the BLOCK_SHUTDOWN
+  // one, in no particular order.
+  ASSERT_EQ(kNumWorkerThreads + 1, result.size());
+  for (size_t i = 0; i < kNumWorkerThreads; i++) {
+    EXPECT_TRUE(std::find(result.begin(), result.end(), static_cast<int>(i)) !=
+                result.end());
+  }
+  EXPECT_TRUE(std::find(result.begin(), result.end(), 102) != result.end());
+}
+
+// Tests that CONTINUE_ON_SHUTDOWN tasks don't block shutdown.
+TEST_F(SequencedWorkerPoolTest, ContinueOnShutdown) {
+  scoped_refptr<TaskRunner> runner(pool()->GetTaskRunnerWithShutdownBehavior(
+      SequencedWorkerPool::CONTINUE_ON_SHUTDOWN));
+  scoped_refptr<SequencedTaskRunner> sequenced_runner(
+      pool()->GetSequencedTaskRunnerWithShutdownBehavior(
+          pool()->GetSequenceToken(),
+          SequencedWorkerPool::CONTINUE_ON_SHUTDOWN));
+  EnsureAllWorkersCreated();
+  ThreadBlocker blocker;
+  pool()->PostWorkerTaskWithShutdownBehavior(
+      FROM_HERE,
+      base::Bind(&TestTracker::BlockTask,
+                 tracker(), 0, &blocker),
+      SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
+  runner->PostTask(
+      FROM_HERE,
+      base::Bind(&TestTracker::BlockTask,
+                 tracker(), 1, &blocker));
+  sequenced_runner->PostTask(
+      FROM_HERE,
+      base::Bind(&TestTracker::BlockTask,
+                 tracker(), 2, &blocker));
+
+  tracker()->WaitUntilTasksBlocked(3);
+
+  // This should not block. If this test hangs, it means it failed.
+  pool()->Shutdown();
+
+  // The task should not have completed yet.
+  EXPECT_EQ(0u, tracker()->WaitUntilTasksComplete(0).size());
+
+  // Posting more tasks should fail.
+  EXPECT_FALSE(pool()->PostWorkerTaskWithShutdownBehavior(
+      FROM_HERE, base::Bind(&TestTracker::FastTask, tracker(), 0),
+      SequencedWorkerPool::CONTINUE_ON_SHUTDOWN));
+  EXPECT_FALSE(runner->PostTask(
+      FROM_HERE, base::Bind(&TestTracker::FastTask, tracker(), 0)));
+  EXPECT_FALSE(sequenced_runner->PostTask(
+      FROM_HERE, base::Bind(&TestTracker::FastTask, tracker(), 0)));
+
+  // Continue the background thread and make sure the tasks can complete.
+  blocker.Unblock(3);
+  std::vector<int> result = tracker()->WaitUntilTasksComplete(3);
+  EXPECT_EQ(3u, result.size());
+}
+
+// Tests that SKIP_ON_SHUTDOWN tasks that have been started block Shutdown
+// until they stop, but tasks not yet started do not.
+TEST_F(SequencedWorkerPoolTest, SkipOnShutdown) {
+  // Start tasks to take all the threads and block them.
+  EnsureAllWorkersCreated();
+  ThreadBlocker blocker;
+
+  // Now block all the threads with SKIP_ON_SHUTDOWN. Shutdown() should not
+  // return until these tasks have completed.
+  for (size_t i = 0; i < kNumWorkerThreads; i++) {
+    pool()->PostWorkerTaskWithShutdownBehavior(
+        FROM_HERE,
+        base::Bind(&TestTracker::BlockTask, tracker(), i, &blocker),
+        SequencedWorkerPool::SKIP_ON_SHUTDOWN);
+  }
+  tracker()->WaitUntilTasksBlocked(kNumWorkerThreads);
+
+  // Now post an additional task as SKIP_ON_SHUTDOWN, which should not be
+  // executed once Shutdown() has been called.
+  pool()->PostWorkerTaskWithShutdownBehavior(
+      FROM_HERE,
+      base::Bind(&TestTracker::BlockTask,
+                 tracker(), 0, &blocker),
+      SequencedWorkerPool::SKIP_ON_SHUTDOWN);
+
+  // This callback will only be invoked if SKIP_ON_SHUTDOWN tasks that have
+  // been started block shutdown.
+  SetWillWaitForShutdownCallback(
+      base::Bind(&EnsureTasksToCompleteCountAndUnblock,
+                 scoped_refptr<TestTracker>(tracker()), 0,
+                 &blocker, kNumWorkerThreads));
+
+  // No tasks should have completed yet.
+  EXPECT_EQ(0u, tracker()->WaitUntilTasksComplete(0).size());
+
+  // This should not block. If this test hangs, it means it failed.
+  pool()->Shutdown();
+
+  // Shutdown should not return until all of the tasks have completed.
+  std::vector<int> result =
+      tracker()->WaitUntilTasksComplete(kNumWorkerThreads);
+
+  // Only tasks marked SKIP_ON_SHUTDOWN that were already started should be
+  // allowed to complete. No additional non-blocking tasks should have been
+  // started.
+  ASSERT_EQ(kNumWorkerThreads, result.size());
+  for (size_t i = 0; i < kNumWorkerThreads; i++) {
+    EXPECT_TRUE(std::find(result.begin(), result.end(), static_cast<int>(i)) !=
+                result.end());
+  }
+}
+
+// Ensure all worker threads are created, and then trigger a spurious
+// work signal. This shouldn't cause any other work signals to be
+// triggered. This is a regression test for http://crbug.com/117469.
+TEST_F(SequencedWorkerPoolTest, SpuriousWorkSignal) {
+  EnsureAllWorkersCreated();
+  int old_has_work_call_count = has_work_call_count();
+  pool()->SignalHasWorkForTesting();
+  // This is inherently racy, but can only produce false positives.
+  base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
+  EXPECT_EQ(old_has_work_call_count + 1, has_work_call_count());
+}
+
+void IsRunningOnCurrentThreadTask(
+    SequencedWorkerPool::SequenceToken test_positive_token,
+    SequencedWorkerPool::SequenceToken test_negative_token,
+    SequencedWorkerPool* pool,
+    SequencedWorkerPool* unused_pool) {
+  EXPECT_TRUE(pool->RunsTasksOnCurrentThread());
+  EXPECT_TRUE(pool->IsRunningSequenceOnCurrentThread(test_positive_token));
+  EXPECT_FALSE(pool->IsRunningSequenceOnCurrentThread(test_negative_token));
+  EXPECT_FALSE(unused_pool->RunsTasksOnCurrentThread());
+  EXPECT_FALSE(
+      unused_pool->IsRunningSequenceOnCurrentThread(test_positive_token));
+  EXPECT_FALSE(
+      unused_pool->IsRunningSequenceOnCurrentThread(test_negative_token));
+}
+
+// Verify correctness of the IsRunningSequenceOnCurrentThread method.
+TEST_F(SequencedWorkerPoolTest, IsRunningOnCurrentThread) {
+  SequencedWorkerPool::SequenceToken token1 = pool()->GetSequenceToken();
+  SequencedWorkerPool::SequenceToken token2 = pool()->GetSequenceToken();
+  SequencedWorkerPool::SequenceToken unsequenced_token;
+
+  scoped_refptr<SequencedWorkerPool> unused_pool =
+      new SequencedWorkerPool(2, "unused_pool");
+
+  EXPECT_FALSE(pool()->RunsTasksOnCurrentThread());
+  EXPECT_FALSE(pool()->IsRunningSequenceOnCurrentThread(token1));
+  EXPECT_FALSE(pool()->IsRunningSequenceOnCurrentThread(token2));
+  EXPECT_FALSE(pool()->IsRunningSequenceOnCurrentThread(unsequenced_token));
+  EXPECT_FALSE(unused_pool->RunsTasksOnCurrentThread());
+  EXPECT_FALSE(unused_pool->IsRunningSequenceOnCurrentThread(token1));
+  EXPECT_FALSE(unused_pool->IsRunningSequenceOnCurrentThread(token2));
+  EXPECT_FALSE(
+      unused_pool->IsRunningSequenceOnCurrentThread(unsequenced_token));
+
+  pool()->PostSequencedWorkerTask(
+      token1, FROM_HERE,
+      base::Bind(&IsRunningOnCurrentThreadTask,
+                 token1, token2, pool(), unused_pool));
+  pool()->PostSequencedWorkerTask(
+      token2, FROM_HERE,
+      base::Bind(&IsRunningOnCurrentThreadTask,
+                 token2, unsequenced_token, pool(), unused_pool));
+  pool()->PostWorkerTask(
+      FROM_HERE,
+      base::Bind(&IsRunningOnCurrentThreadTask,
+                 unsequenced_token, token1, pool(), unused_pool));
+  pool()->Shutdown();
+  unused_pool->Shutdown();
+}
+
+// Checks that tasks are destroyed in the right context during shutdown. If a
+// task is destroyed while SequencedWorkerPool's global lock is held,
+// SequencedWorkerPool might deadlock.
+TEST_F(SequencedWorkerPoolTest, AvoidsDeadlockOnShutdown) {
+  for (int i = 0; i < 4; ++i) {
+    scoped_refptr<DestructionDeadlockChecker> checker(
+        new DestructionDeadlockChecker(pool()));
+    tracker()->PostRepostingTask(pool(), checker);
+  }
+
+  // Shutting down the pool should destroy the DestructionDeadlockCheckers,
+  // which in turn should not deadlock in their destructors.
+  pool()->Shutdown();
+}
+
+// Similar to the test AvoidsDeadlockOnShutdown, but there are now also
+// sequenced, blocking tasks in the queue during shutdown.
+TEST_F(SequencedWorkerPoolTest,
+       AvoidsDeadlockOnShutdownWithSequencedBlockingTasks) {
+  const std::string sequence_token_name("name");
+  for (int i = 0; i < 4; ++i) {
+    scoped_refptr<DestructionDeadlockChecker> checker(
+        new DestructionDeadlockChecker(pool()));
+    tracker()->PostRepostingTask(pool(), checker);
+
+    SequencedWorkerPool::SequenceToken token1 =
+        pool()->GetNamedSequenceToken(sequence_token_name);
+    tracker()->PostRepostingBlockingTask(pool(), token1);
+  }
+
+  // Shutting down the pool should destroy the DestructionDeadlockCheckers,
+  // which in turn should not deadlock in their destructors.
+  pool()->Shutdown();
+}
+
+// Verify that FlushForTesting works as intended.
+TEST_F(SequencedWorkerPoolTest, FlushForTesting) {
+  // Should be fine to call on a new instance.
+  pool()->FlushForTesting();
+
+  // Queue up a bunch of work, including  a long delayed task and
+  // a task that produces additional tasks as an artifact.
+  pool()->PostDelayedWorkerTask(
+      FROM_HERE,
+      base::Bind(&TestTracker::FastTask, tracker(), 0),
+      TimeDelta::FromMinutes(5));
+  pool()->PostWorkerTask(FROM_HERE,
+                         base::Bind(&TestTracker::SlowTask, tracker(), 0));
+  const size_t kNumFastTasks = 20;
+  for (size_t i = 0; i < kNumFastTasks; i++) {
+    pool()->PostWorkerTask(FROM_HERE,
+                           base::Bind(&TestTracker::FastTask, tracker(), 0));
+  }
+  pool()->PostWorkerTask(
+      FROM_HERE,
+      base::Bind(&TestTracker::PostAdditionalTasks, tracker(), 0, pool(),
+                 true));
+
+  // We expect all except the delayed task to have been run. We verify all
+  // closures have been deleted by looking at the refcount of the
+  // tracker.
+  EXPECT_FALSE(tracker()->HasOneRef());
+  pool()->FlushForTesting();
+  EXPECT_TRUE(tracker()->HasOneRef());
+  EXPECT_EQ(1 + kNumFastTasks + 1 + 3, tracker()->GetTasksCompletedCount());
+
+  // Should be fine to call on an idle instance with all threads created, and
+  // spamming the method shouldn't deadlock or confuse the class.
+  pool()->FlushForTesting();
+  pool()->FlushForTesting();
+
+  // Should be fine to call after shutdown too.
+  pool()->Shutdown();
+  pool()->FlushForTesting();
+}
+
+TEST(SequencedWorkerPoolRefPtrTest, ShutsDownCleanWithContinueOnShutdown) {
+  MessageLoop loop;
+  scoped_refptr<SequencedWorkerPool> pool(new SequencedWorkerPool(3, "Pool"));
+  scoped_refptr<SequencedTaskRunner> task_runner =
+      pool->GetSequencedTaskRunnerWithShutdownBehavior(
+          pool->GetSequenceToken(),
+          base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
+
+  // Upon test exit, should shut down without hanging.
+  pool->Shutdown();
+}
+
+class SequencedWorkerPoolTaskRunnerTestDelegate {
+ public:
+  SequencedWorkerPoolTaskRunnerTestDelegate() {}
+
+  ~SequencedWorkerPoolTaskRunnerTestDelegate() {}
+
+  void StartTaskRunner() {
+    pool_owner_.reset(
+        new SequencedWorkerPoolOwner(10, "SequencedWorkerPoolTaskRunnerTest"));
+  }
+
+  scoped_refptr<SequencedWorkerPool> GetTaskRunner() {
+    return pool_owner_->pool();
+  }
+
+  void StopTaskRunner() {
+    // Make sure all tasks are run before shutting down. Delayed tasks are
+    // not run, they're simply deleted.
+    pool_owner_->pool()->FlushForTesting();
+    pool_owner_->pool()->Shutdown();
+    // Don't reset |pool_owner_| here, as the test may still hold a
+    // reference to the pool.
+  }
+
+ private:
+  MessageLoop message_loop_;
+  scoped_ptr<SequencedWorkerPoolOwner> pool_owner_;
+};
+
+INSTANTIATE_TYPED_TEST_CASE_P(
+    SequencedWorkerPool, TaskRunnerTest,
+    SequencedWorkerPoolTaskRunnerTestDelegate);
+
+class SequencedWorkerPoolTaskRunnerWithShutdownBehaviorTestDelegate {
+ public:
+  SequencedWorkerPoolTaskRunnerWithShutdownBehaviorTestDelegate() {}
+
+  ~SequencedWorkerPoolTaskRunnerWithShutdownBehaviorTestDelegate() {
+  }
+
+  void StartTaskRunner() {
+    pool_owner_.reset(
+        new SequencedWorkerPoolOwner(10, "SequencedWorkerPoolTaskRunnerTest"));
+    task_runner_ = pool_owner_->pool()->GetTaskRunnerWithShutdownBehavior(
+        SequencedWorkerPool::BLOCK_SHUTDOWN);
+  }
+
+  scoped_refptr<TaskRunner> GetTaskRunner() {
+    return task_runner_;
+  }
+
+  void StopTaskRunner() {
+    // Make sure all tasks are run before shutting down. Delayed tasks are
+    // not run, they're simply deleted.
+    pool_owner_->pool()->FlushForTesting();
+    pool_owner_->pool()->Shutdown();
+    // Don't reset |pool_owner_| here, as the test may still hold a
+    // reference to the pool.
+  }
+
+ private:
+  MessageLoop message_loop_;
+  scoped_ptr<SequencedWorkerPoolOwner> pool_owner_;
+  scoped_refptr<TaskRunner> task_runner_;
+};
+
+INSTANTIATE_TYPED_TEST_CASE_P(
+    SequencedWorkerPoolTaskRunner, TaskRunnerTest,
+    SequencedWorkerPoolTaskRunnerWithShutdownBehaviorTestDelegate);
+
+class SequencedWorkerPoolSequencedTaskRunnerTestDelegate {
+ public:
+  SequencedWorkerPoolSequencedTaskRunnerTestDelegate() {}
+
+  ~SequencedWorkerPoolSequencedTaskRunnerTestDelegate() {
+  }
+
+  void StartTaskRunner() {
+    pool_owner_.reset(new SequencedWorkerPoolOwner(
+        10, "SequencedWorkerPoolSequencedTaskRunnerTest"));
+    task_runner_ = pool_owner_->pool()->GetSequencedTaskRunner(
+        pool_owner_->pool()->GetSequenceToken());
+  }
+
+  scoped_refptr<SequencedTaskRunner> GetTaskRunner() {
+    return task_runner_;
+  }
+
+  void StopTaskRunner() {
+    // Make sure all tasks are run before shutting down. Delayed tasks are
+    // not run, they're simply deleted.
+    pool_owner_->pool()->FlushForTesting();
+    pool_owner_->pool()->Shutdown();
+    // Don't reset |pool_owner_| here, as the test may still hold a
+    // reference to the pool.
+  }
+
+ private:
+  MessageLoop message_loop_;
+  scoped_ptr<SequencedWorkerPoolOwner> pool_owner_;
+  scoped_refptr<SequencedTaskRunner> task_runner_;
+};
+
+INSTANTIATE_TYPED_TEST_CASE_P(
+    SequencedWorkerPoolSequencedTaskRunner, TaskRunnerTest,
+    SequencedWorkerPoolSequencedTaskRunnerTestDelegate);
+
+INSTANTIATE_TYPED_TEST_CASE_P(
+    SequencedWorkerPoolSequencedTaskRunner, SequencedTaskRunnerTest,
+    SequencedWorkerPoolSequencedTaskRunnerTestDelegate);
+
+}  // namespace
+
+}  // namespace base
diff --git a/base/threading/simple_thread.cc b/base/threading/simple_thread.cc
new file mode 100644
index 0000000..7059cea
--- /dev/null
+++ b/base/threading/simple_thread.cc
@@ -0,0 +1,165 @@
+// Copyright (c) 2010 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/threading/simple_thread.h"
+
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace base {
+
+SimpleThread::SimpleThread(const std::string& name_prefix)
+    : name_prefix_(name_prefix), name_(name_prefix),
+      thread_(), event_(true, false), tid_(0), joined_(false) {
+}
+
+SimpleThread::SimpleThread(const std::string& name_prefix,
+                           const Options& options)
+    : name_prefix_(name_prefix), name_(name_prefix), options_(options),
+      thread_(), event_(true, false), tid_(0), joined_(false) {
+}
+
+SimpleThread::~SimpleThread() {
+  DCHECK(HasBeenStarted()) << "SimpleThread was never started.";
+  DCHECK(HasBeenJoined()) << "SimpleThread destroyed without being Join()ed.";
+}
+
+void SimpleThread::Start() {
+  DCHECK(!HasBeenStarted()) << "Tried to Start a thread multiple times.";
+  bool success;
+  if (options_.priority() == ThreadPriority::NORMAL) {
+    success = PlatformThread::Create(options_.stack_size(), this, &thread_);
+  } else {
+    success = PlatformThread::CreateWithPriority(options_.stack_size(), this,
+                                                 &thread_, options_.priority());
+  }
+  DCHECK(success);
+  base::ThreadRestrictions::ScopedAllowWait allow_wait;
+  event_.Wait();  // Wait for the thread to complete initialization.
+}
+
+void SimpleThread::Join() {
+  DCHECK(HasBeenStarted()) << "Tried to Join a never-started thread.";
+  DCHECK(!HasBeenJoined()) << "Tried to Join a thread multiple times.";
+  PlatformThread::Join(thread_);
+  joined_ = true;
+}
+
+bool SimpleThread::HasBeenStarted() {
+  base::ThreadRestrictions::ScopedAllowWait allow_wait;
+  return event_.IsSignaled();
+}
+
+void SimpleThread::ThreadMain() {
+  tid_ = PlatformThread::CurrentId();
+  // Construct our full name of the form "name_prefix_/TID".
+  name_.push_back('/');
+  name_.append(IntToString(tid_));
+  PlatformThread::SetName(name_);
+
+  // We've initialized our new thread, signal that we're done to Start().
+  event_.Signal();
+
+  Run();
+}
+
+DelegateSimpleThread::DelegateSimpleThread(Delegate* delegate,
+                                           const std::string& name_prefix)
+    : SimpleThread(name_prefix),
+      delegate_(delegate) {
+}
+
+DelegateSimpleThread::DelegateSimpleThread(Delegate* delegate,
+                                           const std::string& name_prefix,
+                                           const Options& options)
+    : SimpleThread(name_prefix, options),
+      delegate_(delegate) {
+}
+
+DelegateSimpleThread::~DelegateSimpleThread() {
+}
+
+void DelegateSimpleThread::Run() {
+  DCHECK(delegate_) << "Tried to call Run without a delegate (called twice?)";
+  delegate_->Run();
+  delegate_ = NULL;
+}
+
+DelegateSimpleThreadPool::DelegateSimpleThreadPool(
+    const std::string& name_prefix,
+    int num_threads)
+    : name_prefix_(name_prefix),
+      num_threads_(num_threads),
+      dry_(true, false) {
+}
+
+DelegateSimpleThreadPool::~DelegateSimpleThreadPool() {
+  DCHECK(threads_.empty());
+  DCHECK(delegates_.empty());
+  DCHECK(!dry_.IsSignaled());
+}
+
+void DelegateSimpleThreadPool::Start() {
+  DCHECK(threads_.empty()) << "Start() called with outstanding threads.";
+  for (int i = 0; i < num_threads_; ++i) {
+    DelegateSimpleThread* thread = new DelegateSimpleThread(this, name_prefix_);
+    thread->Start();
+    threads_.push_back(thread);
+  }
+}
+
+void DelegateSimpleThreadPool::JoinAll() {
+  DCHECK(!threads_.empty()) << "JoinAll() called with no outstanding threads.";
+
+  // Tell all our threads to quit their worker loop.
+  AddWork(NULL, num_threads_);
+
+  // Join and destroy all the worker threads.
+  for (int i = 0; i < num_threads_; ++i) {
+    threads_[i]->Join();
+    delete threads_[i];
+  }
+  threads_.clear();
+  DCHECK(delegates_.empty());
+}
+
+void DelegateSimpleThreadPool::AddWork(Delegate* delegate, int repeat_count) {
+  AutoLock locked(lock_);
+  for (int i = 0; i < repeat_count; ++i)
+    delegates_.push(delegate);
+  // If we were empty, signal that we have work now.
+  if (!dry_.IsSignaled())
+    dry_.Signal();
+}
+
+void DelegateSimpleThreadPool::Run() {
+  Delegate* work = NULL;
+
+  while (true) {
+    dry_.Wait();
+    {
+      AutoLock locked(lock_);
+      if (!dry_.IsSignaled())
+        continue;
+
+      DCHECK(!delegates_.empty());
+      work = delegates_.front();
+      delegates_.pop();
+
+      // Signal to any other threads that we're currently out of work.
+      if (delegates_.empty())
+        dry_.Reset();
+    }
+
+    // A NULL delegate pointer signals us to quit.
+    if (!work)
+      break;
+
+    work->Run();
+  }
+}
+
+}  // namespace base
diff --git a/base/threading/simple_thread.h b/base/threading/simple_thread.h
new file mode 100644
index 0000000..36548d3
--- /dev/null
+++ b/base/threading/simple_thread.h
@@ -0,0 +1,196 @@
+// Copyright (c) 2011 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.
+
+// WARNING: You should probably be using Thread (thread.h) instead.  Thread is
+//          Chrome's message-loop based Thread abstraction, and if you are a
+//          thread running in the browser, there will likely be assumptions
+//          that your thread will have an associated message loop.
+//
+// This is a simple thread interface that backs to a native operating system
+// thread.  You should use this only when you want a thread that does not have
+// an associated MessageLoop.  Unittesting is the best example of this.
+//
+// The simplest interface to use is DelegateSimpleThread, which will create
+// a new thread, and execute the Delegate's virtual Run() in this new thread
+// until it has completed, exiting the thread.
+//
+// NOTE: You *MUST* call Join on the thread to clean up the underlying thread
+// resources.  You are also responsible for destructing the SimpleThread object.
+// It is invalid to destroy a SimpleThread while it is running, or without
+// Start() having been called (and a thread never created).  The Delegate
+// object should live as long as a DelegateSimpleThread.
+//
+// Thread Safety: A SimpleThread is not completely thread safe.  It is safe to
+// access it from the creating thread or from the newly created thread.  This
+// implies that the creator thread should be the thread that calls Join.
+//
+// Example:
+//   class MyThreadRunner : public DelegateSimpleThread::Delegate { ... };
+//   MyThreadRunner runner;
+//   DelegateSimpleThread thread(&runner, "good_name_here");
+//   thread.Start();
+//   // Start will return after the Thread has been successfully started and
+//   // initialized.  The newly created thread will invoke runner->Run(), and
+//   // run until it returns.
+//   thread.Join();  // Wait until the thread has exited.  You *MUST* Join!
+//   // The SimpleThread object is still valid, however you may not call Join
+//   // or Start again.
+
+#ifndef BASE_THREADING_SIMPLE_THREAD_H_
+#define BASE_THREADING_SIMPLE_THREAD_H_
+
+#include <string>
+#include <queue>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/threading/platform_thread.h"
+#include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event.h"
+
+namespace base {
+
+// This is the base SimpleThread.  You can derive from it and implement the
+// virtual Run method, or you can use the DelegateSimpleThread interface.
+class BASE_EXPORT SimpleThread : public PlatformThread::Delegate {
+ public:
+  class BASE_EXPORT Options {
+   public:
+    Options() : stack_size_(0), priority_(ThreadPriority::NORMAL) { }
+    ~Options() { }
+
+    // We use the standard compiler-supplied copy constructor.
+
+    // A custom stack size, or 0 for the system default.
+    void set_stack_size(size_t size) { stack_size_ = size; }
+    size_t stack_size() const { return stack_size_; }
+
+    // A custom thread priority.
+    void set_priority(ThreadPriority priority) { priority_ = priority; }
+    ThreadPriority priority() const { return priority_; }
+   private:
+    size_t stack_size_;
+    ThreadPriority priority_;
+  };
+
+  // Create a SimpleThread.  |options| should be used to manage any specific
+  // configuration involving the thread creation and management.
+  // Every thread has a name, in the form of |name_prefix|/TID, for example
+  // "my_thread/321".  The thread will not be created until Start() is called.
+  explicit SimpleThread(const std::string& name_prefix);
+  SimpleThread(const std::string& name_prefix, const Options& options);
+
+  ~SimpleThread() override;
+
+  virtual void Start();
+  virtual void Join();
+
+  // Subclasses should override the Run method.
+  virtual void Run() = 0;
+
+  // Return the thread name prefix, or "unnamed" if none was supplied.
+  std::string name_prefix() { return name_prefix_; }
+
+  // Return the completed name including TID, only valid after Start().
+  std::string name() { return name_; }
+
+  // Return the thread id, only valid after Start().
+  PlatformThreadId tid() { return tid_; }
+
+  // Return True if Start() has ever been called.
+  bool HasBeenStarted();
+
+  // Return True if Join() has evern been called.
+  bool HasBeenJoined() { return joined_; }
+
+  // Overridden from PlatformThread::Delegate:
+  void ThreadMain() override;
+
+  // Only set priorities with a careful understanding of the consequences.
+  // This is meant for very limited use cases.
+  void SetThreadPriority(ThreadPriority priority) {
+    PlatformThread::SetThreadPriority(thread_, priority);
+  }
+
+ private:
+  const std::string name_prefix_;
+  std::string name_;
+  const Options options_;
+  PlatformThreadHandle thread_;  // PlatformThread handle, invalid after Join!
+  WaitableEvent event_;          // Signaled if Start() was ever called.
+  PlatformThreadId tid_;         // The backing thread's id.
+  bool joined_;                  // True if Join has been called.
+};
+
+class BASE_EXPORT DelegateSimpleThread : public SimpleThread {
+ public:
+  class BASE_EXPORT Delegate {
+   public:
+    Delegate() { }
+    virtual ~Delegate() { }
+    virtual void Run() = 0;
+  };
+
+  DelegateSimpleThread(Delegate* delegate,
+                       const std::string& name_prefix);
+  DelegateSimpleThread(Delegate* delegate,
+                       const std::string& name_prefix,
+                       const Options& options);
+
+  ~DelegateSimpleThread() override;
+  void Run() override;
+
+ private:
+  Delegate* delegate_;
+};
+
+// DelegateSimpleThreadPool allows you to start up a fixed number of threads,
+// and then add jobs which will be dispatched to the threads.  This is
+// convenient when you have a lot of small work that you want done
+// multi-threaded, but don't want to spawn a thread for each small bit of work.
+//
+// You just call AddWork() to add a delegate to the list of work to be done.
+// JoinAll() will make sure that all outstanding work is processed, and wait
+// for everything to finish.  You can reuse a pool, so you can call Start()
+// again after you've called JoinAll().
+class BASE_EXPORT DelegateSimpleThreadPool
+    : public DelegateSimpleThread::Delegate {
+ public:
+  typedef DelegateSimpleThread::Delegate Delegate;
+
+  DelegateSimpleThreadPool(const std::string& name_prefix, int num_threads);
+  ~DelegateSimpleThreadPool() override;
+
+  // Start up all of the underlying threads, and start processing work if we
+  // have any.
+  void Start();
+
+  // Make sure all outstanding work is finished, and wait for and destroy all
+  // of the underlying threads in the pool.
+  void JoinAll();
+
+  // It is safe to AddWork() any time, before or after Start().
+  // Delegate* should always be a valid pointer, NULL is reserved internally.
+  void AddWork(Delegate* work, int repeat_count);
+  void AddWork(Delegate* work) {
+    AddWork(work, 1);
+  }
+
+  // We implement the Delegate interface, for running our internal threads.
+  void Run() override;
+
+ private:
+  const std::string name_prefix_;
+  int num_threads_;
+  std::vector<DelegateSimpleThread*> threads_;
+  std::queue<Delegate*> delegates_;
+  base::Lock lock_;            // Locks delegates_
+  WaitableEvent dry_;    // Not signaled when there is no work to do.
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_SIMPLE_THREAD_H_
diff --git a/base/threading/simple_thread_unittest.cc b/base/threading/simple_thread_unittest.cc
new file mode 100644
index 0000000..7229d36
--- /dev/null
+++ b/base/threading/simple_thread_unittest.cc
@@ -0,0 +1,166 @@
+// Copyright (c) 2012 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/atomic_sequence_num.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/simple_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+class SetIntRunner : public DelegateSimpleThread::Delegate {
+ public:
+  SetIntRunner(int* ptr, int val) : ptr_(ptr), val_(val) { }
+  ~SetIntRunner() override {}
+
+  void Run() override { *ptr_ = val_; }
+
+ private:
+  int* ptr_;
+  int val_;
+};
+
+class WaitEventRunner : public DelegateSimpleThread::Delegate {
+ public:
+  explicit WaitEventRunner(WaitableEvent* event) : event_(event) { }
+  ~WaitEventRunner() override {}
+
+  void Run() override {
+    EXPECT_FALSE(event_->IsSignaled());
+    event_->Signal();
+    EXPECT_TRUE(event_->IsSignaled());
+  }
+ private:
+  WaitableEvent* event_;
+};
+
+class SeqRunner : public DelegateSimpleThread::Delegate {
+ public:
+  explicit SeqRunner(AtomicSequenceNumber* seq) : seq_(seq) { }
+  void Run() override { seq_->GetNext(); }
+
+ private:
+  AtomicSequenceNumber* seq_;
+};
+
+// We count up on a sequence number, firing on the event when we've hit our
+// expected amount, otherwise we wait on the event.  This will ensure that we
+// have all threads outstanding until we hit our expected thread pool size.
+class VerifyPoolRunner : public DelegateSimpleThread::Delegate {
+ public:
+  VerifyPoolRunner(AtomicSequenceNumber* seq,
+                   int total, WaitableEvent* event)
+      : seq_(seq), total_(total), event_(event) { }
+
+  void Run() override {
+    if (seq_->GetNext() == total_) {
+      event_->Signal();
+    } else {
+      event_->Wait();
+    }
+  }
+
+ private:
+  AtomicSequenceNumber* seq_;
+  int total_;
+  WaitableEvent* event_;
+};
+
+}  // namespace
+
+TEST(SimpleThreadTest, CreateAndJoin) {
+  int stack_int = 0;
+
+  SetIntRunner runner(&stack_int, 7);
+  EXPECT_EQ(0, stack_int);
+
+  DelegateSimpleThread thread(&runner, "int_setter");
+  EXPECT_FALSE(thread.HasBeenStarted());
+  EXPECT_FALSE(thread.HasBeenJoined());
+  EXPECT_EQ(0, stack_int);
+
+  thread.Start();
+  EXPECT_TRUE(thread.HasBeenStarted());
+  EXPECT_FALSE(thread.HasBeenJoined());
+
+  thread.Join();
+  EXPECT_TRUE(thread.HasBeenStarted());
+  EXPECT_TRUE(thread.HasBeenJoined());
+  EXPECT_EQ(7, stack_int);
+}
+
+TEST(SimpleThreadTest, WaitForEvent) {
+  // Create a thread, and wait for it to signal us.
+  WaitableEvent event(true, false);
+
+  WaitEventRunner runner(&event);
+  DelegateSimpleThread thread(&runner, "event_waiter");
+
+  EXPECT_FALSE(event.IsSignaled());
+  thread.Start();
+  event.Wait();
+  EXPECT_TRUE(event.IsSignaled());
+  thread.Join();
+}
+
+TEST(SimpleThreadTest, NamedWithOptions) {
+  WaitableEvent event(true, false);
+
+  WaitEventRunner runner(&event);
+  SimpleThread::Options options;
+  DelegateSimpleThread thread(&runner, "event_waiter", options);
+  EXPECT_EQ(thread.name_prefix(), "event_waiter");
+  EXPECT_FALSE(event.IsSignaled());
+
+  thread.Start();
+  EXPECT_EQ(thread.name_prefix(), "event_waiter");
+  EXPECT_EQ(thread.name(),
+            std::string("event_waiter/") + IntToString(thread.tid()));
+  event.Wait();
+
+  EXPECT_TRUE(event.IsSignaled());
+  thread.Join();
+
+  // We keep the name and tid, even after the thread is gone.
+  EXPECT_EQ(thread.name_prefix(), "event_waiter");
+  EXPECT_EQ(thread.name(),
+            std::string("event_waiter/") + IntToString(thread.tid()));
+}
+
+TEST(SimpleThreadTest, ThreadPool) {
+  AtomicSequenceNumber seq;
+  SeqRunner runner(&seq);
+  DelegateSimpleThreadPool pool("seq_runner", 10);
+
+  // Add work before we're running.
+  pool.AddWork(&runner, 300);
+
+  EXPECT_EQ(seq.GetNext(), 0);
+  pool.Start();
+
+  // Add work while we're running.
+  pool.AddWork(&runner, 300);
+
+  pool.JoinAll();
+
+  EXPECT_EQ(seq.GetNext(), 601);
+
+  // We can reuse our pool.  Verify that all 10 threads can actually run in
+  // parallel, so this test will only pass if there are actually 10 threads.
+  AtomicSequenceNumber seq2;
+  WaitableEvent event(true, false);
+  // Changing 9 to 10, for example, would cause us JoinAll() to never return.
+  VerifyPoolRunner verifier(&seq2, 9, &event);
+  pool.Start();
+
+  pool.AddWork(&verifier, 10);
+
+  pool.JoinAll();
+  EXPECT_EQ(seq2.GetNext(), 10);
+}
+
+}  // namespace base
diff --git a/base/threading/thread.cc b/base/threading/thread.cc
new file mode 100644
index 0000000..63b07cb
--- /dev/null
+++ b/base/threading/thread.cc
@@ -0,0 +1,273 @@
+// Copyright (c) 2012 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/threading/thread.h"
+
+#include "base/bind.h"
+#include "base/lazy_instance.h"
+#include "base/location.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "base/threading/thread_id_name_manager.h"
+#include "base/threading/thread_local.h"
+#include "base/threading/thread_restrictions.h"
+
+#if defined(OS_WIN)
+#include "base/win/scoped_com_initializer.h"
+#endif
+
+namespace base {
+
+namespace {
+
+// We use this thread-local variable to record whether or not a thread exited
+// because its Stop method was called.  This allows us to catch cases where
+// MessageLoop::QuitWhenIdle() is called directly, which is unexpected when
+// using a Thread to setup and run a MessageLoop.
+base::LazyInstance<base::ThreadLocalBoolean> lazy_tls_bool =
+    LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+// This is used to trigger the message loop to exit.
+void ThreadQuitHelper() {
+  MessageLoop::current()->QuitWhenIdle();
+  Thread::SetThreadWasQuitProperly(true);
+}
+
+Thread::Options::Options()
+    : message_loop_type(MessageLoop::TYPE_DEFAULT),
+      timer_slack(TIMER_SLACK_NONE),
+      stack_size(0),
+      priority(ThreadPriority::NORMAL) {
+}
+
+Thread::Options::Options(MessageLoop::Type type,
+                         size_t size)
+    : message_loop_type(type),
+      timer_slack(TIMER_SLACK_NONE),
+      stack_size(size),
+      priority(ThreadPriority::NORMAL) {
+}
+
+Thread::Options::~Options() {
+}
+
+Thread::Thread(const std::string& name)
+    :
+#if defined(OS_WIN)
+      com_status_(NONE),
+#endif
+      stopping_(false),
+      running_(false),
+      thread_(0),
+      message_loop_(nullptr),
+      message_loop_timer_slack_(TIMER_SLACK_NONE),
+      name_(name) {
+}
+
+Thread::~Thread() {
+  Stop();
+}
+
+bool Thread::Start() {
+  Options options;
+#if defined(OS_WIN)
+  if (com_status_ == STA)
+    options.message_loop_type = MessageLoop::TYPE_UI;
+#endif
+  return StartWithOptions(options);
+}
+
+bool Thread::StartWithOptions(const Options& options) {
+  DCHECK(!message_loop_);
+#if defined(OS_WIN)
+  DCHECK((com_status_ != STA) ||
+      (options.message_loop_type == MessageLoop::TYPE_UI));
+#endif
+
+  SetThreadWasQuitProperly(false);
+
+  MessageLoop::Type type = options.message_loop_type;
+  if (!options.message_pump_factory.is_null())
+    type = MessageLoop::TYPE_CUSTOM;
+
+  message_loop_timer_slack_ = options.timer_slack;
+  message_loop_ = new MessageLoop(type, options.message_pump_factory);
+
+  start_event_.reset(new WaitableEvent(false, false));
+
+  // Hold the thread_lock_ while starting a new thread, so that we can make sure
+  // that thread_ is populated before the newly created thread accesses it.
+  {
+    AutoLock lock(thread_lock_);
+    bool created;
+    if (options.priority == ThreadPriority::NORMAL) {
+      created = PlatformThread::Create(options.stack_size, this, &thread_);
+    } else {
+      created = PlatformThread::CreateWithPriority(options.stack_size, this,
+                                                   &thread_, options.priority);
+    }
+    if (!created) {
+      DLOG(ERROR) << "failed to create thread";
+      delete message_loop_;
+      message_loop_ = nullptr;
+      start_event_.reset();
+      return false;
+    }
+  }
+
+  DCHECK(message_loop_);
+  return true;
+}
+
+bool Thread::StartAndWaitForTesting() {
+  bool result = Start();
+  if (!result)
+    return false;
+  WaitUntilThreadStarted();
+  return true;
+}
+
+bool Thread::WaitUntilThreadStarted() {
+  if (!start_event_)
+    return false;
+  base::ThreadRestrictions::ScopedAllowWait allow_wait;
+  start_event_->Wait();
+  return true;
+}
+
+void Thread::Stop() {
+  if (!start_event_)
+    return;
+
+  StopSoon();
+
+  // Wait for the thread to exit.
+  //
+  // TODO(darin): Unfortunately, we need to keep message_loop_ around until
+  // the thread exits.  Some consumers are abusing the API.  Make them stop.
+  //
+  PlatformThread::Join(thread_);
+
+  // The thread should NULL message_loop_ on exit.
+  DCHECK(!message_loop_);
+
+  // The thread no longer needs to be joined.
+  start_event_.reset();
+
+  stopping_ = false;
+}
+
+void Thread::StopSoon() {
+  // We should only be called on the same thread that started us.
+
+  DCHECK_NE(thread_id(), PlatformThread::CurrentId());
+
+  if (stopping_ || !message_loop_)
+    return;
+
+  stopping_ = true;
+  task_runner()->PostTask(FROM_HERE, base::Bind(&ThreadQuitHelper));
+}
+
+PlatformThreadId Thread::thread_id() const {
+  AutoLock lock(thread_lock_);
+  return thread_.id();
+}
+
+bool Thread::IsRunning() const {
+  // If the thread's already started (i.e. message_loop_ is non-null) and
+  // not yet requested to stop (i.e. stopping_ is false) we can just return
+  // true. (Note that stopping_ is touched only on the same thread that
+  // starts / started the new thread so we need no locking here.)
+  if (message_loop_ && !stopping_)
+    return true;
+  // Otherwise check the running_ flag, which is set to true by the new thread
+  // only while it is inside Run().
+  AutoLock lock(running_lock_);
+  return running_;
+}
+
+void Thread::SetPriority(ThreadPriority priority) {
+  // The thread must be started (and id known) for this to be
+  // compatible with all platforms.
+  DCHECK(message_loop_ != nullptr);
+  PlatformThread::SetThreadPriority(thread_, priority);
+}
+
+void Thread::Run(MessageLoop* message_loop) {
+  message_loop->Run();
+}
+
+void Thread::SetThreadWasQuitProperly(bool flag) {
+  lazy_tls_bool.Pointer()->Set(flag);
+}
+
+bool Thread::GetThreadWasQuitProperly() {
+  bool quit_properly = true;
+#ifndef NDEBUG
+  quit_properly = lazy_tls_bool.Pointer()->Get();
+#endif
+  return quit_properly;
+}
+
+void Thread::ThreadMain() {
+  // Complete the initialization of our Thread object.
+  PlatformThread::SetName(name_.c_str());
+  ANNOTATE_THREAD_NAME(name_.c_str());  // Tell the name to race detector.
+
+  // Lazily initialize the message_loop so that it can run on this thread.
+  DCHECK(message_loop_);
+  scoped_ptr<MessageLoop> message_loop(message_loop_);
+  message_loop_->BindToCurrentThread();
+  message_loop_->set_thread_name(name_);
+  message_loop_->SetTimerSlack(message_loop_timer_slack_);
+
+#if defined(OS_WIN)
+  scoped_ptr<win::ScopedCOMInitializer> com_initializer;
+  if (com_status_ != NONE) {
+    com_initializer.reset((com_status_ == STA) ?
+        new win::ScopedCOMInitializer() :
+        new win::ScopedCOMInitializer(win::ScopedCOMInitializer::kMTA));
+  }
+#endif
+
+  // Make sure the thread_id() returns current thread.
+  // (This internally acquires lock against PlatformThread::Create)
+  DCHECK_EQ(thread_id(), PlatformThread::CurrentId());
+
+  // Let the thread do extra initialization.
+  Init();
+
+  {
+    AutoLock lock(running_lock_);
+    running_ = true;
+  }
+
+  start_event_->Signal();
+
+  Run(message_loop_);
+
+  {
+    AutoLock lock(running_lock_);
+    running_ = false;
+  }
+
+  // Let the thread do extra cleanup.
+  CleanUp();
+
+#if defined(OS_WIN)
+  com_initializer.reset();
+#endif
+
+  // Assert that MessageLoop::Quit was called by ThreadQuitHelper.
+  DCHECK(GetThreadWasQuitProperly());
+
+  // We can't receive messages anymore.
+  // (The message loop is destructed at the end of this block)
+  message_loop_ = NULL;
+}
+
+}  // namespace base
diff --git a/base/threading/thread.h b/base/threading/thread.h
new file mode 100644
index 0000000..6b70058
--- /dev/null
+++ b/base/threading/thread.h
@@ -0,0 +1,261 @@
+// Copyright (c) 2012 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_THREADING_THREAD_H_
+#define BASE_THREADING_THREAD_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/message_loop/timer_slack.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+class MessagePump;
+class WaitableEvent;
+
+// A simple thread abstraction that establishes a MessageLoop on a new thread.
+// The consumer uses the MessageLoop of the thread to cause code to execute on
+// the thread.  When this object is destroyed the thread is terminated.  All
+// pending tasks queued on the thread's message loop will run to completion
+// before the thread is terminated.
+//
+// WARNING! SUBCLASSES MUST CALL Stop() IN THEIR DESTRUCTORS!  See ~Thread().
+//
+// After the thread is stopped, the destruction sequence is:
+//
+//  (1) Thread::CleanUp()
+//  (2) MessageLoop::~MessageLoop
+//  (3.b)    MessageLoop::DestructionObserver::WillDestroyCurrentMessageLoop
+class BASE_EXPORT Thread : PlatformThread::Delegate {
+ public:
+  struct BASE_EXPORT Options {
+    typedef Callback<scoped_ptr<MessagePump>()> MessagePumpFactory;
+
+    Options();
+    Options(MessageLoop::Type type, size_t size);
+    ~Options();
+
+    // Specifies the type of message loop that will be allocated on the thread.
+    // This is ignored if message_pump_factory.is_null() is false.
+    MessageLoop::Type message_loop_type;
+
+    // Specifies timer slack for thread message loop.
+    TimerSlack timer_slack;
+
+    // Used to create the MessagePump for the MessageLoop. The callback is Run()
+    // on the thread. If message_pump_factory.is_null(), then a MessagePump
+    // appropriate for |message_loop_type| is created. Setting this forces the
+    // MessageLoop::Type to TYPE_CUSTOM.
+    MessagePumpFactory message_pump_factory;
+
+    // Specifies the maximum stack size that the thread is allowed to use.
+    // This does not necessarily correspond to the thread's initial stack size.
+    // A value of 0 indicates that the default maximum should be used.
+    size_t stack_size;
+
+    // Specifies the initial thread priority.
+    ThreadPriority priority;
+  };
+
+  // Constructor.
+  // name is a display string to identify the thread.
+  explicit Thread(const std::string& name);
+
+  // Destroys the thread, stopping it if necessary.
+  //
+  // NOTE: ALL SUBCLASSES OF Thread MUST CALL Stop() IN THEIR DESTRUCTORS (or
+  // guarantee Stop() is explicitly called before the subclass is destroyed).
+  // This is required to avoid a data race between the destructor modifying the
+  // vtable, and the thread's ThreadMain calling the virtual method Run().  It
+  // also ensures that the CleanUp() virtual method is called on the subclass
+  // before it is destructed.
+  ~Thread() override;
+
+#if defined(OS_WIN)
+  // Causes the thread to initialize COM.  This must be called before calling
+  // Start() or StartWithOptions().  If |use_mta| is false, the thread is also
+  // started with a TYPE_UI message loop.  It is an error to call
+  // init_com_with_mta(false) and then StartWithOptions() with any message loop
+  // type other than TYPE_UI.
+  void init_com_with_mta(bool use_mta) {
+    DCHECK(!start_event_);
+    com_status_ = use_mta ? MTA : STA;
+  }
+#endif
+
+  // Starts the thread.  Returns true if the thread was successfully started;
+  // otherwise, returns false.  Upon successful return, the message_loop()
+  // getter will return non-null.
+  //
+  // Note: This function can't be called on Windows with the loader lock held;
+  // i.e. during a DllMain, global object construction or destruction, atexit()
+  // callback.
+  bool Start();
+
+  // Starts the thread. Behaves exactly like Start in addition to allow to
+  // override the default options.
+  //
+  // Note: This function can't be called on Windows with the loader lock held;
+  // i.e. during a DllMain, global object construction or destruction, atexit()
+  // callback.
+  bool StartWithOptions(const Options& options);
+
+  // Starts the thread and wait for the thread to start and run initialization
+  // before returning. It's same as calling Start() and then
+  // WaitUntilThreadStarted().
+  // Note that using this (instead of Start() or StartWithOptions() causes
+  // jank on the calling thread, should be used only in testing code.
+  bool StartAndWaitForTesting();
+
+  // Blocks until the thread starts running. Called within StartAndWait().
+  // Note that calling this causes jank on the calling thread, must be used
+  // carefully for production code.
+  bool WaitUntilThreadStarted();
+
+  // Signals the thread to exit and returns once the thread has exited.  After
+  // this method returns, the Thread object is completely reset and may be used
+  // as if it were newly constructed (i.e., Start may be called again).
+  //
+  // Stop may be called multiple times and is simply ignored if the thread is
+  // already stopped.
+  //
+  // NOTE: If you are a consumer of Thread, it is not necessary to call this
+  // before deleting your Thread objects, as the destructor will do it.
+  // IF YOU ARE A SUBCLASS OF Thread, YOU MUST CALL THIS IN YOUR DESTRUCTOR.
+  void Stop();
+
+  // Signals the thread to exit in the near future.
+  //
+  // WARNING: This function is not meant to be commonly used. Use at your own
+  // risk. Calling this function will cause message_loop() to become invalid in
+  // the near future. This function was created to workaround a specific
+  // deadlock on Windows with printer worker thread. In any other case, Stop()
+  // should be used.
+  //
+  // StopSoon should not be called multiple times as it is risky to do so. It
+  // could cause a timing issue in message_loop() access. Call Stop() to reset
+  // the thread object once it is known that the thread has quit.
+  void StopSoon();
+
+  // Returns the message loop for this thread.  Use the MessageLoop's
+  // PostTask methods to execute code on the thread.  This only returns
+  // non-null after a successful call to Start.  After Stop has been called,
+  // this will return NULL.
+  //
+  // NOTE: You must not call this MessageLoop's Quit method directly.  Use
+  // the Thread's Stop method instead.
+  //
+  MessageLoop* message_loop() const { return message_loop_; }
+
+  // Returns a MessageLoopProxy for this thread. Use the MessageLoopProxy's
+  // PostTask methods to execute code on the thread. Returns NULL if the thread
+  // is not running (e.g. before Start or after Stop have been called). Callers
+  // can hold on to this even after the thread is gone; in this situation,
+  // attempts to PostTask() will fail.
+  //
+  // Note: This method is deprecated. Callers should call task_runner() instead
+  // and use the TaskRunner interfaces for safely interfacing with the Thread.
+  scoped_refptr<MessageLoopProxy> message_loop_proxy() const {
+    return message_loop_ ? message_loop_->message_loop_proxy() : NULL;
+  }
+
+  // Returns a TaskRunner for this thread. Use the TaskRunner's PostTask
+  // methods to execute code on the thread. Returns NULL if the thread is not
+  // running (e.g. before Start or after Stop have been called). Callers can
+  // hold on to this even after the thread is gone; in this situation, attempts
+  // to PostTask() will fail.
+  scoped_refptr<SingleThreadTaskRunner> task_runner() const {
+    return message_loop_ ? message_loop_->task_runner() : nullptr;
+  }
+
+  // Returns the name of this thread (for display in debugger too).
+  const std::string& thread_name() const { return name_; }
+
+  // The native thread handle.
+  PlatformThreadHandle thread_handle() { return thread_; }
+
+  // The thread ID.
+  PlatformThreadId thread_id() const;
+
+  // Returns true if the thread has been started, and not yet stopped.
+  bool IsRunning() const;
+
+  // Sets the thread priority. The thread must already be started.
+  void SetPriority(ThreadPriority priority);
+
+ protected:
+  // Called just prior to starting the message loop
+  virtual void Init() {}
+
+  // Called to start the message loop
+  virtual void Run(MessageLoop* message_loop);
+
+  // Called just after the message loop ends
+  virtual void CleanUp() {}
+
+  static void SetThreadWasQuitProperly(bool flag);
+  static bool GetThreadWasQuitProperly();
+
+  void set_message_loop(MessageLoop* message_loop) {
+    message_loop_ = message_loop;
+  }
+
+ private:
+#if defined(OS_WIN)
+  enum ComStatus {
+    NONE,
+    STA,
+    MTA,
+  };
+#endif
+
+  // PlatformThread::Delegate methods:
+  void ThreadMain() override;
+
+#if defined(OS_WIN)
+  // Whether this thread needs to initialize COM, and if so, in what mode.
+  ComStatus com_status_;
+#endif
+
+  // If true, we're in the middle of stopping, and shouldn't access
+  // |message_loop_|. It may non-NULL and invalid.
+  bool stopping_;
+
+  // True while inside of Run().
+  bool running_;
+  mutable base::Lock running_lock_;  // Protects running_.
+
+  // The thread's handle.
+  PlatformThreadHandle thread_;
+  mutable base::Lock thread_lock_;  // Protects thread_.
+
+  // The thread's message loop.  Valid only while the thread is alive.  Set
+  // by the created thread.
+  MessageLoop* message_loop_;
+
+  // Stores Options::timer_slack_ until the message loop has been bound to
+  // a thread.
+  TimerSlack message_loop_timer_slack_;
+
+  // The name of the thread.  Used for debugging purposes.
+  std::string name_;
+
+  // Non-null if the thread has successfully started.
+  scoped_ptr<WaitableEvent> start_event_;
+
+  friend void ThreadQuitHelper();
+
+  DISALLOW_COPY_AND_ASSIGN(Thread);
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_THREAD_H_
diff --git a/base/threading/thread_checker.h b/base/threading/thread_checker.h
new file mode 100644
index 0000000..449247a
--- /dev/null
+++ b/base/threading/thread_checker.h
@@ -0,0 +1,83 @@
+// Copyright (c) 2012 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_THREADING_THREAD_CHECKER_H_
+#define BASE_THREADING_THREAD_CHECKER_H_
+
+// Apart from debug builds, we also enable the thread checker in
+// builds with DCHECK_ALWAYS_ON so that trybots and waterfall bots
+// with this define will get the same level of thread checking as
+// debug bots.
+//
+// Note that this does not perfectly match situations where DCHECK is
+// enabled.  For example a non-official release build may have
+// DCHECK_ALWAYS_ON undefined (and therefore ThreadChecker would be
+// disabled) but have DCHECKs enabled at runtime.
+#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON))
+#define ENABLE_THREAD_CHECKER 1
+#else
+#define ENABLE_THREAD_CHECKER 0
+#endif
+
+#include "base/threading/thread_checker_impl.h"
+
+namespace base {
+
+// Do nothing implementation, for use in release mode.
+//
+// Note: You should almost always use the ThreadChecker class to get the
+// right version for your build configuration.
+class ThreadCheckerDoNothing {
+ public:
+  bool CalledOnValidThread() const WARN_UNUSED_RESULT {
+    return true;
+  }
+
+  void DetachFromThread() {}
+};
+
+// ThreadChecker is a helper class used to help verify that some methods of a
+// class are called from the same thread. It provides identical functionality to
+// base::NonThreadSafe, but it is meant to be held as a member variable, rather
+// than inherited from base::NonThreadSafe.
+//
+// While inheriting from base::NonThreadSafe may give a clear indication about
+// the thread-safety of a class, it may also lead to violations of the style
+// guide with regard to multiple inheritance. The choice between having a
+// ThreadChecker member and inheriting from base::NonThreadSafe should be based
+// on whether:
+//  - Derived classes need to know the thread they belong to, as opposed to
+//    having that functionality fully encapsulated in the base class.
+//  - Derived classes should be able to reassign the base class to another
+//    thread, via DetachFromThread.
+//
+// If neither of these are true, then having a ThreadChecker member and calling
+// CalledOnValidThread is the preferable solution.
+//
+// Example:
+// class MyClass {
+//  public:
+//   void Foo() {
+//     DCHECK(thread_checker_.CalledOnValidThread());
+//     ... (do stuff) ...
+//   }
+//
+//  private:
+//   ThreadChecker thread_checker_;
+// }
+//
+// In Release mode, CalledOnValidThread will always return true.
+#if ENABLE_THREAD_CHECKER
+class ThreadChecker : public ThreadCheckerImpl {
+};
+#else
+class ThreadChecker : public ThreadCheckerDoNothing {
+};
+#endif  // ENABLE_THREAD_CHECKER
+
+#undef ENABLE_THREAD_CHECKER
+
+}  // namespace base
+
+#endif  // BASE_THREADING_THREAD_CHECKER_H_
diff --git a/base/threading/thread_checker_impl.cc b/base/threading/thread_checker_impl.cc
new file mode 100644
index 0000000..eb87bae
--- /dev/null
+++ b/base/threading/thread_checker_impl.cc
@@ -0,0 +1,34 @@
+// Copyright (c) 2011 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/threading/thread_checker_impl.h"
+
+namespace base {
+
+ThreadCheckerImpl::ThreadCheckerImpl()
+    : valid_thread_id_() {
+  EnsureThreadIdAssigned();
+}
+
+ThreadCheckerImpl::~ThreadCheckerImpl() {}
+
+bool ThreadCheckerImpl::CalledOnValidThread() const {
+  EnsureThreadIdAssigned();
+  AutoLock auto_lock(lock_);
+  return valid_thread_id_ == PlatformThread::CurrentRef();
+}
+
+void ThreadCheckerImpl::DetachFromThread() {
+  AutoLock auto_lock(lock_);
+  valid_thread_id_ = PlatformThreadRef();
+}
+
+void ThreadCheckerImpl::EnsureThreadIdAssigned() const {
+  AutoLock auto_lock(lock_);
+  if (valid_thread_id_.is_null()) {
+    valid_thread_id_ = PlatformThread::CurrentRef();
+  }
+}
+
+}  // namespace base
diff --git a/base/threading/thread_checker_impl.h b/base/threading/thread_checker_impl.h
new file mode 100644
index 0000000..c92e143
--- /dev/null
+++ b/base/threading/thread_checker_impl.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2011 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_THREADING_THREAD_CHECKER_IMPL_H_
+#define BASE_THREADING_THREAD_CHECKER_IMPL_H_
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+// Real implementation of ThreadChecker, for use in debug mode, or
+// for temporary use in release mode (e.g. to CHECK on a threading issue
+// seen only in the wild).
+//
+// Note: You should almost always use the ThreadChecker class to get the
+// right version for your build configuration.
+class BASE_EXPORT ThreadCheckerImpl {
+ public:
+  ThreadCheckerImpl();
+  ~ThreadCheckerImpl();
+
+  bool CalledOnValidThread() const WARN_UNUSED_RESULT;
+
+  // Changes the thread that is checked for in CalledOnValidThread.  This may
+  // be useful when an object may be created on one thread and then used
+  // exclusively on another thread.
+  void DetachFromThread();
+
+ private:
+  void EnsureThreadIdAssigned() const;
+
+  mutable base::Lock lock_;
+  // This is mutable so that CalledOnValidThread can set it.
+  // It's guarded by |lock_|.
+  mutable PlatformThreadRef valid_thread_id_;
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_THREAD_CHECKER_IMPL_H_
diff --git a/base/threading/thread_checker_unittest.cc b/base/threading/thread_checker_unittest.cc
new file mode 100644
index 0000000..d42cbc2
--- /dev/null
+++ b/base/threading/thread_checker_unittest.cc
@@ -0,0 +1,179 @@
+// Copyright (c) 2012 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/basictypes.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/threading/thread_checker.h"
+#include "base/threading/simple_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Duplicated from base/threading/thread_checker.h so that we can be
+// good citizens there and undef the macro.
+#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+#define ENABLE_THREAD_CHECKER 1
+#else
+#define ENABLE_THREAD_CHECKER 0
+#endif
+
+namespace base {
+
+namespace {
+
+// Simple class to exercise the basics of ThreadChecker.
+// Both the destructor and DoStuff should verify that they were
+// called on the same thread as the constructor.
+class ThreadCheckerClass : public ThreadChecker {
+ public:
+  ThreadCheckerClass() {}
+
+  // Verifies that it was called on the same thread as the constructor.
+  void DoStuff() {
+    DCHECK(CalledOnValidThread());
+  }
+
+  void DetachFromThread() {
+    ThreadChecker::DetachFromThread();
+  }
+
+  static void MethodOnDifferentThreadImpl();
+  static void DetachThenCallFromDifferentThreadImpl();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ThreadCheckerClass);
+};
+
+// Calls ThreadCheckerClass::DoStuff on another thread.
+class CallDoStuffOnThread : public base::SimpleThread {
+ public:
+  explicit CallDoStuffOnThread(ThreadCheckerClass* thread_checker_class)
+      : SimpleThread("call_do_stuff_on_thread"),
+        thread_checker_class_(thread_checker_class) {
+  }
+
+  void Run() override { thread_checker_class_->DoStuff(); }
+
+ private:
+  ThreadCheckerClass* thread_checker_class_;
+
+  DISALLOW_COPY_AND_ASSIGN(CallDoStuffOnThread);
+};
+
+// Deletes ThreadCheckerClass on a different thread.
+class DeleteThreadCheckerClassOnThread : public base::SimpleThread {
+ public:
+  explicit DeleteThreadCheckerClassOnThread(
+      ThreadCheckerClass* thread_checker_class)
+      : SimpleThread("delete_thread_checker_class_on_thread"),
+        thread_checker_class_(thread_checker_class) {
+  }
+
+  void Run() override { thread_checker_class_.reset(); }
+
+ private:
+  scoped_ptr<ThreadCheckerClass> thread_checker_class_;
+
+  DISALLOW_COPY_AND_ASSIGN(DeleteThreadCheckerClassOnThread);
+};
+
+}  // namespace
+
+TEST(ThreadCheckerTest, CallsAllowedOnSameThread) {
+  scoped_ptr<ThreadCheckerClass> thread_checker_class(
+      new ThreadCheckerClass);
+
+  // Verify that DoStuff doesn't assert.
+  thread_checker_class->DoStuff();
+
+  // Verify that the destructor doesn't assert.
+  thread_checker_class.reset();
+}
+
+TEST(ThreadCheckerTest, DestructorAllowedOnDifferentThread) {
+  scoped_ptr<ThreadCheckerClass> thread_checker_class(
+      new ThreadCheckerClass);
+
+  // Verify that the destructor doesn't assert
+  // when called on a different thread.
+  DeleteThreadCheckerClassOnThread delete_on_thread(
+      thread_checker_class.release());
+
+  delete_on_thread.Start();
+  delete_on_thread.Join();
+}
+
+TEST(ThreadCheckerTest, DetachFromThread) {
+  scoped_ptr<ThreadCheckerClass> thread_checker_class(
+      new ThreadCheckerClass);
+
+  // Verify that DoStuff doesn't assert when called on a different thread after
+  // a call to DetachFromThread.
+  thread_checker_class->DetachFromThread();
+  CallDoStuffOnThread call_on_thread(thread_checker_class.get());
+
+  call_on_thread.Start();
+  call_on_thread.Join();
+}
+
+#if GTEST_HAS_DEATH_TEST || !ENABLE_THREAD_CHECKER
+
+void ThreadCheckerClass::MethodOnDifferentThreadImpl() {
+  scoped_ptr<ThreadCheckerClass> thread_checker_class(
+      new ThreadCheckerClass);
+
+  // DoStuff should assert in debug builds only when called on a
+  // different thread.
+  CallDoStuffOnThread call_on_thread(thread_checker_class.get());
+
+  call_on_thread.Start();
+  call_on_thread.Join();
+}
+
+#if ENABLE_THREAD_CHECKER
+TEST(ThreadCheckerDeathTest, MethodNotAllowedOnDifferentThreadInDebug) {
+  ASSERT_DEATH({
+      ThreadCheckerClass::MethodOnDifferentThreadImpl();
+    }, "");
+}
+#else
+TEST(ThreadCheckerTest, MethodAllowedOnDifferentThreadInRelease) {
+  ThreadCheckerClass::MethodOnDifferentThreadImpl();
+}
+#endif  // ENABLE_THREAD_CHECKER
+
+void ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl() {
+  scoped_ptr<ThreadCheckerClass> thread_checker_class(
+      new ThreadCheckerClass);
+
+  // DoStuff doesn't assert when called on a different thread
+  // after a call to DetachFromThread.
+  thread_checker_class->DetachFromThread();
+  CallDoStuffOnThread call_on_thread(thread_checker_class.get());
+
+  call_on_thread.Start();
+  call_on_thread.Join();
+
+  // DoStuff should assert in debug builds only after moving to
+  // another thread.
+  thread_checker_class->DoStuff();
+}
+
+#if ENABLE_THREAD_CHECKER
+TEST(ThreadCheckerDeathTest, DetachFromThreadInDebug) {
+  ASSERT_DEATH({
+    ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl();
+    }, "");
+}
+#else
+TEST(ThreadCheckerTest, DetachFromThreadInRelease) {
+  ThreadCheckerClass::DetachThenCallFromDifferentThreadImpl();
+}
+#endif  // ENABLE_THREAD_CHECKER
+
+#endif  // GTEST_HAS_DEATH_TEST || !ENABLE_THREAD_CHECKER
+
+// Just in case we ever get lumped together with other compilation units.
+#undef ENABLE_THREAD_CHECKER
+
+}  // namespace base
diff --git a/base/threading/thread_collision_warner.cc b/base/threading/thread_collision_warner.cc
new file mode 100644
index 0000000..547e11c
--- /dev/null
+++ b/base/threading/thread_collision_warner.cc
@@ -0,0 +1,64 @@
+// Copyright (c) 2010 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/threading/thread_collision_warner.h"
+
+#include "base/logging.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+void DCheckAsserter::warn() {
+  NOTREACHED() << "Thread Collision";
+}
+
+static subtle::Atomic32 CurrentThread() {
+  const PlatformThreadId current_thread_id = PlatformThread::CurrentId();
+  // We need to get the thread id into an atomic data type. This might be a
+  // truncating conversion, but any loss-of-information just increases the
+  // chance of a fault negative, not a false positive.
+  const subtle::Atomic32 atomic_thread_id =
+      static_cast<subtle::Atomic32>(current_thread_id);
+
+  return atomic_thread_id;
+}
+
+void ThreadCollisionWarner::EnterSelf() {
+  // If the active thread is 0 then I'll write the current thread ID
+  // if two or more threads arrive here only one will succeed to
+  // write on valid_thread_id_ the current thread ID.
+  subtle::Atomic32 current_thread_id = CurrentThread();
+
+  int previous_value = subtle::NoBarrier_CompareAndSwap(&valid_thread_id_,
+                                                        0,
+                                                        current_thread_id);
+  if (previous_value != 0 && previous_value != current_thread_id) {
+    // gotcha! a thread is trying to use the same class and that is
+    // not current thread.
+    asserter_->warn();
+  }
+
+  subtle::NoBarrier_AtomicIncrement(&counter_, 1);
+}
+
+void ThreadCollisionWarner::Enter() {
+  subtle::Atomic32 current_thread_id = CurrentThread();
+
+  if (subtle::NoBarrier_CompareAndSwap(&valid_thread_id_,
+                                       0,
+                                       current_thread_id) != 0) {
+    // gotcha! another thread is trying to use the same class.
+    asserter_->warn();
+  }
+
+  subtle::NoBarrier_AtomicIncrement(&counter_, 1);
+}
+
+void ThreadCollisionWarner::Leave() {
+  if (subtle::Barrier_AtomicIncrement(&counter_, -1) == 0) {
+    subtle::NoBarrier_Store(&valid_thread_id_, 0);
+  }
+}
+
+}  // namespace base
diff --git a/base/threading/thread_collision_warner.h b/base/threading/thread_collision_warner.h
new file mode 100644
index 0000000..de4e9c3
--- /dev/null
+++ b/base/threading/thread_collision_warner.h
@@ -0,0 +1,245 @@
+// Copyright (c) 2012 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_THREADING_THREAD_COLLISION_WARNER_H_
+#define BASE_THREADING_THREAD_COLLISION_WARNER_H_
+
+#include <memory>
+
+#include "base/atomicops.h"
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+
+// A helper class alongside macros to be used to verify assumptions about thread
+// safety of a class.
+//
+// Example: Queue implementation non thread-safe but still usable if clients
+//          are synchronized somehow.
+//
+//          In this case the macro DFAKE_SCOPED_LOCK has to be
+//          used, it checks that if a thread is inside the push/pop then
+//          noone else is still inside the pop/push
+//
+// class NonThreadSafeQueue {
+//  public:
+//   ...
+//   void push(int) { DFAKE_SCOPED_LOCK(push_pop_); ... }
+//   int pop() { DFAKE_SCOPED_LOCK(push_pop_); ... }
+//   ...
+//  private:
+//   DFAKE_MUTEX(push_pop_);
+// };
+//
+//
+// Example: Queue implementation non thread-safe but still usable if clients
+//          are synchronized somehow, it calls a method to "protect" from
+//          a "protected" method
+//
+//          In this case the macro DFAKE_SCOPED_RECURSIVE_LOCK
+//          has to be used, it checks that if a thread is inside the push/pop
+//          then noone else is still inside the pop/push
+//
+// class NonThreadSafeQueue {
+//  public:
+//   void push(int) {
+//     DFAKE_SCOPED_LOCK(push_pop_);
+//     ...
+//   }
+//   int pop() {
+//     DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_);
+//     bar();
+//     ...
+//   }
+//   void bar() { DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_); ... }
+//   ...
+//  private:
+//   DFAKE_MUTEX(push_pop_);
+// };
+//
+//
+// Example: Queue implementation not usable even if clients are synchronized,
+//          so only one thread in the class life cycle can use the two members
+//          push/pop.
+//
+//          In this case the macro DFAKE_SCOPED_LOCK_THREAD_LOCKED pins the
+//          specified
+//          critical section the first time a thread enters push or pop, from
+//          that time on only that thread is allowed to execute push or pop.
+//
+// class NonThreadSafeQueue {
+//  public:
+//   ...
+//   void push(int) { DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_); ... }
+//   int pop() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_); ... }
+//   ...
+//  private:
+//   DFAKE_MUTEX(push_pop_);
+// };
+//
+//
+// Example: Class that has to be contructed/destroyed on same thread, it has
+//          a "shareable" method (with external synchronization) and a not
+//          shareable method (even with external synchronization).
+//
+//          In this case 3 Critical sections have to be defined
+//
+// class ExoticClass {
+//  public:
+//   ExoticClass() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... }
+//   ~ExoticClass() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... }
+//
+//   void Shareable() { DFAKE_SCOPED_LOCK(shareable_section_); ... }
+//   void NotShareable() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... }
+//   ...
+//  private:
+//   DFAKE_MUTEX(ctor_dtor_);
+//   DFAKE_MUTEX(shareable_section_);
+// };
+
+
+#if !defined(NDEBUG)
+
+// Defines a class member that acts like a mutex. It is used only as a
+// verification tool.
+#define DFAKE_MUTEX(obj) \
+     mutable base::ThreadCollisionWarner obj
+// Asserts the call is never called simultaneously in two threads. Used at
+// member function scope.
+#define DFAKE_SCOPED_LOCK(obj) \
+     base::ThreadCollisionWarner::ScopedCheck s_check_##obj(&obj)
+// Asserts the call is never called simultaneously in two threads. Used at
+// member function scope. Same as DFAKE_SCOPED_LOCK but allows recursive locks.
+#define DFAKE_SCOPED_RECURSIVE_LOCK(obj) \
+     base::ThreadCollisionWarner::ScopedRecursiveCheck sr_check_##obj(&obj)
+// Asserts the code is always executed in the same thread.
+#define DFAKE_SCOPED_LOCK_THREAD_LOCKED(obj) \
+     base::ThreadCollisionWarner::Check check_##obj(&obj)
+
+#else
+
+#define DFAKE_MUTEX(obj) typedef void InternalFakeMutexType##obj
+#define DFAKE_SCOPED_LOCK(obj) ((void)0)
+#define DFAKE_SCOPED_RECURSIVE_LOCK(obj) ((void)0)
+#define DFAKE_SCOPED_LOCK_THREAD_LOCKED(obj) ((void)0)
+
+#endif
+
+namespace base {
+
+// The class ThreadCollisionWarner uses an Asserter to notify the collision
+// AsserterBase is the interfaces and DCheckAsserter is the default asserter
+// used. During the unit tests is used another class that doesn't "DCHECK"
+// in case of collision (check thread_collision_warner_unittests.cc)
+struct BASE_EXPORT AsserterBase {
+  virtual ~AsserterBase() {}
+  virtual void warn() = 0;
+};
+
+struct BASE_EXPORT DCheckAsserter : public AsserterBase {
+  ~DCheckAsserter() override {}
+  void warn() override;
+};
+
+class BASE_EXPORT ThreadCollisionWarner {
+ public:
+  // The parameter asserter is there only for test purpose
+  explicit ThreadCollisionWarner(AsserterBase* asserter = new DCheckAsserter())
+      : valid_thread_id_(0),
+        counter_(0),
+        asserter_(asserter) {}
+
+  ~ThreadCollisionWarner() {
+    delete asserter_;
+  }
+
+  // This class is meant to be used through the macro
+  // DFAKE_SCOPED_LOCK_THREAD_LOCKED
+  // it doesn't leave the critical section, as opposed to ScopedCheck,
+  // because the critical section being pinned is allowed to be used only
+  // from one thread
+  class BASE_EXPORT Check {
+   public:
+    explicit Check(ThreadCollisionWarner* warner)
+        : warner_(warner) {
+      warner_->EnterSelf();
+    }
+
+    ~Check() {}
+
+   private:
+    ThreadCollisionWarner* warner_;
+
+    DISALLOW_COPY_AND_ASSIGN(Check);
+  };
+
+  // This class is meant to be used through the macro
+  // DFAKE_SCOPED_LOCK
+  class BASE_EXPORT ScopedCheck {
+   public:
+    explicit ScopedCheck(ThreadCollisionWarner* warner)
+        : warner_(warner) {
+      warner_->Enter();
+    }
+
+    ~ScopedCheck() {
+      warner_->Leave();
+    }
+
+   private:
+    ThreadCollisionWarner* warner_;
+
+    DISALLOW_COPY_AND_ASSIGN(ScopedCheck);
+  };
+
+  // This class is meant to be used through the macro
+  // DFAKE_SCOPED_RECURSIVE_LOCK
+  class BASE_EXPORT ScopedRecursiveCheck {
+   public:
+    explicit ScopedRecursiveCheck(ThreadCollisionWarner* warner)
+        : warner_(warner) {
+      warner_->EnterSelf();
+    }
+
+    ~ScopedRecursiveCheck() {
+      warner_->Leave();
+    }
+
+   private:
+    ThreadCollisionWarner* warner_;
+
+    DISALLOW_COPY_AND_ASSIGN(ScopedRecursiveCheck);
+  };
+
+ private:
+  // This method stores the current thread identifier and does a DCHECK
+  // if a another thread has already done it, it is safe if same thread
+  // calls this multiple time (recursion allowed).
+  void EnterSelf();
+
+  // Same as EnterSelf but recursion is not allowed.
+  void Enter();
+
+  // Removes the thread_id stored in order to allow other threads to
+  // call EnterSelf or Enter.
+  void Leave();
+
+  // This stores the thread id that is inside the critical section, if the
+  // value is 0 then no thread is inside.
+  volatile subtle::Atomic32 valid_thread_id_;
+
+  // Counter to trace how many time a critical section was "pinned"
+  // (when allowed) in order to unpin it when counter_ reaches 0.
+  volatile subtle::Atomic32 counter_;
+
+  // Here only for class unit tests purpose, during the test I need to not
+  // DCHECK but notify the collision with something else.
+  AsserterBase* asserter_;
+
+  DISALLOW_COPY_AND_ASSIGN(ThreadCollisionWarner);
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_THREAD_COLLISION_WARNER_H_
diff --git a/base/threading/thread_collision_warner_unittest.cc b/base/threading/thread_collision_warner_unittest.cc
new file mode 100644
index 0000000..d7ce79e
--- /dev/null
+++ b/base/threading/thread_collision_warner_unittest.cc
@@ -0,0 +1,379 @@
+// Copyright (c) 2012 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/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/simple_thread.h"
+#include "base/threading/thread_collision_warner.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// '' : local class member function does not have a body
+MSVC_PUSH_DISABLE_WARNING(4822)
+
+
+#if defined(NDEBUG)
+
+// Would cause a memory leak otherwise.
+#undef DFAKE_MUTEX
+#define DFAKE_MUTEX(obj) scoped_ptr<base::AsserterBase> obj
+
+// In Release, we expect the AsserterBase::warn() to not happen.
+#define EXPECT_NDEBUG_FALSE_DEBUG_TRUE EXPECT_FALSE
+
+#else
+
+// In Debug, we expect the AsserterBase::warn() to happen.
+#define EXPECT_NDEBUG_FALSE_DEBUG_TRUE EXPECT_TRUE
+
+#endif
+
+
+namespace {
+
+// This is the asserter used with ThreadCollisionWarner instead of the default
+// DCheckAsserter. The method fail_state is used to know if a collision took
+// place.
+class AssertReporter : public base::AsserterBase {
+ public:
+  AssertReporter()
+      : failed_(false) {}
+
+  void warn() override { failed_ = true; }
+
+  ~AssertReporter() override {}
+
+  bool fail_state() const { return failed_; }
+  void reset() { failed_ = false; }
+
+ private:
+  bool failed_;
+};
+
+}  // namespace
+
+TEST(ThreadCollisionTest, BookCriticalSection) {
+  AssertReporter* local_reporter = new AssertReporter();
+
+  base::ThreadCollisionWarner warner(local_reporter);
+  EXPECT_FALSE(local_reporter->fail_state());
+
+  {  // Pin section.
+    DFAKE_SCOPED_LOCK_THREAD_LOCKED(warner);
+    EXPECT_FALSE(local_reporter->fail_state());
+    {  // Pin section.
+      DFAKE_SCOPED_LOCK_THREAD_LOCKED(warner);
+      EXPECT_FALSE(local_reporter->fail_state());
+    }
+  }
+}
+
+TEST(ThreadCollisionTest, ScopedRecursiveBookCriticalSection) {
+  AssertReporter* local_reporter = new AssertReporter();
+
+  base::ThreadCollisionWarner warner(local_reporter);
+  EXPECT_FALSE(local_reporter->fail_state());
+
+  {  // Pin section.
+    DFAKE_SCOPED_RECURSIVE_LOCK(warner);
+    EXPECT_FALSE(local_reporter->fail_state());
+    {  // Pin section again (allowed by DFAKE_SCOPED_RECURSIVE_LOCK)
+      DFAKE_SCOPED_RECURSIVE_LOCK(warner);
+      EXPECT_FALSE(local_reporter->fail_state());
+    }  // Unpin section.
+  }  // Unpin section.
+
+  // Check that section is not pinned
+  {  // Pin section.
+    DFAKE_SCOPED_LOCK(warner);
+    EXPECT_FALSE(local_reporter->fail_state());
+  }  // Unpin section.
+}
+
+TEST(ThreadCollisionTest, ScopedBookCriticalSection) {
+  AssertReporter* local_reporter = new AssertReporter();
+
+  base::ThreadCollisionWarner warner(local_reporter);
+  EXPECT_FALSE(local_reporter->fail_state());
+
+  {  // Pin section.
+    DFAKE_SCOPED_LOCK(warner);
+    EXPECT_FALSE(local_reporter->fail_state());
+  }  // Unpin section.
+
+  {  // Pin section.
+    DFAKE_SCOPED_LOCK(warner);
+    EXPECT_FALSE(local_reporter->fail_state());
+    {
+      // Pin section again (not allowed by DFAKE_SCOPED_LOCK)
+      DFAKE_SCOPED_LOCK(warner);
+      EXPECT_NDEBUG_FALSE_DEBUG_TRUE(local_reporter->fail_state());
+      // Reset the status of warner for further tests.
+      local_reporter->reset();
+    }  // Unpin section.
+  }  // Unpin section.
+
+  {
+    // Pin section.
+    DFAKE_SCOPED_LOCK(warner);
+    EXPECT_FALSE(local_reporter->fail_state());
+  }  // Unpin section.
+}
+
+TEST(ThreadCollisionTest, MTBookCriticalSectionTest) {
+  class NonThreadSafeQueue {
+   public:
+    explicit NonThreadSafeQueue(base::AsserterBase* asserter)
+        : push_pop_(asserter) {
+    }
+
+    void push(int value) {
+      DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_);
+    }
+
+    int pop() {
+      DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_);
+      return 0;
+    }
+
+   private:
+    DFAKE_MUTEX(push_pop_);
+
+    DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue);
+  };
+
+  class QueueUser : public base::DelegateSimpleThread::Delegate {
+   public:
+    explicit QueueUser(NonThreadSafeQueue* queue) : queue_(queue) {}
+
+    void Run() override {
+      queue_->push(0);
+      queue_->pop();
+    }
+
+   private:
+    NonThreadSafeQueue* queue_;
+  };
+
+  AssertReporter* local_reporter = new AssertReporter();
+
+  NonThreadSafeQueue queue(local_reporter);
+
+  QueueUser queue_user_a(&queue);
+  QueueUser queue_user_b(&queue);
+
+  base::DelegateSimpleThread thread_a(&queue_user_a, "queue_user_thread_a");
+  base::DelegateSimpleThread thread_b(&queue_user_b, "queue_user_thread_b");
+
+  thread_a.Start();
+  thread_b.Start();
+
+  thread_a.Join();
+  thread_b.Join();
+
+  EXPECT_NDEBUG_FALSE_DEBUG_TRUE(local_reporter->fail_state());
+}
+
+TEST(ThreadCollisionTest, MTScopedBookCriticalSectionTest) {
+  // Queue with a 5 seconds push execution time, hopefuly the two used threads
+  // in the test will enter the push at same time.
+  class NonThreadSafeQueue {
+   public:
+    explicit NonThreadSafeQueue(base::AsserterBase* asserter)
+        : push_pop_(asserter) {
+    }
+
+    void push(int value) {
+      DFAKE_SCOPED_LOCK(push_pop_);
+      base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(5));
+    }
+
+    int pop() {
+      DFAKE_SCOPED_LOCK(push_pop_);
+      return 0;
+    }
+
+   private:
+    DFAKE_MUTEX(push_pop_);
+
+    DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue);
+  };
+
+  class QueueUser : public base::DelegateSimpleThread::Delegate {
+   public:
+    explicit QueueUser(NonThreadSafeQueue* queue) : queue_(queue) {}
+
+    void Run() override {
+      queue_->push(0);
+      queue_->pop();
+    }
+
+   private:
+    NonThreadSafeQueue* queue_;
+  };
+
+  AssertReporter* local_reporter = new AssertReporter();
+
+  NonThreadSafeQueue queue(local_reporter);
+
+  QueueUser queue_user_a(&queue);
+  QueueUser queue_user_b(&queue);
+
+  base::DelegateSimpleThread thread_a(&queue_user_a, "queue_user_thread_a");
+  base::DelegateSimpleThread thread_b(&queue_user_b, "queue_user_thread_b");
+
+  thread_a.Start();
+  thread_b.Start();
+
+  thread_a.Join();
+  thread_b.Join();
+
+  EXPECT_NDEBUG_FALSE_DEBUG_TRUE(local_reporter->fail_state());
+}
+
+TEST(ThreadCollisionTest, MTSynchedScopedBookCriticalSectionTest) {
+  // Queue with a 2 seconds push execution time, hopefuly the two used threads
+  // in the test will enter the push at same time.
+  class NonThreadSafeQueue {
+   public:
+    explicit NonThreadSafeQueue(base::AsserterBase* asserter)
+        : push_pop_(asserter) {
+    }
+
+    void push(int value) {
+      DFAKE_SCOPED_LOCK(push_pop_);
+      base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(2));
+    }
+
+    int pop() {
+      DFAKE_SCOPED_LOCK(push_pop_);
+      return 0;
+    }
+
+   private:
+    DFAKE_MUTEX(push_pop_);
+
+    DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue);
+  };
+
+  // This time the QueueUser class protects the non thread safe queue with
+  // a lock.
+  class QueueUser : public base::DelegateSimpleThread::Delegate {
+   public:
+    QueueUser(NonThreadSafeQueue* queue, base::Lock* lock)
+        : queue_(queue), lock_(lock) {}
+
+    void Run() override {
+      {
+        base::AutoLock auto_lock(*lock_);
+        queue_->push(0);
+      }
+      {
+        base::AutoLock auto_lock(*lock_);
+        queue_->pop();
+      }
+    }
+   private:
+    NonThreadSafeQueue* queue_;
+    base::Lock* lock_;
+  };
+
+  AssertReporter* local_reporter = new AssertReporter();
+
+  NonThreadSafeQueue queue(local_reporter);
+
+  base::Lock lock;
+
+  QueueUser queue_user_a(&queue, &lock);
+  QueueUser queue_user_b(&queue, &lock);
+
+  base::DelegateSimpleThread thread_a(&queue_user_a, "queue_user_thread_a");
+  base::DelegateSimpleThread thread_b(&queue_user_b, "queue_user_thread_b");
+
+  thread_a.Start();
+  thread_b.Start();
+
+  thread_a.Join();
+  thread_b.Join();
+
+  EXPECT_FALSE(local_reporter->fail_state());
+}
+
+TEST(ThreadCollisionTest, MTSynchedScopedRecursiveBookCriticalSectionTest) {
+  // Queue with a 2 seconds push execution time, hopefuly the two used threads
+  // in the test will enter the push at same time.
+  class NonThreadSafeQueue {
+   public:
+    explicit NonThreadSafeQueue(base::AsserterBase* asserter)
+        : push_pop_(asserter) {
+    }
+
+    void push(int) {
+      DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_);
+      bar();
+      base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(2));
+    }
+
+    int pop() {
+      DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_);
+      return 0;
+    }
+
+    void bar() {
+      DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_);
+    }
+
+   private:
+    DFAKE_MUTEX(push_pop_);
+
+    DISALLOW_COPY_AND_ASSIGN(NonThreadSafeQueue);
+  };
+
+  // This time the QueueUser class protects the non thread safe queue with
+  // a lock.
+  class QueueUser : public base::DelegateSimpleThread::Delegate {
+   public:
+    QueueUser(NonThreadSafeQueue* queue, base::Lock* lock)
+        : queue_(queue), lock_(lock) {}
+
+    void Run() override {
+      {
+        base::AutoLock auto_lock(*lock_);
+        queue_->push(0);
+      }
+      {
+        base::AutoLock auto_lock(*lock_);
+        queue_->bar();
+      }
+      {
+        base::AutoLock auto_lock(*lock_);
+        queue_->pop();
+      }
+    }
+   private:
+    NonThreadSafeQueue* queue_;
+    base::Lock* lock_;
+  };
+
+  AssertReporter* local_reporter = new AssertReporter();
+
+  NonThreadSafeQueue queue(local_reporter);
+
+  base::Lock lock;
+
+  QueueUser queue_user_a(&queue, &lock);
+  QueueUser queue_user_b(&queue, &lock);
+
+  base::DelegateSimpleThread thread_a(&queue_user_a, "queue_user_thread_a");
+  base::DelegateSimpleThread thread_b(&queue_user_b, "queue_user_thread_b");
+
+  thread_a.Start();
+  thread_b.Start();
+
+  thread_a.Join();
+  thread_b.Join();
+
+  EXPECT_FALSE(local_reporter->fail_state());
+}
diff --git a/base/threading/thread_id_name_manager.cc b/base/threading/thread_id_name_manager.cc
new file mode 100644
index 0000000..56cfa27
--- /dev/null
+++ b/base/threading/thread_id_name_manager.cc
@@ -0,0 +1,112 @@
+// Copyright (c) 2012 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/threading/thread_id_name_manager.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "base/logging.h"
+#include "base/memory/singleton.h"
+#include "base/strings/string_util.h"
+
+namespace base {
+namespace {
+
+static const char kDefaultName[] = "";
+static std::string* g_default_name;
+
+}
+
+ThreadIdNameManager::ThreadIdNameManager()
+    : main_process_name_(NULL),
+      main_process_id_(kInvalidThreadId) {
+  g_default_name = new std::string(kDefaultName);
+
+  AutoLock locked(lock_);
+  name_to_interned_name_[kDefaultName] = g_default_name;
+}
+
+ThreadIdNameManager::~ThreadIdNameManager() {
+}
+
+ThreadIdNameManager* ThreadIdNameManager::GetInstance() {
+  return Singleton<ThreadIdNameManager,
+      LeakySingletonTraits<ThreadIdNameManager> >::get();
+}
+
+const char* ThreadIdNameManager::GetDefaultInternedString() {
+  return g_default_name->c_str();
+}
+
+void ThreadIdNameManager::RegisterThread(PlatformThreadHandle::Handle handle,
+                                         PlatformThreadId id) {
+  AutoLock locked(lock_);
+  thread_id_to_handle_[id] = handle;
+  thread_handle_to_interned_name_[handle] =
+      name_to_interned_name_[kDefaultName];
+}
+
+void ThreadIdNameManager::SetName(PlatformThreadId id,
+                                  const std::string& name) {
+  AutoLock locked(lock_);
+  NameToInternedNameMap::iterator iter = name_to_interned_name_.find(name);
+  std::string* leaked_str = NULL;
+  if (iter != name_to_interned_name_.end()) {
+    leaked_str = iter->second;
+  } else {
+    leaked_str = new std::string(name);
+    name_to_interned_name_[name] = leaked_str;
+  }
+
+  ThreadIdToHandleMap::iterator id_to_handle_iter =
+      thread_id_to_handle_.find(id);
+
+  // The main thread of a process will not be created as a Thread object which
+  // means there is no PlatformThreadHandler registered.
+  if (id_to_handle_iter == thread_id_to_handle_.end()) {
+    main_process_name_ = leaked_str;
+    main_process_id_ = id;
+    return;
+  }
+  thread_handle_to_interned_name_[id_to_handle_iter->second] = leaked_str;
+}
+
+const char* ThreadIdNameManager::GetName(PlatformThreadId id) {
+  AutoLock locked(lock_);
+
+  if (id == main_process_id_)
+    return main_process_name_->c_str();
+
+  ThreadIdToHandleMap::iterator id_to_handle_iter =
+      thread_id_to_handle_.find(id);
+  if (id_to_handle_iter == thread_id_to_handle_.end())
+    return name_to_interned_name_[kDefaultName]->c_str();
+
+  ThreadHandleToInternedNameMap::iterator handle_to_name_iter =
+      thread_handle_to_interned_name_.find(id_to_handle_iter->second);
+  return handle_to_name_iter->second->c_str();
+}
+
+void ThreadIdNameManager::RemoveName(PlatformThreadHandle::Handle handle,
+                                     PlatformThreadId id) {
+  AutoLock locked(lock_);
+  ThreadHandleToInternedNameMap::iterator handle_to_name_iter =
+      thread_handle_to_interned_name_.find(handle);
+
+  DCHECK(handle_to_name_iter != thread_handle_to_interned_name_.end());
+  thread_handle_to_interned_name_.erase(handle_to_name_iter);
+
+  ThreadIdToHandleMap::iterator id_to_handle_iter =
+      thread_id_to_handle_.find(id);
+  DCHECK((id_to_handle_iter!= thread_id_to_handle_.end()));
+  // The given |id| may have been re-used by the system. Make sure the
+  // mapping points to the provided |handle| before removal.
+  if (id_to_handle_iter->second != handle)
+    return;
+
+  thread_id_to_handle_.erase(id_to_handle_iter);
+}
+
+}  // namespace base
diff --git a/base/threading/thread_id_name_manager.h b/base/threading/thread_id_name_manager.h
new file mode 100644
index 0000000..927d25f
--- /dev/null
+++ b/base/threading/thread_id_name_manager.h
@@ -0,0 +1,67 @@
+// Copyright (c) 2012 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_THREADING_THREAD_ID_NAME_MANAGER_H_
+#define BASE_THREADING_THREAD_ID_NAME_MANAGER_H_
+
+#include <map>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/platform_thread.h"
+
+template <typename T> struct DefaultSingletonTraits;
+
+namespace base {
+
+class BASE_EXPORT ThreadIdNameManager {
+ public:
+  static ThreadIdNameManager* GetInstance();
+
+  static const char* GetDefaultInternedString();
+
+  // Register the mapping between a thread |id| and |handle|.
+  void RegisterThread(PlatformThreadHandle::Handle handle, PlatformThreadId id);
+
+  // Set the name for the given id.
+  void SetName(PlatformThreadId id, const std::string& name);
+
+  // Get the name for the given id.
+  const char* GetName(PlatformThreadId id);
+
+  // Remove the name for the given id.
+  void RemoveName(PlatformThreadHandle::Handle handle, PlatformThreadId id);
+
+ private:
+  friend struct DefaultSingletonTraits<ThreadIdNameManager>;
+
+  typedef std::map<PlatformThreadId, PlatformThreadHandle::Handle>
+      ThreadIdToHandleMap;
+  typedef std::map<PlatformThreadHandle::Handle, std::string*>
+      ThreadHandleToInternedNameMap;
+  typedef std::map<std::string, std::string*> NameToInternedNameMap;
+
+  ThreadIdNameManager();
+  ~ThreadIdNameManager();
+
+  // lock_ protects the name_to_interned_name_, thread_id_to_handle_ and
+  // thread_handle_to_interned_name_ maps.
+  Lock lock_;
+
+  NameToInternedNameMap name_to_interned_name_;
+  ThreadIdToHandleMap thread_id_to_handle_;
+  ThreadHandleToInternedNameMap thread_handle_to_interned_name_;
+
+  // Treat the main process specially as there is no PlatformThreadHandle.
+  std::string* main_process_name_;
+  PlatformThreadId main_process_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(ThreadIdNameManager);
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_THREAD_ID_NAME_MANAGER_H_
diff --git a/base/threading/thread_id_name_manager_unittest.cc b/base/threading/thread_id_name_manager_unittest.cc
new file mode 100644
index 0000000..b17c681
--- /dev/null
+++ b/base/threading/thread_id_name_manager_unittest.cc
@@ -0,0 +1,93 @@
+// Copyright (c) 2012 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/threading/thread_id_name_manager.h"
+
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+typedef PlatformTest ThreadIdNameManagerTest;
+
+namespace {
+
+const char kAThread[] = "a thread";
+const char kBThread[] = "b thread";
+
+TEST_F(ThreadIdNameManagerTest, AddThreads) {
+  base::ThreadIdNameManager* manager = base::ThreadIdNameManager::GetInstance();
+  base::Thread thread_a(kAThread);
+  base::Thread thread_b(kBThread);
+
+  thread_a.StartAndWaitForTesting();
+  thread_b.StartAndWaitForTesting();
+
+  EXPECT_STREQ(kAThread, manager->GetName(thread_a.thread_id()));
+  EXPECT_STREQ(kBThread, manager->GetName(thread_b.thread_id()));
+
+  thread_b.Stop();
+  thread_a.Stop();
+}
+
+TEST_F(ThreadIdNameManagerTest, RemoveThreads) {
+  base::ThreadIdNameManager* manager = base::ThreadIdNameManager::GetInstance();
+  base::Thread thread_a(kAThread);
+
+  thread_a.StartAndWaitForTesting();
+  {
+    base::Thread thread_b(kBThread);
+    thread_b.StartAndWaitForTesting();
+    thread_b.Stop();
+  }
+  EXPECT_STREQ(kAThread, manager->GetName(thread_a.thread_id()));
+
+  thread_a.Stop();
+  EXPECT_STREQ("", manager->GetName(thread_a.thread_id()));
+}
+
+TEST_F(ThreadIdNameManagerTest, RestartThread) {
+  base::ThreadIdNameManager* manager = base::ThreadIdNameManager::GetInstance();
+  base::Thread thread_a(kAThread);
+
+  thread_a.StartAndWaitForTesting();
+  base::PlatformThreadId a_id = thread_a.thread_id();
+  EXPECT_STREQ(kAThread, manager->GetName(a_id));
+  thread_a.Stop();
+
+  thread_a.StartAndWaitForTesting();
+  EXPECT_STREQ("", manager->GetName(a_id));
+  EXPECT_STREQ(kAThread, manager->GetName(thread_a.thread_id()));
+  thread_a.Stop();
+}
+
+TEST_F(ThreadIdNameManagerTest, ThreadNameInterning) {
+  base::ThreadIdNameManager* manager = base::ThreadIdNameManager::GetInstance();
+
+  base::PlatformThreadId a_id = base::PlatformThread::CurrentId();
+  base::PlatformThread::SetName("First Name");
+  std::string version = manager->GetName(a_id);
+
+  base::PlatformThread::SetName("New name");
+  EXPECT_NE(version, manager->GetName(a_id));
+  base::PlatformThread::SetName("");
+}
+
+TEST_F(ThreadIdNameManagerTest, ResettingNameKeepsCorrectInternedValue) {
+  base::ThreadIdNameManager* manager = base::ThreadIdNameManager::GetInstance();
+
+  base::PlatformThreadId a_id = base::PlatformThread::CurrentId();
+  base::PlatformThread::SetName("Test Name");
+  std::string version = manager->GetName(a_id);
+
+  base::PlatformThread::SetName("New name");
+  EXPECT_NE(version, manager->GetName(a_id));
+
+  base::PlatformThread::SetName("Test Name");
+  EXPECT_EQ(version, manager->GetName(a_id));
+
+  base::PlatformThread::SetName("");
+}
+
+}  // namespace
diff --git a/base/threading/thread_local.h b/base/threading/thread_local.h
new file mode 100644
index 0000000..df9c4b7
--- /dev/null
+++ b/base/threading/thread_local.h
@@ -0,0 +1,133 @@
+// Copyright (c) 2011 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.
+
+// WARNING: Thread local storage is a bit tricky to get right.  Please make
+// sure that this is really the proper solution for what you're trying to
+// achieve.  Don't prematurely optimize, most likely you can just use a Lock.
+//
+// These classes implement a wrapper around the platform's TLS storage
+// mechanism.  On construction, they will allocate a TLS slot, and free the
+// TLS slot on destruction.  No memory management (creation or destruction) is
+// handled.  This means for uses of ThreadLocalPointer, you must correctly
+// manage the memory yourself, these classes will not destroy the pointer for
+// you.  There are no at-thread-exit actions taken by these classes.
+//
+// ThreadLocalPointer<Type> wraps a Type*.  It performs no creation or
+// destruction, so memory management must be handled elsewhere.  The first call
+// to Get() on a thread will return NULL.  You can update the pointer with a
+// call to Set().
+//
+// ThreadLocalBoolean wraps a bool.  It will default to false if it has never
+// been set otherwise with Set().
+//
+// Thread Safety:  An instance of ThreadLocalStorage is completely thread safe
+// once it has been created.  If you want to dynamically create an instance,
+// you must of course properly deal with safety and race conditions.  This
+// means a function-level static initializer is generally inappropiate.
+//
+// In Android, the system TLS is limited, the implementation is backed with
+// ThreadLocalStorage.
+//
+// Example usage:
+//   // My class is logically attached to a single thread.  We cache a pointer
+//   // on the thread it was created on, so we can implement current().
+//   MyClass::MyClass() {
+//     DCHECK(Singleton<ThreadLocalPointer<MyClass> >::get()->Get() == NULL);
+//     Singleton<ThreadLocalPointer<MyClass> >::get()->Set(this);
+//   }
+//
+//   MyClass::~MyClass() {
+//     DCHECK(Singleton<ThreadLocalPointer<MyClass> >::get()->Get() != NULL);
+//     Singleton<ThreadLocalPointer<MyClass> >::get()->Set(NULL);
+//   }
+//
+//   // Return the current MyClass associated with the calling thread, can be
+//   // NULL if there isn't a MyClass associated.
+//   MyClass* MyClass::current() {
+//     return Singleton<ThreadLocalPointer<MyClass> >::get()->Get();
+//   }
+
+#ifndef BASE_THREADING_THREAD_LOCAL_H_
+#define BASE_THREADING_THREAD_LOCAL_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/threading/thread_local_storage.h"
+
+#if defined(OS_POSIX)
+#include <pthread.h>
+#endif
+
+namespace base {
+namespace internal {
+
+// Helper functions that abstract the cross-platform APIs.  Do not use directly.
+struct BASE_EXPORT ThreadLocalPlatform {
+#if defined(OS_WIN)
+  typedef unsigned long SlotType;
+#elif defined(OS_ANDROID)
+  typedef ThreadLocalStorage::StaticSlot SlotType;
+#elif defined(OS_POSIX)
+  typedef pthread_key_t SlotType;
+#endif
+
+  static void AllocateSlot(SlotType* slot);
+  static void FreeSlot(SlotType slot);
+  static void* GetValueFromSlot(SlotType slot);
+  static void SetValueInSlot(SlotType slot, void* value);
+};
+
+}  // namespace internal
+
+template <typename Type>
+class ThreadLocalPointer {
+ public:
+  ThreadLocalPointer() : slot_() {
+    internal::ThreadLocalPlatform::AllocateSlot(&slot_);
+  }
+
+  ~ThreadLocalPointer() {
+    internal::ThreadLocalPlatform::FreeSlot(slot_);
+  }
+
+  Type* Get() {
+    return static_cast<Type*>(
+        internal::ThreadLocalPlatform::GetValueFromSlot(slot_));
+  }
+
+  void Set(Type* ptr) {
+    internal::ThreadLocalPlatform::SetValueInSlot(
+        slot_, const_cast<void*>(static_cast<const void*>(ptr)));
+  }
+
+ private:
+  typedef internal::ThreadLocalPlatform::SlotType SlotType;
+
+  SlotType slot_;
+
+  DISALLOW_COPY_AND_ASSIGN(ThreadLocalPointer<Type>);
+};
+
+class ThreadLocalBoolean {
+ public:
+  ThreadLocalBoolean() {}
+  ~ThreadLocalBoolean() {}
+
+  bool Get() {
+    return tlp_.Get() != NULL;
+  }
+
+  void Set(bool val) {
+    tlp_.Set(val ? this : NULL);
+  }
+
+ private:
+  ThreadLocalPointer<void> tlp_;
+
+  DISALLOW_COPY_AND_ASSIGN(ThreadLocalBoolean);
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_THREAD_LOCAL_H_
diff --git a/base/threading/thread_local_android.cc b/base/threading/thread_local_android.cc
new file mode 100644
index 0000000..813dd78
--- /dev/null
+++ b/base/threading/thread_local_android.cc
@@ -0,0 +1,31 @@
+// 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.
+
+#include "base/threading/thread_local.h"
+
+namespace base {
+namespace internal {
+
+// static
+void ThreadLocalPlatform::AllocateSlot(SlotType* slot) {
+  slot->Initialize(nullptr);
+}
+
+// static
+void ThreadLocalPlatform::FreeSlot(SlotType slot) {
+  slot.Free();
+}
+
+// static
+void* ThreadLocalPlatform::GetValueFromSlot(SlotType slot) {
+  return slot.Get();
+}
+
+// static
+void ThreadLocalPlatform::SetValueInSlot(SlotType slot, void* value) {
+  slot.Set(value);
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/threading/thread_local_posix.cc b/base/threading/thread_local_posix.cc
new file mode 100644
index 0000000..75ea479
--- /dev/null
+++ b/base/threading/thread_local_posix.cc
@@ -0,0 +1,42 @@
+// Copyright (c) 2011 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/threading/thread_local.h"
+
+#include <pthread.h>
+
+#include "base/logging.h"
+
+#if !defined(OS_ANDROID)
+
+namespace base {
+namespace internal {
+
+// static
+void ThreadLocalPlatform::AllocateSlot(SlotType* slot) {
+  int error = pthread_key_create(slot, NULL);
+  CHECK_EQ(error, 0);
+}
+
+// static
+void ThreadLocalPlatform::FreeSlot(SlotType slot) {
+  int error = pthread_key_delete(slot);
+  DCHECK_EQ(0, error);
+}
+
+// static
+void* ThreadLocalPlatform::GetValueFromSlot(SlotType slot) {
+  return pthread_getspecific(slot);
+}
+
+// static
+void ThreadLocalPlatform::SetValueInSlot(SlotType slot, void* value) {
+  int error = pthread_setspecific(slot, value);
+  DCHECK_EQ(error, 0);
+}
+
+}  // namespace internal
+}  // namespace base
+
+#endif  // !defined(OS_ANDROID)
diff --git a/base/threading/thread_local_storage.cc b/base/threading/thread_local_storage.cc
new file mode 100644
index 0000000..0bb396c
--- /dev/null
+++ b/base/threading/thread_local_storage.cc
@@ -0,0 +1,249 @@
+// 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.
+
+#include "base/threading/thread_local_storage.h"
+
+#include "base/atomicops.h"
+#include "base/logging.h"
+
+using base::internal::PlatformThreadLocalStorage;
+
+namespace {
+// In order to make TLS destructors work, we need to keep around a function
+// pointer to the destructor for each slot. We keep this array of pointers in a
+// global (static) array.
+// We use the single OS-level TLS slot (giving us one pointer per thread) to
+// hold a pointer to a per-thread array (table) of slots that we allocate to
+// Chromium consumers.
+
+// g_native_tls_key is the one native TLS that we use.  It stores our table.
+base::subtle::Atomic32 g_native_tls_key =
+    PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES;
+
+// g_last_used_tls_key is the high-water-mark of allocated thread local storage.
+// Each allocation is an index into our g_tls_destructors[].  Each such index is
+// assigned to the instance variable slot_ in a ThreadLocalStorage::Slot
+// instance.  We reserve the value slot_ == 0 to indicate that the corresponding
+// instance of ThreadLocalStorage::Slot has been freed (i.e., destructor called,
+// etc.).  This reserved use of 0 is then stated as the initial value of
+// g_last_used_tls_key, so that the first issued index will be 1.
+base::subtle::Atomic32 g_last_used_tls_key = 0;
+
+// The maximum number of 'slots' in our thread local storage stack.
+const int kThreadLocalStorageSize = 256;
+
+// The maximum number of times to try to clear slots by calling destructors.
+// Use pthread naming convention for clarity.
+const int kMaxDestructorIterations = kThreadLocalStorageSize;
+
+// An array of destructor function pointers for the slots.  If a slot has a
+// destructor, it will be stored in its corresponding entry in this array.
+// The elements are volatile to ensure that when the compiler reads the value
+// to potentially call the destructor, it does so once, and that value is tested
+// for null-ness and then used. Yes, that would be a weird de-optimization,
+// but I can imagine some register machines where it was just as easy to
+// re-fetch an array element, and I want to be sure a call to free the key
+// (i.e., null out the destructor entry) that happens on a separate thread can't
+// hurt the racy calls to the destructors on another thread.
+volatile base::ThreadLocalStorage::TLSDestructorFunc
+    g_tls_destructors[kThreadLocalStorageSize];
+
+// This function is called to initialize our entire Chromium TLS system.
+// It may be called very early, and we need to complete most all of the setup
+// (initialization) before calling *any* memory allocator functions, which may
+// recursively depend on this initialization.
+// As a result, we use Atomics, and avoid anything (like a singleton) that might
+// require memory allocations.
+void** ConstructTlsVector() {
+  PlatformThreadLocalStorage::TLSKey key =
+      base::subtle::NoBarrier_Load(&g_native_tls_key);
+  if (key == PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES) {
+    CHECK(PlatformThreadLocalStorage::AllocTLS(&key));
+
+    // The TLS_KEY_OUT_OF_INDEXES is used to find out whether the key is set or
+    // not in NoBarrier_CompareAndSwap, but Posix doesn't have invalid key, we
+    // define an almost impossible value be it.
+    // If we really get TLS_KEY_OUT_OF_INDEXES as value of key, just alloc
+    // another TLS slot.
+    if (key == PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES) {
+      PlatformThreadLocalStorage::TLSKey tmp = key;
+      CHECK(PlatformThreadLocalStorage::AllocTLS(&key) &&
+            key != PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES);
+      PlatformThreadLocalStorage::FreeTLS(tmp);
+    }
+    // Atomically test-and-set the tls_key.  If the key is
+    // TLS_KEY_OUT_OF_INDEXES, go ahead and set it.  Otherwise, do nothing, as
+    // another thread already did our dirty work.
+    if (PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES !=
+        base::subtle::NoBarrier_CompareAndSwap(&g_native_tls_key,
+            PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES, key)) {
+      // We've been shortcut. Another thread replaced g_native_tls_key first so
+      // we need to destroy our index and use the one the other thread got
+      // first.
+      PlatformThreadLocalStorage::FreeTLS(key);
+      key = base::subtle::NoBarrier_Load(&g_native_tls_key);
+    }
+  }
+  CHECK(!PlatformThreadLocalStorage::GetTLSValue(key));
+
+  // Some allocators, such as TCMalloc, make use of thread local storage.
+  // As a result, any attempt to call new (or malloc) will lazily cause such a
+  // system to initialize, which will include registering for a TLS key.  If we
+  // are not careful here, then that request to create a key will call new back,
+  // and we'll have an infinite loop.  We avoid that as follows:
+  // Use a stack allocated vector, so that we don't have dependence on our
+  // allocator until our service is in place.  (i.e., don't even call new until
+  // after we're setup)
+  void* stack_allocated_tls_data[kThreadLocalStorageSize];
+  memset(stack_allocated_tls_data, 0, sizeof(stack_allocated_tls_data));
+  // Ensure that any rentrant calls change the temp version.
+  PlatformThreadLocalStorage::SetTLSValue(key, stack_allocated_tls_data);
+
+  // Allocate an array to store our data.
+  void** tls_data = new void*[kThreadLocalStorageSize];
+  memcpy(tls_data, stack_allocated_tls_data, sizeof(stack_allocated_tls_data));
+  PlatformThreadLocalStorage::SetTLSValue(key, tls_data);
+  return tls_data;
+}
+
+void OnThreadExitInternal(void* value) {
+  DCHECK(value);
+  void** tls_data = static_cast<void**>(value);
+  // Some allocators, such as TCMalloc, use TLS.  As a result, when a thread
+  // terminates, one of the destructor calls we make may be to shut down an
+  // allocator.  We have to be careful that after we've shutdown all of the
+  // known destructors (perchance including an allocator), that we don't call
+  // the allocator and cause it to resurrect itself (with no possibly destructor
+  // call to follow).  We handle this problem as follows:
+  // Switch to using a stack allocated vector, so that we don't have dependence
+  // on our allocator after we have called all g_tls_destructors.  (i.e., don't
+  // even call delete[] after we're done with destructors.)
+  void* stack_allocated_tls_data[kThreadLocalStorageSize];
+  memcpy(stack_allocated_tls_data, tls_data, sizeof(stack_allocated_tls_data));
+  // Ensure that any re-entrant calls change the temp version.
+  PlatformThreadLocalStorage::TLSKey key =
+      base::subtle::NoBarrier_Load(&g_native_tls_key);
+  PlatformThreadLocalStorage::SetTLSValue(key, stack_allocated_tls_data);
+  delete[] tls_data;  // Our last dependence on an allocator.
+
+  int remaining_attempts = kMaxDestructorIterations;
+  bool need_to_scan_destructors = true;
+  while (need_to_scan_destructors) {
+    need_to_scan_destructors = false;
+    // Try to destroy the first-created-slot (which is slot 1) in our last
+    // destructor call.  That user was able to function, and define a slot with
+    // no other services running, so perhaps it is a basic service (like an
+    // allocator) and should also be destroyed last.  If we get the order wrong,
+    // then we'll itterate several more times, so it is really not that
+    // critical (but it might help).
+    base::subtle::Atomic32 last_used_tls_key =
+        base::subtle::NoBarrier_Load(&g_last_used_tls_key);
+    for (int slot = last_used_tls_key; slot > 0; --slot) {
+      void* tls_value = stack_allocated_tls_data[slot];
+      if (tls_value == NULL)
+        continue;
+
+      base::ThreadLocalStorage::TLSDestructorFunc destructor =
+          g_tls_destructors[slot];
+      if (destructor == NULL)
+        continue;
+      stack_allocated_tls_data[slot] = NULL;  // pre-clear the slot.
+      destructor(tls_value);
+      // Any destructor might have called a different service, which then set
+      // a different slot to a non-NULL value.  Hence we need to check
+      // the whole vector again.  This is a pthread standard.
+      need_to_scan_destructors = true;
+    }
+    if (--remaining_attempts <= 0) {
+      NOTREACHED();  // Destructors might not have been called.
+      break;
+    }
+  }
+
+  // Remove our stack allocated vector.
+  PlatformThreadLocalStorage::SetTLSValue(key, NULL);
+}
+
+}  // namespace
+
+namespace base {
+
+namespace internal {
+
+#if defined(OS_WIN)
+void PlatformThreadLocalStorage::OnThreadExit() {
+  PlatformThreadLocalStorage::TLSKey key =
+      base::subtle::NoBarrier_Load(&g_native_tls_key);
+  if (key == PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES)
+    return;
+  void *tls_data = GetTLSValue(key);
+  // Maybe we have never initialized TLS for this thread.
+  if (!tls_data)
+    return;
+  OnThreadExitInternal(tls_data);
+}
+#elif defined(OS_POSIX)
+void PlatformThreadLocalStorage::OnThreadExit(void* value) {
+  OnThreadExitInternal(value);
+}
+#endif  // defined(OS_WIN)
+
+}  // namespace internal
+
+ThreadLocalStorage::Slot::Slot(TLSDestructorFunc destructor) {
+  initialized_ = false;
+  slot_ = 0;
+  Initialize(destructor);
+}
+
+void ThreadLocalStorage::StaticSlot::Initialize(TLSDestructorFunc destructor) {
+  PlatformThreadLocalStorage::TLSKey key =
+      base::subtle::NoBarrier_Load(&g_native_tls_key);
+  if (key == PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES ||
+      !PlatformThreadLocalStorage::GetTLSValue(key))
+    ConstructTlsVector();
+
+  // Grab a new slot.
+  slot_ = base::subtle::NoBarrier_AtomicIncrement(&g_last_used_tls_key, 1);
+  DCHECK_GT(slot_, 0);
+  CHECK_LT(slot_, kThreadLocalStorageSize);
+
+  // Setup our destructor.
+  g_tls_destructors[slot_] = destructor;
+  initialized_ = true;
+}
+
+void ThreadLocalStorage::StaticSlot::Free() {
+  // At this time, we don't reclaim old indices for TLS slots.
+  // So all we need to do is wipe the destructor.
+  DCHECK_GT(slot_, 0);
+  DCHECK_LT(slot_, kThreadLocalStorageSize);
+  g_tls_destructors[slot_] = NULL;
+  slot_ = 0;
+  initialized_ = false;
+}
+
+void* ThreadLocalStorage::StaticSlot::Get() const {
+  void** tls_data = static_cast<void**>(
+      PlatformThreadLocalStorage::GetTLSValue(
+          base::subtle::NoBarrier_Load(&g_native_tls_key)));
+  if (!tls_data)
+    tls_data = ConstructTlsVector();
+  DCHECK_GT(slot_, 0);
+  DCHECK_LT(slot_, kThreadLocalStorageSize);
+  return tls_data[slot_];
+}
+
+void ThreadLocalStorage::StaticSlot::Set(void* value) {
+  void** tls_data = static_cast<void**>(
+      PlatformThreadLocalStorage::GetTLSValue(
+          base::subtle::NoBarrier_Load(&g_native_tls_key)));
+  if (!tls_data)
+    tls_data = ConstructTlsVector();
+  DCHECK_GT(slot_, 0);
+  DCHECK_LT(slot_, kThreadLocalStorageSize);
+  tls_data[slot_] = value;
+}
+
+}  // namespace base
diff --git a/base/threading/thread_local_storage.h b/base/threading/thread_local_storage.h
new file mode 100644
index 0000000..50f8868
--- /dev/null
+++ b/base/threading/thread_local_storage.h
@@ -0,0 +1,144 @@
+// Copyright (c) 2012 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_THREADING_THREAD_LOCAL_STORAGE_H_
+#define BASE_THREADING_THREAD_LOCAL_STORAGE_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#elif defined(OS_POSIX)
+#include <pthread.h>
+#endif
+
+namespace base {
+
+namespace internal {
+
+// WARNING: You should *NOT* be using this class directly.
+// PlatformThreadLocalStorage is low-level abstraction to the OS's TLS
+// interface, you should instead be using ThreadLocalStorage::StaticSlot/Slot.
+class BASE_EXPORT PlatformThreadLocalStorage {
+ public:
+
+#if defined(OS_WIN)
+  typedef unsigned long TLSKey;
+  enum { TLS_KEY_OUT_OF_INDEXES = TLS_OUT_OF_INDEXES };
+#elif defined(OS_POSIX)
+  typedef pthread_key_t TLSKey;
+  // The following is a "reserved key" which is used in our generic Chromium
+  // ThreadLocalStorage implementation.  We expect that an OS will not return
+  // such a key, but if it is returned (i.e., the OS tries to allocate it) we
+  // will just request another key.
+  enum { TLS_KEY_OUT_OF_INDEXES = 0x7FFFFFFF };
+#endif
+
+  // The following methods need to be supported on each OS platform, so that
+  // the Chromium ThreadLocalStore functionality can be constructed.
+  // Chromium will use these methods to acquire a single OS slot, and then use
+  // that to support a much larger number of Chromium slots (independent of the
+  // OS restrictions).
+  // The following returns true if it successfully is able to return an OS
+  // key in |key|.
+  static bool AllocTLS(TLSKey* key);
+  // Note: FreeTLS() doesn't have to be called, it is fine with this leak, OS
+  // might not reuse released slot, you might just reset the TLS value with
+  // SetTLSValue().
+  static void FreeTLS(TLSKey key);
+  static void SetTLSValue(TLSKey key, void* value);
+  static void* GetTLSValue(TLSKey key);
+
+  // Each platform (OS implementation) is required to call this method on each
+  // terminating thread when the thread is about to terminate.  This method
+  // will then call all registered destructors for slots in Chromium
+  // ThreadLocalStorage, until there are no slot values remaining as having
+  // been set on this thread.
+  // Destructors may end up being called multiple times on a terminating
+  // thread, as other destructors may re-set slots that were previously
+  // destroyed.
+#if defined(OS_WIN)
+  // Since Windows which doesn't support TLS destructor, the implementation
+  // should use GetTLSValue() to retrieve the value of TLS slot.
+  static void OnThreadExit();
+#elif defined(OS_POSIX)
+  // |Value| is the data stored in TLS slot, The implementation can't use
+  // GetTLSValue() to retrieve the value of slot as it has already been reset
+  // in Posix.
+  static void OnThreadExit(void* value);
+#endif
+};
+
+}  // namespace internal
+
+// Wrapper for thread local storage.  This class doesn't do much except provide
+// an API for portability.
+class BASE_EXPORT ThreadLocalStorage {
+ public:
+
+  // Prototype for the TLS destructor function, which can be optionally used to
+  // cleanup thread local storage on thread exit.  'value' is the data that is
+  // stored in thread local storage.
+  typedef void (*TLSDestructorFunc)(void* value);
+
+  // StaticSlot uses its own struct initializer-list style static
+  // initialization, as base's LINKER_INITIALIZED requires a constructor and on
+  // some compilers (notably gcc 4.4) this still ends up needing runtime
+  // initialization.
+  #define TLS_INITIALIZER {0}
+
+  // A key representing one value stored in TLS.
+  // Initialize like
+  //   ThreadLocalStorage::StaticSlot my_slot = TLS_INITIALIZER;
+  // If you're not using a static variable, use the convenience class
+  // ThreadLocalStorage::Slot (below) instead.
+  struct BASE_EXPORT StaticSlot {
+    // Set up the TLS slot.  Called by the constructor.
+    // 'destructor' is a pointer to a function to perform per-thread cleanup of
+    // this object.  If set to NULL, no cleanup is done for this TLS slot.
+    void Initialize(TLSDestructorFunc destructor);
+
+    // Free a previously allocated TLS 'slot'.
+    // If a destructor was set for this slot, removes
+    // the destructor so that remaining threads exiting
+    // will not free data.
+    void Free();
+
+    // Get the thread-local value stored in slot 'slot'.
+    // Values are guaranteed to initially be zero.
+    void* Get() const;
+
+    // Set the thread-local value stored in slot 'slot' to
+    // value 'value'.
+    void Set(void* value);
+
+    bool initialized() const { return initialized_; }
+
+    // The internals of this struct should be considered private.
+    bool initialized_;
+    int slot_;
+  };
+
+  // A convenience wrapper around StaticSlot with a constructor. Can be used
+  // as a member variable.
+  class BASE_EXPORT Slot : public StaticSlot {
+   public:
+    // Calls StaticSlot::Initialize().
+    explicit Slot(TLSDestructorFunc destructor = NULL);
+
+   private:
+    using StaticSlot::initialized_;
+    using StaticSlot::slot_;
+
+    DISALLOW_COPY_AND_ASSIGN(Slot);
+  };
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ThreadLocalStorage);
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_THREAD_LOCAL_STORAGE_H_
diff --git a/base/threading/thread_local_storage_posix.cc b/base/threading/thread_local_storage_posix.cc
new file mode 100644
index 0000000..ebaf400
--- /dev/null
+++ b/base/threading/thread_local_storage_posix.cc
@@ -0,0 +1,34 @@
+// Copyright (c) 2012 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/threading/thread_local_storage.h"
+
+#include "base/logging.h"
+
+namespace base {
+
+namespace internal {
+
+bool PlatformThreadLocalStorage::AllocTLS(TLSKey* key) {
+  return !pthread_key_create(key,
+      base::internal::PlatformThreadLocalStorage::OnThreadExit);
+}
+
+void PlatformThreadLocalStorage::FreeTLS(TLSKey key) {
+  int ret = pthread_key_delete(key);
+  DCHECK_EQ(ret, 0);
+}
+
+void* PlatformThreadLocalStorage::GetTLSValue(TLSKey key) {
+  return pthread_getspecific(key);
+}
+
+void PlatformThreadLocalStorage::SetTLSValue(TLSKey key, void* value) {
+  int ret = pthread_setspecific(key, value);
+  DCHECK_EQ(ret, 0);
+}
+
+}  // namespace internal
+
+}  // namespace base
diff --git a/base/threading/thread_local_storage_unittest.cc b/base/threading/thread_local_storage_unittest.cc
new file mode 100644
index 0000000..bcc1d1b
--- /dev/null
+++ b/base/threading/thread_local_storage_unittest.cc
@@ -0,0 +1,128 @@
+// Copyright (c) 2012 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.
+
+#if defined(OS_WIN)
+#include <windows.h>
+#include <process.h>
+#endif
+
+#include "base/threading/simple_thread.h"
+#include "base/threading/thread_local_storage.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_WIN)
+// Ignore warnings about ptr->int conversions that we use when
+// storing ints into ThreadLocalStorage.
+#pragma warning(disable : 4311 4312)
+#endif
+
+namespace base {
+
+namespace {
+
+const int kInitialTlsValue = 0x5555;
+const int kFinalTlsValue = 0x7777;
+// How many times must a destructor be called before we really are done.
+const int kNumberDestructorCallRepetitions = 3;
+
+static ThreadLocalStorage::StaticSlot tls_slot = TLS_INITIALIZER;
+
+class ThreadLocalStorageRunner : public DelegateSimpleThread::Delegate {
+ public:
+  explicit ThreadLocalStorageRunner(int* tls_value_ptr)
+      : tls_value_ptr_(tls_value_ptr) {}
+
+  ~ThreadLocalStorageRunner() override {}
+
+  void Run() override {
+    *tls_value_ptr_ = kInitialTlsValue;
+    tls_slot.Set(tls_value_ptr_);
+
+    int *ptr = static_cast<int*>(tls_slot.Get());
+    EXPECT_EQ(ptr, tls_value_ptr_);
+    EXPECT_EQ(*ptr, kInitialTlsValue);
+    *tls_value_ptr_ = 0;
+
+    ptr = static_cast<int*>(tls_slot.Get());
+    EXPECT_EQ(ptr, tls_value_ptr_);
+    EXPECT_EQ(*ptr, 0);
+
+    *ptr = kFinalTlsValue + kNumberDestructorCallRepetitions;
+  }
+
+ private:
+  int* tls_value_ptr_;
+  DISALLOW_COPY_AND_ASSIGN(ThreadLocalStorageRunner);
+};
+
+
+void ThreadLocalStorageCleanup(void *value) {
+  int *ptr = reinterpret_cast<int*>(value);
+  // Destructors should never be called with a NULL.
+  ASSERT_NE(reinterpret_cast<int*>(NULL), ptr);
+  if (*ptr == kFinalTlsValue)
+    return;  // We've been called enough times.
+  ASSERT_LT(kFinalTlsValue, *ptr);
+  ASSERT_GE(kFinalTlsValue + kNumberDestructorCallRepetitions, *ptr);
+  --*ptr;  // Move closer to our target.
+  // Tell tls that we're not done with this thread, and still need destruction.
+  tls_slot.Set(value);
+}
+
+}  // namespace
+
+TEST(ThreadLocalStorageTest, Basics) {
+  ThreadLocalStorage::Slot slot;
+  slot.Set(reinterpret_cast<void*>(123));
+  int value = reinterpret_cast<intptr_t>(slot.Get());
+  EXPECT_EQ(value, 123);
+}
+
+#if defined(THREAD_SANITIZER) || \
+    (defined(OS_WIN) && defined(ARCH_CPU_X86_64) && !defined(NDEBUG))
+// Do not run the test under ThreadSanitizer. Because this test iterates its
+// own TSD destructor for the maximum possible number of times, TSan can't jump
+// in after the last destructor invocation, therefore the destructor remains
+// unsynchronized with the following users of the same TSD slot. This results
+// in race reports between the destructor and functions in other tests.
+//
+// It is disabled on Win x64 with incremental linking (i.e. "Debug") pending
+// resolution of http://crbug.com/251251.
+#define MAYBE_TLSDestructors DISABLED_TLSDestructors
+#else
+#define MAYBE_TLSDestructors TLSDestructors
+#endif
+TEST(ThreadLocalStorageTest, MAYBE_TLSDestructors) {
+  // Create a TLS index with a destructor.  Create a set of
+  // threads that set the TLS, while the destructor cleans it up.
+  // After the threads finish, verify that the value is cleaned up.
+  const int kNumThreads = 5;
+  int values[kNumThreads];
+  ThreadLocalStorageRunner* thread_delegates[kNumThreads];
+  DelegateSimpleThread* threads[kNumThreads];
+
+  tls_slot.Initialize(ThreadLocalStorageCleanup);
+
+  // Spawn the threads.
+  for (int index = 0; index < kNumThreads; index++) {
+    values[index] = kInitialTlsValue;
+    thread_delegates[index] = new ThreadLocalStorageRunner(&values[index]);
+    threads[index] = new DelegateSimpleThread(thread_delegates[index],
+                                              "tls thread");
+    threads[index]->Start();
+  }
+
+  // Wait for the threads to finish.
+  for (int index = 0; index < kNumThreads; index++) {
+    threads[index]->Join();
+    delete threads[index];
+    delete thread_delegates[index];
+
+    // Verify that the destructor was called and that we reset.
+    EXPECT_EQ(values[index], kFinalTlsValue);
+  }
+  tls_slot.Free();  // Stop doing callbacks to cleanup threads.
+}
+
+}  // namespace base
diff --git a/base/threading/thread_local_storage_win.cc b/base/threading/thread_local_storage_win.cc
new file mode 100644
index 0000000..42a7d01
--- /dev/null
+++ b/base/threading/thread_local_storage_win.cc
@@ -0,0 +1,111 @@
+// Copyright (c) 2012 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/threading/thread_local_storage.h"
+
+#include <windows.h>
+
+#include "base/logging.h"
+
+namespace base {
+
+namespace internal {
+
+bool PlatformThreadLocalStorage::AllocTLS(TLSKey* key) {
+  TLSKey value = TlsAlloc();
+  if (value != TLS_OUT_OF_INDEXES) {
+    *key = value;
+    return true;
+  }
+  return false;
+}
+
+void PlatformThreadLocalStorage::FreeTLS(TLSKey key) {
+  BOOL ret = TlsFree(key);
+  DCHECK(ret);
+}
+
+void* PlatformThreadLocalStorage::GetTLSValue(TLSKey key) {
+  return TlsGetValue(key);
+}
+
+void PlatformThreadLocalStorage::SetTLSValue(TLSKey key, void* value) {
+  BOOL ret = TlsSetValue(key, value);
+  DCHECK(ret);
+}
+
+}  // namespace internal
+
+}  // namespace base
+
+// Thread Termination Callbacks.
+// Windows doesn't support a per-thread destructor with its
+// TLS primitives.  So, we build it manually by inserting a
+// function to be called on each thread's exit.
+// This magic is from http://www.codeproject.com/threads/tls.asp
+// and it works for VC++ 7.0 and later.
+
+// Force a reference to _tls_used to make the linker create the TLS directory
+// if it's not already there.  (e.g. if __declspec(thread) is not used).
+// Force a reference to p_thread_callback_base to prevent whole program
+// optimization from discarding the variable.
+#ifdef _WIN64
+
+#pragma comment(linker, "/INCLUDE:_tls_used")
+#pragma comment(linker, "/INCLUDE:p_thread_callback_base")
+
+#else  // _WIN64
+
+#pragma comment(linker, "/INCLUDE:__tls_used")
+#pragma comment(linker, "/INCLUDE:_p_thread_callback_base")
+
+#endif  // _WIN64
+
+// Static callback function to call with each thread termination.
+void NTAPI OnThreadExit(PVOID module, DWORD reason, PVOID reserved) {
+  // On XP SP0 & SP1, the DLL_PROCESS_ATTACH is never seen. It is sent on SP2+
+  // and on W2K and W2K3. So don't assume it is sent.
+  if (DLL_THREAD_DETACH == reason || DLL_PROCESS_DETACH == reason)
+    base::internal::PlatformThreadLocalStorage::OnThreadExit();
+}
+
+// .CRT$XLA to .CRT$XLZ is an array of PIMAGE_TLS_CALLBACK pointers that are
+// called automatically by the OS loader code (not the CRT) when the module is
+// loaded and on thread creation. They are NOT called if the module has been
+// loaded by a LoadLibrary() call. It must have implicitly been loaded at
+// process startup.
+// By implicitly loaded, I mean that it is directly referenced by the main EXE
+// or by one of its dependent DLLs. Delay-loaded DLL doesn't count as being
+// implicitly loaded.
+//
+// See VC\crt\src\tlssup.c for reference.
+
+// extern "C" suppresses C++ name mangling so we know the symbol name for the
+// linker /INCLUDE:symbol pragma above.
+extern "C" {
+// The linker must not discard p_thread_callback_base.  (We force a reference
+// to this variable with a linker /INCLUDE:symbol pragma to ensure that.) If
+// this variable is discarded, the OnThreadExit function will never be called.
+#ifdef _WIN64
+
+// .CRT section is merged with .rdata on x64 so it must be constant data.
+#pragma const_seg(".CRT$XLB")
+// When defining a const variable, it must have external linkage to be sure the
+// linker doesn't discard it.
+extern const PIMAGE_TLS_CALLBACK p_thread_callback_base;
+const PIMAGE_TLS_CALLBACK p_thread_callback_base = OnThreadExit;
+
+// Reset the default section.
+#pragma const_seg()
+
+#else  // _WIN64
+
+#pragma data_seg(".CRT$XLB")
+PIMAGE_TLS_CALLBACK p_thread_callback_base = OnThreadExit;
+
+// Reset the default section.
+#pragma data_seg()
+
+#endif  // _WIN64
+}  // extern "C"
diff --git a/base/threading/thread_local_unittest.cc b/base/threading/thread_local_unittest.cc
new file mode 100644
index 0000000..e94c1db
--- /dev/null
+++ b/base/threading/thread_local_unittest.cc
@@ -0,0 +1,168 @@
+// Copyright (c) 2012 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/logging.h"
+#include "base/threading/simple_thread.h"
+#include "base/threading/thread_local.h"
+#include "base/synchronization/waitable_event.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+class ThreadLocalTesterBase : public base::DelegateSimpleThreadPool::Delegate {
+ public:
+  typedef base::ThreadLocalPointer<char> TLPType;
+
+  ThreadLocalTesterBase(TLPType* tlp, base::WaitableEvent* done)
+      : tlp_(tlp),
+        done_(done) {
+  }
+  ~ThreadLocalTesterBase() override {}
+
+ protected:
+  TLPType* tlp_;
+  base::WaitableEvent* done_;
+};
+
+class SetThreadLocal : public ThreadLocalTesterBase {
+ public:
+  SetThreadLocal(TLPType* tlp, base::WaitableEvent* done)
+      : ThreadLocalTesterBase(tlp, done),
+        val_(NULL) {
+  }
+  ~SetThreadLocal() override {}
+
+  void set_value(char* val) { val_ = val; }
+
+  void Run() override {
+    DCHECK(!done_->IsSignaled());
+    tlp_->Set(val_);
+    done_->Signal();
+  }
+
+ private:
+  char* val_;
+};
+
+class GetThreadLocal : public ThreadLocalTesterBase {
+ public:
+  GetThreadLocal(TLPType* tlp, base::WaitableEvent* done)
+      : ThreadLocalTesterBase(tlp, done),
+        ptr_(NULL) {
+  }
+  ~GetThreadLocal() override {}
+
+  void set_ptr(char** ptr) { ptr_ = ptr; }
+
+  void Run() override {
+    DCHECK(!done_->IsSignaled());
+    *ptr_ = tlp_->Get();
+    done_->Signal();
+  }
+
+ private:
+  char** ptr_;
+};
+
+}  // namespace
+
+// In this test, we start 2 threads which will access a ThreadLocalPointer.  We
+// make sure the default is NULL, and the pointers are unique to the threads.
+TEST(ThreadLocalTest, Pointer) {
+  base::DelegateSimpleThreadPool tp1("ThreadLocalTest tp1", 1);
+  base::DelegateSimpleThreadPool tp2("ThreadLocalTest tp1", 1);
+  tp1.Start();
+  tp2.Start();
+
+  base::ThreadLocalPointer<char> tlp;
+
+  static char* const kBogusPointer = reinterpret_cast<char*>(0x1234);
+
+  char* tls_val;
+  base::WaitableEvent done(true, false);
+
+  GetThreadLocal getter(&tlp, &done);
+  getter.set_ptr(&tls_val);
+
+  // Check that both threads defaulted to NULL.
+  tls_val = kBogusPointer;
+  done.Reset();
+  tp1.AddWork(&getter);
+  done.Wait();
+  EXPECT_EQ(static_cast<char*>(NULL), tls_val);
+
+  tls_val = kBogusPointer;
+  done.Reset();
+  tp2.AddWork(&getter);
+  done.Wait();
+  EXPECT_EQ(static_cast<char*>(NULL), tls_val);
+
+
+  SetThreadLocal setter(&tlp, &done);
+  setter.set_value(kBogusPointer);
+
+  // Have thread 1 set their pointer value to kBogusPointer.
+  done.Reset();
+  tp1.AddWork(&setter);
+  done.Wait();
+
+  tls_val = NULL;
+  done.Reset();
+  tp1.AddWork(&getter);
+  done.Wait();
+  EXPECT_EQ(kBogusPointer, tls_val);
+
+  // Make sure thread 2 is still NULL
+  tls_val = kBogusPointer;
+  done.Reset();
+  tp2.AddWork(&getter);
+  done.Wait();
+  EXPECT_EQ(static_cast<char*>(NULL), tls_val);
+
+  // Set thread 2 to kBogusPointer + 1.
+  setter.set_value(kBogusPointer + 1);
+
+  done.Reset();
+  tp2.AddWork(&setter);
+  done.Wait();
+
+  tls_val = NULL;
+  done.Reset();
+  tp2.AddWork(&getter);
+  done.Wait();
+  EXPECT_EQ(kBogusPointer + 1, tls_val);
+
+  // Make sure thread 1 is still kBogusPointer.
+  tls_val = NULL;
+  done.Reset();
+  tp1.AddWork(&getter);
+  done.Wait();
+  EXPECT_EQ(kBogusPointer, tls_val);
+
+  tp1.JoinAll();
+  tp2.JoinAll();
+}
+
+TEST(ThreadLocalTest, Boolean) {
+  {
+    base::ThreadLocalBoolean tlb;
+    EXPECT_FALSE(tlb.Get());
+
+    tlb.Set(false);
+    EXPECT_FALSE(tlb.Get());
+
+    tlb.Set(true);
+    EXPECT_TRUE(tlb.Get());
+  }
+
+  // Our slot should have been freed, we're all reset.
+  {
+    base::ThreadLocalBoolean tlb;
+    EXPECT_FALSE(tlb.Get());
+  }
+}
+
+}  // namespace base
diff --git a/base/threading/thread_local_win.cc b/base/threading/thread_local_win.cc
new file mode 100644
index 0000000..1c74e42
--- /dev/null
+++ b/base/threading/thread_local_win.cc
@@ -0,0 +1,40 @@
+// Copyright (c) 2010 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/threading/thread_local.h"
+
+#include <windows.h>
+
+#include "base/logging.h"
+
+namespace base {
+namespace internal {
+
+// static
+void ThreadLocalPlatform::AllocateSlot(SlotType* slot) {
+  *slot = TlsAlloc();
+  CHECK_NE(*slot, TLS_OUT_OF_INDEXES);
+}
+
+// static
+void ThreadLocalPlatform::FreeSlot(SlotType slot) {
+  if (!TlsFree(slot)) {
+    NOTREACHED() << "Failed to deallocate tls slot with TlsFree().";
+  }
+}
+
+// static
+void* ThreadLocalPlatform::GetValueFromSlot(SlotType slot) {
+  return TlsGetValue(slot);
+}
+
+// static
+void ThreadLocalPlatform::SetValueInSlot(SlotType slot, void* value) {
+  if (!TlsSetValue(slot, value)) {
+    LOG(FATAL) << "Failed to TlsSetValue().";
+  }
+}
+
+}  // namespace internal
+}  // namespace base
diff --git a/base/threading/thread_perftest.cc b/base/threading/thread_perftest.cc
new file mode 100644
index 0000000..e865ffa
--- /dev/null
+++ b/base/threading/thread_perftest.cc
@@ -0,0 +1,308 @@
+// 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.
+
+#include "base/base_switches.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/location.h"
+#include "base/memory/scoped_vector.h"
+#include "base/single_thread_task_runner.h"
+#include "base/strings/stringprintf.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/perf/perf_test.h"
+
+#if defined(OS_POSIX)
+#include <pthread.h>
+#endif
+
+namespace base {
+
+namespace {
+
+const int kNumRuns = 100000;
+
+// Base class for a threading perf-test. This sets up some threads for the
+// test and measures the clock-time in addition to time spent on each thread.
+class ThreadPerfTest : public testing::Test {
+ public:
+  ThreadPerfTest()
+      : done_(false, false) {
+    // Disable the task profiler as it adds significant cost!
+    CommandLine::Init(0, NULL);
+    CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+        switches::kProfilerTiming,
+        switches::kProfilerTimingDisabledValue);
+  }
+
+  // To be implemented by each test. Subclass must uses threads_ such that
+  // their cpu-time can be measured. Test must return from PingPong() _and_
+  // call FinishMeasurement from any thread to complete the test.
+  virtual void Init() {}
+  virtual void PingPong(int hops) = 0;
+  virtual void Reset() {}
+
+  void TimeOnThread(base::ThreadTicks* ticks, base::WaitableEvent* done) {
+    *ticks = base::ThreadTicks::Now();
+    done->Signal();
+  }
+
+  base::ThreadTicks ThreadNow(base::Thread* thread) {
+    base::WaitableEvent done(false, false);
+    base::ThreadTicks ticks;
+    thread->task_runner()->PostTask(
+        FROM_HERE, base::Bind(&ThreadPerfTest::TimeOnThread,
+                              base::Unretained(this), &ticks, &done));
+    done.Wait();
+    return ticks;
+  }
+
+  void RunPingPongTest(const std::string& name, unsigned num_threads) {
+    // Create threads and collect starting cpu-time for each thread.
+    std::vector<base::ThreadTicks> thread_starts;
+    while (threads_.size() < num_threads) {
+      threads_.push_back(new base::Thread("PingPonger"));
+      threads_.back()->Start();
+      if (base::ThreadTicks::IsSupported())
+        thread_starts.push_back(ThreadNow(threads_.back()));
+    }
+
+    Init();
+
+    base::TimeTicks start = base::TimeTicks::Now();
+    PingPong(kNumRuns);
+    done_.Wait();
+    base::TimeTicks end = base::TimeTicks::Now();
+
+    // Gather the cpu-time spent on each thread. This does one extra tasks,
+    // but that should be in the noise given enough runs.
+    base::TimeDelta thread_time;
+    while (threads_.size()) {
+      if (base::ThreadTicks::IsSupported()) {
+        thread_time += ThreadNow(threads_.back()) - thread_starts.back();
+        thread_starts.pop_back();
+      }
+      threads_.pop_back();
+    }
+
+    Reset();
+
+    double num_runs = static_cast<double>(kNumRuns);
+    double us_per_task_clock = (end - start).InMicroseconds() / num_runs;
+    double us_per_task_cpu = thread_time.InMicroseconds() / num_runs;
+
+    // Clock time per task.
+    perf_test::PrintResult(
+        "task", "", name + "_time ", us_per_task_clock, "us/hop", true);
+
+    // Total utilization across threads if available (likely higher).
+    if (base::ThreadTicks::IsSupported()) {
+      perf_test::PrintResult(
+          "task", "", name + "_cpu ", us_per_task_cpu, "us/hop", true);
+    }
+  }
+
+ protected:
+  void FinishMeasurement() { done_.Signal(); }
+  ScopedVector<base::Thread> threads_;
+
+ private:
+  base::WaitableEvent done_;
+};
+
+// Class to test task performance by posting empty tasks back and forth.
+class TaskPerfTest : public ThreadPerfTest {
+  base::Thread* NextThread(int count) {
+    return threads_[count % threads_.size()];
+  }
+
+  void PingPong(int hops) override {
+    if (!hops) {
+      FinishMeasurement();
+      return;
+    }
+    NextThread(hops)->task_runner()->PostTask(
+        FROM_HERE, base::Bind(&ThreadPerfTest::PingPong, base::Unretained(this),
+                              hops - 1));
+  }
+};
+
+// This tries to test the 'best-case' as well as the 'worst-case' task posting
+// performance. The best-case keeps one thread alive such that it never yeilds,
+// while the worse-case forces a context switch for every task. Four threads are
+// used to ensure the threads do yeild (with just two it might be possible for
+// both threads to stay awake if they can signal each other fast enough).
+TEST_F(TaskPerfTest, TaskPingPong) {
+  RunPingPongTest("1_Task_Threads", 1);
+  RunPingPongTest("4_Task_Threads", 4);
+}
+
+
+// Same as above, but add observers to test their perf impact.
+class MessageLoopObserver : public base::MessageLoop::TaskObserver {
+ public:
+  void WillProcessTask(const base::PendingTask& pending_task) override {}
+  void DidProcessTask(const base::PendingTask& pending_task) override {}
+};
+MessageLoopObserver message_loop_observer;
+
+class TaskObserverPerfTest : public TaskPerfTest {
+ public:
+  void Init() override {
+    TaskPerfTest::Init();
+    for (size_t i = 0; i < threads_.size(); i++) {
+      threads_[i]->message_loop()->AddTaskObserver(&message_loop_observer);
+    }
+  }
+};
+
+TEST_F(TaskObserverPerfTest, TaskPingPong) {
+  RunPingPongTest("1_Task_Threads_With_Observer", 1);
+  RunPingPongTest("4_Task_Threads_With_Observer", 4);
+}
+
+// Class to test our WaitableEvent performance by signaling back and fort.
+// WaitableEvent is templated so we can also compare with other versions.
+template <typename WaitableEventType>
+class EventPerfTest : public ThreadPerfTest {
+ public:
+  void Init() override {
+    for (size_t i = 0; i < threads_.size(); i++)
+      events_.push_back(new WaitableEventType(false, false));
+  }
+
+  void Reset() override { events_.clear(); }
+
+  void WaitAndSignalOnThread(size_t event) {
+    size_t next_event = (event + 1) % events_.size();
+    int my_hops = 0;
+    do {
+      events_[event]->Wait();
+      my_hops = --remaining_hops_;  // We own 'hops' between Wait and Signal.
+      events_[next_event]->Signal();
+    } while (my_hops > 0);
+    // Once we are done, all threads will signal as hops passes zero.
+    // We only signal completion once, on the thread that reaches zero.
+    if (!my_hops)
+      FinishMeasurement();
+  }
+
+  void PingPong(int hops) override {
+    remaining_hops_ = hops;
+    for (size_t i = 0; i < threads_.size(); i++) {
+      threads_[i]->task_runner()->PostTask(
+          FROM_HERE, base::Bind(&EventPerfTest::WaitAndSignalOnThread,
+                                base::Unretained(this), i));
+    }
+
+    // Kick off the Signal ping-ponging.
+    events_.front()->Signal();
+  }
+
+  int remaining_hops_;
+  ScopedVector<WaitableEventType> events_;
+};
+
+// Similar to the task posting test, this just tests similar functionality
+// using WaitableEvents. We only test four threads (worst-case), but we
+// might want to craft a way to test the best-case (where the thread doesn't
+// end up blocking because the event is already signalled).
+typedef EventPerfTest<base::WaitableEvent> WaitableEventPerfTest;
+TEST_F(WaitableEventPerfTest, EventPingPong) {
+  RunPingPongTest("4_WaitableEvent_Threads", 4);
+}
+
+// Build a minimal event using ConditionVariable.
+class ConditionVariableEvent {
+ public:
+  ConditionVariableEvent(bool manual_reset, bool initially_signaled)
+      : cond_(&lock_), signaled_(false) {
+    DCHECK(!manual_reset);
+    DCHECK(!initially_signaled);
+  }
+
+  void Signal() {
+    {
+      base::AutoLock scoped_lock(lock_);
+      signaled_ = true;
+    }
+    cond_.Signal();
+  }
+
+  void Wait() {
+    base::AutoLock scoped_lock(lock_);
+    while (!signaled_)
+      cond_.Wait();
+    signaled_ = false;
+  }
+
+ private:
+  base::Lock lock_;
+  base::ConditionVariable cond_;
+  bool signaled_;
+};
+
+// This is meant to test the absolute minimal context switching time
+// using our own base synchronization code.
+typedef EventPerfTest<ConditionVariableEvent> ConditionVariablePerfTest;
+TEST_F(ConditionVariablePerfTest, EventPingPong) {
+  RunPingPongTest("4_ConditionVariable_Threads", 4);
+}
+#if defined(OS_POSIX)
+
+// Absolutely 100% minimal posix waitable event. If there is a better/faster
+// way to force a context switch, we should use that instead.
+class PthreadEvent {
+ public:
+  PthreadEvent(bool manual_reset, bool initially_signaled) {
+    DCHECK(!manual_reset);
+    DCHECK(!initially_signaled);
+    pthread_mutex_init(&mutex_, 0);
+    pthread_cond_init(&cond_, 0);
+    signaled_ = false;
+  }
+
+  ~PthreadEvent() {
+    pthread_cond_destroy(&cond_);
+    pthread_mutex_destroy(&mutex_);
+  }
+
+  void Signal() {
+    pthread_mutex_lock(&mutex_);
+    signaled_ = true;
+    pthread_mutex_unlock(&mutex_);
+    pthread_cond_signal(&cond_);
+  }
+
+  void Wait() {
+    pthread_mutex_lock(&mutex_);
+    while (!signaled_)
+      pthread_cond_wait(&cond_, &mutex_);
+    signaled_ = false;
+    pthread_mutex_unlock(&mutex_);
+  }
+
+ private:
+  bool signaled_;
+  pthread_mutex_t mutex_;
+  pthread_cond_t cond_;
+};
+
+// This is meant to test the absolute minimal context switching time.
+// If there is any faster way to do this we should substitute it in.
+typedef EventPerfTest<PthreadEvent> PthreadEventPerfTest;
+TEST_F(PthreadEventPerfTest, EventPingPong) {
+  RunPingPongTest("4_PthreadCondVar_Threads", 4);
+}
+
+#endif
+
+}  // namespace
+
+}  // namespace base
diff --git a/base/threading/thread_restrictions.cc b/base/threading/thread_restrictions.cc
new file mode 100644
index 0000000..871f2dc
--- /dev/null
+++ b/base/threading/thread_restrictions.cc
@@ -0,0 +1,85 @@
+// Copyright (c) 2012 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/threading/thread_restrictions.h"
+
+#if ENABLE_THREAD_RESTRICTIONS
+
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/threading/thread_local.h"
+
+namespace base {
+
+namespace {
+
+LazyInstance<ThreadLocalBoolean>::Leaky
+    g_io_disallowed = LAZY_INSTANCE_INITIALIZER;
+
+LazyInstance<ThreadLocalBoolean>::Leaky
+    g_singleton_disallowed = LAZY_INSTANCE_INITIALIZER;
+
+LazyInstance<ThreadLocalBoolean>::Leaky
+    g_wait_disallowed = LAZY_INSTANCE_INITIALIZER;
+
+}  // anonymous namespace
+
+// static
+bool ThreadRestrictions::SetIOAllowed(bool allowed) {
+  bool previous_disallowed = g_io_disallowed.Get().Get();
+  g_io_disallowed.Get().Set(!allowed);
+  return !previous_disallowed;
+}
+
+// static
+void ThreadRestrictions::AssertIOAllowed() {
+  if (g_io_disallowed.Get().Get()) {
+    LOG(FATAL) <<
+        "Function marked as IO-only was called from a thread that "
+        "disallows IO!  If this thread really should be allowed to "
+        "make IO calls, adjust the call to "
+        "base::ThreadRestrictions::SetIOAllowed() in this thread's "
+        "startup.";
+  }
+}
+
+// static
+bool ThreadRestrictions::SetSingletonAllowed(bool allowed) {
+  bool previous_disallowed = g_singleton_disallowed.Get().Get();
+  g_singleton_disallowed.Get().Set(!allowed);
+  return !previous_disallowed;
+}
+
+// static
+void ThreadRestrictions::AssertSingletonAllowed() {
+  if (g_singleton_disallowed.Get().Get()) {
+    LOG(FATAL) << "LazyInstance/Singleton is not allowed to be used on this "
+               << "thread.  Most likely it's because this thread is not "
+               << "joinable, so AtExitManager may have deleted the object "
+               << "on shutdown, leading to a potential shutdown crash.";
+  }
+}
+
+// static
+void ThreadRestrictions::DisallowWaiting() {
+  g_wait_disallowed.Get().Set(true);
+}
+
+// static
+void ThreadRestrictions::AssertWaitAllowed() {
+  if (g_wait_disallowed.Get().Get()) {
+    LOG(FATAL) << "Waiting is not allowed to be used on this thread to prevent"
+               << "jank and deadlock.";
+  }
+}
+
+bool ThreadRestrictions::SetWaitAllowed(bool allowed) {
+  bool previous_disallowed = g_wait_disallowed.Get().Get();
+  g_wait_disallowed.Get().Set(!allowed);
+  return !previous_disallowed;
+}
+
+}  // namespace base
+
+#endif  // ENABLE_THREAD_RESTRICTIONS
diff --git a/base/threading/thread_restrictions.h b/base/threading/thread_restrictions.h
new file mode 100644
index 0000000..54f50eb
--- /dev/null
+++ b/base/threading/thread_restrictions.h
@@ -0,0 +1,240 @@
+// Copyright (c) 2012 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_THREADING_THREAD_RESTRICTIONS_H_
+#define BASE_THREADING_THREAD_RESTRICTIONS_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+// See comment at top of thread_checker.h
+#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON))
+#define ENABLE_THREAD_RESTRICTIONS 1
+#else
+#define ENABLE_THREAD_RESTRICTIONS 0
+#endif
+
+class BrowserProcessImpl;
+class HistogramSynchronizer;
+class NativeBackendKWallet;
+class ScopedAllowWaitForLegacyWebViewApi;
+
+namespace cc {
+class CompletionEvent;
+class TaskGraphRunner;
+}
+namespace chromeos {
+class BlockingMethodCaller;
+namespace system {
+class StatisticsProviderImpl;
+}
+}
+namespace chrome_browser_net {
+class Predictor;
+}
+namespace content {
+class BrowserGpuChannelHostFactory;
+class BrowserGpuMemoryBufferManager;
+class BrowserShutdownProfileDumper;
+class BrowserTestBase;
+class GpuChannelHost;
+class NestedMessagePumpAndroid;
+class RenderWidgetResizeHelper;
+class ScopedAllowWaitForAndroidLayoutTests;
+class ScopedAllowWaitForDebugURL;
+class TextInputClientMac;
+}  // namespace content
+namespace dbus {
+class Bus;
+}
+namespace disk_cache {
+class BackendImpl;
+class InFlightIO;
+}
+namespace mojo {
+namespace common {
+class WatcherThreadManager;
+}
+}
+namespace net {
+namespace internal {
+class AddressTrackerLinux;
+}
+}
+
+namespace remoting {
+class AutoThread;
+}
+
+namespace base {
+
+namespace android {
+class JavaHandlerThread;
+}
+
+class SequencedWorkerPool;
+class SimpleThread;
+class Thread;
+class ThreadTestHelper;
+
+// Certain behavior is disallowed on certain threads.  ThreadRestrictions helps
+// enforce these rules.  Examples of such rules:
+//
+// * Do not do blocking IO (makes the thread janky)
+// * Do not access Singleton/LazyInstance (may lead to shutdown crashes)
+//
+// Here's more about how the protection works:
+//
+// 1) If a thread should not be allowed to make IO calls, mark it:
+//      base::ThreadRestrictions::SetIOAllowed(false);
+//    By default, threads *are* allowed to make IO calls.
+//    In Chrome browser code, IO calls should be proxied to the File thread.
+//
+// 2) If a function makes a call that will go out to disk, check whether the
+//    current thread is allowed:
+//      base::ThreadRestrictions::AssertIOAllowed();
+//
+//
+// Style tip: where should you put AssertIOAllowed checks?  It's best
+// if you put them as close to the disk access as possible, at the
+// lowest level.  This rule is simple to follow and helps catch all
+// callers.  For example, if your function GoDoSomeBlockingDiskCall()
+// only calls other functions in Chrome and not fopen(), you should go
+// add the AssertIOAllowed checks in the helper functions.
+
+class BASE_EXPORT ThreadRestrictions {
+ public:
+  // Constructing a ScopedAllowIO temporarily allows IO for the current
+  // thread.  Doing this is almost certainly always incorrect.
+  class BASE_EXPORT ScopedAllowIO {
+   public:
+    ScopedAllowIO() { previous_value_ = SetIOAllowed(true); }
+    ~ScopedAllowIO() { SetIOAllowed(previous_value_); }
+   private:
+    // Whether IO is allowed when the ScopedAllowIO was constructed.
+    bool previous_value_;
+
+    DISALLOW_COPY_AND_ASSIGN(ScopedAllowIO);
+  };
+
+  // Constructing a ScopedAllowSingleton temporarily allows accessing for the
+  // current thread.  Doing this is almost always incorrect.
+  class BASE_EXPORT ScopedAllowSingleton {
+   public:
+    ScopedAllowSingleton() { previous_value_ = SetSingletonAllowed(true); }
+    ~ScopedAllowSingleton() { SetSingletonAllowed(previous_value_); }
+   private:
+    // Whether singleton use is allowed when the ScopedAllowSingleton was
+    // constructed.
+    bool previous_value_;
+
+    DISALLOW_COPY_AND_ASSIGN(ScopedAllowSingleton);
+  };
+
+#if ENABLE_THREAD_RESTRICTIONS
+  // Set whether the current thread to make IO calls.
+  // Threads start out in the *allowed* state.
+  // Returns the previous value.
+  static bool SetIOAllowed(bool allowed);
+
+  // Check whether the current thread is allowed to make IO calls,
+  // and DCHECK if not.  See the block comment above the class for
+  // a discussion of where to add these checks.
+  static void AssertIOAllowed();
+
+  // Set whether the current thread can use singletons.  Returns the previous
+  // value.
+  static bool SetSingletonAllowed(bool allowed);
+
+  // Check whether the current thread is allowed to use singletons (Singleton /
+  // LazyInstance).  DCHECKs if not.
+  static void AssertSingletonAllowed();
+
+  // Disable waiting on the current thread. Threads start out in the *allowed*
+  // state. Returns the previous value.
+  static void DisallowWaiting();
+
+  // Check whether the current thread is allowed to wait, and DCHECK if not.
+  static void AssertWaitAllowed();
+#else
+  // Inline the empty definitions of these functions so that they can be
+  // compiled out.
+  static bool SetIOAllowed(bool allowed) { return true; }
+  static void AssertIOAllowed() {}
+  static bool SetSingletonAllowed(bool allowed) { return true; }
+  static void AssertSingletonAllowed() {}
+  static void DisallowWaiting() {}
+  static void AssertWaitAllowed() {}
+#endif
+
+ private:
+  // DO NOT ADD ANY OTHER FRIEND STATEMENTS, talk to jam or brettw first.
+  // BEGIN ALLOWED USAGE.
+  friend class content::BrowserShutdownProfileDumper;
+  friend class content::BrowserTestBase;
+  friend class content::NestedMessagePumpAndroid;
+  friend class content::RenderWidgetResizeHelper;
+  friend class content::ScopedAllowWaitForAndroidLayoutTests;
+  friend class content::ScopedAllowWaitForDebugURL;
+  friend class ::HistogramSynchronizer;
+  friend class ::ScopedAllowWaitForLegacyWebViewApi;
+  friend class cc::CompletionEvent;
+  friend class cc::TaskGraphRunner;
+  friend class mojo::common::WatcherThreadManager;
+  friend class remoting::AutoThread;
+  friend class MessagePumpDefault;
+  friend class SequencedWorkerPool;
+  friend class SimpleThread;
+  friend class Thread;
+  friend class ThreadTestHelper;
+  friend class PlatformThread;
+  friend class android::JavaHandlerThread;
+
+  // END ALLOWED USAGE.
+  // BEGIN USAGE THAT NEEDS TO BE FIXED.
+  friend class ::chromeos::BlockingMethodCaller;  // http://crbug.com/125360
+  friend class ::chromeos::system::StatisticsProviderImpl;  // http://crbug.com/125385
+  friend class chrome_browser_net::Predictor;     // http://crbug.com/78451
+  friend class
+      content::BrowserGpuChannelHostFactory;      // http://crbug.com/125248
+  friend class
+      content::BrowserGpuMemoryBufferManager;     // http://crbug.com/420368
+  friend class content::GpuChannelHost;           // http://crbug.com/125264
+  friend class content::TextInputClientMac;       // http://crbug.com/121917
+  friend class dbus::Bus;                         // http://crbug.com/125222
+  friend class disk_cache::BackendImpl;           // http://crbug.com/74623
+  friend class disk_cache::InFlightIO;            // http://crbug.com/74623
+  friend class net::internal::AddressTrackerLinux;  // http://crbug.com/125097
+  friend class ::BrowserProcessImpl;              // http://crbug.com/125207
+  friend class ::NativeBackendKWallet;            // http://crbug.com/125331
+  // END USAGE THAT NEEDS TO BE FIXED.
+
+#if ENABLE_THREAD_RESTRICTIONS
+  static bool SetWaitAllowed(bool allowed);
+#else
+  static bool SetWaitAllowed(bool allowed) { return true; }
+#endif
+
+  // Constructing a ScopedAllowWait temporarily allows waiting on the current
+  // thread.  Doing this is almost always incorrect, which is why we limit who
+  // can use this through friend. If you find yourself needing to use this, find
+  // another way. Talk to jam or brettw.
+  class BASE_EXPORT ScopedAllowWait {
+   public:
+    ScopedAllowWait() { previous_value_ = SetWaitAllowed(true); }
+    ~ScopedAllowWait() { SetWaitAllowed(previous_value_); }
+   private:
+    // Whether singleton use is allowed when the ScopedAllowWait was
+    // constructed.
+    bool previous_value_;
+
+    DISALLOW_COPY_AND_ASSIGN(ScopedAllowWait);
+  };
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ThreadRestrictions);
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_THREAD_RESTRICTIONS_H_
diff --git a/base/threading/thread_unittest.cc b/base/threading/thread_unittest.cc
new file mode 100644
index 0000000..926d5dd
--- /dev/null
+++ b/base/threading/thread_unittest.cc
@@ -0,0 +1,242 @@
+// Copyright (c) 2012 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/threading/thread.h"
+
+#include <vector>
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/single_thread_task_runner.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+using base::Thread;
+
+typedef PlatformTest ThreadTest;
+
+namespace {
+
+void ToggleValue(bool* value) {
+  ANNOTATE_BENIGN_RACE(value, "Test-only data race on boolean "
+                       "in base/thread_unittest");
+  *value = !*value;
+}
+
+class SleepInsideInitThread : public Thread {
+ public:
+  SleepInsideInitThread() : Thread("none") {
+    init_called_ = false;
+    ANNOTATE_BENIGN_RACE(
+        this, "Benign test-only data race on vptr - http://crbug.com/98219");
+  }
+  ~SleepInsideInitThread() override { Stop(); }
+
+  void Init() override {
+    base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(500));
+    init_called_ = true;
+  }
+  bool InitCalled() { return init_called_; }
+ private:
+  bool init_called_;
+};
+
+enum ThreadEvent {
+  // Thread::Init() was called.
+  THREAD_EVENT_INIT = 0,
+
+  // The MessageLoop for the thread was deleted.
+  THREAD_EVENT_MESSAGE_LOOP_DESTROYED,
+
+  // Thread::CleanUp() was called.
+  THREAD_EVENT_CLEANUP,
+
+  // Keep at end of list.
+  THREAD_NUM_EVENTS
+};
+
+typedef std::vector<ThreadEvent> EventList;
+
+class CaptureToEventList : public Thread {
+ public:
+  // This Thread pushes events into the vector |event_list| to show
+  // the order they occured in. |event_list| must remain valid for the
+  // lifetime of this thread.
+  explicit CaptureToEventList(EventList* event_list)
+      : Thread("none"),
+        event_list_(event_list) {
+  }
+
+  ~CaptureToEventList() override { Stop(); }
+
+  void Init() override { event_list_->push_back(THREAD_EVENT_INIT); }
+
+  void CleanUp() override { event_list_->push_back(THREAD_EVENT_CLEANUP); }
+
+ private:
+  EventList* event_list_;
+};
+
+// Observer that writes a value into |event_list| when a message loop has been
+// destroyed.
+class CapturingDestructionObserver
+    : public base::MessageLoop::DestructionObserver {
+ public:
+  // |event_list| must remain valid throughout the observer's lifetime.
+  explicit CapturingDestructionObserver(EventList* event_list)
+      : event_list_(event_list) {
+  }
+
+  // DestructionObserver implementation:
+  void WillDestroyCurrentMessageLoop() override {
+    event_list_->push_back(THREAD_EVENT_MESSAGE_LOOP_DESTROYED);
+    event_list_ = NULL;
+  }
+
+ private:
+  EventList* event_list_;
+};
+
+// Task that adds a destruction observer to the current message loop.
+void RegisterDestructionObserver(
+    base::MessageLoop::DestructionObserver* observer) {
+  base::MessageLoop::current()->AddDestructionObserver(observer);
+}
+
+}  // namespace
+
+TEST_F(ThreadTest, Restart) {
+  Thread a("Restart");
+  a.Stop();
+  EXPECT_FALSE(a.message_loop());
+  EXPECT_FALSE(a.IsRunning());
+  EXPECT_TRUE(a.Start());
+  EXPECT_TRUE(a.message_loop());
+  EXPECT_TRUE(a.IsRunning());
+  a.Stop();
+  EXPECT_FALSE(a.message_loop());
+  EXPECT_FALSE(a.IsRunning());
+  EXPECT_TRUE(a.Start());
+  EXPECT_TRUE(a.message_loop());
+  EXPECT_TRUE(a.IsRunning());
+  a.Stop();
+  EXPECT_FALSE(a.message_loop());
+  EXPECT_FALSE(a.IsRunning());
+  a.Stop();
+  EXPECT_FALSE(a.message_loop());
+  EXPECT_FALSE(a.IsRunning());
+}
+
+TEST_F(ThreadTest, StartWithOptions_StackSize) {
+  Thread a("StartWithStackSize");
+  // Ensure that the thread can work with only 12 kb and still process a
+  // message.
+  Thread::Options options;
+#if defined(ADDRESS_SANITIZER) && defined(OS_MACOSX)
+  // ASan bloats the stack variables and overflows the 12 kb stack on OSX.
+  options.stack_size = 24*1024;
+#else
+  options.stack_size = 12*1024;
+#endif
+  EXPECT_TRUE(a.StartWithOptions(options));
+  EXPECT_TRUE(a.message_loop());
+  EXPECT_TRUE(a.IsRunning());
+
+  bool was_invoked = false;
+  a.task_runner()->PostTask(FROM_HERE, base::Bind(&ToggleValue, &was_invoked));
+
+  // wait for the task to run (we could use a kernel event here
+  // instead to avoid busy waiting, but this is sufficient for
+  // testing purposes).
+  for (int i = 100; i >= 0 && !was_invoked; --i) {
+    base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10));
+  }
+  EXPECT_TRUE(was_invoked);
+}
+
+TEST_F(ThreadTest, TwoTasks) {
+  bool was_invoked = false;
+  {
+    Thread a("TwoTasks");
+    EXPECT_TRUE(a.Start());
+    EXPECT_TRUE(a.message_loop());
+
+    // Test that all events are dispatched before the Thread object is
+    // destroyed.  We do this by dispatching a sleep event before the
+    // event that will toggle our sentinel value.
+    a.task_runner()->PostTask(
+        FROM_HERE, base::Bind(static_cast<void (*)(base::TimeDelta)>(
+                                  &base::PlatformThread::Sleep),
+                              base::TimeDelta::FromMilliseconds(20)));
+    a.task_runner()->PostTask(FROM_HERE,
+                              base::Bind(&ToggleValue, &was_invoked));
+  }
+  EXPECT_TRUE(was_invoked);
+}
+
+TEST_F(ThreadTest, StopSoon) {
+  Thread a("StopSoon");
+  EXPECT_TRUE(a.Start());
+  EXPECT_TRUE(a.message_loop());
+  EXPECT_TRUE(a.IsRunning());
+  a.StopSoon();
+  a.StopSoon();
+  a.Stop();
+  EXPECT_FALSE(a.message_loop());
+  EXPECT_FALSE(a.IsRunning());
+}
+
+TEST_F(ThreadTest, ThreadName) {
+  Thread a("ThreadName");
+  EXPECT_TRUE(a.Start());
+  EXPECT_EQ("ThreadName", a.thread_name());
+}
+
+// Make sure Init() is called after Start() and before
+// WaitUntilThreadInitialized() returns.
+TEST_F(ThreadTest, SleepInsideInit) {
+  SleepInsideInitThread t;
+  EXPECT_FALSE(t.InitCalled());
+  t.StartAndWaitForTesting();
+  EXPECT_TRUE(t.InitCalled());
+}
+
+// Make sure that the destruction sequence is:
+//
+//  (1) Thread::CleanUp()
+//  (2) MessageLoop::~MessageLoop()
+//      MessageLoop::DestructionObservers called.
+TEST_F(ThreadTest, CleanUp) {
+  EventList captured_events;
+  CapturingDestructionObserver loop_destruction_observer(&captured_events);
+
+  {
+    // Start a thread which writes its event into |captured_events|.
+    CaptureToEventList t(&captured_events);
+    EXPECT_TRUE(t.Start());
+    EXPECT_TRUE(t.message_loop());
+    EXPECT_TRUE(t.IsRunning());
+
+    // Register an observer that writes into |captured_events| once the
+    // thread's message loop is destroyed.
+    t.task_runner()->PostTask(
+        FROM_HERE, base::Bind(&RegisterDestructionObserver,
+                              base::Unretained(&loop_destruction_observer)));
+
+    // Upon leaving this scope, the thread is deleted.
+  }
+
+  // Check the order of events during shutdown.
+  ASSERT_EQ(static_cast<size_t>(THREAD_NUM_EVENTS), captured_events.size());
+  EXPECT_EQ(THREAD_EVENT_INIT, captured_events[0]);
+  EXPECT_EQ(THREAD_EVENT_CLEANUP, captured_events[1]);
+  EXPECT_EQ(THREAD_EVENT_MESSAGE_LOOP_DESTROYED, captured_events[2]);
+}
+
+TEST_F(ThreadTest, ThreadNotStarted) {
+  Thread a("Inert");
+  EXPECT_EQ(nullptr, a.message_loop_proxy());
+  EXPECT_EQ(nullptr, a.task_runner());
+}
diff --git a/base/threading/watchdog.cc b/base/threading/watchdog.cc
new file mode 100644
index 0000000..c063799
--- /dev/null
+++ b/base/threading/watchdog.cc
@@ -0,0 +1,184 @@
+// Copyright (c) 2012 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/threading/watchdog.h"
+
+#include "base/compiler_specific.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+namespace {
+
+// When the debugger breaks (when we alarm), all the other alarms that are
+// armed will expire (also alarm).  To diminish this effect, we track any
+// delay due to debugger breaks, and we *try* to adjust the effective start
+// time of other alarms to step past the debugging break.
+// Without this safety net, any alarm will typically trigger a host of follow
+// on alarms from callers that specify old times.
+
+struct StaticData {
+  // Lock for access of static data...
+  Lock lock;
+
+  // When did we last alarm and get stuck (for a while) in a debugger?
+  TimeTicks last_debugged_alarm_time;
+
+  // How long did we sit on a break in the debugger?
+  TimeDelta last_debugged_alarm_delay;
+};
+
+LazyInstance<StaticData>::Leaky g_static_data = LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+// Start thread running in a Disarmed state.
+Watchdog::Watchdog(const TimeDelta& duration,
+                   const std::string& thread_watched_name,
+                   bool enabled)
+  : enabled_(enabled),
+    lock_(),
+    condition_variable_(&lock_),
+    state_(DISARMED),
+    duration_(duration),
+    thread_watched_name_(thread_watched_name),
+    delegate_(this) {
+  if (!enabled_)
+    return;  // Don't start thread, or doing anything really.
+  enabled_ = PlatformThread::Create(0,  // Default stack size.
+                                    &delegate_,
+                                    &handle_);
+  DCHECK(enabled_);
+}
+
+// Notify watchdog thread, and wait for it to finish up.
+Watchdog::~Watchdog() {
+  if (!enabled_)
+    return;
+  if (!IsJoinable())
+    Cleanup();
+  condition_variable_.Signal();
+  PlatformThread::Join(handle_);
+}
+
+void Watchdog::Cleanup() {
+  if (!enabled_)
+    return;
+  {
+    AutoLock lock(lock_);
+    state_ = SHUTDOWN;
+  }
+  condition_variable_.Signal();
+}
+
+bool Watchdog::IsJoinable() {
+  if (!enabled_)
+    return true;
+  AutoLock lock(lock_);
+  return (state_ == JOINABLE);
+}
+
+void Watchdog::Arm() {
+  ArmAtStartTime(TimeTicks::Now());
+}
+
+void Watchdog::ArmSomeTimeDeltaAgo(const TimeDelta& time_delta) {
+  ArmAtStartTime(TimeTicks::Now() - time_delta);
+}
+
+// Start clock for watchdog.
+void Watchdog::ArmAtStartTime(const TimeTicks start_time) {
+  {
+    AutoLock lock(lock_);
+    start_time_ = start_time;
+    state_ = ARMED;
+  }
+  // Force watchdog to wake up, and go to sleep with the timer ticking with the
+  // proper duration.
+  condition_variable_.Signal();
+}
+
+// Disable watchdog so that it won't do anything when time expires.
+void Watchdog::Disarm() {
+  AutoLock lock(lock_);
+  state_ = DISARMED;
+  // We don't need to signal, as the watchdog will eventually wake up, and it
+  // will check its state and time, and act accordingly.
+}
+
+void Watchdog::Alarm() {
+  DVLOG(1) << "Watchdog alarmed for " << thread_watched_name_;
+}
+
+//------------------------------------------------------------------------------
+// Internal private methods that the watchdog thread uses.
+
+void Watchdog::ThreadDelegate::ThreadMain() {
+  SetThreadName();
+  TimeDelta remaining_duration;
+  StaticData* static_data = g_static_data.Pointer();
+  while (1) {
+    AutoLock lock(watchdog_->lock_);
+    while (DISARMED == watchdog_->state_)
+      watchdog_->condition_variable_.Wait();
+    if (SHUTDOWN == watchdog_->state_) {
+      watchdog_->state_ = JOINABLE;
+      return;
+    }
+    DCHECK(ARMED == watchdog_->state_);
+    remaining_duration = watchdog_->duration_ -
+        (TimeTicks::Now() - watchdog_->start_time_);
+    if (remaining_duration.InMilliseconds() > 0) {
+      // Spurios wake?  Timer drifts?  Go back to sleep for remaining time.
+      watchdog_->condition_variable_.TimedWait(remaining_duration);
+      continue;
+    }
+    // We overslept, so this seems like a real alarm.
+    // Watch out for a user that stopped the debugger on a different alarm!
+    {
+      AutoLock static_lock(static_data->lock);
+      if (static_data->last_debugged_alarm_time > watchdog_->start_time_) {
+        // False alarm: we started our clock before the debugger break (last
+        // alarm time).
+        watchdog_->start_time_ += static_data->last_debugged_alarm_delay;
+        if (static_data->last_debugged_alarm_time > watchdog_->start_time_)
+          // Too many alarms must have taken place.
+          watchdog_->state_ = DISARMED;
+        continue;
+      }
+    }
+    watchdog_->state_ = DISARMED;  // Only alarm at most once.
+    TimeTicks last_alarm_time = TimeTicks::Now();
+    {
+      AutoUnlock unlock(watchdog_->lock_);
+      watchdog_->Alarm();  // Set a break point here to debug on alarms.
+    }
+    TimeDelta last_alarm_delay = TimeTicks::Now() - last_alarm_time;
+    if (last_alarm_delay <= TimeDelta::FromMilliseconds(2))
+      continue;
+    // Ignore race of two alarms/breaks going off at roughly the same time.
+    AutoLock static_lock(static_data->lock);
+    // This was a real debugger break.
+    static_data->last_debugged_alarm_time = last_alarm_time;
+    static_data->last_debugged_alarm_delay = last_alarm_delay;
+  }
+}
+
+void Watchdog::ThreadDelegate::SetThreadName() const {
+  std::string name = watchdog_->thread_watched_name_ + " Watchdog";
+  PlatformThread::SetName(name);
+  DVLOG(1) << "Watchdog active: " << name;
+}
+
+// static
+void Watchdog::ResetStaticData() {
+  StaticData* static_data = g_static_data.Pointer();
+  AutoLock lock(static_data->lock);
+  static_data->last_debugged_alarm_time = TimeTicks();
+  static_data->last_debugged_alarm_delay = TimeDelta();
+}
+
+}  // namespace base
diff --git a/base/threading/watchdog.h b/base/threading/watchdog.h
new file mode 100644
index 0000000..ea3be36
--- /dev/null
+++ b/base/threading/watchdog.h
@@ -0,0 +1,95 @@
+// Copyright (c) 2012 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.
+
+// The Watchdog class creates a second thread that can Alarm if a specific
+// duration of time passes without proper attention.  The duration of time is
+// specified at construction time.  The Watchdog may be used many times by
+// simply calling Arm() (to start timing) and Disarm() (to reset the timer).
+// The Watchdog is typically used under a debugger, where the stack traces on
+// other threads can be examined if/when the Watchdog alarms.
+
+// Some watchdogs will be enabled or disabled via command line switches. To
+// facilitate such code, an "enabled" argument for the constuctor can be used
+// to permanently disable the watchdog.  Disabled watchdogs don't even spawn
+// a second thread, and their methods call (Arm() and Disarm()) return very
+// quickly.
+
+#ifndef BASE_THREADING_WATCHDOG_H_
+#define BASE_THREADING_WATCHDOG_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/platform_thread.h"
+#include "base/time/time.h"
+
+namespace base {
+
+class BASE_EXPORT Watchdog {
+ public:
+  // Constructor specifies how long the Watchdog will wait before alarming.
+  Watchdog(const TimeDelta& duration,
+           const std::string& thread_watched_name,
+           bool enabled);
+  virtual ~Watchdog();
+
+  // Notify watchdog thread to finish up. Sets the state_ to SHUTDOWN.
+  void Cleanup();
+
+  // Returns true if we state_ is JOINABLE (which indicates that Watchdog has
+  // exited).
+  bool IsJoinable();
+
+  // Start timing, and alarm when time expires (unless we're disarm()ed.)
+  void Arm();  // Arm  starting now.
+  void ArmSomeTimeDeltaAgo(const TimeDelta& time_delta);
+  void ArmAtStartTime(const TimeTicks start_time);
+
+  // Reset time, and do not set off the alarm.
+  void Disarm();
+
+  // Alarm is called if the time expires after an Arm() without someone calling
+  // Disarm().  This method can be overridden to create testable classes.
+  virtual void Alarm();
+
+  // Reset static data to initial state. Useful for tests, to ensure
+  // they are independent.
+  static void ResetStaticData();
+
+ private:
+  class ThreadDelegate : public PlatformThread::Delegate {
+   public:
+    explicit ThreadDelegate(Watchdog* watchdog) : watchdog_(watchdog) {
+    }
+    void ThreadMain() override;
+
+   private:
+    void SetThreadName() const;
+
+    Watchdog* watchdog_;
+  };
+
+  enum State {ARMED, DISARMED, SHUTDOWN, JOINABLE };
+
+  bool enabled_;
+
+  Lock lock_;  // Mutex for state_.
+  ConditionVariable condition_variable_;
+  State state_;
+  const TimeDelta duration_;  // How long after start_time_ do we alarm?
+  const std::string thread_watched_name_;
+  PlatformThreadHandle handle_;
+  ThreadDelegate delegate_;  // Store it, because it must outlive the thread.
+
+  TimeTicks start_time_;  // Start of epoch, and alarm after duration_.
+
+  DISALLOW_COPY_AND_ASSIGN(Watchdog);
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_WATCHDOG_H_
diff --git a/base/threading/watchdog_unittest.cc b/base/threading/watchdog_unittest.cc
new file mode 100644
index 0000000..627f46d
--- /dev/null
+++ b/base/threading/watchdog_unittest.cc
@@ -0,0 +1,140 @@
+// Copyright (c) 2012 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/threading/watchdog.h"
+
+#include "base/logging.h"
+#include "base/synchronization/spin_wait.h"
+#include "base/threading/platform_thread.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+//------------------------------------------------------------------------------
+// Provide a derived class to facilitate testing.
+
+class WatchdogCounter : public Watchdog {
+ public:
+  WatchdogCounter(const TimeDelta& duration,
+                  const std::string& thread_watched_name,
+                  bool enabled)
+      : Watchdog(duration, thread_watched_name, enabled),
+        alarm_counter_(0) {
+  }
+
+  ~WatchdogCounter() override {}
+
+  void Alarm() override {
+    alarm_counter_++;
+    Watchdog::Alarm();
+  }
+
+  int alarm_counter() { return alarm_counter_; }
+
+ private:
+  int alarm_counter_;
+
+  DISALLOW_COPY_AND_ASSIGN(WatchdogCounter);
+};
+
+class WatchdogTest : public testing::Test {
+ public:
+  void SetUp() override { Watchdog::ResetStaticData(); }
+};
+
+}  // namespace
+
+//------------------------------------------------------------------------------
+// Actual tests
+
+// Minimal constructor/destructor test.
+TEST_F(WatchdogTest, StartupShutdownTest) {
+  Watchdog watchdog1(TimeDelta::FromMilliseconds(300), "Disabled", false);
+  Watchdog watchdog2(TimeDelta::FromMilliseconds(300), "Enabled", true);
+}
+
+// Test ability to call Arm and Disarm repeatedly.
+TEST_F(WatchdogTest, ArmDisarmTest) {
+  Watchdog watchdog1(TimeDelta::FromMilliseconds(300), "Disabled", false);
+  watchdog1.Arm();
+  watchdog1.Disarm();
+  watchdog1.Arm();
+  watchdog1.Disarm();
+
+  Watchdog watchdog2(TimeDelta::FromMilliseconds(300), "Enabled", true);
+  watchdog2.Arm();
+  watchdog2.Disarm();
+  watchdog2.Arm();
+  watchdog2.Disarm();
+}
+
+// Make sure a basic alarm fires when the time has expired.
+TEST_F(WatchdogTest, AlarmTest) {
+  WatchdogCounter watchdog(TimeDelta::FromMilliseconds(10), "Enabled", true);
+  watchdog.Arm();
+  SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(5),
+                                   watchdog.alarm_counter() > 0);
+  EXPECT_EQ(1, watchdog.alarm_counter());
+}
+
+// Make sure a basic alarm fires when the time has expired.
+TEST_F(WatchdogTest, AlarmPriorTimeTest) {
+  WatchdogCounter watchdog(TimeDelta(), "Enabled2", true);
+  // Set a time in the past.
+  watchdog.ArmSomeTimeDeltaAgo(TimeDelta::FromSeconds(2));
+  // It should instantly go off, but certainly in less than 5 minutes.
+  SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(5),
+                                   watchdog.alarm_counter() > 0);
+
+  EXPECT_EQ(1, watchdog.alarm_counter());
+}
+
+// Make sure a disable alarm does nothing, even if we arm it.
+TEST_F(WatchdogTest, ConstructorDisabledTest) {
+  WatchdogCounter watchdog(TimeDelta::FromMilliseconds(10), "Disabled", false);
+  watchdog.Arm();
+  // Alarm should not fire, as it was disabled.
+  PlatformThread::Sleep(TimeDelta::FromMilliseconds(500));
+  EXPECT_EQ(0, watchdog.alarm_counter());
+}
+
+// Make sure Disarming will prevent firing, even after Arming.
+TEST_F(WatchdogTest, DisarmTest) {
+  WatchdogCounter watchdog(TimeDelta::FromSeconds(1), "Enabled3", true);
+
+  TimeTicks start = TimeTicks::Now();
+  watchdog.Arm();
+  // Sleep a bit, but not past the alarm point.
+  PlatformThread::Sleep(TimeDelta::FromMilliseconds(100));
+  watchdog.Disarm();
+  TimeTicks end = TimeTicks::Now();
+
+  if (end - start > TimeDelta::FromMilliseconds(500)) {
+    LOG(WARNING) << "100ms sleep took over 500ms, making the results of this "
+                 << "timing-sensitive test suspicious.  Aborting now.";
+    return;
+  }
+
+  // Alarm should not have fired before it was disarmed.
+  EXPECT_EQ(0, watchdog.alarm_counter());
+
+  // Sleep past the point where it would have fired if it wasn't disarmed,
+  // and verify that it didn't fire.
+  PlatformThread::Sleep(TimeDelta::FromSeconds(1));
+  EXPECT_EQ(0, watchdog.alarm_counter());
+
+  // ...but even after disarming, we can still use the alarm...
+  // Set a time greater than the timeout into the past.
+  watchdog.ArmSomeTimeDeltaAgo(TimeDelta::FromSeconds(10));
+  // It should almost instantly go off, but certainly in less than 5 minutes.
+  SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(TimeDelta::FromMinutes(5),
+                                   watchdog.alarm_counter() > 0);
+
+  EXPECT_EQ(1, watchdog.alarm_counter());
+}
+
+}  // namespace base
diff --git a/base/threading/worker_pool.cc b/base/threading/worker_pool.cc
new file mode 100644
index 0000000..bc016ce
--- /dev/null
+++ b/base/threading/worker_pool.cc
@@ -0,0 +1,124 @@
+// Copyright (c) 2012 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/threading/worker_pool.h"
+
+#include "base/bind.h"
+#include "base/compiler_specific.h"
+#include "base/debug/leak_annotations.h"
+#include "base/lazy_instance.h"
+#include "base/task_runner.h"
+#include "base/threading/post_task_and_reply_impl.h"
+#include "base/tracked_objects.h"
+
+namespace base {
+
+namespace {
+
+class PostTaskAndReplyWorkerPool : public internal::PostTaskAndReplyImpl {
+ public:
+  explicit PostTaskAndReplyWorkerPool(bool task_is_slow)
+      : task_is_slow_(task_is_slow) {
+  }
+
+ private:
+  bool PostTask(const tracked_objects::Location& from_here,
+                const Closure& task) override {
+    return WorkerPool::PostTask(from_here, task, task_is_slow_);
+  }
+
+  bool task_is_slow_;
+};
+
+// WorkerPoolTaskRunner ---------------------------------------------
+// A TaskRunner which posts tasks to a WorkerPool with a
+// fixed ShutdownBehavior.
+//
+// Note that this class is RefCountedThreadSafe (inherited from TaskRunner).
+class WorkerPoolTaskRunner : public TaskRunner {
+ public:
+  explicit WorkerPoolTaskRunner(bool tasks_are_slow);
+
+  // TaskRunner implementation
+  bool PostDelayedTask(const tracked_objects::Location& from_here,
+                       const Closure& task,
+                       TimeDelta delay) override;
+  bool RunsTasksOnCurrentThread() const override;
+
+ private:
+  ~WorkerPoolTaskRunner() override;
+
+  // Helper function for posting a delayed task. Asserts that the delay is
+  // zero because non-zero delays are not supported.
+  bool PostDelayedTaskAssertZeroDelay(
+      const tracked_objects::Location& from_here,
+      const Closure& task,
+      base::TimeDelta delay);
+
+  const bool tasks_are_slow_;
+
+  DISALLOW_COPY_AND_ASSIGN(WorkerPoolTaskRunner);
+};
+
+WorkerPoolTaskRunner::WorkerPoolTaskRunner(bool tasks_are_slow)
+    : tasks_are_slow_(tasks_are_slow) {
+}
+
+WorkerPoolTaskRunner::~WorkerPoolTaskRunner() {
+}
+
+bool WorkerPoolTaskRunner::PostDelayedTask(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    TimeDelta delay) {
+  return PostDelayedTaskAssertZeroDelay(from_here, task, delay);
+}
+
+bool WorkerPoolTaskRunner::RunsTasksOnCurrentThread() const {
+  return WorkerPool::RunsTasksOnCurrentThread();
+}
+
+bool WorkerPoolTaskRunner::PostDelayedTaskAssertZeroDelay(
+    const tracked_objects::Location& from_here,
+    const Closure& task,
+    base::TimeDelta delay) {
+  DCHECK_EQ(delay.InMillisecondsRoundedUp(), 0)
+      << "WorkerPoolTaskRunner does not support non-zero delays";
+  return WorkerPool::PostTask(from_here, task, tasks_are_slow_);
+}
+
+struct TaskRunnerHolder {
+  TaskRunnerHolder() {
+    taskrunners_[0] = new WorkerPoolTaskRunner(false);
+    taskrunners_[1] = new WorkerPoolTaskRunner(true);
+  }
+  scoped_refptr<TaskRunner> taskrunners_[2];
+};
+
+base::LazyInstance<TaskRunnerHolder>::Leaky
+    g_taskrunners = LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+bool WorkerPool::PostTaskAndReply(const tracked_objects::Location& from_here,
+                                  const Closure& task,
+                                  const Closure& reply,
+                                  bool task_is_slow) {
+  // Do not report PostTaskAndReplyRelay leaks in tests. There's nothing we can
+  // do about them because WorkerPool doesn't have a flushing API.
+  // http://crbug.com/248513
+  // http://crbug.com/290897
+  // Note: this annotation does not cover tasks posted through a TaskRunner.
+  ANNOTATE_SCOPED_MEMORY_LEAK;
+  return PostTaskAndReplyWorkerPool(task_is_slow).PostTaskAndReply(
+      from_here, task, reply);
+}
+
+// static
+const scoped_refptr<TaskRunner>&
+WorkerPool::GetTaskRunner(bool tasks_are_slow) {
+  return g_taskrunners.Get().taskrunners_[tasks_are_slow];
+}
+
+}  // namespace base
diff --git a/base/threading/worker_pool.h b/base/threading/worker_pool.h
new file mode 100644
index 0000000..a52a414
--- /dev/null
+++ b/base/threading/worker_pool.h
@@ -0,0 +1,60 @@
+// Copyright (c) 2012 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_THREADING_WORKER_POOL_H_
+#define BASE_THREADING_WORKER_POOL_H_
+
+#include "base/base_export.h"
+#include "base/callback_forward.h"
+#include "base/memory/ref_counted.h"
+
+class Task;
+
+namespace tracked_objects {
+class Location;
+}  // namespace tracked_objects
+
+namespace base {
+
+class TaskRunner;
+
+// This is a facility that runs tasks that don't require a specific thread or
+// a message loop.
+//
+// WARNING: This shouldn't be used unless absolutely necessary. We don't wait
+// for the worker pool threads to finish on shutdown, so the tasks running
+// inside the pool must be extremely careful about other objects they access
+// (MessageLoops, Singletons, etc). During shutdown these object may no longer
+// exist.
+class BASE_EXPORT WorkerPool {
+ public:
+  // This function posts |task| to run on a worker thread.  |task_is_slow|
+  // should be used for tasks that will take a long time to execute.  Returns
+  // false if |task| could not be posted to a worker thread.  Regardless of
+  // return value, ownership of |task| is transferred to the worker pool.
+  static bool PostTask(const tracked_objects::Location& from_here,
+                       const base::Closure& task, bool task_is_slow);
+
+  // Just like TaskRunner::PostTaskAndReply, except the destination
+  // for |task| is a worker thread and you can specify |task_is_slow| just
+  // like you can for PostTask above.
+  static bool PostTaskAndReply(const tracked_objects::Location& from_here,
+                               const Closure& task,
+                               const Closure& reply,
+                               bool task_is_slow);
+
+  // Return true if the current thread is one that this WorkerPool runs tasks
+  // on.  (Note that if the Windows worker pool is used without going through
+  // this WorkerPool interface, RunsTasksOnCurrentThread would return false on
+  // those threads.)
+  static bool RunsTasksOnCurrentThread();
+
+  // Get a TaskRunner wrapper which posts to the WorkerPool using the given
+  // |task_is_slow| behavior.
+  static const scoped_refptr<TaskRunner>& GetTaskRunner(bool task_is_slow);
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_WORKER_POOL_H_
diff --git a/base/threading/worker_pool_posix.cc b/base/threading/worker_pool_posix.cc
new file mode 100644
index 0000000..349b5d7
--- /dev/null
+++ b/base/threading/worker_pool_posix.cc
@@ -0,0 +1,193 @@
+// Copyright (c) 2012 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/threading/worker_pool_posix.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/strings/stringprintf.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread_local.h"
+#include "base/threading/worker_pool.h"
+#include "base/trace_event/trace_event.h"
+#include "base/tracked_objects.h"
+
+using tracked_objects::TrackedTime;
+
+namespace base {
+
+namespace {
+
+base::LazyInstance<ThreadLocalBoolean>::Leaky
+    g_worker_pool_running_on_this_thread = LAZY_INSTANCE_INITIALIZER;
+
+const int kIdleSecondsBeforeExit = 10 * 60;
+
+class WorkerPoolImpl {
+ public:
+  WorkerPoolImpl();
+  ~WorkerPoolImpl();
+
+  void PostTask(const tracked_objects::Location& from_here,
+                const base::Closure& task, bool task_is_slow);
+
+ private:
+  scoped_refptr<base::PosixDynamicThreadPool> pool_;
+};
+
+WorkerPoolImpl::WorkerPoolImpl()
+    : pool_(new base::PosixDynamicThreadPool("WorkerPool",
+                                             kIdleSecondsBeforeExit)) {
+}
+
+WorkerPoolImpl::~WorkerPoolImpl() {
+  pool_->Terminate();
+}
+
+void WorkerPoolImpl::PostTask(const tracked_objects::Location& from_here,
+                              const base::Closure& task, bool task_is_slow) {
+  pool_->PostTask(from_here, task);
+}
+
+base::LazyInstance<WorkerPoolImpl> g_lazy_worker_pool =
+    LAZY_INSTANCE_INITIALIZER;
+
+class WorkerThread : public PlatformThread::Delegate {
+ public:
+  WorkerThread(const std::string& name_prefix,
+               base::PosixDynamicThreadPool* pool)
+      : name_prefix_(name_prefix),
+        pool_(pool) {}
+
+  void ThreadMain() override;
+
+ private:
+  const std::string name_prefix_;
+  scoped_refptr<base::PosixDynamicThreadPool> pool_;
+
+  DISALLOW_COPY_AND_ASSIGN(WorkerThread);
+};
+
+void WorkerThread::ThreadMain() {
+  g_worker_pool_running_on_this_thread.Get().Set(true);
+  const std::string name = base::StringPrintf(
+      "%s/%d", name_prefix_.c_str(), PlatformThread::CurrentId());
+  // Note |name.c_str()| must remain valid for for the whole life of the thread.
+  PlatformThread::SetName(name);
+
+  for (;;) {
+    PendingTask pending_task = pool_->WaitForTask();
+    if (pending_task.task.is_null())
+      break;
+    TRACE_EVENT2("toplevel", "WorkerThread::ThreadMain::Run",
+        "src_file", pending_task.posted_from.file_name(),
+        "src_func", pending_task.posted_from.function_name());
+
+    tracked_objects::TaskStopwatch stopwatch;
+    stopwatch.Start();
+    pending_task.task.Run();
+    stopwatch.Stop();
+
+    tracked_objects::ThreadData::TallyRunOnWorkerThreadIfTracking(
+        pending_task.birth_tally, pending_task.time_posted, stopwatch);
+  }
+
+  // The WorkerThread is non-joinable, so it deletes itself.
+  delete this;
+}
+
+}  // namespace
+
+// static
+bool WorkerPool::PostTask(const tracked_objects::Location& from_here,
+                          const base::Closure& task, bool task_is_slow) {
+  g_lazy_worker_pool.Pointer()->PostTask(from_here, task, task_is_slow);
+  return true;
+}
+
+// static
+bool WorkerPool::RunsTasksOnCurrentThread() {
+  return g_worker_pool_running_on_this_thread.Get().Get();
+}
+
+PosixDynamicThreadPool::PosixDynamicThreadPool(const std::string& name_prefix,
+                                               int idle_seconds_before_exit)
+    : name_prefix_(name_prefix),
+      idle_seconds_before_exit_(idle_seconds_before_exit),
+      pending_tasks_available_cv_(&lock_),
+      num_idle_threads_(0),
+      terminated_(false) {}
+
+PosixDynamicThreadPool::~PosixDynamicThreadPool() {
+  while (!pending_tasks_.empty())
+    pending_tasks_.pop();
+}
+
+void PosixDynamicThreadPool::Terminate() {
+  {
+    AutoLock locked(lock_);
+    DCHECK(!terminated_) << "Thread pool is already terminated.";
+    terminated_ = true;
+  }
+  pending_tasks_available_cv_.Broadcast();
+}
+
+void PosixDynamicThreadPool::PostTask(
+    const tracked_objects::Location& from_here,
+    const base::Closure& task) {
+  PendingTask pending_task(from_here, task);
+  AddTask(&pending_task);
+}
+
+void PosixDynamicThreadPool::AddTask(PendingTask* pending_task) {
+  AutoLock locked(lock_);
+  DCHECK(!terminated_) <<
+      "This thread pool is already terminated.  Do not post new tasks.";
+
+  pending_tasks_.push(*pending_task);
+  pending_task->task.Reset();
+
+  // We have enough worker threads.
+  if (static_cast<size_t>(num_idle_threads_) >= pending_tasks_.size()) {
+    pending_tasks_available_cv_.Signal();
+  } else {
+    // The new PlatformThread will take ownership of the WorkerThread object,
+    // which will delete itself on exit.
+    WorkerThread* worker =
+        new WorkerThread(name_prefix_, this);
+    PlatformThread::CreateNonJoinable(0, worker);
+  }
+}
+
+PendingTask PosixDynamicThreadPool::WaitForTask() {
+  AutoLock locked(lock_);
+
+  if (terminated_)
+    return PendingTask(FROM_HERE, base::Closure());
+
+  if (pending_tasks_.empty()) {  // No work available, wait for work.
+    num_idle_threads_++;
+    if (num_idle_threads_cv_.get())
+      num_idle_threads_cv_->Signal();
+    pending_tasks_available_cv_.TimedWait(
+        TimeDelta::FromSeconds(idle_seconds_before_exit_));
+    num_idle_threads_--;
+    if (num_idle_threads_cv_.get())
+      num_idle_threads_cv_->Signal();
+    if (pending_tasks_.empty()) {
+      // We waited for work, but there's still no work.  Return NULL to signal
+      // the thread to terminate.
+      return PendingTask(FROM_HERE, base::Closure());
+    }
+  }
+
+  PendingTask pending_task = pending_tasks_.front();
+  pending_tasks_.pop();
+  return pending_task;
+}
+
+}  // namespace base
diff --git a/base/threading/worker_pool_posix.h b/base/threading/worker_pool_posix.h
new file mode 100644
index 0000000..dd0ffb6
--- /dev/null
+++ b/base/threading/worker_pool_posix.h
@@ -0,0 +1,98 @@
+// Copyright (c) 2012 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.
+//
+// The thread pool used in the POSIX implementation of WorkerPool dynamically
+// adds threads as necessary to handle all tasks.  It keeps old threads around
+// for a period of time to allow them to be reused.  After this waiting period,
+// the threads exit.  This thread pool uses non-joinable threads, therefore
+// worker threads are not joined during process shutdown.  This means that
+// potentially long running tasks (such as DNS lookup) do not block process
+// shutdown, but also means that process shutdown may "leak" objects.  Note that
+// although PosixDynamicThreadPool spawns the worker threads and manages the
+// task queue, it does not own the worker threads.  The worker threads ask the
+// PosixDynamicThreadPool for work and eventually clean themselves up.  The
+// worker threads all maintain scoped_refptrs to the PosixDynamicThreadPool
+// instance, which prevents PosixDynamicThreadPool from disappearing before all
+// worker threads exit.  The owner of PosixDynamicThreadPool should likewise
+// maintain a scoped_refptr to the PosixDynamicThreadPool instance.
+//
+// NOTE: The classes defined in this file are only meant for use by the POSIX
+// implementation of WorkerPool.  No one else should be using these classes.
+// These symbols are exported in a header purely for testing purposes.
+
+#ifndef BASE_THREADING_WORKER_POOL_POSIX_H_
+#define BASE_THREADING_WORKER_POOL_POSIX_H_
+
+#include <queue>
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/callback_forward.h"
+#include "base/location.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/pending_task.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/platform_thread.h"
+#include "base/tracked_objects.h"
+
+class Task;
+
+namespace base {
+
+class BASE_EXPORT PosixDynamicThreadPool
+    : public RefCountedThreadSafe<PosixDynamicThreadPool> {
+ public:
+  class PosixDynamicThreadPoolPeer;
+
+  // All worker threads will share the same |name_prefix|.  They will exit after
+  // |idle_seconds_before_exit|.
+  PosixDynamicThreadPool(const std::string& name_prefix,
+                         int idle_seconds_before_exit);
+
+  // Indicates that the thread pool is going away.  Stops handing out tasks to
+  // worker threads.  Wakes up all the idle threads to let them exit.
+  void Terminate();
+
+  // Adds |task| to the thread pool.
+  void PostTask(const tracked_objects::Location& from_here,
+                const Closure& task);
+
+  // Worker thread method to wait for up to |idle_seconds_before_exit| for more
+  // work from the thread pool.  Returns NULL if no work is available.
+  PendingTask WaitForTask();
+
+ private:
+  friend class RefCountedThreadSafe<PosixDynamicThreadPool>;
+  friend class PosixDynamicThreadPoolPeer;
+
+  ~PosixDynamicThreadPool();
+
+  // Adds pending_task to the thread pool.  This function will clear
+  // |pending_task->task|.
+  void AddTask(PendingTask* pending_task);
+
+  const std::string name_prefix_;
+  const int idle_seconds_before_exit_;
+
+  Lock lock_;  // Protects all the variables below.
+
+  // Signal()s worker threads to let them know more tasks are available.
+  // Also used for Broadcast()'ing to worker threads to let them know the pool
+  // is being deleted and they can exit.
+  ConditionVariable pending_tasks_available_cv_;
+  int num_idle_threads_;
+  TaskQueue pending_tasks_;
+  bool terminated_;
+  // Only used for tests to ensure correct thread ordering.  It will always be
+  // NULL in non-test code.
+  scoped_ptr<ConditionVariable> num_idle_threads_cv_;
+
+  DISALLOW_COPY_AND_ASSIGN(PosixDynamicThreadPool);
+};
+
+}  // namespace base
+
+#endif  // BASE_THREADING_WORKER_POOL_POSIX_H_
diff --git a/base/threading/worker_pool_posix_unittest.cc b/base/threading/worker_pool_posix_unittest.cc
new file mode 100644
index 0000000..354a99c
--- /dev/null
+++ b/base/threading/worker_pool_posix_unittest.cc
@@ -0,0 +1,253 @@
+// Copyright (c) 2012 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/threading/worker_pool_posix.h"
+
+#include <set>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/platform_thread.h"
+#include "base/synchronization/waitable_event.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+// Peer class to provide passthrough access to PosixDynamicThreadPool internals.
+class PosixDynamicThreadPool::PosixDynamicThreadPoolPeer {
+ public:
+  explicit PosixDynamicThreadPoolPeer(PosixDynamicThreadPool* pool)
+      : pool_(pool) {}
+
+  Lock* lock() { return &pool_->lock_; }
+  ConditionVariable* pending_tasks_available_cv() {
+    return &pool_->pending_tasks_available_cv_;
+  }
+  const std::queue<PendingTask>& pending_tasks() const {
+    return pool_->pending_tasks_;
+  }
+  int num_idle_threads() const { return pool_->num_idle_threads_; }
+  ConditionVariable* num_idle_threads_cv() {
+    return pool_->num_idle_threads_cv_.get();
+  }
+  void set_num_idle_threads_cv(ConditionVariable* cv) {
+    pool_->num_idle_threads_cv_.reset(cv);
+  }
+
+ private:
+  PosixDynamicThreadPool* pool_;
+
+  DISALLOW_COPY_AND_ASSIGN(PosixDynamicThreadPoolPeer);
+};
+
+namespace {
+
+// IncrementingTask's main purpose is to increment a counter.  It also updates a
+// set of unique thread ids, and signals a ConditionVariable on completion.
+// Note that since it does not block, there is no way to control the number of
+// threads used if more than one IncrementingTask is consecutively posted to the
+// thread pool, since the first one might finish executing before the subsequent
+// PostTask() calls get invoked.
+void IncrementingTask(Lock* counter_lock,
+                      int* counter,
+                      Lock* unique_threads_lock,
+                      std::set<PlatformThreadId>* unique_threads) {
+  {
+    base::AutoLock locked(*unique_threads_lock);
+    unique_threads->insert(PlatformThread::CurrentId());
+  }
+  base::AutoLock locked(*counter_lock);
+  (*counter)++;
+}
+
+// BlockingIncrementingTask is a simple wrapper around IncrementingTask that
+// allows for waiting at the start of Run() for a WaitableEvent to be signalled.
+struct BlockingIncrementingTaskArgs {
+  Lock* counter_lock;
+  int* counter;
+  Lock* unique_threads_lock;
+  std::set<PlatformThreadId>* unique_threads;
+  Lock* num_waiting_to_start_lock;
+  int* num_waiting_to_start;
+  ConditionVariable* num_waiting_to_start_cv;
+  base::WaitableEvent* start;
+};
+
+void BlockingIncrementingTask(const BlockingIncrementingTaskArgs& args) {
+  {
+    base::AutoLock num_waiting_to_start_locked(*args.num_waiting_to_start_lock);
+    (*args.num_waiting_to_start)++;
+  }
+  args.num_waiting_to_start_cv->Signal();
+  args.start->Wait();
+  IncrementingTask(args.counter_lock, args.counter, args.unique_threads_lock,
+                   args.unique_threads);
+}
+
+class PosixDynamicThreadPoolTest : public testing::Test {
+ protected:
+  PosixDynamicThreadPoolTest()
+      : pool_(new base::PosixDynamicThreadPool("dynamic_pool", 60*60)),
+        peer_(pool_.get()),
+        counter_(0),
+        num_waiting_to_start_(0),
+        num_waiting_to_start_cv_(&num_waiting_to_start_lock_),
+        start_(true, false) {}
+
+  void SetUp() override {
+    peer_.set_num_idle_threads_cv(new ConditionVariable(peer_.lock()));
+  }
+
+  void TearDown() override {
+    // Wake up the idle threads so they can terminate.
+    if (pool_.get()) pool_->Terminate();
+  }
+
+  void WaitForTasksToStart(int num_tasks) {
+    base::AutoLock num_waiting_to_start_locked(num_waiting_to_start_lock_);
+    while (num_waiting_to_start_ < num_tasks) {
+      num_waiting_to_start_cv_.Wait();
+    }
+  }
+
+  void WaitForIdleThreads(int num_idle_threads) {
+    base::AutoLock pool_locked(*peer_.lock());
+    while (peer_.num_idle_threads() < num_idle_threads) {
+      peer_.num_idle_threads_cv()->Wait();
+    }
+  }
+
+  base::Closure CreateNewIncrementingTaskCallback() {
+    return base::Bind(&IncrementingTask, &counter_lock_, &counter_,
+                      &unique_threads_lock_, &unique_threads_);
+  }
+
+  base::Closure CreateNewBlockingIncrementingTaskCallback() {
+    BlockingIncrementingTaskArgs args = {
+        &counter_lock_, &counter_, &unique_threads_lock_, &unique_threads_,
+        &num_waiting_to_start_lock_, &num_waiting_to_start_,
+        &num_waiting_to_start_cv_, &start_
+    };
+    return base::Bind(&BlockingIncrementingTask, args);
+  }
+
+  scoped_refptr<base::PosixDynamicThreadPool> pool_;
+  base::PosixDynamicThreadPool::PosixDynamicThreadPoolPeer peer_;
+  Lock counter_lock_;
+  int counter_;
+  Lock unique_threads_lock_;
+  std::set<PlatformThreadId> unique_threads_;
+  Lock num_waiting_to_start_lock_;
+  int num_waiting_to_start_;
+  ConditionVariable num_waiting_to_start_cv_;
+  base::WaitableEvent start_;
+};
+
+}  // namespace
+
+TEST_F(PosixDynamicThreadPoolTest, Basic) {
+  EXPECT_EQ(0, peer_.num_idle_threads());
+  EXPECT_EQ(0U, unique_threads_.size());
+  EXPECT_EQ(0U, peer_.pending_tasks().size());
+
+  // Add one task and wait for it to be completed.
+  pool_->PostTask(FROM_HERE, CreateNewIncrementingTaskCallback());
+
+  WaitForIdleThreads(1);
+
+  EXPECT_EQ(1U, unique_threads_.size()) <<
+      "There should be only one thread allocated for one task.";
+  EXPECT_EQ(1, counter_);
+}
+
+TEST_F(PosixDynamicThreadPoolTest, ReuseIdle) {
+  // Add one task and wait for it to be completed.
+  pool_->PostTask(FROM_HERE, CreateNewIncrementingTaskCallback());
+
+  WaitForIdleThreads(1);
+
+  // Add another 2 tasks.  One should reuse the existing worker thread.
+  pool_->PostTask(FROM_HERE, CreateNewBlockingIncrementingTaskCallback());
+  pool_->PostTask(FROM_HERE, CreateNewBlockingIncrementingTaskCallback());
+
+  WaitForTasksToStart(2);
+  start_.Signal();
+  WaitForIdleThreads(2);
+
+  EXPECT_EQ(2U, unique_threads_.size());
+  EXPECT_EQ(2, peer_.num_idle_threads());
+  EXPECT_EQ(3, counter_);
+}
+
+TEST_F(PosixDynamicThreadPoolTest, TwoActiveTasks) {
+  // Add two blocking tasks.
+  pool_->PostTask(FROM_HERE, CreateNewBlockingIncrementingTaskCallback());
+  pool_->PostTask(FROM_HERE, CreateNewBlockingIncrementingTaskCallback());
+
+  EXPECT_EQ(0, counter_) << "Blocking tasks should not have started yet.";
+
+  WaitForTasksToStart(2);
+  start_.Signal();
+  WaitForIdleThreads(2);
+
+  EXPECT_EQ(2U, unique_threads_.size());
+  EXPECT_EQ(2, peer_.num_idle_threads()) << "Existing threads are now idle.";
+  EXPECT_EQ(2, counter_);
+}
+
+TEST_F(PosixDynamicThreadPoolTest, Complex) {
+  // Add two non blocking tasks and wait for them to finish.
+  pool_->PostTask(FROM_HERE, CreateNewIncrementingTaskCallback());
+
+  WaitForIdleThreads(1);
+
+  // Add two blocking tasks, start them simultaneously, and wait for them to
+  // finish.
+  pool_->PostTask(FROM_HERE, CreateNewBlockingIncrementingTaskCallback());
+  pool_->PostTask(FROM_HERE, CreateNewBlockingIncrementingTaskCallback());
+
+  WaitForTasksToStart(2);
+  start_.Signal();
+  WaitForIdleThreads(2);
+
+  EXPECT_EQ(3, counter_);
+  EXPECT_EQ(2, peer_.num_idle_threads());
+  EXPECT_EQ(2U, unique_threads_.size());
+
+  // Wake up all idle threads so they can exit.
+  {
+    base::AutoLock locked(*peer_.lock());
+    while (peer_.num_idle_threads() > 0) {
+      peer_.pending_tasks_available_cv()->Signal();
+      peer_.num_idle_threads_cv()->Wait();
+    }
+  }
+
+  // Add another non blocking task.  There are no threads to reuse.
+  pool_->PostTask(FROM_HERE, CreateNewIncrementingTaskCallback());
+  WaitForIdleThreads(1);
+
+  // The POSIX implementation of PlatformThread::CurrentId() uses pthread_self()
+  // which is not guaranteed to be unique after a thread joins. The OS X
+  // implemntation of pthread_self() returns the address of the pthread_t, which
+  // is merely a malloc()ed pointer stored in the first TLS slot. When a thread
+  // joins and that structure is freed, the block of memory can be put on the
+  // OS free list, meaning the same address could be reused in a subsequent
+  // allocation. This in fact happens when allocating in a loop as this test
+  // does.
+  //
+  // Because there are two concurrent threads, there's at least the guarantee
+  // of having two unique thread IDs in the set. But after those two threads are
+  // joined, the next-created thread can get a re-used ID if the allocation of
+  // the pthread_t structure is taken from the free list. Therefore, there can
+  // be either 2 or 3 unique thread IDs in the set at this stage in the test.
+  EXPECT_TRUE(unique_threads_.size() >= 2 && unique_threads_.size() <= 3)
+      << "unique_threads_.size() = " << unique_threads_.size();
+  EXPECT_EQ(1, peer_.num_idle_threads());
+  EXPECT_EQ(4, counter_);
+}
+
+}  // namespace base
diff --git a/base/threading/worker_pool_unittest.cc b/base/threading/worker_pool_unittest.cc
new file mode 100644
index 0000000..9a9ab95
--- /dev/null
+++ b/base/threading/worker_pool_unittest.cc
@@ -0,0 +1,112 @@
+// Copyright (c) 2012 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/threading/worker_pool.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/location.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/test/test_timeouts.h"
+#include "base/threading/thread_checker_impl.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+typedef PlatformTest WorkerPoolTest;
+
+namespace base {
+
+namespace {
+
+class PostTaskAndReplyTester
+    : public base::RefCountedThreadSafe<PostTaskAndReplyTester> {
+ public:
+  PostTaskAndReplyTester() : finished_(false), test_event_(false, false) {}
+
+  void RunTest() {
+    ASSERT_TRUE(thread_checker_.CalledOnValidThread());
+    WorkerPool::PostTaskAndReply(
+      FROM_HERE,
+      base::Bind(&PostTaskAndReplyTester::OnWorkerThread, this),
+      base::Bind(&PostTaskAndReplyTester::OnOriginalThread, this),
+      false);
+
+    test_event_.Wait();
+  }
+
+  void OnWorkerThread() {
+    // We're not on the original thread.
+    EXPECT_FALSE(thread_checker_.CalledOnValidThread());
+
+    test_event_.Signal();
+  }
+
+  void OnOriginalThread() {
+    EXPECT_TRUE(thread_checker_.CalledOnValidThread());
+    finished_ = true;
+  }
+
+  bool finished() const {
+    return finished_;
+  }
+
+ private:
+  friend class base::RefCountedThreadSafe<PostTaskAndReplyTester>;
+  ~PostTaskAndReplyTester() {}
+
+  bool finished_;
+  WaitableEvent test_event_;
+
+  // The Impl version performs its checks even in release builds.
+  ThreadCheckerImpl thread_checker_;
+};
+
+}  // namespace
+
+TEST_F(WorkerPoolTest, PostTask) {
+  WaitableEvent test_event(false, false);
+  WaitableEvent long_test_event(false, false);
+
+  WorkerPool::PostTask(FROM_HERE,
+                       base::Bind(&WaitableEvent::Signal,
+                                  base::Unretained(&test_event)),
+                       false);
+  WorkerPool::PostTask(FROM_HERE,
+                       base::Bind(&WaitableEvent::Signal,
+                                  base::Unretained(&long_test_event)),
+                       true);
+
+  test_event.Wait();
+  long_test_event.Wait();
+}
+
+#if defined(OS_WIN) || defined(OS_LINUX)
+// Flaky on Windows and Linux (http://crbug.com/130337)
+#define MAYBE_PostTaskAndReply DISABLED_PostTaskAndReply
+#else
+#define MAYBE_PostTaskAndReply PostTaskAndReply
+#endif
+
+TEST_F(WorkerPoolTest, MAYBE_PostTaskAndReply) {
+  MessageLoop message_loop;
+  scoped_refptr<PostTaskAndReplyTester> tester(new PostTaskAndReplyTester());
+  tester->RunTest();
+
+  const TimeDelta kMaxDuration = TestTimeouts::tiny_timeout();
+  TimeTicks start = TimeTicks::Now();
+  while (!tester->finished() && TimeTicks::Now() - start < kMaxDuration) {
+#if defined(OS_IOS)
+    // Ensure that the other thread has a chance to run even on a single-core
+    // device.
+    pthread_yield_np();
+#endif
+    RunLoop().RunUntilIdle();
+  }
+  EXPECT_TRUE(tester->finished());
+}
+
+}  // namespace base
diff --git a/base/threading/worker_pool_win.cc b/base/threading/worker_pool_win.cc
new file mode 100644
index 0000000..1b0ade5
--- /dev/null
+++ b/base/threading/worker_pool_win.cc
@@ -0,0 +1,73 @@
+// Copyright (c) 2012 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/threading/worker_pool.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/pending_task.h"
+#include "base/threading/thread_local.h"
+#include "base/trace_event/trace_event.h"
+#include "base/tracked_objects.h"
+
+namespace base {
+
+namespace {
+
+base::LazyInstance<ThreadLocalBoolean>::Leaky
+    g_worker_pool_running_on_this_thread = LAZY_INSTANCE_INITIALIZER;
+
+DWORD CALLBACK WorkItemCallback(void* param) {
+  PendingTask* pending_task = static_cast<PendingTask*>(param);
+  TRACE_EVENT2("toplevel", "WorkItemCallback::Run",
+               "src_file", pending_task->posted_from.file_name(),
+               "src_func", pending_task->posted_from.function_name());
+
+  g_worker_pool_running_on_this_thread.Get().Set(true);
+
+  tracked_objects::TaskStopwatch stopwatch;
+  stopwatch.Start();
+  pending_task->task.Run();
+  stopwatch.Stop();
+
+  g_worker_pool_running_on_this_thread.Get().Set(false);
+
+  tracked_objects::ThreadData::TallyRunOnWorkerThreadIfTracking(
+      pending_task->birth_tally, pending_task->time_posted, stopwatch);
+
+  delete pending_task;
+  return 0;
+}
+
+// Takes ownership of |pending_task|
+bool PostTaskInternal(PendingTask* pending_task, bool task_is_slow) {
+  ULONG flags = 0;
+  if (task_is_slow)
+    flags |= WT_EXECUTELONGFUNCTION;
+
+  if (!QueueUserWorkItem(WorkItemCallback, pending_task, flags)) {
+    DPLOG(ERROR) << "QueueUserWorkItem failed";
+    delete pending_task;
+    return false;
+  }
+
+  return true;
+}
+
+}  // namespace
+
+// static
+bool WorkerPool::PostTask(const tracked_objects::Location& from_here,
+                          const base::Closure& task, bool task_is_slow) {
+  PendingTask* pending_task = new PendingTask(from_here, task);
+  return PostTaskInternal(pending_task, task_is_slow);
+}
+
+// static
+bool WorkerPool::RunsTasksOnCurrentThread() {
+  return g_worker_pool_running_on_this_thread.Get().Get();
+}
+
+}  // namespace base
diff --git a/base/time/clock.cc b/base/time/clock.cc
new file mode 100644
index 0000000..34dc37e
--- /dev/null
+++ b/base/time/clock.cc
@@ -0,0 +1,11 @@
+// Copyright (c) 2012 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/time/clock.h"
+
+namespace base {
+
+Clock::~Clock() {}
+
+}  // namespace base
diff --git a/base/time/clock.h b/base/time/clock.h
new file mode 100644
index 0000000..507a850
--- /dev/null
+++ b/base/time/clock.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2012 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_TIME_CLOCK_H_
+#define BASE_TIME_CLOCK_H_
+
+#include "base/base_export.h"
+#include "base/time/time.h"
+
+namespace base {
+
+// A Clock is an interface for objects that vend Times.  It is
+// intended to be able to test the behavior of classes with respect to
+// time.
+//
+// See DefaultClock (base/time/default_clock.h) for the default
+// implementation that simply uses Time::Now().
+//
+// (An implementation that uses Time::SystemTime() should be added as
+// needed.)
+//
+// See SimpleTestClock (base/test/simple_test_clock.h) for a simple
+// test implementation.
+//
+// See TickClock (base/time/tick_clock.h) for the equivalent interface for
+// TimeTicks.
+class BASE_EXPORT Clock {
+ public:
+  virtual ~Clock();
+
+  // Now() must be safe to call from any thread.  The caller cannot
+  // make any ordering assumptions about the returned Time.  For
+  // example, the system clock may change to an earlier time.
+  virtual Time Now() = 0;
+};
+
+}  // namespace base
+
+#endif  // BASE_TIME_CLOCK_H_
diff --git a/base/time/default_clock.cc b/base/time/default_clock.cc
new file mode 100644
index 0000000..5f70114
--- /dev/null
+++ b/base/time/default_clock.cc
@@ -0,0 +1,15 @@
+// Copyright (c) 2012 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/time/default_clock.h"
+
+namespace base {
+
+DefaultClock::~DefaultClock() {}
+
+Time DefaultClock::Now() {
+  return Time::Now();
+}
+
+}  // namespace base
diff --git a/base/time/default_clock.h b/base/time/default_clock.h
new file mode 100644
index 0000000..0b8250e
--- /dev/null
+++ b/base/time/default_clock.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2012 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_TIME_DEFAULT_CLOCK_H_
+#define BASE_TIME_DEFAULT_CLOCK_H_
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/time/clock.h"
+
+namespace base {
+
+// DefaultClock is a Clock implementation that uses Time::Now().
+class BASE_EXPORT DefaultClock : public Clock {
+ public:
+  ~DefaultClock() override;
+
+  // Simply returns Time::Now().
+  Time Now() override;
+};
+
+}  // namespace base
+
+#endif  // BASE_TIME_DEFAULT_CLOCK_H_
diff --git a/base/time/default_tick_clock.cc b/base/time/default_tick_clock.cc
new file mode 100644
index 0000000..ce62fcc
--- /dev/null
+++ b/base/time/default_tick_clock.cc
@@ -0,0 +1,15 @@
+// Copyright (c) 2012 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/time/default_tick_clock.h"
+
+namespace base {
+
+DefaultTickClock::~DefaultTickClock() {}
+
+TimeTicks DefaultTickClock::NowTicks() {
+  return TimeTicks::Now();
+}
+
+}  // namespace base
diff --git a/base/time/default_tick_clock.h b/base/time/default_tick_clock.h
new file mode 100644
index 0000000..cb041e6
--- /dev/null
+++ b/base/time/default_tick_clock.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2012 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_TIME_DEFAULT_TICK_CLOCK_H_
+#define BASE_TIME_DEFAULT_TICK_CLOCK_H_
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/time/tick_clock.h"
+
+namespace base {
+
+// DefaultClock is a Clock implementation that uses TimeTicks::Now().
+class BASE_EXPORT DefaultTickClock : public TickClock {
+ public:
+  ~DefaultTickClock() override;
+
+  // Simply returns TimeTicks::Now().
+  TimeTicks NowTicks() override;
+};
+
+}  // namespace base
+
+#endif  // BASE_TIME_DEFAULT_TICK_CLOCK_H_
diff --git a/base/time/pr_time_unittest.cc b/base/time/pr_time_unittest.cc
new file mode 100644
index 0000000..06043a5
--- /dev/null
+++ b/base/time/pr_time_unittest.cc
@@ -0,0 +1,288 @@
+// Copyright (c) 2012 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 <stdint.h>
+#include <time.h>
+
+#include "base/compiler_specific.h"
+#include "base/third_party/nspr/prtime.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::Time;
+
+namespace {
+
+// time_t representation of 15th Oct 2007 12:45:00 PDT
+PRTime comparison_time_pdt = 1192477500 * Time::kMicrosecondsPerSecond;
+
+// Time with positive tz offset and fractional seconds:
+// 2013-07-08T11:28:12.441381+02:00
+PRTime comparison_time_2 = INT64_C(1373275692441381);   // represented as GMT
+
+// Specialized test fixture allowing time strings without timezones to be
+// tested by comparing them to a known time in the local zone.
+class PRTimeTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    // Use mktime to get a time_t, and turn it into a PRTime by converting
+    // seconds to microseconds.  Use 15th Oct 2007 12:45:00 local.  This
+    // must be a time guaranteed to be outside of a DST fallback hour in
+    // any timezone.
+    struct tm local_comparison_tm = {
+      0,            // second
+      45,           // minute
+      12,           // hour
+      15,           // day of month
+      10 - 1,       // month
+      2007 - 1900,  // year
+      0,            // day of week (ignored, output only)
+      0,            // day of year (ignored, output only)
+      -1            // DST in effect, -1 tells mktime to figure it out
+    };
+    comparison_time_local_ =
+        mktime(&local_comparison_tm) * Time::kMicrosecondsPerSecond;
+    ASSERT_GT(comparison_time_local_, 0);
+
+    const int microseconds = 441381;
+    struct tm local_comparison_tm_2 = {
+      12,           // second
+      28,           // minute
+      11,           // hour
+      8,            // day of month
+      7 - 1,        // month
+      2013 - 1900,  // year
+      0,            // day of week (ignored, output only)
+      0,            // day of year (ignored, output only)
+      -1            // DST in effect, -1 tells mktime to figure it out
+    };
+    comparison_time_local_2_ =
+        mktime(&local_comparison_tm_2) * Time::kMicrosecondsPerSecond;
+    ASSERT_GT(comparison_time_local_2_, 0);
+    comparison_time_local_2_ += microseconds;
+  }
+
+  PRTime comparison_time_local_;
+  PRTime comparison_time_local_2_;
+};
+
+// Tests the PR_ParseTimeString nspr helper function for
+// a variety of time strings.
+TEST_F(PRTimeTest, ParseTimeTest1) {
+  time_t current_time = 0;
+  time(&current_time);
+
+  const int BUFFER_SIZE = 64;
+  struct tm local_time = {0};
+  char time_buf[BUFFER_SIZE] = {0};
+#if defined(OS_WIN)
+  localtime_s(&local_time, &current_time);
+  asctime_s(time_buf, arraysize(time_buf), &local_time);
+#elif defined(OS_POSIX)
+  localtime_r(&current_time, &local_time);
+  asctime_r(&local_time, time_buf);
+#endif
+
+  PRTime current_time64 = static_cast<PRTime>(current_time) * PR_USEC_PER_SEC;
+
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString(time_buf, PR_FALSE, &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+  EXPECT_EQ(current_time64, parsed_time);
+}
+
+TEST_F(PRTimeTest, ParseTimeTest2) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("Mon, 15 Oct 2007 19:45:00 GMT",
+                                       PR_FALSE, &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+  EXPECT_EQ(comparison_time_pdt, parsed_time);
+}
+
+TEST_F(PRTimeTest, ParseTimeTest3) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("15 Oct 07 12:45:00", PR_FALSE,
+                                       &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+  EXPECT_EQ(comparison_time_local_, parsed_time);
+}
+
+TEST_F(PRTimeTest, ParseTimeTest4) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("15 Oct 07 19:45 GMT", PR_FALSE,
+                                       &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+  EXPECT_EQ(comparison_time_pdt, parsed_time);
+}
+
+TEST_F(PRTimeTest, ParseTimeTest5) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("Mon Oct 15 12:45 PDT 2007",
+                                       PR_FALSE, &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+  EXPECT_EQ(comparison_time_pdt, parsed_time);
+}
+
+TEST_F(PRTimeTest, ParseTimeTest6) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("Monday, Oct 15, 2007 12:45 PM",
+                                       PR_FALSE, &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+  EXPECT_EQ(comparison_time_local_, parsed_time);
+}
+
+TEST_F(PRTimeTest, ParseTimeTest7) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("10/15/07 12:45:00 PM", PR_FALSE,
+                                       &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+  EXPECT_EQ(comparison_time_local_, parsed_time);
+}
+
+TEST_F(PRTimeTest, ParseTimeTest8) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("10/15/07 12:45:00. PM", PR_FALSE,
+                                       &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+  EXPECT_EQ(comparison_time_local_, parsed_time);
+}
+
+TEST_F(PRTimeTest, ParseTimeTest9) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("10/15/07 12:45:00.0 PM", PR_FALSE,
+                                       &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+  EXPECT_EQ(comparison_time_local_, parsed_time);
+}
+
+TEST_F(PRTimeTest, ParseTimeTest10) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("15-OCT-2007 12:45pm", PR_FALSE,
+                                       &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+  EXPECT_EQ(comparison_time_local_, parsed_time);
+}
+
+TEST_F(PRTimeTest, ParseTimeTest11) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("16 Oct 2007 4:45-JST (Tuesday)",
+                                       PR_FALSE, &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+  EXPECT_EQ(comparison_time_pdt, parsed_time);
+}
+
+// hh:mm timezone offset.
+TEST_F(PRTimeTest, ParseTimeTest12) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("2013-07-08T11:28:12.441381+02:00",
+                                       PR_FALSE, &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+  EXPECT_EQ(comparison_time_2, parsed_time);
+}
+
+// hhmm timezone offset.
+TEST_F(PRTimeTest, ParseTimeTest13) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("2013-07-08T11:28:12.441381+0200",
+                                       PR_FALSE, &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+  EXPECT_EQ(comparison_time_2, parsed_time);
+}
+
+// hh timezone offset.
+TEST_F(PRTimeTest, ParseTimeTest14) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("2013-07-08T11:28:12.4413819+02",
+                                       PR_FALSE, &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+  EXPECT_EQ(comparison_time_2, parsed_time);
+}
+
+// 5 digits fractional second.
+TEST_F(PRTimeTest, ParseTimeTest15) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("2013-07-08T09:28:12.44138Z",
+                                       PR_FALSE, &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+  EXPECT_EQ(comparison_time_2-1, parsed_time);
+}
+
+// Fractional seconds, local timezone.
+TEST_F(PRTimeTest, ParseTimeTest16) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("2013-07-08T11:28:12.441381",
+                                       PR_FALSE, &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+  EXPECT_EQ(comparison_time_local_2_, parsed_time);
+}
+
+// "Z" (=GMT) timezone.
+TEST_F(PRTimeTest, ParseTimeTest17) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("2013-07-08T09:28:12.441381Z",
+                                       PR_FALSE, &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+  EXPECT_EQ(comparison_time_2, parsed_time);
+}
+
+// "T" delimiter replaced by space.
+TEST_F(PRTimeTest, ParseTimeTest18) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("2013-07-08 09:28:12.441381Z",
+                                       PR_FALSE, &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+  EXPECT_EQ(comparison_time_2, parsed_time);
+}
+
+TEST_F(PRTimeTest, ParseTimeTestInvalid1) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("201-07-08T09:28:12.441381Z",
+                                       PR_FALSE, &parsed_time);
+  EXPECT_EQ(PR_FAILURE, result);
+}
+
+TEST_F(PRTimeTest, ParseTimeTestInvalid2) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("2013-007-08T09:28:12.441381Z",
+                                       PR_FALSE, &parsed_time);
+  EXPECT_EQ(PR_FAILURE, result);
+}
+
+TEST_F(PRTimeTest, ParseTimeTestInvalid3) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("2013-07-008T09:28:12.441381Z",
+                                       PR_FALSE, &parsed_time);
+  EXPECT_EQ(PR_FAILURE, result);
+}
+
+// This test should not crash when compiled with Visual C++ 2005 (see
+// http://crbug.com/4387).
+TEST_F(PRTimeTest, ParseTimeTestOutOfRange) {
+  PRTime parsed_time = 0;
+  // Note the lack of timezone in the time string.  The year has to be 3001.
+  // The date has to be after 23:59:59, December 31, 3000, US Pacific Time, so
+  // we use January 2, 3001 to make sure it's after the magic maximum in any
+  // timezone.
+  PRStatus result = PR_ParseTimeString("Sun Jan  2 00:00:00 3001",
+                                       PR_FALSE, &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+}
+
+TEST_F(PRTimeTest, ParseTimeTestNotNormalized1) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("Mon Oct 15 12:44:60 PDT 2007",
+                                       PR_FALSE, &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+  EXPECT_EQ(comparison_time_pdt, parsed_time);
+}
+
+TEST_F(PRTimeTest, ParseTimeTestNotNormalized2) {
+  PRTime parsed_time = 0;
+  PRStatus result = PR_ParseTimeString("Sun Oct 14 36:45 PDT 2007",
+                                       PR_FALSE, &parsed_time);
+  EXPECT_EQ(PR_SUCCESS, result);
+  EXPECT_EQ(comparison_time_pdt, parsed_time);
+}
+
+}  // namespace
diff --git a/base/time/tick_clock.cc b/base/time/tick_clock.cc
new file mode 100644
index 0000000..495805c
--- /dev/null
+++ b/base/time/tick_clock.cc
@@ -0,0 +1,11 @@
+// Copyright (c) 2012 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/time/tick_clock.h"
+
+namespace base {
+
+TickClock::~TickClock() {}
+
+}  // namespace base
diff --git a/base/time/tick_clock.h b/base/time/tick_clock.h
new file mode 100644
index 0000000..f7aba53
--- /dev/null
+++ b/base/time/tick_clock.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2012 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_TIME_TICK_CLOCK_H_
+#define BASE_TIME_TICK_CLOCK_H_
+
+#include "base/base_export.h"
+#include "base/time/time.h"
+
+namespace base {
+
+// A TickClock is an interface for objects that vend TimeTicks.  It is
+// intended to be able to test the behavior of classes with respect to
+// non-decreasing time.
+//
+// See DefaultTickClock (base/time/default_tick_clock.h) for the default
+// implementation that simply uses TimeTicks::Now().
+//
+// (Other implementations that use TimeTicks::NowFromSystemTime() should
+// be added as needed.)
+//
+// See SimpleTestTickClock (base/test/simple_test_tick_clock.h) for a
+// simple test implementation.
+//
+// See Clock (base/time/clock.h) for the equivalent interface for Times.
+class BASE_EXPORT TickClock {
+ public:
+  virtual ~TickClock();
+
+  // NowTicks() must be safe to call from any thread.  The caller may
+  // assume that NowTicks() is monotonic (but not strictly monotonic).
+  // In other words, the returned TimeTicks will never decrease with
+  // time, although they might "stand still".
+  virtual TimeTicks NowTicks() = 0;
+};
+
+}  // namespace base
+
+#endif  // BASE_TIME_TICK_CLOCK_H_
diff --git a/base/time/time.cc b/base/time/time.cc
new file mode 100644
index 0000000..8cbb382
--- /dev/null
+++ b/base/time/time.cc
@@ -0,0 +1,356 @@
+// Copyright (c) 2012 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/time/time.h"
+
+#include <cmath>
+#include <ios>
+#include <limits>
+#include <ostream>
+#include <sstream>
+
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "base/third_party/nspr/prtime.h"
+
+namespace base {
+
+// TimeDelta ------------------------------------------------------------------
+
+// static
+TimeDelta TimeDelta::Max() {
+  return TimeDelta(std::numeric_limits<int64>::max());
+}
+
+int TimeDelta::InDays() const {
+  if (is_max()) {
+    // Preserve max to prevent overflow.
+    return std::numeric_limits<int>::max();
+  }
+  return static_cast<int>(delta_ / Time::kMicrosecondsPerDay);
+}
+
+int TimeDelta::InHours() const {
+  if (is_max()) {
+    // Preserve max to prevent overflow.
+    return std::numeric_limits<int>::max();
+  }
+  return static_cast<int>(delta_ / Time::kMicrosecondsPerHour);
+}
+
+int TimeDelta::InMinutes() const {
+  if (is_max()) {
+    // Preserve max to prevent overflow.
+    return std::numeric_limits<int>::max();
+  }
+  return static_cast<int>(delta_ / Time::kMicrosecondsPerMinute);
+}
+
+double TimeDelta::InSecondsF() const {
+  if (is_max()) {
+    // Preserve max to prevent overflow.
+    return std::numeric_limits<double>::infinity();
+  }
+  return static_cast<double>(delta_) / Time::kMicrosecondsPerSecond;
+}
+
+int64 TimeDelta::InSeconds() const {
+  if (is_max()) {
+    // Preserve max to prevent overflow.
+    return std::numeric_limits<int64>::max();
+  }
+  return delta_ / Time::kMicrosecondsPerSecond;
+}
+
+double TimeDelta::InMillisecondsF() const {
+  if (is_max()) {
+    // Preserve max to prevent overflow.
+    return std::numeric_limits<double>::infinity();
+  }
+  return static_cast<double>(delta_) / Time::kMicrosecondsPerMillisecond;
+}
+
+int64 TimeDelta::InMilliseconds() const {
+  if (is_max()) {
+    // Preserve max to prevent overflow.
+    return std::numeric_limits<int64>::max();
+  }
+  return delta_ / Time::kMicrosecondsPerMillisecond;
+}
+
+int64 TimeDelta::InMillisecondsRoundedUp() const {
+  if (is_max()) {
+    // Preserve max to prevent overflow.
+    return std::numeric_limits<int64>::max();
+  }
+  return (delta_ + Time::kMicrosecondsPerMillisecond - 1) /
+      Time::kMicrosecondsPerMillisecond;
+}
+
+int64 TimeDelta::InMicroseconds() const {
+  if (is_max()) {
+    // Preserve max to prevent overflow.
+    return std::numeric_limits<int64>::max();
+  }
+  return delta_;
+}
+
+namespace time_internal {
+
+int64 SaturatedAdd(TimeDelta delta, int64 value) {
+  CheckedNumeric<int64> rv(delta.delta_);
+  rv += value;
+  return FromCheckedNumeric(rv);
+}
+
+int64 SaturatedSub(TimeDelta delta, int64 value) {
+  CheckedNumeric<int64> rv(delta.delta_);
+  rv -= value;
+  return FromCheckedNumeric(rv);
+}
+
+int64 FromCheckedNumeric(const CheckedNumeric<int64> value) {
+  if (value.IsValid())
+    return value.ValueUnsafe();
+
+  // We could return max/min but we don't really expose what the maximum delta
+  // is. Instead, return max/(-max), which is something that clients can reason
+  // about.
+  // TODO(rvargas) crbug.com/332611: don't use internal values.
+  int64 limit = std::numeric_limits<int64>::max();
+  if (value.validity() == internal::RANGE_UNDERFLOW)
+    limit = -limit;
+  return value.ValueOrDefault(limit);
+}
+
+}  // namespace time_internal
+
+std::ostream& operator<<(std::ostream& os, TimeDelta time_delta) {
+  return os << time_delta.InSecondsF() << "s";
+}
+
+// Time -----------------------------------------------------------------------
+
+// static
+Time Time::Max() {
+  return Time(std::numeric_limits<int64>::max());
+}
+
+// static
+Time Time::FromTimeT(time_t tt) {
+  if (tt == 0)
+    return Time();  // Preserve 0 so we can tell it doesn't exist.
+  if (tt == std::numeric_limits<time_t>::max())
+    return Max();
+  return Time((tt * kMicrosecondsPerSecond) + kTimeTToMicrosecondsOffset);
+}
+
+time_t Time::ToTimeT() const {
+  if (is_null())
+    return 0;  // Preserve 0 so we can tell it doesn't exist.
+  if (is_max()) {
+    // Preserve max without offset to prevent overflow.
+    return std::numeric_limits<time_t>::max();
+  }
+  if (std::numeric_limits<int64>::max() - kTimeTToMicrosecondsOffset <= us_) {
+    DLOG(WARNING) << "Overflow when converting base::Time with internal " <<
+                     "value " << us_ << " to time_t.";
+    return std::numeric_limits<time_t>::max();
+  }
+  return (us_ - kTimeTToMicrosecondsOffset) / kMicrosecondsPerSecond;
+}
+
+// static
+Time Time::FromDoubleT(double dt) {
+  if (dt == 0 || std::isnan(dt))
+    return Time();  // Preserve 0 so we can tell it doesn't exist.
+  if (dt == std::numeric_limits<double>::infinity())
+    return Max();
+  return Time(static_cast<int64>((dt *
+                                  static_cast<double>(kMicrosecondsPerSecond)) +
+                                 kTimeTToMicrosecondsOffset));
+}
+
+double Time::ToDoubleT() const {
+  if (is_null())
+    return 0;  // Preserve 0 so we can tell it doesn't exist.
+  if (is_max()) {
+    // Preserve max without offset to prevent overflow.
+    return std::numeric_limits<double>::infinity();
+  }
+  return (static_cast<double>(us_ - kTimeTToMicrosecondsOffset) /
+          static_cast<double>(kMicrosecondsPerSecond));
+}
+
+#if defined(OS_POSIX)
+// static
+Time Time::FromTimeSpec(const timespec& ts) {
+  return FromDoubleT(ts.tv_sec +
+                     static_cast<double>(ts.tv_nsec) /
+                         base::Time::kNanosecondsPerSecond);
+}
+#endif
+
+// static
+Time Time::FromJsTime(double ms_since_epoch) {
+  // The epoch is a valid time, so this constructor doesn't interpret
+  // 0 as the null time.
+  if (ms_since_epoch == std::numeric_limits<double>::infinity())
+    return Max();
+  return Time(static_cast<int64>(ms_since_epoch * kMicrosecondsPerMillisecond) +
+              kTimeTToMicrosecondsOffset);
+}
+
+double Time::ToJsTime() const {
+  if (is_null()) {
+    // Preserve 0 so the invalid result doesn't depend on the platform.
+    return 0;
+  }
+  if (is_max()) {
+    // Preserve max without offset to prevent overflow.
+    return std::numeric_limits<double>::infinity();
+  }
+  return (static_cast<double>(us_ - kTimeTToMicrosecondsOffset) /
+          kMicrosecondsPerMillisecond);
+}
+
+int64 Time::ToJavaTime() const {
+  if (is_null()) {
+    // Preserve 0 so the invalid result doesn't depend on the platform.
+    return 0;
+  }
+  if (is_max()) {
+    // Preserve max without offset to prevent overflow.
+    return std::numeric_limits<int64>::max();
+  }
+  return ((us_ - kTimeTToMicrosecondsOffset) /
+          kMicrosecondsPerMillisecond);
+}
+
+// static
+Time Time::UnixEpoch() {
+  Time time;
+  time.us_ = kTimeTToMicrosecondsOffset;
+  return time;
+}
+
+Time Time::LocalMidnight() const {
+  Exploded exploded;
+  LocalExplode(&exploded);
+  exploded.hour = 0;
+  exploded.minute = 0;
+  exploded.second = 0;
+  exploded.millisecond = 0;
+  return FromLocalExploded(exploded);
+}
+
+// static
+bool Time::FromStringInternal(const char* time_string,
+                              bool is_local,
+                              Time* parsed_time) {
+  DCHECK((time_string != NULL) && (parsed_time != NULL));
+
+  if (time_string[0] == '\0')
+    return false;
+
+  PRTime result_time = 0;
+  PRStatus result = PR_ParseTimeString(time_string,
+                                       is_local ? PR_FALSE : PR_TRUE,
+                                       &result_time);
+  if (PR_SUCCESS != result)
+    return false;
+
+  result_time += kTimeTToMicrosecondsOffset;
+  *parsed_time = Time(result_time);
+  return true;
+}
+
+std::ostream& operator<<(std::ostream& os, Time time) {
+  Time::Exploded exploded;
+  time.UTCExplode(&exploded);
+  // Use StringPrintf because iostreams formatting is painful.
+  return os << StringPrintf("%04d-%02d-%02d %02d:%02d:%02d.%03d UTC",
+                            exploded.year,
+                            exploded.month,
+                            exploded.day_of_month,
+                            exploded.hour,
+                            exploded.minute,
+                            exploded.second,
+                            exploded.millisecond);
+}
+
+// Local helper class to hold the conversion from Time to TickTime at the
+// time of the Unix epoch.
+class UnixEpochSingleton {
+ public:
+  UnixEpochSingleton()
+      : unix_epoch_(TimeTicks::Now() - (Time::Now() - Time::UnixEpoch())) {}
+
+  TimeTicks unix_epoch() const { return unix_epoch_; }
+
+ private:
+  const TimeTicks unix_epoch_;
+
+  DISALLOW_COPY_AND_ASSIGN(UnixEpochSingleton);
+};
+
+static LazyInstance<UnixEpochSingleton>::Leaky
+    leaky_unix_epoch_singleton_instance = LAZY_INSTANCE_INITIALIZER;
+
+// Static
+TimeTicks TimeTicks::UnixEpoch() {
+  return leaky_unix_epoch_singleton_instance.Get().unix_epoch();
+}
+
+TimeTicks TimeTicks::SnappedToNextTick(TimeTicks tick_phase,
+                                       TimeDelta tick_interval) const {
+  // |interval_offset| is the offset from |this| to the next multiple of
+  // |tick_interval| after |tick_phase|, possibly negative if in the past.
+  TimeDelta interval_offset = (tick_phase - *this) % tick_interval;
+  // If |this| is exactly on the interval (i.e. offset==0), don't adjust.
+  // Otherwise, if |tick_phase| was in the past, adjust forward to the next
+  // tick after |this|.
+  if (!interval_offset.is_zero() && tick_phase < *this)
+    interval_offset += tick_interval;
+  return *this + interval_offset;
+}
+
+std::ostream& operator<<(std::ostream& os, TimeTicks time_ticks) {
+  // This function formats a TimeTicks object as "bogo-microseconds".
+  // The origin and granularity of the count are platform-specific, and may very
+  // from run to run. Although bogo-microseconds usually roughly correspond to
+  // real microseconds, the only real guarantee is that the number never goes
+  // down during a single run.
+  const TimeDelta as_time_delta = time_ticks - TimeTicks();
+  return os << as_time_delta.InMicroseconds() << " bogo-microseconds";
+}
+
+std::ostream& operator<<(std::ostream& os, ThreadTicks thread_ticks) {
+  const TimeDelta as_time_delta = thread_ticks - ThreadTicks();
+  return os << as_time_delta.InMicroseconds() << " bogo-thread-microseconds";
+}
+
+std::ostream& operator<<(std::ostream& os, TraceTicks trace_ticks) {
+  const TimeDelta as_time_delta = trace_ticks - TraceTicks();
+  return os << as_time_delta.InMicroseconds() << " bogo-trace-microseconds";
+}
+
+// Time::Exploded -------------------------------------------------------------
+
+inline bool is_in_range(int value, int lo, int hi) {
+  return lo <= value && value <= hi;
+}
+
+bool Time::Exploded::HasValidValues() const {
+  return is_in_range(month, 1, 12) &&
+         is_in_range(day_of_week, 0, 6) &&
+         is_in_range(day_of_month, 1, 31) &&
+         is_in_range(hour, 0, 23) &&
+         is_in_range(minute, 0, 59) &&
+         is_in_range(second, 0, 60) &&
+         is_in_range(millisecond, 0, 999);
+}
+
+}  // namespace base
diff --git a/base/time/time.h b/base/time/time.h
new file mode 100644
index 0000000..a02fbeb
--- /dev/null
+++ b/base/time/time.h
@@ -0,0 +1,810 @@
+// Copyright (c) 2012 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.
+
+// Time represents an absolute point in coordinated universal time (UTC),
+// internally represented as microseconds (s/1,000,000) since the Windows epoch
+// (1601-01-01 00:00:00 UTC). System-dependent clock interface routines are
+// defined in time_PLATFORM.cc. Note that values for Time may skew and jump
+// around as the operating system makes adjustments to synchronize (e.g., with
+// NTP servers). Thus, client code that uses the Time class must account for
+// this.
+//
+// TimeDelta represents a duration of time, internally represented in
+// microseconds.
+//
+// TimeTicks, ThreadTicks, and TraceTicks represent an abstract time that is
+// most of the time incrementing, for use in measuring time durations.
+// Internally, they are represented in microseconds. They can not be converted
+// to a human-readable time, but are guaranteed not to decrease (unlike the Time
+// class). Note that TimeTicks may "stand still" (e.g., if the computer is
+// suspended), and ThreadTicks will "stand still" whenever the thread has been
+// de-scheduled by the operating system.
+//
+// All time classes are copyable, assignable, and occupy 64-bits per
+// instance. Thus, they can be efficiently passed by-value (as opposed to
+// by-reference).
+//
+// Definitions of operator<< are provided to make these types work with
+// DCHECK_EQ() and other log macros. For human-readable formatting, see
+// "base/i18n/time_formatting.h".
+//
+// So many choices!  Which time class should you use?  Examples:
+//
+//   Time:        Interpreting the wall-clock time provided by a remote
+//                system. Detecting whether cached resources have
+//                expired. Providing the user with a display of the current date
+//                and time. Determining the amount of time between events across
+//                re-boots of the machine.
+//
+//   TimeTicks:   Tracking the amount of time a task runs. Executing delayed
+//                tasks at the right time. Computing presentation timestamps.
+//                Synchronizing audio and video using TimeTicks as a common
+//                reference clock (lip-sync). Measuring network round-trip
+//                latency.
+//
+//   ThreadTicks: Benchmarking how long the current thread has been doing actual
+//                work.
+//
+//   TraceTicks:  This is only meant to be used by the event tracing
+//                infrastructure, and by outside code modules in special
+//                circumstances.  Please be sure to consult a
+//                base/trace_event/OWNER before committing any new code that
+//                uses this.
+
+#ifndef BASE_TIME_TIME_H_
+#define BASE_TIME_TIME_H_
+
+#include <time.h>
+
+#include <iosfwd>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/numerics/safe_math.h"
+#include "build/build_config.h"
+
+#if defined(OS_MACOSX)
+#include <CoreFoundation/CoreFoundation.h>
+// Avoid Mac system header macro leak.
+#undef TYPE_BOOL
+#endif
+
+#if defined(OS_POSIX)
+#include <unistd.h>
+#include <sys/time.h>
+#endif
+
+#if defined(OS_WIN)
+// For FILETIME in FromFileTime, until it moves to a new converter class.
+// See TODO(iyengar) below.
+#include <windows.h>
+#endif
+
+#include <limits>
+
+namespace base {
+
+class TimeDelta;
+
+// The functions in the time_internal namespace are meant to be used only by the
+// time classes and functions.  Please use the math operators defined in the
+// time classes instead.
+namespace time_internal {
+
+// Add or subtract |value| from a TimeDelta. The int64 argument and return value
+// are in terms of a microsecond timebase.
+BASE_EXPORT int64 SaturatedAdd(TimeDelta delta, int64 value);
+BASE_EXPORT int64 SaturatedSub(TimeDelta delta, int64 value);
+
+// Clamp |value| on overflow and underflow conditions. The int64 argument and
+// return value are in terms of a microsecond timebase.
+BASE_EXPORT int64 FromCheckedNumeric(const CheckedNumeric<int64> value);
+
+}  // namespace time_internal
+
+// TimeDelta ------------------------------------------------------------------
+
+class BASE_EXPORT TimeDelta {
+ public:
+  TimeDelta() : delta_(0) {
+  }
+
+  // Converts units of time to TimeDeltas.
+  static TimeDelta FromDays(int days);
+  static TimeDelta FromHours(int hours);
+  static TimeDelta FromMinutes(int minutes);
+  static TimeDelta FromSeconds(int64 secs);
+  static TimeDelta FromMilliseconds(int64 ms);
+  static TimeDelta FromSecondsD(double secs);
+  static TimeDelta FromMillisecondsD(double ms);
+  static TimeDelta FromMicroseconds(int64 us);
+#if defined(OS_WIN)
+  static TimeDelta FromQPCValue(LONGLONG qpc_value);
+#endif
+
+  // Converts an integer value representing TimeDelta to a class. This is used
+  // when deserializing a |TimeDelta| structure, using a value known to be
+  // compatible. It is not provided as a constructor because the integer type
+  // may be unclear from the perspective of a caller.
+  static TimeDelta FromInternalValue(int64 delta) {
+    return TimeDelta(delta);
+  }
+
+  // Returns the maximum time delta, which should be greater than any reasonable
+  // time delta we might compare it to. Adding or subtracting the maximum time
+  // delta to a time or another time delta has an undefined result.
+  static TimeDelta Max();
+
+  // Returns the internal numeric value of the TimeDelta object. Please don't
+  // use this and do arithmetic on it, as it is more error prone than using the
+  // provided operators.
+  // For serializing, use FromInternalValue to reconstitute.
+  int64 ToInternalValue() const {
+    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 zero.
+  bool is_zero() const {
+    return delta_ == 0;
+  }
+
+  // Returns true if the time delta is the maximum time delta.
+  bool is_max() const {
+    return delta_ == std::numeric_limits<int64>::max();
+  }
+
+#if defined(OS_POSIX)
+  struct timespec ToTimeSpec() const;
+#endif
+
+  // Returns the time delta in some unit. The F versions return a floating
+  // point value, the "regular" versions return a rounded-down value.
+  //
+  // InMillisecondsRoundedUp() instead returns an integer that is rounded up
+  // to the next full millisecond.
+  int InDays() const;
+  int InHours() const;
+  int InMinutes() const;
+  double InSecondsF() const;
+  int64 InSeconds() const;
+  double InMillisecondsF() const;
+  int64 InMilliseconds() const;
+  int64 InMillisecondsRoundedUp() const;
+  int64 InMicroseconds() const;
+
+  TimeDelta& operator=(TimeDelta other) {
+    delta_ = other.delta_;
+    return *this;
+  }
+
+  // Computations with other deltas.
+  TimeDelta operator+(TimeDelta other) const {
+    return TimeDelta(time_internal::SaturatedAdd(*this, other.delta_));
+  }
+  TimeDelta operator-(TimeDelta other) const {
+    return TimeDelta(time_internal::SaturatedSub(*this, other.delta_));
+  }
+
+  TimeDelta& operator+=(TimeDelta other) {
+    return *this = (*this + other);
+  }
+  TimeDelta& operator-=(TimeDelta other) {
+    return *this = (*this - other);
+  }
+  TimeDelta operator-() const {
+    return TimeDelta(-delta_);
+  }
+
+  // Computations with numeric types.
+  template<typename T>
+  TimeDelta operator*(T a) const {
+    CheckedNumeric<int64> rv(delta_);
+    rv *= a;
+    return TimeDelta(time_internal::FromCheckedNumeric(rv));
+  }
+  template<typename T>
+  TimeDelta operator/(T a) const {
+    CheckedNumeric<int64> rv(delta_);
+    rv /= a;
+    return TimeDelta(time_internal::FromCheckedNumeric(rv));
+  }
+  template<typename T>
+  TimeDelta& operator*=(T a) {
+    return *this = (*this * a);
+  }
+  template<typename T>
+  TimeDelta& operator/=(T a) {
+    return *this = (*this / a);
+  }
+
+  int64 operator/(TimeDelta a) const {
+    return delta_ / a.delta_;
+  }
+  TimeDelta operator%(TimeDelta a) const {
+    return TimeDelta(delta_ % a.delta_);
+  }
+
+  // Comparison operators.
+  bool operator==(TimeDelta other) const {
+    return delta_ == other.delta_;
+  }
+  bool operator!=(TimeDelta other) const {
+    return delta_ != other.delta_;
+  }
+  bool operator<(TimeDelta other) const {
+    return delta_ < other.delta_;
+  }
+  bool operator<=(TimeDelta other) const {
+    return delta_ <= other.delta_;
+  }
+  bool operator>(TimeDelta other) const {
+    return delta_ > other.delta_;
+  }
+  bool operator>=(TimeDelta other) const {
+    return delta_ >= other.delta_;
+  }
+
+ private:
+  friend int64 time_internal::SaturatedAdd(TimeDelta delta, int64 value);
+  friend int64 time_internal::SaturatedSub(TimeDelta delta, int64 value);
+
+  // Constructs a delta given the duration in microseconds. This is private
+  // to avoid confusion by callers with an integer constructor. Use
+  // FromSeconds, FromMilliseconds, etc. instead.
+  explicit TimeDelta(int64 delta_us) : delta_(delta_us) {
+  }
+
+  // Delta in microseconds.
+  int64 delta_;
+};
+
+template<typename T>
+inline TimeDelta operator*(T a, TimeDelta td) {
+  return td * a;
+}
+
+// For logging use only.
+BASE_EXPORT std::ostream& operator<<(std::ostream& os, TimeDelta time_delta);
+
+// Do not reference the time_internal::TimeBase template class directly.  Please
+// use one of the time subclasses instead, and only reference the public
+// TimeBase members via those classes.
+namespace time_internal {
+
+// TimeBase--------------------------------------------------------------------
+
+// Provides value storage and comparison/math operations common to all time
+// classes. Each subclass provides for strong type-checking to ensure
+// semantically meaningful comparison/math of time values from the same clock
+// source or timeline.
+template<class TimeClass>
+class TimeBase {
+ public:
+  static const int64 kHoursPerDay = 24;
+  static const int64 kMillisecondsPerSecond = 1000;
+  static const int64 kMillisecondsPerDay = kMillisecondsPerSecond * 60 * 60 *
+                                           kHoursPerDay;
+  static const int64 kMicrosecondsPerMillisecond = 1000;
+  static const int64 kMicrosecondsPerSecond = kMicrosecondsPerMillisecond *
+                                              kMillisecondsPerSecond;
+  static const int64 kMicrosecondsPerMinute = kMicrosecondsPerSecond * 60;
+  static const int64 kMicrosecondsPerHour = kMicrosecondsPerMinute * 60;
+  static const int64 kMicrosecondsPerDay = kMicrosecondsPerHour * kHoursPerDay;
+  static const int64 kMicrosecondsPerWeek = kMicrosecondsPerDay * 7;
+  static const int64 kNanosecondsPerMicrosecond = 1000;
+  static const int64 kNanosecondsPerSecond = kNanosecondsPerMicrosecond *
+                                             kMicrosecondsPerSecond;
+
+  // Returns true if this object has not been initialized.
+  //
+  // Warning: Be careful when writing code that performs math on time values,
+  // since it's possible to produce a valid "zero" result that should not be
+  // interpreted as a "null" value.
+  bool is_null() const {
+    return us_ == 0;
+  }
+
+  // Returns true if this object represents the maximum time.
+  bool is_max() const {
+    return us_ == std::numeric_limits<int64>::max();
+  }
+
+  // For serializing only. Use FromInternalValue() to reconstitute. Please don't
+  // use this and do arithmetic on it, as it is more error prone than using the
+  // provided operators.
+  int64 ToInternalValue() const {
+    return us_;
+  }
+
+  TimeClass& operator=(TimeClass other) {
+    us_ = other.us_;
+    return *(static_cast<TimeClass*>(this));
+  }
+
+  // Compute the difference between two times.
+  TimeDelta operator-(TimeClass other) const {
+    return TimeDelta::FromMicroseconds(us_ - other.us_);
+  }
+
+  // Return a new time modified by some delta.
+  TimeClass operator+(TimeDelta delta) const {
+    return TimeClass(time_internal::SaturatedAdd(delta, us_));
+  }
+  TimeClass operator-(TimeDelta delta) const {
+    return TimeClass(-time_internal::SaturatedSub(delta, us_));
+  }
+
+  // Modify by some time delta.
+  TimeClass& operator+=(TimeDelta delta) {
+    return static_cast<TimeClass&>(*this = (*this + delta));
+  }
+  TimeClass& operator-=(TimeDelta delta) {
+    return static_cast<TimeClass&>(*this = (*this - delta));
+  }
+
+  // Comparison operators
+  bool operator==(TimeClass other) const {
+    return us_ == other.us_;
+  }
+  bool operator!=(TimeClass other) const {
+    return us_ != other.us_;
+  }
+  bool operator<(TimeClass other) const {
+    return us_ < other.us_;
+  }
+  bool operator<=(TimeClass other) const {
+    return us_ <= other.us_;
+  }
+  bool operator>(TimeClass other) const {
+    return us_ > other.us_;
+  }
+  bool operator>=(TimeClass other) const {
+    return us_ >= other.us_;
+  }
+
+  // Converts an integer value representing TimeClass to a class. This is used
+  // when deserializing a |TimeClass| structure, using a value known to be
+  // compatible. It is not provided as a constructor because the integer type
+  // may be unclear from the perspective of a caller.
+  static TimeClass FromInternalValue(int64 us) {
+    return TimeClass(us);
+  }
+
+ protected:
+  explicit TimeBase(int64 us) : us_(us) {
+  }
+
+  // Time value in a microsecond timebase.
+  int64 us_;
+};
+
+}  // namespace time_internal
+
+template<class TimeClass>
+inline TimeClass operator+(TimeDelta delta, TimeClass t) {
+  return t + delta;
+}
+
+// Time -----------------------------------------------------------------------
+
+// Represents a wall clock time in UTC. Values are not guaranteed to be
+// monotonically non-decreasing and are subject to large amounts of skew.
+class BASE_EXPORT Time : public time_internal::TimeBase<Time> {
+ public:
+  // The representation of Jan 1, 1970 UTC in microseconds since the
+  // platform-dependent epoch.
+  static const int64 kTimeTToMicrosecondsOffset;
+
+#if !defined(OS_WIN)
+  // On Mac & Linux, this value is the delta from the Windows epoch of 1601 to
+  // the Posix delta of 1970. This is used for migrating between the old
+  // 1970-based epochs to the new 1601-based ones. It should be removed from
+  // this global header and put in the platform-specific ones when we remove the
+  // migration code.
+  static const int64 kWindowsEpochDeltaMicroseconds;
+#else
+  // To avoid overflow in QPC to Microseconds calculations, since we multiply
+  // by kMicrosecondsPerSecond, then the QPC value should not exceed
+  // (2^63 - 1) / 1E6. If it exceeds that threshold, we divide then multiply.
+  static const int64 kQPCOverflowThreshold = 0x8637BD05AF7;
+#endif
+
+  // Represents an exploded time that can be formatted nicely. This is kind of
+  // like the Win32 SYSTEMTIME structure or the Unix "struct tm" with a few
+  // additions and changes to prevent errors.
+  struct BASE_EXPORT Exploded {
+    int year;          // Four digit year "2007"
+    int month;         // 1-based month (values 1 = January, etc.)
+    int day_of_week;   // 0-based day of week (0 = Sunday, etc.)
+    int day_of_month;  // 1-based day of month (1-31)
+    int hour;          // Hour within the current day (0-23)
+    int minute;        // Minute within the current hour (0-59)
+    int second;        // Second within the current minute (0-59 plus leap
+                       //   seconds which may take it up to 60).
+    int millisecond;   // Milliseconds within the current second (0-999)
+
+    // A cursory test for whether the data members are within their
+    // respective ranges. A 'true' return value does not guarantee the
+    // Exploded value can be successfully converted to a Time value.
+    bool HasValidValues() const;
+  };
+
+  // Contains the NULL time. Use Time::Now() to get the current time.
+  Time() : TimeBase(0) {
+  }
+
+  // Returns the time for epoch in Unix-like system (Jan 1, 1970).
+  static Time UnixEpoch();
+
+  // Returns the current time. Watch out, the system might adjust its clock
+  // in which case time will actually go backwards. We don't guarantee that
+  // times are increasing, or that two calls to Now() won't be the same.
+  static Time Now();
+
+  // Returns the maximum time, which should be greater than any reasonable time
+  // with which we might compare it.
+  static Time Max();
+
+  // Returns the current time. Same as Now() except that this function always
+  // uses system time so that there are no discrepancies between the returned
+  // time and system time even on virtual environments including our test bot.
+  // For timing sensitive unittests, this function should be used.
+  static Time NowFromSystemTime();
+
+  // Converts to/from time_t in UTC and a Time class.
+  // TODO(brettw) this should be removed once everybody starts using the |Time|
+  // class.
+  static Time FromTimeT(time_t tt);
+  time_t ToTimeT() const;
+
+  // Converts time to/from a double which is the number of seconds since epoch
+  // (Jan 1, 1970).  Webkit uses this format to represent time.
+  // Because WebKit initializes double time value to 0 to indicate "not
+  // initialized", we map it to empty Time object that also means "not
+  // initialized".
+  static Time FromDoubleT(double dt);
+  double ToDoubleT() const;
+
+#if defined(OS_POSIX)
+  // Converts the timespec structure to time. MacOS X 10.8.3 (and tentatively,
+  // earlier versions) will have the |ts|'s tv_nsec component zeroed out,
+  // having a 1 second resolution, which agrees with
+  // https://developer.apple.com/legacy/library/#technotes/tn/tn1150.html#HFSPlusDates.
+  static Time FromTimeSpec(const timespec& ts);
+#endif
+
+  // Converts to/from the Javascript convention for times, a number of
+  // milliseconds since the epoch:
+  // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date/getTime.
+  static Time FromJsTime(double ms_since_epoch);
+  double ToJsTime() const;
+
+  // Converts to Java convention for times, a number of
+  // milliseconds since the epoch.
+  int64 ToJavaTime() const;
+
+#if defined(OS_POSIX)
+  static Time FromTimeVal(struct timeval t);
+  struct timeval ToTimeVal() const;
+#endif
+
+#if defined(OS_MACOSX)
+  static Time FromCFAbsoluteTime(CFAbsoluteTime t);
+  CFAbsoluteTime ToCFAbsoluteTime() const;
+#endif
+
+#if defined(OS_WIN)
+  static Time FromFileTime(FILETIME ft);
+  FILETIME ToFileTime() const;
+
+  // The minimum time of a low resolution timer.  This is basically a windows
+  // constant of ~15.6ms.  While it does vary on some older OS versions, we'll
+  // treat it as static across all windows versions.
+  static const int kMinLowResolutionThresholdMs = 16;
+
+  // Enable or disable Windows high resolution timer.
+  static void EnableHighResolutionTimer(bool enable);
+
+  // Activates or deactivates the high resolution timer based on the |activate|
+  // flag.  If the HighResolutionTimer is not Enabled (see
+  // EnableHighResolutionTimer), this function will return false.  Otherwise
+  // returns true.  Each successful activate call must be paired with a
+  // subsequent deactivate call.
+  // All callers to activate the high resolution timer must eventually call
+  // this function to deactivate the high resolution timer.
+  static bool ActivateHighResolutionTimer(bool activate);
+
+  // Returns true if the high resolution timer is both enabled and activated.
+  // This is provided for testing only, and is not tracked in a thread-safe
+  // way.
+  static bool IsHighResolutionTimerInUse();
+#endif
+
+  // Converts an exploded structure representing either the local time or UTC
+  // into a Time class.
+  static Time FromUTCExploded(const Exploded& exploded) {
+    return FromExploded(false, exploded);
+  }
+  static Time FromLocalExploded(const Exploded& exploded) {
+    return FromExploded(true, exploded);
+  }
+
+  // Converts a string representation of time to a Time object.
+  // An example of a time string which is converted is as below:-
+  // "Tue, 15 Nov 1994 12:45:26 GMT". If the timezone is not specified
+  // in the input string, FromString assumes local time and FromUTCString
+  // assumes UTC. A timezone that cannot be parsed (e.g. "UTC" which is not
+  // specified in RFC822) is treated as if the timezone is not specified.
+  // TODO(iyengar) Move the FromString/FromTimeT/ToTimeT/FromFileTime to
+  // a new time converter class.
+  static bool FromString(const char* time_string, Time* parsed_time) {
+    return FromStringInternal(time_string, true, parsed_time);
+  }
+  static bool FromUTCString(const char* time_string, Time* parsed_time) {
+    return FromStringInternal(time_string, false, parsed_time);
+  }
+
+  // Fills the given exploded structure with either the local time or UTC from
+  // this time structure (containing UTC).
+  void UTCExplode(Exploded* exploded) const {
+    return Explode(false, exploded);
+  }
+  void LocalExplode(Exploded* exploded) const {
+    return Explode(true, exploded);
+  }
+
+  // Rounds this time down to the nearest day in local time. It will represent
+  // midnight on that day.
+  Time LocalMidnight() const;
+
+ private:
+  friend class time_internal::TimeBase<Time>;
+
+  explicit Time(int64 us) : TimeBase(us) {
+  }
+
+  // Explodes the given time to either local time |is_local = true| or UTC
+  // |is_local = false|.
+  void Explode(bool is_local, Exploded* exploded) const;
+
+  // Unexplodes a given time assuming the source is either local time
+  // |is_local = true| or UTC |is_local = false|.
+  static Time FromExploded(bool is_local, const Exploded& exploded);
+
+  // Converts a string representation of time to a Time object.
+  // An example of a time string which is converted is as below:-
+  // "Tue, 15 Nov 1994 12:45:26 GMT". If the timezone is not specified
+  // in the input string, local time |is_local = true| or
+  // UTC |is_local = false| is assumed. A timezone that cannot be parsed
+  // (e.g. "UTC" which is not specified in RFC822) is treated as if the
+  // timezone is not specified.
+  static bool FromStringInternal(const char* time_string,
+                                 bool is_local,
+                                 Time* parsed_time);
+};
+
+// Inline the TimeDelta factory methods, for fast TimeDelta construction.
+
+// static
+inline TimeDelta TimeDelta::FromDays(int days) {
+  // Preserve max to prevent overflow.
+  if (days == std::numeric_limits<int>::max())
+    return Max();
+  return TimeDelta(days * Time::kMicrosecondsPerDay);
+}
+
+// static
+inline TimeDelta TimeDelta::FromHours(int hours) {
+  // Preserve max to prevent overflow.
+  if (hours == std::numeric_limits<int>::max())
+    return Max();
+  return TimeDelta(hours * Time::kMicrosecondsPerHour);
+}
+
+// static
+inline TimeDelta TimeDelta::FromMinutes(int minutes) {
+  // Preserve max to prevent overflow.
+  if (minutes == std::numeric_limits<int>::max())
+    return Max();
+  return TimeDelta(minutes * Time::kMicrosecondsPerMinute);
+}
+
+// static
+inline TimeDelta TimeDelta::FromSeconds(int64 secs) {
+  // Preserve max to prevent overflow.
+  if (secs == std::numeric_limits<int64>::max())
+    return Max();
+  return TimeDelta(secs * Time::kMicrosecondsPerSecond);
+}
+
+// static
+inline TimeDelta TimeDelta::FromMilliseconds(int64 ms) {
+  // Preserve max to prevent overflow.
+  if (ms == std::numeric_limits<int64>::max())
+    return Max();
+  return TimeDelta(ms * Time::kMicrosecondsPerMillisecond);
+}
+
+// static
+inline TimeDelta TimeDelta::FromSecondsD(double secs) {
+  // Preserve max to prevent overflow.
+  if (secs == std::numeric_limits<double>::infinity())
+    return Max();
+  return TimeDelta(static_cast<int64>(secs * Time::kMicrosecondsPerSecond));
+}
+
+// static
+inline TimeDelta TimeDelta::FromMillisecondsD(double ms) {
+  // Preserve max to prevent overflow.
+  if (ms == std::numeric_limits<double>::infinity())
+    return Max();
+  return TimeDelta(static_cast<int64>(ms * Time::kMicrosecondsPerMillisecond));
+}
+
+// static
+inline TimeDelta TimeDelta::FromMicroseconds(int64 us) {
+  // Preserve max to prevent overflow.
+  if (us == std::numeric_limits<int64>::max())
+    return Max();
+  return TimeDelta(us);
+}
+
+// For logging use only.
+BASE_EXPORT std::ostream& operator<<(std::ostream& os, Time time);
+
+// TimeTicks ------------------------------------------------------------------
+
+// Represents monotonically non-decreasing clock time.
+class BASE_EXPORT TimeTicks : public time_internal::TimeBase<TimeTicks> {
+ public:
+  TimeTicks() : TimeBase(0) {
+  }
+
+  // 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 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();
+
+#if defined(OS_WIN)
+  // 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);
+#endif
+
+  // Get the TimeTick value at the time of the UnixEpoch. This is useful when
+  // you need to relate the value of TimeTicks to a real time and date.
+  // Note: Upon first invocation, this function takes a snapshot of the realtime
+  // clock to establish a reference point.  This function will return the same
+  // value for the duration of the application, but will be different in future
+  // application runs.
+  static TimeTicks UnixEpoch();
+
+  // Returns |this| snapped to the next tick, given a |tick_phase| and
+  // repeating |tick_interval| in both directions. |this| may be before,
+  // after, or equal to the |tick_phase|.
+  TimeTicks SnappedToNextTick(TimeTicks tick_phase,
+                              TimeDelta tick_interval) const;
+
+#if defined(OS_WIN)
+ protected:
+  typedef DWORD (*TickFunctionType)(void);
+  static TickFunctionType SetMockTickFunction(TickFunctionType ticker);
+#endif
+
+ private:
+  friend class time_internal::TimeBase<TimeTicks>;
+
+  // Please use Now() to create a new object. This is for internal use
+  // and testing.
+  explicit TimeTicks(int64 us) : TimeBase(us) {
+  }
+};
+
+// For logging use only.
+BASE_EXPORT std::ostream& operator<<(std::ostream& os, TimeTicks time_ticks);
+
+// ThreadTicks ----------------------------------------------------------------
+
+// Represents a clock, specific to a particular thread, than runs only while the
+// thread is running.
+class BASE_EXPORT ThreadTicks : public time_internal::TimeBase<ThreadTicks> {
+ public:
+  ThreadTicks() : TimeBase(0) {
+  }
+
+  // Returns true if ThreadTicks::Now() is supported on this system.
+  static bool IsSupported() {
+#if (defined(_POSIX_THREAD_CPUTIME) && (_POSIX_THREAD_CPUTIME >= 0)) || \
+    (defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_ANDROID)
+    return true;
+#else
+    return false;
+#endif
+  }
+
+  // Returns thread-specific CPU-time on systems that support this feature.
+  // Needs to be guarded with a call to IsSupported(). Use this timer
+  // 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.
+  static ThreadTicks Now();
+
+ private:
+  friend class time_internal::TimeBase<ThreadTicks>;
+
+  // Please use Now() to create a new object. This is for internal use
+  // and testing.
+  explicit ThreadTicks(int64 us) : TimeBase(us) {
+  }
+};
+
+// For logging use only.
+BASE_EXPORT std::ostream& operator<<(std::ostream& os, ThreadTicks time_ticks);
+
+// TraceTicks ----------------------------------------------------------------
+
+// Represents high-resolution system trace clock time.
+class BASE_EXPORT TraceTicks : public time_internal::TimeBase<TraceTicks> {
+ public:
+  // We define this even without OS_CHROMEOS for seccomp sandbox testing.
+#if defined(OS_LINUX)
+  // Force definition of the system trace clock; it is a chromeos-only api
+  // at the moment and surfacing it in the right place requires mucking
+  // with glibc et al.
+  static const clockid_t kClockSystemTrace = 11;
+#endif
+
+  TraceTicks() : TimeBase(0) {
+  }
+
+  // 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).
+  //
+  // On some platforms, the clock source used for tracing can vary depending on
+  // hardware and/or kernel support.  Do not make any assumptions without
+  // consulting the documentation for this functionality in the time_win.cc,
+  // time_posix.cc, etc. files.
+  //
+  // NOTE: This is only meant to be used by the event tracing infrastructure,
+  // and by outside code modules in special circumstances.  Please be sure to
+  // consult a base/trace_event/OWNER before committing any new code that uses
+  // this.
+  static TraceTicks Now();
+
+ private:
+  friend class time_internal::TimeBase<TraceTicks>;
+
+  // Please use Now() to create a new object. This is for internal use
+  // and testing.
+  explicit TraceTicks(int64 us) : TimeBase(us) {
+  }
+};
+
+// For logging use only.
+BASE_EXPORT std::ostream& operator<<(std::ostream& os, TraceTicks time_ticks);
+
+}  // namespace base
+
+#endif  // BASE_TIME_TIME_H_
diff --git a/base/time/time_mac.cc b/base/time/time_mac.cc
new file mode 100644
index 0000000..1dbbc33
--- /dev/null
+++ b/base/time/time_mac.cc
@@ -0,0 +1,239 @@
+// Copyright (c) 2012 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/time/time.h"
+
+#include <CoreFoundation/CFDate.h>
+#include <CoreFoundation/CFTimeZone.h>
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+#include <stdint.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <time.h>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/mac/mach_logging.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/mac/scoped_mach_port.h"
+#include "base/numerics/safe_conversions.h"
+
+namespace {
+
+int64_t ComputeCurrentTicks() {
+#if defined(OS_IOS)
+  // On iOS mach_absolute_time stops while the device is sleeping. Instead use
+  // now - KERN_BOOTTIME to get a time difference that is not impacted by clock
+  // changes. KERN_BOOTTIME will be updated by the system whenever the system
+  // clock change.
+  struct timeval boottime;
+  int mib[2] = {CTL_KERN, KERN_BOOTTIME};
+  size_t size = sizeof(boottime);
+  int kr = sysctl(mib, arraysize(mib), &boottime, &size, NULL, 0);
+  DCHECK_EQ(KERN_SUCCESS, kr);
+  base::TimeDelta time_difference = base::Time::Now() -
+      (base::Time::FromTimeT(boottime.tv_sec) +
+       base::TimeDelta::FromMicroseconds(boottime.tv_usec));
+  return time_difference.InMicroseconds();
+#else
+  static mach_timebase_info_data_t timebase_info;
+  if (timebase_info.denom == 0) {
+    // Zero-initialization of statics guarantees that denom will be 0 before
+    // calling mach_timebase_info.  mach_timebase_info will never set denom to
+    // 0 as that would be invalid, so the zero-check can be used to determine
+    // whether mach_timebase_info has already been called.  This is
+    // recommended by Apple's QA1398.
+    kern_return_t kr = mach_timebase_info(&timebase_info);
+    MACH_DCHECK(kr == KERN_SUCCESS, kr) << "mach_timebase_info";
+  }
+
+  // mach_absolute_time is it when it comes to ticks on the Mac.  Other calls
+  // with less precision (such as TickCount) just call through to
+  // mach_absolute_time.
+
+  // timebase_info converts absolute time tick units into nanoseconds.  Convert
+  // to microseconds up front to stave off overflows.
+  base::CheckedNumeric<uint64_t> result(
+      mach_absolute_time() / base::Time::kNanosecondsPerMicrosecond);
+  result *= timebase_info.numer;
+  result /= timebase_info.denom;
+
+  // Don't bother with the rollover handling that the Windows version does.
+  // With numer and denom = 1 (the expected case), the 64-bit absolute time
+  // reported in nanoseconds is enough to last nearly 585 years.
+  return base::checked_cast<int64_t>(result.ValueOrDie());
+#endif  // defined(OS_IOS)
+}
+
+int64_t ComputeThreadTicks() {
+#if defined(OS_IOS)
+  NOTREACHED();
+  return 0;
+#else
+  base::mac::ScopedMachSendRight thread(mach_thread_self());
+  mach_msg_type_number_t thread_info_count = THREAD_BASIC_INFO_COUNT;
+  thread_basic_info_data_t thread_info_data;
+
+  if (thread.get() == MACH_PORT_NULL) {
+    DLOG(ERROR) << "Failed to get mach_thread_self()";
+    return 0;
+  }
+
+  kern_return_t kr = thread_info(
+      thread,
+      THREAD_BASIC_INFO,
+      reinterpret_cast<thread_info_t>(&thread_info_data),
+      &thread_info_count);
+  MACH_DCHECK(kr == KERN_SUCCESS, kr) << "thread_info";
+
+  base::CheckedNumeric<int64_t> absolute_micros(
+      thread_info_data.user_time.seconds);
+  absolute_micros *= base::Time::kMicrosecondsPerSecond;
+  absolute_micros += thread_info_data.user_time.microseconds;
+  return absolute_micros.ValueOrDie();
+#endif  // defined(OS_IOS)
+}
+
+}  // namespace
+
+namespace base {
+
+// The Time routines in this file use Mach and CoreFoundation APIs, since the
+// POSIX definition of time_t in Mac OS X wraps around after 2038--and
+// there are already cookie expiration dates, etc., past that time out in
+// the field.  Using CFDate prevents that problem, and using mach_absolute_time
+// for TimeTicks gives us nice high-resolution interval timing.
+
+// Time -----------------------------------------------------------------------
+
+// Core Foundation uses a double second count since 2001-01-01 00:00:00 UTC.
+// The UNIX epoch is 1970-01-01 00:00:00 UTC.
+// Windows uses a Gregorian epoch of 1601.  We need to match this internally
+// so that our time representations match across all platforms.  See bug 14734.
+//   irb(main):010:0> Time.at(0).getutc()
+//   => Thu Jan 01 00:00:00 UTC 1970
+//   irb(main):011:0> Time.at(-11644473600).getutc()
+//   => Mon Jan 01 00:00:00 UTC 1601
+static const int64 kWindowsEpochDeltaSeconds = INT64_C(11644473600);
+
+// static
+const int64 Time::kWindowsEpochDeltaMicroseconds =
+    kWindowsEpochDeltaSeconds * Time::kMicrosecondsPerSecond;
+
+// Some functions in time.cc use time_t directly, so we provide an offset
+// to convert from time_t (Unix epoch) and internal (Windows epoch).
+// static
+const int64 Time::kTimeTToMicrosecondsOffset = kWindowsEpochDeltaMicroseconds;
+
+// static
+Time Time::Now() {
+  return FromCFAbsoluteTime(CFAbsoluteTimeGetCurrent());
+}
+
+// static
+Time Time::FromCFAbsoluteTime(CFAbsoluteTime t) {
+  COMPILE_ASSERT(std::numeric_limits<CFAbsoluteTime>::has_infinity,
+                 numeric_limits_infinity_is_undefined_when_not_has_infinity);
+  if (t == 0)
+    return Time();  // Consider 0 as a null Time.
+  if (t == std::numeric_limits<CFAbsoluteTime>::infinity())
+    return Max();
+  return Time(static_cast<int64>(
+      (t + kCFAbsoluteTimeIntervalSince1970) * kMicrosecondsPerSecond) +
+      kWindowsEpochDeltaMicroseconds);
+}
+
+CFAbsoluteTime Time::ToCFAbsoluteTime() const {
+  COMPILE_ASSERT(std::numeric_limits<CFAbsoluteTime>::has_infinity,
+                 numeric_limits_infinity_is_undefined_when_not_has_infinity);
+  if (is_null())
+    return 0;  // Consider 0 as a null Time.
+  if (is_max())
+    return std::numeric_limits<CFAbsoluteTime>::infinity();
+  return (static_cast<CFAbsoluteTime>(us_ - kWindowsEpochDeltaMicroseconds) /
+      kMicrosecondsPerSecond) - kCFAbsoluteTimeIntervalSince1970;
+}
+
+// static
+Time Time::NowFromSystemTime() {
+  // Just use Now() because Now() returns the system time.
+  return Now();
+}
+
+// static
+Time Time::FromExploded(bool is_local, const Exploded& exploded) {
+  CFGregorianDate date;
+  date.second = exploded.second +
+      exploded.millisecond / static_cast<double>(kMillisecondsPerSecond);
+  date.minute = exploded.minute;
+  date.hour = exploded.hour;
+  date.day = exploded.day_of_month;
+  date.month = exploded.month;
+  date.year = exploded.year;
+
+  base::ScopedCFTypeRef<CFTimeZoneRef> time_zone(
+      is_local ? CFTimeZoneCopySystem() : NULL);
+  CFAbsoluteTime seconds = CFGregorianDateGetAbsoluteTime(date, time_zone) +
+      kCFAbsoluteTimeIntervalSince1970;
+  return Time(static_cast<int64>(seconds * kMicrosecondsPerSecond) +
+      kWindowsEpochDeltaMicroseconds);
+}
+
+void Time::Explode(bool is_local, Exploded* exploded) const {
+  // Avoid rounding issues, by only putting the integral number of seconds
+  // (rounded towards -infinity) into a |CFAbsoluteTime| (which is a |double|).
+  int64 microsecond = us_ % kMicrosecondsPerSecond;
+  if (microsecond < 0)
+    microsecond += kMicrosecondsPerSecond;
+  CFAbsoluteTime seconds = ((us_ - microsecond) / kMicrosecondsPerSecond) -
+                           kWindowsEpochDeltaSeconds -
+                           kCFAbsoluteTimeIntervalSince1970;
+
+  base::ScopedCFTypeRef<CFTimeZoneRef> time_zone(
+      is_local ? CFTimeZoneCopySystem() : NULL);
+  CFGregorianDate date = CFAbsoluteTimeGetGregorianDate(seconds, time_zone);
+  // 1 = Monday, ..., 7 = Sunday.
+  int cf_day_of_week = CFAbsoluteTimeGetDayOfWeek(seconds, time_zone);
+
+  exploded->year = date.year;
+  exploded->month = date.month;
+  exploded->day_of_week = cf_day_of_week % 7;
+  exploded->day_of_month = date.day;
+  exploded->hour = date.hour;
+  exploded->minute = date.minute;
+  // Make sure seconds are rounded down towards -infinity.
+  exploded->second = floor(date.second);
+  // Calculate milliseconds ourselves, since we rounded the |seconds|, making
+  // sure to round towards -infinity.
+  exploded->millisecond =
+      (microsecond >= 0) ? microsecond / kMicrosecondsPerMillisecond :
+                           (microsecond - kMicrosecondsPerMillisecond + 1) /
+                               kMicrosecondsPerMillisecond;
+}
+
+// TimeTicks ------------------------------------------------------------------
+
+// static
+TimeTicks TimeTicks::Now() {
+  return TimeTicks(ComputeCurrentTicks());
+}
+
+// static
+bool TimeTicks::IsHighResolution() {
+  return true;
+}
+
+// static
+ThreadTicks ThreadTicks::Now() {
+  return ThreadTicks(ComputeThreadTicks());
+}
+
+// static
+TraceTicks TraceTicks::Now() {
+  return TraceTicks(ComputeCurrentTicks());
+}
+
+}  // namespace base
diff --git a/base/time/time_posix.cc b/base/time/time_posix.cc
new file mode 100644
index 0000000..fc82c62
--- /dev/null
+++ b/base/time/time_posix.cc
@@ -0,0 +1,388 @@
+// Copyright (c) 2012 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/time/time.h"
+
+#include <stdint.h>
+#include <sys/time.h>
+#include <time.h>
+#if defined(OS_ANDROID) && !defined(__LP64__)
+#include <time64.h>
+#endif
+#include <unistd.h>
+
+#include <limits>
+#include <ostream>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "build/build_config.h"
+
+#if defined(OS_ANDROID)
+#include "base/os_compat_android.h"
+#elif defined(OS_NACL)
+#include "base/os_compat_nacl.h"
+#endif
+
+#if !defined(OS_MACOSX)
+#include "base/lazy_instance.h"
+#include "base/synchronization/lock.h"
+#endif
+
+namespace {
+
+#if !defined(OS_MACOSX)
+// This prevents a crash on traversing the environment global and looking up
+// the 'TZ' variable in libc. See: crbug.com/390567.
+base::LazyInstance<base::Lock>::Leaky
+    g_sys_time_to_time_struct_lock = LAZY_INSTANCE_INITIALIZER;
+
+// Define a system-specific SysTime that wraps either to a time_t or
+// a time64_t depending on the host system, and associated convertion.
+// See crbug.com/162007
+#if defined(OS_ANDROID) && !defined(__LP64__)
+typedef time64_t SysTime;
+
+SysTime SysTimeFromTimeStruct(struct tm* timestruct, bool is_local) {
+  base::AutoLock locked(g_sys_time_to_time_struct_lock.Get());
+  if (is_local)
+    return mktime64(timestruct);
+  else
+    return timegm64(timestruct);
+}
+
+void SysTimeToTimeStruct(SysTime t, struct tm* timestruct, bool is_local) {
+  base::AutoLock locked(g_sys_time_to_time_struct_lock.Get());
+  if (is_local)
+    localtime64_r(&t, timestruct);
+  else
+    gmtime64_r(&t, timestruct);
+}
+
+#else  // OS_ANDROID && !__LP64__
+typedef time_t SysTime;
+
+SysTime SysTimeFromTimeStruct(struct tm* timestruct, bool is_local) {
+  base::AutoLock locked(g_sys_time_to_time_struct_lock.Get());
+  if (is_local)
+    return mktime(timestruct);
+  else
+    return timegm(timestruct);
+}
+
+void SysTimeToTimeStruct(SysTime t, struct tm* timestruct, bool is_local) {
+  base::AutoLock locked(g_sys_time_to_time_struct_lock.Get());
+  if (is_local)
+    localtime_r(&t, timestruct);
+  else
+    gmtime_r(&t, timestruct);
+}
+#endif  // OS_ANDROID
+
+int64 ConvertTimespecToMicros(const struct timespec& ts) {
+  base::CheckedNumeric<int64> result(ts.tv_sec);
+  result *= base::Time::kMicrosecondsPerSecond;
+  result += (ts.tv_nsec / base::Time::kNanosecondsPerMicrosecond);
+  return result.ValueOrDie();
+}
+
+// Helper function to get results from clock_gettime() and convert to a
+// microsecond timebase. Minimum requirement is MONOTONIC_CLOCK to be supported
+// on the system. FreeBSD 6 has CLOCK_MONOTONIC but defines
+// _POSIX_MONOTONIC_CLOCK to -1.
+#if (defined(OS_POSIX) &&                                               \
+     defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0) || \
+    defined(OS_BSD) || defined(OS_ANDROID)
+int64 ClockNow(clockid_t clk_id) {
+  struct timespec ts;
+  if (clock_gettime(clk_id, &ts) != 0) {
+    NOTREACHED() << "clock_gettime(" << clk_id << ") failed.";
+    return 0;
+  }
+  return ConvertTimespecToMicros(ts);
+}
+#else  // _POSIX_MONOTONIC_CLOCK
+#error No usable tick clock function on this platform.
+#endif  // _POSIX_MONOTONIC_CLOCK
+#endif  // !defined(OS_MACOSX)
+
+}  // namespace
+
+namespace base {
+
+struct timespec TimeDelta::ToTimeSpec() const {
+  int64 microseconds = InMicroseconds();
+  time_t seconds = 0;
+  if (microseconds >= Time::kMicrosecondsPerSecond) {
+    seconds = InSeconds();
+    microseconds -= seconds * Time::kMicrosecondsPerSecond;
+  }
+  struct timespec result =
+      {seconds,
+       static_cast<long>(microseconds * Time::kNanosecondsPerMicrosecond)};
+  return result;
+}
+
+#if !defined(OS_MACOSX)
+// The Time routines in this file use standard POSIX routines, or almost-
+// standard routines in the case of timegm.  We need to use a Mach-specific
+// function for TimeTicks::Now() on Mac OS X.
+
+// Time -----------------------------------------------------------------------
+
+// Windows uses a Gregorian epoch of 1601.  We need to match this internally
+// so that our time representations match across all platforms.  See bug 14734.
+//   irb(main):010:0> Time.at(0).getutc()
+//   => Thu Jan 01 00:00:00 UTC 1970
+//   irb(main):011:0> Time.at(-11644473600).getutc()
+//   => Mon Jan 01 00:00:00 UTC 1601
+static const int64 kWindowsEpochDeltaSeconds = INT64_C(11644473600);
+
+// static
+const int64 Time::kWindowsEpochDeltaMicroseconds =
+    kWindowsEpochDeltaSeconds * Time::kMicrosecondsPerSecond;
+
+// Some functions in time.cc use time_t directly, so we provide an offset
+// to convert from time_t (Unix epoch) and internal (Windows epoch).
+// static
+const int64 Time::kTimeTToMicrosecondsOffset = kWindowsEpochDeltaMicroseconds;
+
+// static
+Time Time::Now() {
+  struct timeval tv;
+  struct timezone tz = { 0, 0 };  // UTC
+  if (gettimeofday(&tv, &tz) != 0) {
+    DCHECK(0) << "Could not determine time of day";
+    PLOG(ERROR) << "Call to gettimeofday failed.";
+    // Return null instead of uninitialized |tv| value, which contains random
+    // garbage data. This may result in the crash seen in crbug.com/147570.
+    return Time();
+  }
+  // Combine seconds and microseconds in a 64-bit field containing microseconds
+  // since the epoch.  That's enough for nearly 600 centuries.  Adjust from
+  // Unix (1970) to Windows (1601) epoch.
+  return Time((tv.tv_sec * kMicrosecondsPerSecond + tv.tv_usec) +
+      kWindowsEpochDeltaMicroseconds);
+}
+
+// static
+Time Time::NowFromSystemTime() {
+  // Just use Now() because Now() returns the system time.
+  return Now();
+}
+
+void Time::Explode(bool is_local, Exploded* exploded) const {
+  // Time stores times with microsecond resolution, but Exploded only carries
+  // millisecond resolution, so begin by being lossy.  Adjust from Windows
+  // epoch (1601) to Unix epoch (1970);
+  int64 microseconds = us_ - kWindowsEpochDeltaMicroseconds;
+  // The following values are all rounded towards -infinity.
+  int64 milliseconds;  // Milliseconds since epoch.
+  SysTime seconds;  // Seconds since epoch.
+  int millisecond;  // Exploded millisecond value (0-999).
+  if (microseconds >= 0) {
+    // Rounding towards -infinity <=> rounding towards 0, in this case.
+    milliseconds = microseconds / kMicrosecondsPerMillisecond;
+    seconds = milliseconds / kMillisecondsPerSecond;
+    millisecond = milliseconds % kMillisecondsPerSecond;
+  } else {
+    // Round these *down* (towards -infinity).
+    milliseconds = (microseconds - kMicrosecondsPerMillisecond + 1) /
+                   kMicrosecondsPerMillisecond;
+    seconds = (milliseconds - kMillisecondsPerSecond + 1) /
+              kMillisecondsPerSecond;
+    // Make this nonnegative (and between 0 and 999 inclusive).
+    millisecond = milliseconds % kMillisecondsPerSecond;
+    if (millisecond < 0)
+      millisecond += kMillisecondsPerSecond;
+  }
+
+  struct tm timestruct;
+  SysTimeToTimeStruct(seconds, &timestruct, is_local);
+
+  exploded->year         = timestruct.tm_year + 1900;
+  exploded->month        = timestruct.tm_mon + 1;
+  exploded->day_of_week  = timestruct.tm_wday;
+  exploded->day_of_month = timestruct.tm_mday;
+  exploded->hour         = timestruct.tm_hour;
+  exploded->minute       = timestruct.tm_min;
+  exploded->second       = timestruct.tm_sec;
+  exploded->millisecond  = millisecond;
+}
+
+// static
+Time Time::FromExploded(bool is_local, const Exploded& exploded) {
+  struct tm timestruct;
+  timestruct.tm_sec    = exploded.second;
+  timestruct.tm_min    = exploded.minute;
+  timestruct.tm_hour   = exploded.hour;
+  timestruct.tm_mday   = exploded.day_of_month;
+  timestruct.tm_mon    = exploded.month - 1;
+  timestruct.tm_year   = exploded.year - 1900;
+  timestruct.tm_wday   = exploded.day_of_week;  // mktime/timegm ignore this
+  timestruct.tm_yday   = 0;     // mktime/timegm ignore this
+  timestruct.tm_isdst  = -1;    // attempt to figure it out
+#if !defined(OS_NACL) && !defined(OS_SOLARIS)
+  timestruct.tm_gmtoff = 0;     // not a POSIX field, so mktime/timegm ignore
+  timestruct.tm_zone   = NULL;  // not a POSIX field, so mktime/timegm ignore
+#endif
+
+
+  int64 milliseconds;
+  SysTime seconds;
+
+  // Certain exploded dates do not really exist due to daylight saving times,
+  // and this causes mktime() to return implementation-defined values when
+  // tm_isdst is set to -1. On Android, the function will return -1, while the
+  // C libraries of other platforms typically return a liberally-chosen value.
+  // Handling this requires the special code below.
+
+  // SysTimeFromTimeStruct() modifies the input structure, save current value.
+  struct tm timestruct0 = timestruct;
+
+  seconds = SysTimeFromTimeStruct(&timestruct, is_local);
+  if (seconds == -1) {
+    // Get the time values with tm_isdst == 0 and 1, then select the closest one
+    // to UTC 00:00:00 that isn't -1.
+    timestruct = timestruct0;
+    timestruct.tm_isdst = 0;
+    int64 seconds_isdst0 = SysTimeFromTimeStruct(&timestruct, is_local);
+
+    timestruct = timestruct0;
+    timestruct.tm_isdst = 1;
+    int64 seconds_isdst1 = SysTimeFromTimeStruct(&timestruct, is_local);
+
+    // seconds_isdst0 or seconds_isdst1 can be -1 for some timezones.
+    // E.g. "CLST" (Chile Summer Time) returns -1 for 'tm_isdt == 1'.
+    if (seconds_isdst0 < 0)
+      seconds = seconds_isdst1;
+    else if (seconds_isdst1 < 0)
+      seconds = seconds_isdst0;
+    else
+      seconds = std::min(seconds_isdst0, seconds_isdst1);
+  }
+
+  // Handle overflow.  Clamping the range to what mktime and timegm might
+  // return is the best that can be done here.  It's not ideal, but it's better
+  // than failing here or ignoring the overflow case and treating each time
+  // overflow as one second prior to the epoch.
+  if (seconds == -1 &&
+      (exploded.year < 1969 || exploded.year > 1970)) {
+    // If exploded.year is 1969 or 1970, take -1 as correct, with the
+    // time indicating 1 second prior to the epoch.  (1970 is allowed to handle
+    // time zone and DST offsets.)  Otherwise, return the most future or past
+    // time representable.  Assumes the time_t epoch is 1970-01-01 00:00:00 UTC.
+    //
+    // The minimum and maximum representible times that mktime and timegm could
+    // return are used here instead of values outside that range to allow for
+    // proper round-tripping between exploded and counter-type time
+    // representations in the presence of possible truncation to time_t by
+    // division and use with other functions that accept time_t.
+    //
+    // When representing the most distant time in the future, add in an extra
+    // 999ms to avoid the time being less than any other possible value that
+    // this function can return.
+
+    // On Android, SysTime is int64, special care must be taken to avoid
+    // overflows.
+    const int64 min_seconds = (sizeof(SysTime) < sizeof(int64))
+                                  ? std::numeric_limits<SysTime>::min()
+                                  : std::numeric_limits<int32_t>::min();
+    const int64 max_seconds = (sizeof(SysTime) < sizeof(int64))
+                                  ? std::numeric_limits<SysTime>::max()
+                                  : std::numeric_limits<int32_t>::max();
+    if (exploded.year < 1969) {
+      milliseconds = min_seconds * kMillisecondsPerSecond;
+    } else {
+      milliseconds = max_seconds * kMillisecondsPerSecond;
+      milliseconds += (kMillisecondsPerSecond - 1);
+    }
+  } else {
+    milliseconds = seconds * kMillisecondsPerSecond + exploded.millisecond;
+  }
+
+  // Adjust from Unix (1970) to Windows (1601) epoch.
+  return Time((milliseconds * kMicrosecondsPerMillisecond) +
+      kWindowsEpochDeltaMicroseconds);
+}
+
+// TimeTicks ------------------------------------------------------------------
+// static
+TimeTicks TimeTicks::Now() {
+  return TimeTicks(ClockNow(CLOCK_MONOTONIC));
+}
+
+// static
+bool TimeTicks::IsHighResolution() {
+  return true;
+}
+
+// static
+ThreadTicks ThreadTicks::Now() {
+#if (defined(_POSIX_THREAD_CPUTIME) && (_POSIX_THREAD_CPUTIME >= 0)) || \
+    defined(OS_ANDROID)
+  return ThreadTicks(ClockNow(CLOCK_THREAD_CPUTIME_ID));
+#else
+  NOTREACHED();
+  return ThreadTicks();
+#endif
+}
+
+// Use the Chrome OS specific system-wide clock.
+#if defined(OS_CHROMEOS)
+// static
+TraceTicks TraceTicks::Now() {
+  struct timespec ts;
+  if (clock_gettime(kClockSystemTrace, &ts) != 0) {
+    // NB: fall-back for a chrome os build running on linux
+    return TraceTicks(ClockNow(CLOCK_MONOTONIC));
+  }
+  return TraceTicks(ConvertTimespecToMicros(ts));
+}
+
+#else  // !defined(OS_CHROMEOS)
+
+// static
+TraceTicks TraceTicks::Now() {
+  return TraceTicks(ClockNow(CLOCK_MONOTONIC));
+}
+
+#endif  // defined(OS_CHROMEOS)
+
+#endif  // !OS_MACOSX
+
+// static
+Time Time::FromTimeVal(struct timeval t) {
+  DCHECK_LT(t.tv_usec, static_cast<int>(Time::kMicrosecondsPerSecond));
+  DCHECK_GE(t.tv_usec, 0);
+  if (t.tv_usec == 0 && t.tv_sec == 0)
+    return Time();
+  if (t.tv_usec == static_cast<suseconds_t>(Time::kMicrosecondsPerSecond) - 1 &&
+      t.tv_sec == std::numeric_limits<time_t>::max())
+    return Max();
+  return Time(
+      (static_cast<int64>(t.tv_sec) * Time::kMicrosecondsPerSecond) +
+      t.tv_usec +
+      kTimeTToMicrosecondsOffset);
+}
+
+struct timeval Time::ToTimeVal() const {
+  struct timeval result;
+  if (is_null()) {
+    result.tv_sec = 0;
+    result.tv_usec = 0;
+    return result;
+  }
+  if (is_max()) {
+    result.tv_sec = std::numeric_limits<time_t>::max();
+    result.tv_usec = static_cast<suseconds_t>(Time::kMicrosecondsPerSecond) - 1;
+    return result;
+  }
+  int64 us = us_ - kTimeTToMicrosecondsOffset;
+  result.tv_sec = us / Time::kMicrosecondsPerSecond;
+  result.tv_usec = us % Time::kMicrosecondsPerSecond;
+  return result;
+}
+
+}  // namespace base
diff --git a/base/time/time_unittest.cc b/base/time/time_unittest.cc
new file mode 100644
index 0000000..b7e05b7
--- /dev/null
+++ b/base/time/time_unittest.cc
@@ -0,0 +1,1103 @@
+// Copyright (c) 2012 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/time/time.h"
+
+#include <stdint.h>
+#include <time.h>
+#include <limits>
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "base/threading/platform_thread.h"
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+// Specialized test fixture allowing time strings without timezones to be
+// tested by comparing them to a known time in the local zone.
+// See also pr_time_unittests.cc
+class TimeTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    // Use mktime to get a time_t, and turn it into a PRTime by converting
+    // seconds to microseconds.  Use 15th Oct 2007 12:45:00 local.  This
+    // must be a time guaranteed to be outside of a DST fallback hour in
+    // any timezone.
+    struct tm local_comparison_tm = {
+      0,            // second
+      45,           // minute
+      12,           // hour
+      15,           // day of month
+      10 - 1,       // month
+      2007 - 1900,  // year
+      0,            // day of week (ignored, output only)
+      0,            // day of year (ignored, output only)
+      -1            // DST in effect, -1 tells mktime to figure it out
+    };
+
+    time_t converted_time = mktime(&local_comparison_tm);
+    ASSERT_GT(converted_time, 0);
+    comparison_time_local_ = Time::FromTimeT(converted_time);
+
+    // time_t representation of 15th Oct 2007 12:45:00 PDT
+    comparison_time_pdt_ = Time::FromTimeT(1192477500);
+  }
+
+  Time comparison_time_local_;
+  Time comparison_time_pdt_;
+};
+
+// Test conversions to/from time_t and exploding/unexploding.
+TEST_F(TimeTest, TimeT) {
+  // C library time and exploded time.
+  time_t now_t_1 = time(NULL);
+  struct tm tms;
+#if defined(OS_WIN)
+  localtime_s(&tms, &now_t_1);
+#elif defined(OS_POSIX)
+  localtime_r(&now_t_1, &tms);
+#endif
+
+  // Convert to ours.
+  Time our_time_1 = Time::FromTimeT(now_t_1);
+  Time::Exploded exploded;
+  our_time_1.LocalExplode(&exploded);
+
+  // This will test both our exploding and our time_t -> Time conversion.
+  EXPECT_EQ(tms.tm_year + 1900, exploded.year);
+  EXPECT_EQ(tms.tm_mon + 1, exploded.month);
+  EXPECT_EQ(tms.tm_mday, exploded.day_of_month);
+  EXPECT_EQ(tms.tm_hour, exploded.hour);
+  EXPECT_EQ(tms.tm_min, exploded.minute);
+  EXPECT_EQ(tms.tm_sec, exploded.second);
+
+  // Convert exploded back to the time struct.
+  Time our_time_2 = Time::FromLocalExploded(exploded);
+  EXPECT_TRUE(our_time_1 == our_time_2);
+
+  time_t now_t_2 = our_time_2.ToTimeT();
+  EXPECT_EQ(now_t_1, now_t_2);
+
+  EXPECT_EQ(10, Time().FromTimeT(10).ToTimeT());
+  EXPECT_EQ(10.0, Time().FromTimeT(10).ToDoubleT());
+
+  // Conversions of 0 should stay 0.
+  EXPECT_EQ(0, Time().ToTimeT());
+  EXPECT_EQ(0, Time::FromTimeT(0).ToInternalValue());
+}
+
+// Test conversions to/from javascript time.
+TEST_F(TimeTest, JsTime) {
+  Time epoch = Time::FromJsTime(0.0);
+  EXPECT_EQ(epoch, Time::UnixEpoch());
+  Time t = Time::FromJsTime(700000.3);
+  EXPECT_EQ(700.0003, t.ToDoubleT());
+  t = Time::FromDoubleT(800.73);
+  EXPECT_EQ(800730.0, t.ToJsTime());
+}
+
+#if defined(OS_POSIX)
+TEST_F(TimeTest, FromTimeVal) {
+  Time now = Time::Now();
+  Time also_now = Time::FromTimeVal(now.ToTimeVal());
+  EXPECT_EQ(now, also_now);
+}
+#endif  // OS_POSIX
+
+TEST_F(TimeTest, FromExplodedWithMilliseconds) {
+  // Some platform implementations of FromExploded are liable to drop
+  // milliseconds if we aren't careful.
+  Time now = Time::NowFromSystemTime();
+  Time::Exploded exploded1 = {0};
+  now.UTCExplode(&exploded1);
+  exploded1.millisecond = 500;
+  Time time = Time::FromUTCExploded(exploded1);
+  Time::Exploded exploded2 = {0};
+  time.UTCExplode(&exploded2);
+  EXPECT_EQ(exploded1.millisecond, exploded2.millisecond);
+}
+
+TEST_F(TimeTest, ZeroIsSymmetric) {
+  Time zero_time(Time::FromTimeT(0));
+  EXPECT_EQ(0, zero_time.ToTimeT());
+
+  EXPECT_EQ(0.0, zero_time.ToDoubleT());
+}
+
+TEST_F(TimeTest, LocalExplode) {
+  Time a = Time::Now();
+  Time::Exploded exploded;
+  a.LocalExplode(&exploded);
+
+  Time b = Time::FromLocalExploded(exploded);
+
+  // The exploded structure doesn't have microseconds, and on Mac & Linux, the
+  // internal OS conversion uses seconds, which will cause truncation. So we
+  // can only make sure that the delta is within one second.
+  EXPECT_TRUE((a - b) < TimeDelta::FromSeconds(1));
+}
+
+TEST_F(TimeTest, UTCExplode) {
+  Time a = Time::Now();
+  Time::Exploded exploded;
+  a.UTCExplode(&exploded);
+
+  Time b = Time::FromUTCExploded(exploded);
+  EXPECT_TRUE((a - b) < TimeDelta::FromSeconds(1));
+}
+
+TEST_F(TimeTest, LocalMidnight) {
+  Time::Exploded exploded;
+  Time::Now().LocalMidnight().LocalExplode(&exploded);
+  EXPECT_EQ(0, exploded.hour);
+  EXPECT_EQ(0, exploded.minute);
+  EXPECT_EQ(0, exploded.second);
+  EXPECT_EQ(0, exploded.millisecond);
+}
+
+TEST_F(TimeTest, ParseTimeTest1) {
+  time_t current_time = 0;
+  time(&current_time);
+
+  const int BUFFER_SIZE = 64;
+  struct tm local_time = {0};
+  char time_buf[BUFFER_SIZE] = {0};
+#if defined(OS_WIN)
+  localtime_s(&local_time, &current_time);
+  asctime_s(time_buf, arraysize(time_buf), &local_time);
+#elif defined(OS_POSIX)
+  localtime_r(&current_time, &local_time);
+  asctime_r(&local_time, time_buf);
+#endif
+
+  Time parsed_time;
+  EXPECT_TRUE(Time::FromString(time_buf, &parsed_time));
+  EXPECT_EQ(current_time, parsed_time.ToTimeT());
+}
+
+TEST_F(TimeTest, DayOfWeekSunday) {
+  Time time;
+  EXPECT_TRUE(Time::FromString("Sun, 06 May 2012 12:00:00 GMT", &time));
+  Time::Exploded exploded;
+  time.UTCExplode(&exploded);
+  EXPECT_EQ(0, exploded.day_of_week);
+}
+
+TEST_F(TimeTest, DayOfWeekWednesday) {
+  Time time;
+  EXPECT_TRUE(Time::FromString("Wed, 09 May 2012 12:00:00 GMT", &time));
+  Time::Exploded exploded;
+  time.UTCExplode(&exploded);
+  EXPECT_EQ(3, exploded.day_of_week);
+}
+
+TEST_F(TimeTest, DayOfWeekSaturday) {
+  Time time;
+  EXPECT_TRUE(Time::FromString("Sat, 12 May 2012 12:00:00 GMT", &time));
+  Time::Exploded exploded;
+  time.UTCExplode(&exploded);
+  EXPECT_EQ(6, exploded.day_of_week);
+}
+
+TEST_F(TimeTest, ParseTimeTest2) {
+  Time parsed_time;
+  EXPECT_TRUE(Time::FromString("Mon, 15 Oct 2007 19:45:00 GMT", &parsed_time));
+  EXPECT_EQ(comparison_time_pdt_, parsed_time);
+}
+
+TEST_F(TimeTest, ParseTimeTest3) {
+  Time parsed_time;
+  EXPECT_TRUE(Time::FromString("15 Oct 07 12:45:00", &parsed_time));
+  EXPECT_EQ(comparison_time_local_, parsed_time);
+}
+
+TEST_F(TimeTest, ParseTimeTest4) {
+  Time parsed_time;
+  EXPECT_TRUE(Time::FromString("15 Oct 07 19:45 GMT", &parsed_time));
+  EXPECT_EQ(comparison_time_pdt_, parsed_time);
+}
+
+TEST_F(TimeTest, ParseTimeTest5) {
+  Time parsed_time;
+  EXPECT_TRUE(Time::FromString("Mon Oct 15 12:45 PDT 2007", &parsed_time));
+  EXPECT_EQ(comparison_time_pdt_, parsed_time);
+}
+
+TEST_F(TimeTest, ParseTimeTest6) {
+  Time parsed_time;
+  EXPECT_TRUE(Time::FromString("Monday, Oct 15, 2007 12:45 PM", &parsed_time));
+  EXPECT_EQ(comparison_time_local_, parsed_time);
+}
+
+TEST_F(TimeTest, ParseTimeTest7) {
+  Time parsed_time;
+  EXPECT_TRUE(Time::FromString("10/15/07 12:45:00 PM", &parsed_time));
+  EXPECT_EQ(comparison_time_local_, parsed_time);
+}
+
+TEST_F(TimeTest, ParseTimeTest8) {
+  Time parsed_time;
+  EXPECT_TRUE(Time::FromString("15-OCT-2007 12:45pm", &parsed_time));
+  EXPECT_EQ(comparison_time_local_, parsed_time);
+}
+
+TEST_F(TimeTest, ParseTimeTest9) {
+  Time parsed_time;
+  EXPECT_TRUE(Time::FromString("16 Oct 2007 4:45-JST (Tuesday)", &parsed_time));
+  EXPECT_EQ(comparison_time_pdt_, parsed_time);
+}
+
+TEST_F(TimeTest, ParseTimeTest10) {
+  Time parsed_time;
+  EXPECT_TRUE(Time::FromString("15/10/07 12:45", &parsed_time));
+  EXPECT_EQ(parsed_time, comparison_time_local_);
+}
+
+// Test some of edge cases around epoch, etc.
+TEST_F(TimeTest, ParseTimeTestEpoch0) {
+  Time parsed_time;
+
+  // time_t == epoch == 0
+  EXPECT_TRUE(Time::FromString("Thu Jan 01 01:00:00 +0100 1970",
+                               &parsed_time));
+  EXPECT_EQ(0, parsed_time.ToTimeT());
+  EXPECT_TRUE(Time::FromString("Thu Jan 01 00:00:00 GMT 1970",
+                               &parsed_time));
+  EXPECT_EQ(0, parsed_time.ToTimeT());
+}
+
+TEST_F(TimeTest, ParseTimeTestEpoch1) {
+  Time parsed_time;
+
+  // time_t == 1 second after epoch == 1
+  EXPECT_TRUE(Time::FromString("Thu Jan 01 01:00:01 +0100 1970",
+                               &parsed_time));
+  EXPECT_EQ(1, parsed_time.ToTimeT());
+  EXPECT_TRUE(Time::FromString("Thu Jan 01 00:00:01 GMT 1970",
+                               &parsed_time));
+  EXPECT_EQ(1, parsed_time.ToTimeT());
+}
+
+TEST_F(TimeTest, ParseTimeTestEpoch2) {
+  Time parsed_time;
+
+  // time_t == 2 seconds after epoch == 2
+  EXPECT_TRUE(Time::FromString("Thu Jan 01 01:00:02 +0100 1970",
+                               &parsed_time));
+  EXPECT_EQ(2, parsed_time.ToTimeT());
+  EXPECT_TRUE(Time::FromString("Thu Jan 01 00:00:02 GMT 1970",
+                               &parsed_time));
+  EXPECT_EQ(2, parsed_time.ToTimeT());
+}
+
+TEST_F(TimeTest, ParseTimeTestEpochNeg1) {
+  Time parsed_time;
+
+  // time_t == 1 second before epoch == -1
+  EXPECT_TRUE(Time::FromString("Thu Jan 01 00:59:59 +0100 1970",
+                               &parsed_time));
+  EXPECT_EQ(-1, parsed_time.ToTimeT());
+  EXPECT_TRUE(Time::FromString("Wed Dec 31 23:59:59 GMT 1969",
+                               &parsed_time));
+  EXPECT_EQ(-1, parsed_time.ToTimeT());
+}
+
+// If time_t is 32 bits, a date after year 2038 will overflow time_t and
+// cause timegm() to return -1.  The parsed time should not be 1 second
+// before epoch.
+TEST_F(TimeTest, ParseTimeTestEpochNotNeg1) {
+  Time parsed_time;
+
+  EXPECT_TRUE(Time::FromString("Wed Dec 31 23:59:59 GMT 2100",
+                               &parsed_time));
+  EXPECT_NE(-1, parsed_time.ToTimeT());
+}
+
+TEST_F(TimeTest, ParseTimeTestEpochNeg2) {
+  Time parsed_time;
+
+  // time_t == 2 seconds before epoch == -2
+  EXPECT_TRUE(Time::FromString("Thu Jan 01 00:59:58 +0100 1970",
+                               &parsed_time));
+  EXPECT_EQ(-2, parsed_time.ToTimeT());
+  EXPECT_TRUE(Time::FromString("Wed Dec 31 23:59:58 GMT 1969",
+                               &parsed_time));
+  EXPECT_EQ(-2, parsed_time.ToTimeT());
+}
+
+TEST_F(TimeTest, ParseTimeTestEpoch1960) {
+  Time parsed_time;
+
+  // time_t before Epoch, in 1960
+  EXPECT_TRUE(Time::FromString("Wed Jun 29 19:40:01 +0100 1960",
+                               &parsed_time));
+  EXPECT_EQ(-299999999, parsed_time.ToTimeT());
+  EXPECT_TRUE(Time::FromString("Wed Jun 29 18:40:01 GMT 1960",
+                               &parsed_time));
+  EXPECT_EQ(-299999999, parsed_time.ToTimeT());
+  EXPECT_TRUE(Time::FromString("Wed Jun 29 17:40:01 GMT 1960",
+                               &parsed_time));
+  EXPECT_EQ(-300003599, parsed_time.ToTimeT());
+}
+
+TEST_F(TimeTest, ParseTimeTestEmpty) {
+  Time parsed_time;
+  EXPECT_FALSE(Time::FromString("", &parsed_time));
+}
+
+TEST_F(TimeTest, ParseTimeTestInvalidString) {
+  Time parsed_time;
+  EXPECT_FALSE(Time::FromString("Monday morning 2000", &parsed_time));
+}
+
+TEST_F(TimeTest, ExplodeBeforeUnixEpoch) {
+  static const int kUnixEpochYear = 1970;  // In case this changes (ha!).
+  Time t;
+  Time::Exploded exploded;
+
+  t = Time::UnixEpoch() - TimeDelta::FromMicroseconds(1);
+  t.UTCExplode(&exploded);
+  EXPECT_TRUE(exploded.HasValidValues());
+  // Should be 1969-12-31 23:59:59 999 milliseconds (and 999 microseconds).
+  EXPECT_EQ(kUnixEpochYear - 1, exploded.year);
+  EXPECT_EQ(12, exploded.month);
+  EXPECT_EQ(31, exploded.day_of_month);
+  EXPECT_EQ(23, exploded.hour);
+  EXPECT_EQ(59, exploded.minute);
+  EXPECT_EQ(59, exploded.second);
+  EXPECT_EQ(999, exploded.millisecond);
+
+  t = Time::UnixEpoch() - TimeDelta::FromMicroseconds(1000);
+  t.UTCExplode(&exploded);
+  EXPECT_TRUE(exploded.HasValidValues());
+  // Should be 1969-12-31 23:59:59 999 milliseconds.
+  EXPECT_EQ(kUnixEpochYear - 1, exploded.year);
+  EXPECT_EQ(12, exploded.month);
+  EXPECT_EQ(31, exploded.day_of_month);
+  EXPECT_EQ(23, exploded.hour);
+  EXPECT_EQ(59, exploded.minute);
+  EXPECT_EQ(59, exploded.second);
+  EXPECT_EQ(999, exploded.millisecond);
+
+  t = Time::UnixEpoch() - TimeDelta::FromMicroseconds(1001);
+  t.UTCExplode(&exploded);
+  EXPECT_TRUE(exploded.HasValidValues());
+  // Should be 1969-12-31 23:59:59 998 milliseconds (and 999 microseconds).
+  EXPECT_EQ(kUnixEpochYear - 1, exploded.year);
+  EXPECT_EQ(12, exploded.month);
+  EXPECT_EQ(31, exploded.day_of_month);
+  EXPECT_EQ(23, exploded.hour);
+  EXPECT_EQ(59, exploded.minute);
+  EXPECT_EQ(59, exploded.second);
+  EXPECT_EQ(998, exploded.millisecond);
+
+  t = Time::UnixEpoch() - TimeDelta::FromMilliseconds(1000);
+  t.UTCExplode(&exploded);
+  EXPECT_TRUE(exploded.HasValidValues());
+  // Should be 1969-12-31 23:59:59.
+  EXPECT_EQ(kUnixEpochYear - 1, exploded.year);
+  EXPECT_EQ(12, exploded.month);
+  EXPECT_EQ(31, exploded.day_of_month);
+  EXPECT_EQ(23, exploded.hour);
+  EXPECT_EQ(59, exploded.minute);
+  EXPECT_EQ(59, exploded.second);
+  EXPECT_EQ(0, exploded.millisecond);
+
+  t = Time::UnixEpoch() - TimeDelta::FromMilliseconds(1001);
+  t.UTCExplode(&exploded);
+  EXPECT_TRUE(exploded.HasValidValues());
+  // Should be 1969-12-31 23:59:58 999 milliseconds.
+  EXPECT_EQ(kUnixEpochYear - 1, exploded.year);
+  EXPECT_EQ(12, exploded.month);
+  EXPECT_EQ(31, exploded.day_of_month);
+  EXPECT_EQ(23, exploded.hour);
+  EXPECT_EQ(59, exploded.minute);
+  EXPECT_EQ(58, exploded.second);
+  EXPECT_EQ(999, exploded.millisecond);
+
+  // Make sure we still handle at/after Unix epoch correctly.
+  t = Time::UnixEpoch();
+  t.UTCExplode(&exploded);
+  EXPECT_TRUE(exploded.HasValidValues());
+  // Should be 1970-12-31 00:00:00 0 milliseconds.
+  EXPECT_EQ(kUnixEpochYear, exploded.year);
+  EXPECT_EQ(1, exploded.month);
+  EXPECT_EQ(1, exploded.day_of_month);
+  EXPECT_EQ(0, exploded.hour);
+  EXPECT_EQ(0, exploded.minute);
+  EXPECT_EQ(0, exploded.second);
+  EXPECT_EQ(0, exploded.millisecond);
+
+  t = Time::UnixEpoch() + TimeDelta::FromMicroseconds(1);
+  t.UTCExplode(&exploded);
+  EXPECT_TRUE(exploded.HasValidValues());
+  // Should be 1970-01-01 00:00:00 0 milliseconds (and 1 microsecond).
+  EXPECT_EQ(kUnixEpochYear, exploded.year);
+  EXPECT_EQ(1, exploded.month);
+  EXPECT_EQ(1, exploded.day_of_month);
+  EXPECT_EQ(0, exploded.hour);
+  EXPECT_EQ(0, exploded.minute);
+  EXPECT_EQ(0, exploded.second);
+  EXPECT_EQ(0, exploded.millisecond);
+
+  t = Time::UnixEpoch() + TimeDelta::FromMicroseconds(1000);
+  t.UTCExplode(&exploded);
+  EXPECT_TRUE(exploded.HasValidValues());
+  // Should be 1970-01-01 00:00:00 1 millisecond.
+  EXPECT_EQ(kUnixEpochYear, exploded.year);
+  EXPECT_EQ(1, exploded.month);
+  EXPECT_EQ(1, exploded.day_of_month);
+  EXPECT_EQ(0, exploded.hour);
+  EXPECT_EQ(0, exploded.minute);
+  EXPECT_EQ(0, exploded.second);
+  EXPECT_EQ(1, exploded.millisecond);
+
+  t = Time::UnixEpoch() + TimeDelta::FromMilliseconds(1000);
+  t.UTCExplode(&exploded);
+  EXPECT_TRUE(exploded.HasValidValues());
+  // Should be 1970-01-01 00:00:01.
+  EXPECT_EQ(kUnixEpochYear, exploded.year);
+  EXPECT_EQ(1, exploded.month);
+  EXPECT_EQ(1, exploded.day_of_month);
+  EXPECT_EQ(0, exploded.hour);
+  EXPECT_EQ(0, exploded.minute);
+  EXPECT_EQ(1, exploded.second);
+  EXPECT_EQ(0, exploded.millisecond);
+
+  t = Time::UnixEpoch() + TimeDelta::FromMilliseconds(1001);
+  t.UTCExplode(&exploded);
+  EXPECT_TRUE(exploded.HasValidValues());
+  // Should be 1970-01-01 00:00:01 1 millisecond.
+  EXPECT_EQ(kUnixEpochYear, exploded.year);
+  EXPECT_EQ(1, exploded.month);
+  EXPECT_EQ(1, exploded.day_of_month);
+  EXPECT_EQ(0, exploded.hour);
+  EXPECT_EQ(0, exploded.minute);
+  EXPECT_EQ(1, exploded.second);
+  EXPECT_EQ(1, exploded.millisecond);
+}
+
+TEST_F(TimeTest, TimeDeltaMax) {
+  TimeDelta max = TimeDelta::Max();
+  EXPECT_TRUE(max.is_max());
+  EXPECT_EQ(max, TimeDelta::Max());
+  EXPECT_GT(max, TimeDelta::FromDays(100 * 365));
+  EXPECT_GT(max, TimeDelta());
+}
+
+TEST_F(TimeTest, TimeDeltaMaxConversions) {
+  TimeDelta t = TimeDelta::Max();
+  EXPECT_EQ(std::numeric_limits<int64>::max(), t.ToInternalValue());
+
+  EXPECT_EQ(std::numeric_limits<int>::max(), t.InDays());
+  EXPECT_EQ(std::numeric_limits<int>::max(), t.InHours());
+  EXPECT_EQ(std::numeric_limits<int>::max(), t.InMinutes());
+  EXPECT_EQ(std::numeric_limits<double>::infinity(), t.InSecondsF());
+  EXPECT_EQ(std::numeric_limits<int64>::max(), t.InSeconds());
+  EXPECT_EQ(std::numeric_limits<double>::infinity(), t.InMillisecondsF());
+  EXPECT_EQ(std::numeric_limits<int64>::max(), t.InMilliseconds());
+  EXPECT_EQ(std::numeric_limits<int64>::max(), t.InMillisecondsRoundedUp());
+
+  t = TimeDelta::FromDays(std::numeric_limits<int>::max());
+  EXPECT_TRUE(t.is_max());
+
+  t = TimeDelta::FromHours(std::numeric_limits<int>::max());
+  EXPECT_TRUE(t.is_max());
+
+  t = TimeDelta::FromMinutes(std::numeric_limits<int>::max());
+  EXPECT_TRUE(t.is_max());
+
+  t = TimeDelta::FromSeconds(std::numeric_limits<int64>::max());
+  EXPECT_TRUE(t.is_max());
+
+  t = TimeDelta::FromMilliseconds(std::numeric_limits<int64>::max());
+  EXPECT_TRUE(t.is_max());
+
+  t = TimeDelta::FromSecondsD(std::numeric_limits<double>::infinity());
+  EXPECT_TRUE(t.is_max());
+
+  t = TimeDelta::FromMillisecondsD(std::numeric_limits<double>::infinity());
+  EXPECT_TRUE(t.is_max());
+
+  t = TimeDelta::FromMicroseconds(std::numeric_limits<int64>::max());
+  EXPECT_TRUE(t.is_max());
+}
+
+TEST_F(TimeTest, Max) {
+  Time max = Time::Max();
+  EXPECT_TRUE(max.is_max());
+  EXPECT_EQ(max, Time::Max());
+  EXPECT_GT(max, Time::Now());
+  EXPECT_GT(max, Time());
+}
+
+TEST_F(TimeTest, MaxConversions) {
+  Time t = Time::Max();
+  EXPECT_EQ(std::numeric_limits<int64>::max(), t.ToInternalValue());
+
+  t = Time::FromDoubleT(std::numeric_limits<double>::infinity());
+  EXPECT_TRUE(t.is_max());
+  EXPECT_EQ(std::numeric_limits<double>::infinity(), t.ToDoubleT());
+
+  t = Time::FromJsTime(std::numeric_limits<double>::infinity());
+  EXPECT_TRUE(t.is_max());
+  EXPECT_EQ(std::numeric_limits<double>::infinity(), t.ToJsTime());
+
+  t = Time::FromTimeT(std::numeric_limits<time_t>::max());
+  EXPECT_TRUE(t.is_max());
+  EXPECT_EQ(std::numeric_limits<time_t>::max(), t.ToTimeT());
+
+#if defined(OS_POSIX)
+  struct timeval tval;
+  tval.tv_sec = std::numeric_limits<time_t>::max();
+  tval.tv_usec = static_cast<suseconds_t>(Time::kMicrosecondsPerSecond) - 1;
+  t = Time::FromTimeVal(tval);
+  EXPECT_TRUE(t.is_max());
+  tval = t.ToTimeVal();
+  EXPECT_EQ(std::numeric_limits<time_t>::max(), tval.tv_sec);
+  EXPECT_EQ(static_cast<suseconds_t>(Time::kMicrosecondsPerSecond) - 1,
+      tval.tv_usec);
+#endif
+
+#if defined(OS_MACOSX)
+  t = Time::FromCFAbsoluteTime(std::numeric_limits<CFAbsoluteTime>::infinity());
+  EXPECT_TRUE(t.is_max());
+  EXPECT_EQ(std::numeric_limits<CFAbsoluteTime>::infinity(),
+            t.ToCFAbsoluteTime());
+#endif
+
+#if defined(OS_WIN)
+  FILETIME ftime;
+  ftime.dwHighDateTime = std::numeric_limits<DWORD>::max();
+  ftime.dwLowDateTime = std::numeric_limits<DWORD>::max();
+  t = Time::FromFileTime(ftime);
+  EXPECT_TRUE(t.is_max());
+  ftime = t.ToFileTime();
+  EXPECT_EQ(std::numeric_limits<DWORD>::max(), ftime.dwHighDateTime);
+  EXPECT_EQ(std::numeric_limits<DWORD>::max(), ftime.dwLowDateTime);
+#endif
+}
+
+#if defined(OS_MACOSX)
+TEST_F(TimeTest, TimeTOverflow) {
+  Time t = Time::FromInternalValue(std::numeric_limits<int64>::max() - 1);
+  EXPECT_FALSE(t.is_max());
+  EXPECT_EQ(std::numeric_limits<time_t>::max(), t.ToTimeT());
+}
+#endif
+
+#if defined(OS_ANDROID)
+TEST_F(TimeTest, FromLocalExplodedCrashOnAndroid) {
+  // This crashed inside Time:: FromLocalExploded() on Android 4.1.2.
+  // See http://crbug.com/287821
+  Time::Exploded midnight = {2013,  // year
+                             10,    // month
+                             0,     // day_of_week
+                             13,    // day_of_month
+                             0,     // hour
+                             0,     // minute
+                             0,     // second
+  };
+  // The string passed to putenv() must be a char* and the documentation states
+  // that it 'becomes part of the environment', so use a static buffer.
+  static char buffer[] = "TZ=America/Santiago";
+  putenv(buffer);
+  tzset();
+  Time t = Time::FromLocalExploded(midnight);
+  EXPECT_EQ(1381633200, t.ToTimeT());
+}
+#endif  // OS_ANDROID
+
+TEST(TimeTicks, Deltas) {
+  for (int index = 0; index < 50; index++) {
+    TimeTicks ticks_start = TimeTicks::Now();
+    base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10));
+    TimeTicks ticks_stop = TimeTicks::Now();
+    TimeDelta delta = ticks_stop - ticks_start;
+    // Note:  Although we asked for a 10ms sleep, if the
+    // time clock has a finer granularity than the Sleep()
+    // clock, it is quite possible to wakeup early.  Here
+    // is how that works:
+    //      Time(ms timer)      Time(us timer)
+    //          5                   5010
+    //          6                   6010
+    //          7                   7010
+    //          8                   8010
+    //          9                   9000
+    // Elapsed  4ms                 3990us
+    //
+    // Unfortunately, our InMilliseconds() function truncates
+    // rather than rounds.  We should consider fixing this
+    // so that our averages come out better.
+    EXPECT_GE(delta.InMilliseconds(), 9);
+    EXPECT_GE(delta.InMicroseconds(), 9000);
+    EXPECT_EQ(delta.InSeconds(), 0);
+  }
+}
+
+static void HighResClockTest(TimeTicks (*GetTicks)()) {
+  // IsHighResolution() is false on some systems.  Since the product still works
+  // even if it's false, it makes this entire test questionable.
+  if (!TimeTicks::IsHighResolution())
+    return;
+
+  // Why do we loop here?
+  // We're trying to measure that intervals increment in a VERY small amount
+  // of time --  less than 15ms.  Unfortunately, if we happen to have a
+  // context switch in the middle of our test, the context switch could easily
+  // exceed our limit.  So, we iterate on this several times.  As long as we're
+  // able to detect the fine-granularity timers at least once, then the test
+  // has succeeded.
+
+  const int kTargetGranularityUs = 15000;  // 15ms
+
+  bool success = false;
+  int retries = 100;  // Arbitrary.
+  TimeDelta delta;
+  while (!success && retries--) {
+    TimeTicks ticks_start = GetTicks();
+    // Loop until we can detect that the clock has changed.  Non-HighRes timers
+    // will increment in chunks, e.g. 15ms.  By spinning until we see a clock
+    // change, we detect the minimum time between measurements.
+    do {
+      delta = GetTicks() - ticks_start;
+    } while (delta.InMilliseconds() == 0);
+
+    if (delta.InMicroseconds() <= kTargetGranularityUs)
+      success = true;
+  }
+
+  // In high resolution mode, we expect to see the clock increment
+  // in intervals less than 15ms.
+  EXPECT_TRUE(success);
+}
+
+TEST(TimeTicks, HighRes) {
+  HighResClockTest(&TimeTicks::Now);
+}
+
+// Fails frequently on Android http://crbug.com/352633 with:
+// Expected: (delta_thread.InMicroseconds()) > (0), actual: 0 vs 0
+#if defined(OS_ANDROID)
+#define MAYBE_ThreadNow DISABLED_ThreadNow
+#else
+#define MAYBE_ThreadNow ThreadNow
+#endif
+TEST(ThreadTicks, MAYBE_ThreadNow) {
+  if (ThreadTicks::IsSupported()) {
+    TimeTicks begin = TimeTicks::Now();
+    ThreadTicks begin_thread = ThreadTicks::Now();
+    // Make sure that ThreadNow value is non-zero.
+    EXPECT_GT(begin_thread, ThreadTicks());
+    // Sleep for 10 milliseconds to get the thread de-scheduled.
+    base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10));
+    ThreadTicks end_thread = ThreadTicks::Now();
+    TimeTicks end = TimeTicks::Now();
+    TimeDelta delta = end - begin;
+    TimeDelta delta_thread = end_thread - begin_thread;
+    // Make sure that some thread time have elapsed.
+    EXPECT_GT(delta_thread.InMicroseconds(), 0);
+    // But the thread time is at least 9ms less than clock time.
+    TimeDelta difference = delta - delta_thread;
+    EXPECT_GE(difference.InMicroseconds(), 9000);
+  }
+}
+
+TEST(TraceTicks, NowFromSystemTraceTime) {
+  // Re-use HighRes test for now since clock properties are identical.
+  using NowFunction = TimeTicks (*)(void);
+  HighResClockTest(reinterpret_cast<NowFunction>(&TraceTicks::Now));
+}
+
+TEST(TimeTicks, SnappedToNextTickBasic) {
+  base::TimeTicks phase = base::TimeTicks::FromInternalValue(4000);
+  base::TimeDelta interval = base::TimeDelta::FromMicroseconds(1000);
+  base::TimeTicks timestamp;
+
+  // Timestamp in previous interval.
+  timestamp = base::TimeTicks::FromInternalValue(3500);
+  EXPECT_EQ(4000,
+            timestamp.SnappedToNextTick(phase, interval).ToInternalValue());
+
+  // Timestamp in next interval.
+  timestamp = base::TimeTicks::FromInternalValue(4500);
+  EXPECT_EQ(5000,
+            timestamp.SnappedToNextTick(phase, interval).ToInternalValue());
+
+  // Timestamp multiple intervals before.
+  timestamp = base::TimeTicks::FromInternalValue(2500);
+  EXPECT_EQ(3000,
+            timestamp.SnappedToNextTick(phase, interval).ToInternalValue());
+
+  // Timestamp multiple intervals after.
+  timestamp = base::TimeTicks::FromInternalValue(6500);
+  EXPECT_EQ(7000,
+            timestamp.SnappedToNextTick(phase, interval).ToInternalValue());
+
+  // Timestamp on previous interval.
+  timestamp = base::TimeTicks::FromInternalValue(3000);
+  EXPECT_EQ(3000,
+            timestamp.SnappedToNextTick(phase, interval).ToInternalValue());
+
+  // Timestamp on next interval.
+  timestamp = base::TimeTicks::FromInternalValue(5000);
+  EXPECT_EQ(5000,
+            timestamp.SnappedToNextTick(phase, interval).ToInternalValue());
+
+  // Timestamp equal to phase.
+  timestamp = base::TimeTicks::FromInternalValue(4000);
+  EXPECT_EQ(4000,
+            timestamp.SnappedToNextTick(phase, interval).ToInternalValue());
+}
+
+TEST(TimeTicks, SnappedToNextTickOverflow) {
+  // int(big_timestamp / interval) < 0, so this causes a crash if the number of
+  // intervals elapsed is attempted to be stored in an int.
+  base::TimeTicks phase = base::TimeTicks::FromInternalValue(0);
+  base::TimeDelta interval = base::TimeDelta::FromMicroseconds(4000);
+  base::TimeTicks big_timestamp =
+      base::TimeTicks::FromInternalValue(8635916564000);
+
+  EXPECT_EQ(8635916564000,
+            big_timestamp.SnappedToNextTick(phase, interval).ToInternalValue());
+  EXPECT_EQ(8635916564000,
+            big_timestamp.SnappedToNextTick(big_timestamp, interval)
+                .ToInternalValue());
+}
+
+TEST(TimeDelta, FromAndIn) {
+  EXPECT_TRUE(TimeDelta::FromDays(2) == TimeDelta::FromHours(48));
+  EXPECT_TRUE(TimeDelta::FromHours(3) == TimeDelta::FromMinutes(180));
+  EXPECT_TRUE(TimeDelta::FromMinutes(2) == TimeDelta::FromSeconds(120));
+  EXPECT_TRUE(TimeDelta::FromSeconds(2) == TimeDelta::FromMilliseconds(2000));
+  EXPECT_TRUE(TimeDelta::FromMilliseconds(2) ==
+              TimeDelta::FromMicroseconds(2000));
+  EXPECT_TRUE(TimeDelta::FromSecondsD(2.3) ==
+              TimeDelta::FromMilliseconds(2300));
+  EXPECT_TRUE(TimeDelta::FromMillisecondsD(2.5) ==
+              TimeDelta::FromMicroseconds(2500));
+  EXPECT_EQ(13, TimeDelta::FromDays(13).InDays());
+  EXPECT_EQ(13, TimeDelta::FromHours(13).InHours());
+  EXPECT_EQ(13, TimeDelta::FromMinutes(13).InMinutes());
+  EXPECT_EQ(13, TimeDelta::FromSeconds(13).InSeconds());
+  EXPECT_EQ(13.0, TimeDelta::FromSeconds(13).InSecondsF());
+  EXPECT_EQ(13, TimeDelta::FromMilliseconds(13).InMilliseconds());
+  EXPECT_EQ(13.0, TimeDelta::FromMilliseconds(13).InMillisecondsF());
+  EXPECT_EQ(13, TimeDelta::FromSecondsD(13.1).InSeconds());
+  EXPECT_EQ(13.1, TimeDelta::FromSecondsD(13.1).InSecondsF());
+  EXPECT_EQ(13, TimeDelta::FromMillisecondsD(13.3).InMilliseconds());
+  EXPECT_EQ(13.3, TimeDelta::FromMillisecondsD(13.3).InMillisecondsF());
+  EXPECT_EQ(13, TimeDelta::FromMicroseconds(13).InMicroseconds());
+}
+
+#if defined(OS_POSIX)
+TEST(TimeDelta, TimeSpecConversion) {
+  struct timespec result = TimeDelta::FromSeconds(0).ToTimeSpec();
+  EXPECT_EQ(result.tv_sec, 0);
+  EXPECT_EQ(result.tv_nsec, 0);
+
+  result = TimeDelta::FromSeconds(1).ToTimeSpec();
+  EXPECT_EQ(result.tv_sec, 1);
+  EXPECT_EQ(result.tv_nsec, 0);
+
+  result = TimeDelta::FromMicroseconds(1).ToTimeSpec();
+  EXPECT_EQ(result.tv_sec, 0);
+  EXPECT_EQ(result.tv_nsec, 1000);
+
+  result = TimeDelta::FromMicroseconds(
+      Time::kMicrosecondsPerSecond + 1).ToTimeSpec();
+  EXPECT_EQ(result.tv_sec, 1);
+  EXPECT_EQ(result.tv_nsec, 1000);
+}
+#endif  // OS_POSIX
+
+// Our internal time format is serialized in things like databases, so it's
+// important that it's consistent across all our platforms.  We use the 1601
+// Windows epoch as the internal format across all platforms.
+TEST(TimeDelta, WindowsEpoch) {
+  Time::Exploded exploded;
+  exploded.year = 1970;
+  exploded.month = 1;
+  exploded.day_of_week = 0;  // Should be unusued.
+  exploded.day_of_month = 1;
+  exploded.hour = 0;
+  exploded.minute = 0;
+  exploded.second = 0;
+  exploded.millisecond = 0;
+  Time t = Time::FromUTCExploded(exploded);
+  // Unix 1970 epoch.
+  EXPECT_EQ(INT64_C(11644473600000000), t.ToInternalValue());
+
+  // We can't test 1601 epoch, since the system time functions on Linux
+  // only compute years starting from 1900.
+}
+
+// We could define this separately for Time, TimeTicks and TimeDelta but the
+// definitions would be identical anyway.
+template <class Any>
+std::string AnyToString(Any any) {
+  std::ostringstream oss;
+  oss << any;
+  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(TimeDelta, NumericOperators) {
+  double d = 0.5;
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            TimeDelta::FromMilliseconds(1000) * d);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            TimeDelta::FromMilliseconds(1000) / d);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            TimeDelta::FromMilliseconds(1000) *= d);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            TimeDelta::FromMilliseconds(1000) /= d);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            d * TimeDelta::FromMilliseconds(1000));
+
+  float f = 0.5;
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            TimeDelta::FromMilliseconds(1000) * f);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            TimeDelta::FromMilliseconds(1000) / f);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            TimeDelta::FromMilliseconds(1000) *= f);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            TimeDelta::FromMilliseconds(1000) /= f);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            f * TimeDelta::FromMilliseconds(1000));
+
+
+  int i = 2;
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            TimeDelta::FromMilliseconds(1000) * i);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            TimeDelta::FromMilliseconds(1000) / i);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            TimeDelta::FromMilliseconds(1000) *= i);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            TimeDelta::FromMilliseconds(1000) /= i);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            i * TimeDelta::FromMilliseconds(1000));
+
+  int64_t i64 = 2;
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            TimeDelta::FromMilliseconds(1000) * i64);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            TimeDelta::FromMilliseconds(1000) / i64);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            TimeDelta::FromMilliseconds(1000) *= i64);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            TimeDelta::FromMilliseconds(1000) /= i64);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            i64 * TimeDelta::FromMilliseconds(1000));
+
+
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            TimeDelta::FromMilliseconds(1000) * 0.5);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            TimeDelta::FromMilliseconds(1000) / 0.5);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            TimeDelta::FromMilliseconds(1000) *= 0.5);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            TimeDelta::FromMilliseconds(1000) /= 0.5);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            0.5 * TimeDelta::FromMilliseconds(1000));
+
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            TimeDelta::FromMilliseconds(1000) * 2);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            TimeDelta::FromMilliseconds(1000) / 2);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            TimeDelta::FromMilliseconds(1000) *= 2);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+            TimeDelta::FromMilliseconds(1000) /= 2);
+  EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+            2 * TimeDelta::FromMilliseconds(1000));
+}
+
+bool IsMin(TimeDelta delta) {
+  return (-delta).is_max();
+}
+
+TEST(TimeDelta, Overflows) {
+  // Some sanity checks.
+  EXPECT_TRUE(TimeDelta::Max().is_max());
+  EXPECT_TRUE(IsMin(-TimeDelta::Max()));
+  EXPECT_GT(TimeDelta(), -TimeDelta::Max());
+
+  TimeDelta large_delta = TimeDelta::Max() - TimeDelta::FromMilliseconds(1);
+  TimeDelta large_negative = -large_delta;
+  EXPECT_GT(TimeDelta(), large_negative);
+  EXPECT_FALSE(large_delta.is_max());
+  EXPECT_FALSE(IsMin(-large_negative));
+  TimeDelta one_second = TimeDelta::FromSeconds(1);
+
+  // Test +, -, * and / operators.
+  EXPECT_TRUE((large_delta + one_second).is_max());
+  EXPECT_TRUE(IsMin(large_negative + (-one_second)));
+  EXPECT_TRUE(IsMin(large_negative - one_second));
+  EXPECT_TRUE((large_delta - (-one_second)).is_max());
+  EXPECT_TRUE((large_delta * 2).is_max());
+  EXPECT_TRUE(IsMin(large_delta * -2));
+  EXPECT_TRUE((large_delta / 0.5).is_max());
+  EXPECT_TRUE(IsMin(large_delta / -0.5));
+
+  // Test +=, -=, *= and /= operators.
+  TimeDelta delta = large_delta;
+  delta += one_second;
+  EXPECT_TRUE(delta.is_max());
+  delta = large_negative;
+  delta += -one_second;
+  EXPECT_TRUE(IsMin(delta));
+
+  delta = large_negative;
+  delta -= one_second;
+  EXPECT_TRUE(IsMin(delta));
+  delta = large_delta;
+  delta -= -one_second;
+  EXPECT_TRUE(delta.is_max());
+
+  delta = large_delta;
+  delta *= 2;
+  EXPECT_TRUE(delta.is_max());
+  delta = large_negative;
+  delta *= 1.5;
+  EXPECT_TRUE(IsMin(delta));
+
+  delta = large_delta;
+  delta /= 0.5;
+  EXPECT_TRUE(delta.is_max());
+  delta = large_negative;
+  delta /= 0.5;
+  EXPECT_TRUE(IsMin(delta));
+
+  // Test operations with Time and TimeTicks.
+  EXPECT_TRUE((large_delta + Time::Now()).is_max());
+  EXPECT_TRUE((large_delta + TimeTicks::Now()).is_max());
+  EXPECT_TRUE((Time::Now() + large_delta).is_max());
+  EXPECT_TRUE((TimeTicks::Now() + large_delta).is_max());
+
+  Time time_now = Time::Now();
+  EXPECT_EQ(one_second, (time_now + one_second) - time_now);
+  EXPECT_EQ(-one_second, (time_now - one_second) - time_now);
+
+  TimeTicks ticks_now = TimeTicks::Now();
+  EXPECT_EQ(-one_second, (ticks_now - one_second) - ticks_now);
+  EXPECT_EQ(one_second, (ticks_now + one_second) - ticks_now);
+}
+
+TEST(TimeDeltaLogging, DCheckEqCompiles) {
+  DCHECK_EQ(TimeDelta(), TimeDelta());
+}
+
+TEST(TimeDeltaLogging, EmptyIsZero) {
+  TimeDelta zero;
+  EXPECT_EQ("0s", AnyToString(zero));
+}
+
+TEST(TimeDeltaLogging, FiveHundredMs) {
+  TimeDelta five_hundred_ms = TimeDelta::FromMilliseconds(500);
+  EXPECT_EQ("0.5s", AnyToString(five_hundred_ms));
+}
+
+TEST(TimeDeltaLogging, MinusTenSeconds) {
+  TimeDelta minus_ten_seconds = TimeDelta::FromSeconds(-10);
+  EXPECT_EQ("-10s", AnyToString(minus_ten_seconds));
+}
+
+TEST(TimeDeltaLogging, DoesNotMessUpFormattingFlags) {
+  std::ostringstream oss;
+  std::ios_base::fmtflags flags_before = oss.flags();
+  oss << TimeDelta();
+  EXPECT_EQ(flags_before, oss.flags());
+}
+
+TEST(TimeDeltaLogging, DoesNotMakeStreamBad) {
+  std::ostringstream oss;
+  oss << TimeDelta();
+  EXPECT_TRUE(oss.good());
+}
+
+TEST(TimeLogging, DCheckEqCompiles) {
+  DCHECK_EQ(Time(), Time());
+}
+
+TEST(TimeLogging, ChromeBirthdate) {
+  Time birthdate;
+  ASSERT_TRUE(Time::FromString("Tue, 02 Sep 2008 09:42:18 GMT", &birthdate));
+  EXPECT_EQ("2008-09-02 09:42:18.000 UTC", AnyToString(birthdate));
+}
+
+TEST(TimeLogging, DoesNotMessUpFormattingFlags) {
+  std::ostringstream oss;
+  std::ios_base::fmtflags flags_before = oss.flags();
+  oss << Time();
+  EXPECT_EQ(flags_before, oss.flags());
+}
+
+TEST(TimeLogging, DoesNotMakeStreamBad) {
+  std::ostringstream oss;
+  oss << Time();
+  EXPECT_TRUE(oss.good());
+}
+
+TEST(TimeTicksLogging, DCheckEqCompiles) {
+  DCHECK_EQ(TimeTicks(), TimeTicks());
+}
+
+TEST(TimeTicksLogging, ZeroTime) {
+  TimeTicks zero;
+  EXPECT_EQ("0 bogo-microseconds", AnyToString(zero));
+}
+
+TEST(TimeTicksLogging, FortyYearsLater) {
+  TimeTicks forty_years_later =
+      TimeTicks() + TimeDelta::FromDays(365.25 * 40);
+  EXPECT_EQ("1262304000000000 bogo-microseconds",
+            AnyToString(forty_years_later));
+}
+
+TEST(TimeTicksLogging, DoesNotMessUpFormattingFlags) {
+  std::ostringstream oss;
+  std::ios_base::fmtflags flags_before = oss.flags();
+  oss << TimeTicks();
+  EXPECT_EQ(flags_before, oss.flags());
+}
+
+TEST(TimeTicksLogging, DoesNotMakeStreamBad) {
+  std::ostringstream oss;
+  oss << TimeTicks();
+  EXPECT_TRUE(oss.good());
+}
+
+}  // namespace
+
+}  // namespace base
diff --git a/base/time/time_win.cc b/base/time/time_win.cc
new file mode 100644
index 0000000..9144483
--- /dev/null
+++ b/base/time/time_win.cc
@@ -0,0 +1,530 @@
+// Copyright (c) 2012 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.
+
+
+// Windows Timer Primer
+//
+// A good article:  http://www.ddj.com/windows/184416651
+// A good mozilla bug:  http://bugzilla.mozilla.org/show_bug.cgi?id=363258
+//
+// The default windows timer, GetSystemTimeAsFileTime is not very precise.
+// It is only good to ~15.5ms.
+//
+// QueryPerformanceCounter is the logical choice for a high-precision timer.
+// However, it is known to be buggy on some hardware.  Specifically, it can
+// sometimes "jump".  On laptops, QPC can also be very expensive to call.
+// It's 3-4x slower than timeGetTime() on desktops, but can be 10x slower
+// on laptops.  A unittest exists which will show the relative cost of various
+// timers on any system.
+//
+// The next logical choice is timeGetTime().  timeGetTime has a precision of
+// 1ms, but only if you call APIs (timeBeginPeriod()) which affect all other
+// applications on the system.  By default, precision is only 15.5ms.
+// Unfortunately, we don't want to call timeBeginPeriod because we don't
+// want to affect other applications.  Further, on mobile platforms, use of
+// faster multimedia timers can hurt battery life.  See the intel
+// article about this here:
+// http://softwarecommunity.intel.com/articles/eng/1086.htm
+//
+// To work around all this, we're going to generally use timeGetTime().  We
+// will only increase the system-wide timer if we're not running on battery
+// power.
+
+#include "base/time/time.h"
+
+#pragma comment(lib, "winmm.lib")
+#include <windows.h>
+#include <mmsystem.h>
+#include <stdint.h>
+
+#include "base/basictypes.h"
+#include "base/cpu.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/synchronization/lock.h"
+
+using base::ThreadTicks;
+using base::Time;
+using base::TimeDelta;
+using base::TimeTicks;
+using base::TraceTicks;
+
+namespace {
+
+// From MSDN, FILETIME "Contains a 64-bit value representing the number of
+// 100-nanosecond intervals since January 1, 1601 (UTC)."
+int64 FileTimeToMicroseconds(const FILETIME& ft) {
+  // Need to bit_cast to fix alignment, then divide by 10 to convert
+  // 100-nanoseconds to milliseconds. This only works on little-endian
+  // machines.
+  return bit_cast<int64, FILETIME>(ft) / 10;
+}
+
+void MicrosecondsToFileTime(int64 us, FILETIME* ft) {
+  DCHECK_GE(us, 0LL) << "Time is less than 0, negative values are not "
+      "representable in FILETIME";
+
+  // Multiply by 10 to convert milliseconds to 100-nanoseconds. Bit_cast will
+  // handle alignment problems. This only works on little-endian machines.
+  *ft = bit_cast<FILETIME, int64>(us * 10);
+}
+
+int64 CurrentWallclockMicroseconds() {
+  FILETIME ft;
+  ::GetSystemTimeAsFileTime(&ft);
+  return FileTimeToMicroseconds(ft);
+}
+
+// Time between resampling the un-granular clock for this API.  60 seconds.
+const int kMaxMillisecondsToAvoidDrift = 60 * Time::kMillisecondsPerSecond;
+
+int64 initial_time = 0;
+TimeTicks initial_ticks;
+
+void InitializeClock() {
+  initial_ticks = TimeTicks::Now();
+  initial_time = CurrentWallclockMicroseconds();
+}
+
+// The two values that ActivateHighResolutionTimer uses to set the systemwide
+// timer interrupt frequency on Windows. It controls how precise timers are
+// but also has a big impact on battery life.
+const int kMinTimerIntervalHighResMs = 1;
+const int kMinTimerIntervalLowResMs = 4;
+// Track if kMinTimerIntervalHighResMs or kMinTimerIntervalLowResMs is active.
+bool g_high_res_timer_enabled = false;
+// How many times the high resolution timer has been called.
+uint32_t g_high_res_timer_count = 0;
+// The lock to control access to the above two variables.
+base::LazyInstance<base::Lock>::Leaky g_high_res_lock =
+    LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+// Time -----------------------------------------------------------------------
+
+// The internal representation of Time uses FILETIME, whose epoch is 1601-01-01
+// 00:00:00 UTC.  ((1970-1601)*365+89)*24*60*60*1000*1000, where 89 is the
+// number of leap year days between 1601 and 1970: (1970-1601)/4 excluding
+// 1700, 1800, and 1900.
+// static
+const int64 Time::kTimeTToMicrosecondsOffset = INT64_C(11644473600000000);
+
+// static
+Time Time::Now() {
+  if (initial_time == 0)
+    InitializeClock();
+
+  // We implement time using the high-resolution timers so that we can get
+  // timeouts which are smaller than 10-15ms.  If we just used
+  // CurrentWallclockMicroseconds(), we'd have the less-granular timer.
+  //
+  // To make this work, we initialize the clock (initial_time) and the
+  // counter (initial_ctr).  To compute the initial time, we can check
+  // the number of ticks that have elapsed, and compute the delta.
+  //
+  // To avoid any drift, we periodically resync the counters to the system
+  // clock.
+  while (true) {
+    TimeTicks ticks = TimeTicks::Now();
+
+    // Calculate the time elapsed since we started our timer
+    TimeDelta elapsed = ticks - initial_ticks;
+
+    // Check if enough time has elapsed that we need to resync the clock.
+    if (elapsed.InMilliseconds() > kMaxMillisecondsToAvoidDrift) {
+      InitializeClock();
+      continue;
+    }
+
+    return Time(elapsed + Time(initial_time));
+  }
+}
+
+// static
+Time Time::NowFromSystemTime() {
+  // Force resync.
+  InitializeClock();
+  return Time(initial_time);
+}
+
+// static
+Time Time::FromFileTime(FILETIME ft) {
+  if (bit_cast<int64, FILETIME>(ft) == 0)
+    return Time();
+  if (ft.dwHighDateTime == std::numeric_limits<DWORD>::max() &&
+      ft.dwLowDateTime == std::numeric_limits<DWORD>::max())
+    return Max();
+  return Time(FileTimeToMicroseconds(ft));
+}
+
+FILETIME Time::ToFileTime() const {
+  if (is_null())
+    return bit_cast<FILETIME, int64>(0);
+  if (is_max()) {
+    FILETIME result;
+    result.dwHighDateTime = std::numeric_limits<DWORD>::max();
+    result.dwLowDateTime = std::numeric_limits<DWORD>::max();
+    return result;
+  }
+  FILETIME utc_ft;
+  MicrosecondsToFileTime(us_, &utc_ft);
+  return utc_ft;
+}
+
+// static
+void Time::EnableHighResolutionTimer(bool enable) {
+  base::AutoLock lock(g_high_res_lock.Get());
+  if (g_high_res_timer_enabled == enable)
+    return;
+  g_high_res_timer_enabled = enable;
+  if (!g_high_res_timer_count)
+    return;
+  // Since g_high_res_timer_count != 0, an ActivateHighResolutionTimer(true)
+  // was called which called timeBeginPeriod with g_high_res_timer_enabled
+  // with a value which is the opposite of |enable|. With that information we
+  // call timeEndPeriod with the same value used in timeBeginPeriod and
+  // therefore undo the period effect.
+  if (enable) {
+    timeEndPeriod(kMinTimerIntervalLowResMs);
+    timeBeginPeriod(kMinTimerIntervalHighResMs);
+  } else {
+    timeEndPeriod(kMinTimerIntervalHighResMs);
+    timeBeginPeriod(kMinTimerIntervalLowResMs);
+  }
+}
+
+// static
+bool Time::ActivateHighResolutionTimer(bool activating) {
+  // We only do work on the transition from zero to one or one to zero so we
+  // can easily undo the effect (if necessary) when EnableHighResolutionTimer is
+  // called.
+  const uint32_t max = std::numeric_limits<uint32_t>::max();
+
+  base::AutoLock lock(g_high_res_lock.Get());
+  UINT period = g_high_res_timer_enabled ? kMinTimerIntervalHighResMs
+                                         : kMinTimerIntervalLowResMs;
+  if (activating) {
+    DCHECK_NE(g_high_res_timer_count, max);
+    ++g_high_res_timer_count;
+    if (g_high_res_timer_count == 1)
+      timeBeginPeriod(period);
+  } else {
+    DCHECK_NE(g_high_res_timer_count, 0u);
+    --g_high_res_timer_count;
+    if (g_high_res_timer_count == 0)
+      timeEndPeriod(period);
+  }
+  return (period == kMinTimerIntervalHighResMs);
+}
+
+// static
+bool Time::IsHighResolutionTimerInUse() {
+  base::AutoLock lock(g_high_res_lock.Get());
+  return g_high_res_timer_enabled && g_high_res_timer_count > 0;
+}
+
+// static
+Time Time::FromExploded(bool is_local, const Exploded& exploded) {
+  // Create the system struct representing our exploded time. It will either be
+  // in local time or UTC.
+  SYSTEMTIME st;
+  st.wYear = static_cast<WORD>(exploded.year);
+  st.wMonth = static_cast<WORD>(exploded.month);
+  st.wDayOfWeek = static_cast<WORD>(exploded.day_of_week);
+  st.wDay = static_cast<WORD>(exploded.day_of_month);
+  st.wHour = static_cast<WORD>(exploded.hour);
+  st.wMinute = static_cast<WORD>(exploded.minute);
+  st.wSecond = static_cast<WORD>(exploded.second);
+  st.wMilliseconds = static_cast<WORD>(exploded.millisecond);
+
+  FILETIME ft;
+  bool success = true;
+  // Ensure that it's in UTC.
+  if (is_local) {
+    SYSTEMTIME utc_st;
+    success = TzSpecificLocalTimeToSystemTime(NULL, &st, &utc_st) &&
+              SystemTimeToFileTime(&utc_st, &ft);
+  } else {
+    success = !!SystemTimeToFileTime(&st, &ft);
+  }
+
+  if (!success) {
+    NOTREACHED() << "Unable to convert time";
+    return Time(0);
+  }
+  return Time(FileTimeToMicroseconds(ft));
+}
+
+void Time::Explode(bool is_local, Exploded* exploded) const {
+  if (us_ < 0LL) {
+    // We are not able to convert it to FILETIME.
+    ZeroMemory(exploded, sizeof(*exploded));
+    return;
+  }
+
+  // FILETIME in UTC.
+  FILETIME utc_ft;
+  MicrosecondsToFileTime(us_, &utc_ft);
+
+  // FILETIME in local time if necessary.
+  bool success = true;
+  // FILETIME in SYSTEMTIME (exploded).
+  SYSTEMTIME st = {0};
+  if (is_local) {
+    SYSTEMTIME utc_st;
+    // We don't use FileTimeToLocalFileTime here, since it uses the current
+    // settings for the time zone and daylight saving time. Therefore, if it is
+    // daylight saving time, it will take daylight saving time into account,
+    // even if the time you are converting is in standard time.
+    success = FileTimeToSystemTime(&utc_ft, &utc_st) &&
+              SystemTimeToTzSpecificLocalTime(NULL, &utc_st, &st);
+  } else {
+    success = !!FileTimeToSystemTime(&utc_ft, &st);
+  }
+
+  if (!success) {
+    NOTREACHED() << "Unable to convert time, don't know why";
+    ZeroMemory(exploded, sizeof(*exploded));
+    return;
+  }
+
+  exploded->year = st.wYear;
+  exploded->month = st.wMonth;
+  exploded->day_of_week = st.wDayOfWeek;
+  exploded->day_of_month = st.wDay;
+  exploded->hour = st.wHour;
+  exploded->minute = st.wMinute;
+  exploded->second = st.wSecond;
+  exploded->millisecond = st.wMilliseconds;
+}
+
+// TimeTicks ------------------------------------------------------------------
+namespace {
+
+// We define a wrapper to adapt between the __stdcall and __cdecl call of the
+// mock function, and to avoid a static constructor.  Assigning an import to a
+// function pointer directly would require setup code to fetch from the IAT.
+DWORD timeGetTimeWrapper() {
+  return timeGetTime();
+}
+
+DWORD (*g_tick_function)(void) = &timeGetTimeWrapper;
+
+// Accumulation of time lost due to rollover (in milliseconds).
+int64 g_rollover_ms = 0;
+
+// The last timeGetTime value we saw, to detect rollover.
+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
+// code is low-level, and we don't want to use Singletons here (it would be too
+// 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 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(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 = g_tick_function();
+  if (now < g_last_seen_now)
+    g_rollover_ms += 0x100000000I64;  // ~49.7 days.
+  g_last_seen_now = now;
+  return TimeDelta::FromMilliseconds(now + g_rollover_ms);
+}
+
+// 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, 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 (<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 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 (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.
+
+using NowFunction = TimeDelta (*)(void);
+
+TimeDelta InitialNowFunction();
+TimeDelta InitialSystemTraceNowFunction();
+
+// 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);
+  }
+  // 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 QPCNow() {
+  LARGE_INTEGER now;
+  QueryPerformanceCounter(&now);
+  return QPCValueToTimeDelta(now.QuadPart);
+}
+
+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;
+}
+
+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 TimeTicks::Now() and
+  // TraceTicks::Now() must use the low-resolution clock.
+  //
+  // If the QPC implementation is expensive and/or unreliable, TimeTicks::Now()
+  // will use the low-resolution clock, but TraceTicks::Now() 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 (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;
+  }
+
+  // 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() {
+  InitializeNowFunctionPointers();
+  return g_now_function();
+}
+
+TimeDelta InitialSystemTraceNowFunction() {
+  InitializeNowFunctionPointers();
+  return g_system_trace_now_function();
+}
+
+}  // namespace
+
+// static
+TimeTicks::TickFunctionType TimeTicks::SetMockTickFunction(
+    TickFunctionType ticker) {
+  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() + g_now_function();
+}
+
+// static
+bool TimeTicks::IsHighResolution() {
+  if (g_now_function == &InitialNowFunction)
+    InitializeNowFunctionPointers();
+  return g_now_function == &QPCNow;
+}
+
+// static
+ThreadTicks ThreadTicks::Now() {
+  NOTREACHED();
+  return ThreadTicks();
+}
+
+// static
+TraceTicks TraceTicks::Now() {
+  return TraceTicks() + g_system_trace_now_function();
+}
+
+// static
+TimeTicks TimeTicks::FromQPCValue(LONGLONG qpc_value) {
+  return TimeTicks() + QPCValueToTimeDelta(qpc_value);
+}
+
+// TimeDelta ------------------------------------------------------------------
+
+// static
+TimeDelta TimeDelta::FromQPCValue(LONGLONG qpc_value) {
+  return QPCValueToTimeDelta(qpc_value);
+}
diff --git a/base/time/time_win_unittest.cc b/base/time/time_win_unittest.cc
new file mode 100644
index 0000000..75b237e
--- /dev/null
+++ b/base/time/time_win_unittest.cc
@@ -0,0 +1,268 @@
+// Copyright (c) 2012 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 <windows.h>
+#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"
+
+using base::Time;
+using base::TimeDelta;
+using base::TimeTicks;
+using base::TraceTicks;
+
+namespace {
+
+class MockTimeTicks : public TimeTicks {
+ public:
+  static DWORD Ticker() {
+    return static_cast<int>(InterlockedIncrement(&ticker_));
+  }
+
+  static void InstallTicker() {
+    old_tick_function_ = SetMockTickFunction(&Ticker);
+    ticker_ = -5;
+  }
+
+  static void UninstallTicker() {
+    SetMockTickFunction(old_tick_function_);
+  }
+
+ private:
+  static volatile LONG ticker_;
+  static TickFunctionType old_tick_function_;
+};
+
+volatile LONG MockTimeTicks::ticker_;
+MockTimeTicks::TickFunctionType MockTimeTicks::old_tick_function_;
+
+HANDLE g_rollover_test_start;
+
+unsigned __stdcall RolloverTestThreadMain(void* param) {
+  int64 counter = reinterpret_cast<int64>(param);
+  DWORD rv = WaitForSingleObject(g_rollover_test_start, INFINITE);
+  EXPECT_EQ(rv, WAIT_OBJECT_0);
+
+  TimeTicks last = TimeTicks::Now();
+  for (int index = 0; index < counter; index++) {
+    TimeTicks now = TimeTicks::Now();
+    int64 milliseconds = (now - last).InMilliseconds();
+    // This is a tight loop; we could have looped faster than our
+    // measurements, so the time might be 0 millis.
+    EXPECT_GE(milliseconds, 0);
+    EXPECT_LT(milliseconds, 250);
+    last = now;
+  }
+  return 0;
+}
+
+}  // namespace
+
+TEST(TimeTicks, WinRollover) {
+  // The internal counter rolls over at ~49days.  We'll use a mock
+  // timer to test this case.
+  // Basic test algorithm:
+  //   1) Set clock to rollover - N
+  //   2) Create N threads
+  //   3) Start the threads
+  //   4) Each thread loops through TimeTicks() N times
+  //   5) Each thread verifies integrity of result.
+
+  const int kThreads = 8;
+  // Use int64 so we can cast into a void* without a compiler warning.
+  const int64 kChecks = 10;
+
+  // It takes a lot of iterations to reproduce the bug!
+  // (See bug 1081395)
+  for (int loop = 0; loop < 4096; loop++) {
+    // Setup
+    MockTimeTicks::InstallTicker();
+    g_rollover_test_start = CreateEvent(0, TRUE, FALSE, 0);
+    HANDLE threads[kThreads];
+
+    for (int index = 0; index < kThreads; index++) {
+      void* argument = reinterpret_cast<void*>(kChecks);
+      unsigned thread_id;
+      threads[index] = reinterpret_cast<HANDLE>(
+        _beginthreadex(NULL, 0, RolloverTestThreadMain, argument, 0,
+          &thread_id));
+      EXPECT_NE((HANDLE)NULL, threads[index]);
+    }
+
+    // Start!
+    SetEvent(g_rollover_test_start);
+
+    // Wait for threads to finish
+    for (int index = 0; index < kThreads; index++) {
+      DWORD rv = WaitForSingleObject(threads[index], INFINITE);
+      EXPECT_EQ(rv, WAIT_OBJECT_0);
+      // Since using _beginthreadex() (as opposed to _beginthread),
+      // an explicit CloseHandle() is supposed to be called.
+      CloseHandle(threads[index]);
+    }
+
+    CloseHandle(g_rollover_test_start);
+
+    // Teardown
+    MockTimeTicks::UninstallTicker();
+  }
+}
+
+TEST(TimeTicks, SubMillisecondTimers) {
+  // IsHighResolution() is false on some systems.  Since the product still works
+  // even if it's false, it makes this entire test questionable.
+  if (!TimeTicks::IsHighResolution())
+    return;
+
+  const int kRetries = 1000;
+  bool saw_submillisecond_timer = false;
+
+  // Run kRetries attempts to see a sub-millisecond timer.
+  for (int index = 0; index < kRetries; index++) {
+    TimeTicks last_time = TimeTicks::Now();
+    TimeDelta delta;
+    // Spin until the clock has detected a change.
+    do {
+      delta = TimeTicks::Now() - last_time;
+    } while (delta.InMicroseconds() == 0);
+    if (delta.InMicroseconds() < 1000) {
+      saw_submillisecond_timer = true;
+      break;
+    }
+  }
+  EXPECT_TRUE(saw_submillisecond_timer);
+}
+
+TEST(TimeTicks, TimeGetTimeCaps) {
+  // Test some basic assumptions that we expect about how timeGetDevCaps works.
+
+  TIMECAPS caps;
+  MMRESULT status = timeGetDevCaps(&caps, sizeof(caps));
+  EXPECT_EQ(TIMERR_NOERROR, status);
+  if (status != TIMERR_NOERROR) {
+    printf("Could not get timeGetDevCaps\n");
+    return;
+  }
+
+  EXPECT_GE(static_cast<int>(caps.wPeriodMin), 1);
+  EXPECT_GT(static_cast<int>(caps.wPeriodMax), 1);
+  EXPECT_GE(static_cast<int>(caps.wPeriodMin), 1);
+  EXPECT_GT(static_cast<int>(caps.wPeriodMax), 1);
+  printf("timeGetTime range is %d to %dms\n", caps.wPeriodMin,
+    caps.wPeriodMax);
+}
+
+TEST(TimeTicks, QueryPerformanceFrequency) {
+  // Test some basic assumptions that we expect about QPC.
+
+  LARGE_INTEGER frequency;
+  BOOL rv = QueryPerformanceFrequency(&frequency);
+  EXPECT_EQ(TRUE, rv);
+  EXPECT_GT(frequency.QuadPart, 1000000);  // Expect at least 1MHz
+  printf("QueryPerformanceFrequency is %5.2fMHz\n",
+    frequency.QuadPart / 1000000.0);
+}
+
+TEST(TimeTicks, TimerPerformance) {
+  // Verify that various timer mechanisms can always complete quickly.
+  // Note:  This is a somewhat arbitrary test.
+  const int kLoops = 10000;
+
+  typedef TimeTicks (*TestFunc)();
+  struct TestCase {
+    TestFunc func;
+    const char *description;
+  };
+  // Cheating a bit here:  assumes sizeof(TimeTicks) == sizeof(Time)
+  // in order to create a single test case list.
+  COMPILE_ASSERT(sizeof(TimeTicks) == sizeof(Time),
+                 test_only_works_with_same_sizes);
+  TestCase cases[] = {
+    { reinterpret_cast<TestFunc>(&Time::Now), "Time::Now" },
+    { &TimeTicks::Now, "TimeTicks::Now" },
+    { reinterpret_cast<TestFunc>(&TraceTicks::Now), "TraceTicks::Now" },
+    { NULL, "" }
+  };
+
+  int test_case = 0;
+  while (cases[test_case].func) {
+    TimeTicks start = TimeTicks::Now();
+    for (int index = 0; index < kLoops; index++)
+      cases[test_case].func();
+    TimeTicks stop = TimeTicks::Now();
+    // Turning off the check for acceptible delays.  Without this check,
+    // the test really doesn't do much other than measure.  But the
+    // measurements are still useful for testing timers on various platforms.
+    // The reason to remove the check is because the tests run on many
+    // buildbots, some of which are VMs.  These machines can run horribly
+    // slow, and there is really no value for checking against a max timer.
+    //const int kMaxTime = 35;  // Maximum acceptible milliseconds for test.
+    //EXPECT_LT((stop - start).InMilliseconds(), kMaxTime);
+    printf("%s: %1.2fus per call\n", cases[test_case].description,
+      (stop - start).InMillisecondsF() * 1000 / kLoops);
+    test_case++;
+  }
+}
+
+TEST(TimeTicks, FromQPCValue) {
+  if (!TimeTicks::IsHighResolution())
+    return;
+
+  LARGE_INTEGER frequency;
+  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/base/timer/elapsed_timer.cc b/base/timer/elapsed_timer.cc
new file mode 100644
index 0000000..f2a2f71
--- /dev/null
+++ b/base/timer/elapsed_timer.cc
@@ -0,0 +1,17 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/timer/elapsed_timer.h"
+
+namespace base {
+
+ElapsedTimer::ElapsedTimer() {
+  begin_ = TimeTicks::Now();
+}
+
+TimeDelta ElapsedTimer::Elapsed() const {
+  return TimeTicks::Now() - begin_;
+}
+
+}  // namespace base
diff --git a/base/timer/elapsed_timer.h b/base/timer/elapsed_timer.h
new file mode 100644
index 0000000..592858a
--- /dev/null
+++ b/base/timer/elapsed_timer.h
@@ -0,0 +1,30 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TIMER_ELAPSED_TIMER_H_
+#define BASE_TIMER_ELAPSED_TIMER_H_
+
+#include "base/base_export.h"
+#include "base/macros.h"
+#include "base/time/time.h"
+
+namespace base {
+
+// A simple wrapper around TimeTicks::Now().
+class BASE_EXPORT ElapsedTimer {
+ public:
+  ElapsedTimer();
+
+  // Returns the time elapsed since object construction.
+  TimeDelta Elapsed() const;
+
+ private:
+  TimeTicks begin_;
+
+  DISALLOW_COPY_AND_ASSIGN(ElapsedTimer);
+};
+
+}  // namespace base
+
+#endif  // BASE_TIMER_ELAPSED_TIMER_H_
diff --git a/base/timer/hi_res_timer_manager.h b/base/timer/hi_res_timer_manager.h
new file mode 100644
index 0000000..ed0e1e0
--- /dev/null
+++ b/base/timer/hi_res_timer_manager.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2011 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_TIMER_HI_RES_TIMER_MANAGER_H_
+#define BASE_TIMER_HI_RES_TIMER_MANAGER_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/power_monitor/power_observer.h"
+
+namespace base {
+
+// Ensures that the Windows high resolution timer is only used
+// when not running on battery power.
+class BASE_EXPORT HighResolutionTimerManager : public base::PowerObserver {
+ public:
+  HighResolutionTimerManager();
+  ~HighResolutionTimerManager() override;
+
+  // base::PowerObserver method.
+  void OnPowerStateChange(bool on_battery_power) override;
+
+  // Returns true if the hi resolution clock could be used right now.
+  bool hi_res_clock_available() const { return hi_res_clock_available_; }
+
+ private:
+  // Enable or disable the faster multimedia timer.
+  void UseHiResClock(bool use);
+
+  bool hi_res_clock_available_;
+
+  DISALLOW_COPY_AND_ASSIGN(HighResolutionTimerManager);
+};
+
+}  // namespace base
+
+#endif  // BASE_TIMER_HI_RES_TIMER_MANAGER_H_
diff --git a/base/timer/hi_res_timer_manager_posix.cc b/base/timer/hi_res_timer_manager_posix.cc
new file mode 100644
index 0000000..d2f152c
--- /dev/null
+++ b/base/timer/hi_res_timer_manager_posix.cc
@@ -0,0 +1,24 @@
+// Copyright (c) 2011 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/timer/hi_res_timer_manager.h"
+
+// On POSIX we don't need to do anything special with the system timer.
+
+namespace base {
+
+HighResolutionTimerManager::HighResolutionTimerManager()
+    : hi_res_clock_available_(false) {
+}
+
+HighResolutionTimerManager::~HighResolutionTimerManager() {
+}
+
+void HighResolutionTimerManager::OnPowerStateChange(bool on_battery_power) {
+}
+
+void HighResolutionTimerManager::UseHiResClock(bool use) {
+}
+
+}  // namespace base
diff --git a/base/timer/hi_res_timer_manager_unittest.cc b/base/timer/hi_res_timer_manager_unittest.cc
new file mode 100644
index 0000000..5475a91
--- /dev/null
+++ b/base/timer/hi_res_timer_manager_unittest.cc
@@ -0,0 +1,58 @@
+// Copyright (c) 2012 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/timer/hi_res_timer_manager.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/power_monitor/power_monitor.h"
+#include "base/power_monitor/power_monitor_device_source.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+#if defined(OS_WIN)
+TEST(HiResTimerManagerTest, ToggleOnOff) {
+  // The power monitor creates Window to receive power notifications from
+  // Windows, which makes this test flaky if you run while the machine
+  // goes in or out of AC power.
+  base::MessageLoop loop(base::MessageLoop::TYPE_UI);
+  scoped_ptr<base::PowerMonitorSource> power_monitor_source(
+      new base::PowerMonitorDeviceSource());
+  scoped_ptr<base::PowerMonitor> power_monitor(
+      new base::PowerMonitor(power_monitor_source.Pass()));
+
+  HighResolutionTimerManager manager;
+  // Simulate a on-AC power event to get to a known initial state.
+  manager.OnPowerStateChange(false);
+
+  // Loop a few times to test power toggling.
+  for (int times = 0; times != 3; ++times) {
+    // The manager has the high resolution clock enabled now.
+    EXPECT_TRUE(manager.hi_res_clock_available());
+    // But the Time class has it off, because it hasn't been activated.
+    EXPECT_FALSE(base::Time::IsHighResolutionTimerInUse());
+
+    // Activate the high resolution timer.
+    base::Time::ActivateHighResolutionTimer(true);
+    EXPECT_TRUE(base::Time::IsHighResolutionTimerInUse());
+
+    // Simulate a on-battery power event.
+    manager.OnPowerStateChange(true);
+    EXPECT_FALSE(manager.hi_res_clock_available());
+    EXPECT_FALSE(base::Time::IsHighResolutionTimerInUse());
+
+    // Back to on-AC power.
+    manager.OnPowerStateChange(false);
+    EXPECT_TRUE(manager.hi_res_clock_available());
+    EXPECT_TRUE(base::Time::IsHighResolutionTimerInUse());
+
+    // De-activate the high resolution timer.
+    base::Time::ActivateHighResolutionTimer(false);
+  }
+}
+#endif  // defined(OS_WIN)
+
+}  // namespace base
diff --git a/base/timer/hi_res_timer_manager_win.cc b/base/timer/hi_res_timer_manager_win.cc
new file mode 100644
index 0000000..692f72b
--- /dev/null
+++ b/base/timer/hi_res_timer_manager_win.cc
@@ -0,0 +1,36 @@
+// Copyright (c) 2011 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/timer/hi_res_timer_manager.h"
+
+#include "base/power_monitor/power_monitor.h"
+#include "base/time/time.h"
+
+namespace base {
+
+HighResolutionTimerManager::HighResolutionTimerManager()
+    : hi_res_clock_available_(false) {
+  base::PowerMonitor* power_monitor = base::PowerMonitor::Get();
+  DCHECK(power_monitor != NULL);
+  power_monitor->AddObserver(this);
+  UseHiResClock(!power_monitor->IsOnBatteryPower());
+}
+
+HighResolutionTimerManager::~HighResolutionTimerManager() {
+  base::PowerMonitor::Get()->RemoveObserver(this);
+  UseHiResClock(false);
+}
+
+void HighResolutionTimerManager::OnPowerStateChange(bool on_battery_power) {
+  UseHiResClock(!on_battery_power);
+}
+
+void HighResolutionTimerManager::UseHiResClock(bool use) {
+  if (use == hi_res_clock_available_)
+    return;
+  hi_res_clock_available_ = use;
+  base::Time::EnableHighResolutionTimer(use);
+}
+
+}  // namespace base
diff --git a/base/timer/mock_timer.cc b/base/timer/mock_timer.cc
new file mode 100644
index 0000000..296071e
--- /dev/null
+++ b/base/timer/mock_timer.cc
@@ -0,0 +1,63 @@
+// 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.
+
+#include "base/timer/mock_timer.h"
+
+namespace base {
+
+MockTimer::MockTimer(bool retain_user_task, bool is_repeating)
+    : Timer(retain_user_task, is_repeating),
+      is_running_(false) {
+}
+
+MockTimer::MockTimer(const tracked_objects::Location& posted_from,
+                     TimeDelta delay,
+                     const base::Closure& user_task,
+                     bool is_repeating)
+    : Timer(true, is_repeating),
+      delay_(delay),
+      is_running_(false) {
+}
+
+MockTimer::~MockTimer() {
+}
+
+bool MockTimer::IsRunning() const {
+  return is_running_;
+}
+
+base::TimeDelta MockTimer::GetCurrentDelay() const {
+  return delay_;
+}
+
+void MockTimer::Start(const tracked_objects::Location& posted_from,
+                      TimeDelta delay,
+                      const base::Closure& user_task) {
+  delay_ = delay;
+  user_task_ = user_task;
+  Reset();
+}
+
+void MockTimer::Stop() {
+  is_running_ = false;
+  if (!retain_user_task())
+    user_task_.Reset();
+}
+
+void MockTimer::Reset() {
+  DCHECK(!user_task_.is_null());
+  is_running_ = true;
+}
+
+void MockTimer::Fire() {
+  DCHECK(is_running_);
+  base::Closure old_task = user_task_;
+  if (is_repeating())
+    Reset();
+  else
+    Stop();
+  old_task.Run();
+}
+
+}  // namespace base
diff --git a/base/timer/mock_timer.h b/base/timer/mock_timer.h
new file mode 100644
index 0000000..e18a5c0
--- /dev/null
+++ b/base/timer/mock_timer.h
@@ -0,0 +1,41 @@
+// 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.
+
+#ifndef BASE_TIMER_MOCK_TIMER_H_
+#define BASE_TIMER_MOCK_TIMER_H_
+
+#include "base/timer/timer.h"
+
+namespace base {
+
+class BASE_EXPORT MockTimer : public Timer {
+ public:
+  MockTimer(bool retain_user_task, bool is_repeating);
+  MockTimer(const tracked_objects::Location& posted_from,
+            TimeDelta delay,
+            const base::Closure& user_task,
+            bool is_repeating);
+  ~MockTimer() override;
+
+  // base::Timer implementation.
+  bool IsRunning() const override;
+  base::TimeDelta GetCurrentDelay() const override;
+  void Start(const tracked_objects::Location& posted_from,
+             base::TimeDelta delay,
+             const base::Closure& user_task) override;
+  void Stop() override;
+  void Reset() override;
+
+  // Testing methods.
+  void Fire();
+
+ private:
+  base::Closure user_task_;
+  TimeDelta delay_;
+  bool is_running_;
+};
+
+}  // namespace base
+
+#endif  // BASE_TIMER_MOCK_TIMER_H_
diff --git a/base/timer/mock_timer_unittest.cc b/base/timer/mock_timer_unittest.cc
new file mode 100644
index 0000000..f6b6953
--- /dev/null
+++ b/base/timer/mock_timer_unittest.cc
@@ -0,0 +1,82 @@
+// 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.
+
+#include "base/timer/mock_timer.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+void CallMeMaybe(int *number) {
+  (*number)++;
+}
+
+TEST(MockTimerTest, FiresOnce) {
+  int calls = 0;
+  base::MockTimer timer(false, false);
+  base::TimeDelta delay = base::TimeDelta::FromSeconds(2);
+  timer.Start(FROM_HERE, delay,
+              base::Bind(&CallMeMaybe,
+                         base::Unretained(&calls)));
+  EXPECT_EQ(delay, timer.GetCurrentDelay());
+  EXPECT_TRUE(timer.IsRunning());
+  timer.Fire();
+  EXPECT_FALSE(timer.IsRunning());
+  EXPECT_EQ(1, calls);
+}
+
+TEST(MockTimerTest, FiresRepeatedly) {
+  int calls = 0;
+  base::MockTimer timer(true, true);
+  base::TimeDelta delay = base::TimeDelta::FromSeconds(2);
+  timer.Start(FROM_HERE, delay,
+              base::Bind(&CallMeMaybe,
+                         base::Unretained(&calls)));
+  timer.Fire();
+  EXPECT_TRUE(timer.IsRunning());
+  timer.Fire();
+  timer.Fire();
+  EXPECT_TRUE(timer.IsRunning());
+  EXPECT_EQ(3, calls);
+}
+
+TEST(MockTimerTest, Stops) {
+  int calls = 0;
+  base::MockTimer timer(true, true);
+  base::TimeDelta delay = base::TimeDelta::FromSeconds(2);
+  timer.Start(FROM_HERE, delay,
+              base::Bind(&CallMeMaybe,
+                         base::Unretained(&calls)));
+  EXPECT_TRUE(timer.IsRunning());
+  timer.Stop();
+  EXPECT_FALSE(timer.IsRunning());
+}
+
+class HasWeakPtr : public base::SupportsWeakPtr<HasWeakPtr> {
+ public:
+  HasWeakPtr() {}
+  virtual ~HasWeakPtr() {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HasWeakPtr);
+};
+
+void DoNothingWithWeakPtr(HasWeakPtr* has_weak_ptr) {
+}
+
+TEST(MockTimerTest, DoesNotRetainClosure) {
+  HasWeakPtr *has_weak_ptr = new HasWeakPtr();
+  base::WeakPtr<HasWeakPtr> weak_ptr(has_weak_ptr->AsWeakPtr());
+  base::MockTimer timer(false, false);
+  base::TimeDelta delay = base::TimeDelta::FromSeconds(2);
+  ASSERT_TRUE(weak_ptr.get());
+  timer.Start(FROM_HERE, delay,
+              base::Bind(&DoNothingWithWeakPtr,
+                         base::Owned(has_weak_ptr)));
+  ASSERT_TRUE(weak_ptr.get());
+  timer.Fire();
+  ASSERT_FALSE(weak_ptr.get());
+}
+
+}  // namespace
diff --git a/base/timer/timer.cc b/base/timer/timer.cc
new file mode 100644
index 0000000..fa6b8cd
--- /dev/null
+++ b/base/timer/timer.cc
@@ -0,0 +1,218 @@
+// Copyright (c) 2012 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/timer/timer.h"
+
+#include <stddef.h>
+
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/single_thread_task_runner.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+// BaseTimerTaskInternal is a simple delegate for scheduling a callback to
+// Timer in the thread's default task runner. It also handles the following
+// edge cases:
+// - deleted by the task runner.
+// - abandoned (orphaned) by Timer.
+class BaseTimerTaskInternal {
+ public:
+  explicit BaseTimerTaskInternal(Timer* timer)
+      : timer_(timer) {
+  }
+
+  ~BaseTimerTaskInternal() {
+    // This task may be getting cleared because the task runner has been
+    // destructed.  If so, don't leave Timer with a dangling pointer
+    // to this.
+    if (timer_)
+      timer_->StopAndAbandon();
+  }
+
+  void Run() {
+    // timer_ is NULL if we were abandoned.
+    if (!timer_)
+      return;
+
+    // *this will be deleted by the task runner, so Timer needs to
+    // forget us:
+    timer_->scheduled_task_ = NULL;
+
+    // Although Timer should not call back into *this, let's clear
+    // the timer_ member first to be pedantic.
+    Timer* timer = timer_;
+    timer_ = NULL;
+    timer->RunScheduledTask();
+  }
+
+  // The task remains in the MessageLoop queue, but nothing will happen when it
+  // runs.
+  void Abandon() {
+    timer_ = NULL;
+  }
+
+ private:
+  Timer* timer_;
+};
+
+Timer::Timer(bool retain_user_task, bool is_repeating)
+    : scheduled_task_(NULL),
+      thread_id_(0),
+      is_repeating_(is_repeating),
+      retain_user_task_(retain_user_task),
+      is_running_(false) {
+}
+
+Timer::Timer(const tracked_objects::Location& posted_from,
+             TimeDelta delay,
+             const base::Closure& user_task,
+             bool is_repeating)
+    : scheduled_task_(NULL),
+      posted_from_(posted_from),
+      delay_(delay),
+      user_task_(user_task),
+      thread_id_(0),
+      is_repeating_(is_repeating),
+      retain_user_task_(true),
+      is_running_(false) {
+}
+
+Timer::~Timer() {
+  StopAndAbandon();
+}
+
+bool Timer::IsRunning() const {
+  return is_running_;
+}
+
+TimeDelta Timer::GetCurrentDelay() const {
+  return delay_;
+}
+
+void Timer::SetTaskRunner(scoped_refptr<SingleThreadTaskRunner> task_runner) {
+  // Do not allow changing the task runner once something has been scheduled.
+  DCHECK_EQ(thread_id_, 0);
+  task_runner_.swap(task_runner);
+}
+
+void Timer::Start(const tracked_objects::Location& posted_from,
+                  TimeDelta delay,
+                  const base::Closure& user_task) {
+  SetTaskInfo(posted_from, delay, user_task);
+  Reset();
+}
+
+void Timer::Stop() {
+  is_running_ = false;
+  if (!retain_user_task_)
+    user_task_.Reset();
+}
+
+void Timer::Reset() {
+  DCHECK(!user_task_.is_null());
+
+  // If there's no pending task, start one up and return.
+  if (!scheduled_task_) {
+    PostNewScheduledTask(delay_);
+    return;
+  }
+
+  // Set the new desired_run_time_.
+  if (delay_ > TimeDelta::FromMicroseconds(0))
+    desired_run_time_ = TimeTicks::Now() + delay_;
+  else
+    desired_run_time_ = TimeTicks();
+
+  // We can use the existing scheduled task if it arrives before the new
+  // desired_run_time_.
+  if (desired_run_time_ >= scheduled_run_time_) {
+    is_running_ = true;
+    return;
+  }
+
+  // We can't reuse the scheduled_task_, so abandon it and post a new one.
+  AbandonScheduledTask();
+  PostNewScheduledTask(delay_);
+}
+
+void Timer::SetTaskInfo(const tracked_objects::Location& posted_from,
+                        TimeDelta delay,
+                        const base::Closure& user_task) {
+  posted_from_ = posted_from;
+  delay_ = delay;
+  user_task_ = user_task;
+}
+
+void Timer::PostNewScheduledTask(TimeDelta delay) {
+  DCHECK(scheduled_task_ == NULL);
+  is_running_ = true;
+  scheduled_task_ = new BaseTimerTaskInternal(this);
+  if (delay > TimeDelta::FromMicroseconds(0)) {
+    GetTaskRunner()->PostDelayedTask(posted_from_,
+        base::Bind(&BaseTimerTaskInternal::Run, base::Owned(scheduled_task_)),
+        delay);
+    scheduled_run_time_ = desired_run_time_ = TimeTicks::Now() + delay;
+  } else {
+    GetTaskRunner()->PostTask(posted_from_,
+        base::Bind(&BaseTimerTaskInternal::Run, base::Owned(scheduled_task_)));
+    scheduled_run_time_ = desired_run_time_ = TimeTicks();
+  }
+  // Remember the thread ID that posts the first task -- this will be verified
+  // later when the task is abandoned to detect misuse from multiple threads.
+  if (!thread_id_) {
+    DCHECK(GetTaskRunner()->BelongsToCurrentThread());
+    thread_id_ = static_cast<int>(PlatformThread::CurrentId());
+  }
+}
+
+scoped_refptr<SingleThreadTaskRunner> Timer::GetTaskRunner() {
+  return task_runner_.get() ? task_runner_ : ThreadTaskRunnerHandle::Get();
+}
+
+void Timer::AbandonScheduledTask() {
+  DCHECK(thread_id_ == 0 ||
+         thread_id_ == static_cast<int>(PlatformThread::CurrentId()));
+  if (scheduled_task_) {
+    scheduled_task_->Abandon();
+    scheduled_task_ = NULL;
+  }
+}
+
+void Timer::RunScheduledTask() {
+  // Task may have been disabled.
+  if (!is_running_)
+    return;
+
+  // First check if we need to delay the task because of a new target time.
+  if (desired_run_time_ > scheduled_run_time_) {
+    // TimeTicks::Now() can be expensive, so only call it if we know the user
+    // has changed the desired_run_time_.
+    TimeTicks now = TimeTicks::Now();
+    // Task runner may have called us late anyway, so only post a continuation
+    // task if the desired_run_time_ is in the future.
+    if (desired_run_time_ > now) {
+      // Post a new task to span the remaining time.
+      PostNewScheduledTask(desired_run_time_ - now);
+      return;
+    }
+  }
+
+  // Make a local copy of the task to run. The Stop method will reset the
+  // user_task_ member if retain_user_task_ is false.
+  base::Closure task = user_task_;
+
+  if (is_repeating_)
+    PostNewScheduledTask(delay_);
+  else
+    Stop();
+
+  task.Run();
+
+  // No more member accesses here: *this could be deleted at this point.
+}
+
+}  // namespace base
diff --git a/base/timer/timer.h b/base/timer/timer.h
new file mode 100644
index 0000000..1ef58a3
--- /dev/null
+++ b/base/timer/timer.h
@@ -0,0 +1,268 @@
+// Copyright (c) 2012 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.
+
+// OneShotTimer and RepeatingTimer provide a simple timer API.  As the names
+// suggest, OneShotTimer calls you back once after a time delay expires.
+// RepeatingTimer on the other hand calls you back periodically with the
+// prescribed time interval.
+//
+// OneShotTimer and RepeatingTimer both cancel the timer when they go out of
+// scope, which makes it easy to ensure that you do not get called when your
+// object has gone out of scope.  Just instantiate a OneShotTimer or
+// RepeatingTimer as a member variable of the class for which you wish to
+// receive timer events.
+//
+// Sample RepeatingTimer usage:
+//
+//   class MyClass {
+//    public:
+//     void StartDoingStuff() {
+//       timer_.Start(FROM_HERE, TimeDelta::FromSeconds(1),
+//                    this, &MyClass::DoStuff);
+//     }
+//     void StopDoingStuff() {
+//       timer_.Stop();
+//     }
+//    private:
+//     void DoStuff() {
+//       // This method is called every second to do stuff.
+//       ...
+//     }
+//     base::RepeatingTimer<MyClass> timer_;
+//   };
+//
+// Both OneShotTimer and RepeatingTimer also support a Reset method, which
+// allows you to easily defer the timer event until the timer delay passes once
+// again.  So, in the above example, if 0.5 seconds have already passed,
+// calling Reset on timer_ would postpone DoStuff by another 1 second.  In
+// other words, Reset is shorthand for calling Stop and then Start again with
+// the same arguments.
+//
+// NOTE: These APIs are not thread safe. Always call from the same thread.
+
+#ifndef BASE_TIMER_TIMER_H_
+#define BASE_TIMER_TIMER_H_
+
+// IMPORTANT: If you change timer code, make sure that all tests (including
+// disabled ones) from timer_unittests.cc pass locally. Some are disabled
+// because they're flaky on the buildbot, but when you run them locally you
+// should be able to tell the difference.
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback.h"
+#include "base/location.h"
+#include "base/time/time.h"
+
+namespace base {
+
+class BaseTimerTaskInternal;
+class SingleThreadTaskRunner;
+
+//-----------------------------------------------------------------------------
+// This class wraps MessageLoop::PostDelayedTask to manage delayed and repeating
+// tasks. It must be destructed on the same thread that starts tasks. There are
+// DCHECKs in place to verify this.
+//
+class BASE_EXPORT Timer {
+ public:
+  // Construct a timer in repeating or one-shot mode. Start or SetTaskInfo must
+  // be called later to set task info. |retain_user_task| determines whether the
+  // user_task is retained or reset when it runs or stops.
+  Timer(bool retain_user_task, bool is_repeating);
+
+  // Construct a timer with retained task info.
+  Timer(const tracked_objects::Location& posted_from,
+        TimeDelta delay,
+        const base::Closure& user_task,
+        bool is_repeating);
+
+  virtual ~Timer();
+
+  // Returns true if the timer is running (i.e., not stopped).
+  virtual bool IsRunning() const;
+
+  // Returns the current delay for this timer.
+  virtual TimeDelta GetCurrentDelay() const;
+
+  // Set the task runner on which the task should be scheduled. This method can
+  // only be called before any tasks have been scheduled. The task runner must
+  // run tasks on the same thread the timer is used on.
+  virtual void SetTaskRunner(scoped_refptr<SingleThreadTaskRunner> task_runner);
+
+  // Start the timer to run at the given |delay| from now. If the timer is
+  // already running, it will be replaced to call the given |user_task|.
+  virtual void Start(const tracked_objects::Location& posted_from,
+                     TimeDelta delay,
+                     const base::Closure& user_task);
+
+  // Call this method to stop and cancel the timer.  It is a no-op if the timer
+  // is not running.
+  virtual void Stop();
+
+  // Call this method to reset the timer delay. The user_task_ must be set. If
+  // the timer is not running, this will start it by posting a task.
+  virtual void Reset();
+
+  const base::Closure& user_task() const { return user_task_; }
+  const TimeTicks& desired_run_time() const { return desired_run_time_; }
+
+ protected:
+  // Used to initiate a new delayed task.  This has the side-effect of disabling
+  // scheduled_task_ if it is non-null.
+  void SetTaskInfo(const tracked_objects::Location& posted_from,
+                   TimeDelta delay,
+                   const base::Closure& user_task);
+
+  void set_user_task(const Closure& task) { user_task_ = task; }
+  void set_desired_run_time(TimeTicks desired) { desired_run_time_ = desired; }
+  void set_is_running(bool running) { is_running_ = running; }
+
+  const tracked_objects::Location& posted_from() const { return posted_from_; }
+  bool retain_user_task() const { return retain_user_task_; }
+  bool is_repeating() const { return is_repeating_; }
+  bool is_running() const { return is_running_; }
+
+ private:
+  friend class BaseTimerTaskInternal;
+
+  // Allocates a new scheduled_task_ and posts it on the current MessageLoop
+  // with the given |delay|. scheduled_task_ must be NULL. scheduled_run_time_
+  // and desired_run_time_ are reset to Now() + delay.
+  void PostNewScheduledTask(TimeDelta delay);
+
+  // Returns the task runner on which the task should be scheduled. If the
+  // corresponding task_runner_ field is null, the task runner for the current
+  // thread is returned.
+  scoped_refptr<SingleThreadTaskRunner> GetTaskRunner();
+
+  // Disable scheduled_task_ and abandon it so that it no longer refers back to
+  // this object.
+  void AbandonScheduledTask();
+
+  // Called by BaseTimerTaskInternal when the MessageLoop runs it.
+  void RunScheduledTask();
+
+  // Stop running task (if any) and abandon scheduled task (if any).
+  void StopAndAbandon() {
+    Stop();
+    AbandonScheduledTask();
+  }
+
+  // When non-NULL, the scheduled_task_ is waiting in the MessageLoop to call
+  // RunScheduledTask() at scheduled_run_time_.
+  BaseTimerTaskInternal* scheduled_task_;
+
+  // The task runner on which the task should be scheduled. If it is null, the
+  // task runner for the current thread should be used.
+  scoped_refptr<SingleThreadTaskRunner> task_runner_;
+
+  // Location in user code.
+  tracked_objects::Location posted_from_;
+  // Delay requested by user.
+  TimeDelta delay_;
+  // user_task_ is what the user wants to be run at desired_run_time_.
+  base::Closure user_task_;
+
+  // The estimated time that the MessageLoop will run the scheduled_task_ that
+  // will call RunScheduledTask(). This time can be a "zero" TimeTicks if the
+  // task must be run immediately.
+  TimeTicks scheduled_run_time_;
+
+  // The desired run time of user_task_. The user may update this at any time,
+  // even if their previous request has not run yet. If desired_run_time_ is
+  // greater than scheduled_run_time_, a continuation task will be posted to
+  // wait for the remaining time. This allows us to reuse the pending task so as
+  // not to flood the MessageLoop with orphaned tasks when the user code
+  // excessively Stops and Starts the timer. This time can be a "zero" TimeTicks
+  // if the task must be run immediately.
+  TimeTicks desired_run_time_;
+
+  // Thread ID of current MessageLoop for verifying single-threaded usage.
+  int thread_id_;
+
+  // Repeating timers automatically post the task again before calling the task
+  // callback.
+  const bool is_repeating_;
+
+  // If true, hold on to the user_task_ closure object for reuse.
+  const bool retain_user_task_;
+
+  // If true, user_task_ is scheduled to run sometime in the future.
+  bool is_running_;
+
+  DISALLOW_COPY_AND_ASSIGN(Timer);
+};
+
+//-----------------------------------------------------------------------------
+// This class is an implementation detail of OneShotTimer and RepeatingTimer.
+// Please do not use this class directly.
+template <class Receiver, bool kIsRepeating>
+class BaseTimerMethodPointer : public Timer {
+ public:
+  typedef void (Receiver::*ReceiverMethod)();
+
+  // This is here to work around the fact that Timer::Start is "hidden" by the
+  // Start definition below, rather than being overloaded.
+  // TODO(tim): We should remove uses of BaseTimerMethodPointer::Start below
+  // and convert callers to use the base::Closure version in Timer::Start,
+  // see bug 148832.
+  using Timer::Start;
+
+  BaseTimerMethodPointer() : Timer(kIsRepeating, kIsRepeating) {}
+
+  // Start the timer to run at the given |delay| from now. If the timer is
+  // already running, it will be replaced to call a task formed from
+  // |reviewer->*method|.
+  virtual void Start(const tracked_objects::Location& posted_from,
+                     TimeDelta delay,
+                     Receiver* receiver,
+                     ReceiverMethod method) {
+    Timer::Start(posted_from, delay,
+                 base::Bind(method, base::Unretained(receiver)));
+  }
+};
+
+//-----------------------------------------------------------------------------
+// A simple, one-shot timer.  See usage notes at the top of the file.
+template <class Receiver>
+class OneShotTimer : public BaseTimerMethodPointer<Receiver, false> {};
+
+//-----------------------------------------------------------------------------
+// A simple, repeating timer.  See usage notes at the top of the file.
+template <class Receiver>
+class RepeatingTimer : public BaseTimerMethodPointer<Receiver, true> {};
+
+//-----------------------------------------------------------------------------
+// A Delay timer is like The Button from Lost. Once started, you have to keep
+// calling Reset otherwise it will call the given method in the MessageLoop
+// thread.
+//
+// Once created, it is inactive until Reset is called. Once |delay| seconds have
+// passed since the last call to Reset, the callback is made. Once the callback
+// has been made, it's inactive until Reset is called again.
+//
+// If destroyed, the timeout is canceled and will not occur even if already
+// inflight.
+template <class Receiver>
+class DelayTimer : protected Timer {
+ public:
+  typedef void (Receiver::*ReceiverMethod)();
+
+  DelayTimer(const tracked_objects::Location& posted_from,
+             TimeDelta delay,
+             Receiver* receiver,
+             ReceiverMethod method)
+      : Timer(posted_from, delay,
+              base::Bind(method, base::Unretained(receiver)),
+              false) {}
+
+  void Reset() override { Timer::Reset(); }
+};
+
+}  // namespace base
+
+#endif  // BASE_TIMER_TIMER_H_
diff --git a/base/timer/timer_unittest.cc b/base/timer/timer_unittest.cc
new file mode 100644
index 0000000..7213b80
--- /dev/null
+++ b/base/timer/timer_unittest.cc
@@ -0,0 +1,537 @@
+// Copyright (c) 2012 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/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/test/test_simple_task_runner.h"
+#include "base/timer/timer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::TimeDelta;
+using base::SingleThreadTaskRunner;
+
+namespace {
+
+// The message loops on which each timer should be tested.
+const base::MessageLoop::Type testing_message_loops[] = {
+  base::MessageLoop::TYPE_DEFAULT,
+  base::MessageLoop::TYPE_IO,
+#if !defined(OS_IOS)  // iOS does not allow direct running of the UI loop.
+  base::MessageLoop::TYPE_UI,
+#endif
+};
+
+const int kNumTestingMessageLoops = arraysize(testing_message_loops);
+
+class OneShotTimerTester {
+ public:
+  explicit OneShotTimerTester(bool* did_run, unsigned milliseconds = 10)
+      : did_run_(did_run),
+        delay_ms_(milliseconds),
+        quit_message_loop_(true) {
+  }
+
+  void Start() {
+    timer_.Start(FROM_HERE, TimeDelta::FromMilliseconds(delay_ms_), this,
+                 &OneShotTimerTester::Run);
+  }
+
+  void SetTaskRunner(scoped_refptr<SingleThreadTaskRunner> task_runner) {
+    quit_message_loop_ = false;
+    timer_.SetTaskRunner(task_runner);
+  }
+
+ private:
+  void Run() {
+    *did_run_ = true;
+    if (quit_message_loop_) {
+      base::MessageLoop::current()->QuitWhenIdle();
+    }
+  }
+
+  bool* did_run_;
+  base::OneShotTimer<OneShotTimerTester> timer_;
+  const unsigned delay_ms_;
+  bool quit_message_loop_;
+};
+
+class OneShotSelfDeletingTimerTester {
+ public:
+  explicit OneShotSelfDeletingTimerTester(bool* did_run) :
+      did_run_(did_run),
+      timer_(new base::OneShotTimer<OneShotSelfDeletingTimerTester>()) {
+  }
+
+  void Start() {
+    timer_->Start(FROM_HERE, TimeDelta::FromMilliseconds(10), this,
+                  &OneShotSelfDeletingTimerTester::Run);
+  }
+
+ private:
+  void Run() {
+    *did_run_ = true;
+    timer_.reset();
+    base::MessageLoop::current()->QuitWhenIdle();
+  }
+
+  bool* did_run_;
+  scoped_ptr<base::OneShotTimer<OneShotSelfDeletingTimerTester> > timer_;
+};
+
+class RepeatingTimerTester {
+ public:
+  explicit RepeatingTimerTester(bool* did_run, const TimeDelta& delay)
+      : did_run_(did_run), counter_(10), delay_(delay) {
+  }
+
+  void Start() {
+    timer_.Start(FROM_HERE, delay_, this, &RepeatingTimerTester::Run);
+  }
+
+ private:
+  void Run() {
+    if (--counter_ == 0) {
+      *did_run_ = true;
+      timer_.Stop();
+      base::MessageLoop::current()->QuitWhenIdle();
+    }
+  }
+
+  bool* did_run_;
+  int counter_;
+  TimeDelta delay_;
+  base::RepeatingTimer<RepeatingTimerTester> timer_;
+};
+
+void RunTest_OneShotTimer(base::MessageLoop::Type message_loop_type) {
+  base::MessageLoop loop(message_loop_type);
+
+  bool did_run = false;
+  OneShotTimerTester f(&did_run);
+  f.Start();
+
+  base::MessageLoop::current()->Run();
+
+  EXPECT_TRUE(did_run);
+}
+
+void RunTest_OneShotTimer_Cancel(base::MessageLoop::Type message_loop_type) {
+  base::MessageLoop loop(message_loop_type);
+
+  bool did_run_a = false;
+  OneShotTimerTester* a = new OneShotTimerTester(&did_run_a);
+
+  // This should run before the timer expires.
+  base::MessageLoop::current()->DeleteSoon(FROM_HERE, a);
+
+  // Now start the timer.
+  a->Start();
+
+  bool did_run_b = false;
+  OneShotTimerTester b(&did_run_b);
+  b.Start();
+
+  base::MessageLoop::current()->Run();
+
+  EXPECT_FALSE(did_run_a);
+  EXPECT_TRUE(did_run_b);
+}
+
+void RunTest_OneShotSelfDeletingTimer(
+    base::MessageLoop::Type message_loop_type) {
+  base::MessageLoop loop(message_loop_type);
+
+  bool did_run = false;
+  OneShotSelfDeletingTimerTester f(&did_run);
+  f.Start();
+
+  base::MessageLoop::current()->Run();
+
+  EXPECT_TRUE(did_run);
+}
+
+void RunTest_RepeatingTimer(base::MessageLoop::Type message_loop_type,
+                            const TimeDelta& delay) {
+  base::MessageLoop loop(message_loop_type);
+
+  bool did_run = false;
+  RepeatingTimerTester f(&did_run, delay);
+  f.Start();
+
+  base::MessageLoop::current()->Run();
+
+  EXPECT_TRUE(did_run);
+}
+
+void RunTest_RepeatingTimer_Cancel(base::MessageLoop::Type message_loop_type,
+                                   const TimeDelta& delay) {
+  base::MessageLoop loop(message_loop_type);
+
+  bool did_run_a = false;
+  RepeatingTimerTester* a = new RepeatingTimerTester(&did_run_a, delay);
+
+  // This should run before the timer expires.
+  base::MessageLoop::current()->DeleteSoon(FROM_HERE, a);
+
+  // Now start the timer.
+  a->Start();
+
+  bool did_run_b = false;
+  RepeatingTimerTester b(&did_run_b, delay);
+  b.Start();
+
+  base::MessageLoop::current()->Run();
+
+  EXPECT_FALSE(did_run_a);
+  EXPECT_TRUE(did_run_b);
+}
+
+class DelayTimerTarget {
+ public:
+  bool signaled() const { return signaled_; }
+
+  void Signal() {
+    ASSERT_FALSE(signaled_);
+    signaled_ = true;
+  }
+
+ private:
+  bool signaled_ = false;
+};
+
+void RunTest_DelayTimer_NoCall(base::MessageLoop::Type message_loop_type) {
+  base::MessageLoop loop(message_loop_type);
+
+  // If Delay is never called, the timer shouldn't go off.
+  DelayTimerTarget target;
+  base::DelayTimer<DelayTimerTarget> timer(FROM_HERE,
+      TimeDelta::FromMilliseconds(1), &target, &DelayTimerTarget::Signal);
+
+  bool did_run = false;
+  OneShotTimerTester tester(&did_run);
+  tester.Start();
+  base::MessageLoop::current()->Run();
+
+  ASSERT_FALSE(target.signaled());
+}
+
+void RunTest_DelayTimer_OneCall(base::MessageLoop::Type message_loop_type) {
+  base::MessageLoop loop(message_loop_type);
+
+  DelayTimerTarget target;
+  base::DelayTimer<DelayTimerTarget> timer(FROM_HERE,
+      TimeDelta::FromMilliseconds(1), &target, &DelayTimerTarget::Signal);
+  timer.Reset();
+
+  bool did_run = false;
+  OneShotTimerTester tester(&did_run, 100 /* milliseconds */);
+  tester.Start();
+  base::MessageLoop::current()->Run();
+
+  ASSERT_TRUE(target.signaled());
+}
+
+struct ResetHelper {
+  ResetHelper(base::DelayTimer<DelayTimerTarget>* timer,
+              DelayTimerTarget* target)
+      : timer_(timer),
+        target_(target) {
+  }
+
+  void Reset() {
+    ASSERT_FALSE(target_->signaled());
+    timer_->Reset();
+  }
+
+ private:
+  base::DelayTimer<DelayTimerTarget> *const timer_;
+  DelayTimerTarget *const target_;
+};
+
+void RunTest_DelayTimer_Reset(base::MessageLoop::Type message_loop_type) {
+  base::MessageLoop loop(message_loop_type);
+
+  // If Delay is never called, the timer shouldn't go off.
+  DelayTimerTarget target;
+  base::DelayTimer<DelayTimerTarget> timer(FROM_HERE,
+      TimeDelta::FromMilliseconds(50), &target, &DelayTimerTarget::Signal);
+  timer.Reset();
+
+  ResetHelper reset_helper(&timer, &target);
+
+  base::OneShotTimer<ResetHelper> timers[20];
+  for (size_t i = 0; i < arraysize(timers); ++i) {
+    timers[i].Start(FROM_HERE, TimeDelta::FromMilliseconds(i * 10),
+                    &reset_helper, &ResetHelper::Reset);
+  }
+
+  bool did_run = false;
+  OneShotTimerTester tester(&did_run, 300);
+  tester.Start();
+  base::MessageLoop::current()->Run();
+
+  ASSERT_TRUE(target.signaled());
+}
+
+class DelayTimerFatalTarget {
+ public:
+  void Signal() {
+    ASSERT_TRUE(false);
+  }
+};
+
+
+void RunTest_DelayTimer_Deleted(base::MessageLoop::Type message_loop_type) {
+  base::MessageLoop loop(message_loop_type);
+
+  DelayTimerFatalTarget target;
+
+  {
+    base::DelayTimer<DelayTimerFatalTarget> timer(
+        FROM_HERE, TimeDelta::FromMilliseconds(50), &target,
+        &DelayTimerFatalTarget::Signal);
+    timer.Reset();
+  }
+
+  // When the timer is deleted, the DelayTimerFatalTarget should never be
+  // called.
+  base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
+}
+
+}  // namespace
+
+//-----------------------------------------------------------------------------
+// Each test is run against each type of MessageLoop.  That way we are sure
+// that timers work properly in all configurations.
+
+TEST(TimerTest, OneShotTimer) {
+  for (int i = 0; i < kNumTestingMessageLoops; i++) {
+    RunTest_OneShotTimer(testing_message_loops[i]);
+  }
+}
+
+TEST(TimerTest, OneShotTimer_Cancel) {
+  for (int i = 0; i < kNumTestingMessageLoops; i++) {
+    RunTest_OneShotTimer_Cancel(testing_message_loops[i]);
+  }
+}
+
+// If underline timer does not handle properly, we will crash or fail
+// in full page heap environment.
+TEST(TimerTest, OneShotSelfDeletingTimer) {
+  for (int i = 0; i < kNumTestingMessageLoops; i++) {
+    RunTest_OneShotSelfDeletingTimer(testing_message_loops[i]);
+  }
+}
+
+TEST(TimerTest, OneShotTimer_CustomTaskRunner) {
+  scoped_refptr<base::TestSimpleTaskRunner> task_runner =
+      new base::TestSimpleTaskRunner();
+
+  bool did_run = false;
+  OneShotTimerTester f(&did_run);
+  f.SetTaskRunner(task_runner);
+  f.Start();
+
+  EXPECT_FALSE(did_run);
+  task_runner->RunUntilIdle();
+  EXPECT_TRUE(did_run);
+}
+
+TEST(TimerTest, RepeatingTimer) {
+  for (int i = 0; i < kNumTestingMessageLoops; i++) {
+    RunTest_RepeatingTimer(testing_message_loops[i],
+                           TimeDelta::FromMilliseconds(10));
+  }
+}
+
+TEST(TimerTest, RepeatingTimer_Cancel) {
+  for (int i = 0; i < kNumTestingMessageLoops; i++) {
+    RunTest_RepeatingTimer_Cancel(testing_message_loops[i],
+                                  TimeDelta::FromMilliseconds(10));
+  }
+}
+
+TEST(TimerTest, RepeatingTimerZeroDelay) {
+  for (int i = 0; i < kNumTestingMessageLoops; i++) {
+    RunTest_RepeatingTimer(testing_message_loops[i],
+                           TimeDelta::FromMilliseconds(0));
+  }
+}
+
+TEST(TimerTest, RepeatingTimerZeroDelay_Cancel) {
+  for (int i = 0; i < kNumTestingMessageLoops; i++) {
+    RunTest_RepeatingTimer_Cancel(testing_message_loops[i],
+                                  TimeDelta::FromMilliseconds(0));
+  }
+}
+
+TEST(TimerTest, DelayTimer_NoCall) {
+  for (int i = 0; i < kNumTestingMessageLoops; i++) {
+    RunTest_DelayTimer_NoCall(testing_message_loops[i]);
+  }
+}
+
+TEST(TimerTest, DelayTimer_OneCall) {
+  for (int i = 0; i < kNumTestingMessageLoops; i++) {
+    RunTest_DelayTimer_OneCall(testing_message_loops[i]);
+  }
+}
+
+// It's flaky on the buildbot, http://crbug.com/25038.
+TEST(TimerTest, DISABLED_DelayTimer_Reset) {
+  for (int i = 0; i < kNumTestingMessageLoops; i++) {
+    RunTest_DelayTimer_Reset(testing_message_loops[i]);
+  }
+}
+
+TEST(TimerTest, DelayTimer_Deleted) {
+  for (int i = 0; i < kNumTestingMessageLoops; i++) {
+    RunTest_DelayTimer_Deleted(testing_message_loops[i]);
+  }
+}
+
+TEST(TimerTest, MessageLoopShutdown) {
+  // This test is designed to verify that shutdown of the
+  // message loop does not cause crashes if there were pending
+  // timers not yet fired.  It may only trigger exceptions
+  // if debug heap checking is enabled.
+  bool did_run = false;
+  {
+    OneShotTimerTester a(&did_run);
+    OneShotTimerTester b(&did_run);
+    OneShotTimerTester c(&did_run);
+    OneShotTimerTester d(&did_run);
+    {
+      base::MessageLoop loop;
+      a.Start();
+      b.Start();
+    }  // MessageLoop destructs by falling out of scope.
+  }  // OneShotTimers destruct.  SHOULD NOT CRASH, of course.
+
+  EXPECT_FALSE(did_run);
+}
+
+void TimerTestCallback() {
+}
+
+TEST(TimerTest, NonRepeatIsRunning) {
+  {
+    base::MessageLoop loop;
+    base::Timer timer(false, false);
+    EXPECT_FALSE(timer.IsRunning());
+    timer.Start(FROM_HERE, TimeDelta::FromDays(1),
+                base::Bind(&TimerTestCallback));
+    EXPECT_TRUE(timer.IsRunning());
+    timer.Stop();
+    EXPECT_FALSE(timer.IsRunning());
+    EXPECT_TRUE(timer.user_task().is_null());
+  }
+
+  {
+    base::Timer timer(true, false);
+    base::MessageLoop loop;
+    EXPECT_FALSE(timer.IsRunning());
+    timer.Start(FROM_HERE, TimeDelta::FromDays(1),
+                base::Bind(&TimerTestCallback));
+    EXPECT_TRUE(timer.IsRunning());
+    timer.Stop();
+    EXPECT_FALSE(timer.IsRunning());
+    ASSERT_FALSE(timer.user_task().is_null());
+    timer.Reset();
+    EXPECT_TRUE(timer.IsRunning());
+  }
+}
+
+TEST(TimerTest, NonRepeatMessageLoopDeath) {
+  base::Timer timer(false, false);
+  {
+    base::MessageLoop loop;
+    EXPECT_FALSE(timer.IsRunning());
+    timer.Start(FROM_HERE, TimeDelta::FromDays(1),
+                base::Bind(&TimerTestCallback));
+    EXPECT_TRUE(timer.IsRunning());
+  }
+  EXPECT_FALSE(timer.IsRunning());
+  EXPECT_TRUE(timer.user_task().is_null());
+}
+
+TEST(TimerTest, RetainRepeatIsRunning) {
+  base::MessageLoop loop;
+  base::Timer timer(FROM_HERE, TimeDelta::FromDays(1),
+                    base::Bind(&TimerTestCallback), true);
+  EXPECT_FALSE(timer.IsRunning());
+  timer.Reset();
+  EXPECT_TRUE(timer.IsRunning());
+  timer.Stop();
+  EXPECT_FALSE(timer.IsRunning());
+  timer.Reset();
+  EXPECT_TRUE(timer.IsRunning());
+}
+
+TEST(TimerTest, RetainNonRepeatIsRunning) {
+  base::MessageLoop loop;
+  base::Timer timer(FROM_HERE, TimeDelta::FromDays(1),
+                    base::Bind(&TimerTestCallback), false);
+  EXPECT_FALSE(timer.IsRunning());
+  timer.Reset();
+  EXPECT_TRUE(timer.IsRunning());
+  timer.Stop();
+  EXPECT_FALSE(timer.IsRunning());
+  timer.Reset();
+  EXPECT_TRUE(timer.IsRunning());
+}
+
+namespace {
+
+bool g_callback_happened1 = false;
+bool g_callback_happened2 = false;
+
+void ClearAllCallbackHappened() {
+  g_callback_happened1 = false;
+  g_callback_happened2 = false;
+}
+
+void SetCallbackHappened1() {
+  g_callback_happened1 = true;
+  base::MessageLoop::current()->QuitWhenIdle();
+}
+
+void SetCallbackHappened2() {
+  g_callback_happened2 = true;
+  base::MessageLoop::current()->QuitWhenIdle();
+}
+
+TEST(TimerTest, ContinuationStopStart) {
+  {
+    ClearAllCallbackHappened();
+    base::MessageLoop loop;
+    base::Timer timer(false, false);
+    timer.Start(FROM_HERE, TimeDelta::FromMilliseconds(10),
+                base::Bind(&SetCallbackHappened1));
+    timer.Stop();
+    timer.Start(FROM_HERE, TimeDelta::FromMilliseconds(40),
+                base::Bind(&SetCallbackHappened2));
+    base::MessageLoop::current()->Run();
+    EXPECT_FALSE(g_callback_happened1);
+    EXPECT_TRUE(g_callback_happened2);
+  }
+}
+
+TEST(TimerTest, ContinuationReset) {
+  {
+    ClearAllCallbackHappened();
+    base::MessageLoop loop;
+    base::Timer timer(false, false);
+    timer.Start(FROM_HERE, TimeDelta::FromMilliseconds(10),
+                base::Bind(&SetCallbackHappened1));
+    timer.Reset();
+    // Since Reset happened before task ran, the user_task must not be cleared:
+    ASSERT_FALSE(timer.user_task().is_null());
+    base::MessageLoop::current()->Run();
+    EXPECT_TRUE(g_callback_happened1);
+  }
+}
+
+}  // namespace
diff --git a/base/tools_sanity_unittest.cc b/base/tools_sanity_unittest.cc
new file mode 100644
index 0000000..c0541d1
--- /dev/null
+++ b/base/tools_sanity_unittest.cc
@@ -0,0 +1,342 @@
+// Copyright (c) 2012 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 contains intentional memory errors, some of which may lead to
+// crashes if the test is ran without special memory testing tools. We use these
+// errors to verify the sanity of the tools.
+
+#include "base/atomicops.h"
+#include "base/debug/asan_invalid_access.h"
+#include "base/debug/profiler.h"
+#include "base/message_loop/message_loop.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+const base::subtle::Atomic32 kMagicValue = 42;
+
+// Helper for memory accesses that can potentially corrupt memory or cause a
+// crash during a native run.
+#if defined(ADDRESS_SANITIZER) || defined(SYZYASAN)
+#if defined(OS_IOS)
+// EXPECT_DEATH is not supported on IOS.
+#define HARMFUL_ACCESS(action,error_regexp) do { action; } while (0)
+#elif defined(SYZYASAN)
+// We won't get a meaningful error message because we're not running under the
+// SyzyASan logger, but we can at least make sure that the error has been
+// generated in the SyzyASan runtime.
+#define HARMFUL_ACCESS(action,unused) \
+if (debug::IsBinaryInstrumented()) { EXPECT_DEATH(action, \
+                                                  "AsanRuntime::OnError"); }
+#else
+#define HARMFUL_ACCESS(action,error_regexp) EXPECT_DEATH(action,error_regexp)
+#endif  // !OS_IOS && !SYZYASAN
+#else
+#define HARMFUL_ACCESS(action,error_regexp) \
+do { if (RunningOnValgrind()) { action; } } while (0)
+#endif
+
+void DoReadUninitializedValue(char *ptr) {
+  // Comparison with 64 is to prevent clang from optimizing away the
+  // jump -- valgrind only catches jumps and conditional moves, but clang uses
+  // the borrow flag if the condition is just `*ptr == '\0'`.
+  if (*ptr == 64) {
+    VLOG(1) << "Uninit condition is true";
+  } else {
+    VLOG(1) << "Uninit condition is false";
+  }
+}
+
+void ReadUninitializedValue(char *ptr) {
+#if defined(MEMORY_SANITIZER)
+  EXPECT_DEATH(DoReadUninitializedValue(ptr),
+               "use-of-uninitialized-value");
+#else
+  DoReadUninitializedValue(ptr);
+#endif
+}
+
+void ReadValueOutOfArrayBoundsLeft(char *ptr) {
+  char c = ptr[-2];
+  VLOG(1) << "Reading a byte out of bounds: " << c;
+}
+
+void ReadValueOutOfArrayBoundsRight(char *ptr, size_t size) {
+  char c = ptr[size + 1];
+  VLOG(1) << "Reading a byte out of bounds: " << c;
+}
+
+// This is harmless if you run it under Valgrind thanks to redzones.
+void WriteValueOutOfArrayBoundsLeft(char *ptr) {
+  ptr[-1] = kMagicValue;
+}
+
+// This is harmless if you run it under Valgrind thanks to redzones.
+void WriteValueOutOfArrayBoundsRight(char *ptr, size_t size) {
+  ptr[size] = kMagicValue;
+}
+
+void MakeSomeErrors(char *ptr, size_t size) {
+  ReadUninitializedValue(ptr);
+
+  HARMFUL_ACCESS(ReadValueOutOfArrayBoundsLeft(ptr),
+                 "2 bytes to the left");
+  HARMFUL_ACCESS(ReadValueOutOfArrayBoundsRight(ptr, size),
+                 "1 bytes to the right");
+  HARMFUL_ACCESS(WriteValueOutOfArrayBoundsLeft(ptr),
+                 "1 bytes to the left");
+  HARMFUL_ACCESS(WriteValueOutOfArrayBoundsRight(ptr, size),
+                 "0 bytes to the right");
+}
+
+}  // namespace
+
+// A memory leak detector should report an error in this test.
+TEST(ToolsSanityTest, MemoryLeak) {
+  // Without the |volatile|, clang optimizes away the next two lines.
+  int* volatile leak = new int[256];  // Leak some memory intentionally.
+  leak[4] = 1;  // Make sure the allocated memory is used.
+}
+
+#if (defined(ADDRESS_SANITIZER) && defined(OS_IOS)) || defined(SYZYASAN)
+// Because iOS doesn't support death tests, each of the following tests will
+// crash the whole program under Asan. On Windows Asan is based on SyzyAsan; the
+// error report mechanism is different than with Asan so these tests will fail.
+#define MAYBE_AccessesToNewMemory DISABLED_AccessesToNewMemory
+#define MAYBE_AccessesToMallocMemory DISABLED_AccessesToMallocMemory
+#else
+#define MAYBE_AccessesToNewMemory AccessesToNewMemory
+#define MAYBE_AccessesToMallocMemory AccessesToMallocMemory
+#endif // (defined(ADDRESS_SANITIZER) && defined(OS_IOS)) || defined(SYZYASAN)
+
+// The following tests pass with Clang r170392, but not r172454, which
+// makes AddressSanitizer detect errors in them. We disable these tests under
+// AddressSanitizer until we fully switch to Clang r172454. After that the
+// tests should be put back under the (defined(OS_IOS) || defined(OS_WIN))
+// clause above.
+// See also http://crbug.com/172614.
+#if defined(ADDRESS_SANITIZER) || defined(SYZYASAN)
+#define MAYBE_SingleElementDeletedWithBraces \
+    DISABLED_SingleElementDeletedWithBraces
+#define MAYBE_ArrayDeletedWithoutBraces DISABLED_ArrayDeletedWithoutBraces
+#else
+#define MAYBE_ArrayDeletedWithoutBraces ArrayDeletedWithoutBraces
+#define MAYBE_SingleElementDeletedWithBraces SingleElementDeletedWithBraces
+#endif  // defined(ADDRESS_SANITIZER) || defined(SYZYASAN)
+
+TEST(ToolsSanityTest, MAYBE_AccessesToNewMemory) {
+  char *foo = new char[10];
+  MakeSomeErrors(foo, 10);
+  delete [] foo;
+  // Use after delete.
+  HARMFUL_ACCESS(foo[5] = 0, "heap-use-after-free");
+}
+
+TEST(ToolsSanityTest, MAYBE_AccessesToMallocMemory) {
+  char *foo = reinterpret_cast<char*>(malloc(10));
+  MakeSomeErrors(foo, 10);
+  free(foo);
+  // Use after free.
+  HARMFUL_ACCESS(foo[5] = 0, "heap-use-after-free");
+}
+
+static int* allocateArray() {
+  // Clang warns about the mismatched new[]/delete if they occur in the same
+  // function.
+  return new int[10];
+}
+
+TEST(ToolsSanityTest, MAYBE_ArrayDeletedWithoutBraces) {
+#if !defined(ADDRESS_SANITIZER) && !defined(SYZYASAN)
+  // This test may corrupt memory if not run under Valgrind or compiled with
+  // AddressSanitizer.
+  if (!RunningOnValgrind())
+    return;
+#endif
+
+  // Without the |volatile|, clang optimizes away the next two lines.
+  int* volatile foo = allocateArray();
+  delete foo;
+}
+
+static int* allocateScalar() {
+  // Clang warns about the mismatched new/delete[] if they occur in the same
+  // function.
+  return new int;
+}
+
+TEST(ToolsSanityTest, MAYBE_SingleElementDeletedWithBraces) {
+#if !defined(ADDRESS_SANITIZER)
+  // This test may corrupt memory if not run under Valgrind or compiled with
+  // AddressSanitizer.
+  if (!RunningOnValgrind())
+    return;
+#endif
+
+  // Without the |volatile|, clang optimizes away the next two lines.
+  int* volatile foo = allocateScalar();
+  (void) foo;
+  delete [] foo;
+}
+
+#if defined(ADDRESS_SANITIZER) || defined(SYZYASAN)
+
+TEST(ToolsSanityTest, DISABLED_AddressSanitizerNullDerefCrashTest) {
+  // Intentionally crash to make sure AddressSanitizer is running.
+  // This test should not be ran on bots.
+  int* volatile zero = NULL;
+  *zero = 0;
+}
+
+TEST(ToolsSanityTest, DISABLED_AddressSanitizerLocalOOBCrashTest) {
+  // Intentionally crash to make sure AddressSanitizer is instrumenting
+  // the local variables.
+  // This test should not be ran on bots.
+  int array[5];
+  // Work around the OOB warning reported by Clang.
+  int* volatile access = &array[5];
+  *access = 43;
+}
+
+namespace {
+int g_asan_test_global_array[10];
+}  // namespace
+
+TEST(ToolsSanityTest, DISABLED_AddressSanitizerGlobalOOBCrashTest) {
+  // Intentionally crash to make sure AddressSanitizer is instrumenting
+  // the global variables.
+  // This test should not be ran on bots.
+
+  // Work around the OOB warning reported by Clang.
+  int* volatile access = g_asan_test_global_array - 1;
+  *access = 43;
+}
+
+TEST(ToolsSanityTest, AsanHeapOverflow) {
+  HARMFUL_ACCESS(debug::AsanHeapOverflow() ,"to the right");
+}
+
+TEST(ToolsSanityTest, AsanHeapUnderflow) {
+  HARMFUL_ACCESS(debug::AsanHeapUnderflow(), "to the left");
+}
+
+TEST(ToolsSanityTest, AsanHeapUseAfterFree) {
+  HARMFUL_ACCESS(debug::AsanHeapUseAfterFree(), "heap-use-after-free");
+}
+
+#if defined(SYZYASAN)
+TEST(ToolsSanityTest, AsanCorruptHeapBlock) {
+  HARMFUL_ACCESS(debug::AsanCorruptHeapBlock(), "");
+}
+
+TEST(ToolsSanityTest, AsanCorruptHeap) {
+  // This test will kill the process by raising an exception, there's no
+  // particular string to look for in the stack trace.
+  EXPECT_DEATH(debug::AsanCorruptHeap(), "");
+}
+#endif  // SYZYASAN
+
+#endif  // ADDRESS_SANITIZER || SYZYASAN
+
+namespace {
+
+// We use caps here just to ensure that the method name doesn't interfere with
+// the wildcarded suppressions.
+class TOOLS_SANITY_TEST_CONCURRENT_THREAD : public PlatformThread::Delegate {
+ public:
+  explicit TOOLS_SANITY_TEST_CONCURRENT_THREAD(bool *value) : value_(value) {}
+  ~TOOLS_SANITY_TEST_CONCURRENT_THREAD() override {}
+  void ThreadMain() override {
+    *value_ = true;
+
+    // Sleep for a few milliseconds so the two threads are more likely to live
+    // simultaneously. Otherwise we may miss the report due to mutex
+    // lock/unlock's inside thread creation code in pure-happens-before mode...
+    PlatformThread::Sleep(TimeDelta::FromMilliseconds(100));
+  }
+ private:
+  bool *value_;
+};
+
+class ReleaseStoreThread : public PlatformThread::Delegate {
+ public:
+  explicit ReleaseStoreThread(base::subtle::Atomic32 *value) : value_(value) {}
+  ~ReleaseStoreThread() override {}
+  void ThreadMain() override {
+    base::subtle::Release_Store(value_, kMagicValue);
+
+    // Sleep for a few milliseconds so the two threads are more likely to live
+    // simultaneously. Otherwise we may miss the report due to mutex
+    // lock/unlock's inside thread creation code in pure-happens-before mode...
+    PlatformThread::Sleep(TimeDelta::FromMilliseconds(100));
+  }
+ private:
+  base::subtle::Atomic32 *value_;
+};
+
+class AcquireLoadThread : public PlatformThread::Delegate {
+ public:
+  explicit AcquireLoadThread(base::subtle::Atomic32 *value) : value_(value) {}
+  ~AcquireLoadThread() override {}
+  void ThreadMain() override {
+    // Wait for the other thread to make Release_Store
+    PlatformThread::Sleep(TimeDelta::FromMilliseconds(100));
+    base::subtle::Acquire_Load(value_);
+  }
+ private:
+  base::subtle::Atomic32 *value_;
+};
+
+void RunInParallel(PlatformThread::Delegate *d1, PlatformThread::Delegate *d2) {
+  PlatformThreadHandle a;
+  PlatformThreadHandle b;
+  PlatformThread::Create(0, d1, &a);
+  PlatformThread::Create(0, d2, &b);
+  PlatformThread::Join(a);
+  PlatformThread::Join(b);
+}
+
+#if defined(THREAD_SANITIZER)
+void DataRace() {
+  bool *shared = new bool(false);
+  TOOLS_SANITY_TEST_CONCURRENT_THREAD thread1(shared), thread2(shared);
+  RunInParallel(&thread1, &thread2);
+  EXPECT_TRUE(*shared);
+  delete shared;
+  // We're in a death test - crash.
+  CHECK(0);
+}
+#endif
+
+}  // namespace
+
+#if defined(THREAD_SANITIZER)
+// A data race detector should report an error in this test.
+TEST(ToolsSanityTest, DataRace) {
+  // The suppression regexp must match that in base/debug/tsan_suppressions.cc.
+  EXPECT_DEATH(DataRace(), "1 race:base/tools_sanity_unittest.cc");
+}
+#endif
+
+TEST(ToolsSanityTest, AnnotateBenignRace) {
+  bool shared = false;
+  ANNOTATE_BENIGN_RACE(&shared, "Intentional race - make sure doesn't show up");
+  TOOLS_SANITY_TEST_CONCURRENT_THREAD thread1(&shared), thread2(&shared);
+  RunInParallel(&thread1, &thread2);
+  EXPECT_TRUE(shared);
+}
+
+TEST(ToolsSanityTest, AtomicsAreIgnored) {
+  base::subtle::Atomic32 shared = 0;
+  ReleaseStoreThread thread1(&shared);
+  AcquireLoadThread thread2(&shared);
+  RunInParallel(&thread1, &thread2);
+  EXPECT_EQ(kMagicValue, shared);
+}
+
+}  // namespace base
diff --git a/base/trace_event/BUILD.gn b/base/trace_event/BUILD.gn
new file mode 100644
index 0000000..3a8a5bf
--- /dev/null
+++ b/base/trace_event/BUILD.gn
@@ -0,0 +1,115 @@
+# 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.
+
+source_set("trace_event") {
+  sources = [
+    "java_heap_dump_provider_android.cc",
+    "java_heap_dump_provider_android.h",
+    "memory_allocator_dump.cc",
+    "memory_allocator_dump.h",
+    "memory_allocator_dump_guid.cc",
+    "memory_allocator_dump_guid.h",
+    "memory_dump_manager.cc",
+    "memory_dump_manager.h",
+    "memory_dump_provider.h",
+    "memory_dump_request_args.h",
+    "memory_dump_session_state.cc",
+    "memory_dump_session_state.h",
+    "process_memory_dump.cc",
+    "process_memory_dump.h",
+    "process_memory_maps.cc",
+    "process_memory_maps.h",
+    "process_memory_maps_dump_provider.cc",
+    "process_memory_maps_dump_provider.h",
+    "process_memory_totals.cc",
+    "process_memory_totals.h",
+    "process_memory_totals_dump_provider.cc",
+    "process_memory_totals_dump_provider.h",
+    "trace_config.cc",
+    "trace_config.h",
+    "trace_event.h",
+    "trace_event_android.cc",
+    "trace_event_argument.cc",
+    "trace_event_argument.h",
+    "trace_event_etw_export_win.cc",
+    "trace_event_etw_export_win.h",
+    "trace_event_impl.cc",
+    "trace_event_impl.h",
+    "trace_event_impl_constants.cc",
+    "trace_event_memory.cc",
+    "trace_event_memory.h",
+    "trace_event_memory_overhead.cc",
+    "trace_event_memory_overhead.h",
+    "trace_event_synthetic_delay.cc",
+    "trace_event_synthetic_delay.h",
+    "trace_event_system_stats_monitor.cc",
+    "trace_event_system_stats_monitor.h",
+    "trace_event_win.cc",
+    "trace_event_win.h",
+    "winheap_dump_provider_win.cc",
+    "winheap_dump_provider_win.h",
+  ]
+
+  if (is_nacl) {
+    sources -= [
+      "process_memory_totals_dump_provider.cc",
+      "trace_event_system_stats_monitor.cc",
+    ]
+  }
+
+  if (is_linux || is_android) {
+    sources += [
+      "malloc_dump_provider.cc",
+      "malloc_dump_provider.h",
+    ]
+  }
+
+  configs += [ "//base:base_implementation" ]
+
+  deps = [
+    "//base/debug",
+    "//base/json",
+    "//base/memory",
+    "//base/process",
+    "//base/third_party/dynamic_annotations",
+  ]
+
+  if (is_win) {
+    deps += [ "//base/trace_event/etw_manifest:chrome_events_win" ]
+  }
+
+  allow_circular_includes_from = [
+    "//base/debug",
+    "//base/memory",
+    "//base/process",
+  ]
+
+  visibility = [ "//base/*" ]
+}
+
+source_set("trace_event_unittests") {
+  testonly = true
+  sources = [
+    "java_heap_dump_provider_android_unittest.cc",
+    "memory_allocator_dump_unittest.cc",
+    "memory_dump_manager_unittest.cc",
+    "process_memory_dump_unittest.cc",
+    "process_memory_maps_dump_provider_unittest.cc",
+    "process_memory_totals_dump_provider_unittest.cc",
+    "trace_config_unittest.cc",
+    "trace_event_argument_unittest.cc",
+    "trace_event_memory_unittest.cc",
+    "trace_event_synthetic_delay_unittest.cc",
+    "trace_event_system_stats_monitor_unittest.cc",
+    "trace_event_unittest.cc",
+    "trace_event_win_unittest.cc",
+    "winheap_dump_provider_win_unittest.cc",
+  ]
+
+  deps = [
+    "//base/test:test_support",
+    "//testing/gmock",
+    "//testing/gtest",
+  ]
+}
diff --git a/base/trace_event/OWNERS b/base/trace_event/OWNERS
new file mode 100644
index 0000000..aa1d675
--- /dev/null
+++ b/base/trace_event/OWNERS
@@ -0,0 +1,4 @@
+nduca@chromium.org
+dsinclair@chromium.org
+primiano@chromium.org
+per-file trace_event_android.cc=wangxianzhu@chromium.org
diff --git a/base/trace_event/etw_manifest/BUILD.gn b/base/trace_event/etw_manifest/BUILD.gn
new file mode 100644
index 0000000..f62e356
--- /dev/null
+++ b/base/trace_event/etw_manifest/BUILD.gn
@@ -0,0 +1,48 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+assert(is_win, "This only runs on Windows.")
+
+# Makes the .h/.rc files from the .man file.
+action("chrome_events_win_generate") {
+  visibility = [ ":*" ]
+  script = "build/message_compiler.py"
+
+  sources = [
+    "chrome_events_win.man",
+  ]
+
+  outputs = [
+    "$target_gen_dir/chrome_events_win.h",
+    "$target_gen_dir/chrome_events_win.rc",
+  ]
+
+  args = [
+    # Where to put the header.
+    "-h",
+    rebase_path("$target_gen_dir", root_build_dir),
+
+    # Where to put the .rc file.
+    "-r",
+    rebase_path("$target_gen_dir", root_build_dir),
+
+    # Generate the user-mode code.
+    "-um",
+    rebase_path("chrome_events_win.man", root_build_dir),
+  ]
+}
+
+# Compile the generated files.
+source_set("chrome_events_win") {
+  visibility = [
+    "//base/trace_event/*",
+    "//chrome:main_dll",
+  ]
+
+  sources = get_target_outputs(":chrome_events_win_generate")
+
+  deps = [
+    ":chrome_events_win_generate",
+  ]
+}
diff --git a/base/trace_event/etw_manifest/BUILD/message_compiler.py b/base/trace_event/etw_manifest/BUILD/message_compiler.py
new file mode 100644
index 0000000..be5927d
--- /dev/null
+++ b/base/trace_event/etw_manifest/BUILD/message_compiler.py
@@ -0,0 +1,16 @@
+# 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.
+
+# Runs the Microsoft Message Compiler (mc.exe). This Python adapter is for the
+# GN build, which can only run Python and not native binaries.
+
+import subprocess
+import sys
+
+# mc writes to stderr, so this explicily redirects to stdout and eats it.
+try:
+  subprocess.check_output(["mc.exe"] + sys.argv[1:], stderr=subprocess.STDOUT)
+except subprocess.CalledProcessError as e:
+  print e.output
+  sys.exit(e.returncode)
diff --git a/base/trace_event/etw_manifest/chrome_events_win.man b/base/trace_event/etw_manifest/chrome_events_win.man
new file mode 100644
index 0000000..10a8ddf
--- /dev/null
+++ b/base/trace_event/etw_manifest/chrome_events_win.man
@@ -0,0 +1,84 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes'?>
+<instrumentationManifest
+    xmlns="http://schemas.microsoft.com/win/2004/08/events"
+    xmlns:win="http://manifests.microsoft.com/win/2004/08/windows/events"
+    xmlns:xs="http://www.w3.org/2001/XMLSchema"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://schemas.microsoft.com/win/2004/08/events eventman.xsd"
+    >
+  <instrumentation>
+    <events>
+      <provider
+          guid="{D2D578D9-2936-45B6-A09f-30E32715F42D}"
+          messageFileName="chrome.dll"
+          name="Chrome"
+          resourceFileName="chrome.dll"
+          symbol="CHROME"
+          >
+        <channels>
+          <importChannel
+              chid="SYSTEM"
+              name="System"
+              />
+        </channels>
+        <templates>
+          <template tid="tid_chrome_event">
+            <data
+                inType="win:AnsiString"
+                name="Name"
+                />
+            <data
+                inType="win:AnsiString"
+                name="Phase"
+                />
+            <data
+                inType="win:AnsiString"
+                name="Arg Name 1"
+                />
+            <data
+                inType="win:AnsiString"
+                name="Arg Value 1"
+                />
+            <data
+                inType="win:AnsiString"
+                name="Arg Name 2"
+                />
+            <data
+                inType="win:AnsiString"
+                name="Arg Value 2"
+                />
+            <data
+                inType="win:AnsiString"
+                name="Arg Name 3"
+                />
+            <data
+                inType="win:AnsiString"
+                name="Arg Value 3"
+                />
+          </template>
+        </templates>
+        <events>
+          <event
+              channel="SYSTEM"
+              level="win:Informational"
+              message="$(string.ChromeEvent.EventMessage)"
+              opcode="win:Info"
+              symbol="ChromeEvent"
+              template="tid_chrome_event"
+              value="1"
+              />
+        </events>
+      </provider>
+    </events>
+  </instrumentation>
+  <localization xmlns="http://schemas.microsoft.com/win/2004/08/events">
+    <resources culture="en-US">
+      <stringTable>
+        <string
+            id="ChromeEvent.EventMessage"
+            value="Chrome Event: %1 (%2)"
+            />
+      </stringTable>
+    </resources>
+  </localization>
+</instrumentationManifest>
diff --git a/base/trace_event/etw_manifest/etw_manifest.gyp b/base/trace_event/etw_manifest/etw_manifest.gyp
new file mode 100644
index 0000000..b2f0eb8
--- /dev/null
+++ b/base/trace_event/etw_manifest/etw_manifest.gyp
@@ -0,0 +1,41 @@
+# 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.
+{
+  'targets': [
+    {
+      # GN version: //base/trace_event/etw_manifest/BUILD.gn
+      'target_name': 'etw_manifest',
+      'type': 'none',
+      'toolsets': ['host', 'target'],
+      'hard_dependency': 1,
+      'conditions': [
+        ['OS=="win"', {
+          'sources': [
+            'chrome_events_win.man',
+          ],
+          'variables': {
+            'man_output_dir': '<(SHARED_INTERMEDIATE_DIR)/base/trace_event/etw_manifest',
+          },
+          'rules': [{
+            # Rule to run the message compiler.
+            'rule_name': 'message_compiler',
+            'extension': 'man',
+            'outputs': [
+              '<(man_output_dir)/chrome_events_win.h',
+              '<(man_output_dir)/chrome_events_win.rc',
+            ],
+            'action': [
+              'mc.exe',
+              '-h', '<(man_output_dir)',
+              '-r', '<(man_output_dir)/.',
+              '-um',
+              '<(RULE_INPUT_PATH)',
+            ],
+            'message': 'Running message compiler on <(RULE_INPUT_PATH)',
+          }],
+        }],
+      ],
+    }
+  ]
+}
diff --git a/base/trace_event/java_heap_dump_provider_android.cc b/base/trace_event/java_heap_dump_provider_android.cc
new file mode 100644
index 0000000..4f5986d
--- /dev/null
+++ b/base/trace_event/java_heap_dump_provider_android.cc
@@ -0,0 +1,46 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/java_heap_dump_provider_android.h"
+
+#include "base/android/java_runtime.h"
+#include "base/trace_event/process_memory_dump.h"
+
+namespace base {
+namespace trace_event {
+
+// static
+JavaHeapDumpProvider* JavaHeapDumpProvider::GetInstance() {
+  return Singleton<JavaHeapDumpProvider,
+                   LeakySingletonTraits<JavaHeapDumpProvider>>::get();
+}
+
+JavaHeapDumpProvider::JavaHeapDumpProvider() {
+}
+
+JavaHeapDumpProvider::~JavaHeapDumpProvider() {
+}
+
+// Called at trace dump point time. Creates a snapshot with the memory counters
+// for the current process.
+bool JavaHeapDumpProvider::OnMemoryDump(ProcessMemoryDump* pmd) {
+  // These numbers come from java.lang.Runtime stats.
+  long total_heap_size = 0;
+  long free_heap_size = 0;
+  android::JavaRuntime::GetMemoryUsage(&total_heap_size, &free_heap_size);
+
+  MemoryAllocatorDump* outer_dump = pmd->CreateAllocatorDump("java_heap");
+  outer_dump->AddScalar(MemoryAllocatorDump::kNameSize,
+                        MemoryAllocatorDump::kUnitsBytes, total_heap_size);
+
+  MemoryAllocatorDump* inner_dump =
+      pmd->CreateAllocatorDump("java_heap/allocated_objects");
+  inner_dump->AddScalar(MemoryAllocatorDump::kNameSize,
+                        MemoryAllocatorDump::kUnitsBytes,
+                        total_heap_size - free_heap_size);
+  return true;
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/java_heap_dump_provider_android.h b/base/trace_event/java_heap_dump_provider_android.h
new file mode 100644
index 0000000..2f31047
--- /dev/null
+++ b/base/trace_event/java_heap_dump_provider_android.h
@@ -0,0 +1,34 @@
+// 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_JAVA_HEAP_DUMP_PROVIDER_ANDROID_H_
+#define BASE_TRACE_EVENT_JAVA_HEAP_DUMP_PROVIDER_ANDROID_H_
+
+#include "base/memory/singleton.h"
+#include "base/trace_event/memory_dump_provider.h"
+
+namespace base {
+namespace trace_event {
+
+// Dump provider which collects process-wide memory stats.
+class BASE_EXPORT JavaHeapDumpProvider : public MemoryDumpProvider {
+ public:
+  static JavaHeapDumpProvider* GetInstance();
+
+  // MemoryDumpProvider implementation.
+  bool OnMemoryDump(ProcessMemoryDump* pmd) override;
+
+ private:
+  friend struct DefaultSingletonTraits<JavaHeapDumpProvider>;
+
+  JavaHeapDumpProvider();
+  ~JavaHeapDumpProvider() override;
+
+  DISALLOW_COPY_AND_ASSIGN(JavaHeapDumpProvider);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_JAVA_HEAP_DUMP_PROVIDER_ANDROID_H_
diff --git a/base/trace_event/java_heap_dump_provider_android_unittest.cc b/base/trace_event/java_heap_dump_provider_android_unittest.cc
new file mode 100644
index 0000000..bbefba5
--- /dev/null
+++ b/base/trace_event/java_heap_dump_provider_android_unittest.cc
@@ -0,0 +1,21 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/java_heap_dump_provider_android.h"
+
+#include "base/trace_event/process_memory_dump.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+TEST(JavaHeapDumpProviderTest, JavaHeapDump) {
+  auto jhdp = JavaHeapDumpProvider::GetInstance();
+  scoped_ptr<ProcessMemoryDump> pmd(new ProcessMemoryDump(nullptr));
+
+  jhdp->OnMemoryDump(pmd.get());
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/malloc_dump_provider.cc b/base/trace_event/malloc_dump_provider.cc
new file mode 100644
index 0000000..92d513f
--- /dev/null
+++ b/base/trace_event/malloc_dump_provider.cc
@@ -0,0 +1,54 @@
+// 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/malloc_dump_provider.h"
+
+#include <malloc.h>
+
+#include "base/trace_event/process_memory_dump.h"
+
+namespace base {
+namespace trace_event {
+
+// static
+const char MallocDumpProvider::kAllocatedObjects[] = "malloc/allocated_objects";
+
+// static
+MallocDumpProvider* MallocDumpProvider::GetInstance() {
+  return Singleton<MallocDumpProvider,
+                   LeakySingletonTraits<MallocDumpProvider>>::get();
+}
+
+MallocDumpProvider::MallocDumpProvider() {
+}
+
+MallocDumpProvider::~MallocDumpProvider() {
+}
+
+// Called at trace dump point time. Creates a snapshot the memory counters for
+// the current process.
+bool MallocDumpProvider::OnMemoryDump(ProcessMemoryDump* pmd) {
+  struct mallinfo info = mallinfo();
+  DCHECK_GE(info.arena + info.hblkhd, info.uordblks);
+
+  // When the system allocator is implemented by tcmalloc, the total physical
+  // size is given by |arena| and |hblkhd| is 0. In case of Android's jemalloc
+  // |arena| is 0 and the outer pages size is reported by |hblkhd|. In case of
+  // dlmalloc the total is given by |arena| + |hblkhd|.
+  // For more details see link: http://goo.gl/fMR8lF.
+  MemoryAllocatorDump* outer_dump = pmd->CreateAllocatorDump("malloc");
+  outer_dump->AddScalar(MemoryAllocatorDump::kNameSize,
+                        MemoryAllocatorDump::kUnitsBytes,
+                        info.arena + info.hblkhd);
+
+  // Total allocated space is given by |uordblks|.
+  MemoryAllocatorDump* inner_dump = pmd->CreateAllocatorDump(kAllocatedObjects);
+  inner_dump->AddScalar(MemoryAllocatorDump::kNameSize,
+                        MemoryAllocatorDump::kUnitsBytes, info.uordblks);
+
+  return true;
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/malloc_dump_provider.h b/base/trace_event/malloc_dump_provider.h
new file mode 100644
index 0000000..0a51ff7
--- /dev/null
+++ b/base/trace_event/malloc_dump_provider.h
@@ -0,0 +1,40 @@
+// 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_MALLOC_DUMP_PROVIDER_H_
+#define BASE_TRACE_EVENT_MALLOC_DUMP_PROVIDER_H_
+
+#include <istream>
+
+#include "base/memory/singleton.h"
+#include "base/trace_event/memory_dump_provider.h"
+
+namespace base {
+namespace trace_event {
+
+// Dump provider which collects process-wide memory stats.
+class BASE_EXPORT MallocDumpProvider : public MemoryDumpProvider {
+ public:
+  // Name of the allocated_objects dump. Use this to declare suballocator dumps
+  // from other dump providers.
+  static const char kAllocatedObjects[];
+
+  static MallocDumpProvider* GetInstance();
+
+  // MemoryDumpProvider implementation.
+  bool OnMemoryDump(ProcessMemoryDump* pmd) override;
+
+ private:
+  friend struct DefaultSingletonTraits<MallocDumpProvider>;
+
+  MallocDumpProvider();
+  ~MallocDumpProvider() override;
+
+  DISALLOW_COPY_AND_ASSIGN(MallocDumpProvider);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_MALLOC_DUMP_PROVIDER_H_
diff --git a/base/trace_event/memory_allocator_dump.cc b/base/trace_event/memory_allocator_dump.cc
new file mode 100644
index 0000000..4037f94
--- /dev/null
+++ b/base/trace_event/memory_allocator_dump.cc
@@ -0,0 +1,101 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/memory_allocator_dump.h"
+
+#include "base/format_macros.h"
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/memory_dump_manager.h"
+#include "base/trace_event/memory_dump_provider.h"
+#include "base/trace_event/process_memory_dump.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "base/values.h"
+
+namespace base {
+namespace trace_event {
+
+const char MemoryAllocatorDump::kNameSize[] = "size";
+const char MemoryAllocatorDump::kNameObjectsCount[] = "objects_count";
+const char MemoryAllocatorDump::kTypeScalar[] = "scalar";
+const char MemoryAllocatorDump::kTypeString[] = "string";
+const char MemoryAllocatorDump::kUnitsBytes[] = "bytes";
+const char MemoryAllocatorDump::kUnitsObjects[] = "objects";
+
+MemoryAllocatorDump::MemoryAllocatorDump(const std::string& absolute_name,
+                                         ProcessMemoryDump* process_memory_dump,
+                                         const MemoryAllocatorDumpGuid& guid)
+    : absolute_name_(absolute_name),
+      process_memory_dump_(process_memory_dump),
+      attributes_(new TracedValue),
+      guid_(guid) {
+  // The |absolute_name| cannot be empty.
+  DCHECK(!absolute_name.empty());
+
+  // The |absolute_name| can contain slash separator, but not leading or
+  // trailing ones.
+  DCHECK(absolute_name[0] != '/' && *absolute_name.rbegin() != '/');
+
+  // Dots are not allowed anywhere as the underlying base::DictionaryValue
+  // would treat them magically and split in sub-nodes, which is not intended.
+  DCHECK_EQ(std::string::npos, absolute_name.find_first_of('.'));
+}
+
+// If the caller didn't provide a guid, make one up by hashing the
+// absolute_name with the current PID.
+// Rationale: |absolute_name| is already supposed to be unique within a
+// process, the pid will make it unique among all processes.
+MemoryAllocatorDump::MemoryAllocatorDump(const std::string& absolute_name,
+                                         ProcessMemoryDump* process_memory_dump)
+    : MemoryAllocatorDump(absolute_name,
+                          process_memory_dump,
+                          MemoryAllocatorDumpGuid(StringPrintf(
+                              "%d:%s",
+                              TraceLog::GetInstance()->process_id(),
+                              absolute_name.c_str()))) {
+  string_conversion_buffer_.reserve(16);
+}
+
+MemoryAllocatorDump::~MemoryAllocatorDump() {
+}
+
+void MemoryAllocatorDump::AddScalar(const char* name,
+                                    const char* units,
+                                    uint64 value) {
+  SStringPrintf(&string_conversion_buffer_, "%" PRIx64, value);
+  attributes_->BeginDictionary(name);
+  attributes_->SetString("type", kTypeScalar);
+  attributes_->SetString("units", units);
+  attributes_->SetString("value", string_conversion_buffer_);
+  attributes_->EndDictionary();
+}
+
+void MemoryAllocatorDump::AddScalarF(const char* name,
+                                     const char* units,
+                                     double value) {
+  attributes_->BeginDictionary(name);
+  attributes_->SetString("type", kTypeScalar);
+  attributes_->SetString("units", units);
+  attributes_->SetDouble("value", value);
+  attributes_->EndDictionary();
+}
+
+void MemoryAllocatorDump::AddString(const char* name,
+                                    const char* units,
+                                    const std::string& value) {
+  attributes_->BeginDictionary(name);
+  attributes_->SetString("type", kTypeString);
+  attributes_->SetString("units", units);
+  attributes_->SetString("value", value);
+  attributes_->EndDictionary();
+}
+
+void MemoryAllocatorDump::AsValueInto(TracedValue* value) const {
+  value->BeginDictionaryWithCopiedName(absolute_name_);
+  value->SetString("guid", guid_.ToString());
+  value->SetValue("attrs", *attributes_);
+  value->EndDictionary();  // "allocator_name/heap_subheap": { ... }
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/memory_allocator_dump.h b/base/trace_event/memory_allocator_dump.h
new file mode 100644
index 0000000..c5297a5
--- /dev/null
+++ b/base/trace_event/memory_allocator_dump.h
@@ -0,0 +1,88 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_MEMORY_ALLOCATOR_DUMP_H_
+#define BASE_TRACE_EVENT_MEMORY_ALLOCATOR_DUMP_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/trace_event/memory_allocator_dump_guid.h"
+#include "base/values.h"
+
+namespace base {
+namespace trace_event {
+
+class MemoryDumpManager;
+class ProcessMemoryDump;
+class TracedValue;
+
+// Data model for user-land memory allocator dumps.
+class BASE_EXPORT MemoryAllocatorDump {
+ public:
+  // MemoryAllocatorDump is owned by ProcessMemoryDump.
+  MemoryAllocatorDump(const std::string& absolute_name,
+                      ProcessMemoryDump* process_memory_dump,
+                      const MemoryAllocatorDumpGuid& guid);
+  MemoryAllocatorDump(const std::string& absolute_name,
+                      ProcessMemoryDump* process_memory_dump);
+  ~MemoryAllocatorDump();
+
+  // Standard attribute name to model allocated space.
+  static const char kNameSize[];
+
+  // Standard attribute name to model the number of objects allocated.
+  static const char kNameObjectsCount[];
+
+  static const char kTypeScalar[];    // Type name for scalar attributes.
+  static const char kTypeString[];    // Type name for string attributes.
+  static const char kUnitsBytes[];    // Unit name to represent bytes.
+  static const char kUnitsObjects[];  // Unit name to represent #objects.
+
+  // Absolute name, unique within the scope of an entire ProcessMemoryDump.
+  const std::string& absolute_name() const { return absolute_name_; }
+
+  // Helper setter for scalar attributes.
+  void AddScalar(const char* name, const char* units, uint64 value);
+  void AddScalarF(const char* name, const char* units, double value);
+  void AddString(const char* name, const char* units, const std::string& value);
+
+  // Called at trace generation time to populate the TracedValue.
+  void AsValueInto(TracedValue* value) const;
+
+  // Get the ProcessMemoryDump instance that owns this.
+  ProcessMemoryDump* process_memory_dump() const {
+    return process_memory_dump_;
+  }
+
+  // |guid| is an optional global dump identifier, unique across all processes
+  // within the scope of a global dump. It is only required when using the
+  // graph APIs (see TODO_method_name) to express retention / suballocation or
+  // cross process sharing. See crbug.com/492102 for design docs.
+  // Subsequent MemoryAllocatorDump(s) with the same |absolute_name| are
+  // expected to have the same guid.
+  const MemoryAllocatorDumpGuid& guid() const { return guid_; }
+
+  TracedValue* attributes_for_testing() const { return attributes_.get(); }
+
+ private:
+  const std::string absolute_name_;
+  ProcessMemoryDump* const process_memory_dump_;  // Not owned (PMD owns this).
+  scoped_refptr<TracedValue> attributes_;
+  MemoryAllocatorDumpGuid guid_;
+
+  // A local buffer for Sprintf conversion on fastpath. Avoids allocating
+  // temporary strings on each AddScalar() call.
+  std::string string_conversion_buffer_;
+
+  DISALLOW_COPY_AND_ASSIGN(MemoryAllocatorDump);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_MEMORY_ALLOCATOR_DUMP_H_
diff --git a/base/trace_event/memory_allocator_dump_guid.cc b/base/trace_event/memory_allocator_dump_guid.cc
new file mode 100644
index 0000000..a4ea50d
--- /dev/null
+++ b/base/trace_event/memory_allocator_dump_guid.cc
@@ -0,0 +1,30 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/memory_allocator_dump_guid.h"
+
+#include "base/format_macros.h"
+#include "base/hash.h"
+#include "base/strings/stringprintf.h"
+
+namespace base {
+namespace trace_event {
+
+MemoryAllocatorDumpGuid::MemoryAllocatorDumpGuid(uint64 guid) : guid_(guid) {
+}
+
+MemoryAllocatorDumpGuid::MemoryAllocatorDumpGuid()
+    : MemoryAllocatorDumpGuid(0u) {
+}
+
+MemoryAllocatorDumpGuid::MemoryAllocatorDumpGuid(const std::string& guid_str)
+    : MemoryAllocatorDumpGuid(Hash(guid_str)) {
+}
+
+std::string MemoryAllocatorDumpGuid::ToString() const {
+  return StringPrintf("%" PRIx64, guid_);
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/memory_allocator_dump_guid.h b/base/trace_event/memory_allocator_dump_guid.h
new file mode 100644
index 0000000..84c12ef
--- /dev/null
+++ b/base/trace_event/memory_allocator_dump_guid.h
@@ -0,0 +1,48 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_MEMORY_ALLOCATOR_DUMP_GUID_H_
+#define BASE_TRACE_EVENT_MEMORY_ALLOCATOR_DUMP_GUID_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace trace_event {
+
+class BASE_EXPORT MemoryAllocatorDumpGuid {
+ public:
+  MemoryAllocatorDumpGuid();
+  explicit MemoryAllocatorDumpGuid(uint64 guid);
+
+  // Utility ctor to hash a GUID if the caller prefers a string. The caller
+  // still has to ensure that |guid_str| is unique, per snapshot, within the
+  // global scope of all the traced processes.
+  explicit MemoryAllocatorDumpGuid(const std::string& guid_str);
+
+  // Returns a (hex-encoded) string representation of the guid.
+  std::string ToString() const;
+
+  bool empty() const { return guid_ == 0u; }
+
+  bool operator==(const MemoryAllocatorDumpGuid& other) const {
+    return guid_ == other.guid_;
+  }
+
+  bool operator!=(const MemoryAllocatorDumpGuid& other) const {
+    return !(*this == other);
+  }
+
+ private:
+  uint64 guid_;
+
+  // Deliberately copy-able.
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_MEMORY_ALLOCATOR_DUMP_GUID_H_
diff --git a/base/trace_event/memory_allocator_dump_unittest.cc b/base/trace_event/memory_allocator_dump_unittest.cc
new file mode 100644
index 0000000..85b98d6
--- /dev/null
+++ b/base/trace_event/memory_allocator_dump_unittest.cc
@@ -0,0 +1,183 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/memory_allocator_dump.h"
+
+#include "base/format_macros.h"
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/memory_allocator_dump_guid.h"
+#include "base/trace_event/memory_dump_provider.h"
+#include "base/trace_event/memory_dump_session_state.h"
+#include "base/trace_event/process_memory_dump.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+namespace {
+
+class FakeMemoryAllocatorDumpProvider : public MemoryDumpProvider {
+ public:
+  bool OnMemoryDump(ProcessMemoryDump* pmd) override {
+    MemoryAllocatorDump* root_heap =
+        pmd->CreateAllocatorDump("foobar_allocator");
+
+    root_heap->AddScalar(MemoryAllocatorDump::kNameSize,
+                         MemoryAllocatorDump::kUnitsBytes, 4096);
+    root_heap->AddScalar(MemoryAllocatorDump::kNameObjectsCount,
+                         MemoryAllocatorDump::kUnitsObjects, 42);
+    root_heap->AddScalar("attr1", "units1", 1234);
+    root_heap->AddString("attr2", "units2", "string_value");
+    root_heap->AddScalarF("attr3", "units3", 42.5f);
+
+    MemoryAllocatorDump* sub_heap =
+        pmd->CreateAllocatorDump("foobar_allocator/sub_heap");
+    sub_heap->AddScalar(MemoryAllocatorDump::kNameSize,
+                        MemoryAllocatorDump::kUnitsBytes, 1);
+    sub_heap->AddScalar(MemoryAllocatorDump::kNameObjectsCount,
+                        MemoryAllocatorDump::kUnitsObjects, 3);
+
+    pmd->CreateAllocatorDump("foobar_allocator/sub_heap/empty");
+    // Leave the rest of sub heap deliberately uninitialized, to check that
+    // CreateAllocatorDump returns a properly zero-initialized object.
+
+    return true;
+  }
+};
+
+scoped_ptr<Value> CheckAttribute(const MemoryAllocatorDump* dump,
+                                 const std::string& name,
+                                 const char* expected_type,
+                                 const char* expected_units) {
+  scoped_ptr<Value> raw_attrs = dump->attributes_for_testing()->ToBaseValue();
+  DictionaryValue* args = nullptr;
+  DictionaryValue* arg = nullptr;
+  std::string arg_value;
+  const Value* out_value = nullptr;
+  EXPECT_TRUE(raw_attrs->GetAsDictionary(&args));
+  EXPECT_TRUE(args->GetDictionary(name, &arg));
+  EXPECT_TRUE(arg->GetString("type", &arg_value));
+  EXPECT_EQ(expected_type, arg_value);
+  EXPECT_TRUE(arg->GetString("units", &arg_value));
+  EXPECT_EQ(expected_units, arg_value);
+  EXPECT_TRUE(arg->Get("value", &out_value));
+  return out_value ? out_value->CreateDeepCopy() : scoped_ptr<Value>();
+}
+
+void CheckString(const MemoryAllocatorDump* dump,
+                 const std::string& name,
+                 const char* expected_type,
+                 const char* expected_units,
+                 const std::string& expected_value) {
+  std::string attr_str_value;
+  auto attr_value = CheckAttribute(dump, name, expected_type, expected_units);
+  EXPECT_TRUE(attr_value->GetAsString(&attr_str_value));
+  EXPECT_EQ(expected_value, attr_str_value);
+}
+
+void CheckScalar(const MemoryAllocatorDump* dump,
+                 const std::string& name,
+                 const char* expected_units,
+                 uint64 expected_value) {
+  CheckString(dump, name, MemoryAllocatorDump::kTypeScalar, expected_units,
+              StringPrintf("%" PRIx64, expected_value));
+}
+
+void CheckScalarF(const MemoryAllocatorDump* dump,
+                  const std::string& name,
+                  const char* expected_units,
+                  double expected_value) {
+  auto attr_value = CheckAttribute(dump, name, MemoryAllocatorDump::kTypeScalar,
+                                   expected_units);
+  double attr_double_value;
+  EXPECT_TRUE(attr_value->GetAsDouble(&attr_double_value));
+  EXPECT_EQ(expected_value, attr_double_value);
+}
+
+}  // namespace
+
+TEST(MemoryAllocatorDumpTest, GuidGeneration) {
+  scoped_ptr<MemoryAllocatorDump> mad(
+      new MemoryAllocatorDump("foo", nullptr, MemoryAllocatorDumpGuid(0x42u)));
+  ASSERT_EQ("42", mad->guid().ToString());
+
+  // If the dumper does not provide a Guid, the MAD will make one up on the
+  // flight. Furthermore that Guid will stay stable across across multiple
+  // snapshots if the |absolute_name| of the dump doesn't change
+  mad.reset(new MemoryAllocatorDump("bar", nullptr));
+  const MemoryAllocatorDumpGuid guid_bar = mad->guid();
+  ASSERT_FALSE(guid_bar.empty());
+  ASSERT_FALSE(guid_bar.ToString().empty());
+  ASSERT_EQ(guid_bar, mad->guid());
+
+  mad.reset(new MemoryAllocatorDump("bar", nullptr));
+  const MemoryAllocatorDumpGuid guid_bar_2 = mad->guid();
+  ASSERT_EQ(guid_bar, guid_bar_2);
+
+  mad.reset(new MemoryAllocatorDump("baz", nullptr));
+  const MemoryAllocatorDumpGuid guid_baz = mad->guid();
+  ASSERT_NE(guid_bar, guid_baz);
+}
+
+TEST(MemoryAllocatorDumpTest, DumpIntoProcessMemoryDump) {
+  FakeMemoryAllocatorDumpProvider fmadp;
+  ProcessMemoryDump pmd(make_scoped_refptr(new MemoryDumpSessionState()));
+
+  fmadp.OnMemoryDump(&pmd);
+
+  ASSERT_EQ(3u, pmd.allocator_dumps().size());
+
+  const MemoryAllocatorDump* root_heap =
+      pmd.GetAllocatorDump("foobar_allocator");
+  ASSERT_NE(nullptr, root_heap);
+  EXPECT_EQ("foobar_allocator", root_heap->absolute_name());
+  CheckScalar(root_heap, MemoryAllocatorDump::kNameSize,
+              MemoryAllocatorDump::kUnitsBytes, 4096);
+  CheckScalar(root_heap, MemoryAllocatorDump::kNameObjectsCount,
+              MemoryAllocatorDump::kUnitsObjects, 42);
+  CheckScalar(root_heap, "attr1", "units1", 1234);
+  CheckString(root_heap, "attr2", MemoryAllocatorDump::kTypeString, "units2",
+              "string_value");
+  CheckScalarF(root_heap, "attr3", "units3", 42.5f);
+
+  const MemoryAllocatorDump* sub_heap =
+      pmd.GetAllocatorDump("foobar_allocator/sub_heap");
+  ASSERT_NE(nullptr, sub_heap);
+  EXPECT_EQ("foobar_allocator/sub_heap", sub_heap->absolute_name());
+  CheckScalar(sub_heap, MemoryAllocatorDump::kNameSize,
+              MemoryAllocatorDump::kUnitsBytes, 1);
+  CheckScalar(sub_heap, MemoryAllocatorDump::kNameObjectsCount,
+              MemoryAllocatorDump::kUnitsObjects, 3);
+  const MemoryAllocatorDump* empty_sub_heap =
+      pmd.GetAllocatorDump("foobar_allocator/sub_heap/empty");
+  ASSERT_NE(nullptr, empty_sub_heap);
+  EXPECT_EQ("foobar_allocator/sub_heap/empty", empty_sub_heap->absolute_name());
+  auto raw_attrs = empty_sub_heap->attributes_for_testing()->ToBaseValue();
+  DictionaryValue* attrs = nullptr;
+  ASSERT_TRUE(raw_attrs->GetAsDictionary(&attrs));
+  ASSERT_FALSE(attrs->HasKey(MemoryAllocatorDump::kNameSize));
+  ASSERT_FALSE(attrs->HasKey(MemoryAllocatorDump::kNameObjectsCount));
+
+  // Check that the AsValueInfo doesn't hit any DCHECK.
+  scoped_refptr<TracedValue> traced_value(new TracedValue());
+  pmd.AsValueInto(traced_value.get());
+}
+
+// DEATH tests are not supported in Android / iOS.
+#if !defined(NDEBUG) && !defined(OS_ANDROID) && !defined(OS_IOS)
+TEST(MemoryAllocatorDumpTest, ForbidDuplicatesDeathTest) {
+  FakeMemoryAllocatorDumpProvider fmadp;
+  ProcessMemoryDump pmd(make_scoped_refptr(new MemoryDumpSessionState()));
+  pmd.CreateAllocatorDump("foo_allocator");
+  pmd.CreateAllocatorDump("bar_allocator/heap");
+  ASSERT_DEATH(pmd.CreateAllocatorDump("foo_allocator"), "");
+  ASSERT_DEATH(pmd.CreateAllocatorDump("bar_allocator/heap"), "");
+  ASSERT_DEATH(pmd.CreateAllocatorDump(""), "");
+}
+#endif
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/memory_dump_manager.cc b/base/trace_event/memory_dump_manager.cc
new file mode 100644
index 0000000..1e0a36a
--- /dev/null
+++ b/base/trace_event/memory_dump_manager.cc
@@ -0,0 +1,424 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/memory_dump_manager.h"
+
+#include <algorithm>
+
+#include "base/atomic_sequence_num.h"
+#include "base/compiler_specific.h"
+#include "base/trace_event/memory_dump_provider.h"
+#include "base/trace_event/memory_dump_session_state.h"
+#include "base/trace_event/process_memory_dump.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "build/build_config.h"
+
+#if !defined(OS_NACL)
+#include "base/trace_event/process_memory_totals_dump_provider.h"
+#endif
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+#include "base/trace_event/malloc_dump_provider.h"
+#include "base/trace_event/process_memory_maps_dump_provider.h"
+#endif
+
+#if defined(OS_ANDROID)
+#include "base/trace_event/java_heap_dump_provider_android.h"
+#endif
+
+#if defined(OS_WIN)
+#include "base/trace_event/winheap_dump_provider_win.h"
+#endif
+
+namespace base {
+namespace trace_event {
+
+namespace {
+
+// TODO(primiano): this should be smarter and should do something similar to
+// trace event synthetic delays.
+const char kTraceCategory[] = TRACE_DISABLED_BY_DEFAULT("memory-infra");
+
+// Throttle mmaps at a rate of once every kHeavyMmapsDumpsRate standard dumps.
+const int kHeavyMmapsDumpsRate = 8;  // 250 ms * 8 = 2000 ms.
+const int kDumpIntervalMs = 250;
+const int kTraceEventNumArgs = 1;
+const char* kTraceEventArgNames[] = {"dumps"};
+const unsigned char kTraceEventArgTypes[] = {TRACE_VALUE_TYPE_CONVERTABLE};
+
+StaticAtomicSequenceNumber g_next_guid;
+uint32 g_periodic_dumps_count = 0;
+MemoryDumpManager* g_instance_for_testing = nullptr;
+MemoryDumpProvider* g_mmaps_dump_provider = nullptr;
+
+const char* MemoryDumpTypeToString(const MemoryDumpType& dump_type) {
+  switch (dump_type) {
+    case MemoryDumpType::TASK_BEGIN:
+      return "TASK_BEGIN";
+    case MemoryDumpType::TASK_END:
+      return "TASK_END";
+    case MemoryDumpType::PERIODIC_INTERVAL:
+      return "PERIODIC_INTERVAL";
+    case MemoryDumpType::PERIODIC_INTERVAL_WITH_MMAPS:
+      return "PERIODIC_INTERVAL_WITH_MMAPS";
+    case MemoryDumpType::EXPLICITLY_TRIGGERED:
+      return "EXPLICITLY_TRIGGERED";
+  }
+  NOTREACHED();
+  return "UNKNOWN";
+}
+
+// Internal class used to hold details about ProcessMemoryDump requests for the
+// current process.
+class ProcessMemoryDumpHolder
+    : public RefCountedThreadSafe<ProcessMemoryDumpHolder> {
+ public:
+  ProcessMemoryDumpHolder(
+      MemoryDumpRequestArgs req_args,
+      const scoped_refptr<MemoryDumpSessionState>& session_state,
+      MemoryDumpCallback callback)
+      : process_memory_dump(session_state),
+        req_args(req_args),
+        callback(callback),
+        task_runner(MessageLoop::current()->task_runner()),
+        num_pending_async_requests(0) {}
+
+  ProcessMemoryDump process_memory_dump;
+  const MemoryDumpRequestArgs req_args;
+
+  // Callback passed to the initial call to CreateProcessDump().
+  MemoryDumpCallback callback;
+
+  // Thread on which FinalizeDumpAndAddToTrace() should be called, which is the
+  // same that invoked the initial CreateProcessDump().
+  const scoped_refptr<SingleThreadTaskRunner> task_runner;
+
+  // Number of pending ContinueAsyncProcessDump() calls.
+  int num_pending_async_requests;
+
+ private:
+  friend class RefCountedThreadSafe<ProcessMemoryDumpHolder>;
+  virtual ~ProcessMemoryDumpHolder() {}
+  DISALLOW_COPY_AND_ASSIGN(ProcessMemoryDumpHolder);
+};
+
+void FinalizeDumpAndAddToTrace(
+    const scoped_refptr<ProcessMemoryDumpHolder>& pmd_holder) {
+  DCHECK_EQ(0, pmd_holder->num_pending_async_requests);
+
+  if (!pmd_holder->task_runner->BelongsToCurrentThread()) {
+    pmd_holder->task_runner->PostTask(
+        FROM_HERE, Bind(&FinalizeDumpAndAddToTrace, pmd_holder));
+    return;
+  }
+
+  scoped_refptr<ConvertableToTraceFormat> event_value(new TracedValue());
+  pmd_holder->process_memory_dump.AsValueInto(
+      static_cast<TracedValue*>(event_value.get()));
+  const char* const event_name =
+      MemoryDumpTypeToString(pmd_holder->req_args.dump_type);
+
+  TRACE_EVENT_API_ADD_TRACE_EVENT(
+      TRACE_EVENT_PHASE_MEMORY_DUMP,
+      TraceLog::GetCategoryGroupEnabled(kTraceCategory), event_name,
+      pmd_holder->req_args.dump_guid, kTraceEventNumArgs, kTraceEventArgNames,
+      kTraceEventArgTypes, nullptr /* arg_values */, &event_value,
+      TRACE_EVENT_FLAG_HAS_ID);
+
+  if (!pmd_holder->callback.is_null()) {
+    pmd_holder->callback.Run(pmd_holder->req_args.dump_guid, true);
+    pmd_holder->callback.Reset();
+  }
+}
+
+void RequestPeriodicGlobalDump() {
+  MemoryDumpType dump_type = g_periodic_dumps_count == 0
+                                 ? MemoryDumpType::PERIODIC_INTERVAL_WITH_MMAPS
+                                 : MemoryDumpType::PERIODIC_INTERVAL;
+  if (++g_periodic_dumps_count == kHeavyMmapsDumpsRate)
+    g_periodic_dumps_count = 0;
+
+  MemoryDumpManager::GetInstance()->RequestGlobalDump(dump_type);
+}
+
+}  // namespace
+
+// static
+const char* const MemoryDumpManager::kTraceCategoryForTesting = kTraceCategory;
+
+// static
+MemoryDumpManager* MemoryDumpManager::GetInstance() {
+  if (g_instance_for_testing)
+    return g_instance_for_testing;
+
+  return Singleton<MemoryDumpManager,
+                   LeakySingletonTraits<MemoryDumpManager>>::get();
+}
+
+// static
+void MemoryDumpManager::SetInstanceForTesting(MemoryDumpManager* instance) {
+  if (instance)
+    instance->skip_core_dumpers_auto_registration_for_testing_ = true;
+  g_instance_for_testing = instance;
+}
+
+MemoryDumpManager::MemoryDumpManager()
+    : delegate_(nullptr),
+      memory_tracing_enabled_(0),
+      skip_core_dumpers_auto_registration_for_testing_(false) {
+  g_next_guid.GetNext();  // Make sure that first guid is not zero.
+}
+
+MemoryDumpManager::~MemoryDumpManager() {
+  base::trace_event::TraceLog::GetInstance()->RemoveEnabledStateObserver(this);
+}
+
+void MemoryDumpManager::Initialize() {
+  TRACE_EVENT0(kTraceCategory, "init");  // Add to trace-viewer category list.
+  trace_event::TraceLog::GetInstance()->AddEnabledStateObserver(this);
+
+  if (skip_core_dumpers_auto_registration_for_testing_)
+    return;
+
+  // Enable the core dump providers.
+#if !defined(OS_NACL)
+  RegisterDumpProvider(ProcessMemoryTotalsDumpProvider::GetInstance());
+#endif
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+  g_mmaps_dump_provider = ProcessMemoryMapsDumpProvider::GetInstance();
+  RegisterDumpProvider(g_mmaps_dump_provider);
+  RegisterDumpProvider(MallocDumpProvider::GetInstance());
+#endif
+
+#if defined(OS_ANDROID)
+  RegisterDumpProvider(JavaHeapDumpProvider::GetInstance());
+#endif
+
+#if defined(OS_WIN)
+  RegisterDumpProvider(WinHeapDumpProvider::GetInstance());
+#endif
+}
+
+void MemoryDumpManager::SetDelegate(MemoryDumpManagerDelegate* delegate) {
+  AutoLock lock(lock_);
+  DCHECK_EQ(static_cast<MemoryDumpManagerDelegate*>(nullptr), delegate_);
+  delegate_ = delegate;
+}
+
+void MemoryDumpManager::RegisterDumpProvider(
+    MemoryDumpProvider* mdp,
+    const scoped_refptr<SingleThreadTaskRunner>& task_runner) {
+  MemoryDumpProviderInfo mdp_info(task_runner);
+  AutoLock lock(lock_);
+  dump_providers_.insert(std::make_pair(mdp, mdp_info));
+}
+
+void MemoryDumpManager::RegisterDumpProvider(MemoryDumpProvider* mdp) {
+  RegisterDumpProvider(mdp, nullptr);
+}
+
+void MemoryDumpManager::UnregisterDumpProvider(MemoryDumpProvider* mdp) {
+  AutoLock lock(lock_);
+
+  auto it = dump_providers_.find(mdp);
+  if (it == dump_providers_.end())
+    return;
+
+  const MemoryDumpProviderInfo& mdp_info = it->second;
+  // Unregistration of a MemoryDumpProvider while tracing is ongoing is safe
+  // only if the MDP has specified a thread affinity (via task_runner()) AND
+  // the unregistration happens on the same thread (so the MDP cannot unregister
+  // and OnMemoryDump() at the same time).
+  // Otherwise, it is not possible to guarantee that its unregistration is
+  // race-free. If you hit this DCHECK, your MDP has a bug.
+  DCHECK_IMPLIES(
+      subtle::NoBarrier_Load(&memory_tracing_enabled_),
+      mdp_info.task_runner && mdp_info.task_runner->BelongsToCurrentThread())
+      << "The MemoryDumpProvider attempted to unregister itself in a racy way. "
+      << " Please file a crbug.";
+
+  // Remove from the enabled providers list. This is to deal with the case that
+  // UnregisterDumpProvider is called while the trace is enabled.
+  dump_providers_.erase(it);
+}
+
+void MemoryDumpManager::RequestGlobalDump(
+    MemoryDumpType dump_type,
+    const MemoryDumpCallback& callback) {
+  // Bail out immediately if tracing is not enabled at all.
+  if (!UNLIKELY(subtle::NoBarrier_Load(&memory_tracing_enabled_)))
+    return;
+
+  const uint64 guid =
+      TraceLog::GetInstance()->MangleEventId(g_next_guid.GetNext());
+
+  // The delegate_ is supposed to be thread safe, immutable and long lived.
+  // No need to keep the lock after we ensure that a delegate has been set.
+  MemoryDumpManagerDelegate* delegate;
+  {
+    AutoLock lock(lock_);
+    delegate = delegate_;
+  }
+
+  if (delegate) {
+    // The delegate is in charge to coordinate the request among all the
+    // processes and call the CreateLocalDumpPoint on the local process.
+    MemoryDumpRequestArgs args = {guid, dump_type};
+    delegate->RequestGlobalMemoryDump(args, callback);
+  } else if (!callback.is_null()) {
+    callback.Run(guid, false /* success */);
+  }
+}
+
+void MemoryDumpManager::RequestGlobalDump(MemoryDumpType dump_type) {
+  RequestGlobalDump(dump_type, MemoryDumpCallback());
+}
+
+// Creates a memory dump for the current process and appends it to the trace.
+void MemoryDumpManager::CreateProcessDump(const MemoryDumpRequestArgs& args,
+                                          const MemoryDumpCallback& callback) {
+  scoped_refptr<ProcessMemoryDumpHolder> pmd_holder(
+      new ProcessMemoryDumpHolder(args, session_state_, callback));
+  ProcessMemoryDump* pmd = &pmd_holder->process_memory_dump;
+  bool did_any_provider_dump = false;
+
+  // Iterate over the active dump providers and invoke OnMemoryDump(pmd).
+  // The MDM guarantees linearity (at most one MDP is active within one
+  // process) and thread-safety (MDM enforces the right locking when entering /
+  // leaving the MDP.OnMemoryDump() call). This is to simplify the clients'
+  // design
+  // and not let the MDPs worry about locking.
+  // As regards thread affinity, depending on the MDP configuration (see
+  // memory_dump_provider.h), the OnMemoryDump() invocation can happen:
+  //  - Synchronousy on the MDM thread, when MDP.task_runner() is not set.
+  //  - Posted on MDP.task_runner(), when MDP.task_runner() is set.
+  {
+    AutoLock lock(lock_);
+    for (auto it = dump_providers_.begin(); it != dump_providers_.end(); ++it) {
+      MemoryDumpProvider* mdp = it->first;
+      MemoryDumpProviderInfo* mdp_info = &it->second;
+      // Mmaps dumping is very heavyweight and cannot be performed at the same
+      // rate of other dumps. TODO(primiano): this is a hack and should be
+      // cleaned up as part of crbug.com/499731.
+      if (mdp == g_mmaps_dump_provider &&
+          args.dump_type != MemoryDumpType::PERIODIC_INTERVAL_WITH_MMAPS) {
+        continue;
+      }
+      if (mdp_info->disabled)
+        continue;
+      if (mdp_info->task_runner) {
+        // The OnMemoryDump() call must be posted.
+        bool did_post_async_task = mdp_info->task_runner->PostTask(
+            FROM_HERE, Bind(&MemoryDumpManager::ContinueAsyncProcessDump,
+                            Unretained(this), Unretained(mdp), pmd_holder));
+        // The thread underlying the TaskRunner might have gone away.
+        if (did_post_async_task)
+          ++pmd_holder->num_pending_async_requests;
+      } else {
+        // Invoke the dump provider synchronously.
+        did_any_provider_dump |= InvokeDumpProviderLocked(mdp, pmd);
+      }
+    }
+  }  // AutoLock
+
+  // If at least one synchronous provider did dump and there are no pending
+  // asynchronous requests, add the dump to the trace and invoke the callback
+  // straight away (FinalizeDumpAndAddToTrace() takes care of the callback).
+  if (did_any_provider_dump && pmd_holder->num_pending_async_requests == 0)
+    FinalizeDumpAndAddToTrace(pmd_holder);
+}
+
+// Invokes the MemoryDumpProvider.OnMemoryDump(), taking care of the fail-safe
+// logic which disables the dumper when failing (crbug.com/461788).
+bool MemoryDumpManager::InvokeDumpProviderLocked(MemoryDumpProvider* mdp,
+                                                 ProcessMemoryDump* pmd) {
+  lock_.AssertAcquired();
+  bool dump_successful = mdp->OnMemoryDump(pmd);
+  if (!dump_successful) {
+    LOG(ERROR) << "The memory dumper failed, possibly due to sandboxing "
+                  "(crbug.com/461788), disabling it for current process. Try "
+                  "restarting chrome with the --no-sandbox switch.";
+    dump_providers_.find(mdp)->second.disabled = true;
+  }
+  return dump_successful;
+}
+
+// This is posted to arbitrary threads as a continuation of CreateProcessDump(),
+// when one or more MemoryDumpProvider(s) require the OnMemoryDump() call to
+// happen on a different thread.
+void MemoryDumpManager::ContinueAsyncProcessDump(
+    MemoryDumpProvider* mdp,
+    scoped_refptr<ProcessMemoryDumpHolder> pmd_holder) {
+  bool should_finalize_dump = false;
+  {
+    // The lock here is to guarantee that different asynchronous dumps on
+    // different threads are still serialized, so that the MemoryDumpProvider
+    // has a consistent view of the |pmd| argument passed.
+    AutoLock lock(lock_);
+    ProcessMemoryDump* pmd = &pmd_holder->process_memory_dump;
+
+    // Check if the MemoryDumpProvider is still there. It might have been
+    // destroyed and unregistered while hopping threads.
+    if (dump_providers_.count(mdp))
+      InvokeDumpProviderLocked(mdp, pmd);
+
+    // Finalize the dump appending it to the trace if this was the last
+    // asynchronous request pending.
+    --pmd_holder->num_pending_async_requests;
+    if (pmd_holder->num_pending_async_requests == 0)
+      should_finalize_dump = true;
+  }  // AutoLock(lock_)
+
+  if (should_finalize_dump)
+    FinalizeDumpAndAddToTrace(pmd_holder);
+}
+
+void MemoryDumpManager::OnTraceLogEnabled() {
+  // TODO(primiano): at this point we query  TraceLog::GetCurrentCategoryFilter
+  // to figure out (and cache) which dumpers should be enabled or not.
+  // For the moment piggy back everything on the generic "memory" category.
+  bool enabled;
+  TRACE_EVENT_CATEGORY_GROUP_ENABLED(kTraceCategory, &enabled);
+
+  AutoLock lock(lock_);
+
+  // There is no point starting the tracing without a delegate.
+  if (!enabled || !delegate_) {
+    // Disable all the providers.
+    for (auto it = dump_providers_.begin(); it != dump_providers_.end(); ++it)
+      it->second.disabled = true;
+    return;
+  }
+
+  session_state_ = new MemoryDumpSessionState();
+  for (auto it = dump_providers_.begin(); it != dump_providers_.end(); ++it)
+    it->second.disabled = false;
+
+  subtle::NoBarrier_Store(&memory_tracing_enabled_, 1);
+
+  if (delegate_->IsCoordinatorProcess()) {
+    g_periodic_dumps_count = 0;
+    periodic_dump_timer_.Start(FROM_HERE,
+                               TimeDelta::FromMilliseconds(kDumpIntervalMs),
+                               base::Bind(&RequestPeriodicGlobalDump));
+  }
+}
+
+void MemoryDumpManager::OnTraceLogDisabled() {
+  AutoLock lock(lock_);
+  periodic_dump_timer_.Stop();
+  subtle::NoBarrier_Store(&memory_tracing_enabled_, 0);
+  session_state_ = nullptr;
+}
+
+MemoryDumpManager::MemoryDumpProviderInfo::MemoryDumpProviderInfo(
+    const scoped_refptr<SingleThreadTaskRunner>& task_runner)
+    : task_runner(task_runner), disabled(false) {
+}
+MemoryDumpManager::MemoryDumpProviderInfo::~MemoryDumpProviderInfo() {
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/memory_dump_manager.h b/base/trace_event/memory_dump_manager.h
new file mode 100644
index 0000000..3645ac1
--- /dev/null
+++ b/base/trace_event/memory_dump_manager.h
@@ -0,0 +1,170 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_MEMORY_DUMP_MANAGER_H_
+#define BASE_TRACE_EVENT_MEMORY_DUMP_MANAGER_H_
+
+#include <vector>
+
+#include "base/atomicops.h"
+#include "base/containers/hash_tables.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/singleton.h"
+#include "base/synchronization/lock.h"
+#include "base/timer/timer.h"
+#include "base/trace_event/memory_dump_request_args.h"
+#include "base/trace_event/trace_event.h"
+
+namespace base {
+
+class SingleThreadTaskRunner;
+
+namespace trace_event {
+
+namespace {
+class ProcessMemoryDumpHolder;
+}
+
+class MemoryDumpManagerDelegate;
+class MemoryDumpProvider;
+class ProcessMemoryDump;
+class MemoryDumpSessionState;
+
+// This is the interface exposed to the rest of the codebase to deal with
+// memory tracing. The main entry point for clients is represented by
+// RequestDumpPoint(). The extension by Un(RegisterDumpProvider).
+class BASE_EXPORT MemoryDumpManager : public TraceLog::EnabledStateObserver {
+ public:
+  static const char* const kTraceCategoryForTesting;
+
+  static MemoryDumpManager* GetInstance();
+
+  // Invoked once per process to register the TraceLog observer.
+  void Initialize();
+
+  // See the lifetime and thread-safety requirements on the delegate below in
+  // the |MemoryDumpManagerDelegate| docstring.
+  void SetDelegate(MemoryDumpManagerDelegate* delegate);
+
+  // MemoryDumpManager does NOT take memory ownership of |mdp|, which is
+  // expected to either be a singleton or unregister itself.
+  // If the optional |task_runner| argument is non-null, all the calls to the
+  // |mdp| will be issues on the given thread. Otherwise, the |mdp| should be
+  // able to handle calls on arbitrary threads.
+  void RegisterDumpProvider(
+      MemoryDumpProvider* mdp,
+      const scoped_refptr<SingleThreadTaskRunner>& task_runner);
+  void RegisterDumpProvider(MemoryDumpProvider* mdp);
+  void UnregisterDumpProvider(MemoryDumpProvider* mdp);
+
+  // Requests a memory dump. The dump might happen or not depending on the
+  // filters and categories specified when enabling tracing.
+  // The optional |callback| is executed asynchronously, on an arbitrary thread,
+  // to notify about the completion of the global dump (i.e. after all the
+  // processes have dumped) and its success (true iff all the dumps were
+  // successful).
+  void RequestGlobalDump(MemoryDumpType dump_type,
+                         const MemoryDumpCallback& callback);
+
+  // Same as above (still asynchronous), but without callback.
+  void RequestGlobalDump(MemoryDumpType dump_type);
+
+  // TraceLog::EnabledStateObserver implementation.
+  void OnTraceLogEnabled() override;
+  void OnTraceLogDisabled() override;
+
+  // Returns the MemoryDumpSessionState object, which is shared by all the
+  // ProcessMemoryDump and MemoryAllocatorDump instances through all the tracing
+  // session lifetime.
+  const scoped_refptr<MemoryDumpSessionState>& session_state() const {
+    return session_state_;
+  }
+
+ private:
+  // Descriptor struct used to hold information about registered MDPs. It is
+  // deliberately copyable, in order to allow to be used as hash_map value.
+  struct MemoryDumpProviderInfo {
+    MemoryDumpProviderInfo(
+        const scoped_refptr<SingleThreadTaskRunner>& task_runner);
+    ~MemoryDumpProviderInfo();
+
+    scoped_refptr<SingleThreadTaskRunner> task_runner;  // Optional.
+    bool disabled;  // For fail-safe logic (auto-disable failing MDPs).
+  };
+
+  friend struct DefaultDeleter<MemoryDumpManager>;  // For the testing instance.
+  friend struct DefaultSingletonTraits<MemoryDumpManager>;
+  friend class MemoryDumpManagerDelegate;
+  friend class MemoryDumpManagerTest;
+
+  static void SetInstanceForTesting(MemoryDumpManager* instance);
+
+  MemoryDumpManager();
+  virtual ~MemoryDumpManager();
+
+  // Internal, used only by MemoryDumpManagerDelegate.
+  // Creates a memory dump for the current process and appends it to the trace.
+  // |callback| will be invoked asynchronously upon completion on the same
+  // thread on which CreateProcessDump() was called.
+  void CreateProcessDump(const MemoryDumpRequestArgs& args,
+                         const MemoryDumpCallback& callback);
+
+  bool InvokeDumpProviderLocked(MemoryDumpProvider* mdp,
+                                ProcessMemoryDump* pmd);
+  void ContinueAsyncProcessDump(
+      MemoryDumpProvider* mdp,
+      scoped_refptr<ProcessMemoryDumpHolder> pmd_holder);
+
+  hash_map<MemoryDumpProvider*, MemoryDumpProviderInfo> dump_providers_;
+
+  // Shared among all the PMDs to keep state scoped to the tracing session.
+  scoped_refptr<MemoryDumpSessionState> session_state_;
+
+  MemoryDumpManagerDelegate* delegate_;  // Not owned.
+
+  // Protects from concurrent accesses to the |dump_providers_*| and |delegate_|
+  // to guard against disabling logging while dumping on another thread.
+  Lock lock_;
+
+  // Optimization to avoid attempting any memory dump (i.e. to not walk an empty
+  // dump_providers_enabled_ list) when tracing is not enabled.
+  subtle::AtomicWord memory_tracing_enabled_;
+
+  // For time-triggered periodic dumps.
+  RepeatingTimer<MemoryDumpManager> periodic_dump_timer_;
+
+  // Skips the auto-registration of the core dumpers during Initialize().
+  bool skip_core_dumpers_auto_registration_for_testing_;
+
+  DISALLOW_COPY_AND_ASSIGN(MemoryDumpManager);
+};
+
+// The delegate is supposed to be long lived (read: a Singleton) and thread
+// safe (i.e. should expect calls from any thread and handle thread hopping).
+class BASE_EXPORT MemoryDumpManagerDelegate {
+ public:
+  virtual void RequestGlobalMemoryDump(const MemoryDumpRequestArgs& args,
+                                       const MemoryDumpCallback& callback) = 0;
+
+  // Determines whether the MemoryDumpManager instance should be the master
+  // (the ones which initiates and coordinates the multiprocess dumps) or not.
+  virtual bool IsCoordinatorProcess() const = 0;
+
+ protected:
+  MemoryDumpManagerDelegate() {}
+  virtual ~MemoryDumpManagerDelegate() {}
+
+  void CreateProcessDump(const MemoryDumpRequestArgs& args,
+                         const MemoryDumpCallback& callback) {
+    MemoryDumpManager::GetInstance()->CreateProcessDump(args, callback);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MemoryDumpManagerDelegate);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_MEMORY_DUMP_MANAGER_H_
diff --git a/base/trace_event/memory_dump_manager_unittest.cc b/base/trace_event/memory_dump_manager_unittest.cc
new file mode 100644
index 0000000..3112615
--- /dev/null
+++ b/base/trace_event/memory_dump_manager_unittest.cc
@@ -0,0 +1,283 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/memory_dump_manager.h"
+
+#include "base/bind_helpers.h"
+#include "base/memory/scoped_vector.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/threading/thread.h"
+#include "base/trace_event/memory_dump_provider.h"
+#include "base/trace_event/process_memory_dump.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::Invoke;
+using testing::Return;
+
+namespace base {
+namespace trace_event {
+
+// Testing MemoryDumpManagerDelegate which short-circuits dump requests locally
+// instead of performing IPC dances.
+class MemoryDumpManagerDelegateForTesting : public MemoryDumpManagerDelegate {
+ public:
+  void RequestGlobalMemoryDump(
+      const base::trace_event::MemoryDumpRequestArgs& args,
+      const MemoryDumpCallback& callback) override {
+    CreateProcessDump(args, callback);
+  }
+
+  bool IsCoordinatorProcess() const override { return false; }
+};
+
+class MemoryDumpManagerTest : public testing::Test {
+ public:
+  void SetUp() override {
+    message_loop_.reset(new MessageLoop());
+    mdm_.reset(new MemoryDumpManager());
+    MemoryDumpManager::SetInstanceForTesting(mdm_.get());
+    ASSERT_EQ(mdm_, MemoryDumpManager::GetInstance());
+    MemoryDumpManager::GetInstance()->Initialize();
+    MemoryDumpManager::GetInstance()->SetDelegate(&delegate_);
+  }
+
+  void TearDown() override {
+    MemoryDumpManager::SetInstanceForTesting(nullptr);
+    mdm_.reset();
+    message_loop_.reset();
+    TraceLog::DeleteForTesting();
+  }
+
+  void DumpCallbackAdapter(scoped_refptr<SingleThreadTaskRunner> task_runner,
+                           Closure closure,
+                           uint64 dump_guid,
+                           bool success) {
+    task_runner->PostTask(FROM_HERE, closure);
+  }
+
+ protected:
+  const char* kTraceCategory = MemoryDumpManager::kTraceCategoryForTesting;
+
+  void EnableTracing(const char* category) {
+    TraceLog::GetInstance()->SetEnabled(
+        TraceConfig(category, ""), TraceLog::RECORDING_MODE);
+  }
+
+  void DisableTracing() { TraceLog::GetInstance()->SetDisabled(); }
+
+  scoped_ptr<MemoryDumpManager> mdm_;
+
+ private:
+  scoped_ptr<MessageLoop> message_loop_;
+  MemoryDumpManagerDelegateForTesting delegate_;
+
+  // We want our singleton torn down after each test.
+  ShadowingAtExitManager at_exit_manager_;
+};
+
+class MockDumpProvider : public MemoryDumpProvider {
+ public:
+  MockDumpProvider() : last_session_state_(nullptr) {}
+
+  // Ctor used by the RespectTaskRunnerAffinity test.
+  explicit MockDumpProvider(
+      const scoped_refptr<SingleThreadTaskRunner>& task_runner)
+      : last_session_state_(nullptr), task_runner_(task_runner) {}
+
+  virtual ~MockDumpProvider() {}
+
+  MOCK_METHOD1(OnMemoryDump, bool(ProcessMemoryDump* pmd));
+
+  // OnMemoryDump() override for the RespectTaskRunnerAffinity test.
+  bool OnMemoryDump_CheckTaskRunner(ProcessMemoryDump* pmd) {
+    EXPECT_TRUE(task_runner_->RunsTasksOnCurrentThread());
+    return true;
+  }
+
+  // OnMemoryDump() override for the SharedSessionState test.
+  bool OnMemoryDump_CheckSessionState(ProcessMemoryDump* pmd) {
+    MemoryDumpSessionState* cur_session_state = pmd->session_state().get();
+    if (last_session_state_)
+      EXPECT_EQ(last_session_state_, cur_session_state);
+    last_session_state_ = cur_session_state;
+    return true;
+  }
+
+ private:
+  MemoryDumpSessionState* last_session_state_;
+  scoped_refptr<SingleThreadTaskRunner> task_runner_;
+};
+
+TEST_F(MemoryDumpManagerTest, SingleDumper) {
+  MockDumpProvider mdp;
+  mdm_->RegisterDumpProvider(&mdp);
+
+  // Check that the dumper is not called if the memory category is not enabled.
+  EnableTracing("foo-and-bar-but-not-memory");
+  EXPECT_CALL(mdp, OnMemoryDump(_)).Times(0);
+  mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+  DisableTracing();
+
+  // Now repeat enabling the memory category and check that the dumper is
+  // invoked this time.
+  EnableTracing(kTraceCategory);
+  EXPECT_CALL(mdp, OnMemoryDump(_)).Times(3).WillRepeatedly(Return(true));
+  for (int i = 0; i < 3; ++i)
+    mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+  DisableTracing();
+
+  mdm_->UnregisterDumpProvider(&mdp);
+
+  // Finally check the unregister logic (no calls to the mdp after unregister).
+  EnableTracing(kTraceCategory);
+  EXPECT_CALL(mdp, OnMemoryDump(_)).Times(0);
+  mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+  TraceLog::GetInstance()->SetDisabled();
+}
+
+TEST_F(MemoryDumpManagerTest, SharedSessionState) {
+  MockDumpProvider mdp1;
+  MockDumpProvider mdp2;
+  mdm_->RegisterDumpProvider(&mdp1);
+  mdm_->RegisterDumpProvider(&mdp2);
+
+  EnableTracing(kTraceCategory);
+  EXPECT_CALL(mdp1, OnMemoryDump(_))
+      .Times(2)
+      .WillRepeatedly(
+          Invoke(&mdp1, &MockDumpProvider::OnMemoryDump_CheckSessionState));
+  EXPECT_CALL(mdp2, OnMemoryDump(_))
+      .Times(2)
+      .WillRepeatedly(
+          Invoke(&mdp2, &MockDumpProvider::OnMemoryDump_CheckSessionState));
+
+  for (int i = 0; i < 2; ++i)
+    mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+
+  DisableTracing();
+}
+
+TEST_F(MemoryDumpManagerTest, MultipleDumpers) {
+  MockDumpProvider mdp1;
+  MockDumpProvider mdp2;
+
+  // Enable only mdp1.
+  mdm_->RegisterDumpProvider(&mdp1);
+  EnableTracing(kTraceCategory);
+  EXPECT_CALL(mdp1, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(true));
+  EXPECT_CALL(mdp2, OnMemoryDump(_)).Times(0);
+  mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+  DisableTracing();
+
+  // Invert: enable mdp1 and disable mdp2.
+  mdm_->UnregisterDumpProvider(&mdp1);
+  mdm_->RegisterDumpProvider(&mdp2);
+  EnableTracing(kTraceCategory);
+  EXPECT_CALL(mdp1, OnMemoryDump(_)).Times(0);
+  EXPECT_CALL(mdp2, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(true));
+  mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+  DisableTracing();
+
+  // Enable both mdp1 and mdp2.
+  mdm_->RegisterDumpProvider(&mdp1);
+  EnableTracing(kTraceCategory);
+  EXPECT_CALL(mdp1, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(true));
+  EXPECT_CALL(mdp2, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(true));
+  mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+  DisableTracing();
+}
+
+// Fails on Linux TSan. http://crbug.com/499983
+#if defined(OS_LINUX)
+#define MAYBE_RespectTaskRunnerAffinity DISABLED_RespectTaskRunnerAffinity
+#else
+#define MAYBE_RespectTaskRunnerAffinity RespectTaskRunnerAffinity
+#endif
+
+// Checks that the MemoryDumpManager respects the thread affinity when a
+// MemoryDumpProvider specifies a task_runner(). The test starts creating 8
+// threads and registering a MemoryDumpProvider on each of them. At each
+// iteration, one thread is removed, to check the live unregistration logic.
+TEST_F(MemoryDumpManagerTest, MAYBE_RespectTaskRunnerAffinity) {
+  const uint32 kNumInitialThreads = 8;
+
+  ScopedVector<Thread> threads;
+  ScopedVector<MockDumpProvider> mdps;
+
+  // Create the threads and setup the expectations. Given that at each iteration
+  // we will pop out one thread/MemoryDumpProvider, each MDP is supposed to be
+  // invoked a number of times equal to its index.
+  for (uint32 i = kNumInitialThreads; i > 0; --i) {
+    threads.push_back(new Thread("test thread"));
+    threads.back()->Start();
+    mdps.push_back(new MockDumpProvider(threads.back()->task_runner()));
+    MockDumpProvider* mdp = mdps.back();
+    mdm_->RegisterDumpProvider(mdp, threads.back()->task_runner());
+    EXPECT_CALL(*mdp, OnMemoryDump(_))
+        .Times(i)
+        .WillRepeatedly(
+            Invoke(mdp, &MockDumpProvider::OnMemoryDump_CheckTaskRunner));
+  }
+
+  EnableTracing(kTraceCategory);
+
+  while (!threads.empty()) {
+    {
+      RunLoop run_loop;
+      MemoryDumpCallback callback =
+          Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this),
+               MessageLoop::current()->task_runner(), run_loop.QuitClosure());
+      mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED, callback);
+      // This nested message loop (|run_loop|) will be quit if and only if
+      // the RequestGlobalDump callback is invoked.
+      run_loop.Run();
+    }
+
+    // Unregister a MDP and destroy one thread at each iteration to check the
+    // live unregistration logic. The unregistration needs to happen on the same
+    // thread the MDP belongs to.
+    {
+      RunLoop run_loop;
+      Closure unregistration =
+          Bind(&MemoryDumpManager::UnregisterDumpProvider,
+               Unretained(mdm_.get()), Unretained(mdps.back()));
+      threads.back()->task_runner()->PostTaskAndReply(FROM_HERE, unregistration,
+                                                      run_loop.QuitClosure());
+      run_loop.Run();
+    }
+    mdps.pop_back();
+    threads.back()->Stop();
+    threads.pop_back();
+  }
+
+  DisableTracing();
+}
+
+// Enable both dump providers, make mdp1 fail and assert that only mdp2 is
+// invoked the 2nd time.
+// FIXME(primiano): remove once crbug.com/461788 gets fixed.
+TEST_F(MemoryDumpManagerTest, DisableFailingDumpers) {
+  MockDumpProvider mdp1;
+  MockDumpProvider mdp2;
+
+  mdm_->RegisterDumpProvider(&mdp1);
+  mdm_->RegisterDumpProvider(&mdp2);
+  EnableTracing(kTraceCategory);
+
+  EXPECT_CALL(mdp1, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(false));
+  EXPECT_CALL(mdp2, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(true));
+  mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+
+  EXPECT_CALL(mdp1, OnMemoryDump(_)).Times(0);
+  EXPECT_CALL(mdp2, OnMemoryDump(_)).Times(1).WillRepeatedly(Return(false));
+  mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED);
+
+  DisableTracing();
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/memory_dump_provider.h b/base/trace_event/memory_dump_provider.h
new file mode 100644
index 0000000..6e6551c
--- /dev/null
+++ b/base/trace_event/memory_dump_provider.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_MEMORY_DUMP_PROVIDER_H_
+#define BASE_TRACE_EVENT_MEMORY_DUMP_PROVIDER_H_
+
+#include "base/base_export.h"
+#include "base/macros.h"
+
+namespace base {
+namespace trace_event {
+
+class ProcessMemoryDump;
+
+// The contract interface that memory dump providers must implement.
+class BASE_EXPORT MemoryDumpProvider {
+ public:
+  // Called by the MemoryDumpManager when generating memory dumps.
+  // The embedder should return true if the |pmd| was successfully populated,
+  // false if something went wrong and the dump should be considered invalid.
+  // (Note, the MemoryDumpManager has a fail-safe logic which will disable the
+  // MemoryDumpProvider for the entire trace session if it fails consistently).
+  virtual bool OnMemoryDump(ProcessMemoryDump* pmd) = 0;
+
+ protected:
+  MemoryDumpProvider() {}
+  virtual ~MemoryDumpProvider() {}
+
+  DISALLOW_COPY_AND_ASSIGN(MemoryDumpProvider);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_MEMORY_DUMP_PROVIDER_H_
diff --git a/base/trace_event/memory_dump_request_args.h b/base/trace_event/memory_dump_request_args.h
new file mode 100644
index 0000000..6507972
--- /dev/null
+++ b/base/trace_event/memory_dump_request_args.h
@@ -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.
+
+#ifndef BASE_TRACE_EVENT_MEMORY_DUMP_REQUEST_ARGS_H_
+#define BASE_TRACE_EVENT_MEMORY_DUMP_REQUEST_ARGS_H_
+
+// This file defines the types and structs used to issue memory dump requests.
+// These are also used in the IPCs for coordinating inter-process memory dumps.
+
+#include "base/base_export.h"
+#include "base/callback.h"
+
+namespace base {
+namespace trace_event {
+
+// Captures the reason why a memory dump is being requested. This is to allow
+// selective enabling of dumps, filtering and post-processing.
+enum class MemoryDumpType {
+  TASK_BEGIN,         // Dumping memory at the beginning of a message-loop task.
+  TASK_END,           // Dumping memory at the ending of a message-loop task.
+  PERIODIC_INTERVAL,  // Dumping memory at periodic intervals.
+  PERIODIC_INTERVAL_WITH_MMAPS,  // As above but w/ heavyweight mmaps dumps.
+                                 // Temporary workaround for crbug.com/499731.
+  EXPLICITLY_TRIGGERED,  // Non maskable dump request.
+  LAST = EXPLICITLY_TRIGGERED // For IPC macros.
+};
+
+using MemoryDumpCallback = Callback<void(uint64 dump_guid, bool success)>;
+
+struct BASE_EXPORT MemoryDumpRequestArgs {
+  // Globally unique identifier. In multi-process dumps, all processes issue a
+  // local dump with the same guid. This allows the trace importers to
+  // reconstruct the global dump.
+  uint64 dump_guid;
+
+  MemoryDumpType dump_type;
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_MEMORY_DUMP_REQUEST_ARGS_H_
diff --git a/base/trace_event/memory_dump_session_state.cc b/base/trace_event/memory_dump_session_state.cc
new file mode 100644
index 0000000..433ac14
--- /dev/null
+++ b/base/trace_event/memory_dump_session_state.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/memory_dump_session_state.h"
+
+namespace base {
+namespace trace_event {
+
+MemoryDumpSessionState::MemoryDumpSessionState() {
+}
+
+MemoryDumpSessionState::~MemoryDumpSessionState() {
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/memory_dump_session_state.h b/base/trace_event/memory_dump_session_state.h
new file mode 100644
index 0000000..cf29b85
--- /dev/null
+++ b/base/trace_event/memory_dump_session_state.h
@@ -0,0 +1,31 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_MEMORY_DUMP_SESSION_STATE_H_
+#define BASE_TRACE_EVENT_MEMORY_DUMP_SESSION_STATE_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/memory/ref_counted.h"
+
+namespace base {
+namespace trace_event {
+
+// Container for state variables that should be shared across all the memory
+// dumps in a tracing session.
+class BASE_EXPORT MemoryDumpSessionState
+    : public RefCountedThreadSafe<MemoryDumpSessionState> {
+ public:
+  MemoryDumpSessionState();
+
+ private:
+  friend class RefCountedThreadSafe<MemoryDumpSessionState>;
+  ~MemoryDumpSessionState();
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_MEMORY_DUMP_SESSION_STATE_H_
diff --git a/base/trace_event/process_memory_dump.cc b/base/trace_event/process_memory_dump.cc
new file mode 100644
index 0000000..46ae1fc
--- /dev/null
+++ b/base/trace_event/process_memory_dump.cc
@@ -0,0 +1,159 @@
+// 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_dump.h"
+
+#include "base/trace_event/process_memory_totals.h"
+#include "base/trace_event/trace_event_argument.h"
+
+namespace base {
+namespace trace_event {
+
+namespace {
+const char kEdgeTypeOwnership[] = "ownership";
+
+std::string GetSharedGlobalAllocatorDumpName(
+    const MemoryAllocatorDumpGuid& guid) {
+  return "global/" + guid.ToString();
+}
+}  // namespace
+
+ProcessMemoryDump::ProcessMemoryDump(
+    const scoped_refptr<MemoryDumpSessionState>& session_state)
+    : has_process_totals_(false),
+      has_process_mmaps_(false),
+      session_state_(session_state) {
+}
+
+ProcessMemoryDump::~ProcessMemoryDump() {
+}
+
+MemoryAllocatorDump* ProcessMemoryDump::CreateAllocatorDump(
+    const std::string& absolute_name) {
+  MemoryAllocatorDump* mad = new MemoryAllocatorDump(absolute_name, this);
+  AddAllocatorDumpInternal(mad);  // Takes ownership of |mad|.
+  return mad;
+}
+
+MemoryAllocatorDump* ProcessMemoryDump::CreateAllocatorDump(
+    const std::string& absolute_name,
+    const MemoryAllocatorDumpGuid& guid) {
+  MemoryAllocatorDump* mad = new MemoryAllocatorDump(absolute_name, this, guid);
+  AddAllocatorDumpInternal(mad);  // Takes ownership of |mad|.
+  return mad;
+}
+
+void ProcessMemoryDump::AddAllocatorDumpInternal(MemoryAllocatorDump* mad) {
+  DCHECK_EQ(0ul, allocator_dumps_.count(mad->absolute_name()));
+  allocator_dumps_storage_.push_back(mad);
+  allocator_dumps_[mad->absolute_name()] = mad;
+}
+
+MemoryAllocatorDump* ProcessMemoryDump::GetAllocatorDump(
+    const std::string& absolute_name) const {
+  auto it = allocator_dumps_.find(absolute_name);
+  return it == allocator_dumps_.end() ? nullptr : it->second;
+}
+
+MemoryAllocatorDump* ProcessMemoryDump::CreateSharedGlobalAllocatorDump(
+    const MemoryAllocatorDumpGuid& guid) {
+  return CreateAllocatorDump(GetSharedGlobalAllocatorDumpName(guid), guid);
+}
+
+MemoryAllocatorDump* ProcessMemoryDump::GetSharedGlobalAllocatorDump(
+    const MemoryAllocatorDumpGuid& guid) const {
+  return GetAllocatorDump(GetSharedGlobalAllocatorDumpName(guid));
+}
+
+void ProcessMemoryDump::Clear() {
+  if (has_process_totals_) {
+    process_totals_.Clear();
+    has_process_totals_ = false;
+  }
+
+  if (has_process_mmaps_) {
+    process_mmaps_.Clear();
+    has_process_mmaps_ = false;
+  }
+
+  allocator_dumps_storage_.clear();
+  allocator_dumps_.clear();
+  allocator_dumps_edges_.clear();
+}
+
+void ProcessMemoryDump::TakeAllDumpsFrom(ProcessMemoryDump* other) {
+  DCHECK(!other->has_process_totals() && !other->has_process_mmaps());
+
+  // Moves the ownership of all MemoryAllocatorDump(s) contained in |other|
+  // into this ProcessMemoryDump.
+  for (MemoryAllocatorDump* mad : other->allocator_dumps_storage_) {
+    // Check that we don't merge duplicates.
+    DCHECK_EQ(0ul, allocator_dumps_.count(mad->absolute_name()));
+    allocator_dumps_storage_.push_back(mad);
+    allocator_dumps_[mad->absolute_name()] = mad;
+  }
+  other->allocator_dumps_storage_.weak_clear();
+  other->allocator_dumps_.clear();
+
+  // Move all the edges.
+  allocator_dumps_edges_.insert(allocator_dumps_edges_.end(),
+                                other->allocator_dumps_edges_.begin(),
+                                other->allocator_dumps_edges_.end());
+  other->allocator_dumps_edges_.clear();
+}
+
+void ProcessMemoryDump::AsValueInto(TracedValue* value) const {
+  if (has_process_totals_) {
+    value->BeginDictionary("process_totals");
+    process_totals_.AsValueInto(value);
+    value->EndDictionary();
+  }
+
+  if (has_process_mmaps_) {
+    value->BeginDictionary("process_mmaps");
+    process_mmaps_.AsValueInto(value);
+    value->EndDictionary();
+  }
+
+  if (allocator_dumps_storage_.size() > 0) {
+    value->BeginDictionary("allocators");
+    for (const MemoryAllocatorDump* allocator_dump : allocator_dumps_storage_)
+      allocator_dump->AsValueInto(value);
+    value->EndDictionary();
+  }
+
+  value->BeginArray("allocators_graph");
+  for (const MemoryAllocatorDumpEdge& edge : allocator_dumps_edges_) {
+    value->BeginDictionary();
+    value->SetString("source", edge.source.ToString());
+    value->SetString("target", edge.target.ToString());
+    value->SetInteger("importance", edge.importance);
+    value->SetString("type", edge.type);
+    value->EndDictionary();
+  }
+  value->EndArray();
+}
+
+void ProcessMemoryDump::AddOwnershipEdge(const MemoryAllocatorDumpGuid& source,
+                                         const MemoryAllocatorDumpGuid& target,
+                                         int importance) {
+  allocator_dumps_edges_.push_back(
+      {source, target, importance, kEdgeTypeOwnership});
+}
+
+void ProcessMemoryDump::AddOwnershipEdge(
+    const MemoryAllocatorDumpGuid& source,
+    const MemoryAllocatorDumpGuid& target) {
+  AddOwnershipEdge(source, target, 0 /* importance */);
+}
+
+void ProcessMemoryDump::AddSuballocation(const MemoryAllocatorDumpGuid& source,
+                                         const std::string& target_node_name) {
+  std::string child_mad_name = target_node_name + "/__" + source.ToString();
+  MemoryAllocatorDump* target_child_mad = CreateAllocatorDump(child_mad_name);
+  AddOwnershipEdge(source, target_child_mad->guid());
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/process_memory_dump.h b/base/trace_event/process_memory_dump.h
new file mode 100644
index 0000000..88ce28a
--- /dev/null
+++ b/base/trace_event/process_memory_dump.h
@@ -0,0 +1,160 @@
+// 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_DUMP_H_
+#define BASE_TRACE_EVENT_PROCESS_MEMORY_DUMP_H_
+
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/containers/hash_tables.h"
+#include "base/containers/small_map.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_vector.h"
+#include "base/trace_event/memory_allocator_dump.h"
+#include "base/trace_event/memory_allocator_dump_guid.h"
+#include "base/trace_event/memory_dump_session_state.h"
+#include "base/trace_event/process_memory_maps.h"
+#include "base/trace_event/process_memory_totals.h"
+
+namespace base {
+namespace trace_event {
+
+class ConvertableToTraceFormat;
+class MemoryDumpManager;
+class MemoryDumpSessionState;
+
+// ProcessMemoryDump is as a strongly typed container which enforces the data
+// model for each memory dump 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:
+  struct MemoryAllocatorDumpEdge {
+    MemoryAllocatorDumpGuid source;
+    MemoryAllocatorDumpGuid target;
+    int importance;
+    const char* type;
+  };
+
+  // Maps allocator dumps absolute names (allocator_name/heap/subheap) to
+  // MemoryAllocatorDump instances.
+  using AllocatorDumpsMap =
+      SmallMap<hash_map<std::string, MemoryAllocatorDump*>>;
+
+  ProcessMemoryDump(const scoped_refptr<MemoryDumpSessionState>& session_state);
+  ~ProcessMemoryDump();
+
+  // Called at trace generation time to populate the TracedValue.
+  void AsValueInto(TracedValue* value) const;
+
+  // Removes all the MemoryAllocatorDump(s) contained in this instance. This
+  // ProcessMemoryDump can be safely reused as if it was new once this returns.
+  void Clear();
+
+  // Merges all MemoryAllocatorDump(s) contained in |other| inside this
+  // ProcessMemoryDump, transferring their ownership to this instance.
+  // |other| will be an empty ProcessMemoryDump after this method returns.
+  // This is to allow dump providers to pre-populate ProcessMemoryDump instances
+  // and later move their contents into the ProcessMemoryDump passed as argument
+  // of the MemoryDumpProvider::OnMemoryDump(ProcessMemoryDump*) callback.
+  void TakeAllDumpsFrom(ProcessMemoryDump* other);
+
+  ProcessMemoryTotals* process_totals() { return &process_totals_; }
+  bool has_process_totals() const { return has_process_totals_; }
+  void set_has_process_totals() { has_process_totals_ = true; }
+
+  ProcessMemoryMaps* process_mmaps() { return &process_mmaps_; }
+  bool has_process_mmaps() const { return has_process_mmaps_; }
+  void set_has_process_mmaps() { has_process_mmaps_ = true; }
+
+  // Creates a new MemoryAllocatorDump with the given name and returns the
+  // empty object back to the caller.
+  // Arguments:
+  //   absolute_name: a name that uniquely identifies allocator dumps produced
+  //       by this provider. It is possible to specify nesting by using a
+  //       path-like string (e.g., v8/isolate1/heap1, v8/isolate1/heap2).
+  //       Leading or trailing slashes are not allowed.
+  //   guid: an optional identifier, unique among all processes within the
+  //       scope of a global dump. This is only relevant when using
+  //       AddOwnershipEdge(). If omitted, it will be automatically generated.
+  // ProcessMemoryDump handles the memory ownership of its MemoryAllocatorDumps.
+  MemoryAllocatorDump* CreateAllocatorDump(const std::string& absolute_name);
+  MemoryAllocatorDump* CreateAllocatorDump(const std::string& absolute_name,
+                                           const MemoryAllocatorDumpGuid& guid);
+
+  // Looks up a MemoryAllocatorDump given its allocator and heap names, or
+  // nullptr if not found.
+  MemoryAllocatorDump* GetAllocatorDump(const std::string& absolute_name) const;
+
+  // Creates a shared MemoryAllocatorDump, to express cross-process sharing.
+  // Shared allocator dumps are allowed to have duplicate guids within the
+  // global scope, in order to reference the same dump from multiple processes.
+  // See the design doc goo.gl/keU6Bf for reference usage patterns.
+  MemoryAllocatorDump* CreateSharedGlobalAllocatorDump(
+      const MemoryAllocatorDumpGuid& guid);
+
+  // Looks up a shared MemoryAllocatorDump given its guid.
+  MemoryAllocatorDump* GetSharedGlobalAllocatorDump(
+      const MemoryAllocatorDumpGuid& guid) const;
+
+  // Returns the map of the MemoryAllocatorDumps added to this dump.
+  const AllocatorDumpsMap& allocator_dumps() const { return allocator_dumps_; }
+
+  // Adds an ownership relationship between two MemoryAllocatorDump(s) with the
+  // semantics: |source| owns |target|, and has the effect of attributing
+  // the memory usage of |target| to |source|. |importance| is optional and
+  // relevant only for the cases of co-ownership, where it acts as a z-index:
+  // the owner with the highest importance will be attributed |target|'s memory.
+  void AddOwnershipEdge(const MemoryAllocatorDumpGuid& source,
+                        const MemoryAllocatorDumpGuid& target,
+                        int importance);
+  void AddOwnershipEdge(const MemoryAllocatorDumpGuid& source,
+                        const MemoryAllocatorDumpGuid& target);
+
+  const std::vector<MemoryAllocatorDumpEdge>& allocator_dumps_edges() const {
+    return allocator_dumps_edges_;
+  }
+
+  // Utility method to add a suballocation relationship with the following
+  // semantics: |source| is suballocated from |target_node_name|.
+  // This creates a child node of |target_node_name| and adds an ownership edge
+  // between |source| and the new child node. As a result, the UI will not
+  // account the memory of |source| in the target node.
+  void AddSuballocation(const MemoryAllocatorDumpGuid& source,
+                        const std::string& target_node_name);
+
+  const scoped_refptr<MemoryDumpSessionState>& session_state() const {
+    return session_state_;
+  }
+
+ private:
+  void AddAllocatorDumpInternal(MemoryAllocatorDump* mad);
+
+  ProcessMemoryTotals process_totals_;
+  bool has_process_totals_;
+
+  ProcessMemoryMaps process_mmaps_;
+  bool has_process_mmaps_;
+
+  AllocatorDumpsMap allocator_dumps_;
+
+  // ProcessMemoryDump handles the memory ownership of all its belongings.
+  ScopedVector<MemoryAllocatorDump> allocator_dumps_storage_;
+
+  // State shared among all PMDs instances created in a given trace session.
+  scoped_refptr<MemoryDumpSessionState> session_state_;
+
+  // Keeps track of relationships between MemoryAllocatorDump(s).
+  std::vector<MemoryAllocatorDumpEdge> allocator_dumps_edges_;
+
+  DISALLOW_COPY_AND_ASSIGN(ProcessMemoryDump);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_PROCESS_MEMORY_DUMP_H_
diff --git a/base/trace_event/process_memory_dump_unittest.cc b/base/trace_event/process_memory_dump_unittest.cc
new file mode 100644
index 0000000..1e1fbc6
--- /dev/null
+++ b/base/trace_event/process_memory_dump_unittest.cc
@@ -0,0 +1,158 @@
+// 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_dump.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "base/trace_event/memory_allocator_dump_guid.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+TEST(ProcessMemoryDumpTest, Clear) {
+  scoped_ptr<ProcessMemoryDump> pmd1(new ProcessMemoryDump(nullptr));
+  pmd1->CreateAllocatorDump("mad1");
+  pmd1->CreateAllocatorDump("mad2");
+  ASSERT_FALSE(pmd1->allocator_dumps().empty());
+
+  pmd1->process_totals()->set_resident_set_bytes(42);
+  pmd1->set_has_process_totals();
+
+  pmd1->process_mmaps()->AddVMRegion(ProcessMemoryMaps::VMRegion());
+  pmd1->set_has_process_mmaps();
+
+  pmd1->AddOwnershipEdge(MemoryAllocatorDumpGuid(42),
+                         MemoryAllocatorDumpGuid(4242));
+
+  MemoryAllocatorDumpGuid shared_mad_guid(1);
+  pmd1->CreateSharedGlobalAllocatorDump(shared_mad_guid);
+
+  pmd1->Clear();
+  ASSERT_TRUE(pmd1->allocator_dumps().empty());
+  ASSERT_TRUE(pmd1->allocator_dumps_edges().empty());
+  ASSERT_EQ(nullptr, pmd1->GetAllocatorDump("mad1"));
+  ASSERT_EQ(nullptr, pmd1->GetAllocatorDump("mad2"));
+  ASSERT_FALSE(pmd1->has_process_totals());
+  ASSERT_FALSE(pmd1->has_process_mmaps());
+  ASSERT_TRUE(pmd1->process_mmaps()->vm_regions().empty());
+  ASSERT_EQ(nullptr, pmd1->GetSharedGlobalAllocatorDump(shared_mad_guid));
+
+  // Check that calling AsValueInto() doesn't cause a crash.
+  scoped_refptr<TracedValue> traced_value(new TracedValue());
+  pmd1->AsValueInto(traced_value.get());
+
+  // Check that the pmd can be reused and behaves as expected.
+  auto mad1 = pmd1->CreateAllocatorDump("mad1");
+  auto mad3 = pmd1->CreateAllocatorDump("mad3");
+  auto shared_mad = pmd1->CreateSharedGlobalAllocatorDump(shared_mad_guid);
+  ASSERT_EQ(3u, pmd1->allocator_dumps().size());
+  ASSERT_EQ(mad1, pmd1->GetAllocatorDump("mad1"));
+  ASSERT_EQ(nullptr, pmd1->GetAllocatorDump("mad2"));
+  ASSERT_EQ(mad3, pmd1->GetAllocatorDump("mad3"));
+  ASSERT_EQ(shared_mad, pmd1->GetSharedGlobalAllocatorDump(shared_mad_guid));
+
+  traced_value = new TracedValue();
+  pmd1->AsValueInto(traced_value.get());
+
+  pmd1.reset();
+}
+
+TEST(ProcessMemoryDumpTest, TakeAllDumpsFrom) {
+  scoped_refptr<TracedValue> traced_value(new TracedValue());
+
+  scoped_ptr<ProcessMemoryDump> pmd1(new ProcessMemoryDump(nullptr));
+  auto mad1_1 = pmd1->CreateAllocatorDump("pmd1/mad1");
+  auto mad1_2 = pmd1->CreateAllocatorDump("pmd1/mad2");
+  pmd1->AddOwnershipEdge(mad1_1->guid(), mad1_2->guid());
+
+  scoped_ptr<ProcessMemoryDump> pmd2(new ProcessMemoryDump(nullptr));
+  auto mad2_1 = pmd2->CreateAllocatorDump("pmd2/mad1");
+  auto mad2_2 = pmd2->CreateAllocatorDump("pmd2/mad2");
+  pmd1->AddOwnershipEdge(mad2_1->guid(), mad2_2->guid());
+
+  MemoryAllocatorDumpGuid shared_mad_guid(1);
+  auto shared_mad = pmd2->CreateSharedGlobalAllocatorDump(shared_mad_guid);
+
+  pmd1->TakeAllDumpsFrom(pmd2.get());
+
+  // Make sure that pmd2 is empty but still usable after it has been emptied.
+  ASSERT_TRUE(pmd2->allocator_dumps().empty());
+  ASSERT_TRUE(pmd2->allocator_dumps_edges().empty());
+  pmd2->CreateAllocatorDump("pmd2/this_mad_stays_with_pmd2");
+  ASSERT_EQ(1u, pmd2->allocator_dumps().size());
+  ASSERT_EQ(1u, pmd2->allocator_dumps().count("pmd2/this_mad_stays_with_pmd2"));
+  pmd2->AddOwnershipEdge(MemoryAllocatorDumpGuid(42),
+                         MemoryAllocatorDumpGuid(4242));
+
+  // Check that calling AsValueInto() doesn't cause a crash.
+  pmd2->AsValueInto(traced_value.get());
+
+  // Free the |pmd2| to check that the memory ownership of the two MAD(s)
+  // has been transferred to |pmd1|.
+  pmd2.reset();
+
+  // Now check that |pmd1| has been effectively merged.
+  ASSERT_EQ(5u, pmd1->allocator_dumps().size());
+  ASSERT_EQ(1u, pmd1->allocator_dumps().count("pmd1/mad1"));
+  ASSERT_EQ(1u, pmd1->allocator_dumps().count("pmd1/mad2"));
+  ASSERT_EQ(1u, pmd1->allocator_dumps().count("pmd2/mad1"));
+  ASSERT_EQ(1u, pmd1->allocator_dumps().count("pmd1/mad2"));
+  ASSERT_EQ(2u, pmd1->allocator_dumps_edges().size());
+  ASSERT_EQ(shared_mad, pmd1->GetSharedGlobalAllocatorDump(shared_mad_guid));
+
+  // Check that calling AsValueInto() doesn't cause a crash.
+  traced_value = new TracedValue();
+  pmd1->AsValueInto(traced_value.get());
+
+  pmd1.reset();
+}
+
+TEST(ProcessMemoryDumpTest, Suballocations) {
+  scoped_ptr<ProcessMemoryDump> pmd(new ProcessMemoryDump(nullptr));
+  const std::string allocator_dump_name = "fakealloc/allocated_objects";
+  pmd->CreateAllocatorDump(allocator_dump_name);
+
+  // Create one allocation with an auto-assigned guid and mark it as a
+  // suballocation of "fakealloc/allocated_objects".
+  auto pic1_dump = pmd->CreateAllocatorDump("picturemanager/picture1");
+  pmd->AddSuballocation(pic1_dump->guid(), allocator_dump_name);
+
+  // Same here, but this time create an allocation with an explicit guid.
+  auto pic2_dump = pmd->CreateAllocatorDump("picturemanager/picture2",
+                                            MemoryAllocatorDumpGuid(0x42));
+  pmd->AddSuballocation(pic2_dump->guid(), allocator_dump_name);
+
+  // Now check that AddSuballocation() has created anonymous child dumps under
+  // "fakealloc/allocated_objects".
+  auto anon_node_1_it = pmd->allocator_dumps().find(
+      allocator_dump_name + "/__" + pic1_dump->guid().ToString());
+  ASSERT_NE(pmd->allocator_dumps().end(), anon_node_1_it);
+
+  auto anon_node_2_it =
+      pmd->allocator_dumps().find(allocator_dump_name + "/__42");
+  ASSERT_NE(pmd->allocator_dumps().end(), anon_node_2_it);
+
+  // Finally check that AddSuballocation() has created also the
+  // edges between the pictures and the anonymous allocator child dumps.
+  bool found_edge[2]{false, false};
+  for (const auto& e : pmd->allocator_dumps_edges()) {
+    found_edge[0] |= (e.source == pic1_dump->guid() &&
+                      e.target == anon_node_1_it->second->guid());
+    found_edge[1] |= (e.source == pic2_dump->guid() &&
+                      e.target == anon_node_2_it->second->guid());
+  }
+  ASSERT_TRUE(found_edge[0]);
+  ASSERT_TRUE(found_edge[1]);
+
+  // Check that calling AsValueInto() doesn't cause a crash.
+  scoped_refptr<TracedValue> traced_value(new TracedValue());
+  pmd->AsValueInto(traced_value.get());
+
+  pmd.reset();
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/process_memory_maps.cc b/base/trace_event/process_memory_maps.cc
new file mode 100644
index 0000000..bb400de
--- /dev/null
+++ b/base/trace_event/process_memory_maps.cc
@@ -0,0 +1,74 @@
+// 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_maps.h"
+
+#include "base/format_macros.h"
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event_argument.h"
+
+namespace base {
+namespace trace_event {
+
+// static
+const uint32 ProcessMemoryMaps::VMRegion::kProtectionFlagsRead = 4;
+const uint32 ProcessMemoryMaps::VMRegion::kProtectionFlagsWrite = 2;
+const uint32 ProcessMemoryMaps::VMRegion::kProtectionFlagsExec = 1;
+
+ProcessMemoryMaps::VMRegion::VMRegion()
+    : start_address(0),
+      size_in_bytes(0),
+      protection_flags(0),
+      byte_stats_private_dirty_resident(0),
+      byte_stats_private_clean_resident(0),
+      byte_stats_shared_dirty_resident(0),
+      byte_stats_shared_clean_resident(0),
+      byte_stats_swapped(0),
+      byte_stats_proportional_resident(0) {
+}
+
+ProcessMemoryMaps::ProcessMemoryMaps() {
+}
+
+ProcessMemoryMaps::~ProcessMemoryMaps() {
+}
+
+void ProcessMemoryMaps::AsValueInto(TracedValue* value) const {
+  static const char kHexFmt[] = "%" PRIx64;
+
+  // Refer to the design doc goo.gl/sxfFY8 for the semantic of these fields.
+  value->BeginArray("vm_regions");
+  for (const auto& region : vm_regions_) {
+    value->BeginDictionary();
+
+    value->SetString("sa", StringPrintf(kHexFmt, region.start_address));
+    value->SetString("sz", StringPrintf(kHexFmt, region.size_in_bytes));
+    value->SetInteger("pf", region.protection_flags);
+    value->SetString("mf", region.mapped_file);
+
+    value->BeginDictionary("bs");  // byte stats
+    value->SetString(
+        "pss", StringPrintf(kHexFmt, region.byte_stats_proportional_resident));
+    value->SetString(
+        "pd", StringPrintf(kHexFmt, region.byte_stats_private_dirty_resident));
+    value->SetString(
+        "pc", StringPrintf(kHexFmt, region.byte_stats_private_clean_resident));
+    value->SetString(
+        "sd", StringPrintf(kHexFmt, region.byte_stats_shared_dirty_resident));
+    value->SetString(
+        "sc", StringPrintf(kHexFmt, region.byte_stats_shared_clean_resident));
+    value->SetString("sw", StringPrintf(kHexFmt, region.byte_stats_swapped));
+    value->EndDictionary();
+
+    value->EndDictionary();
+  }
+  value->EndArray();
+}
+
+void ProcessMemoryMaps::Clear() {
+  vm_regions_.clear();
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/process_memory_maps.h b/base/trace_event/process_memory_maps.h
new file mode 100644
index 0000000..b06a850
--- /dev/null
+++ b/base/trace_event/process_memory_maps.h
@@ -0,0 +1,68 @@
+// 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_MAPS_H_
+#define BASE_TRACE_EVENT_PROCESS_MEMORY_MAPS_H_
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace trace_event {
+
+class TracedValue;
+
+// Data model for process-wide memory stats.
+class BASE_EXPORT ProcessMemoryMaps {
+ public:
+  struct BASE_EXPORT VMRegion {
+    static const uint32 kProtectionFlagsRead;
+    static const uint32 kProtectionFlagsWrite;
+    static const uint32 kProtectionFlagsExec;
+
+    VMRegion();
+
+    uint64 start_address;
+    uint64 size_in_bytes;
+    uint32 protection_flags;
+    std::string mapped_file;
+
+    // private_dirty_resident + private_clean_resident + shared_dirty_resident +
+    // shared_clean_resident = resident set size.
+    uint64 byte_stats_private_dirty_resident;
+    uint64 byte_stats_private_clean_resident;
+    uint64 byte_stats_shared_dirty_resident;
+    uint64 byte_stats_shared_clean_resident;
+
+    uint64 byte_stats_swapped;
+
+    // For multiprocess accounting.
+    uint64 byte_stats_proportional_resident;
+  };
+
+  ProcessMemoryMaps();
+  ~ProcessMemoryMaps();
+
+  void AddVMRegion(const VMRegion& region) { vm_regions_.push_back(region); }
+  const std::vector<VMRegion>& vm_regions() const { return vm_regions_; }
+
+  // Called at trace generation time to populate the TracedValue.
+  void AsValueInto(TracedValue* value) const;
+
+  // Clears up all the VMRegion(s) stored.
+  void Clear();
+
+ private:
+  std::vector<VMRegion> vm_regions_;
+
+  DISALLOW_COPY_AND_ASSIGN(ProcessMemoryMaps);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_PROCESS_MEMORY_MAPS_H_
diff --git a/base/trace_event/process_memory_maps_dump_provider.cc b/base/trace_event/process_memory_maps_dump_provider.cc
new file mode 100644
index 0000000..e0ae20d
--- /dev/null
+++ b/base/trace_event/process_memory_maps_dump_provider.cc
@@ -0,0 +1,191 @@
+// 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_maps_dump_provider.h"
+
+#include <cctype>
+#include <fstream>
+
+#include "base/logging.h"
+#include "base/process/process_metrics.h"
+#include "base/trace_event/process_memory_dump.h"
+#include "base/trace_event/process_memory_maps.h"
+
+namespace base {
+namespace trace_event {
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+// static
+std::istream* ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = nullptr;
+
+namespace {
+
+const uint32 kMaxLineSize = 4096;
+
+bool ParseSmapsHeader(std::istream* smaps,
+                      ProcessMemoryMaps::VMRegion* region) {
+  // e.g., "00400000-00421000 r-xp 00000000 fc:01 1234  /foo.so\n"
+  bool res = true;  // Whether this region should be appended or skipped.
+  uint64 end_addr;
+  std::string protection_flags;
+  std::string ignored;
+  *smaps >> std::hex >> region->start_address;
+  smaps->ignore(1);
+  *smaps >> std::hex >> end_addr;
+  if (end_addr > region->start_address) {
+    region->size_in_bytes = end_addr - region->start_address;
+  } else {
+    // This is not just paranoia, it can actually happen (See crbug.com/461237).
+    region->size_in_bytes = 0;
+    res = false;
+  }
+
+  region->protection_flags = 0;
+  *smaps >> protection_flags;
+  CHECK_EQ(4UL, protection_flags.size());
+  if (protection_flags[0] == 'r') {
+    region->protection_flags |=
+        ProcessMemoryMaps::VMRegion::kProtectionFlagsRead;
+  }
+  if (protection_flags[1] == 'w') {
+    region->protection_flags |=
+        ProcessMemoryMaps::VMRegion::kProtectionFlagsWrite;
+  }
+  if (protection_flags[2] == 'x') {
+    region->protection_flags |=
+        ProcessMemoryMaps::VMRegion::kProtectionFlagsExec;
+  }
+  *smaps >> ignored;  // Ignore mapped file offset.
+  *smaps >> ignored;  // Ignore device maj-min (fc:01 in the example above).
+  *smaps >> ignored;  // Ignore inode number (1234 in the example above).
+
+  while (smaps->peek() == ' ')
+    smaps->ignore(1);
+  char mapped_file[kMaxLineSize];
+  smaps->getline(mapped_file, sizeof(mapped_file));
+  region->mapped_file = mapped_file;
+
+  return res;
+}
+
+uint64 ReadCounterBytes(std::istream* smaps) {
+  uint64 counter_value = 0;
+  *smaps >> std::dec >> counter_value;
+  return counter_value * 1024;
+}
+
+uint32 ParseSmapsCounter(std::istream* smaps,
+                         ProcessMemoryMaps::VMRegion* region) {
+  // A smaps counter lines looks as follows: "RSS:  0 Kb\n"
+  uint32 res = 1;
+  std::string counter_name;
+  *smaps >> counter_name;
+
+  // TODO(primiano): "Swap" should also be accounted as resident. Check
+  // whether Rss isn't already counting swapped and fix below if that is
+  // the case.
+  if (counter_name == "Pss:") {
+    region->byte_stats_proportional_resident = ReadCounterBytes(smaps);
+  } else if (counter_name == "Private_Dirty:") {
+    region->byte_stats_private_dirty_resident = ReadCounterBytes(smaps);
+  } else if (counter_name == "Private_Clean:") {
+    region->byte_stats_private_clean_resident = ReadCounterBytes(smaps);
+  } else if (counter_name == "Shared_Dirty:") {
+    region->byte_stats_shared_dirty_resident = ReadCounterBytes(smaps);
+  } else if (counter_name == "Shared_Clean:") {
+    region->byte_stats_shared_clean_resident = ReadCounterBytes(smaps);
+  } else if (counter_name == "Swap:") {
+    region->byte_stats_swapped = ReadCounterBytes(smaps);
+  } else {
+    res = 0;
+  }
+
+#ifndef NDEBUG
+  // Paranoid check against changes of the Kernel /proc interface.
+  if (res) {
+    std::string unit;
+    *smaps >> unit;
+    DCHECK_EQ("kB", unit);
+  }
+#endif
+
+  smaps->ignore(kMaxLineSize, '\n');
+
+  return res;
+}
+
+uint32 ReadLinuxProcSmapsFile(std::istream* smaps, ProcessMemoryMaps* pmm) {
+  if (!smaps->good())
+    return 0;
+
+  const uint32 kNumExpectedCountersPerRegion = 6;
+  uint32 counters_parsed_for_current_region = 0;
+  uint32 num_valid_regions = 0;
+  ProcessMemoryMaps::VMRegion region;
+  bool should_add_current_region = false;
+  for (;;) {
+    int next = smaps->peek();
+    if (next == std::ifstream::traits_type::eof() || next == '\n')
+      break;
+    if (isxdigit(next) && !isupper(next)) {
+      region = ProcessMemoryMaps::VMRegion();
+      counters_parsed_for_current_region = 0;
+      should_add_current_region = ParseSmapsHeader(smaps, &region);
+    } else {
+      counters_parsed_for_current_region += ParseSmapsCounter(smaps, &region);
+      DCHECK_LE(counters_parsed_for_current_region,
+                kNumExpectedCountersPerRegion);
+      if (counters_parsed_for_current_region == kNumExpectedCountersPerRegion) {
+        if (should_add_current_region) {
+          pmm->AddVMRegion(region);
+          ++num_valid_regions;
+          should_add_current_region = false;
+        }
+      }
+    }
+  }
+  return num_valid_regions;
+}
+
+}  // namespace
+#endif  // defined(OS_LINUX) || defined(OS_ANDROID)
+
+// static
+ProcessMemoryMapsDumpProvider* ProcessMemoryMapsDumpProvider::GetInstance() {
+  return Singleton<ProcessMemoryMapsDumpProvider,
+                   LeakySingletonTraits<ProcessMemoryMapsDumpProvider>>::get();
+}
+
+ProcessMemoryMapsDumpProvider::ProcessMemoryMapsDumpProvider() {
+}
+
+ProcessMemoryMapsDumpProvider::~ProcessMemoryMapsDumpProvider() {
+}
+
+// Called at trace dump point time. Creates a snapshot the memory maps for the
+// current process.
+bool ProcessMemoryMapsDumpProvider::OnMemoryDump(ProcessMemoryDump* pmd) {
+  uint32 res = 0;
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+  if (UNLIKELY(proc_smaps_for_testing)) {
+    res = ReadLinuxProcSmapsFile(proc_smaps_for_testing, pmd->process_mmaps());
+  } else {
+    std::ifstream proc_self_smaps("/proc/self/smaps");
+    res = ReadLinuxProcSmapsFile(&proc_self_smaps, pmd->process_mmaps());
+  }
+#else
+  LOG(ERROR) << "ProcessMemoryMaps dump provider is supported only on Linux";
+#endif
+
+  if (res > 0) {
+    pmd->set_has_process_mmaps();
+    return true;
+  }
+
+  return false;
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/process_memory_maps_dump_provider.h b/base/trace_event/process_memory_maps_dump_provider.h
new file mode 100644
index 0000000..c73c4d2
--- /dev/null
+++ b/base/trace_event/process_memory_maps_dump_provider.h
@@ -0,0 +1,42 @@
+// 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_MAPS_DUMP_PROVIDER_H_
+#define BASE_TRACE_EVENT_PROCESS_MEMORY_MAPS_DUMP_PROVIDER_H_
+
+#include <istream>
+
+#include "base/gtest_prod_util.h"
+#include "base/memory/singleton.h"
+#include "base/trace_event/memory_dump_provider.h"
+
+namespace base {
+namespace trace_event {
+
+// Dump provider which collects process-wide memory stats.
+class BASE_EXPORT ProcessMemoryMapsDumpProvider : public MemoryDumpProvider {
+ public:
+  static ProcessMemoryMapsDumpProvider* GetInstance();
+
+  // MemoryDumpProvider implementation.
+  bool OnMemoryDump(ProcessMemoryDump* pmd) override;
+
+ private:
+  friend struct DefaultSingletonTraits<ProcessMemoryMapsDumpProvider>;
+  FRIEND_TEST_ALL_PREFIXES(ProcessMemoryMapsDumpProviderTest, ParseProcSmaps);
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+  static std::istream* proc_smaps_for_testing;
+#endif
+
+  ProcessMemoryMapsDumpProvider();
+  ~ProcessMemoryMapsDumpProvider() override;
+
+  DISALLOW_COPY_AND_ASSIGN(ProcessMemoryMapsDumpProvider);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_PROCESS_MEMORY_MAPS_DUMP_PROVIDER_H_
diff --git a/base/trace_event/process_memory_maps_dump_provider_unittest.cc b/base/trace_event/process_memory_maps_dump_provider_unittest.cc
new file mode 100644
index 0000000..5416e11
--- /dev/null
+++ b/base/trace_event/process_memory_maps_dump_provider_unittest.cc
@@ -0,0 +1,184 @@
+// 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_maps_dump_provider.h"
+
+#include <fstream>
+#include <sstream>
+
+#include "base/trace_event/process_memory_dump.h"
+#include "base/trace_event/process_memory_maps.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+namespace {
+const char kTestSmaps1[] =
+    "00400000-004be000 r-xp 00000000 fc:01 1234              /file/1\n"
+    "Size:                760 kB\n"
+    "Rss:                 296 kB\n"
+    "Pss:                 162 kB\n"
+    "Shared_Clean:        228 kB\n"
+    "Shared_Dirty:          0 kB\n"
+    "Private_Clean:         0 kB\n"
+    "Private_Dirty:        68 kB\n"
+    "Referenced:          296 kB\n"
+    "Anonymous:            68 kB\n"
+    "AnonHugePages:         0 kB\n"
+    "Swap:                  4 kB\n"
+    "KernelPageSize:        4 kB\n"
+    "MMUPageSize:           4 kB\n"
+    "Locked:                0 kB\n"
+    "VmFlags: rd ex mr mw me dw sd\n"
+    "ff000000-ff800000 -w-p 00001080 fc:01 0            /file/name with space\n"
+    "Size:                  0 kB\n"
+    "Rss:                 192 kB\n"
+    "Pss:                 128 kB\n"
+    "Shared_Clean:        120 kB\n"
+    "Shared_Dirty:          4 kB\n"
+    "Private_Clean:        60 kB\n"
+    "Private_Dirty:         8 kB\n"
+    "Referenced:          296 kB\n"
+    "Anonymous:             0 kB\n"
+    "AnonHugePages:         0 kB\n"
+    "Swap:                  0 kB\n"
+    "KernelPageSize:        4 kB\n"
+    "MMUPageSize:           4 kB\n"
+    "Locked:                0 kB\n"
+    "VmFlags: rd ex mr mw me dw sd";
+
+const char kTestSmaps2[] =
+    // An invalid region, with zero size and overlapping with the last one
+    // (See crbug.com/461237).
+    "7fe7ce79c000-7fe7ce79c000 ---p 00000000 00:00 0 \n"
+    "Size:                  4 kB\n"
+    "Rss:                   0 kB\n"
+    "Pss:                   0 kB\n"
+    "Shared_Clean:          0 kB\n"
+    "Shared_Dirty:          0 kB\n"
+    "Private_Clean:         0 kB\n"
+    "Private_Dirty:         0 kB\n"
+    "Referenced:            0 kB\n"
+    "Anonymous:             0 kB\n"
+    "AnonHugePages:         0 kB\n"
+    "Swap:                  0 kB\n"
+    "KernelPageSize:        4 kB\n"
+    "MMUPageSize:           4 kB\n"
+    "Locked:                0 kB\n"
+    "VmFlags: rd ex mr mw me dw sd\n"
+    // A invalid region with its range going backwards.
+    "00400000-00200000 ---p 00000000 00:00 0 \n"
+    "Size:                  4 kB\n"
+    "Rss:                   0 kB\n"
+    "Pss:                   0 kB\n"
+    "Shared_Clean:          0 kB\n"
+    "Shared_Dirty:          0 kB\n"
+    "Private_Clean:         0 kB\n"
+    "Private_Dirty:         0 kB\n"
+    "Referenced:            0 kB\n"
+    "Anonymous:             0 kB\n"
+    "AnonHugePages:         0 kB\n"
+    "Swap:                  0 kB\n"
+    "KernelPageSize:        4 kB\n"
+    "MMUPageSize:           4 kB\n"
+    "Locked:                0 kB\n"
+    "VmFlags: rd ex mr mw me dw sd\n"
+    // A good anonymous region at the end.
+    "7fe7ce79c000-7fe7ce7a8000 ---p 00000000 00:00 0 \n"
+    "Size:                 48 kB\n"
+    "Rss:                  40 kB\n"
+    "Pss:                  32 kB\n"
+    "Shared_Clean:         16 kB\n"
+    "Shared_Dirty:         12 kB\n"
+    "Private_Clean:         8 kB\n"
+    "Private_Dirty:         4 kB\n"
+    "Referenced:           40 kB\n"
+    "Anonymous:            16 kB\n"
+    "AnonHugePages:         0 kB\n"
+    "Swap:                  0 kB\n"
+    "KernelPageSize:        4 kB\n"
+    "MMUPageSize:           4 kB\n"
+    "Locked:                0 kB\n"
+    "VmFlags: rd wr mr mw me ac sd\n";
+}  // namespace
+
+TEST(ProcessMemoryMapsDumpProviderTest, ParseProcSmaps) {
+  const uint32 kProtR = ProcessMemoryMaps::VMRegion::kProtectionFlagsRead;
+  const uint32 kProtW = ProcessMemoryMaps::VMRegion::kProtectionFlagsWrite;
+  const uint32 kProtX = ProcessMemoryMaps::VMRegion::kProtectionFlagsExec;
+
+  auto pmmdp = ProcessMemoryMapsDumpProvider::GetInstance();
+
+  // Emulate a non-existent /proc/self/smaps.
+  ProcessMemoryDump pmd_invalid(nullptr /* session_state */);
+  std::ifstream non_existent_file("/tmp/does-not-exist");
+  ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = &non_existent_file;
+  CHECK_EQ(false, non_existent_file.good());
+  pmmdp->OnMemoryDump(&pmd_invalid);
+  ASSERT_FALSE(pmd_invalid.has_process_mmaps());
+
+  // Emulate an empty /proc/self/smaps.
+  std::ifstream empty_file("/dev/null");
+  ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = &empty_file;
+  CHECK_EQ(true, empty_file.good());
+  pmmdp->OnMemoryDump(&pmd_invalid);
+  ASSERT_FALSE(pmd_invalid.has_process_mmaps());
+
+  // Parse the 1st smaps file.
+  ProcessMemoryDump pmd_1(nullptr /* session_state */);
+  std::istringstream test_smaps_1(kTestSmaps1);
+  ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = &test_smaps_1;
+  pmmdp->OnMemoryDump(&pmd_1);
+  ASSERT_TRUE(pmd_1.has_process_mmaps());
+  const auto& regions_1 = pmd_1.process_mmaps()->vm_regions();
+  ASSERT_EQ(2UL, regions_1.size());
+
+  EXPECT_EQ(0x00400000UL, regions_1[0].start_address);
+  EXPECT_EQ(0x004be000UL - 0x00400000UL, regions_1[0].size_in_bytes);
+  EXPECT_EQ(kProtR | kProtX, regions_1[0].protection_flags);
+  EXPECT_EQ("/file/1", regions_1[0].mapped_file);
+  EXPECT_EQ(162 * 1024UL, regions_1[0].byte_stats_proportional_resident);
+  EXPECT_EQ(228 * 1024UL, regions_1[0].byte_stats_shared_clean_resident);
+  EXPECT_EQ(0UL, regions_1[0].byte_stats_shared_dirty_resident);
+  EXPECT_EQ(0UL, regions_1[0].byte_stats_private_clean_resident);
+  EXPECT_EQ(68 * 1024UL, regions_1[0].byte_stats_private_dirty_resident);
+  EXPECT_EQ(4 * 1024UL, regions_1[0].byte_stats_swapped);
+
+  EXPECT_EQ(0xff000000UL, regions_1[1].start_address);
+  EXPECT_EQ(0xff800000UL - 0xff000000UL, regions_1[1].size_in_bytes);
+  EXPECT_EQ(kProtW, regions_1[1].protection_flags);
+  EXPECT_EQ("/file/name with space", regions_1[1].mapped_file);
+  EXPECT_EQ(128 * 1024UL, regions_1[1].byte_stats_proportional_resident);
+  EXPECT_EQ(120 * 1024UL, regions_1[1].byte_stats_shared_clean_resident);
+  EXPECT_EQ(4 * 1024UL, regions_1[1].byte_stats_shared_dirty_resident);
+  EXPECT_EQ(60 * 1024UL, regions_1[1].byte_stats_private_clean_resident);
+  EXPECT_EQ(8 * 1024UL, regions_1[1].byte_stats_private_dirty_resident);
+  EXPECT_EQ(0 * 1024UL, regions_1[1].byte_stats_swapped);
+
+  // Parse the 2nd smaps file.
+  ProcessMemoryDump pmd_2(nullptr /* session_state */);
+  std::istringstream test_smaps_2(kTestSmaps2);
+  ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = &test_smaps_2;
+  pmmdp->OnMemoryDump(&pmd_2);
+  ASSERT_TRUE(pmd_2.has_process_mmaps());
+  const auto& regions_2 = pmd_2.process_mmaps()->vm_regions();
+  ASSERT_EQ(1UL, regions_2.size());
+  EXPECT_EQ(0x7fe7ce79c000UL, regions_2[0].start_address);
+  EXPECT_EQ(0x7fe7ce7a8000UL - 0x7fe7ce79c000UL, regions_2[0].size_in_bytes);
+  EXPECT_EQ(0U, regions_2[0].protection_flags);
+  EXPECT_EQ("", regions_2[0].mapped_file);
+  EXPECT_EQ(32 * 1024UL, regions_2[0].byte_stats_proportional_resident);
+  EXPECT_EQ(16 * 1024UL, regions_2[0].byte_stats_shared_clean_resident);
+  EXPECT_EQ(12 * 1024UL, regions_2[0].byte_stats_shared_dirty_resident);
+  EXPECT_EQ(8 * 1024UL, regions_2[0].byte_stats_private_clean_resident);
+  EXPECT_EQ(4 * 1024UL, regions_2[0].byte_stats_private_dirty_resident);
+  EXPECT_EQ(0 * 1024UL, regions_2[0].byte_stats_swapped);
+}
+#endif  // defined(OS_LINUX) || defined(OS_ANDROID)
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/process_memory_totals.cc b/base/trace_event/process_memory_totals.cc
new file mode 100644
index 0000000..1270924
--- /dev/null
+++ b/base/trace_event/process_memory_totals.cc
@@ -0,0 +1,35 @@
+// 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/format_macros.h"
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event_argument.h"
+
+namespace base {
+namespace trace_event {
+
+ProcessMemoryTotals::ProcessMemoryTotals()
+    : resident_set_bytes_(0),
+      peak_resident_set_bytes_(0),
+      is_peak_rss_resetable_(false) {
+}
+
+void ProcessMemoryTotals::AsValueInto(TracedValue* value) const {
+  value->SetString("resident_set_bytes",
+                   StringPrintf("%" PRIx64, resident_set_bytes_));
+  if (peak_resident_set_bytes_ > 0) {
+    value->SetString("peak_resident_set_bytes",
+                     StringPrintf("%" PRIx64, peak_resident_set_bytes_));
+    value->SetBoolean("is_peak_rss_resetable", is_peak_rss_resetable_);
+  }
+}
+
+void ProcessMemoryTotals::Clear() {
+  resident_set_bytes_ = 0;
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/process_memory_totals.h b/base/trace_event/process_memory_totals.h
new file mode 100644
index 0000000..1bf8bdc
--- /dev/null
+++ b/base/trace_event/process_memory_totals.h
@@ -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.
+
+#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;
+
+// Data model for process-wide memory stats.
+class BASE_EXPORT ProcessMemoryTotals {
+ public:
+  ProcessMemoryTotals();
+
+  // Called at trace generation time to populate the TracedValue.
+  void AsValueInto(TracedValue* value) const;
+
+  // Clears up all the data collected.
+  void Clear();
+
+  uint64 resident_set_bytes() const { return resident_set_bytes_; }
+  void set_resident_set_bytes(uint64 value) { resident_set_bytes_ = value; }
+
+  uint64 peak_resident_set_bytes() const { return peak_resident_set_bytes_; }
+  void set_peak_resident_set_bytes(uint64 value) {
+    peak_resident_set_bytes_ = value;
+  }
+
+  // On some platforms (recent linux kernels, see goo.gl/sMvAVz) the peak rss
+  // can be reset. When is_peak_rss_resettable == true, the peak refers to
+  // peak from the previous measurement. When false, it is the absolute peak
+  // since the start of the process.
+  bool is_peak_rss_resetable() const { return is_peak_rss_resetable_; }
+  void set_is_peak_rss_resetable(bool value) { is_peak_rss_resetable_ = value; }
+
+ private:
+  uint64 resident_set_bytes_;
+  uint64 peak_resident_set_bytes_;
+  bool is_peak_rss_resetable_;
+
+  DISALLOW_COPY_AND_ASSIGN(ProcessMemoryTotals);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_PROCESS_MEMORY_TOTALS_H_
diff --git a/base/trace_event/process_memory_totals_dump_provider.cc b/base/trace_event/process_memory_totals_dump_provider.cc
new file mode 100644
index 0000000..37f9bed
--- /dev/null
+++ b/base/trace_event/process_memory_totals_dump_provider.cc
@@ -0,0 +1,93 @@
+// 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"
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+#include <fcntl.h>
+
+#include "base/files/file_util.h"
+
+namespace {
+bool kernel_supports_rss_peak_reset = true;
+const char kClearPeakRssCommand[] = "5";
+}
+#endif
+
+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.
+bool ProcessMemoryTotalsDumpProvider::OnMemoryDump(ProcessMemoryDump* pmd) {
+  const uint64 rss_bytes = rss_bytes_for_testing
+                               ? rss_bytes_for_testing
+                               : process_metrics_->GetWorkingSetSize();
+
+  uint64 peak_rss_bytes = 0;
+
+#if !defined(OS_IOS)
+  peak_rss_bytes = process_metrics_->GetPeakWorkingSetSize();
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+  if (kernel_supports_rss_peak_reset) {
+    // TODO(ssid): Fix crbug.com/461788 to write to the file from sandboxed
+    // processes.
+    int clear_refs_fd = open("/proc/self/clear_refs", O_WRONLY);
+    if (clear_refs_fd > 0 &&
+        WriteFileDescriptor(clear_refs_fd, kClearPeakRssCommand,
+                            sizeof(kClearPeakRssCommand))) {
+      pmd->process_totals()->set_is_peak_rss_resetable(true);
+    } else {
+      kernel_supports_rss_peak_reset = false;
+    }
+    close(clear_refs_fd);
+  }
+#endif  // defined(OS_LINUX) || defined(OS_ANDROID)
+#endif  // !defined(OS_IOS)
+
+  if (rss_bytes > 0) {
+    pmd->process_totals()->set_resident_set_bytes(rss_bytes);
+    pmd->process_totals()->set_peak_resident_set_bytes(peak_rss_bytes);
+    pmd->set_has_process_totals();
+    return true;
+  }
+
+  return false;
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/process_memory_totals_dump_provider.h b/base/trace_event/process_memory_totals_dump_provider.h
new file mode 100644
index 0000000..6c86eb6
--- /dev/null
+++ b/base/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.
+  bool OnMemoryDump(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/base/trace_event/process_memory_totals_dump_provider_unittest.cc b/base/trace_event/process_memory_totals_dump_provider_unittest.cc
new file mode 100644
index 0000000..f9bb6c0
--- /dev/null
+++ b/base/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 pmtdp = ProcessMemoryTotalsDumpProvider::GetInstance();
+  scoped_ptr<ProcessMemoryDump> pmd_before(new ProcessMemoryDump(nullptr));
+  scoped_ptr<ProcessMemoryDump> pmd_after(new ProcessMemoryDump(nullptr));
+
+  ProcessMemoryTotalsDumpProvider::rss_bytes_for_testing = 1024;
+  pmtdp->OnMemoryDump(pmd_before.get());
+
+  // Pretend that the RSS of the process increased of +1M.
+  const size_t kAllocSize = 1048576;
+  ProcessMemoryTotalsDumpProvider::rss_bytes_for_testing += kAllocSize;
+
+  pmtdp->OnMemoryDump(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/base/trace_event/trace_config.cc b/base/trace_event/trace_config.cc
new file mode 100644
index 0000000..ef9b892
--- /dev/null
+++ b/base/trace_event/trace_config.cc
@@ -0,0 +1,547 @@
+// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/trace_config.h"
+
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_tokenizer.h"
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event.h"
+
+namespace base {
+namespace trace_event {
+
+namespace {
+
+// String options that can be used to initialize TraceOptions.
+const char kRecordUntilFull[] = "record-until-full";
+const char kRecordContinuously[] = "record-continuously";
+const char kRecordAsMuchAsPossible[] = "record-as-much-as-possible";
+const char kTraceToConsole[] = "trace-to-console";
+const char kEnableSampling[] = "enable-sampling";
+const char kEnableSystrace[] = "enable-systrace";
+const char kEnableArgumentFilter[] = "enable-argument-filter";
+
+// String parameters that can be used to parse the trace config string.
+const char kRecordModeParam[] = "record_mode";
+const char kEnableSamplingParam[] = "enable_sampling";
+const char kEnableSystraceParam[] = "enable_systrace";
+const char kEnableArgumentFilterParam[] = "enable_argument_filter";
+const char kIncludedCategoriesParam[] = "included_categories";
+const char kExcludedCategoriesParam[] = "excluded_categories";
+const char kSyntheticDelaysParam[] = "synthetic_delays";
+
+const char kSyntheticDelayCategoryFilterPrefix[] = "DELAY(";
+
+}  // namespace
+
+TraceConfig::TraceConfig() {
+  InitializeDefault();
+}
+
+TraceConfig::TraceConfig(const std::string& category_filter_string,
+                         const std::string& trace_options_string) {
+  InitializeFromStrings(category_filter_string, trace_options_string);
+}
+
+TraceConfig::TraceConfig(const std::string& category_filter_string,
+                         TraceRecordMode record_mode) {
+  std::string trace_options_string;
+  switch (record_mode) {
+    case RECORD_UNTIL_FULL:
+      trace_options_string = kRecordUntilFull;
+      break;
+    case RECORD_CONTINUOUSLY:
+      trace_options_string = kRecordContinuously;
+      break;
+    case RECORD_AS_MUCH_AS_POSSIBLE:
+      trace_options_string = kRecordAsMuchAsPossible;
+      break;
+    case ECHO_TO_CONSOLE:
+      trace_options_string = kTraceToConsole;
+      break;
+    default:
+      NOTREACHED();
+  }
+  InitializeFromStrings(category_filter_string, trace_options_string);
+}
+
+TraceConfig::TraceConfig(const std::string& config_string) {
+  if (!config_string.empty())
+    InitializeFromConfigString(config_string);
+  else
+    InitializeDefault();
+}
+
+TraceConfig::TraceConfig(const TraceConfig& tc)
+    : record_mode_(tc.record_mode_),
+      enable_sampling_(tc.enable_sampling_),
+      enable_systrace_(tc.enable_systrace_),
+      enable_argument_filter_(tc.enable_argument_filter_),
+      included_categories_(tc.included_categories_),
+      disabled_categories_(tc.disabled_categories_),
+      excluded_categories_(tc.excluded_categories_),
+      synthetic_delays_(tc.synthetic_delays_) {
+}
+
+TraceConfig::~TraceConfig() {
+}
+
+TraceConfig& TraceConfig::operator=(const TraceConfig& rhs) {
+  if (this == &rhs)
+    return *this;
+
+  record_mode_ = rhs.record_mode_;
+  enable_sampling_ = rhs.enable_sampling_;
+  enable_systrace_ = rhs.enable_systrace_;
+  enable_argument_filter_ = rhs.enable_argument_filter_;
+  included_categories_ = rhs.included_categories_;
+  disabled_categories_ = rhs.disabled_categories_;
+  excluded_categories_ = rhs.excluded_categories_;
+  synthetic_delays_ = rhs.synthetic_delays_;
+  return *this;
+}
+
+const TraceConfig::StringList& TraceConfig::GetSyntheticDelayValues() const {
+  return synthetic_delays_;
+}
+
+std::string TraceConfig::ToString() const {
+  base::DictionaryValue dict;
+  ToDict(dict);
+
+  std::string json;
+  base::JSONWriter::Write(dict, &json);
+
+  return json;
+}
+
+std::string TraceConfig::ToCategoryFilterString() const {
+  std::string filter_string;
+  WriteCategoryFilterString(included_categories_, &filter_string, true);
+  WriteCategoryFilterString(disabled_categories_, &filter_string, true);
+  WriteCategoryFilterString(excluded_categories_, &filter_string, false);
+  WriteCategoryFilterString(synthetic_delays_, &filter_string);
+  return filter_string;
+}
+
+bool TraceConfig::IsCategoryGroupEnabled(
+    const char* category_group_name) const {
+  // TraceLog should call this method only as part of enabling/disabling
+  // categories.
+
+  bool had_enabled_by_default = false;
+  DCHECK(category_group_name);
+  CStringTokenizer category_group_tokens(
+      category_group_name, category_group_name + strlen(category_group_name),
+      ",");
+  while (category_group_tokens.GetNext()) {
+    std::string category_group_token = category_group_tokens.token();
+    // Don't allow empty tokens, nor tokens with leading or trailing space.
+    DCHECK(!TraceConfig::IsEmptyOrContainsLeadingOrTrailingWhitespace(
+               category_group_token))
+        << "Disallowed category string";
+    if (IsCategoryEnabled(category_group_token.c_str())) {
+      return true;
+    }
+    if (!MatchPattern(category_group_token.c_str(),
+                      TRACE_DISABLED_BY_DEFAULT("*")))
+      had_enabled_by_default = true;
+  }
+  // Do a second pass to check for explicitly disabled categories
+  // (those explicitly enabled have priority due to first pass).
+  category_group_tokens.Reset();
+  bool category_group_disabled = false;
+  while (category_group_tokens.GetNext()) {
+    std::string category_group_token = category_group_tokens.token();
+    for (StringList::const_iterator ci = excluded_categories_.begin();
+         ci != excluded_categories_.end();
+         ++ci) {
+      if (MatchPattern(category_group_token.c_str(), ci->c_str())) {
+        // Current token of category_group_name is present in excluded_list.
+        // Flag the exclusion and proceed further to check if any of the
+        // remaining categories of category_group_name is not present in the
+        // excluded_ list.
+        category_group_disabled = true;
+        break;
+      }
+      // One of the category of category_group_name is not present in
+      // excluded_ list. So, it has to be included_ list. Enable the
+      // category_group_name for recording.
+      category_group_disabled = false;
+    }
+    // One of the categories present in category_group_name is not present in
+    // excluded_ list. Implies this category_group_name group can be enabled
+    // for recording, since one of its groups is enabled for recording.
+    if (!category_group_disabled)
+      break;
+  }
+  // If the category group is not excluded, and there are no included patterns
+  // we consider this category group enabled, as long as it had categories
+  // other than disabled-by-default.
+  return !category_group_disabled &&
+         included_categories_.empty() && had_enabled_by_default;
+}
+
+void TraceConfig::Merge(const TraceConfig& config) {
+  if (record_mode_ != config.record_mode_
+      || enable_sampling_ != config.enable_sampling_
+      || enable_systrace_ != config.enable_systrace_
+      || enable_argument_filter_ != config.enable_argument_filter_) {
+    DLOG(ERROR) << "Attempting to merge trace config with a different "
+                << "set of options.";
+  }
+
+  // Keep included patterns only if both filters have an included entry.
+  // Otherwise, one of the filter was specifying "*" and we want to honor the
+  // broadest filter.
+  if (HasIncludedPatterns() && config.HasIncludedPatterns()) {
+    included_categories_.insert(included_categories_.end(),
+                                config.included_categories_.begin(),
+                                config.included_categories_.end());
+  } else {
+    included_categories_.clear();
+  }
+
+  disabled_categories_.insert(disabled_categories_.end(),
+                              config.disabled_categories_.begin(),
+                              config.disabled_categories_.end());
+  excluded_categories_.insert(excluded_categories_.end(),
+                              config.excluded_categories_.begin(),
+                              config.excluded_categories_.end());
+  synthetic_delays_.insert(synthetic_delays_.end(),
+                           config.synthetic_delays_.begin(),
+                           config.synthetic_delays_.end());
+}
+
+void TraceConfig::Clear() {
+  record_mode_ = RECORD_UNTIL_FULL;
+  enable_sampling_ = false;
+  enable_systrace_ = false;
+  enable_argument_filter_ = false;
+  included_categories_.clear();
+  disabled_categories_.clear();
+  excluded_categories_.clear();
+  synthetic_delays_.clear();
+}
+
+void TraceConfig::InitializeDefault() {
+  record_mode_ = RECORD_UNTIL_FULL;
+  enable_sampling_ = false;
+  enable_systrace_ = false;
+  enable_argument_filter_ = false;
+  excluded_categories_.push_back("*Debug");
+  excluded_categories_.push_back("*Test");
+}
+
+void TraceConfig::InitializeFromConfigString(const std::string& config_string) {
+  scoped_ptr<base::Value> value(base::JSONReader::Read(config_string));
+  if (!value || !value->IsType(base::Value::TYPE_DICTIONARY)) {
+    InitializeDefault();
+    return;
+  }
+  scoped_ptr<base::DictionaryValue> dict(
+        static_cast<base::DictionaryValue*>(value.release()));
+
+  record_mode_ = RECORD_UNTIL_FULL;
+  std::string record_mode;
+  if (dict->GetString(kRecordModeParam, &record_mode)) {
+    if (record_mode == kRecordUntilFull) {
+      record_mode_ = RECORD_UNTIL_FULL;
+    } else if (record_mode == kRecordContinuously) {
+      record_mode_ = RECORD_CONTINUOUSLY;
+    } else if (record_mode == kTraceToConsole) {
+      record_mode_ = ECHO_TO_CONSOLE;
+    } else if (record_mode == kRecordAsMuchAsPossible) {
+      record_mode_ = RECORD_AS_MUCH_AS_POSSIBLE;
+    }
+  }
+
+  bool enable_sampling;
+  if (!dict->GetBoolean(kEnableSamplingParam, &enable_sampling))
+    enable_sampling_ = false;
+  else
+    enable_sampling_ = enable_sampling;
+
+  bool enable_systrace;
+  if (!dict->GetBoolean(kEnableSystraceParam, &enable_systrace))
+    enable_systrace_ = false;
+  else
+    enable_systrace_ = enable_systrace;
+
+  bool enable_argument_filter;
+  if (!dict->GetBoolean(kEnableArgumentFilterParam, &enable_argument_filter))
+    enable_argument_filter_ = false;
+  else
+    enable_argument_filter_ = enable_argument_filter;
+
+
+  base::ListValue* category_list = NULL;
+  if (dict->GetList(kIncludedCategoriesParam, &category_list))
+    SetCategoriesFromIncludedList(*category_list);
+  if (dict->GetList(kExcludedCategoriesParam, &category_list))
+    SetCategoriesFromExcludedList(*category_list);
+  if (dict->GetList(kSyntheticDelaysParam, &category_list))
+    SetSyntheticDelaysFromList(*category_list);
+}
+
+void TraceConfig::InitializeFromStrings(
+    const std::string& category_filter_string,
+    const std::string& trace_options_string) {
+  if (!category_filter_string.empty()) {
+    std::vector<std::string> split;
+    std::vector<std::string>::iterator iter;
+    base::SplitString(category_filter_string, ',', &split);
+    for (iter = split.begin(); iter != split.end(); ++iter) {
+      std::string category = *iter;
+      // Ignore empty categories.
+      if (category.empty())
+        continue;
+      // Synthetic delays are of the form 'DELAY(delay;option;option;...)'.
+      if (category.find(kSyntheticDelayCategoryFilterPrefix) == 0 &&
+          category.at(category.size() - 1) == ')') {
+        category = category.substr(
+            strlen(kSyntheticDelayCategoryFilterPrefix),
+            category.size() - strlen(kSyntheticDelayCategoryFilterPrefix) - 1);
+        size_t name_length = category.find(';');
+        if (name_length != std::string::npos && name_length > 0 &&
+            name_length != category.size() - 1) {
+          synthetic_delays_.push_back(category);
+        }
+      } else if (category.at(0) == '-') {
+        // Excluded categories start with '-'.
+        // Remove '-' from category string.
+        category = category.substr(1);
+        excluded_categories_.push_back(category);
+      } else if (category.compare(0, strlen(TRACE_DISABLED_BY_DEFAULT("")),
+                                  TRACE_DISABLED_BY_DEFAULT("")) == 0) {
+        disabled_categories_.push_back(category);
+      } else {
+        included_categories_.push_back(category);
+      }
+    }
+  }
+
+  record_mode_ = RECORD_UNTIL_FULL;
+  enable_sampling_ = false;
+  enable_systrace_ = false;
+  enable_argument_filter_ = false;
+  if(!trace_options_string.empty()) {
+    std::vector<std::string> split;
+    std::vector<std::string>::iterator iter;
+    base::SplitString(trace_options_string, ',', &split);
+    for (iter = split.begin(); iter != split.end(); ++iter) {
+      if (*iter == kRecordUntilFull) {
+        record_mode_ = RECORD_UNTIL_FULL;
+      } else if (*iter == kRecordContinuously) {
+        record_mode_ = RECORD_CONTINUOUSLY;
+      } else if (*iter == kTraceToConsole) {
+        record_mode_ = ECHO_TO_CONSOLE;
+      } else if (*iter == kRecordAsMuchAsPossible) {
+        record_mode_ = RECORD_AS_MUCH_AS_POSSIBLE;
+      } else if (*iter == kEnableSampling) {
+        enable_sampling_ = true;
+      } else if (*iter == kEnableSystrace) {
+        enable_systrace_ = true;
+      } else if (*iter == kEnableArgumentFilter) {
+        enable_argument_filter_ = true;
+      }
+    }
+  }
+}
+
+void TraceConfig::SetCategoriesFromIncludedList(
+    const base::ListValue& included_list) {
+  included_categories_.clear();
+  for (size_t i = 0; i < included_list.GetSize(); ++i) {
+    std::string category;
+    if (!included_list.GetString(i, &category))
+      continue;
+    if (category.compare(0, strlen(TRACE_DISABLED_BY_DEFAULT("")),
+                         TRACE_DISABLED_BY_DEFAULT("")) == 0) {
+      disabled_categories_.push_back(category);
+    } else {
+      included_categories_.push_back(category);
+    }
+  }
+}
+
+void TraceConfig::SetCategoriesFromExcludedList(
+    const base::ListValue& excluded_list) {
+  excluded_categories_.clear();
+  for (size_t i = 0; i < excluded_list.GetSize(); ++i) {
+    std::string category;
+    if (excluded_list.GetString(i, &category))
+      excluded_categories_.push_back(category);
+  }
+}
+
+void TraceConfig::SetSyntheticDelaysFromList(const base::ListValue& list) {
+  synthetic_delays_.clear();
+  for (size_t i = 0; i < list.GetSize(); ++i) {
+    std::string delay;
+    if (!list.GetString(i, &delay))
+      continue;
+    // Synthetic delays are of the form "delay;option;option;...".
+    size_t name_length = delay.find(';');
+    if (name_length != std::string::npos && name_length > 0 &&
+        name_length != delay.size() - 1) {
+      synthetic_delays_.push_back(delay);
+    }
+  }
+}
+
+void TraceConfig::AddCategoryToDict(base::DictionaryValue& dict,
+                                    const char* param,
+                                    const StringList& categories) const {
+  if (categories.empty())
+    return;
+
+  scoped_ptr<base::ListValue> list(new base::ListValue());
+  for (StringList::const_iterator ci = categories.begin();
+       ci != categories.end();
+       ++ci) {
+    list->AppendString(*ci);
+  }
+
+  dict.Set(param, list.Pass());
+}
+
+void TraceConfig::ToDict(base::DictionaryValue& dict) const {
+  switch (record_mode_) {
+    case RECORD_UNTIL_FULL:
+      dict.SetString(kRecordModeParam, kRecordUntilFull);
+      break;
+    case RECORD_CONTINUOUSLY:
+      dict.SetString(kRecordModeParam, kRecordContinuously);
+      break;
+    case RECORD_AS_MUCH_AS_POSSIBLE:
+      dict.SetString(kRecordModeParam, kRecordAsMuchAsPossible);
+      break;
+    case ECHO_TO_CONSOLE:
+      dict.SetString(kRecordModeParam, kTraceToConsole);
+      break;
+    default:
+      NOTREACHED();
+  }
+
+  if (enable_sampling_)
+    dict.SetBoolean(kEnableSamplingParam, true);
+  else
+    dict.SetBoolean(kEnableSamplingParam, false);
+
+  if (enable_systrace_)
+    dict.SetBoolean(kEnableSystraceParam, true);
+  else
+    dict.SetBoolean(kEnableSystraceParam, false);
+
+  if (enable_argument_filter_)
+    dict.SetBoolean(kEnableArgumentFilterParam, true);
+  else
+    dict.SetBoolean(kEnableArgumentFilterParam, false);
+
+  StringList categories(included_categories_);
+  categories.insert(categories.end(),
+                    disabled_categories_.begin(),
+                    disabled_categories_.end());
+  AddCategoryToDict(dict, kIncludedCategoriesParam, categories);
+  AddCategoryToDict(dict, kExcludedCategoriesParam, excluded_categories_);
+  AddCategoryToDict(dict, kSyntheticDelaysParam, synthetic_delays_);
+}
+
+std::string TraceConfig::ToTraceOptionsString() const {
+  std::string ret;
+  switch (record_mode_) {
+    case RECORD_UNTIL_FULL:
+      ret = kRecordUntilFull;
+      break;
+    case RECORD_CONTINUOUSLY:
+      ret = kRecordContinuously;
+      break;
+    case RECORD_AS_MUCH_AS_POSSIBLE:
+      ret = kRecordAsMuchAsPossible;
+      break;
+    case ECHO_TO_CONSOLE:
+      ret = kTraceToConsole;
+      break;
+    default:
+      NOTREACHED();
+  }
+  if (enable_sampling_)
+    ret = ret + "," + kEnableSampling;
+  if (enable_systrace_)
+    ret = ret + "," + kEnableSystrace;
+  if (enable_argument_filter_)
+    ret = ret + "," + kEnableArgumentFilter;
+  return ret;
+}
+
+void TraceConfig::WriteCategoryFilterString(const StringList& values,
+                                            std::string* out,
+                                            bool included) const {
+  bool prepend_comma = !out->empty();
+  int token_cnt = 0;
+  for (StringList::const_iterator ci = values.begin();
+       ci != values.end(); ++ci) {
+    if (token_cnt > 0 || prepend_comma)
+      StringAppendF(out, ",");
+    StringAppendF(out, "%s%s", (included ? "" : "-"), ci->c_str());
+    ++token_cnt;
+  }
+}
+
+void TraceConfig::WriteCategoryFilterString(const StringList& delays,
+                                            std::string* out) const {
+  bool prepend_comma = !out->empty();
+  int token_cnt = 0;
+  for (StringList::const_iterator ci = delays.begin();
+       ci != delays.end(); ++ci) {
+    if (token_cnt > 0 || prepend_comma)
+      StringAppendF(out, ",");
+    StringAppendF(out, "%s%s)", kSyntheticDelayCategoryFilterPrefix,
+                  ci->c_str());
+    ++token_cnt;
+  }
+}
+
+bool TraceConfig::IsCategoryEnabled(const char* category_name) const {
+  StringList::const_iterator ci;
+
+  // Check the disabled- filters and the disabled-* wildcard first so that a
+  // "*" filter does not include the disabled.
+  for (ci = disabled_categories_.begin();
+       ci != disabled_categories_.end();
+       ++ci) {
+    if (MatchPattern(category_name, ci->c_str()))
+      return true;
+  }
+
+  if (MatchPattern(category_name, TRACE_DISABLED_BY_DEFAULT("*")))
+    return false;
+
+  for (ci = included_categories_.begin();
+       ci != included_categories_.end();
+       ++ci) {
+    if (MatchPattern(category_name, ci->c_str()))
+      return true;
+  }
+
+  return false;
+}
+
+bool TraceConfig::IsEmptyOrContainsLeadingOrTrailingWhitespace(
+    const std::string& str) {
+  return  str.empty() ||
+          str.at(0) == ' ' ||
+          str.at(str.length() - 1) == ' ';
+}
+
+bool TraceConfig::HasIncludedPatterns() const {
+  return !included_categories_.empty();
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/trace_config.h b/base/trace_event/trace_config.h
new file mode 100644
index 0000000..a9f8306
--- /dev/null
+++ b/base/trace_event/trace_config.h
@@ -0,0 +1,205 @@
+// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_TRACE_CONFIG_H_
+#define BASE_TRACE_EVENT_TRACE_CONFIG_H_
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/gtest_prod_util.h"
+#include "base/values.h"
+
+namespace base {
+namespace trace_event {
+
+// Options determines how the trace buffer stores data.
+enum TraceRecordMode {
+  // Record until the trace buffer is full.
+  RECORD_UNTIL_FULL,
+
+  // Record until the user ends the trace. The trace buffer is a fixed size
+  // and we use it as a ring buffer during recording.
+  RECORD_CONTINUOUSLY,
+
+  // Record until the trace buffer is full, but with a huge buffer size.
+  RECORD_AS_MUCH_AS_POSSIBLE,
+
+  // Echo to console. Events are discarded.
+  ECHO_TO_CONSOLE,
+};
+
+class BASE_EXPORT TraceConfig {
+ public:
+  typedef std::vector<std::string> StringList;
+
+  TraceConfig();
+
+  // Create TraceConfig object from category filter and trace options strings.
+  //
+  // |category_filter_string| is a comma-delimited list of category wildcards.
+  // A category can have an optional '-' prefix to make it an excluded category.
+  // All the same rules apply above, so for example, having both included and
+  // excluded categories in the same list would not be supported.
+  //
+  // Category filters can also be used to configure synthetic delays.
+  //
+  // |trace_options_string| is a comma-delimited list of trace options.
+  // Possible options are: "record-until-full", "record-continuously",
+  // "record-as-much-as-possible", "trace-to-console", "enable-sampling",
+  // "enable-systrace" and "enable-argument-filter".
+  // The first 4 options are trace recoding modes and hence
+  // mutually exclusive. If more than one trace recording modes appear in the
+  // options_string, the last one takes precedence. If none of the trace
+  // recording mode is specified, recording mode is RECORD_UNTIL_FULL.
+  //
+  // The trace option will first be reset to the default option
+  // (record_mode set to RECORD_UNTIL_FULL, enable_sampling, enable_systrace,
+  // and enable_argument_filter set to false) before options parsed from
+  // |trace_options_string| are applied on it. If |trace_options_string| is
+  // invalid, the final state of trace options is undefined.
+  //
+  // Example: TraceConfig("test_MyTest*", "record-until-full");
+  // Example: TraceConfig("test_MyTest*,test_OtherStuff",
+  //                      "record-continuously, enable-sampling");
+  // Example: TraceConfig("-excluded_category1,-excluded_category2",
+  //                      "record-until-full, trace-to-console");
+  //          would set ECHO_TO_CONSOLE as the recording mode.
+  // Example: TraceConfig("-*,webkit", "");
+  //          would disable everything but webkit; and use default options.
+  // Example: TraceConfig("-webkit", "");
+  //          would enable everything but webkit; and use default options.
+  // Example: TraceConfig("DELAY(gpu.PresentingFrame;16)", "");
+  //          would make swap buffers always take at least 16 ms; and use
+  //          default options.
+  // Example: TraceConfig("DELAY(gpu.PresentingFrame;16;oneshot)", "");
+  //          would make swap buffers take at least 16 ms the first time it is
+  //          called; and use default options.
+  // Example: TraceConfig("DELAY(gpu.PresentingFrame;16;alternating)", "");
+  //          would make swap buffers take at least 16 ms every other time it
+  //          is called; and use default options.
+  TraceConfig(const std::string& category_filter_string,
+              const std::string& trace_options_string);
+
+  TraceConfig(const std::string& category_filter_string,
+              TraceRecordMode record_mode);
+
+  // Create TraceConfig object from the trace config string.
+  //
+  // |config_string| is a dictionary formatted as a JSON string, containing both
+  // category filters and trace options.
+  //
+  // Example:
+  //   {
+  //     "record_mode": "record-continuously",
+  //     "enable_sampling": true,
+  //     "enable_systrace": true,
+  //     "enable_argument_filter": true,
+  //     "included_categories": ["included",
+  //                             "inc_pattern*",
+  //                             "disabled-by-default-category1"],
+  //     "excluded_categories": ["excluded", "exc_pattern*"],
+  //     "synthetic_delays": ["test.Delay1;16", "test.Delay2;32"]
+  //   }
+  explicit TraceConfig(const std::string& config_string);
+
+  TraceConfig(const TraceConfig& tc);
+
+  ~TraceConfig();
+
+  TraceConfig& operator=(const TraceConfig& rhs);
+
+  // Return a list of the synthetic delays specified in this category filter.
+  const StringList& GetSyntheticDelayValues() const;
+
+  TraceRecordMode GetTraceRecordMode() const { return record_mode_; }
+  bool IsSamplingEnabled() const { return enable_sampling_; }
+  bool IsSystraceEnabled() const { return enable_systrace_; }
+  bool IsArgumentFilterEnabled() const { return enable_argument_filter_; }
+
+  void SetTraceRecordMode(TraceRecordMode mode) { record_mode_ = mode; }
+  void EnableSampling() { enable_sampling_ = true; }
+  void EnableSystrace() { enable_systrace_ = true; }
+  void EnableArgumentFilter() { enable_argument_filter_ = true; }
+
+  // Writes the string representation of the TraceConfig. The string is JSON
+  // formatted.
+  std::string ToString() const;
+
+  // Write the string representation of the CategoryFilter part.
+  std::string ToCategoryFilterString() const;
+
+  // Returns true if at least one category in the list is enabled by this
+  // trace config.
+  bool IsCategoryGroupEnabled(const char* category_group) const;
+
+  // Merges config with the current TraceConfig
+  void Merge(const TraceConfig& config);
+
+  void Clear();
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(TraceConfigTest, TraceConfigFromValidLegacyFormat);
+  FRIEND_TEST_ALL_PREFIXES(TraceConfigTest,
+                           TraceConfigFromInvalidLegacyStrings);
+  FRIEND_TEST_ALL_PREFIXES(TraceConfigTest, ConstructDefaultTraceConfig);
+  FRIEND_TEST_ALL_PREFIXES(TraceConfigTest, TraceConfigFromValidString);
+  FRIEND_TEST_ALL_PREFIXES(TraceConfigTest, TraceConfigFromInvalidString);
+  FRIEND_TEST_ALL_PREFIXES(TraceConfigTest,
+                           IsEmptyOrContainsLeadingOrTrailingWhitespace);
+
+  // The default trace config, used when none is provided.
+  // Allows all non-disabled-by-default categories through, except if they end
+  // in the suffix 'Debug' or 'Test'.
+  void InitializeDefault();
+
+  // Initialize from the config string
+  void InitializeFromConfigString(const std::string& config_string);
+
+  // Initialize from category filter and trace options strings
+  void InitializeFromStrings(const std::string& category_filter_string,
+                             const std::string& trace_options_string);
+
+  void SetCategoriesFromIncludedList(const base::ListValue& included_list);
+  void SetCategoriesFromExcludedList(const base::ListValue& excluded_list);
+  void SetSyntheticDelaysFromList(const base::ListValue& list);
+  void AddCategoryToDict(base::DictionaryValue& dict,
+                         const char* param,
+                         const StringList& categories) const;
+
+  // Convert TraceConfig to the dict representation of the TraceConfig.
+  void ToDict(base::DictionaryValue& dict) const;
+
+  std::string ToTraceOptionsString() const;
+
+  void WriteCategoryFilterString(const StringList& values,
+                                 std::string* out,
+                                 bool included) const;
+  void WriteCategoryFilterString(const StringList& delays,
+                                 std::string* out) const;
+
+  // Returns true if category is enable according to this trace config.
+  bool IsCategoryEnabled(const char* category_name) const;
+
+  static bool IsEmptyOrContainsLeadingOrTrailingWhitespace(
+      const std::string& str);
+
+  bool HasIncludedPatterns() const;
+
+  TraceRecordMode record_mode_;
+  bool enable_sampling_ : 1;
+  bool enable_systrace_ : 1;
+  bool enable_argument_filter_ : 1;
+
+  StringList included_categories_;
+  StringList disabled_categories_;
+  StringList excluded_categories_;
+  StringList synthetic_delays_;
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_TRACE_CONFIG_H_
diff --git a/base/trace_event/trace_config_unittest.cc b/base/trace_event/trace_config_unittest.cc
new file mode 100644
index 0000000..a2a3703
--- /dev/null
+++ b/base/trace_event/trace_config_unittest.cc
@@ -0,0 +1,492 @@
+// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/trace_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+namespace {
+
+const char kDefaultTraceConfigString[] =
+  "{"
+    "\"enable_argument_filter\":false,"
+    "\"enable_sampling\":false,"
+    "\"enable_systrace\":false,"
+    "\"excluded_categories\":[\"*Debug\",\"*Test\"],"
+    "\"record_mode\":\"record-until-full\""
+  "}";
+
+}  // namespace
+
+TEST(TraceConfigTest, TraceConfigFromValidLegacyFormat) {
+  // From trace options strings
+  TraceConfig config("", "record-until-full");
+  EXPECT_EQ(RECORD_UNTIL_FULL, config.GetTraceRecordMode());
+  EXPECT_FALSE(config.IsSamplingEnabled());
+  EXPECT_FALSE(config.IsSystraceEnabled());
+  EXPECT_FALSE(config.IsArgumentFilterEnabled());
+  EXPECT_STREQ("record-until-full", config.ToTraceOptionsString().c_str());
+
+  config = TraceConfig("", "record-continuously");
+  EXPECT_EQ(RECORD_CONTINUOUSLY, config.GetTraceRecordMode());
+  EXPECT_FALSE(config.IsSamplingEnabled());
+  EXPECT_FALSE(config.IsSystraceEnabled());
+  EXPECT_FALSE(config.IsArgumentFilterEnabled());
+  EXPECT_STREQ("record-continuously", config.ToTraceOptionsString().c_str());
+
+  config = TraceConfig("", "trace-to-console");
+  EXPECT_EQ(ECHO_TO_CONSOLE, config.GetTraceRecordMode());
+  EXPECT_FALSE(config.IsSamplingEnabled());
+  EXPECT_FALSE(config.IsSystraceEnabled());
+  EXPECT_FALSE(config.IsArgumentFilterEnabled());
+  EXPECT_STREQ("trace-to-console", config.ToTraceOptionsString().c_str());
+
+  config = TraceConfig("", "record-as-much-as-possible");
+  EXPECT_EQ(RECORD_AS_MUCH_AS_POSSIBLE, config.GetTraceRecordMode());
+  EXPECT_FALSE(config.IsSamplingEnabled());
+  EXPECT_FALSE(config.IsSystraceEnabled());
+  EXPECT_FALSE(config.IsArgumentFilterEnabled());
+  EXPECT_STREQ("record-as-much-as-possible",
+               config.ToTraceOptionsString().c_str());
+
+  config = TraceConfig("", "record-until-full, enable-sampling");
+  EXPECT_EQ(RECORD_UNTIL_FULL, config.GetTraceRecordMode());
+  EXPECT_TRUE(config.IsSamplingEnabled());
+  EXPECT_FALSE(config.IsSystraceEnabled());
+  EXPECT_FALSE(config.IsArgumentFilterEnabled());
+  EXPECT_STREQ("record-until-full,enable-sampling",
+               config.ToTraceOptionsString().c_str());
+
+  config = TraceConfig("", "enable-systrace, record-continuously");
+  EXPECT_EQ(RECORD_CONTINUOUSLY, config.GetTraceRecordMode());
+  EXPECT_FALSE(config.IsSamplingEnabled());
+  EXPECT_TRUE(config.IsSystraceEnabled());
+  EXPECT_FALSE(config.IsArgumentFilterEnabled());
+  EXPECT_STREQ("record-continuously,enable-systrace",
+               config.ToTraceOptionsString().c_str());
+
+  config = TraceConfig("", "enable-argument-filter,record-as-much-as-possible");
+  EXPECT_EQ(RECORD_AS_MUCH_AS_POSSIBLE, config.GetTraceRecordMode());
+  EXPECT_FALSE(config.IsSamplingEnabled());
+  EXPECT_FALSE(config.IsSystraceEnabled());
+  EXPECT_TRUE(config.IsArgumentFilterEnabled());
+  EXPECT_STREQ("record-as-much-as-possible,enable-argument-filter",
+               config.ToTraceOptionsString().c_str());
+
+  config = TraceConfig(
+    "",
+    "enable-systrace,trace-to-console,enable-sampling,enable-argument-filter");
+  EXPECT_EQ(ECHO_TO_CONSOLE, config.GetTraceRecordMode());
+  EXPECT_TRUE(config.IsSamplingEnabled());
+  EXPECT_TRUE(config.IsSystraceEnabled());
+  EXPECT_TRUE(config.IsArgumentFilterEnabled());
+  EXPECT_STREQ(
+    "trace-to-console,enable-sampling,enable-systrace,enable-argument-filter",
+    config.ToTraceOptionsString().c_str());
+
+  config = TraceConfig(
+    "", "record-continuously, record-until-full, trace-to-console");
+  EXPECT_EQ(ECHO_TO_CONSOLE, config.GetTraceRecordMode());
+  EXPECT_FALSE(config.IsSamplingEnabled());
+  EXPECT_FALSE(config.IsSystraceEnabled());
+  EXPECT_FALSE(config.IsArgumentFilterEnabled());
+  EXPECT_STREQ("trace-to-console", config.ToTraceOptionsString().c_str());
+
+  // From TraceRecordMode
+  config = TraceConfig("", RECORD_UNTIL_FULL);
+  EXPECT_EQ(RECORD_UNTIL_FULL, config.GetTraceRecordMode());
+  EXPECT_FALSE(config.IsSamplingEnabled());
+  EXPECT_FALSE(config.IsSystraceEnabled());
+  EXPECT_FALSE(config.IsArgumentFilterEnabled());
+  EXPECT_STREQ("record-until-full", config.ToTraceOptionsString().c_str());
+
+  config = TraceConfig("", RECORD_CONTINUOUSLY);
+  EXPECT_EQ(RECORD_CONTINUOUSLY, config.GetTraceRecordMode());
+  EXPECT_FALSE(config.IsSamplingEnabled());
+  EXPECT_FALSE(config.IsSystraceEnabled());
+  EXPECT_FALSE(config.IsArgumentFilterEnabled());
+  EXPECT_STREQ("record-continuously", config.ToTraceOptionsString().c_str());
+
+  config = TraceConfig("", ECHO_TO_CONSOLE);
+  EXPECT_EQ(ECHO_TO_CONSOLE, config.GetTraceRecordMode());
+  EXPECT_FALSE(config.IsSamplingEnabled());
+  EXPECT_FALSE(config.IsSystraceEnabled());
+  EXPECT_FALSE(config.IsArgumentFilterEnabled());
+  EXPECT_STREQ("trace-to-console", config.ToTraceOptionsString().c_str());
+
+  config = TraceConfig("", RECORD_AS_MUCH_AS_POSSIBLE);
+  EXPECT_EQ(RECORD_AS_MUCH_AS_POSSIBLE, config.GetTraceRecordMode());
+  EXPECT_FALSE(config.IsSamplingEnabled());
+  EXPECT_FALSE(config.IsSystraceEnabled());
+  EXPECT_FALSE(config.IsArgumentFilterEnabled());
+  EXPECT_STREQ("record-as-much-as-possible",
+               config.ToTraceOptionsString().c_str());
+
+  // From category filter strings
+  config = TraceConfig("-*Debug,-*Test", "");
+  EXPECT_STREQ("-*Debug,-*Test", config.ToCategoryFilterString().c_str());
+
+  config = TraceConfig("included,-excluded,inc_pattern*,-exc_pattern*", "");
+  EXPECT_STREQ("included,inc_pattern*,-excluded,-exc_pattern*",
+               config.ToCategoryFilterString().c_str());
+
+  config = TraceConfig("only_inc_cat", "");
+  EXPECT_STREQ("only_inc_cat", config.ToCategoryFilterString().c_str());
+
+  config = TraceConfig("-only_exc_cat", "");
+  EXPECT_STREQ("-only_exc_cat", config.ToCategoryFilterString().c_str());
+
+  config = TraceConfig("disabled-by-default-cc,-excluded", "");
+  EXPECT_STREQ("disabled-by-default-cc,-excluded",
+               config.ToCategoryFilterString().c_str());
+
+  config = TraceConfig("disabled-by-default-cc,included", "");
+  EXPECT_STREQ("included,disabled-by-default-cc",
+               config.ToCategoryFilterString().c_str());
+
+  config = TraceConfig("DELAY(test.Delay1;16),included", "");
+  EXPECT_STREQ("included,DELAY(test.Delay1;16)",
+               config.ToCategoryFilterString().c_str());
+
+  // From both trace options and category filter strings
+  config = TraceConfig("", "");
+  EXPECT_EQ(RECORD_UNTIL_FULL, config.GetTraceRecordMode());
+  EXPECT_FALSE(config.IsSamplingEnabled());
+  EXPECT_FALSE(config.IsSystraceEnabled());
+  EXPECT_FALSE(config.IsArgumentFilterEnabled());
+  EXPECT_STREQ("", config.ToCategoryFilterString().c_str());
+  EXPECT_STREQ("record-until-full", config.ToTraceOptionsString().c_str());
+
+  config = TraceConfig("included,-excluded,inc_pattern*,-exc_pattern*",
+                       "enable-systrace, trace-to-console, enable-sampling");
+  EXPECT_EQ(ECHO_TO_CONSOLE, config.GetTraceRecordMode());
+  EXPECT_TRUE(config.IsSamplingEnabled());
+  EXPECT_TRUE(config.IsSystraceEnabled());
+  EXPECT_FALSE(config.IsArgumentFilterEnabled());
+  EXPECT_STREQ("included,inc_pattern*,-excluded,-exc_pattern*",
+               config.ToCategoryFilterString().c_str());
+  EXPECT_STREQ("trace-to-console,enable-sampling,enable-systrace",
+               config.ToTraceOptionsString().c_str());
+
+  // From both trace options and category filter strings with spaces.
+  config = TraceConfig(" included , -excluded, inc_pattern*, ,-exc_pattern*   ",
+                       "enable-systrace, ,trace-to-console, enable-sampling  ");
+  EXPECT_EQ(ECHO_TO_CONSOLE, config.GetTraceRecordMode());
+  EXPECT_TRUE(config.IsSamplingEnabled());
+  EXPECT_TRUE(config.IsSystraceEnabled());
+  EXPECT_FALSE(config.IsArgumentFilterEnabled());
+  EXPECT_STREQ("included,inc_pattern*,-excluded,-exc_pattern*",
+               config.ToCategoryFilterString().c_str());
+  EXPECT_STREQ("trace-to-console,enable-sampling,enable-systrace",
+               config.ToTraceOptionsString().c_str());
+
+  // From category filter string and TraceRecordMode
+  config = TraceConfig("included,-excluded,inc_pattern*,-exc_pattern*",
+                       RECORD_CONTINUOUSLY);
+  EXPECT_EQ(RECORD_CONTINUOUSLY, config.GetTraceRecordMode());
+  EXPECT_FALSE(config.IsSystraceEnabled());
+  EXPECT_FALSE(config.IsSamplingEnabled());
+  EXPECT_FALSE(config.IsArgumentFilterEnabled());
+  EXPECT_STREQ("included,inc_pattern*,-excluded,-exc_pattern*",
+               config.ToCategoryFilterString().c_str());
+  EXPECT_STREQ("record-continuously", config.ToTraceOptionsString().c_str());
+}
+
+TEST(TraceConfigTest, TraceConfigFromInvalidLegacyStrings) {
+  TraceConfig config("", "foo-bar-baz");
+  EXPECT_EQ(RECORD_UNTIL_FULL, config.GetTraceRecordMode());
+  EXPECT_FALSE(config.IsSamplingEnabled());
+  EXPECT_FALSE(config.IsSystraceEnabled());
+  EXPECT_FALSE(config.IsArgumentFilterEnabled());
+  EXPECT_STREQ("", config.ToCategoryFilterString().c_str());
+  EXPECT_STREQ("record-until-full", config.ToTraceOptionsString().c_str());
+
+  config = TraceConfig("arbitrary-category", "foo-bar-baz, enable-systrace");
+  EXPECT_EQ(RECORD_UNTIL_FULL, config.GetTraceRecordMode());
+  EXPECT_FALSE(config.IsSamplingEnabled());
+  EXPECT_TRUE(config.IsSystraceEnabled());
+  EXPECT_FALSE(config.IsArgumentFilterEnabled());
+  EXPECT_STREQ("arbitrary-category", config.ToCategoryFilterString().c_str());
+  EXPECT_STREQ("record-until-full,enable-systrace",
+               config.ToTraceOptionsString().c_str());
+
+  const char* const configs[] = {
+    "",
+    "DELAY(",
+    "DELAY(;",
+    "DELAY(;)",
+    "DELAY(test.Delay)",
+    "DELAY(test.Delay;)"
+  };
+  for (size_t i = 0; i < arraysize(configs); i++) {
+    TraceConfig tc(configs[i], "");
+    EXPECT_EQ(0u, tc.GetSyntheticDelayValues().size());
+  }
+}
+
+TEST(TraceConfigTest, ConstructDefaultTraceConfig) {
+  // Make sure that upon an empty string, we fall back to the default config.
+  TraceConfig tc;
+  EXPECT_STREQ(kDefaultTraceConfigString, tc.ToString().c_str());
+  EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
+  EXPECT_FALSE(tc.IsSamplingEnabled());
+  EXPECT_FALSE(tc.IsSystraceEnabled());
+  EXPECT_FALSE(tc.IsArgumentFilterEnabled());
+  EXPECT_STREQ("-*Debug,-*Test", tc.ToCategoryFilterString().c_str());
+
+  EXPECT_FALSE(tc.IsCategoryEnabled("Category1"));
+  EXPECT_FALSE(tc.IsCategoryEnabled("not-excluded-category"));
+  EXPECT_FALSE(tc.IsCategoryEnabled("CategoryTest"));
+  EXPECT_FALSE(tc.IsCategoryEnabled("CategoryDebug"));
+  EXPECT_FALSE(tc.IsCategoryEnabled("disabled-by-default-cc"));
+
+  EXPECT_TRUE(tc.IsCategoryGroupEnabled("Category1"));
+  EXPECT_TRUE(tc.IsCategoryGroupEnabled("not-excluded-category"));
+  EXPECT_FALSE(tc.IsCategoryGroupEnabled("CategoryTest"));
+  EXPECT_FALSE(tc.IsCategoryGroupEnabled("CategoryDebug"));
+  EXPECT_FALSE(tc.IsCategoryGroupEnabled("disabled-by-default-cc"));
+
+  EXPECT_TRUE(tc.IsCategoryGroupEnabled("Category1,CategoryDebug"));
+  EXPECT_TRUE(tc.IsCategoryGroupEnabled("CategoryDebug,Category1"));
+  EXPECT_TRUE(tc.IsCategoryGroupEnabled("CategoryTest,not-excluded-category"));
+  EXPECT_FALSE(tc.IsCategoryGroupEnabled("CategoryDebug,CategoryTest"));
+}
+
+TEST(TraceConfigTest, TraceConfigFromValidString) {
+  // Using some non-empty config string.
+  const char config_string[] =
+    "{"
+      "\"enable_argument_filter\":true,"
+      "\"enable_sampling\":true,"
+      "\"enable_systrace\":true,"
+      "\"excluded_categories\":[\"excluded\",\"exc_pattern*\"],"
+      "\"included_categories\":[\"included\","
+                               "\"inc_pattern*\","
+                               "\"disabled-by-default-cc\"],"
+      "\"record_mode\":\"record-continuously\","
+      "\"synthetic_delays\":[\"test.Delay1;16\",\"test.Delay2;32\"]"
+    "}";
+  TraceConfig tc(config_string);
+
+  EXPECT_STREQ(config_string, tc.ToString().c_str());
+  EXPECT_EQ(RECORD_CONTINUOUSLY, tc.GetTraceRecordMode());
+  EXPECT_TRUE(tc.IsSamplingEnabled());
+  EXPECT_TRUE(tc.IsSystraceEnabled());
+  EXPECT_TRUE(tc.IsArgumentFilterEnabled());
+  EXPECT_STREQ("included,inc_pattern*,disabled-by-default-cc,-excluded,"
+               "-exc_pattern*,DELAY(test.Delay1;16),DELAY(test.Delay2;32)",
+               tc.ToCategoryFilterString().c_str());
+
+  EXPECT_TRUE(tc.IsCategoryEnabled("included"));
+  EXPECT_TRUE(tc.IsCategoryEnabled("inc_pattern_category"));
+  EXPECT_TRUE(tc.IsCategoryEnabled("disabled-by-default-cc"));
+  EXPECT_FALSE(tc.IsCategoryEnabled("excluded"));
+  EXPECT_FALSE(tc.IsCategoryEnabled("exc_pattern_category"));
+  EXPECT_FALSE(tc.IsCategoryEnabled("disabled-by-default-others"));
+  EXPECT_FALSE(tc.IsCategoryEnabled("not-excluded-nor-included"));
+
+  EXPECT_TRUE(tc.IsCategoryGroupEnabled("included"));
+  EXPECT_TRUE(tc.IsCategoryGroupEnabled("inc_pattern_category"));
+  EXPECT_TRUE(tc.IsCategoryGroupEnabled("disabled-by-default-cc"));
+  EXPECT_FALSE(tc.IsCategoryGroupEnabled("excluded"));
+  EXPECT_FALSE(tc.IsCategoryGroupEnabled("exc_pattern_category"));
+  EXPECT_FALSE(tc.IsCategoryGroupEnabled("disabled-by-default-others"));
+  EXPECT_FALSE(tc.IsCategoryGroupEnabled("not-excluded-nor-included"));
+
+  EXPECT_TRUE(tc.IsCategoryGroupEnabled("included,excluded"));
+  EXPECT_FALSE(tc.IsCategoryGroupEnabled("excluded,exc_pattern_category"));
+  EXPECT_TRUE(tc.IsCategoryGroupEnabled("included,DELAY(test.Delay1;16)"));
+  EXPECT_FALSE(tc.IsCategoryGroupEnabled("DELAY(test.Delay1;16)"));
+
+  EXPECT_EQ(2u, tc.GetSyntheticDelayValues().size());
+  EXPECT_STREQ("test.Delay1;16", tc.GetSyntheticDelayValues()[0].c_str());
+  EXPECT_STREQ("test.Delay2;32", tc.GetSyntheticDelayValues()[1].c_str());
+
+  const char config_string_2[] = "{\"included_categories\":[\"*\"]}";
+  TraceConfig tc2(config_string_2);
+  EXPECT_TRUE(tc2.IsCategoryEnabled("non-disabled-by-default-pattern"));
+  EXPECT_FALSE(tc2.IsCategoryEnabled("disabled-by-default-pattern"));
+  EXPECT_TRUE(tc2.IsCategoryGroupEnabled("non-disabled-by-default-pattern"));
+  EXPECT_FALSE(tc2.IsCategoryGroupEnabled("disabled-by-default-pattern"));
+
+  // Clear
+  tc.Clear();
+  EXPECT_STREQ(tc.ToString().c_str(),
+               "{"
+                 "\"enable_argument_filter\":false,"
+                 "\"enable_sampling\":false,"
+                 "\"enable_systrace\":false,"
+                 "\"record_mode\":\"record-until-full\""
+               "}");
+}
+
+TEST(TraceConfigTest, TraceConfigFromInvalidString) {
+  // The config string needs to be a dictionary correctly formatted as a JSON
+  // string. Otherwise, it will fall back to the default initialization.
+  TraceConfig tc("");
+  EXPECT_STREQ(kDefaultTraceConfigString, tc.ToString().c_str());
+  EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
+  EXPECT_FALSE(tc.IsSamplingEnabled());
+  EXPECT_FALSE(tc.IsSystraceEnabled());
+  EXPECT_FALSE(tc.IsArgumentFilterEnabled());
+  EXPECT_STREQ("-*Debug,-*Test", tc.ToCategoryFilterString().c_str());
+
+  tc = TraceConfig("This is an invalid config string.");
+  EXPECT_STREQ(kDefaultTraceConfigString, tc.ToString().c_str());
+  EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
+  EXPECT_FALSE(tc.IsSamplingEnabled());
+  EXPECT_FALSE(tc.IsSystraceEnabled());
+  EXPECT_FALSE(tc.IsArgumentFilterEnabled());
+  EXPECT_STREQ("-*Debug,-*Test", tc.ToCategoryFilterString().c_str());
+
+  tc = TraceConfig("[\"This\", \"is\", \"not\", \"a\", \"dictionary\"]");
+  EXPECT_STREQ(kDefaultTraceConfigString, tc.ToString().c_str());
+  EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
+  EXPECT_FALSE(tc.IsSamplingEnabled());
+  EXPECT_FALSE(tc.IsSystraceEnabled());
+  EXPECT_FALSE(tc.IsArgumentFilterEnabled());
+  EXPECT_STREQ("-*Debug,-*Test", tc.ToCategoryFilterString().c_str());
+
+  tc = TraceConfig("{\"record_mode\": invalid-value-needs-double-quote}");
+  EXPECT_STREQ(kDefaultTraceConfigString, tc.ToString().c_str());
+  EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
+  EXPECT_FALSE(tc.IsSamplingEnabled());
+  EXPECT_FALSE(tc.IsSystraceEnabled());
+  EXPECT_FALSE(tc.IsArgumentFilterEnabled());
+  EXPECT_STREQ("-*Debug,-*Test", tc.ToCategoryFilterString().c_str());
+
+  // If the config string a dictionary formatted as a JSON string, it will
+  // initialize TraceConfig with best effort.
+  tc = TraceConfig("{}");
+  EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
+  EXPECT_FALSE(tc.IsSamplingEnabled());
+  EXPECT_FALSE(tc.IsSystraceEnabled());
+  EXPECT_FALSE(tc.IsArgumentFilterEnabled());
+  EXPECT_STREQ("", tc.ToCategoryFilterString().c_str());
+
+  tc = TraceConfig("{\"arbitrary-key\":\"arbitrary-value\"}");
+  EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
+  EXPECT_FALSE(tc.IsSamplingEnabled());
+  EXPECT_FALSE(tc.IsSystraceEnabled());
+  EXPECT_FALSE(tc.IsArgumentFilterEnabled());
+  EXPECT_STREQ("", tc.ToCategoryFilterString().c_str());
+
+  const char invalid_config_string[] =
+    "{"
+      "\"enable_sampling\":\"true\","
+      "\"enable_systrace\":1,"
+      "\"excluded_categories\":[\"excluded\"],"
+      "\"included_categories\":\"not a list\","
+      "\"record_mode\":\"arbitrary-mode\","
+      "\"synthetic_delays\":[\"test.Delay1;16\","
+                            "\"invalid-delay\","
+                            "\"test.Delay2;32\"]"
+    "}";
+  tc = TraceConfig(invalid_config_string);
+  EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
+  EXPECT_FALSE(tc.IsSamplingEnabled());
+  EXPECT_FALSE(tc.IsSystraceEnabled());
+  EXPECT_FALSE(tc.IsArgumentFilterEnabled());
+  EXPECT_STREQ("-excluded,DELAY(test.Delay1;16),DELAY(test.Delay2;32)",
+               tc.ToCategoryFilterString().c_str());
+
+  const char invalid_config_string_2[] =
+    "{"
+      "\"included_categories\":[\"category\",\"disabled-by-default-pattern\"],"
+      "\"excluded_categories\":[\"category\",\"disabled-by-default-pattern\"]"
+    "}";
+  tc = TraceConfig(invalid_config_string_2);
+  EXPECT_TRUE(tc.IsCategoryEnabled("category"));
+  EXPECT_TRUE(tc.IsCategoryEnabled("disabled-by-default-pattern"));
+  EXPECT_TRUE(tc.IsCategoryGroupEnabled("category"));
+  EXPECT_TRUE(tc.IsCategoryGroupEnabled("disabled-by-default-pattern"));
+}
+
+TEST(TraceConfigTest, MergingTraceConfigs) {
+  // Merge
+  TraceConfig tc;
+  TraceConfig tc2("included,-excluded,inc_pattern*,-exc_pattern*", "");
+  tc.Merge(tc2);
+  EXPECT_STREQ("{"
+                 "\"enable_argument_filter\":false,"
+                 "\"enable_sampling\":false,"
+                 "\"enable_systrace\":false,"
+                 "\"excluded_categories\":["
+                   "\"*Debug\",\"*Test\",\"excluded\",\"exc_pattern*\""
+                 "],"
+                 "\"record_mode\":\"record-until-full\""
+               "}",
+               tc.ToString().c_str());
+
+  tc = TraceConfig("DELAY(test.Delay1;16)", "");
+  tc2 = TraceConfig("DELAY(test.Delay2;32)", "");
+  tc.Merge(tc2);
+  EXPECT_EQ(2u, tc.GetSyntheticDelayValues().size());
+  EXPECT_STREQ("test.Delay1;16", tc.GetSyntheticDelayValues()[0].c_str());
+  EXPECT_STREQ("test.Delay2;32", tc.GetSyntheticDelayValues()[1].c_str());
+}
+
+TEST(TraceConfigTest, IsCategoryGroupEnabled) {
+  // Enabling a disabled- category does not require all categories to be traced
+  // to be included.
+  TraceConfig tc("disabled-by-default-cc,-excluded", "");
+  EXPECT_STREQ("disabled-by-default-cc,-excluded",
+               tc.ToCategoryFilterString().c_str());
+  EXPECT_TRUE(tc.IsCategoryGroupEnabled("disabled-by-default-cc"));
+  EXPECT_TRUE(tc.IsCategoryGroupEnabled("some_other_group"));
+  EXPECT_FALSE(tc.IsCategoryGroupEnabled("excluded"));
+
+  // Enabled a disabled- category and also including makes all categories to
+  // be traced require including.
+  tc = TraceConfig("disabled-by-default-cc,included", "");
+  EXPECT_STREQ("included,disabled-by-default-cc",
+               tc.ToCategoryFilterString().c_str());
+  EXPECT_TRUE(tc.IsCategoryGroupEnabled("disabled-by-default-cc"));
+  EXPECT_TRUE(tc.IsCategoryGroupEnabled("included"));
+  EXPECT_FALSE(tc.IsCategoryGroupEnabled("other_included"));
+}
+
+TEST(TraceConfigTest, IsEmptyOrContainsLeadingOrTrailingWhitespace) {
+  // Test that IsEmptyOrContainsLeadingOrTrailingWhitespace actually catches
+  // categories that are explicitly forbidden.
+  // This method is called in a DCHECK to assert that we don't have these types
+  // of strings as categories.
+  EXPECT_TRUE(TraceConfig::IsEmptyOrContainsLeadingOrTrailingWhitespace(
+      " bad_category "));
+  EXPECT_TRUE(TraceConfig::IsEmptyOrContainsLeadingOrTrailingWhitespace(
+      " bad_category"));
+  EXPECT_TRUE(TraceConfig::IsEmptyOrContainsLeadingOrTrailingWhitespace(
+      "bad_category "));
+  EXPECT_TRUE(TraceConfig::IsEmptyOrContainsLeadingOrTrailingWhitespace(
+      "   bad_category"));
+  EXPECT_TRUE(TraceConfig::IsEmptyOrContainsLeadingOrTrailingWhitespace(
+      "bad_category   "));
+  EXPECT_TRUE(TraceConfig::IsEmptyOrContainsLeadingOrTrailingWhitespace(
+      "   bad_category   "));
+  EXPECT_TRUE(TraceConfig::IsEmptyOrContainsLeadingOrTrailingWhitespace(
+      ""));
+  EXPECT_FALSE(TraceConfig::IsEmptyOrContainsLeadingOrTrailingWhitespace(
+      "good_category"));
+}
+
+TEST(TraceConfigTest, SetTraceOptionValues) {
+  TraceConfig tc;
+  EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
+  EXPECT_FALSE(tc.IsSamplingEnabled());
+  EXPECT_FALSE(tc.IsSystraceEnabled());
+
+  tc.SetTraceRecordMode(RECORD_AS_MUCH_AS_POSSIBLE);
+  EXPECT_EQ(RECORD_AS_MUCH_AS_POSSIBLE, tc.GetTraceRecordMode());
+
+  tc.EnableSampling();
+  EXPECT_TRUE(tc.IsSamplingEnabled());
+
+  tc.EnableSystrace();
+  EXPECT_TRUE(tc.IsSystraceEnabled());
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/trace_event.gypi b/base/trace_event/trace_event.gypi
new file mode 100644
index 0000000..82a87cc
--- /dev/null
+++ b/base/trace_event/trace_event.gypi
@@ -0,0 +1,78 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'variables': {
+    'trace_event_sources' : [
+      'trace_event/java_heap_dump_provider_android.cc',
+      'trace_event/java_heap_dump_provider_android.h',
+      'trace_event/memory_allocator_dump.cc',
+      'trace_event/memory_allocator_dump.h',
+      'trace_event/memory_allocator_dump_guid.cc',
+      'trace_event/memory_allocator_dump_guid.h',
+      'trace_event/memory_dump_manager.cc',
+      'trace_event/memory_dump_manager.h',
+      'trace_event/memory_dump_provider.h',
+      'trace_event/memory_dump_request_args.h',
+      'trace_event/memory_dump_session_state.cc',
+      'trace_event/memory_dump_session_state.h',
+      'trace_event/process_memory_dump.cc',
+      'trace_event/process_memory_dump.h',
+      'trace_event/process_memory_maps.cc',
+      'trace_event/process_memory_maps.h',
+      'trace_event/process_memory_maps_dump_provider.cc',
+      'trace_event/process_memory_maps_dump_provider.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_config.cc',
+      'trace_event/trace_config.h',
+      'trace_event/trace_event.h',
+      'trace_event/trace_event_android.cc',
+      'trace_event/trace_event_argument.cc',
+      'trace_event/trace_event_argument.h',
+      'trace_event/trace_event_etw_export_win.cc',
+      'trace_event/trace_event_etw_export_win.h',
+      'trace_event/trace_event_impl.cc',
+      'trace_event/trace_event_impl.h',
+      'trace_event/trace_event_impl_constants.cc',
+      'trace_event/trace_event_memory.cc',
+      'trace_event/trace_event_memory.h',
+      'trace_event/trace_event_memory_overhead.cc',
+      'trace_event/trace_event_memory_overhead.h',
+      'trace_event/trace_event_synthetic_delay.cc',
+      'trace_event/trace_event_synthetic_delay.h',
+      'trace_event/trace_event_system_stats_monitor.cc',
+      'trace_event/trace_event_system_stats_monitor.h',
+      'trace_event/trace_event_win.cc',
+      'trace_event/trace_event_win.h',
+      'trace_event/winheap_dump_provider_win.cc',
+      'trace_event/winheap_dump_provider_win.h',
+    ],
+    'conditions': [
+      ['OS == "linux" or OS == "android"', {
+          'trace_event_sources': [
+            'trace_event/malloc_dump_provider.cc',
+            'trace_event/malloc_dump_provider.h',
+          ],
+      }],
+    ],
+    'trace_event_test_sources' : [
+      'trace_event/java_heap_dump_provider_android_unittest.cc',
+      'trace_event/memory_allocator_dump_unittest.cc',
+      'trace_event/memory_dump_manager_unittest.cc',
+      'trace_event/process_memory_dump_unittest.cc',
+      'trace_event/process_memory_maps_dump_provider_unittest.cc',
+      'trace_event/process_memory_totals_dump_provider_unittest.cc',
+      'trace_event/trace_config_unittest.cc',
+      'trace_event/trace_event_argument_unittest.cc',
+      'trace_event/trace_event_memory_unittest.cc',
+      'trace_event/trace_event_synthetic_delay_unittest.cc',
+      'trace_event/trace_event_system_stats_monitor_unittest.cc',
+      'trace_event/trace_event_unittest.cc',
+      'trace_event/trace_event_win_unittest.cc',
+      'trace_event/winheap_dump_provider_win_unittest.cc',
+    ],
+  },
+}
diff --git a/base/trace_event/trace_event.h b/base/trace_event/trace_event.h
new file mode 100644
index 0000000..c41ca1e
--- /dev/null
+++ b/base/trace_event/trace_event.h
@@ -0,0 +1,1717 @@
+// Copyright (c) 2012 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 header file defines the set of trace_event macros without specifying
+// how the events actually get collected and stored. If you need to expose trace
+// events to some other universe, you can copy-and-paste this file as well as
+// trace_event.h, modifying the macros contained there as necessary for the
+// target platform. The end result is that multiple libraries can funnel events
+// through to a shared trace event collector.
+
+// Trace events are for tracking application performance and resource usage.
+// Macros are provided to track:
+//    Begin and end of function calls
+//    Counters
+//
+// Events are issued against categories. Whereas LOG's
+// categories are statically defined, TRACE categories are created
+// implicitly with a string. For example:
+//   TRACE_EVENT_INSTANT0("MY_SUBSYSTEM", "SomeImportantEvent",
+//                        TRACE_EVENT_SCOPE_THREAD)
+//
+// It is often the case that one trace may belong in multiple categories at the
+// same time. The first argument to the trace can be a comma-separated list of
+// categories, forming a category group, like:
+//
+// TRACE_EVENT_INSTANT0("input,views", "OnMouseOver", TRACE_EVENT_SCOPE_THREAD)
+//
+// We can enable/disable tracing of OnMouseOver by enabling/disabling either
+// category.
+//
+// Events can be INSTANT, or can be pairs of BEGIN and END in the same scope:
+//   TRACE_EVENT_BEGIN0("MY_SUBSYSTEM", "SomethingCostly")
+//   doSomethingCostly()
+//   TRACE_EVENT_END0("MY_SUBSYSTEM", "SomethingCostly")
+// Note: our tools can't always determine the correct BEGIN/END pairs unless
+// these are used in the same scope. Use ASYNC_BEGIN/ASYNC_END macros if you
+// need them to be in separate scopes.
+//
+// A common use case is to trace entire function scopes. This
+// issues a trace BEGIN and END automatically:
+//   void doSomethingCostly() {
+//     TRACE_EVENT0("MY_SUBSYSTEM", "doSomethingCostly");
+//     ...
+//   }
+//
+// Additional parameters can be associated with an event:
+//   void doSomethingCostly2(int howMuch) {
+//     TRACE_EVENT1("MY_SUBSYSTEM", "doSomethingCostly",
+//         "howMuch", howMuch);
+//     ...
+//   }
+//
+// The trace system will automatically add to this information the
+// current process id, thread id, and a timestamp in microseconds.
+//
+// To trace an asynchronous procedure such as an IPC send/receive, use
+// ASYNC_BEGIN and ASYNC_END:
+//   [single threaded sender code]
+//     static int send_count = 0;
+//     ++send_count;
+//     TRACE_EVENT_ASYNC_BEGIN0("ipc", "message", send_count);
+//     Send(new MyMessage(send_count));
+//   [receive code]
+//     void OnMyMessage(send_count) {
+//       TRACE_EVENT_ASYNC_END0("ipc", "message", send_count);
+//     }
+// The third parameter is a unique ID to match ASYNC_BEGIN/ASYNC_END pairs.
+// ASYNC_BEGIN and ASYNC_END can occur on any thread of any traced process.
+// Pointers can be used for the ID parameter, and they will be mangled
+// internally so that the same pointer on two different processes will not
+// match. For example:
+//   class MyTracedClass {
+//    public:
+//     MyTracedClass() {
+//       TRACE_EVENT_ASYNC_BEGIN0("category", "MyTracedClass", this);
+//     }
+//     ~MyTracedClass() {
+//       TRACE_EVENT_ASYNC_END0("category", "MyTracedClass", this);
+//     }
+//   }
+//
+// Trace event also supports counters, which is a way to track a quantity
+// as it varies over time. Counters are created with the following macro:
+//   TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter", g_myCounterValue);
+//
+// Counters are process-specific. The macro itself can be issued from any
+// thread, however.
+//
+// Sometimes, you want to track two counters at once. You can do this with two
+// counter macros:
+//   TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter0", g_myCounterValue[0]);
+//   TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter1", g_myCounterValue[1]);
+// Or you can do it with a combined macro:
+//   TRACE_COUNTER2("MY_SUBSYSTEM", "myCounter",
+//       "bytesPinned", g_myCounterValue[0],
+//       "bytesAllocated", g_myCounterValue[1]);
+// This indicates to the tracing UI that these counters should be displayed
+// in a single graph, as a summed area chart.
+//
+// Since counters are in a global namespace, you may want to disambiguate with a
+// unique ID, by using the TRACE_COUNTER_ID* variations.
+//
+// By default, trace collection is compiled in, but turned off at runtime.
+// Collecting trace data is the responsibility of the embedding
+// application. In Chrome's case, navigating to about:tracing will turn on
+// tracing and display data collected across all active processes.
+//
+//
+// Memory scoping note:
+// Tracing copies the pointers, not the string content, of the strings passed
+// in for category_group, name, and arg_names.  Thus, the following code will
+// cause problems:
+//     char* str = strdup("importantName");
+//     TRACE_EVENT_INSTANT0("SUBSYSTEM", str);  // BAD!
+//     free(str);                   // Trace system now has dangling pointer
+//
+// To avoid this issue with the |name| and |arg_name| parameters, use the
+// TRACE_EVENT_COPY_XXX overloads of the macros at additional runtime overhead.
+// Notes: The category must always be in a long-lived char* (i.e. static const).
+//        The |arg_values|, when used, are always deep copied with the _COPY
+//        macros.
+//
+// When are string argument values copied:
+// const char* arg_values are only referenced by default:
+//     TRACE_EVENT1("category", "name",
+//                  "arg1", "literal string is only referenced");
+// Use TRACE_STR_COPY to force copying of a const char*:
+//     TRACE_EVENT1("category", "name",
+//                  "arg1", TRACE_STR_COPY("string will be copied"));
+// std::string arg_values are always copied:
+//     TRACE_EVENT1("category", "name",
+//                  "arg1", std::string("string will be copied"));
+//
+//
+// Convertable notes:
+// Converting a large data type to a string can be costly. To help with this,
+// the trace framework provides an interface ConvertableToTraceFormat. If you
+// inherit from it and implement the AppendAsTraceFormat method the trace
+// framework will call back to your object to convert a trace output time. This
+// means, if the category for the event is disabled, the conversion will not
+// happen.
+//
+//   class MyData : public base::trace_event::ConvertableToTraceFormat {
+//    public:
+//     MyData() {}
+//     void AppendAsTraceFormat(std::string* out) const override {
+//       out->append("{\"foo\":1}");
+//     }
+//    private:
+//     ~MyData() override {}
+//     DISALLOW_COPY_AND_ASSIGN(MyData);
+//   };
+//
+//   TRACE_EVENT1("foo", "bar", "data",
+//                scoped_refptr<ConvertableToTraceFormat>(new MyData()));
+//
+// The trace framework will take ownership if the passed pointer and it will
+// be free'd when the trace buffer is flushed.
+//
+// Note, we only do the conversion when the buffer is flushed, so the provided
+// data object should not be modified after it's passed to the trace framework.
+//
+//
+// Thread Safety:
+// A thread safe singleton and mutex are used for thread safety. Category
+// enabled flags are used to limit the performance impact when the system
+// is not enabled.
+//
+// TRACE_EVENT macros first cache a pointer to a category. The categories are
+// statically allocated and safe at all times, even after exit. Fetching a
+// category is protected by the TraceLog::lock_. Multiple threads initializing
+// the static variable is safe, as they will be serialized by the lock and
+// multiple calls will return the same pointer to the category.
+//
+// Then the category_group_enabled flag is checked. This is a unsigned char, and
+// not intended to be multithread safe. It optimizes access to AddTraceEvent
+// which is threadsafe internally via TraceLog::lock_. The enabled flag may
+// cause some threads to incorrectly call or skip calling AddTraceEvent near
+// the time of the system being enabled or disabled. This is acceptable as
+// we tolerate some data loss while the system is being enabled/disabled and
+// because AddTraceEvent is threadsafe internally and checks the enabled state
+// again under lock.
+//
+// Without the use of these static category pointers and enabled flags all
+// trace points would carry a significant performance cost of acquiring a lock
+// and resolving the category.
+
+#ifndef BASE_TRACE_EVENT_TRACE_EVENT_H_
+#define BASE_TRACE_EVENT_TRACE_EVENT_H_
+
+#include <string>
+
+#include "base/atomicops.h"
+#include "base/time/time.h"
+#include "base/trace_event/trace_event_impl.h"
+#include "base/trace_event/trace_event_memory.h"
+#include "base/trace_event/trace_event_system_stats_monitor.h"
+#include "build/build_config.h"
+
+// By default, const char* argument values are assumed to have long-lived scope
+// and will not be copied. Use this macro to force a const char* to be copied.
+#define TRACE_STR_COPY(str) \
+    trace_event_internal::TraceStringWithCopy(str)
+
+// This will mark the trace event as disabled by default. The user will need
+// to explicitly enable the event.
+#define TRACE_DISABLED_BY_DEFAULT(name) "disabled-by-default-" name
+
+// By default, uint64 ID argument values are not mangled with the Process ID in
+// TRACE_EVENT_ASYNC macros. Use this macro to force Process ID mangling.
+#define TRACE_ID_MANGLE(id) \
+    trace_event_internal::TraceID::ForceMangle(id)
+
+// By default, pointers are mangled with the Process ID in TRACE_EVENT_ASYNC
+// macros. Use this macro to prevent Process ID mangling.
+#define TRACE_ID_DONT_MANGLE(id) \
+    trace_event_internal::TraceID::DontMangle(id)
+
+// Records a pair of begin and end events called "name" for the current
+// scope, with 0, 1 or 2 associated arguments. If the category is not
+// enabled, then this does nothing.
+// - category and name strings must have application lifetime (statics or
+//   literals). They may not include " chars.
+#define TRACE_EVENT0(category_group, name) \
+    INTERNAL_TRACE_MEMORY(category_group, name) \
+    INTERNAL_TRACE_EVENT_ADD_SCOPED(category_group, name)
+#define TRACE_EVENT1(category_group, name, arg1_name, arg1_val) \
+    INTERNAL_TRACE_MEMORY(category_group, name) \
+    INTERNAL_TRACE_EVENT_ADD_SCOPED(category_group, name, arg1_name, arg1_val)
+#define TRACE_EVENT2( \
+    category_group, name, arg1_name, arg1_val, arg2_name, arg2_val) \
+  INTERNAL_TRACE_MEMORY(category_group, name) \
+  INTERNAL_TRACE_EVENT_ADD_SCOPED( \
+      category_group, name, arg1_name, arg1_val, arg2_name, arg2_val)
+
+// Records events like TRACE_EVENT2 but uses |memory_tag| for memory tracing.
+// Use this where |name| is too generic to accurately aggregate allocations.
+#define TRACE_EVENT_WITH_MEMORY_TAG2( \
+    category, name, memory_tag, arg1_name, arg1_val, arg2_name, arg2_val) \
+  INTERNAL_TRACE_MEMORY(category, memory_tag) \
+  INTERNAL_TRACE_EVENT_ADD_SCOPED( \
+      category, name, arg1_name, arg1_val, arg2_name, arg2_val)
+
+// UNSHIPPED_TRACE_EVENT* are like TRACE_EVENT* except that they are not
+// included in official builds.
+
+#if OFFICIAL_BUILD
+#undef TRACING_IS_OFFICIAL_BUILD
+#define TRACING_IS_OFFICIAL_BUILD 1
+#elif !defined(TRACING_IS_OFFICIAL_BUILD)
+#define TRACING_IS_OFFICIAL_BUILD 0
+#endif
+
+#if TRACING_IS_OFFICIAL_BUILD
+#define UNSHIPPED_TRACE_EVENT0(category_group, name) (void)0
+#define UNSHIPPED_TRACE_EVENT1(category_group, name, arg1_name, arg1_val) \
+    (void)0
+#define UNSHIPPED_TRACE_EVENT2(category_group, name, arg1_name, arg1_val, \
+                               arg2_name, arg2_val) (void)0
+#define UNSHIPPED_TRACE_EVENT_INSTANT0(category_group, name, scope) (void)0
+#define UNSHIPPED_TRACE_EVENT_INSTANT1(category_group, name, scope, \
+                                       arg1_name, arg1_val) (void)0
+#define UNSHIPPED_TRACE_EVENT_INSTANT2(category_group, name, scope, \
+                                       arg1_name, arg1_val, \
+                                       arg2_name, arg2_val) (void)0
+#else
+#define UNSHIPPED_TRACE_EVENT0(category_group, name) \
+    TRACE_EVENT0(category_group, name)
+#define UNSHIPPED_TRACE_EVENT1(category_group, name, arg1_name, arg1_val) \
+    TRACE_EVENT1(category_group, name, arg1_name, arg1_val)
+#define UNSHIPPED_TRACE_EVENT2(category_group, name, arg1_name, arg1_val, \
+                               arg2_name, arg2_val) \
+    TRACE_EVENT2(category_group, name, arg1_name, arg1_val, arg2_name, arg2_val)
+#define UNSHIPPED_TRACE_EVENT_INSTANT0(category_group, name, scope) \
+    TRACE_EVENT_INSTANT0(category_group, name, scope)
+#define UNSHIPPED_TRACE_EVENT_INSTANT1(category_group, name, scope, \
+                                       arg1_name, arg1_val) \
+    TRACE_EVENT_INSTANT1(category_group, name, scope, arg1_name, arg1_val)
+#define UNSHIPPED_TRACE_EVENT_INSTANT2(category_group, name, scope, \
+                                       arg1_name, arg1_val, \
+                                       arg2_name, arg2_val) \
+    TRACE_EVENT_INSTANT2(category_group, name, scope, arg1_name, arg1_val, \
+                         arg2_name, arg2_val)
+#endif
+
+// Records a single event called "name" immediately, with 0, 1 or 2
+// associated arguments. If the category is not enabled, then this
+// does nothing.
+// - category and name strings must have application lifetime (statics or
+//   literals). They may not include " chars.
+#define TRACE_EVENT_INSTANT0(category_group, name, scope) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \
+        category_group, name, TRACE_EVENT_FLAG_NONE | scope)
+#define TRACE_EVENT_INSTANT1(category_group, name, scope, arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \
+        category_group, name, TRACE_EVENT_FLAG_NONE | scope, \
+        arg1_name, arg1_val)
+#define TRACE_EVENT_INSTANT2(category_group, name, scope, arg1_name, arg1_val, \
+                             arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \
+        category_group, name, TRACE_EVENT_FLAG_NONE | scope, \
+        arg1_name, arg1_val, arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_INSTANT0(category_group, name, scope) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \
+        category_group, name, TRACE_EVENT_FLAG_COPY | scope)
+#define TRACE_EVENT_COPY_INSTANT1(category_group, name, scope, \
+                                  arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \
+        category_group, name, TRACE_EVENT_FLAG_COPY | scope, arg1_name, \
+        arg1_val)
+#define TRACE_EVENT_COPY_INSTANT2(category_group, name, scope, \
+                                  arg1_name, arg1_val, \
+                                  arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \
+        category_group, name, TRACE_EVENT_FLAG_COPY | scope, \
+        arg1_name, arg1_val, arg2_name, arg2_val)
+
+// Sets the current sample state to the given category and name (both must be
+// constant strings). These states are intended for a sampling profiler.
+// Implementation note: we store category and name together because we don't
+// want the inconsistency/expense of storing two pointers.
+// |thread_bucket| is [0..2] and is used to statically isolate samples in one
+// thread from others.
+#define TRACE_EVENT_SET_SAMPLING_STATE_FOR_BUCKET( \
+    bucket_number, category, name)                 \
+        trace_event_internal::                     \
+        TraceEventSamplingStateScope<bucket_number>::Set(category "\0" name)
+
+// Returns a current sampling state of the given bucket.
+#define TRACE_EVENT_GET_SAMPLING_STATE_FOR_BUCKET(bucket_number) \
+    trace_event_internal::TraceEventSamplingStateScope<bucket_number>::Current()
+
+// Creates a scope of a sampling state of the given bucket.
+//
+// {  // The sampling state is set within this scope.
+//    TRACE_EVENT_SAMPLING_STATE_SCOPE_FOR_BUCKET(0, "category", "name");
+//    ...;
+// }
+#define TRACE_EVENT_SCOPED_SAMPLING_STATE_FOR_BUCKET(                   \
+    bucket_number, category, name)                                      \
+    trace_event_internal::TraceEventSamplingStateScope<bucket_number>   \
+        traceEventSamplingScope(category "\0" name);
+
+// Syntactic sugars for the sampling tracing in the main thread.
+#define TRACE_EVENT_SCOPED_SAMPLING_STATE(category, name) \
+    TRACE_EVENT_SCOPED_SAMPLING_STATE_FOR_BUCKET(0, category, name)
+#define TRACE_EVENT_GET_SAMPLING_STATE() \
+    TRACE_EVENT_GET_SAMPLING_STATE_FOR_BUCKET(0)
+#define TRACE_EVENT_SET_SAMPLING_STATE(category, name) \
+    TRACE_EVENT_SET_SAMPLING_STATE_FOR_BUCKET(0, category, name)
+
+
+// Records a single BEGIN event called "name" immediately, with 0, 1 or 2
+// associated arguments. If the category is not enabled, then this
+// does nothing.
+// - category and name strings must have application lifetime (statics or
+//   literals). They may not include " chars.
+#define TRACE_EVENT_BEGIN0(category_group, name) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \
+        category_group, name, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_BEGIN1(category_group, name, arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \
+        category_group, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+#define TRACE_EVENT_BEGIN2(category_group, name, arg1_name, arg1_val, \
+        arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \
+        category_group, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \
+        arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_BEGIN0(category_group, name) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \
+        category_group, name, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_BEGIN1(category_group, name, arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \
+        category_group, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_BEGIN2(category_group, name, arg1_name, arg1_val, \
+        arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \
+        category_group, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \
+        arg2_name, arg2_val)
+
+// Similar to TRACE_EVENT_BEGINx but with a custom |at| timestamp provided.
+// - |id| is used to match the _BEGIN event with the _END event.
+//   Events are considered to match if their category_group, name and id values
+//   all match. |id| must either be a pointer or an integer value up to 64 bits.
+//   If it's a pointer, the bits will be xored with a hash of the process ID so
+//   that the same pointer on two different processes will not collide.
+#define TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0(category_group, \
+        name, id, thread_id, timestamp) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+        TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, thread_id, \
+        timestamp, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP0( \
+        category_group, name, id, thread_id, timestamp) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+        TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, thread_id, \
+        timestamp, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP1( \
+        category_group, name, id, thread_id, timestamp, arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+        TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, thread_id, \
+        timestamp, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP2( \
+        category_group, name, id, thread_id, timestamp, arg1_name, arg1_val, \
+        arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+        TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, thread_id, \
+        timestamp, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, arg2_name, \
+        arg2_val)
+
+// Records a single END event for "name" immediately. If the category
+// is not enabled, then this does nothing.
+// - category and name strings must have application lifetime (statics or
+//   literals). They may not include " chars.
+#define TRACE_EVENT_END0(category_group, name) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \
+        category_group, name, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_END1(category_group, name, arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \
+        category_group, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+#define TRACE_EVENT_END2(category_group, name, arg1_name, arg1_val, \
+        arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \
+        category_group, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \
+        arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_END0(category_group, name) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \
+        category_group, name, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_END1(category_group, name, arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \
+        category_group, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_END2(category_group, name, arg1_name, arg1_val, \
+        arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \
+        category_group, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \
+        arg2_name, arg2_val)
+
+// Similar to TRACE_EVENT_ENDx but with a custom |at| timestamp provided.
+// - |id| is used to match the _BEGIN event with the _END event.
+//   Events are considered to match if their category_group, name and id values
+//   all match. |id| must either be a pointer or an integer value up to 64 bits.
+//   If it's a pointer, the bits will be xored with a hash of the process ID so
+//   that the same pointer on two different processes will not collide.
+#define TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0(category_group, \
+        name, id, thread_id, timestamp) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+        TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, thread_id, \
+        timestamp, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP0( \
+        category_group, name, id, thread_id, timestamp) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+        TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, thread_id, \
+        timestamp, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP1( \
+        category_group, name, id, thread_id, timestamp, arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+        TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, thread_id, \
+        timestamp, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP2( \
+        category_group, name, id, thread_id, timestamp, arg1_name, arg1_val, \
+        arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+        TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, thread_id, \
+        timestamp, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, arg2_name, \
+        arg2_val)
+
+// Records the value of a counter called "name" immediately. Value
+// must be representable as a 32 bit integer.
+// - category and name strings must have application lifetime (statics or
+//   literals). They may not include " chars.
+#define TRACE_COUNTER1(category_group, name, value) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, \
+        category_group, name, TRACE_EVENT_FLAG_NONE, \
+        "value", static_cast<int>(value))
+#define TRACE_COPY_COUNTER1(category_group, name, value) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, \
+        category_group, name, TRACE_EVENT_FLAG_COPY, \
+        "value", static_cast<int>(value))
+
+// Records the values of a multi-parted counter called "name" immediately.
+// The UI will treat value1 and value2 as parts of a whole, displaying their
+// values as a stacked-bar chart.
+// - category and name strings must have application lifetime (statics or
+//   literals). They may not include " chars.
+#define TRACE_COUNTER2(category_group, name, value1_name, value1_val, \
+        value2_name, value2_val) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, \
+        category_group, name, TRACE_EVENT_FLAG_NONE, \
+        value1_name, static_cast<int>(value1_val), \
+        value2_name, static_cast<int>(value2_val))
+#define TRACE_COPY_COUNTER2(category_group, name, value1_name, value1_val, \
+        value2_name, value2_val) \
+    INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, \
+        category_group, name, TRACE_EVENT_FLAG_COPY, \
+        value1_name, static_cast<int>(value1_val), \
+        value2_name, static_cast<int>(value2_val))
+
+// Records the value of a counter called "name" immediately. Value
+// must be representable as a 32 bit integer.
+// - category and name strings must have application lifetime (statics or
+//   literals). They may not include " chars.
+// - |id| is used to disambiguate counters with the same name. It must either
+//   be a pointer or an integer value up to 64 bits. If it's a pointer, the bits
+//   will be xored with a hash of the process ID so that the same pointer on
+//   two different processes will not collide.
+#define TRACE_COUNTER_ID1(category_group, name, id, value) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE, \
+        "value", static_cast<int>(value))
+#define TRACE_COPY_COUNTER_ID1(category_group, name, id, value) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, \
+        category_group, name, id, TRACE_EVENT_FLAG_COPY, \
+        "value", static_cast<int>(value))
+
+// Records the values of a multi-parted counter called "name" immediately.
+// The UI will treat value1 and value2 as parts of a whole, displaying their
+// values as a stacked-bar chart.
+// - category and name strings must have application lifetime (statics or
+//   literals). They may not include " chars.
+// - |id| is used to disambiguate counters with the same name. It must either
+//   be a pointer or an integer value up to 64 bits. If it's a pointer, the bits
+//   will be xored with a hash of the process ID so that the same pointer on
+//   two different processes will not collide.
+#define TRACE_COUNTER_ID2(category_group, name, id, value1_name, value1_val, \
+        value2_name, value2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE, \
+        value1_name, static_cast<int>(value1_val), \
+        value2_name, static_cast<int>(value2_val))
+#define TRACE_COPY_COUNTER_ID2(category_group, name, id, value1_name, \
+        value1_val, value2_name, value2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, \
+        category_group, name, id, TRACE_EVENT_FLAG_COPY, \
+        value1_name, static_cast<int>(value1_val), \
+        value2_name, static_cast<int>(value2_val))
+
+// TRACE_EVENT_SAMPLE_* events are injected by the sampling profiler.
+#define TRACE_EVENT_SAMPLE_WITH_TID_AND_TIMESTAMP0(category_group, name,       \
+                                                   thread_id, timestamp)       \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                          \
+      TRACE_EVENT_PHASE_SAMPLE, category_group, name, 0, thread_id, timestamp, \
+      TRACE_EVENT_FLAG_NONE)
+
+#define TRACE_EVENT_SAMPLE_WITH_TID_AND_TIMESTAMP1(                            \
+    category_group, name, thread_id, timestamp, arg1_name, arg1_val)           \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                          \
+      TRACE_EVENT_PHASE_SAMPLE, category_group, name, 0, thread_id, timestamp, \
+      TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+
+#define TRACE_EVENT_SAMPLE_WITH_TID_AND_TIMESTAMP2(category_group, name,       \
+                                                   thread_id, timestamp,       \
+                                                   arg1_name, arg1_val,        \
+                                                   arg2_name, arg2_val)        \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(                          \
+      TRACE_EVENT_PHASE_SAMPLE, category_group, name, 0, thread_id, timestamp, \
+      TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, arg2_name, arg2_val)
+
+// ASYNC_STEP_* APIs should be only used by legacy code. New code should
+// consider using NESTABLE_ASYNC_* APIs to describe substeps within an async
+// event.
+// Records a single ASYNC_BEGIN event called "name" immediately, with 0, 1 or 2
+// associated arguments. If the category is not enabled, then this
+// does nothing.
+// - category and name strings must have application lifetime (statics or
+//   literals). They may not include " chars.
+// - |id| is used to match the ASYNC_BEGIN event with the ASYNC_END event. ASYNC
+//   events are considered to match if their category_group, name and id values
+//   all match. |id| must either be a pointer or an integer value up to 64 bits.
+//   If it's a pointer, the bits will be xored with a hash of the process ID so
+//   that the same pointer on two different processes will not collide.
+//
+// An asynchronous operation can consist of multiple phases. The first phase is
+// defined by the ASYNC_BEGIN calls. Additional phases can be defined using the
+// ASYNC_STEP_INTO or ASYNC_STEP_PAST macros. The ASYNC_STEP_INTO macro will
+// annotate the block following the call. The ASYNC_STEP_PAST macro will
+// annotate the block prior to the call. Note that any particular event must use
+// only STEP_INTO or STEP_PAST macros; they can not mix and match. When the
+// operation completes, call ASYNC_END.
+//
+// An ASYNC trace typically occurs on a single thread (if not, they will only be
+// drawn on the thread defined in the ASYNC_BEGIN event), but all events in that
+// operation must use the same |name| and |id|. Each step can have its own
+// args.
+#define TRACE_EVENT_ASYNC_BEGIN0(category_group, name, id) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_ASYNC_BEGIN1(category_group, name, id, arg1_name, \
+        arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+#define TRACE_EVENT_ASYNC_BEGIN2(category_group, name, id, arg1_name, \
+        arg1_val, arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE, \
+        arg1_name, arg1_val, arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_ASYNC_BEGIN0(category_group, name, id) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \
+        category_group, name, id, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_ASYNC_BEGIN1(category_group, name, id, arg1_name, \
+        arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \
+        category_group, name, id, TRACE_EVENT_FLAG_COPY, \
+        arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_ASYNC_BEGIN2(category_group, name, id, arg1_name, \
+        arg1_val, arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \
+        category_group, name, id, TRACE_EVENT_FLAG_COPY, \
+        arg1_name, arg1_val, arg2_name, arg2_val)
+
+// Similar to TRACE_EVENT_ASYNC_BEGINx but with a custom |at| timestamp
+// provided.
+#define TRACE_EVENT_ASYNC_BEGIN_WITH_TIMESTAMP0(category_group, \
+        name, id, timestamp) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+        TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, \
+        static_cast<int>(base::PlatformThread::CurrentId()), \
+        timestamp, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_COPY_ASYNC_BEGIN_WITH_TIMESTAMP0(category_group, \
+        name, id, timestamp) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+        TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, \
+        static_cast<int>(base::PlatformThread::CurrentId()), \
+        timestamp, TRACE_EVENT_FLAG_COPY)
+
+// Records a single ASYNC_STEP_INTO event for |step| immediately. If the
+// category is not enabled, then this does nothing. The |name| and |id| must
+// match the ASYNC_BEGIN event above. The |step| param identifies this step
+// within the async event. This should be called at the beginning of the next
+// phase of an asynchronous operation. The ASYNC_BEGIN event must not have any
+// ASYNC_STEP_PAST events.
+#define TRACE_EVENT_ASYNC_STEP_INTO0(category_group, name, id, step) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP_INTO, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE, "step", step)
+#define TRACE_EVENT_ASYNC_STEP_INTO1(category_group, name, id, step, \
+                                     arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP_INTO, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE, "step", step, \
+        arg1_name, arg1_val)
+
+// Similar to TRACE_EVENT_ASYNC_STEP_INTOx but with a custom |at| timestamp
+// provided.
+#define TRACE_EVENT_ASYNC_STEP_INTO_WITH_TIMESTAMP0(category_group, name, \
+        id, step, timestamp) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+        TRACE_EVENT_PHASE_ASYNC_STEP_INTO, category_group, name, id, \
+        static_cast<int>(base::PlatformThread::CurrentId()), \
+        timestamp, TRACE_EVENT_FLAG_NONE, "step", step)
+
+// Records a single ASYNC_STEP_PAST event for |step| immediately. If the
+// category is not enabled, then this does nothing. The |name| and |id| must
+// match the ASYNC_BEGIN event above. The |step| param identifies this step
+// within the async event. This should be called at the beginning of the next
+// phase of an asynchronous operation. The ASYNC_BEGIN event must not have any
+// ASYNC_STEP_INTO events.
+#define TRACE_EVENT_ASYNC_STEP_PAST0(category_group, name, id, step) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP_PAST, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE, "step", step)
+#define TRACE_EVENT_ASYNC_STEP_PAST1(category_group, name, id, step, \
+                                     arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP_PAST, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE, "step", step, \
+        arg1_name, arg1_val)
+
+// Records a single ASYNC_END event for "name" immediately. If the category
+// is not enabled, then this does nothing.
+#define TRACE_EVENT_ASYNC_END0(category_group, name, id) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_ASYNC_END1(category_group, name, id, arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+#define TRACE_EVENT_ASYNC_END2(category_group, name, id, arg1_name, arg1_val, \
+        arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE, \
+        arg1_name, arg1_val, arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_ASYNC_END0(category_group, name, id) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \
+        category_group, name, id, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_ASYNC_END1(category_group, name, id, arg1_name, \
+        arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \
+        category_group, name, id, TRACE_EVENT_FLAG_COPY, \
+        arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_ASYNC_END2(category_group, name, id, arg1_name, \
+        arg1_val, arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \
+        category_group, name, id, TRACE_EVENT_FLAG_COPY, \
+        arg1_name, arg1_val, arg2_name, arg2_val)
+
+// Similar to TRACE_EVENT_ASYNC_ENDx but with a custom |at| timestamp provided.
+#define TRACE_EVENT_ASYNC_END_WITH_TIMESTAMP0(category_group, \
+        name, id, timestamp) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+        TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, \
+        static_cast<int>(base::PlatformThread::CurrentId()), \
+        timestamp, TRACE_EVENT_FLAG_NONE)
+
+// NESTABLE_ASYNC_* APIs are used to describe an async operation, which can
+// be nested within a NESTABLE_ASYNC event and/or have inner NESTABLE_ASYNC
+// events.
+// - category and name strings must have application lifetime (statics or
+//   literals). They may not include " chars.
+// - A pair of NESTABLE_ASYNC_BEGIN event and NESTABLE_ASYNC_END event is
+//   considered as a match if their category_group, name and id all match.
+// - |id| must either be a pointer or an integer value up to 64 bits.
+//   If it's a pointer, the bits will be xored with a hash of the process ID so
+//   that the same pointer on two different processes will not collide.
+// - |id| is used to match a child NESTABLE_ASYNC event with its parent
+//   NESTABLE_ASYNC event. Therefore, events in the same nested event tree must
+//   be logged using the same id and category_group.
+//
+// Unmatched NESTABLE_ASYNC_END event will be parsed as an event that starts
+// at the first NESTABLE_ASYNC event of that id, and unmatched
+// NESTABLE_ASYNC_BEGIN event will be parsed as an event that ends at the last
+// NESTABLE_ASYNC event of that id. Corresponding warning messages for
+// unmatched events will be shown in the analysis view.
+
+// Records a single NESTABLE_ASYNC_BEGIN event called "name" immediately, with
+// 0, 1 or 2 associated arguments. If the category is not enabled, then this
+// does nothing.
+#define TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(category_group, name, id) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(category_group, name, id, arg1_name, \
+        arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+#define TRACE_EVENT_NESTABLE_ASYNC_BEGIN2(category_group, name, id, arg1_name, \
+        arg1_val, arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \
+        arg2_name, arg2_val)
+// Records a single NESTABLE_ASYNC_END event called "name" immediately, with 0
+// or 2 associated arguments. If the category is not enabled, then this does
+// nothing.
+#define TRACE_EVENT_NESTABLE_ASYNC_END0(category_group, name, id) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_NESTABLE_ASYNC_END2(category_group, name, id, arg1_name, \
+        arg1_val, arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \
+        arg2_name, arg2_val)
+
+#define TRACE_EVENT_COPY_NESTABLE_ASYNC_BEGIN_WITH_TTS2(category_group, name, \
+        id, arg1_name, arg1_val, arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, \
+        category_group, name, id, \
+        TRACE_EVENT_FLAG_ASYNC_TTS | TRACE_EVENT_FLAG_COPY, \
+        arg1_name, arg1_val, arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_NESTABLE_ASYNC_END_WITH_TTS2(category_group, name, \
+        id, arg1_name, arg1_val, arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, \
+        category_group, name, id, \
+        TRACE_EVENT_FLAG_ASYNC_TTS | TRACE_EVENT_FLAG_COPY, \
+        arg1_name, arg1_val, arg2_name, arg2_val)
+
+// Similar to TRACE_EVENT_NESTABLE_ASYNC_{BEGIN,END}x but with a custom
+// |timestamp| provided.
+#define TRACE_EVENT_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP0(category_group, name, \
+        id, timestamp) \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+        TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, category_group, name, id, \
+        static_cast<int>(base::PlatformThread::CurrentId()), timestamp, \
+        TRACE_EVENT_FLAG_NONE)
+
+#define TRACE_EVENT_NESTABLE_ASYNC_END_WITH_TIMESTAMP0(category_group, name, \
+        id, timestamp) \
+  INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+        TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, category_group, name, id, \
+        static_cast<int>(base::PlatformThread::CurrentId()), timestamp, \
+        TRACE_EVENT_FLAG_NONE)
+
+// Records a single NESTABLE_ASYNC_INSTANT event called "name" immediately,
+// with 2 associated arguments. If the category is not enabled, then this
+// does nothing.
+#define TRACE_EVENT_NESTABLE_ASYNC_INSTANT2(category_group, name, id, \
+        arg1_name, arg1_val, arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \
+        arg2_name, arg2_val)
+
+// Records a single FLOW_BEGIN event called "name" immediately, with 0, 1 or 2
+// associated arguments. If the category is not enabled, then this
+// does nothing.
+// - category and name strings must have application lifetime (statics or
+//   literals). They may not include " chars.
+// - |id| is used to match the FLOW_BEGIN event with the FLOW_END event. FLOW
+//   events are considered to match if their category_group, name and id values
+//   all match. |id| must either be a pointer or an integer value up to 64 bits.
+//   If it's a pointer, the bits will be xored with a hash of the process ID so
+//   that the same pointer on two different processes will not collide.
+// FLOW events are different from ASYNC events in how they are drawn by the
+// tracing UI. A FLOW defines asynchronous data flow, such as posting a task
+// (FLOW_BEGIN) and later executing that task (FLOW_END). Expect FLOWs to be
+// drawn as lines or arrows from FLOW_BEGIN scopes to FLOW_END scopes. Similar
+// to ASYNC, a FLOW can consist of multiple phases. The first phase is defined
+// by the FLOW_BEGIN calls. Additional phases can be defined using the FLOW_STEP
+// macros. When the operation completes, call FLOW_END. An async operation can
+// span threads and processes, but all events in that operation must use the
+// same |name| and |id|. Each event can have its own args.
+#define TRACE_EVENT_FLOW_BEGIN0(category_group, name, id) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_FLOW_BEGIN1(category_group, name, id, arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+#define TRACE_EVENT_FLOW_BEGIN2(category_group, name, id, arg1_name, arg1_val, \
+        arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE, \
+        arg1_name, arg1_val, arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_FLOW_BEGIN0(category_group, name, id) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \
+        category_group, name, id, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_FLOW_BEGIN1(category_group, name, id, arg1_name, \
+        arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \
+        category_group, name, id, TRACE_EVENT_FLAG_COPY, \
+        arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_FLOW_BEGIN2(category_group, name, id, arg1_name, \
+        arg1_val, arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \
+        category_group, name, id, TRACE_EVENT_FLAG_COPY, \
+        arg1_name, arg1_val, arg2_name, arg2_val)
+
+// Records a single FLOW_STEP event for |step| immediately. If the category
+// is not enabled, then this does nothing. The |name| and |id| must match the
+// FLOW_BEGIN event above. The |step| param identifies this step within the
+// async event. This should be called at the beginning of the next phase of an
+// asynchronous operation.
+#define TRACE_EVENT_FLOW_STEP0(category_group, name, id, step) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE, "step", step)
+#define TRACE_EVENT_FLOW_STEP1(category_group, name, id, step, \
+        arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE, "step", step, \
+        arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_FLOW_STEP0(category_group, name, id, step) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, \
+        category_group, name, id, TRACE_EVENT_FLAG_COPY, "step", step)
+#define TRACE_EVENT_COPY_FLOW_STEP1(category_group, name, id, step, \
+        arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, \
+        category_group, name, id, TRACE_EVENT_FLAG_COPY, "step", step, \
+        arg1_name, arg1_val)
+
+// Records a single FLOW_END event for "name" immediately. If the category
+// is not enabled, then this does nothing.
+#define TRACE_EVENT_FLOW_END0(category_group, name, id) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_FLOW_END_BIND_TO_ENCLOSING0(category_group, name, id) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \
+        category_group, name, id, TRACE_EVENT_FLAG_BIND_TO_ENCLOSING)
+#define TRACE_EVENT_FLOW_END1(category_group, name, id, arg1_name, arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
+#define TRACE_EVENT_FLOW_END2(category_group, name, id, arg1_name, arg1_val, \
+        arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \
+        category_group, name, id, TRACE_EVENT_FLAG_NONE, \
+        arg1_name, arg1_val, arg2_name, arg2_val)
+#define TRACE_EVENT_COPY_FLOW_END0(category_group, name, id) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \
+        category_group, name, id, TRACE_EVENT_FLAG_COPY)
+#define TRACE_EVENT_COPY_FLOW_END1(category_group, name, id, arg1_name, \
+        arg1_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \
+        category_group, name, id, TRACE_EVENT_FLAG_COPY, \
+        arg1_name, arg1_val)
+#define TRACE_EVENT_COPY_FLOW_END2(category_group, name, id, arg1_name, \
+        arg1_val, arg2_name, arg2_val) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \
+        category_group, name, id, TRACE_EVENT_FLAG_COPY, \
+        arg1_name, arg1_val, arg2_name, arg2_val)
+
+// Macros to track the life time and value of arbitrary client objects.
+// See also TraceTrackableObject.
+#define TRACE_EVENT_OBJECT_CREATED_WITH_ID(category_group, name, id) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_CREATE_OBJECT, \
+        category_group, name, TRACE_ID_DONT_MANGLE(id), TRACE_EVENT_FLAG_NONE)
+
+#define TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(category_group, name, id, snapshot) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_SNAPSHOT_OBJECT, \
+        category_group, name, TRACE_ID_DONT_MANGLE(id), TRACE_EVENT_FLAG_NONE,\
+        "snapshot", snapshot)
+
+#define TRACE_EVENT_OBJECT_DELETED_WITH_ID(category_group, name, id) \
+    INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_DELETE_OBJECT, \
+        category_group, name, TRACE_ID_DONT_MANGLE(id), TRACE_EVENT_FLAG_NONE)
+
+#define INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE() \
+  UNLIKELY(*INTERNAL_TRACE_EVENT_UID(category_group_enabled) &           \
+           (base::trace_event::TraceLog::ENABLED_FOR_RECORDING |         \
+            base::trace_event::TraceLog::ENABLED_FOR_EVENT_CALLBACK |    \
+            base::trace_event::TraceLog::ENABLED_FOR_ETW_EXPORT))
+
+// Macro to efficiently determine if a given category group is enabled.
+#define TRACE_EVENT_CATEGORY_GROUP_ENABLED(category_group, ret) \
+    do { \
+      INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \
+      if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \
+        *ret = true; \
+      } else { \
+        *ret = false; \
+      } \
+    } while (0)
+
+// Macro to efficiently determine, through polling, if a new trace has begun.
+#define TRACE_EVENT_IS_NEW_TRACE(ret) \
+    do { \
+      static int INTERNAL_TRACE_EVENT_UID(lastRecordingNumber) = 0; \
+      int num_traces_recorded = TRACE_EVENT_API_GET_NUM_TRACES_RECORDED(); \
+      if (num_traces_recorded != -1 && \
+          num_traces_recorded != \
+          INTERNAL_TRACE_EVENT_UID(lastRecordingNumber)) { \
+        INTERNAL_TRACE_EVENT_UID(lastRecordingNumber) = \
+            num_traces_recorded; \
+        *ret = true; \
+      } else { \
+        *ret = false; \
+      } \
+    } while (0)
+
+////////////////////////////////////////////////////////////////////////////////
+// Implementation specific tracing API definitions.
+
+// Get a pointer to the enabled state of the given trace category. Only
+// long-lived literal strings should be given as the category group. The
+// returned pointer can be held permanently in a local static for example. If
+// the unsigned char is non-zero, tracing is enabled. If tracing is enabled,
+// TRACE_EVENT_API_ADD_TRACE_EVENT can be called. It's OK if tracing is disabled
+// between the load of the tracing state and the call to
+// TRACE_EVENT_API_ADD_TRACE_EVENT, because this flag only provides an early out
+// for best performance when tracing is disabled.
+// const unsigned char*
+//     TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(const char* category_group)
+#define TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED \
+    base::trace_event::TraceLog::GetCategoryGroupEnabled
+
+// Get the number of times traces have been recorded. This is used to implement
+// the TRACE_EVENT_IS_NEW_TRACE facility.
+// unsigned int TRACE_EVENT_API_GET_NUM_TRACES_RECORDED()
+#define TRACE_EVENT_API_GET_NUM_TRACES_RECORDED \
+    base::trace_event::TraceLog::GetInstance()->GetNumTracesRecorded
+
+// Add a trace event to the platform tracing system.
+// base::trace_event::TraceEventHandle TRACE_EVENT_API_ADD_TRACE_EVENT(
+//                    char phase,
+//                    const unsigned char* category_group_enabled,
+//                    const char* name,
+//                    unsigned long long id,
+//                    int num_args,
+//                    const char** arg_names,
+//                    const unsigned char* arg_types,
+//                    const unsigned long long* arg_values,
+//                    unsigned char flags)
+#define TRACE_EVENT_API_ADD_TRACE_EVENT \
+    base::trace_event::TraceLog::GetInstance()->AddTraceEvent
+
+// Add a trace event to the platform tracing system.
+// base::trace_event::TraceEventHandle
+// TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_TIMESTAMP(
+//                    char phase,
+//                    const unsigned char* category_group_enabled,
+//                    const char* name,
+//                    unsigned long long id,
+//                    int thread_id,
+//                    const TraceTicks& timestamp,
+//                    int num_args,
+//                    const char** arg_names,
+//                    const unsigned char* arg_types,
+//                    const unsigned long long* arg_values,
+//                    unsigned char flags)
+#define TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP \
+    base::trace_event::TraceLog::GetInstance() \
+      ->AddTraceEventWithThreadIdAndTimestamp
+
+// Set the duration field of a COMPLETE trace event.
+// void TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(
+//     const unsigned char* category_group_enabled,
+//     const char* name,
+//     base::trace_event::TraceEventHandle id)
+#define TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION \
+    base::trace_event::TraceLog::GetInstance()->UpdateTraceEventDuration
+
+// Defines atomic operations used internally by the tracing system.
+#define TRACE_EVENT_API_ATOMIC_WORD base::subtle::AtomicWord
+#define TRACE_EVENT_API_ATOMIC_LOAD(var) base::subtle::NoBarrier_Load(&(var))
+#define TRACE_EVENT_API_ATOMIC_STORE(var, value) \
+    base::subtle::NoBarrier_Store(&(var), (value))
+
+// Defines visibility for classes in trace_event.h
+#define TRACE_EVENT_API_CLASS_EXPORT BASE_EXPORT
+
+// The thread buckets for the sampling profiler.
+TRACE_EVENT_API_CLASS_EXPORT extern \
+    TRACE_EVENT_API_ATOMIC_WORD g_trace_state[3];
+
+#define TRACE_EVENT_API_THREAD_BUCKET(thread_bucket)                           \
+    g_trace_state[thread_bucket]
+
+////////////////////////////////////////////////////////////////////////////////
+
+// Implementation detail: trace event macros create temporary variables
+// to keep instrumentation overhead low. These macros give each temporary
+// variable a unique name based on the line number to prevent name collisions.
+#define INTERNAL_TRACE_EVENT_UID3(a,b) \
+    trace_event_unique_##a##b
+#define INTERNAL_TRACE_EVENT_UID2(a,b) \
+    INTERNAL_TRACE_EVENT_UID3(a,b)
+#define INTERNAL_TRACE_EVENT_UID(name_prefix) \
+    INTERNAL_TRACE_EVENT_UID2(name_prefix, __LINE__)
+
+// Implementation detail: internal macro to create static category.
+// No barriers are needed, because this code is designed to operate safely
+// even when the unsigned char* points to garbage data (which may be the case
+// on processors without cache coherency).
+#define INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO_CUSTOM_VARIABLES( \
+    category_group, atomic, category_group_enabled) \
+    category_group_enabled = \
+        reinterpret_cast<const unsigned char*>(TRACE_EVENT_API_ATOMIC_LOAD( \
+            atomic)); \
+    if (UNLIKELY(!category_group_enabled)) { \
+      category_group_enabled = \
+          TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(category_group); \
+      TRACE_EVENT_API_ATOMIC_STORE(atomic, \
+          reinterpret_cast<TRACE_EVENT_API_ATOMIC_WORD>( \
+              category_group_enabled)); \
+    }
+
+#define INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group) \
+    static TRACE_EVENT_API_ATOMIC_WORD INTERNAL_TRACE_EVENT_UID(atomic) = 0; \
+    const unsigned char* INTERNAL_TRACE_EVENT_UID(category_group_enabled); \
+    INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO_CUSTOM_VARIABLES(category_group, \
+        INTERNAL_TRACE_EVENT_UID(atomic), \
+        INTERNAL_TRACE_EVENT_UID(category_group_enabled));
+
+// Implementation detail: internal macro to create static category and add
+// event if the category is enabled.
+#define INTERNAL_TRACE_EVENT_ADD(phase, category_group, name, flags, ...) \
+    do { \
+      INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \
+      if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \
+        trace_event_internal::AddTraceEvent( \
+            phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, \
+            trace_event_internal::kNoEventId, flags, ##__VA_ARGS__); \
+      } \
+    } while (0)
+
+// Implementation detail: internal macro to create static category and add begin
+// event if the category is enabled. Also adds the end event when the scope
+// ends.
+#define INTERNAL_TRACE_EVENT_ADD_SCOPED(category_group, name, ...) \
+    INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \
+    trace_event_internal::ScopedTracer INTERNAL_TRACE_EVENT_UID(tracer); \
+    if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \
+      base::trace_event::TraceEventHandle h = \
+          trace_event_internal::AddTraceEvent( \
+              TRACE_EVENT_PHASE_COMPLETE, \
+              INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, \
+              trace_event_internal::kNoEventId, TRACE_EVENT_FLAG_NONE, \
+              ##__VA_ARGS__); \
+      INTERNAL_TRACE_EVENT_UID(tracer).Initialize( \
+          INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, h); \
+    }
+
+// Implementation detail: internal macro to create static category and add
+// event if the category is enabled.
+#define INTERNAL_TRACE_EVENT_ADD_WITH_ID(phase, category_group, name, id, \
+                                         flags, ...) \
+    do { \
+      INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \
+      if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \
+        unsigned char trace_event_flags = flags | TRACE_EVENT_FLAG_HAS_ID; \
+        trace_event_internal::TraceID trace_event_trace_id( \
+            id, &trace_event_flags); \
+        trace_event_internal::AddTraceEvent( \
+            phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), \
+            name, trace_event_trace_id.data(), trace_event_flags, \
+            ##__VA_ARGS__); \
+      } \
+    } while (0)
+
+// Implementation detail: internal macro to create static category and add
+// event if the category is enabled.
+#define INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(phase, \
+        category_group, name, id, thread_id, timestamp, flags, ...) \
+    do { \
+      INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \
+      if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \
+        unsigned char trace_event_flags = flags | TRACE_EVENT_FLAG_HAS_ID; \
+        trace_event_internal::TraceID trace_event_trace_id( \
+            id, &trace_event_flags); \
+        trace_event_internal::AddTraceEventWithThreadIdAndTimestamp( \
+            phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), \
+            name, trace_event_trace_id.data(), \
+            thread_id, base::TraceTicks::FromInternalValue(timestamp), \
+            trace_event_flags | TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP, \
+            ##__VA_ARGS__); \
+      } \
+    } while (0)
+
+// Notes regarding the following definitions:
+// New values can be added and propagated to third party libraries, but existing
+// definitions must never be changed, because third party libraries may use old
+// definitions.
+
+// Phase indicates the nature of an event entry. E.g. part of a begin/end pair.
+#define TRACE_EVENT_PHASE_BEGIN    ('B')
+#define TRACE_EVENT_PHASE_END      ('E')
+#define TRACE_EVENT_PHASE_COMPLETE ('X')
+#define TRACE_EVENT_PHASE_INSTANT  ('I')
+#define TRACE_EVENT_PHASE_ASYNC_BEGIN ('S')
+#define TRACE_EVENT_PHASE_ASYNC_STEP_INTO  ('T')
+#define TRACE_EVENT_PHASE_ASYNC_STEP_PAST  ('p')
+#define TRACE_EVENT_PHASE_ASYNC_END   ('F')
+#define TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN ('b')
+#define TRACE_EVENT_PHASE_NESTABLE_ASYNC_END ('e')
+#define TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT ('n')
+#define TRACE_EVENT_PHASE_FLOW_BEGIN ('s')
+#define TRACE_EVENT_PHASE_FLOW_STEP  ('t')
+#define TRACE_EVENT_PHASE_FLOW_END   ('f')
+#define TRACE_EVENT_PHASE_METADATA ('M')
+#define TRACE_EVENT_PHASE_COUNTER  ('C')
+#define TRACE_EVENT_PHASE_SAMPLE  ('P')
+#define TRACE_EVENT_PHASE_CREATE_OBJECT ('N')
+#define TRACE_EVENT_PHASE_SNAPSHOT_OBJECT ('O')
+#define TRACE_EVENT_PHASE_DELETE_OBJECT ('D')
+#define TRACE_EVENT_PHASE_MEMORY_DUMP ('v')
+
+// Flags for changing the behavior of TRACE_EVENT_API_ADD_TRACE_EVENT.
+#define TRACE_EVENT_FLAG_NONE         (static_cast<unsigned char>(0))
+#define TRACE_EVENT_FLAG_COPY         (static_cast<unsigned char>(1 << 0))
+#define TRACE_EVENT_FLAG_HAS_ID       (static_cast<unsigned char>(1 << 1))
+#define TRACE_EVENT_FLAG_MANGLE_ID    (static_cast<unsigned char>(1 << 2))
+#define TRACE_EVENT_FLAG_SCOPE_OFFSET (static_cast<unsigned char>(1 << 3))
+#define TRACE_EVENT_FLAG_SCOPE_EXTRA  (static_cast<unsigned char>(1 << 4))
+#define TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP (static_cast<unsigned char>(1 << 5))
+#define TRACE_EVENT_FLAG_ASYNC_TTS    (static_cast<unsigned char>(1 << 6))
+#define TRACE_EVENT_FLAG_BIND_TO_ENCLOSING (static_cast<unsigned char>(1 << 7))
+
+#define TRACE_EVENT_FLAG_SCOPE_MASK   (static_cast<unsigned char>( \
+    TRACE_EVENT_FLAG_SCOPE_OFFSET | TRACE_EVENT_FLAG_SCOPE_EXTRA))
+
+// Type values for identifying types in the TraceValue union.
+#define TRACE_VALUE_TYPE_BOOL         (static_cast<unsigned char>(1))
+#define TRACE_VALUE_TYPE_UINT         (static_cast<unsigned char>(2))
+#define TRACE_VALUE_TYPE_INT          (static_cast<unsigned char>(3))
+#define TRACE_VALUE_TYPE_DOUBLE       (static_cast<unsigned char>(4))
+#define TRACE_VALUE_TYPE_POINTER      (static_cast<unsigned char>(5))
+#define TRACE_VALUE_TYPE_STRING       (static_cast<unsigned char>(6))
+#define TRACE_VALUE_TYPE_COPY_STRING  (static_cast<unsigned char>(7))
+#define TRACE_VALUE_TYPE_CONVERTABLE  (static_cast<unsigned char>(8))
+
+// Enum reflecting the scope of an INSTANT event. Must fit within
+// TRACE_EVENT_FLAG_SCOPE_MASK.
+#define TRACE_EVENT_SCOPE_GLOBAL  (static_cast<unsigned char>(0 << 3))
+#define TRACE_EVENT_SCOPE_PROCESS (static_cast<unsigned char>(1 << 3))
+#define TRACE_EVENT_SCOPE_THREAD  (static_cast<unsigned char>(2 << 3))
+
+#define TRACE_EVENT_SCOPE_NAME_GLOBAL  ('g')
+#define TRACE_EVENT_SCOPE_NAME_PROCESS ('p')
+#define TRACE_EVENT_SCOPE_NAME_THREAD  ('t')
+
+namespace trace_event_internal {
+
+// Specify these values when the corresponding argument of AddTraceEvent is not
+// used.
+const int kZeroNumArgs = 0;
+const unsigned long long kNoEventId = 0;
+
+// TraceID encapsulates an ID that can either be an integer or pointer. Pointers
+// are by default mangled with the Process ID so that they are unlikely to
+// collide when the same pointer is used on different processes.
+class TraceID {
+ public:
+  class DontMangle {
+   public:
+    explicit DontMangle(const void* id)
+        : data_(static_cast<unsigned long long>(
+              reinterpret_cast<uintptr_t>(id))) {}
+    explicit DontMangle(unsigned long long id) : data_(id) {}
+    explicit DontMangle(unsigned long id) : data_(id) {}
+    explicit DontMangle(unsigned int id) : data_(id) {}
+    explicit DontMangle(unsigned short id) : data_(id) {}
+    explicit DontMangle(unsigned char id) : data_(id) {}
+    explicit DontMangle(long long id)
+        : data_(static_cast<unsigned long long>(id)) {}
+    explicit DontMangle(long id)
+        : data_(static_cast<unsigned long long>(id)) {}
+    explicit DontMangle(int id)
+        : data_(static_cast<unsigned long long>(id)) {}
+    explicit DontMangle(short id)
+        : data_(static_cast<unsigned long long>(id)) {}
+    explicit DontMangle(signed char id)
+        : data_(static_cast<unsigned long long>(id)) {}
+    unsigned long long data() const { return data_; }
+   private:
+    unsigned long long data_;
+  };
+
+  class ForceMangle {
+   public:
+    explicit ForceMangle(unsigned long long id) : data_(id) {}
+    explicit ForceMangle(unsigned long id) : data_(id) {}
+    explicit ForceMangle(unsigned int id) : data_(id) {}
+    explicit ForceMangle(unsigned short id) : data_(id) {}
+    explicit ForceMangle(unsigned char id) : data_(id) {}
+    explicit ForceMangle(long long id)
+        : data_(static_cast<unsigned long long>(id)) {}
+    explicit ForceMangle(long id)
+        : data_(static_cast<unsigned long long>(id)) {}
+    explicit ForceMangle(int id)
+        : data_(static_cast<unsigned long long>(id)) {}
+    explicit ForceMangle(short id)
+        : data_(static_cast<unsigned long long>(id)) {}
+    explicit ForceMangle(signed char id)
+        : data_(static_cast<unsigned long long>(id)) {}
+    unsigned long long data() const { return data_; }
+   private:
+    unsigned long long data_;
+  };
+  TraceID(const void* id, unsigned char* flags)
+      : data_(static_cast<unsigned long long>(
+              reinterpret_cast<uintptr_t>(id))) {
+    *flags |= TRACE_EVENT_FLAG_MANGLE_ID;
+  }
+  TraceID(ForceMangle id, unsigned char* flags) : data_(id.data()) {
+    *flags |= TRACE_EVENT_FLAG_MANGLE_ID;
+  }
+  TraceID(DontMangle id, unsigned char* flags) : data_(id.data()) {
+  }
+  TraceID(unsigned long long id, unsigned char* flags)
+      : data_(id) { (void)flags; }
+  TraceID(unsigned long id, unsigned char* flags)
+      : data_(id) { (void)flags; }
+  TraceID(unsigned int id, unsigned char* flags)
+      : data_(id) { (void)flags; }
+  TraceID(unsigned short id, unsigned char* flags)
+      : data_(id) { (void)flags; }
+  TraceID(unsigned char id, unsigned char* flags)
+      : data_(id) { (void)flags; }
+  TraceID(long long id, unsigned char* flags)
+      : data_(static_cast<unsigned long long>(id)) { (void)flags; }
+  TraceID(long id, unsigned char* flags)
+      : data_(static_cast<unsigned long long>(id)) { (void)flags; }
+  TraceID(int id, unsigned char* flags)
+      : data_(static_cast<unsigned long long>(id)) { (void)flags; }
+  TraceID(short id, unsigned char* flags)
+      : data_(static_cast<unsigned long long>(id)) { (void)flags; }
+  TraceID(signed char id, unsigned char* flags)
+      : data_(static_cast<unsigned long long>(id)) { (void)flags; }
+
+  unsigned long long data() const { return data_; }
+
+ private:
+  unsigned long long data_;
+};
+
+// Simple union to store various types as unsigned long long.
+union TraceValueUnion {
+  bool as_bool;
+  unsigned long long as_uint;
+  long long as_int;
+  double as_double;
+  const void* as_pointer;
+  const char* as_string;
+};
+
+// Simple container for const char* that should be copied instead of retained.
+class TraceStringWithCopy {
+ public:
+  explicit TraceStringWithCopy(const char* str) : str_(str) {}
+  const char* str() const { return str_; }
+ private:
+  const char* str_;
+};
+
+// Define SetTraceValue for each allowed type. It stores the type and
+// value in the return arguments. This allows this API to avoid declaring any
+// structures so that it is portable to third_party libraries.
+#define INTERNAL_DECLARE_SET_TRACE_VALUE(actual_type, \
+                                         arg_expression, \
+                                         union_member, \
+                                         value_type_id) \
+    static inline void SetTraceValue( \
+        actual_type arg, \
+        unsigned char* type, \
+        unsigned long long* value) { \
+      TraceValueUnion type_value; \
+      type_value.union_member = arg_expression; \
+      *type = value_type_id; \
+      *value = type_value.as_uint; \
+    }
+// Simpler form for int types that can be safely casted.
+#define INTERNAL_DECLARE_SET_TRACE_VALUE_INT(actual_type, \
+                                             value_type_id) \
+    static inline void SetTraceValue( \
+        actual_type arg, \
+        unsigned char* type, \
+        unsigned long long* value) { \
+      *type = value_type_id; \
+      *value = static_cast<unsigned long long>(arg); \
+    }
+
+INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned long long, TRACE_VALUE_TYPE_UINT)
+INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned long, TRACE_VALUE_TYPE_UINT)
+INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned int, TRACE_VALUE_TYPE_UINT)
+INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned short, TRACE_VALUE_TYPE_UINT)
+INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned char, TRACE_VALUE_TYPE_UINT)
+INTERNAL_DECLARE_SET_TRACE_VALUE_INT(long long, TRACE_VALUE_TYPE_INT)
+INTERNAL_DECLARE_SET_TRACE_VALUE_INT(long, TRACE_VALUE_TYPE_INT)
+INTERNAL_DECLARE_SET_TRACE_VALUE_INT(int, TRACE_VALUE_TYPE_INT)
+INTERNAL_DECLARE_SET_TRACE_VALUE_INT(short, TRACE_VALUE_TYPE_INT)
+INTERNAL_DECLARE_SET_TRACE_VALUE_INT(signed char, TRACE_VALUE_TYPE_INT)
+INTERNAL_DECLARE_SET_TRACE_VALUE(bool, arg, as_bool, TRACE_VALUE_TYPE_BOOL)
+INTERNAL_DECLARE_SET_TRACE_VALUE(double, arg, as_double,
+                                 TRACE_VALUE_TYPE_DOUBLE)
+INTERNAL_DECLARE_SET_TRACE_VALUE(const void*, arg, as_pointer,
+                                 TRACE_VALUE_TYPE_POINTER)
+INTERNAL_DECLARE_SET_TRACE_VALUE(const char*, arg, as_string,
+                                 TRACE_VALUE_TYPE_STRING)
+INTERNAL_DECLARE_SET_TRACE_VALUE(const TraceStringWithCopy&, arg.str(),
+                                 as_string, TRACE_VALUE_TYPE_COPY_STRING)
+
+#undef INTERNAL_DECLARE_SET_TRACE_VALUE
+#undef INTERNAL_DECLARE_SET_TRACE_VALUE_INT
+
+// std::string version of SetTraceValue so that trace arguments can be strings.
+static inline void SetTraceValue(const std::string& arg,
+                                 unsigned char* type,
+                                 unsigned long long* value) {
+  TraceValueUnion type_value;
+  type_value.as_string = arg.c_str();
+  *type = TRACE_VALUE_TYPE_COPY_STRING;
+  *value = type_value.as_uint;
+}
+
+// base::Time, base::TimeTicks, etc. versions of SetTraceValue to make it easier
+// to trace these types.
+static inline void SetTraceValue(const base::Time arg,
+                                 unsigned char* type,
+                                 unsigned long long* value) {
+  *type = TRACE_VALUE_TYPE_INT;
+  *value = arg.ToInternalValue();
+}
+
+static inline void SetTraceValue(const base::TimeTicks arg,
+                                 unsigned char* type,
+                                 unsigned long long* value) {
+  *type = TRACE_VALUE_TYPE_INT;
+  *value = arg.ToInternalValue();
+}
+
+static inline void SetTraceValue(const base::ThreadTicks arg,
+                                 unsigned char* type,
+                                 unsigned long long* value) {
+  *type = TRACE_VALUE_TYPE_INT;
+  *value = arg.ToInternalValue();
+}
+
+static inline void SetTraceValue(const base::TraceTicks arg,
+                                 unsigned char* type,
+                                 unsigned long long* value) {
+  *type = TRACE_VALUE_TYPE_INT;
+  *value = arg.ToInternalValue();
+}
+
+// These AddTraceEvent and AddTraceEventWithThreadIdAndTimestamp template
+// functions are defined here instead of in the macro, because the arg_values
+// could be temporary objects, such as std::string. In order to store
+// pointers to the internal c_str and pass through to the tracing API,
+// the arg_values must live throughout these procedures.
+
+static inline base::trace_event::TraceEventHandle
+AddTraceEventWithThreadIdAndTimestamp(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    unsigned long long id,
+    int thread_id,
+    const base::TraceTicks& timestamp,
+    unsigned char flags,
+    const char* arg1_name,
+    const scoped_refptr<base::trace_event::ConvertableToTraceFormat>&
+        arg1_val) {
+  const int num_args = 1;
+  unsigned char arg_types[1] = { TRACE_VALUE_TYPE_CONVERTABLE };
+  return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
+      phase, category_group_enabled, name, id, thread_id, timestamp,
+      num_args, &arg1_name, arg_types, NULL, &arg1_val, flags);
+}
+
+template<class ARG1_TYPE>
+static inline base::trace_event::TraceEventHandle
+AddTraceEventWithThreadIdAndTimestamp(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    unsigned long long id,
+    int thread_id,
+    const base::TraceTicks& timestamp,
+    unsigned char flags,
+    const char* arg1_name,
+    const ARG1_TYPE& arg1_val,
+    const char* arg2_name,
+    const scoped_refptr<base::trace_event::ConvertableToTraceFormat>&
+        arg2_val) {
+  const int num_args = 2;
+  const char* arg_names[2] = { arg1_name, arg2_name };
+
+  unsigned char arg_types[2];
+  unsigned long long arg_values[2];
+  SetTraceValue(arg1_val, &arg_types[0], &arg_values[0]);
+  arg_types[1] = TRACE_VALUE_TYPE_CONVERTABLE;
+
+  scoped_refptr<base::trace_event::ConvertableToTraceFormat>
+      convertable_values[2];
+  convertable_values[1] = arg2_val;
+
+  return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
+      phase, category_group_enabled, name, id, thread_id, timestamp,
+      num_args, arg_names, arg_types, arg_values, convertable_values, flags);
+}
+
+template<class ARG2_TYPE>
+static inline base::trace_event::TraceEventHandle
+AddTraceEventWithThreadIdAndTimestamp(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    unsigned long long id,
+    int thread_id,
+    const base::TraceTicks& timestamp,
+    unsigned char flags,
+    const char* arg1_name,
+    const scoped_refptr<base::trace_event::ConvertableToTraceFormat>& arg1_val,
+    const char* arg2_name,
+    const ARG2_TYPE& arg2_val) {
+  const int num_args = 2;
+  const char* arg_names[2] = { arg1_name, arg2_name };
+
+  unsigned char arg_types[2];
+  unsigned long long arg_values[2];
+  arg_types[0] = TRACE_VALUE_TYPE_CONVERTABLE;
+  arg_values[0] = 0;
+  SetTraceValue(arg2_val, &arg_types[1], &arg_values[1]);
+
+  scoped_refptr<base::trace_event::ConvertableToTraceFormat>
+      convertable_values[2];
+  convertable_values[0] = arg1_val;
+
+  return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
+      phase, category_group_enabled, name, id, thread_id, timestamp,
+      num_args, arg_names, arg_types, arg_values, convertable_values, flags);
+}
+
+static inline base::trace_event::TraceEventHandle
+AddTraceEventWithThreadIdAndTimestamp(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    unsigned long long id,
+    int thread_id,
+    const base::TraceTicks& timestamp,
+    unsigned char flags,
+    const char* arg1_name,
+    const scoped_refptr<base::trace_event::ConvertableToTraceFormat>& arg1_val,
+    const char* arg2_name,
+    const scoped_refptr<base::trace_event::ConvertableToTraceFormat>&
+        arg2_val) {
+  const int num_args = 2;
+  const char* arg_names[2] = { arg1_name, arg2_name };
+  unsigned char arg_types[2] =
+      { TRACE_VALUE_TYPE_CONVERTABLE, TRACE_VALUE_TYPE_CONVERTABLE };
+  scoped_refptr<base::trace_event::ConvertableToTraceFormat>
+      convertable_values[2] = {arg1_val, arg2_val};
+
+  return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
+      phase, category_group_enabled, name, id, thread_id, timestamp,
+      num_args, arg_names, arg_types, NULL, convertable_values, flags);
+}
+
+static inline base::trace_event::TraceEventHandle
+AddTraceEventWithThreadIdAndTimestamp(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    unsigned long long id,
+    int thread_id,
+    const base::TraceTicks& timestamp,
+    unsigned char flags) {
+  return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
+      phase, category_group_enabled, name, id, thread_id, timestamp,
+      kZeroNumArgs, NULL, NULL, NULL, NULL, flags);
+}
+
+static inline base::trace_event::TraceEventHandle AddTraceEvent(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    unsigned long long id,
+    unsigned char flags) {
+  const int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
+  const base::TraceTicks now = base::TraceTicks::Now();
+  return AddTraceEventWithThreadIdAndTimestamp(phase, category_group_enabled,
+                                               name, id, thread_id, now, flags);
+}
+
+template<class ARG1_TYPE>
+static inline base::trace_event::TraceEventHandle
+AddTraceEventWithThreadIdAndTimestamp(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    unsigned long long id,
+    int thread_id,
+    const base::TraceTicks& timestamp,
+    unsigned char flags,
+    const char* arg1_name,
+    const ARG1_TYPE& arg1_val) {
+  const int num_args = 1;
+  unsigned char arg_types[1];
+  unsigned long long arg_values[1];
+  SetTraceValue(arg1_val, &arg_types[0], &arg_values[0]);
+  return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
+      phase, category_group_enabled, name, id, thread_id, timestamp,
+      num_args, &arg1_name, arg_types, arg_values, NULL, flags);
+}
+
+template<class ARG1_TYPE>
+static inline base::trace_event::TraceEventHandle AddTraceEvent(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    unsigned long long id,
+    unsigned char flags,
+    const char* arg1_name,
+    const ARG1_TYPE& arg1_val) {
+  int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
+  base::TraceTicks now = base::TraceTicks::Now();
+  return AddTraceEventWithThreadIdAndTimestamp(phase, category_group_enabled,
+                                               name, id, thread_id, now, flags,
+                                               arg1_name, arg1_val);
+}
+
+template<class ARG1_TYPE, class ARG2_TYPE>
+static inline base::trace_event::TraceEventHandle
+AddTraceEventWithThreadIdAndTimestamp(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    unsigned long long id,
+    int thread_id,
+    const base::TraceTicks& timestamp,
+    unsigned char flags,
+    const char* arg1_name,
+    const ARG1_TYPE& arg1_val,
+    const char* arg2_name,
+    const ARG2_TYPE& arg2_val) {
+  const int num_args = 2;
+  const char* arg_names[2] = { arg1_name, arg2_name };
+  unsigned char arg_types[2];
+  unsigned long long arg_values[2];
+  SetTraceValue(arg1_val, &arg_types[0], &arg_values[0]);
+  SetTraceValue(arg2_val, &arg_types[1], &arg_values[1]);
+  return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
+      phase, category_group_enabled, name, id, thread_id, timestamp,
+      num_args, arg_names, arg_types, arg_values, NULL, flags);
+}
+
+template<class ARG1_TYPE, class ARG2_TYPE>
+static inline base::trace_event::TraceEventHandle AddTraceEvent(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    unsigned long long id,
+    unsigned char flags,
+    const char* arg1_name,
+    const ARG1_TYPE& arg1_val,
+    const char* arg2_name,
+    const ARG2_TYPE& arg2_val) {
+  int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
+  base::TraceTicks now = base::TraceTicks::Now();
+  return AddTraceEventWithThreadIdAndTimestamp(phase, category_group_enabled,
+                                               name, id, thread_id, now, flags,
+                                               arg1_name, arg1_val,
+                                               arg2_name, arg2_val);
+}
+
+// Used by TRACE_EVENTx macros. Do not use directly.
+class TRACE_EVENT_API_CLASS_EXPORT ScopedTracer {
+ public:
+  // Note: members of data_ intentionally left uninitialized. See Initialize.
+  ScopedTracer() : p_data_(NULL) {}
+
+  ~ScopedTracer() {
+    if (p_data_ && *data_.category_group_enabled)
+      TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(
+          data_.category_group_enabled, data_.name, data_.event_handle);
+  }
+
+  void Initialize(const unsigned char* category_group_enabled,
+                  const char* name,
+                  base::trace_event::TraceEventHandle event_handle) {
+    data_.category_group_enabled = category_group_enabled;
+    data_.name = name;
+    data_.event_handle = event_handle;
+    p_data_ = &data_;
+  }
+
+ private:
+  // This Data struct workaround is to avoid initializing all the members
+  // in Data during construction of this object, since this object is always
+  // constructed, even when tracing is disabled. If the members of Data were
+  // members of this class instead, compiler warnings occur about potential
+  // uninitialized accesses.
+  struct Data {
+    const unsigned char* category_group_enabled;
+    const char* name;
+    base::trace_event::TraceEventHandle event_handle;
+  };
+  Data* p_data_;
+  Data data_;
+};
+
+// Used by TRACE_EVENT_BINARY_EFFICIENTx macro. Do not use directly.
+class TRACE_EVENT_API_CLASS_EXPORT ScopedTraceBinaryEfficient {
+ public:
+  ScopedTraceBinaryEfficient(const char* category_group, const char* name);
+  ~ScopedTraceBinaryEfficient();
+
+ private:
+  const unsigned char* category_group_enabled_;
+  const char* name_;
+  base::trace_event::TraceEventHandle event_handle_;
+};
+
+// This macro generates less code then TRACE_EVENT0 but is also
+// slower to execute when tracing is off. It should generally only be
+// used with code that is seldom executed or conditionally executed
+// when debugging.
+// For now the category_group must be "gpu".
+#define TRACE_EVENT_BINARY_EFFICIENT0(category_group, name) \
+    trace_event_internal::ScopedTraceBinaryEfficient \
+        INTERNAL_TRACE_EVENT_UID(scoped_trace)(category_group, name);
+
+// TraceEventSamplingStateScope records the current sampling state
+// and sets a new sampling state. When the scope exists, it restores
+// the sampling state having recorded.
+template<size_t BucketNumber>
+class TraceEventSamplingStateScope {
+ public:
+  TraceEventSamplingStateScope(const char* category_and_name) {
+    previous_state_ = TraceEventSamplingStateScope<BucketNumber>::Current();
+    TraceEventSamplingStateScope<BucketNumber>::Set(category_and_name);
+  }
+
+  ~TraceEventSamplingStateScope() {
+    TraceEventSamplingStateScope<BucketNumber>::Set(previous_state_);
+  }
+
+  static inline const char* Current() {
+    return reinterpret_cast<const char*>(TRACE_EVENT_API_ATOMIC_LOAD(
+      g_trace_state[BucketNumber]));
+  }
+
+  static inline void Set(const char* category_and_name) {
+    TRACE_EVENT_API_ATOMIC_STORE(
+      g_trace_state[BucketNumber],
+      reinterpret_cast<TRACE_EVENT_API_ATOMIC_WORD>(
+        const_cast<char*>(category_and_name)));
+  }
+
+ private:
+  const char* previous_state_;
+};
+
+}  // namespace trace_event_internal
+
+namespace base {
+namespace trace_event {
+
+template<typename IDType> class TraceScopedTrackableObject {
+ public:
+  TraceScopedTrackableObject(const char* category_group, const char* name,
+      IDType id)
+    : category_group_(category_group),
+      name_(name),
+      id_(id) {
+    TRACE_EVENT_OBJECT_CREATED_WITH_ID(category_group_, name_, id_);
+  }
+
+  template <typename ArgType> void snapshot(ArgType snapshot) {
+    TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(category_group_, name_, id_, snapshot);
+  }
+
+  ~TraceScopedTrackableObject() {
+    TRACE_EVENT_OBJECT_DELETED_WITH_ID(category_group_, name_, id_);
+  }
+
+ private:
+  const char* category_group_;
+  const char* name_;
+  IDType id_;
+
+  DISALLOW_COPY_AND_ASSIGN(TraceScopedTrackableObject);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_TRACE_EVENT_H_
diff --git a/base/trace_event/trace_event_android.cc b/base/trace_event/trace_event_android.cc
new file mode 100644
index 0000000..465649d
--- /dev/null
+++ b/base/trace_event/trace_event_android.cc
@@ -0,0 +1,199 @@
+// Copyright (c) 2012 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/trace_event_impl.h"
+
+#include <fcntl.h>
+
+#include "base/format_macros.h"
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/trace_event/trace_event.h"
+
+namespace {
+
+int g_atrace_fd = -1;
+const char kATraceMarkerFile[] = "/sys/kernel/debug/tracing/trace_marker";
+
+void WriteEvent(
+    char phase,
+    const char* category_group,
+    const char* name,
+    unsigned long long id,
+    const char** arg_names,
+    const unsigned char* arg_types,
+    const base::trace_event::TraceEvent::TraceValue* arg_values,
+    const scoped_refptr<base::trace_event::ConvertableToTraceFormat>*
+        convertable_values,
+    unsigned char flags) {
+  std::string out = base::StringPrintf("%c|%d|%s", phase, getpid(), name);
+  if (flags & TRACE_EVENT_FLAG_HAS_ID)
+    base::StringAppendF(&out, "-%" PRIx64, static_cast<uint64>(id));
+  out += '|';
+
+  for (int i = 0; i < base::trace_event::kTraceMaxNumArgs && arg_names[i];
+       ++i) {
+    if (i)
+      out += ';';
+    out += arg_names[i];
+    out += '=';
+    std::string::size_type value_start = out.length();
+    if (arg_types[i] == TRACE_VALUE_TYPE_CONVERTABLE) {
+      convertable_values[i]->AppendAsTraceFormat(&out);
+    } else {
+      base::trace_event::TraceEvent::AppendValueAsJSON(arg_types[i],
+                                                       arg_values[i], &out);
+    }
+    // Remove the quotes which may confuse the atrace script.
+    ReplaceSubstringsAfterOffset(&out, value_start, "\\\"", "'");
+    ReplaceSubstringsAfterOffset(&out, value_start, "\"", "");
+    // Replace chars used for separators with similar chars in the value.
+    std::replace(out.begin() + value_start, out.end(), ';', ',');
+    std::replace(out.begin() + value_start, out.end(), '|', '!');
+  }
+
+  out += '|';
+  out += category_group;
+  write(g_atrace_fd, out.c_str(), out.size());
+}
+
+void NoOpOutputCallback(base::WaitableEvent* complete_event,
+                        const scoped_refptr<base::RefCountedString>&,
+                        bool has_more_events) {
+  if (!has_more_events)
+    complete_event->Signal();
+}
+
+void EndChromeTracing(base::trace_event::TraceLog* trace_log,
+                      base::WaitableEvent* complete_event) {
+  trace_log->SetDisabled();
+  // Delete the buffered trace events as they have been sent to atrace.
+  trace_log->Flush(base::Bind(&NoOpOutputCallback, complete_event));
+}
+
+}  // namespace
+
+namespace base {
+namespace trace_event {
+
+// These functions support Android systrace.py when 'webview' category is
+// traced. With the new adb_profile_chrome, we may have two phases:
+// - before WebView is ready for combined tracing, we can use adb_profile_chrome
+//   to trace android categories other than 'webview' and chromium categories.
+//   In this way we can avoid the conflict between StartATrace/StopATrace and
+//   the intents.
+// - TODO(wangxianzhu): after WebView is ready for combined tracing, remove
+//   StartATrace, StopATrace and SendToATrace, and perhaps send Java traces
+//   directly to atrace in trace_event_binding.cc.
+
+void TraceLog::StartATrace() {
+  if (g_atrace_fd != -1)
+    return;
+
+  g_atrace_fd = open(kATraceMarkerFile, O_WRONLY);
+  if (g_atrace_fd == -1) {
+    PLOG(WARNING) << "Couldn't open " << kATraceMarkerFile;
+    return;
+  }
+  TraceConfig trace_config;
+  trace_config.SetTraceRecordMode(RECORD_CONTINUOUSLY);
+  SetEnabled(trace_config, TraceLog::RECORDING_MODE);
+}
+
+void TraceLog::StopATrace() {
+  if (g_atrace_fd == -1)
+    return;
+
+  close(g_atrace_fd);
+  g_atrace_fd = -1;
+
+  // TraceLog::Flush() requires the current thread to have a message loop, but
+  // this thread called from Java may not have one, so flush in another thread.
+  Thread end_chrome_tracing_thread("end_chrome_tracing");
+  WaitableEvent complete_event(false, false);
+  end_chrome_tracing_thread.Start();
+  end_chrome_tracing_thread.task_runner()->PostTask(
+      FROM_HERE, base::Bind(&EndChromeTracing, Unretained(this),
+                            Unretained(&complete_event)));
+  complete_event.Wait();
+}
+
+void TraceEvent::SendToATrace() {
+  if (g_atrace_fd == -1)
+    return;
+
+  const char* category_group =
+      TraceLog::GetCategoryGroupName(category_group_enabled_);
+
+  switch (phase_) {
+    case TRACE_EVENT_PHASE_BEGIN:
+      WriteEvent('B', category_group, name_, id_,
+                 arg_names_, arg_types_, arg_values_, convertable_values_,
+                 flags_);
+      break;
+
+    case TRACE_EVENT_PHASE_COMPLETE:
+      WriteEvent(duration_.ToInternalValue() == -1 ? 'B' : 'E',
+                 category_group, name_, id_,
+                 arg_names_, arg_types_, arg_values_, convertable_values_,
+                 flags_);
+      break;
+
+    case TRACE_EVENT_PHASE_END:
+      // Though a single 'E' is enough, here append pid, name and
+      // category_group etc. So that unpaired events can be found easily.
+      WriteEvent('E', category_group, name_, id_,
+                 arg_names_, arg_types_, arg_values_, convertable_values_,
+                 flags_);
+      break;
+
+    case TRACE_EVENT_PHASE_INSTANT:
+      // Simulate an instance event with a pair of begin/end events.
+      WriteEvent('B', category_group, name_, id_,
+                 arg_names_, arg_types_, arg_values_, convertable_values_,
+                 flags_);
+      write(g_atrace_fd, "E", 1);
+      break;
+
+    case TRACE_EVENT_PHASE_COUNTER:
+      for (int i = 0; i < kTraceMaxNumArgs && arg_names_[i]; ++i) {
+        DCHECK(arg_types_[i] == TRACE_VALUE_TYPE_INT);
+        std::string out = base::StringPrintf(
+            "C|%d|%s-%s", getpid(), name_, arg_names_[i]);
+        if (flags_ & TRACE_EVENT_FLAG_HAS_ID)
+          StringAppendF(&out, "-%" PRIx64, static_cast<uint64>(id_));
+        StringAppendF(&out, "|%d|%s",
+                      static_cast<int>(arg_values_[i].as_int), category_group);
+        write(g_atrace_fd, out.c_str(), out.size());
+      }
+      break;
+
+    default:
+      // Do nothing.
+      break;
+  }
+}
+
+void TraceLog::AddClockSyncMetadataEvent() {
+  int atrace_fd = open(kATraceMarkerFile, O_WRONLY | O_APPEND);
+  if (atrace_fd == -1) {
+    PLOG(WARNING) << "Couldn't open " << kATraceMarkerFile;
+    return;
+  }
+
+  // Android's kernel trace system has a trace_marker feature: this is a file on
+  // debugfs that takes the written data and pushes it onto the trace
+  // buffer. So, to establish clock sync, we write our monotonic clock into that
+  // trace buffer.
+  double now_in_seconds = (TraceTicks::Now() - TraceTicks()).InSecondsF();
+  std::string marker = StringPrintf(
+      "trace_event_clock_sync: parent_ts=%f\n", now_in_seconds);
+  if (write(atrace_fd, marker.c_str(), marker.size()) == -1)
+    PLOG(WARNING) << "Couldn't write to " << kATraceMarkerFile;
+  close(atrace_fd);
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/trace_event_argument.cc b/base/trace_event/trace_event_argument.cc
new file mode 100644
index 0000000..14a4499
--- /dev/null
+++ b/base/trace_event/trace_event_argument.cc
@@ -0,0 +1,462 @@
+// Copyright (c) 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.
+
+#include "base/trace_event/trace_event_argument.h"
+
+#include "base/json/json_writer.h"
+#include "base/trace_event/trace_event_memory_overhead.h"
+#include "base/values.h"
+
+namespace base {
+namespace trace_event {
+
+namespace {
+const char kTypeStartDict = '{';
+const char kTypeEndDict = '}';
+const char kTypeStartArray = '[';
+const char kTypeEndArray = ']';
+const char kTypeBool = 'b';
+const char kTypeInt = 'i';
+const char kTypeDouble = 'd';
+const char kTypeString = 's';
+const char kTypeCStr = '*';
+
+#ifndef NDEBUG
+const bool kStackTypeDict = false;
+const bool kStackTypeArray = true;
+#define DCHECK_CURRENT_CONTAINER_IS(x) DCHECK_EQ(x, nesting_stack_.back())
+#define DCHECK_CONTAINER_STACK_DEPTH_EQ(x) DCHECK_EQ(x, nesting_stack_.size())
+#define DEBUG_PUSH_CONTAINER(x) nesting_stack_.push_back(x)
+#define DEBUG_POP_CONTAINER() nesting_stack_.pop_back()
+#else
+#define DCHECK_CURRENT_CONTAINER_IS(x) do {} while (0)
+#define DCHECK_CONTAINER_STACK_DEPTH_EQ(x) do {} while (0)
+#define DEBUG_PUSH_CONTAINER(x) do {} while (0)
+#define DEBUG_POP_CONTAINER() do {} while (0)
+#endif
+
+inline void WriteKeyNameAsRawPtr(Pickle& pickle, const char* ptr) {
+  pickle.WriteBytes(&kTypeCStr, 1);
+  pickle.WriteUInt64(static_cast<uint64>(reinterpret_cast<uintptr_t>(ptr)));
+}
+
+inline void WriteKeyNameAsStdString(Pickle& pickle, const std::string& str) {
+  pickle.WriteBytes(&kTypeString, 1);
+  pickle.WriteString(str);
+}
+
+std::string ReadKeyName(PickleIterator& pickle_iterator) {
+  const char* type = nullptr;
+  bool res = pickle_iterator.ReadBytes(&type, 1);
+  std::string key_name;
+  if (res && *type == kTypeCStr) {
+    uint64 ptr_value = 0;
+    res = pickle_iterator.ReadUInt64(&ptr_value);
+    key_name = reinterpret_cast<const char*>(static_cast<uintptr_t>(ptr_value));
+  } else if (res && *type == kTypeString) {
+    res = pickle_iterator.ReadString(&key_name);
+  }
+  DCHECK(res);
+  return key_name;
+}
+}  // namespace
+
+TracedValue::TracedValue() : TracedValue(0) {
+}
+
+TracedValue::TracedValue(size_t capacity) {
+  DEBUG_PUSH_CONTAINER(kStackTypeDict);
+  if (capacity)
+    pickle_.Reserve(capacity);
+}
+
+TracedValue::~TracedValue() {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  DEBUG_POP_CONTAINER();
+  DCHECK_CONTAINER_STACK_DEPTH_EQ(0u);
+}
+
+void TracedValue::SetInteger(const char* name, int value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeInt, 1);
+  pickle_.WriteInt(value);
+  WriteKeyNameAsRawPtr(pickle_, name);
+}
+
+void TracedValue::SetIntegerWithCopiedName(const std::string& name, int value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeInt, 1);
+  pickle_.WriteInt(value);
+  WriteKeyNameAsStdString(pickle_, name);
+}
+
+void TracedValue::SetDouble(const char* name, double value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeDouble, 1);
+  pickle_.WriteDouble(value);
+  WriteKeyNameAsRawPtr(pickle_, name);
+}
+
+void TracedValue::SetDoubleWithCopiedName(const std::string& name,
+                                          double value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeDouble, 1);
+  pickle_.WriteDouble(value);
+  WriteKeyNameAsStdString(pickle_, name);
+}
+
+void TracedValue::SetBoolean(const char* name, bool value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeBool, 1);
+  pickle_.WriteBool(value);
+  WriteKeyNameAsRawPtr(pickle_, name);
+}
+
+void TracedValue::SetBooleanWithCopiedName(const std::string& name,
+                                           bool value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeBool, 1);
+  pickle_.WriteBool(value);
+  WriteKeyNameAsStdString(pickle_, name);
+}
+
+void TracedValue::SetString(const char* name, const std::string& value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeString, 1);
+  pickle_.WriteString(value);
+  WriteKeyNameAsRawPtr(pickle_, name);
+}
+
+void TracedValue::SetStringWithCopiedName(const std::string& name,
+                                          const std::string& value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeString, 1);
+  pickle_.WriteString(value);
+  WriteKeyNameAsStdString(pickle_, name);
+}
+
+void TracedValue::SetValue(const char* name, const TracedValue& value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  BeginDictionary(name);
+  pickle_.WriteBytes(value.pickle_.payload(),
+                     static_cast<int>(value.pickle_.payload_size()));
+  EndDictionary();
+}
+
+void TracedValue::SetValueWithCopiedName(const std::string& name,
+                                         const TracedValue& value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  BeginDictionaryWithCopiedName(name);
+  pickle_.WriteBytes(value.pickle_.payload(),
+                     static_cast<int>(value.pickle_.payload_size()));
+  EndDictionary();
+}
+
+void TracedValue::BeginDictionary(const char* name) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  DEBUG_PUSH_CONTAINER(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeStartDict, 1);
+  WriteKeyNameAsRawPtr(pickle_, name);
+}
+
+void TracedValue::BeginDictionaryWithCopiedName(const std::string& name) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  DEBUG_PUSH_CONTAINER(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeStartDict, 1);
+  WriteKeyNameAsStdString(pickle_, name);
+}
+
+void TracedValue::BeginArray(const char* name) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  DEBUG_PUSH_CONTAINER(kStackTypeArray);
+  pickle_.WriteBytes(&kTypeStartArray, 1);
+  WriteKeyNameAsRawPtr(pickle_, name);
+}
+
+void TracedValue::BeginArrayWithCopiedName(const std::string& name) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  DEBUG_PUSH_CONTAINER(kStackTypeArray);
+  pickle_.WriteBytes(&kTypeStartArray, 1);
+  WriteKeyNameAsStdString(pickle_, name);
+}
+
+void TracedValue::EndDictionary() {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  DEBUG_POP_CONTAINER();
+  pickle_.WriteBytes(&kTypeEndDict, 1);
+}
+
+void TracedValue::AppendInteger(int value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
+  pickle_.WriteBytes(&kTypeInt, 1);
+  pickle_.WriteInt(value);
+}
+
+void TracedValue::AppendDouble(double value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
+  pickle_.WriteBytes(&kTypeDouble, 1);
+  pickle_.WriteDouble(value);
+}
+
+void TracedValue::AppendBoolean(bool value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
+  pickle_.WriteBytes(&kTypeBool, 1);
+  pickle_.WriteBool(value);
+}
+
+void TracedValue::AppendString(const std::string& value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
+  pickle_.WriteBytes(&kTypeString, 1);
+  pickle_.WriteString(value);
+}
+
+void TracedValue::BeginArray() {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
+  DEBUG_PUSH_CONTAINER(kStackTypeArray);
+  pickle_.WriteBytes(&kTypeStartArray, 1);
+}
+
+void TracedValue::BeginDictionary() {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
+  DEBUG_PUSH_CONTAINER(kStackTypeDict);
+  pickle_.WriteBytes(&kTypeStartDict, 1);
+}
+
+void TracedValue::EndArray() {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
+  DEBUG_POP_CONTAINER();
+  pickle_.WriteBytes(&kTypeEndArray, 1);
+}
+
+void TracedValue::SetValue(const char* name, scoped_ptr<base::Value> value) {
+  SetBaseValueWithCopiedName(name, *value);
+}
+
+void TracedValue::SetBaseValueWithCopiedName(const std::string& name,
+                                             const base::Value& value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  switch (value.GetType()) {
+    case base::Value::TYPE_NULL:
+    case base::Value::TYPE_BINARY:
+      NOTREACHED();
+      break;
+
+    case base::Value::TYPE_BOOLEAN: {
+      bool bool_value;
+      value.GetAsBoolean(&bool_value);
+      SetBooleanWithCopiedName(name, bool_value);
+    } break;
+
+    case base::Value::TYPE_INTEGER: {
+      int int_value;
+      value.GetAsInteger(&int_value);
+      SetIntegerWithCopiedName(name, int_value);
+    } break;
+
+    case base::Value::TYPE_DOUBLE: {
+      double double_value;
+      value.GetAsDouble(&double_value);
+      SetDoubleWithCopiedName(name, double_value);
+    } break;
+
+    case base::Value::TYPE_STRING: {
+      const StringValue* string_value;
+      value.GetAsString(&string_value);
+      SetStringWithCopiedName(name, string_value->GetString());
+    } break;
+
+    case base::Value::TYPE_DICTIONARY: {
+      const DictionaryValue* dict_value;
+      value.GetAsDictionary(&dict_value);
+      BeginDictionaryWithCopiedName(name);
+      for (DictionaryValue::Iterator it(*dict_value); !it.IsAtEnd();
+           it.Advance()) {
+        SetBaseValueWithCopiedName(it.key(), it.value());
+      }
+      EndDictionary();
+    } break;
+
+    case base::Value::TYPE_LIST: {
+      const ListValue* list_value;
+      value.GetAsList(&list_value);
+      BeginArrayWithCopiedName(name);
+      for (base::Value* base_value : *list_value)
+        AppendBaseValue(*base_value);
+      EndArray();
+    } break;
+  }
+}
+
+void TracedValue::AppendBaseValue(const base::Value& value) {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
+  switch (value.GetType()) {
+    case base::Value::TYPE_NULL:
+    case base::Value::TYPE_BINARY:
+      NOTREACHED();
+      break;
+
+    case base::Value::TYPE_BOOLEAN: {
+      bool bool_value;
+      value.GetAsBoolean(&bool_value);
+      AppendBoolean(bool_value);
+    } break;
+
+    case base::Value::TYPE_INTEGER: {
+      int int_value;
+      value.GetAsInteger(&int_value);
+      AppendInteger(int_value);
+    } break;
+
+    case base::Value::TYPE_DOUBLE: {
+      double double_value;
+      value.GetAsDouble(&double_value);
+      AppendDouble(double_value);
+    } break;
+
+    case base::Value::TYPE_STRING: {
+      const StringValue* string_value;
+      value.GetAsString(&string_value);
+      AppendString(string_value->GetString());
+    } break;
+
+    case base::Value::TYPE_DICTIONARY: {
+      const DictionaryValue* dict_value;
+      value.GetAsDictionary(&dict_value);
+      BeginDictionary();
+      for (DictionaryValue::Iterator it(*dict_value); !it.IsAtEnd();
+           it.Advance()) {
+        SetBaseValueWithCopiedName(it.key(), it.value());
+      }
+      EndDictionary();
+    } break;
+
+    case base::Value::TYPE_LIST: {
+      const ListValue* list_value;
+      value.GetAsList(&list_value);
+      BeginArray();
+      for (base::Value* base_value : *list_value)
+        AppendBaseValue(*base_value);
+      EndArray();
+    } break;
+  }
+}
+
+scoped_ptr<base::Value> TracedValue::ToBaseValue() const {
+  scoped_ptr<DictionaryValue> root(new DictionaryValue);
+  DictionaryValue* cur_dict = root.get();
+  ListValue* cur_list = nullptr;
+  std::vector<Value*> stack;
+  PickleIterator it(pickle_);
+  const char* type;
+
+  while (it.ReadBytes(&type, 1)) {
+    DCHECK((cur_dict && !cur_list) || (cur_list && !cur_dict));
+    switch (*type) {
+      case kTypeStartDict: {
+        auto new_dict = new DictionaryValue();
+        if (cur_dict) {
+          cur_dict->Set(ReadKeyName(it), make_scoped_ptr(new_dict));
+          stack.push_back(cur_dict);
+          cur_dict = new_dict;
+        } else {
+          cur_list->Append(make_scoped_ptr(new_dict));
+          stack.push_back(cur_list);
+          cur_list = nullptr;
+          cur_dict = new_dict;
+        }
+      } break;
+
+      case kTypeEndArray:
+      case kTypeEndDict: {
+        if (stack.back()->GetAsDictionary(&cur_dict)) {
+          cur_list = nullptr;
+        } else if (stack.back()->GetAsList(&cur_list)) {
+          cur_dict = nullptr;
+        }
+        stack.pop_back();
+      } break;
+
+      case kTypeStartArray: {
+        auto new_list = new ListValue();
+        if (cur_dict) {
+          cur_dict->Set(ReadKeyName(it), make_scoped_ptr(new_list));
+          stack.push_back(cur_dict);
+          cur_dict = nullptr;
+          cur_list = new_list;
+        } else {
+          cur_list->Append(make_scoped_ptr(new_list));
+          stack.push_back(cur_list);
+          cur_list = new_list;
+        }
+      } break;
+
+      case kTypeBool: {
+        bool value;
+        CHECK(it.ReadBool(&value));
+        if (cur_dict) {
+          cur_dict->SetBoolean(ReadKeyName(it), value);
+        } else {
+          cur_list->AppendBoolean(value);
+        }
+      } break;
+
+      case kTypeInt: {
+        int value;
+        CHECK(it.ReadInt(&value));
+        if (cur_dict) {
+          cur_dict->SetInteger(ReadKeyName(it), value);
+        } else {
+          cur_list->AppendInteger(value);
+        }
+      } break;
+
+      case kTypeDouble: {
+        double value;
+        CHECK(it.ReadDouble(&value));
+        if (cur_dict) {
+          cur_dict->SetDouble(ReadKeyName(it), value);
+        } else {
+          cur_list->AppendDouble(value);
+        }
+      } break;
+
+      case kTypeString: {
+        std::string value;
+        CHECK(it.ReadString(&value));
+        if (cur_dict) {
+          cur_dict->SetString(ReadKeyName(it), value);
+        } else {
+          cur_list->AppendString(value);
+        }
+      } break;
+
+      default:
+        NOTREACHED();
+    }
+  }
+  DCHECK(stack.empty());
+  return root.Pass();
+}
+
+void TracedValue::AppendAsTraceFormat(std::string* out) const {
+  DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
+  DCHECK_CONTAINER_STACK_DEPTH_EQ(1u);
+
+  // TODO(primiano): this could be smarter, skip the ToBaseValue encoding and
+  // produce the JSON on its own. This will require refactoring JSONWriter
+  // to decouple the base::Value traversal from the JSON writing bits
+  std::string tmp;
+  JSONWriter::Write(*ToBaseValue(), &tmp);
+  *out += tmp;
+}
+
+void TracedValue::EstimateTraceMemoryOverhead(
+    TraceEventMemoryOverhead* overhead) {
+  overhead->Add("TracedValue",
+                pickle_.GetTotalAllocatedSize() /* allocated size */,
+                pickle_.size() /* resident size */);
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/trace_event_argument.h b/base/trace_event/trace_event_argument.h
new file mode 100644
index 0000000..aab58bc
--- /dev/null
+++ b/base/trace_event/trace_event_argument.h
@@ -0,0 +1,89 @@
+// 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.
+
+#ifndef BASE_TRACE_EVENT_TRACE_EVENT_ARGUMENT_H_
+#define BASE_TRACE_EVENT_TRACE_EVENT_ARGUMENT_H_
+
+#include <string>
+#include <vector>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/pickle.h"
+#include "base/trace_event/trace_event.h"
+
+namespace base {
+
+class Value;
+
+namespace trace_event {
+
+class BASE_EXPORT TracedValue : public ConvertableToTraceFormat {
+ public:
+  TracedValue();
+  explicit TracedValue(size_t capacity);
+
+  void EndDictionary();
+  void EndArray();
+
+  // These methods assume that |name| is a long lived "quoted" string.
+  void SetInteger(const char* name, int value);
+  void SetDouble(const char* name, double value);
+  void SetBoolean(const char* name, bool value);
+  void SetString(const char* name, const std::string& value);
+  void SetValue(const char* name, const TracedValue& value);
+  void BeginDictionary(const char* name);
+  void BeginArray(const char* name);
+
+  // These, instead, can be safely passed a temporary string.
+  void SetIntegerWithCopiedName(const std::string& name, int value);
+  void SetDoubleWithCopiedName(const std::string& name, double value);
+  void SetBooleanWithCopiedName(const std::string& name, bool value);
+  void SetStringWithCopiedName(const std::string& name,
+                               const std::string& value);
+  void SetValueWithCopiedName(const std::string& name,
+                              const TracedValue& value);
+  void BeginDictionaryWithCopiedName(const std::string& name);
+  void BeginArrayWithCopiedName(const std::string& name);
+
+  void AppendInteger(int);
+  void AppendDouble(double);
+  void AppendBoolean(bool);
+  void AppendString(const std::string&);
+  void BeginArray();
+  void BeginDictionary();
+
+  // ConvertableToTraceFormat implementation.
+  void AppendAsTraceFormat(std::string* out) const override;
+
+  void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead) override;
+
+  // DEPRECATED: do not use, here only for legacy reasons. These methods causes
+  // a copy-and-translation of the base::Value into the equivalent TracedValue.
+  // TODO(primiano): migrate the (three) existing clients to the cheaper
+  // SetValue(TracedValue) API. crbug.com/495628.
+  void SetValue(const char* name, scoped_ptr<base::Value> value);
+  void SetBaseValueWithCopiedName(const std::string& name,
+                                  const base::Value& value);
+  void AppendBaseValue(const base::Value& value);
+
+  // Public for tests only.
+  scoped_ptr<base::Value> ToBaseValue() const;
+
+ private:
+  ~TracedValue() override;
+
+  Pickle pickle_;
+
+#ifndef NDEBUG
+  // In debug builds checks the pairings of {Start,End}{Dictionary,Array}
+  std::vector<bool> nesting_stack_;
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(TracedValue);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_TRACE_EVENT_ARGUMENT_H_
diff --git a/base/trace_event/trace_event_argument_unittest.cc b/base/trace_event/trace_event_argument_unittest.cc
new file mode 100644
index 0000000..cb1cf2e
--- /dev/null
+++ b/base/trace_event/trace_event_argument_unittest.cc
@@ -0,0 +1,146 @@
+// Copyright (c) 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.
+
+#include "base/trace_event/trace_event_argument.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+TEST(TraceEventArgumentTest, FlatDictionary) {
+  scoped_refptr<TracedValue> value = new TracedValue();
+  value->SetInteger("int", 2014);
+  value->SetDouble("double", 0.0);
+  value->SetBoolean("bool", true);
+  value->SetString("string", "string");
+  std::string json = "PREFIX";
+  value->AppendAsTraceFormat(&json);
+  EXPECT_EQ(
+      "PREFIX{\"bool\":true,\"double\":0.0,\"int\":2014,\"string\":\"string\"}",
+      json);
+}
+
+TEST(TraceEventArgumentTest, Hierarchy) {
+  scoped_refptr<TracedValue> value = new TracedValue();
+  value->SetInteger("i0", 2014);
+  value->BeginDictionary("dict1");
+  value->SetInteger("i1", 2014);
+  value->BeginDictionary("dict2");
+  value->SetBoolean("b2", false);
+  value->EndDictionary();
+  value->SetString("s1", "foo");
+  value->EndDictionary();
+  value->SetDouble("d0", 0.0);
+  value->SetBoolean("b0", true);
+  value->BeginArray("a1");
+  value->AppendInteger(1);
+  value->AppendBoolean(true);
+  value->BeginDictionary();
+  value->SetInteger("i2", 3);
+  value->EndDictionary();
+  value->EndArray();
+  value->SetString("s0", "foo");
+  std::string json;
+  value->AppendAsTraceFormat(&json);
+  EXPECT_EQ(
+      "{\"a1\":[1,true,{\"i2\":3}],\"b0\":true,\"d0\":0.0,\"dict1\":{\"dict2\":"
+      "{\"b2\":false},\"i1\":2014,\"s1\":\"foo\"},\"i0\":2014,\"s0\":"
+      "\"foo\"}",
+      json);
+}
+
+TEST(TraceEventArgumentTest, LongStrings) {
+  std::string kLongString = "supercalifragilisticexpialidocious";
+  std::string kLongString2 = "0123456789012345678901234567890123456789";
+  char kLongString3[4096];
+  for (size_t i = 0; i < sizeof(kLongString3); ++i)
+    kLongString3[i] = 'a' + (i % 25);
+  kLongString3[sizeof(kLongString3) - 1] = '\0';
+
+  scoped_refptr<TracedValue> value = new TracedValue();
+  value->SetString("a", "short");
+  value->SetString("b", kLongString);
+  value->BeginArray("c");
+  value->AppendString(kLongString2);
+  value->AppendString("");
+  value->BeginDictionary();
+  value->SetString("a", kLongString3);
+  value->EndDictionary();
+  value->EndArray();
+
+  std::string json;
+  value->AppendAsTraceFormat(&json);
+  EXPECT_EQ("{\"a\":\"short\",\"b\":\"" + kLongString + "\",\"c\":[\"" +
+                kLongString2 + "\",\"\",{\"a\":\"" + kLongString3 + "\"}]}",
+            json);
+}
+
+TEST(TraceEventArgumentTest, PassBaseValue) {
+  FundamentalValue int_value(42);
+  FundamentalValue bool_value(true);
+  FundamentalValue double_value(42.0f);
+
+  auto dict_value = make_scoped_ptr(new DictionaryValue);
+  dict_value->SetBoolean("bool", true);
+  dict_value->SetInteger("int", 42);
+  dict_value->SetDouble("double", 42.0f);
+  dict_value->SetString("string", std::string("a") + "b");
+  dict_value->SetString("string", std::string("a") + "b");
+
+  auto list_value = make_scoped_ptr(new ListValue);
+  list_value->AppendBoolean(false);
+  list_value->AppendInteger(1);
+  list_value->AppendString("in_list");
+  list_value->Append(dict_value.Pass());
+
+  scoped_refptr<TracedValue> value = new TracedValue();
+  value->BeginDictionary("outer_dict");
+  value->SetValue("inner_list", list_value.Pass());
+  value->EndDictionary();
+
+  dict_value.reset();
+  list_value.reset();
+
+  std::string json;
+  value->AppendAsTraceFormat(&json);
+  EXPECT_EQ(
+      "{\"outer_dict\":{\"inner_list\":[false,1,\"in_list\",{\"bool\":true,"
+      "\"double\":42.0,\"int\":42,\"string\":\"ab\"}]}}",
+      json);
+}
+
+TEST(TraceEventArgumentTest, PassTracedValue) {
+  auto dict_value = make_scoped_refptr(new TracedValue);
+  dict_value->SetInteger("a", 1);
+
+  auto nested_dict_value = make_scoped_refptr(new TracedValue);
+  nested_dict_value->SetInteger("b", 2);
+  nested_dict_value->BeginArray("c");
+  nested_dict_value->AppendString("foo");
+  nested_dict_value->EndArray();
+
+  dict_value->SetValue("e", *nested_dict_value);
+
+  // Check the merged result.
+  std::string json;
+  dict_value->AppendAsTraceFormat(&json);
+  EXPECT_EQ("{\"a\":1,\"e\":{\"b\":2,\"c\":[\"foo\"]}}", json);
+
+  // Check that the passed nestd dict was left unouthced.
+  json = "";
+  nested_dict_value->AppendAsTraceFormat(&json);
+  EXPECT_EQ("{\"b\":2,\"c\":[\"foo\"]}", json);
+
+  // And that it is still usable.
+  nested_dict_value->SetInteger("f", 3);
+  nested_dict_value->BeginDictionary("g");
+  nested_dict_value->EndDictionary();
+  json = "";
+  nested_dict_value->AppendAsTraceFormat(&json);
+  EXPECT_EQ("{\"b\":2,\"c\":[\"foo\"],\"f\":3,\"g\":{}}", json);
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/trace_event_etw_export_win.cc b/base/trace_event/trace_event_etw_export_win.cc
new file mode 100644
index 0000000..d199bf5
--- /dev/null
+++ b/base/trace_event/trace_event_etw_export_win.cc
@@ -0,0 +1,252 @@
+// 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/trace_event_etw_export_win.h"
+
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/memory/singleton.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_impl.h"
+
+// The GetProcAddress technique is borrowed from
+// https://github.com/google/UIforETW/tree/master/ETWProviders
+//
+// EVNTAPI is used in evntprov.h which is included by chrome_events_win.h.
+// We define EVNTAPI without the DECLSPEC_IMPORT specifier so that we can
+// implement these functions locally instead of using the import library, and
+// can therefore still run on Windows XP.
+#define EVNTAPI __stdcall
+// Include the event register/write/unregister macros compiled from the manifest
+// file. Note that this includes evntprov.h which requires a Vista+ Windows SDK.
+//
+// In SHARED_INTERMEDIATE_DIR.
+#include "base/trace_event/etw_manifest/chrome_events_win.h"  // NOLINT
+
+namespace {
+// Typedefs for use with GetProcAddress
+typedef ULONG(__stdcall* tEventRegister)(LPCGUID ProviderId,
+                                         PENABLECALLBACK EnableCallback,
+                                         PVOID CallbackContext,
+                                         PREGHANDLE RegHandle);
+typedef ULONG(__stdcall* tEventWrite)(REGHANDLE RegHandle,
+                                      PCEVENT_DESCRIPTOR EventDescriptor,
+                                      ULONG UserDataCount,
+                                      PEVENT_DATA_DESCRIPTOR UserData);
+typedef ULONG(__stdcall* tEventUnregister)(REGHANDLE RegHandle);
+
+tEventRegister EventRegisterProc = nullptr;
+tEventWrite EventWriteProc = nullptr;
+tEventUnregister EventUnregisterProc = nullptr;
+}  // namespace
+
+// Redirector function for EventRegister. Called by macros in
+// chrome_events_win.h
+ULONG EVNTAPI EventRegister(LPCGUID ProviderId,
+                            PENABLECALLBACK EnableCallback,
+                            PVOID CallbackContext,
+                            PREGHANDLE RegHandle) {
+  if (EventRegisterProc)
+    return EventRegisterProc(ProviderId, EnableCallback, CallbackContext,
+                             RegHandle);
+  *RegHandle = 0;
+  return 0;
+}
+
+// Redirector function for EventWrite. Called by macros in
+// chrome_events_win.h
+ULONG EVNTAPI EventWrite(REGHANDLE RegHandle,
+                         PCEVENT_DESCRIPTOR EventDescriptor,
+                         ULONG UserDataCount,
+                         PEVENT_DATA_DESCRIPTOR UserData) {
+  if (EventWriteProc)
+    return EventWriteProc(RegHandle, EventDescriptor, UserDataCount, UserData);
+  return 0;
+}
+
+// Redirector function for EventUnregister. Called by macros in
+// chrome_events_win.h
+ULONG EVNTAPI EventUnregister(REGHANDLE RegHandle) {
+  if (EventUnregisterProc)
+    return EventUnregisterProc(RegHandle);
+  return 0;
+}
+
+namespace base {
+namespace trace_event {
+
+TraceEventETWExport::TraceEventETWExport() : ETWExportEnabled_(false) {
+  // Find Advapi32.dll. This should always succeed.
+  HMODULE AdvapiDLL = ::LoadLibraryW(L"Advapi32.dll");
+  if (AdvapiDLL) {
+    // Try to find the ETW functions. This will fail on XP.
+    EventRegisterProc = reinterpret_cast<tEventRegister>(
+        ::GetProcAddress(AdvapiDLL, "EventRegister"));
+    EventWriteProc = reinterpret_cast<tEventWrite>(
+        ::GetProcAddress(AdvapiDLL, "EventWrite"));
+    EventUnregisterProc = reinterpret_cast<tEventUnregister>(
+        ::GetProcAddress(AdvapiDLL, "EventUnregister"));
+
+    // Register the ETW provider. If registration fails then the event logging
+    // calls will fail (on XP this call will do nothing).
+    EventRegisterChrome();
+  }
+}
+
+TraceEventETWExport::~TraceEventETWExport() {
+  EventUnregisterChrome();
+}
+
+// static
+TraceEventETWExport* TraceEventETWExport::GetInstance() {
+  return Singleton<TraceEventETWExport,
+                   StaticMemorySingletonTraits<TraceEventETWExport>>::get();
+}
+
+// static
+void TraceEventETWExport::EnableETWExport() {
+  if (GetInstance())
+    GetInstance()->ETWExportEnabled_ = true;
+}
+
+// static
+void TraceEventETWExport::DisableETWExport() {
+  if (GetInstance())
+    GetInstance()->ETWExportEnabled_ = false;
+}
+
+// static
+void TraceEventETWExport::AddEvent(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    unsigned long long id,
+    int num_args,
+    const char** arg_names,
+    const unsigned char* arg_types,
+    const unsigned long long* arg_values,
+    const scoped_refptr<ConvertableToTraceFormat>* convertable_values) {
+  // We bail early in case exporting is disabled or no consumer is listening.
+  if (!GetInstance() || !GetInstance()->ETWExportEnabled_ ||
+      !EventEnabledChromeEvent())
+    return;
+
+  const char* phase_string = nullptr;
+  // Space to store the phase identifier and null-terminator, when needed.
+  char phase_buffer[2];
+  switch (phase) {
+    case TRACE_EVENT_PHASE_BEGIN:
+      phase_string = "Begin";
+      break;
+    case TRACE_EVENT_PHASE_END:
+      phase_string = "End";
+      break;
+    case TRACE_EVENT_PHASE_COMPLETE:
+      phase_string = "Complete";
+      break;
+    case TRACE_EVENT_PHASE_INSTANT:
+      phase_string = "Instant";
+      break;
+    case TRACE_EVENT_PHASE_ASYNC_BEGIN:
+      phase_string = "Async Begin";
+      break;
+    case TRACE_EVENT_PHASE_ASYNC_STEP_INTO:
+      phase_string = "Async Step Into";
+      break;
+    case TRACE_EVENT_PHASE_ASYNC_STEP_PAST:
+      phase_string = "Async Step Past";
+      break;
+    case TRACE_EVENT_PHASE_ASYNC_END:
+      phase_string = "Async End";
+      break;
+    case TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN:
+      phase_string = "Nestable Async Begin";
+      break;
+    case TRACE_EVENT_PHASE_NESTABLE_ASYNC_END:
+      phase_string = "Nestable Async End";
+      break;
+    case TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT:
+      phase_string = "Nestable Async Instant";
+      break;
+    case TRACE_EVENT_PHASE_FLOW_BEGIN:
+      phase_string = "Phase Flow Begin";
+      break;
+    case TRACE_EVENT_PHASE_FLOW_STEP:
+      phase_string = "Phase Flow Step";
+      break;
+    case TRACE_EVENT_PHASE_FLOW_END:
+      phase_string = "Phase Flow End";
+      break;
+    case TRACE_EVENT_PHASE_METADATA:
+      phase_string = "Phase Metadata";
+      break;
+    case TRACE_EVENT_PHASE_COUNTER:
+      phase_string = "Phase Counter";
+      break;
+    case TRACE_EVENT_PHASE_SAMPLE:
+      phase_string = "Phase Sample";
+      break;
+    case TRACE_EVENT_PHASE_CREATE_OBJECT:
+      phase_string = "Phase Create Object";
+      break;
+    case TRACE_EVENT_PHASE_SNAPSHOT_OBJECT:
+      phase_string = "Phase Snapshot Object";
+      break;
+    case TRACE_EVENT_PHASE_DELETE_OBJECT:
+      phase_string = "Phase Delete Object";
+      break;
+    default:
+      phase_buffer[0] = phase;
+      phase_buffer[1] = 0;
+      phase_string = phase_buffer;
+      break;
+  }
+
+  std::string arg_values_string[3];
+  for (int i = 0; i < num_args; i++) {
+    if (arg_types[i] == TRACE_VALUE_TYPE_CONVERTABLE) {
+      // Temporarily do nothing here. This function consumes 1/3 to 1/2 of
+      // *total* process CPU time when ETW tracing, and many of the strings
+      // created exceed WPA's 4094 byte limit and are shown as:
+      // "Unable to parse data". See crbug.com/488257
+      //convertable_values[i]->AppendAsTraceFormat(arg_values_string + i);
+    } else {
+      TraceEvent::TraceValue trace_event;
+      trace_event.as_uint = arg_values[i];
+      TraceEvent::AppendValueAsJSON(arg_types[i], trace_event,
+                                    arg_values_string + i);
+    }
+  }
+
+  EventWriteChromeEvent(
+      name, phase_string, num_args > 0 ? arg_names[0] : "",
+      arg_values_string[0].c_str(), num_args > 1 ? arg_names[1] : "",
+      arg_values_string[1].c_str(), num_args > 2 ? arg_names[2] : "",
+      arg_values_string[2].c_str());
+}
+
+// static
+void TraceEventETWExport::AddCustomEvent(const char* name,
+                                         char const* phase,
+                                         const char* arg_name_1,
+                                         const char* arg_value_1,
+                                         const char* arg_name_2,
+                                         const char* arg_value_2,
+                                         const char* arg_name_3,
+                                         const char* arg_value_3) {
+  if (!GetInstance() || !GetInstance()->ETWExportEnabled_ ||
+      !EventEnabledChromeEvent())
+    return;
+
+  EventWriteChromeEvent(name, phase, arg_name_1, arg_value_1, arg_name_2,
+                        arg_value_2, arg_name_3, arg_value_3);
+}
+
+void TraceEventETWExport::Resurrect() {
+  StaticMemorySingletonTraits<TraceEventETWExport>::Resurrect();
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/trace_event_etw_export_win.h b/base/trace_event/trace_event_etw_export_win.h
new file mode 100644
index 0000000..eefe820
--- /dev/null
+++ b/base/trace_event/trace_event_etw_export_win.h
@@ -0,0 +1,75 @@
+// 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.
+
+// This file contains the Windows-specific exporting to ETW.
+#ifndef BASE_TRACE_EVENT_TRACE_EVENT_ETW_EXPORT_WIN_H_
+#define BASE_TRACE_EVENT_TRACE_EVENT_ETW_EXPORT_WIN_H_
+
+#include "base/base_export.h"
+#include "base/trace_event/trace_event_impl.h"
+
+// Fwd.
+template <typename Type>
+struct StaticMemorySingletonTraits;
+
+namespace base {
+namespace trace_event {
+
+class BASE_EXPORT TraceEventETWExport {
+ public:
+  ~TraceEventETWExport();
+
+  // Retrieves the singleton.
+  // Note that this may return NULL post-AtExit processing.
+  static TraceEventETWExport* GetInstance();
+
+  // Enables/disables exporting of events to ETW. If disabled,
+  // AddEvent and AddCustomEvent will simply return when called.
+  static void EnableETWExport();
+  static void DisableETWExport();
+
+  static bool isETWExportEnabled() {
+    return (GetInstance() && GetInstance()->ETWExportEnabled_);
+  }
+
+  // Exports an event to ETW. This is mainly used in
+  // TraceLog::AddTraceEventWithThreadIdAndTimestamp to export internal events.
+  static void AddEvent(
+      char phase,
+      const unsigned char* category_group_enabled,
+      const char* name,
+      unsigned long long id,
+      int num_args,
+      const char** arg_names,
+      const unsigned char* arg_types,
+      const unsigned long long* arg_values,
+      const scoped_refptr<ConvertableToTraceFormat>* convertable_values);
+
+  // Exports an event to ETW. This should be used when exporting an event only
+  // to ETW. Supports three arguments to be passed to ETW.
+  // TODO(georgesak): Allow different providers.
+  static void AddCustomEvent(const char* name,
+                             char const* phase,
+                             const char* arg_name_1,
+                             const char* arg_value_1,
+                             const char* arg_name_2,
+                             const char* arg_value_2,
+                             const char* arg_name_3,
+                             const char* arg_value_3);
+
+  void Resurrect();
+
+ private:
+  bool ETWExportEnabled_;
+  // Ensure only the provider can construct us.
+  friend struct StaticMemorySingletonTraits<TraceEventETWExport>;
+  TraceEventETWExport();
+
+  DISALLOW_COPY_AND_ASSIGN(TraceEventETWExport);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_TRACE_EVENT_ETW_EXPORT_WIN_H_
diff --git a/base/trace_event/trace_event_impl.cc b/base/trace_event/trace_event_impl.cc
new file mode 100644
index 0000000..b5d4298
--- /dev/null
+++ b/base/trace_event/trace_event_impl.cc
@@ -0,0 +1,2495 @@
+// Copyright (c) 2012 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/trace_event_impl.h"
+
+#include <algorithm>
+#include <cmath>
+
+#include "base/base_switches.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/debug/leak_annotations.h"
+#include "base/format_macros.h"
+#include "base/json/string_escape.h"
+#include "base/lazy_instance.h"
+#include "base/location.h"
+#include "base/memory/singleton.h"
+#include "base/process/process_metrics.h"
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_tokenizer.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/synchronization/cancellation_flag.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/sys_info.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread_id_name_manager.h"
+#include "base/threading/worker_pool.h"
+#include "base/time/time.h"
+#include "base/trace_event/memory_dump_manager.h"
+#include "base/trace_event/memory_dump_provider.h"
+#include "base/trace_event/process_memory_dump.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_synthetic_delay.h"
+
+#if defined(OS_WIN)
+#include "base/trace_event/trace_event_etw_export_win.h"
+#include "base/trace_event/trace_event_win.h"
+#endif
+
+class DeleteTraceLogForTesting {
+ public:
+  static void Delete() {
+    Singleton<base::trace_event::TraceLog,
+              LeakySingletonTraits<base::trace_event::TraceLog>>::OnExit(0);
+  }
+};
+
+// The thread buckets for the sampling profiler.
+BASE_EXPORT TRACE_EVENT_API_ATOMIC_WORD g_trace_state[3];
+
+namespace base {
+namespace trace_event {
+
+namespace {
+
+// The overhead of TraceEvent above this threshold will be reported in the
+// trace.
+const int kOverheadReportThresholdInMicroseconds = 50;
+
+// Controls the number of trace events we will buffer in-memory
+// before throwing them away.
+const size_t kTraceBufferChunkSize = TraceBufferChunk::kTraceBufferChunkSize;
+const size_t kTraceEventVectorBigBufferChunks =
+    512000000 / kTraceBufferChunkSize;
+const size_t kTraceEventVectorBufferChunks = 256000 / kTraceBufferChunkSize;
+const size_t kTraceEventRingBufferChunks = kTraceEventVectorBufferChunks / 4;
+const size_t kTraceEventBufferSizeInBytes = 100 * 1024;
+// Can store results for 30 seconds with 1 ms sampling interval.
+const size_t kMonitorTraceEventBufferChunks = 30000 / kTraceBufferChunkSize;
+// ECHO_TO_CONSOLE needs a small buffer to hold the unfinished COMPLETE events.
+const size_t kEchoToConsoleTraceEventBufferChunks = 256;
+
+const int kThreadFlushTimeoutMs = 3000;
+
+#if !defined(OS_NACL)
+// These categories will cause deadlock when ECHO_TO_CONSOLE. crbug.com/325575.
+const char kEchoToConsoleCategoryFilter[] = "-ipc,-task";
+#endif
+
+#define MAX_CATEGORY_GROUPS 100
+
+// Parallel arrays g_category_groups and g_category_group_enabled are separate
+// so that a pointer to a member of g_category_group_enabled can be easily
+// converted to an index into g_category_groups. This allows macros to deal
+// only with char enabled pointers from g_category_group_enabled, and we can
+// convert internally to determine the category name from the char enabled
+// pointer.
+const char* g_category_groups[MAX_CATEGORY_GROUPS] = {
+  "toplevel",
+  "tracing already shutdown",
+  "tracing categories exhausted; must increase MAX_CATEGORY_GROUPS",
+  "__metadata",
+  // For reporting trace_event overhead. For thread local event buffers only.
+  "trace_event_overhead"};
+
+// The enabled flag is char instead of bool so that the API can be used from C.
+unsigned char g_category_group_enabled[MAX_CATEGORY_GROUPS] = { 0 };
+// Indexes here have to match the g_category_groups array indexes above.
+const int g_category_already_shutdown = 1;
+const int g_category_categories_exhausted = 2;
+const int g_category_metadata = 3;
+const int g_category_trace_event_overhead = 4;
+const int g_num_builtin_categories = 5;
+// Skip default categories.
+base::subtle::AtomicWord g_category_index = g_num_builtin_categories;
+
+// The name of the current thread. This is used to decide if the current
+// thread name has changed. We combine all the seen thread names into the
+// output name for the thread.
+LazyInstance<ThreadLocalPointer<const char> >::Leaky
+    g_current_thread_name = LAZY_INSTANCE_INITIALIZER;
+
+ThreadTicks ThreadNow() {
+  return ThreadTicks::IsSupported() ? ThreadTicks::Now() : ThreadTicks();
+}
+
+class TraceBufferRingBuffer : public TraceBuffer {
+ public:
+  TraceBufferRingBuffer(size_t max_chunks)
+      : max_chunks_(max_chunks),
+        recyclable_chunks_queue_(new size_t[queue_capacity()]),
+        queue_head_(0),
+        queue_tail_(max_chunks),
+        current_iteration_index_(0),
+        current_chunk_seq_(1) {
+    chunks_.reserve(max_chunks);
+    for (size_t i = 0; i < max_chunks; ++i)
+      recyclable_chunks_queue_[i] = i;
+  }
+
+  scoped_ptr<TraceBufferChunk> GetChunk(size_t* index) override {
+    // Because the number of threads is much less than the number of chunks,
+    // the queue should never be empty.
+    DCHECK(!QueueIsEmpty());
+
+    *index = recyclable_chunks_queue_[queue_head_];
+    queue_head_ = NextQueueIndex(queue_head_);
+    current_iteration_index_ = queue_head_;
+
+    if (*index >= chunks_.size())
+      chunks_.resize(*index + 1);
+
+    TraceBufferChunk* chunk = chunks_[*index];
+    chunks_[*index] = NULL;  // Put NULL in the slot of a in-flight chunk.
+    if (chunk)
+      chunk->Reset(current_chunk_seq_++);
+    else
+      chunk = new TraceBufferChunk(current_chunk_seq_++);
+
+    return scoped_ptr<TraceBufferChunk>(chunk);
+  }
+
+  void ReturnChunk(size_t index, scoped_ptr<TraceBufferChunk> chunk) override {
+    // When this method is called, the queue should not be full because it
+    // can contain all chunks including the one to be returned.
+    DCHECK(!QueueIsFull());
+    DCHECK(chunk);
+    DCHECK_LT(index, chunks_.size());
+    DCHECK(!chunks_[index]);
+    chunks_[index] = chunk.release();
+    recyclable_chunks_queue_[queue_tail_] = index;
+    queue_tail_ = NextQueueIndex(queue_tail_);
+  }
+
+  bool IsFull() const override { return false; }
+
+  size_t Size() const override {
+    // This is approximate because not all of the chunks are full.
+    return chunks_.size() * kTraceBufferChunkSize;
+  }
+
+  size_t Capacity() const override {
+    return max_chunks_ * kTraceBufferChunkSize;
+  }
+
+  TraceEvent* GetEventByHandle(TraceEventHandle handle) override {
+    if (handle.chunk_index >= chunks_.size())
+      return NULL;
+    TraceBufferChunk* chunk = chunks_[handle.chunk_index];
+    if (!chunk || chunk->seq() != handle.chunk_seq)
+      return NULL;
+    return chunk->GetEventAt(handle.event_index);
+  }
+
+  const TraceBufferChunk* NextChunk() override {
+    if (chunks_.empty())
+      return NULL;
+
+    while (current_iteration_index_ != queue_tail_) {
+      size_t chunk_index = recyclable_chunks_queue_[current_iteration_index_];
+      current_iteration_index_ = NextQueueIndex(current_iteration_index_);
+      if (chunk_index >= chunks_.size()) // Skip uninitialized chunks.
+        continue;
+      DCHECK(chunks_[chunk_index]);
+      return chunks_[chunk_index];
+    }
+    return NULL;
+  }
+
+  scoped_ptr<TraceBuffer> CloneForIteration() const override {
+    scoped_ptr<ClonedTraceBuffer> cloned_buffer(new ClonedTraceBuffer());
+    for (size_t queue_index = queue_head_; queue_index != queue_tail_;
+        queue_index = NextQueueIndex(queue_index)) {
+      size_t chunk_index = recyclable_chunks_queue_[queue_index];
+      if (chunk_index >= chunks_.size()) // Skip uninitialized chunks.
+        continue;
+      TraceBufferChunk* chunk = chunks_[chunk_index];
+      cloned_buffer->chunks_.push_back(chunk ? chunk->Clone().release() : NULL);
+    }
+    return cloned_buffer.Pass();
+  }
+
+  void EstimateTraceMemoryOverhead(
+      TraceEventMemoryOverhead* overhead) override {
+    overhead->Add("TraceBufferRingBuffer", sizeof(*this));
+    for (size_t queue_index = queue_head_; queue_index != queue_tail_;
+         queue_index = NextQueueIndex(queue_index)) {
+      size_t chunk_index = recyclable_chunks_queue_[queue_index];
+      if (chunk_index >= chunks_.size())  // Skip uninitialized chunks.
+        continue;
+      chunks_[chunk_index]->EstimateTraceMemoryOverhead(overhead);
+    }
+  }
+
+ private:
+  class ClonedTraceBuffer : public TraceBuffer {
+   public:
+    ClonedTraceBuffer() : current_iteration_index_(0) {}
+
+    // The only implemented method.
+    const TraceBufferChunk* NextChunk() override {
+      return current_iteration_index_ < chunks_.size() ?
+          chunks_[current_iteration_index_++] : NULL;
+    }
+
+    scoped_ptr<TraceBufferChunk> GetChunk(size_t* index) override {
+      NOTIMPLEMENTED();
+      return scoped_ptr<TraceBufferChunk>();
+    }
+    void ReturnChunk(size_t index, scoped_ptr<TraceBufferChunk>) override {
+      NOTIMPLEMENTED();
+    }
+    bool IsFull() const override { return false; }
+    size_t Size() const override { return 0; }
+    size_t Capacity() const override { return 0; }
+    TraceEvent* GetEventByHandle(TraceEventHandle handle) override {
+      return NULL;
+    }
+    scoped_ptr<TraceBuffer> CloneForIteration() const override {
+      NOTIMPLEMENTED();
+      return scoped_ptr<TraceBuffer>();
+    }
+    void EstimateTraceMemoryOverhead(
+        TraceEventMemoryOverhead* overhead) override {
+      NOTIMPLEMENTED();
+    }
+
+    size_t current_iteration_index_;
+    ScopedVector<TraceBufferChunk> chunks_;
+  };
+
+  bool QueueIsEmpty() const {
+    return queue_head_ == queue_tail_;
+  }
+
+  size_t QueueSize() const {
+    return queue_tail_ > queue_head_ ? queue_tail_ - queue_head_ :
+        queue_tail_ + queue_capacity() - queue_head_;
+  }
+
+  bool QueueIsFull() const {
+    return QueueSize() == queue_capacity() - 1;
+  }
+
+  size_t queue_capacity() const {
+    // One extra space to help distinguish full state and empty state.
+    return max_chunks_ + 1;
+  }
+
+  size_t NextQueueIndex(size_t index) const {
+    index++;
+    if (index >= queue_capacity())
+      index = 0;
+    return index;
+  }
+
+  size_t max_chunks_;
+  ScopedVector<TraceBufferChunk> chunks_;
+
+  scoped_ptr<size_t[]> recyclable_chunks_queue_;
+  size_t queue_head_;
+  size_t queue_tail_;
+
+  size_t current_iteration_index_;
+  uint32 current_chunk_seq_;
+
+  DISALLOW_COPY_AND_ASSIGN(TraceBufferRingBuffer);
+};
+
+class TraceBufferVector : public TraceBuffer {
+ public:
+  TraceBufferVector(size_t max_chunks)
+      : in_flight_chunk_count_(0),
+        current_iteration_index_(0),
+        max_chunks_(max_chunks) {
+    chunks_.reserve(max_chunks_);
+  }
+
+  scoped_ptr<TraceBufferChunk> GetChunk(size_t* index) override {
+    // This function may be called when adding normal events or indirectly from
+    // AddMetadataEventsWhileLocked(). We can not DECHECK(!IsFull()) because we
+    // have to add the metadata events and flush thread-local buffers even if
+    // the buffer is full.
+    *index = chunks_.size();
+    chunks_.push_back(NULL);  // Put NULL in the slot of a in-flight chunk.
+    ++in_flight_chunk_count_;
+    // + 1 because zero chunk_seq is not allowed.
+    return scoped_ptr<TraceBufferChunk>(
+        new TraceBufferChunk(static_cast<uint32>(*index) + 1));
+  }
+
+  void ReturnChunk(size_t index, scoped_ptr<TraceBufferChunk> chunk) override {
+    DCHECK_GT(in_flight_chunk_count_, 0u);
+    DCHECK_LT(index, chunks_.size());
+    DCHECK(!chunks_[index]);
+    --in_flight_chunk_count_;
+    chunks_[index] = chunk.release();
+  }
+
+  bool IsFull() const override { return chunks_.size() >= max_chunks_; }
+
+  size_t Size() const override {
+    // This is approximate because not all of the chunks are full.
+    return chunks_.size() * kTraceBufferChunkSize;
+  }
+
+  size_t Capacity() const override {
+    return max_chunks_ * kTraceBufferChunkSize;
+  }
+
+  TraceEvent* GetEventByHandle(TraceEventHandle handle) override {
+    if (handle.chunk_index >= chunks_.size())
+      return NULL;
+    TraceBufferChunk* chunk = chunks_[handle.chunk_index];
+    if (!chunk || chunk->seq() != handle.chunk_seq)
+      return NULL;
+    return chunk->GetEventAt(handle.event_index);
+  }
+
+  const TraceBufferChunk* NextChunk() override {
+    while (current_iteration_index_ < chunks_.size()) {
+      // Skip in-flight chunks.
+      const TraceBufferChunk* chunk = chunks_[current_iteration_index_++];
+      if (chunk)
+        return chunk;
+    }
+    return NULL;
+  }
+
+  scoped_ptr<TraceBuffer> CloneForIteration() const override {
+    NOTIMPLEMENTED();
+    return scoped_ptr<TraceBuffer>();
+  }
+
+  void EstimateTraceMemoryOverhead(
+      TraceEventMemoryOverhead* overhead) override {
+    // Skip the in-flight chunks owned by the threads. They will be accounted
+    // by the per-thread-local dumper, see ThreadLocalEventBuffer::OnMemoryDump.
+    overhead->Add("TraceBufferVector", sizeof(*this));
+    for (size_t i = 0; i < chunks_.size(); ++i) {
+      TraceBufferChunk* chunk = chunks_[i];
+      if (chunk)
+        chunk->EstimateTraceMemoryOverhead(overhead);
+    }
+  }
+
+ private:
+  size_t in_flight_chunk_count_;
+  size_t current_iteration_index_;
+  size_t max_chunks_;
+  ScopedVector<TraceBufferChunk> chunks_;
+
+  DISALLOW_COPY_AND_ASSIGN(TraceBufferVector);
+};
+
+template <typename T>
+void InitializeMetadataEvent(TraceEvent* trace_event,
+                             int thread_id,
+                             const char* metadata_name, const char* arg_name,
+                             const T& value) {
+  if (!trace_event)
+    return;
+
+  int num_args = 1;
+  unsigned char arg_type;
+  unsigned long long arg_value;
+  ::trace_event_internal::SetTraceValue(value, &arg_type, &arg_value);
+  trace_event->Initialize(thread_id,
+                          TraceTicks(), ThreadTicks(),
+                          TRACE_EVENT_PHASE_METADATA,
+                          &g_category_group_enabled[g_category_metadata],
+                          metadata_name, ::trace_event_internal::kNoEventId,
+                          num_args, &arg_name, &arg_type, &arg_value, NULL,
+                          TRACE_EVENT_FLAG_NONE);
+}
+
+class AutoThreadLocalBoolean {
+ public:
+  explicit AutoThreadLocalBoolean(ThreadLocalBoolean* thread_local_boolean)
+      : thread_local_boolean_(thread_local_boolean) {
+    DCHECK(!thread_local_boolean_->Get());
+    thread_local_boolean_->Set(true);
+  }
+  ~AutoThreadLocalBoolean() {
+    thread_local_boolean_->Set(false);
+  }
+
+ private:
+  ThreadLocalBoolean* thread_local_boolean_;
+  DISALLOW_COPY_AND_ASSIGN(AutoThreadLocalBoolean);
+};
+
+}  // namespace
+
+TraceBufferChunk::TraceBufferChunk(uint32 seq) : next_free_(0), seq_(seq) {
+}
+
+TraceBufferChunk::~TraceBufferChunk() {
+}
+
+void TraceBufferChunk::Reset(uint32 new_seq) {
+  for (size_t i = 0; i < next_free_; ++i)
+    chunk_[i].Reset();
+  next_free_ = 0;
+  seq_ = new_seq;
+  cached_overhead_estimate_when_full_.reset();
+}
+
+TraceEvent* TraceBufferChunk::AddTraceEvent(size_t* event_index) {
+  DCHECK(!IsFull());
+  *event_index = next_free_++;
+  return &chunk_[*event_index];
+}
+
+scoped_ptr<TraceBufferChunk> TraceBufferChunk::Clone() const {
+  scoped_ptr<TraceBufferChunk> cloned_chunk(new TraceBufferChunk(seq_));
+  cloned_chunk->next_free_ = next_free_;
+  for (size_t i = 0; i < next_free_; ++i)
+    cloned_chunk->chunk_[i].CopyFrom(chunk_[i]);
+  return cloned_chunk.Pass();
+}
+
+void TraceBufferChunk::EstimateTraceMemoryOverhead(
+    TraceEventMemoryOverhead* overhead) {
+  if (cached_overhead_estimate_when_full_) {
+    DCHECK(IsFull());
+    overhead->Update(*cached_overhead_estimate_when_full_);
+    return;
+  }
+
+  // Cache the memory overhead estimate only if the chunk is full.
+  TraceEventMemoryOverhead* estimate = overhead;
+  if (IsFull()) {
+    cached_overhead_estimate_when_full_.reset(new TraceEventMemoryOverhead);
+    estimate = cached_overhead_estimate_when_full_.get();
+  }
+
+  estimate->Add("TraceBufferChunk", sizeof(*this));
+  for (size_t i = 0; i < next_free_; ++i)
+    chunk_[i].EstimateTraceMemoryOverhead(estimate);
+
+  if (IsFull()) {
+    estimate->AddSelf();
+    overhead->Update(*estimate);
+  }
+}
+
+// A helper class that allows the lock to be acquired in the middle of the scope
+// and unlocks at the end of scope if locked.
+class TraceLog::OptionalAutoLock {
+ public:
+  explicit OptionalAutoLock(Lock* lock) : lock_(lock), locked_(false) {}
+
+  ~OptionalAutoLock() {
+    if (locked_)
+      lock_->Release();
+  }
+
+  void EnsureAcquired() {
+    if (!locked_) {
+      lock_->Acquire();
+      locked_ = true;
+    }
+  }
+
+ private:
+  Lock* lock_;
+  bool locked_;
+  DISALLOW_COPY_AND_ASSIGN(OptionalAutoLock);
+};
+
+// Use this function instead of TraceEventHandle constructor to keep the
+// overhead of ScopedTracer (trace_event.h) constructor minimum.
+void MakeHandle(uint32 chunk_seq, size_t chunk_index, size_t event_index,
+                TraceEventHandle* handle) {
+  DCHECK(chunk_seq);
+  DCHECK(chunk_index < (1u << 16));
+  DCHECK(event_index < (1u << 16));
+  handle->chunk_seq = chunk_seq;
+  handle->chunk_index = static_cast<uint16>(chunk_index);
+  handle->event_index = static_cast<uint16>(event_index);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// TraceEvent
+//
+////////////////////////////////////////////////////////////////////////////////
+
+namespace {
+
+size_t GetAllocLength(const char* str) { return str ? strlen(str) + 1 : 0; }
+
+// Copies |*member| into |*buffer|, sets |*member| to point to this new
+// location, and then advances |*buffer| by the amount written.
+void CopyTraceEventParameter(char** buffer,
+                             const char** member,
+                             const char* end) {
+  if (*member) {
+    size_t written = strlcpy(*buffer, *member, end - *buffer) + 1;
+    DCHECK_LE(static_cast<int>(written), end - *buffer);
+    *member = *buffer;
+    *buffer += written;
+  }
+}
+
+}  // namespace
+
+TraceEvent::TraceEvent()
+    : duration_(TimeDelta::FromInternalValue(-1)),
+      id_(0u),
+      category_group_enabled_(NULL),
+      name_(NULL),
+      thread_id_(0),
+      phase_(TRACE_EVENT_PHASE_BEGIN),
+      flags_(0) {
+  for (int i = 0; i < kTraceMaxNumArgs; ++i)
+    arg_names_[i] = NULL;
+  memset(arg_values_, 0, sizeof(arg_values_));
+}
+
+TraceEvent::~TraceEvent() {
+}
+
+void TraceEvent::CopyFrom(const TraceEvent& other) {
+  timestamp_ = other.timestamp_;
+  thread_timestamp_ = other.thread_timestamp_;
+  duration_ = other.duration_;
+  id_ = other.id_;
+  category_group_enabled_ = other.category_group_enabled_;
+  name_ = other.name_;
+  thread_id_ = other.thread_id_;
+  phase_ = other.phase_;
+  flags_ = other.flags_;
+  parameter_copy_storage_ = other.parameter_copy_storage_;
+
+  for (int i = 0; i < kTraceMaxNumArgs; ++i) {
+    arg_names_[i] = other.arg_names_[i];
+    arg_types_[i] = other.arg_types_[i];
+    arg_values_[i] = other.arg_values_[i];
+    convertable_values_[i] = other.convertable_values_[i];
+  }
+}
+
+void TraceEvent::Initialize(
+    int thread_id,
+    TraceTicks timestamp,
+    ThreadTicks thread_timestamp,
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    unsigned long long id,
+    int num_args,
+    const char** arg_names,
+    const unsigned char* arg_types,
+    const unsigned long long* arg_values,
+    const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
+    unsigned char flags) {
+  timestamp_ = timestamp;
+  thread_timestamp_ = thread_timestamp;
+  duration_ = TimeDelta::FromInternalValue(-1);
+  id_ = id;
+  category_group_enabled_ = category_group_enabled;
+  name_ = name;
+  thread_id_ = thread_id;
+  phase_ = phase;
+  flags_ = flags;
+
+  // Clamp num_args since it may have been set by a third_party library.
+  num_args = (num_args > kTraceMaxNumArgs) ? kTraceMaxNumArgs : num_args;
+  int i = 0;
+  for (; i < num_args; ++i) {
+    arg_names_[i] = arg_names[i];
+    arg_types_[i] = arg_types[i];
+
+    if (arg_types[i] == TRACE_VALUE_TYPE_CONVERTABLE)
+      convertable_values_[i] = convertable_values[i];
+    else
+      arg_values_[i].as_uint = arg_values[i];
+  }
+  for (; i < kTraceMaxNumArgs; ++i) {
+    arg_names_[i] = NULL;
+    arg_values_[i].as_uint = 0u;
+    convertable_values_[i] = NULL;
+    arg_types_[i] = TRACE_VALUE_TYPE_UINT;
+  }
+
+  bool copy = !!(flags & TRACE_EVENT_FLAG_COPY);
+  size_t alloc_size = 0;
+  if (copy) {
+    alloc_size += GetAllocLength(name);
+    for (i = 0; i < num_args; ++i) {
+      alloc_size += GetAllocLength(arg_names_[i]);
+      if (arg_types_[i] == TRACE_VALUE_TYPE_STRING)
+        arg_types_[i] = TRACE_VALUE_TYPE_COPY_STRING;
+    }
+  }
+
+  bool arg_is_copy[kTraceMaxNumArgs];
+  for (i = 0; i < num_args; ++i) {
+    // No copying of convertable types, we retain ownership.
+    if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE)
+      continue;
+
+    // We only take a copy of arg_vals if they are of type COPY_STRING.
+    arg_is_copy[i] = (arg_types_[i] == TRACE_VALUE_TYPE_COPY_STRING);
+    if (arg_is_copy[i])
+      alloc_size += GetAllocLength(arg_values_[i].as_string);
+  }
+
+  if (alloc_size) {
+    parameter_copy_storage_ = new RefCountedString;
+    parameter_copy_storage_->data().resize(alloc_size);
+    char* ptr = string_as_array(&parameter_copy_storage_->data());
+    const char* end = ptr + alloc_size;
+    if (copy) {
+      CopyTraceEventParameter(&ptr, &name_, end);
+      for (i = 0; i < num_args; ++i) {
+        CopyTraceEventParameter(&ptr, &arg_names_[i], end);
+      }
+    }
+    for (i = 0; i < num_args; ++i) {
+      if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE)
+        continue;
+      if (arg_is_copy[i])
+        CopyTraceEventParameter(&ptr, &arg_values_[i].as_string, end);
+    }
+    DCHECK_EQ(end, ptr) << "Overrun by " << ptr - end;
+  }
+}
+
+void TraceEvent::Reset() {
+  // Only reset fields that won't be initialized in Initialize(), or that may
+  // hold references to other objects.
+  duration_ = TimeDelta::FromInternalValue(-1);
+  parameter_copy_storage_ = NULL;
+  for (int i = 0; i < kTraceMaxNumArgs; ++i)
+    convertable_values_[i] = NULL;
+  cached_memory_overhead_estimate_.reset();
+}
+
+void TraceEvent::UpdateDuration(const TraceTicks& now,
+                                const ThreadTicks& thread_now) {
+  DCHECK_EQ(duration_.ToInternalValue(), -1);
+  duration_ = now - timestamp_;
+  thread_duration_ = thread_now - thread_timestamp_;
+}
+
+void TraceEvent::EstimateTraceMemoryOverhead(
+    TraceEventMemoryOverhead* overhead) {
+  if (!cached_memory_overhead_estimate_) {
+    cached_memory_overhead_estimate_.reset(new TraceEventMemoryOverhead);
+    cached_memory_overhead_estimate_->Add("TraceEvent", sizeof(*this));
+    // TODO(primiano): parameter_copy_storage_ is refcounted and, in theory,
+    // could be shared by several events and we might overcount. In practice
+    // this is unlikely but it's worth checking.
+    if (parameter_copy_storage_) {
+      cached_memory_overhead_estimate_->AddRefCountedString(
+          *parameter_copy_storage_.get());
+    }
+    for (size_t i = 0; i < kTraceMaxNumArgs; ++i) {
+      if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE) {
+        convertable_values_[i]->EstimateTraceMemoryOverhead(
+            cached_memory_overhead_estimate_.get());
+      }
+    }
+    cached_memory_overhead_estimate_->AddSelf();
+  }
+  overhead->Update(*cached_memory_overhead_estimate_);
+}
+
+// static
+void TraceEvent::AppendValueAsJSON(unsigned char type,
+                                   TraceEvent::TraceValue value,
+                                   std::string* out) {
+  switch (type) {
+    case TRACE_VALUE_TYPE_BOOL:
+      *out += value.as_bool ? "true" : "false";
+      break;
+    case TRACE_VALUE_TYPE_UINT:
+      StringAppendF(out, "%" PRIu64, static_cast<uint64>(value.as_uint));
+      break;
+    case TRACE_VALUE_TYPE_INT:
+      StringAppendF(out, "%" PRId64, static_cast<int64>(value.as_int));
+      break;
+    case TRACE_VALUE_TYPE_DOUBLE: {
+      // FIXME: base/json/json_writer.cc is using the same code,
+      //        should be made into a common method.
+      std::string real;
+      double val = value.as_double;
+      if (std::isfinite(val)) {
+        real = DoubleToString(val);
+        // Ensure that the number has a .0 if there's no decimal or 'e'.  This
+        // makes sure that when we read the JSON back, it's interpreted as a
+        // real rather than an int.
+        if (real.find('.') == std::string::npos &&
+            real.find('e') == std::string::npos &&
+            real.find('E') == std::string::npos) {
+          real.append(".0");
+        }
+        // The JSON spec requires that non-integer values in the range (-1,1)
+        // have a zero before the decimal point - ".52" is not valid, "0.52" is.
+        if (real[0] == '.') {
+          real.insert(0, "0");
+        } else if (real.length() > 1 && real[0] == '-' && real[1] == '.') {
+          // "-.1" bad "-0.1" good
+          real.insert(1, "0");
+        }
+      } else if (std::isnan(val)){
+        // The JSON spec doesn't allow NaN and Infinity (since these are
+        // objects in EcmaScript).  Use strings instead.
+        real = "\"NaN\"";
+      } else if (val < 0) {
+        real = "\"-Infinity\"";
+      } else {
+        real = "\"Infinity\"";
+      }
+      StringAppendF(out, "%s", real.c_str());
+      break;
+    }
+    case TRACE_VALUE_TYPE_POINTER:
+      // JSON only supports double and int numbers.
+      // So as not to lose bits from a 64-bit pointer, output as a hex string.
+      StringAppendF(out, "\"0x%" PRIx64 "\"", static_cast<uint64>(
+                                     reinterpret_cast<intptr_t>(
+                                     value.as_pointer)));
+      break;
+    case TRACE_VALUE_TYPE_STRING:
+    case TRACE_VALUE_TYPE_COPY_STRING:
+      EscapeJSONString(value.as_string ? value.as_string : "NULL", true, out);
+      break;
+    default:
+      NOTREACHED() << "Don't know how to print this value";
+      break;
+  }
+}
+
+void TraceEvent::AppendAsJSON(
+    std::string* out,
+    const ArgumentFilterPredicate& argument_filter_predicate) const {
+  int64 time_int64 = timestamp_.ToInternalValue();
+  int process_id = TraceLog::GetInstance()->process_id();
+  const char* category_group_name =
+      TraceLog::GetCategoryGroupName(category_group_enabled_);
+
+  // Category group checked at category creation time.
+  DCHECK(!strchr(name_, '"'));
+  StringAppendF(out, "{\"pid\":%i,\"tid\":%i,\"ts\":%" PRId64
+                     ","
+                     "\"ph\":\"%c\",\"cat\":\"%s\",\"name\":\"%s\",\"args\":",
+                process_id, thread_id_, time_int64, phase_, category_group_name,
+                name_);
+
+  // Output argument names and values, stop at first NULL argument name.
+  bool strip_args = arg_names_[0] && !argument_filter_predicate.is_null() &&
+                    !argument_filter_predicate.Run(category_group_name, name_);
+
+  if (strip_args) {
+    *out += "\"__stripped__\"";
+  } else {
+    *out += "{";
+
+    for (int i = 0; i < kTraceMaxNumArgs && arg_names_[i]; ++i) {
+      if (i > 0)
+        *out += ",";
+      *out += "\"";
+      *out += arg_names_[i];
+      *out += "\":";
+
+      if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE)
+        convertable_values_[i]->AppendAsTraceFormat(out);
+      else
+        AppendValueAsJSON(arg_types_[i], arg_values_[i], out);
+    }
+
+    *out += "}";
+  }
+
+  if (phase_ == TRACE_EVENT_PHASE_COMPLETE) {
+    int64 duration = duration_.ToInternalValue();
+    if (duration != -1)
+      StringAppendF(out, ",\"dur\":%" PRId64, duration);
+    if (!thread_timestamp_.is_null()) {
+      int64 thread_duration = thread_duration_.ToInternalValue();
+      if (thread_duration != -1)
+        StringAppendF(out, ",\"tdur\":%" PRId64, thread_duration);
+    }
+  }
+
+  // Output tts if thread_timestamp is valid.
+  if (!thread_timestamp_.is_null()) {
+    int64 thread_time_int64 = thread_timestamp_.ToInternalValue();
+    StringAppendF(out, ",\"tts\":%" PRId64, thread_time_int64);
+  }
+
+  // Output async tts marker field if flag is set.
+  if (flags_ & TRACE_EVENT_FLAG_ASYNC_TTS) {
+    StringAppendF(out, ", \"use_async_tts\":1");
+  }
+
+  // If id_ is set, print it out as a hex string so we don't loose any
+  // bits (it might be a 64-bit pointer).
+  if (flags_ & TRACE_EVENT_FLAG_HAS_ID)
+    StringAppendF(out, ",\"id\":\"0x%" PRIx64 "\"", static_cast<uint64>(id_));
+
+  if (flags_ & TRACE_EVENT_FLAG_BIND_TO_ENCLOSING)
+    StringAppendF(out, ",\"bp\":\"e\"");
+
+  // Instant events also output their scope.
+  if (phase_ == TRACE_EVENT_PHASE_INSTANT) {
+    char scope = '?';
+    switch (flags_ & TRACE_EVENT_FLAG_SCOPE_MASK) {
+      case TRACE_EVENT_SCOPE_GLOBAL:
+        scope = TRACE_EVENT_SCOPE_NAME_GLOBAL;
+        break;
+
+      case TRACE_EVENT_SCOPE_PROCESS:
+        scope = TRACE_EVENT_SCOPE_NAME_PROCESS;
+        break;
+
+      case TRACE_EVENT_SCOPE_THREAD:
+        scope = TRACE_EVENT_SCOPE_NAME_THREAD;
+        break;
+    }
+    StringAppendF(out, ",\"s\":\"%c\"", scope);
+  }
+
+  *out += "}";
+}
+
+void TraceEvent::AppendPrettyPrinted(std::ostringstream* out) const {
+  *out << name_ << "[";
+  *out << TraceLog::GetCategoryGroupName(category_group_enabled_);
+  *out << "]";
+  if (arg_names_[0]) {
+    *out << ", {";
+    for (int i = 0; i < kTraceMaxNumArgs && arg_names_[i]; ++i) {
+      if (i > 0)
+        *out << ", ";
+      *out << arg_names_[i] << ":";
+      std::string value_as_text;
+
+      if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE)
+        convertable_values_[i]->AppendAsTraceFormat(&value_as_text);
+      else
+        AppendValueAsJSON(arg_types_[i], arg_values_[i], &value_as_text);
+
+      *out << value_as_text;
+    }
+    *out << "}";
+  }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// TraceResultBuffer
+//
+////////////////////////////////////////////////////////////////////////////////
+
+TraceResultBuffer::OutputCallback
+    TraceResultBuffer::SimpleOutput::GetCallback() {
+  return Bind(&SimpleOutput::Append, Unretained(this));
+}
+
+void TraceResultBuffer::SimpleOutput::Append(
+    const std::string& json_trace_output) {
+  json_output += json_trace_output;
+}
+
+TraceResultBuffer::TraceResultBuffer() : append_comma_(false) {
+}
+
+TraceResultBuffer::~TraceResultBuffer() {
+}
+
+void TraceResultBuffer::SetOutputCallback(
+    const OutputCallback& json_chunk_callback) {
+  output_callback_ = json_chunk_callback;
+}
+
+void TraceResultBuffer::Start() {
+  append_comma_ = false;
+  output_callback_.Run("[");
+}
+
+void TraceResultBuffer::AddFragment(const std::string& trace_fragment) {
+  if (append_comma_)
+    output_callback_.Run(",");
+  append_comma_ = true;
+  output_callback_.Run(trace_fragment);
+}
+
+void TraceResultBuffer::Finish() {
+  output_callback_.Run("]");
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// TraceSamplingThread
+//
+////////////////////////////////////////////////////////////////////////////////
+class TraceBucketData;
+typedef base::Callback<void(TraceBucketData*)> TraceSampleCallback;
+
+class TraceBucketData {
+ public:
+  TraceBucketData(base::subtle::AtomicWord* bucket,
+                  const char* name,
+                  TraceSampleCallback callback);
+  ~TraceBucketData();
+
+  TRACE_EVENT_API_ATOMIC_WORD* bucket;
+  const char* bucket_name;
+  TraceSampleCallback callback;
+};
+
+// This object must be created on the IO thread.
+class TraceSamplingThread : public PlatformThread::Delegate {
+ public:
+  TraceSamplingThread();
+  ~TraceSamplingThread() override;
+
+  // Implementation of PlatformThread::Delegate:
+  void ThreadMain() override;
+
+  static void DefaultSamplingCallback(TraceBucketData* bucekt_data);
+
+  void Stop();
+  void WaitSamplingEventForTesting();
+
+ private:
+  friend class TraceLog;
+
+  void GetSamples();
+  // Not thread-safe. Once the ThreadMain has been called, this can no longer
+  // be called.
+  void RegisterSampleBucket(TRACE_EVENT_API_ATOMIC_WORD* bucket,
+                            const char* const name,
+                            TraceSampleCallback callback);
+  // Splits a combined "category\0name" into the two component parts.
+  static void ExtractCategoryAndName(const char* combined,
+                                     const char** category,
+                                     const char** name);
+  std::vector<TraceBucketData> sample_buckets_;
+  bool thread_running_;
+  CancellationFlag cancellation_flag_;
+  WaitableEvent waitable_event_for_testing_;
+};
+
+
+TraceSamplingThread::TraceSamplingThread()
+    : thread_running_(false),
+      waitable_event_for_testing_(false, false) {
+}
+
+TraceSamplingThread::~TraceSamplingThread() {
+}
+
+void TraceSamplingThread::ThreadMain() {
+  PlatformThread::SetName("Sampling Thread");
+  thread_running_ = true;
+  const int kSamplingFrequencyMicroseconds = 1000;
+  while (!cancellation_flag_.IsSet()) {
+    PlatformThread::Sleep(
+        TimeDelta::FromMicroseconds(kSamplingFrequencyMicroseconds));
+    GetSamples();
+    waitable_event_for_testing_.Signal();
+  }
+}
+
+// static
+void TraceSamplingThread::DefaultSamplingCallback(
+    TraceBucketData* bucket_data) {
+  TRACE_EVENT_API_ATOMIC_WORD category_and_name =
+      TRACE_EVENT_API_ATOMIC_LOAD(*bucket_data->bucket);
+  if (!category_and_name)
+    return;
+  const char* const combined =
+      reinterpret_cast<const char* const>(category_and_name);
+  const char* category_group;
+  const char* name;
+  ExtractCategoryAndName(combined, &category_group, &name);
+  TRACE_EVENT_API_ADD_TRACE_EVENT(TRACE_EVENT_PHASE_SAMPLE,
+      TraceLog::GetCategoryGroupEnabled(category_group),
+      name, 0, 0, NULL, NULL, NULL, NULL, 0);
+}
+
+void TraceSamplingThread::GetSamples() {
+  for (size_t i = 0; i < sample_buckets_.size(); ++i) {
+    TraceBucketData* bucket_data = &sample_buckets_[i];
+    bucket_data->callback.Run(bucket_data);
+  }
+}
+
+void TraceSamplingThread::RegisterSampleBucket(
+    TRACE_EVENT_API_ATOMIC_WORD* bucket,
+    const char* const name,
+    TraceSampleCallback callback) {
+  // Access to sample_buckets_ doesn't cause races with the sampling thread
+  // that uses the sample_buckets_, because it is guaranteed that
+  // RegisterSampleBucket is called before the sampling thread is created.
+  DCHECK(!thread_running_);
+  sample_buckets_.push_back(TraceBucketData(bucket, name, callback));
+}
+
+// static
+void TraceSamplingThread::ExtractCategoryAndName(const char* combined,
+                                                 const char** category,
+                                                 const char** name) {
+  *category = combined;
+  *name = &combined[strlen(combined) + 1];
+}
+
+void TraceSamplingThread::Stop() {
+  cancellation_flag_.Set();
+}
+
+void TraceSamplingThread::WaitSamplingEventForTesting() {
+  waitable_event_for_testing_.Wait();
+}
+
+TraceBucketData::TraceBucketData(base::subtle::AtomicWord* bucket,
+                                 const char* name,
+                                 TraceSampleCallback callback)
+    : bucket(bucket),
+      bucket_name(name),
+      callback(callback) {
+}
+
+TraceBucketData::~TraceBucketData() {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// TraceLog
+//
+////////////////////////////////////////////////////////////////////////////////
+
+class TraceLog::ThreadLocalEventBuffer
+    : public MessageLoop::DestructionObserver,
+      public MemoryDumpProvider {
+ public:
+  ThreadLocalEventBuffer(TraceLog* trace_log);
+  ~ThreadLocalEventBuffer() override;
+
+  TraceEvent* AddTraceEvent(TraceEventHandle* handle);
+
+  void ReportOverhead(const TraceTicks& event_timestamp,
+                      const ThreadTicks& event_thread_timestamp);
+
+  TraceEvent* GetEventByHandle(TraceEventHandle handle) {
+    if (!chunk_ || handle.chunk_seq != chunk_->seq() ||
+        handle.chunk_index != chunk_index_)
+      return NULL;
+
+    return chunk_->GetEventAt(handle.event_index);
+  }
+
+  int generation() const { return generation_; }
+
+ private:
+  // MessageLoop::DestructionObserver
+  void WillDestroyCurrentMessageLoop() override;
+
+  // MemoryDumpProvider implementation.
+  bool OnMemoryDump(ProcessMemoryDump* pmd) override;
+
+  void FlushWhileLocked();
+
+  void CheckThisIsCurrentBuffer() const {
+    DCHECK(trace_log_->thread_local_event_buffer_.Get() == this);
+  }
+
+  // Since TraceLog is a leaky singleton, trace_log_ will always be valid
+  // as long as the thread exists.
+  TraceLog* trace_log_;
+  scoped_ptr<TraceBufferChunk> chunk_;
+  size_t chunk_index_;
+  int event_count_;
+  TimeDelta overhead_;
+  int generation_;
+
+  DISALLOW_COPY_AND_ASSIGN(ThreadLocalEventBuffer);
+};
+
+TraceLog::ThreadLocalEventBuffer::ThreadLocalEventBuffer(TraceLog* trace_log)
+    : trace_log_(trace_log),
+      chunk_index_(0),
+      event_count_(0),
+      generation_(trace_log->generation()) {
+  // ThreadLocalEventBuffer is created only if the thread has a message loop, so
+  // the following message_loop won't be NULL.
+  MessageLoop* message_loop = MessageLoop::current();
+  message_loop->AddDestructionObserver(this);
+
+  // This is to report the local memory usage when memory-infra is enabled.
+  MemoryDumpManager::GetInstance()->RegisterDumpProvider(
+      this, ThreadTaskRunnerHandle::Get());
+
+  AutoLock lock(trace_log->lock_);
+  trace_log->thread_message_loops_.insert(message_loop);
+}
+
+TraceLog::ThreadLocalEventBuffer::~ThreadLocalEventBuffer() {
+  CheckThisIsCurrentBuffer();
+  MessageLoop::current()->RemoveDestructionObserver(this);
+  MemoryDumpManager::GetInstance()->UnregisterDumpProvider(this);
+
+  // Zero event_count_ happens in either of the following cases:
+  // - no event generated for the thread;
+  // - the thread has no message loop;
+  // - trace_event_overhead is disabled.
+  if (event_count_) {
+    InitializeMetadataEvent(AddTraceEvent(NULL),
+                            static_cast<int>(base::PlatformThread::CurrentId()),
+                            "overhead", "average_overhead",
+                            overhead_.InMillisecondsF() / event_count_);
+  }
+
+  {
+    AutoLock lock(trace_log_->lock_);
+    FlushWhileLocked();
+    trace_log_->thread_message_loops_.erase(MessageLoop::current());
+  }
+  trace_log_->thread_local_event_buffer_.Set(NULL);
+}
+
+TraceEvent* TraceLog::ThreadLocalEventBuffer::AddTraceEvent(
+    TraceEventHandle* handle) {
+  CheckThisIsCurrentBuffer();
+
+  if (chunk_ && chunk_->IsFull()) {
+    AutoLock lock(trace_log_->lock_);
+    FlushWhileLocked();
+    chunk_.reset();
+  }
+  if (!chunk_) {
+    AutoLock lock(trace_log_->lock_);
+    chunk_ = trace_log_->logged_events_->GetChunk(&chunk_index_);
+    trace_log_->CheckIfBufferIsFullWhileLocked();
+  }
+  if (!chunk_)
+    return NULL;
+
+  size_t event_index;
+  TraceEvent* trace_event = chunk_->AddTraceEvent(&event_index);
+  if (trace_event && handle)
+    MakeHandle(chunk_->seq(), chunk_index_, event_index, handle);
+
+  return trace_event;
+}
+
+void TraceLog::ThreadLocalEventBuffer::ReportOverhead(
+    const TraceTicks& event_timestamp,
+    const ThreadTicks& event_thread_timestamp) {
+  if (!g_category_group_enabled[g_category_trace_event_overhead])
+    return;
+
+  CheckThisIsCurrentBuffer();
+
+  event_count_++;
+  ThreadTicks thread_now = ThreadNow();
+  TraceTicks now = trace_log_->OffsetNow();
+  TimeDelta overhead = now - event_timestamp;
+  if (overhead.InMicroseconds() >= kOverheadReportThresholdInMicroseconds) {
+    TraceEvent* trace_event = AddTraceEvent(NULL);
+    if (trace_event) {
+      trace_event->Initialize(
+          static_cast<int>(PlatformThread::CurrentId()),
+          event_timestamp, event_thread_timestamp,
+          TRACE_EVENT_PHASE_COMPLETE,
+          &g_category_group_enabled[g_category_trace_event_overhead],
+          "overhead", 0, 0, NULL, NULL, NULL, NULL, 0);
+      trace_event->UpdateDuration(now, thread_now);
+    }
+  }
+  overhead_ += overhead;
+}
+
+void TraceLog::ThreadLocalEventBuffer::WillDestroyCurrentMessageLoop() {
+  delete this;
+}
+
+bool TraceLog::ThreadLocalEventBuffer::OnMemoryDump(ProcessMemoryDump* pmd) {
+  if (!chunk_)
+    return true;
+  std::string dump_base_name = StringPrintf(
+      "tracing/thread_%d", static_cast<int>(PlatformThread::CurrentId()));
+  TraceEventMemoryOverhead overhead;
+  chunk_->EstimateTraceMemoryOverhead(&overhead);
+  overhead.DumpInto(dump_base_name.c_str(), pmd);
+  return true;
+}
+
+void TraceLog::ThreadLocalEventBuffer::FlushWhileLocked() {
+  if (!chunk_)
+    return;
+
+  trace_log_->lock_.AssertAcquired();
+  if (trace_log_->CheckGeneration(generation_)) {
+    // Return the chunk to the buffer only if the generation matches.
+    trace_log_->logged_events_->ReturnChunk(chunk_index_, chunk_.Pass());
+  }
+  // Otherwise this method may be called from the destructor, or TraceLog will
+  // find the generation mismatch and delete this buffer soon.
+}
+
+TraceLogStatus::TraceLogStatus() : event_capacity(0), event_count(0) {
+}
+
+TraceLogStatus::~TraceLogStatus() {
+}
+
+// static
+TraceLog* TraceLog::GetInstance() {
+  return Singleton<TraceLog, LeakySingletonTraits<TraceLog> >::get();
+}
+
+TraceLog::TraceLog()
+    : mode_(DISABLED),
+      num_traces_recorded_(0),
+      event_callback_(0),
+      dispatching_to_observer_list_(false),
+      process_sort_index_(0),
+      process_id_hash_(0),
+      process_id_(0),
+      watch_category_(0),
+      trace_options_(kInternalRecordUntilFull),
+      sampling_thread_handle_(0),
+      trace_config_(TraceConfig()),
+      event_callback_trace_config_(TraceConfig()),
+      thread_shared_chunk_index_(0),
+      generation_(0),
+      use_worker_thread_(false) {
+  // Trace is enabled or disabled on one thread while other threads are
+  // accessing the enabled flag. We don't care whether edge-case events are
+  // traced or not, so we allow races on the enabled flag to keep the trace
+  // macros fast.
+  // TODO(jbates): ANNOTATE_BENIGN_RACE_SIZED crashes windows TSAN bots:
+  // ANNOTATE_BENIGN_RACE_SIZED(g_category_group_enabled,
+  //                            sizeof(g_category_group_enabled),
+  //                           "trace_event category enabled");
+  for (int i = 0; i < MAX_CATEGORY_GROUPS; ++i) {
+    ANNOTATE_BENIGN_RACE(&g_category_group_enabled[i],
+                         "trace_event category enabled");
+  }
+#if defined(OS_NACL)  // NaCl shouldn't expose the process id.
+  SetProcessID(0);
+#else
+  SetProcessID(static_cast<int>(GetCurrentProcId()));
+
+  // NaCl also shouldn't access the command line.
+  if (CommandLine::InitializedForCurrentProcess() &&
+      CommandLine::ForCurrentProcess()->HasSwitch(switches::kTraceToConsole)) {
+    std::string filter = CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+        switches::kTraceToConsole);
+    if (filter.empty()) {
+      filter = kEchoToConsoleCategoryFilter;
+    } else {
+      filter.append(",");
+      filter.append(kEchoToConsoleCategoryFilter);
+    }
+
+    LOG(ERROR) << "Start " << switches::kTraceToConsole
+               << " with CategoryFilter '" << filter << "'.";
+    SetEnabled(TraceConfig(filter, ECHO_TO_CONSOLE), RECORDING_MODE);
+  }
+#endif
+
+  logged_events_.reset(CreateTraceBuffer());
+
+  MemoryDumpManager::GetInstance()->RegisterDumpProvider(this);
+}
+
+TraceLog::~TraceLog() {
+}
+
+bool TraceLog::OnMemoryDump(ProcessMemoryDump* pmd) {
+  TraceEventMemoryOverhead overhead;
+  overhead.Add("TraceLog", sizeof(*this));
+  if (logged_events_)
+    logged_events_->EstimateTraceMemoryOverhead(&overhead);
+  overhead.AddSelf();
+  overhead.DumpInto("tracing/main_trace_log", pmd);
+  return true;
+}
+
+const unsigned char* TraceLog::GetCategoryGroupEnabled(
+    const char* category_group) {
+  TraceLog* tracelog = GetInstance();
+  if (!tracelog) {
+    DCHECK(!g_category_group_enabled[g_category_already_shutdown]);
+    return &g_category_group_enabled[g_category_already_shutdown];
+  }
+  return tracelog->GetCategoryGroupEnabledInternal(category_group);
+}
+
+const char* TraceLog::GetCategoryGroupName(
+    const unsigned char* category_group_enabled) {
+  // Calculate the index of the category group by finding
+  // category_group_enabled in g_category_group_enabled array.
+  uintptr_t category_begin =
+      reinterpret_cast<uintptr_t>(g_category_group_enabled);
+  uintptr_t category_ptr = reinterpret_cast<uintptr_t>(category_group_enabled);
+  DCHECK(category_ptr >= category_begin &&
+         category_ptr < reinterpret_cast<uintptr_t>(
+             g_category_group_enabled + MAX_CATEGORY_GROUPS)) <<
+      "out of bounds category pointer";
+  uintptr_t category_index =
+      (category_ptr - category_begin) / sizeof(g_category_group_enabled[0]);
+  return g_category_groups[category_index];
+}
+
+void TraceLog::UpdateCategoryGroupEnabledFlag(size_t category_index) {
+  unsigned char enabled_flag = 0;
+  const char* category_group = g_category_groups[category_index];
+  if (mode_ == RECORDING_MODE &&
+      trace_config_.IsCategoryGroupEnabled(category_group))
+    enabled_flag |= ENABLED_FOR_RECORDING;
+  else if (mode_ == MONITORING_MODE &&
+      trace_config_.IsCategoryGroupEnabled(category_group))
+    enabled_flag |= ENABLED_FOR_MONITORING;
+  if (event_callback_ &&
+      event_callback_trace_config_.IsCategoryGroupEnabled(category_group))
+    enabled_flag |= ENABLED_FOR_EVENT_CALLBACK;
+#if defined(OS_WIN)
+  if (base::trace_event::TraceEventETWExport::isETWExportEnabled())
+    enabled_flag |= ENABLED_FOR_ETW_EXPORT;
+#endif
+
+  g_category_group_enabled[category_index] = enabled_flag;
+}
+
+void TraceLog::UpdateCategoryGroupEnabledFlags() {
+  size_t category_index = base::subtle::NoBarrier_Load(&g_category_index);
+  for (size_t i = 0; i < category_index; i++)
+    UpdateCategoryGroupEnabledFlag(i);
+}
+
+void TraceLog::UpdateSyntheticDelaysFromTraceConfig() {
+  ResetTraceEventSyntheticDelays();
+  const TraceConfig::StringList& delays =
+      trace_config_.GetSyntheticDelayValues();
+  TraceConfig::StringList::const_iterator ci;
+  for (ci = delays.begin(); ci != delays.end(); ++ci) {
+    StringTokenizer tokens(*ci, ";");
+    if (!tokens.GetNext())
+      continue;
+    TraceEventSyntheticDelay* delay =
+        TraceEventSyntheticDelay::Lookup(tokens.token());
+    while (tokens.GetNext()) {
+      std::string token = tokens.token();
+      char* duration_end;
+      double target_duration = strtod(token.c_str(), &duration_end);
+      if (duration_end != token.c_str()) {
+        delay->SetTargetDuration(TimeDelta::FromMicroseconds(
+            static_cast<int64>(target_duration * 1e6)));
+      } else if (token == "static") {
+        delay->SetMode(TraceEventSyntheticDelay::STATIC);
+      } else if (token == "oneshot") {
+        delay->SetMode(TraceEventSyntheticDelay::ONE_SHOT);
+      } else if (token == "alternating") {
+        delay->SetMode(TraceEventSyntheticDelay::ALTERNATING);
+      }
+    }
+  }
+}
+
+const unsigned char* TraceLog::GetCategoryGroupEnabledInternal(
+    const char* category_group) {
+  DCHECK(!strchr(category_group, '"')) <<
+      "Category groups may not contain double quote";
+  // The g_category_groups is append only, avoid using a lock for the fast path.
+  size_t current_category_index = base::subtle::Acquire_Load(&g_category_index);
+
+  // Search for pre-existing category group.
+  for (size_t i = 0; i < current_category_index; ++i) {
+    if (strcmp(g_category_groups[i], category_group) == 0) {
+      return &g_category_group_enabled[i];
+    }
+  }
+
+  unsigned char* category_group_enabled = NULL;
+  // This is the slow path: the lock is not held in the case above, so more
+  // than one thread could have reached here trying to add the same category.
+  // Only hold to lock when actually appending a new category, and
+  // check the categories groups again.
+  AutoLock lock(lock_);
+  size_t category_index = base::subtle::Acquire_Load(&g_category_index);
+  for (size_t i = 0; i < category_index; ++i) {
+    if (strcmp(g_category_groups[i], category_group) == 0) {
+      return &g_category_group_enabled[i];
+    }
+  }
+
+  // Create a new category group.
+  DCHECK(category_index < MAX_CATEGORY_GROUPS) <<
+      "must increase MAX_CATEGORY_GROUPS";
+  if (category_index < MAX_CATEGORY_GROUPS) {
+    // Don't hold on to the category_group pointer, so that we can create
+    // category groups with strings not known at compile time (this is
+    // required by SetWatchEvent).
+    const char* new_group = strdup(category_group);
+    ANNOTATE_LEAKING_OBJECT_PTR(new_group);
+    g_category_groups[category_index] = new_group;
+    DCHECK(!g_category_group_enabled[category_index]);
+    // Note that if both included and excluded patterns in the
+    // TraceConfig are empty, we exclude nothing,
+    // thereby enabling this category group.
+    UpdateCategoryGroupEnabledFlag(category_index);
+    category_group_enabled = &g_category_group_enabled[category_index];
+    // Update the max index now.
+    base::subtle::Release_Store(&g_category_index, category_index + 1);
+  } else {
+    category_group_enabled =
+        &g_category_group_enabled[g_category_categories_exhausted];
+  }
+  return category_group_enabled;
+}
+
+void TraceLog::GetKnownCategoryGroups(
+    std::vector<std::string>* category_groups) {
+  AutoLock lock(lock_);
+  category_groups->push_back(
+      g_category_groups[g_category_trace_event_overhead]);
+  size_t category_index = base::subtle::NoBarrier_Load(&g_category_index);
+  for (size_t i = g_num_builtin_categories; i < category_index; i++)
+    category_groups->push_back(g_category_groups[i]);
+}
+
+void TraceLog::SetEnabled(const TraceConfig& trace_config, Mode mode) {
+  std::vector<EnabledStateObserver*> observer_list;
+  {
+    AutoLock lock(lock_);
+
+    // Can't enable tracing when Flush() is in progress.
+    DCHECK(!flush_task_runner_);
+
+    InternalTraceOptions new_options =
+        GetInternalOptionsFromTraceConfig(trace_config);
+
+   InternalTraceOptions old_options = trace_options();
+
+    if (IsEnabled()) {
+      if (new_options != old_options) {
+        DLOG(ERROR) << "Attempting to re-enable tracing with a different "
+                    << "set of options.";
+      }
+
+      if (mode != mode_) {
+        DLOG(ERROR) << "Attempting to re-enable tracing with a different mode.";
+      }
+
+      trace_config_.Merge(trace_config);
+      UpdateCategoryGroupEnabledFlags();
+      return;
+    }
+
+    if (dispatching_to_observer_list_) {
+      DLOG(ERROR) <<
+          "Cannot manipulate TraceLog::Enabled state from an observer.";
+      return;
+    }
+
+    mode_ = mode;
+
+    if (new_options != old_options) {
+      subtle::NoBarrier_Store(&trace_options_, new_options);
+      UseNextTraceBuffer();
+    }
+
+    num_traces_recorded_++;
+
+    trace_config_ = TraceConfig(trace_config);
+    UpdateCategoryGroupEnabledFlags();
+    UpdateSyntheticDelaysFromTraceConfig();
+
+    if (new_options & kInternalEnableSampling) {
+      sampling_thread_.reset(new TraceSamplingThread);
+      sampling_thread_->RegisterSampleBucket(
+          &g_trace_state[0],
+          "bucket0",
+          Bind(&TraceSamplingThread::DefaultSamplingCallback));
+      sampling_thread_->RegisterSampleBucket(
+          &g_trace_state[1],
+          "bucket1",
+          Bind(&TraceSamplingThread::DefaultSamplingCallback));
+      sampling_thread_->RegisterSampleBucket(
+          &g_trace_state[2],
+          "bucket2",
+          Bind(&TraceSamplingThread::DefaultSamplingCallback));
+      if (!PlatformThread::Create(
+            0, sampling_thread_.get(), &sampling_thread_handle_)) {
+        DCHECK(false) << "failed to create thread";
+      }
+    }
+
+    dispatching_to_observer_list_ = true;
+    observer_list = enabled_state_observer_list_;
+  }
+  // Notify observers outside the lock in case they trigger trace events.
+  for (size_t i = 0; i < observer_list.size(); ++i)
+    observer_list[i]->OnTraceLogEnabled();
+
+  {
+    AutoLock lock(lock_);
+    dispatching_to_observer_list_ = false;
+  }
+}
+
+void TraceLog::SetArgumentFilterPredicate(
+    const TraceEvent::ArgumentFilterPredicate& argument_filter_predicate) {
+  AutoLock lock(lock_);
+  DCHECK(!argument_filter_predicate.is_null());
+  DCHECK(argument_filter_predicate_.is_null());
+  argument_filter_predicate_ = argument_filter_predicate;
+}
+
+TraceLog::InternalTraceOptions TraceLog::GetInternalOptionsFromTraceConfig(
+    const TraceConfig& config) {
+  InternalTraceOptions ret =
+      config.IsSamplingEnabled() ? kInternalEnableSampling : kInternalNone;
+  if (config.IsArgumentFilterEnabled())
+    ret |= kInternalEnableArgumentFilter;
+  switch (config.GetTraceRecordMode()) {
+    case RECORD_UNTIL_FULL:
+      return ret | kInternalRecordUntilFull;
+    case RECORD_CONTINUOUSLY:
+      return ret | kInternalRecordContinuously;
+    case ECHO_TO_CONSOLE:
+      return ret | kInternalEchoToConsole;
+    case RECORD_AS_MUCH_AS_POSSIBLE:
+      return ret | kInternalRecordAsMuchAsPossible;
+  }
+  NOTREACHED();
+  return kInternalNone;
+}
+
+TraceConfig TraceLog::GetCurrentTraceConfig() const {
+  AutoLock lock(lock_);
+  return trace_config_;
+}
+
+void TraceLog::SetDisabled() {
+  AutoLock lock(lock_);
+  SetDisabledWhileLocked();
+}
+
+void TraceLog::SetDisabledWhileLocked() {
+  lock_.AssertAcquired();
+
+  if (!IsEnabled())
+    return;
+
+  if (dispatching_to_observer_list_) {
+    DLOG(ERROR)
+        << "Cannot manipulate TraceLog::Enabled state from an observer.";
+    return;
+  }
+
+  mode_ = DISABLED;
+
+  if (sampling_thread_.get()) {
+    // Stop the sampling thread.
+    sampling_thread_->Stop();
+    lock_.Release();
+    PlatformThread::Join(sampling_thread_handle_);
+    lock_.Acquire();
+    sampling_thread_handle_ = PlatformThreadHandle();
+    sampling_thread_.reset();
+  }
+
+  trace_config_.Clear();
+  subtle::NoBarrier_Store(&watch_category_, 0);
+  watch_event_name_ = "";
+  UpdateCategoryGroupEnabledFlags();
+  AddMetadataEventsWhileLocked();
+
+  dispatching_to_observer_list_ = true;
+  std::vector<EnabledStateObserver*> observer_list =
+      enabled_state_observer_list_;
+
+  {
+    // Dispatch to observers outside the lock in case the observer triggers a
+    // trace event.
+    AutoUnlock unlock(lock_);
+    for (size_t i = 0; i < observer_list.size(); ++i)
+      observer_list[i]->OnTraceLogDisabled();
+  }
+  dispatching_to_observer_list_ = false;
+}
+
+int TraceLog::GetNumTracesRecorded() {
+  AutoLock lock(lock_);
+  if (!IsEnabled())
+    return -1;
+  return num_traces_recorded_;
+}
+
+void TraceLog::AddEnabledStateObserver(EnabledStateObserver* listener) {
+  enabled_state_observer_list_.push_back(listener);
+}
+
+void TraceLog::RemoveEnabledStateObserver(EnabledStateObserver* listener) {
+  std::vector<EnabledStateObserver*>::iterator it =
+      std::find(enabled_state_observer_list_.begin(),
+                enabled_state_observer_list_.end(),
+                listener);
+  if (it != enabled_state_observer_list_.end())
+    enabled_state_observer_list_.erase(it);
+}
+
+bool TraceLog::HasEnabledStateObserver(EnabledStateObserver* listener) const {
+  std::vector<EnabledStateObserver*>::const_iterator it =
+      std::find(enabled_state_observer_list_.begin(),
+                enabled_state_observer_list_.end(),
+                listener);
+  return it != enabled_state_observer_list_.end();
+}
+
+TraceLogStatus TraceLog::GetStatus() const {
+  AutoLock lock(lock_);
+  TraceLogStatus result;
+  result.event_capacity = logged_events_->Capacity();
+  result.event_count = logged_events_->Size();
+  return result;
+}
+
+bool TraceLog::BufferIsFull() const {
+  AutoLock lock(lock_);
+  return logged_events_->IsFull();
+}
+
+TraceBuffer* TraceLog::CreateTraceBuffer() {
+  InternalTraceOptions options = trace_options();
+  if (options & kInternalRecordContinuously)
+    return new TraceBufferRingBuffer(kTraceEventRingBufferChunks);
+  else if ((options & kInternalEnableSampling) && mode_ == MONITORING_MODE)
+    return new TraceBufferRingBuffer(kMonitorTraceEventBufferChunks);
+  else if (options & kInternalEchoToConsole)
+    return new TraceBufferRingBuffer(kEchoToConsoleTraceEventBufferChunks);
+  else if (options & kInternalRecordAsMuchAsPossible)
+    return CreateTraceBufferVectorOfSize(kTraceEventVectorBigBufferChunks);
+  return CreateTraceBufferVectorOfSize(kTraceEventVectorBufferChunks);
+}
+
+TraceBuffer* TraceLog::CreateTraceBufferVectorOfSize(size_t max_chunks) {
+  return new TraceBufferVector(max_chunks);
+}
+
+TraceEvent* TraceLog::AddEventToThreadSharedChunkWhileLocked(
+    TraceEventHandle* handle, bool check_buffer_is_full) {
+  lock_.AssertAcquired();
+
+  if (thread_shared_chunk_ && thread_shared_chunk_->IsFull()) {
+    logged_events_->ReturnChunk(thread_shared_chunk_index_,
+                                thread_shared_chunk_.Pass());
+  }
+
+  if (!thread_shared_chunk_) {
+    thread_shared_chunk_ = logged_events_->GetChunk(
+        &thread_shared_chunk_index_);
+    if (check_buffer_is_full)
+      CheckIfBufferIsFullWhileLocked();
+  }
+  if (!thread_shared_chunk_)
+    return NULL;
+
+  size_t event_index;
+  TraceEvent* trace_event = thread_shared_chunk_->AddTraceEvent(&event_index);
+  if (trace_event && handle) {
+    MakeHandle(thread_shared_chunk_->seq(), thread_shared_chunk_index_,
+               event_index, handle);
+  }
+  return trace_event;
+}
+
+void TraceLog::CheckIfBufferIsFullWhileLocked() {
+  lock_.AssertAcquired();
+  if (logged_events_->IsFull()) {
+    if (buffer_limit_reached_timestamp_.is_null()) {
+      buffer_limit_reached_timestamp_ = OffsetNow();
+    }
+    SetDisabledWhileLocked();
+  }
+}
+
+void TraceLog::SetEventCallbackEnabled(const TraceConfig& trace_config,
+                                       EventCallback cb) {
+  AutoLock lock(lock_);
+  subtle::NoBarrier_Store(&event_callback_,
+                          reinterpret_cast<subtle::AtomicWord>(cb));
+  event_callback_trace_config_ = trace_config;
+  UpdateCategoryGroupEnabledFlags();
+};
+
+void TraceLog::SetEventCallbackDisabled() {
+  AutoLock lock(lock_);
+  subtle::NoBarrier_Store(&event_callback_, 0);
+  UpdateCategoryGroupEnabledFlags();
+}
+
+// Flush() works as the following:
+// 1. Flush() is called in thread A whose task runner is saved in
+//    flush_task_runner_;
+// 2. If thread_message_loops_ is not empty, thread A posts task to each message
+//    loop to flush the thread local buffers; otherwise finish the flush;
+// 3. FlushCurrentThread() deletes the thread local event buffer:
+//    - The last batch of events of the thread are flushed into the main buffer;
+//    - The message loop will be removed from thread_message_loops_;
+//    If this is the last message loop, finish the flush;
+// 4. If any thread hasn't finish its flush in time, finish the flush.
+void TraceLog::Flush(const TraceLog::OutputCallback& cb,
+                     bool use_worker_thread) {
+  use_worker_thread_ = use_worker_thread;
+  if (IsEnabled()) {
+    // Can't flush when tracing is enabled because otherwise PostTask would
+    // - generate more trace events;
+    // - deschedule the calling thread on some platforms causing inaccurate
+    //   timing of the trace events.
+    scoped_refptr<RefCountedString> empty_result = new RefCountedString;
+    if (!cb.is_null())
+      cb.Run(empty_result, false);
+    LOG(WARNING) << "Ignored TraceLog::Flush called when tracing is enabled";
+    return;
+  }
+
+  int generation = this->generation();
+  // Copy of thread_message_loops_ to be used without locking.
+  std::vector<scoped_refptr<SingleThreadTaskRunner> >
+      thread_message_loop_task_runners;
+  {
+    AutoLock lock(lock_);
+    DCHECK(!flush_task_runner_);
+    flush_task_runner_ = ThreadTaskRunnerHandle::IsSet()
+                             ? ThreadTaskRunnerHandle::Get()
+                             : nullptr;
+    DCHECK_IMPLIES(thread_message_loops_.size(), flush_task_runner_);
+    flush_output_callback_ = cb;
+
+    if (thread_shared_chunk_) {
+      logged_events_->ReturnChunk(thread_shared_chunk_index_,
+                                  thread_shared_chunk_.Pass());
+    }
+
+    if (thread_message_loops_.size()) {
+      for (hash_set<MessageLoop*>::const_iterator it =
+           thread_message_loops_.begin();
+           it != thread_message_loops_.end(); ++it) {
+        thread_message_loop_task_runners.push_back((*it)->task_runner());
+      }
+    }
+  }
+
+  if (thread_message_loop_task_runners.size()) {
+    for (size_t i = 0; i < thread_message_loop_task_runners.size(); ++i) {
+      thread_message_loop_task_runners[i]->PostTask(
+          FROM_HERE,
+          Bind(&TraceLog::FlushCurrentThread, Unretained(this), generation));
+    }
+    flush_task_runner_->PostDelayedTask(
+        FROM_HERE,
+        Bind(&TraceLog::OnFlushTimeout, Unretained(this), generation),
+        TimeDelta::FromMilliseconds(kThreadFlushTimeoutMs));
+    return;
+  }
+
+  FinishFlush(generation);
+}
+
+// Usually it runs on a different thread.
+void TraceLog::ConvertTraceEventsToTraceFormat(
+    scoped_ptr<TraceBuffer> logged_events,
+    const OutputCallback& flush_output_callback,
+    const TraceEvent::ArgumentFilterPredicate& argument_filter_predicate) {
+  if (flush_output_callback.is_null())
+    return;
+
+  // The callback need to be called at least once even if there is no events
+  // to let the caller know the completion of flush.
+  bool has_more_events = true;
+  do {
+    scoped_refptr<RefCountedString> json_events_str_ptr =
+        new RefCountedString();
+
+    while (json_events_str_ptr->size() < kTraceEventBufferSizeInBytes) {
+      const TraceBufferChunk* chunk = logged_events->NextChunk();
+      has_more_events = chunk != NULL;
+      if (!chunk)
+        break;
+      for (size_t j = 0; j < chunk->size(); ++j) {
+        if (json_events_str_ptr->size())
+          json_events_str_ptr->data().append(",\n");
+        chunk->GetEventAt(j)->AppendAsJSON(&(json_events_str_ptr->data()),
+                                           argument_filter_predicate);
+      }
+    }
+    flush_output_callback.Run(json_events_str_ptr, has_more_events);
+  } while (has_more_events);
+}
+
+void TraceLog::FinishFlush(int generation) {
+  scoped_ptr<TraceBuffer> previous_logged_events;
+  OutputCallback flush_output_callback;
+  TraceEvent::ArgumentFilterPredicate argument_filter_predicate;
+
+  if (!CheckGeneration(generation))
+    return;
+
+  {
+    AutoLock lock(lock_);
+
+    previous_logged_events.swap(logged_events_);
+    UseNextTraceBuffer();
+    thread_message_loops_.clear();
+
+    flush_task_runner_ = NULL;
+    flush_output_callback = flush_output_callback_;
+    flush_output_callback_.Reset();
+
+    if (trace_options() & kInternalEnableArgumentFilter) {
+      CHECK(!argument_filter_predicate_.is_null());
+      argument_filter_predicate = argument_filter_predicate_;
+    }
+  }
+
+  if (use_worker_thread_ &&
+      WorkerPool::PostTask(
+          FROM_HERE, Bind(&TraceLog::ConvertTraceEventsToTraceFormat,
+                          Passed(&previous_logged_events),
+                          flush_output_callback, argument_filter_predicate),
+          true)) {
+    return;
+  }
+
+  ConvertTraceEventsToTraceFormat(previous_logged_events.Pass(),
+                                  flush_output_callback,
+                                  argument_filter_predicate);
+}
+
+// Run in each thread holding a local event buffer.
+void TraceLog::FlushCurrentThread(int generation) {
+  {
+    AutoLock lock(lock_);
+    if (!CheckGeneration(generation) || !flush_task_runner_) {
+      // This is late. The corresponding flush has finished.
+      return;
+    }
+  }
+
+  // This will flush the thread local buffer.
+  delete thread_local_event_buffer_.Get();
+
+  AutoLock lock(lock_);
+  if (!CheckGeneration(generation) || !flush_task_runner_ ||
+      thread_message_loops_.size())
+    return;
+
+  flush_task_runner_->PostTask(
+      FROM_HERE, Bind(&TraceLog::FinishFlush, Unretained(this), generation));
+}
+
+void TraceLog::OnFlushTimeout(int generation) {
+  {
+    AutoLock lock(lock_);
+    if (!CheckGeneration(generation) || !flush_task_runner_) {
+      // Flush has finished before timeout.
+      return;
+    }
+
+    LOG(WARNING) <<
+        "The following threads haven't finished flush in time. "
+        "If this happens stably for some thread, please call "
+        "TraceLog::GetInstance()->SetCurrentThreadBlocksMessageLoop() from "
+        "the thread to avoid its trace events from being lost.";
+    for (hash_set<MessageLoop*>::const_iterator it =
+         thread_message_loops_.begin();
+         it != thread_message_loops_.end(); ++it) {
+      LOG(WARNING) << "Thread: " << (*it)->thread_name();
+    }
+  }
+  FinishFlush(generation);
+}
+
+void TraceLog::FlushButLeaveBufferIntact(
+    const TraceLog::OutputCallback& flush_output_callback) {
+  scoped_ptr<TraceBuffer> previous_logged_events;
+  TraceEvent::ArgumentFilterPredicate argument_filter_predicate;
+  {
+    AutoLock lock(lock_);
+    AddMetadataEventsWhileLocked();
+    if (thread_shared_chunk_) {
+      // Return the chunk to the main buffer to flush the sampling data.
+      logged_events_->ReturnChunk(thread_shared_chunk_index_,
+                                  thread_shared_chunk_.Pass());
+    }
+    previous_logged_events = logged_events_->CloneForIteration().Pass();
+
+    if (trace_options() & kInternalEnableArgumentFilter) {
+      CHECK(!argument_filter_predicate_.is_null());
+      argument_filter_predicate = argument_filter_predicate_;
+    }
+  }  // release lock
+
+  ConvertTraceEventsToTraceFormat(previous_logged_events.Pass(),
+                                  flush_output_callback,
+                                  argument_filter_predicate);
+}
+
+void TraceLog::UseNextTraceBuffer() {
+  logged_events_.reset(CreateTraceBuffer());
+  subtle::NoBarrier_AtomicIncrement(&generation_, 1);
+  thread_shared_chunk_.reset();
+  thread_shared_chunk_index_ = 0;
+}
+
+TraceEventHandle TraceLog::AddTraceEvent(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    unsigned long long id,
+    int num_args,
+    const char** arg_names,
+    const unsigned char* arg_types,
+    const unsigned long long* arg_values,
+    const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
+    unsigned char flags) {
+  int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
+  base::TraceTicks now = base::TraceTicks::Now();
+  return AddTraceEventWithThreadIdAndTimestamp(phase, category_group_enabled,
+                                               name, id, thread_id, now,
+                                               num_args, arg_names,
+                                               arg_types, arg_values,
+                                               convertable_values, flags);
+}
+
+TraceEventHandle TraceLog::AddTraceEventWithThreadIdAndTimestamp(
+    char phase,
+    const unsigned char* category_group_enabled,
+    const char* name,
+    unsigned long long id,
+    int thread_id,
+    const TraceTicks& timestamp,
+    int num_args,
+    const char** arg_names,
+    const unsigned char* arg_types,
+    const unsigned long long* arg_values,
+    const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
+    unsigned char flags) {
+  TraceEventHandle handle = { 0, 0, 0 };
+  if (!*category_group_enabled)
+    return handle;
+
+  // Avoid re-entrance of AddTraceEvent. This may happen in GPU process when
+  // ECHO_TO_CONSOLE is enabled: AddTraceEvent -> LOG(ERROR) ->
+  // GpuProcessLogMessageHandler -> PostPendingTask -> TRACE_EVENT ...
+  if (thread_is_in_trace_event_.Get())
+    return handle;
+
+  AutoThreadLocalBoolean thread_is_in_trace_event(&thread_is_in_trace_event_);
+
+  DCHECK(name);
+  DCHECK(!timestamp.is_null());
+
+  if (flags & TRACE_EVENT_FLAG_MANGLE_ID)
+    id = MangleEventId(id);
+
+  TraceTicks offset_event_timestamp = OffsetTimestamp(timestamp);
+  TraceTicks now = flags & TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP ?
+      OffsetNow() : offset_event_timestamp;
+  ThreadTicks thread_now = ThreadNow();
+
+  ThreadLocalEventBuffer* thread_local_event_buffer = NULL;
+  // A ThreadLocalEventBuffer needs the message loop
+  // - to know when the thread exits;
+  // - to handle the final flush.
+  // For a thread without a message loop or the message loop may be blocked, the
+  // trace events will be added into the main buffer directly.
+  if (!thread_blocks_message_loop_.Get() && MessageLoop::current()) {
+    thread_local_event_buffer = thread_local_event_buffer_.Get();
+    if (thread_local_event_buffer &&
+        !CheckGeneration(thread_local_event_buffer->generation())) {
+      delete thread_local_event_buffer;
+      thread_local_event_buffer = NULL;
+    }
+    if (!thread_local_event_buffer) {
+      thread_local_event_buffer = new ThreadLocalEventBuffer(this);
+      thread_local_event_buffer_.Set(thread_local_event_buffer);
+    }
+  }
+
+  // Check and update the current thread name only if the event is for the
+  // current thread to avoid locks in most cases.
+  if (thread_id == static_cast<int>(PlatformThread::CurrentId())) {
+    const char* new_name = ThreadIdNameManager::GetInstance()->
+        GetName(thread_id);
+    // Check if the thread name has been set or changed since the previous
+    // call (if any), but don't bother if the new name is empty. Note this will
+    // not detect a thread name change within the same char* buffer address: we
+    // favor common case performance over corner case correctness.
+    if (new_name != g_current_thread_name.Get().Get() &&
+        new_name && *new_name) {
+      g_current_thread_name.Get().Set(new_name);
+
+      AutoLock thread_info_lock(thread_info_lock_);
+
+      hash_map<int, std::string>::iterator existing_name =
+          thread_names_.find(thread_id);
+      if (existing_name == thread_names_.end()) {
+        // This is a new thread id, and a new name.
+        thread_names_[thread_id] = new_name;
+      } else {
+        // This is a thread id that we've seen before, but potentially with a
+        // new name.
+        std::vector<StringPiece> existing_names;
+        Tokenize(existing_name->second, ",", &existing_names);
+        bool found = std::find(existing_names.begin(),
+                               existing_names.end(),
+                               new_name) != existing_names.end();
+        if (!found) {
+          if (existing_names.size())
+            existing_name->second.push_back(',');
+          existing_name->second.append(new_name);
+        }
+      }
+    }
+  }
+
+#if defined(OS_WIN)
+  // This is done sooner rather than later, to avoid creating the event and
+  // acquiring the lock, which is not needed for ETW as it's already threadsafe.
+  if (*category_group_enabled & ENABLED_FOR_ETW_EXPORT)
+    TraceEventETWExport::AddEvent(phase, category_group_enabled, name, id,
+                                  num_args, arg_names, arg_types, arg_values,
+                                  convertable_values);
+#endif  // OS_WIN
+
+  std::string console_message;
+  if (*category_group_enabled &
+      (ENABLED_FOR_RECORDING | ENABLED_FOR_MONITORING)) {
+    OptionalAutoLock lock(&lock_);
+
+    TraceEvent* trace_event = NULL;
+    if (thread_local_event_buffer) {
+      trace_event = thread_local_event_buffer->AddTraceEvent(&handle);
+    } else {
+      lock.EnsureAcquired();
+      trace_event = AddEventToThreadSharedChunkWhileLocked(&handle, true);
+    }
+
+    if (trace_event) {
+      trace_event->Initialize(thread_id, offset_event_timestamp, thread_now,
+                              phase, category_group_enabled, name, id,
+                              num_args, arg_names, arg_types, arg_values,
+                              convertable_values, flags);
+
+#if defined(OS_ANDROID)
+      trace_event->SendToATrace();
+#endif
+    }
+
+    if (trace_options() & kInternalEchoToConsole) {
+      console_message = EventToConsoleMessage(
+          phase == TRACE_EVENT_PHASE_COMPLETE ? TRACE_EVENT_PHASE_BEGIN : phase,
+          timestamp, trace_event);
+    }
+  }
+
+  if (console_message.size())
+    LOG(ERROR) << console_message;
+
+  if (reinterpret_cast<const unsigned char*>(subtle::NoBarrier_Load(
+      &watch_category_)) == category_group_enabled) {
+    bool event_name_matches;
+    WatchEventCallback watch_event_callback_copy;
+    {
+      AutoLock lock(lock_);
+      event_name_matches = watch_event_name_ == name;
+      watch_event_callback_copy = watch_event_callback_;
+    }
+    if (event_name_matches) {
+      if (!watch_event_callback_copy.is_null())
+        watch_event_callback_copy.Run();
+    }
+  }
+
+  if (*category_group_enabled & ENABLED_FOR_EVENT_CALLBACK) {
+    EventCallback event_callback = reinterpret_cast<EventCallback>(
+        subtle::NoBarrier_Load(&event_callback_));
+    if (event_callback) {
+      event_callback(offset_event_timestamp,
+                     phase == TRACE_EVENT_PHASE_COMPLETE ?
+                         TRACE_EVENT_PHASE_BEGIN : phase,
+                     category_group_enabled, name, id,
+                     num_args, arg_names, arg_types, arg_values,
+                     flags);
+    }
+  }
+
+  if (thread_local_event_buffer)
+    thread_local_event_buffer->ReportOverhead(now, thread_now);
+
+  return handle;
+}
+
+// May be called when a COMPELETE event ends and the unfinished event has been
+// recycled (phase == TRACE_EVENT_PHASE_END and trace_event == NULL).
+std::string TraceLog::EventToConsoleMessage(unsigned char phase,
+                                            const TraceTicks& timestamp,
+                                            TraceEvent* trace_event) {
+  AutoLock thread_info_lock(thread_info_lock_);
+
+  // The caller should translate TRACE_EVENT_PHASE_COMPLETE to
+  // TRACE_EVENT_PHASE_BEGIN or TRACE_EVENT_END.
+  DCHECK(phase != TRACE_EVENT_PHASE_COMPLETE);
+
+  TimeDelta duration;
+  int thread_id = trace_event ?
+      trace_event->thread_id() : PlatformThread::CurrentId();
+  if (phase == TRACE_EVENT_PHASE_END) {
+    duration = timestamp - thread_event_start_times_[thread_id].top();
+    thread_event_start_times_[thread_id].pop();
+  }
+
+  std::string thread_name = thread_names_[thread_id];
+  if (thread_colors_.find(thread_name) == thread_colors_.end())
+    thread_colors_[thread_name] = (thread_colors_.size() % 6) + 1;
+
+  std::ostringstream log;
+  log << base::StringPrintf("%s: \x1b[0;3%dm",
+                            thread_name.c_str(),
+                            thread_colors_[thread_name]);
+
+  size_t depth = 0;
+  if (thread_event_start_times_.find(thread_id) !=
+      thread_event_start_times_.end())
+    depth = thread_event_start_times_[thread_id].size();
+
+  for (size_t i = 0; i < depth; ++i)
+    log << "| ";
+
+  if (trace_event)
+    trace_event->AppendPrettyPrinted(&log);
+  if (phase == TRACE_EVENT_PHASE_END)
+    log << base::StringPrintf(" (%.3f ms)", duration.InMillisecondsF());
+
+  log << "\x1b[0;m";
+
+  if (phase == TRACE_EVENT_PHASE_BEGIN)
+    thread_event_start_times_[thread_id].push(timestamp);
+
+  return log.str();
+}
+
+void TraceLog::AddTraceEventEtw(char phase,
+                                const char* name,
+                                const void* id,
+                                const char* extra) {
+#if defined(OS_WIN)
+  TraceEventETWProvider::Trace(name, phase, id, extra);
+#endif
+  INTERNAL_TRACE_EVENT_ADD(phase, "ETW Trace Event", name,
+                           TRACE_EVENT_FLAG_COPY, "id", id, "extra", extra);
+}
+
+void TraceLog::AddTraceEventEtw(char phase,
+                                const char* name,
+                                const void* id,
+                                const std::string& extra) {
+#if defined(OS_WIN)
+  TraceEventETWProvider::Trace(name, phase, id, extra);
+#endif
+  INTERNAL_TRACE_EVENT_ADD(phase, "ETW Trace Event", name,
+                           TRACE_EVENT_FLAG_COPY, "id", id, "extra", extra);
+}
+
+void TraceLog::UpdateTraceEventDuration(
+    const unsigned char* category_group_enabled,
+    const char* name,
+    TraceEventHandle handle) {
+  // Avoid re-entrance of AddTraceEvent. This may happen in GPU process when
+  // ECHO_TO_CONSOLE is enabled: AddTraceEvent -> LOG(ERROR) ->
+  // GpuProcessLogMessageHandler -> PostPendingTask -> TRACE_EVENT ...
+  if (thread_is_in_trace_event_.Get())
+    return;
+
+  AutoThreadLocalBoolean thread_is_in_trace_event(&thread_is_in_trace_event_);
+
+  ThreadTicks thread_now = ThreadNow();
+  TraceTicks now = OffsetNow();
+
+  std::string console_message;
+  if (*category_group_enabled & ENABLED_FOR_RECORDING) {
+    OptionalAutoLock lock(&lock_);
+
+    TraceEvent* trace_event = GetEventByHandleInternal(handle, &lock);
+    if (trace_event) {
+      DCHECK(trace_event->phase() == TRACE_EVENT_PHASE_COMPLETE);
+      trace_event->UpdateDuration(now, thread_now);
+#if defined(OS_ANDROID)
+      trace_event->SendToATrace();
+#endif
+    }
+
+    if (trace_options() & kInternalEchoToConsole) {
+      console_message = EventToConsoleMessage(TRACE_EVENT_PHASE_END,
+                                              now, trace_event);
+    }
+  }
+
+  if (console_message.size())
+    LOG(ERROR) << console_message;
+
+  if (*category_group_enabled & ENABLED_FOR_EVENT_CALLBACK) {
+    EventCallback event_callback = reinterpret_cast<EventCallback>(
+        subtle::NoBarrier_Load(&event_callback_));
+    if (event_callback) {
+      event_callback(now, TRACE_EVENT_PHASE_END, category_group_enabled, name,
+                     trace_event_internal::kNoEventId, 0, NULL, NULL, NULL,
+                     TRACE_EVENT_FLAG_NONE);
+    }
+  }
+}
+
+void TraceLog::SetWatchEvent(const std::string& category_name,
+                             const std::string& event_name,
+                             const WatchEventCallback& callback) {
+  const unsigned char* category = GetCategoryGroupEnabled(
+      category_name.c_str());
+  AutoLock lock(lock_);
+  subtle::NoBarrier_Store(&watch_category_,
+                          reinterpret_cast<subtle::AtomicWord>(category));
+  watch_event_name_ = event_name;
+  watch_event_callback_ = callback;
+}
+
+void TraceLog::CancelWatchEvent() {
+  AutoLock lock(lock_);
+  subtle::NoBarrier_Store(&watch_category_, 0);
+  watch_event_name_ = "";
+  watch_event_callback_.Reset();
+}
+
+uint64 TraceLog::MangleEventId(uint64 id) {
+  return id ^ process_id_hash_;
+}
+
+void TraceLog::AddMetadataEventsWhileLocked() {
+  lock_.AssertAcquired();
+
+#if !defined(OS_NACL)  // NaCl shouldn't expose the process id.
+  InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
+                          0,
+                          "num_cpus", "number",
+                          base::SysInfo::NumberOfProcessors());
+#endif
+
+
+  int current_thread_id = static_cast<int>(base::PlatformThread::CurrentId());
+  if (process_sort_index_ != 0) {
+    InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
+                            current_thread_id,
+                            "process_sort_index", "sort_index",
+                            process_sort_index_);
+  }
+
+  if (process_name_.size()) {
+    InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
+                            current_thread_id,
+                            "process_name", "name",
+                            process_name_);
+  }
+
+  if (process_labels_.size() > 0) {
+    std::vector<std::string> labels;
+    for(base::hash_map<int, std::string>::iterator it = process_labels_.begin();
+        it != process_labels_.end();
+        it++) {
+      labels.push_back(it->second);
+    }
+    InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
+                            current_thread_id,
+                            "process_labels", "labels",
+                            JoinString(labels, ','));
+  }
+
+  // Thread sort indices.
+  for(hash_map<int, int>::iterator it = thread_sort_indices_.begin();
+      it != thread_sort_indices_.end();
+      it++) {
+    if (it->second == 0)
+      continue;
+    InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
+                            it->first,
+                            "thread_sort_index", "sort_index",
+                            it->second);
+  }
+
+  // Thread names.
+  AutoLock thread_info_lock(thread_info_lock_);
+  for(hash_map<int, std::string>::iterator it = thread_names_.begin();
+      it != thread_names_.end();
+      it++) {
+    if (it->second.empty())
+      continue;
+    InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
+                            it->first,
+                            "thread_name", "name",
+                            it->second);
+  }
+
+  // If buffer is full, add a metadata record to report this.
+  if (!buffer_limit_reached_timestamp_.is_null()) {
+    InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
+                            current_thread_id,
+                            "trace_buffer_overflowed",
+                            "overflowed_at_ts",
+                            buffer_limit_reached_timestamp_);
+  }
+}
+
+void TraceLog::WaitSamplingEventForTesting() {
+  if (!sampling_thread_)
+    return;
+  sampling_thread_->WaitSamplingEventForTesting();
+}
+
+void TraceLog::DeleteForTesting() {
+  DeleteTraceLogForTesting::Delete();
+}
+
+TraceEvent* TraceLog::GetEventByHandle(TraceEventHandle handle) {
+  return GetEventByHandleInternal(handle, NULL);
+}
+
+TraceEvent* TraceLog::GetEventByHandleInternal(TraceEventHandle handle,
+                                               OptionalAutoLock* lock) {
+  if (!handle.chunk_seq)
+    return NULL;
+
+  if (thread_local_event_buffer_.Get()) {
+    TraceEvent* trace_event =
+        thread_local_event_buffer_.Get()->GetEventByHandle(handle);
+    if (trace_event)
+      return trace_event;
+  }
+
+  // The event has been out-of-control of the thread local buffer.
+  // Try to get the event from the main buffer with a lock.
+  if (lock)
+    lock->EnsureAcquired();
+
+  if (thread_shared_chunk_ &&
+      handle.chunk_index == thread_shared_chunk_index_) {
+    return handle.chunk_seq == thread_shared_chunk_->seq() ?
+        thread_shared_chunk_->GetEventAt(handle.event_index) : NULL;
+  }
+
+  return logged_events_->GetEventByHandle(handle);
+}
+
+void TraceLog::SetProcessID(int process_id) {
+  process_id_ = process_id;
+  // Create a FNV hash from the process ID for XORing.
+  // See http://isthe.com/chongo/tech/comp/fnv/ for algorithm details.
+  unsigned long long offset_basis = 14695981039346656037ull;
+  unsigned long long fnv_prime = 1099511628211ull;
+  unsigned long long pid = static_cast<unsigned long long>(process_id_);
+  process_id_hash_ = (offset_basis ^ pid) * fnv_prime;
+}
+
+void TraceLog::SetProcessSortIndex(int sort_index) {
+  AutoLock lock(lock_);
+  process_sort_index_ = sort_index;
+}
+
+void TraceLog::SetProcessName(const std::string& process_name) {
+  AutoLock lock(lock_);
+  process_name_ = process_name;
+}
+
+void TraceLog::UpdateProcessLabel(
+    int label_id, const std::string& current_label) {
+  if(!current_label.length())
+    return RemoveProcessLabel(label_id);
+
+  AutoLock lock(lock_);
+  process_labels_[label_id] = current_label;
+}
+
+void TraceLog::RemoveProcessLabel(int label_id) {
+  AutoLock lock(lock_);
+  base::hash_map<int, std::string>::iterator it = process_labels_.find(
+      label_id);
+  if (it == process_labels_.end())
+    return;
+
+  process_labels_.erase(it);
+}
+
+void TraceLog::SetThreadSortIndex(PlatformThreadId thread_id, int sort_index) {
+  AutoLock lock(lock_);
+  thread_sort_indices_[static_cast<int>(thread_id)] = sort_index;
+}
+
+void TraceLog::SetTimeOffset(TimeDelta offset) {
+  time_offset_ = offset;
+}
+
+size_t TraceLog::GetObserverCountForTest() const {
+  return enabled_state_observer_list_.size();
+}
+
+void TraceLog::SetCurrentThreadBlocksMessageLoop() {
+  thread_blocks_message_loop_.Set(true);
+  if (thread_local_event_buffer_.Get()) {
+    // This will flush the thread local buffer.
+    delete thread_local_event_buffer_.Get();
+  }
+}
+
+void ConvertableToTraceFormat::EstimateTraceMemoryOverhead(
+    TraceEventMemoryOverhead* overhead) {
+  overhead->Add("ConvertableToTraceFormat(Unknown)", sizeof(*this));
+}
+
+}  // namespace trace_event
+}  // namespace base
+
+namespace trace_event_internal {
+
+ScopedTraceBinaryEfficient::ScopedTraceBinaryEfficient(
+    const char* category_group, const char* name) {
+  // The single atom works because for now the category_group can only be "gpu".
+  DCHECK_EQ(strcmp(category_group, "gpu"), 0);
+  static TRACE_EVENT_API_ATOMIC_WORD atomic = 0;
+  INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO_CUSTOM_VARIABLES(
+      category_group, atomic, category_group_enabled_);
+  name_ = name;
+  if (*category_group_enabled_) {
+    event_handle_ =
+        TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
+            TRACE_EVENT_PHASE_COMPLETE, category_group_enabled_, name,
+            trace_event_internal::kNoEventId,
+            static_cast<int>(base::PlatformThread::CurrentId()),
+            base::TraceTicks::Now(), 0, NULL, NULL, NULL, NULL,
+            TRACE_EVENT_FLAG_NONE);
+  }
+}
+
+ScopedTraceBinaryEfficient::~ScopedTraceBinaryEfficient() {
+  if (*category_group_enabled_) {
+    TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(category_group_enabled_,
+                                                name_, event_handle_);
+  }
+}
+
+}  // namespace trace_event_internal
diff --git a/base/trace_event/trace_event_impl.h b/base/trace_event/trace_event_impl.h
new file mode 100644
index 0000000..503a69d
--- /dev/null
+++ b/base/trace_event/trace_event_impl.h
@@ -0,0 +1,704 @@
+// Copyright (c) 2012 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_TRACE_EVENT_IMPL_H_
+#define BASE_TRACE_EVENT_TRACE_EVENT_IMPL_H_
+
+#include <stack>
+#include <string>
+#include <vector>
+
+#include "base/atomicops.h"
+#include "base/base_export.h"
+#include "base/callback.h"
+#include "base/containers/hash_tables.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_vector.h"
+#include "base/observer_list.h"
+#include "base/single_thread_task_runner.h"
+#include "base/strings/string_util.h"
+#include "base/synchronization/condition_variable.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/thread.h"
+#include "base/threading/thread_local.h"
+#include "base/trace_event/memory_dump_provider.h"
+#include "base/trace_event/trace_config.h"
+#include "base/trace_event/trace_event_memory_overhead.h"
+
+// Older style trace macros with explicit id and extra data
+// Only these macros result in publishing data to ETW as currently implemented.
+// TODO(georgesak): Update/replace these with new ETW macros.
+#define TRACE_EVENT_BEGIN_ETW(name, id, extra) \
+    base::trace_event::TraceLog::AddTraceEventEtw( \
+        TRACE_EVENT_PHASE_BEGIN, \
+        name, reinterpret_cast<const void*>(id), extra)
+
+#define TRACE_EVENT_END_ETW(name, id, extra) \
+    base::trace_event::TraceLog::AddTraceEventEtw( \
+        TRACE_EVENT_PHASE_END, \
+        name, reinterpret_cast<const void*>(id), extra)
+
+#define TRACE_EVENT_INSTANT_ETW(name, id, extra) \
+    base::trace_event::TraceLog::AddTraceEventEtw( \
+        TRACE_EVENT_PHASE_INSTANT, \
+        name, reinterpret_cast<const void*>(id), extra)
+
+template <typename Type>
+struct DefaultSingletonTraits;
+
+namespace base {
+
+class WaitableEvent;
+class MessageLoop;
+
+namespace trace_event {
+
+// For any argument of type TRACE_VALUE_TYPE_CONVERTABLE the provided
+// class must implement this interface.
+class BASE_EXPORT ConvertableToTraceFormat
+    : public RefCounted<ConvertableToTraceFormat> {
+ public:
+  // Append the class info to the provided |out| string. The appended
+  // data must be a valid JSON object. Strings must be properly quoted, and
+  // escaped. There is no processing applied to the content after it is
+  // appended.
+  virtual void AppendAsTraceFormat(std::string* out) const = 0;
+
+  virtual void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead);
+
+  std::string ToString() const {
+    std::string result;
+    AppendAsTraceFormat(&result);
+    return result;
+  }
+
+ protected:
+  virtual ~ConvertableToTraceFormat() {}
+
+ private:
+  friend class RefCounted<ConvertableToTraceFormat>;
+};
+
+struct TraceEventHandle {
+  uint32 chunk_seq;
+  uint16 chunk_index;
+  uint16 event_index;
+};
+
+const int kTraceMaxNumArgs = 2;
+
+class BASE_EXPORT TraceEvent {
+ public:
+  union TraceValue {
+    bool as_bool;
+    unsigned long long as_uint;
+    long long as_int;
+    double as_double;
+    const void* as_pointer;
+    const char* as_string;
+  };
+
+  TraceEvent();
+  ~TraceEvent();
+
+  // We don't need to copy TraceEvent except when TraceEventBuffer is cloned.
+  // Use explicit copy method to avoid accidentally misuse of copy.
+  void CopyFrom(const TraceEvent& other);
+
+  void Initialize(
+      int thread_id,
+      TraceTicks timestamp,
+      ThreadTicks thread_timestamp,
+      char phase,
+      const unsigned char* category_group_enabled,
+      const char* name,
+      unsigned long long id,
+      int num_args,
+      const char** arg_names,
+      const unsigned char* arg_types,
+      const unsigned long long* arg_values,
+      const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
+      unsigned char flags);
+
+  void Reset();
+
+  void UpdateDuration(const TraceTicks& now, const ThreadTicks& thread_now);
+
+  void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead*);
+
+  // Serialize event data to JSON
+  typedef base::Callback<bool(const char* category_group_name,
+                              const char* event_name)> ArgumentFilterPredicate;
+  void AppendAsJSON(
+      std::string* out,
+      const ArgumentFilterPredicate& argument_filter_predicate) const;
+  void AppendPrettyPrinted(std::ostringstream* out) const;
+
+  static void AppendValueAsJSON(unsigned char type,
+                                TraceValue value,
+                                std::string* out);
+
+  TraceTicks timestamp() const { return timestamp_; }
+  ThreadTicks thread_timestamp() const { return thread_timestamp_; }
+  char phase() const { return phase_; }
+  int thread_id() const { return thread_id_; }
+  TimeDelta duration() const { return duration_; }
+  TimeDelta thread_duration() const { return thread_duration_; }
+  unsigned long long id() const { return id_; }
+  unsigned char flags() const { return flags_; }
+
+  // Exposed for unittesting:
+
+  const base::RefCountedString* parameter_copy_storage() const {
+    return parameter_copy_storage_.get();
+  }
+
+  const unsigned char* category_group_enabled() const {
+    return category_group_enabled_;
+  }
+
+  const char* name() const { return name_; }
+
+#if defined(OS_ANDROID)
+  void SendToATrace();
+#endif
+
+ private:
+  // Note: these are ordered by size (largest first) for optimal packing.
+  TraceTicks timestamp_;
+  ThreadTicks thread_timestamp_;
+  TimeDelta duration_;
+  TimeDelta thread_duration_;
+  // id_ can be used to store phase-specific data.
+  unsigned long long id_;
+  scoped_ptr<TraceEventMemoryOverhead> cached_memory_overhead_estimate_;
+  TraceValue arg_values_[kTraceMaxNumArgs];
+  const char* arg_names_[kTraceMaxNumArgs];
+  scoped_refptr<ConvertableToTraceFormat> convertable_values_[kTraceMaxNumArgs];
+  const unsigned char* category_group_enabled_;
+  const char* name_;
+  scoped_refptr<base::RefCountedString> parameter_copy_storage_;
+  int thread_id_;
+  char phase_;
+  unsigned char flags_;
+  unsigned char arg_types_[kTraceMaxNumArgs];
+
+  DISALLOW_COPY_AND_ASSIGN(TraceEvent);
+};
+
+// TraceBufferChunk is the basic unit of TraceBuffer.
+class BASE_EXPORT TraceBufferChunk {
+ public:
+  explicit TraceBufferChunk(uint32 seq);
+  ~TraceBufferChunk();
+
+  void Reset(uint32 new_seq);
+  TraceEvent* AddTraceEvent(size_t* event_index);
+  bool IsFull() const { return next_free_ == kTraceBufferChunkSize; }
+
+  uint32 seq() const { return seq_; }
+  size_t capacity() const { return kTraceBufferChunkSize; }
+  size_t size() const { return next_free_; }
+
+  TraceEvent* GetEventAt(size_t index) {
+    DCHECK(index < size());
+    return &chunk_[index];
+  }
+  const TraceEvent* GetEventAt(size_t index) const {
+    DCHECK(index < size());
+    return &chunk_[index];
+  }
+
+  scoped_ptr<TraceBufferChunk> Clone() const;
+
+  void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead);
+
+  static const size_t kTraceBufferChunkSize = 64;
+
+ private:
+  size_t next_free_;
+  scoped_ptr<TraceEventMemoryOverhead> cached_overhead_estimate_when_full_;
+  TraceEvent chunk_[kTraceBufferChunkSize];
+  uint32 seq_;
+};
+
+// TraceBuffer holds the events as they are collected.
+class BASE_EXPORT TraceBuffer {
+ public:
+  virtual ~TraceBuffer() {}
+
+  virtual scoped_ptr<TraceBufferChunk> GetChunk(size_t *index) = 0;
+  virtual void ReturnChunk(size_t index,
+                           scoped_ptr<TraceBufferChunk> chunk) = 0;
+
+  virtual bool IsFull() const = 0;
+  virtual size_t Size() const = 0;
+  virtual size_t Capacity() const = 0;
+  virtual TraceEvent* GetEventByHandle(TraceEventHandle handle) = 0;
+
+  // For iteration. Each TraceBuffer can only be iterated once.
+  virtual const TraceBufferChunk* NextChunk() = 0;
+
+  virtual scoped_ptr<TraceBuffer> CloneForIteration() const = 0;
+
+  // Computes an estimate of the size of the buffer, including all the retained
+  // objects.
+  virtual void EstimateTraceMemoryOverhead(
+      TraceEventMemoryOverhead* overhead) = 0;
+};
+
+// TraceResultBuffer collects and converts trace fragments returned by TraceLog
+// to JSON output.
+class BASE_EXPORT TraceResultBuffer {
+ public:
+  typedef base::Callback<void(const std::string&)> OutputCallback;
+
+  // If you don't need to stream JSON chunks out efficiently, and just want to
+  // get a complete JSON string after calling Finish, use this struct to collect
+  // JSON trace output.
+  struct BASE_EXPORT SimpleOutput {
+    OutputCallback GetCallback();
+    void Append(const std::string& json_string);
+
+    // Do what you want with the json_output_ string after calling
+    // TraceResultBuffer::Finish.
+    std::string json_output;
+  };
+
+  TraceResultBuffer();
+  ~TraceResultBuffer();
+
+  // Set callback. The callback will be called during Start with the initial
+  // JSON output and during AddFragment and Finish with following JSON output
+  // chunks. The callback target must live past the last calls to
+  // TraceResultBuffer::Start/AddFragment/Finish.
+  void SetOutputCallback(const OutputCallback& json_chunk_callback);
+
+  // Start JSON output. This resets all internal state, so you can reuse
+  // the TraceResultBuffer by calling Start.
+  void Start();
+
+  // Call AddFragment 0 or more times to add trace fragments from TraceLog.
+  void AddFragment(const std::string& trace_fragment);
+
+  // When all fragments have been added, call Finish to complete the JSON
+  // formatted output.
+  void Finish();
+
+ private:
+  OutputCallback output_callback_;
+  bool append_comma_;
+};
+
+class TraceSamplingThread;
+
+struct BASE_EXPORT TraceLogStatus {
+  TraceLogStatus();
+  ~TraceLogStatus();
+  size_t event_capacity;
+  size_t event_count;
+};
+
+class BASE_EXPORT TraceLog : public MemoryDumpProvider {
+ public:
+  enum Mode {
+    DISABLED = 0,
+    RECORDING_MODE,
+    MONITORING_MODE,
+  };
+
+  // The pointer returned from GetCategoryGroupEnabledInternal() points to a
+  // value with zero or more of the following bits. Used in this class only.
+  // The TRACE_EVENT macros should only use the value as a bool.
+  // These values must be in sync with macro values in TraceEvent.h in Blink.
+  enum CategoryGroupEnabledFlags {
+    // Category group enabled for the recording mode.
+    ENABLED_FOR_RECORDING = 1 << 0,
+    // Category group enabled for the monitoring mode.
+    ENABLED_FOR_MONITORING = 1 << 1,
+    // Category group enabled by SetEventCallbackEnabled().
+    ENABLED_FOR_EVENT_CALLBACK = 1 << 2,
+    // Category group enabled to export events to ETW.
+    ENABLED_FOR_ETW_EXPORT = 1 << 3
+  };
+
+  static TraceLog* GetInstance();
+
+  // Get set of known category groups. This can change as new code paths are
+  // reached. The known category groups are inserted into |category_groups|.
+  void GetKnownCategoryGroups(std::vector<std::string>* category_groups);
+
+  // Retrieves a copy (for thread-safety) of the current TraceConfig.
+  TraceConfig GetCurrentTraceConfig() const;
+
+  // Enables normal tracing (recording trace events in the trace buffer).
+  // See TraceConfig comments for details on how to control what categories
+  // will be traced. If tracing has already been enabled, |category_filter| will
+  // be merged into the current category filter.
+  void SetEnabled(const TraceConfig& trace_config, Mode mode);
+
+  // Disables normal tracing for all categories.
+  void SetDisabled();
+
+  bool IsEnabled() { return mode_ != DISABLED; }
+
+  // The number of times we have begun recording traces. If tracing is off,
+  // returns -1. If tracing is on, then it returns the number of times we have
+  // recorded a trace. By watching for this number to increment, you can
+  // passively discover when a new trace has begun. This is then used to
+  // implement the TRACE_EVENT_IS_NEW_TRACE() primitive.
+  int GetNumTracesRecorded();
+
+#if defined(OS_ANDROID)
+  void StartATrace();
+  void StopATrace();
+  void AddClockSyncMetadataEvent();
+#endif
+
+  // Enabled state listeners give a callback when tracing is enabled or
+  // disabled. This can be used to tie into other library's tracing systems
+  // on-demand.
+  class BASE_EXPORT EnabledStateObserver {
+   public:
+    // Called just after the tracing system becomes enabled, outside of the
+    // |lock_|. TraceLog::IsEnabled() is true at this point.
+    virtual void OnTraceLogEnabled() = 0;
+
+    // Called just after the tracing system disables, outside of the |lock_|.
+    // TraceLog::IsEnabled() is false at this point.
+    virtual void OnTraceLogDisabled() = 0;
+  };
+  void AddEnabledStateObserver(EnabledStateObserver* listener);
+  void RemoveEnabledStateObserver(EnabledStateObserver* listener);
+  bool HasEnabledStateObserver(EnabledStateObserver* listener) const;
+
+  TraceLogStatus GetStatus() const;
+  bool BufferIsFull() const;
+
+  // Computes an estimate of the size of the TraceLog including all the retained
+  // objects.
+  void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead);
+
+  // Not using base::Callback because of its limited by 7 parameters.
+  // Also, using primitive type allows directly passing callback from WebCore.
+  // WARNING: It is possible for the previously set callback to be called
+  // after a call to SetEventCallbackEnabled() that replaces or a call to
+  // SetEventCallbackDisabled() that disables the callback.
+  // This callback may be invoked on any thread.
+  // For TRACE_EVENT_PHASE_COMPLETE events, the client will still receive pairs
+  // of TRACE_EVENT_PHASE_BEGIN and TRACE_EVENT_PHASE_END events to keep the
+  // interface simple.
+  typedef void (*EventCallback)(TraceTicks timestamp,
+                                char phase,
+                                const unsigned char* category_group_enabled,
+                                const char* name,
+                                unsigned long long id,
+                                int num_args,
+                                const char* const arg_names[],
+                                const unsigned char arg_types[],
+                                const unsigned long long arg_values[],
+                                unsigned char flags);
+
+  // Enable tracing for EventCallback.
+  void SetEventCallbackEnabled(const TraceConfig& trace_config,
+                               EventCallback cb);
+  void SetEventCallbackDisabled();
+  void SetArgumentFilterPredicate(
+      const TraceEvent::ArgumentFilterPredicate& argument_filter_predicate);
+
+  // Flush all collected events to the given output callback. The callback will
+  // be called one or more times either synchronously or asynchronously from
+  // the current thread with IPC-bite-size chunks. The string format is
+  // undefined. Use TraceResultBuffer to convert one or more trace strings to
+  // JSON. The callback can be null if the caller doesn't want any data.
+  // Due to the implementation of thread-local buffers, flush can't be
+  // done when tracing is enabled. If called when tracing is enabled, the
+  // callback will be called directly with (empty_string, false) to indicate
+  // the end of this unsuccessful flush. Flush does the serialization
+  // on the same thread if the caller doesn't set use_worker_thread explicitly.
+  typedef base::Callback<void(const scoped_refptr<base::RefCountedString>&,
+                              bool has_more_events)> OutputCallback;
+  void Flush(const OutputCallback& cb, bool use_worker_thread = false);
+  void FlushButLeaveBufferIntact(const OutputCallback& flush_output_callback);
+
+  // Called by TRACE_EVENT* macros, don't call this directly.
+  // The name parameter is a category group for example:
+  // TRACE_EVENT0("renderer,webkit", "WebViewImpl::HandleInputEvent")
+  static const unsigned char* GetCategoryGroupEnabled(const char* name);
+  static const char* GetCategoryGroupName(
+      const unsigned char* category_group_enabled);
+
+  // Called by TRACE_EVENT* macros, don't call this directly.
+  // If |copy| is set, |name|, |arg_name1| and |arg_name2| will be deep copied
+  // into the event; see "Memory scoping note" and TRACE_EVENT_COPY_XXX above.
+  TraceEventHandle AddTraceEvent(
+      char phase,
+      const unsigned char* category_group_enabled,
+      const char* name,
+      unsigned long long id,
+      int num_args,
+      const char** arg_names,
+      const unsigned char* arg_types,
+      const unsigned long long* arg_values,
+      const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
+      unsigned char flags);
+  TraceEventHandle AddTraceEventWithThreadIdAndTimestamp(
+      char phase,
+      const unsigned char* category_group_enabled,
+      const char* name,
+      unsigned long long id,
+      int thread_id,
+      const TraceTicks& timestamp,
+      int num_args,
+      const char** arg_names,
+      const unsigned char* arg_types,
+      const unsigned long long* arg_values,
+      const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
+      unsigned char flags);
+  static void AddTraceEventEtw(char phase,
+                               const char* category_group,
+                               const void* id,
+                               const char* extra);
+  static void AddTraceEventEtw(char phase,
+                               const char* category_group,
+                               const void* id,
+                               const std::string& extra);
+
+  void UpdateTraceEventDuration(const unsigned char* category_group_enabled,
+                                const char* name,
+                                TraceEventHandle handle);
+
+  // For every matching event, the callback will be called.
+  typedef base::Callback<void()> WatchEventCallback;
+  void SetWatchEvent(const std::string& category_name,
+                     const std::string& event_name,
+                     const WatchEventCallback& callback);
+  // Cancel the watch event. If tracing is enabled, this may race with the
+  // watch event notification firing.
+  void CancelWatchEvent();
+
+  int process_id() const { return process_id_; }
+
+  uint64 MangleEventId(uint64 id);
+
+  // Exposed for unittesting:
+
+  void WaitSamplingEventForTesting();
+
+  // Allows deleting our singleton instance.
+  static void DeleteForTesting();
+
+  // Allow tests to inspect TraceEvents.
+  TraceEvent* GetEventByHandle(TraceEventHandle handle);
+
+  void SetProcessID(int process_id);
+
+  // Process sort indices, if set, override the order of a process will appear
+  // relative to other processes in the trace viewer. Processes are sorted first
+  // on their sort index, ascending, then by their name, and then tid.
+  void SetProcessSortIndex(int sort_index);
+
+  // Sets the name of the process.
+  void SetProcessName(const std::string& process_name);
+
+  // Processes can have labels in addition to their names. Use labels, for
+  // instance, to list out the web page titles that a process is handling.
+  void UpdateProcessLabel(int label_id, const std::string& current_label);
+  void RemoveProcessLabel(int label_id);
+
+  // Thread sort indices, if set, override the order of a thread will appear
+  // within its process in the trace viewer. Threads are sorted first on their
+  // sort index, ascending, then by their name, and then tid.
+  void SetThreadSortIndex(PlatformThreadId , int sort_index);
+
+  // Allow setting an offset between the current TraceTicks time and the time
+  // that should be reported.
+  void SetTimeOffset(TimeDelta offset);
+
+  size_t GetObserverCountForTest() const;
+
+  // Call this method if the current thread may block the message loop to
+  // prevent the thread from using the thread-local buffer because the thread
+  // may not handle the flush request in time causing lost of unflushed events.
+  void SetCurrentThreadBlocksMessageLoop();
+
+ private:
+  typedef unsigned int InternalTraceOptions;
+
+  FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture,
+                           TraceBufferRingBufferGetReturnChunk);
+  FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture,
+                           TraceBufferRingBufferHalfIteration);
+  FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture,
+                           TraceBufferRingBufferFullIteration);
+  FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture,
+                           TraceBufferVectorReportFull);
+  FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture,
+                           ConvertTraceConfigToInternalOptions);
+  FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture,
+                           TraceRecordAsMuchAsPossibleMode);
+
+  // This allows constructor and destructor to be private and usable only
+  // by the Singleton class.
+  friend struct DefaultSingletonTraits<TraceLog>;
+
+  // MemoryDumpProvider implementation.
+  bool OnMemoryDump(ProcessMemoryDump* pmd) override;
+
+  // Enable/disable each category group based on the current mode_,
+  // category_filter_, event_callback_ and event_callback_category_filter_.
+  // Enable the category group in the enabled mode if category_filter_ matches
+  // the category group, or event_callback_ is not null and
+  // event_callback_category_filter_ matches the category group.
+  void UpdateCategoryGroupEnabledFlags();
+  void UpdateCategoryGroupEnabledFlag(size_t category_index);
+
+  // Configure synthetic delays based on the values set in the current
+  // trace config.
+  void UpdateSyntheticDelaysFromTraceConfig();
+
+  InternalTraceOptions GetInternalOptionsFromTraceConfig(
+      const TraceConfig& config);
+
+  class ThreadLocalEventBuffer;
+  class OptionalAutoLock;
+
+  TraceLog();
+  ~TraceLog() override;
+  const unsigned char* GetCategoryGroupEnabledInternal(const char* name);
+  void AddMetadataEventsWhileLocked();
+
+  InternalTraceOptions trace_options() const {
+    return static_cast<InternalTraceOptions>(
+        subtle::NoBarrier_Load(&trace_options_));
+  }
+
+  TraceBuffer* trace_buffer() const { return logged_events_.get(); }
+  TraceBuffer* CreateTraceBuffer();
+  TraceBuffer* CreateTraceBufferVectorOfSize(size_t max_chunks);
+
+  std::string EventToConsoleMessage(unsigned char phase,
+                                    const TraceTicks& timestamp,
+                                    TraceEvent* trace_event);
+
+  TraceEvent* AddEventToThreadSharedChunkWhileLocked(TraceEventHandle* handle,
+                                                     bool check_buffer_is_full);
+  void CheckIfBufferIsFullWhileLocked();
+  void SetDisabledWhileLocked();
+
+  TraceEvent* GetEventByHandleInternal(TraceEventHandle handle,
+                                       OptionalAutoLock* lock);
+
+  // |generation| is used in the following callbacks to check if the callback
+  // is called for the flush of the current |logged_events_|.
+  void FlushCurrentThread(int generation);
+  // Usually it runs on a different thread.
+  static void ConvertTraceEventsToTraceFormat(
+      scoped_ptr<TraceBuffer> logged_events,
+      const TraceLog::OutputCallback& flush_output_callback,
+      const TraceEvent::ArgumentFilterPredicate& argument_filter_predicate);
+  void FinishFlush(int generation);
+  void OnFlushTimeout(int generation);
+
+  int generation() const {
+    return static_cast<int>(subtle::NoBarrier_Load(&generation_));
+  }
+  bool CheckGeneration(int generation) const {
+    return generation == this->generation();
+  }
+  void UseNextTraceBuffer();
+
+  TraceTicks OffsetNow() const {
+    return OffsetTimestamp(TraceTicks::Now());
+  }
+  TraceTicks OffsetTimestamp(const TraceTicks& timestamp) const {
+    return timestamp - time_offset_;
+  }
+
+  // Internal representation of trace options since we store the currently used
+  // trace option as an AtomicWord.
+  static const InternalTraceOptions kInternalNone;
+  static const InternalTraceOptions kInternalRecordUntilFull;
+  static const InternalTraceOptions kInternalRecordContinuously;
+  static const InternalTraceOptions kInternalEchoToConsole;
+  static const InternalTraceOptions kInternalEnableSampling;
+  static const InternalTraceOptions kInternalRecordAsMuchAsPossible;
+  static const InternalTraceOptions kInternalEnableArgumentFilter;
+
+  // This lock protects TraceLog member accesses (except for members protected
+  // by thread_info_lock_) from arbitrary threads.
+  mutable Lock lock_;
+  // This lock protects accesses to thread_names_, thread_event_start_times_
+  // and thread_colors_.
+  Lock thread_info_lock_;
+  Mode mode_;
+  int num_traces_recorded_;
+  scoped_ptr<TraceBuffer> logged_events_;
+  subtle::AtomicWord /* EventCallback */ event_callback_;
+  bool dispatching_to_observer_list_;
+  std::vector<EnabledStateObserver*> enabled_state_observer_list_;
+
+  std::string process_name_;
+  base::hash_map<int, std::string> process_labels_;
+  int process_sort_index_;
+  base::hash_map<int, int> thread_sort_indices_;
+  base::hash_map<int, std::string> thread_names_;
+
+  // The following two maps are used only when ECHO_TO_CONSOLE.
+  base::hash_map<int, std::stack<TraceTicks> > thread_event_start_times_;
+  base::hash_map<std::string, int> thread_colors_;
+
+  TraceTicks buffer_limit_reached_timestamp_;
+
+  // XORed with TraceID to make it unlikely to collide with other processes.
+  unsigned long long process_id_hash_;
+
+  int process_id_;
+
+  TimeDelta time_offset_;
+
+  // Allow tests to wake up when certain events occur.
+  WatchEventCallback watch_event_callback_;
+  subtle::AtomicWord /* const unsigned char* */ watch_category_;
+  std::string watch_event_name_;
+
+  subtle::AtomicWord /* Options */ trace_options_;
+
+  // Sampling thread handles.
+  scoped_ptr<TraceSamplingThread> sampling_thread_;
+  PlatformThreadHandle sampling_thread_handle_;
+
+  TraceConfig trace_config_;
+  TraceConfig event_callback_trace_config_;
+
+  ThreadLocalPointer<ThreadLocalEventBuffer> thread_local_event_buffer_;
+  ThreadLocalBoolean thread_blocks_message_loop_;
+  ThreadLocalBoolean thread_is_in_trace_event_;
+
+  // Contains the message loops of threads that have had at least one event
+  // added into the local event buffer. Not using SingleThreadTaskRunner
+  // because we need to know the life time of the message loops.
+  hash_set<MessageLoop*> thread_message_loops_;
+
+  // For events which can't be added into the thread local buffer, e.g. events
+  // from threads without a message loop.
+  scoped_ptr<TraceBufferChunk> thread_shared_chunk_;
+  size_t thread_shared_chunk_index_;
+
+  // Set when asynchronous Flush is in progress.
+  OutputCallback flush_output_callback_;
+  scoped_refptr<SingleThreadTaskRunner> flush_task_runner_;
+  TraceEvent::ArgumentFilterPredicate argument_filter_predicate_;
+  subtle::AtomicWord generation_;
+  bool use_worker_thread_;
+
+  DISALLOW_COPY_AND_ASSIGN(TraceLog);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_TRACE_EVENT_IMPL_H_
diff --git a/base/trace_event/trace_event_impl_constants.cc b/base/trace_event/trace_event_impl_constants.cc
new file mode 100644
index 0000000..b7f3b4c
--- /dev/null
+++ b/base/trace_event/trace_event_impl_constants.cc
@@ -0,0 +1,27 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/trace_event_impl.h"
+
+namespace base {
+namespace trace_event {
+
+// Constant used by TraceLog's internal implementation of trace_option.
+const TraceLog::InternalTraceOptions
+    TraceLog::kInternalNone = 0;
+const TraceLog::InternalTraceOptions
+    TraceLog::kInternalRecordUntilFull = 1 << 0;
+const TraceLog::InternalTraceOptions
+    TraceLog::kInternalRecordContinuously = 1 << 1;
+const TraceLog::InternalTraceOptions
+    TraceLog::kInternalEnableSampling = 1 << 2;
+const TraceLog::InternalTraceOptions
+    TraceLog::kInternalEchoToConsole = 1 << 3;
+const TraceLog::InternalTraceOptions
+    TraceLog::kInternalRecordAsMuchAsPossible = 1 << 4;
+const TraceLog::InternalTraceOptions
+    TraceLog::kInternalEnableArgumentFilter = 1 << 5;
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/trace_event_memory.cc b/base/trace_event/trace_event_memory.cc
new file mode 100644
index 0000000..8959589
--- /dev/null
+++ b/base/trace_event/trace_event_memory.cc
@@ -0,0 +1,437 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/trace_event_memory.h"
+
+#include "base/debug/leak_annotations.h"
+#include "base/lazy_instance.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/single_thread_task_runner.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/threading/thread_local_storage.h"
+#include "base/trace_event/trace_event.h"
+
+namespace base {
+namespace trace_event {
+
+namespace {
+
+// Maximum number of nested TRACE_EVENT scopes to record. Must be less than
+// or equal to HeapProfileTable::kMaxStackDepth / 2 because we record two
+// entries on the pseudo-stack per scope.
+const size_t kMaxScopeDepth = 16;
+
+/////////////////////////////////////////////////////////////////////////////
+// Holds a memory dump until the tracing system needs to serialize it.
+class MemoryDumpHolder : public base::trace_event::ConvertableToTraceFormat {
+ public:
+  // Takes ownership of dump, which must be a JSON string, allocated with
+  // malloc() and NULL terminated.
+  explicit MemoryDumpHolder(char* dump) : dump_(dump) {}
+
+  // base::trace_event::ConvertableToTraceFormat overrides:
+  void AppendAsTraceFormat(std::string* out) const override {
+    AppendHeapProfileAsTraceFormat(dump_, out);
+  }
+
+ private:
+  ~MemoryDumpHolder() override { free(dump_); }
+
+  char* dump_;
+
+  DISALLOW_COPY_AND_ASSIGN(MemoryDumpHolder);
+};
+
+/////////////////////////////////////////////////////////////////////////////
+// Records a stack of TRACE_MEMORY events. One per thread is required.
+struct TraceMemoryStack {
+  TraceMemoryStack() : scope_depth(0) {
+    memset(scope_data, 0, kMaxScopeDepth * sizeof(scope_data[0]));
+  }
+
+  // Depth of the currently nested TRACE_EVENT scopes. Allowed to be greater
+  // than kMaxScopeDepth so we can match scope pushes and pops even if we don't
+  // have enough space to store the EventData.
+  size_t scope_depth;
+
+  // Stack of categories and names.
+  ScopedTraceMemory::ScopeData scope_data[kMaxScopeDepth];
+};
+
+// Pointer to a TraceMemoryStack per thread.
+base::ThreadLocalStorage::StaticSlot tls_trace_memory_stack = TLS_INITIALIZER;
+
+// Clean up memory pointed to by our thread-local storage.
+void DeleteStackOnThreadCleanup(void* value) {
+  TraceMemoryStack* stack = static_cast<TraceMemoryStack*>(value);
+  delete stack;
+}
+
+// Initializes the thread-local TraceMemoryStack pointer.
+void InitThreadLocalStorage() {
+  if (tls_trace_memory_stack.initialized())
+    return;
+  // Initialize the thread-local storage key.
+  tls_trace_memory_stack.Initialize(&DeleteStackOnThreadCleanup);
+}
+
+// Clean up thread-local-storage in the main thread.
+void CleanupThreadLocalStorage() {
+  if (!tls_trace_memory_stack.initialized())
+    return;
+  TraceMemoryStack* stack =
+      static_cast<TraceMemoryStack*>(tls_trace_memory_stack.Get());
+  delete stack;
+  tls_trace_memory_stack.Set(NULL);
+  // Intentionally do not release the thread-local-storage key here, that is,
+  // do not call tls_trace_memory_stack.Free(). Other threads have lazily
+  // created pointers in thread-local-storage via GetTraceMemoryStack() below.
+  // Those threads need to run the DeleteStack() destructor function when they
+  // exit. If we release the key the destructor will not be called and those
+  // threads will not clean up their memory.
+}
+
+// Returns the thread-local trace memory stack for the current thread, creating
+// one if needed. Returns NULL if the thread-local storage key isn't
+// initialized, which indicates that heap profiling isn't running.
+TraceMemoryStack* GetTraceMemoryStack() {
+  TraceMemoryStack* stack =
+      static_cast<TraceMemoryStack*>(tls_trace_memory_stack.Get());
+  // Lazily initialize TraceMemoryStack objects for new threads.
+  if (!stack) {
+    stack = new TraceMemoryStack;
+    tls_trace_memory_stack.Set(stack);
+  }
+  return stack;
+}
+
+// Returns a "pseudo-stack" of pointers to trace event categories and names.
+// Because tcmalloc stores one pointer per stack frame this converts N nested
+// trace events into N * 2 pseudo-stack entries. Thus this macro invocation:
+//    TRACE_EVENT0("category1", "name1");
+//    TRACE_EVENT0("category2", "name2");
+// becomes this pseudo-stack:
+//    stack_out[0] = "category1"
+//    stack_out[1] = "name1"
+//    stack_out[2] = "category2"
+//    stack_out[3] = "name2"
+// Returns int instead of size_t to match the signature required by tcmalloc.
+int GetPseudoStack(int skip_count_ignored, void** stack_out) {
+  // If the tracing system isn't fully initialized, just skip this allocation.
+  // Attempting to initialize will allocate memory, causing this function to
+  // be called recursively from inside the allocator.
+  if (!tls_trace_memory_stack.initialized() || !tls_trace_memory_stack.Get())
+    return 0;
+  TraceMemoryStack* stack =
+      static_cast<TraceMemoryStack*>(tls_trace_memory_stack.Get());
+  // Copy at most kMaxScopeDepth scope entries.
+  const size_t count = std::min(stack->scope_depth, kMaxScopeDepth);
+  // Notes that memcpy() works for zero bytes.
+  memcpy(stack_out,
+         stack->scope_data,
+         count * sizeof(stack->scope_data[0]));
+  // Each item in the trace event stack contains both name and category so tell
+  // tcmalloc that we have returned |count| * 2 stack frames.
+  return static_cast<int>(count * 2);
+}
+
+}  // namespace
+
+//////////////////////////////////////////////////////////////////////////////
+
+TraceMemoryController::TraceMemoryController(
+    scoped_refptr<SingleThreadTaskRunner> task_runner,
+    HeapProfilerStartFunction heap_profiler_start_function,
+    HeapProfilerStopFunction heap_profiler_stop_function,
+    GetHeapProfileFunction get_heap_profile_function)
+    : task_runner_(task_runner.Pass()),
+      heap_profiler_start_function_(heap_profiler_start_function),
+      heap_profiler_stop_function_(heap_profiler_stop_function),
+      get_heap_profile_function_(get_heap_profile_function),
+      weak_factory_(this) {
+  // Force the "memory" category to show up in the trace viewer.
+  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("memory"), "init");
+  // Watch for the tracing system being enabled.
+  TraceLog::GetInstance()->AddEnabledStateObserver(this);
+}
+
+TraceMemoryController::~TraceMemoryController() {
+  if (dump_timer_.IsRunning())
+    StopProfiling();
+  TraceLog::GetInstance()->RemoveEnabledStateObserver(this);
+}
+
+// base::trace_event::TraceLog::EnabledStateChangedObserver overrides:
+void TraceMemoryController::OnTraceLogEnabled() {
+  // Check to see if tracing is enabled for the memory category.
+  bool enabled;
+  TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("memory"),
+                                     &enabled);
+  if (!enabled)
+    return;
+  DVLOG(1) << "OnTraceLogEnabled";
+  task_runner_->PostTask(FROM_HERE,
+                         base::Bind(&TraceMemoryController::StartProfiling,
+                                    weak_factory_.GetWeakPtr()));
+}
+
+void TraceMemoryController::OnTraceLogDisabled() {
+  // The memory category is always disabled before OnTraceLogDisabled() is
+  // called, so we cannot tell if it was enabled before. Always try to turn
+  // off profiling.
+  DVLOG(1) << "OnTraceLogDisabled";
+  task_runner_->PostTask(FROM_HERE,
+                         base::Bind(&TraceMemoryController::StopProfiling,
+                                    weak_factory_.GetWeakPtr()));
+}
+
+void TraceMemoryController::StartProfiling() {
+  // Watch for the tracing framework sending enabling more than once.
+  if (dump_timer_.IsRunning())
+    return;
+  DVLOG(1) << "Starting trace memory";
+  InitThreadLocalStorage();
+  ScopedTraceMemory::set_enabled(true);
+  // Call ::HeapProfilerWithPseudoStackStart().
+  heap_profiler_start_function_(&GetPseudoStack);
+  const int kDumpIntervalSeconds = 5;
+  dump_timer_.Start(FROM_HERE,
+                    TimeDelta::FromSeconds(kDumpIntervalSeconds),
+                    base::Bind(&TraceMemoryController::DumpMemoryProfile,
+                               weak_factory_.GetWeakPtr()));
+}
+
+void TraceMemoryController::DumpMemoryProfile() {
+  // Don't trace allocations here in the memory tracing system.
+  INTERNAL_TRACE_MEMORY(TRACE_DISABLED_BY_DEFAULT("memory"),
+                        TRACE_MEMORY_IGNORE);
+
+  DVLOG(1) << "DumpMemoryProfile";
+  // MemoryDumpHolder takes ownership of this string. See GetHeapProfile() in
+  // tcmalloc for details.
+  char* dump = get_heap_profile_function_();
+  const int kSnapshotId = 1;
+  TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
+      TRACE_DISABLED_BY_DEFAULT("memory"),
+      "memory::Heap",
+      kSnapshotId,
+      scoped_refptr<ConvertableToTraceFormat>(new MemoryDumpHolder(dump)));
+}
+
+void TraceMemoryController::StopProfiling() {
+  // Watch for the tracing framework sending disabled more than once.
+  if (!dump_timer_.IsRunning())
+    return;
+  DVLOG(1) << "Stopping trace memory";
+  dump_timer_.Stop();
+  ScopedTraceMemory::set_enabled(false);
+  CleanupThreadLocalStorage();
+  // Call ::HeapProfilerStop().
+  heap_profiler_stop_function_();
+}
+
+bool TraceMemoryController::IsTimerRunningForTest() const {
+  return dump_timer_.IsRunning();
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+// static
+bool ScopedTraceMemory::enabled_ = false;
+
+void ScopedTraceMemory::Initialize(const char* category, const char* name) {
+  DCHECK(enabled_);
+  // Get our thread's copy of the stack.
+  TraceMemoryStack* trace_memory_stack = GetTraceMemoryStack();
+  const size_t index = trace_memory_stack->scope_depth;
+  // Don't record data for deeply nested scopes, but continue to increment
+  // |stack_depth| so we can match pushes and pops.
+  if (index < kMaxScopeDepth) {
+    ScopeData& event = trace_memory_stack->scope_data[index];
+    event.category = category;
+    event.name = name;
+  }
+  trace_memory_stack->scope_depth++;
+}
+
+void ScopedTraceMemory::Destroy() {
+  DCHECK(enabled_);
+  // Get our thread's copy of the stack.
+  TraceMemoryStack* trace_memory_stack = GetTraceMemoryStack();
+  // The tracing system can be turned on with ScopedTraceMemory objects
+  // allocated on the stack, so avoid potential underflow as they are destroyed.
+  if (trace_memory_stack->scope_depth > 0)
+    trace_memory_stack->scope_depth--;
+}
+
+// static
+void ScopedTraceMemory::InitForTest() {
+  InitThreadLocalStorage();
+  enabled_ = true;
+}
+
+// static
+void ScopedTraceMemory::CleanupForTest() {
+  enabled_ = false;
+  CleanupThreadLocalStorage();
+}
+
+// static
+int ScopedTraceMemory::GetStackDepthForTest() {
+  TraceMemoryStack* stack = GetTraceMemoryStack();
+  return static_cast<int>(stack->scope_depth);
+}
+
+// static
+ScopedTraceMemory::ScopeData ScopedTraceMemory::GetScopeDataForTest(
+    int stack_index) {
+  TraceMemoryStack* stack = GetTraceMemoryStack();
+  return stack->scope_data[stack_index];
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+void AppendHeapProfileAsTraceFormat(const char* input, std::string* output) {
+  // Heap profile output has a header total line, then a list of stacks with
+  // memory totals, like this:
+  //
+  // heap profile:    357:    55227 [ 14653:  2624014] @ heapprofile
+  //    95:    40940 [   649:   114260] @ 0x7fa7f4b3be13
+  //    77:    32546 [   742:   106234] @
+  //    68:     4195 [  1087:    98009] @ 0x7fa7fa9b9ba0 0x7fa7f4b3be13
+  //
+  // MAPPED_LIBRARIES:
+  // 1be411fc1000-1be4139e4000 rw-p 00000000 00:00 0
+  // 1be4139e4000-1be4139e5000 ---p 00000000 00:00 0
+  // ...
+  //
+  // Skip input after MAPPED_LIBRARIES.
+  std::string input_string;
+  const char* mapped_libraries = strstr(input, "MAPPED_LIBRARIES");
+  if (mapped_libraries) {
+    input_string.assign(input, mapped_libraries - input);
+  } else {
+    input_string.assign(input);
+  }
+
+  std::vector<std::string> lines;
+  size_t line_count = Tokenize(input_string, "\n", &lines);
+  if (line_count == 0) {
+    DLOG(WARNING) << "No lines found";
+    return;
+  }
+
+  // Handle the initial summary line.
+  output->append("[");
+  AppendHeapProfileTotalsAsTraceFormat(lines[0], output);
+
+  // Handle the following stack trace lines.
+  for (size_t i = 1; i < line_count; ++i) {
+    const std::string& line = lines[i];
+    AppendHeapProfileLineAsTraceFormat(line, output);
+  }
+  output->append("]\n");
+}
+
+void AppendHeapProfileTotalsAsTraceFormat(const std::string& line,
+                                          std::string* output) {
+  // This is what a line looks like:
+  // heap profile:    357:    55227 [ 14653:  2624014] @ heapprofile
+  //
+  // The numbers represent total allocations since profiling was enabled.
+  // From the example above:
+  //     357 = Outstanding allocations (mallocs - frees)
+  //   55227 = Outstanding bytes (malloc bytes - free bytes)
+  //   14653 = Total allocations (mallocs)
+  // 2624014 = Total bytes (malloc bytes)
+  std::vector<std::string> tokens;
+  Tokenize(line, " :[]@", &tokens);
+  if (tokens.size() < 4) {
+    DLOG(WARNING) << "Invalid totals line " << line;
+    return;
+  }
+  DCHECK_EQ(tokens[0], "heap");
+  DCHECK_EQ(tokens[1], "profile");
+  output->append("{\"current_allocs\": ");
+  output->append(tokens[2]);
+  output->append(", \"current_bytes\": ");
+  output->append(tokens[3]);
+  output->append(", \"trace\": \"\"}");
+}
+
+bool AppendHeapProfileLineAsTraceFormat(const std::string& line,
+                                        std::string* output) {
+  // This is what a line looks like:
+  //    68:     4195 [  1087:    98009] @ 0x7fa7fa9b9ba0 0x7fa7f4b3be13
+  //
+  // The numbers represent allocations for a particular stack trace since
+  // profiling was enabled. From the example above:
+  //    68 = Outstanding allocations (mallocs - frees)
+  //  4195 = Outstanding bytes (malloc bytes - free bytes)
+  //  1087 = Total allocations (mallocs)
+  // 98009 = Total bytes (malloc bytes)
+  //
+  // 0x7fa7fa9b9ba0 0x7fa7f4b3be13 = Stack trace represented as pointers to
+  //                                 static strings from trace event categories
+  //                                 and names.
+  std::vector<std::string> tokens;
+  Tokenize(line, " :[]@", &tokens);
+  // It's valid to have no stack addresses, so only require 4 tokens.
+  if (tokens.size() < 4) {
+    DLOG(WARNING) << "Invalid line " << line;
+    return false;
+  }
+  // Don't bother with stacks that have no current allocations.
+  if (tokens[0] == "0")
+    return false;
+  output->append(",\n");
+  output->append("{\"current_allocs\": ");
+  output->append(tokens[0]);
+  output->append(", \"current_bytes\": ");
+  output->append(tokens[1]);
+  output->append(", \"trace\": \"");
+
+  // Convert pairs of "stack addresses" into category and name strings.
+  const std::string kSingleQuote = "'";
+  for (size_t t = 4; t < tokens.size(); t += 2) {
+    // Casting strings into pointers is ugly but otherwise tcmalloc would need
+    // to gain a special output serializer just for pseudo-stacks.
+    const char* trace_category = StringFromHexAddress(tokens[t]);
+    DCHECK_LT(t + 1, tokens.size());
+    const char* trace_name = StringFromHexAddress(tokens[t + 1]);
+
+    // TODO(jamescook): Report the trace category and name separately to the
+    // trace viewer and allow it to decide what decorations to apply. For now
+    // just hard-code a decoration for posted tasks (toplevel).
+    std::string trace_string(trace_name);
+    if (!strcmp(trace_category, "toplevel"))
+      trace_string.append("->PostTask");
+
+    // Some trace name strings have double quotes, convert them to single.
+    ReplaceChars(trace_string, "\"", kSingleQuote, &trace_string);
+
+    output->append(trace_string);
+
+    // Trace viewer expects a trailing space.
+    output->append(" ");
+  }
+  output->append("\"}");
+  return true;
+}
+
+const char* StringFromHexAddress(const std::string& hex_address) {
+  uint64 address = 0;
+  if (!base::HexStringToUInt64(hex_address, &address))
+    return "error";
+  if (!address)
+    return "null";
+  // Note that this cast handles 64-bit to 32-bit conversion if necessary.
+  return reinterpret_cast<const char*>(address);
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/trace_event_memory.h b/base/trace_event/trace_event_memory.h
new file mode 100644
index 0000000..e2b3ae9
--- /dev/null
+++ b/base/trace_event/trace_event_memory.h
@@ -0,0 +1,171 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_TRACE_EVENT_MEMORY_H_
+#define BASE_TRACE_EVENT_TRACE_EVENT_MEMORY_H_
+
+#include "base/base_export.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/timer/timer.h"
+#include "base/trace_event/trace_event_impl.h"
+
+// TODO(jamescook): Windows support for memory tracing.
+#if !defined(NO_TCMALLOC) && !defined(OS_NACL) && \
+    (defined(OS_LINUX) || defined(OS_ANDROID))
+#define TCMALLOC_TRACE_MEMORY_SUPPORTED 1
+#endif
+
+namespace base {
+
+class SingleThreadTaskRunner;
+
+namespace trace_event {
+
+// Watches for chrome://tracing to be enabled or disabled. When tracing is
+// enabled, also enables tcmalloc heap profiling. This class is the preferred
+// way to turn trace-base heap memory profiling on and off.
+class BASE_EXPORT TraceMemoryController
+    : public TraceLog::EnabledStateObserver {
+ public:
+  typedef int (*StackGeneratorFunction)(int skip_count, void** stack);
+  typedef void (*HeapProfilerStartFunction)(StackGeneratorFunction callback);
+  typedef void (*HeapProfilerStopFunction)();
+  typedef char* (*GetHeapProfileFunction)();
+
+  // |task_runner| must be a task runner for the primary thread for the client
+  // process, e.g. the UI thread in a browser. The function pointers must be
+  // pointers to tcmalloc heap profiling functions; by avoiding direct calls to
+  // these functions we avoid a dependency on third_party/tcmalloc from base.
+  TraceMemoryController(scoped_refptr<SingleThreadTaskRunner> task_runner,
+                        HeapProfilerStartFunction heap_profiler_start_function,
+                        HeapProfilerStopFunction heap_profiler_stop_function,
+                        GetHeapProfileFunction get_heap_profile_function);
+  virtual ~TraceMemoryController();
+
+  // base::trace_event::TraceLog::EnabledStateChangedObserver overrides:
+  void OnTraceLogEnabled() override;
+  void OnTraceLogDisabled() override;
+
+  // Starts heap memory profiling.
+  void StartProfiling();
+
+  // Captures a heap profile.
+  void DumpMemoryProfile();
+
+  // If memory tracing is enabled, dumps a memory profile to the tracing system.
+  void StopProfiling();
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(TraceMemoryTest, TraceMemoryController);
+
+  bool IsTimerRunningForTest() const;
+
+  // Ensures the observer starts and stops tracing on the primary thread.
+  scoped_refptr<SingleThreadTaskRunner> task_runner_;
+
+  // Pointers to tcmalloc heap profiling functions. Allows this class to use
+  // tcmalloc functions without introducing a dependency from base to tcmalloc.
+  HeapProfilerStartFunction heap_profiler_start_function_;
+  HeapProfilerStopFunction heap_profiler_stop_function_;
+  GetHeapProfileFunction get_heap_profile_function_;
+
+  // Timer to schedule memory profile dumps.
+  RepeatingTimer<TraceMemoryController> dump_timer_;
+
+  WeakPtrFactory<TraceMemoryController> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(TraceMemoryController);
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+// A scoped context for memory tracing. Pushes the name onto a stack for
+// recording by tcmalloc heap profiling.
+class BASE_EXPORT ScopedTraceMemory {
+ public:
+  struct ScopeData {
+    const char* category;
+    const char* name;
+  };
+
+  // Memory for |category| and |name| must be static, for example, literal
+  // strings in a TRACE_EVENT macro.
+  ScopedTraceMemory(const char* category, const char* name) {
+    if (!enabled_)
+      return;
+    Initialize(category, name);
+  }
+  ~ScopedTraceMemory() {
+    if (!enabled_)
+      return;
+    Destroy();
+  }
+
+  // Enables the storing of trace names on a per-thread stack.
+  static void set_enabled(bool enabled) { enabled_ = enabled; }
+
+  // Testing interface:
+  static void InitForTest();
+  static void CleanupForTest();
+  static int GetStackDepthForTest();
+  static ScopeData GetScopeDataForTest(int stack_index);
+
+ private:
+  void Initialize(const char* category, const char* name);
+  void Destroy();
+
+  static bool enabled_;
+  DISALLOW_COPY_AND_ASSIGN(ScopedTraceMemory);
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+// Converts tcmalloc's heap profiler data with pseudo-stacks in |input| to
+// trace event compatible JSON and appends to |output|. Visible for testing.
+BASE_EXPORT void AppendHeapProfileAsTraceFormat(const char* input,
+                                                std::string* output);
+
+// Converts the first |line| of heap profiler data, which contains totals for
+// all allocations in a special format, into trace event compatible JSON and
+// appends to |output|. Visible for testing.
+BASE_EXPORT void AppendHeapProfileTotalsAsTraceFormat(const std::string& line,
+                                                      std::string* output);
+
+// Converts a single |line| of heap profiler data into trace event compatible
+// JSON and appends to |output|. Returns true if the line was valid and has a
+// non-zero number of current allocations. Visible for testing.
+BASE_EXPORT bool AppendHeapProfileLineAsTraceFormat(const std::string& line,
+                                                    std::string* output);
+
+// Returns a pointer to a string given its hexadecimal address in |hex_address|.
+// Handles both 32-bit and 64-bit addresses. Returns "null" for null pointers
+// and "error" if |address| could not be parsed. Visible for testing.
+BASE_EXPORT const char* StringFromHexAddress(const std::string& hex_address);
+
+}  // namespace trace_event
+}  // namespace base
+
+// Make local variables with unique names based on the line number. Note that
+// the extra level of redirection is needed.
+#define INTERNAL_TRACE_MEMORY_ID3(line) trace_memory_unique_##line
+#define INTERNAL_TRACE_MEMORY_ID2(line) INTERNAL_TRACE_MEMORY_ID3(line)
+#define INTERNAL_TRACE_MEMORY_ID INTERNAL_TRACE_MEMORY_ID2(__LINE__)
+
+// This is the core macro that adds a scope to each TRACE_EVENT location.
+// It generates a unique local variable name using the macros above.
+#if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED)
+#define INTERNAL_TRACE_MEMORY(category, name) \
+  base::trace_event::ScopedTraceMemory INTERNAL_TRACE_MEMORY_ID(category, name);
+#else
+#define INTERNAL_TRACE_MEMORY(category, name)
+#endif  // defined(TRACE_MEMORY_SUPPORTED)
+
+// A special trace name that allows us to ignore memory allocations inside
+// the memory dump system itself. The allocations are recorded, but the
+// visualizer skips them. Must match the value in heap.js.
+#define TRACE_MEMORY_IGNORE "trace-memory-ignore"
+
+#endif  // BASE_TRACE_EVENT_TRACE_EVENT_MEMORY_H_
diff --git a/base/trace_event/trace_event_memory_overhead.cc b/base/trace_event/trace_event_memory_overhead.cc
new file mode 100644
index 0000000..0cc3d59
--- /dev/null
+++ b/base/trace_event/trace_event_memory_overhead.cc
@@ -0,0 +1,154 @@
+// 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/trace_event_memory_overhead.h"
+
+#include <algorithm>
+
+#include "base/memory/ref_counted_memory.h"
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/memory_allocator_dump.h"
+#include "base/trace_event/process_memory_dump.h"
+#include "base/values.h"
+
+namespace {
+size_t RoundUp(size_t size, size_t alignment) {
+  return (size + alignment - 1) & ~(alignment - 1);
+}
+}  // namespace
+
+namespace base {
+namespace trace_event {
+
+TraceEventMemoryOverhead::TraceEventMemoryOverhead() {
+}
+
+TraceEventMemoryOverhead::~TraceEventMemoryOverhead() {
+}
+
+void TraceEventMemoryOverhead::AddOrCreateInternal(
+    const char* object_type,
+    size_t count,
+    size_t allocated_size_in_bytes,
+    size_t resident_size_in_bytes) {
+  auto it = allocated_objects_.find(object_type);
+  if (it == allocated_objects_.end()) {
+    allocated_objects_.insert(std::make_pair(
+        object_type,
+        ObjectCountAndSize(
+            {count, allocated_size_in_bytes, resident_size_in_bytes})));
+    return;
+  }
+  it->second.count += count;
+  it->second.allocated_size_in_bytes += allocated_size_in_bytes;
+  it->second.resident_size_in_bytes += resident_size_in_bytes;
+}
+
+void TraceEventMemoryOverhead::Add(const char* object_type,
+                                   size_t allocated_size_in_bytes) {
+  Add(object_type, allocated_size_in_bytes, allocated_size_in_bytes);
+}
+
+void TraceEventMemoryOverhead::Add(const char* object_type,
+                                   size_t allocated_size_in_bytes,
+                                   size_t resident_size_in_bytes) {
+  AddOrCreateInternal(object_type, 1, allocated_size_in_bytes,
+                      resident_size_in_bytes);
+}
+
+void TraceEventMemoryOverhead::AddString(const std::string& str) {
+  // The number below are empirical and mainly based on profiling of real-world
+  // std::string implementations:
+  //  - even short string end up malloc()-inc at least 32 bytes.
+  //  - longer stings seem to malloc() multiples of 16 bytes.
+  Add("std::string",
+      sizeof(std::string) + std::max<size_t>(RoundUp(str.capacity(), 16), 32u));
+}
+
+void TraceEventMemoryOverhead::AddRefCountedString(
+    const RefCountedString& str) {
+  Add("RefCountedString", sizeof(RefCountedString));
+  AddString(str.data());
+}
+
+void TraceEventMemoryOverhead::AddValue(const Value& value) {
+  switch (value.GetType()) {
+    case Value::TYPE_NULL:
+    case Value::TYPE_BOOLEAN:
+    case Value::TYPE_INTEGER:
+    case Value::TYPE_DOUBLE:
+      Add("FundamentalValue", sizeof(Value));
+      break;
+
+    case Value::TYPE_STRING: {
+      const StringValue* string_value = nullptr;
+      value.GetAsString(&string_value);
+      Add("StringValue", sizeof(StringValue));
+      AddString(string_value->GetString());
+    } break;
+
+    case Value::TYPE_BINARY: {
+      const BinaryValue* binary_value = nullptr;
+      value.GetAsBinary(&binary_value);
+      Add("BinaryValue", sizeof(BinaryValue) + binary_value->GetSize());
+    } break;
+
+    case Value::TYPE_DICTIONARY: {
+      const DictionaryValue* dictionary_value = nullptr;
+      value.GetAsDictionary(&dictionary_value);
+      Add("DictionaryValue", sizeof(DictionaryValue));
+      for (DictionaryValue::Iterator it(*dictionary_value); !it.IsAtEnd();
+           it.Advance()) {
+        AddString(it.key());
+        AddValue(it.value());
+      }
+    } break;
+
+    case Value::TYPE_LIST: {
+      const ListValue* list_value = nullptr;
+      value.GetAsList(&list_value);
+      Add("ListValue", sizeof(ListValue));
+      for (const Value* v : *list_value)
+        AddValue(*v);
+    } break;
+
+    default:
+      NOTREACHED();
+  }
+}
+
+void TraceEventMemoryOverhead::AddSelf() {
+  size_t estimated_size = sizeof(*this);
+  // If the SmallMap did overflow its static capacity, its elements will be
+  // allocated on the heap and have to be accounted separately.
+  if (allocated_objects_.UsingFullMap())
+    estimated_size += sizeof(map_type::value_type) * allocated_objects_.size();
+  Add("TraceEventMemoryOverhead", estimated_size);
+}
+
+void TraceEventMemoryOverhead::Update(const TraceEventMemoryOverhead& other) {
+  for (const auto& it : other.allocated_objects_) {
+    AddOrCreateInternal(it.first, it.second.count,
+                        it.second.allocated_size_in_bytes,
+                        it.second.resident_size_in_bytes);
+  }
+}
+
+void TraceEventMemoryOverhead::DumpInto(const char* base_name,
+                                        ProcessMemoryDump* pmd) const {
+  for (const auto& it : allocated_objects_) {
+    std::string dump_name = StringPrintf("%s/%s", base_name, it.first);
+    MemoryAllocatorDump* mad = pmd->CreateAllocatorDump(dump_name);
+    mad->AddScalar(MemoryAllocatorDump::kNameSize,
+                   MemoryAllocatorDump::kUnitsBytes,
+                   it.second.allocated_size_in_bytes);
+    mad->AddScalar("resident_size", MemoryAllocatorDump::kUnitsBytes,
+                   it.second.resident_size_in_bytes);
+    mad->AddScalar(MemoryAllocatorDump::kNameObjectsCount,
+                   MemoryAllocatorDump::kUnitsObjects, it.second.count);
+  }
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/trace_event_memory_overhead.h b/base/trace_event/trace_event_memory_overhead.h
new file mode 100644
index 0000000..8ecf12d
--- /dev/null
+++ b/base/trace_event/trace_event_memory_overhead.h
@@ -0,0 +1,71 @@
+// 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_TRACE_EVENT_MEMORY_OVERHEAD_H_
+#define BASE_TRACE_EVENT_TRACE_EVENT_MEMORY_OVERHEAD_H_
+
+#include "base/base_export.h"
+#include "base/containers/hash_tables.h"
+#include "base/containers/small_map.h"
+
+namespace base {
+
+class RefCountedString;
+class Value;
+
+namespace trace_event {
+
+class ProcessMemoryDump;
+
+// Used to estimate the memory overhead of the tracing infrastructure.
+class BASE_EXPORT TraceEventMemoryOverhead {
+ public:
+  TraceEventMemoryOverhead();
+  ~TraceEventMemoryOverhead();
+
+  // Use this method to account the overhead of an object for which an estimate
+  // is known for both the allocated and resident memory.
+  void Add(const char* object_type,
+           size_t allocated_size_in_bytes,
+           size_t resident_size_in_bytes);
+
+  // Similar to Add() above, but assumes that
+  // |resident_size_in_bytes| == |allocated_size_in_bytes|.
+  void Add(const char* object_type, size_t allocated_size_in_bytes);
+
+  // Specialized profiling functions for commonly used object types.
+  void AddString(const std::string& str);
+  void AddValue(const Value& value);
+  void AddRefCountedString(const RefCountedString& str);
+
+  // Call this after all the Add* methods above to account the memory used by
+  // this TraceEventMemoryOverhead instance itself.
+  void AddSelf();
+
+  // Adds up and merges all the values from |other| to this instance.
+  void Update(const TraceEventMemoryOverhead& other);
+
+  void DumpInto(const char* base_name, ProcessMemoryDump* pmd) const;
+
+ private:
+  struct ObjectCountAndSize {
+    size_t count;
+    size_t allocated_size_in_bytes;
+    size_t resident_size_in_bytes;
+  };
+  using map_type = SmallMap<hash_map<const char*, ObjectCountAndSize>, 16>;
+  map_type allocated_objects_;
+
+  void AddOrCreateInternal(const char* object_type,
+                           size_t count,
+                           size_t allocated_size_in_bytes,
+                           size_t resident_size_in_bytes);
+
+  DISALLOW_COPY_AND_ASSIGN(TraceEventMemoryOverhead);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_TRACE_EVENT_MEMORY_OVERHEAD_H_
diff --git a/base/trace_event/trace_event_memory_unittest.cc b/base/trace_event/trace_event_memory_unittest.cc
new file mode 100644
index 0000000..781a054
--- /dev/null
+++ b/base/trace_event/trace_event_memory_unittest.cc
@@ -0,0 +1,236 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/trace_event_memory.h"
+
+#include <sstream>
+#include <string>
+
+#include "base/trace_event/trace_event_impl.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED)
+#include "third_party/tcmalloc/chromium/src/gperftools/heap-profiler.h"
+#endif
+
+namespace base {
+namespace trace_event {
+
+// Tests for the trace event memory tracking system. Exists as a class so it
+// can be a friend of TraceMemoryController.
+class TraceMemoryTest : public testing::Test {
+ public:
+  TraceMemoryTest() {}
+  ~TraceMemoryTest() override {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TraceMemoryTest);
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+#if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED)
+
+TEST_F(TraceMemoryTest, TraceMemoryController) {
+  MessageLoop message_loop;
+
+  // Start with no observers of the TraceLog.
+  EXPECT_EQ(0u, TraceLog::GetInstance()->GetObserverCountForTest());
+
+  // Creating a controller adds it to the TraceLog observer list.
+  scoped_ptr<TraceMemoryController> controller(new TraceMemoryController(
+      message_loop.task_runner(), ::HeapProfilerWithPseudoStackStart,
+      ::HeapProfilerStop, ::GetHeapProfile));
+  EXPECT_EQ(1u, TraceLog::GetInstance()->GetObserverCountForTest());
+  EXPECT_TRUE(
+      TraceLog::GetInstance()->HasEnabledStateObserver(controller.get()));
+
+  // By default the observer isn't dumping memory profiles.
+  EXPECT_FALSE(controller->IsTimerRunningForTest());
+
+  // Simulate enabling tracing.
+  controller->StartProfiling();
+  message_loop.RunUntilIdle();
+  EXPECT_TRUE(controller->IsTimerRunningForTest());
+
+  // Simulate disabling tracing.
+  controller->StopProfiling();
+  message_loop.RunUntilIdle();
+  EXPECT_FALSE(controller->IsTimerRunningForTest());
+
+  // Deleting the observer removes it from the TraceLog observer list.
+  controller.reset();
+  EXPECT_EQ(0u, TraceLog::GetInstance()->GetObserverCountForTest());
+}
+
+TEST_F(TraceMemoryTest, ScopedTraceMemory) {
+  ScopedTraceMemory::InitForTest();
+
+  // Start with an empty stack.
+  EXPECT_EQ(0, ScopedTraceMemory::GetStackDepthForTest());
+
+  {
+    // Push an item.
+    ScopedTraceMemory scope1("cat1", "name1");
+    EXPECT_EQ(1, ScopedTraceMemory::GetStackDepthForTest());
+    EXPECT_EQ("cat1", ScopedTraceMemory::GetScopeDataForTest(0).category);
+    EXPECT_EQ("name1", ScopedTraceMemory::GetScopeDataForTest(0).name);
+
+    {
+      // One more item.
+      ScopedTraceMemory scope2("cat2", "name2");
+      EXPECT_EQ(2, ScopedTraceMemory::GetStackDepthForTest());
+      EXPECT_EQ("cat2", ScopedTraceMemory::GetScopeDataForTest(1).category);
+      EXPECT_EQ("name2", ScopedTraceMemory::GetScopeDataForTest(1).name);
+    }
+
+    // Ended scope 2.
+    EXPECT_EQ(1, ScopedTraceMemory::GetStackDepthForTest());
+  }
+
+  // Ended scope 1.
+  EXPECT_EQ(0, ScopedTraceMemory::GetStackDepthForTest());
+
+  ScopedTraceMemory::CleanupForTest();
+}
+
+void TestDeepScopeNesting(int current, int depth) {
+  EXPECT_EQ(current, ScopedTraceMemory::GetStackDepthForTest());
+  ScopedTraceMemory scope("category", "name");
+  if (current < depth)
+    TestDeepScopeNesting(current + 1, depth);
+  EXPECT_EQ(current + 1, ScopedTraceMemory::GetStackDepthForTest());
+}
+
+TEST_F(TraceMemoryTest, DeepScopeNesting) {
+  ScopedTraceMemory::InitForTest();
+
+  // Ensure really deep scopes don't crash.
+  TestDeepScopeNesting(0, 100);
+
+  ScopedTraceMemory::CleanupForTest();
+}
+
+#endif  // defined(TRACE_MEMORY_SUPPORTED)
+
+/////////////////////////////////////////////////////////////////////////////
+
+TEST_F(TraceMemoryTest, AppendHeapProfileTotalsAsTraceFormat) {
+  // Empty input gives empty output.
+  std::string empty_output;
+  AppendHeapProfileTotalsAsTraceFormat("", &empty_output);
+  EXPECT_EQ("", empty_output);
+
+  // Typical case.
+  const char input[] =
+      "heap profile:    357:    55227 [ 14653:  2624014] @ heapprofile";
+  const std::string kExpectedOutput =
+      "{\"current_allocs\": 357, \"current_bytes\": 55227, \"trace\": \"\"}";
+  std::string output;
+  AppendHeapProfileTotalsAsTraceFormat(input, &output);
+  EXPECT_EQ(kExpectedOutput, output);
+}
+
+TEST_F(TraceMemoryTest, AppendHeapProfileLineAsTraceFormat) {
+  // Empty input gives empty output.
+  std::string empty_output;
+  EXPECT_FALSE(AppendHeapProfileLineAsTraceFormat("", &empty_output));
+  EXPECT_EQ("", empty_output);
+
+  // Invalid input returns false.
+  std::string junk_output;
+  EXPECT_FALSE(AppendHeapProfileLineAsTraceFormat("junk", &junk_output));
+
+  // Input with normal category and name entries.
+  const char kCategory[] = "category";
+  const char kName[] = "name";
+  std::ostringstream input;
+  input << "   68:     4195 [  1087:    98009] @ " << &kCategory << " "
+        << &kName;
+  const std::string kExpectedOutput =
+      ",\n"
+      "{"
+      "\"current_allocs\": 68, "
+      "\"current_bytes\": 4195, "
+      "\"trace\": \"name \""
+      "}";
+  std::string output;
+  EXPECT_TRUE(
+      AppendHeapProfileLineAsTraceFormat(input.str().c_str(), &output));
+  EXPECT_EQ(kExpectedOutput, output);
+
+  // Input with with the category "toplevel".
+  // TODO(jamescook): Eliminate this special case and move the logic to the
+  // trace viewer code.
+  const char kTaskCategory[] = "toplevel";
+  const char kTaskName[] = "TaskName";
+  std::ostringstream input2;
+  input2 << "   68:     4195 [  1087:    98009] @ " << &kTaskCategory << " "
+        << &kTaskName;
+  const std::string kExpectedOutput2 =
+      ",\n"
+      "{"
+      "\"current_allocs\": 68, "
+      "\"current_bytes\": 4195, "
+      "\"trace\": \"TaskName->PostTask \""
+      "}";
+  std::string output2;
+  EXPECT_TRUE(
+      AppendHeapProfileLineAsTraceFormat(input2.str().c_str(), &output2));
+  EXPECT_EQ(kExpectedOutput2, output2);
+
+  // Zero current allocations is skipped.
+  std::ostringstream zero_input;
+  zero_input << "   0:     0 [  1087:    98009] @ " << &kCategory << " "
+             << &kName;
+  std::string zero_output;
+  EXPECT_FALSE(AppendHeapProfileLineAsTraceFormat(zero_input.str().c_str(),
+                                                  &zero_output));
+  EXPECT_EQ("", zero_output);
+}
+
+TEST_F(TraceMemoryTest, AppendHeapProfileAsTraceFormat) {
+  // Empty input gives empty output.
+  std::string empty_output;
+  AppendHeapProfileAsTraceFormat("", &empty_output);
+  EXPECT_EQ("", empty_output);
+
+  // Typical case.
+  const char input[] =
+      "heap profile:    357:    55227 [ 14653:  2624014] @ heapprofile\n"
+      "   95:    40940 [   649:   114260] @\n"
+      "   77:    32546 [   742:   106234] @ 0x0 0x0\n"
+      "    0:        0 [   132:     4236] @ 0x0\n"
+      "\n"
+      "MAPPED_LIBRARIES:\n"
+      "1be411fc1000-1be4139e4000 rw-p 00000000 00:00 0\n"
+      "1be4139e4000-1be4139e5000 ---p 00000000 00:00 0\n";
+  const std::string kExpectedOutput =
+      "[{"
+      "\"current_allocs\": 357, "
+      "\"current_bytes\": 55227, "
+      "\"trace\": \"\"},\n"
+      "{\"current_allocs\": 95, "
+      "\"current_bytes\": 40940, "
+      "\"trace\": \"\"},\n"
+      "{\"current_allocs\": 77, "
+      "\"current_bytes\": 32546, "
+      "\"trace\": \"null \""
+      "}]\n";
+  std::string output;
+  AppendHeapProfileAsTraceFormat(input, &output);
+  EXPECT_EQ(kExpectedOutput, output);
+}
+
+TEST_F(TraceMemoryTest, StringFromHexAddress) {
+  EXPECT_STREQ("null", StringFromHexAddress("0x0"));
+  EXPECT_STREQ("error", StringFromHexAddress("not an address"));
+  const char kHello[] = "hello";
+  std::ostringstream hex_address;
+  hex_address << &kHello;
+  EXPECT_STREQ(kHello, StringFromHexAddress(hex_address.str()));
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/trace_event_synthetic_delay.cc b/base/trace_event/trace_event_synthetic_delay.cc
new file mode 100644
index 0000000..bad79cc
--- /dev/null
+++ b/base/trace_event/trace_event_synthetic_delay.cc
@@ -0,0 +1,235 @@
+// 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.
+
+#include "base/memory/singleton.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "base/trace_event/trace_event_synthetic_delay.h"
+
+namespace {
+const int kMaxSyntheticDelays = 32;
+}  // namespace
+
+namespace base {
+namespace trace_event {
+
+TraceEventSyntheticDelayClock::TraceEventSyntheticDelayClock() {}
+TraceEventSyntheticDelayClock::~TraceEventSyntheticDelayClock() {}
+
+class TraceEventSyntheticDelayRegistry : public TraceEventSyntheticDelayClock {
+ public:
+  static TraceEventSyntheticDelayRegistry* GetInstance();
+
+  TraceEventSyntheticDelay* GetOrCreateDelay(const char* name);
+  void ResetAllDelays();
+
+  // TraceEventSyntheticDelayClock implementation.
+  base::TimeTicks Now() override;
+
+ private:
+  TraceEventSyntheticDelayRegistry();
+
+  friend struct DefaultSingletonTraits<TraceEventSyntheticDelayRegistry>;
+
+  Lock lock_;
+  TraceEventSyntheticDelay delays_[kMaxSyntheticDelays];
+  TraceEventSyntheticDelay dummy_delay_;
+  base::subtle::Atomic32 delay_count_;
+
+  DISALLOW_COPY_AND_ASSIGN(TraceEventSyntheticDelayRegistry);
+};
+
+TraceEventSyntheticDelay::TraceEventSyntheticDelay()
+    : mode_(STATIC), begin_count_(0), trigger_count_(0), clock_(NULL) {}
+
+TraceEventSyntheticDelay::~TraceEventSyntheticDelay() {}
+
+TraceEventSyntheticDelay* TraceEventSyntheticDelay::Lookup(
+    const std::string& name) {
+  return TraceEventSyntheticDelayRegistry::GetInstance()->GetOrCreateDelay(
+      name.c_str());
+}
+
+void TraceEventSyntheticDelay::Initialize(
+    const std::string& name,
+    TraceEventSyntheticDelayClock* clock) {
+  name_ = name;
+  clock_ = clock;
+}
+
+void TraceEventSyntheticDelay::SetTargetDuration(
+    base::TimeDelta target_duration) {
+  AutoLock lock(lock_);
+  target_duration_ = target_duration;
+  trigger_count_ = 0;
+  begin_count_ = 0;
+}
+
+void TraceEventSyntheticDelay::SetMode(Mode mode) {
+  AutoLock lock(lock_);
+  mode_ = mode;
+}
+
+void TraceEventSyntheticDelay::SetClock(TraceEventSyntheticDelayClock* clock) {
+  AutoLock lock(lock_);
+  clock_ = clock;
+}
+
+void TraceEventSyntheticDelay::Begin() {
+  // Note that we check for a non-zero target duration without locking to keep
+  // things quick for the common case when delays are disabled. Since the delay
+  // calculation is done with a lock held, it will always be correct. The only
+  // downside of this is that we may fail to apply some delays when the target
+  // duration changes.
+  ANNOTATE_BENIGN_RACE(&target_duration_, "Synthetic delay duration");
+  if (!target_duration_.ToInternalValue())
+    return;
+
+  base::TimeTicks start_time = clock_->Now();
+  {
+    AutoLock lock(lock_);
+    if (++begin_count_ != 1)
+      return;
+    end_time_ = CalculateEndTimeLocked(start_time);
+  }
+}
+
+void TraceEventSyntheticDelay::BeginParallel(base::TimeTicks* out_end_time) {
+  // See note in Begin().
+  ANNOTATE_BENIGN_RACE(&target_duration_, "Synthetic delay duration");
+  if (!target_duration_.ToInternalValue()) {
+    *out_end_time = base::TimeTicks();
+    return;
+  }
+
+  base::TimeTicks start_time = clock_->Now();
+  {
+    AutoLock lock(lock_);
+    *out_end_time = CalculateEndTimeLocked(start_time);
+  }
+}
+
+void TraceEventSyntheticDelay::End() {
+  // See note in Begin().
+  ANNOTATE_BENIGN_RACE(&target_duration_, "Synthetic delay duration");
+  if (!target_duration_.ToInternalValue())
+    return;
+
+  base::TimeTicks end_time;
+  {
+    AutoLock lock(lock_);
+    if (!begin_count_ || --begin_count_ != 0)
+      return;
+    end_time = end_time_;
+  }
+  if (!end_time.is_null())
+    ApplyDelay(end_time);
+}
+
+void TraceEventSyntheticDelay::EndParallel(base::TimeTicks end_time) {
+  if (!end_time.is_null())
+    ApplyDelay(end_time);
+}
+
+base::TimeTicks TraceEventSyntheticDelay::CalculateEndTimeLocked(
+    base::TimeTicks start_time) {
+  if (mode_ == ONE_SHOT && trigger_count_++)
+    return base::TimeTicks();
+  else if (mode_ == ALTERNATING && trigger_count_++ % 2)
+    return base::TimeTicks();
+  return start_time + target_duration_;
+}
+
+void TraceEventSyntheticDelay::ApplyDelay(base::TimeTicks end_time) {
+  TRACE_EVENT0("synthetic_delay", name_.c_str());
+  while (clock_->Now() < end_time) {
+    // Busy loop.
+  }
+}
+
+TraceEventSyntheticDelayRegistry*
+TraceEventSyntheticDelayRegistry::GetInstance() {
+  return Singleton<
+      TraceEventSyntheticDelayRegistry,
+      LeakySingletonTraits<TraceEventSyntheticDelayRegistry> >::get();
+}
+
+TraceEventSyntheticDelayRegistry::TraceEventSyntheticDelayRegistry()
+    : delay_count_(0) {}
+
+TraceEventSyntheticDelay* TraceEventSyntheticDelayRegistry::GetOrCreateDelay(
+    const char* name) {
+  // Try to find an existing delay first without locking to make the common case
+  // fast.
+  int delay_count = base::subtle::Acquire_Load(&delay_count_);
+  for (int i = 0; i < delay_count; ++i) {
+    if (!strcmp(name, delays_[i].name_.c_str()))
+      return &delays_[i];
+  }
+
+  AutoLock lock(lock_);
+  delay_count = base::subtle::Acquire_Load(&delay_count_);
+  for (int i = 0; i < delay_count; ++i) {
+    if (!strcmp(name, delays_[i].name_.c_str()))
+      return &delays_[i];
+  }
+
+  DCHECK(delay_count < kMaxSyntheticDelays)
+      << "must increase kMaxSyntheticDelays";
+  if (delay_count >= kMaxSyntheticDelays)
+    return &dummy_delay_;
+
+  delays_[delay_count].Initialize(std::string(name), this);
+  base::subtle::Release_Store(&delay_count_, delay_count + 1);
+  return &delays_[delay_count];
+}
+
+base::TimeTicks TraceEventSyntheticDelayRegistry::Now() {
+  return base::TimeTicks::Now();
+}
+
+void TraceEventSyntheticDelayRegistry::ResetAllDelays() {
+  AutoLock lock(lock_);
+  int delay_count = base::subtle::Acquire_Load(&delay_count_);
+  for (int i = 0; i < delay_count; ++i) {
+    delays_[i].SetTargetDuration(base::TimeDelta());
+    delays_[i].SetClock(this);
+  }
+}
+
+void ResetTraceEventSyntheticDelays() {
+  TraceEventSyntheticDelayRegistry::GetInstance()->ResetAllDelays();
+}
+
+}  // namespace trace_event
+}  // namespace base
+
+namespace trace_event_internal {
+
+ScopedSyntheticDelay::ScopedSyntheticDelay(const char* name,
+                                           base::subtle::AtomicWord* impl_ptr)
+    : delay_impl_(GetOrCreateDelay(name, impl_ptr)) {
+  delay_impl_->BeginParallel(&end_time_);
+}
+
+ScopedSyntheticDelay::~ScopedSyntheticDelay() {
+  delay_impl_->EndParallel(end_time_);
+}
+
+base::trace_event::TraceEventSyntheticDelay* GetOrCreateDelay(
+    const char* name,
+    base::subtle::AtomicWord* impl_ptr) {
+  base::trace_event::TraceEventSyntheticDelay* delay_impl =
+      reinterpret_cast<base::trace_event::TraceEventSyntheticDelay*>(
+          base::subtle::Acquire_Load(impl_ptr));
+  if (!delay_impl) {
+    delay_impl =
+        base::trace_event::TraceEventSyntheticDelayRegistry::GetInstance()
+            ->GetOrCreateDelay(name);
+    base::subtle::Release_Store(
+        impl_ptr, reinterpret_cast<base::subtle::AtomicWord>(delay_impl));
+  }
+  return delay_impl;
+}
+
+}  // namespace trace_event_internal
diff --git a/base/trace_event/trace_event_synthetic_delay.h b/base/trace_event/trace_event_synthetic_delay.h
new file mode 100644
index 0000000..0df794b
--- /dev/null
+++ b/base/trace_event/trace_event_synthetic_delay.h
@@ -0,0 +1,166 @@
+// 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.
+
+// The synthetic delay framework makes it possible to dynamically inject
+// arbitrary delays into into different parts of the codebase. This can be used,
+// for instance, for testing various task scheduling algorithms.
+//
+// The delays are specified in terms of a target duration for a given block of
+// code. If the code executes faster than the duration, the thread is made to
+// sleep until the deadline is met.
+//
+// Code can be instrumented for delays with two sets of macros. First, for
+// delays that should apply within a scope, use the following macro:
+//
+//   TRACE_EVENT_SYNTHETIC_DELAY("cc.LayerTreeHost.DrawAndSwap");
+//
+// For delaying operations that span multiple scopes, use:
+//
+//   TRACE_EVENT_SYNTHETIC_DELAY_BEGIN("cc.Scheduler.BeginMainFrame");
+//   ...
+//   TRACE_EVENT_SYNTHETIC_DELAY_END("cc.Scheduler.BeginMainFrame");
+//
+// Here BEGIN establishes the start time for the delay and END executes the
+// delay based on the remaining time. If BEGIN is called multiple times in a
+// row, END should be called a corresponding number of times. Only the last
+// call to END will have an effect.
+//
+// Note that a single delay may begin on one thread and end on another. This
+// implies that a single delay cannot not be applied in several threads at once.
+
+#ifndef BASE_TRACE_EVENT_TRACE_EVENT_SYNTHETIC_DELAY_H_
+#define BASE_TRACE_EVENT_TRACE_EVENT_SYNTHETIC_DELAY_H_
+
+#include "base/atomicops.h"
+#include "base/synchronization/lock.h"
+#include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
+
+// Apply a named delay in the current scope.
+#define TRACE_EVENT_SYNTHETIC_DELAY(name)                                     \
+  static base::subtle::AtomicWord INTERNAL_TRACE_EVENT_UID(impl_ptr) = 0;     \
+  trace_event_internal::ScopedSyntheticDelay INTERNAL_TRACE_EVENT_UID(delay)( \
+      name, &INTERNAL_TRACE_EVENT_UID(impl_ptr));
+
+// Begin a named delay, establishing its timing start point. May be called
+// multiple times as long as the calls to TRACE_EVENT_SYNTHETIC_DELAY_END are
+// balanced. Only the first call records the timing start point.
+#define TRACE_EVENT_SYNTHETIC_DELAY_BEGIN(name)                          \
+  do {                                                                   \
+    static base::subtle::AtomicWord impl_ptr = 0;                        \
+    trace_event_internal::GetOrCreateDelay(name, &impl_ptr)->Begin();    \
+  } while (false)
+
+// End a named delay. The delay is applied only if this call matches the
+// first corresponding call to TRACE_EVENT_SYNTHETIC_DELAY_BEGIN with the
+// same delay.
+#define TRACE_EVENT_SYNTHETIC_DELAY_END(name)                         \
+  do {                                                                \
+    static base::subtle::AtomicWord impl_ptr = 0;                     \
+    trace_event_internal::GetOrCreateDelay(name, &impl_ptr)->End();   \
+  } while (false)
+
+template <typename Type>
+struct DefaultSingletonTraits;
+
+namespace base {
+namespace trace_event {
+
+// Time source for computing delay durations. Used for testing.
+class TRACE_EVENT_API_CLASS_EXPORT TraceEventSyntheticDelayClock {
+ public:
+  TraceEventSyntheticDelayClock();
+  virtual ~TraceEventSyntheticDelayClock();
+  virtual base::TimeTicks Now() = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TraceEventSyntheticDelayClock);
+};
+
+// Single delay point instance.
+class TRACE_EVENT_API_CLASS_EXPORT TraceEventSyntheticDelay {
+ public:
+  enum Mode {
+    STATIC,      // Apply the configured delay every time.
+    ONE_SHOT,    // Apply the configured delay just once.
+    ALTERNATING  // Apply the configured delay every other time.
+  };
+
+  // Returns an existing named delay instance or creates a new one with |name|.
+  static TraceEventSyntheticDelay* Lookup(const std::string& name);
+
+  void SetTargetDuration(TimeDelta target_duration);
+  void SetMode(Mode mode);
+  void SetClock(TraceEventSyntheticDelayClock* clock);
+
+  // Begin the delay, establishing its timing start point. May be called
+  // multiple times as long as the calls to End() are balanced. Only the first
+  // call records the timing start point.
+  void Begin();
+
+  // End the delay. The delay is applied only if this call matches the first
+  // corresponding call to Begin() with the same delay.
+  void End();
+
+  // Begin a parallel instance of the delay. Several parallel instances may be
+  // active simultaneously and will complete independently. The computed end
+  // time for the delay is stored in |out_end_time|, which should later be
+  // passed to EndParallel().
+  void BeginParallel(base::TimeTicks* out_end_time);
+
+  // End a previously started parallel delay. |end_time| is the delay end point
+  // computed by BeginParallel().
+  void EndParallel(base::TimeTicks end_time);
+
+ private:
+  TraceEventSyntheticDelay();
+  ~TraceEventSyntheticDelay();
+  friend class TraceEventSyntheticDelayRegistry;
+
+  void Initialize(const std::string& name,
+                  TraceEventSyntheticDelayClock* clock);
+  base::TimeTicks CalculateEndTimeLocked(base::TimeTicks start_time);
+  void ApplyDelay(base::TimeTicks end_time);
+
+  Lock lock_;
+  Mode mode_;
+  std::string name_;
+  int begin_count_;
+  int trigger_count_;
+  base::TimeTicks end_time_;
+  base::TimeDelta target_duration_;
+  TraceEventSyntheticDelayClock* clock_;
+
+  DISALLOW_COPY_AND_ASSIGN(TraceEventSyntheticDelay);
+};
+
+// Set the target durations of all registered synthetic delay points to zero.
+TRACE_EVENT_API_CLASS_EXPORT void ResetTraceEventSyntheticDelays();
+
+}  // namespace trace_event
+}  // namespace base
+
+namespace trace_event_internal {
+
+// Helper class for scoped delays. Do not use directly.
+class TRACE_EVENT_API_CLASS_EXPORT ScopedSyntheticDelay {
+ public:
+  explicit ScopedSyntheticDelay(const char* name,
+                                base::subtle::AtomicWord* impl_ptr);
+  ~ScopedSyntheticDelay();
+
+ private:
+  base::trace_event::TraceEventSyntheticDelay* delay_impl_;
+  base::TimeTicks end_time_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedSyntheticDelay);
+};
+
+// Helper for registering delays. Do not use directly.
+TRACE_EVENT_API_CLASS_EXPORT base::trace_event::TraceEventSyntheticDelay*
+    GetOrCreateDelay(const char* name, base::subtle::AtomicWord* impl_ptr);
+
+}  // namespace trace_event_internal
+
+#endif  // BASE_TRACE_EVENT_TRACE_EVENT_SYNTHETIC_DELAY_H_
diff --git a/base/trace_event/trace_event_synthetic_delay_unittest.cc b/base/trace_event/trace_event_synthetic_delay_unittest.cc
new file mode 100644
index 0000000..1dc0fc2
--- /dev/null
+++ b/base/trace_event/trace_event_synthetic_delay_unittest.cc
@@ -0,0 +1,154 @@
+// 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.
+
+#include "base/trace_event/trace_event_synthetic_delay.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+namespace {
+
+const int kTargetDurationMs = 100;
+// Allow some leeway in timings to make it possible to run these tests with a
+// wall clock time source too.
+const int kShortDurationMs = 10;
+
+}  // namespace
+
+class TraceEventSyntheticDelayTest : public testing::Test,
+                                     public TraceEventSyntheticDelayClock {
+ public:
+  TraceEventSyntheticDelayTest() {}
+  ~TraceEventSyntheticDelayTest() override { ResetTraceEventSyntheticDelays(); }
+
+  // TraceEventSyntheticDelayClock implementation.
+  base::TimeTicks Now() override {
+    AdvanceTime(base::TimeDelta::FromMilliseconds(kShortDurationMs / 10));
+    return now_;
+  }
+
+  TraceEventSyntheticDelay* ConfigureDelay(const char* name) {
+    TraceEventSyntheticDelay* delay = TraceEventSyntheticDelay::Lookup(name);
+    delay->SetClock(this);
+    delay->SetTargetDuration(
+        base::TimeDelta::FromMilliseconds(kTargetDurationMs));
+    return delay;
+  }
+
+  void AdvanceTime(base::TimeDelta delta) { now_ += delta; }
+
+  int64 TestFunction() {
+    base::TimeTicks start = Now();
+    { TRACE_EVENT_SYNTHETIC_DELAY("test.Delay"); }
+    return (Now() - start).InMilliseconds();
+  }
+
+  int64 AsyncTestFunctionBegin() {
+    base::TimeTicks start = Now();
+    { TRACE_EVENT_SYNTHETIC_DELAY_BEGIN("test.AsyncDelay"); }
+    return (Now() - start).InMilliseconds();
+  }
+
+  int64 AsyncTestFunctionEnd() {
+    base::TimeTicks start = Now();
+    { TRACE_EVENT_SYNTHETIC_DELAY_END("test.AsyncDelay"); }
+    return (Now() - start).InMilliseconds();
+  }
+
+ private:
+  base::TimeTicks now_;
+
+  DISALLOW_COPY_AND_ASSIGN(TraceEventSyntheticDelayTest);
+};
+
+TEST_F(TraceEventSyntheticDelayTest, StaticDelay) {
+  TraceEventSyntheticDelay* delay = ConfigureDelay("test.Delay");
+  delay->SetMode(TraceEventSyntheticDelay::STATIC);
+  EXPECT_GE(TestFunction(), kTargetDurationMs);
+}
+
+TEST_F(TraceEventSyntheticDelayTest, OneShotDelay) {
+  TraceEventSyntheticDelay* delay = ConfigureDelay("test.Delay");
+  delay->SetMode(TraceEventSyntheticDelay::ONE_SHOT);
+  EXPECT_GE(TestFunction(), kTargetDurationMs);
+  EXPECT_LT(TestFunction(), kShortDurationMs);
+
+  delay->SetTargetDuration(
+      base::TimeDelta::FromMilliseconds(kTargetDurationMs));
+  EXPECT_GE(TestFunction(), kTargetDurationMs);
+}
+
+TEST_F(TraceEventSyntheticDelayTest, AlternatingDelay) {
+  TraceEventSyntheticDelay* delay = ConfigureDelay("test.Delay");
+  delay->SetMode(TraceEventSyntheticDelay::ALTERNATING);
+  EXPECT_GE(TestFunction(), kTargetDurationMs);
+  EXPECT_LT(TestFunction(), kShortDurationMs);
+  EXPECT_GE(TestFunction(), kTargetDurationMs);
+  EXPECT_LT(TestFunction(), kShortDurationMs);
+}
+
+TEST_F(TraceEventSyntheticDelayTest, AsyncDelay) {
+  ConfigureDelay("test.AsyncDelay");
+  EXPECT_LT(AsyncTestFunctionBegin(), kShortDurationMs);
+  EXPECT_GE(AsyncTestFunctionEnd(), kTargetDurationMs / 2);
+}
+
+TEST_F(TraceEventSyntheticDelayTest, AsyncDelayExceeded) {
+  ConfigureDelay("test.AsyncDelay");
+  EXPECT_LT(AsyncTestFunctionBegin(), kShortDurationMs);
+  AdvanceTime(base::TimeDelta::FromMilliseconds(kTargetDurationMs));
+  EXPECT_LT(AsyncTestFunctionEnd(), kShortDurationMs);
+}
+
+TEST_F(TraceEventSyntheticDelayTest, AsyncDelayNoActivation) {
+  ConfigureDelay("test.AsyncDelay");
+  EXPECT_LT(AsyncTestFunctionEnd(), kShortDurationMs);
+}
+
+TEST_F(TraceEventSyntheticDelayTest, AsyncDelayNested) {
+  ConfigureDelay("test.AsyncDelay");
+  EXPECT_LT(AsyncTestFunctionBegin(), kShortDurationMs);
+  EXPECT_LT(AsyncTestFunctionBegin(), kShortDurationMs);
+  EXPECT_LT(AsyncTestFunctionEnd(), kShortDurationMs);
+  EXPECT_GE(AsyncTestFunctionEnd(), kTargetDurationMs / 2);
+}
+
+TEST_F(TraceEventSyntheticDelayTest, AsyncDelayUnbalanced) {
+  ConfigureDelay("test.AsyncDelay");
+  EXPECT_LT(AsyncTestFunctionBegin(), kShortDurationMs);
+  EXPECT_GE(AsyncTestFunctionEnd(), kTargetDurationMs / 2);
+  EXPECT_LT(AsyncTestFunctionEnd(), kShortDurationMs);
+
+  EXPECT_LT(AsyncTestFunctionBegin(), kShortDurationMs);
+  EXPECT_GE(AsyncTestFunctionEnd(), kTargetDurationMs / 2);
+}
+
+TEST_F(TraceEventSyntheticDelayTest, ResetDelays) {
+  ConfigureDelay("test.Delay");
+  ResetTraceEventSyntheticDelays();
+  EXPECT_LT(TestFunction(), kShortDurationMs);
+}
+
+TEST_F(TraceEventSyntheticDelayTest, BeginParallel) {
+  TraceEventSyntheticDelay* delay = ConfigureDelay("test.AsyncDelay");
+  base::TimeTicks end_times[2];
+  base::TimeTicks start_time = Now();
+
+  delay->BeginParallel(&end_times[0]);
+  EXPECT_FALSE(end_times[0].is_null());
+
+  delay->BeginParallel(&end_times[1]);
+  EXPECT_FALSE(end_times[1].is_null());
+
+  delay->EndParallel(end_times[0]);
+  EXPECT_GE((Now() - start_time).InMilliseconds(), kTargetDurationMs);
+
+  start_time = Now();
+  delay->EndParallel(end_times[1]);
+  EXPECT_LT((Now() - start_time).InMilliseconds(), kShortDurationMs);
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/trace_event_system_stats_monitor.cc b/base/trace_event/trace_event_system_stats_monitor.cc
new file mode 100644
index 0000000..c08d9b9
--- /dev/null
+++ b/base/trace_event/trace_event_system_stats_monitor.cc
@@ -0,0 +1,133 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/trace_event_system_stats_monitor.h"
+
+#include "base/debug/leak_annotations.h"
+#include "base/json/json_writer.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/thread_local_storage.h"
+#include "base/trace_event/trace_event.h"
+
+namespace base {
+namespace trace_event {
+
+namespace {
+
+/////////////////////////////////////////////////////////////////////////////
+// Holds profiled system stats until the tracing system needs to serialize it.
+class SystemStatsHolder : public base::trace_event::ConvertableToTraceFormat {
+ public:
+  SystemStatsHolder() { }
+
+  // Fills system_metrics_ with profiled system memory and disk stats.
+  // Uses the previous stats to compute rates if this is not the first profile.
+  void GetSystemProfilingStats();
+
+  // base::trace_event::ConvertableToTraceFormat overrides:
+  void AppendAsTraceFormat(std::string* out) const override {
+    AppendSystemProfileAsTraceFormat(system_stats_, out);
+  }
+
+ private:
+  ~SystemStatsHolder() override {}
+
+  SystemMetrics system_stats_;
+
+  DISALLOW_COPY_AND_ASSIGN(SystemStatsHolder);
+};
+
+void SystemStatsHolder::GetSystemProfilingStats() {
+  system_stats_ = SystemMetrics::Sample();
+}
+
+}  // namespace
+
+//////////////////////////////////////////////////////////////////////////////
+
+TraceEventSystemStatsMonitor::TraceEventSystemStatsMonitor(
+    scoped_refptr<SingleThreadTaskRunner> task_runner)
+    : task_runner_(task_runner),
+      weak_factory_(this) {
+  // Force the "system_stats" category to show up in the trace viewer.
+  TraceLog::GetCategoryGroupEnabled(TRACE_DISABLED_BY_DEFAULT("system_stats"));
+
+  // Allow this to be instantiated on unsupported platforms, but don't run.
+  TraceLog::GetInstance()->AddEnabledStateObserver(this);
+}
+
+TraceEventSystemStatsMonitor::~TraceEventSystemStatsMonitor() {
+  if (dump_timer_.IsRunning())
+    StopProfiling();
+  TraceLog::GetInstance()->RemoveEnabledStateObserver(this);
+}
+
+void TraceEventSystemStatsMonitor::OnTraceLogEnabled() {
+  // Check to see if system tracing is enabled.
+  bool enabled;
+
+  TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT(
+                                     "system_stats"), &enabled);
+  if (!enabled)
+    return;
+  task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&TraceEventSystemStatsMonitor::StartProfiling,
+                 weak_factory_.GetWeakPtr()));
+}
+
+void TraceEventSystemStatsMonitor::OnTraceLogDisabled() {
+  task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&TraceEventSystemStatsMonitor::StopProfiling,
+                 weak_factory_.GetWeakPtr()));
+}
+
+void TraceEventSystemStatsMonitor::StartProfiling() {
+  // Watch for the tracing framework sending enabling more than once.
+  if (dump_timer_.IsRunning())
+    return;
+
+  dump_timer_.Start(FROM_HERE,
+                    TimeDelta::FromMilliseconds(TraceEventSystemStatsMonitor::
+                                                kSamplingIntervalMilliseconds),
+                    base::Bind(&TraceEventSystemStatsMonitor::
+                               DumpSystemStats,
+                               weak_factory_.GetWeakPtr()));
+}
+
+// If system tracing is enabled, dumps a profile to the tracing system.
+void TraceEventSystemStatsMonitor::DumpSystemStats() {
+  scoped_refptr<SystemStatsHolder> dump_holder = new SystemStatsHolder();
+  dump_holder->GetSystemProfilingStats();
+
+  TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
+      TRACE_DISABLED_BY_DEFAULT("system_stats"),
+      "base::TraceEventSystemStatsMonitor::SystemStats",
+      this,
+      scoped_refptr<ConvertableToTraceFormat>(dump_holder));
+}
+
+void TraceEventSystemStatsMonitor::StopProfiling() {
+  dump_timer_.Stop();
+}
+
+bool TraceEventSystemStatsMonitor::IsTimerRunningForTest() const {
+  return dump_timer_.IsRunning();
+}
+
+void AppendSystemProfileAsTraceFormat(const SystemMetrics& system_metrics,
+                                      std::string* output) {
+  std::string tmp;
+  base::JSONWriter::Write(*system_metrics.ToValue(), &tmp);
+  *output += tmp;
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/trace_event_system_stats_monitor.h b/base/trace_event/trace_event_system_stats_monitor.h
new file mode 100644
index 0000000..051669a
--- /dev/null
+++ b/base/trace_event/trace_event_system_stats_monitor.h
@@ -0,0 +1,75 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_TRACE_EVENT_SYSTEM_STATS_MONITOR_H_
+#define BASE_TRACE_EVENT_TRACE_EVENT_SYSTEM_STATS_MONITOR_H_
+
+#include "base/base_export.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/process/process_metrics.h"
+#include "base/timer/timer.h"
+#include "base/trace_event/trace_event_impl.h"
+
+namespace base {
+
+class SingleThreadTaskRunner;
+
+namespace trace_event {
+
+// Watches for chrome://tracing to be enabled or disabled. When tracing is
+// enabled, also enables system events profiling. This class is the preferred
+// way to turn system tracing on and off.
+class BASE_EXPORT TraceEventSystemStatsMonitor
+    : public TraceLog::EnabledStateObserver {
+ public:
+  // Length of time interval between stat profiles.
+  static const int kSamplingIntervalMilliseconds = 2000;
+
+  // |task_runner| must be the primary thread for the client
+  // process, e.g. the UI thread in a browser.
+  explicit TraceEventSystemStatsMonitor(
+      scoped_refptr<SingleThreadTaskRunner> task_runner);
+
+  virtual ~TraceEventSystemStatsMonitor();
+
+  // base::trace_event::TraceLog::EnabledStateChangedObserver overrides:
+  void OnTraceLogEnabled() override;
+  void OnTraceLogDisabled() override;
+
+  // Retrieves system profiling at the current time.
+  void DumpSystemStats();
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(TraceSystemStatsMonitorTest,
+                           TraceEventSystemStatsMonitor);
+
+  bool IsTimerRunningForTest() const;
+
+  void StartProfiling();
+
+  void StopProfiling();
+
+  // Ensures the observer starts and stops tracing on the primary thread.
+  scoped_refptr<SingleThreadTaskRunner> task_runner_;
+
+  // Timer to schedule system profile dumps.
+  RepeatingTimer<TraceEventSystemStatsMonitor> dump_timer_;
+
+  WeakPtrFactory<TraceEventSystemStatsMonitor> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(TraceEventSystemStatsMonitor);
+};
+
+// Converts system memory profiling stats in |input| to
+// trace event compatible JSON and appends to |output|. Visible for testing.
+BASE_EXPORT void AppendSystemProfileAsTraceFormat(const SystemMetrics&
+                                                  system_stats,
+                                                  std::string* output);
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_TRACE_EVENT_SYSTEM_STATS_MONITOR_H_
diff --git a/base/trace_event/trace_event_system_stats_monitor_unittest.cc b/base/trace_event/trace_event_system_stats_monitor_unittest.cc
new file mode 100644
index 0000000..03dff59
--- /dev/null
+++ b/base/trace_event/trace_event_system_stats_monitor_unittest.cc
@@ -0,0 +1,64 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/trace_event_system_stats_monitor.h"
+
+#include <sstream>
+#include <string>
+
+#include "base/trace_event/trace_event_impl.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+#if !defined(OS_IOS)
+// Tests for the system stats monitor.
+// Exists as a class so it can be a friend of TraceEventSystemStatsMonitor.
+class TraceSystemStatsMonitorTest : public testing::Test {
+ public:
+  TraceSystemStatsMonitorTest() {}
+  ~TraceSystemStatsMonitorTest() override {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TraceSystemStatsMonitorTest);
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+TEST_F(TraceSystemStatsMonitorTest, TraceEventSystemStatsMonitor) {
+  MessageLoop message_loop;
+
+  // Start with no observers of the TraceLog.
+  EXPECT_EQ(0u, TraceLog::GetInstance()->GetObserverCountForTest());
+
+  // Creating a system stats monitor adds it to the TraceLog observer list.
+  scoped_ptr<TraceEventSystemStatsMonitor> system_stats_monitor(
+      new TraceEventSystemStatsMonitor(message_loop.task_runner()));
+  EXPECT_EQ(1u, TraceLog::GetInstance()->GetObserverCountForTest());
+  EXPECT_TRUE(
+      TraceLog::GetInstance()->HasEnabledStateObserver(
+          system_stats_monitor.get()));
+
+  // By default the observer isn't dumping memory profiles.
+  EXPECT_FALSE(system_stats_monitor->IsTimerRunningForTest());
+
+  // Simulate enabling tracing.
+  system_stats_monitor->StartProfiling();
+  message_loop.RunUntilIdle();
+  EXPECT_TRUE(system_stats_monitor->IsTimerRunningForTest());
+
+  // Simulate disabling tracing.
+  system_stats_monitor->StopProfiling();
+  message_loop.RunUntilIdle();
+  EXPECT_FALSE(system_stats_monitor->IsTimerRunningForTest());
+
+  // Deleting the observer removes it from the TraceLog observer list.
+  system_stats_monitor.reset();
+  EXPECT_EQ(0u, TraceLog::GetInstance()->GetObserverCountForTest());
+}
+#endif  // !defined(OS_IOS)
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/trace_event_unittest.cc b/base/trace_event/trace_event_unittest.cc
new file mode 100644
index 0000000..796c386
--- /dev/null
+++ b/base/trace_event/trace_event_unittest.cc
@@ -0,0 +1,2897 @@
+// Copyright (c) 2012 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 <math.h>
+#include <cstdlib>
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+#include "base/location.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/singleton.h"
+#include "base/process/process_handle.h"
+#include "base/single_thread_task_runner.h"
+#include "base/strings/stringprintf.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/platform_thread.h"
+#include "base/threading/thread.h"
+#include "base/time/time.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_synthetic_delay.h"
+#include "base/values.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+namespace {
+
+enum CompareOp {
+  IS_EQUAL,
+  IS_NOT_EQUAL,
+};
+
+struct JsonKeyValue {
+  const char* key;
+  const char* value;
+  CompareOp op;
+};
+
+const int kThreadId = 42;
+const int kAsyncId = 5;
+const char kAsyncIdStr[] = "0x5";
+const int kAsyncId2 = 6;
+const char kAsyncId2Str[] = "0x6";
+const int kFlowId = 7;
+const char kFlowIdStr[] = "0x7";
+
+const  char kRecordAllCategoryFilter[] = "*";
+
+class TraceEventTestFixture : public testing::Test {
+ public:
+  void OnTraceDataCollected(
+      WaitableEvent* flush_complete_event,
+      const scoped_refptr<base::RefCountedString>& events_str,
+      bool has_more_events);
+  void OnWatchEventMatched() {
+    ++event_watch_notification_;
+  }
+  DictionaryValue* FindMatchingTraceEntry(const JsonKeyValue* key_values);
+  DictionaryValue* FindNamePhase(const char* name, const char* phase);
+  DictionaryValue* FindNamePhaseKeyValue(const char* name,
+                                         const char* phase,
+                                         const char* key,
+                                         const char* value);
+  void DropTracedMetadataRecords();
+  bool FindMatchingValue(const char* key,
+                         const char* value);
+  bool FindNonMatchingValue(const char* key,
+                            const char* value);
+  void Clear() {
+    trace_parsed_.Clear();
+    json_output_.json_output.clear();
+  }
+
+  void BeginTrace() {
+    BeginSpecificTrace("*");
+  }
+
+  void BeginSpecificTrace(const std::string& filter) {
+    event_watch_notification_ = 0;
+    TraceLog::GetInstance()->SetEnabled(TraceConfig(filter, ""),
+                                        TraceLog::RECORDING_MODE);
+  }
+
+  void EndTraceAndFlush() {
+    WaitableEvent flush_complete_event(false, false);
+    EndTraceAndFlushAsync(&flush_complete_event);
+    flush_complete_event.Wait();
+  }
+
+  // Used when testing thread-local buffers which requires the thread initiating
+  // flush to have a message loop.
+  void EndTraceAndFlushInThreadWithMessageLoop() {
+    WaitableEvent flush_complete_event(false, false);
+    Thread flush_thread("flush");
+    flush_thread.Start();
+    flush_thread.task_runner()->PostTask(
+        FROM_HERE, base::Bind(&TraceEventTestFixture::EndTraceAndFlushAsync,
+                              base::Unretained(this), &flush_complete_event));
+    flush_complete_event.Wait();
+  }
+
+  void EndTraceAndFlushAsync(WaitableEvent* flush_complete_event) {
+    TraceLog::GetInstance()->SetDisabled();
+    TraceLog::GetInstance()->Flush(
+        base::Bind(&TraceEventTestFixture::OnTraceDataCollected,
+                   base::Unretained(static_cast<TraceEventTestFixture*>(this)),
+                   base::Unretained(flush_complete_event)));
+  }
+
+  void FlushMonitoring() {
+    WaitableEvent flush_complete_event(false, false);
+    FlushMonitoring(&flush_complete_event);
+    flush_complete_event.Wait();
+  }
+
+  void FlushMonitoring(WaitableEvent* flush_complete_event) {
+    TraceLog::GetInstance()->FlushButLeaveBufferIntact(
+        base::Bind(&TraceEventTestFixture::OnTraceDataCollected,
+                   base::Unretained(static_cast<TraceEventTestFixture*>(this)),
+                   base::Unretained(flush_complete_event)));
+  }
+
+  void SetUp() override {
+    const char* name = PlatformThread::GetName();
+    old_thread_name_ = name ? strdup(name) : NULL;
+
+    TraceLog::DeleteForTesting();
+    TraceLog* tracelog = TraceLog::GetInstance();
+    ASSERT_TRUE(tracelog);
+    ASSERT_FALSE(tracelog->IsEnabled());
+    trace_buffer_.SetOutputCallback(json_output_.GetCallback());
+    event_watch_notification_ = 0;
+  }
+  void TearDown() override {
+    if (TraceLog::GetInstance())
+      EXPECT_FALSE(TraceLog::GetInstance()->IsEnabled());
+    PlatformThread::SetName(old_thread_name_ ? old_thread_name_ : "");
+    free(old_thread_name_);
+    old_thread_name_ = NULL;
+    // We want our singleton torn down after each test.
+    TraceLog::DeleteForTesting();
+  }
+
+  char* old_thread_name_;
+  ListValue trace_parsed_;
+  TraceResultBuffer trace_buffer_;
+  TraceResultBuffer::SimpleOutput json_output_;
+  int event_watch_notification_;
+
+ private:
+  // We want our singleton torn down after each test.
+  ShadowingAtExitManager at_exit_manager_;
+  Lock lock_;
+};
+
+void TraceEventTestFixture::OnTraceDataCollected(
+    WaitableEvent* flush_complete_event,
+    const scoped_refptr<base::RefCountedString>& events_str,
+    bool has_more_events) {
+  AutoLock lock(lock_);
+  json_output_.json_output.clear();
+  trace_buffer_.Start();
+  trace_buffer_.AddFragment(events_str->data());
+  trace_buffer_.Finish();
+
+  scoped_ptr<Value> root;
+  root.reset(base::JSONReader::DeprecatedRead(
+      json_output_.json_output, JSON_PARSE_RFC | JSON_DETACHABLE_CHILDREN));
+
+  if (!root.get()) {
+    LOG(ERROR) << json_output_.json_output;
+  }
+
+  ListValue* root_list = NULL;
+  ASSERT_TRUE(root.get());
+  ASSERT_TRUE(root->GetAsList(&root_list));
+
+  // Move items into our aggregate collection
+  while (root_list->GetSize()) {
+    scoped_ptr<Value> item;
+    root_list->Remove(0, &item);
+    trace_parsed_.Append(item.release());
+  }
+
+  if (!has_more_events)
+    flush_complete_event->Signal();
+}
+
+static bool CompareJsonValues(const std::string& lhs,
+                              const std::string& rhs,
+                              CompareOp op) {
+  switch (op) {
+    case IS_EQUAL:
+      return lhs == rhs;
+    case IS_NOT_EQUAL:
+      return lhs != rhs;
+    default:
+      CHECK(0);
+  }
+  return false;
+}
+
+static bool IsKeyValueInDict(const JsonKeyValue* key_value,
+                             DictionaryValue* dict) {
+  Value* value = NULL;
+  std::string value_str;
+  if (dict->Get(key_value->key, &value) &&
+      value->GetAsString(&value_str) &&
+      CompareJsonValues(value_str, key_value->value, key_value->op))
+    return true;
+
+  // Recurse to test arguments
+  DictionaryValue* args_dict = NULL;
+  dict->GetDictionary("args", &args_dict);
+  if (args_dict)
+    return IsKeyValueInDict(key_value, args_dict);
+
+  return false;
+}
+
+static bool IsAllKeyValueInDict(const JsonKeyValue* key_values,
+                                DictionaryValue* dict) {
+  // Scan all key_values, they must all be present and equal.
+  while (key_values && key_values->key) {
+    if (!IsKeyValueInDict(key_values, dict))
+      return false;
+    ++key_values;
+  }
+  return true;
+}
+
+DictionaryValue* TraceEventTestFixture::FindMatchingTraceEntry(
+    const JsonKeyValue* key_values) {
+  // Scan all items
+  size_t trace_parsed_count = trace_parsed_.GetSize();
+  for (size_t i = 0; i < trace_parsed_count; i++) {
+    Value* value = NULL;
+    trace_parsed_.Get(i, &value);
+    if (!value || value->GetType() != Value::TYPE_DICTIONARY)
+      continue;
+    DictionaryValue* dict = static_cast<DictionaryValue*>(value);
+
+    if (IsAllKeyValueInDict(key_values, dict))
+      return dict;
+  }
+  return NULL;
+}
+
+void TraceEventTestFixture::DropTracedMetadataRecords() {
+  scoped_ptr<ListValue> old_trace_parsed(trace_parsed_.DeepCopy());
+  size_t old_trace_parsed_size = old_trace_parsed->GetSize();
+  trace_parsed_.Clear();
+
+  for (size_t i = 0; i < old_trace_parsed_size; i++) {
+    Value* value = NULL;
+    old_trace_parsed->Get(i, &value);
+    if (!value || value->GetType() != Value::TYPE_DICTIONARY) {
+      trace_parsed_.Append(value->DeepCopy());
+      continue;
+    }
+    DictionaryValue* dict = static_cast<DictionaryValue*>(value);
+    std::string tmp;
+    if (dict->GetString("ph", &tmp) && tmp == "M")
+      continue;
+
+    trace_parsed_.Append(value->DeepCopy());
+  }
+}
+
+DictionaryValue* TraceEventTestFixture::FindNamePhase(const char* name,
+                                                      const char* phase) {
+  JsonKeyValue key_values[] = {
+    {"name", name, IS_EQUAL},
+    {"ph", phase, IS_EQUAL},
+    {0, 0, IS_EQUAL}
+  };
+  return FindMatchingTraceEntry(key_values);
+}
+
+DictionaryValue* TraceEventTestFixture::FindNamePhaseKeyValue(
+    const char* name,
+    const char* phase,
+    const char* key,
+    const char* value) {
+  JsonKeyValue key_values[] = {
+    {"name", name, IS_EQUAL},
+    {"ph", phase, IS_EQUAL},
+    {key, value, IS_EQUAL},
+    {0, 0, IS_EQUAL}
+  };
+  return FindMatchingTraceEntry(key_values);
+}
+
+bool TraceEventTestFixture::FindMatchingValue(const char* key,
+                                              const char* value) {
+  JsonKeyValue key_values[] = {
+    {key, value, IS_EQUAL},
+    {0, 0, IS_EQUAL}
+  };
+  return FindMatchingTraceEntry(key_values);
+}
+
+bool TraceEventTestFixture::FindNonMatchingValue(const char* key,
+                                                 const char* value) {
+  JsonKeyValue key_values[] = {
+    {key, value, IS_NOT_EQUAL},
+    {0, 0, IS_EQUAL}
+  };
+  return FindMatchingTraceEntry(key_values);
+}
+
+bool IsStringInDict(const char* string_to_match, const DictionaryValue* dict) {
+  for (DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) {
+    if (it.key().find(string_to_match) != std::string::npos)
+      return true;
+
+    std::string value_str;
+    it.value().GetAsString(&value_str);
+    if (value_str.find(string_to_match) != std::string::npos)
+      return true;
+  }
+
+  // Recurse to test arguments
+  const DictionaryValue* args_dict = NULL;
+  dict->GetDictionary("args", &args_dict);
+  if (args_dict)
+    return IsStringInDict(string_to_match, args_dict);
+
+  return false;
+}
+
+const DictionaryValue* FindTraceEntry(
+    const ListValue& trace_parsed,
+    const char* string_to_match,
+    const DictionaryValue* match_after_this_item = NULL) {
+  // Scan all items
+  size_t trace_parsed_count = trace_parsed.GetSize();
+  for (size_t i = 0; i < trace_parsed_count; i++) {
+    const Value* value = NULL;
+    trace_parsed.Get(i, &value);
+    if (match_after_this_item) {
+      if (value == match_after_this_item)
+         match_after_this_item = NULL;
+      continue;
+    }
+    if (!value || value->GetType() != Value::TYPE_DICTIONARY)
+      continue;
+    const DictionaryValue* dict = static_cast<const DictionaryValue*>(value);
+
+    if (IsStringInDict(string_to_match, dict))
+      return dict;
+  }
+  return NULL;
+}
+
+std::vector<const DictionaryValue*> FindTraceEntries(
+    const ListValue& trace_parsed,
+    const char* string_to_match) {
+  std::vector<const DictionaryValue*> hits;
+  size_t trace_parsed_count = trace_parsed.GetSize();
+  for (size_t i = 0; i < trace_parsed_count; i++) {
+    const Value* value = NULL;
+    trace_parsed.Get(i, &value);
+    if (!value || value->GetType() != Value::TYPE_DICTIONARY)
+      continue;
+    const DictionaryValue* dict = static_cast<const DictionaryValue*>(value);
+
+    if (IsStringInDict(string_to_match, dict))
+      hits.push_back(dict);
+  }
+  return hits;
+}
+
+const char kControlCharacters[] = "\001\002\003\n\r";
+
+void TraceWithAllMacroVariants(WaitableEvent* task_complete_event) {
+  {
+    TRACE_EVENT_BEGIN_ETW("TRACE_EVENT_BEGIN_ETW call", 0x1122, "extrastring1");
+    TRACE_EVENT_END_ETW("TRACE_EVENT_END_ETW call", 0x3344, "extrastring2");
+    TRACE_EVENT_INSTANT_ETW("TRACE_EVENT_INSTANT_ETW call",
+                            0x5566, "extrastring3");
+
+    TRACE_EVENT0("all", "TRACE_EVENT0 call");
+    TRACE_EVENT1("all", "TRACE_EVENT1 call", "name1", "value1");
+    TRACE_EVENT2("all", "TRACE_EVENT2 call",
+                 "name1", "\"value1\"",
+                 "name2", "value\\2");
+
+    TRACE_EVENT_INSTANT0("all", "TRACE_EVENT_INSTANT0 call",
+                         TRACE_EVENT_SCOPE_GLOBAL);
+    TRACE_EVENT_INSTANT1("all", "TRACE_EVENT_INSTANT1 call",
+                         TRACE_EVENT_SCOPE_PROCESS, "name1", "value1");
+    TRACE_EVENT_INSTANT2("all", "TRACE_EVENT_INSTANT2 call",
+                         TRACE_EVENT_SCOPE_THREAD,
+                         "name1", "value1",
+                         "name2", "value2");
+
+    TRACE_EVENT_BEGIN0("all", "TRACE_EVENT_BEGIN0 call");
+    TRACE_EVENT_BEGIN1("all", "TRACE_EVENT_BEGIN1 call", "name1", "value1");
+    TRACE_EVENT_BEGIN2("all", "TRACE_EVENT_BEGIN2 call",
+                       "name1", "value1",
+                       "name2", "value2");
+
+    TRACE_EVENT_END0("all", "TRACE_EVENT_END0 call");
+    TRACE_EVENT_END1("all", "TRACE_EVENT_END1 call", "name1", "value1");
+    TRACE_EVENT_END2("all", "TRACE_EVENT_END2 call",
+                     "name1", "value1",
+                     "name2", "value2");
+
+    TRACE_EVENT_ASYNC_BEGIN0("all", "TRACE_EVENT_ASYNC_BEGIN0 call", kAsyncId);
+    TRACE_EVENT_ASYNC_BEGIN1("all", "TRACE_EVENT_ASYNC_BEGIN1 call", kAsyncId,
+                             "name1", "value1");
+    TRACE_EVENT_ASYNC_BEGIN2("all", "TRACE_EVENT_ASYNC_BEGIN2 call", kAsyncId,
+                             "name1", "value1",
+                             "name2", "value2");
+
+    TRACE_EVENT_ASYNC_STEP_INTO0("all", "TRACE_EVENT_ASYNC_STEP_INTO0 call",
+                                 kAsyncId, "step_begin1");
+    TRACE_EVENT_ASYNC_STEP_INTO1("all", "TRACE_EVENT_ASYNC_STEP_INTO1 call",
+                                 kAsyncId, "step_begin2", "name1", "value1");
+
+    TRACE_EVENT_ASYNC_END0("all", "TRACE_EVENT_ASYNC_END0 call", kAsyncId);
+    TRACE_EVENT_ASYNC_END1("all", "TRACE_EVENT_ASYNC_END1 call", kAsyncId,
+                           "name1", "value1");
+    TRACE_EVENT_ASYNC_END2("all", "TRACE_EVENT_ASYNC_END2 call", kAsyncId,
+                           "name1", "value1",
+                           "name2", "value2");
+
+    TRACE_EVENT_FLOW_BEGIN0("all", "TRACE_EVENT_FLOW_BEGIN0 call", kFlowId);
+    TRACE_EVENT_FLOW_STEP0("all", "TRACE_EVENT_FLOW_STEP0 call",
+                           kFlowId, "step1");
+    TRACE_EVENT_FLOW_END_BIND_TO_ENCLOSING0("all",
+        "TRACE_EVENT_FLOW_END_BIND_TO_ENCLOSING0 call", kFlowId);
+
+    TRACE_EVENT_BEGIN_ETW("TRACE_EVENT_BEGIN_ETW0 call", kAsyncId, NULL);
+    TRACE_EVENT_BEGIN_ETW("TRACE_EVENT_BEGIN_ETW1 call", kAsyncId, "value");
+    TRACE_EVENT_END_ETW("TRACE_EVENT_END_ETW0 call", kAsyncId, NULL);
+    TRACE_EVENT_END_ETW("TRACE_EVENT_END_ETW1 call", kAsyncId, "value");
+    TRACE_EVENT_INSTANT_ETW("TRACE_EVENT_INSTANT_ETW0 call", kAsyncId, NULL);
+    TRACE_EVENT_INSTANT_ETW("TRACE_EVENT_INSTANT_ETW1 call", kAsyncId, "value");
+
+    TRACE_COUNTER1("all", "TRACE_COUNTER1 call", 31415);
+    TRACE_COUNTER2("all", "TRACE_COUNTER2 call",
+                   "a", 30000,
+                   "b", 1415);
+
+    TRACE_COUNTER_ID1("all", "TRACE_COUNTER_ID1 call", 0x319009, 31415);
+    TRACE_COUNTER_ID2("all", "TRACE_COUNTER_ID2 call", 0x319009,
+                      "a", 30000, "b", 1415);
+
+    TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP0("all",
+        "TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP0 call",
+        kAsyncId, kThreadId, 12345);
+    TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP0("all",
+        "TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP0 call",
+        kAsyncId, kThreadId, 23456);
+
+    TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0("all",
+        "TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0 call",
+        kAsyncId2, kThreadId, 34567);
+    TRACE_EVENT_ASYNC_STEP_PAST0("all", "TRACE_EVENT_ASYNC_STEP_PAST0 call",
+                                 kAsyncId2, "step_end1");
+    TRACE_EVENT_ASYNC_STEP_PAST1("all", "TRACE_EVENT_ASYNC_STEP_PAST1 call",
+                                 kAsyncId2, "step_end2", "name1", "value1");
+
+    TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0("all",
+        "TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0 call",
+        kAsyncId2, kThreadId, 45678);
+
+    TRACE_EVENT_OBJECT_CREATED_WITH_ID("all", "tracked object 1", 0x42);
+    TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
+        "all", "tracked object 1", 0x42, "hello");
+    TRACE_EVENT_OBJECT_DELETED_WITH_ID("all", "tracked object 1", 0x42);
+
+    TraceScopedTrackableObject<int> trackable("all", "tracked object 2",
+                                              0x2128506);
+    trackable.snapshot("world");
+
+    TRACE_EVENT1(kControlCharacters, kControlCharacters,
+                 kControlCharacters, kControlCharacters);
+  }  // Scope close causes TRACE_EVENT0 etc to send their END events.
+
+  if (task_complete_event)
+    task_complete_event->Signal();
+}
+
+void ValidateAllTraceMacrosCreatedData(const ListValue& trace_parsed) {
+  const DictionaryValue* item = NULL;
+
+#define EXPECT_FIND_(string) \
+    item = FindTraceEntry(trace_parsed, string); \
+    EXPECT_TRUE(item);
+#define EXPECT_NOT_FIND_(string) \
+    item = FindTraceEntry(trace_parsed, string); \
+    EXPECT_FALSE(item);
+#define EXPECT_SUB_FIND_(string) \
+    if (item) \
+      EXPECT_TRUE(IsStringInDict(string, item));
+
+  EXPECT_FIND_("ETW Trace Event");
+  EXPECT_FIND_("all");
+  EXPECT_FIND_("TRACE_EVENT_BEGIN_ETW call");
+  {
+    std::string str_val;
+    EXPECT_TRUE(item && item->GetString("args.id", &str_val));
+    EXPECT_STREQ("0x1122", str_val.c_str());
+  }
+  EXPECT_SUB_FIND_("extrastring1");
+  EXPECT_FIND_("TRACE_EVENT_END_ETW call");
+  EXPECT_FIND_("TRACE_EVENT_INSTANT_ETW call");
+  EXPECT_FIND_("TRACE_EVENT0 call");
+  {
+    std::string ph;
+    std::string ph_end;
+    EXPECT_TRUE((item = FindTraceEntry(trace_parsed, "TRACE_EVENT0 call")));
+    EXPECT_TRUE((item && item->GetString("ph", &ph)));
+    EXPECT_EQ("X", ph);
+    item = FindTraceEntry(trace_parsed, "TRACE_EVENT0 call", item);
+    EXPECT_FALSE(item);
+  }
+  EXPECT_FIND_("TRACE_EVENT1 call");
+  EXPECT_SUB_FIND_("name1");
+  EXPECT_SUB_FIND_("value1");
+  EXPECT_FIND_("TRACE_EVENT2 call");
+  EXPECT_SUB_FIND_("name1");
+  EXPECT_SUB_FIND_("\"value1\"");
+  EXPECT_SUB_FIND_("name2");
+  EXPECT_SUB_FIND_("value\\2");
+
+  EXPECT_FIND_("TRACE_EVENT_INSTANT0 call");
+  {
+    std::string scope;
+    EXPECT_TRUE((item && item->GetString("s", &scope)));
+    EXPECT_EQ("g", scope);
+  }
+  EXPECT_FIND_("TRACE_EVENT_INSTANT1 call");
+  {
+    std::string scope;
+    EXPECT_TRUE((item && item->GetString("s", &scope)));
+    EXPECT_EQ("p", scope);
+  }
+  EXPECT_SUB_FIND_("name1");
+  EXPECT_SUB_FIND_("value1");
+  EXPECT_FIND_("TRACE_EVENT_INSTANT2 call");
+  {
+    std::string scope;
+    EXPECT_TRUE((item && item->GetString("s", &scope)));
+    EXPECT_EQ("t", scope);
+  }
+  EXPECT_SUB_FIND_("name1");
+  EXPECT_SUB_FIND_("value1");
+  EXPECT_SUB_FIND_("name2");
+  EXPECT_SUB_FIND_("value2");
+
+  EXPECT_FIND_("TRACE_EVENT_BEGIN0 call");
+  EXPECT_FIND_("TRACE_EVENT_BEGIN1 call");
+  EXPECT_SUB_FIND_("name1");
+  EXPECT_SUB_FIND_("value1");
+  EXPECT_FIND_("TRACE_EVENT_BEGIN2 call");
+  EXPECT_SUB_FIND_("name1");
+  EXPECT_SUB_FIND_("value1");
+  EXPECT_SUB_FIND_("name2");
+  EXPECT_SUB_FIND_("value2");
+
+  EXPECT_FIND_("TRACE_EVENT_END0 call");
+  EXPECT_FIND_("TRACE_EVENT_END1 call");
+  EXPECT_SUB_FIND_("name1");
+  EXPECT_SUB_FIND_("value1");
+  EXPECT_FIND_("TRACE_EVENT_END2 call");
+  EXPECT_SUB_FIND_("name1");
+  EXPECT_SUB_FIND_("value1");
+  EXPECT_SUB_FIND_("name2");
+  EXPECT_SUB_FIND_("value2");
+
+  EXPECT_FIND_("TRACE_EVENT_ASYNC_BEGIN0 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_(kAsyncIdStr);
+  EXPECT_FIND_("TRACE_EVENT_ASYNC_BEGIN1 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_(kAsyncIdStr);
+  EXPECT_SUB_FIND_("name1");
+  EXPECT_SUB_FIND_("value1");
+  EXPECT_FIND_("TRACE_EVENT_ASYNC_BEGIN2 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_(kAsyncIdStr);
+  EXPECT_SUB_FIND_("name1");
+  EXPECT_SUB_FIND_("value1");
+  EXPECT_SUB_FIND_("name2");
+  EXPECT_SUB_FIND_("value2");
+
+  EXPECT_FIND_("TRACE_EVENT_ASYNC_STEP_INTO0 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_(kAsyncIdStr);
+  EXPECT_SUB_FIND_("step_begin1");
+  EXPECT_FIND_("TRACE_EVENT_ASYNC_STEP_INTO1 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_(kAsyncIdStr);
+  EXPECT_SUB_FIND_("step_begin2");
+  EXPECT_SUB_FIND_("name1");
+  EXPECT_SUB_FIND_("value1");
+
+  EXPECT_FIND_("TRACE_EVENT_ASYNC_END0 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_(kAsyncIdStr);
+  EXPECT_FIND_("TRACE_EVENT_ASYNC_END1 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_(kAsyncIdStr);
+  EXPECT_SUB_FIND_("name1");
+  EXPECT_SUB_FIND_("value1");
+  EXPECT_FIND_("TRACE_EVENT_ASYNC_END2 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_(kAsyncIdStr);
+  EXPECT_SUB_FIND_("name1");
+  EXPECT_SUB_FIND_("value1");
+  EXPECT_SUB_FIND_("name2");
+  EXPECT_SUB_FIND_("value2");
+
+  EXPECT_FIND_("TRACE_EVENT_FLOW_BEGIN0 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_(kFlowIdStr);
+  EXPECT_FIND_("TRACE_EVENT_FLOW_STEP0 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_(kFlowIdStr);
+  EXPECT_SUB_FIND_("step1");
+  EXPECT_FIND_("TRACE_EVENT_FLOW_END_BIND_TO_ENCLOSING0 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_(kFlowIdStr);
+
+  EXPECT_FIND_("TRACE_EVENT_BEGIN_ETW0 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_(kAsyncIdStr);
+  EXPECT_SUB_FIND_("extra");
+  EXPECT_SUB_FIND_("NULL");
+  EXPECT_FIND_("TRACE_EVENT_BEGIN_ETW1 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_(kAsyncIdStr);
+  EXPECT_SUB_FIND_("extra");
+  EXPECT_SUB_FIND_("value");
+  EXPECT_FIND_("TRACE_EVENT_END_ETW0 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_(kAsyncIdStr);
+  EXPECT_SUB_FIND_("extra");
+  EXPECT_SUB_FIND_("NULL");
+  EXPECT_FIND_("TRACE_EVENT_END_ETW1 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_(kAsyncIdStr);
+  EXPECT_SUB_FIND_("extra");
+  EXPECT_SUB_FIND_("value");
+  EXPECT_FIND_("TRACE_EVENT_INSTANT_ETW0 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_(kAsyncIdStr);
+  EXPECT_SUB_FIND_("extra");
+  EXPECT_SUB_FIND_("NULL");
+  EXPECT_FIND_("TRACE_EVENT_INSTANT_ETW1 call");
+  EXPECT_SUB_FIND_("id");
+  EXPECT_SUB_FIND_(kAsyncIdStr);
+  EXPECT_SUB_FIND_("extra");
+  EXPECT_SUB_FIND_("value");
+
+  EXPECT_FIND_("TRACE_COUNTER1 call");
+  {
+    std::string ph;
+    EXPECT_TRUE((item && item->GetString("ph", &ph)));
+    EXPECT_EQ("C", ph);
+
+    int value;
+    EXPECT_TRUE((item && item->GetInteger("args.value", &value)));
+    EXPECT_EQ(31415, value);
+  }
+
+  EXPECT_FIND_("TRACE_COUNTER2 call");
+  {
+    std::string ph;
+    EXPECT_TRUE((item && item->GetString("ph", &ph)));
+    EXPECT_EQ("C", ph);
+
+    int value;
+    EXPECT_TRUE((item && item->GetInteger("args.a", &value)));
+    EXPECT_EQ(30000, value);
+
+    EXPECT_TRUE((item && item->GetInteger("args.b", &value)));
+    EXPECT_EQ(1415, value);
+  }
+
+  EXPECT_FIND_("TRACE_COUNTER_ID1 call");
+  {
+    std::string id;
+    EXPECT_TRUE((item && item->GetString("id", &id)));
+    EXPECT_EQ("0x319009", id);
+
+    std::string ph;
+    EXPECT_TRUE((item && item->GetString("ph", &ph)));
+    EXPECT_EQ("C", ph);
+
+    int value;
+    EXPECT_TRUE((item && item->GetInteger("args.value", &value)));
+    EXPECT_EQ(31415, value);
+  }
+
+  EXPECT_FIND_("TRACE_COUNTER_ID2 call");
+  {
+    std::string id;
+    EXPECT_TRUE((item && item->GetString("id", &id)));
+    EXPECT_EQ("0x319009", id);
+
+    std::string ph;
+    EXPECT_TRUE((item && item->GetString("ph", &ph)));
+    EXPECT_EQ("C", ph);
+
+    int value;
+    EXPECT_TRUE((item && item->GetInteger("args.a", &value)));
+    EXPECT_EQ(30000, value);
+
+    EXPECT_TRUE((item && item->GetInteger("args.b", &value)));
+    EXPECT_EQ(1415, value);
+  }
+
+  EXPECT_FIND_("TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP0 call");
+  {
+    int val;
+    EXPECT_TRUE((item && item->GetInteger("ts", &val)));
+    EXPECT_EQ(12345, val);
+    EXPECT_TRUE((item && item->GetInteger("tid", &val)));
+    EXPECT_EQ(kThreadId, val);
+    std::string id;
+    EXPECT_TRUE((item && item->GetString("id", &id)));
+    EXPECT_EQ(kAsyncIdStr, id);
+  }
+
+  EXPECT_FIND_("TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP0 call");
+  {
+    int val;
+    EXPECT_TRUE((item && item->GetInteger("ts", &val)));
+    EXPECT_EQ(23456, val);
+    EXPECT_TRUE((item && item->GetInteger("tid", &val)));
+    EXPECT_EQ(kThreadId, val);
+    std::string id;
+    EXPECT_TRUE((item && item->GetString("id", &id)));
+    EXPECT_EQ(kAsyncIdStr, id);
+  }
+
+  EXPECT_FIND_("TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0 call");
+  {
+    int val;
+    EXPECT_TRUE((item && item->GetInteger("ts", &val)));
+    EXPECT_EQ(34567, val);
+    EXPECT_TRUE((item && item->GetInteger("tid", &val)));
+    EXPECT_EQ(kThreadId, val);
+    std::string id;
+    EXPECT_TRUE((item && item->GetString("id", &id)));
+    EXPECT_EQ(kAsyncId2Str, id);
+  }
+
+  EXPECT_FIND_("TRACE_EVENT_ASYNC_STEP_PAST0 call");
+  {
+    EXPECT_SUB_FIND_("id");
+    EXPECT_SUB_FIND_(kAsyncId2Str);
+    EXPECT_SUB_FIND_("step_end1");
+    EXPECT_FIND_("TRACE_EVENT_ASYNC_STEP_PAST1 call");
+    EXPECT_SUB_FIND_("id");
+    EXPECT_SUB_FIND_(kAsyncId2Str);
+    EXPECT_SUB_FIND_("step_end2");
+    EXPECT_SUB_FIND_("name1");
+    EXPECT_SUB_FIND_("value1");
+  }
+
+  EXPECT_FIND_("TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0 call");
+  {
+    int val;
+    EXPECT_TRUE((item && item->GetInteger("ts", &val)));
+    EXPECT_EQ(45678, val);
+    EXPECT_TRUE((item && item->GetInteger("tid", &val)));
+    EXPECT_EQ(kThreadId, val);
+    std::string id;
+    EXPECT_TRUE((item && item->GetString("id", &id)));
+    EXPECT_EQ(kAsyncId2Str, id);
+  }
+
+  EXPECT_FIND_("tracked object 1");
+  {
+    std::string phase;
+    std::string id;
+    std::string snapshot;
+
+    EXPECT_TRUE((item && item->GetString("ph", &phase)));
+    EXPECT_EQ("N", phase);
+    EXPECT_TRUE((item && item->GetString("id", &id)));
+    EXPECT_EQ("0x42", id);
+
+    item = FindTraceEntry(trace_parsed, "tracked object 1", item);
+    EXPECT_TRUE(item);
+    EXPECT_TRUE(item && item->GetString("ph", &phase));
+    EXPECT_EQ("O", phase);
+    EXPECT_TRUE(item && item->GetString("id", &id));
+    EXPECT_EQ("0x42", id);
+    EXPECT_TRUE(item && item->GetString("args.snapshot", &snapshot));
+    EXPECT_EQ("hello", snapshot);
+
+    item = FindTraceEntry(trace_parsed, "tracked object 1", item);
+    EXPECT_TRUE(item);
+    EXPECT_TRUE(item && item->GetString("ph", &phase));
+    EXPECT_EQ("D", phase);
+    EXPECT_TRUE(item && item->GetString("id", &id));
+    EXPECT_EQ("0x42", id);
+  }
+
+  EXPECT_FIND_("tracked object 2");
+  {
+    std::string phase;
+    std::string id;
+    std::string snapshot;
+
+    EXPECT_TRUE(item && item->GetString("ph", &phase));
+    EXPECT_EQ("N", phase);
+    EXPECT_TRUE(item && item->GetString("id", &id));
+    EXPECT_EQ("0x2128506", id);
+
+    item = FindTraceEntry(trace_parsed, "tracked object 2", item);
+    EXPECT_TRUE(item);
+    EXPECT_TRUE(item && item->GetString("ph", &phase));
+    EXPECT_EQ("O", phase);
+    EXPECT_TRUE(item && item->GetString("id", &id));
+    EXPECT_EQ("0x2128506", id);
+    EXPECT_TRUE(item && item->GetString("args.snapshot", &snapshot));
+    EXPECT_EQ("world", snapshot);
+
+    item = FindTraceEntry(trace_parsed, "tracked object 2", item);
+    EXPECT_TRUE(item);
+    EXPECT_TRUE(item && item->GetString("ph", &phase));
+    EXPECT_EQ("D", phase);
+    EXPECT_TRUE(item && item->GetString("id", &id));
+    EXPECT_EQ("0x2128506", id);
+  }
+
+  EXPECT_FIND_(kControlCharacters);
+  EXPECT_SUB_FIND_(kControlCharacters);
+}
+
+void TraceManyInstantEvents(int thread_id, int num_events,
+                            WaitableEvent* task_complete_event) {
+  for (int i = 0; i < num_events; i++) {
+    TRACE_EVENT_INSTANT2("all", "multi thread event",
+                         TRACE_EVENT_SCOPE_THREAD,
+                         "thread", thread_id,
+                         "event", i);
+  }
+
+  if (task_complete_event)
+    task_complete_event->Signal();
+}
+
+void ValidateInstantEventPresentOnEveryThread(const ListValue& trace_parsed,
+                                              int num_threads,
+                                              int num_events) {
+  std::map<int, std::map<int, bool> > results;
+
+  size_t trace_parsed_count = trace_parsed.GetSize();
+  for (size_t i = 0; i < trace_parsed_count; i++) {
+    const Value* value = NULL;
+    trace_parsed.Get(i, &value);
+    if (!value || value->GetType() != Value::TYPE_DICTIONARY)
+      continue;
+    const DictionaryValue* dict = static_cast<const DictionaryValue*>(value);
+    std::string name;
+    dict->GetString("name", &name);
+    if (name != "multi thread event")
+      continue;
+
+    int thread = 0;
+    int event = 0;
+    EXPECT_TRUE(dict->GetInteger("args.thread", &thread));
+    EXPECT_TRUE(dict->GetInteger("args.event", &event));
+    results[thread][event] = true;
+  }
+
+  EXPECT_FALSE(results[-1][-1]);
+  for (int thread = 0; thread < num_threads; thread++) {
+    for (int event = 0; event < num_events; event++) {
+      EXPECT_TRUE(results[thread][event]);
+    }
+  }
+}
+
+}  // namespace
+
+// Simple Test for emitting data and validating it was received.
+TEST_F(TraceEventTestFixture, DataCaptured) {
+  TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
+                                      TraceLog::RECORDING_MODE);
+
+  TraceWithAllMacroVariants(NULL);
+
+  EndTraceAndFlush();
+
+  ValidateAllTraceMacrosCreatedData(trace_parsed_);
+}
+
+class MockEnabledStateChangedObserver :
+      public TraceLog::EnabledStateObserver {
+ public:
+  MOCK_METHOD0(OnTraceLogEnabled, void());
+  MOCK_METHOD0(OnTraceLogDisabled, void());
+};
+
+TEST_F(TraceEventTestFixture, EnabledObserverFiresOnEnable) {
+  MockEnabledStateChangedObserver observer;
+  TraceLog::GetInstance()->AddEnabledStateObserver(&observer);
+
+  EXPECT_CALL(observer, OnTraceLogEnabled())
+      .Times(1);
+  TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
+                                      TraceLog::RECORDING_MODE);
+  testing::Mock::VerifyAndClear(&observer);
+  EXPECT_TRUE(TraceLog::GetInstance()->IsEnabled());
+
+  // Cleanup.
+  TraceLog::GetInstance()->RemoveEnabledStateObserver(&observer);
+  TraceLog::GetInstance()->SetDisabled();
+}
+
+TEST_F(TraceEventTestFixture, EnabledObserverDoesntFireOnSecondEnable) {
+  TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
+                                      TraceLog::RECORDING_MODE);
+
+  testing::StrictMock<MockEnabledStateChangedObserver> observer;
+  TraceLog::GetInstance()->AddEnabledStateObserver(&observer);
+
+  EXPECT_CALL(observer, OnTraceLogEnabled())
+      .Times(0);
+  EXPECT_CALL(observer, OnTraceLogDisabled())
+      .Times(0);
+  TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
+                                      TraceLog::RECORDING_MODE);
+  testing::Mock::VerifyAndClear(&observer);
+  EXPECT_TRUE(TraceLog::GetInstance()->IsEnabled());
+
+  // Cleanup.
+  TraceLog::GetInstance()->RemoveEnabledStateObserver(&observer);
+  TraceLog::GetInstance()->SetDisabled();
+  TraceLog::GetInstance()->SetDisabled();
+}
+
+TEST_F(TraceEventTestFixture, EnabledObserverFiresOnFirstDisable) {
+  TraceConfig tc_inc_all("*", "");
+  TraceLog::GetInstance()->SetEnabled(tc_inc_all, TraceLog::RECORDING_MODE);
+  TraceLog::GetInstance()->SetEnabled(tc_inc_all, TraceLog::RECORDING_MODE);
+
+  testing::StrictMock<MockEnabledStateChangedObserver> observer;
+  TraceLog::GetInstance()->AddEnabledStateObserver(&observer);
+
+  EXPECT_CALL(observer, OnTraceLogEnabled())
+      .Times(0);
+  EXPECT_CALL(observer, OnTraceLogDisabled())
+      .Times(1);
+  TraceLog::GetInstance()->SetDisabled();
+  testing::Mock::VerifyAndClear(&observer);
+
+  // Cleanup.
+  TraceLog::GetInstance()->RemoveEnabledStateObserver(&observer);
+  TraceLog::GetInstance()->SetDisabled();
+}
+
+TEST_F(TraceEventTestFixture, EnabledObserverFiresOnDisable) {
+  TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
+                                      TraceLog::RECORDING_MODE);
+
+  MockEnabledStateChangedObserver observer;
+  TraceLog::GetInstance()->AddEnabledStateObserver(&observer);
+
+  EXPECT_CALL(observer, OnTraceLogDisabled())
+      .Times(1);
+  TraceLog::GetInstance()->SetDisabled();
+  testing::Mock::VerifyAndClear(&observer);
+
+  // Cleanup.
+  TraceLog::GetInstance()->RemoveEnabledStateObserver(&observer);
+}
+
+// Tests the IsEnabled() state of TraceLog changes before callbacks.
+class AfterStateChangeEnabledStateObserver
+    : public TraceLog::EnabledStateObserver {
+ public:
+  AfterStateChangeEnabledStateObserver() {}
+  virtual ~AfterStateChangeEnabledStateObserver() {}
+
+  // TraceLog::EnabledStateObserver overrides:
+  void OnTraceLogEnabled() override {
+    EXPECT_TRUE(TraceLog::GetInstance()->IsEnabled());
+  }
+
+  void OnTraceLogDisabled() override {
+    EXPECT_FALSE(TraceLog::GetInstance()->IsEnabled());
+  }
+};
+
+TEST_F(TraceEventTestFixture, ObserversFireAfterStateChange) {
+  AfterStateChangeEnabledStateObserver observer;
+  TraceLog::GetInstance()->AddEnabledStateObserver(&observer);
+
+  TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
+                                      TraceLog::RECORDING_MODE);
+  EXPECT_TRUE(TraceLog::GetInstance()->IsEnabled());
+
+  TraceLog::GetInstance()->SetDisabled();
+  EXPECT_FALSE(TraceLog::GetInstance()->IsEnabled());
+
+  TraceLog::GetInstance()->RemoveEnabledStateObserver(&observer);
+}
+
+// Tests that a state observer can remove itself during a callback.
+class SelfRemovingEnabledStateObserver
+    : public TraceLog::EnabledStateObserver {
+ public:
+  SelfRemovingEnabledStateObserver() {}
+  virtual ~SelfRemovingEnabledStateObserver() {}
+
+  // TraceLog::EnabledStateObserver overrides:
+  void OnTraceLogEnabled() override {}
+
+  void OnTraceLogDisabled() override {
+    TraceLog::GetInstance()->RemoveEnabledStateObserver(this);
+  }
+};
+
+TEST_F(TraceEventTestFixture, SelfRemovingObserver) {
+  ASSERT_EQ(0u, TraceLog::GetInstance()->GetObserverCountForTest());
+
+  SelfRemovingEnabledStateObserver observer;
+  TraceLog::GetInstance()->AddEnabledStateObserver(&observer);
+  EXPECT_EQ(1u, TraceLog::GetInstance()->GetObserverCountForTest());
+
+  TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
+                                      TraceLog::RECORDING_MODE);
+  TraceLog::GetInstance()->SetDisabled();
+  // The observer removed itself on disable.
+  EXPECT_EQ(0u, TraceLog::GetInstance()->GetObserverCountForTest());
+}
+
+bool IsNewTrace() {
+  bool is_new_trace;
+  TRACE_EVENT_IS_NEW_TRACE(&is_new_trace);
+  return is_new_trace;
+}
+
+TEST_F(TraceEventTestFixture, NewTraceRecording) {
+  ASSERT_FALSE(IsNewTrace());
+  TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
+                                      TraceLog::RECORDING_MODE);
+  // First call to IsNewTrace() should succeed. But, the second shouldn't.
+  ASSERT_TRUE(IsNewTrace());
+  ASSERT_FALSE(IsNewTrace());
+  EndTraceAndFlush();
+
+  // IsNewTrace() should definitely be false now.
+  ASSERT_FALSE(IsNewTrace());
+
+  // Start another trace. IsNewTrace() should become true again, briefly, as
+  // before.
+  TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
+                                      TraceLog::RECORDING_MODE);
+  ASSERT_TRUE(IsNewTrace());
+  ASSERT_FALSE(IsNewTrace());
+
+  // Cleanup.
+  EndTraceAndFlush();
+}
+
+
+// Test that categories work.
+TEST_F(TraceEventTestFixture, Categories) {
+  // Test that categories that are used can be retrieved whether trace was
+  // enabled or disabled when the trace event was encountered.
+  TRACE_EVENT_INSTANT0("c1", "name", TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("c2", "name", TRACE_EVENT_SCOPE_THREAD);
+  BeginTrace();
+  TRACE_EVENT_INSTANT0("c3", "name", TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("c4", "name", TRACE_EVENT_SCOPE_THREAD);
+  // Category groups containing more than one category.
+  TRACE_EVENT_INSTANT0("c5,c6", "name", TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("c7,c8", "name", TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("c9"), "name",
+                       TRACE_EVENT_SCOPE_THREAD);
+
+  EndTraceAndFlush();
+  std::vector<std::string> cat_groups;
+  TraceLog::GetInstance()->GetKnownCategoryGroups(&cat_groups);
+  EXPECT_TRUE(std::find(cat_groups.begin(),
+                        cat_groups.end(), "c1") != cat_groups.end());
+  EXPECT_TRUE(std::find(cat_groups.begin(),
+                        cat_groups.end(), "c2") != cat_groups.end());
+  EXPECT_TRUE(std::find(cat_groups.begin(),
+                        cat_groups.end(), "c3") != cat_groups.end());
+  EXPECT_TRUE(std::find(cat_groups.begin(),
+                        cat_groups.end(), "c4") != cat_groups.end());
+  EXPECT_TRUE(std::find(cat_groups.begin(),
+                        cat_groups.end(), "c5,c6") != cat_groups.end());
+  EXPECT_TRUE(std::find(cat_groups.begin(),
+                        cat_groups.end(), "c7,c8") != cat_groups.end());
+  EXPECT_TRUE(std::find(cat_groups.begin(),
+                        cat_groups.end(),
+                        "disabled-by-default-c9") != cat_groups.end());
+  // Make sure metadata isn't returned.
+  EXPECT_TRUE(std::find(cat_groups.begin(),
+                        cat_groups.end(), "__metadata") == cat_groups.end());
+
+  const std::vector<std::string> empty_categories;
+  std::vector<std::string> included_categories;
+  std::vector<std::string> excluded_categories;
+
+  // Test that category filtering works.
+
+  // Include nonexistent category -> no events
+  Clear();
+  included_categories.clear();
+  TraceLog::GetInstance()->SetEnabled(TraceConfig("not_found823564786", ""),
+                                      TraceLog::RECORDING_MODE);
+  TRACE_EVENT_INSTANT0("cat1", "name", TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("cat2", "name", TRACE_EVENT_SCOPE_THREAD);
+  EndTraceAndFlush();
+  DropTracedMetadataRecords();
+  EXPECT_TRUE(trace_parsed_.empty());
+
+  // Include existent category -> only events of that category
+  Clear();
+  included_categories.clear();
+  TraceLog::GetInstance()->SetEnabled(TraceConfig("inc", ""),
+                                      TraceLog::RECORDING_MODE);
+  TRACE_EVENT_INSTANT0("inc", "name", TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("inc2", "name", TRACE_EVENT_SCOPE_THREAD);
+  EndTraceAndFlush();
+  DropTracedMetadataRecords();
+  EXPECT_TRUE(FindMatchingValue("cat", "inc"));
+  EXPECT_FALSE(FindNonMatchingValue("cat", "inc"));
+
+  // Include existent wildcard -> all categories matching wildcard
+  Clear();
+  included_categories.clear();
+  TraceLog::GetInstance()->SetEnabled(
+      TraceConfig("inc_wildcard_*,inc_wildchar_?_end", ""),
+      TraceLog::RECORDING_MODE);
+  TRACE_EVENT_INSTANT0("inc_wildcard_abc", "included",
+      TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("inc_wildcard_", "included", TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("inc_wildchar_x_end", "included",
+      TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("inc_wildchar_bla_end", "not_inc",
+      TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("cat1", "not_inc", TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("cat2", "not_inc", TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("inc_wildcard_category,other_category", "included",
+      TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0(
+      "non_included_category,inc_wildcard_category", "included",
+      TRACE_EVENT_SCOPE_THREAD);
+  EndTraceAndFlush();
+  EXPECT_TRUE(FindMatchingValue("cat", "inc_wildcard_abc"));
+  EXPECT_TRUE(FindMatchingValue("cat", "inc_wildcard_"));
+  EXPECT_TRUE(FindMatchingValue("cat", "inc_wildchar_x_end"));
+  EXPECT_FALSE(FindMatchingValue("name", "not_inc"));
+  EXPECT_TRUE(FindMatchingValue("cat", "inc_wildcard_category,other_category"));
+  EXPECT_TRUE(FindMatchingValue("cat",
+                                "non_included_category,inc_wildcard_category"));
+
+  included_categories.clear();
+
+  // Exclude nonexistent category -> all events
+  Clear();
+  TraceLog::GetInstance()->SetEnabled(TraceConfig("-not_found823564786", ""),
+                                      TraceLog::RECORDING_MODE);
+  TRACE_EVENT_INSTANT0("cat1", "name", TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("cat2", "name", TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("category1,category2", "name", TRACE_EVENT_SCOPE_THREAD);
+  EndTraceAndFlush();
+  EXPECT_TRUE(FindMatchingValue("cat", "cat1"));
+  EXPECT_TRUE(FindMatchingValue("cat", "cat2"));
+  EXPECT_TRUE(FindMatchingValue("cat", "category1,category2"));
+
+  // Exclude existent category -> only events of other categories
+  Clear();
+  TraceLog::GetInstance()->SetEnabled(TraceConfig("-inc", ""),
+                                      TraceLog::RECORDING_MODE);
+  TRACE_EVENT_INSTANT0("inc", "name", TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("inc2", "name", TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("inc2,inc", "name", TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("inc,inc2", "name", TRACE_EVENT_SCOPE_THREAD);
+  EndTraceAndFlush();
+  EXPECT_TRUE(FindMatchingValue("cat", "inc2"));
+  EXPECT_FALSE(FindMatchingValue("cat", "inc"));
+  EXPECT_TRUE(FindMatchingValue("cat", "inc2,inc"));
+  EXPECT_TRUE(FindMatchingValue("cat", "inc,inc2"));
+
+  // Exclude existent wildcard -> all categories not matching wildcard
+  Clear();
+  TraceLog::GetInstance()->SetEnabled(
+      TraceConfig("-inc_wildcard_*,-inc_wildchar_?_end", ""),
+      TraceLog::RECORDING_MODE);
+  TRACE_EVENT_INSTANT0("inc_wildcard_abc", "not_inc",
+      TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("inc_wildcard_", "not_inc",
+      TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("inc_wildchar_x_end", "not_inc",
+      TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("inc_wildchar_bla_end", "included",
+      TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("cat1", "included", TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("cat2", "included", TRACE_EVENT_SCOPE_THREAD);
+  EndTraceAndFlush();
+  EXPECT_TRUE(FindMatchingValue("cat", "inc_wildchar_bla_end"));
+  EXPECT_TRUE(FindMatchingValue("cat", "cat1"));
+  EXPECT_TRUE(FindMatchingValue("cat", "cat2"));
+  EXPECT_FALSE(FindMatchingValue("name", "not_inc"));
+}
+
+
+// Test EVENT_WATCH_NOTIFICATION
+TEST_F(TraceEventTestFixture, EventWatchNotification) {
+  // Basic one occurrence.
+  BeginTrace();
+  TraceLog::WatchEventCallback callback =
+      base::Bind(&TraceEventTestFixture::OnWatchEventMatched,
+                 base::Unretained(this));
+  TraceLog::GetInstance()->SetWatchEvent("cat", "event", callback);
+  TRACE_EVENT_INSTANT0("cat", "event", TRACE_EVENT_SCOPE_THREAD);
+  EndTraceAndFlush();
+  EXPECT_EQ(event_watch_notification_, 1);
+
+  // Auto-reset after end trace.
+  BeginTrace();
+  TraceLog::GetInstance()->SetWatchEvent("cat", "event", callback);
+  EndTraceAndFlush();
+  BeginTrace();
+  TRACE_EVENT_INSTANT0("cat", "event", TRACE_EVENT_SCOPE_THREAD);
+  EndTraceAndFlush();
+  EXPECT_EQ(event_watch_notification_, 0);
+
+  // Multiple occurrence.
+  BeginTrace();
+  int num_occurrences = 5;
+  TraceLog::GetInstance()->SetWatchEvent("cat", "event", callback);
+  for (int i = 0; i < num_occurrences; ++i)
+    TRACE_EVENT_INSTANT0("cat", "event", TRACE_EVENT_SCOPE_THREAD);
+  EndTraceAndFlush();
+  EXPECT_EQ(event_watch_notification_, num_occurrences);
+
+  // Wrong category.
+  BeginTrace();
+  TraceLog::GetInstance()->SetWatchEvent("cat", "event", callback);
+  TRACE_EVENT_INSTANT0("wrong_cat", "event", TRACE_EVENT_SCOPE_THREAD);
+  EndTraceAndFlush();
+  EXPECT_EQ(event_watch_notification_, 0);
+
+  // Wrong name.
+  BeginTrace();
+  TraceLog::GetInstance()->SetWatchEvent("cat", "event", callback);
+  TRACE_EVENT_INSTANT0("cat", "wrong_event", TRACE_EVENT_SCOPE_THREAD);
+  EndTraceAndFlush();
+  EXPECT_EQ(event_watch_notification_, 0);
+
+  // Canceled.
+  BeginTrace();
+  TraceLog::GetInstance()->SetWatchEvent("cat", "event", callback);
+  TraceLog::GetInstance()->CancelWatchEvent();
+  TRACE_EVENT_INSTANT0("cat", "event", TRACE_EVENT_SCOPE_THREAD);
+  EndTraceAndFlush();
+  EXPECT_EQ(event_watch_notification_, 0);
+}
+
+// Test ASYNC_BEGIN/END events
+TEST_F(TraceEventTestFixture, AsyncBeginEndEvents) {
+  BeginTrace();
+
+  unsigned long long id = 0xfeedbeeffeedbeefull;
+  TRACE_EVENT_ASYNC_BEGIN0("cat", "name1", id);
+  TRACE_EVENT_ASYNC_STEP_INTO0("cat", "name1", id, "step1");
+  TRACE_EVENT_ASYNC_END0("cat", "name1", id);
+  TRACE_EVENT_BEGIN0("cat", "name2");
+  TRACE_EVENT_ASYNC_BEGIN0("cat", "name3", 0);
+  TRACE_EVENT_ASYNC_STEP_PAST0("cat", "name3", 0, "step2");
+
+  EndTraceAndFlush();
+
+  EXPECT_TRUE(FindNamePhase("name1", "S"));
+  EXPECT_TRUE(FindNamePhase("name1", "T"));
+  EXPECT_TRUE(FindNamePhase("name1", "F"));
+
+  std::string id_str;
+  StringAppendF(&id_str, "0x%llx", id);
+
+  EXPECT_TRUE(FindNamePhaseKeyValue("name1", "S", "id", id_str.c_str()));
+  EXPECT_TRUE(FindNamePhaseKeyValue("name1", "T", "id", id_str.c_str()));
+  EXPECT_TRUE(FindNamePhaseKeyValue("name1", "F", "id", id_str.c_str()));
+  EXPECT_TRUE(FindNamePhaseKeyValue("name3", "S", "id", "0x0"));
+  EXPECT_TRUE(FindNamePhaseKeyValue("name3", "p", "id", "0x0"));
+
+  // BEGIN events should not have id
+  EXPECT_FALSE(FindNamePhaseKeyValue("name2", "B", "id", "0"));
+}
+
+// Test ASYNC_BEGIN/END events
+TEST_F(TraceEventTestFixture, AsyncBeginEndPointerMangling) {
+  void* ptr = this;
+
+  TraceLog::GetInstance()->SetProcessID(100);
+  BeginTrace();
+  TRACE_EVENT_ASYNC_BEGIN0("cat", "name1", ptr);
+  TRACE_EVENT_ASYNC_BEGIN0("cat", "name2", ptr);
+  EndTraceAndFlush();
+
+  TraceLog::GetInstance()->SetProcessID(200);
+  BeginTrace();
+  TRACE_EVENT_ASYNC_END0("cat", "name1", ptr);
+  EndTraceAndFlush();
+
+  DictionaryValue* async_begin = FindNamePhase("name1", "S");
+  DictionaryValue* async_begin2 = FindNamePhase("name2", "S");
+  DictionaryValue* async_end = FindNamePhase("name1", "F");
+  EXPECT_TRUE(async_begin);
+  EXPECT_TRUE(async_begin2);
+  EXPECT_TRUE(async_end);
+
+  Value* value = NULL;
+  std::string async_begin_id_str;
+  std::string async_begin2_id_str;
+  std::string async_end_id_str;
+  ASSERT_TRUE(async_begin->Get("id", &value));
+  ASSERT_TRUE(value->GetAsString(&async_begin_id_str));
+  ASSERT_TRUE(async_begin2->Get("id", &value));
+  ASSERT_TRUE(value->GetAsString(&async_begin2_id_str));
+  ASSERT_TRUE(async_end->Get("id", &value));
+  ASSERT_TRUE(value->GetAsString(&async_end_id_str));
+
+  EXPECT_STREQ(async_begin_id_str.c_str(), async_begin2_id_str.c_str());
+  EXPECT_STRNE(async_begin_id_str.c_str(), async_end_id_str.c_str());
+}
+
+// Test that static strings are not copied.
+TEST_F(TraceEventTestFixture, StaticStringVsString) {
+  TraceLog* tracer = TraceLog::GetInstance();
+  // Make sure old events are flushed:
+  EXPECT_EQ(0u, tracer->GetStatus().event_count);
+  const unsigned char* category_group_enabled =
+      TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED("cat");
+
+  {
+    BeginTrace();
+    // Test that string arguments are copied.
+    TraceEventHandle handle1 =
+        trace_event_internal::AddTraceEvent(
+            TRACE_EVENT_PHASE_INSTANT, category_group_enabled, "name1", 0, 0,
+            "arg1", std::string("argval"), "arg2", std::string("argval"));
+    // Test that static TRACE_STR_COPY string arguments are copied.
+    TraceEventHandle handle2 =
+        trace_event_internal::AddTraceEvent(
+            TRACE_EVENT_PHASE_INSTANT, category_group_enabled, "name2", 0, 0,
+            "arg1", TRACE_STR_COPY("argval"),
+            "arg2", TRACE_STR_COPY("argval"));
+    EXPECT_GT(tracer->GetStatus().event_count, 1u);
+    const TraceEvent* event1 = tracer->GetEventByHandle(handle1);
+    const TraceEvent* event2 = tracer->GetEventByHandle(handle2);
+    ASSERT_TRUE(event1);
+    ASSERT_TRUE(event2);
+    EXPECT_STREQ("name1", event1->name());
+    EXPECT_STREQ("name2", event2->name());
+    EXPECT_TRUE(event1->parameter_copy_storage() != NULL);
+    EXPECT_TRUE(event2->parameter_copy_storage() != NULL);
+    EXPECT_GT(event1->parameter_copy_storage()->size(), 0u);
+    EXPECT_GT(event2->parameter_copy_storage()->size(), 0u);
+    EndTraceAndFlush();
+  }
+
+  {
+    BeginTrace();
+    // Test that static literal string arguments are not copied.
+    TraceEventHandle handle1 =
+        trace_event_internal::AddTraceEvent(
+            TRACE_EVENT_PHASE_INSTANT, category_group_enabled, "name1", 0, 0,
+            "arg1", "argval", "arg2", "argval");
+    // Test that static TRACE_STR_COPY NULL string arguments are not copied.
+    const char* str1 = NULL;
+    const char* str2 = NULL;
+    TraceEventHandle handle2 =
+        trace_event_internal::AddTraceEvent(
+            TRACE_EVENT_PHASE_INSTANT, category_group_enabled, "name2", 0, 0,
+            "arg1", TRACE_STR_COPY(str1),
+            "arg2", TRACE_STR_COPY(str2));
+    EXPECT_GT(tracer->GetStatus().event_count, 1u);
+    const TraceEvent* event1 = tracer->GetEventByHandle(handle1);
+    const TraceEvent* event2 = tracer->GetEventByHandle(handle2);
+    ASSERT_TRUE(event1);
+    ASSERT_TRUE(event2);
+    EXPECT_STREQ("name1", event1->name());
+    EXPECT_STREQ("name2", event2->name());
+    EXPECT_TRUE(event1->parameter_copy_storage() == NULL);
+    EXPECT_TRUE(event2->parameter_copy_storage() == NULL);
+    EndTraceAndFlush();
+  }
+}
+
+// Test that data sent from other threads is gathered
+TEST_F(TraceEventTestFixture, DataCapturedOnThread) {
+  BeginTrace();
+
+  Thread thread("1");
+  WaitableEvent task_complete_event(false, false);
+  thread.Start();
+
+  thread.task_runner()->PostTask(
+      FROM_HERE, base::Bind(&TraceWithAllMacroVariants, &task_complete_event));
+  task_complete_event.Wait();
+  thread.Stop();
+
+  EndTraceAndFlush();
+  ValidateAllTraceMacrosCreatedData(trace_parsed_);
+}
+
+// Test that data sent from multiple threads is gathered
+TEST_F(TraceEventTestFixture, DataCapturedManyThreads) {
+  BeginTrace();
+
+  const int num_threads = 4;
+  const int num_events = 4000;
+  Thread* threads[num_threads];
+  WaitableEvent* task_complete_events[num_threads];
+  for (int i = 0; i < num_threads; i++) {
+    threads[i] = new Thread(StringPrintf("Thread %d", i));
+    task_complete_events[i] = new WaitableEvent(false, false);
+    threads[i]->Start();
+    threads[i]->task_runner()->PostTask(
+        FROM_HERE, base::Bind(&TraceManyInstantEvents, i, num_events,
+                              task_complete_events[i]));
+  }
+
+  for (int i = 0; i < num_threads; i++) {
+    task_complete_events[i]->Wait();
+  }
+
+  // Let half of the threads end before flush.
+  for (int i = 0; i < num_threads / 2; i++) {
+    threads[i]->Stop();
+    delete threads[i];
+    delete task_complete_events[i];
+  }
+
+  EndTraceAndFlushInThreadWithMessageLoop();
+  ValidateInstantEventPresentOnEveryThread(trace_parsed_,
+                                           num_threads, num_events);
+
+  // Let the other half of the threads end after flush.
+  for (int i = num_threads / 2; i < num_threads; i++) {
+    threads[i]->Stop();
+    delete threads[i];
+    delete task_complete_events[i];
+  }
+}
+
+// Test that thread and process names show up in the trace
+TEST_F(TraceEventTestFixture, ThreadNames) {
+  // Create threads before we enable tracing to make sure
+  // that tracelog still captures them.
+  const int kNumThreads = 4;
+  const int kNumEvents = 10;
+  Thread* threads[kNumThreads];
+  PlatformThreadId thread_ids[kNumThreads];
+  for (int i = 0; i < kNumThreads; i++)
+    threads[i] = new Thread(StringPrintf("Thread %d", i));
+
+  // Enable tracing.
+  BeginTrace();
+
+  // Now run some trace code on these threads.
+  WaitableEvent* task_complete_events[kNumThreads];
+  for (int i = 0; i < kNumThreads; i++) {
+    task_complete_events[i] = new WaitableEvent(false, false);
+    threads[i]->Start();
+    thread_ids[i] = threads[i]->thread_id();
+    threads[i]->task_runner()->PostTask(
+        FROM_HERE, base::Bind(&TraceManyInstantEvents, i, kNumEvents,
+                              task_complete_events[i]));
+  }
+  for (int i = 0; i < kNumThreads; i++) {
+    task_complete_events[i]->Wait();
+  }
+
+  // Shut things down.
+  for (int i = 0; i < kNumThreads; i++) {
+    threads[i]->Stop();
+    delete threads[i];
+    delete task_complete_events[i];
+  }
+
+  EndTraceAndFlush();
+
+  std::string tmp;
+  int tmp_int;
+  const DictionaryValue* item;
+
+  // Make sure we get thread name metadata.
+  // Note, the test suite may have created a ton of threads.
+  // So, we'll have thread names for threads we didn't create.
+  std::vector<const DictionaryValue*> items =
+      FindTraceEntries(trace_parsed_, "thread_name");
+  for (int i = 0; i < static_cast<int>(items.size()); i++) {
+    item = items[i];
+    ASSERT_TRUE(item);
+    EXPECT_TRUE(item->GetInteger("tid", &tmp_int));
+
+    // See if this thread name is one of the threads we just created
+    for (int j = 0; j < kNumThreads; j++) {
+      if (static_cast<int>(thread_ids[j]) != tmp_int)
+        continue;
+
+      std::string expected_name = StringPrintf("Thread %d", j);
+      EXPECT_TRUE(item->GetString("ph", &tmp) && tmp == "M");
+      EXPECT_TRUE(item->GetInteger("pid", &tmp_int) &&
+                  tmp_int == static_cast<int>(base::GetCurrentProcId()));
+      // If the thread name changes or the tid gets reused, the name will be
+      // a comma-separated list of thread names, so look for a substring.
+      EXPECT_TRUE(item->GetString("args.name", &tmp) &&
+                  tmp.find(expected_name) != std::string::npos);
+    }
+  }
+}
+
+TEST_F(TraceEventTestFixture, ThreadNameChanges) {
+  BeginTrace();
+
+  PlatformThread::SetName("");
+  TRACE_EVENT_INSTANT0("drink", "water", TRACE_EVENT_SCOPE_THREAD);
+
+  PlatformThread::SetName("cafe");
+  TRACE_EVENT_INSTANT0("drink", "coffee", TRACE_EVENT_SCOPE_THREAD);
+
+  PlatformThread::SetName("shop");
+  // No event here, so won't appear in combined name.
+
+  PlatformThread::SetName("pub");
+  TRACE_EVENT_INSTANT0("drink", "beer", TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("drink", "wine", TRACE_EVENT_SCOPE_THREAD);
+
+  PlatformThread::SetName(" bar");
+  TRACE_EVENT_INSTANT0("drink", "whisky", TRACE_EVENT_SCOPE_THREAD);
+
+  EndTraceAndFlush();
+
+  std::vector<const DictionaryValue*> items =
+      FindTraceEntries(trace_parsed_, "thread_name");
+  EXPECT_EQ(1u, items.size());
+  ASSERT_GT(items.size(), 0u);
+  const DictionaryValue* item = items[0];
+  ASSERT_TRUE(item);
+  int tid;
+  EXPECT_TRUE(item->GetInteger("tid", &tid));
+  EXPECT_EQ(PlatformThread::CurrentId(), static_cast<PlatformThreadId>(tid));
+
+  std::string expected_name = "cafe,pub, bar";
+  std::string tmp;
+  EXPECT_TRUE(item->GetString("args.name", &tmp));
+  EXPECT_EQ(expected_name, tmp);
+}
+
+// Test that the disabled trace categories are included/excluded from the
+// trace output correctly.
+TEST_F(TraceEventTestFixture, DisabledCategories) {
+  BeginTrace();
+  TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("cc"), "first",
+                       TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("included", "first", TRACE_EVENT_SCOPE_THREAD);
+  EndTraceAndFlush();
+  {
+    const DictionaryValue* item = NULL;
+    ListValue& trace_parsed = trace_parsed_;
+    EXPECT_NOT_FIND_("disabled-by-default-cc");
+    EXPECT_FIND_("included");
+  }
+  Clear();
+
+  BeginSpecificTrace("disabled-by-default-cc");
+  TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("cc"), "second",
+                       TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("other_included", "second", TRACE_EVENT_SCOPE_THREAD);
+  EndTraceAndFlush();
+
+  {
+    const DictionaryValue* item = NULL;
+    ListValue& trace_parsed = trace_parsed_;
+    EXPECT_FIND_("disabled-by-default-cc");
+    EXPECT_FIND_("other_included");
+  }
+
+  Clear();
+
+  BeginSpecificTrace("other_included");
+  TRACE_EVENT_INSTANT0(TRACE_DISABLED_BY_DEFAULT("cc") ",other_included",
+                       "first", TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_INSTANT0("other_included," TRACE_DISABLED_BY_DEFAULT("cc"),
+                       "second", TRACE_EVENT_SCOPE_THREAD);
+  EndTraceAndFlush();
+
+  {
+    const DictionaryValue* item = NULL;
+    ListValue& trace_parsed = trace_parsed_;
+    EXPECT_FIND_("disabled-by-default-cc,other_included");
+    EXPECT_FIND_("other_included,disabled-by-default-cc");
+  }
+}
+
+TEST_F(TraceEventTestFixture, NormallyNoDeepCopy) {
+  // Test that the TRACE_EVENT macros do not deep-copy their string. If they
+  // do so it may indicate a performance regression, but more-over it would
+  // make the DEEP_COPY overloads redundant.
+  std::string name_string("event name");
+
+  BeginTrace();
+  TRACE_EVENT_INSTANT0("category", name_string.c_str(),
+                       TRACE_EVENT_SCOPE_THREAD);
+
+  // Modify the string in place (a wholesale reassignment may leave the old
+  // string intact on the heap).
+  name_string[0] = '@';
+
+  EndTraceAndFlush();
+
+  EXPECT_FALSE(FindTraceEntry(trace_parsed_, "event name"));
+  EXPECT_TRUE(FindTraceEntry(trace_parsed_, name_string.c_str()));
+}
+
+TEST_F(TraceEventTestFixture, DeepCopy) {
+  static const char kOriginalName1[] = "name1";
+  static const char kOriginalName2[] = "name2";
+  static const char kOriginalName3[] = "name3";
+  std::string name1(kOriginalName1);
+  std::string name2(kOriginalName2);
+  std::string name3(kOriginalName3);
+  std::string arg1("arg1");
+  std::string arg2("arg2");
+  std::string val1("val1");
+  std::string val2("val2");
+
+  BeginTrace();
+  TRACE_EVENT_COPY_INSTANT0("category", name1.c_str(),
+                            TRACE_EVENT_SCOPE_THREAD);
+  TRACE_EVENT_COPY_BEGIN1("category", name2.c_str(),
+                          arg1.c_str(), 5);
+  TRACE_EVENT_COPY_END2("category", name3.c_str(),
+                        arg1.c_str(), val1,
+                        arg2.c_str(), val2);
+
+  // As per NormallyNoDeepCopy, modify the strings in place.
+  name1[0] = name2[0] = name3[0] = arg1[0] = arg2[0] = val1[0] = val2[0] = '@';
+
+  EndTraceAndFlush();
+
+  EXPECT_FALSE(FindTraceEntry(trace_parsed_, name1.c_str()));
+  EXPECT_FALSE(FindTraceEntry(trace_parsed_, name2.c_str()));
+  EXPECT_FALSE(FindTraceEntry(trace_parsed_, name3.c_str()));
+
+  const DictionaryValue* entry1 = FindTraceEntry(trace_parsed_, kOriginalName1);
+  const DictionaryValue* entry2 = FindTraceEntry(trace_parsed_, kOriginalName2);
+  const DictionaryValue* entry3 = FindTraceEntry(trace_parsed_, kOriginalName3);
+  ASSERT_TRUE(entry1);
+  ASSERT_TRUE(entry2);
+  ASSERT_TRUE(entry3);
+
+  int i;
+  EXPECT_FALSE(entry2->GetInteger("args.@rg1", &i));
+  EXPECT_TRUE(entry2->GetInteger("args.arg1", &i));
+  EXPECT_EQ(5, i);
+
+  std::string s;
+  EXPECT_TRUE(entry3->GetString("args.arg1", &s));
+  EXPECT_EQ("val1", s);
+  EXPECT_TRUE(entry3->GetString("args.arg2", &s));
+  EXPECT_EQ("val2", s);
+}
+
+// Test that TraceResultBuffer outputs the correct result whether it is added
+// in chunks or added all at once.
+TEST_F(TraceEventTestFixture, TraceResultBuffer) {
+  Clear();
+
+  trace_buffer_.Start();
+  trace_buffer_.AddFragment("bla1");
+  trace_buffer_.AddFragment("bla2");
+  trace_buffer_.AddFragment("bla3,bla4");
+  trace_buffer_.Finish();
+  EXPECT_STREQ(json_output_.json_output.c_str(), "[bla1,bla2,bla3,bla4]");
+
+  Clear();
+
+  trace_buffer_.Start();
+  trace_buffer_.AddFragment("bla1,bla2,bla3,bla4");
+  trace_buffer_.Finish();
+  EXPECT_STREQ(json_output_.json_output.c_str(), "[bla1,bla2,bla3,bla4]");
+}
+
+// Test that trace_event parameters are not evaluated if the tracing
+// system is disabled.
+TEST_F(TraceEventTestFixture, TracingIsLazy) {
+  BeginTrace();
+
+  int a = 0;
+  TRACE_EVENT_INSTANT1("category", "test", TRACE_EVENT_SCOPE_THREAD, "a", a++);
+  EXPECT_EQ(1, a);
+
+  TraceLog::GetInstance()->SetDisabled();
+
+  TRACE_EVENT_INSTANT1("category", "test", TRACE_EVENT_SCOPE_THREAD, "a", a++);
+  EXPECT_EQ(1, a);
+
+  EndTraceAndFlush();
+}
+
+TEST_F(TraceEventTestFixture, TraceEnableDisable) {
+  TraceLog* trace_log = TraceLog::GetInstance();
+  TraceConfig tc_inc_all("*", "");
+  trace_log->SetEnabled(tc_inc_all, TraceLog::RECORDING_MODE);
+  EXPECT_TRUE(trace_log->IsEnabled());
+  trace_log->SetDisabled();
+  EXPECT_FALSE(trace_log->IsEnabled());
+
+  trace_log->SetEnabled(tc_inc_all, TraceLog::RECORDING_MODE);
+  EXPECT_TRUE(trace_log->IsEnabled());
+  const std::vector<std::string> empty;
+  trace_log->SetEnabled(TraceConfig(), TraceLog::RECORDING_MODE);
+  EXPECT_TRUE(trace_log->IsEnabled());
+  trace_log->SetDisabled();
+  EXPECT_FALSE(trace_log->IsEnabled());
+  trace_log->SetDisabled();
+  EXPECT_FALSE(trace_log->IsEnabled());
+}
+
+TEST_F(TraceEventTestFixture, TraceCategoriesAfterNestedEnable) {
+  TraceLog* trace_log = TraceLog::GetInstance();
+  trace_log->SetEnabled(TraceConfig("foo,bar", ""), TraceLog::RECORDING_MODE);
+  EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("foo"));
+  EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("bar"));
+  EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("baz"));
+  trace_log->SetEnabled(TraceConfig("foo2", ""), TraceLog::RECORDING_MODE);
+  EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("foo2"));
+  EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("baz"));
+  // The "" becomes the default catergory set when applied.
+  trace_log->SetEnabled(TraceConfig(), TraceLog::RECORDING_MODE);
+  EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("foo"));
+  EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("baz"));
+  EXPECT_STREQ(
+    "-*Debug,-*Test",
+    trace_log->GetCurrentTraceConfig().ToCategoryFilterString().c_str());
+  trace_log->SetDisabled();
+  trace_log->SetDisabled();
+  trace_log->SetDisabled();
+  EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("foo"));
+  EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("baz"));
+
+  trace_log->SetEnabled(TraceConfig("-foo,-bar", ""), TraceLog::RECORDING_MODE);
+  EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("foo"));
+  EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("baz"));
+  trace_log->SetEnabled(TraceConfig("moo", ""), TraceLog::RECORDING_MODE);
+  EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("baz"));
+  EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("moo"));
+  EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("foo"));
+  EXPECT_STREQ(
+    "-foo,-bar",
+    trace_log->GetCurrentTraceConfig().ToCategoryFilterString().c_str());
+  trace_log->SetDisabled();
+  trace_log->SetDisabled();
+
+  // Make sure disabled categories aren't cleared if we set in the second.
+  trace_log->SetEnabled(TraceConfig("disabled-by-default-cc,foo", ""),
+                        TraceLog::RECORDING_MODE);
+  EXPECT_FALSE(*trace_log->GetCategoryGroupEnabled("bar"));
+  trace_log->SetEnabled(TraceConfig("disabled-by-default-gpu", ""),
+                        TraceLog::RECORDING_MODE);
+  EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("disabled-by-default-cc"));
+  EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("disabled-by-default-gpu"));
+  EXPECT_TRUE(*trace_log->GetCategoryGroupEnabled("bar"));
+  EXPECT_STREQ(
+    "disabled-by-default-cc,disabled-by-default-gpu",
+    trace_log->GetCurrentTraceConfig().ToCategoryFilterString().c_str());
+  trace_log->SetDisabled();
+  trace_log->SetDisabled();
+}
+
+TEST_F(TraceEventTestFixture, TraceSampling) {
+  TraceLog::GetInstance()->SetEnabled(
+    TraceConfig(kRecordAllCategoryFilter, "record-until-full,enable-sampling"),
+    TraceLog::RECORDING_MODE);
+
+  TRACE_EVENT_SET_SAMPLING_STATE_FOR_BUCKET(1, "cc", "Stuff");
+  TraceLog::GetInstance()->WaitSamplingEventForTesting();
+  TRACE_EVENT_SET_SAMPLING_STATE_FOR_BUCKET(1, "cc", "Things");
+  TraceLog::GetInstance()->WaitSamplingEventForTesting();
+
+  EndTraceAndFlush();
+
+  // Make sure we hit at least once.
+  EXPECT_TRUE(FindNamePhase("Stuff", "P"));
+  EXPECT_TRUE(FindNamePhase("Things", "P"));
+}
+
+TEST_F(TraceEventTestFixture, TraceSamplingScope) {
+  TraceLog::GetInstance()->SetEnabled(
+    TraceConfig(kRecordAllCategoryFilter, "record-until-full,enable-sampling"),
+    TraceLog::RECORDING_MODE);
+
+  TRACE_EVENT_SCOPED_SAMPLING_STATE("AAA", "name");
+  TraceLog::GetInstance()->WaitSamplingEventForTesting();
+  {
+    EXPECT_STREQ(TRACE_EVENT_GET_SAMPLING_STATE(), "AAA");
+    TRACE_EVENT_SCOPED_SAMPLING_STATE("BBB", "name");
+    TraceLog::GetInstance()->WaitSamplingEventForTesting();
+    EXPECT_STREQ(TRACE_EVENT_GET_SAMPLING_STATE(), "BBB");
+  }
+  TraceLog::GetInstance()->WaitSamplingEventForTesting();
+  {
+    EXPECT_STREQ(TRACE_EVENT_GET_SAMPLING_STATE(), "AAA");
+    TRACE_EVENT_SCOPED_SAMPLING_STATE("CCC", "name");
+    TraceLog::GetInstance()->WaitSamplingEventForTesting();
+    EXPECT_STREQ(TRACE_EVENT_GET_SAMPLING_STATE(), "CCC");
+  }
+  TraceLog::GetInstance()->WaitSamplingEventForTesting();
+  {
+    EXPECT_STREQ(TRACE_EVENT_GET_SAMPLING_STATE(), "AAA");
+    TRACE_EVENT_SET_SAMPLING_STATE("DDD", "name");
+    TraceLog::GetInstance()->WaitSamplingEventForTesting();
+    EXPECT_STREQ(TRACE_EVENT_GET_SAMPLING_STATE(), "DDD");
+  }
+  TraceLog::GetInstance()->WaitSamplingEventForTesting();
+  EXPECT_STREQ(TRACE_EVENT_GET_SAMPLING_STATE(), "DDD");
+
+  EndTraceAndFlush();
+}
+
+TEST_F(TraceEventTestFixture, TraceContinuousSampling) {
+  TraceLog::GetInstance()->SetEnabled(
+    TraceConfig(kRecordAllCategoryFilter, "record-until-full,enable-sampling"),
+    TraceLog::MONITORING_MODE);
+
+  TRACE_EVENT_SET_SAMPLING_STATE_FOR_BUCKET(1, "category", "AAA");
+  TraceLog::GetInstance()->WaitSamplingEventForTesting();
+  TRACE_EVENT_SET_SAMPLING_STATE_FOR_BUCKET(1, "category", "BBB");
+  TraceLog::GetInstance()->WaitSamplingEventForTesting();
+
+  FlushMonitoring();
+
+  // Make sure we can get the profiled data.
+  EXPECT_TRUE(FindNamePhase("AAA", "P"));
+  EXPECT_TRUE(FindNamePhase("BBB", "P"));
+
+  Clear();
+  TraceLog::GetInstance()->WaitSamplingEventForTesting();
+
+  TRACE_EVENT_SET_SAMPLING_STATE_FOR_BUCKET(1, "category", "CCC");
+  TraceLog::GetInstance()->WaitSamplingEventForTesting();
+  TRACE_EVENT_SET_SAMPLING_STATE_FOR_BUCKET(1, "category", "DDD");
+  TraceLog::GetInstance()->WaitSamplingEventForTesting();
+
+  FlushMonitoring();
+
+  // Make sure the profiled data is accumulated.
+  EXPECT_TRUE(FindNamePhase("AAA", "P"));
+  EXPECT_TRUE(FindNamePhase("BBB", "P"));
+  EXPECT_TRUE(FindNamePhase("CCC", "P"));
+  EXPECT_TRUE(FindNamePhase("DDD", "P"));
+
+  Clear();
+
+  TraceLog::GetInstance()->SetDisabled();
+
+  // Make sure disabling the continuous sampling thread clears
+  // the profiled data.
+  EXPECT_FALSE(FindNamePhase("AAA", "P"));
+  EXPECT_FALSE(FindNamePhase("BBB", "P"));
+  EXPECT_FALSE(FindNamePhase("CCC", "P"));
+  EXPECT_FALSE(FindNamePhase("DDD", "P"));
+
+  Clear();
+}
+
+class MyData : public ConvertableToTraceFormat {
+ public:
+  MyData() {}
+
+  void AppendAsTraceFormat(std::string* out) const override {
+    out->append("{\"foo\":1}");
+  }
+
+ private:
+  ~MyData() override {}
+  DISALLOW_COPY_AND_ASSIGN(MyData);
+};
+
+TEST_F(TraceEventTestFixture, ConvertableTypes) {
+  TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
+                                      TraceLog::RECORDING_MODE);
+
+  scoped_refptr<ConvertableToTraceFormat> data(new MyData());
+  scoped_refptr<ConvertableToTraceFormat> data1(new MyData());
+  scoped_refptr<ConvertableToTraceFormat> data2(new MyData());
+  TRACE_EVENT1("foo", "bar", "data", data);
+  TRACE_EVENT2("foo", "baz",
+               "data1", data1,
+               "data2", data2);
+
+
+  scoped_refptr<ConvertableToTraceFormat> convertData1(new MyData());
+  scoped_refptr<ConvertableToTraceFormat> convertData2(new MyData());
+  TRACE_EVENT2(
+      "foo",
+      "string_first",
+      "str",
+      "string value 1",
+      "convert",
+      convertData1);
+  TRACE_EVENT2(
+      "foo",
+      "string_second",
+      "convert",
+      convertData2,
+      "str",
+      "string value 2");
+  EndTraceAndFlush();
+
+  // One arg version.
+  DictionaryValue* dict = FindNamePhase("bar", "X");
+  ASSERT_TRUE(dict);
+
+  const DictionaryValue* args_dict = NULL;
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+
+  const Value* value = NULL;
+  const DictionaryValue* convertable_dict = NULL;
+  EXPECT_TRUE(args_dict->Get("data", &value));
+  ASSERT_TRUE(value->GetAsDictionary(&convertable_dict));
+
+  int foo_val;
+  EXPECT_TRUE(convertable_dict->GetInteger("foo", &foo_val));
+  EXPECT_EQ(1, foo_val);
+
+  // Two arg version.
+  dict = FindNamePhase("baz", "X");
+  ASSERT_TRUE(dict);
+
+  args_dict = NULL;
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+
+  value = NULL;
+  convertable_dict = NULL;
+  EXPECT_TRUE(args_dict->Get("data1", &value));
+  ASSERT_TRUE(value->GetAsDictionary(&convertable_dict));
+
+  value = NULL;
+  convertable_dict = NULL;
+  EXPECT_TRUE(args_dict->Get("data2", &value));
+  ASSERT_TRUE(value->GetAsDictionary(&convertable_dict));
+
+  // Convertable with other types.
+  dict = FindNamePhase("string_first", "X");
+  ASSERT_TRUE(dict);
+
+  args_dict = NULL;
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+
+  std::string str_value;
+  EXPECT_TRUE(args_dict->GetString("str", &str_value));
+  EXPECT_STREQ("string value 1", str_value.c_str());
+
+  value = NULL;
+  convertable_dict = NULL;
+  foo_val = 0;
+  EXPECT_TRUE(args_dict->Get("convert", &value));
+  ASSERT_TRUE(value->GetAsDictionary(&convertable_dict));
+  EXPECT_TRUE(convertable_dict->GetInteger("foo", &foo_val));
+  EXPECT_EQ(1, foo_val);
+
+  dict = FindNamePhase("string_second", "X");
+  ASSERT_TRUE(dict);
+
+  args_dict = NULL;
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+
+  EXPECT_TRUE(args_dict->GetString("str", &str_value));
+  EXPECT_STREQ("string value 2", str_value.c_str());
+
+  value = NULL;
+  convertable_dict = NULL;
+  foo_val = 0;
+  EXPECT_TRUE(args_dict->Get("convert", &value));
+  ASSERT_TRUE(value->GetAsDictionary(&convertable_dict));
+  EXPECT_TRUE(convertable_dict->GetInteger("foo", &foo_val));
+  EXPECT_EQ(1, foo_val);
+}
+
+TEST_F(TraceEventTestFixture, PrimitiveArgs) {
+  TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
+                                      TraceLog::RECORDING_MODE);
+
+  TRACE_EVENT1("foo", "event1", "int_one", 1);
+  TRACE_EVENT1("foo", "event2", "int_neg_ten", -10);
+  TRACE_EVENT1("foo", "event3", "float_one", 1.0f);
+  TRACE_EVENT1("foo", "event4", "float_half", .5f);
+  TRACE_EVENT1("foo", "event5", "float_neghalf", -.5f);
+  TRACE_EVENT1("foo", "event6", "float_infinity",
+      std::numeric_limits<float>::infinity());
+  TRACE_EVENT1("foo", "event6b", "float_neg_infinity",
+      -std::numeric_limits<float>::infinity());
+  TRACE_EVENT1("foo", "event7", "double_nan",
+      std::numeric_limits<double>::quiet_NaN());
+  void* p = 0;
+  TRACE_EVENT1("foo", "event8", "pointer_null", p);
+  p = reinterpret_cast<void*>(0xbadf00d);
+  TRACE_EVENT1("foo", "event9", "pointer_badf00d", p);
+  TRACE_EVENT1("foo", "event10", "bool_true", true);
+  TRACE_EVENT1("foo", "event11", "bool_false", false);
+  TRACE_EVENT1("foo", "event12", "time_null",
+      base::Time());
+  TRACE_EVENT1("foo", "event13", "time_one",
+      base::Time::FromInternalValue(1));
+  TRACE_EVENT1("foo", "event14", "timeticks_null",
+      base::TimeTicks());
+  TRACE_EVENT1("foo", "event15", "timeticks_one",
+      base::TimeTicks::FromInternalValue(1));
+  EndTraceAndFlush();
+
+  const DictionaryValue* args_dict = NULL;
+  DictionaryValue* dict = NULL;
+  const Value* value = NULL;
+  std::string str_value;
+  int int_value;
+  double double_value;
+  bool bool_value;
+
+  dict = FindNamePhase("event1", "X");
+  ASSERT_TRUE(dict);
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+  EXPECT_TRUE(args_dict->GetInteger("int_one", &int_value));
+  EXPECT_EQ(1, int_value);
+
+  dict = FindNamePhase("event2", "X");
+  ASSERT_TRUE(dict);
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+  EXPECT_TRUE(args_dict->GetInteger("int_neg_ten", &int_value));
+  EXPECT_EQ(-10, int_value);
+
+  // 1f must be serlized to JSON as "1.0" in order to be a double, not an int.
+  dict = FindNamePhase("event3", "X");
+  ASSERT_TRUE(dict);
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+  EXPECT_TRUE(args_dict->Get("float_one", &value));
+  EXPECT_TRUE(value->IsType(Value::TYPE_DOUBLE));
+  EXPECT_TRUE(value->GetAsDouble(&double_value));
+  EXPECT_EQ(1, double_value);
+
+  // .5f must be serlized to JSON as "0.5".
+  dict = FindNamePhase("event4", "X");
+  ASSERT_TRUE(dict);
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+  EXPECT_TRUE(args_dict->Get("float_half", &value));
+  EXPECT_TRUE(value->IsType(Value::TYPE_DOUBLE));
+  EXPECT_TRUE(value->GetAsDouble(&double_value));
+  EXPECT_EQ(0.5, double_value);
+
+  // -.5f must be serlized to JSON as "-0.5".
+  dict = FindNamePhase("event5", "X");
+  ASSERT_TRUE(dict);
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+  EXPECT_TRUE(args_dict->Get("float_neghalf", &value));
+  EXPECT_TRUE(value->IsType(Value::TYPE_DOUBLE));
+  EXPECT_TRUE(value->GetAsDouble(&double_value));
+  EXPECT_EQ(-0.5, double_value);
+
+  // Infinity is serialized to JSON as a string.
+  dict = FindNamePhase("event6", "X");
+  ASSERT_TRUE(dict);
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+  EXPECT_TRUE(args_dict->GetString("float_infinity", &str_value));
+  EXPECT_STREQ("Infinity", str_value.c_str());
+  dict = FindNamePhase("event6b", "X");
+  ASSERT_TRUE(dict);
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+  EXPECT_TRUE(args_dict->GetString("float_neg_infinity", &str_value));
+  EXPECT_STREQ("-Infinity", str_value.c_str());
+
+  // NaN is serialized to JSON as a string.
+  dict = FindNamePhase("event7", "X");
+  ASSERT_TRUE(dict);
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+  EXPECT_TRUE(args_dict->GetString("double_nan", &str_value));
+  EXPECT_STREQ("NaN", str_value.c_str());
+
+  // NULL pointers should be serialized as "0x0".
+  dict = FindNamePhase("event8", "X");
+  ASSERT_TRUE(dict);
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+  EXPECT_TRUE(args_dict->GetString("pointer_null", &str_value));
+  EXPECT_STREQ("0x0", str_value.c_str());
+
+  // Other pointers should be serlized as a hex string.
+  dict = FindNamePhase("event9", "X");
+  ASSERT_TRUE(dict);
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+  EXPECT_TRUE(args_dict->GetString("pointer_badf00d", &str_value));
+  EXPECT_STREQ("0xbadf00d", str_value.c_str());
+
+  dict = FindNamePhase("event10", "X");
+  ASSERT_TRUE(dict);
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+  EXPECT_TRUE(args_dict->GetBoolean("bool_true", &bool_value));
+  EXPECT_TRUE(bool_value);
+
+  dict = FindNamePhase("event11", "X");
+  ASSERT_TRUE(dict);
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+  EXPECT_TRUE(args_dict->GetBoolean("bool_false", &bool_value));
+  EXPECT_FALSE(bool_value);
+
+  dict = FindNamePhase("event12", "X");
+  ASSERT_TRUE(dict);
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+  EXPECT_TRUE(args_dict->GetInteger("time_null", &int_value));
+  EXPECT_EQ(0, int_value);
+
+  dict = FindNamePhase("event13", "X");
+  ASSERT_TRUE(dict);
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+  EXPECT_TRUE(args_dict->GetInteger("time_one", &int_value));
+  EXPECT_EQ(1, int_value);
+
+  dict = FindNamePhase("event14", "X");
+  ASSERT_TRUE(dict);
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+  EXPECT_TRUE(args_dict->GetInteger("timeticks_null", &int_value));
+  EXPECT_EQ(0, int_value);
+
+  dict = FindNamePhase("event15", "X");
+  ASSERT_TRUE(dict);
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+  EXPECT_TRUE(args_dict->GetInteger("timeticks_one", &int_value));
+  EXPECT_EQ(1, int_value);
+}
+
+namespace {
+
+bool IsTraceEventArgsWhitelisted(const char* category_group_name,
+                                 const char* event_name) {
+  if (MatchPattern(category_group_name, "toplevel") &&
+      MatchPattern(event_name, "*")) {
+    return true;
+  }
+
+  return false;
+}
+
+}  // namespace
+
+TEST_F(TraceEventTestFixture, ArgsWhitelisting) {
+  TraceLog::GetInstance()->SetArgumentFilterPredicate(
+      base::Bind(&IsTraceEventArgsWhitelisted));
+
+  TraceLog::GetInstance()->SetEnabled(
+    TraceConfig(kRecordAllCategoryFilter, "enable-argument-filter"),
+    TraceLog::RECORDING_MODE);
+
+  TRACE_EVENT1("toplevel", "event1", "int_one", 1);
+  TRACE_EVENT1("whitewashed", "event2", "int_two", 1);
+  EndTraceAndFlush();
+
+  const DictionaryValue* args_dict = NULL;
+  DictionaryValue* dict = NULL;
+  int int_value;
+
+  dict = FindNamePhase("event1", "X");
+  ASSERT_TRUE(dict);
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+  EXPECT_TRUE(args_dict->GetInteger("int_one", &int_value));
+  EXPECT_EQ(1, int_value);
+
+  dict = FindNamePhase("event2", "X");
+  ASSERT_TRUE(dict);
+  dict->GetDictionary("args", &args_dict);
+  ASSERT_TRUE(args_dict);
+  EXPECT_FALSE(args_dict->GetInteger("int_two", &int_value));
+
+  std::string args_string;
+  EXPECT_TRUE(dict->GetString("args", &args_string));
+  EXPECT_EQ(args_string, "__stripped__");
+}
+
+class TraceEventCallbackTest : public TraceEventTestFixture {
+ public:
+  void SetUp() override {
+    TraceEventTestFixture::SetUp();
+    ASSERT_EQ(NULL, s_instance);
+    s_instance = this;
+  }
+  void TearDown() override {
+    TraceLog::GetInstance()->SetDisabled();
+    ASSERT_TRUE(s_instance);
+    s_instance = NULL;
+    TraceEventTestFixture::TearDown();
+  }
+
+ protected:
+  // For TraceEventCallbackAndRecordingX tests.
+  void VerifyCallbackAndRecordedEvents(size_t expected_callback_count,
+                                       size_t expected_recorded_count) {
+    // Callback events.
+    EXPECT_EQ(expected_callback_count, collected_events_names_.size());
+    for (size_t i = 0; i < collected_events_names_.size(); ++i) {
+      EXPECT_EQ("callback", collected_events_categories_[i]);
+      EXPECT_EQ("yes", collected_events_names_[i]);
+    }
+
+    // Recorded events.
+    EXPECT_EQ(expected_recorded_count, trace_parsed_.GetSize());
+    EXPECT_TRUE(FindTraceEntry(trace_parsed_, "recording"));
+    EXPECT_FALSE(FindTraceEntry(trace_parsed_, "callback"));
+    EXPECT_TRUE(FindTraceEntry(trace_parsed_, "yes"));
+    EXPECT_FALSE(FindTraceEntry(trace_parsed_, "no"));
+  }
+
+  void VerifyCollectedEvent(size_t i,
+                            unsigned phase,
+                            const std::string& category,
+                            const std::string& name) {
+    EXPECT_EQ(phase, collected_events_phases_[i]);
+    EXPECT_EQ(category, collected_events_categories_[i]);
+    EXPECT_EQ(name, collected_events_names_[i]);
+  }
+
+  std::vector<std::string> collected_events_categories_;
+  std::vector<std::string> collected_events_names_;
+  std::vector<unsigned char> collected_events_phases_;
+  std::vector<TraceTicks> collected_events_timestamps_;
+
+  static TraceEventCallbackTest* s_instance;
+  static void Callback(TraceTicks timestamp,
+                       char phase,
+                       const unsigned char* category_group_enabled,
+                       const char* name,
+                       unsigned long long id,
+                       int num_args,
+                       const char* const arg_names[],
+                       const unsigned char arg_types[],
+                       const unsigned long long arg_values[],
+                       unsigned char flags) {
+    s_instance->collected_events_phases_.push_back(phase);
+    s_instance->collected_events_categories_.push_back(
+        TraceLog::GetCategoryGroupName(category_group_enabled));
+    s_instance->collected_events_names_.push_back(name);
+    s_instance->collected_events_timestamps_.push_back(timestamp);
+  }
+};
+
+TraceEventCallbackTest* TraceEventCallbackTest::s_instance;
+
+TEST_F(TraceEventCallbackTest, TraceEventCallback) {
+  TRACE_EVENT_INSTANT0("all", "before enable", TRACE_EVENT_SCOPE_THREAD);
+  TraceLog::GetInstance()->SetEventCallbackEnabled(
+      TraceConfig(kRecordAllCategoryFilter, ""), Callback);
+  TRACE_EVENT_INSTANT0("all", "event1", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_INSTANT0("all", "event2", TRACE_EVENT_SCOPE_GLOBAL);
+  {
+    TRACE_EVENT0("all", "duration");
+    TRACE_EVENT_INSTANT0("all", "event3", TRACE_EVENT_SCOPE_GLOBAL);
+  }
+  TraceLog::GetInstance()->SetEventCallbackDisabled();
+  TRACE_EVENT_INSTANT0("all", "after callback removed",
+                       TRACE_EVENT_SCOPE_GLOBAL);
+  ASSERT_EQ(5u, collected_events_names_.size());
+  EXPECT_EQ("event1", collected_events_names_[0]);
+  EXPECT_EQ(TRACE_EVENT_PHASE_INSTANT, collected_events_phases_[0]);
+  EXPECT_EQ("event2", collected_events_names_[1]);
+  EXPECT_EQ(TRACE_EVENT_PHASE_INSTANT, collected_events_phases_[1]);
+  EXPECT_EQ("duration", collected_events_names_[2]);
+  EXPECT_EQ(TRACE_EVENT_PHASE_BEGIN, collected_events_phases_[2]);
+  EXPECT_EQ("event3", collected_events_names_[3]);
+  EXPECT_EQ(TRACE_EVENT_PHASE_INSTANT, collected_events_phases_[3]);
+  EXPECT_EQ("duration", collected_events_names_[4]);
+  EXPECT_EQ(TRACE_EVENT_PHASE_END, collected_events_phases_[4]);
+  for (size_t i = 1; i < collected_events_timestamps_.size(); i++) {
+    EXPECT_LE(collected_events_timestamps_[i - 1],
+              collected_events_timestamps_[i]);
+  }
+}
+
+TEST_F(TraceEventCallbackTest, TraceEventCallbackWhileFull) {
+  TraceLog::GetInstance()->SetEnabled(TraceConfig(kRecordAllCategoryFilter, ""),
+                                      TraceLog::RECORDING_MODE);
+  do {
+    TRACE_EVENT_INSTANT0("all", "badger badger", TRACE_EVENT_SCOPE_GLOBAL);
+  } while (!TraceLog::GetInstance()->BufferIsFull());
+  TraceLog::GetInstance()->SetEventCallbackEnabled(
+      TraceConfig(kRecordAllCategoryFilter, ""), Callback);
+  TRACE_EVENT_INSTANT0("all", "a snake", TRACE_EVENT_SCOPE_GLOBAL);
+  TraceLog::GetInstance()->SetEventCallbackDisabled();
+  ASSERT_EQ(1u, collected_events_names_.size());
+  EXPECT_EQ("a snake", collected_events_names_[0]);
+}
+
+// 1: Enable callback, enable recording, disable callback, disable recording.
+TEST_F(TraceEventCallbackTest, TraceEventCallbackAndRecording1) {
+  TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
+  TraceLog::GetInstance()->SetEventCallbackEnabled(TraceConfig("callback", ""),
+                                                   Callback);
+  TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_INSTANT0("callback", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+  TraceLog::GetInstance()->SetEnabled(TraceConfig("recording", ""),
+                                      TraceLog::RECORDING_MODE);
+  TRACE_EVENT_INSTANT0("recording", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_INSTANT0("callback", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+  TraceLog::GetInstance()->SetEventCallbackDisabled();
+  TRACE_EVENT_INSTANT0("recording", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
+  EndTraceAndFlush();
+  TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
+
+  DropTracedMetadataRecords();
+  VerifyCallbackAndRecordedEvents(2, 2);
+}
+
+// 2: Enable callback, enable recording, disable recording, disable callback.
+TEST_F(TraceEventCallbackTest, TraceEventCallbackAndRecording2) {
+  TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
+  TraceLog::GetInstance()->SetEventCallbackEnabled(TraceConfig("callback", ""),
+                                                   Callback);
+  TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_INSTANT0("callback", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+  TraceLog::GetInstance()->SetEnabled(TraceConfig("recording", ""),
+                                      TraceLog::RECORDING_MODE);
+  TRACE_EVENT_INSTANT0("recording", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_INSTANT0("callback", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+  EndTraceAndFlush();
+  TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_INSTANT0("callback", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+  TraceLog::GetInstance()->SetEventCallbackDisabled();
+  TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
+
+  DropTracedMetadataRecords();
+  VerifyCallbackAndRecordedEvents(3, 1);
+}
+
+// 3: Enable recording, enable callback, disable callback, disable recording.
+TEST_F(TraceEventCallbackTest, TraceEventCallbackAndRecording3) {
+  TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
+  TraceLog::GetInstance()->SetEnabled(TraceConfig("recording", ""),
+                                      TraceLog::RECORDING_MODE);
+  TRACE_EVENT_INSTANT0("recording", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
+  TraceLog::GetInstance()->SetEventCallbackEnabled(TraceConfig("callback", ""),
+                                                   Callback);
+  TRACE_EVENT_INSTANT0("recording", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_INSTANT0("callback", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+  TraceLog::GetInstance()->SetEventCallbackDisabled();
+  TRACE_EVENT_INSTANT0("recording", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
+  EndTraceAndFlush();
+  TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
+
+  DropTracedMetadataRecords();
+  VerifyCallbackAndRecordedEvents(1, 3);
+}
+
+// 4: Enable recording, enable callback, disable recording, disable callback.
+TEST_F(TraceEventCallbackTest, TraceEventCallbackAndRecording4) {
+  TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
+  TraceLog::GetInstance()->SetEnabled(TraceConfig("recording", ""),
+                                      TraceLog::RECORDING_MODE);
+  TRACE_EVENT_INSTANT0("recording", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
+  TraceLog::GetInstance()->SetEventCallbackEnabled(TraceConfig("callback", ""),
+                                                   Callback);
+  TRACE_EVENT_INSTANT0("recording", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_INSTANT0("callback", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+  EndTraceAndFlush();
+  TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_INSTANT0("callback", "yes", TRACE_EVENT_SCOPE_GLOBAL);
+  TraceLog::GetInstance()->SetEventCallbackDisabled();
+  TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
+
+  DropTracedMetadataRecords();
+  VerifyCallbackAndRecordedEvents(2, 2);
+}
+
+TEST_F(TraceEventCallbackTest, TraceEventCallbackAndRecordingDuration) {
+  TraceLog::GetInstance()->SetEventCallbackEnabled(
+      TraceConfig(kRecordAllCategoryFilter, ""), Callback);
+  {
+    TRACE_EVENT0("callback", "duration1");
+    TraceLog::GetInstance()->SetEnabled(
+        TraceConfig(kRecordAllCategoryFilter, ""), TraceLog::RECORDING_MODE);
+    TRACE_EVENT0("callback", "duration2");
+    EndTraceAndFlush();
+    TRACE_EVENT0("callback", "duration3");
+  }
+  TraceLog::GetInstance()->SetEventCallbackDisabled();
+
+  ASSERT_EQ(6u, collected_events_names_.size());
+  VerifyCollectedEvent(0, TRACE_EVENT_PHASE_BEGIN, "callback", "duration1");
+  VerifyCollectedEvent(1, TRACE_EVENT_PHASE_BEGIN, "callback", "duration2");
+  VerifyCollectedEvent(2, TRACE_EVENT_PHASE_BEGIN, "callback", "duration3");
+  VerifyCollectedEvent(3, TRACE_EVENT_PHASE_END, "callback", "duration3");
+  VerifyCollectedEvent(4, TRACE_EVENT_PHASE_END, "callback", "duration2");
+  VerifyCollectedEvent(5, TRACE_EVENT_PHASE_END, "callback", "duration1");
+}
+
+TEST_F(TraceEventTestFixture, TraceBufferVectorReportFull) {
+  TraceLog* trace_log = TraceLog::GetInstance();
+  trace_log->SetEnabled(
+      TraceConfig(kRecordAllCategoryFilter, ""), TraceLog::RECORDING_MODE);
+  trace_log->logged_events_.reset(
+      trace_log->CreateTraceBufferVectorOfSize(100));
+  do {
+    TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0(
+        "all", "with_timestamp", 0, 0, TraceTicks::Now().ToInternalValue());
+    TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0(
+        "all", "with_timestamp", 0, 0, TraceTicks::Now().ToInternalValue());
+  } while (!trace_log->BufferIsFull());
+
+  EndTraceAndFlush();
+
+  const DictionaryValue* trace_full_metadata = NULL;
+
+  trace_full_metadata = FindTraceEntry(trace_parsed_,
+                                       "overflowed_at_ts");
+  std::string phase;
+  double buffer_limit_reached_timestamp = 0;
+
+  EXPECT_TRUE(trace_full_metadata);
+  EXPECT_TRUE(trace_full_metadata->GetString("ph", &phase));
+  EXPECT_EQ("M", phase);
+  EXPECT_TRUE(trace_full_metadata->GetDouble(
+      "args.overflowed_at_ts", &buffer_limit_reached_timestamp));
+  EXPECT_DOUBLE_EQ(
+      static_cast<double>(
+          trace_log->buffer_limit_reached_timestamp_.ToInternalValue()),
+      buffer_limit_reached_timestamp);
+
+  // Test that buffer_limit_reached_timestamp's value is between the timestamp
+  // of the last trace event and current time.
+  DropTracedMetadataRecords();
+  const DictionaryValue* last_trace_event = NULL;
+  double last_trace_event_timestamp = 0;
+  EXPECT_TRUE(trace_parsed_.GetDictionary(trace_parsed_.GetSize() - 1,
+                                          &last_trace_event));
+  EXPECT_TRUE(last_trace_event->GetDouble("ts", &last_trace_event_timestamp));
+  EXPECT_LE(last_trace_event_timestamp, buffer_limit_reached_timestamp);
+  EXPECT_LE(buffer_limit_reached_timestamp,
+            trace_log->OffsetNow().ToInternalValue());
+}
+
+TEST_F(TraceEventTestFixture, TraceBufferRingBufferGetReturnChunk) {
+  TraceLog::GetInstance()->SetEnabled(
+      TraceConfig(kRecordAllCategoryFilter, RECORD_CONTINUOUSLY),
+      TraceLog::RECORDING_MODE);
+  TraceBuffer* buffer = TraceLog::GetInstance()->trace_buffer();
+  size_t capacity = buffer->Capacity();
+  size_t num_chunks = capacity / TraceBufferChunk::kTraceBufferChunkSize;
+  uint32 last_seq = 0;
+  size_t chunk_index;
+  EXPECT_EQ(0u, buffer->Size());
+
+  scoped_ptr<TraceBufferChunk*[]> chunks(new TraceBufferChunk*[num_chunks]);
+  for (size_t i = 0; i < num_chunks; ++i) {
+    chunks[i] = buffer->GetChunk(&chunk_index).release();
+    EXPECT_TRUE(chunks[i]);
+    EXPECT_EQ(i, chunk_index);
+    EXPECT_GT(chunks[i]->seq(), last_seq);
+    EXPECT_EQ((i + 1) * TraceBufferChunk::kTraceBufferChunkSize,
+              buffer->Size());
+    last_seq = chunks[i]->seq();
+  }
+
+  // Ring buffer is never full.
+  EXPECT_FALSE(buffer->IsFull());
+
+  // Return all chunks in original order.
+  for (size_t i = 0; i < num_chunks; ++i)
+    buffer->ReturnChunk(i, scoped_ptr<TraceBufferChunk>(chunks[i]));
+
+  // Should recycle the chunks in the returned order.
+  for (size_t i = 0; i < num_chunks; ++i) {
+    chunks[i] = buffer->GetChunk(&chunk_index).release();
+    EXPECT_TRUE(chunks[i]);
+    EXPECT_EQ(i, chunk_index);
+    EXPECT_GT(chunks[i]->seq(), last_seq);
+    last_seq = chunks[i]->seq();
+  }
+
+  // Return all chunks in reverse order.
+  for (size_t i = 0; i < num_chunks; ++i) {
+    buffer->ReturnChunk(
+        num_chunks - i - 1,
+        scoped_ptr<TraceBufferChunk>(chunks[num_chunks - i - 1]));
+  }
+
+  // Should recycle the chunks in the returned order.
+  for (size_t i = 0; i < num_chunks; ++i) {
+    chunks[i] = buffer->GetChunk(&chunk_index).release();
+    EXPECT_TRUE(chunks[i]);
+    EXPECT_EQ(num_chunks - i - 1, chunk_index);
+    EXPECT_GT(chunks[i]->seq(), last_seq);
+    last_seq = chunks[i]->seq();
+  }
+
+  for (size_t i = 0; i < num_chunks; ++i)
+    buffer->ReturnChunk(i, scoped_ptr<TraceBufferChunk>(chunks[i]));
+
+  TraceLog::GetInstance()->SetDisabled();
+}
+
+TEST_F(TraceEventTestFixture, TraceBufferRingBufferHalfIteration) {
+  TraceLog::GetInstance()->SetEnabled(
+      TraceConfig(kRecordAllCategoryFilter, RECORD_CONTINUOUSLY),
+      TraceLog::RECORDING_MODE);
+  TraceBuffer* buffer = TraceLog::GetInstance()->trace_buffer();
+  size_t capacity = buffer->Capacity();
+  size_t num_chunks = capacity / TraceBufferChunk::kTraceBufferChunkSize;
+  size_t chunk_index;
+  EXPECT_EQ(0u, buffer->Size());
+  EXPECT_FALSE(buffer->NextChunk());
+
+  size_t half_chunks = num_chunks / 2;
+  scoped_ptr<TraceBufferChunk*[]> chunks(new TraceBufferChunk*[half_chunks]);
+
+  for (size_t i = 0; i < half_chunks; ++i) {
+    chunks[i] = buffer->GetChunk(&chunk_index).release();
+    EXPECT_TRUE(chunks[i]);
+    EXPECT_EQ(i, chunk_index);
+  }
+  for (size_t i = 0; i < half_chunks; ++i)
+    buffer->ReturnChunk(i, scoped_ptr<TraceBufferChunk>(chunks[i]));
+
+  for (size_t i = 0; i < half_chunks; ++i)
+    EXPECT_EQ(chunks[i], buffer->NextChunk());
+  EXPECT_FALSE(buffer->NextChunk());
+  TraceLog::GetInstance()->SetDisabled();
+}
+
+TEST_F(TraceEventTestFixture, TraceBufferRingBufferFullIteration) {
+  TraceLog::GetInstance()->SetEnabled(
+      TraceConfig(kRecordAllCategoryFilter, RECORD_CONTINUOUSLY),
+      TraceLog::RECORDING_MODE);
+  TraceBuffer* buffer = TraceLog::GetInstance()->trace_buffer();
+  size_t capacity = buffer->Capacity();
+  size_t num_chunks = capacity / TraceBufferChunk::kTraceBufferChunkSize;
+  size_t chunk_index;
+  EXPECT_EQ(0u, buffer->Size());
+  EXPECT_FALSE(buffer->NextChunk());
+
+  scoped_ptr<TraceBufferChunk*[]> chunks(new TraceBufferChunk*[num_chunks]);
+
+  for (size_t i = 0; i < num_chunks; ++i) {
+    chunks[i] = buffer->GetChunk(&chunk_index).release();
+    EXPECT_TRUE(chunks[i]);
+    EXPECT_EQ(i, chunk_index);
+  }
+  for (size_t i = 0; i < num_chunks; ++i)
+    buffer->ReturnChunk(i, scoped_ptr<TraceBufferChunk>(chunks[i]));
+
+  for (size_t i = 0; i < num_chunks; ++i)
+    EXPECT_TRUE(chunks[i] == buffer->NextChunk());
+  EXPECT_FALSE(buffer->NextChunk());
+  TraceLog::GetInstance()->SetDisabled();
+}
+
+TEST_F(TraceEventTestFixture, TraceRecordAsMuchAsPossibleMode) {
+  TraceLog::GetInstance()->SetEnabled(
+    TraceConfig(kRecordAllCategoryFilter, RECORD_AS_MUCH_AS_POSSIBLE),
+    TraceLog::RECORDING_MODE);
+  TraceBuffer* buffer = TraceLog::GetInstance()->trace_buffer();
+  EXPECT_EQ(512000000UL, buffer->Capacity());
+  TraceLog::GetInstance()->SetDisabled();
+}
+
+void BlockUntilStopped(WaitableEvent* task_start_event,
+                       WaitableEvent* task_stop_event) {
+  task_start_event->Signal();
+  task_stop_event->Wait();
+}
+
+TEST_F(TraceEventTestFixture, SetCurrentThreadBlocksMessageLoopBeforeTracing) {
+  BeginTrace();
+
+  Thread thread("1");
+  WaitableEvent task_complete_event(false, false);
+  thread.Start();
+  thread.task_runner()->PostTask(
+      FROM_HERE, Bind(&TraceLog::SetCurrentThreadBlocksMessageLoop,
+                      Unretained(TraceLog::GetInstance())));
+
+  thread.task_runner()->PostTask(
+      FROM_HERE, Bind(&TraceWithAllMacroVariants, &task_complete_event));
+  task_complete_event.Wait();
+
+  WaitableEvent task_start_event(false, false);
+  WaitableEvent task_stop_event(false, false);
+  thread.task_runner()->PostTask(
+      FROM_HERE, Bind(&BlockUntilStopped, &task_start_event, &task_stop_event));
+  task_start_event.Wait();
+
+  EndTraceAndFlush();
+  ValidateAllTraceMacrosCreatedData(trace_parsed_);
+
+  task_stop_event.Signal();
+  thread.Stop();
+}
+
+TEST_F(TraceEventTestFixture, ConvertTraceConfigToInternalOptions) {
+  TraceLog* trace_log = TraceLog::GetInstance();
+  EXPECT_EQ(TraceLog::kInternalRecordUntilFull,
+            trace_log->GetInternalOptionsFromTraceConfig(
+                TraceConfig(kRecordAllCategoryFilter, RECORD_UNTIL_FULL)));
+
+  EXPECT_EQ(TraceLog::kInternalRecordContinuously,
+            trace_log->GetInternalOptionsFromTraceConfig(
+                TraceConfig(kRecordAllCategoryFilter, RECORD_CONTINUOUSLY)));
+
+  EXPECT_EQ(TraceLog::kInternalEchoToConsole,
+            trace_log->GetInternalOptionsFromTraceConfig(
+                TraceConfig(kRecordAllCategoryFilter, ECHO_TO_CONSOLE)));
+
+  EXPECT_EQ(
+      TraceLog::kInternalRecordUntilFull | TraceLog::kInternalEnableSampling,
+      trace_log->GetInternalOptionsFromTraceConfig(
+          TraceConfig(kRecordAllCategoryFilter,
+                      "record-until-full,enable-sampling")));
+
+  EXPECT_EQ(
+      TraceLog::kInternalRecordContinuously | TraceLog::kInternalEnableSampling,
+      trace_log->GetInternalOptionsFromTraceConfig(
+          TraceConfig(kRecordAllCategoryFilter,
+                      "record-continuously,enable-sampling")));
+
+  EXPECT_EQ(
+      TraceLog::kInternalEchoToConsole | TraceLog::kInternalEnableSampling,
+      trace_log->GetInternalOptionsFromTraceConfig(
+          TraceConfig(kRecordAllCategoryFilter,
+                      "trace-to-console,enable-sampling")));
+
+  EXPECT_EQ(
+      TraceLog::kInternalEchoToConsole | TraceLog::kInternalEnableSampling,
+      trace_log->GetInternalOptionsFromTraceConfig(
+          TraceConfig("*",
+                      "trace-to-console,enable-sampling,enable-systrace")));
+}
+
+void SetBlockingFlagAndBlockUntilStopped(WaitableEvent* task_start_event,
+                                         WaitableEvent* task_stop_event) {
+  TraceLog::GetInstance()->SetCurrentThreadBlocksMessageLoop();
+  BlockUntilStopped(task_start_event, task_stop_event);
+}
+
+TEST_F(TraceEventTestFixture, SetCurrentThreadBlocksMessageLoopAfterTracing) {
+  BeginTrace();
+
+  Thread thread("1");
+  WaitableEvent task_complete_event(false, false);
+  thread.Start();
+
+  thread.task_runner()->PostTask(
+      FROM_HERE, Bind(&TraceWithAllMacroVariants, &task_complete_event));
+  task_complete_event.Wait();
+
+  WaitableEvent task_start_event(false, false);
+  WaitableEvent task_stop_event(false, false);
+  thread.task_runner()->PostTask(
+      FROM_HERE, Bind(&SetBlockingFlagAndBlockUntilStopped, &task_start_event,
+                      &task_stop_event));
+  task_start_event.Wait();
+
+  EndTraceAndFlush();
+  ValidateAllTraceMacrosCreatedData(trace_parsed_);
+
+  task_stop_event.Signal();
+  thread.Stop();
+}
+
+TEST_F(TraceEventTestFixture, ThreadOnceBlocking) {
+  BeginTrace();
+
+  Thread thread("1");
+  WaitableEvent task_complete_event(false, false);
+  thread.Start();
+
+  thread.task_runner()->PostTask(
+      FROM_HERE, Bind(&TraceWithAllMacroVariants, &task_complete_event));
+  task_complete_event.Wait();
+  task_complete_event.Reset();
+
+  WaitableEvent task_start_event(false, false);
+  WaitableEvent task_stop_event(false, false);
+  thread.task_runner()->PostTask(
+      FROM_HERE, Bind(&BlockUntilStopped, &task_start_event, &task_stop_event));
+  task_start_event.Wait();
+
+  // The thread will timeout in this flush.
+  EndTraceAndFlushInThreadWithMessageLoop();
+  Clear();
+
+  // Let the thread's message loop continue to spin.
+  task_stop_event.Signal();
+
+  // The following sequence ensures that the FlushCurrentThread task has been
+  // executed in the thread before continuing.
+  task_start_event.Reset();
+  task_stop_event.Reset();
+  thread.task_runner()->PostTask(
+      FROM_HERE, Bind(&BlockUntilStopped, &task_start_event, &task_stop_event));
+  task_start_event.Wait();
+  task_stop_event.Signal();
+  Clear();
+
+  // TraceLog should discover the generation mismatch and recover the thread
+  // local buffer for the thread without any error.
+  BeginTrace();
+  thread.task_runner()->PostTask(
+      FROM_HERE, Bind(&TraceWithAllMacroVariants, &task_complete_event));
+  task_complete_event.Wait();
+  task_complete_event.Reset();
+  EndTraceAndFlushInThreadWithMessageLoop();
+  ValidateAllTraceMacrosCreatedData(trace_parsed_);
+}
+
+std::string* g_log_buffer = NULL;
+bool MockLogMessageHandler(int, const char*, int, size_t,
+                           const std::string& str) {
+  if (!g_log_buffer)
+    g_log_buffer = new std::string();
+  g_log_buffer->append(str);
+  return false;
+}
+
+TEST_F(TraceEventTestFixture, EchoToConsole) {
+  logging::LogMessageHandlerFunction old_log_message_handler =
+      logging::GetLogMessageHandler();
+  logging::SetLogMessageHandler(MockLogMessageHandler);
+
+  TraceLog::GetInstance()->SetEnabled(
+      TraceConfig(kRecordAllCategoryFilter, ECHO_TO_CONSOLE),
+      TraceLog::RECORDING_MODE);
+  TRACE_EVENT_BEGIN0("a", "begin_end");
+  {
+    TRACE_EVENT0("b", "duration");
+    TRACE_EVENT0("b1", "duration1");
+  }
+  TRACE_EVENT_INSTANT0("c", "instant", TRACE_EVENT_SCOPE_GLOBAL);
+  TRACE_EVENT_END0("a", "begin_end");
+
+  EXPECT_NE(std::string::npos, g_log_buffer->find("begin_end[a]\x1b"));
+  EXPECT_NE(std::string::npos, g_log_buffer->find("| duration[b]\x1b"));
+  EXPECT_NE(std::string::npos, g_log_buffer->find("| | duration1[b1]\x1b"));
+  EXPECT_NE(std::string::npos, g_log_buffer->find("| | duration1[b1] ("));
+  EXPECT_NE(std::string::npos, g_log_buffer->find("| duration[b] ("));
+  EXPECT_NE(std::string::npos, g_log_buffer->find("| instant[c]\x1b"));
+  EXPECT_NE(std::string::npos, g_log_buffer->find("begin_end[a] ("));
+
+  EndTraceAndFlush();
+  delete g_log_buffer;
+  logging::SetLogMessageHandler(old_log_message_handler);
+  g_log_buffer = NULL;
+}
+
+bool LogMessageHandlerWithTraceEvent(int, const char*, int, size_t,
+                                     const std::string&) {
+  TRACE_EVENT0("log", "trace_event");
+  return false;
+}
+
+TEST_F(TraceEventTestFixture, EchoToConsoleTraceEventRecursion) {
+  logging::LogMessageHandlerFunction old_log_message_handler =
+      logging::GetLogMessageHandler();
+  logging::SetLogMessageHandler(LogMessageHandlerWithTraceEvent);
+
+  TraceLog::GetInstance()->SetEnabled(
+      TraceConfig(kRecordAllCategoryFilter, ECHO_TO_CONSOLE),
+      TraceLog::RECORDING_MODE);
+  {
+    // This should not cause deadlock or infinite recursion.
+    TRACE_EVENT0("b", "duration");
+  }
+
+  EndTraceAndFlush();
+  logging::SetLogMessageHandler(old_log_message_handler);
+}
+
+TEST_F(TraceEventTestFixture, TimeOffset) {
+  BeginTrace();
+  // Let TraceLog timer start from 0.
+  TimeDelta time_offset = TraceTicks::Now() - TraceTicks();
+  TraceLog::GetInstance()->SetTimeOffset(time_offset);
+
+  {
+    TRACE_EVENT0("all", "duration1");
+    TRACE_EVENT0("all", "duration2");
+  }
+  TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0(
+      "all", "with_timestamp", 0, 0, TraceTicks::Now().ToInternalValue());
+  TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0(
+      "all", "with_timestamp", 0, 0, TraceTicks::Now().ToInternalValue());
+
+  EndTraceAndFlush();
+  DropTracedMetadataRecords();
+
+  double end_time = static_cast<double>(
+      (TraceTicks::Now() - time_offset).ToInternalValue());
+  double last_timestamp = 0;
+  for (size_t i = 0; i < trace_parsed_.GetSize(); ++i) {
+    const DictionaryValue* item;
+    EXPECT_TRUE(trace_parsed_.GetDictionary(i, &item));
+    double timestamp;
+    EXPECT_TRUE(item->GetDouble("ts", &timestamp));
+    EXPECT_GE(timestamp, last_timestamp);
+    EXPECT_LE(timestamp, end_time);
+    last_timestamp = timestamp;
+  }
+}
+
+TEST_F(TraceEventTestFixture, ConfigureSyntheticDelays) {
+  BeginSpecificTrace("DELAY(test.Delay;0.05)");
+
+  base::TimeTicks start = base::TimeTicks::Now();
+  {
+    TRACE_EVENT_SYNTHETIC_DELAY("test.Delay");
+  }
+  base::TimeDelta duration = base::TimeTicks::Now() - start;
+  EXPECT_GE(duration.InMilliseconds(), 50);
+
+  EndTraceAndFlush();
+}
+
+TEST_F(TraceEventTestFixture, BadSyntheticDelayConfigurations) {
+  const char* const filters[] = {
+    "",
+    "DELAY(",
+    "DELAY(;",
+    "DELAY(;)",
+    "DELAY(test.Delay)",
+    "DELAY(test.Delay;)"
+  };
+  for (size_t i = 0; i < arraysize(filters); i++) {
+    BeginSpecificTrace(filters[i]);
+    EndTraceAndFlush();
+    TraceConfig trace_config = TraceLog::GetInstance()->GetCurrentTraceConfig();
+    EXPECT_EQ(0u, trace_config.GetSyntheticDelayValues().size());
+  }
+}
+
+TEST_F(TraceEventTestFixture, SyntheticDelayConfigurationMerging) {
+  TraceConfig config1("DELAY(test.Delay1;16)", "");
+  TraceConfig config2("DELAY(test.Delay2;32)", "");
+  config1.Merge(config2);
+  EXPECT_EQ(2u, config1.GetSyntheticDelayValues().size());
+}
+
+TEST_F(TraceEventTestFixture, SyntheticDelayConfigurationToString) {
+  const char filter[] = "DELAY(test.Delay;16;oneshot)";
+  TraceConfig config(filter, "");
+  EXPECT_EQ(filter, config.ToCategoryFilterString());
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/trace_event_win.cc b/base/trace_event/trace_event_win.cc
new file mode 100644
index 0000000..ebb55c8
--- /dev/null
+++ b/base/trace_event/trace_event_win.cc
@@ -0,0 +1,124 @@
+// Copyright (c) 2012 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/trace_event_win.h"
+
+#include "base/logging.h"
+#include "base/memory/singleton.h"
+#include <initguid.h>  // NOLINT
+
+namespace base {
+namespace trace_event {
+
+using base::win::EtwEventType;
+using base::win::EtwMofEvent;
+
+// {3DADA31D-19EF-4dc1-B345-037927193422}
+const GUID kChromeTraceProviderName = {
+    0x3dada31d, 0x19ef, 0x4dc1, 0xb3, 0x45, 0x3, 0x79, 0x27, 0x19, 0x34, 0x22 };
+
+// {B967AE67-BB22-49d7-9406-55D91EE1D560}
+const GUID kTraceEventClass32 = {
+    0xb967ae67, 0xbb22, 0x49d7, 0x94, 0x6, 0x55, 0xd9, 0x1e, 0xe1, 0xd5, 0x60 };
+
+// {97BE602D-2930-4ac3-8046-B6763B631DFE}
+const GUID kTraceEventClass64 = {
+    0x97be602d, 0x2930, 0x4ac3, 0x80, 0x46, 0xb6, 0x76, 0x3b, 0x63, 0x1d, 0xfe};
+
+
+TraceEventETWProvider::TraceEventETWProvider() :
+    EtwTraceProvider(kChromeTraceProviderName) {
+  Register();
+}
+
+TraceEventETWProvider* TraceEventETWProvider::GetInstance() {
+  return Singleton<TraceEventETWProvider,
+      StaticMemorySingletonTraits<TraceEventETWProvider> >::get();
+}
+
+bool TraceEventETWProvider::StartTracing() {
+  return true;
+}
+
+void TraceEventETWProvider::TraceEvent(const char* name,
+                                       size_t name_len,
+                                       char type,
+                                       const void* id,
+                                       const char* extra,
+                                       size_t extra_len) {
+  // Make sure we don't touch NULL.
+  if (name == NULL)
+    name = "";
+  if (extra == NULL)
+    extra = "";
+
+  EtwEventType etw_type = 0;
+  switch (type) {
+    case TRACE_EVENT_PHASE_BEGIN:
+      etw_type = kTraceEventTypeBegin;
+      break;
+    case TRACE_EVENT_PHASE_END:
+      etw_type = kTraceEventTypeEnd;
+      break;
+
+    case TRACE_EVENT_PHASE_INSTANT:
+      etw_type = kTraceEventTypeInstant;
+      break;
+
+    default:
+      NOTREACHED() << "Unknown event type";
+      etw_type = kTraceEventTypeInstant;
+      break;
+  }
+
+  EtwMofEvent<5> event(kTraceEventClass32,
+                       etw_type,
+                       TRACE_LEVEL_INFORMATION);
+  event.SetField(0, name_len + 1, name);
+  event.SetField(1, sizeof(id), &id);
+  event.SetField(2, extra_len + 1, extra);
+
+  // These variables are declared here so that they are not out of scope when
+  // the event is logged.
+  DWORD depth;
+  void* backtrace[32];
+
+  // See whether we're to capture a backtrace.
+  if (enable_flags() & CAPTURE_STACK_TRACE) {
+    depth = CaptureStackBackTrace(0,
+                                  arraysize(backtrace),
+                                  backtrace,
+                                  NULL);
+    event.SetField(3, sizeof(depth), &depth);
+    event.SetField(4, sizeof(backtrace[0]) * depth, backtrace);
+  }
+
+  // Trace the event.
+  Log(event.get());
+}
+
+void TraceEventETWProvider::Trace(const char* name,
+                                  size_t name_len,
+                                  char type,
+                                  const void* id,
+                                  const char* extra,
+                                  size_t extra_len) {
+  TraceEventETWProvider* provider = TraceEventETWProvider::GetInstance();
+  if (provider && provider->IsTracing()) {
+    // Compute the name & extra lengths if not supplied already.
+    if (name_len == kUseStrlen)
+      name_len = (name == NULL) ? 0 : strlen(name);
+    if (extra_len == kUseStrlen)
+      extra_len = (extra == NULL) ? 0 : strlen(extra);
+
+    provider->TraceEvent(name, name_len, type, id, extra, extra_len);
+  }
+}
+
+void TraceEventETWProvider::Resurrect() {
+  StaticMemorySingletonTraits<TraceEventETWProvider>::Resurrect();
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/trace_event_win.h b/base/trace_event/trace_event_win.h
new file mode 100644
index 0000000..4161361
--- /dev/null
+++ b/base/trace_event/trace_event_win.h
@@ -0,0 +1,125 @@
+// Copyright (c) 2012 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 contains the Windows-specific declarations for trace_event.h.
+#ifndef BASE_TRACE_EVENT_TRACE_EVENT_WIN_H_
+#define BASE_TRACE_EVENT_TRACE_EVENT_WIN_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/trace_event/trace_event.h"
+#include "base/win/event_trace_provider.h"
+
+// Fwd.
+template <typename Type>
+struct StaticMemorySingletonTraits;
+
+namespace base {
+namespace trace_event {
+
+// This EtwTraceProvider subclass implements ETW logging
+// for the macros above on Windows.
+class BASE_EXPORT TraceEventETWProvider : public base::win::EtwTraceProvider {
+ public:
+   static const size_t kUseStrlen = static_cast<size_t>(-1);
+
+  // Start logging trace events.
+  // This is a noop in this implementation.
+  static bool StartTracing();
+
+  // Trace begin/end/instant events, this is the bottleneck implementation
+  // all the others defer to.
+  // Allowing the use of std::string for name or extra is a convenience,
+  // whereas passing name or extra as a const char* avoids the construction
+  // of temporary std::string instances.
+  // If kUseStrlen is passed for name_len or extra_len, the strlen of the string
+  // will be used for length.
+  static void Trace(const char* name,
+                    size_t name_len,
+                    char type,
+                    const void* id,
+                    const char* extra,
+                    size_t extra_len);
+
+  // Allows passing extra as a std::string for convenience.
+  static void Trace(const char* name,
+                    char type,
+                    const void* id,
+                    const std::string& extra) {
+    return Trace(name, kUseStrlen, type, id, extra.c_str(), extra.length());
+  }
+
+  // Allows passing extra as a const char* to avoid constructing temporary
+  // std::string instances where not needed.
+  static void Trace(const char* name,
+                    char type,
+                    const void* id,
+                    const char* extra) {
+    return Trace(name, kUseStrlen, type, id, extra, kUseStrlen);
+  }
+
+  // Retrieves the singleton.
+  // Note that this may return NULL post-AtExit processing.
+  static TraceEventETWProvider* GetInstance();
+
+  // Returns true iff tracing is turned on.
+  bool IsTracing() {
+    return enable_level() >= TRACE_LEVEL_INFORMATION;
+  }
+
+  // Emit a trace of type |type| containing |name|, |id|, and |extra|.
+  // Note: |name| and |extra| must be NULL, or a zero-terminated string of
+  //    length |name_len| or |extra_len| respectively.
+  // Note: if name_len or extra_len are kUseStrlen, the length of the
+  //    corresponding string will be used.
+  void TraceEvent(const char* name,
+                  size_t name_len,
+                  char type,
+                  const void* id,
+                  const char* extra,
+                  size_t extra_len);
+
+  // Exposed for unittesting only, allows resurrecting our
+  // singleton instance post-AtExit processing.
+  static void Resurrect();
+
+ private:
+  // Ensure only the provider can construct us.
+  friend struct StaticMemorySingletonTraits<TraceEventETWProvider>;
+  TraceEventETWProvider();
+
+  DISALLOW_COPY_AND_ASSIGN(TraceEventETWProvider);
+};
+
+// The ETW trace provider GUID.
+BASE_EXPORT extern const GUID kChromeTraceProviderName;
+
+// The ETW event class GUID for 32 bit events.
+BASE_EXPORT extern const GUID kTraceEventClass32;
+
+// The ETW event class GUID for 64 bit events.
+BASE_EXPORT extern const GUID kTraceEventClass64;
+
+// The ETW event types, IDs 0x00-0x09 are reserved, so start at 0x10.
+const base::win::EtwEventType kTraceEventTypeBegin = 0x10;
+const base::win::EtwEventType kTraceEventTypeEnd = 0x11;
+const base::win::EtwEventType kTraceEventTypeInstant = 0x12;
+
+// If this flag is set in enable flags
+enum TraceEventETWFlags {
+  CAPTURE_STACK_TRACE = 0x0001,
+};
+
+// The event format consists of:
+// The "name" string as a zero-terminated ASCII string.
+// The id pointer in the machine bitness.
+// The "extra" string as a zero-terminated ASCII string.
+// Optionally the stack trace, consisting of a DWORD "depth", followed
+//    by an array of void* (machine bitness) of length "depth".
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_TRACE_EVENT_WIN_H_
diff --git a/base/trace_event/trace_event_win_unittest.cc b/base/trace_event/trace_event_win_unittest.cc
new file mode 100644
index 0000000..d4dc854
--- /dev/null
+++ b/base/trace_event/trace_event_win_unittest.cc
@@ -0,0 +1,319 @@
+// Copyright (c) 2011 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/trace_event.h"
+
+#include <strstream>
+
+#include "base/at_exit.h"
+#include "base/basictypes.h"
+#include "base/files/file_util.h"
+#include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_win.h"
+#include "base/win/event_trace_consumer.h"
+#include "base/win/event_trace_controller.h"
+#include "base/win/event_trace_provider.h"
+#include "base/win/windows_version.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include <initguid.h>  // NOLINT - must be last include.
+
+namespace base {
+namespace trace_event {
+
+namespace {
+
+using testing::_;
+using testing::AnyNumber;
+using testing::InSequence;
+using testing::Ge;
+using testing::Le;
+using testing::NotNull;
+
+using base::win::EtwEventType;
+using base::win::EtwTraceConsumerBase;
+using base::win::EtwTraceController;
+using base::win::EtwTraceProperties;
+
+// Data for unittests traces.
+const char kEmpty[] = "";
+const char kName[] = "unittest.trace_name";
+const char kExtra[] = "UnittestDummyExtraString";
+const void* kId = kName;
+
+const wchar_t kTestSessionName[] = L"TraceEvent unittest session";
+
+MATCHER_P(BufferStartsWith, str, "Buffer starts with") {
+  return memcmp(arg, str.c_str(), str.length()) == 0;
+}
+
+// Duplicated from <evntrace.h> to fix link problems.
+DEFINE_GUID( /* 68fdd900-4a3e-11d1-84f4-0000f80464e3 */
+    kEventTraceGuid,
+    0x68fdd900,
+    0x4a3e,
+    0x11d1,
+    0x84, 0xf4, 0x00, 0x00, 0xf8, 0x04, 0x64, 0xe3);
+
+class TestEventConsumer: public EtwTraceConsumerBase<TestEventConsumer> {
+ public:
+  TestEventConsumer() {
+    EXPECT_TRUE(current_ == NULL);
+    current_ = this;
+  }
+
+  ~TestEventConsumer() {
+    EXPECT_TRUE(current_ == this);
+    current_ = NULL;
+  }
+
+  MOCK_METHOD4(Event, void(REFGUID event_class,
+                      EtwEventType event_type,
+                      size_t buf_len,
+                      const void* buf));
+
+  static void ProcessEvent(EVENT_TRACE* event) {
+    ASSERT_TRUE(current_ != NULL);
+    current_->Event(event->Header.Guid,
+                    event->Header.Class.Type,
+                    event->MofLength,
+                    event->MofData);
+  }
+
+ private:
+  static TestEventConsumer* current_;
+};
+
+TestEventConsumer* TestEventConsumer::current_ = NULL;
+
+class TraceEventWinTest: public testing::Test {
+ public:
+  TraceEventWinTest() {
+  }
+
+  void SetUp() override {
+    bool is_xp = win::GetVersion() < base::win::VERSION_VISTA;
+
+    if (is_xp) {
+      // Tear down any dangling session from an earlier failing test.
+      EtwTraceProperties ignore;
+      EtwTraceController::Stop(kTestSessionName, &ignore);
+    }
+
+    // Resurrect and initialize the TraceLog singleton instance.
+    // On Vista and better, we need the provider registered before we
+    // start the private, in-proc session, but on XP we need the global
+    // session created and the provider enabled before we register our
+    // provider.
+    TraceEventETWProvider* tracelog = NULL;
+    if (!is_xp) {
+      TraceEventETWProvider::Resurrect();
+      tracelog = TraceEventETWProvider::GetInstance();
+      ASSERT_TRUE(tracelog != NULL);
+      ASSERT_FALSE(tracelog->IsTracing());
+    }
+
+    // Create the log file.
+    ASSERT_TRUE(base::CreateTemporaryFile(&log_file_));
+
+    // Create a private log session on the file.
+    EtwTraceProperties prop;
+    ASSERT_HRESULT_SUCCEEDED(prop.SetLoggerFileName(log_file_.value().c_str()));
+    EVENT_TRACE_PROPERTIES& p = *prop.get();
+    p.Wnode.ClientContext = 1;  // QPC timer accuracy.
+    p.LogFileMode = EVENT_TRACE_FILE_MODE_SEQUENTIAL;   // Sequential log.
+
+    // On Vista and later, we create a private in-process log session, because
+    // otherwise we'd need administrator privileges. Unfortunately we can't
+    // do the same on XP and better, because the semantics of a private
+    // logger session are different, and the IN_PROC flag is not supported.
+    if (!is_xp) {
+      p.LogFileMode |= EVENT_TRACE_PRIVATE_IN_PROC |  // In-proc for non-admin.
+          EVENT_TRACE_PRIVATE_LOGGER_MODE;  // Process-private log.
+    }
+
+    p.MaximumFileSize = 100;  // 100M file size.
+    p.FlushTimer = 1;  // 1 second flush lag.
+    ASSERT_HRESULT_SUCCEEDED(controller_.Start(kTestSessionName, &prop));
+
+    // Enable the TraceLog provider GUID.
+    ASSERT_HRESULT_SUCCEEDED(
+        controller_.EnableProvider(kChromeTraceProviderName,
+                                   TRACE_LEVEL_INFORMATION,
+                                   0));
+
+    if (is_xp) {
+      TraceEventETWProvider::Resurrect();
+      tracelog = TraceEventETWProvider::GetInstance();
+    }
+    ASSERT_TRUE(tracelog != NULL);
+    EXPECT_TRUE(tracelog->IsTracing());
+  }
+
+  void TearDown() override {
+    EtwTraceProperties prop;
+    if (controller_.session() != 0)
+      EXPECT_HRESULT_SUCCEEDED(controller_.Stop(&prop));
+
+    if (!log_file_.value().empty())
+      base::DeleteFile(log_file_, false);
+
+    // We want our singleton torn down after each test.
+    TraceLog::DeleteForTesting();
+  }
+
+  void ExpectEvent(REFGUID guid,
+                   EtwEventType type,
+                   const char* name,
+                   size_t name_len,
+                   const void* id,
+                   const char* extra,
+                   size_t extra_len) {
+    // Build the trace event buffer we expect will result from this.
+    std::stringbuf str;
+    str.sputn(name, name_len + 1);
+    str.sputn(reinterpret_cast<const char*>(&id), sizeof(id));
+    str.sputn(extra, extra_len + 1);
+
+    // And set up the expectation for the event callback.
+    EXPECT_CALL(consumer_, Event(guid,
+                                 type,
+                                 testing::Ge(str.str().length()),
+                                 BufferStartsWith(str.str())));
+  }
+
+  void ExpectPlayLog() {
+    // Ignore EventTraceGuid events.
+    EXPECT_CALL(consumer_, Event(kEventTraceGuid, _, _, _))
+        .Times(AnyNumber());
+  }
+
+  void PlayLog() {
+    EtwTraceProperties prop;
+    EXPECT_HRESULT_SUCCEEDED(controller_.Flush(&prop));
+    EXPECT_HRESULT_SUCCEEDED(controller_.Stop(&prop));
+    ASSERT_HRESULT_SUCCEEDED(
+        consumer_.OpenFileSession(log_file_.value().c_str()));
+
+    ASSERT_HRESULT_SUCCEEDED(consumer_.Consume());
+  }
+
+ private:
+  // We want our singleton torn down after each test.
+  ShadowingAtExitManager at_exit_manager_;
+  EtwTraceController controller_;
+  FilePath log_file_;
+  TestEventConsumer consumer_;
+};
+
+}  // namespace
+
+
+TEST_F(TraceEventWinTest, TraceLog) {
+  ExpectPlayLog();
+
+  // The events should arrive in the same sequence as the expects.
+  InSequence in_sequence;
+
+  // Full argument version, passing lengths explicitly.
+  TraceEventETWProvider::Trace(kName,
+                        strlen(kName),
+                        TRACE_EVENT_PHASE_BEGIN,
+                        kId,
+                        kExtra,
+                        strlen(kExtra));
+
+  ExpectEvent(kTraceEventClass32,
+              kTraceEventTypeBegin,
+              kName, strlen(kName),
+              kId,
+              kExtra, strlen(kExtra));
+
+  // Const char* version.
+  TraceEventETWProvider::Trace(static_cast<const char*>(kName),
+                        TRACE_EVENT_PHASE_END,
+                        kId,
+                        static_cast<const char*>(kExtra));
+
+  ExpectEvent(kTraceEventClass32,
+              kTraceEventTypeEnd,
+              kName, strlen(kName),
+              kId,
+              kExtra, strlen(kExtra));
+
+  // std::string extra version.
+  TraceEventETWProvider::Trace(static_cast<const char*>(kName),
+                        TRACE_EVENT_PHASE_INSTANT,
+                        kId,
+                        std::string(kExtra));
+
+  ExpectEvent(kTraceEventClass32,
+              kTraceEventTypeInstant,
+              kName, strlen(kName),
+              kId,
+              kExtra, strlen(kExtra));
+
+
+  // Test for sanity on NULL inputs.
+  TraceEventETWProvider::Trace(NULL,
+                        0,
+                        TRACE_EVENT_PHASE_BEGIN,
+                        kId,
+                        NULL,
+                        0);
+
+  ExpectEvent(kTraceEventClass32,
+              kTraceEventTypeBegin,
+              kEmpty, 0,
+              kId,
+              kEmpty, 0);
+
+  TraceEventETWProvider::Trace(NULL,
+                        TraceEventETWProvider::kUseStrlen,
+                        TRACE_EVENT_PHASE_END,
+                        kId,
+                        NULL,
+                        TraceEventETWProvider::kUseStrlen);
+
+  ExpectEvent(kTraceEventClass32,
+              kTraceEventTypeEnd,
+              kEmpty, 0,
+              kId,
+              kEmpty, 0);
+
+  PlayLog();
+}
+
+TEST_F(TraceEventWinTest, Macros) {
+  ExpectPlayLog();
+
+  // The events should arrive in the same sequence as the expects.
+  InSequence in_sequence;
+
+  TRACE_EVENT_BEGIN_ETW(kName, kId, kExtra);
+  ExpectEvent(kTraceEventClass32,
+              kTraceEventTypeBegin,
+              kName, strlen(kName),
+              kId,
+              kExtra, strlen(kExtra));
+
+  TRACE_EVENT_END_ETW(kName, kId, kExtra);
+  ExpectEvent(kTraceEventClass32,
+              kTraceEventTypeEnd,
+              kName, strlen(kName),
+              kId,
+              kExtra, strlen(kExtra));
+
+  TRACE_EVENT_INSTANT_ETW(kName, kId, kExtra);
+  ExpectEvent(kTraceEventClass32,
+              kTraceEventTypeInstant,
+              kName, strlen(kName),
+              kId,
+              kExtra, strlen(kExtra));
+
+  PlayLog();
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/winheap_dump_provider_win.cc b/base/trace_event/winheap_dump_provider_win.cc
new file mode 100644
index 0000000..82bb016
--- /dev/null
+++ b/base/trace_event/winheap_dump_provider_win.cc
@@ -0,0 +1,117 @@
+// 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/winheap_dump_provider_win.h"
+
+#include <windows.h>
+
+#include "base/trace_event/process_memory_dump.h"
+#include "base/win/windows_version.h"
+
+namespace base {
+namespace trace_event {
+
+namespace {
+
+// Report a heap dump to a process memory dump. The |heap_info| structure
+// contains the information about this heap, and |dump_absolute_name| will be
+// used to represent it in the report.
+void ReportHeapDump(ProcessMemoryDump* pmd,
+                    const WinHeapInfo& heap_info,
+                    const std::string& dump_absolute_name) {
+  MemoryAllocatorDump* outer_dump =
+      pmd->CreateAllocatorDump(dump_absolute_name);
+  outer_dump->AddScalar(MemoryAllocatorDump::kNameSize,
+                        MemoryAllocatorDump::kUnitsBytes,
+                        heap_info.committed_size);
+
+  MemoryAllocatorDump* inner_dump =
+      pmd->CreateAllocatorDump(dump_absolute_name + "/allocated_objects");
+  inner_dump->AddScalar(MemoryAllocatorDump::kNameSize,
+                        MemoryAllocatorDump::kUnitsBytes,
+                        heap_info.allocated_size);
+  inner_dump->AddScalar(MemoryAllocatorDump::kNameObjectsCount,
+                        MemoryAllocatorDump::kUnitsObjects,
+                        heap_info.block_count);
+}
+
+}  // namespace
+
+WinHeapDumpProvider* WinHeapDumpProvider::GetInstance() {
+  return Singleton<WinHeapDumpProvider,
+                   LeakySingletonTraits<WinHeapDumpProvider>>::get();
+}
+
+bool WinHeapDumpProvider::OnMemoryDump(ProcessMemoryDump* pmd) {
+  // This method might be flaky for 2 reasons:
+  //   - GetProcessHeaps is racy by design. It returns a snapshot of the
+  //     available heaps, but there's no guarantee that that snapshot remains
+  //     valid. If a heap disappears between GetProcessHeaps() and HeapWalk()
+  //     then chaos should be assumed. This flakyness is acceptable for tracing.
+  //   - The MSDN page for HeapLock says: "If the HeapLock function is called on
+  //     a heap created with the HEAP_NO_SERIALIZATION flag, the results are
+  //     undefined.". This is a problem on Windows XP where some system DLLs are
+  //     known for creating heaps with this particular flag. For this reason
+  //     this function should be disabled on XP.
+  //
+  // See https://crbug.com/487291 for more details about this.
+  if (base::win::GetVersion() < base::win::VERSION_VISTA)
+    return false;
+
+  // Retrieves the number of heaps in the current process.
+  DWORD number_of_heaps = ::GetProcessHeaps(0, NULL);
+  WinHeapInfo all_heap_info = {0};
+
+  // Try to retrieve a handle to all the heaps owned by this process. Returns
+  // false if the number of heaps has changed.
+  //
+  // This is inherently racy as is, but it's not something that we observe a lot
+  // in Chrome, the heaps tend to be created at startup only.
+  scoped_ptr<HANDLE[]> all_heaps(new HANDLE[number_of_heaps]);
+  if (::GetProcessHeaps(number_of_heaps, all_heaps.get()) != number_of_heaps)
+    return false;
+
+  // Skip the pointer to the heap array to avoid accounting the memory used by
+  // this dump provider.
+  std::set<void*> block_to_skip;
+  block_to_skip.insert(all_heaps.get());
+
+  // Retrieves some metrics about each heap.
+  for (size_t i = 0; i < number_of_heaps; ++i) {
+    WinHeapInfo heap_info = {0};
+    heap_info.heap_id = all_heaps[i];
+    GetHeapInformation(&heap_info, block_to_skip);
+
+    all_heap_info.allocated_size += heap_info.allocated_size;
+    all_heap_info.committed_size += heap_info.committed_size;
+    all_heap_info.block_count += heap_info.block_count;
+  }
+  // Report the heap dump.
+  ReportHeapDump(pmd, all_heap_info, "winheap");
+  return true;
+}
+
+bool WinHeapDumpProvider::GetHeapInformation(
+    WinHeapInfo* heap_info,
+    const std::set<void*>& block_to_skip) {
+  CHECK(::HeapLock(heap_info->heap_id) == TRUE);
+  PROCESS_HEAP_ENTRY heap_entry;
+  heap_entry.lpData = nullptr;
+  // Walk over all the entries in this heap.
+  while (::HeapWalk(heap_info->heap_id, &heap_entry) != FALSE) {
+    if (block_to_skip.count(heap_entry.lpData) == 1)
+      continue;
+    if ((heap_entry.wFlags & PROCESS_HEAP_ENTRY_BUSY) != 0) {
+      heap_info->allocated_size += heap_entry.cbData;
+      heap_info->block_count++;
+    } else if ((heap_entry.wFlags & PROCESS_HEAP_REGION) != 0) {
+      heap_info->committed_size += heap_entry.Region.dwCommittedSize;
+    }
+  }
+  CHECK(::HeapUnlock(heap_info->heap_id) == TRUE);
+  return true;
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/trace_event/winheap_dump_provider_win.h b/base/trace_event/winheap_dump_provider_win.h
new file mode 100644
index 0000000..99239a0
--- /dev/null
+++ b/base/trace_event/winheap_dump_provider_win.h
@@ -0,0 +1,52 @@
+// 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_WINHEAP_DUMP_PROVIDER_WIN_H_
+#define BASE_TRACE_EVENT_WINHEAP_DUMP_PROVIDER_WIN_H_
+
+#include <set>
+
+#include "base/memory/singleton.h"
+#include "base/trace_event/memory_dump_provider.h"
+
+namespace base {
+namespace trace_event {
+
+// A structure containing some information about a given heap.
+struct WinHeapInfo {
+  HANDLE heap_id;
+  size_t committed_size;
+  size_t allocated_size;
+  size_t block_count;
+};
+
+// Dump provider which collects process-wide heap memory stats. This provider
+// iterates over all the heaps of the current process to gather some metrics
+// about them.
+class BASE_EXPORT WinHeapDumpProvider : public MemoryDumpProvider {
+ public:
+  static WinHeapDumpProvider* GetInstance();
+
+  // MemoryDumpProvider implementation.
+  bool OnMemoryDump(ProcessMemoryDump* pmd) override;
+
+ private:
+  friend struct DefaultSingletonTraits<WinHeapDumpProvider>;
+
+  // Retrieves the information about given heap. The |heap_info| should contain
+  // a valid handle to an existing heap. The blocks contained in the
+  // |block_to_skip| set will be ignored.
+  bool GetHeapInformation(WinHeapInfo* heap_info,
+                          const std::set<void*>& block_to_skip);
+
+  WinHeapDumpProvider() {}
+  ~WinHeapDumpProvider() override {}
+
+  DISALLOW_COPY_AND_ASSIGN(WinHeapDumpProvider);
+};
+
+}  // namespace trace_event
+}  // namespace base
+
+#endif  // BASE_TRACE_EVENT_WINHEAP_DUMP_PROVIDER_WIN_H_
diff --git a/base/trace_event/winheap_dump_provider_win_unittest.cc b/base/trace_event/winheap_dump_provider_win_unittest.cc
new file mode 100644
index 0000000..865a1d2
--- /dev/null
+++ b/base/trace_event/winheap_dump_provider_win_unittest.cc
@@ -0,0 +1,27 @@
+// 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/winheap_dump_provider_win.h"
+
+#include <windows.h>
+
+#include "base/trace_event/memory_dump_session_state.h"
+#include "base/trace_event/process_memory_dump.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+TEST(WinHeapDumpProviderTest, OnMemoryDump) {
+  ProcessMemoryDump pmd(make_scoped_refptr(new MemoryDumpSessionState()));
+
+  WinHeapDumpProvider* winheap_dump_provider =
+      WinHeapDumpProvider::GetInstance();
+  ASSERT_NE(static_cast<WinHeapDumpProvider*>(nullptr), winheap_dump_provider);
+
+  ASSERT_NO_FATAL_FAILURE(winheap_dump_provider->OnMemoryDump(&pmd));
+}
+
+}  // namespace trace_event
+}  // namespace base
diff --git a/base/tracked_objects.cc b/base/tracked_objects.cc
new file mode 100644
index 0000000..9db05c0
--- /dev/null
+++ b/base/tracked_objects.cc
@@ -0,0 +1,1007 @@
+// Copyright (c) 2012 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/tracked_objects.h"
+
+#include <limits.h>
+#include <stdlib.h>
+
+#include "base/atomicops.h"
+#include "base/base_switches.h"
+#include "base/command_line.h"
+#include "base/compiler_specific.h"
+#include "base/debug/leak_annotations.h"
+#include "base/logging.h"
+#include "base/process/process_handle.h"
+#include "base/profiler/alternate_timer.h"
+#include "base/strings/stringprintf.h"
+#include "base/third_party/valgrind/memcheck.h"
+#include "base/tracking_info.h"
+
+using base::TimeDelta;
+
+namespace base {
+class TimeDelta;
+}
+
+namespace tracked_objects {
+
+namespace {
+// When ThreadData is first initialized, should we start in an ACTIVE state to
+// record all of the startup-time tasks, or should we start up DEACTIVATED, so
+// that we only record after parsing the command line flag --enable-tracking.
+// Note that the flag may force either state, so this really controls only the
+// period of time up until that flag is parsed.  If there is no flag seen, then
+// this state may prevail for much or all of the process lifetime.
+const ThreadData::Status kInitialStartupState = ThreadData::PROFILING_ACTIVE;
+
+// Control whether an alternate time source (Now() function) is supported by
+// the ThreadData class.  This compile time flag should be set to true if we
+// want other modules (such as a memory allocator, or a thread-specific CPU time
+// clock) to be able to provide a thread-specific Now() function.  Without this
+// compile-time flag, the code will only support the wall-clock time.  This flag
+// can be flipped to efficiently disable this path (if there is a performance
+// problem with its presence).
+static const bool kAllowAlternateTimeSourceHandling = true;
+
+// Possible states of the profiler timing enabledness.
+enum {
+  UNDEFINED_TIMING,
+  ENABLED_TIMING,
+  DISABLED_TIMING,
+};
+
+// State of the profiler timing enabledness.
+base::subtle::Atomic32 g_profiler_timing_enabled = UNDEFINED_TIMING;
+
+// Returns whether profiler timing is enabled.  The default is true, but this
+// may be overridden by a command-line flag.  Some platforms may
+// programmatically set this command-line flag to the "off" value if it's not
+// specified.
+// This in turn can be overridden by explicitly calling
+// ThreadData::EnableProfilerTiming, say, based on a field trial.
+inline bool IsProfilerTimingEnabled() {
+  // Reading |g_profiler_timing_enabled| is done without barrier because
+  // multiple initialization is not an issue while the barrier can be relatively
+  // costly given that this method is sometimes called in a tight loop.
+  base::subtle::Atomic32 current_timing_enabled =
+      base::subtle::NoBarrier_Load(&g_profiler_timing_enabled);
+  if (current_timing_enabled == UNDEFINED_TIMING) {
+    if (!base::CommandLine::InitializedForCurrentProcess())
+      return true;
+    current_timing_enabled =
+        (base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+             switches::kProfilerTiming) ==
+         switches::kProfilerTimingDisabledValue)
+            ? DISABLED_TIMING
+            : ENABLED_TIMING;
+    base::subtle::NoBarrier_Store(&g_profiler_timing_enabled,
+                                  current_timing_enabled);
+  }
+  return current_timing_enabled == ENABLED_TIMING;
+}
+
+}  // namespace
+
+//------------------------------------------------------------------------------
+// DeathData tallies durations when a death takes place.
+
+DeathData::DeathData()
+    : count_(0),
+      sample_probability_count_(0),
+      run_duration_sum_(0),
+      queue_duration_sum_(0),
+      run_duration_max_(0),
+      queue_duration_max_(0),
+      run_duration_sample_(0),
+      queue_duration_sample_(0),
+      last_phase_snapshot_(nullptr) {
+}
+
+DeathData::DeathData(const DeathData& other)
+    : count_(other.count_),
+      sample_probability_count_(other.sample_probability_count_),
+      run_duration_sum_(other.run_duration_sum_),
+      queue_duration_sum_(other.queue_duration_sum_),
+      run_duration_max_(other.run_duration_max_),
+      queue_duration_max_(other.queue_duration_max_),
+      run_duration_sample_(other.run_duration_sample_),
+      queue_duration_sample_(other.queue_duration_sample_),
+      last_phase_snapshot_(nullptr) {
+  // This constructor will be used by std::map when adding new DeathData values
+  // to the map.  At that point, last_phase_snapshot_ is still NULL, so we don't
+  // need to worry about ownership transfer.
+  DCHECK(other.last_phase_snapshot_ == nullptr);
+}
+
+DeathData::~DeathData() {
+  while (last_phase_snapshot_) {
+    const DeathDataPhaseSnapshot* snapshot = last_phase_snapshot_;
+    last_phase_snapshot_ = snapshot->prev;
+    delete snapshot;
+  }
+}
+
+// TODO(jar): I need to see if this macro to optimize branching is worth using.
+//
+// This macro has no branching, so it is surely fast, and is equivalent to:
+//             if (assign_it)
+//               target = source;
+// We use a macro rather than a template to force this to inline.
+// Related code for calculating max is discussed on the web.
+#define CONDITIONAL_ASSIGN(assign_it, target, source) \
+    ((target) ^= ((target) ^ (source)) & -static_cast<int32>(assign_it))
+
+void DeathData::RecordDeath(const int32 queue_duration,
+                            const int32 run_duration,
+                            const uint32 random_number) {
+  // We'll just clamp at INT_MAX, but we should note this in the UI as such.
+  if (count_ < INT_MAX)
+    ++count_;
+
+  int sample_probability_count = sample_probability_count_;
+  if (sample_probability_count < INT_MAX)
+    ++sample_probability_count;
+  sample_probability_count_ = sample_probability_count;
+
+  queue_duration_sum_ += queue_duration;
+  run_duration_sum_ += run_duration;
+
+  if (queue_duration_max_ < queue_duration)
+    queue_duration_max_ = queue_duration;
+  if (run_duration_max_ < run_duration)
+    run_duration_max_ = run_duration;
+
+  // Take a uniformly distributed sample over all durations ever supplied during
+  // the current profiling phase.
+  // The probability that we (instead) use this new sample is
+  // 1/sample_probability_count_. This results in a completely uniform selection
+  // of the sample (at least when we don't clamp sample_probability_count_...
+  // but that should be inconsequentially likely).  We ignore the fact that we
+  // correlated our selection of a sample to the run and queue times (i.e., we
+  // used them to generate random_number).
+  CHECK_GT(sample_probability_count, 0);
+  if (0 == (random_number % sample_probability_count)) {
+    queue_duration_sample_ = queue_duration;
+    run_duration_sample_ = run_duration;
+  }
+}
+
+void DeathData::OnProfilingPhaseCompleted(int profiling_phase) {
+  // Snapshotting and storing current state.
+  last_phase_snapshot_ = new DeathDataPhaseSnapshot(
+      profiling_phase, count_, run_duration_sum_, run_duration_max_,
+      run_duration_sample_, queue_duration_sum_, queue_duration_max_,
+      queue_duration_sample_, last_phase_snapshot_);
+
+  // Not touching fields for which a delta can be computed by comparing with a
+  // snapshot from the previous phase. Resetting other fields.  Sample values
+  // will be reset upon next death recording because sample_probability_count_
+  // is set to 0.
+  // We avoid resetting to 0 in favor of deltas whenever possible.  The reason
+  // is that for incrementable fields, resetting to 0 from the snapshot thread
+  // potentially in parallel with incrementing in the death thread may result in
+  // significant data corruption that has a potential to grow with time.  Not
+  // resetting incrementable fields and using deltas will cause any
+  // off-by-little corruptions to be likely fixed at the next snapshot.
+  // The max values are not incrementable, and cannot be deduced using deltas
+  // for a given phase. Hence, we have to reset them to 0.  But the potential
+  // damage is limited to getting the previous phase's max to apply for the next
+  // phase, and the error doesn't have a potential to keep growing with new
+  // resets.
+  // sample_probability_count_ is incrementable, but must be reset to 0 at the
+  // phase end, so that we start a new uniformly randomized sample selection
+  // after the reset.  Corruptions due to race conditions are possible, but the
+  // damage is limited to selecting a wrong sample, which is not something that
+  // can cause accumulating or cascading effects.
+  // If there were no corruptions caused by race conditions, we never send a
+  // sample for the previous phase in the next phase's snapshot because
+  // ThreadData::SnapshotExecutedTasks doesn't send deltas with 0 count.
+  sample_probability_count_ = 0;
+  run_duration_max_ = 0;
+  queue_duration_max_ = 0;
+}
+
+//------------------------------------------------------------------------------
+DeathDataSnapshot::DeathDataSnapshot()
+    : count(-1),
+      run_duration_sum(-1),
+      run_duration_max(-1),
+      run_duration_sample(-1),
+      queue_duration_sum(-1),
+      queue_duration_max(-1),
+      queue_duration_sample(-1) {
+}
+
+DeathDataSnapshot::DeathDataSnapshot(int count,
+                                     int32 run_duration_sum,
+                                     int32 run_duration_max,
+                                     int32 run_duration_sample,
+                                     int32 queue_duration_sum,
+                                     int32 queue_duration_max,
+                                     int32 queue_duration_sample)
+    : count(count),
+      run_duration_sum(run_duration_sum),
+      run_duration_max(run_duration_max),
+      run_duration_sample(run_duration_sample),
+      queue_duration_sum(queue_duration_sum),
+      queue_duration_max(queue_duration_max),
+      queue_duration_sample(queue_duration_sample) {
+}
+
+DeathDataSnapshot::~DeathDataSnapshot() {
+}
+
+DeathDataSnapshot DeathDataSnapshot::Delta(
+    const DeathDataSnapshot& older) const {
+  return DeathDataSnapshot(count - older.count,
+                           run_duration_sum - older.run_duration_sum,
+                           run_duration_max, run_duration_sample,
+                           queue_duration_sum - older.queue_duration_sum,
+                           queue_duration_max, queue_duration_sample);
+}
+
+//------------------------------------------------------------------------------
+BirthOnThread::BirthOnThread(const Location& location,
+                             const ThreadData& current)
+    : location_(location),
+      birth_thread_(&current) {
+}
+
+//------------------------------------------------------------------------------
+BirthOnThreadSnapshot::BirthOnThreadSnapshot() {
+}
+
+BirthOnThreadSnapshot::BirthOnThreadSnapshot(const BirthOnThread& birth)
+    : location(birth.location()),
+      thread_name(birth.birth_thread()->thread_name()) {
+}
+
+BirthOnThreadSnapshot::~BirthOnThreadSnapshot() {
+}
+
+//------------------------------------------------------------------------------
+Births::Births(const Location& location, const ThreadData& current)
+    : BirthOnThread(location, current),
+      birth_count_(1) { }
+
+int Births::birth_count() const { return birth_count_; }
+
+void Births::RecordBirth() { ++birth_count_; }
+
+//------------------------------------------------------------------------------
+// ThreadData maintains the central data for all births and deaths on a single
+// thread.
+
+// TODO(jar): We should pull all these static vars together, into a struct, and
+// optimize layout so that we benefit from locality of reference during accesses
+// to them.
+
+// static
+NowFunction* ThreadData::now_function_ = NULL;
+
+// static
+bool ThreadData::now_function_is_time_ = false;
+
+// A TLS slot which points to the ThreadData instance for the current thread.
+// We do a fake initialization here (zeroing out data), and then the real
+// in-place construction happens when we call tls_index_.Initialize().
+// static
+base::ThreadLocalStorage::StaticSlot ThreadData::tls_index_ = TLS_INITIALIZER;
+
+// static
+int ThreadData::worker_thread_data_creation_count_ = 0;
+
+// static
+int ThreadData::cleanup_count_ = 0;
+
+// static
+int ThreadData::incarnation_counter_ = 0;
+
+// static
+ThreadData* ThreadData::all_thread_data_list_head_ = NULL;
+
+// static
+ThreadData* ThreadData::first_retired_worker_ = NULL;
+
+// static
+base::LazyInstance<base::Lock>::Leaky
+    ThreadData::list_lock_ = LAZY_INSTANCE_INITIALIZER;
+
+// static
+ThreadData::Status ThreadData::status_ = ThreadData::UNINITIALIZED;
+
+ThreadData::ThreadData(const std::string& suggested_name)
+    : next_(NULL),
+      next_retired_worker_(NULL),
+      worker_thread_number_(0),
+      incarnation_count_for_pool_(-1),
+      current_stopwatch_(NULL) {
+  DCHECK_GE(suggested_name.size(), 0u);
+  thread_name_ = suggested_name;
+  PushToHeadOfList();  // Which sets real incarnation_count_for_pool_.
+}
+
+ThreadData::ThreadData(int thread_number)
+    : next_(NULL),
+      next_retired_worker_(NULL),
+      worker_thread_number_(thread_number),
+      incarnation_count_for_pool_(-1),
+      current_stopwatch_(NULL) {
+  CHECK_GT(thread_number, 0);
+  base::StringAppendF(&thread_name_, "WorkerThread-%d", thread_number);
+  PushToHeadOfList();  // Which sets real incarnation_count_for_pool_.
+}
+
+ThreadData::~ThreadData() {
+}
+
+void ThreadData::PushToHeadOfList() {
+  // Toss in a hint of randomness (atop the uniniitalized value).
+  (void)VALGRIND_MAKE_MEM_DEFINED_IF_ADDRESSABLE(&random_number_,
+                                                 sizeof(random_number_));
+  MSAN_UNPOISON(&random_number_, sizeof(random_number_));
+  random_number_ += static_cast<uint32>(this - static_cast<ThreadData*>(0));
+  random_number_ ^= (Now() - TrackedTime()).InMilliseconds();
+
+  DCHECK(!next_);
+  base::AutoLock lock(*list_lock_.Pointer());
+  incarnation_count_for_pool_ = incarnation_counter_;
+  next_ = all_thread_data_list_head_;
+  all_thread_data_list_head_ = this;
+}
+
+// static
+ThreadData* ThreadData::first() {
+  base::AutoLock lock(*list_lock_.Pointer());
+  return all_thread_data_list_head_;
+}
+
+ThreadData* ThreadData::next() const { return next_; }
+
+// static
+void ThreadData::InitializeThreadContext(const std::string& suggested_name) {
+  Initialize();
+  ThreadData* current_thread_data =
+      reinterpret_cast<ThreadData*>(tls_index_.Get());
+  if (current_thread_data)
+    return;  // Browser tests instigate this.
+  current_thread_data = new ThreadData(suggested_name);
+  tls_index_.Set(current_thread_data);
+}
+
+// static
+ThreadData* ThreadData::Get() {
+  if (!tls_index_.initialized())
+    return NULL;  // For unittests only.
+  ThreadData* registered = reinterpret_cast<ThreadData*>(tls_index_.Get());
+  if (registered)
+    return registered;
+
+  // We must be a worker thread, since we didn't pre-register.
+  ThreadData* worker_thread_data = NULL;
+  int worker_thread_number = 0;
+  {
+    base::AutoLock lock(*list_lock_.Pointer());
+    if (first_retired_worker_) {
+      worker_thread_data = first_retired_worker_;
+      first_retired_worker_ = first_retired_worker_->next_retired_worker_;
+      worker_thread_data->next_retired_worker_ = NULL;
+    } else {
+      worker_thread_number = ++worker_thread_data_creation_count_;
+    }
+  }
+
+  // If we can't find a previously used instance, then we have to create one.
+  if (!worker_thread_data) {
+    DCHECK_GT(worker_thread_number, 0);
+    worker_thread_data = new ThreadData(worker_thread_number);
+  }
+  DCHECK_GT(worker_thread_data->worker_thread_number_, 0);
+
+  tls_index_.Set(worker_thread_data);
+  return worker_thread_data;
+}
+
+// static
+void ThreadData::OnThreadTermination(void* thread_data) {
+  DCHECK(thread_data);  // TLS should *never* call us with a NULL.
+  // We must NOT do any allocations during this callback.  There is a chance
+  // that the allocator is no longer active on this thread.
+  reinterpret_cast<ThreadData*>(thread_data)->OnThreadTerminationCleanup();
+}
+
+void ThreadData::OnThreadTerminationCleanup() {
+  // The list_lock_ was created when we registered the callback, so it won't be
+  // allocated here despite the lazy reference.
+  base::AutoLock lock(*list_lock_.Pointer());
+  if (incarnation_counter_ != incarnation_count_for_pool_)
+    return;  // ThreadData was constructed in an earlier unit test.
+  ++cleanup_count_;
+  // Only worker threads need to be retired and reused.
+  if (!worker_thread_number_) {
+    return;
+  }
+  // We must NOT do any allocations during this callback.
+  // Using the simple linked lists avoids all allocations.
+  DCHECK_EQ(this->next_retired_worker_, reinterpret_cast<ThreadData*>(NULL));
+  this->next_retired_worker_ = first_retired_worker_;
+  first_retired_worker_ = this;
+}
+
+// static
+void ThreadData::Snapshot(int current_profiling_phase,
+                          ProcessDataSnapshot* process_data_snapshot) {
+  // Get an unchanging copy of a ThreadData list.
+  ThreadData* my_list = ThreadData::first();
+
+  // Gather data serially.
+  // This hackish approach *can* get some slightly corrupt tallies, as we are
+  // grabbing values without the protection of a lock, but it has the advantage
+  // of working even with threads that don't have message loops.  If a user
+  // sees any strangeness, they can always just run their stats gathering a
+  // second time.
+  BirthCountMap birth_counts;
+  for (ThreadData* thread_data = my_list; thread_data;
+       thread_data = thread_data->next()) {
+    thread_data->SnapshotExecutedTasks(current_profiling_phase,
+                                       &process_data_snapshot->phased_snapshots,
+                                       &birth_counts);
+  }
+
+  // Add births that are still active -- i.e. objects that have tallied a birth,
+  // but have not yet tallied a matching death, and hence must be either
+  // running, queued up, or being held in limbo for future posting.
+  auto* current_phase_tasks =
+      &process_data_snapshot->phased_snapshots[current_profiling_phase].tasks;
+  for (const auto& birth_count : birth_counts) {
+    if (birth_count.second > 0) {
+      current_phase_tasks->push_back(
+          TaskSnapshot(BirthOnThreadSnapshot(*birth_count.first),
+                       DeathDataSnapshot(birth_count.second, 0, 0, 0, 0, 0, 0),
+                       "Still_Alive"));
+    }
+  }
+}
+
+// static
+void ThreadData::OnProfilingPhaseCompleted(int profiling_phase) {
+  // Get an unchanging copy of a ThreadData list.
+  ThreadData* my_list = ThreadData::first();
+
+  // Add snapshots for all instances of death data in all threads serially.
+  // This hackish approach *can* get some slightly corrupt tallies, as we are
+  // grabbing values without the protection of a lock, but it has the advantage
+  // of working even with threads that don't have message loops.  Any corruption
+  // shouldn't cause "cascading damage" to anything else (in later phases).
+  for (ThreadData* thread_data = my_list; thread_data;
+       thread_data = thread_data->next()) {
+    thread_data->OnProfilingPhaseCompletedOnThread(profiling_phase);
+  }
+}
+
+Births* ThreadData::TallyABirth(const Location& location) {
+  BirthMap::iterator it = birth_map_.find(location);
+  Births* child;
+  if (it != birth_map_.end()) {
+    child =  it->second;
+    child->RecordBirth();
+  } else {
+    child = new Births(location, *this);  // Leak this.
+    // Lock since the map may get relocated now, and other threads sometimes
+    // snapshot it (but they lock before copying it).
+    base::AutoLock lock(map_lock_);
+    birth_map_[location] = child;
+  }
+
+  return child;
+}
+
+void ThreadData::TallyADeath(const Births& births,
+                             int32 queue_duration,
+                             const TaskStopwatch& stopwatch) {
+  int32 run_duration = stopwatch.RunDurationMs();
+
+  // Stir in some randomness, plus add constant in case durations are zero.
+  const uint32 kSomePrimeNumber = 2147483647;
+  random_number_ += queue_duration + run_duration + kSomePrimeNumber;
+  // An address is going to have some randomness to it as well ;-).
+  random_number_ ^= static_cast<uint32>(&births - reinterpret_cast<Births*>(0));
+
+  // We don't have queue durations without OS timer.  OS timer is automatically
+  // used for task-post-timing, so the use of an alternate timer implies all
+  // queue times are invalid, unless it was explicitly said that we can trust
+  // the alternate timer.
+  if (kAllowAlternateTimeSourceHandling &&
+      now_function_ &&
+      !now_function_is_time_) {
+    queue_duration = 0;
+  }
+
+  DeathMap::iterator it = death_map_.find(&births);
+  DeathData* death_data;
+  if (it != death_map_.end()) {
+    death_data = &it->second;
+  } else {
+    base::AutoLock lock(map_lock_);  // Lock as the map may get relocated now.
+    death_data = &death_map_[&births];
+  }  // Release lock ASAP.
+  death_data->RecordDeath(queue_duration, run_duration, random_number_);
+}
+
+// static
+Births* ThreadData::TallyABirthIfActive(const Location& location) {
+  if (!TrackingStatus())
+    return NULL;
+  ThreadData* current_thread_data = Get();
+  if (!current_thread_data)
+    return NULL;
+  return current_thread_data->TallyABirth(location);
+}
+
+// static
+void ThreadData::TallyRunOnNamedThreadIfTracking(
+    const base::TrackingInfo& completed_task,
+    const TaskStopwatch& stopwatch) {
+  // Even if we have been DEACTIVATED, we will process any pending births so
+  // that our data structures (which counted the outstanding births) remain
+  // consistent.
+  const Births* births = completed_task.birth_tally;
+  if (!births)
+    return;
+  ThreadData* current_thread_data = stopwatch.GetThreadData();
+  if (!current_thread_data)
+    return;
+
+  // Watch out for a race where status_ is changing, and hence one or both
+  // of start_of_run or end_of_run is zero.  In that case, we didn't bother to
+  // get a time value since we "weren't tracking" and we were trying to be
+  // efficient by not calling for a genuine time value.  For simplicity, we'll
+  // use a default zero duration when we can't calculate a true value.
+  TrackedTime start_of_run = stopwatch.StartTime();
+  int32 queue_duration = 0;
+  if (!start_of_run.is_null()) {
+    queue_duration = (start_of_run - completed_task.EffectiveTimePosted())
+        .InMilliseconds();
+  }
+  current_thread_data->TallyADeath(*births, queue_duration, stopwatch);
+}
+
+// static
+void ThreadData::TallyRunOnWorkerThreadIfTracking(
+    const Births* births,
+    const TrackedTime& time_posted,
+    const TaskStopwatch& stopwatch) {
+  // Even if we have been DEACTIVATED, we will process any pending births so
+  // that our data structures (which counted the outstanding births) remain
+  // consistent.
+  if (!births)
+    return;
+
+  // TODO(jar): Support the option to coalesce all worker-thread activity under
+  // one ThreadData instance that uses locks to protect *all* access.  This will
+  // reduce memory (making it provably bounded), but run incrementally slower
+  // (since we'll use locks on TallyABirth and TallyADeath).  The good news is
+  // that the locks on TallyADeath will be *after* the worker thread has run,
+  // and hence nothing will be waiting for the completion (...  besides some
+  // other thread that might like to run).  Also, the worker threads tasks are
+  // generally longer, and hence the cost of the lock may perchance be amortized
+  // over the long task's lifetime.
+  ThreadData* current_thread_data = stopwatch.GetThreadData();
+  if (!current_thread_data)
+    return;
+
+  TrackedTime start_of_run = stopwatch.StartTime();
+  int32 queue_duration = 0;
+  if (!start_of_run.is_null()) {
+    queue_duration = (start_of_run - time_posted).InMilliseconds();
+  }
+  current_thread_data->TallyADeath(*births, queue_duration, stopwatch);
+}
+
+// static
+void ThreadData::TallyRunInAScopedRegionIfTracking(
+    const Births* births,
+    const TaskStopwatch& stopwatch) {
+  // Even if we have been DEACTIVATED, we will process any pending births so
+  // that our data structures (which counted the outstanding births) remain
+  // consistent.
+  if (!births)
+    return;
+
+  ThreadData* current_thread_data = stopwatch.GetThreadData();
+  if (!current_thread_data)
+    return;
+
+  int32 queue_duration = 0;
+  current_thread_data->TallyADeath(*births, queue_duration, stopwatch);
+}
+
+void ThreadData::SnapshotExecutedTasks(
+    int current_profiling_phase,
+    PhasedProcessDataSnapshotMap* phased_snapshots,
+    BirthCountMap* birth_counts) {
+  // Get copy of data, so that the data will not change during the iterations
+  // and processing.
+  BirthMap birth_map;
+  DeathsSnapshot deaths;
+  SnapshotMaps(current_profiling_phase, &birth_map, &deaths);
+
+  for (const auto& birth : birth_map) {
+    (*birth_counts)[birth.second] += birth.second->birth_count();
+  }
+
+  for (const auto& death : deaths) {
+    (*birth_counts)[death.first] -= death.first->birth_count();
+
+    // For the current death data, walk through all its snapshots, starting from
+    // the current one, then from the previous profiling phase etc., and for
+    // each snapshot calculate the delta between the snapshot and the previous
+    // phase, if any.  Store the deltas in the result.
+    for (const DeathDataPhaseSnapshot* phase = &death.second; phase;
+         phase = phase->prev) {
+      const DeathDataSnapshot& death_data =
+          phase->prev ? phase->death_data.Delta(phase->prev->death_data)
+                      : phase->death_data;
+
+      if (death_data.count > 0) {
+        (*phased_snapshots)[phase->profiling_phase].tasks.push_back(
+            TaskSnapshot(BirthOnThreadSnapshot(*death.first), death_data,
+                         thread_name()));
+      }
+    }
+  }
+}
+
+// This may be called from another thread.
+void ThreadData::SnapshotMaps(int profiling_phase,
+                              BirthMap* birth_map,
+                              DeathsSnapshot* deaths) {
+  base::AutoLock lock(map_lock_);
+
+  for (const auto& birth : birth_map_)
+    (*birth_map)[birth.first] = birth.second;
+
+  for (const auto& death : death_map_) {
+    deaths->push_back(std::make_pair(
+        death.first,
+        DeathDataPhaseSnapshot(profiling_phase, death.second.count(),
+                               death.second.run_duration_sum(),
+                               death.second.run_duration_max(),
+                               death.second.run_duration_sample(),
+                               death.second.queue_duration_sum(),
+                               death.second.queue_duration_max(),
+                               death.second.queue_duration_sample(),
+                               death.second.last_phase_snapshot())));
+  }
+}
+
+void ThreadData::OnProfilingPhaseCompletedOnThread(int profiling_phase) {
+  base::AutoLock lock(map_lock_);
+
+  for (auto& death : death_map_) {
+    death.second.OnProfilingPhaseCompleted(profiling_phase);
+  }
+}
+
+static void OptionallyInitializeAlternateTimer() {
+  NowFunction* alternate_time_source = GetAlternateTimeSource();
+  if (alternate_time_source)
+    ThreadData::SetAlternateTimeSource(alternate_time_source);
+}
+
+void ThreadData::Initialize() {
+  if (status_ >= DEACTIVATED)
+    return;  // Someone else did the initialization.
+  // Due to racy lazy initialization in tests, we'll need to recheck status_
+  // after we acquire the lock.
+
+  // Ensure that we don't double initialize tls.  We are called when single
+  // threaded in the product, but some tests may be racy and lazy about our
+  // initialization.
+  base::AutoLock lock(*list_lock_.Pointer());
+  if (status_ >= DEACTIVATED)
+    return;  // Someone raced in here and beat us.
+
+  // Put an alternate timer in place if the environment calls for it, such as
+  // for tracking TCMalloc allocations.  This insertion is idempotent, so we
+  // don't mind if there is a race, and we'd prefer not to be in a lock while
+  // doing this work.
+  if (kAllowAlternateTimeSourceHandling)
+    OptionallyInitializeAlternateTimer();
+
+  // Perform the "real" TLS initialization now, and leave it intact through
+  // process termination.
+  if (!tls_index_.initialized()) {  // Testing may have initialized this.
+    DCHECK_EQ(status_, UNINITIALIZED);
+    tls_index_.Initialize(&ThreadData::OnThreadTermination);
+    DCHECK(tls_index_.initialized());
+  } else {
+    // TLS was initialzed for us earlier.
+    DCHECK_EQ(status_, DORMANT_DURING_TESTS);
+  }
+
+  // Incarnation counter is only significant to testing, as it otherwise will
+  // never again change in this process.
+  ++incarnation_counter_;
+
+  // The lock is not critical for setting status_, but it doesn't hurt.  It also
+  // ensures that if we have a racy initialization, that we'll bail as soon as
+  // we get the lock earlier in this method.
+  status_ = kInitialStartupState;
+  DCHECK(status_ != UNINITIALIZED);
+}
+
+// static
+void ThreadData::InitializeAndSetTrackingStatus(Status status) {
+  DCHECK_GE(status, DEACTIVATED);
+  DCHECK_LE(status, PROFILING_ACTIVE);
+
+  Initialize();  // No-op if already initialized.
+
+  if (status > DEACTIVATED)
+    status = PROFILING_ACTIVE;
+  status_ = status;
+}
+
+// static
+ThreadData::Status ThreadData::status() {
+  return status_;
+}
+
+// static
+bool ThreadData::TrackingStatus() {
+  return status_ > DEACTIVATED;
+}
+
+// static
+void ThreadData::SetAlternateTimeSource(NowFunction* now_function) {
+  DCHECK(now_function);
+  if (kAllowAlternateTimeSourceHandling)
+    now_function_ = now_function;
+}
+
+// static
+void ThreadData::EnableProfilerTiming() {
+  base::subtle::NoBarrier_Store(&g_profiler_timing_enabled, ENABLED_TIMING);
+}
+
+// static
+TrackedTime ThreadData::Now() {
+  if (kAllowAlternateTimeSourceHandling && now_function_)
+    return TrackedTime::FromMilliseconds((*now_function_)());
+  if (IsProfilerTimingEnabled() && TrackingStatus())
+    return TrackedTime::Now();
+  return TrackedTime();  // Super fast when disabled, or not compiled.
+}
+
+// static
+void ThreadData::EnsureCleanupWasCalled(int major_threads_shutdown_count) {
+  base::AutoLock lock(*list_lock_.Pointer());
+  if (worker_thread_data_creation_count_ == 0)
+    return;  // We haven't really run much, and couldn't have leaked.
+
+  // TODO(jar): until this is working on XP, don't run the real test.
+#if 0
+  // Verify that we've at least shutdown/cleanup the major namesd threads.  The
+  // caller should tell us how many thread shutdowns should have taken place by
+  // now.
+  CHECK_GT(cleanup_count_, major_threads_shutdown_count);
+#endif
+}
+
+// static
+void ThreadData::ShutdownSingleThreadedCleanup(bool leak) {
+  // This is only called from test code, where we need to cleanup so that
+  // additional tests can be run.
+  // We must be single threaded... but be careful anyway.
+  InitializeAndSetTrackingStatus(DEACTIVATED);
+
+  ThreadData* thread_data_list;
+  {
+    base::AutoLock lock(*list_lock_.Pointer());
+    thread_data_list = all_thread_data_list_head_;
+    all_thread_data_list_head_ = NULL;
+    ++incarnation_counter_;
+    // To be clean, break apart the retired worker list (though we leak them).
+    while (first_retired_worker_) {
+      ThreadData* worker = first_retired_worker_;
+      CHECK_GT(worker->worker_thread_number_, 0);
+      first_retired_worker_ = worker->next_retired_worker_;
+      worker->next_retired_worker_ = NULL;
+    }
+  }
+
+  // Put most global static back in pristine shape.
+  worker_thread_data_creation_count_ = 0;
+  cleanup_count_ = 0;
+  tls_index_.Set(NULL);
+  status_ = DORMANT_DURING_TESTS;  // Almost UNINITIALIZED.
+
+  // To avoid any chance of racing in unit tests, which is the only place we
+  // call this function, we may sometimes leak all the data structures we
+  // recovered, as they may still be in use on threads from prior tests!
+  if (leak) {
+    ThreadData* thread_data = thread_data_list;
+    while (thread_data) {
+      ANNOTATE_LEAKING_OBJECT_PTR(thread_data);
+      thread_data = thread_data->next();
+    }
+    return;
+  }
+
+  // When we want to cleanup (on a single thread), here is what we do.
+
+  // Do actual recursive delete in all ThreadData instances.
+  while (thread_data_list) {
+    ThreadData* next_thread_data = thread_data_list;
+    thread_data_list = thread_data_list->next();
+
+    for (BirthMap::iterator it = next_thread_data->birth_map_.begin();
+         next_thread_data->birth_map_.end() != it; ++it)
+      delete it->second;  // Delete the Birth Records.
+    delete next_thread_data;  // Includes all Death Records.
+  }
+}
+
+//------------------------------------------------------------------------------
+TaskStopwatch::TaskStopwatch()
+    : wallclock_duration_ms_(0),
+      current_thread_data_(NULL),
+      excluded_duration_ms_(0),
+      parent_(NULL) {
+#if DCHECK_IS_ON()
+  state_ = CREATED;
+  child_ = NULL;
+#endif
+}
+
+TaskStopwatch::~TaskStopwatch() {
+#if DCHECK_IS_ON()
+  DCHECK(state_ != RUNNING);
+  DCHECK(child_ == NULL);
+#endif
+}
+
+void TaskStopwatch::Start() {
+#if DCHECK_IS_ON()
+  DCHECK(state_ == CREATED);
+  state_ = RUNNING;
+#endif
+
+  start_time_ = ThreadData::Now();
+
+  current_thread_data_ = ThreadData::Get();
+  if (!current_thread_data_)
+    return;
+
+  parent_ = current_thread_data_->current_stopwatch_;
+#if DCHECK_IS_ON()
+  if (parent_) {
+    DCHECK(parent_->state_ == RUNNING);
+    DCHECK(parent_->child_ == NULL);
+    parent_->child_ = this;
+  }
+#endif
+  current_thread_data_->current_stopwatch_ = this;
+}
+
+void TaskStopwatch::Stop() {
+  const TrackedTime end_time = ThreadData::Now();
+#if DCHECK_IS_ON()
+  DCHECK(state_ == RUNNING);
+  state_ = STOPPED;
+  DCHECK(child_ == NULL);
+#endif
+
+  if (!start_time_.is_null() && !end_time.is_null()) {
+    wallclock_duration_ms_ = (end_time - start_time_).InMilliseconds();
+  }
+
+  if (!current_thread_data_)
+    return;
+
+  DCHECK(current_thread_data_->current_stopwatch_ == this);
+  current_thread_data_->current_stopwatch_ = parent_;
+  if (!parent_)
+    return;
+
+#if DCHECK_IS_ON()
+  DCHECK(parent_->state_ == RUNNING);
+  DCHECK(parent_->child_ == this);
+  parent_->child_ = NULL;
+#endif
+  parent_->excluded_duration_ms_ += wallclock_duration_ms_;
+  parent_ = NULL;
+}
+
+TrackedTime TaskStopwatch::StartTime() const {
+#if DCHECK_IS_ON()
+  DCHECK(state_ != CREATED);
+#endif
+
+  return start_time_;
+}
+
+int32 TaskStopwatch::RunDurationMs() const {
+#if DCHECK_IS_ON()
+  DCHECK(state_ == STOPPED);
+#endif
+
+  return wallclock_duration_ms_ - excluded_duration_ms_;
+}
+
+ThreadData* TaskStopwatch::GetThreadData() const {
+#if DCHECK_IS_ON()
+  DCHECK(state_ != CREATED);
+#endif
+
+  return current_thread_data_;
+}
+
+//------------------------------------------------------------------------------
+// DeathDataPhaseSnapshot
+
+DeathDataPhaseSnapshot::DeathDataPhaseSnapshot(
+    int profiling_phase,
+    int count,
+    int32 run_duration_sum,
+    int32 run_duration_max,
+    int32 run_duration_sample,
+    int32 queue_duration_sum,
+    int32 queue_duration_max,
+    int32 queue_duration_sample,
+    const DeathDataPhaseSnapshot* prev)
+    : profiling_phase(profiling_phase),
+      death_data(count,
+                 run_duration_sum,
+                 run_duration_max,
+                 run_duration_sample,
+                 queue_duration_sum,
+                 queue_duration_max,
+                 queue_duration_sample),
+      prev(prev) {
+}
+
+//------------------------------------------------------------------------------
+// TaskSnapshot
+
+TaskSnapshot::TaskSnapshot() {
+}
+
+TaskSnapshot::TaskSnapshot(const BirthOnThreadSnapshot& birth,
+                           const DeathDataSnapshot& death_data,
+                           const std::string& death_thread_name)
+    : birth(birth),
+      death_data(death_data),
+      death_thread_name(death_thread_name) {
+}
+
+TaskSnapshot::~TaskSnapshot() {
+}
+
+//------------------------------------------------------------------------------
+// ProcessDataPhaseSnapshot
+
+ProcessDataPhaseSnapshot::ProcessDataPhaseSnapshot() {
+}
+
+ProcessDataPhaseSnapshot::~ProcessDataPhaseSnapshot() {
+}
+
+//------------------------------------------------------------------------------
+// ProcessDataPhaseSnapshot
+
+ProcessDataSnapshot::ProcessDataSnapshot()
+#if !defined(OS_NACL)
+    : process_id(base::GetCurrentProcId()) {
+#else
+    : process_id(base::kNullProcessId) {
+#endif
+}
+
+ProcessDataSnapshot::~ProcessDataSnapshot() {
+}
+
+}  // namespace tracked_objects
diff --git a/base/tracked_objects.h b/base/tracked_objects.h
new file mode 100644
index 0000000..8f83794
--- /dev/null
+++ b/base/tracked_objects.h
@@ -0,0 +1,812 @@
+// Copyright (c) 2012 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_TRACKED_OBJECTS_H_
+#define BASE_TRACKED_OBJECTS_H_
+
+#include <map>
+#include <set>
+#include <stack>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/containers/hash_tables.h"
+#include "base/gtest_prod_util.h"
+#include "base/lazy_instance.h"
+#include "base/location.h"
+#include "base/process/process_handle.h"
+#include "base/profiler/alternate_timer.h"
+#include "base/profiler/tracked_time.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/thread_checker.h"
+#include "base/threading/thread_local_storage.h"
+
+namespace base {
+struct TrackingInfo;
+}
+
+// TrackedObjects provides a database of stats about objects (generally Tasks)
+// that are tracked.  Tracking means their birth, death, duration, birth thread,
+// death thread, and birth place are recorded.  This data is carefully spread
+// across a series of objects so that the counts and times can be rapidly
+// updated without (usually) having to lock the data, and hence there is usually
+// very little contention caused by the tracking.  The data can be viewed via
+// the about:profiler URL, with a variety of sorting and filtering choices.
+//
+// These classes serve as the basis of a profiler of sorts for the Tasks system.
+// As a result, design decisions were made to maximize speed, by minimizing
+// recurring allocation/deallocation, lock contention and data copying.  In the
+// "stable" state, which is reached relatively quickly, there is no separate
+// marginal allocation cost associated with construction or destruction of
+// tracked objects, no locks are generally employed, and probably the largest
+// computational cost is associated with obtaining start and stop times for
+// instances as they are created and destroyed.
+//
+// The following describes the life cycle of tracking an instance.
+//
+// First off, when the instance is created, the FROM_HERE macro is expanded
+// to specify the birth place (file, line, function) where the instance was
+// created.  That data is used to create a transient Location instance
+// encapsulating the above triple of information.  The strings (like __FILE__)
+// are passed around by reference, with the assumption that they are static, and
+// will never go away.  This ensures that the strings can be dealt with as atoms
+// with great efficiency (i.e., copying of strings is never needed, and
+// comparisons for equality can be based on pointer comparisons).
+//
+// Next, a Births instance is created for use ONLY on the thread where this
+// instance was created.  That Births instance records (in a base class
+// BirthOnThread) references to the static data provided in a Location instance,
+// as well as a pointer specifying the thread on which the birth takes place.
+// Hence there is at most one Births instance for each Location on each thread.
+// The derived Births class contains slots for recording statistics about all
+// instances born at the same location.  Statistics currently include only the
+// count of instances constructed.
+//
+// Since the base class BirthOnThread contains only constant data, it can be
+// freely accessed by any thread at any time (i.e., only the statistic needs to
+// be handled carefully, and stats are updated exclusively on the birth thread).
+//
+// For Tasks, having now either constructed or found the Births instance
+// described above, a pointer to the Births instance is then recorded into the
+// PendingTask structure in MessageLoop.  This fact alone is very useful in
+// debugging, when there is a question of where an instance came from.  In
+// addition, the birth time is also recorded and used to later evaluate the
+// lifetime duration of the whole Task.  As a result of the above embedding, we
+// can find out a Task's location of birth, and thread of birth, without using
+// any locks, as all that data is constant across the life of the process.
+//
+// The above work *could* also be done for any other object as well by calling
+// TallyABirthIfActive() and TallyRunOnNamedThreadIfTracking() as appropriate.
+//
+// The amount of memory used in the above data structures depends on how many
+// threads there are, and how many Locations of construction there are.
+// Fortunately, we don't use memory that is the product of those two counts, but
+// rather we only need one Births instance for each thread that constructs an
+// instance at a Location.  In many cases, instances are only created on one
+// thread, so the memory utilization is actually fairly restrained.
+//
+// Lastly, when an instance is deleted, the final tallies of statistics are
+// carefully accumulated.  That tallying writes into slots (members) in a
+// collection of DeathData instances.  For each birth place Location that is
+// destroyed on a thread, there is a DeathData instance to record the additional
+// death count, as well as accumulate the run-time and queue-time durations for
+// the instance as it is destroyed (dies).  By maintaining a single place to
+// aggregate this running sum *only* for the given thread, we avoid the need to
+// lock such DeathData instances. (i.e., these accumulated stats in a DeathData
+// instance are exclusively updated by the singular owning thread).
+//
+// With the above life cycle description complete, the major remaining detail
+// is explaining how each thread maintains a list of DeathData instances, and
+// of Births instances, and is able to avoid additional (redundant/unnecessary)
+// allocations.
+//
+// Each thread maintains a list of data items specific to that thread in a
+// ThreadData instance (for that specific thread only).  The two critical items
+// are lists of DeathData and Births instances.  These lists are maintained in
+// STL maps, which are indexed by Location.  As noted earlier, we can compare
+// locations very efficiently as we consider the underlying data (file,
+// function, line) to be atoms, and hence pointer comparison is used rather than
+// (slow) string comparisons.
+//
+// To provide a mechanism for iterating over all "known threads," which means
+// threads that have recorded a birth or a death, we create a singly linked list
+// of ThreadData instances.  Each such instance maintains a pointer to the next
+// one.  A static member of ThreadData provides a pointer to the first item on
+// this global list, and access via that all_thread_data_list_head_ item
+// requires the use of the list_lock_.
+// When new ThreadData instances is added to the global list, it is pre-pended,
+// which ensures that any prior acquisition of the list is valid (i.e., the
+// holder can iterate over it without fear of it changing, or the necessity of
+// using an additional lock.  Iterations are actually pretty rare (used
+// primarily for cleanup, or snapshotting data for display), so this lock has
+// very little global performance impact.
+//
+// The above description tries to define the high performance (run time)
+// portions of these classes.  After gathering statistics, calls instigated
+// by visiting about:profiler will assemble and aggregate data for display.  The
+// following data structures are used for producing such displays.  They are
+// not performance critical, and their only major constraint is that they should
+// be able to run concurrently with ongoing augmentation of the birth and death
+// data.
+//
+// This header also exports collection of classes that provide "snapshotted"
+// representations of the core tracked_objects:: classes.  These snapshotted
+// representations are designed for safe transmission of the tracked_objects::
+// data across process boundaries.  Each consists of:
+// (1) a default constructor, to support the IPC serialization macros,
+// (2) a constructor that extracts data from the type being snapshotted, and
+// (3) the snapshotted data.
+//
+// For a given birth location, information about births is spread across data
+// structures that are asynchronously changing on various threads.  For
+// serialization and display purposes, we need to construct TaskSnapshot
+// instances for each combination of birth thread, death thread, and location,
+// along with the count of such lifetimes.  We gather such data into a
+// TaskSnapshot instances, so that such instances can be sorted and
+// aggregated (and remain frozen during our processing).
+//
+// Profiling consists of phases.  The concrete phase in the sequence of phases
+// is identified by its 0-based index.
+//
+// The ProcessDataPhaseSnapshot struct is a serialized representation of the
+// list of ThreadData objects for a process for a concrete profiling phase.  It
+// holds a set of TaskSnapshots.  The statistics in a snapshot are gathered
+// asynhcronously relative to their ongoing updates.
+// It is possible, though highly unlikely, that stats could be incorrectly
+// recorded by this process (all data is held in 32 bit ints, but we are not
+// atomically collecting all data, so we could have count that does not, for
+// example, match with the number of durations we accumulated).  The advantage
+// to having fast (non-atomic) updates of the data outweighs the minimal risk of
+// a singular corrupt statistic snapshot (only the snapshot could be corrupt,
+// not the underlying and ongoing statistic).  In contrast, pointer data that
+// is accessed during snapshotting is completely invariant, and hence is
+// perfectly acquired (i.e., no potential corruption, and no risk of a bad
+// memory reference).
+//
+// TODO(jar): We can implement a Snapshot system that *tries* to grab the
+// snapshots on the source threads *when* they have MessageLoops available
+// (worker threads don't have message loops generally, and hence gathering from
+// them will continue to be asynchronous).  We had an implementation of this in
+// the past, but the difficulty is dealing with message loops being terminated.
+// We can *try* to spam the available threads via some message loop proxy to
+// achieve this feat, and it *might* be valuable when we are collecting data
+// for upload via UMA (where correctness of data may be more significant than
+// for a single screen of about:profiler).
+//
+// TODO(jar): We need to store DataCollections, and provide facilities for
+// taking the difference between two gathered DataCollections.  For now, we're
+// just adding a hack that Reset()s to zero all counts and stats.  This is also
+// done in a slightly thread-unsafe fashion, as the resetting is done
+// asynchronously relative to ongoing updates (but all data is 32 bit in size).
+// For basic profiling, this will work "most of the time," and should be
+// sufficient... but storing away DataCollections is the "right way" to do this.
+// We'll accomplish this via JavaScript storage of snapshots, and then we'll
+// remove the Reset() methods.  We may also need a short-term-max value in
+// DeathData that is reset (as synchronously as possible) during each snapshot.
+// This will facilitate displaying a max value for each snapshot period.
+
+namespace tracked_objects {
+
+//------------------------------------------------------------------------------
+// For a specific thread, and a specific birth place, the collection of all
+// death info (with tallies for each death thread, to prevent access conflicts).
+class ThreadData;
+class BASE_EXPORT BirthOnThread {
+ public:
+  BirthOnThread(const Location& location, const ThreadData& current);
+
+  const Location location() const { return location_; }
+  const ThreadData* birth_thread() const { return birth_thread_; }
+
+ private:
+  // File/lineno of birth.  This defines the essence of the task, as the context
+  // of the birth (construction) often tell what the item is for.  This field
+  // is const, and hence safe to access from any thread.
+  const Location location_;
+
+  // The thread that records births into this object.  Only this thread is
+  // allowed to update birth_count_ (which changes over time).
+  const ThreadData* const birth_thread_;
+
+  DISALLOW_COPY_AND_ASSIGN(BirthOnThread);
+};
+
+//------------------------------------------------------------------------------
+// A "snapshotted" representation of the BirthOnThread class.
+
+struct BASE_EXPORT BirthOnThreadSnapshot {
+  BirthOnThreadSnapshot();
+  explicit BirthOnThreadSnapshot(const BirthOnThread& birth);
+  ~BirthOnThreadSnapshot();
+
+  LocationSnapshot location;
+  std::string thread_name;
+};
+
+//------------------------------------------------------------------------------
+// A class for accumulating counts of births (without bothering with a map<>).
+
+class BASE_EXPORT Births: public BirthOnThread {
+ public:
+  Births(const Location& location, const ThreadData& current);
+
+  int birth_count() const;
+
+  // When we have a birth we update the count for this birthplace.
+  void RecordBirth();
+
+ private:
+  // The number of births on this thread for our location_.
+  int birth_count_;
+
+  DISALLOW_COPY_AND_ASSIGN(Births);
+};
+
+//------------------------------------------------------------------------------
+// A "snapshotted" representation of the DeathData class.
+
+struct BASE_EXPORT DeathDataSnapshot {
+  DeathDataSnapshot();
+
+  // Constructs the snapshot from individual values.
+  // The alternative would be taking a DeathData parameter, but this would
+  // create a loop since DeathData indirectly refers DeathDataSnapshot.  Passing
+  // a wrapper structure as a param or using an empty constructor for
+  // snapshotting DeathData would be less efficient.
+  DeathDataSnapshot(int count,
+                    int32 run_duration_sum,
+                    int32 run_duration_max,
+                    int32 run_duration_sample,
+                    int32 queue_duration_sum,
+                    int32 queue_duration_max,
+                    int32 queue_duration_sample);
+  ~DeathDataSnapshot();
+
+  // Calculates and returns the delta between this snapshot and an earlier
+  // snapshot of the same task |older|.
+  DeathDataSnapshot Delta(const DeathDataSnapshot& older) const;
+
+  int count;
+  int32 run_duration_sum;
+  int32 run_duration_max;
+  int32 run_duration_sample;
+  int32 queue_duration_sum;
+  int32 queue_duration_max;
+  int32 queue_duration_sample;
+};
+
+//------------------------------------------------------------------------------
+// A "snapshotted" representation of the DeathData for a particular profiling
+// phase.  Used as an element of the list of phase snapshots owned by DeathData.
+
+struct DeathDataPhaseSnapshot {
+  DeathDataPhaseSnapshot(int profiling_phase,
+                         int count,
+                         int32 run_duration_sum,
+                         int32 run_duration_max,
+                         int32 run_duration_sample,
+                         int32 queue_duration_sum,
+                         int32 queue_duration_max,
+                         int32 queue_duration_sample,
+                         const DeathDataPhaseSnapshot* prev);
+
+  // Profiling phase at which completion this snapshot was taken.
+  int profiling_phase;
+
+  // Death data snapshot.
+  DeathDataSnapshot death_data;
+
+  // Pointer to a snapshot from the previous phase.
+  const DeathDataPhaseSnapshot* prev;
+};
+
+//------------------------------------------------------------------------------
+// Information about deaths of a task on a given thread, called "death thread".
+// Access to members of this class is never protected by a lock.  The fields
+// are accessed in such a way that corruptions resulting from race conditions
+// are not significant, and don't accumulate as a result of multiple accesses.
+// All invocations of DeathData::OnProfilingPhaseCompleted and
+// ThreadData::SnapshotMaps (which takes DeathData snapshot) in a given process
+// must be called from the same thread. It doesn't matter what thread it is, but
+// it's important the same thread is used as a snapshot thread during the whole
+// process lifetime.  All fields except sample_probability_count_ can be
+// snapshotted.
+
+class BASE_EXPORT DeathData {
+ public:
+  DeathData();
+  DeathData(const DeathData& other);
+  ~DeathData();
+
+  // Update stats for a task destruction (death) that had a Run() time of
+  // |duration|, and has had a queueing delay of |queue_duration|.
+  void RecordDeath(const int32 queue_duration,
+                   const int32 run_duration,
+                   const uint32 random_number);
+
+  // Metrics and past snapshots accessors, used only for serialization and in
+  // tests.
+  int count() const { return count_; }
+  int32 run_duration_sum() const { return run_duration_sum_; }
+  int32 run_duration_max() const { return run_duration_max_; }
+  int32 run_duration_sample() const { return run_duration_sample_; }
+  int32 queue_duration_sum() const { return queue_duration_sum_; }
+  int32 queue_duration_max() const { return queue_duration_max_; }
+  int32 queue_duration_sample() const { return queue_duration_sample_; }
+  const DeathDataPhaseSnapshot* last_phase_snapshot() const {
+    return last_phase_snapshot_;
+  }
+
+  // Called when the current profiling phase, identified by |profiling_phase|,
+  // ends.
+  // Must be called only on the snapshot thread.
+  void OnProfilingPhaseCompleted(int profiling_phase);
+
+ private:
+  // Members are ordered from most regularly read and updated, to least
+  // frequently used.  This might help a bit with cache lines.
+  // Number of runs seen (divisor for calculating averages).
+  // Can be incremented only on the death thread.
+  int count_;
+
+  // Count used in determining probability of selecting exec/queue times from a
+  // recorded death as samples.
+  // Gets incremented only on the death thread, but can be set to 0 by
+  // OnProfilingPhaseCompleted() on the snapshot thread.
+  int sample_probability_count_;
+
+  // Basic tallies, used to compute averages.  Can be incremented only on the
+  // death thread.
+  int32 run_duration_sum_;
+  int32 queue_duration_sum_;
+  // Max values, used by local visualization routines.  These are often read,
+  // but rarely updated.  The max values get assigned only on the death thread,
+  // but these fields can be set to 0 by OnProfilingPhaseCompleted() on the
+  // snapshot thread.
+  int32 run_duration_max_;
+  int32 queue_duration_max_;
+  // Samples, used by crowd sourcing gatherers.  These are almost never read,
+  // and rarely updated.  They can be modified only on the death thread.
+  int32 run_duration_sample_;
+  int32 queue_duration_sample_;
+
+  // Snapshot of this death data made at the last profiling phase completion, if
+  // any.  DeathData owns the whole list starting with this pointer.
+  // Can be accessed only on the snapshot thread.
+  const DeathDataPhaseSnapshot* last_phase_snapshot_;
+
+  DISALLOW_ASSIGN(DeathData);
+};
+
+//------------------------------------------------------------------------------
+// A temporary collection of data that can be sorted and summarized.  It is
+// gathered (carefully) from many threads.  Instances are held in arrays and
+// processed, filtered, and rendered.
+// The source of this data was collected on many threads, and is asynchronously
+// changing.  The data in this instance is not asynchronously changing.
+
+struct BASE_EXPORT TaskSnapshot {
+  TaskSnapshot();
+  TaskSnapshot(const BirthOnThreadSnapshot& birth,
+               const DeathDataSnapshot& death_data,
+               const std::string& death_thread_name);
+  ~TaskSnapshot();
+
+  BirthOnThreadSnapshot birth;
+  // Delta between death data for a thread for a certain profiling phase and the
+  // snapshot for the pervious phase, if any.  Otherwise, just a snapshot.
+  DeathDataSnapshot death_data;
+  std::string death_thread_name;
+};
+
+//------------------------------------------------------------------------------
+// For each thread, we have a ThreadData that stores all tracking info generated
+// on this thread.  This prevents the need for locking as data accumulates.
+// We use ThreadLocalStorage to quickly identfy the current ThreadData context.
+// We also have a linked list of ThreadData instances, and that list is used to
+// harvest data from all existing instances.
+
+struct ProcessDataPhaseSnapshot;
+struct ProcessDataSnapshot;
+class BASE_EXPORT TaskStopwatch;
+
+// Map from profiling phase number to the process-wide snapshotted
+// representation of the list of ThreadData objects that died during the given
+// phase.
+typedef std::map<int, ProcessDataPhaseSnapshot> PhasedProcessDataSnapshotMap;
+
+class BASE_EXPORT ThreadData {
+ public:
+  // Current allowable states of the tracking system.  The states can vary
+  // between ACTIVE and DEACTIVATED, but can never go back to UNINITIALIZED.
+  enum Status {
+    UNINITIALIZED,         // Pristine, link-time state before running.
+    DORMANT_DURING_TESTS,  // Only used during testing.
+    DEACTIVATED,           // No longer recording profiling.
+    PROFILING_ACTIVE,      // Recording profiles.
+    STATUS_LAST = PROFILING_ACTIVE
+  };
+
+  typedef base::hash_map<Location, Births*, Location::Hash> BirthMap;
+  typedef std::map<const Births*, DeathData> DeathMap;
+
+  // Initialize the current thread context with a new instance of ThreadData.
+  // This is used by all threads that have names, and should be explicitly
+  // set *before* any births on the threads have taken place.  It is generally
+  // only used by the message loop, which has a well defined thread name.
+  static void InitializeThreadContext(const std::string& suggested_name);
+
+  // Using Thread Local Store, find the current instance for collecting data.
+  // If an instance does not exist, construct one (and remember it for use on
+  // this thread.
+  // This may return NULL if the system is disabled for any reason.
+  static ThreadData* Get();
+
+  // Fills |process_data_snapshot| with phased snapshots of all profiling
+  // phases, including the current one, identified by |current_profiling_phase|.
+  // |current_profiling_phase| is necessary because a child process can start
+  // after several phase-changing events, so it needs to receive the current
+  // phase number from the browser process to fill the correct entry for the
+  // current phase in the |process_data_snapshot| map.
+  static void Snapshot(int current_profiling_phase,
+                       ProcessDataSnapshot* process_data_snapshot);
+
+  // Called when the current profiling phase, identified by |profiling_phase|,
+  // ends.
+  // |profiling_phase| is necessary because a child process can start after
+  // several phase-changing events, so it needs to receive the phase number from
+  // the browser process to fill the correct entry in the
+  // completed_phases_snapshots_ map.
+  static void OnProfilingPhaseCompleted(int profiling_phase);
+
+  // Finds (or creates) a place to count births from the given location in this
+  // thread, and increment that tally.
+  // TallyABirthIfActive will returns NULL if the birth cannot be tallied.
+  static Births* TallyABirthIfActive(const Location& location);
+
+  // Records the end of a timed run of an object.  The |completed_task| contains
+  // a pointer to a Births, the time_posted, and a delayed_start_time if any.
+  // The |start_of_run| indicates when we started to perform the run of the
+  // task.  The delayed_start_time is non-null for tasks that were posted as
+  // delayed tasks, and it indicates when the task should have run (i.e., when
+  // it should have posted out of the timer queue, and into the work queue.
+  // The |end_of_run| was just obtained by a call to Now() (just after the task
+  // finished).  It is provided as an argument to help with testing.
+  static void TallyRunOnNamedThreadIfTracking(
+      const base::TrackingInfo& completed_task,
+      const TaskStopwatch& stopwatch);
+
+  // Record the end of a timed run of an object.  The |birth| is the record for
+  // the instance, the |time_posted| records that instant, which is presumed to
+  // be when the task was posted into a queue to run on a worker thread.
+  // The |start_of_run| is when the worker thread started to perform the run of
+  // the task.
+  // The |end_of_run| was just obtained by a call to Now() (just after the task
+  // finished).
+  static void TallyRunOnWorkerThreadIfTracking(const Births* births,
+                                               const TrackedTime& time_posted,
+                                               const TaskStopwatch& stopwatch);
+
+  // Record the end of execution in region, generally corresponding to a scope
+  // being exited.
+  static void TallyRunInAScopedRegionIfTracking(const Births* births,
+                                                const TaskStopwatch& stopwatch);
+
+  const std::string& thread_name() const { return thread_name_; }
+
+  // Initializes all statics if needed (this initialization call should be made
+  // while we are single threaded).
+  static void Initialize();
+
+  // Sets internal status_.
+  // If |status| is false, then status_ is set to DEACTIVATED.
+  // If |status| is true, then status_ is set to PROFILING_ACTIVE.
+  static void InitializeAndSetTrackingStatus(Status status);
+
+  static Status status();
+
+  // Indicate if any sort of profiling is being done (i.e., we are more than
+  // DEACTIVATED).
+  static bool TrackingStatus();
+
+  // Enables profiler timing.
+  static void EnableProfilerTiming();
+
+  // Provide a time function that does nothing (runs fast) when we don't have
+  // the profiler enabled.  It will generally be optimized away when it is
+  // ifdef'ed to be small enough (allowing the profiler to be "compiled out" of
+  // the code).
+  static TrackedTime Now();
+
+  // Use the function |now| to provide current times, instead of calling the
+  // TrackedTime::Now() function.  Since this alternate function is being used,
+  // the other time arguments (used for calculating queueing delay) will be
+  // ignored.
+  static void SetAlternateTimeSource(NowFunction* now);
+
+  // This function can be called at process termination to validate that thread
+  // cleanup routines have been called for at least some number of named
+  // threads.
+  static void EnsureCleanupWasCalled(int major_threads_shutdown_count);
+
+ private:
+  friend class TaskStopwatch;
+  // Allow only tests to call ShutdownSingleThreadedCleanup.  We NEVER call it
+  // in production code.
+  // TODO(jar): Make this a friend in DEBUG only, so that the optimizer has a
+  // better change of optimizing (inlining? etc.) private methods (knowing that
+  // there will be no need for an external entry point).
+  friend class TrackedObjectsTest;
+  FRIEND_TEST_ALL_PREFIXES(TrackedObjectsTest, MinimalStartupShutdown);
+  FRIEND_TEST_ALL_PREFIXES(TrackedObjectsTest, TinyStartupShutdown);
+
+  typedef std::map<const BirthOnThread*, int> BirthCountMap;
+
+  typedef std::vector<std::pair<const Births*, DeathDataPhaseSnapshot>>
+      DeathsSnapshot;
+
+  // Worker thread construction creates a name since there is none.
+  explicit ThreadData(int thread_number);
+
+  // Message loop based construction should provide a name.
+  explicit ThreadData(const std::string& suggested_name);
+
+  ~ThreadData();
+
+  // Push this instance to the head of all_thread_data_list_head_, linking it to
+  // the previous head.  This is performed after each construction, and leaves
+  // the instance permanently on that list.
+  void PushToHeadOfList();
+
+  // (Thread safe) Get start of list of all ThreadData instances using the lock.
+  static ThreadData* first();
+
+  // Iterate through the null terminated list of ThreadData instances.
+  ThreadData* next() const;
+
+
+  // In this thread's data, record a new birth.
+  Births* TallyABirth(const Location& location);
+
+  // Find a place to record a death on this thread.
+  void TallyADeath(const Births& births,
+                   int32 queue_duration,
+                   const TaskStopwatch& stopwatch);
+
+  // Snapshots (under a lock) the profiled data for the tasks for this thread
+  // and writes all of the executed tasks' data -- i.e. the data for all
+  // profiling phases (including the current one: |current_profiling_phase|) for
+  // the tasks with with entries in the death_map_ -- into |phased_snapshots|.
+  // Also updates the |birth_counts| tally for each task to keep track of the
+  // number of living instances of the task -- that is, each task maps to the
+  // number of births for the task that have not yet been balanced by a death.
+  void SnapshotExecutedTasks(int current_profiling_phase,
+                             PhasedProcessDataSnapshotMap* phased_snapshots,
+                             BirthCountMap* birth_counts);
+
+  // Using our lock, make a copy of the specified maps.  This call may be made
+  // on  non-local threads, which necessitate the use of the lock to prevent
+  // the map(s) from being reallocated while they are copied.
+  void SnapshotMaps(int profiling_phase,
+                    BirthMap* birth_map,
+                    DeathsSnapshot* deaths);
+
+  // Called for this thread when the current profiling phase, identified by
+  // |profiling_phase|, ends.
+  void OnProfilingPhaseCompletedOnThread(int profiling_phase);
+
+  // This method is called by the TLS system when a thread terminates.
+  // The argument may be NULL if this thread has never tracked a birth or death.
+  static void OnThreadTermination(void* thread_data);
+
+  // This method should be called when a worker thread terminates, so that we
+  // can save all the thread data into a cache of reusable ThreadData instances.
+  void OnThreadTerminationCleanup();
+
+  // Cleans up data structures, and returns statics to near pristine (mostly
+  // uninitialized) state.  If there is any chance that other threads are still
+  // using the data structures, then the |leak| argument should be passed in as
+  // true, and the data structures (birth maps, death maps, ThreadData
+  // insntances, etc.) will be leaked and not deleted.  If you have joined all
+  // threads since the time that InitializeAndSetTrackingStatus() was called,
+  // then you can pass in a |leak| value of false, and this function will
+  // delete recursively all data structures, starting with the list of
+  // ThreadData instances.
+  static void ShutdownSingleThreadedCleanup(bool leak);
+
+  // When non-null, this specifies an external function that supplies monotone
+  // increasing time functcion.
+  static NowFunction* now_function_;
+
+  // If true, now_function_ returns values that can be used to calculate queue
+  // time.
+  static bool now_function_is_time_;
+
+  // We use thread local store to identify which ThreadData to interact with.
+  static base::ThreadLocalStorage::StaticSlot tls_index_;
+
+  // List of ThreadData instances for use with worker threads.  When a worker
+  // thread is done (terminated), we push it onto this list.  When a new worker
+  // thread is created, we first try to re-use a ThreadData instance from the
+  // list, and if none are available, construct a new one.
+  // This is only accessed while list_lock_ is held.
+  static ThreadData* first_retired_worker_;
+
+  // Link to the most recently created instance (starts a null terminated list).
+  // The list is traversed by about:profiler when it needs to snapshot data.
+  // This is only accessed while list_lock_ is held.
+  static ThreadData* all_thread_data_list_head_;
+
+  // The next available worker thread number.  This should only be accessed when
+  // the list_lock_ is held.
+  static int worker_thread_data_creation_count_;
+
+  // The number of times TLS has called us back to cleanup a ThreadData
+  // instance.  This is only accessed while list_lock_ is held.
+  static int cleanup_count_;
+
+  // Incarnation sequence number, indicating how many times (during unittests)
+  // we've either transitioned out of UNINITIALIZED, or into that state.  This
+  // value is only accessed while the list_lock_ is held.
+  static int incarnation_counter_;
+
+  // Protection for access to all_thread_data_list_head_, and to
+  // unregistered_thread_data_pool_.  This lock is leaked at shutdown.
+  // The lock is very infrequently used, so we can afford to just make a lazy
+  // instance and be safe.
+  static base::LazyInstance<base::Lock>::Leaky list_lock_;
+
+  // We set status_ to SHUTDOWN when we shut down the tracking service.
+  static Status status_;
+
+  // Link to next instance (null terminated list).  Used to globally track all
+  // registered instances (corresponds to all registered threads where we keep
+  // data).
+  ThreadData* next_;
+
+  // Pointer to another ThreadData instance for a Worker-Thread that has been
+  // retired (its thread was terminated).  This value is non-NULL only for a
+  // retired ThreadData associated with a Worker-Thread.
+  ThreadData* next_retired_worker_;
+
+  // The name of the thread that is being recorded.  If this thread has no
+  // message_loop, then this is a worker thread, with a sequence number postfix.
+  std::string thread_name_;
+
+  // Indicate if this is a worker thread, and the ThreadData contexts should be
+  // stored in the unregistered_thread_data_pool_ when not in use.
+  // Value is zero when it is not a worker thread.  Value is a positive integer
+  // corresponding to the created thread name if it is a worker thread.
+  int worker_thread_number_;
+
+  // A map used on each thread to keep track of Births on this thread.
+  // This map should only be accessed on the thread it was constructed on.
+  // When a snapshot is needed, this structure can be locked in place for the
+  // duration of the snapshotting activity.
+  BirthMap birth_map_;
+
+  // Similar to birth_map_, this records informations about death of tracked
+  // instances (i.e., when a tracked instance was destroyed on this thread).
+  // It is locked before changing, and hence other threads may access it by
+  // locking before reading it.
+  DeathMap death_map_;
+
+  // Lock to protect *some* access to BirthMap and DeathMap.  The maps are
+  // regularly read and written on this thread, but may only be read from other
+  // threads.  To support this, we acquire this lock if we are writing from this
+  // thread, or reading from another thread.  For reading from this thread we
+  // don't need a lock, as there is no potential for a conflict since the
+  // writing is only done from this thread.
+  mutable base::Lock map_lock_;
+
+  // A random number that we used to select decide which sample to keep as a
+  // representative sample in each DeathData instance.  We can't start off with
+  // much randomness (because we can't call RandInt() on all our threads), so
+  // we stir in more and more as we go.
+  uint32 random_number_;
+
+  // Record of what the incarnation_counter_ was when this instance was created.
+  // If the incarnation_counter_ has changed, then we avoid pushing into the
+  // pool (this is only critical in tests which go through multiple
+  // incarnations).
+  int incarnation_count_for_pool_;
+
+  // Most recently started (i.e. most nested) stopwatch on the current thread,
+  // if it exists; NULL otherwise.
+  TaskStopwatch* current_stopwatch_;
+
+  DISALLOW_COPY_AND_ASSIGN(ThreadData);
+};
+
+//------------------------------------------------------------------------------
+// Stopwatch to measure task run time or simply create a time interval that will
+// be subtracted from the current most nested task's run time.  Stopwatches
+// coordinate with the stopwatches in which they are nested to avoid
+// double-counting nested tasks run times.
+
+class BASE_EXPORT TaskStopwatch {
+ public:
+  // Starts the stopwatch.
+  TaskStopwatch();
+  ~TaskStopwatch();
+
+  // Starts stopwatch.
+  void Start();
+
+  // Stops stopwatch.
+  void Stop();
+
+  // Returns the start time.
+  TrackedTime StartTime() const;
+
+  // Task's duration is calculated as the wallclock duration between starting
+  // and stopping this stopwatch, minus the wallclock durations of any other
+  // instances that are immediately nested in this one, started and stopped on
+  // this thread during that period.
+  int32 RunDurationMs() const;
+
+  // Returns tracking info for the current thread.
+  ThreadData* GetThreadData() const;
+
+ private:
+  // Time when the stopwatch was started.
+  TrackedTime start_time_;
+
+  // Wallclock duration of the task.
+  int32 wallclock_duration_ms_;
+
+  // Tracking info for the current thread.
+  ThreadData* current_thread_data_;
+
+  // Sum of wallclock durations of all stopwatches that were directly nested in
+  // this one.
+  int32 excluded_duration_ms_;
+
+  // Stopwatch which was running on our thread when this stopwatch was started.
+  // That preexisting stopwatch must be adjusted to the exclude the wallclock
+  // duration of this stopwatch.
+  TaskStopwatch* parent_;
+
+#if DCHECK_IS_ON()
+  // State of the stopwatch.  Stopwatch is first constructed in a created state
+  // state, then is optionally started/stopped, then destructed.
+  enum { CREATED, RUNNING, STOPPED } state_;
+
+  // Currently running stopwatch that is directly nested in this one, if such
+  // stopwatch exists.  NULL otherwise.
+  TaskStopwatch* child_;
+#endif
+};
+
+//------------------------------------------------------------------------------
+// A snapshotted representation of the list of ThreadData objects for a process,
+// for a single profiling phase.
+
+struct BASE_EXPORT ProcessDataPhaseSnapshot {
+ public:
+  ProcessDataPhaseSnapshot();
+  ~ProcessDataPhaseSnapshot();
+
+  std::vector<TaskSnapshot> tasks;
+};
+
+//------------------------------------------------------------------------------
+// A snapshotted representation of the list of ThreadData objects for a process,
+// for all profiling phases, including the current one.
+
+struct BASE_EXPORT ProcessDataSnapshot {
+ public:
+  ProcessDataSnapshot();
+  ~ProcessDataSnapshot();
+
+  PhasedProcessDataSnapshotMap phased_snapshots;
+  base::ProcessId process_id;
+};
+
+}  // namespace tracked_objects
+
+#endif  // BASE_TRACKED_OBJECTS_H_
diff --git a/base/tracked_objects_unittest.cc b/base/tracked_objects_unittest.cc
new file mode 100644
index 0000000..cdbf9ac
--- /dev/null
+++ b/base/tracked_objects_unittest.cc
@@ -0,0 +1,1186 @@
+// Copyright (c) 2012 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.
+
+// Test of classes in the tracked_objects.h classes.
+
+#include "base/tracked_objects.h"
+
+#include <stddef.h>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/process/process_handle.h"
+#include "base/time/time.h"
+#include "base/tracking_info.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+const int kLineNumber = 1776;
+const char kFile[] = "FixedUnitTestFileName";
+const char kWorkerThreadName[] = "WorkerThread-1";
+const char kMainThreadName[] = "SomeMainThreadName";
+const char kStillAlive[] = "Still_Alive";
+
+namespace tracked_objects {
+
+class TrackedObjectsTest : public testing::Test {
+ protected:
+  TrackedObjectsTest() {
+    // On entry, leak any database structures in case they are still in use by
+    // prior threads.
+    ThreadData::ShutdownSingleThreadedCleanup(true);
+
+    test_time_ = 0;
+    ThreadData::SetAlternateTimeSource(&TrackedObjectsTest::GetTestTime);
+    ThreadData::now_function_is_time_ = true;
+  }
+
+  ~TrackedObjectsTest() override {
+    // We should not need to leak any structures we create, since we are
+    // single threaded, and carefully accounting for items.
+    ThreadData::ShutdownSingleThreadedCleanup(false);
+  }
+
+  // Reset the profiler state.
+  void Reset() {
+    ThreadData::ShutdownSingleThreadedCleanup(false);
+    test_time_ = 0;
+  }
+
+  // Simulate a birth on the thread named |thread_name|, at the given
+  // |location|.
+  void TallyABirth(const Location& location, const std::string& thread_name) {
+    // If the |thread_name| is empty, we don't initialize system with a thread
+    // name, so we're viewed as a worker thread.
+    if (!thread_name.empty())
+      ThreadData::InitializeThreadContext(kMainThreadName);
+
+    // Do not delete |birth|.  We don't own it.
+    Births* birth = ThreadData::TallyABirthIfActive(location);
+
+    if (ThreadData::status() == ThreadData::DEACTIVATED)
+      EXPECT_EQ(reinterpret_cast<Births*>(NULL), birth);
+    else
+      EXPECT_NE(reinterpret_cast<Births*>(NULL), birth);
+  }
+
+  // Helper function to verify the most common test expectations.
+  void ExpectSimpleProcessData(const ProcessDataSnapshot& process_data,
+                               const std::string& function_name,
+                               const std::string& birth_thread,
+                               const std::string& death_thread,
+                               int count,
+                               int run_ms,
+                               int queue_ms) {
+    ASSERT_EQ(1u, process_data.phased_snapshots.size());
+    auto it = process_data.phased_snapshots.find(0);
+    ASSERT_TRUE(it != process_data.phased_snapshots.end());
+    const ProcessDataPhaseSnapshot& process_data_phase = it->second;
+
+    ASSERT_EQ(1u, process_data_phase.tasks.size());
+
+    EXPECT_EQ(kFile, process_data_phase.tasks[0].birth.location.file_name);
+    EXPECT_EQ(function_name,
+              process_data_phase.tasks[0].birth.location.function_name);
+    EXPECT_EQ(kLineNumber,
+              process_data_phase.tasks[0].birth.location.line_number);
+
+    EXPECT_EQ(birth_thread, process_data_phase.tasks[0].birth.thread_name);
+
+    EXPECT_EQ(count, process_data_phase.tasks[0].death_data.count);
+    EXPECT_EQ(count * run_ms,
+              process_data_phase.tasks[0].death_data.run_duration_sum);
+    EXPECT_EQ(run_ms, process_data_phase.tasks[0].death_data.run_duration_max);
+    EXPECT_EQ(run_ms,
+              process_data_phase.tasks[0].death_data.run_duration_sample);
+    EXPECT_EQ(count * queue_ms,
+              process_data_phase.tasks[0].death_data.queue_duration_sum);
+    EXPECT_EQ(queue_ms,
+              process_data_phase.tasks[0].death_data.queue_duration_max);
+    EXPECT_EQ(queue_ms,
+              process_data_phase.tasks[0].death_data.queue_duration_sample);
+
+    EXPECT_EQ(death_thread, process_data_phase.tasks[0].death_thread_name);
+
+    EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
+  }
+
+  // Sets time that will be returned by ThreadData::Now().
+  static void SetTestTime(unsigned int test_time) { test_time_ = test_time; }
+
+ private:
+  // Returns test time in milliseconds.
+  static unsigned int GetTestTime() { return test_time_; }
+
+  // Test time in milliseconds.
+  static unsigned int test_time_;
+};
+
+// static
+unsigned int TrackedObjectsTest::test_time_;
+
+TEST_F(TrackedObjectsTest, TaskStopwatchNoStartStop) {
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+
+  // Check that creating and destroying a stopwatch without starting it doesn't
+  // crash.
+  TaskStopwatch stopwatch;
+}
+
+TEST_F(TrackedObjectsTest, MinimalStartupShutdown) {
+  // Minimal test doesn't even create any tasks.
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+
+  EXPECT_FALSE(ThreadData::first());  // No activity even on this thread.
+  ThreadData* data = ThreadData::Get();
+  EXPECT_TRUE(ThreadData::first());  // Now class was constructed.
+  ASSERT_TRUE(data);
+  EXPECT_FALSE(data->next());
+  EXPECT_EQ(data, ThreadData::Get());
+  ThreadData::BirthMap birth_map;
+  ThreadData::DeathsSnapshot deaths;
+  data->SnapshotMaps(0, &birth_map, &deaths);
+  EXPECT_EQ(0u, birth_map.size());
+  EXPECT_EQ(0u, deaths.size());
+
+  // Clean up with no leaking.
+  Reset();
+
+  // Do it again, just to be sure we reset state completely.
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+  EXPECT_FALSE(ThreadData::first());  // No activity even on this thread.
+  data = ThreadData::Get();
+  EXPECT_TRUE(ThreadData::first());  // Now class was constructed.
+  ASSERT_TRUE(data);
+  EXPECT_FALSE(data->next());
+  EXPECT_EQ(data, ThreadData::Get());
+  birth_map.clear();
+  deaths.clear();
+  data->SnapshotMaps(0, &birth_map, &deaths);
+  EXPECT_EQ(0u, birth_map.size());
+  EXPECT_EQ(0u, deaths.size());
+}
+
+TEST_F(TrackedObjectsTest, TinyStartupShutdown) {
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+
+  // Instigate tracking on a single tracked object, on our thread.
+  const char kFunction[] = "TinyStartupShutdown";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+  ThreadData::TallyABirthIfActive(location);
+
+  ThreadData* data = ThreadData::first();
+  ASSERT_TRUE(data);
+  EXPECT_FALSE(data->next());
+  EXPECT_EQ(data, ThreadData::Get());
+  ThreadData::BirthMap birth_map;
+  ThreadData::DeathsSnapshot deaths;
+  data->SnapshotMaps(0, &birth_map, &deaths);
+  EXPECT_EQ(1u, birth_map.size());                         // 1 birth location.
+  EXPECT_EQ(1, birth_map.begin()->second->birth_count());  // 1 birth.
+  EXPECT_EQ(0u, deaths.size());                            // No deaths.
+
+
+  // Now instigate another birth, while we are timing the run of the first
+  // execution.
+  // Create a child (using the same birth location).
+  // TrackingInfo will call TallyABirth() during construction.
+  const int32 start_time = 1;
+  base::TimeTicks kBogusBirthTime = base::TimeTicks() +
+      base::TimeDelta::FromMilliseconds(start_time);
+  base::TrackingInfo pending_task(location, kBogusBirthTime);
+  SetTestTime(1);
+  TaskStopwatch stopwatch;
+  stopwatch.Start();
+  // Finally conclude the outer run.
+  const int32 time_elapsed = 1000;
+  SetTestTime(start_time + time_elapsed);
+  stopwatch.Stop();
+
+  ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
+
+  birth_map.clear();
+  deaths.clear();
+  data->SnapshotMaps(0, &birth_map, &deaths);
+  EXPECT_EQ(1u, birth_map.size());                         // 1 birth location.
+  EXPECT_EQ(2, birth_map.begin()->second->birth_count());  // 2 births.
+  EXPECT_EQ(1u, deaths.size());                            // 1 location.
+  EXPECT_EQ(1, deaths.begin()->second.death_data.count);   // 1 death.
+
+  // The births were at the same location as the one known death.
+  EXPECT_EQ(birth_map.begin()->second, deaths.begin()->first);
+
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(0, &process_data);
+
+  ASSERT_EQ(1u, process_data.phased_snapshots.size());
+  auto it = process_data.phased_snapshots.find(0);
+  ASSERT_TRUE(it != process_data.phased_snapshots.end());
+  const ProcessDataPhaseSnapshot& process_data_phase = it->second;
+  ASSERT_EQ(1u, process_data_phase.tasks.size());
+  EXPECT_EQ(kFile, process_data_phase.tasks[0].birth.location.file_name);
+  EXPECT_EQ(kFunction,
+            process_data_phase.tasks[0].birth.location.function_name);
+  EXPECT_EQ(kLineNumber,
+            process_data_phase.tasks[0].birth.location.line_number);
+  EXPECT_EQ(kWorkerThreadName, process_data_phase.tasks[0].birth.thread_name);
+  EXPECT_EQ(1, process_data_phase.tasks[0].death_data.count);
+  EXPECT_EQ(time_elapsed,
+            process_data_phase.tasks[0].death_data.run_duration_sum);
+  EXPECT_EQ(time_elapsed,
+            process_data_phase.tasks[0].death_data.run_duration_max);
+  EXPECT_EQ(time_elapsed,
+            process_data_phase.tasks[0].death_data.run_duration_sample);
+  EXPECT_EQ(0, process_data_phase.tasks[0].death_data.queue_duration_sum);
+  EXPECT_EQ(0, process_data_phase.tasks[0].death_data.queue_duration_max);
+  EXPECT_EQ(0, process_data_phase.tasks[0].death_data.queue_duration_sample);
+  EXPECT_EQ(kWorkerThreadName, process_data_phase.tasks[0].death_thread_name);
+}
+
+TEST_F(TrackedObjectsTest, DeathDataTestRecordDeath) {
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+
+  scoped_ptr<DeathData> data(new DeathData());
+  ASSERT_NE(data, reinterpret_cast<DeathData*>(NULL));
+  EXPECT_EQ(data->run_duration_sum(), 0);
+  EXPECT_EQ(data->run_duration_max(), 0);
+  EXPECT_EQ(data->run_duration_sample(), 0);
+  EXPECT_EQ(data->queue_duration_sum(), 0);
+  EXPECT_EQ(data->queue_duration_max(), 0);
+  EXPECT_EQ(data->queue_duration_sample(), 0);
+  EXPECT_EQ(data->count(), 0);
+  EXPECT_EQ(nullptr, data->last_phase_snapshot());
+
+  int32 run_ms = 42;
+  int32 queue_ms = 8;
+
+  const int kUnrandomInt = 0;  // Fake random int that ensure we sample data.
+  data->RecordDeath(queue_ms, run_ms, kUnrandomInt);
+  EXPECT_EQ(data->run_duration_sum(), run_ms);
+  EXPECT_EQ(data->run_duration_max(), run_ms);
+  EXPECT_EQ(data->run_duration_sample(), run_ms);
+  EXPECT_EQ(data->queue_duration_sum(), queue_ms);
+  EXPECT_EQ(data->queue_duration_max(), queue_ms);
+  EXPECT_EQ(data->queue_duration_sample(), queue_ms);
+  EXPECT_EQ(data->count(), 1);
+  EXPECT_EQ(nullptr, data->last_phase_snapshot());
+
+  data->RecordDeath(queue_ms, run_ms, kUnrandomInt);
+  EXPECT_EQ(data->run_duration_sum(), run_ms + run_ms);
+  EXPECT_EQ(data->run_duration_max(), run_ms);
+  EXPECT_EQ(data->run_duration_sample(), run_ms);
+  EXPECT_EQ(data->queue_duration_sum(), queue_ms + queue_ms);
+  EXPECT_EQ(data->queue_duration_max(), queue_ms);
+  EXPECT_EQ(data->queue_duration_sample(), queue_ms);
+  EXPECT_EQ(data->count(), 2);
+  EXPECT_EQ(nullptr, data->last_phase_snapshot());
+}
+
+TEST_F(TrackedObjectsTest, DeathDataTest2Phases) {
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+
+  scoped_ptr<DeathData> data(new DeathData());
+  ASSERT_NE(data, reinterpret_cast<DeathData*>(NULL));
+
+  int32 run_ms = 42;
+  int32 queue_ms = 8;
+
+  const int kUnrandomInt = 0;  // Fake random int that ensure we sample data.
+  data->RecordDeath(queue_ms, run_ms, kUnrandomInt);
+  data->RecordDeath(queue_ms, run_ms, kUnrandomInt);
+
+  data->OnProfilingPhaseCompleted(123);
+  EXPECT_EQ(data->run_duration_sum(), run_ms + run_ms);
+  EXPECT_EQ(data->run_duration_max(), 0);
+  EXPECT_EQ(data->run_duration_sample(), run_ms);
+  EXPECT_EQ(data->queue_duration_sum(), queue_ms + queue_ms);
+  EXPECT_EQ(data->queue_duration_max(), 0);
+  EXPECT_EQ(data->queue_duration_sample(), queue_ms);
+  EXPECT_EQ(data->count(), 2);
+  ASSERT_NE(nullptr, data->last_phase_snapshot());
+  EXPECT_EQ(123, data->last_phase_snapshot()->profiling_phase);
+  EXPECT_EQ(2, data->last_phase_snapshot()->death_data.count);
+  EXPECT_EQ(2 * run_ms,
+            data->last_phase_snapshot()->death_data.run_duration_sum);
+  EXPECT_EQ(run_ms, data->last_phase_snapshot()->death_data.run_duration_max);
+  EXPECT_EQ(run_ms,
+            data->last_phase_snapshot()->death_data.run_duration_sample);
+  EXPECT_EQ(2 * queue_ms,
+            data->last_phase_snapshot()->death_data.queue_duration_sum);
+  EXPECT_EQ(queue_ms,
+            data->last_phase_snapshot()->death_data.queue_duration_max);
+  EXPECT_EQ(queue_ms,
+            data->last_phase_snapshot()->death_data.queue_duration_sample);
+  EXPECT_EQ(nullptr, data->last_phase_snapshot()->prev);
+
+  int32 run_ms1 = 21;
+  int32 queue_ms1 = 4;
+
+  data->RecordDeath(queue_ms1, run_ms1, kUnrandomInt);
+  EXPECT_EQ(data->run_duration_sum(), run_ms + run_ms + run_ms1);
+  EXPECT_EQ(data->run_duration_max(), run_ms1);
+  EXPECT_EQ(data->run_duration_sample(), run_ms1);
+  EXPECT_EQ(data->queue_duration_sum(), queue_ms + queue_ms + queue_ms1);
+  EXPECT_EQ(data->queue_duration_max(), queue_ms1);
+  EXPECT_EQ(data->queue_duration_sample(), queue_ms1);
+  EXPECT_EQ(data->count(), 3);
+  ASSERT_NE(nullptr, data->last_phase_snapshot());
+  EXPECT_EQ(123, data->last_phase_snapshot()->profiling_phase);
+  EXPECT_EQ(2, data->last_phase_snapshot()->death_data.count);
+  EXPECT_EQ(2 * run_ms,
+            data->last_phase_snapshot()->death_data.run_duration_sum);
+  EXPECT_EQ(run_ms, data->last_phase_snapshot()->death_data.run_duration_max);
+  EXPECT_EQ(run_ms,
+            data->last_phase_snapshot()->death_data.run_duration_sample);
+  EXPECT_EQ(2 * queue_ms,
+            data->last_phase_snapshot()->death_data.queue_duration_sum);
+  EXPECT_EQ(queue_ms,
+            data->last_phase_snapshot()->death_data.queue_duration_max);
+  EXPECT_EQ(queue_ms,
+            data->last_phase_snapshot()->death_data.queue_duration_sample);
+  EXPECT_EQ(nullptr, data->last_phase_snapshot()->prev);
+}
+
+TEST_F(TrackedObjectsTest, Delta) {
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+
+  DeathDataSnapshot snapshot;
+  snapshot.count = 10;
+  snapshot.run_duration_sum = 100;
+  snapshot.run_duration_max = 50;
+  snapshot.run_duration_sample = 25;
+  snapshot.queue_duration_sum = 200;
+  snapshot.queue_duration_max = 101;
+  snapshot.queue_duration_sample = 26;
+
+  DeathDataSnapshot older_snapshot;
+  older_snapshot.count = 2;
+  older_snapshot.run_duration_sum = 95;
+  older_snapshot.run_duration_max = 48;
+  older_snapshot.run_duration_sample = 22;
+  older_snapshot.queue_duration_sum = 190;
+  older_snapshot.queue_duration_max = 99;
+  older_snapshot.queue_duration_sample = 21;
+
+  const DeathDataSnapshot& delta = snapshot.Delta(older_snapshot);
+  EXPECT_EQ(8, delta.count);
+  EXPECT_EQ(5, delta.run_duration_sum);
+  EXPECT_EQ(50, delta.run_duration_max);
+  EXPECT_EQ(25, delta.run_duration_sample);
+  EXPECT_EQ(10, delta.queue_duration_sum);
+  EXPECT_EQ(101, delta.queue_duration_max);
+  EXPECT_EQ(26, delta.queue_duration_sample);
+}
+
+TEST_F(TrackedObjectsTest, DeactivatedBirthOnlyToSnapshotWorkerThread) {
+  // Start in the deactivated state.
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::DEACTIVATED);
+
+  const char kFunction[] = "DeactivatedBirthOnlyToSnapshotWorkerThread";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+  TallyABirth(location, std::string());
+
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(0, &process_data);
+
+  ASSERT_EQ(1u, process_data.phased_snapshots.size());
+
+  auto it = process_data.phased_snapshots.find(0);
+  ASSERT_TRUE(it != process_data.phased_snapshots.end());
+  const ProcessDataPhaseSnapshot& process_data_phase = it->second;
+
+  ASSERT_EQ(0u, process_data_phase.tasks.size());
+
+  EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
+}
+
+TEST_F(TrackedObjectsTest, DeactivatedBirthOnlyToSnapshotMainThread) {
+  // Start in the deactivated state.
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::DEACTIVATED);
+
+  const char kFunction[] = "DeactivatedBirthOnlyToSnapshotMainThread";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+  TallyABirth(location, kMainThreadName);
+
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(0, &process_data);
+
+  ASSERT_EQ(1u, process_data.phased_snapshots.size());
+
+  auto it = process_data.phased_snapshots.find(0);
+  ASSERT_TRUE(it != process_data.phased_snapshots.end());
+  const ProcessDataPhaseSnapshot& process_data_phase = it->second;
+
+  ASSERT_EQ(0u, process_data_phase.tasks.size());
+
+  EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
+}
+
+TEST_F(TrackedObjectsTest, BirthOnlyToSnapshotWorkerThread) {
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+
+  const char kFunction[] = "BirthOnlyToSnapshotWorkerThread";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+  TallyABirth(location, std::string());
+
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(0, &process_data);
+  ExpectSimpleProcessData(process_data, kFunction, kWorkerThreadName,
+                          kStillAlive, 1, 0, 0);
+}
+
+TEST_F(TrackedObjectsTest, BirthOnlyToSnapshotMainThread) {
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+
+  const char kFunction[] = "BirthOnlyToSnapshotMainThread";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+  TallyABirth(location, kMainThreadName);
+
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(0, &process_data);
+  ExpectSimpleProcessData(process_data, kFunction, kMainThreadName, kStillAlive,
+                          1, 0, 0);
+}
+
+TEST_F(TrackedObjectsTest, LifeCycleToSnapshotMainThread) {
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+
+  const char kFunction[] = "LifeCycleToSnapshotMainThread";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+  TallyABirth(location, kMainThreadName);
+
+  const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1);
+  const base::TimeTicks kDelayedStartTime = base::TimeTicks();
+  // TrackingInfo will call TallyABirth() during construction.
+  base::TrackingInfo pending_task(location, kDelayedStartTime);
+  pending_task.time_posted = kTimePosted;  // Overwrite implied Now().
+
+  const unsigned int kStartOfRun = 5;
+  const unsigned int kEndOfRun = 7;
+  SetTestTime(kStartOfRun);
+  TaskStopwatch stopwatch;
+  stopwatch.Start();
+  SetTestTime(kEndOfRun);
+  stopwatch.Stop();
+
+  ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
+
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(0, &process_data);
+  ExpectSimpleProcessData(process_data, kFunction, kMainThreadName,
+                          kMainThreadName, 1, 2, 4);
+}
+
+TEST_F(TrackedObjectsTest, TwoPhases) {
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+
+  const char kFunction[] = "TwoPhases";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+  TallyABirth(location, kMainThreadName);
+
+  const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1);
+  const base::TimeTicks kDelayedStartTime = base::TimeTicks();
+  // TrackingInfo will call TallyABirth() during construction.
+  base::TrackingInfo pending_task(location, kDelayedStartTime);
+  pending_task.time_posted = kTimePosted;  // Overwrite implied Now().
+
+  const unsigned int kStartOfRun = 5;
+  const unsigned int kEndOfRun = 7;
+  SetTestTime(kStartOfRun);
+  TaskStopwatch stopwatch;
+  stopwatch.Start();
+  SetTestTime(kEndOfRun);
+  stopwatch.Stop();
+
+  ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
+
+  ThreadData::OnProfilingPhaseCompleted(0);
+
+  TallyABirth(location, kMainThreadName);
+
+  const TrackedTime kTimePosted1 = TrackedTime::FromMilliseconds(9);
+  const base::TimeTicks kDelayedStartTime1 = base::TimeTicks();
+  // TrackingInfo will call TallyABirth() during construction.
+  base::TrackingInfo pending_task1(location, kDelayedStartTime1);
+  pending_task1.time_posted = kTimePosted1;  // Overwrite implied Now().
+
+  const unsigned int kStartOfRun1 = 11;
+  const unsigned int kEndOfRun1 = 21;
+  SetTestTime(kStartOfRun1);
+  TaskStopwatch stopwatch1;
+  stopwatch1.Start();
+  SetTestTime(kEndOfRun1);
+  stopwatch1.Stop();
+
+  ThreadData::TallyRunOnNamedThreadIfTracking(pending_task1, stopwatch1);
+
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(1, &process_data);
+
+  ASSERT_EQ(2u, process_data.phased_snapshots.size());
+
+  auto it0 = process_data.phased_snapshots.find(0);
+  ASSERT_TRUE(it0 != process_data.phased_snapshots.end());
+  const ProcessDataPhaseSnapshot& process_data_phase0 = it0->second;
+
+  ASSERT_EQ(1u, process_data_phase0.tasks.size());
+
+  EXPECT_EQ(kFile, process_data_phase0.tasks[0].birth.location.file_name);
+  EXPECT_EQ(kFunction,
+            process_data_phase0.tasks[0].birth.location.function_name);
+  EXPECT_EQ(kLineNumber,
+            process_data_phase0.tasks[0].birth.location.line_number);
+
+  EXPECT_EQ(kMainThreadName, process_data_phase0.tasks[0].birth.thread_name);
+
+  EXPECT_EQ(1, process_data_phase0.tasks[0].death_data.count);
+  EXPECT_EQ(2, process_data_phase0.tasks[0].death_data.run_duration_sum);
+  EXPECT_EQ(2, process_data_phase0.tasks[0].death_data.run_duration_max);
+  EXPECT_EQ(2, process_data_phase0.tasks[0].death_data.run_duration_sample);
+  EXPECT_EQ(4, process_data_phase0.tasks[0].death_data.queue_duration_sum);
+  EXPECT_EQ(4, process_data_phase0.tasks[0].death_data.queue_duration_max);
+  EXPECT_EQ(4, process_data_phase0.tasks[0].death_data.queue_duration_sample);
+
+  EXPECT_EQ(kMainThreadName, process_data_phase0.tasks[0].death_thread_name);
+
+  auto it1 = process_data.phased_snapshots.find(1);
+  ASSERT_TRUE(it1 != process_data.phased_snapshots.end());
+  const ProcessDataPhaseSnapshot& process_data_phase1 = it1->second;
+
+  ASSERT_EQ(1u, process_data_phase1.tasks.size());
+
+  EXPECT_EQ(kFile, process_data_phase1.tasks[0].birth.location.file_name);
+  EXPECT_EQ(kFunction,
+            process_data_phase1.tasks[0].birth.location.function_name);
+  EXPECT_EQ(kLineNumber,
+            process_data_phase1.tasks[0].birth.location.line_number);
+
+  EXPECT_EQ(kMainThreadName, process_data_phase1.tasks[0].birth.thread_name);
+
+  EXPECT_EQ(1, process_data_phase1.tasks[0].death_data.count);
+  EXPECT_EQ(10, process_data_phase1.tasks[0].death_data.run_duration_sum);
+  EXPECT_EQ(10, process_data_phase1.tasks[0].death_data.run_duration_max);
+  EXPECT_EQ(10, process_data_phase1.tasks[0].death_data.run_duration_sample);
+  EXPECT_EQ(2, process_data_phase1.tasks[0].death_data.queue_duration_sum);
+  EXPECT_EQ(2, process_data_phase1.tasks[0].death_data.queue_duration_max);
+  EXPECT_EQ(2, process_data_phase1.tasks[0].death_data.queue_duration_sample);
+
+  EXPECT_EQ(kMainThreadName, process_data_phase1.tasks[0].death_thread_name);
+
+  EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
+}
+
+TEST_F(TrackedObjectsTest, ThreePhases) {
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+
+  const char kFunction[] = "ThreePhases";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+
+  // Phase 0
+  {
+    TallyABirth(location, kMainThreadName);
+
+    // TrackingInfo will call TallyABirth() during construction.
+    SetTestTime(10);
+    base::TrackingInfo pending_task(location, base::TimeTicks());
+
+    SetTestTime(17);
+    TaskStopwatch stopwatch;
+    stopwatch.Start();
+    SetTestTime(23);
+    stopwatch.Stop();
+
+    ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
+  }
+
+  ThreadData::OnProfilingPhaseCompleted(0);
+
+  // Phase 1
+  {
+    TallyABirth(location, kMainThreadName);
+
+    SetTestTime(30);
+    base::TrackingInfo pending_task(location, base::TimeTicks());
+
+    SetTestTime(35);
+    TaskStopwatch stopwatch;
+    stopwatch.Start();
+    SetTestTime(39);
+    stopwatch.Stop();
+
+    ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
+  }
+
+  ThreadData::OnProfilingPhaseCompleted(1);
+
+  // Phase 2
+  {
+    TallyABirth(location, kMainThreadName);
+
+    // TrackingInfo will call TallyABirth() during construction.
+    SetTestTime(40);
+    base::TrackingInfo pending_task(location, base::TimeTicks());
+
+    SetTestTime(43);
+    TaskStopwatch stopwatch;
+    stopwatch.Start();
+    SetTestTime(45);
+    stopwatch.Stop();
+
+    ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
+  }
+
+  // Snapshot and check results.
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(2, &process_data);
+
+  ASSERT_EQ(3u, process_data.phased_snapshots.size());
+
+  auto it0 = process_data.phased_snapshots.find(0);
+  ASSERT_TRUE(it0 != process_data.phased_snapshots.end());
+  const ProcessDataPhaseSnapshot& process_data_phase0 = it0->second;
+
+  ASSERT_EQ(1u, process_data_phase0.tasks.size());
+
+  EXPECT_EQ(kFile, process_data_phase0.tasks[0].birth.location.file_name);
+  EXPECT_EQ(kFunction,
+            process_data_phase0.tasks[0].birth.location.function_name);
+  EXPECT_EQ(kLineNumber,
+            process_data_phase0.tasks[0].birth.location.line_number);
+
+  EXPECT_EQ(kMainThreadName, process_data_phase0.tasks[0].birth.thread_name);
+
+  EXPECT_EQ(1, process_data_phase0.tasks[0].death_data.count);
+  EXPECT_EQ(6, process_data_phase0.tasks[0].death_data.run_duration_sum);
+  EXPECT_EQ(6, process_data_phase0.tasks[0].death_data.run_duration_max);
+  EXPECT_EQ(6, process_data_phase0.tasks[0].death_data.run_duration_sample);
+  EXPECT_EQ(7, process_data_phase0.tasks[0].death_data.queue_duration_sum);
+  EXPECT_EQ(7, process_data_phase0.tasks[0].death_data.queue_duration_max);
+  EXPECT_EQ(7, process_data_phase0.tasks[0].death_data.queue_duration_sample);
+
+  EXPECT_EQ(kMainThreadName, process_data_phase0.tasks[0].death_thread_name);
+
+  auto it1 = process_data.phased_snapshots.find(1);
+  ASSERT_TRUE(it1 != process_data.phased_snapshots.end());
+  const ProcessDataPhaseSnapshot& process_data_phase1 = it1->second;
+
+  ASSERT_EQ(1u, process_data_phase1.tasks.size());
+
+  EXPECT_EQ(kFile, process_data_phase1.tasks[0].birth.location.file_name);
+  EXPECT_EQ(kFunction,
+            process_data_phase1.tasks[0].birth.location.function_name);
+  EXPECT_EQ(kLineNumber,
+            process_data_phase1.tasks[0].birth.location.line_number);
+
+  EXPECT_EQ(kMainThreadName, process_data_phase1.tasks[0].birth.thread_name);
+
+  EXPECT_EQ(1, process_data_phase1.tasks[0].death_data.count);
+  EXPECT_EQ(4, process_data_phase1.tasks[0].death_data.run_duration_sum);
+  EXPECT_EQ(4, process_data_phase1.tasks[0].death_data.run_duration_max);
+  EXPECT_EQ(4, process_data_phase1.tasks[0].death_data.run_duration_sample);
+  EXPECT_EQ(5, process_data_phase1.tasks[0].death_data.queue_duration_sum);
+  EXPECT_EQ(5, process_data_phase1.tasks[0].death_data.queue_duration_max);
+  EXPECT_EQ(5, process_data_phase1.tasks[0].death_data.queue_duration_sample);
+
+  EXPECT_EQ(kMainThreadName, process_data_phase1.tasks[0].death_thread_name);
+
+  auto it2 = process_data.phased_snapshots.find(2);
+  ASSERT_TRUE(it2 != process_data.phased_snapshots.end());
+  const ProcessDataPhaseSnapshot& process_data_phase2 = it2->second;
+
+  ASSERT_EQ(1u, process_data_phase2.tasks.size());
+
+  EXPECT_EQ(kFile, process_data_phase2.tasks[0].birth.location.file_name);
+  EXPECT_EQ(kFunction,
+            process_data_phase2.tasks[0].birth.location.function_name);
+  EXPECT_EQ(kLineNumber,
+            process_data_phase2.tasks[0].birth.location.line_number);
+
+  EXPECT_EQ(kMainThreadName, process_data_phase2.tasks[0].birth.thread_name);
+
+  EXPECT_EQ(1, process_data_phase2.tasks[0].death_data.count);
+  EXPECT_EQ(2, process_data_phase2.tasks[0].death_data.run_duration_sum);
+  EXPECT_EQ(2, process_data_phase2.tasks[0].death_data.run_duration_max);
+  EXPECT_EQ(2, process_data_phase2.tasks[0].death_data.run_duration_sample);
+  EXPECT_EQ(3, process_data_phase2.tasks[0].death_data.queue_duration_sum);
+  EXPECT_EQ(3, process_data_phase2.tasks[0].death_data.queue_duration_max);
+  EXPECT_EQ(3, process_data_phase2.tasks[0].death_data.queue_duration_sample);
+
+  EXPECT_EQ(kMainThreadName, process_data_phase2.tasks[0].death_thread_name);
+
+  EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
+}
+
+TEST_F(TrackedObjectsTest, TwoPhasesSecondEmpty) {
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+
+  const char kFunction[] = "TwoPhasesSecondEmpty";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+  ThreadData::InitializeThreadContext(kMainThreadName);
+
+  const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1);
+  const base::TimeTicks kDelayedStartTime = base::TimeTicks();
+  // TrackingInfo will call TallyABirth() during construction.
+  base::TrackingInfo pending_task(location, kDelayedStartTime);
+  pending_task.time_posted = kTimePosted;  // Overwrite implied Now().
+
+  const unsigned int kStartOfRun = 5;
+  const unsigned int kEndOfRun = 7;
+  SetTestTime(kStartOfRun);
+  TaskStopwatch stopwatch;
+  stopwatch.Start();
+  SetTestTime(kEndOfRun);
+  stopwatch.Stop();
+
+  ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
+
+  ThreadData::OnProfilingPhaseCompleted(0);
+
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(1, &process_data);
+
+  ASSERT_EQ(2u, process_data.phased_snapshots.size());
+
+  auto it0 = process_data.phased_snapshots.find(0);
+  ASSERT_TRUE(it0 != process_data.phased_snapshots.end());
+  const ProcessDataPhaseSnapshot& process_data_phase0 = it0->second;
+
+  ASSERT_EQ(1u, process_data_phase0.tasks.size());
+
+  EXPECT_EQ(kFile, process_data_phase0.tasks[0].birth.location.file_name);
+  EXPECT_EQ(kFunction,
+            process_data_phase0.tasks[0].birth.location.function_name);
+  EXPECT_EQ(kLineNumber,
+            process_data_phase0.tasks[0].birth.location.line_number);
+
+  EXPECT_EQ(kMainThreadName, process_data_phase0.tasks[0].birth.thread_name);
+
+  EXPECT_EQ(1, process_data_phase0.tasks[0].death_data.count);
+  EXPECT_EQ(2, process_data_phase0.tasks[0].death_data.run_duration_sum);
+  EXPECT_EQ(2, process_data_phase0.tasks[0].death_data.run_duration_max);
+  EXPECT_EQ(2, process_data_phase0.tasks[0].death_data.run_duration_sample);
+  EXPECT_EQ(4, process_data_phase0.tasks[0].death_data.queue_duration_sum);
+  EXPECT_EQ(4, process_data_phase0.tasks[0].death_data.queue_duration_max);
+  EXPECT_EQ(4, process_data_phase0.tasks[0].death_data.queue_duration_sample);
+
+  EXPECT_EQ(kMainThreadName, process_data_phase0.tasks[0].death_thread_name);
+
+  auto it1 = process_data.phased_snapshots.find(1);
+  ASSERT_TRUE(it1 != process_data.phased_snapshots.end());
+  const ProcessDataPhaseSnapshot& process_data_phase1 = it1->second;
+
+  ASSERT_EQ(0u, process_data_phase1.tasks.size());
+
+  EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
+}
+
+TEST_F(TrackedObjectsTest, TwoPhasesFirstEmpty) {
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+
+  ThreadData::OnProfilingPhaseCompleted(0);
+
+  const char kFunction[] = "TwoPhasesSecondEmpty";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+  ThreadData::InitializeThreadContext(kMainThreadName);
+
+  const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1);
+  const base::TimeTicks kDelayedStartTime = base::TimeTicks();
+  // TrackingInfo will call TallyABirth() during construction.
+  base::TrackingInfo pending_task(location, kDelayedStartTime);
+  pending_task.time_posted = kTimePosted;  // Overwrite implied Now().
+
+  const unsigned int kStartOfRun = 5;
+  const unsigned int kEndOfRun = 7;
+  SetTestTime(kStartOfRun);
+  TaskStopwatch stopwatch;
+  stopwatch.Start();
+  SetTestTime(kEndOfRun);
+  stopwatch.Stop();
+
+  ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
+
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(1, &process_data);
+
+  ASSERT_EQ(1u, process_data.phased_snapshots.size());
+
+  auto it1 = process_data.phased_snapshots.find(1);
+  ASSERT_TRUE(it1 != process_data.phased_snapshots.end());
+  const ProcessDataPhaseSnapshot& process_data_phase1 = it1->second;
+
+  ASSERT_EQ(1u, process_data_phase1.tasks.size());
+
+  EXPECT_EQ(kFile, process_data_phase1.tasks[0].birth.location.file_name);
+  EXPECT_EQ(kFunction,
+            process_data_phase1.tasks[0].birth.location.function_name);
+  EXPECT_EQ(kLineNumber,
+            process_data_phase1.tasks[0].birth.location.line_number);
+
+  EXPECT_EQ(kMainThreadName, process_data_phase1.tasks[0].birth.thread_name);
+
+  EXPECT_EQ(1, process_data_phase1.tasks[0].death_data.count);
+  EXPECT_EQ(2, process_data_phase1.tasks[0].death_data.run_duration_sum);
+  EXPECT_EQ(2, process_data_phase1.tasks[0].death_data.run_duration_max);
+  EXPECT_EQ(2, process_data_phase1.tasks[0].death_data.run_duration_sample);
+  EXPECT_EQ(4, process_data_phase1.tasks[0].death_data.queue_duration_sum);
+  EXPECT_EQ(4, process_data_phase1.tasks[0].death_data.queue_duration_max);
+  EXPECT_EQ(4, process_data_phase1.tasks[0].death_data.queue_duration_sample);
+
+  EXPECT_EQ(kMainThreadName, process_data_phase1.tasks[0].death_thread_name);
+
+  EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
+}
+
+// We will deactivate tracking after the birth, and before the death, and
+// demonstrate that the lifecycle is completely tallied. This ensures that
+// our tallied births are matched by tallied deaths (except for when the
+// task is still running, or is queued).
+TEST_F(TrackedObjectsTest, LifeCycleMidDeactivatedToSnapshotMainThread) {
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+
+  const char kFunction[] = "LifeCycleMidDeactivatedToSnapshotMainThread";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+  TallyABirth(location, kMainThreadName);
+
+  const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1);
+  const base::TimeTicks kDelayedStartTime = base::TimeTicks();
+  // TrackingInfo will call TallyABirth() during construction.
+  base::TrackingInfo pending_task(location, kDelayedStartTime);
+  pending_task.time_posted = kTimePosted;  // Overwrite implied Now().
+
+  // Turn off tracking now that we have births.
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::DEACTIVATED);
+
+  const unsigned int kStartOfRun = 5;
+  const unsigned int kEndOfRun = 7;
+  SetTestTime(kStartOfRun);
+  TaskStopwatch stopwatch;
+  stopwatch.Start();
+  SetTestTime(kEndOfRun);
+  stopwatch.Stop();
+
+  ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
+
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(0, &process_data);
+  ExpectSimpleProcessData(process_data, kFunction, kMainThreadName,
+                          kMainThreadName, 1, 2, 4);
+}
+
+// We will deactivate tracking before starting a life cycle, and neither
+// the birth nor the death will be recorded.
+TEST_F(TrackedObjectsTest, LifeCyclePreDeactivatedToSnapshotMainThread) {
+  // Start in the deactivated state.
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::DEACTIVATED);
+
+  const char kFunction[] = "LifeCyclePreDeactivatedToSnapshotMainThread";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+  TallyABirth(location, kMainThreadName);
+
+  const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1);
+  const base::TimeTicks kDelayedStartTime = base::TimeTicks();
+  // TrackingInfo will call TallyABirth() during construction.
+  base::TrackingInfo pending_task(location, kDelayedStartTime);
+  pending_task.time_posted = kTimePosted;  // Overwrite implied Now().
+
+  const unsigned int kStartOfRun = 5;
+  const unsigned int kEndOfRun = 7;
+  SetTestTime(kStartOfRun);
+  TaskStopwatch stopwatch;
+  stopwatch.Start();
+  SetTestTime(kEndOfRun);
+  stopwatch.Stop();
+
+  ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
+
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(0, &process_data);
+
+  ASSERT_EQ(1u, process_data.phased_snapshots.size());
+
+  auto it = process_data.phased_snapshots.find(0);
+  ASSERT_TRUE(it != process_data.phased_snapshots.end());
+  const ProcessDataPhaseSnapshot& process_data_phase = it->second;
+
+  ASSERT_EQ(0u, process_data_phase.tasks.size());
+
+  EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
+}
+
+TEST_F(TrackedObjectsTest, TwoLives) {
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+
+  const char kFunction[] = "TwoLives";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+  TallyABirth(location, kMainThreadName);
+
+  const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1);
+  const base::TimeTicks kDelayedStartTime = base::TimeTicks();
+  // TrackingInfo will call TallyABirth() during construction.
+  base::TrackingInfo pending_task(location, kDelayedStartTime);
+  pending_task.time_posted = kTimePosted;  // Overwrite implied Now().
+
+  const unsigned int kStartOfRun = 5;
+  const unsigned int kEndOfRun = 7;
+  SetTestTime(kStartOfRun);
+  TaskStopwatch stopwatch;
+  stopwatch.Start();
+  SetTestTime(kEndOfRun);
+  stopwatch.Stop();
+
+  ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
+
+  // TrackingInfo will call TallyABirth() during construction.
+  base::TrackingInfo pending_task2(location, kDelayedStartTime);
+  pending_task2.time_posted = kTimePosted;  // Overwrite implied Now().
+  SetTestTime(kStartOfRun);
+  TaskStopwatch stopwatch2;
+  stopwatch2.Start();
+  SetTestTime(kEndOfRun);
+  stopwatch2.Stop();
+
+  ThreadData::TallyRunOnNamedThreadIfTracking(pending_task2, stopwatch2);
+
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(0, &process_data);
+  ExpectSimpleProcessData(process_data, kFunction, kMainThreadName,
+                          kMainThreadName, 2, 2, 4);
+}
+
+TEST_F(TrackedObjectsTest, DifferentLives) {
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+
+  // Use a well named thread.
+  ThreadData::InitializeThreadContext(kMainThreadName);
+  const char kFunction[] = "DifferentLives";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+
+  const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1);
+  const base::TimeTicks kDelayedStartTime = base::TimeTicks();
+  // TrackingInfo will call TallyABirth() during construction.
+  base::TrackingInfo pending_task(location, kDelayedStartTime);
+  pending_task.time_posted = kTimePosted;  // Overwrite implied Now().
+
+  const unsigned int kStartOfRun = 5;
+  const unsigned int kEndOfRun = 7;
+  SetTestTime(kStartOfRun);
+  TaskStopwatch stopwatch;
+  stopwatch.Start();
+  SetTestTime(kEndOfRun);
+  stopwatch.Stop();
+
+  ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, stopwatch);
+
+  const int kSecondFakeLineNumber = 999;
+  Location second_location(kFunction, kFile, kSecondFakeLineNumber, NULL);
+
+  // TrackingInfo will call TallyABirth() during construction.
+  base::TrackingInfo pending_task2(second_location, kDelayedStartTime);
+  pending_task2.time_posted = kTimePosted;  // Overwrite implied Now().
+
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(0, &process_data);
+
+  ASSERT_EQ(1u, process_data.phased_snapshots.size());
+  auto it = process_data.phased_snapshots.find(0);
+  ASSERT_TRUE(it != process_data.phased_snapshots.end());
+  const ProcessDataPhaseSnapshot& process_data_phase = it->second;
+
+  ASSERT_EQ(2u, process_data_phase.tasks.size());
+
+  EXPECT_EQ(kFile, process_data_phase.tasks[0].birth.location.file_name);
+  EXPECT_EQ(kFunction,
+            process_data_phase.tasks[0].birth.location.function_name);
+  EXPECT_EQ(kLineNumber,
+            process_data_phase.tasks[0].birth.location.line_number);
+  EXPECT_EQ(kMainThreadName, process_data_phase.tasks[0].birth.thread_name);
+  EXPECT_EQ(1, process_data_phase.tasks[0].death_data.count);
+  EXPECT_EQ(2, process_data_phase.tasks[0].death_data.run_duration_sum);
+  EXPECT_EQ(2, process_data_phase.tasks[0].death_data.run_duration_max);
+  EXPECT_EQ(2, process_data_phase.tasks[0].death_data.run_duration_sample);
+  EXPECT_EQ(4, process_data_phase.tasks[0].death_data.queue_duration_sum);
+  EXPECT_EQ(4, process_data_phase.tasks[0].death_data.queue_duration_max);
+  EXPECT_EQ(4, process_data_phase.tasks[0].death_data.queue_duration_sample);
+  EXPECT_EQ(kMainThreadName, process_data_phase.tasks[0].death_thread_name);
+  EXPECT_EQ(kFile, process_data_phase.tasks[1].birth.location.file_name);
+  EXPECT_EQ(kFunction,
+            process_data_phase.tasks[1].birth.location.function_name);
+  EXPECT_EQ(kSecondFakeLineNumber,
+            process_data_phase.tasks[1].birth.location.line_number);
+  EXPECT_EQ(kMainThreadName, process_data_phase.tasks[1].birth.thread_name);
+  EXPECT_EQ(1, process_data_phase.tasks[1].death_data.count);
+  EXPECT_EQ(0, process_data_phase.tasks[1].death_data.run_duration_sum);
+  EXPECT_EQ(0, process_data_phase.tasks[1].death_data.run_duration_max);
+  EXPECT_EQ(0, process_data_phase.tasks[1].death_data.run_duration_sample);
+  EXPECT_EQ(0, process_data_phase.tasks[1].death_data.queue_duration_sum);
+  EXPECT_EQ(0, process_data_phase.tasks[1].death_data.queue_duration_max);
+  EXPECT_EQ(0, process_data_phase.tasks[1].death_data.queue_duration_sample);
+  EXPECT_EQ(kStillAlive, process_data_phase.tasks[1].death_thread_name);
+  EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
+}
+
+TEST_F(TrackedObjectsTest, TaskWithNestedExclusion) {
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+
+  const char kFunction[] = "TaskWithNestedExclusion";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+  TallyABirth(location, kMainThreadName);
+
+  const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1);
+  const base::TimeTicks kDelayedStartTime = base::TimeTicks();
+  // TrackingInfo will call TallyABirth() during construction.
+  base::TrackingInfo pending_task(location, kDelayedStartTime);
+  pending_task.time_posted = kTimePosted;  // Overwrite implied Now().
+
+  SetTestTime(5);
+  TaskStopwatch task_stopwatch;
+  task_stopwatch.Start();
+  {
+    SetTestTime(8);
+    TaskStopwatch exclusion_stopwatch;
+    exclusion_stopwatch.Start();
+    SetTestTime(12);
+    exclusion_stopwatch.Stop();
+  }
+  SetTestTime(15);
+  task_stopwatch.Stop();
+
+  ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, task_stopwatch);
+
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(0, &process_data);
+  ExpectSimpleProcessData(process_data, kFunction, kMainThreadName,
+                          kMainThreadName, 1, 6, 4);
+}
+
+TEST_F(TrackedObjectsTest, TaskWith2NestedExclusions) {
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+
+  const char kFunction[] = "TaskWith2NestedExclusions";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+  TallyABirth(location, kMainThreadName);
+
+  const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1);
+  const base::TimeTicks kDelayedStartTime = base::TimeTicks();
+  // TrackingInfo will call TallyABirth() during construction.
+  base::TrackingInfo pending_task(location, kDelayedStartTime);
+  pending_task.time_posted = kTimePosted;  // Overwrite implied Now().
+
+  SetTestTime(5);
+  TaskStopwatch task_stopwatch;
+  task_stopwatch.Start();
+  {
+    SetTestTime(8);
+    TaskStopwatch exclusion_stopwatch;
+    exclusion_stopwatch.Start();
+    SetTestTime(12);
+    exclusion_stopwatch.Stop();
+
+    SetTestTime(15);
+    TaskStopwatch exclusion_stopwatch2;
+    exclusion_stopwatch2.Start();
+    SetTestTime(18);
+    exclusion_stopwatch2.Stop();
+  }
+  SetTestTime(25);
+  task_stopwatch.Stop();
+
+  ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, task_stopwatch);
+
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(0, &process_data);
+  ExpectSimpleProcessData(process_data, kFunction, kMainThreadName,
+                          kMainThreadName, 1, 13, 4);
+}
+
+TEST_F(TrackedObjectsTest, TaskWithNestedExclusionWithNestedTask) {
+  ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
+
+  const char kFunction[] = "TaskWithNestedExclusionWithNestedTask";
+  Location location(kFunction, kFile, kLineNumber, NULL);
+
+  const int kSecondFakeLineNumber = 999;
+
+  TallyABirth(location, kMainThreadName);
+
+  const TrackedTime kTimePosted = TrackedTime::FromMilliseconds(1);
+  const base::TimeTicks kDelayedStartTime = base::TimeTicks();
+  // TrackingInfo will call TallyABirth() during construction.
+  base::TrackingInfo pending_task(location, kDelayedStartTime);
+  pending_task.time_posted = kTimePosted;  // Overwrite implied Now().
+
+  SetTestTime(5);
+  TaskStopwatch task_stopwatch;
+  task_stopwatch.Start();
+  {
+    SetTestTime(8);
+    TaskStopwatch exclusion_stopwatch;
+    exclusion_stopwatch.Start();
+    {
+      Location second_location(kFunction, kFile, kSecondFakeLineNumber, NULL);
+      base::TrackingInfo nested_task(second_location, kDelayedStartTime);
+       // Overwrite implied Now().
+      nested_task.time_posted = TrackedTime::FromMilliseconds(8);
+      SetTestTime(9);
+      TaskStopwatch nested_task_stopwatch;
+      nested_task_stopwatch.Start();
+      SetTestTime(11);
+      nested_task_stopwatch.Stop();
+      ThreadData::TallyRunOnNamedThreadIfTracking(
+          nested_task, nested_task_stopwatch);
+    }
+    SetTestTime(12);
+    exclusion_stopwatch.Stop();
+  }
+  SetTestTime(15);
+  task_stopwatch.Stop();
+
+  ThreadData::TallyRunOnNamedThreadIfTracking(pending_task, task_stopwatch);
+
+  ProcessDataSnapshot process_data;
+  ThreadData::Snapshot(0, &process_data);
+
+  ASSERT_EQ(1u, process_data.phased_snapshots.size());
+  auto it = process_data.phased_snapshots.find(0);
+  ASSERT_TRUE(it != process_data.phased_snapshots.end());
+  const ProcessDataPhaseSnapshot& process_data_phase = it->second;
+
+  // The order in which the two task follow is platform-dependent.
+  int t0 =
+      (process_data_phase.tasks[0].birth.location.line_number == kLineNumber)
+          ? 0
+          : 1;
+  int t1 = 1 - t0;
+
+  ASSERT_EQ(2u, process_data_phase.tasks.size());
+  EXPECT_EQ(kFile, process_data_phase.tasks[t0].birth.location.file_name);
+  EXPECT_EQ(kFunction,
+            process_data_phase.tasks[t0].birth.location.function_name);
+  EXPECT_EQ(kLineNumber,
+            process_data_phase.tasks[t0].birth.location.line_number);
+  EXPECT_EQ(kMainThreadName, process_data_phase.tasks[t0].birth.thread_name);
+  EXPECT_EQ(1, process_data_phase.tasks[t0].death_data.count);
+  EXPECT_EQ(6, process_data_phase.tasks[t0].death_data.run_duration_sum);
+  EXPECT_EQ(6, process_data_phase.tasks[t0].death_data.run_duration_max);
+  EXPECT_EQ(6, process_data_phase.tasks[t0].death_data.run_duration_sample);
+  EXPECT_EQ(4, process_data_phase.tasks[t0].death_data.queue_duration_sum);
+  EXPECT_EQ(4, process_data_phase.tasks[t0].death_data.queue_duration_max);
+  EXPECT_EQ(4, process_data_phase.tasks[t0].death_data.queue_duration_sample);
+  EXPECT_EQ(kMainThreadName, process_data_phase.tasks[t0].death_thread_name);
+  EXPECT_EQ(kFile, process_data_phase.tasks[t1].birth.location.file_name);
+  EXPECT_EQ(kFunction,
+            process_data_phase.tasks[t1].birth.location.function_name);
+  EXPECT_EQ(kSecondFakeLineNumber,
+            process_data_phase.tasks[t1].birth.location.line_number);
+  EXPECT_EQ(kMainThreadName, process_data_phase.tasks[t1].birth.thread_name);
+  EXPECT_EQ(1, process_data_phase.tasks[t1].death_data.count);
+  EXPECT_EQ(2, process_data_phase.tasks[t1].death_data.run_duration_sum);
+  EXPECT_EQ(2, process_data_phase.tasks[t1].death_data.run_duration_max);
+  EXPECT_EQ(2, process_data_phase.tasks[t1].death_data.run_duration_sample);
+  EXPECT_EQ(1, process_data_phase.tasks[t1].death_data.queue_duration_sum);
+  EXPECT_EQ(1, process_data_phase.tasks[t1].death_data.queue_duration_max);
+  EXPECT_EQ(1, process_data_phase.tasks[t1].death_data.queue_duration_sample);
+  EXPECT_EQ(kMainThreadName, process_data_phase.tasks[t1].death_thread_name);
+  EXPECT_EQ(base::GetCurrentProcId(), process_data.process_id);
+}
+
+}  // namespace tracked_objects
diff --git a/base/tracking_info.cc b/base/tracking_info.cc
new file mode 100644
index 0000000..c02b2f4
--- /dev/null
+++ b/base/tracking_info.cc
@@ -0,0 +1,28 @@
+// Copyright (c) 2012 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/tracking_info.h"
+
+#include <stddef.h>
+#include "base/tracked_objects.h"
+
+namespace base {
+
+TrackingInfo::TrackingInfo()
+    : birth_tally(NULL) {
+}
+
+TrackingInfo::TrackingInfo(
+    const tracked_objects::Location& posted_from,
+    base::TimeTicks delayed_run_time)
+    : birth_tally(
+          tracked_objects::ThreadData::TallyABirthIfActive(posted_from)),
+      time_posted(tracked_objects::ThreadData::Now()),
+      delayed_run_time(delayed_run_time) {
+}
+
+TrackingInfo::~TrackingInfo() {}
+
+}  // namespace base
+
diff --git a/base/tracking_info.h b/base/tracking_info.h
new file mode 100644
index 0000000..6c3bcd1
--- /dev/null
+++ b/base/tracking_info.h
@@ -0,0 +1,58 @@
+// Copyright (c) 2012 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 is a simple struct with tracking information that is stored
+// with a PendingTask (when message_loop is handling the task).
+// Only the information that is shared with the profiler in tracked_objects
+// are included in this structure.
+
+
+#ifndef BASE_TRACKING_INFO_H_
+#define BASE_TRACKING_INFO_H_
+
+#include "base/base_export.h"
+#include "base/profiler/tracked_time.h"
+#include "base/time/time.h"
+
+namespace tracked_objects {
+class Location;
+class Births;
+}
+
+namespace base {
+
+// This structure is copied around by value.
+struct BASE_EXPORT TrackingInfo {
+  TrackingInfo();
+  TrackingInfo(const tracked_objects::Location& posted_from,
+               base::TimeTicks delayed_run_time);
+  ~TrackingInfo();
+
+  // To avoid conflating our stats with the delay duration in a PostDelayedTask,
+  // we identify such tasks, and replace their post_time with the time they
+  // were scheduled (requested?) to emerge from the delayed task queue. This
+  // means that queuing delay for such tasks will show how long they went
+  // unserviced, after they *could* be serviced.  This is the same stat as we
+  // have for non-delayed tasks, and we consistently call it queuing delay.
+  tracked_objects::TrackedTime EffectiveTimePosted() const {
+    return delayed_run_time.is_null()
+               ? time_posted
+               : tracked_objects::TrackedTime(delayed_run_time);
+  }
+
+  // Record of location and thread that the task came from.
+  tracked_objects::Births* birth_tally;
+
+  // Time when the related task was posted. Note that this value may be empty
+  // if task profiling is disabled, and should only be used in conjunction with
+  // profiling-related reporting.
+  tracked_objects::TrackedTime time_posted;
+
+  // The time when the task should be run.
+  base::TimeTicks delayed_run_time;
+};
+
+}  // namespace base
+
+#endif  // BASE_TRACKING_INFO_H_
diff --git a/base/tuple.h b/base/tuple.h
new file mode 100644
index 0000000..ef51d85
--- /dev/null
+++ b/base/tuple.h
@@ -0,0 +1,336 @@
+// Copyright (c) 2011 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.
+
+// A Tuple is a generic templatized container, similar in concept to std::pair
+// and std::tuple.  The convenient MakeTuple() function takes any number of
+// arguments and will construct and return the appropriate Tuple object.  The
+// functions DispatchToMethod and DispatchToFunction take a function pointer or
+// instance and method pointer, and unpack a tuple into arguments to the call.
+//
+// Tuple elements are copied by value, and stored in the tuple.  See the unit
+// tests for more details of how/when the values are copied.
+//
+// Example usage:
+//   // These two methods of creating a Tuple are identical.
+//   Tuple<int, const char*> tuple_a(1, "wee");
+//   Tuple<int, const char*> tuple_b = MakeTuple(1, "wee");
+//
+//   void SomeFunc(int a, const char* b) { }
+//   DispatchToFunction(&SomeFunc, tuple_a);  // SomeFunc(1, "wee")
+//   DispatchToFunction(
+//       &SomeFunc, MakeTuple(10, "foo"));    // SomeFunc(10, "foo")
+//
+//   struct { void SomeMeth(int a, int b, int c) { } } foo;
+//   DispatchToMethod(&foo, &Foo::SomeMeth, MakeTuple(1, 2, 3));
+//   // foo->SomeMeth(1, 2, 3);
+
+#ifndef BASE_TUPLE_H_
+#define BASE_TUPLE_H_
+
+#include "base/bind_helpers.h"
+
+namespace base {
+
+// Index sequences
+//
+// Minimal clone of the similarly-named C++14 functionality.
+
+template <size_t...>
+struct IndexSequence {};
+
+template <size_t... Ns>
+struct MakeIndexSequenceImpl;
+
+#if defined(_PREFAST_) && defined(OS_WIN)
+
+// Work around VC++ 2013 /analyze internal compiler error:
+// https://connect.microsoft.com/VisualStudio/feedback/details/1053626
+
+template <> struct MakeIndexSequenceImpl<0> {
+  using Type = IndexSequence<>;
+};
+template <> struct MakeIndexSequenceImpl<1> {
+  using Type = IndexSequence<0>;
+};
+template <> struct MakeIndexSequenceImpl<2> {
+  using Type = IndexSequence<0,1>;
+};
+template <> struct MakeIndexSequenceImpl<3> {
+  using Type = IndexSequence<0,1,2>;
+};
+template <> struct MakeIndexSequenceImpl<4> {
+  using Type = IndexSequence<0,1,2,3>;
+};
+template <> struct MakeIndexSequenceImpl<5> {
+  using Type = IndexSequence<0,1,2,3,4>;
+};
+template <> struct MakeIndexSequenceImpl<6> {
+  using Type = IndexSequence<0,1,2,3,4,5>;
+};
+template <> struct MakeIndexSequenceImpl<7> {
+  using Type = IndexSequence<0,1,2,3,4,5,6>;
+};
+template <> struct MakeIndexSequenceImpl<8> {
+  using Type = IndexSequence<0,1,2,3,4,5,6,7>;
+};
+template <> struct MakeIndexSequenceImpl<9> {
+  using Type = IndexSequence<0,1,2,3,4,5,6,7,8>;
+};
+template <> struct MakeIndexSequenceImpl<10> {
+  using Type = IndexSequence<0,1,2,3,4,5,6,7,8,9>;
+};
+template <> struct MakeIndexSequenceImpl<11> {
+  using Type = IndexSequence<0,1,2,3,4,5,6,7,8,9,10>;
+};
+template <> struct MakeIndexSequenceImpl<12> {
+  using Type = IndexSequence<0,1,2,3,4,5,6,7,8,9,10,11>;
+};
+template <> struct MakeIndexSequenceImpl<13> {
+  using Type = IndexSequence<0,1,2,3,4,5,6,7,8,9,10,11,12>;
+};
+
+#else  // defined(WIN) && defined(_PREFAST_)
+
+template <size_t... Ns>
+struct MakeIndexSequenceImpl<0, Ns...> {
+  using Type = IndexSequence<Ns...>;
+};
+
+template <size_t N, size_t... Ns>
+struct MakeIndexSequenceImpl<N, Ns...>
+    : MakeIndexSequenceImpl<N - 1, N - 1, Ns...> {};
+
+#endif  // defined(WIN) && defined(_PREFAST_)
+
+template <size_t N>
+using MakeIndexSequence = typename MakeIndexSequenceImpl<N>::Type;
+
+// Traits ----------------------------------------------------------------------
+//
+// A simple traits class for tuple arguments.
+//
+// ValueType: the bare, nonref version of a type (same as the type for nonrefs).
+// RefType: the ref version of a type (same as the type for refs).
+// ParamType: what type to pass to functions (refs should not be constified).
+
+template <class P>
+struct TupleTraits {
+  typedef P ValueType;
+  typedef P& RefType;
+  typedef const P& ParamType;
+};
+
+template <class P>
+struct TupleTraits<P&> {
+  typedef P ValueType;
+  typedef P& RefType;
+  typedef P& ParamType;
+};
+
+// Tuple -----------------------------------------------------------------------
+//
+// This set of classes is useful for bundling 0 or more heterogeneous data types
+// into a single variable.  The advantage of this is that it greatly simplifies
+// function objects that need to take an arbitrary number of parameters; see
+// RunnableMethod and IPC::MessageWithTuple.
+//
+// Tuple<> is supplied to act as a 'void' type.  It can be used, for example,
+// when dispatching to a function that accepts no arguments (see the
+// Dispatchers below).
+// Tuple<A> is rarely useful.  One such use is when A is non-const ref that you
+// want filled by the dispatchee, and the tuple is merely a container for that
+// output (a "tier").  See MakeRefTuple and its usages.
+
+template <typename IxSeq, typename... Ts>
+struct TupleBaseImpl;
+template <typename... Ts>
+using TupleBase = TupleBaseImpl<MakeIndexSequence<sizeof...(Ts)>, Ts...>;
+template <size_t N, typename T>
+struct TupleLeaf;
+
+template <typename... Ts>
+struct Tuple : TupleBase<Ts...> {
+  Tuple() : TupleBase<Ts...>() {}
+  explicit Tuple(typename TupleTraits<Ts>::ParamType... args)
+      : TupleBase<Ts...>(args...) {}
+};
+
+// Avoids ambiguity between Tuple's two constructors.
+template <>
+struct Tuple<> {};
+
+template <size_t... Ns, typename... Ts>
+struct TupleBaseImpl<IndexSequence<Ns...>, Ts...> : TupleLeaf<Ns, Ts>... {
+  TupleBaseImpl() : TupleLeaf<Ns, Ts>()... {}
+  explicit TupleBaseImpl(typename TupleTraits<Ts>::ParamType... args)
+      : TupleLeaf<Ns, Ts>(args)... {}
+};
+
+template <size_t N, typename T>
+struct TupleLeaf {
+  TupleLeaf() {}
+  explicit TupleLeaf(typename TupleTraits<T>::ParamType x) : x(x) {}
+
+  T& get() { return x; }
+  const T& get() const { return x; }
+
+  T x;
+};
+
+// Tuple getters --------------------------------------------------------------
+//
+// Allows accessing an arbitrary tuple element by index.
+//
+// Example usage:
+//   base::Tuple<int, double> t2;
+//   base::get<0>(t2) = 42;
+//   base::get<1>(t2) = 3.14;
+
+template <size_t I, typename T>
+T& get(TupleLeaf<I, T>& leaf) {
+  return leaf.get();
+}
+
+template <size_t I, typename T>
+const T& get(const TupleLeaf<I, T>& leaf) {
+  return leaf.get();
+}
+
+// Tuple types ----------------------------------------------------------------
+//
+// Allows for selection of ValueTuple/RefTuple/ParamTuple without needing the
+// definitions of class types the tuple takes as parameters.
+
+template <typename T>
+struct TupleTypes;
+
+template <typename... Ts>
+struct TupleTypes<Tuple<Ts...>> {
+  using ValueTuple = Tuple<typename TupleTraits<Ts>::ValueType...>;
+  using RefTuple = Tuple<typename TupleTraits<Ts>::RefType...>;
+  using ParamTuple = Tuple<typename TupleTraits<Ts>::ParamType...>;
+};
+
+// Tuple creators -------------------------------------------------------------
+//
+// Helper functions for constructing tuples while inferring the template
+// argument types.
+
+template <typename... Ts>
+inline Tuple<Ts...> MakeTuple(const Ts&... arg) {
+  return Tuple<Ts...>(arg...);
+}
+
+// The following set of helpers make what Boost refers to as "Tiers" - a tuple
+// of references.
+
+template <typename... Ts>
+inline Tuple<Ts&...> MakeRefTuple(Ts&... arg) {
+  return Tuple<Ts&...>(arg...);
+}
+
+// Dispatchers ----------------------------------------------------------------
+//
+// Helper functions that call the given method on an object, with the unpacked
+// tuple arguments.  Notice that they all have the same number of arguments,
+// so you need only write:
+//   DispatchToMethod(object, &Object::method, args);
+// This is very useful for templated dispatchers, since they don't need to know
+// what type |args| is.
+
+// Non-Static Dispatchers with no out params.
+
+template <typename ObjT, typename Method, typename A>
+inline void DispatchToMethod(ObjT* obj, Method method, const A& arg) {
+  (obj->*method)(base::internal::UnwrapTraits<A>::Unwrap(arg));
+}
+
+template <typename ObjT, typename Method, typename... Ts, size_t... Ns>
+inline void DispatchToMethodImpl(ObjT* obj,
+                                 Method method,
+                                 const Tuple<Ts...>& arg,
+                                 IndexSequence<Ns...>) {
+  (obj->*method)(base::internal::UnwrapTraits<Ts>::Unwrap(get<Ns>(arg))...);
+}
+
+template <typename ObjT, typename Method, typename... Ts>
+inline void DispatchToMethod(ObjT* obj,
+                             Method method,
+                             const Tuple<Ts...>& arg) {
+  DispatchToMethodImpl(obj, method, arg, MakeIndexSequence<sizeof...(Ts)>());
+}
+
+// Static Dispatchers with no out params.
+
+template <typename Function, typename A>
+inline void DispatchToMethod(Function function, const A& arg) {
+  (*function)(base::internal::UnwrapTraits<A>::Unwrap(arg));
+}
+
+template <typename Function, typename... Ts, size_t... Ns>
+inline void DispatchToFunctionImpl(Function function,
+                                   const Tuple<Ts...>& arg,
+                                   IndexSequence<Ns...>) {
+  (*function)(base::internal::UnwrapTraits<Ts>::Unwrap(get<Ns>(arg))...);
+}
+
+template <typename Function, typename... Ts>
+inline void DispatchToFunction(Function function, const Tuple<Ts...>& arg) {
+  DispatchToFunctionImpl(function, arg, MakeIndexSequence<sizeof...(Ts)>());
+}
+
+// Dispatchers with out parameters.
+
+template <typename ObjT,
+          typename Method,
+          typename In,
+          typename... OutTs,
+          size_t... OutNs>
+inline void DispatchToMethodImpl(ObjT* obj,
+                                 Method method,
+                                 const In& in,
+                                 Tuple<OutTs...>* out,
+                                 IndexSequence<OutNs...>) {
+  (obj->*method)(base::internal::UnwrapTraits<In>::Unwrap(in),
+                 &get<OutNs>(*out)...);
+}
+
+template <typename ObjT, typename Method, typename In, typename... OutTs>
+inline void DispatchToMethod(ObjT* obj,
+                             Method method,
+                             const In& in,
+                             Tuple<OutTs...>* out) {
+  DispatchToMethodImpl(obj, method, in, out,
+                       MakeIndexSequence<sizeof...(OutTs)>());
+}
+
+template <typename ObjT,
+          typename Method,
+          typename... InTs,
+          typename... OutTs,
+          size_t... InNs,
+          size_t... OutNs>
+inline void DispatchToMethodImpl(ObjT* obj,
+                                 Method method,
+                                 const Tuple<InTs...>& in,
+                                 Tuple<OutTs...>* out,
+                                 IndexSequence<InNs...>,
+                                 IndexSequence<OutNs...>) {
+  (obj->*method)(base::internal::UnwrapTraits<InTs>::Unwrap(get<InNs>(in))...,
+                 &get<OutNs>(*out)...);
+}
+
+template <typename ObjT, typename Method, typename... InTs, typename... OutTs>
+inline void DispatchToMethod(ObjT* obj,
+                             Method method,
+                             const Tuple<InTs...>& in,
+                             Tuple<OutTs...>* out) {
+  DispatchToMethodImpl(obj, method, in, out,
+                       MakeIndexSequence<sizeof...(InTs)>(),
+                       MakeIndexSequence<sizeof...(OutTs)>());
+}
+
+}  // namespace base
+
+#endif  // BASE_TUPLE_H_
diff --git a/base/tuple_unittest.cc b/base/tuple_unittest.cc
new file mode 100644
index 0000000..55a9139
--- /dev/null
+++ b/base/tuple_unittest.cc
@@ -0,0 +1,134 @@
+// Copyright (c) 2006-2008 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/tuple.h"
+
+#include "base/compiler_specific.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+void DoAdd(int a, int b, int c, int* res) {
+  *res = a + b + c;
+}
+
+struct Addy {
+  Addy() { }
+  void DoAdd(int a, int b, int c, int d, int* res) {
+    *res = a + b + c + d;
+  }
+};
+
+struct Addz {
+  Addz() { }
+  void DoAdd(int a, int b, int c, int d, int e, int* res) {
+    *res = a + b + c + d + e;
+  }
+};
+
+}  // namespace
+
+TEST(TupleTest, Basic) {
+  base::Tuple<> t0 = base::MakeTuple();
+  ALLOW_UNUSED_LOCAL(t0);
+  base::Tuple<int> t1(1);
+  base::Tuple<int, const char*> t2 =
+      base::MakeTuple(1, static_cast<const char*>("wee"));
+  base::Tuple<int, int, int> t3(1, 2, 3);
+  base::Tuple<int, int, int, int*> t4(1, 2, 3, &get<0>(t1));
+  base::Tuple<int, int, int, int, int*> t5(1, 2, 3, 4, &get<0>(t4));
+  base::Tuple<int, int, int, int, int, int*> t6(1, 2, 3, 4, 5, &get<0>(t4));
+
+  EXPECT_EQ(1, get<0>(t1));
+  EXPECT_EQ(1, get<0>(t2));
+  EXPECT_EQ(1, get<0>(t3));
+  EXPECT_EQ(2, get<1>(t3));
+  EXPECT_EQ(3, get<2>(t3));
+  EXPECT_EQ(1, get<0>(t4));
+  EXPECT_EQ(2, get<1>(t4));
+  EXPECT_EQ(3, get<2>(t4));
+  EXPECT_EQ(1, get<0>(t5));
+  EXPECT_EQ(2, get<1>(t5));
+  EXPECT_EQ(3, get<2>(t5));
+  EXPECT_EQ(4, get<3>(t5));
+  EXPECT_EQ(1, get<0>(t6));
+  EXPECT_EQ(2, get<1>(t6));
+  EXPECT_EQ(3, get<2>(t6));
+  EXPECT_EQ(4, get<3>(t6));
+  EXPECT_EQ(5, get<4>(t6));
+
+  EXPECT_EQ(1, get<0>(t1));
+  DispatchToFunction(&DoAdd, t4);
+  EXPECT_EQ(6, get<0>(t1));
+
+  int res = 0;
+  DispatchToFunction(&DoAdd, base::MakeTuple(9, 8, 7, &res));
+  EXPECT_EQ(24, res);
+
+  Addy addy;
+  EXPECT_EQ(1, get<0>(t4));
+  DispatchToMethod(&addy, &Addy::DoAdd, t5);
+  EXPECT_EQ(10, get<0>(t4));
+
+  Addz addz;
+  EXPECT_EQ(10, get<0>(t4));
+  DispatchToMethod(&addz, &Addz::DoAdd, t6);
+  EXPECT_EQ(15, get<0>(t4));
+}
+
+namespace {
+
+struct CopyLogger {
+  CopyLogger() { ++TimesConstructed; }
+  CopyLogger(const CopyLogger& tocopy) { ++TimesConstructed; ++TimesCopied; }
+  ~CopyLogger() { }
+
+  static int TimesCopied;
+  static int TimesConstructed;
+};
+
+void SomeLoggerMethRef(const CopyLogger& logy, const CopyLogger* ptr, bool* b) {
+  *b = &logy == ptr;
+}
+
+void SomeLoggerMethCopy(CopyLogger logy, const CopyLogger* ptr, bool* b) {
+  *b = &logy == ptr;
+}
+
+int CopyLogger::TimesCopied = 0;
+int CopyLogger::TimesConstructed = 0;
+
+}  // namespace
+
+TEST(TupleTest, Copying) {
+  CopyLogger logger;
+  EXPECT_EQ(0, CopyLogger::TimesCopied);
+  EXPECT_EQ(1, CopyLogger::TimesConstructed);
+
+  bool res = false;
+
+  // Creating the tuple should copy the class to store internally in the tuple.
+  base::Tuple<CopyLogger, CopyLogger*, bool*> tuple(logger, &logger, &res);
+  get<1>(tuple) = &get<0>(tuple);
+  EXPECT_EQ(2, CopyLogger::TimesConstructed);
+  EXPECT_EQ(1, CopyLogger::TimesCopied);
+
+  // Our internal Logger and the one passed to the function should be the same.
+  res = false;
+  DispatchToFunction(&SomeLoggerMethRef, tuple);
+  EXPECT_TRUE(res);
+  EXPECT_EQ(2, CopyLogger::TimesConstructed);
+  EXPECT_EQ(1, CopyLogger::TimesCopied);
+
+  // Now they should be different, since the function call will make a copy.
+  res = false;
+  DispatchToFunction(&SomeLoggerMethCopy, tuple);
+  EXPECT_FALSE(res);
+  EXPECT_EQ(3, CopyLogger::TimesConstructed);
+  EXPECT_EQ(2, CopyLogger::TimesCopied);
+}
+
+}  // namespace base
diff --git a/base/value_conversions.cc b/base/value_conversions.cc
new file mode 100644
index 0000000..45cd619
--- /dev/null
+++ b/base/value_conversions.cc
@@ -0,0 +1,49 @@
+// Copyright (c) 2012 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/value_conversions.h"
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/files/file_path.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/time/time.h"
+#include "base/values.h"
+
+namespace base {
+
+// |Value| internally stores strings in UTF-8, so we have to convert from the
+// system native code to UTF-8 and back.
+StringValue* CreateFilePathValue(const FilePath& in_value) {
+  return new StringValue(in_value.AsUTF8Unsafe());
+}
+
+bool GetValueAsFilePath(const Value& value, FilePath* file_path) {
+  std::string str;
+  if (!value.GetAsString(&str))
+    return false;
+  if (file_path)
+    *file_path = FilePath::FromUTF8Unsafe(str);
+  return true;
+}
+
+// |Value| does not support 64-bit integers, and doubles do not have enough
+// precision, so we store the 64-bit time value as a string instead.
+StringValue* CreateTimeDeltaValue(const TimeDelta& time) {
+  std::string string_value = base::Int64ToString(time.ToInternalValue());
+  return new StringValue(string_value);
+}
+
+bool GetValueAsTimeDelta(const Value& value, TimeDelta* time) {
+  std::string str;
+  int64 int_value;
+  if (!value.GetAsString(&str) || !base::StringToInt64(str, &int_value))
+    return false;
+  if (time)
+    *time = TimeDelta::FromInternalValue(int_value);
+  return true;
+}
+
+}  // namespace base
diff --git a/base/value_conversions.h b/base/value_conversions.h
new file mode 100644
index 0000000..452c587
--- /dev/null
+++ b/base/value_conversions.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2012 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_VALUE_CONVERSIONS_H_
+#define BASE_VALUE_CONVERSIONS_H_
+
+// This file contains methods to convert things to a |Value| and back.
+
+#include "base/base_export.h"
+
+
+namespace base {
+
+class FilePath;
+class TimeDelta;
+class StringValue;
+class Value;
+
+// The caller takes ownership of the returned value.
+BASE_EXPORT StringValue* CreateFilePathValue(const FilePath& in_value);
+BASE_EXPORT bool GetValueAsFilePath(const Value& value, FilePath* file_path);
+
+BASE_EXPORT StringValue* CreateTimeDeltaValue(const TimeDelta& time);
+BASE_EXPORT bool GetValueAsTimeDelta(const Value& value, TimeDelta* time);
+
+}  // namespace base
+
+#endif  // BASE_VALUE_CONVERSIONS_H_
diff --git a/base/values.cc b/base/values.cc
new file mode 100644
index 0000000..4534d27
--- /dev/null
+++ b/base/values.cc
@@ -0,0 +1,1181 @@
+// Copyright (c) 2012 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/values.h"
+
+#include <string.h>
+
+#include <algorithm>
+#include <cmath>
+#include <ostream>
+
+#include "base/json/json_writer.h"
+#include "base/logging.h"
+#include "base/move.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+
+namespace base {
+
+namespace {
+
+scoped_ptr<Value> CopyWithoutEmptyChildren(const Value& node);
+
+// Make a deep copy of |node|, but don't include empty lists or dictionaries
+// in the copy. It's possible for this function to return NULL and it
+// expects |node| to always be non-NULL.
+scoped_ptr<ListValue> CopyListWithoutEmptyChildren(const ListValue& list) {
+  scoped_ptr<ListValue> copy;
+  for (ListValue::const_iterator it = list.begin(); it != list.end(); ++it) {
+    scoped_ptr<Value> child_copy = CopyWithoutEmptyChildren(**it);
+    if (child_copy) {
+      if (!copy)
+        copy.reset(new ListValue);
+      copy->Append(child_copy.Pass());
+    }
+  }
+  return copy;
+}
+
+scoped_ptr<DictionaryValue> CopyDictionaryWithoutEmptyChildren(
+    const DictionaryValue& dict) {
+  scoped_ptr<DictionaryValue> copy;
+  for (DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) {
+    scoped_ptr<Value> child_copy = CopyWithoutEmptyChildren(it.value());
+    if (child_copy) {
+      if (!copy)
+        copy.reset(new DictionaryValue);
+      copy->SetWithoutPathExpansion(it.key(), child_copy.Pass());
+    }
+  }
+  return copy;
+}
+
+scoped_ptr<Value> CopyWithoutEmptyChildren(const Value& node) {
+  switch (node.GetType()) {
+    case Value::TYPE_LIST:
+      return CopyListWithoutEmptyChildren(static_cast<const ListValue&>(node));
+
+    case Value::TYPE_DICTIONARY:
+      return CopyDictionaryWithoutEmptyChildren(
+          static_cast<const DictionaryValue&>(node));
+
+    default:
+      return node.CreateDeepCopy();
+  }
+}
+
+// A small functor for comparing Values for std::find_if and similar.
+class ValueEquals {
+ public:
+  // Pass the value against which all consecutive calls of the () operator will
+  // compare their argument to. This Value object must not be destroyed while
+  // the ValueEquals is  in use.
+  explicit ValueEquals(const Value* first) : first_(first) { }
+
+  bool operator ()(const Value* second) const {
+    return first_->Equals(second);
+  }
+
+ private:
+  const Value* first_;
+};
+
+}  // namespace
+
+Value::~Value() {
+}
+
+// static
+scoped_ptr<Value> Value::CreateNullValue() {
+  return make_scoped_ptr(new Value(TYPE_NULL));
+}
+
+bool Value::GetAsBinary(const BinaryValue** out_value) const {
+  return false;
+}
+
+bool Value::GetAsBoolean(bool* out_value) const {
+  return false;
+}
+
+bool Value::GetAsInteger(int* out_value) const {
+  return false;
+}
+
+bool Value::GetAsDouble(double* out_value) const {
+  return false;
+}
+
+bool Value::GetAsString(std::string* out_value) const {
+  return false;
+}
+
+bool Value::GetAsString(string16* out_value) const {
+  return false;
+}
+
+bool Value::GetAsString(const StringValue** out_value) const {
+  return false;
+}
+
+bool Value::GetAsList(ListValue** out_value) {
+  return false;
+}
+
+bool Value::GetAsList(const ListValue** out_value) const {
+  return false;
+}
+
+bool Value::GetAsDictionary(DictionaryValue** out_value) {
+  return false;
+}
+
+bool Value::GetAsDictionary(const DictionaryValue** out_value) const {
+  return false;
+}
+
+Value* Value::DeepCopy() const {
+  // This method should only be getting called for null Values--all subclasses
+  // need to provide their own implementation;.
+  DCHECK(IsType(TYPE_NULL));
+  return CreateNullValue().release();
+}
+
+scoped_ptr<Value> Value::CreateDeepCopy() const {
+  return make_scoped_ptr(DeepCopy());
+}
+
+bool Value::Equals(const Value* other) const {
+  // This method should only be getting called for null Values--all subclasses
+  // need to provide their own implementation;.
+  DCHECK(IsType(TYPE_NULL));
+  return other->IsType(TYPE_NULL);
+}
+
+// static
+bool Value::Equals(const Value* a, const Value* b) {
+  if ((a == NULL) && (b == NULL)) return true;
+  if ((a == NULL) ^  (b == NULL)) return false;
+  return a->Equals(b);
+}
+
+Value::Value(Type type) : type_(type) {}
+
+Value::Value(const Value& that) : type_(that.type_) {}
+
+Value& Value::operator=(const Value& that) {
+  type_ = that.type_;
+  return *this;
+}
+
+///////////////////// FundamentalValue ////////////////////
+
+FundamentalValue::FundamentalValue(bool in_value)
+    : Value(TYPE_BOOLEAN), boolean_value_(in_value) {
+}
+
+FundamentalValue::FundamentalValue(int in_value)
+    : Value(TYPE_INTEGER), integer_value_(in_value) {
+}
+
+FundamentalValue::FundamentalValue(double in_value)
+    : Value(TYPE_DOUBLE), double_value_(in_value) {
+  if (!std::isfinite(double_value_)) {
+    NOTREACHED() << "Non-finite (i.e. NaN or positive/negative infinity) "
+                 << "values cannot be represented in JSON";
+    double_value_ = 0.0;
+  }
+}
+
+FundamentalValue::~FundamentalValue() {
+}
+
+bool FundamentalValue::GetAsBoolean(bool* out_value) const {
+  if (out_value && IsType(TYPE_BOOLEAN))
+    *out_value = boolean_value_;
+  return (IsType(TYPE_BOOLEAN));
+}
+
+bool FundamentalValue::GetAsInteger(int* out_value) const {
+  if (out_value && IsType(TYPE_INTEGER))
+    *out_value = integer_value_;
+  return (IsType(TYPE_INTEGER));
+}
+
+bool FundamentalValue::GetAsDouble(double* out_value) const {
+  if (out_value && IsType(TYPE_DOUBLE))
+    *out_value = double_value_;
+  else if (out_value && IsType(TYPE_INTEGER))
+    *out_value = integer_value_;
+  return (IsType(TYPE_DOUBLE) || IsType(TYPE_INTEGER));
+}
+
+FundamentalValue* FundamentalValue::DeepCopy() const {
+  switch (GetType()) {
+    case TYPE_BOOLEAN:
+      return new FundamentalValue(boolean_value_);
+
+    case TYPE_INTEGER:
+      return new FundamentalValue(integer_value_);
+
+    case TYPE_DOUBLE:
+      return new FundamentalValue(double_value_);
+
+    default:
+      NOTREACHED();
+      return NULL;
+  }
+}
+
+bool FundamentalValue::Equals(const Value* other) const {
+  if (other->GetType() != GetType())
+    return false;
+
+  switch (GetType()) {
+    case TYPE_BOOLEAN: {
+      bool lhs, rhs;
+      return GetAsBoolean(&lhs) && other->GetAsBoolean(&rhs) && lhs == rhs;
+    }
+    case TYPE_INTEGER: {
+      int lhs, rhs;
+      return GetAsInteger(&lhs) && other->GetAsInteger(&rhs) && lhs == rhs;
+    }
+    case TYPE_DOUBLE: {
+      double lhs, rhs;
+      return GetAsDouble(&lhs) && other->GetAsDouble(&rhs) && lhs == rhs;
+    }
+    default:
+      NOTREACHED();
+      return false;
+  }
+}
+
+///////////////////// StringValue ////////////////////
+
+StringValue::StringValue(const std::string& in_value)
+    : Value(TYPE_STRING),
+      value_(in_value) {
+  DCHECK(IsStringUTF8(in_value));
+}
+
+StringValue::StringValue(const string16& in_value)
+    : Value(TYPE_STRING),
+      value_(UTF16ToUTF8(in_value)) {
+}
+
+StringValue::~StringValue() {
+}
+
+std::string* StringValue::GetString() {
+  return &value_;
+}
+
+const std::string& StringValue::GetString() const {
+  return value_;
+}
+
+bool StringValue::GetAsString(std::string* out_value) const {
+  if (out_value)
+    *out_value = value_;
+  return true;
+}
+
+bool StringValue::GetAsString(string16* out_value) const {
+  if (out_value)
+    *out_value = UTF8ToUTF16(value_);
+  return true;
+}
+
+bool StringValue::GetAsString(const StringValue** out_value) const {
+  if (out_value)
+    *out_value = this;
+  return true;
+}
+
+StringValue* StringValue::DeepCopy() const {
+  return new StringValue(value_);
+}
+
+bool StringValue::Equals(const Value* other) const {
+  if (other->GetType() != GetType())
+    return false;
+  std::string lhs, rhs;
+  return GetAsString(&lhs) && other->GetAsString(&rhs) && lhs == rhs;
+}
+
+///////////////////// BinaryValue ////////////////////
+
+BinaryValue::BinaryValue()
+    : Value(TYPE_BINARY),
+      size_(0) {
+}
+
+BinaryValue::BinaryValue(scoped_ptr<char[]> buffer, size_t size)
+    : Value(TYPE_BINARY),
+      buffer_(buffer.Pass()),
+      size_(size) {
+}
+
+BinaryValue::~BinaryValue() {
+}
+
+// static
+BinaryValue* BinaryValue::CreateWithCopiedBuffer(const char* buffer,
+                                                 size_t size) {
+  char* buffer_copy = new char[size];
+  memcpy(buffer_copy, buffer, size);
+  scoped_ptr<char[]> scoped_buffer_copy(buffer_copy);
+  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_);
+}
+
+bool BinaryValue::Equals(const Value* other) const {
+  if (other->GetType() != GetType())
+    return false;
+  const BinaryValue* other_binary = static_cast<const BinaryValue*>(other);
+  if (other_binary->size_ != size_)
+    return false;
+  return !memcmp(GetBuffer(), other_binary->GetBuffer(), size_);
+}
+
+///////////////////// DictionaryValue ////////////////////
+
+DictionaryValue::DictionaryValue()
+    : Value(TYPE_DICTIONARY) {
+}
+
+DictionaryValue::~DictionaryValue() {
+  Clear();
+}
+
+bool DictionaryValue::GetAsDictionary(DictionaryValue** out_value) {
+  if (out_value)
+    *out_value = this;
+  return true;
+}
+
+bool DictionaryValue::GetAsDictionary(const DictionaryValue** out_value) const {
+  if (out_value)
+    *out_value = this;
+  return true;
+}
+
+bool DictionaryValue::HasKey(const std::string& key) const {
+  DCHECK(IsStringUTF8(key));
+  ValueMap::const_iterator current_entry = dictionary_.find(key);
+  DCHECK((current_entry == dictionary_.end()) || current_entry->second);
+  return current_entry != dictionary_.end();
+}
+
+void DictionaryValue::Clear() {
+  ValueMap::iterator dict_iterator = dictionary_.begin();
+  while (dict_iterator != dictionary_.end()) {
+    delete dict_iterator->second;
+    ++dict_iterator;
+  }
+
+  dictionary_.clear();
+}
+
+void DictionaryValue::Set(const std::string& path, scoped_ptr<Value> in_value) {
+  DCHECK(IsStringUTF8(path));
+  DCHECK(in_value);
+
+  std::string current_path(path);
+  DictionaryValue* current_dictionary = this;
+  for (size_t delimiter_position = current_path.find('.');
+       delimiter_position != std::string::npos;
+       delimiter_position = current_path.find('.')) {
+    // Assume that we're indexing into a dictionary.
+    std::string key(current_path, 0, delimiter_position);
+    DictionaryValue* child_dictionary = NULL;
+    if (!current_dictionary->GetDictionary(key, &child_dictionary)) {
+      child_dictionary = new DictionaryValue;
+      current_dictionary->SetWithoutPathExpansion(key, child_dictionary);
+    }
+
+    current_dictionary = child_dictionary;
+    current_path.erase(0, delimiter_position + 1);
+  }
+
+  current_dictionary->SetWithoutPathExpansion(current_path, in_value.Pass());
+}
+
+void DictionaryValue::Set(const std::string& path, Value* in_value) {
+  Set(path, make_scoped_ptr(in_value));
+}
+
+void DictionaryValue::SetBoolean(const std::string& path, bool in_value) {
+  Set(path, new FundamentalValue(in_value));
+}
+
+void DictionaryValue::SetInteger(const std::string& path, int in_value) {
+  Set(path, new FundamentalValue(in_value));
+}
+
+void DictionaryValue::SetDouble(const std::string& path, double in_value) {
+  Set(path, new FundamentalValue(in_value));
+}
+
+void DictionaryValue::SetString(const std::string& path,
+                                const std::string& in_value) {
+  Set(path, new StringValue(in_value));
+}
+
+void DictionaryValue::SetString(const std::string& path,
+                                const string16& in_value) {
+  Set(path, new StringValue(in_value));
+}
+
+void DictionaryValue::SetWithoutPathExpansion(const std::string& key,
+                                              scoped_ptr<Value> in_value) {
+  Value* bare_ptr = in_value.release();
+  // If there's an existing value here, we need to delete it, because
+  // we own all our children.
+  std::pair<ValueMap::iterator, bool> ins_res =
+      dictionary_.insert(std::make_pair(key, bare_ptr));
+  if (!ins_res.second) {
+    DCHECK_NE(ins_res.first->second, bare_ptr);  // This would be bogus
+    delete ins_res.first->second;
+    ins_res.first->second = bare_ptr;
+  }
+}
+
+void DictionaryValue::SetWithoutPathExpansion(const std::string& key,
+                                              Value* in_value) {
+  SetWithoutPathExpansion(key, make_scoped_ptr(in_value));
+}
+
+void DictionaryValue::SetBooleanWithoutPathExpansion(
+    const std::string& path, bool in_value) {
+  SetWithoutPathExpansion(path, new FundamentalValue(in_value));
+}
+
+void DictionaryValue::SetIntegerWithoutPathExpansion(
+    const std::string& path, int in_value) {
+  SetWithoutPathExpansion(path, new FundamentalValue(in_value));
+}
+
+void DictionaryValue::SetDoubleWithoutPathExpansion(
+    const std::string& path, double in_value) {
+  SetWithoutPathExpansion(path, new FundamentalValue(in_value));
+}
+
+void DictionaryValue::SetStringWithoutPathExpansion(
+    const std::string& path, const std::string& in_value) {
+  SetWithoutPathExpansion(path, new StringValue(in_value));
+}
+
+void DictionaryValue::SetStringWithoutPathExpansion(
+    const std::string& path, const string16& in_value) {
+  SetWithoutPathExpansion(path, new StringValue(in_value));
+}
+
+bool DictionaryValue::Get(const std::string& path,
+                          const Value** out_value) const {
+  DCHECK(IsStringUTF8(path));
+  std::string current_path(path);
+  const DictionaryValue* current_dictionary = this;
+  for (size_t delimiter_position = current_path.find('.');
+       delimiter_position != std::string::npos;
+       delimiter_position = current_path.find('.')) {
+    const DictionaryValue* child_dictionary = NULL;
+    if (!current_dictionary->GetDictionary(
+            current_path.substr(0, delimiter_position), &child_dictionary))
+      return false;
+
+    current_dictionary = child_dictionary;
+    current_path.erase(0, delimiter_position + 1);
+  }
+
+  return current_dictionary->GetWithoutPathExpansion(current_path, out_value);
+}
+
+bool DictionaryValue::Get(const std::string& path, Value** out_value)  {
+  return static_cast<const DictionaryValue&>(*this).Get(
+      path,
+      const_cast<const Value**>(out_value));
+}
+
+bool DictionaryValue::GetBoolean(const std::string& path,
+                                 bool* bool_value) const {
+  const Value* value;
+  if (!Get(path, &value))
+    return false;
+
+  return value->GetAsBoolean(bool_value);
+}
+
+bool DictionaryValue::GetInteger(const std::string& path,
+                                 int* out_value) const {
+  const Value* value;
+  if (!Get(path, &value))
+    return false;
+
+  return value->GetAsInteger(out_value);
+}
+
+bool DictionaryValue::GetDouble(const std::string& path,
+                                double* out_value) const {
+  const Value* value;
+  if (!Get(path, &value))
+    return false;
+
+  return value->GetAsDouble(out_value);
+}
+
+bool DictionaryValue::GetString(const std::string& path,
+                                std::string* out_value) const {
+  const Value* value;
+  if (!Get(path, &value))
+    return false;
+
+  return value->GetAsString(out_value);
+}
+
+bool DictionaryValue::GetString(const std::string& path,
+                                string16* out_value) const {
+  const Value* value;
+  if (!Get(path, &value))
+    return false;
+
+  return value->GetAsString(out_value);
+}
+
+bool DictionaryValue::GetStringASCII(const std::string& path,
+                                     std::string* out_value) const {
+  std::string out;
+  if (!GetString(path, &out))
+    return false;
+
+  if (!IsStringASCII(out)) {
+    NOTREACHED();
+    return false;
+  }
+
+  out_value->assign(out);
+  return true;
+}
+
+bool DictionaryValue::GetBinary(const std::string& path,
+                                const BinaryValue** out_value) const {
+  const Value* value;
+  bool result = Get(path, &value);
+  if (!result || !value->IsType(TYPE_BINARY))
+    return false;
+
+  if (out_value)
+    *out_value = static_cast<const BinaryValue*>(value);
+
+  return true;
+}
+
+bool DictionaryValue::GetBinary(const std::string& path,
+                                BinaryValue** out_value) {
+  return static_cast<const DictionaryValue&>(*this).GetBinary(
+      path,
+      const_cast<const BinaryValue**>(out_value));
+}
+
+bool DictionaryValue::GetDictionary(const std::string& path,
+                                    const DictionaryValue** out_value) const {
+  const Value* value;
+  bool result = Get(path, &value);
+  if (!result || !value->IsType(TYPE_DICTIONARY))
+    return false;
+
+  if (out_value)
+    *out_value = static_cast<const DictionaryValue*>(value);
+
+  return true;
+}
+
+bool DictionaryValue::GetDictionary(const std::string& path,
+                                    DictionaryValue** out_value) {
+  return static_cast<const DictionaryValue&>(*this).GetDictionary(
+      path,
+      const_cast<const DictionaryValue**>(out_value));
+}
+
+bool DictionaryValue::GetList(const std::string& path,
+                              const ListValue** out_value) const {
+  const Value* value;
+  bool result = Get(path, &value);
+  if (!result || !value->IsType(TYPE_LIST))
+    return false;
+
+  if (out_value)
+    *out_value = static_cast<const ListValue*>(value);
+
+  return true;
+}
+
+bool DictionaryValue::GetList(const std::string& path, ListValue** out_value) {
+  return static_cast<const DictionaryValue&>(*this).GetList(
+      path,
+      const_cast<const ListValue**>(out_value));
+}
+
+bool DictionaryValue::GetWithoutPathExpansion(const std::string& key,
+                                              const Value** out_value) const {
+  DCHECK(IsStringUTF8(key));
+  ValueMap::const_iterator entry_iterator = dictionary_.find(key);
+  if (entry_iterator == dictionary_.end())
+    return false;
+
+  const Value* entry = entry_iterator->second;
+  if (out_value)
+    *out_value = entry;
+  return true;
+}
+
+bool DictionaryValue::GetWithoutPathExpansion(const std::string& key,
+                                              Value** out_value) {
+  return static_cast<const DictionaryValue&>(*this).GetWithoutPathExpansion(
+      key,
+      const_cast<const Value**>(out_value));
+}
+
+bool DictionaryValue::GetBooleanWithoutPathExpansion(const std::string& key,
+                                                     bool* out_value) const {
+  const Value* value;
+  if (!GetWithoutPathExpansion(key, &value))
+    return false;
+
+  return value->GetAsBoolean(out_value);
+}
+
+bool DictionaryValue::GetIntegerWithoutPathExpansion(const std::string& key,
+                                                     int* out_value) const {
+  const Value* value;
+  if (!GetWithoutPathExpansion(key, &value))
+    return false;
+
+  return value->GetAsInteger(out_value);
+}
+
+bool DictionaryValue::GetDoubleWithoutPathExpansion(const std::string& key,
+                                                    double* out_value) const {
+  const Value* value;
+  if (!GetWithoutPathExpansion(key, &value))
+    return false;
+
+  return value->GetAsDouble(out_value);
+}
+
+bool DictionaryValue::GetStringWithoutPathExpansion(
+    const std::string& key,
+    std::string* out_value) const {
+  const Value* value;
+  if (!GetWithoutPathExpansion(key, &value))
+    return false;
+
+  return value->GetAsString(out_value);
+}
+
+bool DictionaryValue::GetStringWithoutPathExpansion(const std::string& key,
+                                                    string16* out_value) const {
+  const Value* value;
+  if (!GetWithoutPathExpansion(key, &value))
+    return false;
+
+  return value->GetAsString(out_value);
+}
+
+bool DictionaryValue::GetDictionaryWithoutPathExpansion(
+    const std::string& key,
+    const DictionaryValue** out_value) const {
+  const Value* value;
+  bool result = GetWithoutPathExpansion(key, &value);
+  if (!result || !value->IsType(TYPE_DICTIONARY))
+    return false;
+
+  if (out_value)
+    *out_value = static_cast<const DictionaryValue*>(value);
+
+  return true;
+}
+
+bool DictionaryValue::GetDictionaryWithoutPathExpansion(
+    const std::string& key,
+    DictionaryValue** out_value) {
+  const DictionaryValue& const_this =
+      static_cast<const DictionaryValue&>(*this);
+  return const_this.GetDictionaryWithoutPathExpansion(
+          key,
+          const_cast<const DictionaryValue**>(out_value));
+}
+
+bool DictionaryValue::GetListWithoutPathExpansion(
+    const std::string& key,
+    const ListValue** out_value) const {
+  const Value* value;
+  bool result = GetWithoutPathExpansion(key, &value);
+  if (!result || !value->IsType(TYPE_LIST))
+    return false;
+
+  if (out_value)
+    *out_value = static_cast<const ListValue*>(value);
+
+  return true;
+}
+
+bool DictionaryValue::GetListWithoutPathExpansion(const std::string& key,
+                                                  ListValue** out_value) {
+  return
+      static_cast<const DictionaryValue&>(*this).GetListWithoutPathExpansion(
+          key,
+          const_cast<const ListValue**>(out_value));
+}
+
+bool DictionaryValue::Remove(const std::string& path,
+                             scoped_ptr<Value>* out_value) {
+  DCHECK(IsStringUTF8(path));
+  std::string current_path(path);
+  DictionaryValue* current_dictionary = this;
+  size_t delimiter_position = current_path.rfind('.');
+  if (delimiter_position != std::string::npos) {
+    if (!GetDictionary(current_path.substr(0, delimiter_position),
+                       &current_dictionary))
+      return false;
+    current_path.erase(0, delimiter_position + 1);
+  }
+
+  return current_dictionary->RemoveWithoutPathExpansion(current_path,
+                                                        out_value);
+}
+
+bool DictionaryValue::RemoveWithoutPathExpansion(const std::string& key,
+                                                 scoped_ptr<Value>* out_value) {
+  DCHECK(IsStringUTF8(key));
+  ValueMap::iterator entry_iterator = dictionary_.find(key);
+  if (entry_iterator == dictionary_.end())
+    return false;
+
+  Value* entry = entry_iterator->second;
+  if (out_value)
+    out_value->reset(entry);
+  else
+    delete entry;
+  dictionary_.erase(entry_iterator);
+  return true;
+}
+
+bool DictionaryValue::RemovePath(const std::string& path,
+                                 scoped_ptr<Value>* out_value) {
+  bool result = false;
+  size_t delimiter_position = path.find('.');
+
+  if (delimiter_position == std::string::npos)
+    return RemoveWithoutPathExpansion(path, out_value);
+
+  const std::string subdict_path = path.substr(0, delimiter_position);
+  DictionaryValue* subdict = NULL;
+  if (!GetDictionary(subdict_path, &subdict))
+    return false;
+  result = subdict->RemovePath(path.substr(delimiter_position + 1),
+                               out_value);
+  if (result && subdict->empty())
+    RemoveWithoutPathExpansion(subdict_path, NULL);
+
+  return result;
+}
+
+scoped_ptr<DictionaryValue> DictionaryValue::DeepCopyWithoutEmptyChildren()
+    const {
+  scoped_ptr<DictionaryValue> copy = CopyDictionaryWithoutEmptyChildren(*this);
+  if (!copy)
+    copy.reset(new DictionaryValue);
+  return copy;
+}
+
+void DictionaryValue::MergeDictionary(const DictionaryValue* dictionary) {
+  for (DictionaryValue::Iterator it(*dictionary); !it.IsAtEnd(); it.Advance()) {
+    const Value* merge_value = &it.value();
+    // Check whether we have to merge dictionaries.
+    if (merge_value->IsType(Value::TYPE_DICTIONARY)) {
+      DictionaryValue* sub_dict;
+      if (GetDictionaryWithoutPathExpansion(it.key(), &sub_dict)) {
+        sub_dict->MergeDictionary(
+            static_cast<const DictionaryValue*>(merge_value));
+        continue;
+      }
+    }
+    // All other cases: Make a copy and hook it up.
+    SetWithoutPathExpansion(it.key(), merge_value->DeepCopy());
+  }
+}
+
+void DictionaryValue::Swap(DictionaryValue* other) {
+  dictionary_.swap(other->dictionary_);
+}
+
+DictionaryValue::Iterator::Iterator(const DictionaryValue& target)
+    : target_(target),
+      it_(target.dictionary_.begin()) {}
+
+DictionaryValue::Iterator::~Iterator() {}
+
+DictionaryValue* DictionaryValue::DeepCopy() const {
+  DictionaryValue* result = new DictionaryValue;
+
+  for (ValueMap::const_iterator current_entry(dictionary_.begin());
+       current_entry != dictionary_.end(); ++current_entry) {
+    result->SetWithoutPathExpansion(current_entry->first,
+                                    current_entry->second->DeepCopy());
+  }
+
+  return result;
+}
+
+scoped_ptr<DictionaryValue> DictionaryValue::CreateDeepCopy() const {
+  return make_scoped_ptr(DeepCopy());
+}
+
+bool DictionaryValue::Equals(const Value* other) const {
+  if (other->GetType() != GetType())
+    return false;
+
+  const DictionaryValue* other_dict =
+      static_cast<const DictionaryValue*>(other);
+  Iterator lhs_it(*this);
+  Iterator rhs_it(*other_dict);
+  while (!lhs_it.IsAtEnd() && !rhs_it.IsAtEnd()) {
+    if (lhs_it.key() != rhs_it.key() ||
+        !lhs_it.value().Equals(&rhs_it.value())) {
+      return false;
+    }
+    lhs_it.Advance();
+    rhs_it.Advance();
+  }
+  if (!lhs_it.IsAtEnd() || !rhs_it.IsAtEnd())
+    return false;
+
+  return true;
+}
+
+///////////////////// ListValue ////////////////////
+
+ListValue::ListValue() : Value(TYPE_LIST) {
+}
+
+ListValue::~ListValue() {
+  Clear();
+}
+
+void ListValue::Clear() {
+  for (ValueVector::iterator i(list_.begin()); i != list_.end(); ++i)
+    delete *i;
+  list_.clear();
+}
+
+bool ListValue::Set(size_t index, Value* in_value) {
+  if (!in_value)
+    return false;
+
+  if (index >= list_.size()) {
+    // Pad out any intermediate indexes with null settings
+    while (index > list_.size())
+      Append(CreateNullValue());
+    Append(in_value);
+  } else {
+    DCHECK(list_[index] != in_value);
+    delete list_[index];
+    list_[index] = in_value;
+  }
+  return true;
+}
+
+bool ListValue::Set(size_t index, scoped_ptr<Value> in_value) {
+  return Set(index, in_value.release());
+}
+
+bool ListValue::Get(size_t index, const Value** out_value) const {
+  if (index >= list_.size())
+    return false;
+
+  if (out_value)
+    *out_value = list_[index];
+
+  return true;
+}
+
+bool ListValue::Get(size_t index, Value** out_value) {
+  return static_cast<const ListValue&>(*this).Get(
+      index,
+      const_cast<const Value**>(out_value));
+}
+
+bool ListValue::GetBoolean(size_t index, bool* bool_value) const {
+  const Value* value;
+  if (!Get(index, &value))
+    return false;
+
+  return value->GetAsBoolean(bool_value);
+}
+
+bool ListValue::GetInteger(size_t index, int* out_value) const {
+  const Value* value;
+  if (!Get(index, &value))
+    return false;
+
+  return value->GetAsInteger(out_value);
+}
+
+bool ListValue::GetDouble(size_t index, double* out_value) const {
+  const Value* value;
+  if (!Get(index, &value))
+    return false;
+
+  return value->GetAsDouble(out_value);
+}
+
+bool ListValue::GetString(size_t index, std::string* out_value) const {
+  const Value* value;
+  if (!Get(index, &value))
+    return false;
+
+  return value->GetAsString(out_value);
+}
+
+bool ListValue::GetString(size_t index, string16* out_value) const {
+  const Value* value;
+  if (!Get(index, &value))
+    return false;
+
+  return value->GetAsString(out_value);
+}
+
+bool ListValue::GetBinary(size_t index, const BinaryValue** out_value) const {
+  const Value* value;
+  bool result = Get(index, &value);
+  if (!result || !value->IsType(TYPE_BINARY))
+    return false;
+
+  if (out_value)
+    *out_value = static_cast<const BinaryValue*>(value);
+
+  return true;
+}
+
+bool ListValue::GetBinary(size_t index, BinaryValue** out_value) {
+  return static_cast<const ListValue&>(*this).GetBinary(
+      index,
+      const_cast<const BinaryValue**>(out_value));
+}
+
+bool ListValue::GetDictionary(size_t index,
+                              const DictionaryValue** out_value) const {
+  const Value* value;
+  bool result = Get(index, &value);
+  if (!result || !value->IsType(TYPE_DICTIONARY))
+    return false;
+
+  if (out_value)
+    *out_value = static_cast<const DictionaryValue*>(value);
+
+  return true;
+}
+
+bool ListValue::GetDictionary(size_t index, DictionaryValue** out_value) {
+  return static_cast<const ListValue&>(*this).GetDictionary(
+      index,
+      const_cast<const DictionaryValue**>(out_value));
+}
+
+bool ListValue::GetList(size_t index, const ListValue** out_value) const {
+  const Value* value;
+  bool result = Get(index, &value);
+  if (!result || !value->IsType(TYPE_LIST))
+    return false;
+
+  if (out_value)
+    *out_value = static_cast<const ListValue*>(value);
+
+  return true;
+}
+
+bool ListValue::GetList(size_t index, ListValue** out_value) {
+  return static_cast<const ListValue&>(*this).GetList(
+      index,
+      const_cast<const ListValue**>(out_value));
+}
+
+bool ListValue::Remove(size_t index, scoped_ptr<Value>* out_value) {
+  if (index >= list_.size())
+    return false;
+
+  if (out_value)
+    out_value->reset(list_[index]);
+  else
+    delete list_[index];
+
+  list_.erase(list_.begin() + index);
+  return true;
+}
+
+bool ListValue::Remove(const Value& value, size_t* index) {
+  for (ValueVector::iterator i(list_.begin()); i != list_.end(); ++i) {
+    if ((*i)->Equals(&value)) {
+      size_t previous_index = i - list_.begin();
+      delete *i;
+      list_.erase(i);
+
+      if (index)
+        *index = previous_index;
+      return true;
+    }
+  }
+  return false;
+}
+
+ListValue::iterator ListValue::Erase(iterator iter,
+                                     scoped_ptr<Value>* out_value) {
+  if (out_value)
+    out_value->reset(*iter);
+  else
+    delete *iter;
+
+  return list_.erase(iter);
+}
+
+void ListValue::Append(scoped_ptr<Value> in_value) {
+  Append(in_value.release());
+}
+
+void ListValue::Append(Value* in_value) {
+  DCHECK(in_value);
+  list_.push_back(in_value);
+}
+
+void ListValue::AppendBoolean(bool in_value) {
+  Append(new FundamentalValue(in_value));
+}
+
+void ListValue::AppendInteger(int in_value) {
+  Append(new FundamentalValue(in_value));
+}
+
+void ListValue::AppendDouble(double in_value) {
+  Append(new FundamentalValue(in_value));
+}
+
+void ListValue::AppendString(const std::string& in_value) {
+  Append(new StringValue(in_value));
+}
+
+void ListValue::AppendString(const string16& in_value) {
+  Append(new StringValue(in_value));
+}
+
+void ListValue::AppendStrings(const std::vector<std::string>& in_values) {
+  for (std::vector<std::string>::const_iterator it = in_values.begin();
+       it != in_values.end(); ++it) {
+    AppendString(*it);
+  }
+}
+
+void ListValue::AppendStrings(const std::vector<string16>& in_values) {
+  for (std::vector<string16>::const_iterator it = in_values.begin();
+       it != in_values.end(); ++it) {
+    AppendString(*it);
+  }
+}
+
+bool ListValue::AppendIfNotPresent(Value* in_value) {
+  DCHECK(in_value);
+  for (ValueVector::const_iterator i(list_.begin()); i != list_.end(); ++i) {
+    if ((*i)->Equals(in_value)) {
+      delete in_value;
+      return false;
+    }
+  }
+  list_.push_back(in_value);
+  return true;
+}
+
+bool ListValue::Insert(size_t index, Value* in_value) {
+  DCHECK(in_value);
+  if (index > list_.size())
+    return false;
+
+  list_.insert(list_.begin() + index, in_value);
+  return true;
+}
+
+ListValue::const_iterator ListValue::Find(const Value& value) const {
+  return std::find_if(list_.begin(), list_.end(), ValueEquals(&value));
+}
+
+void ListValue::Swap(ListValue* other) {
+  list_.swap(other->list_);
+}
+
+bool ListValue::GetAsList(ListValue** out_value) {
+  if (out_value)
+    *out_value = this;
+  return true;
+}
+
+bool ListValue::GetAsList(const ListValue** out_value) const {
+  if (out_value)
+    *out_value = this;
+  return true;
+}
+
+ListValue* ListValue::DeepCopy() const {
+  ListValue* result = new ListValue;
+
+  for (ValueVector::const_iterator i(list_.begin()); i != list_.end(); ++i)
+    result->Append((*i)->DeepCopy());
+
+  return result;
+}
+
+scoped_ptr<ListValue> ListValue::CreateDeepCopy() const {
+  return make_scoped_ptr(DeepCopy());
+}
+
+bool ListValue::Equals(const Value* other) const {
+  if (other->GetType() != GetType())
+    return false;
+
+  const ListValue* other_list =
+      static_cast<const ListValue*>(other);
+  const_iterator lhs_it, rhs_it;
+  for (lhs_it = begin(), rhs_it = other_list->begin();
+       lhs_it != end() && rhs_it != other_list->end();
+       ++lhs_it, ++rhs_it) {
+    if (!(*lhs_it)->Equals(*rhs_it))
+      return false;
+  }
+  if (lhs_it != end() || rhs_it != other_list->end())
+    return false;
+
+  return true;
+}
+
+ValueSerializer::~ValueSerializer() {
+}
+
+ValueDeserializer::~ValueDeserializer() {
+}
+
+std::ostream& operator<<(std::ostream& out, const Value& value) {
+  std::string json;
+  JSONWriter::WriteWithOptions(value, JSONWriter::OPTIONS_PRETTY_PRINT, &json);
+  return out << json;
+}
+
+}  // namespace base
diff --git a/base/values.h b/base/values.h
new file mode 100644
index 0000000..7feef9d
--- /dev/null
+++ b/base/values.h
@@ -0,0 +1,558 @@
+// Copyright (c) 2012 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 specifies a recursive data storage class called Value intended for
+// storing settings and other persistable data.
+//
+// A Value represents something that can be stored in JSON or passed to/from
+// JavaScript. As such, it is NOT a generalized variant type, since only the
+// types supported by JavaScript/JSON are supported.
+//
+// IN PARTICULAR this means that there is no support for int64 or unsigned
+// numbers. Writing JSON with such types would violate the spec. If you need
+// something like this, either use a double or make a string value containing
+// the number you want.
+
+#ifndef BASE_VALUES_H_
+#define BASE_VALUES_H_
+
+#include <stddef.h>
+
+#include <iosfwd>
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string16.h"
+
+namespace base {
+
+class BinaryValue;
+class DictionaryValue;
+class FundamentalValue;
+class ListValue;
+class StringValue;
+class Value;
+
+typedef std::vector<Value*> ValueVector;
+typedef std::map<std::string, Value*> ValueMap;
+
+// The Value class is the base class for Values. A Value can be instantiated
+// via the Create*Value() factory methods, or by directly creating instances of
+// the subclasses.
+//
+// See the file-level comment above for more information.
+class BASE_EXPORT Value {
+ public:
+  enum Type {
+    TYPE_NULL = 0,
+    TYPE_BOOLEAN,
+    TYPE_INTEGER,
+    TYPE_DOUBLE,
+    TYPE_STRING,
+    TYPE_BINARY,
+    TYPE_DICTIONARY,
+    TYPE_LIST
+    // Note: Do not add more types. See the file-level comment above for why.
+  };
+
+  virtual ~Value();
+
+  static scoped_ptr<Value> CreateNullValue();
+
+  // Returns the type of the value stored by the current Value object.
+  // Each type will be implemented by only one subclass of Value, so it's
+  // safe to use the Type to determine whether you can cast from
+  // Value* to (Implementing Class)*.  Also, a Value object never changes
+  // its type after construction.
+  Type GetType() const { return type_; }
+
+  // Returns true if the current object represents a given type.
+  bool IsType(Type type) const { return type == type_; }
+
+  // These methods allow the convenient retrieval of the contents of the Value.
+  // If the current object can be converted into the given type, the value is
+  // returned through the |out_value| parameter and true is returned;
+  // otherwise, false is returned and |out_value| is unchanged.
+  virtual bool GetAsBoolean(bool* out_value) const;
+  virtual bool GetAsInteger(int* out_value) const;
+  virtual bool GetAsDouble(double* out_value) const;
+  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);
+  virtual bool GetAsDictionary(const DictionaryValue** out_value) const;
+  // Note: Do not add more types. See the file-level comment above for why.
+
+  // This creates a deep copy of the entire Value tree, and returns a pointer
+  // to the copy.  The caller gets ownership of the copy, of course.
+  //
+  // Subclasses return their own type directly in their overrides;
+  // this works because C++ supports covariant return types.
+  virtual Value* DeepCopy() const;
+  // Preferred version of DeepCopy. TODO(estade): remove the above.
+  scoped_ptr<Value> CreateDeepCopy() const;
+
+  // Compares if two Value objects have equal contents.
+  virtual bool Equals(const Value* other) const;
+
+  // Compares if two Value objects have equal contents. Can handle NULLs.
+  // NULLs are considered equal but different from Value::CreateNullValue().
+  static bool Equals(const Value* a, const Value* b);
+
+ protected:
+  // These aren't safe for end-users, but they are useful for subclasses.
+  explicit Value(Type type);
+  Value(const Value& that);
+  Value& operator=(const Value& that);
+
+ private:
+  Type type_;
+};
+
+// FundamentalValue represents the simple fundamental types of values.
+class BASE_EXPORT FundamentalValue : public Value {
+ public:
+  explicit FundamentalValue(bool in_value);
+  explicit FundamentalValue(int in_value);
+  explicit FundamentalValue(double in_value);
+  ~FundamentalValue() override;
+
+  // Overridden from Value:
+  bool GetAsBoolean(bool* out_value) const override;
+  bool GetAsInteger(int* out_value) const override;
+  // Values of both type TYPE_INTEGER and TYPE_DOUBLE can be obtained as
+  // doubles.
+  bool GetAsDouble(double* out_value) const override;
+  FundamentalValue* DeepCopy() const override;
+  bool Equals(const Value* other) const override;
+
+ private:
+  union {
+    bool boolean_value_;
+    int integer_value_;
+    double double_value_;
+  };
+};
+
+class BASE_EXPORT StringValue : public Value {
+ public:
+  // Initializes a StringValue with a UTF-8 narrow character string.
+  explicit StringValue(const std::string& in_value);
+
+  // Initializes a StringValue with a string16.
+  explicit StringValue(const string16& in_value);
+
+  ~StringValue() override;
+
+  // Returns |value_| as a pointer or reference.
+  std::string* GetString();
+  const std::string& GetString() const;
+
+  // Overridden from Value:
+  bool GetAsString(std::string* out_value) const override;
+  bool GetAsString(string16* out_value) const override;
+  bool GetAsString(const StringValue** out_value) const override;
+  StringValue* DeepCopy() const override;
+  bool Equals(const Value* other) const override;
+
+ private:
+  std::string value_;
+};
+
+class BASE_EXPORT BinaryValue: public Value {
+ public:
+  // Creates a BinaryValue with a null buffer and size of 0.
+  BinaryValue();
+
+  // Creates a BinaryValue, taking ownership of the bytes pointed to by
+  // |buffer|.
+  BinaryValue(scoped_ptr<char[]> buffer, size_t size);
+
+  ~BinaryValue() override;
+
+  // For situations where you want to keep ownership of your buffer, this
+  // factory method creates a new BinaryValue by copying the contents of the
+  // buffer that's passed in.
+  static BinaryValue* CreateWithCopiedBuffer(const char* buffer, size_t size);
+
+  size_t GetSize() const { return size_; }
+
+  // May return NULL.
+  char* GetBuffer() { return buffer_.get(); }
+  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;
+
+ private:
+  scoped_ptr<char[]> buffer_;
+  size_t size_;
+
+  DISALLOW_COPY_AND_ASSIGN(BinaryValue);
+};
+
+// DictionaryValue provides a key-value dictionary with (optional) "path"
+// parsing for recursive access; see the comment at the top of the file. Keys
+// are |std::string|s and should be UTF-8 encoded.
+class BASE_EXPORT DictionaryValue : public Value {
+ public:
+  DictionaryValue();
+  ~DictionaryValue() override;
+
+  // Overridden from Value:
+  bool GetAsDictionary(DictionaryValue** out_value) override;
+  bool GetAsDictionary(const DictionaryValue** out_value) const override;
+
+  // Returns true if the current dictionary has a value for the given key.
+  bool HasKey(const std::string& key) const;
+
+  // Returns the number of Values in this dictionary.
+  size_t size() const { return dictionary_.size(); }
+
+  // Returns whether the dictionary is empty.
+  bool empty() const { return dictionary_.empty(); }
+
+  // Clears any current contents of this dictionary.
+  void Clear();
+
+  // Sets the Value associated with the given path starting from this object.
+  // A path has the form "<key>" or "<key>.<key>.[...]", where "." indexes
+  // into the next DictionaryValue down.  Obviously, "." can't be used
+  // within a key, but there are no other restrictions on keys.
+  // If the key at any step of the way doesn't exist, or exists but isn't
+  // a DictionaryValue, a new DictionaryValue will be created and attached
+  // to the path in that location. |in_value| must be non-null.
+  void Set(const std::string& path, scoped_ptr<Value> in_value);
+  // Deprecated version of the above. TODO(estade): remove.
+  void Set(const std::string& path, Value* in_value);
+
+  // Convenience forms of Set().  These methods will replace any existing
+  // value at that path, even if it has a different type.
+  void SetBoolean(const std::string& path, bool in_value);
+  void SetInteger(const std::string& path, int in_value);
+  void SetDouble(const std::string& path, double in_value);
+  void SetString(const std::string& path, const std::string& in_value);
+  void SetString(const std::string& path, const string16& in_value);
+
+  // Like Set(), but without special treatment of '.'.  This allows e.g. URLs to
+  // be used as paths.
+  void SetWithoutPathExpansion(const std::string& key,
+                               scoped_ptr<Value> in_value);
+  // Deprecated version of the above. TODO(estade): remove.
+  void SetWithoutPathExpansion(const std::string& key, Value* in_value);
+
+  // Convenience forms of SetWithoutPathExpansion().
+  void SetBooleanWithoutPathExpansion(const std::string& path, bool in_value);
+  void SetIntegerWithoutPathExpansion(const std::string& path, int in_value);
+  void SetDoubleWithoutPathExpansion(const std::string& path, double in_value);
+  void SetStringWithoutPathExpansion(const std::string& path,
+                                     const std::string& in_value);
+  void SetStringWithoutPathExpansion(const std::string& path,
+                                     const string16& in_value);
+
+  // Gets the Value associated with the given path starting from this object.
+  // A path has the form "<key>" or "<key>.<key>.[...]", where "." indexes
+  // into the next DictionaryValue down.  If the path can be resolved
+  // successfully, the value for the last key in the path will be returned
+  // through the |out_value| parameter, and the function will return true.
+  // Otherwise, it will return false and |out_value| will be untouched.
+  // Note that the dictionary always owns the value that's returned.
+  // |out_value| is optional and will only be set if non-NULL.
+  bool Get(const std::string& path, const Value** out_value) const;
+  bool Get(const std::string& path, Value** out_value);
+
+  // These are convenience forms of Get().  The value will be retrieved
+  // and the return value will be true if the path is valid and the value at
+  // the end of the path can be returned in the form specified.
+  // |out_value| is optional and will only be set if non-NULL.
+  bool GetBoolean(const std::string& path, bool* out_value) const;
+  bool GetInteger(const std::string& path, int* out_value) const;
+  // Values of both type TYPE_INTEGER and TYPE_DOUBLE can be obtained as
+  // doubles.
+  bool GetDouble(const std::string& path, double* out_value) const;
+  bool GetString(const std::string& path, std::string* out_value) const;
+  bool GetString(const std::string& path, string16* out_value) const;
+  bool GetStringASCII(const std::string& path, std::string* out_value) const;
+  bool GetBinary(const std::string& path, const BinaryValue** out_value) const;
+  bool GetBinary(const std::string& path, BinaryValue** out_value);
+  bool GetDictionary(const std::string& path,
+                     const DictionaryValue** out_value) const;
+  bool GetDictionary(const std::string& path, DictionaryValue** out_value);
+  bool GetList(const std::string& path, const ListValue** out_value) const;
+  bool GetList(const std::string& path, ListValue** out_value);
+
+  // Like Get(), but without special treatment of '.'.  This allows e.g. URLs to
+  // be used as paths.
+  bool GetWithoutPathExpansion(const std::string& key,
+                               const Value** out_value) const;
+  bool GetWithoutPathExpansion(const std::string& key, Value** out_value);
+  bool GetBooleanWithoutPathExpansion(const std::string& key,
+                                      bool* out_value) const;
+  bool GetIntegerWithoutPathExpansion(const std::string& key,
+                                      int* out_value) const;
+  bool GetDoubleWithoutPathExpansion(const std::string& key,
+                                     double* out_value) const;
+  bool GetStringWithoutPathExpansion(const std::string& key,
+                                     std::string* out_value) const;
+  bool GetStringWithoutPathExpansion(const std::string& key,
+                                     string16* out_value) const;
+  bool GetDictionaryWithoutPathExpansion(
+      const std::string& key,
+      const DictionaryValue** out_value) const;
+  bool GetDictionaryWithoutPathExpansion(const std::string& key,
+                                         DictionaryValue** out_value);
+  bool GetListWithoutPathExpansion(const std::string& key,
+                                   const ListValue** out_value) const;
+  bool GetListWithoutPathExpansion(const std::string& key,
+                                   ListValue** out_value);
+
+  // Removes the Value with the specified path from this dictionary (or one
+  // of its child dictionaries, if the path is more than just a local key).
+  // If |out_value| is non-NULL, the removed Value will be passed out via
+  // |out_value|.  If |out_value| is NULL, the removed value will be deleted.
+  // This method returns true if |path| is a valid path; otherwise it will
+  // return false and the DictionaryValue object will be unchanged.
+  virtual bool Remove(const std::string& path, scoped_ptr<Value>* out_value);
+
+  // Like Remove(), but without special treatment of '.'.  This allows e.g. URLs
+  // to be used as paths.
+  virtual bool RemoveWithoutPathExpansion(const std::string& key,
+                                          scoped_ptr<Value>* out_value);
+
+  // Removes a path, clearing out all dictionaries on |path| that remain empty
+  // after removing the value at |path|.
+  virtual bool RemovePath(const std::string& path,
+                          scoped_ptr<Value>* out_value);
+
+  // Makes a copy of |this| but doesn't include empty dictionaries and lists in
+  // the copy.  This never returns NULL, even if |this| itself is empty.
+  scoped_ptr<DictionaryValue> DeepCopyWithoutEmptyChildren() const;
+
+  // Merge |dictionary| into this dictionary. This is done recursively, i.e. any
+  // sub-dictionaries will be merged as well. In case of key collisions, the
+  // passed in dictionary takes precedence and data already present will be
+  // replaced. Values within |dictionary| are deep-copied, so |dictionary| may
+  // be freed any time after this call.
+  void MergeDictionary(const DictionaryValue* dictionary);
+
+  // Swaps contents with the |other| dictionary.
+  virtual void Swap(DictionaryValue* other);
+
+  // This class provides an iterator over both keys and values in the
+  // dictionary.  It can't be used to modify the dictionary.
+  class BASE_EXPORT Iterator {
+   public:
+    explicit Iterator(const DictionaryValue& target);
+    ~Iterator();
+
+    bool IsAtEnd() const { return it_ == target_.dictionary_.end(); }
+    void Advance() { ++it_; }
+
+    const std::string& key() const { return it_->first; }
+    const Value& value() const { return *it_->second; }
+
+   private:
+    const DictionaryValue& target_;
+    ValueMap::const_iterator it_;
+  };
+
+  // Overridden from Value:
+  DictionaryValue* DeepCopy() const override;
+  // Preferred version of DeepCopy. TODO(estade): remove the above.
+  scoped_ptr<DictionaryValue> CreateDeepCopy() const;
+  bool Equals(const Value* other) const override;
+
+ private:
+  ValueMap dictionary_;
+
+  DISALLOW_COPY_AND_ASSIGN(DictionaryValue);
+};
+
+// This type of Value represents a list of other Value values.
+class BASE_EXPORT ListValue : public Value {
+ public:
+  typedef ValueVector::iterator iterator;
+  typedef ValueVector::const_iterator const_iterator;
+
+  ListValue();
+  ~ListValue() override;
+
+  // Clears the contents of this ListValue
+  void Clear();
+
+  // Returns the number of Values in this list.
+  size_t GetSize() const { return list_.size(); }
+
+  // Returns whether the list is empty.
+  bool empty() const { return list_.empty(); }
+
+  // Sets the list item at the given index to be the Value specified by
+  // the value given.  If the index beyond the current end of the list, null
+  // Values will be used to pad out the list.
+  // Returns true if successful, or false if the index was negative or
+  // the value is a null pointer.
+  bool Set(size_t index, Value* in_value);
+  // Preferred version of the above. TODO(estade): remove the above.
+  bool Set(size_t index, scoped_ptr<Value> in_value);
+
+  // Gets the Value at the given index.  Modifies |out_value| (and returns true)
+  // only if the index falls within the current list range.
+  // Note that the list always owns the Value passed out via |out_value|.
+  // |out_value| is optional and will only be set if non-NULL.
+  bool Get(size_t index, const Value** out_value) const;
+  bool Get(size_t index, Value** out_value);
+
+  // Convenience forms of Get().  Modifies |out_value| (and returns true)
+  // only if the index is valid and the Value at that index can be returned
+  // in the specified form.
+  // |out_value| is optional and will only be set if non-NULL.
+  bool GetBoolean(size_t index, bool* out_value) const;
+  bool GetInteger(size_t index, int* out_value) const;
+  // Values of both type TYPE_INTEGER and TYPE_DOUBLE can be obtained as
+  // doubles.
+  bool GetDouble(size_t index, double* out_value) const;
+  bool GetString(size_t index, std::string* out_value) const;
+  bool GetString(size_t index, string16* out_value) const;
+  bool GetBinary(size_t index, const BinaryValue** out_value) const;
+  bool GetBinary(size_t index, BinaryValue** out_value);
+  bool GetDictionary(size_t index, const DictionaryValue** out_value) const;
+  bool GetDictionary(size_t index, DictionaryValue** out_value);
+  bool GetList(size_t index, const ListValue** out_value) const;
+  bool GetList(size_t index, ListValue** out_value);
+
+  // Removes the Value with the specified index from this list.
+  // If |out_value| is non-NULL, the removed Value AND ITS OWNERSHIP will be
+  // passed out via |out_value|.  If |out_value| is NULL, the removed value will
+  // be deleted.  This method returns true if |index| is valid; otherwise
+  // it will return false and the ListValue object will be unchanged.
+  virtual bool Remove(size_t index, scoped_ptr<Value>* out_value);
+
+  // Removes the first instance of |value| found in the list, if any, and
+  // deletes it. |index| is the location where |value| was found. Returns false
+  // if not found.
+  bool Remove(const Value& value, size_t* index);
+
+  // Removes the element at |iter|. If |out_value| is NULL, the value will be
+  // deleted, otherwise ownership of the value is passed back to the caller.
+  // Returns an iterator pointing to the location of the element that
+  // followed the erased element.
+  iterator Erase(iterator iter, scoped_ptr<Value>* out_value);
+
+  // Appends a Value to the end of the list.
+  void Append(scoped_ptr<Value> in_value);
+  // Deprecated version of the above. TODO(estade): remove.
+  void Append(Value* in_value);
+
+  // Convenience forms of Append.
+  void AppendBoolean(bool in_value);
+  void AppendInteger(int in_value);
+  void AppendDouble(double in_value);
+  void AppendString(const std::string& in_value);
+  void AppendString(const string16& in_value);
+  void AppendStrings(const std::vector<std::string>& in_values);
+  void AppendStrings(const std::vector<string16>& in_values);
+
+  // Appends a Value if it's not already present. Takes ownership of the
+  // |in_value|. Returns true if successful, or false if the value was already
+  // present. If the value was already present the |in_value| is deleted.
+  bool AppendIfNotPresent(Value* in_value);
+
+  // Insert a Value at index.
+  // Returns true if successful, or false if the index was out of range.
+  bool Insert(size_t index, Value* in_value);
+
+  // Searches for the first instance of |value| in the list using the Equals
+  // method of the Value type.
+  // Returns a const_iterator to the found item or to end() if none exists.
+  const_iterator Find(const Value& value) const;
+
+  // Swaps contents with the |other| list.
+  virtual void Swap(ListValue* other);
+
+  // Iteration.
+  iterator begin() { return list_.begin(); }
+  iterator end() { return list_.end(); }
+
+  const_iterator begin() const { return list_.begin(); }
+  const_iterator end() const { return list_.end(); }
+
+  // Overridden from Value:
+  bool GetAsList(ListValue** out_value) override;
+  bool GetAsList(const ListValue** out_value) const override;
+  ListValue* DeepCopy() const override;
+  bool Equals(const Value* other) const override;
+
+  // Preferred version of DeepCopy. TODO(estade): remove DeepCopy.
+  scoped_ptr<ListValue> CreateDeepCopy() const;
+
+ private:
+  ValueVector list_;
+
+  DISALLOW_COPY_AND_ASSIGN(ListValue);
+};
+
+// This interface is implemented by classes that know how to serialize
+// Value objects.
+class BASE_EXPORT ValueSerializer {
+ public:
+  virtual ~ValueSerializer();
+
+  virtual bool Serialize(const Value& root) = 0;
+};
+
+// This interface is implemented by classes that know how to deserialize Value
+// objects.
+class BASE_EXPORT ValueDeserializer {
+ public:
+  virtual ~ValueDeserializer();
+
+  // This method deserializes the subclass-specific format into a Value object.
+  // If the return value is non-NULL, the caller takes ownership of returned
+  // Value. If the return value is NULL, and if error_code is non-NULL,
+  // error_code will be set with the underlying error.
+  // If |error_message| is non-null, it will be filled in with a formatted
+  // error message including the location of the error if appropriate.
+  virtual Value* Deserialize(int* error_code, std::string* error_str) = 0;
+};
+
+// Stream operator so Values can be used in assertion statements.  In order that
+// gtest uses this operator to print readable output on test failures, we must
+// override each specific type. Otherwise, the default template implementation
+// is preferred over an upcast.
+BASE_EXPORT std::ostream& operator<<(std::ostream& out, const Value& value);
+
+BASE_EXPORT inline std::ostream& operator<<(std::ostream& out,
+                                            const FundamentalValue& value) {
+  return out << static_cast<const Value&>(value);
+}
+
+BASE_EXPORT inline std::ostream& operator<<(std::ostream& out,
+                                            const StringValue& value) {
+  return out << static_cast<const Value&>(value);
+}
+
+BASE_EXPORT inline std::ostream& operator<<(std::ostream& out,
+                                            const DictionaryValue& value) {
+  return out << static_cast<const Value&>(value);
+}
+
+BASE_EXPORT inline std::ostream& operator<<(std::ostream& out,
+                                            const ListValue& value) {
+  return out << static_cast<const Value&>(value);
+}
+
+}  // namespace base
+
+#endif  // BASE_VALUES_H_
diff --git a/base/values_unittest.cc b/base/values_unittest.cc
new file mode 100644
index 0000000..37ed7ce
--- /dev/null
+++ b/base/values_unittest.cc
@@ -0,0 +1,1145 @@
+// Copyright (c) 2012 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 <limits>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(ValuesTest, Basic) {
+  // Test basic dictionary getting/setting
+  DictionaryValue settings;
+  std::string homepage = "http://google.com";
+  ASSERT_FALSE(settings.GetString("global.homepage", &homepage));
+  ASSERT_EQ(std::string("http://google.com"), homepage);
+
+  ASSERT_FALSE(settings.Get("global", NULL));
+  settings.SetBoolean("global", true);
+  ASSERT_TRUE(settings.Get("global", NULL));
+  settings.SetString("global.homepage", "http://scurvy.com");
+  ASSERT_TRUE(settings.Get("global", NULL));
+  homepage = "http://google.com";
+  ASSERT_TRUE(settings.GetString("global.homepage", &homepage));
+  ASSERT_EQ(std::string("http://scurvy.com"), homepage);
+
+  // Test storing a dictionary in a list.
+  ListValue* toolbar_bookmarks;
+  ASSERT_FALSE(
+    settings.GetList("global.toolbar.bookmarks", &toolbar_bookmarks));
+
+  scoped_ptr<ListValue> new_toolbar_bookmarks(new ListValue);
+  settings.Set("global.toolbar.bookmarks", new_toolbar_bookmarks.Pass());
+  ASSERT_TRUE(settings.GetList("global.toolbar.bookmarks", &toolbar_bookmarks));
+
+  scoped_ptr<DictionaryValue> new_bookmark(new DictionaryValue);
+  new_bookmark->SetString("name", "Froogle");
+  new_bookmark->SetString("url", "http://froogle.com");
+  toolbar_bookmarks->Append(new_bookmark.Pass());
+
+  ListValue* bookmark_list;
+  ASSERT_TRUE(settings.GetList("global.toolbar.bookmarks", &bookmark_list));
+  DictionaryValue* bookmark;
+  ASSERT_EQ(1U, bookmark_list->GetSize());
+  ASSERT_TRUE(bookmark_list->GetDictionary(0, &bookmark));
+  std::string bookmark_name = "Unnamed";
+  ASSERT_TRUE(bookmark->GetString("name", &bookmark_name));
+  ASSERT_EQ(std::string("Froogle"), bookmark_name);
+  std::string bookmark_url;
+  ASSERT_TRUE(bookmark->GetString("url", &bookmark_url));
+  ASSERT_EQ(std::string("http://froogle.com"), bookmark_url);
+}
+
+TEST(ValuesTest, List) {
+  scoped_ptr<ListValue> mixed_list(new ListValue());
+  mixed_list->Set(0, make_scoped_ptr(new FundamentalValue(true)));
+  mixed_list->Set(1, make_scoped_ptr(new FundamentalValue(42)));
+  mixed_list->Set(2, make_scoped_ptr(new FundamentalValue(88.8)));
+  mixed_list->Set(3, make_scoped_ptr(new StringValue("foo")));
+  ASSERT_EQ(4u, mixed_list->GetSize());
+
+  Value *value = NULL;
+  bool bool_value = false;
+  int int_value = 0;
+  double double_value = 0.0;
+  std::string string_value;
+
+  ASSERT_FALSE(mixed_list->Get(4, &value));
+
+  ASSERT_FALSE(mixed_list->GetInteger(0, &int_value));
+  ASSERT_EQ(0, int_value);
+  ASSERT_FALSE(mixed_list->GetBoolean(1, &bool_value));
+  ASSERT_FALSE(bool_value);
+  ASSERT_FALSE(mixed_list->GetString(2, &string_value));
+  ASSERT_EQ("", string_value);
+  ASSERT_FALSE(mixed_list->GetInteger(2, &int_value));
+  ASSERT_EQ(0, int_value);
+  ASSERT_FALSE(mixed_list->GetBoolean(3, &bool_value));
+  ASSERT_FALSE(bool_value);
+
+  ASSERT_TRUE(mixed_list->GetBoolean(0, &bool_value));
+  ASSERT_TRUE(bool_value);
+  ASSERT_TRUE(mixed_list->GetInteger(1, &int_value));
+  ASSERT_EQ(42, int_value);
+  // implicit conversion from Integer to Double should be possible.
+  ASSERT_TRUE(mixed_list->GetDouble(1, &double_value));
+  ASSERT_EQ(42, double_value);
+  ASSERT_TRUE(mixed_list->GetDouble(2, &double_value));
+  ASSERT_EQ(88.8, double_value);
+  ASSERT_TRUE(mixed_list->GetString(3, &string_value));
+  ASSERT_EQ("foo", string_value);
+
+  // Try searching in the mixed list.
+  base::FundamentalValue sought_value(42);
+  base::FundamentalValue not_found_value(false);
+
+  ASSERT_NE(mixed_list->end(), mixed_list->Find(sought_value));
+  ASSERT_TRUE((*mixed_list->Find(sought_value))->GetAsInteger(&int_value));
+  ASSERT_EQ(42, int_value);
+  ASSERT_EQ(mixed_list->end(), mixed_list->Find(not_found_value));
+}
+
+TEST(ValuesTest, BinaryValue) {
+  // Default constructor creates a BinaryValue with a null buffer and size 0.
+  scoped_ptr<BinaryValue> binary(new BinaryValue());
+  ASSERT_TRUE(binary.get());
+  ASSERT_EQ(NULL, binary->GetBuffer());
+  ASSERT_EQ(0U, binary->GetSize());
+
+  // Test the common case of a non-empty buffer
+  scoped_ptr<char[]> buffer(new char[15]);
+  char* original_buffer = buffer.get();
+  binary.reset(new BinaryValue(buffer.Pass(), 15));
+  ASSERT_TRUE(binary.get());
+  ASSERT_TRUE(binary->GetBuffer());
+  ASSERT_EQ(original_buffer, binary->GetBuffer());
+  ASSERT_EQ(15U, binary->GetSize());
+
+  char stack_buffer[42];
+  memset(stack_buffer, '!', 42);
+  binary.reset(BinaryValue::CreateWithCopiedBuffer(stack_buffer, 42));
+  ASSERT_TRUE(binary.get());
+  ASSERT_TRUE(binary->GetBuffer());
+  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) {
+  // Test overloaded StringValue constructor.
+  scoped_ptr<Value> narrow_value(new StringValue("narrow"));
+  ASSERT_TRUE(narrow_value.get());
+  ASSERT_TRUE(narrow_value->IsType(Value::TYPE_STRING));
+  scoped_ptr<Value> utf16_value(new StringValue(ASCIIToUTF16("utf16")));
+  ASSERT_TRUE(utf16_value.get());
+  ASSERT_TRUE(utf16_value->IsType(Value::TYPE_STRING));
+
+  // Test overloaded GetAsString.
+  std::string narrow = "http://google.com";
+  string16 utf16 = ASCIIToUTF16("http://google.com");
+  const StringValue* string_value = NULL;
+  ASSERT_TRUE(narrow_value->GetAsString(&narrow));
+  ASSERT_TRUE(narrow_value->GetAsString(&utf16));
+  ASSERT_TRUE(narrow_value->GetAsString(&string_value));
+  ASSERT_EQ(std::string("narrow"), narrow);
+  ASSERT_EQ(ASCIIToUTF16("narrow"), utf16);
+  ASSERT_EQ(string_value->GetString(), narrow);
+
+  ASSERT_TRUE(utf16_value->GetAsString(&narrow));
+  ASSERT_TRUE(utf16_value->GetAsString(&utf16));
+  ASSERT_TRUE(utf16_value->GetAsString(&string_value));
+  ASSERT_EQ(std::string("utf16"), narrow);
+  ASSERT_EQ(ASCIIToUTF16("utf16"), utf16);
+  ASSERT_EQ(string_value->GetString(), narrow);
+
+  // Don't choke on NULL values.
+  ASSERT_TRUE(narrow_value->GetAsString(static_cast<string16*>(NULL)));
+  ASSERT_TRUE(narrow_value->GetAsString(static_cast<std::string*>(NULL)));
+  ASSERT_TRUE(narrow_value->GetAsString(
+                  static_cast<const StringValue**>(NULL)));
+}
+
+// This is a Value object that allows us to tell if it's been
+// properly deleted by modifying the value of external flag on destruction.
+class DeletionTestValue : public Value {
+ public:
+  explicit DeletionTestValue(bool* deletion_flag) : Value(TYPE_NULL) {
+    Init(deletion_flag);  // Separate function so that we can use ASSERT_*
+  }
+
+  void Init(bool* deletion_flag) {
+    ASSERT_TRUE(deletion_flag);
+    deletion_flag_ = deletion_flag;
+    *deletion_flag_ = false;
+  }
+
+  ~DeletionTestValue() override { *deletion_flag_ = true; }
+
+ private:
+  bool* deletion_flag_;
+};
+
+TEST(ValuesTest, ListDeletion) {
+  bool deletion_flag = true;
+
+  {
+    ListValue list;
+    list.Append(make_scoped_ptr(new DeletionTestValue(&deletion_flag)));
+    EXPECT_FALSE(deletion_flag);
+  }
+  EXPECT_TRUE(deletion_flag);
+
+  {
+    ListValue list;
+    list.Append(make_scoped_ptr(new DeletionTestValue(&deletion_flag)));
+    EXPECT_FALSE(deletion_flag);
+    list.Clear();
+    EXPECT_TRUE(deletion_flag);
+  }
+
+  {
+    ListValue list;
+    list.Append(make_scoped_ptr(new DeletionTestValue(&deletion_flag)));
+    EXPECT_FALSE(deletion_flag);
+    EXPECT_TRUE(list.Set(0, Value::CreateNullValue()));
+    EXPECT_TRUE(deletion_flag);
+  }
+}
+
+TEST(ValuesTest, ListRemoval) {
+  bool deletion_flag = true;
+  scoped_ptr<Value> removed_item;
+
+  {
+    ListValue list;
+    list.Append(make_scoped_ptr(new DeletionTestValue(&deletion_flag)));
+    EXPECT_FALSE(deletion_flag);
+    EXPECT_EQ(1U, list.GetSize());
+    EXPECT_FALSE(list.Remove(std::numeric_limits<size_t>::max(),
+                             &removed_item));
+    EXPECT_FALSE(list.Remove(1, &removed_item));
+    EXPECT_TRUE(list.Remove(0, &removed_item));
+    ASSERT_TRUE(removed_item);
+    EXPECT_EQ(0U, list.GetSize());
+  }
+  EXPECT_FALSE(deletion_flag);
+  removed_item.reset();
+  EXPECT_TRUE(deletion_flag);
+
+  {
+    ListValue list;
+    list.Append(make_scoped_ptr(new DeletionTestValue(&deletion_flag)));
+    EXPECT_FALSE(deletion_flag);
+    EXPECT_TRUE(list.Remove(0, NULL));
+    EXPECT_TRUE(deletion_flag);
+    EXPECT_EQ(0U, list.GetSize());
+  }
+
+  {
+    ListValue list;
+    scoped_ptr<DeletionTestValue> value(new DeletionTestValue(&deletion_flag));
+    DeletionTestValue* original_value = value.get();
+    list.Append(value.Pass());
+    EXPECT_FALSE(deletion_flag);
+    size_t index = 0;
+    list.Remove(*original_value, &index);
+    EXPECT_EQ(0U, index);
+    EXPECT_TRUE(deletion_flag);
+    EXPECT_EQ(0U, list.GetSize());
+  }
+}
+
+TEST(ValuesTest, DictionaryDeletion) {
+  std::string key = "test";
+  bool deletion_flag = true;
+
+  {
+    DictionaryValue dict;
+    dict.Set(key, make_scoped_ptr(new DeletionTestValue(&deletion_flag)));
+    EXPECT_FALSE(deletion_flag);
+  }
+  EXPECT_TRUE(deletion_flag);
+
+  {
+    DictionaryValue dict;
+    dict.Set(key, make_scoped_ptr(new DeletionTestValue(&deletion_flag)));
+    EXPECT_FALSE(deletion_flag);
+    dict.Clear();
+    EXPECT_TRUE(deletion_flag);
+  }
+
+  {
+    DictionaryValue dict;
+    dict.Set(key, make_scoped_ptr(new DeletionTestValue(&deletion_flag)));
+    EXPECT_FALSE(deletion_flag);
+    dict.Set(key, Value::CreateNullValue());
+    EXPECT_TRUE(deletion_flag);
+  }
+}
+
+TEST(ValuesTest, DictionaryRemoval) {
+  std::string key = "test";
+  bool deletion_flag = true;
+  scoped_ptr<Value> removed_item;
+
+  {
+    DictionaryValue dict;
+    dict.Set(key, make_scoped_ptr(new DeletionTestValue(&deletion_flag)));
+    EXPECT_FALSE(deletion_flag);
+    EXPECT_TRUE(dict.HasKey(key));
+    EXPECT_FALSE(dict.Remove("absent key", &removed_item));
+    EXPECT_TRUE(dict.Remove(key, &removed_item));
+    EXPECT_FALSE(dict.HasKey(key));
+    ASSERT_TRUE(removed_item);
+  }
+  EXPECT_FALSE(deletion_flag);
+  removed_item.reset();
+  EXPECT_TRUE(deletion_flag);
+
+  {
+    DictionaryValue dict;
+    dict.Set(key, make_scoped_ptr(new DeletionTestValue(&deletion_flag)));
+    EXPECT_FALSE(deletion_flag);
+    EXPECT_TRUE(dict.HasKey(key));
+    EXPECT_TRUE(dict.Remove(key, NULL));
+    EXPECT_TRUE(deletion_flag);
+    EXPECT_FALSE(dict.HasKey(key));
+  }
+}
+
+TEST(ValuesTest, DictionaryWithoutPathExpansion) {
+  DictionaryValue dict;
+  dict.Set("this.is.expanded", Value::CreateNullValue());
+  dict.SetWithoutPathExpansion("this.isnt.expanded", Value::CreateNullValue());
+
+  EXPECT_FALSE(dict.HasKey("this.is.expanded"));
+  EXPECT_TRUE(dict.HasKey("this"));
+  Value* value1;
+  EXPECT_TRUE(dict.Get("this", &value1));
+  DictionaryValue* value2;
+  ASSERT_TRUE(dict.GetDictionaryWithoutPathExpansion("this", &value2));
+  EXPECT_EQ(value1, value2);
+  EXPECT_EQ(1U, value2->size());
+
+  EXPECT_TRUE(dict.HasKey("this.isnt.expanded"));
+  Value* value3;
+  EXPECT_FALSE(dict.Get("this.isnt.expanded", &value3));
+  Value* value4;
+  ASSERT_TRUE(dict.GetWithoutPathExpansion("this.isnt.expanded", &value4));
+  EXPECT_EQ(Value::TYPE_NULL, value4->GetType());
+}
+
+// Tests the deprecated version of SetWithoutPathExpansion.
+// TODO(estade): remove.
+TEST(ValuesTest, DictionaryWithoutPathExpansionDeprecated) {
+  DictionaryValue dict;
+  dict.Set("this.is.expanded", Value::CreateNullValue());
+  dict.SetWithoutPathExpansion("this.isnt.expanded", Value::CreateNullValue());
+
+  EXPECT_FALSE(dict.HasKey("this.is.expanded"));
+  EXPECT_TRUE(dict.HasKey("this"));
+  Value* value1;
+  EXPECT_TRUE(dict.Get("this", &value1));
+  DictionaryValue* value2;
+  ASSERT_TRUE(dict.GetDictionaryWithoutPathExpansion("this", &value2));
+  EXPECT_EQ(value1, value2);
+  EXPECT_EQ(1U, value2->size());
+
+  EXPECT_TRUE(dict.HasKey("this.isnt.expanded"));
+  Value* value3;
+  EXPECT_FALSE(dict.Get("this.isnt.expanded", &value3));
+  Value* value4;
+  ASSERT_TRUE(dict.GetWithoutPathExpansion("this.isnt.expanded", &value4));
+  EXPECT_EQ(Value::TYPE_NULL, value4->GetType());
+}
+
+TEST(ValuesTest, DictionaryRemovePath) {
+  DictionaryValue dict;
+  dict.SetInteger("a.long.way.down", 1);
+  dict.SetBoolean("a.long.key.path", true);
+
+  scoped_ptr<Value> removed_item;
+  EXPECT_TRUE(dict.RemovePath("a.long.way.down", &removed_item));
+  ASSERT_TRUE(removed_item);
+  EXPECT_TRUE(removed_item->IsType(base::Value::TYPE_INTEGER));
+  EXPECT_FALSE(dict.HasKey("a.long.way.down"));
+  EXPECT_FALSE(dict.HasKey("a.long.way"));
+  EXPECT_TRUE(dict.Get("a.long.key.path", NULL));
+
+  removed_item.reset();
+  EXPECT_FALSE(dict.RemovePath("a.long.way.down", &removed_item));
+  EXPECT_FALSE(removed_item);
+  EXPECT_TRUE(dict.Get("a.long.key.path", NULL));
+
+  removed_item.reset();
+  EXPECT_TRUE(dict.RemovePath("a.long.key.path", &removed_item));
+  ASSERT_TRUE(removed_item);
+  EXPECT_TRUE(removed_item->IsType(base::Value::TYPE_BOOLEAN));
+  EXPECT_TRUE(dict.empty());
+}
+
+TEST(ValuesTest, DeepCopy) {
+  DictionaryValue original_dict;
+  scoped_ptr<Value> scoped_null = Value::CreateNullValue();
+  Value* original_null = scoped_null.get();
+  original_dict.Set("null", scoped_null.Pass());
+  scoped_ptr<FundamentalValue> scoped_bool(new FundamentalValue(true));
+  FundamentalValue* original_bool = scoped_bool.get();
+  original_dict.Set("bool", scoped_bool.Pass());
+  scoped_ptr<FundamentalValue> scoped_int(new FundamentalValue(42));
+  FundamentalValue* original_int = scoped_int.get();
+  original_dict.Set("int", scoped_int.Pass());
+  scoped_ptr<FundamentalValue> scoped_double(new FundamentalValue(3.14));
+  FundamentalValue* original_double = scoped_double.get();
+  original_dict.Set("double", scoped_double.Pass());
+  scoped_ptr<StringValue> scoped_string(new StringValue("hello"));
+  StringValue* original_string = scoped_string.get();
+  original_dict.Set("string", scoped_string.Pass());
+  scoped_ptr<StringValue> scoped_string16(
+      new StringValue(ASCIIToUTF16("hello16")));
+  StringValue* original_string16 = scoped_string16.get();
+  original_dict.Set("string16", scoped_string16.Pass());
+
+  scoped_ptr<char[]> original_buffer(new char[42]);
+  memset(original_buffer.get(), '!', 42);
+  scoped_ptr<BinaryValue> scoped_binary(
+      new BinaryValue(original_buffer.Pass(), 42));
+  BinaryValue* original_binary = scoped_binary.get();
+  original_dict.Set("binary", scoped_binary.Pass());
+
+  scoped_ptr<ListValue> scoped_list(new ListValue());
+  Value* original_list = scoped_list.get();
+  scoped_ptr<FundamentalValue> scoped_list_element_0(new FundamentalValue(0));
+  Value* original_list_element_0 = scoped_list_element_0.get();
+  scoped_list->Append(scoped_list_element_0.Pass());
+  scoped_ptr<FundamentalValue> scoped_list_element_1(new FundamentalValue(1));
+  Value* original_list_element_1 = scoped_list_element_1.get();
+  scoped_list->Append(scoped_list_element_1.Pass());
+  original_dict.Set("list", scoped_list.Pass());
+
+  scoped_ptr<DictionaryValue> scoped_nested_dictionary(new DictionaryValue());
+  Value* original_nested_dictionary = scoped_nested_dictionary.get();
+  scoped_nested_dictionary->SetString("key", "value");
+  original_dict.Set("dictionary", scoped_nested_dictionary.Pass());
+
+  scoped_ptr<DictionaryValue> copy_dict = original_dict.CreateDeepCopy();
+  ASSERT_TRUE(copy_dict.get());
+  ASSERT_NE(copy_dict.get(), &original_dict);
+
+  Value* copy_null = NULL;
+  ASSERT_TRUE(copy_dict->Get("null", &copy_null));
+  ASSERT_TRUE(copy_null);
+  ASSERT_NE(copy_null, original_null);
+  ASSERT_TRUE(copy_null->IsType(Value::TYPE_NULL));
+
+  Value* copy_bool = NULL;
+  ASSERT_TRUE(copy_dict->Get("bool", &copy_bool));
+  ASSERT_TRUE(copy_bool);
+  ASSERT_NE(copy_bool, original_bool);
+  ASSERT_TRUE(copy_bool->IsType(Value::TYPE_BOOLEAN));
+  bool copy_bool_value = false;
+  ASSERT_TRUE(copy_bool->GetAsBoolean(&copy_bool_value));
+  ASSERT_TRUE(copy_bool_value);
+
+  Value* copy_int = NULL;
+  ASSERT_TRUE(copy_dict->Get("int", &copy_int));
+  ASSERT_TRUE(copy_int);
+  ASSERT_NE(copy_int, original_int);
+  ASSERT_TRUE(copy_int->IsType(Value::TYPE_INTEGER));
+  int copy_int_value = 0;
+  ASSERT_TRUE(copy_int->GetAsInteger(&copy_int_value));
+  ASSERT_EQ(42, copy_int_value);
+
+  Value* copy_double = NULL;
+  ASSERT_TRUE(copy_dict->Get("double", &copy_double));
+  ASSERT_TRUE(copy_double);
+  ASSERT_NE(copy_double, original_double);
+  ASSERT_TRUE(copy_double->IsType(Value::TYPE_DOUBLE));
+  double copy_double_value = 0;
+  ASSERT_TRUE(copy_double->GetAsDouble(&copy_double_value));
+  ASSERT_EQ(3.14, copy_double_value);
+
+  Value* copy_string = NULL;
+  ASSERT_TRUE(copy_dict->Get("string", &copy_string));
+  ASSERT_TRUE(copy_string);
+  ASSERT_NE(copy_string, original_string);
+  ASSERT_TRUE(copy_string->IsType(Value::TYPE_STRING));
+  std::string copy_string_value;
+  string16 copy_string16_value;
+  ASSERT_TRUE(copy_string->GetAsString(&copy_string_value));
+  ASSERT_TRUE(copy_string->GetAsString(&copy_string16_value));
+  ASSERT_EQ(std::string("hello"), copy_string_value);
+  ASSERT_EQ(ASCIIToUTF16("hello"), copy_string16_value);
+
+  Value* copy_string16 = NULL;
+  ASSERT_TRUE(copy_dict->Get("string16", &copy_string16));
+  ASSERT_TRUE(copy_string16);
+  ASSERT_NE(copy_string16, original_string16);
+  ASSERT_TRUE(copy_string16->IsType(Value::TYPE_STRING));
+  ASSERT_TRUE(copy_string16->GetAsString(&copy_string_value));
+  ASSERT_TRUE(copy_string16->GetAsString(&copy_string16_value));
+  ASSERT_EQ(std::string("hello16"), copy_string_value);
+  ASSERT_EQ(ASCIIToUTF16("hello16"), copy_string16_value);
+
+  Value* copy_binary = NULL;
+  ASSERT_TRUE(copy_dict->Get("binary", &copy_binary));
+  ASSERT_TRUE(copy_binary);
+  ASSERT_NE(copy_binary, original_binary);
+  ASSERT_TRUE(copy_binary->IsType(Value::TYPE_BINARY));
+  ASSERT_NE(original_binary->GetBuffer(),
+    static_cast<BinaryValue*>(copy_binary)->GetBuffer());
+  ASSERT_EQ(original_binary->GetSize(),
+    static_cast<BinaryValue*>(copy_binary)->GetSize());
+  ASSERT_EQ(0, memcmp(original_binary->GetBuffer(),
+               static_cast<BinaryValue*>(copy_binary)->GetBuffer(),
+               original_binary->GetSize()));
+
+  Value* copy_value = NULL;
+  ASSERT_TRUE(copy_dict->Get("list", &copy_value));
+  ASSERT_TRUE(copy_value);
+  ASSERT_NE(copy_value, original_list);
+  ASSERT_TRUE(copy_value->IsType(Value::TYPE_LIST));
+  ListValue* copy_list = NULL;
+  ASSERT_TRUE(copy_value->GetAsList(&copy_list));
+  ASSERT_TRUE(copy_list);
+  ASSERT_EQ(2U, copy_list->GetSize());
+
+  Value* copy_list_element_0;
+  ASSERT_TRUE(copy_list->Get(0, &copy_list_element_0));
+  ASSERT_TRUE(copy_list_element_0);
+  ASSERT_NE(copy_list_element_0, original_list_element_0);
+  int copy_list_element_0_value;
+  ASSERT_TRUE(copy_list_element_0->GetAsInteger(&copy_list_element_0_value));
+  ASSERT_EQ(0, copy_list_element_0_value);
+
+  Value* copy_list_element_1;
+  ASSERT_TRUE(copy_list->Get(1, &copy_list_element_1));
+  ASSERT_TRUE(copy_list_element_1);
+  ASSERT_NE(copy_list_element_1, original_list_element_1);
+  int copy_list_element_1_value;
+  ASSERT_TRUE(copy_list_element_1->GetAsInteger(&copy_list_element_1_value));
+  ASSERT_EQ(1, copy_list_element_1_value);
+
+  copy_value = NULL;
+  ASSERT_TRUE(copy_dict->Get("dictionary", &copy_value));
+  ASSERT_TRUE(copy_value);
+  ASSERT_NE(copy_value, original_nested_dictionary);
+  ASSERT_TRUE(copy_value->IsType(Value::TYPE_DICTIONARY));
+  DictionaryValue* copy_nested_dictionary = NULL;
+  ASSERT_TRUE(copy_value->GetAsDictionary(&copy_nested_dictionary));
+  ASSERT_TRUE(copy_nested_dictionary);
+  EXPECT_TRUE(copy_nested_dictionary->HasKey("key"));
+}
+
+TEST(ValuesTest, Equals) {
+  scoped_ptr<Value> null1(Value::CreateNullValue());
+  scoped_ptr<Value> null2(Value::CreateNullValue());
+  EXPECT_NE(null1.get(), null2.get());
+  EXPECT_TRUE(null1->Equals(null2.get()));
+
+  FundamentalValue boolean(false);
+  EXPECT_FALSE(null1->Equals(&boolean));
+
+  DictionaryValue dv;
+  dv.SetBoolean("a", false);
+  dv.SetInteger("b", 2);
+  dv.SetDouble("c", 2.5);
+  dv.SetString("d1", "string");
+  dv.SetString("d2", ASCIIToUTF16("http://google.com"));
+  dv.Set("e", Value::CreateNullValue());
+
+  scoped_ptr<DictionaryValue> copy = dv.CreateDeepCopy();
+  EXPECT_TRUE(dv.Equals(copy.get()));
+
+  scoped_ptr<ListValue> list(new ListValue);
+  ListValue* original_list = list.get();
+  list->Append(Value::CreateNullValue());
+  list->Append(make_scoped_ptr(new DictionaryValue));
+  scoped_ptr<Value> list_copy(list->CreateDeepCopy());
+
+  dv.Set("f", list.Pass());
+  EXPECT_FALSE(dv.Equals(copy.get()));
+  copy->Set("f", list_copy.Pass());
+  EXPECT_TRUE(dv.Equals(copy.get()));
+
+  original_list->Append(make_scoped_ptr(new FundamentalValue(true)));
+  EXPECT_FALSE(dv.Equals(copy.get()));
+
+  // Check if Equals detects differences in only the keys.
+  copy = dv.CreateDeepCopy();
+  EXPECT_TRUE(dv.Equals(copy.get()));
+  copy->Remove("a", NULL);
+  copy->SetBoolean("aa", false);
+  EXPECT_FALSE(dv.Equals(copy.get()));
+}
+
+TEST(ValuesTest, StaticEquals) {
+  scoped_ptr<Value> null1(Value::CreateNullValue());
+  scoped_ptr<Value> null2(Value::CreateNullValue());
+  EXPECT_TRUE(Value::Equals(null1.get(), null2.get()));
+  EXPECT_TRUE(Value::Equals(NULL, NULL));
+
+  scoped_ptr<Value> i42(new FundamentalValue(42));
+  scoped_ptr<Value> j42(new FundamentalValue(42));
+  scoped_ptr<Value> i17(new FundamentalValue(17));
+  EXPECT_TRUE(Value::Equals(i42.get(), i42.get()));
+  EXPECT_TRUE(Value::Equals(j42.get(), i42.get()));
+  EXPECT_TRUE(Value::Equals(i42.get(), j42.get()));
+  EXPECT_FALSE(Value::Equals(i42.get(), i17.get()));
+  EXPECT_FALSE(Value::Equals(i42.get(), NULL));
+  EXPECT_FALSE(Value::Equals(NULL, i42.get()));
+
+  // NULL and Value::CreateNullValue() are intentionally different: We need
+  // support for NULL as a return value for "undefined" without caring for
+  // ownership of the pointer.
+  EXPECT_FALSE(Value::Equals(null1.get(), NULL));
+  EXPECT_FALSE(Value::Equals(NULL, null1.get()));
+}
+
+TEST(ValuesTest, DeepCopyCovariantReturnTypes) {
+  DictionaryValue original_dict;
+  scoped_ptr<Value> scoped_null(Value::CreateNullValue());
+  Value* original_null = scoped_null.get();
+  original_dict.Set("null", scoped_null.Pass());
+  scoped_ptr<FundamentalValue> scoped_bool(new FundamentalValue(true));
+  Value* original_bool = scoped_bool.get();
+  original_dict.Set("bool", scoped_bool.Pass());
+  scoped_ptr<FundamentalValue> scoped_int(new FundamentalValue(42));
+  Value* original_int = scoped_int.get();
+  original_dict.Set("int", scoped_int.Pass());
+  scoped_ptr<FundamentalValue> scoped_double(new FundamentalValue(3.14));
+  Value* original_double = scoped_double.get();
+  original_dict.Set("double", scoped_double.Pass());
+  scoped_ptr<StringValue> scoped_string(new StringValue("hello"));
+  Value* original_string = scoped_string.get();
+  original_dict.Set("string", scoped_string.Pass());
+  scoped_ptr<StringValue> scoped_string16(
+      new StringValue(ASCIIToUTF16("hello16")));
+  Value* original_string16 = scoped_string16.get();
+  original_dict.Set("string16", scoped_string16.Pass());
+
+  scoped_ptr<char[]> original_buffer(new char[42]);
+  memset(original_buffer.get(), '!', 42);
+  scoped_ptr<BinaryValue> scoped_binary(
+      new BinaryValue(original_buffer.Pass(), 42));
+  Value* original_binary = scoped_binary.get();
+  original_dict.Set("binary", scoped_binary.Pass());
+
+  scoped_ptr<ListValue> scoped_list(new ListValue());
+  Value* original_list = scoped_list.get();
+  scoped_ptr<FundamentalValue> scoped_list_element_0(new FundamentalValue(0));
+  scoped_list->Append(scoped_list_element_0.Pass());
+  scoped_ptr<FundamentalValue> scoped_list_element_1(new FundamentalValue(1));
+  scoped_list->Append(scoped_list_element_1.Pass());
+  original_dict.Set("list", scoped_list.Pass());
+
+  scoped_ptr<Value> copy_dict = original_dict.CreateDeepCopy();
+  scoped_ptr<Value> copy_null = original_null->CreateDeepCopy();
+  scoped_ptr<Value> copy_bool = original_bool->CreateDeepCopy();
+  scoped_ptr<Value> copy_int = original_int->CreateDeepCopy();
+  scoped_ptr<Value> copy_double = original_double->CreateDeepCopy();
+  scoped_ptr<Value> copy_string = original_string->CreateDeepCopy();
+  scoped_ptr<Value> copy_string16 = original_string16->CreateDeepCopy();
+  scoped_ptr<Value> copy_binary = original_binary->CreateDeepCopy();
+  scoped_ptr<Value> copy_list = original_list->CreateDeepCopy();
+
+  EXPECT_TRUE(original_dict.Equals(copy_dict.get()));
+  EXPECT_TRUE(original_null->Equals(copy_null.get()));
+  EXPECT_TRUE(original_bool->Equals(copy_bool.get()));
+  EXPECT_TRUE(original_int->Equals(copy_int.get()));
+  EXPECT_TRUE(original_double->Equals(copy_double.get()));
+  EXPECT_TRUE(original_string->Equals(copy_string.get()));
+  EXPECT_TRUE(original_string16->Equals(copy_string16.get()));
+  EXPECT_TRUE(original_binary->Equals(copy_binary.get()));
+  EXPECT_TRUE(original_list->Equals(copy_list.get()));
+}
+
+TEST(ValuesTest, RemoveEmptyChildren) {
+  scoped_ptr<DictionaryValue> root(new DictionaryValue);
+  // Remove empty lists and dictionaries.
+  root->Set("empty_dict", make_scoped_ptr(new DictionaryValue));
+  root->Set("empty_list", make_scoped_ptr(new ListValue));
+  root->SetWithoutPathExpansion("a.b.c.d.e",
+                                make_scoped_ptr(new DictionaryValue));
+  root = root->DeepCopyWithoutEmptyChildren();
+  EXPECT_TRUE(root->empty());
+
+  // Make sure we don't prune too much.
+  root->SetBoolean("bool", true);
+  root->Set("empty_dict", make_scoped_ptr(new DictionaryValue));
+  root->SetString("empty_string", std::string());
+  root = root->DeepCopyWithoutEmptyChildren();
+  EXPECT_EQ(2U, root->size());
+
+  // Should do nothing.
+  root = root->DeepCopyWithoutEmptyChildren();
+  EXPECT_EQ(2U, root->size());
+
+  // Nested test cases.  These should all reduce back to the bool and string
+  // set above.
+  {
+    root->Set("a.b.c.d.e", make_scoped_ptr(new DictionaryValue));
+    root = root->DeepCopyWithoutEmptyChildren();
+    EXPECT_EQ(2U, root->size());
+  }
+  {
+    scoped_ptr<DictionaryValue> inner(new DictionaryValue);
+    inner->Set("empty_dict", make_scoped_ptr(new DictionaryValue));
+    inner->Set("empty_list", make_scoped_ptr(new ListValue));
+    root->Set("dict_with_empty_children", inner.Pass());
+    root = root->DeepCopyWithoutEmptyChildren();
+    EXPECT_EQ(2U, root->size());
+  }
+  {
+    scoped_ptr<ListValue> inner(new ListValue);
+    inner->Append(make_scoped_ptr(new DictionaryValue));
+    inner->Append(make_scoped_ptr(new ListValue));
+    root->Set("list_with_empty_children", inner.Pass());
+    root = root->DeepCopyWithoutEmptyChildren();
+    EXPECT_EQ(2U, root->size());
+  }
+
+  // Nested with siblings.
+  {
+    scoped_ptr<ListValue> inner(new ListValue());
+    inner->Append(make_scoped_ptr(new DictionaryValue));
+    inner->Append(make_scoped_ptr(new ListValue));
+    root->Set("list_with_empty_children", inner.Pass());
+    scoped_ptr<DictionaryValue> inner2(new DictionaryValue);
+    inner2->Set("empty_dict", make_scoped_ptr(new DictionaryValue));
+    inner2->Set("empty_list", make_scoped_ptr(new ListValue));
+    root->Set("dict_with_empty_children", inner2.Pass());
+    root = root->DeepCopyWithoutEmptyChildren();
+    EXPECT_EQ(2U, root->size());
+  }
+
+  // Make sure nested values don't get pruned.
+  {
+    scoped_ptr<ListValue> inner(new ListValue);
+    scoped_ptr<ListValue> inner2(new ListValue);
+    inner2->Append(make_scoped_ptr(new StringValue("hello")));
+    inner->Append(make_scoped_ptr(new DictionaryValue));
+    inner->Append(inner2.Pass());
+    root->Set("list_with_empty_children", inner.Pass());
+    root = root->DeepCopyWithoutEmptyChildren();
+    EXPECT_EQ(3U, root->size());
+
+    ListValue* inner_value, *inner_value2;
+    EXPECT_TRUE(root->GetList("list_with_empty_children", &inner_value));
+    EXPECT_EQ(1U, inner_value->GetSize());  // Dictionary was pruned.
+    EXPECT_TRUE(inner_value->GetList(0, &inner_value2));
+    EXPECT_EQ(1U, inner_value2->GetSize());
+  }
+}
+
+TEST(ValuesTest, MergeDictionary) {
+  scoped_ptr<DictionaryValue> base(new DictionaryValue);
+  base->SetString("base_key", "base_key_value_base");
+  base->SetString("collide_key", "collide_key_value_base");
+  scoped_ptr<DictionaryValue> base_sub_dict(new DictionaryValue);
+  base_sub_dict->SetString("sub_base_key", "sub_base_key_value_base");
+  base_sub_dict->SetString("sub_collide_key", "sub_collide_key_value_base");
+  base->Set("sub_dict_key", base_sub_dict.Pass());
+
+  scoped_ptr<DictionaryValue> merge(new DictionaryValue);
+  merge->SetString("merge_key", "merge_key_value_merge");
+  merge->SetString("collide_key", "collide_key_value_merge");
+  scoped_ptr<DictionaryValue> merge_sub_dict(new DictionaryValue);
+  merge_sub_dict->SetString("sub_merge_key", "sub_merge_key_value_merge");
+  merge_sub_dict->SetString("sub_collide_key", "sub_collide_key_value_merge");
+  merge->Set("sub_dict_key", merge_sub_dict.Pass());
+
+  base->MergeDictionary(merge.get());
+
+  EXPECT_EQ(4U, base->size());
+  std::string base_key_value;
+  EXPECT_TRUE(base->GetString("base_key", &base_key_value));
+  EXPECT_EQ("base_key_value_base", base_key_value); // Base value preserved.
+  std::string collide_key_value;
+  EXPECT_TRUE(base->GetString("collide_key", &collide_key_value));
+  EXPECT_EQ("collide_key_value_merge", collide_key_value); // Replaced.
+  std::string merge_key_value;
+  EXPECT_TRUE(base->GetString("merge_key", &merge_key_value));
+  EXPECT_EQ("merge_key_value_merge", merge_key_value); // Merged in.
+
+  DictionaryValue* res_sub_dict;
+  EXPECT_TRUE(base->GetDictionary("sub_dict_key", &res_sub_dict));
+  EXPECT_EQ(3U, res_sub_dict->size());
+  std::string sub_base_key_value;
+  EXPECT_TRUE(res_sub_dict->GetString("sub_base_key", &sub_base_key_value));
+  EXPECT_EQ("sub_base_key_value_base", sub_base_key_value); // Preserved.
+  std::string sub_collide_key_value;
+  EXPECT_TRUE(res_sub_dict->GetString("sub_collide_key",
+                                      &sub_collide_key_value));
+  EXPECT_EQ("sub_collide_key_value_merge", sub_collide_key_value); // Replaced.
+  std::string sub_merge_key_value;
+  EXPECT_TRUE(res_sub_dict->GetString("sub_merge_key", &sub_merge_key_value));
+  EXPECT_EQ("sub_merge_key_value_merge", sub_merge_key_value); // Merged in.
+}
+
+TEST(ValuesTest, MergeDictionaryDeepCopy) {
+  scoped_ptr<DictionaryValue> child(new DictionaryValue);
+  DictionaryValue* original_child = child.get();
+  child->SetString("test", "value");
+  EXPECT_EQ(1U, child->size());
+
+  std::string value;
+  EXPECT_TRUE(child->GetString("test", &value));
+  EXPECT_EQ("value", value);
+
+  scoped_ptr<DictionaryValue> base(new DictionaryValue);
+  base->Set("dict", child.Pass());
+  EXPECT_EQ(1U, base->size());
+
+  DictionaryValue* ptr;
+  EXPECT_TRUE(base->GetDictionary("dict", &ptr));
+  EXPECT_EQ(original_child, ptr);
+
+  scoped_ptr<DictionaryValue> merged(new DictionaryValue);
+  merged->MergeDictionary(base.get());
+  EXPECT_EQ(1U, merged->size());
+  EXPECT_TRUE(merged->GetDictionary("dict", &ptr));
+  EXPECT_NE(original_child, ptr);
+  EXPECT_TRUE(ptr->GetString("test", &value));
+  EXPECT_EQ("value", value);
+
+  original_child->SetString("test", "overwrite");
+  base.reset();
+  EXPECT_TRUE(ptr->GetString("test", &value));
+  EXPECT_EQ("value", value);
+}
+
+TEST(ValuesTest, DictionaryIterator) {
+  DictionaryValue dict;
+  for (DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) {
+    ADD_FAILURE();
+  }
+
+  StringValue value1("value1");
+  dict.Set("key1", value1.CreateDeepCopy());
+  bool seen1 = false;
+  for (DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) {
+    EXPECT_FALSE(seen1);
+    EXPECT_EQ("key1", it.key());
+    EXPECT_TRUE(value1.Equals(&it.value()));
+    seen1 = true;
+  }
+  EXPECT_TRUE(seen1);
+
+  StringValue value2("value2");
+  dict.Set("key2", value2.CreateDeepCopy());
+  bool seen2 = seen1 = false;
+  for (DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) {
+    if (it.key() == "key1") {
+      EXPECT_FALSE(seen1);
+      EXPECT_TRUE(value1.Equals(&it.value()));
+      seen1 = true;
+    } else if (it.key() == "key2") {
+      EXPECT_FALSE(seen2);
+      EXPECT_TRUE(value2.Equals(&it.value()));
+      seen2 = true;
+    } else {
+      ADD_FAILURE();
+    }
+  }
+  EXPECT_TRUE(seen1);
+  EXPECT_TRUE(seen2);
+}
+
+// DictionaryValue/ListValue's Get*() methods should accept NULL as an out-value
+// and still return true/false based on success.
+TEST(ValuesTest, GetWithNullOutValue) {
+  DictionaryValue main_dict;
+  ListValue main_list;
+
+  FundamentalValue bool_value(false);
+  FundamentalValue int_value(1234);
+  FundamentalValue double_value(12.34567);
+  StringValue string_value("foo");
+  BinaryValue binary_value;
+  DictionaryValue dict_value;
+  ListValue list_value;
+
+  main_dict.Set("bool", bool_value.CreateDeepCopy());
+  main_dict.Set("int", int_value.CreateDeepCopy());
+  main_dict.Set("double", double_value.CreateDeepCopy());
+  main_dict.Set("string", string_value.CreateDeepCopy());
+  main_dict.Set("binary", binary_value.CreateDeepCopy());
+  main_dict.Set("dict", dict_value.CreateDeepCopy());
+  main_dict.Set("list", list_value.CreateDeepCopy());
+
+  main_list.Append(bool_value.CreateDeepCopy());
+  main_list.Append(int_value.CreateDeepCopy());
+  main_list.Append(double_value.CreateDeepCopy());
+  main_list.Append(string_value.CreateDeepCopy());
+  main_list.Append(binary_value.CreateDeepCopy());
+  main_list.Append(dict_value.CreateDeepCopy());
+  main_list.Append(list_value.CreateDeepCopy());
+
+  EXPECT_TRUE(main_dict.Get("bool", NULL));
+  EXPECT_TRUE(main_dict.Get("int", NULL));
+  EXPECT_TRUE(main_dict.Get("double", NULL));
+  EXPECT_TRUE(main_dict.Get("string", NULL));
+  EXPECT_TRUE(main_dict.Get("binary", NULL));
+  EXPECT_TRUE(main_dict.Get("dict", NULL));
+  EXPECT_TRUE(main_dict.Get("list", NULL));
+  EXPECT_FALSE(main_dict.Get("DNE", NULL));
+
+  EXPECT_TRUE(main_dict.GetBoolean("bool", NULL));
+  EXPECT_FALSE(main_dict.GetBoolean("int", NULL));
+  EXPECT_FALSE(main_dict.GetBoolean("double", NULL));
+  EXPECT_FALSE(main_dict.GetBoolean("string", NULL));
+  EXPECT_FALSE(main_dict.GetBoolean("binary", NULL));
+  EXPECT_FALSE(main_dict.GetBoolean("dict", NULL));
+  EXPECT_FALSE(main_dict.GetBoolean("list", NULL));
+  EXPECT_FALSE(main_dict.GetBoolean("DNE", NULL));
+
+  EXPECT_FALSE(main_dict.GetInteger("bool", NULL));
+  EXPECT_TRUE(main_dict.GetInteger("int", NULL));
+  EXPECT_FALSE(main_dict.GetInteger("double", NULL));
+  EXPECT_FALSE(main_dict.GetInteger("string", NULL));
+  EXPECT_FALSE(main_dict.GetInteger("binary", NULL));
+  EXPECT_FALSE(main_dict.GetInteger("dict", NULL));
+  EXPECT_FALSE(main_dict.GetInteger("list", NULL));
+  EXPECT_FALSE(main_dict.GetInteger("DNE", NULL));
+
+  // Both int and double values can be obtained from GetDouble.
+  EXPECT_FALSE(main_dict.GetDouble("bool", NULL));
+  EXPECT_TRUE(main_dict.GetDouble("int", NULL));
+  EXPECT_TRUE(main_dict.GetDouble("double", NULL));
+  EXPECT_FALSE(main_dict.GetDouble("string", NULL));
+  EXPECT_FALSE(main_dict.GetDouble("binary", NULL));
+  EXPECT_FALSE(main_dict.GetDouble("dict", NULL));
+  EXPECT_FALSE(main_dict.GetDouble("list", NULL));
+  EXPECT_FALSE(main_dict.GetDouble("DNE", NULL));
+
+  EXPECT_FALSE(main_dict.GetString("bool", static_cast<std::string*>(NULL)));
+  EXPECT_FALSE(main_dict.GetString("int", static_cast<std::string*>(NULL)));
+  EXPECT_FALSE(main_dict.GetString("double", static_cast<std::string*>(NULL)));
+  EXPECT_TRUE(main_dict.GetString("string", static_cast<std::string*>(NULL)));
+  EXPECT_FALSE(main_dict.GetString("binary", static_cast<std::string*>(NULL)));
+  EXPECT_FALSE(main_dict.GetString("dict", static_cast<std::string*>(NULL)));
+  EXPECT_FALSE(main_dict.GetString("list", static_cast<std::string*>(NULL)));
+  EXPECT_FALSE(main_dict.GetString("DNE", static_cast<std::string*>(NULL)));
+
+  EXPECT_FALSE(main_dict.GetString("bool", static_cast<string16*>(NULL)));
+  EXPECT_FALSE(main_dict.GetString("int", static_cast<string16*>(NULL)));
+  EXPECT_FALSE(main_dict.GetString("double", static_cast<string16*>(NULL)));
+  EXPECT_TRUE(main_dict.GetString("string", static_cast<string16*>(NULL)));
+  EXPECT_FALSE(main_dict.GetString("binary", static_cast<string16*>(NULL)));
+  EXPECT_FALSE(main_dict.GetString("dict", static_cast<string16*>(NULL)));
+  EXPECT_FALSE(main_dict.GetString("list", static_cast<string16*>(NULL)));
+  EXPECT_FALSE(main_dict.GetString("DNE", static_cast<string16*>(NULL)));
+
+  EXPECT_FALSE(main_dict.GetBinary("bool", NULL));
+  EXPECT_FALSE(main_dict.GetBinary("int", NULL));
+  EXPECT_FALSE(main_dict.GetBinary("double", NULL));
+  EXPECT_FALSE(main_dict.GetBinary("string", NULL));
+  EXPECT_TRUE(main_dict.GetBinary("binary", NULL));
+  EXPECT_FALSE(main_dict.GetBinary("dict", NULL));
+  EXPECT_FALSE(main_dict.GetBinary("list", NULL));
+  EXPECT_FALSE(main_dict.GetBinary("DNE", NULL));
+
+  EXPECT_FALSE(main_dict.GetDictionary("bool", NULL));
+  EXPECT_FALSE(main_dict.GetDictionary("int", NULL));
+  EXPECT_FALSE(main_dict.GetDictionary("double", NULL));
+  EXPECT_FALSE(main_dict.GetDictionary("string", NULL));
+  EXPECT_FALSE(main_dict.GetDictionary("binary", NULL));
+  EXPECT_TRUE(main_dict.GetDictionary("dict", NULL));
+  EXPECT_FALSE(main_dict.GetDictionary("list", NULL));
+  EXPECT_FALSE(main_dict.GetDictionary("DNE", NULL));
+
+  EXPECT_FALSE(main_dict.GetList("bool", NULL));
+  EXPECT_FALSE(main_dict.GetList("int", NULL));
+  EXPECT_FALSE(main_dict.GetList("double", NULL));
+  EXPECT_FALSE(main_dict.GetList("string", NULL));
+  EXPECT_FALSE(main_dict.GetList("binary", NULL));
+  EXPECT_FALSE(main_dict.GetList("dict", NULL));
+  EXPECT_TRUE(main_dict.GetList("list", NULL));
+  EXPECT_FALSE(main_dict.GetList("DNE", NULL));
+
+  EXPECT_TRUE(main_dict.GetWithoutPathExpansion("bool", NULL));
+  EXPECT_TRUE(main_dict.GetWithoutPathExpansion("int", NULL));
+  EXPECT_TRUE(main_dict.GetWithoutPathExpansion("double", NULL));
+  EXPECT_TRUE(main_dict.GetWithoutPathExpansion("string", NULL));
+  EXPECT_TRUE(main_dict.GetWithoutPathExpansion("binary", NULL));
+  EXPECT_TRUE(main_dict.GetWithoutPathExpansion("dict", NULL));
+  EXPECT_TRUE(main_dict.GetWithoutPathExpansion("list", NULL));
+  EXPECT_FALSE(main_dict.GetWithoutPathExpansion("DNE", NULL));
+
+  EXPECT_TRUE(main_dict.GetBooleanWithoutPathExpansion("bool", NULL));
+  EXPECT_FALSE(main_dict.GetBooleanWithoutPathExpansion("int", NULL));
+  EXPECT_FALSE(main_dict.GetBooleanWithoutPathExpansion("double", NULL));
+  EXPECT_FALSE(main_dict.GetBooleanWithoutPathExpansion("string", NULL));
+  EXPECT_FALSE(main_dict.GetBooleanWithoutPathExpansion("binary", NULL));
+  EXPECT_FALSE(main_dict.GetBooleanWithoutPathExpansion("dict", NULL));
+  EXPECT_FALSE(main_dict.GetBooleanWithoutPathExpansion("list", NULL));
+  EXPECT_FALSE(main_dict.GetBooleanWithoutPathExpansion("DNE", NULL));
+
+  EXPECT_FALSE(main_dict.GetIntegerWithoutPathExpansion("bool", NULL));
+  EXPECT_TRUE(main_dict.GetIntegerWithoutPathExpansion("int", NULL));
+  EXPECT_FALSE(main_dict.GetIntegerWithoutPathExpansion("double", NULL));
+  EXPECT_FALSE(main_dict.GetIntegerWithoutPathExpansion("string", NULL));
+  EXPECT_FALSE(main_dict.GetIntegerWithoutPathExpansion("binary", NULL));
+  EXPECT_FALSE(main_dict.GetIntegerWithoutPathExpansion("dict", NULL));
+  EXPECT_FALSE(main_dict.GetIntegerWithoutPathExpansion("list", NULL));
+  EXPECT_FALSE(main_dict.GetIntegerWithoutPathExpansion("DNE", NULL));
+
+  EXPECT_FALSE(main_dict.GetDoubleWithoutPathExpansion("bool", NULL));
+  EXPECT_TRUE(main_dict.GetDoubleWithoutPathExpansion("int", NULL));
+  EXPECT_TRUE(main_dict.GetDoubleWithoutPathExpansion("double", NULL));
+  EXPECT_FALSE(main_dict.GetDoubleWithoutPathExpansion("string", NULL));
+  EXPECT_FALSE(main_dict.GetDoubleWithoutPathExpansion("binary", NULL));
+  EXPECT_FALSE(main_dict.GetDoubleWithoutPathExpansion("dict", NULL));
+  EXPECT_FALSE(main_dict.GetDoubleWithoutPathExpansion("list", NULL));
+  EXPECT_FALSE(main_dict.GetDoubleWithoutPathExpansion("DNE", NULL));
+
+  EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion(
+      "bool", static_cast<std::string*>(NULL)));
+  EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion(
+      "int", static_cast<std::string*>(NULL)));
+  EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion(
+      "double", static_cast<std::string*>(NULL)));
+  EXPECT_TRUE(main_dict.GetStringWithoutPathExpansion(
+      "string", static_cast<std::string*>(NULL)));
+  EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion(
+      "binary", static_cast<std::string*>(NULL)));
+  EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion(
+      "dict", static_cast<std::string*>(NULL)));
+  EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion(
+      "list", static_cast<std::string*>(NULL)));
+  EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion(
+      "DNE", static_cast<std::string*>(NULL)));
+
+  EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion(
+      "bool", static_cast<string16*>(NULL)));
+  EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion(
+      "int", static_cast<string16*>(NULL)));
+  EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion(
+      "double", static_cast<string16*>(NULL)));
+  EXPECT_TRUE(main_dict.GetStringWithoutPathExpansion(
+      "string", static_cast<string16*>(NULL)));
+  EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion(
+      "binary", static_cast<string16*>(NULL)));
+  EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion(
+      "dict", static_cast<string16*>(NULL)));
+  EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion(
+      "list", static_cast<string16*>(NULL)));
+  EXPECT_FALSE(main_dict.GetStringWithoutPathExpansion(
+      "DNE", static_cast<string16*>(NULL)));
+
+  // There is no GetBinaryWithoutPathExpansion for some reason, but if there
+  // were it should be tested here...
+
+  EXPECT_FALSE(main_dict.GetDictionaryWithoutPathExpansion("bool", NULL));
+  EXPECT_FALSE(main_dict.GetDictionaryWithoutPathExpansion("int", NULL));
+  EXPECT_FALSE(main_dict.GetDictionaryWithoutPathExpansion("double", NULL));
+  EXPECT_FALSE(main_dict.GetDictionaryWithoutPathExpansion("string", NULL));
+  EXPECT_FALSE(main_dict.GetDictionaryWithoutPathExpansion("binary", NULL));
+  EXPECT_TRUE(main_dict.GetDictionaryWithoutPathExpansion("dict", NULL));
+  EXPECT_FALSE(main_dict.GetDictionaryWithoutPathExpansion("list", NULL));
+  EXPECT_FALSE(main_dict.GetDictionaryWithoutPathExpansion("DNE", NULL));
+
+  EXPECT_FALSE(main_dict.GetListWithoutPathExpansion("bool", NULL));
+  EXPECT_FALSE(main_dict.GetListWithoutPathExpansion("int", NULL));
+  EXPECT_FALSE(main_dict.GetListWithoutPathExpansion("double", NULL));
+  EXPECT_FALSE(main_dict.GetListWithoutPathExpansion("string", NULL));
+  EXPECT_FALSE(main_dict.GetListWithoutPathExpansion("binary", NULL));
+  EXPECT_FALSE(main_dict.GetListWithoutPathExpansion("dict", NULL));
+  EXPECT_TRUE(main_dict.GetListWithoutPathExpansion("list", NULL));
+  EXPECT_FALSE(main_dict.GetListWithoutPathExpansion("DNE", NULL));
+
+  EXPECT_TRUE(main_list.Get(0, NULL));
+  EXPECT_TRUE(main_list.Get(1, NULL));
+  EXPECT_TRUE(main_list.Get(2, NULL));
+  EXPECT_TRUE(main_list.Get(3, NULL));
+  EXPECT_TRUE(main_list.Get(4, NULL));
+  EXPECT_TRUE(main_list.Get(5, NULL));
+  EXPECT_TRUE(main_list.Get(6, NULL));
+  EXPECT_FALSE(main_list.Get(7, NULL));
+
+  EXPECT_TRUE(main_list.GetBoolean(0, NULL));
+  EXPECT_FALSE(main_list.GetBoolean(1, NULL));
+  EXPECT_FALSE(main_list.GetBoolean(2, NULL));
+  EXPECT_FALSE(main_list.GetBoolean(3, NULL));
+  EXPECT_FALSE(main_list.GetBoolean(4, NULL));
+  EXPECT_FALSE(main_list.GetBoolean(5, NULL));
+  EXPECT_FALSE(main_list.GetBoolean(6, NULL));
+  EXPECT_FALSE(main_list.GetBoolean(7, NULL));
+
+  EXPECT_FALSE(main_list.GetInteger(0, NULL));
+  EXPECT_TRUE(main_list.GetInteger(1, NULL));
+  EXPECT_FALSE(main_list.GetInteger(2, NULL));
+  EXPECT_FALSE(main_list.GetInteger(3, NULL));
+  EXPECT_FALSE(main_list.GetInteger(4, NULL));
+  EXPECT_FALSE(main_list.GetInteger(5, NULL));
+  EXPECT_FALSE(main_list.GetInteger(6, NULL));
+  EXPECT_FALSE(main_list.GetInteger(7, NULL));
+
+  EXPECT_FALSE(main_list.GetDouble(0, NULL));
+  EXPECT_TRUE(main_list.GetDouble(1, NULL));
+  EXPECT_TRUE(main_list.GetDouble(2, NULL));
+  EXPECT_FALSE(main_list.GetDouble(3, NULL));
+  EXPECT_FALSE(main_list.GetDouble(4, NULL));
+  EXPECT_FALSE(main_list.GetDouble(5, NULL));
+  EXPECT_FALSE(main_list.GetDouble(6, NULL));
+  EXPECT_FALSE(main_list.GetDouble(7, NULL));
+
+  EXPECT_FALSE(main_list.GetString(0, static_cast<std::string*>(NULL)));
+  EXPECT_FALSE(main_list.GetString(1, static_cast<std::string*>(NULL)));
+  EXPECT_FALSE(main_list.GetString(2, static_cast<std::string*>(NULL)));
+  EXPECT_TRUE(main_list.GetString(3, static_cast<std::string*>(NULL)));
+  EXPECT_FALSE(main_list.GetString(4, static_cast<std::string*>(NULL)));
+  EXPECT_FALSE(main_list.GetString(5, static_cast<std::string*>(NULL)));
+  EXPECT_FALSE(main_list.GetString(6, static_cast<std::string*>(NULL)));
+  EXPECT_FALSE(main_list.GetString(7, static_cast<std::string*>(NULL)));
+
+  EXPECT_FALSE(main_list.GetString(0, static_cast<string16*>(NULL)));
+  EXPECT_FALSE(main_list.GetString(1, static_cast<string16*>(NULL)));
+  EXPECT_FALSE(main_list.GetString(2, static_cast<string16*>(NULL)));
+  EXPECT_TRUE(main_list.GetString(3, static_cast<string16*>(NULL)));
+  EXPECT_FALSE(main_list.GetString(4, static_cast<string16*>(NULL)));
+  EXPECT_FALSE(main_list.GetString(5, static_cast<string16*>(NULL)));
+  EXPECT_FALSE(main_list.GetString(6, static_cast<string16*>(NULL)));
+  EXPECT_FALSE(main_list.GetString(7, static_cast<string16*>(NULL)));
+
+  EXPECT_FALSE(main_list.GetBinary(0, NULL));
+  EXPECT_FALSE(main_list.GetBinary(1, NULL));
+  EXPECT_FALSE(main_list.GetBinary(2, NULL));
+  EXPECT_FALSE(main_list.GetBinary(3, NULL));
+  EXPECT_TRUE(main_list.GetBinary(4, NULL));
+  EXPECT_FALSE(main_list.GetBinary(5, NULL));
+  EXPECT_FALSE(main_list.GetBinary(6, NULL));
+  EXPECT_FALSE(main_list.GetBinary(7, NULL));
+
+  EXPECT_FALSE(main_list.GetDictionary(0, NULL));
+  EXPECT_FALSE(main_list.GetDictionary(1, NULL));
+  EXPECT_FALSE(main_list.GetDictionary(2, NULL));
+  EXPECT_FALSE(main_list.GetDictionary(3, NULL));
+  EXPECT_FALSE(main_list.GetDictionary(4, NULL));
+  EXPECT_TRUE(main_list.GetDictionary(5, NULL));
+  EXPECT_FALSE(main_list.GetDictionary(6, NULL));
+  EXPECT_FALSE(main_list.GetDictionary(7, NULL));
+
+  EXPECT_FALSE(main_list.GetList(0, NULL));
+  EXPECT_FALSE(main_list.GetList(1, NULL));
+  EXPECT_FALSE(main_list.GetList(2, NULL));
+  EXPECT_FALSE(main_list.GetList(3, NULL));
+  EXPECT_FALSE(main_list.GetList(4, NULL));
+  EXPECT_FALSE(main_list.GetList(5, NULL));
+  EXPECT_TRUE(main_list.GetList(6, NULL));
+  EXPECT_FALSE(main_list.GetList(7, NULL));
+}
+
+}  // namespace base
diff --git a/base/version.cc b/base/version.cc
new file mode 100644
index 0000000..ede8a45
--- /dev/null
+++ b/base/version.cc
@@ -0,0 +1,176 @@
+// Copyright (c) 2012 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/version.h"
+
+#include <stddef.h>
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+
+namespace base {
+
+namespace {
+
+// Parses the |numbers| vector representing the different numbers
+// inside the version string and constructs a vector of valid integers. It stops
+// when it reaches an invalid item (including the wildcard character). |parsed|
+// is the resulting integer vector. Function returns true if all numbers were
+// parsed successfully, false otherwise.
+bool ParseVersionNumbers(const std::string& version_str,
+                         std::vector<uint32_t>* parsed) {
+  std::vector<std::string> numbers;
+  SplitString(version_str, '.', &numbers);
+  if (numbers.empty())
+    return false;
+
+  for (std::vector<std::string>::const_iterator it = numbers.begin();
+       it != numbers.end(); ++it) {
+    if (StartsWithASCII(*it, "+", false))
+      return false;
+    unsigned int num;
+    if (!StringToUint(*it, &num))
+      return false;
+
+    // This throws out leading zeros for the first item only.
+    if (it == numbers.begin() && UintToString(num) != *it)
+      return false;
+
+    // StringToUint returns unsigned int but Version fields are uint32_t.
+    static_assert(sizeof (uint32_t) == sizeof (unsigned int),
+        "uint32_t must be same as unsigned int");
+    parsed->push_back(num);
+  }
+  return true;
+}
+
+// Compares version components in |components1| with components in
+// |components2|. Returns -1, 0 or 1 if |components1| is less than, equal to,
+// or greater than |components2|, respectively.
+int CompareVersionComponents(const std::vector<uint32_t>& components1,
+                             const std::vector<uint32_t>& components2) {
+  const size_t count = std::min(components1.size(), components2.size());
+  for (size_t i = 0; i < count; ++i) {
+    if (components1[i] > components2[i])
+      return 1;
+    if (components1[i] < components2[i])
+      return -1;
+  }
+  if (components1.size() > components2.size()) {
+    for (size_t i = count; i < components1.size(); ++i) {
+      if (components1[i] > 0)
+        return 1;
+    }
+  } else if (components1.size() < components2.size()) {
+    for (size_t i = count; i < components2.size(); ++i) {
+      if (components2[i] > 0)
+        return -1;
+    }
+  }
+  return 0;
+}
+
+}  // namespace
+
+Version::Version() {
+}
+
+Version::~Version() {
+}
+
+Version::Version(const std::string& version_str) {
+  std::vector<uint32_t> parsed;
+  if (!ParseVersionNumbers(version_str, &parsed))
+    return;
+
+  components_.swap(parsed);
+}
+
+bool Version::IsValid() const {
+  return (!components_.empty());
+}
+
+// static
+bool Version::IsValidWildcardString(const std::string& wildcard_string) {
+  std::string version_string = wildcard_string;
+  if (EndsWith(wildcard_string.c_str(), ".*", false))
+    version_string = wildcard_string.substr(0, wildcard_string.size() - 2);
+
+  Version version(version_string);
+  return version.IsValid();
+}
+
+bool Version::IsOlderThan(const std::string& version_str) const {
+  Version proposed_ver(version_str);
+  if (!proposed_ver.IsValid())
+    return false;
+  return (CompareTo(proposed_ver) < 0);
+}
+
+int Version::CompareToWildcardString(const std::string& wildcard_string) const {
+  DCHECK(IsValid());
+  DCHECK(Version::IsValidWildcardString(wildcard_string));
+
+  // Default behavior if the string doesn't end with a wildcard.
+  if (!EndsWith(wildcard_string.c_str(), ".*", false)) {
+    Version version(wildcard_string);
+    DCHECK(version.IsValid());
+    return CompareTo(version);
+  }
+
+  std::vector<uint32_t> parsed;
+  const bool success = ParseVersionNumbers(
+      wildcard_string.substr(0, wildcard_string.length() - 2), &parsed);
+  DCHECK(success);
+  const int comparison = CompareVersionComponents(components_, parsed);
+  // If the version is smaller than the wildcard version's |parsed| vector,
+  // then the wildcard has no effect (e.g. comparing 1.2.3 and 1.3.*) and the
+  // version is still smaller. Same logic for equality (e.g. comparing 1.2.2 to
+  // 1.2.2.* is 0 regardless of the wildcard). Under this logic,
+  // 1.2.0.0.0.0 compared to 1.2.* is 0.
+  if (comparison == -1 || comparison == 0)
+    return comparison;
+
+  // Catch the case where the digits of |parsed| are found in |components_|,
+  // which means that the two are equal since |parsed| has a trailing "*".
+  // (e.g. 1.2.3 vs. 1.2.* will return 0). All other cases return 1 since
+  // components is greater (e.g. 3.2.3 vs 1.*).
+  DCHECK_GT(parsed.size(), 0UL);
+  const size_t min_num_comp = std::min(components_.size(), parsed.size());
+  for (size_t i = 0; i < min_num_comp; ++i) {
+    if (components_[i] != parsed[i])
+      return 1;
+  }
+  return 0;
+}
+
+bool Version::Equals(const Version& that) const {
+  DCHECK(IsValid());
+  DCHECK(that.IsValid());
+  return (CompareTo(that) == 0);
+}
+
+int Version::CompareTo(const Version& other) const {
+  DCHECK(IsValid());
+  DCHECK(other.IsValid());
+  return CompareVersionComponents(components_, other.components_);
+}
+
+const std::string Version::GetString() const {
+  DCHECK(IsValid());
+  std::string version_str;
+  size_t count = components_.size();
+  for (size_t i = 0; i < count - 1; ++i) {
+    version_str.append(IntToString(components_[i]));
+    version_str.append(".");
+  }
+  version_str.append(IntToString(components_[count - 1]));
+  return version_str;
+}
+
+}  // namespace base
diff --git a/base/version.h b/base/version.h
new file mode 100644
index 0000000..814acaa
--- /dev/null
+++ b/base/version.h
@@ -0,0 +1,73 @@
+// Copyright (c) 2012 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_VERSION_H_
+#define BASE_VERSION_H_
+
+#include <stdint.h>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+
+// Version represents a dotted version number, like "1.2.3.4", supporting
+// parsing and comparison.
+class BASE_EXPORT Version {
+ public:
+  // The only thing you can legally do to a default constructed
+  // Version object is assign to it.
+  Version();
+
+  ~Version();
+
+  // Initializes from a decimal dotted version number, like "0.1.1".
+  // Each component is limited to a uint16. Call IsValid() to learn
+  // the outcome.
+  explicit Version(const std::string& version_str);
+
+  // Returns true if the object contains a valid version number.
+  bool IsValid() const;
+
+  // Returns true if the version wildcard string is valid. The version wildcard
+  // string may end with ".*" (e.g. 1.2.*, 1.*). Any other arrangement with "*"
+  // is invalid (e.g. 1.*.3 or 1.2.3*). This functions defaults to standard
+  // Version behavior (IsValid) if no wildcard is present.
+  static bool IsValidWildcardString(const std::string& wildcard_string);
+
+  // Commonly used pattern. Given a valid version object, compare if a
+  // |version_str| results in a newer version. Returns true if the
+  // string represents valid version and if the version is greater than
+  // than the version of this object.
+  bool IsOlderThan(const std::string& version_str) const;
+
+  bool Equals(const Version& other) const;
+
+  // Returns -1, 0, 1 for <, ==, >.
+  int CompareTo(const Version& other) const;
+
+  // Given a valid version object, compare if a |wildcard_string| results in a
+  // newer version. This function will default to CompareTo if the string does
+  // not end in wildcard sequence ".*". IsValidWildcard(wildcard_string) must be
+  // true before using this function.
+  int CompareToWildcardString(const std::string& wildcard_string) const;
+
+  // Return the string representation of this version.
+  const std::string GetString() const;
+
+  const std::vector<uint32_t>& components() const { return components_; }
+
+ private:
+  std::vector<uint32_t> components_;
+};
+
+}  // namespace base
+
+// TODO(xhwang) remove this when all users are updated to explicitly use the
+// namespace
+using base::Version;
+
+#endif  // BASE_VERSION_H_
diff --git a/base/version_unittest.cc b/base/version_unittest.cc
new file mode 100644
index 0000000..f40ed27
--- /dev/null
+++ b/base/version_unittest.cc
@@ -0,0 +1,154 @@
+// Copyright (c) 2012 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/version.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+TEST(VersionTest, DefaultConstructor) {
+  Version v;
+  EXPECT_FALSE(v.IsValid());
+}
+
+TEST(VersionTest, ValueSemantics) {
+  Version v1("1.2.3.4");
+  EXPECT_TRUE(v1.IsValid());
+  Version v3;
+  EXPECT_FALSE(v3.IsValid());
+  {
+    Version v2(v1);
+    v3 = v2;
+    EXPECT_TRUE(v2.IsValid());
+    EXPECT_TRUE(v1.Equals(v2));
+  }
+  EXPECT_TRUE(v3.Equals(v1));
+}
+
+TEST(VersionTest, GetVersionFromString) {
+  static const struct version_string {
+    const char* input;
+    size_t parts;
+    uint32_t firstpart;
+    bool success;
+  } cases[] = {
+    {"", 0, 0, false},
+    {" ", 0, 0, false},
+    {"\t", 0, 0, false},
+    {"\n", 0, 0, false},
+    {"  ", 0, 0, false},
+    {".", 0, 0, false},
+    {" . ", 0, 0, false},
+    {"0", 1, 0, true},
+    {"0.", 0, 0, false},
+    {"0.0", 2, 0, true},
+    {"4294967295.0", 2, 4294967295, true},
+    {"4294967296.0", 0, 0, false},
+    {"-1.0", 0, 0, false},
+    {"1.-1.0", 0, 0, false},
+    {"1,--1.0", 0, 0, false},
+    {"+1.0", 0, 0, false},
+    {"1.+1.0", 0, 0, false},
+    {"1+1.0", 0, 0, false},
+    {"++1.0", 0, 0, false},
+    {"1.0a", 0, 0, false},
+    {"1.2.3.4.5.6.7.8.9.0", 10, 1, true},
+    {"02.1", 0, 0, false},
+    {"0.01", 2, 0, true},
+    {"f.1", 0, 0, false},
+    {"15.007.20011", 3, 15, true},
+    {"15.5.28.130162", 4, 15, true},
+  };
+
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    Version version(cases[i].input);
+    EXPECT_EQ(cases[i].success, version.IsValid());
+    if (cases[i].success) {
+      EXPECT_EQ(cases[i].parts, version.components().size());
+      EXPECT_EQ(cases[i].firstpart, version.components()[0]);
+    }
+  }
+}
+
+TEST(VersionTest, Compare) {
+  static const struct version_compare {
+    const char* lhs;
+    const char* rhs;
+    int expected;
+  } cases[] = {
+    {"1.0", "1.0", 0},
+    {"1.0", "0.0", 1},
+    {"1.0", "2.0", -1},
+    {"1.0", "1.1", -1},
+    {"1.1", "1.0", 1},
+    {"1.0", "1.0.1", -1},
+    {"1.1", "1.0.1", 1},
+    {"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},
+    {"11.0.10", "15.5.28.130162", -1},
+  };
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    Version lhs(cases[i].lhs);
+    Version rhs(cases[i].rhs);
+    EXPECT_EQ(lhs.CompareTo(rhs), cases[i].expected) <<
+        cases[i].lhs << " ? " << cases[i].rhs;
+
+    EXPECT_EQ(lhs.IsOlderThan(cases[i].rhs), (cases[i].expected == -1));
+  }
+}
+
+TEST(VersionTest, CompareToWildcardString) {
+  static const struct version_compare {
+    const char* lhs;
+    const char* rhs;
+    int expected;
+  } cases[] = {
+    {"1.0", "1.*", 0},
+    {"1.0", "0.*", 1},
+    {"1.0", "2.*", -1},
+    {"1.2.3", "1.2.3.*", 0},
+    {"10.0", "1.0.*", 1},
+    {"1.0", "3.0.*", -1},
+    {"1.4", "1.3.0.*", 1},
+    {"1.3.9", "1.3.*", 0},
+    {"1.4.1", "1.3.*", 1},
+    {"1.3", "1.4.5.*", -1},
+    {"1.5", "1.4.5.*", 1},
+    {"1.3.9", "1.3.*", 0},
+    {"1.2.0.0.0.0", "1.2.*", 0},
+  };
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    const Version version(cases[i].lhs);
+    const int result = version.CompareToWildcardString(cases[i].rhs);
+    EXPECT_EQ(result, cases[i].expected) << cases[i].lhs << "?" << cases[i].rhs;
+  }
+}
+
+TEST(VersionTest, IsValidWildcardString) {
+  static const struct version_compare {
+    const char* version;
+    bool expected;
+  } cases[] = {
+    {"1.0", true},
+    {"", false},
+    {"1.2.3.4.5.6", true},
+    {"1.2.3.*", true},
+    {"1.2.3.5*", false},
+    {"1.2.3.56*", false},
+    {"1.*.3", false},
+    {"20.*", true},
+    {"+2.*", false},
+    {"*", false},
+    {"*.2", false},
+  };
+  for (size_t i = 0; i < arraysize(cases); ++i) {
+    EXPECT_EQ(Version::IsValidWildcardString(cases[i].version),
+        cases[i].expected) << cases[i].version << "?" << cases[i].expected;
+  }
+}
+
+}  // namespace
diff --git a/base/vlog.cc b/base/vlog.cc
new file mode 100644
index 0000000..519ceff
--- /dev/null
+++ b/base/vlog.cc
@@ -0,0 +1,180 @@
+// Copyright (c) 2010 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/vlog.h"
+
+#include <cstddef>
+#include <ostream>
+#include <utility>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+
+namespace logging {
+
+const int VlogInfo::kDefaultVlogLevel = 0;
+
+struct VlogInfo::VmodulePattern {
+  enum MatchTarget { MATCH_MODULE, MATCH_FILE };
+
+  explicit VmodulePattern(const std::string& pattern);
+
+  VmodulePattern();
+
+  std::string pattern;
+  int vlog_level;
+  MatchTarget match_target;
+};
+
+VlogInfo::VmodulePattern::VmodulePattern(const std::string& pattern)
+    : pattern(pattern),
+      vlog_level(VlogInfo::kDefaultVlogLevel),
+      match_target(MATCH_MODULE) {
+  // If the pattern contains a {forward,back} slash, we assume that
+  // it's meant to be tested against the entire __FILE__ string.
+  std::string::size_type first_slash = pattern.find_first_of("\\/");
+  if (first_slash != std::string::npos)
+    match_target = MATCH_FILE;
+}
+
+VlogInfo::VmodulePattern::VmodulePattern()
+    : vlog_level(VlogInfo::kDefaultVlogLevel),
+      match_target(MATCH_MODULE) {}
+
+VlogInfo::VlogInfo(const std::string& v_switch,
+                   const std::string& vmodule_switch,
+                   int* min_log_level)
+    : min_log_level_(min_log_level) {
+  DCHECK(min_log_level != NULL);
+
+  int vlog_level = 0;
+  if (!v_switch.empty()) {
+    if (base::StringToInt(v_switch, &vlog_level)) {
+      SetMaxVlogLevel(vlog_level);
+    } else {
+      DLOG(WARNING) << "Could not parse v switch \"" << v_switch << "\"";
+    }
+  }
+
+  base::StringPairs kv_pairs;
+  if (!base::SplitStringIntoKeyValuePairs(
+          vmodule_switch, '=', ',', &kv_pairs)) {
+    DLOG(WARNING) << "Could not fully parse vmodule switch \""
+                  << vmodule_switch << "\"";
+  }
+  for (base::StringPairs::const_iterator it = kv_pairs.begin();
+       it != kv_pairs.end(); ++it) {
+    VmodulePattern pattern(it->first);
+    if (!base::StringToInt(it->second, &pattern.vlog_level)) {
+      DLOG(WARNING) << "Parsed vlog level for \""
+                    << it->first << "=" << it->second
+                    << "\" as " << pattern.vlog_level;
+    }
+    vmodule_levels_.push_back(pattern);
+  }
+}
+
+VlogInfo::~VlogInfo() {}
+
+namespace {
+
+// Given a path, returns the basename with the extension chopped off
+// (and any -inl suffix).  We avoid using FilePath to minimize the
+// number of dependencies the logging system has.
+base::StringPiece GetModule(const base::StringPiece& file) {
+  base::StringPiece module(file);
+  base::StringPiece::size_type last_slash_pos =
+      module.find_last_of("\\/");
+  if (last_slash_pos != base::StringPiece::npos)
+    module.remove_prefix(last_slash_pos + 1);
+  base::StringPiece::size_type extension_start = module.rfind('.');
+  module = module.substr(0, extension_start);
+  static const char kInlSuffix[] = "-inl";
+  static const int kInlSuffixLen = arraysize(kInlSuffix) - 1;
+  if (module.ends_with(kInlSuffix))
+    module.remove_suffix(kInlSuffixLen);
+  return module;
+}
+
+}  // namespace
+
+int VlogInfo::GetVlogLevel(const base::StringPiece& file) const {
+  if (!vmodule_levels_.empty()) {
+    base::StringPiece module(GetModule(file));
+    for (std::vector<VmodulePattern>::const_iterator it =
+             vmodule_levels_.begin(); it != vmodule_levels_.end(); ++it) {
+      base::StringPiece target(
+          (it->match_target == VmodulePattern::MATCH_FILE) ? file : module);
+      if (MatchVlogPattern(target, it->pattern))
+        return it->vlog_level;
+    }
+  }
+  return GetMaxVlogLevel();
+}
+
+void VlogInfo::SetMaxVlogLevel(int level) {
+  // Log severity is the negative verbosity.
+  *min_log_level_ = -level;
+}
+
+int VlogInfo::GetMaxVlogLevel() const {
+  return -*min_log_level_;
+}
+
+bool MatchVlogPattern(const base::StringPiece& string,
+                      const base::StringPiece& vlog_pattern) {
+  base::StringPiece p(vlog_pattern);
+  base::StringPiece s(string);
+  // Consume characters until the next star.
+  while (!p.empty() && !s.empty() && (p[0] != '*')) {
+    switch (p[0]) {
+      // A slash (forward or back) must match a slash (forward or back).
+      case '/':
+      case '\\':
+        if ((s[0] != '/') && (s[0] != '\\'))
+          return false;
+        break;
+
+      // A '?' matches anything.
+      case '?':
+        break;
+
+      // Anything else must match literally.
+      default:
+        if (p[0] != s[0])
+          return false;
+        break;
+    }
+    p.remove_prefix(1), s.remove_prefix(1);
+  }
+
+  // An empty pattern here matches only an empty string.
+  if (p.empty())
+    return s.empty();
+
+  // Coalesce runs of consecutive stars.  There should be at least
+  // one.
+  while (!p.empty() && (p[0] == '*'))
+    p.remove_prefix(1);
+
+  // Since we moved past the stars, an empty pattern here matches
+  // anything.
+  if (p.empty())
+    return true;
+
+  // Since we moved past the stars and p is non-empty, if some
+  // non-empty substring of s matches p, then we ourselves match.
+  while (!s.empty()) {
+    if (MatchVlogPattern(s, p))
+      return true;
+    s.remove_prefix(1);
+  }
+
+  // Otherwise, we couldn't find a match.
+  return false;
+}
+
+}  // namespace logging
diff --git a/base/vlog.h b/base/vlog.h
new file mode 100644
index 0000000..a32ed14
--- /dev/null
+++ b/base/vlog.h
@@ -0,0 +1,77 @@
+// Copyright (c) 2011 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_VLOG_H_
+#define BASE_VLOG_H_
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/strings/string_piece.h"
+
+namespace logging {
+
+// A helper class containing all the settings for vlogging.
+class BASE_EXPORT VlogInfo {
+ public:
+  static const int kDefaultVlogLevel;
+
+  // |v_switch| gives the default maximal active V-logging level; 0 is
+  // the default.  Normally positive values are used for V-logging
+  // levels.
+  //
+  // |vmodule_switch| gives the per-module maximal V-logging levels to
+  // override the value given by |v_switch|.
+  // E.g. "my_module=2,foo*=3" would change the logging level for all
+  // code in source files "my_module.*" and "foo*.*" ("-inl" suffixes
+  // are also disregarded for this matching).
+  //
+  // |log_severity| points to an int that stores the log level. If a valid
+  // |v_switch| is provided, it will set the log level, and the default
+  // vlog severity will be read from there..
+  //
+  // Any pattern containing a forward or backward slash will be tested
+  // against the whole pathname and not just the module.  E.g.,
+  // "*/foo/bar/*=2" would change the logging level for all code in
+  // source files under a "foo/bar" directory.
+  VlogInfo(const std::string& v_switch,
+           const std::string& vmodule_switch,
+           int* min_log_level);
+  ~VlogInfo();
+
+  // Returns the vlog level for a given file (usually taken from
+  // __FILE__).
+  int GetVlogLevel(const base::StringPiece& file) const;
+
+ private:
+  void SetMaxVlogLevel(int level);
+  int GetMaxVlogLevel() const;
+
+  // VmodulePattern holds all the information for each pattern parsed
+  // from |vmodule_switch|.
+  struct VmodulePattern;
+  std::vector<VmodulePattern> vmodule_levels_;
+  int* min_log_level_;
+
+  DISALLOW_COPY_AND_ASSIGN(VlogInfo);
+};
+
+// Returns true if the string passed in matches the vlog pattern.  The
+// vlog pattern string can contain wildcards like * and ?.  ? matches
+// exactly one character while * matches 0 or more characters.  Also,
+// as a special case, a / or \ character matches either / or \.
+//
+// Examples:
+//   "kh?n" matches "khan" but not "khn" or "khaan"
+//   "kh*n" matches "khn", "khan", or even "khaaaaan"
+//   "/foo\bar" matches "/foo/bar", "\foo\bar", or "/foo\bar"
+//     (disregarding C escaping rules)
+BASE_EXPORT bool MatchVlogPattern(const base::StringPiece& string,
+                                  const base::StringPiece& vlog_pattern);
+
+}  // namespace logging
+
+#endif  // BASE_VLOG_H_
diff --git a/base/vlog_unittest.cc b/base/vlog_unittest.cc
new file mode 100644
index 0000000..b505d4c
--- /dev/null
+++ b/base/vlog_unittest.cc
@@ -0,0 +1,125 @@
+// Copyright (c) 2010 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/vlog.h"
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace logging {
+
+namespace {
+
+TEST(VlogTest, NoVmodule) {
+  int min_log_level = 0;
+  EXPECT_EQ(0,
+            VlogInfo(std::string(), std::string(), &min_log_level)
+                .GetVlogLevel("test1"));
+  EXPECT_EQ(0,
+            VlogInfo("0", std::string(), &min_log_level).GetVlogLevel("test2"));
+  EXPECT_EQ(
+      0, VlogInfo("blah", std::string(), &min_log_level).GetVlogLevel("test3"));
+  EXPECT_EQ(
+      0,
+      VlogInfo("0blah1", std::string(), &min_log_level).GetVlogLevel("test4"));
+  EXPECT_EQ(1,
+            VlogInfo("1", std::string(), &min_log_level).GetVlogLevel("test5"));
+  EXPECT_EQ(5,
+            VlogInfo("5", std::string(), &min_log_level).GetVlogLevel("test6"));
+}
+
+TEST(VlogTest, MatchVlogPattern) {
+  // Degenerate cases.
+  EXPECT_TRUE(MatchVlogPattern("", ""));
+  EXPECT_TRUE(MatchVlogPattern("", "****"));
+  EXPECT_FALSE(MatchVlogPattern("", "x"));
+  EXPECT_FALSE(MatchVlogPattern("x", ""));
+
+  // Basic.
+  EXPECT_TRUE(MatchVlogPattern("blah", "blah"));
+
+  // ? should match exactly one character.
+  EXPECT_TRUE(MatchVlogPattern("blah", "bl?h"));
+  EXPECT_FALSE(MatchVlogPattern("blh", "bl?h"));
+  EXPECT_FALSE(MatchVlogPattern("blaah", "bl?h"));
+  EXPECT_TRUE(MatchVlogPattern("blah", "?lah"));
+  EXPECT_FALSE(MatchVlogPattern("lah", "?lah"));
+  EXPECT_FALSE(MatchVlogPattern("bblah", "?lah"));
+
+  // * can match any number (even 0) of characters.
+  EXPECT_TRUE(MatchVlogPattern("blah", "bl*h"));
+  EXPECT_TRUE(MatchVlogPattern("blabcdefh", "bl*h"));
+  EXPECT_TRUE(MatchVlogPattern("blh", "bl*h"));
+  EXPECT_TRUE(MatchVlogPattern("blah", "*blah"));
+  EXPECT_TRUE(MatchVlogPattern("ohblah", "*blah"));
+  EXPECT_TRUE(MatchVlogPattern("blah", "blah*"));
+  EXPECT_TRUE(MatchVlogPattern("blahhhh", "blah*"));
+  EXPECT_TRUE(MatchVlogPattern("blahhhh", "blah*"));
+  EXPECT_TRUE(MatchVlogPattern("blah", "*blah*"));
+  EXPECT_TRUE(MatchVlogPattern("blahhhh", "*blah*"));
+  EXPECT_TRUE(MatchVlogPattern("bbbblahhhh", "*blah*"));
+
+  // Multiple *s should work fine.
+  EXPECT_TRUE(MatchVlogPattern("ballaah", "b*la*h"));
+  EXPECT_TRUE(MatchVlogPattern("blah", "b*la*h"));
+  EXPECT_TRUE(MatchVlogPattern("bbbblah", "b*la*h"));
+  EXPECT_TRUE(MatchVlogPattern("blaaah", "b*la*h"));
+
+  // There should be no escaping going on.
+  EXPECT_TRUE(MatchVlogPattern("bl\\ah", "bl\\?h"));
+  EXPECT_FALSE(MatchVlogPattern("bl?h", "bl\\?h"));
+  EXPECT_TRUE(MatchVlogPattern("bl\\aaaah", "bl\\*h"));
+  EXPECT_FALSE(MatchVlogPattern("bl*h", "bl\\*h"));
+
+  // Any slash matches any slash.
+  EXPECT_TRUE(MatchVlogPattern("/b\\lah", "/b\\lah"));
+  EXPECT_TRUE(MatchVlogPattern("\\b/lah", "/b\\lah"));
+}
+
+TEST(VlogTest, VmoduleBasic) {
+  const char kVSwitch[] = "-1";
+  const char kVModuleSwitch[] =
+      "foo=,bar=0,baz=blah,,qux=0blah1,quux=1,corge.ext=5";
+  int min_log_level = 0;
+  VlogInfo vlog_info(kVSwitch, kVModuleSwitch, &min_log_level);
+  EXPECT_EQ(-1, vlog_info.GetVlogLevel("/path/to/grault.cc"));
+  EXPECT_EQ(0, vlog_info.GetVlogLevel("/path/to/foo.cc"));
+  EXPECT_EQ(0, vlog_info.GetVlogLevel("D:\\Path\\To\\bar-inl.mm"));
+  EXPECT_EQ(-1, vlog_info.GetVlogLevel("D:\\path\\to what/bar_unittest.m"));
+  EXPECT_EQ(0, vlog_info.GetVlogLevel("baz.h"));
+  EXPECT_EQ(0, vlog_info.GetVlogLevel("/another/path/to/qux.h"));
+  EXPECT_EQ(1, vlog_info.GetVlogLevel("/path/to/quux"));
+  EXPECT_EQ(5, vlog_info.GetVlogLevel("c:\\path/to/corge.ext.h"));
+}
+
+TEST(VlogTest, VmoduleDirs) {
+  const char kVModuleSwitch[] =
+      "foo/bar.cc=1,baz\\*\\qux.cc=2,*quux/*=3,*/*-inl.h=4";
+  int min_log_level = 0;
+  VlogInfo vlog_info(std::string(), kVModuleSwitch, &min_log_level);
+  EXPECT_EQ(0, vlog_info.GetVlogLevel("/foo/bar.cc"));
+  EXPECT_EQ(0, vlog_info.GetVlogLevel("bar.cc"));
+  EXPECT_EQ(1, vlog_info.GetVlogLevel("foo/bar.cc"));
+
+  EXPECT_EQ(0, vlog_info.GetVlogLevel("baz/grault/qux.h"));
+  EXPECT_EQ(0, vlog_info.GetVlogLevel("/baz/grault/qux.cc"));
+  EXPECT_EQ(2, vlog_info.GetVlogLevel("baz/grault/qux.cc"));
+  EXPECT_EQ(2, vlog_info.GetVlogLevel("baz/grault/blah/qux.cc"));
+  EXPECT_EQ(2, vlog_info.GetVlogLevel("baz\\grault\\qux.cc"));
+  EXPECT_EQ(2, vlog_info.GetVlogLevel("baz\\grault//blah\\qux.cc"));
+
+  EXPECT_EQ(0, vlog_info.GetVlogLevel("/foo/bar/baz/quux.cc"));
+  EXPECT_EQ(3, vlog_info.GetVlogLevel("/foo/bar/baz/quux/grault.cc"));
+  EXPECT_EQ(3, vlog_info.GetVlogLevel("/foo\\bar/baz\\quux/grault.cc"));
+
+  EXPECT_EQ(0, vlog_info.GetVlogLevel("foo/bar/test-inl.cc"));
+  EXPECT_EQ(4, vlog_info.GetVlogLevel("foo/bar/test-inl.h"));
+  EXPECT_EQ(4, vlog_info.GetVlogLevel("foo/bar/baz/blah-inl.h"));
+}
+
+}  // namespace
+
+}  // namespace logging
diff --git a/base/win/OWNERS b/base/win/OWNERS
new file mode 100644
index 0000000..8624efe
--- /dev/null
+++ b/base/win/OWNERS
@@ -0,0 +1,3 @@
+cpu@chromium.org
+grt@chromium.org
+rvargas@chromium.org
diff --git a/base/win/dllmain.cc b/base/win/dllmain.cc
new file mode 100644
index 0000000..907c7f4
--- /dev/null
+++ b/base/win/dllmain.cc
@@ -0,0 +1,123 @@
+// Copyright (c) 2012 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.
+
+// Windows doesn't support pthread_key_create's destr_function, and in fact
+// it's a bit tricky to get code to run when a thread exits.  This is
+// cargo-cult magic from http://www.codeproject.com/threads/tls.asp.
+// We are trying to be compatible with both a LoadLibrary style invocation, as
+// well as static linking. This code only needs to be included if we use
+// LoadLibrary, but it hooks into the "standard" set of TLS callbacks that are
+// provided for static linking.
+
+// This code is deliberately written to match the style of calls seen in
+// base/threading/thread_local_storage_win.cc.  Please keep the two in sync if
+// coding conventions are changed.
+
+// WARNING: Do *NOT* try to include this in the construction of the base
+// library, even though it potentially drives code in
+// base/threading/thread_local_storage_win.cc.  If you do, some users will end
+// up getting duplicate definition of DllMain() in some of their later links.
+
+// Force a reference to _tls_used to make the linker create the TLS directory
+// if it's not already there (that is, even if __declspec(thread) is not used).
+// Force a reference to p_thread_callback_dllmain_typical_entry to prevent whole
+// program optimization from discarding the variables.
+
+#include <windows.h>
+
+#include "base/compiler_specific.h"
+#include "base/win/win_util.h"
+
+// Indicate if another service is scanning the callbacks.  When this becomes
+// set to true, then DllMain() will stop supporting the callback service. This
+// value is set to true the first time any of our callbacks are called, as that
+// shows that some other service is handling callbacks.
+static bool linker_notifications_are_active = false;
+
+// This will be our mostly no-op callback that we'll list.  We won't
+// deliberately call it, and if it is called, that means we don't need to do any
+// of the callbacks anymore.  We expect such a call to arrive via a
+// THREAD_ATTACH message, long before we'd have to perform our THREAD_DETACH
+// callbacks.
+static void NTAPI on_callback(PVOID h, DWORD reason, PVOID reserved);
+
+#ifdef _WIN64
+
+#pragma comment(linker, "/INCLUDE:_tls_used")
+#pragma comment(linker, "/INCLUDE:p_thread_callback_dllmain_typical_entry")
+
+#else  // _WIN64
+
+#pragma comment(linker, "/INCLUDE:__tls_used")
+#pragma comment(linker, "/INCLUDE:_p_thread_callback_dllmain_typical_entry")
+
+#endif  // _WIN64
+
+// Explicitly depend on VC\crt\src\tlssup.c variables
+// to bracket the list of TLS callbacks.
+extern "C" PIMAGE_TLS_CALLBACK __xl_a, __xl_z;
+
+// extern "C" suppresses C++ name mangling so we know the symbol names for the
+// linker /INCLUDE:symbol pragmas above.
+extern "C" {
+#ifdef _WIN64
+
+// .CRT section is merged with .rdata on x64 so it must be constant data.
+#pragma data_seg(push, old_seg)
+// Use a typical possible name in the .CRT$XL? list of segments.
+#pragma const_seg(".CRT$XLB")
+// When defining a const variable, it must have external linkage to be sure the
+// linker doesn't discard it.
+extern const PIMAGE_TLS_CALLBACK p_thread_callback_dllmain_typical_entry;
+const PIMAGE_TLS_CALLBACK p_thread_callback_dllmain_typical_entry = on_callback;
+#pragma data_seg(pop, old_seg)
+
+#else  // _WIN64
+
+#pragma data_seg(push, old_seg)
+// Use a typical possible name in the .CRT$XL? list of segments.
+#pragma data_seg(".CRT$XLB")
+PIMAGE_TLS_CALLBACK p_thread_callback_dllmain_typical_entry = on_callback;
+#pragma data_seg(pop, old_seg)
+
+#endif  // _WIN64
+}  // extern "C"
+
+// Custom crash code to get a unique entry in crash reports.
+NOINLINE static void CrashOnProcessDetach() {
+  *static_cast<volatile int*>(0) = 0x356;
+}
+
+// Make DllMain call the listed callbacks.  This way any third parties that are
+// linked in will also be called.
+BOOL WINAPI DllMain(PVOID h, DWORD reason, PVOID reserved) {
+  if (DLL_PROCESS_DETACH == reason && base::win::ShouldCrashOnProcessDetach())
+    CrashOnProcessDetach();
+
+  if (DLL_THREAD_DETACH != reason && DLL_PROCESS_DETACH != reason)
+    return true;  // We won't service THREAD_ATTACH calls.
+
+  if (linker_notifications_are_active)
+    return true;  // Some other service is doing this work.
+
+  for (PIMAGE_TLS_CALLBACK* it = &__xl_a; it < &__xl_z; ++it) {
+    if (*it == NULL || *it == on_callback)
+      continue;  // Don't bother to call our own callback.
+    (*it)(h, reason, reserved);
+  }
+  return true;
+}
+
+static void NTAPI on_callback(PVOID h, DWORD reason, PVOID reserved) {
+  // Do nothing.  We were just a place holder in the list used to test that we
+  // call all items.
+  // If we are called, it means that some other system is scanning the callbacks
+  // and we don't need to do so in DllMain().
+  linker_notifications_are_active = true;
+  // Note: If some other routine some how plays this same game... we could both
+  // decide not to do the scanning <sigh>, but this trick should suppress
+  // duplicate calls on Vista, where the runtime takes care of the callbacks,
+  // and allow us to do the callbacks on XP, where we are currently devoid of
+  // callbacks (due to an explicit LoadLibrary call).
+}
diff --git a/base/win/enum_variant.cc b/base/win/enum_variant.cc
new file mode 100644
index 0000000..2975560
--- /dev/null
+++ b/base/win/enum_variant.cc
@@ -0,0 +1,83 @@
+// Copyright (c) 2011 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/win/enum_variant.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+
+namespace base {
+namespace win {
+
+EnumVariant::EnumVariant(unsigned long count)
+    : items_(new VARIANT[count]),
+      count_(count),
+      current_index_(0) {
+}
+
+EnumVariant::~EnumVariant() {
+}
+
+VARIANT* EnumVariant::ItemAt(unsigned long index) {
+  DCHECK(index < count_);
+  return &items_[index];
+}
+
+ULONG STDMETHODCALLTYPE EnumVariant::AddRef() {
+  return IUnknownImpl::AddRef();
+}
+
+ULONG STDMETHODCALLTYPE EnumVariant::Release() {
+  return IUnknownImpl::Release();
+}
+
+STDMETHODIMP EnumVariant::QueryInterface(REFIID riid, void** ppv) {
+  if (riid == IID_IEnumVARIANT) {
+    *ppv = static_cast<IEnumVARIANT*>(this);
+    AddRef();
+    return S_OK;
+  }
+
+  return IUnknownImpl::QueryInterface(riid, ppv);
+}
+
+STDMETHODIMP EnumVariant::Next(ULONG requested_count,
+                               VARIANT* out_elements,
+                               ULONG* out_elements_received) {
+  unsigned long count = std::min(requested_count, count_ - current_index_);
+  for (unsigned long i = 0; i < count; ++i)
+    out_elements[i] = items_[current_index_ + i];
+  current_index_ += count;
+  *out_elements_received = count;
+
+  return (count == requested_count ? S_OK : S_FALSE);
+}
+
+STDMETHODIMP EnumVariant::Skip(ULONG skip_count) {
+  unsigned long count = skip_count;
+  if (current_index_ + count > count_)
+    count = count_ - current_index_;
+
+  current_index_ += count;
+  return (count == skip_count ? S_OK : S_FALSE);
+}
+
+STDMETHODIMP EnumVariant::Reset() {
+  current_index_ = 0;
+  return S_OK;
+}
+
+STDMETHODIMP EnumVariant::Clone(IEnumVARIANT** out_cloned_object) {
+  EnumVariant* other = new EnumVariant(count_);
+  if (count_ > 0)
+    memcpy(other->ItemAt(0), &items_[0], count_ * sizeof(VARIANT));
+  other->Skip(current_index_);
+  other->AddRef();
+  *out_cloned_object = other;
+  return S_OK;
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/enum_variant.h b/base/win/enum_variant.h
new file mode 100644
index 0000000..2caaccd
--- /dev/null
+++ b/base/win/enum_variant.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2011 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_WIN_ENUM_VARIANT_H_
+#define BASE_WIN_ENUM_VARIANT_H_
+
+#include <unknwn.h>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/win/iunknown_impl.h"
+
+namespace base {
+namespace win {
+
+// A simple implementation of IEnumVARIANT.
+class BASE_EXPORT EnumVariant
+  : public IEnumVARIANT,
+    public IUnknownImpl {
+ public:
+  // The constructor allocates an array of size |count|. Then use
+  // ItemAt to set the value of each item in the array to initialize it.
+  explicit EnumVariant(unsigned long count);
+
+  // Returns a mutable pointer to the item at position |index|.
+  VARIANT* ItemAt(unsigned long index);
+
+  // IUnknown.
+  ULONG STDMETHODCALLTYPE AddRef() override;
+  ULONG STDMETHODCALLTYPE Release() override;
+  STDMETHODIMP QueryInterface(REFIID riid, void** ppv) override;
+
+  // IEnumVARIANT.
+  STDMETHODIMP Next(ULONG requested_count,
+                    VARIANT* out_elements,
+                    ULONG* out_elements_received) override;
+  STDMETHODIMP Skip(ULONG skip_count) override;
+  STDMETHODIMP Reset() override;
+  STDMETHODIMP Clone(IEnumVARIANT** out_cloned_object) override;
+
+ private:
+  ~EnumVariant() override;
+
+  scoped_ptr<VARIANT[]> items_;
+  unsigned long count_;
+  unsigned long current_index_;
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_ENUM_VARIANT_H_
diff --git a/base/win/enum_variant_unittest.cc b/base/win/enum_variant_unittest.cc
new file mode 100644
index 0000000..99645a2
--- /dev/null
+++ b/base/win/enum_variant_unittest.cc
@@ -0,0 +1,118 @@
+// Copyright (c) 2011 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/win/enum_variant.h"
+
+#include "base/win/scoped_com_initializer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace win {
+
+TEST(EnumVariantTest, EmptyEnumVariant) {
+  ScopedCOMInitializer com_initializer;
+
+  EnumVariant* ev = new EnumVariant(0);
+  ev->AddRef();
+
+  IUnknown* iunknown;
+  EXPECT_TRUE(SUCCEEDED(
+      ev->QueryInterface(IID_IUnknown, reinterpret_cast<void**>(&iunknown))));
+  iunknown->Release();
+
+  IEnumVARIANT* ienumvariant;
+  EXPECT_TRUE(SUCCEEDED(
+      ev->QueryInterface(IID_IEnumVARIANT,
+                         reinterpret_cast<void**>(&ienumvariant))));
+  EXPECT_EQ(ev, ienumvariant);
+  ienumvariant->Release();
+
+  VARIANT out_element;
+  ULONG out_received = 0;
+  EXPECT_EQ(S_FALSE, ev->Next(1, &out_element, &out_received));
+  EXPECT_EQ(0, out_received);
+
+  EXPECT_EQ(S_FALSE, ev->Skip(1));
+
+  EXPECT_EQ(S_OK, ev->Reset());
+
+  IEnumVARIANT* ev2 = NULL;
+  EXPECT_EQ(S_OK, ev->Clone(&ev2));
+
+  EXPECT_NE(static_cast<IEnumVARIANT*>(NULL), ev2);
+  EXPECT_NE(ev, ev2);
+  EXPECT_EQ(S_FALSE, ev2->Skip(1));
+  EXPECT_EQ(S_OK, ev2->Reset());
+
+  ULONG ev2_finalrefcount = ev2->Release();
+  EXPECT_EQ(0, ev2_finalrefcount);
+
+  ULONG ev_finalrefcount = ev->Release();
+  EXPECT_EQ(0, ev_finalrefcount);
+}
+
+TEST(EnumVariantTest, SimpleEnumVariant) {
+  ScopedCOMInitializer com_initializer;
+
+  EnumVariant* ev = new EnumVariant(3);
+  ev->AddRef();
+  ev->ItemAt(0)->vt = VT_I4;
+  ev->ItemAt(0)->lVal = 10;
+  ev->ItemAt(1)->vt = VT_I4;
+  ev->ItemAt(1)->lVal = 20;
+  ev->ItemAt(2)->vt = VT_I4;
+  ev->ItemAt(2)->lVal = 30;
+
+  // Get elements one at a time.
+  VARIANT out_element;
+  ULONG out_received = 0;
+  EXPECT_EQ(S_OK, ev->Next(1, &out_element, &out_received));
+  EXPECT_EQ(1, out_received);
+  EXPECT_EQ(VT_I4, out_element.vt);
+  EXPECT_EQ(10, out_element.lVal);
+  EXPECT_EQ(S_OK, ev->Skip(1));
+  EXPECT_EQ(S_OK, ev->Next(1, &out_element, &out_received));
+  EXPECT_EQ(1, out_received);
+  EXPECT_EQ(VT_I4, out_element.vt);
+  EXPECT_EQ(30, out_element.lVal);
+  EXPECT_EQ(S_FALSE, ev->Next(1, &out_element, &out_received));
+
+  // Reset and get all elements at once.
+  VARIANT out_elements[3];
+  EXPECT_EQ(S_OK, ev->Reset());
+  EXPECT_EQ(S_OK, ev->Next(3, out_elements, &out_received));
+  EXPECT_EQ(3, out_received);
+  EXPECT_EQ(VT_I4, out_elements[0].vt);
+  EXPECT_EQ(10, out_elements[0].lVal);
+  EXPECT_EQ(VT_I4, out_elements[1].vt);
+  EXPECT_EQ(20, out_elements[1].lVal);
+  EXPECT_EQ(VT_I4, out_elements[2].vt);
+  EXPECT_EQ(30, out_elements[2].lVal);
+  EXPECT_EQ(S_FALSE, ev->Next(1, &out_element, &out_received));
+
+  // Clone it.
+  IEnumVARIANT* ev2 = NULL;
+  EXPECT_EQ(S_OK, ev->Clone(&ev2));
+  EXPECT_TRUE(ev2 != NULL);
+  EXPECT_EQ(S_FALSE, ev->Next(1, &out_element, &out_received));
+  EXPECT_EQ(S_OK, ev2->Reset());
+  EXPECT_EQ(S_OK, ev2->Next(3, out_elements, &out_received));
+  EXPECT_EQ(3, out_received);
+  EXPECT_EQ(VT_I4, out_elements[0].vt);
+  EXPECT_EQ(10, out_elements[0].lVal);
+  EXPECT_EQ(VT_I4, out_elements[1].vt);
+  EXPECT_EQ(20, out_elements[1].lVal);
+  EXPECT_EQ(VT_I4, out_elements[2].vt);
+  EXPECT_EQ(30, out_elements[2].lVal);
+  EXPECT_EQ(S_FALSE, ev2->Next(1, &out_element, &out_received));
+
+  ULONG ev2_finalrefcount = ev2->Release();
+  EXPECT_EQ(0, ev2_finalrefcount);
+
+  ULONG ev_finalrefcount = ev->Release();
+  EXPECT_EQ(0, ev_finalrefcount);
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/event_trace_consumer.h b/base/win/event_trace_consumer.h
new file mode 100644
index 0000000..fd44894
--- /dev/null
+++ b/base/win/event_trace_consumer.h
@@ -0,0 +1,148 @@
+// Copyright (c) 2012 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.
+//
+// Declaration of a Windows event trace consumer base class.
+#ifndef BASE_WIN_EVENT_TRACE_CONSUMER_H_
+#define BASE_WIN_EVENT_TRACE_CONSUMER_H_
+
+#include <windows.h>
+#include <wmistr.h>
+#include <evntrace.h>
+#include <vector>
+#include "base/basictypes.h"
+
+namespace base {
+namespace win {
+
+// This class is a base class that makes it easier to consume events
+// from realtime or file sessions. Concrete consumers need to subclass
+// a specialization of this class and override the ProcessEvent and/or
+// the ProcessBuffer methods to implement the event consumption logic.
+// Usage might look like:
+// class MyConsumer: public EtwTraceConsumerBase<MyConsumer, 1> {
+//  protected:
+//    static VOID WINAPI ProcessEvent(PEVENT_TRACE event);
+// };
+//
+// MyConsumer consumer;
+// consumer.OpenFileSession(file_path);
+// consumer.Consume();
+template <class ImplClass>
+class EtwTraceConsumerBase {
+ public:
+  // Constructs a closed consumer.
+  EtwTraceConsumerBase() {
+  }
+
+  ~EtwTraceConsumerBase() {
+    Close();
+  }
+
+  // Opens the named realtime session, which must be existent.
+  // Note: You can use OpenRealtimeSession or OpenFileSession
+  //    to open as many as MAXIMUM_WAIT_OBJECTS (63) sessions at
+  //    any one time, though only one of them may be a realtime
+  //    session.
+  HRESULT OpenRealtimeSession(const wchar_t* session_name);
+
+  // Opens the event trace log in "file_name", which must be a full or
+  // relative path to an existing event trace log file.
+  // Note: You can use OpenRealtimeSession or OpenFileSession
+  //    to open as many as kNumSessions at any one time.
+  HRESULT OpenFileSession(const wchar_t* file_name);
+
+  // Consume all open sessions from beginning to end.
+  HRESULT Consume();
+
+  // Close all open sessions.
+  HRESULT Close();
+
+ protected:
+  // Override in subclasses to handle events.
+  static void ProcessEvent(EVENT_TRACE* event) {
+  }
+  // Override in subclasses to handle buffers.
+  static bool ProcessBuffer(EVENT_TRACE_LOGFILE* buffer) {
+    return true;  // keep going
+  }
+
+ protected:
+  // Currently open sessions.
+  std::vector<TRACEHANDLE> trace_handles_;
+
+ private:
+  // These delegate to ImplClass callbacks with saner signatures.
+  static void WINAPI ProcessEventCallback(EVENT_TRACE* event) {
+    ImplClass::ProcessEvent(event);
+  }
+  static ULONG WINAPI ProcessBufferCallback(PEVENT_TRACE_LOGFILE buffer) {
+    return ImplClass::ProcessBuffer(buffer);
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(EtwTraceConsumerBase);
+};
+
+template <class ImplClass> inline
+HRESULT EtwTraceConsumerBase<ImplClass>::OpenRealtimeSession(
+    const wchar_t* session_name) {
+  EVENT_TRACE_LOGFILE logfile = {};
+  logfile.LoggerName = const_cast<wchar_t*>(session_name);
+  logfile.LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
+  logfile.BufferCallback = &ProcessBufferCallback;
+  logfile.EventCallback = &ProcessEventCallback;
+  logfile.Context = this;
+  TRACEHANDLE trace_handle = ::OpenTrace(&logfile);
+  if (reinterpret_cast<TRACEHANDLE>(INVALID_HANDLE_VALUE) == trace_handle)
+    return HRESULT_FROM_WIN32(::GetLastError());
+
+  trace_handles_.push_back(trace_handle);
+  return S_OK;
+}
+
+template <class ImplClass> inline
+HRESULT EtwTraceConsumerBase<ImplClass>::OpenFileSession(
+    const wchar_t* file_name) {
+  EVENT_TRACE_LOGFILE logfile = {};
+  logfile.LogFileName = const_cast<wchar_t*>(file_name);
+  logfile.BufferCallback = &ProcessBufferCallback;
+  logfile.EventCallback = &ProcessEventCallback;
+  logfile.Context = this;
+  TRACEHANDLE trace_handle = ::OpenTrace(&logfile);
+  if (reinterpret_cast<TRACEHANDLE>(INVALID_HANDLE_VALUE) == trace_handle)
+    return HRESULT_FROM_WIN32(::GetLastError());
+
+  trace_handles_.push_back(trace_handle);
+  return S_OK;
+}
+
+template <class ImplClass> inline
+HRESULT EtwTraceConsumerBase<ImplClass>::Consume() {
+  ULONG err = ::ProcessTrace(&trace_handles_[0],
+                             static_cast<ULONG>(trace_handles_.size()),
+                             NULL,
+                             NULL);
+  return HRESULT_FROM_WIN32(err);
+}
+
+template <class ImplClass> inline
+HRESULT EtwTraceConsumerBase<ImplClass>::Close() {
+  HRESULT hr = S_OK;
+  for (size_t i = 0; i < trace_handles_.size(); ++i) {
+    if (NULL != trace_handles_[i]) {
+      ULONG ret = ::CloseTrace(trace_handles_[i]);
+      trace_handles_[i] = NULL;
+
+      if (FAILED(HRESULT_FROM_WIN32(ret)))
+        hr = HRESULT_FROM_WIN32(ret);
+    }
+  }
+  trace_handles_.clear();
+
+  return hr;
+}
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_EVENT_TRACE_CONSUMER_H_
diff --git a/base/win/event_trace_consumer_unittest.cc b/base/win/event_trace_consumer_unittest.cc
new file mode 100644
index 0000000..ecbf238
--- /dev/null
+++ b/base/win/event_trace_consumer_unittest.cc
@@ -0,0 +1,366 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Unit tests for event trace consumer base class.
+#include "base/win/event_trace_consumer.h"
+
+#include <list>
+
+#include <objbase.h>
+
+#include "base/basictypes.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/logging.h"
+#include "base/process/process_handle.h"
+#include "base/strings/stringprintf.h"
+#include "base/win/event_trace_controller.h"
+#include "base/win/event_trace_provider.h"
+#include "base/win/scoped_handle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#include <initguid.h>  // NOLINT - has to be last
+
+namespace base {
+namespace win {
+
+namespace {
+
+typedef std::list<EVENT_TRACE> EventQueue;
+
+class TestConsumer: public EtwTraceConsumerBase<TestConsumer> {
+ public:
+  TestConsumer() {
+    sank_event_.Set(::CreateEvent(NULL, TRUE, FALSE, NULL));
+    ClearQueue();
+  }
+
+  ~TestConsumer() {
+    ClearQueue();
+    sank_event_.Close();
+  }
+
+  void ClearQueue() {
+    for (EventQueue::const_iterator it(events_.begin()), end(events_.end());
+         it != end; ++it) {
+      delete[] reinterpret_cast<char*>(it->MofData);
+    }
+
+    events_.clear();
+  }
+
+  static void EnqueueEvent(EVENT_TRACE* event) {
+    events_.push_back(*event);
+    EVENT_TRACE& back = events_.back();
+
+    if (event->MofData != NULL && event->MofLength != 0) {
+      back.MofData = new char[event->MofLength];
+      memcpy(back.MofData, event->MofData, event->MofLength);
+    }
+  }
+
+  static void ProcessEvent(EVENT_TRACE* event) {
+    EnqueueEvent(event);
+    ::SetEvent(sank_event_.Get());
+  }
+
+  static ScopedHandle sank_event_;
+  static EventQueue events_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TestConsumer);
+};
+
+ScopedHandle TestConsumer::sank_event_;
+EventQueue TestConsumer::events_;
+
+class EtwTraceConsumerBaseTest: public testing::Test {
+ public:
+  EtwTraceConsumerBaseTest()
+      : session_name_(StringPrintf(L"TestSession-%d", GetCurrentProcId())) {
+  }
+
+  void SetUp() override {
+    // Cleanup any potentially dangling sessions.
+    EtwTraceProperties ignore;
+    EtwTraceController::Stop(session_name_.c_str(), &ignore);
+
+    // Allocate a new GUID for each provider test.
+    ASSERT_HRESULT_SUCCEEDED(::CoCreateGuid(&test_provider_));
+  }
+
+  void TearDown() override {
+    // Cleanup any potentially dangling sessions.
+    EtwTraceProperties ignore;
+    EtwTraceController::Stop(session_name_.c_str(), &ignore);
+  }
+
+ protected:
+  GUID test_provider_;
+  std::wstring session_name_;
+};
+
+}  // namespace
+
+TEST_F(EtwTraceConsumerBaseTest, Initialize) {
+  TestConsumer consumer_;
+}
+
+TEST_F(EtwTraceConsumerBaseTest, OpenRealtimeSucceedsWhenNoSession) {
+  TestConsumer consumer_;
+  ASSERT_HRESULT_SUCCEEDED(
+      consumer_.OpenRealtimeSession(session_name_.c_str()));
+}
+
+TEST_F(EtwTraceConsumerBaseTest, ConsumerImmediateFailureWhenNoSession) {
+  TestConsumer consumer_;
+  ASSERT_HRESULT_SUCCEEDED(
+      consumer_.OpenRealtimeSession(session_name_.c_str()));
+  ASSERT_HRESULT_FAILED(consumer_.Consume());
+}
+
+namespace {
+
+class EtwTraceConsumerRealtimeTest: public EtwTraceConsumerBaseTest {
+ public:
+  void SetUp() override {
+    EtwTraceConsumerBaseTest::SetUp();
+    ASSERT_HRESULT_SUCCEEDED(
+        consumer_.OpenRealtimeSession(session_name_.c_str()));
+  }
+
+  void TearDown() override {
+    consumer_.Close();
+    EtwTraceConsumerBaseTest::TearDown();
+  }
+
+  DWORD ConsumerThread() {
+    ::SetEvent(consumer_ready_.Get());
+    return consumer_.Consume();
+  }
+
+  static DWORD WINAPI ConsumerThreadMainProc(void* arg) {
+    return reinterpret_cast<EtwTraceConsumerRealtimeTest*>(arg)->
+        ConsumerThread();
+  }
+
+  HRESULT StartConsumerThread() {
+    consumer_ready_.Set(::CreateEvent(NULL, TRUE, FALSE, NULL));
+    EXPECT_TRUE(consumer_ready_.IsValid());
+    consumer_thread_.Set(::CreateThread(NULL, 0, ConsumerThreadMainProc, this,
+                                        0, NULL));
+    if (consumer_thread_.Get() == NULL)
+      return HRESULT_FROM_WIN32(::GetLastError());
+
+    HANDLE events[] = { consumer_ready_.Get(), consumer_thread_.Get() };
+    DWORD result = ::WaitForMultipleObjects(arraysize(events), events,
+                                            FALSE, INFINITE);
+    switch (result) {
+      case WAIT_OBJECT_0:
+        // The event was set, the consumer_ is ready.
+        return S_OK;
+      case WAIT_OBJECT_0 + 1: {
+          // The thread finished. This may race with the event, so check
+          // explicitly for the event here, before concluding there's trouble.
+          if (::WaitForSingleObject(consumer_ready_.Get(), 0) == WAIT_OBJECT_0)
+            return S_OK;
+          DWORD exit_code = 0;
+          if (::GetExitCodeThread(consumer_thread_.Get(), &exit_code))
+            return exit_code;
+          return HRESULT_FROM_WIN32(::GetLastError());
+        }
+      default:
+        return E_UNEXPECTED;
+    }
+  }
+
+  // Waits for consumer_ thread to exit, and returns its exit code.
+  HRESULT JoinConsumerThread() {
+    if (::WaitForSingleObject(consumer_thread_.Get(), INFINITE) !=
+        WAIT_OBJECT_0) {
+      return HRESULT_FROM_WIN32(::GetLastError());
+    }
+
+    DWORD exit_code = 0;
+    if (::GetExitCodeThread(consumer_thread_.Get(), &exit_code))
+      return exit_code;
+
+    return HRESULT_FROM_WIN32(::GetLastError());
+  }
+
+  TestConsumer consumer_;
+  ScopedHandle consumer_ready_;
+  ScopedHandle consumer_thread_;
+};
+
+}  // namespace
+
+TEST_F(EtwTraceConsumerRealtimeTest, ConsumerReturnsWhenSessionClosed) {
+  EtwTraceController controller;
+  if (controller.StartRealtimeSession(session_name_.c_str(), 100 * 1024) ==
+      E_ACCESSDENIED) {
+    VLOG(1) << "You must be an administrator to run this test on Vista";
+    return;
+  }
+
+  // Start the consumer_.
+  ASSERT_HRESULT_SUCCEEDED(StartConsumerThread());
+
+  // Wait around for the consumer_ thread a bit.
+  ASSERT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(consumer_thread_.Get(), 50));
+  ASSERT_HRESULT_SUCCEEDED(controller.Stop(NULL));
+
+  // The consumer_ returns success on session stop.
+  ASSERT_HRESULT_SUCCEEDED(JoinConsumerThread());
+}
+
+namespace {
+
+// {57E47923-A549-476f-86CA-503D57F59E62}
+DEFINE_GUID(
+    kTestEventType,
+    0x57e47923, 0xa549, 0x476f, 0x86, 0xca, 0x50, 0x3d, 0x57, 0xf5, 0x9e, 0x62);
+
+}  // namespace
+
+TEST_F(EtwTraceConsumerRealtimeTest, ConsumeEvent) {
+  EtwTraceController controller;
+  if (controller.StartRealtimeSession(session_name_.c_str(), 100 * 1024) ==
+      E_ACCESSDENIED) {
+    VLOG(1) << "You must be an administrator to run this test on Vista";
+    return;
+  }
+
+  ASSERT_HRESULT_SUCCEEDED(controller.EnableProvider(
+      test_provider_, TRACE_LEVEL_VERBOSE, 0xFFFFFFFF));
+
+  EtwTraceProvider provider(test_provider_);
+  ASSERT_EQ(ERROR_SUCCESS, provider.Register());
+
+  // Start the consumer_.
+  ASSERT_HRESULT_SUCCEEDED(StartConsumerThread());
+  ASSERT_EQ(0, TestConsumer::events_.size());
+
+  EtwMofEvent<1> event(kTestEventType, 1, TRACE_LEVEL_ERROR);
+  EXPECT_EQ(ERROR_SUCCESS, provider.Log(&event.header));
+  EXPECT_EQ(WAIT_OBJECT_0,
+            ::WaitForSingleObject(TestConsumer::sank_event_.Get(), INFINITE));
+  ASSERT_HRESULT_SUCCEEDED(controller.Stop(NULL));
+  ASSERT_HRESULT_SUCCEEDED(JoinConsumerThread());
+  ASSERT_NE(0u, TestConsumer::events_.size());
+}
+
+namespace {
+
+// We run events through a file session to assert that
+// the content comes through.
+class EtwTraceConsumerDataTest: public EtwTraceConsumerBaseTest {
+ public:
+  EtwTraceConsumerDataTest() {
+  }
+
+  void SetUp() override {
+    EtwTraceConsumerBaseTest::SetUp();
+
+    EtwTraceProperties prop;
+    EtwTraceController::Stop(session_name_.c_str(), &prop);
+
+    // Create a temp dir for this test.
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+    // Construct a temp file name in our dir.
+    temp_file_ = temp_dir_.path().Append(L"test.etl");
+  }
+
+  void TearDown() override {
+    EXPECT_TRUE(base::DeleteFile(temp_file_, false));
+
+    EtwTraceConsumerBaseTest::TearDown();
+  }
+
+  HRESULT LogEventToTempSession(PEVENT_TRACE_HEADER header) {
+    EtwTraceController controller;
+
+    // Set up a file session.
+    HRESULT hr = controller.StartFileSession(session_name_.c_str(),
+                                             temp_file_.value().c_str());
+    if (FAILED(hr))
+      return hr;
+
+    // Enable our provider.
+    EXPECT_HRESULT_SUCCEEDED(controller.EnableProvider(
+        test_provider_, TRACE_LEVEL_VERBOSE, 0xFFFFFFFF));
+
+    EtwTraceProvider provider(test_provider_);
+    // Then register our provider, means we get a session handle immediately.
+    EXPECT_EQ(ERROR_SUCCESS, provider.Register());
+    // Trace the event, it goes to the temp file.
+    EXPECT_EQ(ERROR_SUCCESS, provider.Log(header));
+    EXPECT_HRESULT_SUCCEEDED(controller.DisableProvider(test_provider_));
+    EXPECT_HRESULT_SUCCEEDED(provider.Unregister());
+    EXPECT_HRESULT_SUCCEEDED(controller.Flush(NULL));
+    EXPECT_HRESULT_SUCCEEDED(controller.Stop(NULL));
+
+    return S_OK;
+  }
+
+  HRESULT ConsumeEventFromTempSession() {
+    // Now consume the event(s).
+    TestConsumer consumer_;
+    HRESULT hr = consumer_.OpenFileSession(temp_file_.value().c_str());
+    if (SUCCEEDED(hr))
+      hr = consumer_.Consume();
+    consumer_.Close();
+    // And nab the result.
+    events_.swap(TestConsumer::events_);
+    return hr;
+  }
+
+  HRESULT RoundTripEvent(PEVENT_TRACE_HEADER header, PEVENT_TRACE* trace) {
+    base::DeleteFile(temp_file_, false);
+
+    HRESULT hr = LogEventToTempSession(header);
+    if (SUCCEEDED(hr))
+      hr = ConsumeEventFromTempSession();
+
+    if (FAILED(hr))
+      return hr;
+
+    // We should now have the event in the queue.
+    if (events_.empty())
+      return E_FAIL;
+
+    *trace = &events_.back();
+    return S_OK;
+  }
+
+  EventQueue events_;
+  ScopedTempDir temp_dir_;
+  FilePath temp_file_;
+};
+
+}  // namespace
+
+
+TEST_F(EtwTraceConsumerDataTest, RoundTrip) {
+  EtwMofEvent<1> event(kTestEventType, 1, TRACE_LEVEL_ERROR);
+
+  static const char kData[] = "This is but test data";
+  event.fields[0].DataPtr = reinterpret_cast<ULONG64>(kData);
+  event.fields[0].Length = sizeof(kData);
+
+  PEVENT_TRACE trace = NULL;
+  HRESULT hr = RoundTripEvent(&event.header, &trace);
+  if (hr == E_ACCESSDENIED) {
+    VLOG(1) << "You must be an administrator to run this test on Vista";
+    return;
+  }
+  ASSERT_HRESULT_SUCCEEDED(hr) << "RoundTripEvent failed";
+  ASSERT_TRUE(trace != NULL);
+  ASSERT_EQ(sizeof(kData), trace->MofLength);
+  ASSERT_STREQ(kData, reinterpret_cast<const char*>(trace->MofData));
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/event_trace_controller.cc b/base/win/event_trace_controller.cc
new file mode 100644
index 0000000..9a35a6b
--- /dev/null
+++ b/base/win/event_trace_controller.cc
@@ -0,0 +1,173 @@
+// Copyright (c) 2009 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.
+//
+// Implementation of a Windows event trace controller class.
+#include "base/win/event_trace_controller.h"
+#include "base/logging.h"
+
+namespace base {
+namespace win {
+
+EtwTraceProperties::EtwTraceProperties() {
+  memset(buffer_, 0, sizeof(buffer_));
+  EVENT_TRACE_PROPERTIES* prop = get();
+
+  prop->Wnode.BufferSize = sizeof(buffer_);
+  prop->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
+  prop->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
+  prop->LogFileNameOffset = sizeof(EVENT_TRACE_PROPERTIES) +
+                            sizeof(wchar_t) * kMaxStringLen;
+}
+
+HRESULT EtwTraceProperties::SetLoggerName(const wchar_t* logger_name) {
+  size_t len = wcslen(logger_name) + 1;
+  if (kMaxStringLen < len)
+    return E_INVALIDARG;
+
+  memcpy(buffer_ + get()->LoggerNameOffset,
+         logger_name,
+         sizeof(wchar_t) * len);
+  return S_OK;
+}
+
+HRESULT EtwTraceProperties::SetLoggerFileName(const wchar_t* logger_file_name) {
+  size_t len = wcslen(logger_file_name) + 1;
+  if (kMaxStringLen < len)
+    return E_INVALIDARG;
+
+  memcpy(buffer_ + get()->LogFileNameOffset,
+         logger_file_name,
+         sizeof(wchar_t) * len);
+  return S_OK;
+}
+
+EtwTraceController::EtwTraceController() : session_(NULL) {
+}
+
+EtwTraceController::~EtwTraceController() {
+  Stop(NULL);
+}
+
+HRESULT EtwTraceController::Start(const wchar_t* session_name,
+    EtwTraceProperties* prop) {
+  DCHECK(NULL == session_ && session_name_.empty());
+  EtwTraceProperties ignore;
+  if (prop == NULL)
+    prop = &ignore;
+
+  HRESULT hr = Start(session_name, prop, &session_);
+  if (SUCCEEDED(hr))
+    session_name_ = session_name;
+
+  return hr;
+}
+
+HRESULT EtwTraceController::StartFileSession(const wchar_t* session_name,
+    const wchar_t* logfile_path, bool realtime) {
+  DCHECK(NULL == session_ && session_name_.empty());
+
+  EtwTraceProperties prop;
+  prop.SetLoggerFileName(logfile_path);
+  EVENT_TRACE_PROPERTIES& p = *prop.get();
+  p.Wnode.ClientContext = 1;  // QPC timer accuracy.
+  p.LogFileMode = EVENT_TRACE_FILE_MODE_SEQUENTIAL;  // Sequential log.
+  if (realtime)
+    p.LogFileMode |= EVENT_TRACE_REAL_TIME_MODE;
+
+  p.MaximumFileSize = 100;  // 100M file size.
+  p.FlushTimer = 30;  // 30 seconds flush lag.
+  return Start(session_name, &prop);
+}
+
+HRESULT EtwTraceController::StartRealtimeSession(const wchar_t* session_name,
+    size_t buffer_size) {
+  DCHECK(NULL == session_ && session_name_.empty());
+  EtwTraceProperties prop;
+  EVENT_TRACE_PROPERTIES& p = *prop.get();
+  p.LogFileMode = EVENT_TRACE_REAL_TIME_MODE | EVENT_TRACE_USE_PAGED_MEMORY;
+  p.FlushTimer = 1;  // flush every second.
+  p.BufferSize = 16;  // 16 K buffers.
+  p.LogFileNameOffset = 0;
+  return Start(session_name, &prop);
+}
+
+HRESULT EtwTraceController::EnableProvider(REFGUID provider, UCHAR level,
+    ULONG flags) {
+  ULONG error = ::EnableTrace(TRUE, flags, level, &provider, session_);
+  return HRESULT_FROM_WIN32(error);
+}
+
+HRESULT EtwTraceController::DisableProvider(REFGUID provider) {
+  ULONG error = ::EnableTrace(FALSE, 0, 0, &provider, session_);
+  return HRESULT_FROM_WIN32(error);
+}
+
+HRESULT EtwTraceController::Stop(EtwTraceProperties* properties) {
+  EtwTraceProperties ignore;
+  if (properties == NULL)
+    properties = &ignore;
+
+  ULONG error = ::ControlTrace(session_, NULL, properties->get(),
+    EVENT_TRACE_CONTROL_STOP);
+  if (ERROR_SUCCESS != error)
+    return HRESULT_FROM_WIN32(error);
+
+  session_ = NULL;
+  session_name_.clear();
+  return S_OK;
+}
+
+HRESULT EtwTraceController::Flush(EtwTraceProperties* properties) {
+  EtwTraceProperties ignore;
+  if (properties == NULL)
+    properties = &ignore;
+
+  ULONG error = ::ControlTrace(session_, NULL, properties->get(),
+                               EVENT_TRACE_CONTROL_FLUSH);
+  if (ERROR_SUCCESS != error)
+    return HRESULT_FROM_WIN32(error);
+
+  return S_OK;
+}
+
+HRESULT EtwTraceController::Start(const wchar_t* session_name,
+    EtwTraceProperties* properties, TRACEHANDLE* session_handle) {
+  DCHECK(properties != NULL);
+  ULONG err = ::StartTrace(session_handle, session_name, properties->get());
+  return HRESULT_FROM_WIN32(err);
+}
+
+HRESULT EtwTraceController::Query(const wchar_t* session_name,
+    EtwTraceProperties* properties) {
+  ULONG err = ::ControlTrace(NULL, session_name, properties->get(),
+                             EVENT_TRACE_CONTROL_QUERY);
+  return HRESULT_FROM_WIN32(err);
+};
+
+HRESULT EtwTraceController::Update(const wchar_t* session_name,
+    EtwTraceProperties* properties) {
+  DCHECK(properties != NULL);
+  ULONG err = ::ControlTrace(NULL, session_name, properties->get(),
+                             EVENT_TRACE_CONTROL_UPDATE);
+  return HRESULT_FROM_WIN32(err);
+}
+
+HRESULT EtwTraceController::Stop(const wchar_t* session_name,
+    EtwTraceProperties* properties) {
+  DCHECK(properties != NULL);
+  ULONG err = ::ControlTrace(NULL, session_name, properties->get(),
+                             EVENT_TRACE_CONTROL_STOP);
+  return HRESULT_FROM_WIN32(err);
+}
+
+HRESULT EtwTraceController::Flush(const wchar_t* session_name,
+    EtwTraceProperties* properties) {
+  DCHECK(properties != NULL);
+  ULONG err = ::ControlTrace(NULL, session_name, properties->get(),
+                             EVENT_TRACE_CONTROL_FLUSH);
+  return HRESULT_FROM_WIN32(err);
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/event_trace_controller.h b/base/win/event_trace_controller.h
new file mode 100644
index 0000000..69e755b
--- /dev/null
+++ b/base/win/event_trace_controller.h
@@ -0,0 +1,151 @@
+// Copyright (c) 2011 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.
+//
+// Declaration of a Windows event trace controller class.
+// The controller takes care of creating and manipulating event trace
+// sessions.
+//
+// Event tracing for Windows is a system-provided service that provides
+// logging control and high-performance transport for generic, binary trace
+// events. Event trace providers register with the system by their name,
+// which is a GUID, and can from that point forward receive callbacks that
+// start or end tracing and that change their trace level and enable mask.
+//
+// A trace controller can create an event tracing session, which either
+// sends events to a binary file, or to a realtime consumer, or both.
+//
+// A trace consumer consumes events from zero or one realtime session,
+// as well as potentially from multiple binary trace files.
+#ifndef BASE_WIN_EVENT_TRACE_CONTROLLER_H_
+#define BASE_WIN_EVENT_TRACE_CONTROLLER_H_
+
+#include <windows.h>
+#include <wmistr.h>
+#include <evntrace.h>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace win {
+
+// Utility class to make it easier to work with EVENT_TRACE_PROPERTIES.
+// The EVENT_TRACE_PROPERTIES structure contains information about an
+// event tracing session.
+class BASE_EXPORT EtwTraceProperties {
+ public:
+  EtwTraceProperties();
+
+  EVENT_TRACE_PROPERTIES* get() {
+    return &properties_;
+  }
+
+  const EVENT_TRACE_PROPERTIES* get() const {
+    return reinterpret_cast<const EVENT_TRACE_PROPERTIES*>(&properties_);
+  }
+
+  const wchar_t* GetLoggerName() const {
+    return reinterpret_cast<const wchar_t *>(buffer_ + get()->LoggerNameOffset);
+  }
+
+  // Copies logger_name to the properties structure.
+  HRESULT SetLoggerName(const wchar_t* logger_name);
+  const wchar_t* GetLoggerFileName() const {
+    return reinterpret_cast<const wchar_t*>(buffer_ + get()->LogFileNameOffset);
+  }
+
+  // Copies logger_file_name to the properties structure.
+  HRESULT SetLoggerFileName(const wchar_t* logger_file_name);
+
+  // Max string len for name and session name is 1024 per documentation.
+  static const size_t kMaxStringLen = 1024;
+  // Properties buffer allocates space for header and for
+  // max length for name and session name.
+  static const size_t kBufSize = sizeof(EVENT_TRACE_PROPERTIES)
+      + 2 * sizeof(wchar_t) * (kMaxStringLen);
+
+ private:
+  // The EVENT_TRACE_PROPERTIES structure needs to be overlaid on a
+  // larger buffer to allow storing the logger name and logger file
+  // name contiguously with the structure.
+  union {
+   public:
+    // Our properties header.
+    EVENT_TRACE_PROPERTIES properties_;
+    // The actual size of the buffer is forced by this member.
+    char buffer_[kBufSize];
+  };
+
+  DISALLOW_COPY_AND_ASSIGN(EtwTraceProperties);
+};
+
+// This class implements an ETW controller, which knows how to start and
+// stop event tracing sessions, as well as controlling ETW provider
+// log levels and enable bit masks under the session.
+class BASE_EXPORT EtwTraceController {
+ public:
+  EtwTraceController();
+  ~EtwTraceController();
+
+  // Start a session with given name and properties.
+  HRESULT Start(const wchar_t* session_name, EtwTraceProperties* prop);
+
+  // Starts a session tracing to a file with some default properties.
+  HRESULT StartFileSession(const wchar_t* session_name,
+                           const wchar_t* logfile_path,
+                           bool realtime = false);
+
+  // Starts a realtime session with some default properties.
+  HRESULT StartRealtimeSession(const wchar_t* session_name,
+                               size_t buffer_size);
+
+  // Enables "provider" at "level" for this session.
+  // This will cause all providers registered with the GUID
+  // "provider" to start tracing at the new level, systemwide.
+  HRESULT EnableProvider(const GUID& provider, UCHAR level,
+                         ULONG flags = 0xFFFFFFFF);
+  // Disables "provider".
+  HRESULT DisableProvider(const GUID& provider);
+
+  // Stops our session and retrieve the new properties of the session,
+  // properties may be NULL.
+  HRESULT Stop(EtwTraceProperties* properties);
+
+  // Flushes our session and retrieve the current properties,
+  // properties may be NULL.
+  HRESULT Flush(EtwTraceProperties* properties);
+
+  // Static utility functions for controlling
+  // sessions we don't necessarily own.
+  static HRESULT Start(const wchar_t* session_name,
+                       EtwTraceProperties* properties,
+                       TRACEHANDLE* session_handle);
+
+  static HRESULT Query(const wchar_t* session_name,
+                       EtwTraceProperties* properties);
+
+  static HRESULT Update(const wchar_t* session_name,
+                        EtwTraceProperties* properties);
+
+  static HRESULT Stop(const wchar_t* session_name,
+                      EtwTraceProperties* properties);
+  static HRESULT Flush(const wchar_t* session_name,
+                       EtwTraceProperties* properties);
+
+  // Accessors.
+  TRACEHANDLE session() const { return session_; }
+  const wchar_t* session_name() const { return session_name_.c_str(); }
+
+ private:
+  std::wstring session_name_;
+  TRACEHANDLE session_;
+
+  DISALLOW_COPY_AND_ASSIGN(EtwTraceController);
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_EVENT_TRACE_CONTROLLER_H_
diff --git a/base/win/event_trace_controller_unittest.cc b/base/win/event_trace_controller_unittest.cc
new file mode 100644
index 0000000..a2cd81c
--- /dev/null
+++ b/base/win/event_trace_controller_unittest.cc
@@ -0,0 +1,234 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Unit tests for event trace controller.
+
+#include <objbase.h>
+#include <initguid.h>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/logging.h"
+#include "base/process/process_handle.h"
+#include "base/strings/stringprintf.h"
+#include "base/sys_info.h"
+#include "base/win/event_trace_controller.h"
+#include "base/win/event_trace_provider.h"
+#include "base/win/scoped_handle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+DEFINE_GUID(kGuidNull,
+    0x0000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0);
+
+const ULONG kTestProviderFlags = 0xCAFEBABE;
+
+class TestingProvider: public EtwTraceProvider {
+ public:
+  explicit TestingProvider(const GUID& provider_name)
+      : EtwTraceProvider(provider_name) {
+    callback_event_.Set(::CreateEvent(NULL, TRUE, FALSE, NULL));
+  }
+
+  void WaitForCallback() {
+    ::WaitForSingleObject(callback_event_.Get(), INFINITE);
+    ::ResetEvent(callback_event_.Get());
+  }
+
+ private:
+  void OnEventsEnabled() override { ::SetEvent(callback_event_.Get()); }
+  void PostEventsDisabled() override { ::SetEvent(callback_event_.Get()); }
+
+  ScopedHandle callback_event_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestingProvider);
+};
+
+}  // namespace
+
+TEST(EtwTracePropertiesTest, Initialization) {
+  EtwTraceProperties prop;
+
+  EVENT_TRACE_PROPERTIES* p = prop.get();
+  EXPECT_NE(0u, p->Wnode.BufferSize);
+  EXPECT_EQ(0u, p->Wnode.ProviderId);
+  EXPECT_EQ(0u, p->Wnode.HistoricalContext);
+
+  EXPECT_TRUE(kGuidNull == p->Wnode.Guid);
+  EXPECT_EQ(0, p->Wnode.ClientContext);
+  EXPECT_EQ(WNODE_FLAG_TRACED_GUID, p->Wnode.Flags);
+
+  EXPECT_EQ(0, p->BufferSize);
+  EXPECT_EQ(0, p->MinimumBuffers);
+  EXPECT_EQ(0, p->MaximumBuffers);
+  EXPECT_EQ(0, p->MaximumFileSize);
+  EXPECT_EQ(0, p->LogFileMode);
+  EXPECT_EQ(0, p->FlushTimer);
+  EXPECT_EQ(0, p->EnableFlags);
+  EXPECT_EQ(0, p->AgeLimit);
+
+  EXPECT_EQ(0, p->NumberOfBuffers);
+  EXPECT_EQ(0, p->FreeBuffers);
+  EXPECT_EQ(0, p->EventsLost);
+  EXPECT_EQ(0, p->BuffersWritten);
+  EXPECT_EQ(0, p->LogBuffersLost);
+  EXPECT_EQ(0, p->RealTimeBuffersLost);
+  EXPECT_EQ(0, p->LoggerThreadId);
+  EXPECT_NE(0u, p->LogFileNameOffset);
+  EXPECT_NE(0u, p->LoggerNameOffset);
+}
+
+TEST(EtwTracePropertiesTest, Strings) {
+  EtwTraceProperties prop;
+
+  ASSERT_STREQ(L"", prop.GetLoggerFileName());
+  ASSERT_STREQ(L"", prop.GetLoggerName());
+
+  std::wstring name(1023, L'A');
+  ASSERT_HRESULT_SUCCEEDED(prop.SetLoggerFileName(name.c_str()));
+  ASSERT_HRESULT_SUCCEEDED(prop.SetLoggerName(name.c_str()));
+  ASSERT_STREQ(name.c_str(), prop.GetLoggerFileName());
+  ASSERT_STREQ(name.c_str(), prop.GetLoggerName());
+
+  std::wstring name2(1024, L'A');
+  ASSERT_HRESULT_FAILED(prop.SetLoggerFileName(name2.c_str()));
+  ASSERT_HRESULT_FAILED(prop.SetLoggerName(name2.c_str()));
+}
+
+namespace {
+
+class EtwTraceControllerTest : public testing::Test {
+ public:
+  EtwTraceControllerTest()
+      : session_name_(StringPrintf(L"TestSession-%d", GetCurrentProcId())) {
+  }
+
+  void SetUp() override {
+    EtwTraceProperties ignore;
+    EtwTraceController::Stop(session_name_.c_str(), &ignore);
+
+    // Allocate a new provider name GUID for each test.
+    ASSERT_HRESULT_SUCCEEDED(::CoCreateGuid(&test_provider_));
+  }
+
+  void TearDown() override {
+    EtwTraceProperties prop;
+    EtwTraceController::Stop(session_name_.c_str(), &prop);
+  }
+
+ protected:
+  GUID test_provider_;
+  std::wstring session_name_;
+};
+
+}  // namespace
+
+TEST_F(EtwTraceControllerTest, Initialize) {
+  EtwTraceController controller;
+
+  EXPECT_EQ(NULL, controller.session());
+  EXPECT_STREQ(L"", controller.session_name());
+}
+
+
+TEST_F(EtwTraceControllerTest, StartRealTimeSession) {
+  EtwTraceController controller;
+
+  HRESULT hr = controller.StartRealtimeSession(session_name_.c_str(),
+                                               100 * 1024);
+  if (hr == E_ACCESSDENIED) {
+    VLOG(1) << "You must be an administrator to run this test on Vista";
+    return;
+  }
+
+  EXPECT_TRUE(NULL != controller.session());
+  EXPECT_STREQ(session_name_.c_str(), controller.session_name());
+
+  EXPECT_HRESULT_SUCCEEDED(controller.Stop(NULL));
+  EXPECT_EQ(NULL, controller.session());
+  EXPECT_STREQ(L"", controller.session_name());
+}
+
+TEST_F(EtwTraceControllerTest, StartFileSession) {
+  ScopedTempDir temp_dir;
+  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+  FilePath temp;
+  ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir.path(), &temp));
+
+  EtwTraceController controller;
+  HRESULT hr = controller.StartFileSession(session_name_.c_str(),
+                                           temp.value().c_str());
+  if (hr == E_ACCESSDENIED) {
+    VLOG(1) << "You must be an administrator to run this test on Vista";
+    base::DeleteFile(temp, false);
+    return;
+  }
+
+  EXPECT_TRUE(NULL != controller.session());
+  EXPECT_STREQ(session_name_.c_str(), controller.session_name());
+
+  EXPECT_HRESULT_SUCCEEDED(controller.Stop(NULL));
+  EXPECT_EQ(NULL, controller.session());
+  EXPECT_STREQ(L"", controller.session_name());
+  base::DeleteFile(temp, false);
+}
+
+TEST_F(EtwTraceControllerTest, EnableDisable) {
+  TestingProvider provider(test_provider_);
+
+  EXPECT_EQ(ERROR_SUCCESS, provider.Register());
+  EXPECT_EQ(NULL, provider.session_handle());
+
+  EtwTraceController controller;
+  HRESULT hr = controller.StartRealtimeSession(session_name_.c_str(),
+                                               100 * 1024);
+  if (hr == E_ACCESSDENIED) {
+    VLOG(1) << "You must be an administrator to run this test on Vista";
+    return;
+  }
+
+  EXPECT_HRESULT_SUCCEEDED(controller.EnableProvider(test_provider_,
+                           TRACE_LEVEL_VERBOSE, kTestProviderFlags));
+
+  provider.WaitForCallback();
+
+  EXPECT_EQ(TRACE_LEVEL_VERBOSE, provider.enable_level());
+  EXPECT_EQ(kTestProviderFlags, provider.enable_flags());
+
+  EXPECT_HRESULT_SUCCEEDED(controller.DisableProvider(test_provider_));
+
+  provider.WaitForCallback();
+
+  EXPECT_EQ(0, provider.enable_level());
+  EXPECT_EQ(0, provider.enable_flags());
+
+  EXPECT_EQ(ERROR_SUCCESS, provider.Unregister());
+
+  // Enable the provider again, before registering.
+  EXPECT_HRESULT_SUCCEEDED(controller.EnableProvider(test_provider_,
+                           TRACE_LEVEL_VERBOSE, kTestProviderFlags));
+
+  // Register the provider again, the settings above
+  // should take immediate effect.
+  EXPECT_EQ(ERROR_SUCCESS, provider.Register());
+
+  EXPECT_EQ(TRACE_LEVEL_VERBOSE, provider.enable_level());
+  EXPECT_EQ(kTestProviderFlags, provider.enable_flags());
+
+  EXPECT_HRESULT_SUCCEEDED(controller.Stop(NULL));
+
+  provider.WaitForCallback();
+
+  // Session should have wound down.
+  EXPECT_EQ(0, provider.enable_level());
+  EXPECT_EQ(0, provider.enable_flags());
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/event_trace_provider.cc b/base/win/event_trace_provider.cc
new file mode 100644
index 0000000..8fcf67d
--- /dev/null
+++ b/base/win/event_trace_provider.cc
@@ -0,0 +1,134 @@
+// Copyright (c) 2012 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/win/event_trace_provider.h"
+#include <windows.h>
+#include <cguid.h>
+
+namespace base {
+namespace win {
+
+TRACE_GUID_REGISTRATION EtwTraceProvider::obligatory_guid_registration_ = {
+  &GUID_NULL,
+  NULL
+};
+
+EtwTraceProvider::EtwTraceProvider(const GUID& provider_name)
+    : provider_name_(provider_name), registration_handle_(NULL),
+      session_handle_(NULL), enable_flags_(0), enable_level_(0) {
+}
+
+EtwTraceProvider::EtwTraceProvider()
+    : provider_name_(GUID_NULL), registration_handle_(NULL),
+      session_handle_(NULL), enable_flags_(0), enable_level_(0) {
+}
+
+EtwTraceProvider::~EtwTraceProvider() {
+  Unregister();
+}
+
+ULONG EtwTraceProvider::EnableEvents(void* buffer) {
+  session_handle_ = ::GetTraceLoggerHandle(buffer);
+  if (NULL == session_handle_) {
+    return ::GetLastError();
+  }
+
+  enable_flags_ = ::GetTraceEnableFlags(session_handle_);
+  enable_level_ = ::GetTraceEnableLevel(session_handle_);
+
+  // Give subclasses a chance to digest the state change.
+  OnEventsEnabled();
+
+  return ERROR_SUCCESS;
+}
+
+ULONG EtwTraceProvider::DisableEvents() {
+  // Give subclasses a chance to digest the state change.
+  OnEventsDisabled();
+
+  enable_level_ = 0;
+  enable_flags_ = 0;
+  session_handle_ = NULL;
+
+  PostEventsDisabled();
+
+  return ERROR_SUCCESS;
+}
+
+ULONG EtwTraceProvider::Callback(WMIDPREQUESTCODE request, void* buffer) {
+  switch (request) {
+    case WMI_ENABLE_EVENTS:
+      return EnableEvents(buffer);
+    case WMI_DISABLE_EVENTS:
+      return DisableEvents();
+    default:
+      return ERROR_INVALID_PARAMETER;
+  }
+  // Not reached.
+}
+
+ULONG WINAPI EtwTraceProvider::ControlCallback(WMIDPREQUESTCODE request,
+    void* context, ULONG *reserved, void* buffer) {
+  EtwTraceProvider *provider = reinterpret_cast<EtwTraceProvider*>(context);
+
+  return provider->Callback(request, buffer);
+}
+
+ULONG EtwTraceProvider::Register() {
+  if (provider_name_ == GUID_NULL)
+    return ERROR_INVALID_NAME;
+
+  return ::RegisterTraceGuids(ControlCallback, this, &provider_name_,
+      1, &obligatory_guid_registration_, NULL, NULL, &registration_handle_);
+}
+
+ULONG EtwTraceProvider::Unregister() {
+  // If a session is active, notify subclasses that it's going away.
+  if (session_handle_ != NULL)
+    DisableEvents();
+
+  ULONG ret = ::UnregisterTraceGuids(registration_handle_);
+
+  registration_handle_ = NULL;
+
+  return ret;
+}
+
+ULONG EtwTraceProvider::Log(const EtwEventClass& event_class,
+    EtwEventType type, EtwEventLevel level, const char *message) {
+  if (NULL == session_handle_ || enable_level_ < level)
+    return ERROR_SUCCESS;  // No one listening.
+
+  EtwMofEvent<1> event(event_class, type, level);
+
+  event.fields[0].DataPtr = reinterpret_cast<ULONG64>(message);
+  event.fields[0].Length = message ?
+      static_cast<ULONG>(sizeof(message[0]) * (1 + strlen(message))) : 0;
+
+  return ::TraceEvent(session_handle_, &event.header);
+}
+
+ULONG EtwTraceProvider::Log(const EtwEventClass& event_class,
+    EtwEventType type, EtwEventLevel level, const wchar_t *message) {
+  if (NULL == session_handle_ || enable_level_ < level)
+    return ERROR_SUCCESS;  // No one listening.
+
+  EtwMofEvent<1> event(event_class, type, level);
+
+  event.fields[0].DataPtr = reinterpret_cast<ULONG64>(message);
+  event.fields[0].Length = message ?
+      static_cast<ULONG>(sizeof(message[0]) * (1 + wcslen(message))) : 0;
+
+  return ::TraceEvent(session_handle_, &event.header);
+}
+
+ULONG EtwTraceProvider::Log(EVENT_TRACE_HEADER* event) {
+  if (enable_level_ < event->Class.Level)
+    return ERROR_SUCCESS;
+
+  return ::TraceEvent(session_handle_, event);
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/event_trace_provider.h b/base/win/event_trace_provider.h
new file mode 100644
index 0000000..7907347
--- /dev/null
+++ b/base/win/event_trace_provider.h
@@ -0,0 +1,180 @@
+// Copyright (c) 2011 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.
+//
+// Declaration of a Windows event trace provider class, to allow using
+// Windows Event Tracing for logging transport and control.
+#ifndef BASE_WIN_EVENT_TRACE_PROVIDER_H_
+#define BASE_WIN_EVENT_TRACE_PROVIDER_H_
+
+#include <windows.h>
+#include <wmistr.h>
+#include <evntrace.h>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace win {
+
+typedef GUID EtwEventClass;
+typedef UCHAR EtwEventType;
+typedef UCHAR EtwEventLevel;
+typedef USHORT EtwEventVersion;
+typedef ULONG EtwEventFlags;
+
+// Base class is a POD for correctness.
+template <size_t N> struct EtwMofEventBase {
+  EVENT_TRACE_HEADER header;
+  MOF_FIELD fields[N];
+};
+
+// Utility class to auto-initialize event trace header structures.
+template <size_t N> class EtwMofEvent: public EtwMofEventBase<N> {
+ public:
+  typedef EtwMofEventBase<N> Super;
+
+  // Clang and the C++ standard don't allow unqualified lookup into dependent
+  // bases, hence these using decls to explicitly pull the names out.
+  using EtwMofEventBase<N>::header;
+  using EtwMofEventBase<N>::fields;
+
+  EtwMofEvent() {
+    memset(static_cast<Super*>(this), 0, sizeof(Super));
+  }
+
+  EtwMofEvent(const EtwEventClass& event_class, EtwEventType type,
+              EtwEventLevel level) {
+    memset(static_cast<Super*>(this), 0, sizeof(Super));
+    header.Size = sizeof(Super);
+    header.Guid = event_class;
+    header.Class.Type = type;
+    header.Class.Level = level;
+    header.Flags = WNODE_FLAG_TRACED_GUID | WNODE_FLAG_USE_MOF_PTR;
+  }
+
+  EtwMofEvent(const EtwEventClass& event_class, EtwEventType type,
+              EtwEventVersion version, EtwEventLevel level) {
+    memset(static_cast<Super*>(this), 0, sizeof(Super));
+    header.Size = sizeof(Super);
+    header.Guid = event_class;
+    header.Class.Type = type;
+    header.Class.Version = version;
+    header.Class.Level = level;
+    header.Flags = WNODE_FLAG_TRACED_GUID | WNODE_FLAG_USE_MOF_PTR;
+  }
+
+  void SetField(int field, size_t size, const void *data) {
+    // DCHECK(field < N);
+    if ((field < N) && (size <= kuint32max)) {
+      fields[field].DataPtr = reinterpret_cast<ULONG64>(data);
+      fields[field].Length = static_cast<ULONG>(size);
+    }
+  }
+
+  EVENT_TRACE_HEADER* get() { return& header; }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(EtwMofEvent);
+};
+
+// Trace provider with Event Tracing for Windows. The trace provider
+// registers with ETW by its name which is a GUID. ETW calls back to
+// the object whenever the trace level or enable flags for this provider
+// name changes.
+// Users of this class can test whether logging is currently enabled at
+// a particular trace level, and whether particular enable flags are set,
+// before other resources are consumed to generate and issue the log
+// messages themselves.
+class BASE_EXPORT EtwTraceProvider {
+ public:
+  // Creates an event trace provider identified by provider_name, which
+  // will be the name registered with Event Tracing for Windows (ETW).
+  explicit EtwTraceProvider(const GUID& provider_name);
+
+  // Creates an unnamed event trace provider, the provider must be given
+  // a name before registration.
+  EtwTraceProvider();
+  virtual ~EtwTraceProvider();
+
+  // Registers the trace provider with Event Tracing for Windows.
+  // Note: from this point forward ETW may call the provider's control
+  //    callback. If the provider's name is enabled in some trace session
+  //    already, the callback may occur recursively from this call, so
+  //    call this only when you're ready to handle callbacks.
+  ULONG Register();
+  // Unregisters the trace provider with ETW.
+  ULONG Unregister();
+
+  // Accessors.
+  void set_provider_name(const GUID& provider_name) {
+    provider_name_ = provider_name;
+  }
+  const GUID& provider_name() const { return provider_name_; }
+  TRACEHANDLE registration_handle() const { return registration_handle_; }
+  TRACEHANDLE session_handle() const { return session_handle_; }
+  EtwEventFlags enable_flags() const { return enable_flags_; }
+  EtwEventLevel enable_level() const { return enable_level_; }
+
+  // Returns true iff logging should be performed for "level" and "flags".
+  // Note: flags is treated as a bitmask, and should normally have a single
+  //      bit set, to test whether to log for a particular sub "facility".
+  bool ShouldLog(EtwEventLevel level, EtwEventFlags flags) {
+    return NULL != session_handle_ && level >= enable_level_ &&
+        (0 != (flags & enable_flags_));
+  }
+
+  // Simple wrappers to log Unicode and ANSI strings.
+  // Do nothing if !ShouldLog(level, 0xFFFFFFFF).
+  ULONG Log(const EtwEventClass& event_class, EtwEventType type,
+            EtwEventLevel level, const char *message);
+  ULONG Log(const EtwEventClass& event_class, EtwEventType type,
+            EtwEventLevel level, const wchar_t *message);
+
+  // Log the provided event.
+  ULONG Log(EVENT_TRACE_HEADER* event);
+
+ protected:
+  // Called after events have been enabled, override in subclasses
+  // to set up state or log at the start of a session.
+  // Note: This function may be called ETW's thread and may be racy,
+  //    bring your own locking if needed.
+  virtual void OnEventsEnabled() {}
+
+  // Called just before events are disabled, override in subclasses
+  // to tear down state or log at the end of a session.
+  // Note: This function may be called ETW's thread and may be racy,
+  //    bring your own locking if needed.
+  virtual void OnEventsDisabled() {}
+
+  // Called just after events have been disabled, override in subclasses
+  // to tear down state at the end of a session. At this point it's
+  // to late to log anything to the session.
+  // Note: This function may be called ETW's thread and may be racy,
+  //    bring your own locking if needed.
+  virtual void PostEventsDisabled() {}
+
+ private:
+  ULONG EnableEvents(PVOID buffer);
+  ULONG DisableEvents();
+  ULONG Callback(WMIDPREQUESTCODE request, PVOID buffer);
+  static ULONG WINAPI ControlCallback(WMIDPREQUESTCODE request, PVOID context,
+                                      ULONG *reserved, PVOID buffer);
+
+  GUID provider_name_;
+  TRACEHANDLE registration_handle_;
+  TRACEHANDLE session_handle_;
+  EtwEventFlags enable_flags_;
+  EtwEventLevel enable_level_;
+
+  // We don't use this, but on XP we're obliged to pass one in to
+  // RegisterTraceGuids. Non-const, because that's how the API needs it.
+  static TRACE_GUID_REGISTRATION obligatory_guid_registration_;
+
+  DISALLOW_COPY_AND_ASSIGN(EtwTraceProvider);
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_EVENT_TRACE_PROVIDER_H_
diff --git a/base/win/event_trace_provider_unittest.cc b/base/win/event_trace_provider_unittest.cc
new file mode 100644
index 0000000..55b5ae6
--- /dev/null
+++ b/base/win/event_trace_provider_unittest.cc
@@ -0,0 +1,110 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Unit tests for event trace provider.
+#include "base/win/event_trace_provider.h"
+#include <new>
+#include "testing/gtest/include/gtest/gtest.h"
+#include <initguid.h>  // NOLINT - has to be last
+
+namespace {
+
+using base::win::EtwTraceProvider;
+using base::win::EtwMofEvent;
+
+// {7F0FD37F-FA3C-4cd6-9242-DF60967A2CB2}
+DEFINE_GUID(kTestProvider,
+  0x7f0fd37f, 0xfa3c, 0x4cd6, 0x92, 0x42, 0xdf, 0x60, 0x96, 0x7a, 0x2c, 0xb2);
+
+// {7F0FD37F-FA3C-4cd6-9242-DF60967A2CB2}
+DEFINE_GUID(kTestEventClass,
+  0x7f0fd37f, 0xfa3c, 0x4cd6, 0x92, 0x42, 0xdf, 0x60, 0x96, 0x7a, 0x2c, 0xb2);
+
+}  // namespace
+
+TEST(EtwTraceProviderTest, ToleratesPreCreateInvocations) {
+  // Because the trace provider is used in logging, it's important that
+  // it be possible to use static provider instances without regard to
+  // whether they've been constructed or destructed.
+  // The interface of the class is designed to tolerate this usage.
+  char buf[sizeof(EtwTraceProvider)] = {0};
+  EtwTraceProvider& provider = reinterpret_cast<EtwTraceProvider&>(buf);
+
+  EXPECT_EQ(NULL, provider.registration_handle());
+  EXPECT_EQ(NULL, provider.session_handle());
+  EXPECT_EQ(0, provider.enable_flags());
+  EXPECT_EQ(0, provider.enable_level());
+
+  EXPECT_FALSE(provider.ShouldLog(TRACE_LEVEL_FATAL, 0xfffffff));
+
+  // We expect these not to crash.
+  provider.Log(kTestEventClass, 0, TRACE_LEVEL_FATAL, "foo");
+  provider.Log(kTestEventClass, 0, TRACE_LEVEL_FATAL, L"foo");
+
+  EtwMofEvent<1> dummy(kTestEventClass, 0, TRACE_LEVEL_FATAL);
+  DWORD data = 0;
+  dummy.SetField(0, sizeof(data), &data);
+  provider.Log(dummy.get());
+
+  // Placement-new the provider into our buffer.
+  new (buf) EtwTraceProvider(kTestProvider);
+
+  // Registration is now safe.
+  EXPECT_EQ(ERROR_SUCCESS, provider.Register());
+
+  // Destruct the instance, this should unregister it.
+  provider.EtwTraceProvider::~EtwTraceProvider();
+
+  // And post-destruction, all of the above should still be safe.
+  EXPECT_EQ(NULL, provider.registration_handle());
+  EXPECT_EQ(NULL, provider.session_handle());
+  EXPECT_EQ(0, provider.enable_flags());
+  EXPECT_EQ(0, provider.enable_level());
+
+  EXPECT_FALSE(provider.ShouldLog(TRACE_LEVEL_FATAL, 0xfffffff));
+
+  // We expect these not to crash.
+  provider.Log(kTestEventClass, 0, TRACE_LEVEL_FATAL, "foo");
+  provider.Log(kTestEventClass, 0, TRACE_LEVEL_FATAL, L"foo");
+  provider.Log(dummy.get());
+}
+
+TEST(EtwTraceProviderTest, Initialize) {
+  EtwTraceProvider provider(kTestProvider);
+
+  EXPECT_EQ(NULL, provider.registration_handle());
+  EXPECT_EQ(NULL, provider.session_handle());
+  EXPECT_EQ(0, provider.enable_flags());
+  EXPECT_EQ(0, provider.enable_level());
+}
+
+TEST(EtwTraceProviderTest, Register) {
+  EtwTraceProvider provider(kTestProvider);
+
+  ASSERT_EQ(ERROR_SUCCESS, provider.Register());
+  EXPECT_NE(NULL, provider.registration_handle());
+  ASSERT_EQ(ERROR_SUCCESS, provider.Unregister());
+  EXPECT_EQ(NULL, provider.registration_handle());
+}
+
+TEST(EtwTraceProviderTest, RegisterWithNoNameFails) {
+  EtwTraceProvider provider;
+
+  EXPECT_TRUE(provider.Register() != ERROR_SUCCESS);
+}
+
+TEST(EtwTraceProviderTest, Enable) {
+  EtwTraceProvider provider(kTestProvider);
+
+  ASSERT_EQ(ERROR_SUCCESS, provider.Register());
+  EXPECT_NE(NULL, provider.registration_handle());
+
+  // No session so far.
+  EXPECT_EQ(NULL, provider.session_handle());
+  EXPECT_EQ(0, provider.enable_flags());
+  EXPECT_EQ(0, provider.enable_level());
+
+  ASSERT_EQ(ERROR_SUCCESS, provider.Unregister());
+  EXPECT_EQ(NULL, provider.registration_handle());
+}
diff --git a/base/win/i18n.cc b/base/win/i18n.cc
new file mode 100644
index 0000000..9e523a1
--- /dev/null
+++ b/base/win/i18n.cc
@@ -0,0 +1,169 @@
+// Copyright (c) 2010 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/win/i18n.h"
+
+#include <windows.h>
+
+#include "base/logging.h"
+
+namespace {
+
+// Keep this enum in sync with kLanguageFunctionNames.
+enum LanguageFunction {
+  SYSTEM_LANGUAGES,
+  USER_LANGUAGES,
+  PROCESS_LANGUAGES,
+  THREAD_LANGUAGES,
+  NUM_FUNCTIONS
+};
+
+const char kSystemLanguagesFunctionName[] = "GetSystemPreferredUILanguages";
+const char kUserLanguagesFunctionName[] = "GetUserPreferredUILanguages";
+const char kProcessLanguagesFunctionName[] = "GetProcessPreferredUILanguages";
+const char kThreadLanguagesFunctionName[] = "GetThreadPreferredUILanguages";
+
+// Keep this array in sync with enum LanguageFunction.
+const char *const kLanguageFunctionNames[] = {
+  &kSystemLanguagesFunctionName[0],
+  &kUserLanguagesFunctionName[0],
+  &kProcessLanguagesFunctionName[0],
+  &kThreadLanguagesFunctionName[0]
+};
+
+COMPILE_ASSERT(NUM_FUNCTIONS == arraysize(kLanguageFunctionNames),
+               language_function_enum_and_names_out_of_sync);
+
+// Calls one of the MUI Get*PreferredUILanguages functions, placing the result
+// in |languages|.  |function| identifies the function to call and |flags| is
+// the function-specific flags (callers must not specify MUI_LANGUAGE_ID or
+// MUI_LANGUAGE_NAME).  Returns true if at least one language is placed in
+// |languages|.
+bool GetMUIPreferredUILanguageList(LanguageFunction function, ULONG flags,
+                                   std::vector<wchar_t>* languages) {
+  DCHECK(0 <= function && NUM_FUNCTIONS > function);
+  DCHECK_EQ(0U, (flags & (MUI_LANGUAGE_ID | MUI_LANGUAGE_NAME)));
+  DCHECK(languages);
+
+  HMODULE kernel32 = GetModuleHandle(L"kernel32.dll");
+  if (NULL != kernel32) {
+    typedef BOOL (WINAPI* GetPreferredUILanguages_Fn)(
+        DWORD, PULONG, PZZWSTR, PULONG);
+    GetPreferredUILanguages_Fn get_preferred_ui_languages =
+        reinterpret_cast<GetPreferredUILanguages_Fn>(
+            GetProcAddress(kernel32, kLanguageFunctionNames[function]));
+    if (NULL != get_preferred_ui_languages) {
+      const ULONG call_flags = flags | MUI_LANGUAGE_NAME;
+      ULONG language_count = 0;
+      ULONG buffer_length = 0;
+      if (get_preferred_ui_languages(call_flags, &language_count, NULL,
+                                     &buffer_length) &&
+          0 != buffer_length) {
+        languages->resize(buffer_length);
+        if (get_preferred_ui_languages(call_flags, &language_count,
+                                       &(*languages)[0], &buffer_length) &&
+            0 != language_count) {
+          DCHECK(languages->size() == buffer_length);
+          return true;
+        } else {
+          DPCHECK(0 == language_count)
+              << "Failed getting preferred UI languages.";
+        }
+      } else {
+        DPCHECK(0 == buffer_length)
+            << "Failed getting size of preferred UI languages.";
+      }
+    } else {
+      DVLOG(2) << "MUI not available.";
+    }
+  } else {
+    NOTREACHED() << "kernel32.dll not found.";
+  }
+
+  return false;
+}
+
+bool GetUserDefaultUILanguage(std::wstring* language, std::wstring* region) {
+  DCHECK(language);
+
+  LANGID lang_id = ::GetUserDefaultUILanguage();
+  if (LOCALE_CUSTOM_UI_DEFAULT != lang_id) {
+    const LCID locale_id = MAKELCID(lang_id, SORT_DEFAULT);
+    // max size for LOCALE_SISO639LANGNAME and LOCALE_SISO3166CTRYNAME is 9
+    wchar_t result_buffer[9];
+    int result_length =
+        GetLocaleInfo(locale_id, LOCALE_SISO639LANGNAME, &result_buffer[0],
+                      arraysize(result_buffer));
+    DPCHECK(0 != result_length) << "Failed getting language id";
+    if (1 < result_length) {
+      language->assign(&result_buffer[0], result_length - 1);
+      region->clear();
+      if (SUBLANG_NEUTRAL != SUBLANGID(lang_id)) {
+        result_length =
+            GetLocaleInfo(locale_id, LOCALE_SISO3166CTRYNAME, &result_buffer[0],
+                          arraysize(result_buffer));
+        DPCHECK(0 != result_length) << "Failed getting region id";
+        if (1 < result_length)
+          region->assign(&result_buffer[0], result_length - 1);
+      }
+      return true;
+    }
+  } else {
+    // This is entirely unexpected on pre-Vista, which is the only time we
+    // should try GetUserDefaultUILanguage anyway.
+    NOTREACHED() << "Cannot determine language for a supplemental locale.";
+  }
+  return false;
+}
+
+bool GetPreferredUILanguageList(LanguageFunction function, ULONG flags,
+                                std::vector<std::wstring>* languages) {
+  std::vector<wchar_t> buffer;
+  std::wstring language;
+  std::wstring region;
+
+  if (GetMUIPreferredUILanguageList(function, flags, &buffer)) {
+    std::vector<wchar_t>::const_iterator scan = buffer.begin();
+    language.assign(&*scan);
+    while (!language.empty()) {
+      languages->push_back(language);
+      scan += language.size() + 1;
+      language.assign(&*scan);
+    }
+  } else if (GetUserDefaultUILanguage(&language, &region)) {
+    // Mimic the MUI behavior of putting the neutral version of the lang after
+    // the regional one (e.g., "fr-CA, fr").
+    if (!region.empty())
+      languages->push_back(std::wstring(language)
+                               .append(1, L'-')
+                               .append(region));
+    languages->push_back(language);
+  } else {
+    return false;
+  }
+
+  return true;
+}
+
+}  // namespace
+
+namespace base {
+namespace win {
+namespace i18n {
+
+bool GetUserPreferredUILanguageList(std::vector<std::wstring>* languages) {
+  DCHECK(languages);
+  return GetPreferredUILanguageList(USER_LANGUAGES, 0, languages);
+}
+
+bool GetThreadPreferredUILanguageList(std::vector<std::wstring>* languages) {
+  DCHECK(languages);
+  return GetPreferredUILanguageList(
+      THREAD_LANGUAGES, MUI_MERGE_SYSTEM_FALLBACK | MUI_MERGE_USER_FALLBACK,
+      languages);
+}
+
+}  // namespace i18n
+}  // namespace win
+}  // namespace base
diff --git a/base/win/i18n.h b/base/win/i18n.h
new file mode 100644
index 0000000..c0379c1
--- /dev/null
+++ b/base/win/i18n.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2011 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_WIN_I18N_H_
+#define BASE_WIN_I18N_H_
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace win {
+namespace i18n {
+
+// Adds to |languages| the list of user preferred UI languages from MUI, if
+// available, falling-back on the user default UI language otherwise.  Returns
+// true if at least one language is added.
+BASE_EXPORT bool GetUserPreferredUILanguageList(
+    std::vector<std::wstring>* languages);
+
+// Adds to |languages| the list of thread, process, user, and system preferred
+// UI languages from MUI, if available, falling-back on the user default UI
+// language otherwise.  Returns true if at least one language is added.
+BASE_EXPORT bool GetThreadPreferredUILanguageList(
+    std::vector<std::wstring>* languages);
+
+}  // namespace i18n
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_I18N_H_
diff --git a/base/win/i18n_unittest.cc b/base/win/i18n_unittest.cc
new file mode 100644
index 0000000..781fc39
--- /dev/null
+++ b/base/win/i18n_unittest.cc
@@ -0,0 +1,42 @@
+// Copyright (c) 2010 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 contains unit tests for Windows internationalization funcs.
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+#include "base/win/i18n.h"
+#include "base/win/windows_version.h"
+
+namespace base {
+namespace win {
+namespace i18n {
+
+// Tests that at least one user preferred UI language can be obtained.
+TEST(I18NTest, GetUserPreferredUILanguageList) {
+  std::vector<std::wstring> languages;
+  EXPECT_TRUE(GetUserPreferredUILanguageList(&languages));
+  EXPECT_NE(static_cast<std::vector<std::wstring>::size_type>(0),
+            languages.size());
+  for (std::vector<std::wstring>::const_iterator scan = languages.begin(),
+          end = languages.end(); scan != end; ++scan) {
+    EXPECT_FALSE((*scan).empty());
+  }
+}
+
+// Tests that at least one thread preferred UI language can be obtained.
+TEST(I18NTest, GetThreadPreferredUILanguageList) {
+  std::vector<std::wstring> languages;
+  EXPECT_TRUE(GetThreadPreferredUILanguageList(&languages));
+  EXPECT_NE(static_cast<std::vector<std::wstring>::size_type>(0),
+            languages.size());
+  for (std::vector<std::wstring>::const_iterator scan = languages.begin(),
+          end = languages.end(); scan != end; ++scan) {
+    EXPECT_FALSE((*scan).empty());
+  }
+}
+
+}  // namespace i18n
+}  // namespace win
+}  // namespace base
diff --git a/base/win/iat_patch_function.cc b/base/win/iat_patch_function.cc
new file mode 100644
index 0000000..13acd65
--- /dev/null
+++ b/base/win/iat_patch_function.cc
@@ -0,0 +1,307 @@
+// Copyright (c) 2011 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/win/iat_patch_function.h"
+
+#include "base/logging.h"
+#include "base/win/pe_image.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+struct InterceptFunctionInformation {
+  bool finished_operation;
+  const char* imported_from_module;
+  const char* function_name;
+  void* new_function;
+  void** old_function;
+  IMAGE_THUNK_DATA** iat_thunk;
+  DWORD return_code;
+};
+
+void* GetIATFunction(IMAGE_THUNK_DATA* iat_thunk) {
+  if (NULL == iat_thunk) {
+    NOTREACHED();
+    return NULL;
+  }
+
+  // Works around the 64 bit portability warning:
+  // The Function member inside IMAGE_THUNK_DATA is really a pointer
+  // to the IAT function. IMAGE_THUNK_DATA correctly maps to IMAGE_THUNK_DATA32
+  // or IMAGE_THUNK_DATA64 for correct pointer size.
+  union FunctionThunk {
+    IMAGE_THUNK_DATA thunk;
+    void* pointer;
+  } iat_function;
+
+  iat_function.thunk = *iat_thunk;
+  return iat_function.pointer;
+}
+
+bool InterceptEnumCallback(const base::win::PEImage& image, const char* module,
+                           DWORD ordinal, const char* name, DWORD hint,
+                           IMAGE_THUNK_DATA* iat, void* cookie) {
+  InterceptFunctionInformation* intercept_information =
+    reinterpret_cast<InterceptFunctionInformation*>(cookie);
+
+  if (NULL == intercept_information) {
+    NOTREACHED();
+    return false;
+  }
+
+  DCHECK(module);
+
+  if ((0 == lstrcmpiA(module, intercept_information->imported_from_module)) &&
+     (NULL != name) &&
+     (0 == lstrcmpiA(name, intercept_information->function_name))) {
+    // Save the old pointer.
+    if (NULL != intercept_information->old_function) {
+      *(intercept_information->old_function) = GetIATFunction(iat);
+    }
+
+    if (NULL != intercept_information->iat_thunk) {
+      *(intercept_information->iat_thunk) = iat;
+    }
+
+    // portability check
+    COMPILE_ASSERT(sizeof(iat->u1.Function) ==
+      sizeof(intercept_information->new_function), unknown_IAT_thunk_format);
+
+    // Patch the function.
+    intercept_information->return_code =
+      ModifyCode(&(iat->u1.Function),
+                 &(intercept_information->new_function),
+                 sizeof(intercept_information->new_function));
+
+    // Terminate further enumeration.
+    intercept_information->finished_operation = true;
+    return false;
+  }
+
+  return true;
+}
+
+// Helper to intercept a function in an import table of a specific
+// module.
+//
+// Arguments:
+// module_handle          Module to be intercepted
+// imported_from_module   Module that exports the symbol
+// function_name          Name of the API to be intercepted
+// new_function           Interceptor function
+// old_function           Receives the original function pointer
+// iat_thunk              Receives pointer to IAT_THUNK_DATA
+//                        for the API from the import table.
+//
+// Returns: Returns NO_ERROR on success or Windows error code
+//          as defined in winerror.h
+DWORD InterceptImportedFunction(HMODULE module_handle,
+                                const char* imported_from_module,
+                                const char* function_name, void* new_function,
+                                void** old_function,
+                                IMAGE_THUNK_DATA** iat_thunk) {
+  if ((NULL == module_handle) || (NULL == imported_from_module) ||
+     (NULL == function_name) || (NULL == new_function)) {
+    NOTREACHED();
+    return ERROR_INVALID_PARAMETER;
+  }
+
+  base::win::PEImage target_image(module_handle);
+  if (!target_image.VerifyMagic()) {
+    NOTREACHED();
+    return ERROR_INVALID_PARAMETER;
+  }
+
+  InterceptFunctionInformation intercept_information = {
+    false,
+    imported_from_module,
+    function_name,
+    new_function,
+    old_function,
+    iat_thunk,
+    ERROR_GEN_FAILURE};
+
+  // First go through the IAT. If we don't find the import we are looking
+  // for in IAT, search delay import table.
+  target_image.EnumAllImports(InterceptEnumCallback, &intercept_information);
+  if (!intercept_information.finished_operation) {
+    target_image.EnumAllDelayImports(InterceptEnumCallback,
+                                     &intercept_information);
+  }
+
+  return intercept_information.return_code;
+}
+
+// Restore intercepted IAT entry with the original function.
+//
+// Arguments:
+// intercept_function     Interceptor function
+// original_function      Receives the original function pointer
+//
+// Returns: Returns NO_ERROR on success or Windows error code
+//          as defined in winerror.h
+DWORD RestoreImportedFunction(void* intercept_function,
+                              void* original_function,
+                              IMAGE_THUNK_DATA* iat_thunk) {
+  if ((NULL == intercept_function) || (NULL == original_function) ||
+      (NULL == iat_thunk)) {
+    NOTREACHED();
+    return ERROR_INVALID_PARAMETER;
+  }
+
+  if (GetIATFunction(iat_thunk) != intercept_function) {
+    // Check if someone else has intercepted on top of us.
+    // We cannot unpatch in this case, just raise a red flag.
+    NOTREACHED();
+    return ERROR_INVALID_FUNCTION;
+  }
+
+  return ModifyCode(&(iat_thunk->u1.Function),
+                    &original_function,
+                    sizeof(original_function));
+}
+
+}  // namespace
+
+// Change the page protection (of code pages) to writable and copy
+// the data at the specified location
+//
+// Arguments:
+// old_code               Target location to copy
+// new_code               Source
+// length                 Number of bytes to copy
+//
+// Returns: Windows error code (winerror.h). NO_ERROR if successful
+DWORD ModifyCode(void* old_code, void* new_code, int length) {
+  if ((NULL == old_code) || (NULL == new_code) || (0 == length)) {
+    NOTREACHED();
+    return ERROR_INVALID_PARAMETER;
+  }
+
+  // Change the page protection so that we can write.
+  MEMORY_BASIC_INFORMATION memory_info;
+  DWORD error = NO_ERROR;
+  DWORD old_page_protection = 0;
+
+  if (!VirtualQuery(old_code, &memory_info, sizeof(memory_info))) {
+    error = GetLastError();
+    return error;
+  }
+
+  DWORD is_executable = (PAGE_EXECUTE | PAGE_EXECUTE_READ |
+                        PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY) &
+                        memory_info.Protect;
+
+  if (VirtualProtect(old_code,
+                     length,
+                     is_executable ? PAGE_EXECUTE_READWRITE :
+                                     PAGE_READWRITE,
+                     &old_page_protection)) {
+
+    // Write the data.
+    CopyMemory(old_code, new_code, length);
+
+    // Restore the old page protection.
+    error = ERROR_SUCCESS;
+    VirtualProtect(old_code,
+                  length,
+                  old_page_protection,
+                  &old_page_protection);
+  } else {
+    error = GetLastError();
+  }
+
+  return error;
+}
+
+IATPatchFunction::IATPatchFunction()
+    : module_handle_(NULL),
+      original_function_(NULL),
+      iat_thunk_(NULL),
+      intercept_function_(NULL) {
+}
+
+IATPatchFunction::~IATPatchFunction() {
+  if (NULL != intercept_function_) {
+    DWORD error = Unpatch();
+    DCHECK_EQ(static_cast<DWORD>(NO_ERROR), error);
+  }
+}
+
+DWORD IATPatchFunction::Patch(const wchar_t* module,
+                              const char* imported_from_module,
+                              const char* function_name,
+                              void* new_function) {
+  HMODULE module_handle = LoadLibraryW(module);
+  if (module_handle == NULL) {
+    NOTREACHED();
+    return GetLastError();
+  }
+
+  DWORD error = PatchFromModule(module_handle, imported_from_module,
+                                function_name, new_function);
+  if (NO_ERROR == error) {
+    module_handle_ = module_handle;
+  } else {
+    FreeLibrary(module_handle);
+  }
+
+  return error;
+}
+
+DWORD IATPatchFunction::PatchFromModule(HMODULE module,
+                                        const char* imported_from_module,
+                                        const char* function_name,
+                                        void* new_function) {
+  DCHECK_EQ(static_cast<void*>(NULL), original_function_);
+  DCHECK_EQ(static_cast<IMAGE_THUNK_DATA*>(NULL), iat_thunk_);
+  DCHECK_EQ(static_cast<void*>(NULL), intercept_function_);
+  DCHECK(module);
+
+  DWORD error = InterceptImportedFunction(module,
+                                          imported_from_module,
+                                          function_name,
+                                          new_function,
+                                          &original_function_,
+                                          &iat_thunk_);
+
+  if (NO_ERROR == error) {
+    DCHECK_NE(original_function_, intercept_function_);
+    intercept_function_ = new_function;
+  }
+
+  return error;
+}
+
+DWORD IATPatchFunction::Unpatch() {
+  DWORD error = RestoreImportedFunction(intercept_function_,
+                                        original_function_,
+                                        iat_thunk_);
+  DCHECK_EQ(static_cast<DWORD>(NO_ERROR), error);
+
+  // Hands off the intercept if we fail to unpatch.
+  // If IATPatchFunction::Unpatch fails during RestoreImportedFunction
+  // it means that we cannot safely unpatch the import address table
+  // patch. In this case its better to be hands off the intercept as
+  // trying to unpatch again in the destructor of IATPatchFunction is
+  // not going to be any safer
+  if (module_handle_)
+    FreeLibrary(module_handle_);
+  module_handle_ = NULL;
+  intercept_function_ = NULL;
+  original_function_ = NULL;
+  iat_thunk_ = NULL;
+
+  return error;
+}
+
+void* IATPatchFunction::original_function() const {
+  DCHECK(is_patched());
+  return original_function_;
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/iat_patch_function.h b/base/win/iat_patch_function.h
new file mode 100644
index 0000000..8be97f8
--- /dev/null
+++ b/base/win/iat_patch_function.h
@@ -0,0 +1,83 @@
+// Copyright (c) 2011 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_WIN_IAT_PATCH_FUNCTION_H_
+#define BASE_WIN_IAT_PATCH_FUNCTION_H_
+
+#include <windows.h>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace win {
+
+// A class that encapsulates Import Address Table patching helpers and restores
+// the original function in the destructor.
+//
+// It will intercept functions for a specific DLL imported from another DLL.
+// This is the case when, for example, we want to intercept
+// CertDuplicateCertificateContext function (exported from crypt32.dll) called
+// by wininet.dll.
+class BASE_EXPORT IATPatchFunction {
+ public:
+  IATPatchFunction();
+  ~IATPatchFunction();
+
+  // Intercept a function in an import table of a specific
+  // module. Save the original function and the import
+  // table address. These values will be used later
+  // during Unpatch
+  //
+  // Arguments:
+  // module                 Module to be intercepted
+  // imported_from_module   Module that exports the 'function_name'
+  // function_name          Name of the API to be intercepted
+  //
+  // Returns: Windows error code (winerror.h). NO_ERROR if successful
+  //
+  // Note: Patching a function will make the IAT patch take some "ownership" on
+  // |module|.  It will LoadLibrary(module) to keep the DLL alive until a call
+  // to Unpatch(), which will call FreeLibrary() and allow the module to be
+  // unloaded.  The idea is to help prevent the DLL from going away while a
+  // patch is still active.
+  DWORD Patch(const wchar_t* module,
+              const char* imported_from_module,
+              const char* function_name,
+              void* new_function);
+
+  // Same as Patch(), but uses a handle to a |module| instead of the DLL name.
+  DWORD PatchFromModule(HMODULE module,
+                        const char* imported_from_module,
+                        const char* function_name,
+                        void* new_function);
+
+  // Unpatch the IAT entry using internally saved original
+  // function.
+  //
+  // Returns: Windows error code (winerror.h). NO_ERROR if successful
+  DWORD Unpatch();
+
+  bool is_patched() const {
+    return (NULL != intercept_function_);
+  }
+
+  void* original_function() const;
+
+
+ private:
+  HMODULE module_handle_;
+  void* intercept_function_;
+  void* original_function_;
+  IMAGE_THUNK_DATA* iat_thunk_;
+
+  DISALLOW_COPY_AND_ASSIGN(IATPatchFunction);
+};
+
+BASE_EXPORT DWORD ModifyCode(void* old_code, void* new_code, int length);
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_IAT_PATCH_FUNCTION_H_
diff --git a/base/win/iunknown_impl.cc b/base/win/iunknown_impl.cc
new file mode 100644
index 0000000..9baa0f3
--- /dev/null
+++ b/base/win/iunknown_impl.cc
@@ -0,0 +1,42 @@
+// Copyright (c) 2011 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/win/iunknown_impl.h"
+
+namespace base {
+namespace win {
+
+IUnknownImpl::IUnknownImpl()
+    : ref_count_(0) {
+}
+
+IUnknownImpl::~IUnknownImpl() {
+}
+
+ULONG STDMETHODCALLTYPE IUnknownImpl::AddRef() {
+  base::AtomicRefCountInc(&ref_count_);
+  return 1;
+}
+
+ULONG STDMETHODCALLTYPE IUnknownImpl::Release() {
+  if (!base::AtomicRefCountDec(&ref_count_)) {
+    delete this;
+    return 0;
+  }
+  return 1;
+}
+
+STDMETHODIMP IUnknownImpl::QueryInterface(REFIID riid, void** ppv) {
+  if (riid == IID_IUnknown) {
+    *ppv = static_cast<IUnknown*>(this);
+    AddRef();
+    return S_OK;
+  }
+
+  *ppv = NULL;
+  return E_NOINTERFACE;
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/iunknown_impl.h b/base/win/iunknown_impl.h
new file mode 100644
index 0000000..b7de205
--- /dev/null
+++ b/base/win/iunknown_impl.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2012 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_WIN_IUNKNOWN_IMPL_H_
+#define BASE_WIN_IUNKNOWN_IMPL_H_
+
+#include <unknwn.h>
+
+#include "base/atomic_ref_count.h"
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+
+namespace base {
+namespace win {
+
+// IUnknown implementation for other classes to derive from.
+class BASE_EXPORT IUnknownImpl : public IUnknown {
+ public:
+  IUnknownImpl();
+
+  ULONG STDMETHODCALLTYPE AddRef() override;
+  ULONG STDMETHODCALLTYPE Release() override;
+
+  // Subclasses should extend this to return any interfaces they provide.
+  STDMETHODIMP QueryInterface(REFIID riid, void** ppv) override;
+
+ protected:
+  virtual ~IUnknownImpl();
+
+ private:
+  AtomicRefCount ref_count_;
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_IUNKNOWN_IMPL_H_
diff --git a/base/win/iunknown_impl_unittest.cc b/base/win/iunknown_impl_unittest.cc
new file mode 100644
index 0000000..874a43a
--- /dev/null
+++ b/base/win/iunknown_impl_unittest.cc
@@ -0,0 +1,49 @@
+// Copyright (c) 2011 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/win/iunknown_impl.h"
+
+#include "base/win/scoped_com_initializer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace win {
+
+class TestIUnknownImplSubclass : public IUnknownImpl {
+ public:
+  TestIUnknownImplSubclass() {
+    ++instance_count;
+  }
+  ~TestIUnknownImplSubclass() override { --instance_count; }
+  static int instance_count;
+};
+
+// static
+int TestIUnknownImplSubclass::instance_count = 0;
+
+TEST(IUnknownImplTest, IUnknownImpl) {
+  ScopedCOMInitializer com_initializer;
+
+  EXPECT_EQ(0, TestIUnknownImplSubclass::instance_count);
+  IUnknown* u = new TestIUnknownImplSubclass();
+
+  EXPECT_EQ(1, TestIUnknownImplSubclass::instance_count);
+
+  EXPECT_EQ(1, u->AddRef());
+  EXPECT_EQ(1, u->AddRef());
+
+  IUnknown* other = NULL;
+  EXPECT_EQ(E_NOINTERFACE, u->QueryInterface(
+      IID_IDispatch, reinterpret_cast<void**>(&other)));
+  EXPECT_EQ(S_OK, u->QueryInterface(
+      IID_IUnknown, reinterpret_cast<void**>(&other)));
+  other->Release();
+
+  EXPECT_EQ(1, u->Release());
+  EXPECT_EQ(0, u->Release());
+  EXPECT_EQ(0, TestIUnknownImplSubclass::instance_count);
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/message_window.cc b/base/win/message_window.cc
new file mode 100644
index 0000000..58010e4
--- /dev/null
+++ b/base/win/message_window.cc
@@ -0,0 +1,166 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/win/message_window.h"
+
+#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";
+
+namespace base {
+namespace win {
+
+// Used along with LazyInstance to register a window class for message-only
+// windows created by MessageWindow.
+class MessageWindow::WindowClass {
+ public:
+  WindowClass();
+  ~WindowClass();
+
+  ATOM atom() { return atom_; }
+  HINSTANCE instance() { return instance_; }
+
+ private:
+  ATOM atom_;
+  HINSTANCE instance_;
+
+  DISALLOW_COPY_AND_ASSIGN(WindowClass);
+};
+
+static LazyInstance<MessageWindow::WindowClass> g_window_class =
+    LAZY_INSTANCE_INITIALIZER;
+
+MessageWindow::WindowClass::WindowClass()
+    : atom_(0),
+      instance_(base::GetModuleFromAddress(&MessageWindow::WindowProc)) {
+  WNDCLASSEX window_class;
+  window_class.cbSize = sizeof(window_class);
+  window_class.style = 0;
+  window_class.lpfnWndProc = &base::win::WrappedWindowProc<WindowProc>;
+  window_class.cbClsExtra = 0;
+  window_class.cbWndExtra = 0;
+  window_class.hInstance = instance_;
+  window_class.hIcon = NULL;
+  window_class.hCursor = NULL;
+  window_class.hbrBackground = NULL;
+  window_class.lpszMenuName = NULL;
+  window_class.lpszClassName = kMessageWindowClassName;
+  window_class.hIconSm = NULL;
+  atom_ = RegisterClassEx(&window_class);
+  if (atom_ == 0) {
+    PLOG(ERROR)
+        << "Failed to register the window class for a message-only window";
+  }
+}
+
+MessageWindow::WindowClass::~WindowClass() {
+  if (atom_ != 0) {
+    BOOL result = UnregisterClass(MAKEINTATOM(atom_), instance_);
+    // Hitting this DCHECK usually means that some MessageWindow objects were
+    // leaked. For example not calling
+    // ui::Clipboard::DestroyClipboardForCurrentThread() results in a leaked
+    // MessageWindow.
+    DCHECK(result);
+  }
+}
+
+MessageWindow::MessageWindow()
+    : window_(NULL) {
+}
+
+MessageWindow::~MessageWindow() {
+  DCHECK(CalledOnValidThread());
+
+  if (window_ != NULL) {
+    BOOL result = DestroyWindow(window_);
+    DCHECK(result);
+  }
+}
+
+bool MessageWindow::Create(const MessageCallback& message_callback) {
+  return DoCreate(message_callback, NULL);
+}
+
+bool MessageWindow::CreateNamed(const MessageCallback& message_callback,
+                                const string16& window_name) {
+  return DoCreate(message_callback, window_name.c_str());
+}
+
+// static
+HWND MessageWindow::FindWindow(const string16& window_name) {
+  return FindWindowEx(HWND_MESSAGE, NULL, kMessageWindowClassName,
+                      window_name.c_str());
+}
+
+bool MessageWindow::DoCreate(const MessageCallback& message_callback,
+                             const wchar_t* window_name) {
+  DCHECK(CalledOnValidThread());
+  DCHECK(message_callback_.is_null());
+  DCHECK(!window_);
+
+  message_callback_ = message_callback;
+
+  WindowClass& window_class = g_window_class.Get();
+  window_ = CreateWindow(MAKEINTATOM(window_class.atom()), window_name, 0, 0, 0,
+                         0, 0, HWND_MESSAGE, 0, window_class.instance(), this);
+  if (!window_) {
+    PLOG(ERROR) << "Failed to create a message-only window";
+    return false;
+  }
+
+  return true;
+}
+
+// static
+LRESULT CALLBACK MessageWindow::WindowProc(HWND hwnd,
+                                           UINT message,
+                                           WPARAM wparam,
+                                           LPARAM lparam) {
+  MessageWindow* self = reinterpret_cast<MessageWindow*>(
+      GetWindowLongPtr(hwnd, GWLP_USERDATA));
+
+  switch (message) {
+    // Set up the self before handling WM_CREATE.
+    case WM_CREATE: {
+      CREATESTRUCT* cs = reinterpret_cast<CREATESTRUCT*>(lparam);
+      self = reinterpret_cast<MessageWindow*>(cs->lpCreateParams);
+
+      // Make |hwnd| available to the message handler. At this point the control
+      // hasn't returned from CreateWindow() yet.
+      self->window_ = hwnd;
+
+      // Store pointer to the self to the window's user data.
+      SetLastError(ERROR_SUCCESS);
+      LONG_PTR result = SetWindowLongPtr(
+          hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(self));
+      CHECK(result != 0 || GetLastError() == ERROR_SUCCESS);
+      break;
+    }
+
+    // Clear the pointer to stop calling the self once WM_DESTROY is
+    // received.
+    case WM_DESTROY: {
+      SetLastError(ERROR_SUCCESS);
+      LONG_PTR result = SetWindowLongPtr(hwnd, GWLP_USERDATA, NULL);
+      CHECK(result != 0 || GetLastError() == ERROR_SUCCESS);
+      break;
+    }
+  }
+
+  // Handle the message.
+  if (self) {
+    LRESULT message_result;
+    if (self->message_callback_.Run(message, wparam, lparam, &message_result))
+      return message_result;
+  }
+
+  return DefWindowProc(hwnd, message, wparam, lparam);
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/message_window.h b/base/win/message_window.h
new file mode 100644
index 0000000..ae0c6f0
--- /dev/null
+++ b/base/win/message_window.h
@@ -0,0 +1,75 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_MESSAGE_WINDOW_H_
+#define BASE_WIN_MESSAGE_WINDOW_H_
+
+#include <windows.h>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/strings/string16.h"
+#include "base/threading/non_thread_safe.h"
+
+namespace base {
+namespace win {
+
+// Implements a message-only window.
+class BASE_EXPORT MessageWindow : public base::NonThreadSafe {
+ public:
+  // Used to register a process-wide message window class.
+  class WindowClass;
+
+  // Implement this callback to handle messages received by the message window.
+  // If the callback returns |false|, the first four parameters are passed to
+  // DefWindowProc(). Otherwise, |*result| is returned by the window procedure.
+  typedef base::Callback<bool(UINT message,
+                              WPARAM wparam,
+                              LPARAM lparam,
+                              LRESULT* result)> MessageCallback;
+
+  MessageWindow();
+  ~MessageWindow();
+
+  // Creates a message-only window. The incoming messages will be passed by
+  // |message_callback|. |message_callback| must outlive |this|.
+  bool Create(const MessageCallback& message_callback);
+
+  // Same as Create() but assigns the name to the created window.
+  bool CreateNamed(const MessageCallback& message_callback,
+                   const string16& window_name);
+
+  HWND hwnd() const { return window_; }
+
+  // Retrieves a handle of the first message-only window with matching
+  // |window_name|.
+  static HWND FindWindow(const string16& window_name);
+
+ private:
+  // Give |WindowClass| access to WindowProc().
+  friend class WindowClass;
+
+  // Contains the actual window creation code.
+  bool DoCreate(const MessageCallback& message_callback,
+                const wchar_t* window_name);
+
+  // Invoked by the OS to process incoming window messages.
+  static LRESULT CALLBACK WindowProc(HWND hwnd, UINT message, WPARAM wparam,
+                                     LPARAM lparam);
+
+  // Invoked to handle messages received by the window.
+  MessageCallback message_callback_;
+
+  // Handle of the input window.
+  HWND window_;
+
+  DISALLOW_COPY_AND_ASSIGN(MessageWindow);
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_MESSAGE_WINDOW_H_
diff --git a/base/win/message_window_unittest.cc b/base/win/message_window_unittest.cc
new file mode 100644
index 0000000..00248bf
--- /dev/null
+++ b/base/win/message_window_unittest.cc
@@ -0,0 +1,61 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/bind.h"
+#include "base/guid.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/win/message_window.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+bool HandleMessage(
+    UINT message, WPARAM wparam, LPARAM lparam, LRESULT* result) {
+  // Return |wparam| as the result of WM_USER message.
+  if (message == WM_USER) {
+    *result = wparam;
+    return true;
+  }
+
+  return false;
+}
+
+}  // namespace
+
+// Checks that a window can be created.
+TEST(MessageWindowTest, Create) {
+  win::MessageWindow window;
+  EXPECT_TRUE(window.Create(base::Bind(&HandleMessage)));
+}
+
+// Checks that a named window can be created.
+TEST(MessageWindowTest, CreateNamed) {
+  win::MessageWindow window;
+  EXPECT_TRUE(window.CreateNamed(base::Bind(&HandleMessage),
+              UTF8ToUTF16("test_message_window")));
+}
+
+// Verifies that the created window can receive messages.
+TEST(MessageWindowTest, SendMessage) {
+  win::MessageWindow window;
+  EXPECT_TRUE(window.Create(base::Bind(&HandleMessage)));
+
+  EXPECT_EQ(SendMessage(window.hwnd(), WM_USER, 100, 0), 100);
+}
+
+// Verifies that a named window can be found by name.
+TEST(MessageWindowTest, FindWindow) {
+  string16 name = UTF8ToUTF16(base::GenerateGUID());
+  win::MessageWindow window;
+  EXPECT_TRUE(window.CreateNamed(base::Bind(&HandleMessage), name));
+
+  HWND hwnd = win::MessageWindow::FindWindow(name);
+  EXPECT_TRUE(hwnd != NULL);
+  EXPECT_EQ(SendMessage(hwnd, WM_USER, 200, 0), 200);
+}
+
+}  // namespace base
diff --git a/base/win/metro.cc b/base/win/metro.cc
new file mode 100644
index 0000000..7946698
--- /dev/null
+++ b/base/win/metro.cc
@@ -0,0 +1,110 @@
+// Copyright (c) 2012 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/win/metro.h"
+
+#include "base/strings/string_util.h"
+
+namespace base {
+namespace win {
+
+HMODULE GetMetroModule() {
+  const HMODULE kUninitialized = reinterpret_cast<HMODULE>(1);
+  static HMODULE metro_module = kUninitialized;
+
+  if (metro_module == kUninitialized) {
+    // Initialize the cache, note that the initialization is idempotent
+    // under the assumption that metro_driver is never unloaded, so the
+    // race to this assignment is safe.
+    metro_module = GetModuleHandleA("metro_driver.dll");
+    if (metro_module != NULL) {
+      // This must be a metro process if the metro_driver is loaded.
+      DCHECK(IsMetroProcess());
+    }
+  }
+
+  DCHECK(metro_module != kUninitialized);
+  return metro_module;
+}
+
+bool IsMetroProcess() {
+  enum ImmersiveState {
+    kImmersiveUnknown,
+    kImmersiveTrue,
+    kImmersiveFalse
+  };
+  // The immersive state of a process can never change.
+  // Look it up once and cache it here.
+  static ImmersiveState state = kImmersiveUnknown;
+
+  if (state == kImmersiveUnknown) {
+    if (IsProcessImmersive(::GetCurrentProcess())) {
+      state = kImmersiveTrue;
+    } else {
+      state = kImmersiveFalse;
+    }
+  }
+  DCHECK_NE(kImmersiveUnknown, state);
+  return state == kImmersiveTrue;
+}
+
+bool IsProcessImmersive(HANDLE process) {
+  typedef BOOL (WINAPI* IsImmersiveProcessFunc)(HANDLE process);
+  HMODULE user32 = ::GetModuleHandleA("user32.dll");
+  DCHECK(user32 != NULL);
+
+  IsImmersiveProcessFunc is_immersive_process =
+      reinterpret_cast<IsImmersiveProcessFunc>(
+          ::GetProcAddress(user32, "IsImmersiveProcess"));
+
+  if (is_immersive_process)
+    return is_immersive_process(process) ? true: false;
+  return false;
+}
+
+wchar_t* LocalAllocAndCopyString(const string16& src) {
+  size_t dest_size = (src.length() + 1) * sizeof(wchar_t);
+  wchar_t* dest = reinterpret_cast<wchar_t*>(LocalAlloc(LPTR, dest_size));
+  base::wcslcpy(dest, src.c_str(), dest_size);
+  return dest;
+}
+
+// Metro driver exports for getting the launch type, initial url, initial
+// search term, etc.
+extern "C" {
+typedef const wchar_t* (*GetInitialUrl)();
+typedef const wchar_t* (*GetInitialSearchString)();
+typedef base::win::MetroLaunchType (*GetLaunchType)(
+    base::win::MetroPreviousExecutionState* previous_state);
+}
+
+MetroLaunchType GetMetroLaunchParams(string16* params) {
+  HMODULE metro = base::win::GetMetroModule();
+  if (!metro)
+    return base::win::METRO_LAUNCH_ERROR;
+
+  GetLaunchType get_launch_type = reinterpret_cast<GetLaunchType>(
+      ::GetProcAddress(metro, "GetLaunchType"));
+  DCHECK(get_launch_type);
+
+  base::win::MetroLaunchType launch_type = get_launch_type(NULL);
+
+  if ((launch_type == base::win::METRO_PROTOCOL) ||
+      (launch_type == base::win::METRO_LAUNCH)) {
+    GetInitialUrl initial_metro_url = reinterpret_cast<GetInitialUrl>(
+        ::GetProcAddress(metro, "GetInitialUrl"));
+    DCHECK(initial_metro_url);
+    *params = initial_metro_url();
+  } else if (launch_type == base::win::METRO_SEARCH) {
+    GetInitialSearchString initial_search_string =
+        reinterpret_cast<GetInitialSearchString>(
+            ::GetProcAddress(metro, "GetInitialSearchString"));
+    DCHECK(initial_search_string);
+    *params = initial_search_string();
+  }
+  return launch_type;
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/metro.h b/base/win/metro.h
new file mode 100644
index 0000000..0696006
--- /dev/null
+++ b/base/win/metro.h
@@ -0,0 +1,125 @@
+// Copyright (c) 2012 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_WIN_METRO_H_
+#define BASE_WIN_METRO_H_
+
+#include <windows.h>
+
+#include "base/base_export.h"
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/strings/string16.h"
+
+namespace base {
+namespace win {
+
+// Identifies the type of the metro launch.
+enum MetroLaunchType {
+  METRO_LAUNCH,
+  METRO_SEARCH,
+  METRO_SHARE,
+  METRO_FILE,
+  METRO_PROTOCOL,
+  METRO_LAUNCH_ERROR,
+  METRO_LASTLAUNCHTYPE,
+};
+
+// In metro mode, this enum identifies the last execution state, i.e. whether
+// we crashed, terminated, etc.
+enum MetroPreviousExecutionState {
+  NOTRUNNING,
+  RUNNING,
+  SUSPENDED,
+  TERMINATED,
+  CLOSEDBYUSER,
+  LASTEXECUTIONSTATE,
+};
+
+// Enum values for UMA histogram reporting of site-specific tile pinning.
+// TODO(tapted): Move this to win8/util when ready (http://crbug.com/160288).
+enum MetroSecondaryTilePinUmaResult {
+  METRO_PIN_STATE_NONE,
+  METRO_PIN_INITIATED,
+  METRO_PIN_LOGO_READY,
+  METRO_PIN_REQUEST_SHOW_ERROR,
+  METRO_PIN_RESULT_CANCEL,
+  METRO_PIN_RESULT_OK,
+  METRO_PIN_RESULT_OTHER,
+  METRO_PIN_RESULT_ERROR,
+  METRO_UNPIN_INITIATED,
+  METRO_UNPIN_REQUEST_SHOW_ERROR,
+  METRO_UNPIN_RESULT_CANCEL,
+  METRO_UNPIN_RESULT_OK,
+  METRO_UNPIN_RESULT_OTHER,
+  METRO_UNPIN_RESULT_ERROR,
+  METRO_PIN_STATE_LIMIT
+};
+
+// Contains information about the currently displayed tab in metro mode.
+struct CurrentTabInfo {
+  wchar_t* title;
+  wchar_t* url;
+};
+
+// Returns the handle to the metro dll loaded in the process. A NULL return
+// indicates that the metro dll was not loaded in the process.
+BASE_EXPORT HMODULE GetMetroModule();
+
+// Returns true if this process is running as an immersive program
+// in Windows Metro mode.
+BASE_EXPORT bool IsMetroProcess();
+
+// Returns true if the process identified by the handle passed in is an
+// immersive (Metro) process.
+BASE_EXPORT bool IsProcessImmersive(HANDLE process);
+
+// Allocates and returns the destination string via the LocalAlloc API after
+// copying the src to it.
+BASE_EXPORT wchar_t* LocalAllocAndCopyString(const string16& src);
+
+// Returns the type of launch and the activation params. For example if the
+// the launch is for METRO_PROTOCOL then the params is a url.
+BASE_EXPORT MetroLaunchType GetMetroLaunchParams(string16* params);
+
+// Handler function for the buttons on a metro dialog box
+typedef void (*MetroDialogButtonPressedHandler)();
+
+// Handler function invoked when a metro style notification is clicked.
+typedef void (*MetroNotificationClickedHandler)(const wchar_t* context);
+
+// Function to display metro style notifications.
+typedef void (*MetroNotification)(const char* origin_url,
+                                  const char* icon_url,
+                                  const wchar_t* title,
+                                  const wchar_t* body,
+                                  const wchar_t* display_source,
+                                  const char* notification_id,
+                                  MetroNotificationClickedHandler handler,
+                                  const wchar_t* handler_context);
+
+// Function to cancel displayed notification.
+typedef bool (*MetroCancelNotification)(const char* notification_id);
+
+// Callback for UMA invoked by Metro Pin and UnPin functions after user gesture.
+typedef base::Callback<void(MetroSecondaryTilePinUmaResult)>
+    MetroPinUmaResultCallback;
+
+// Function to pin a site-specific tile (bookmark) to the start screen.
+typedef void (*MetroPinToStartScreen)(
+    const string16& tile_id,
+    const string16& title,
+    const string16& url,
+    const FilePath& logo_path,
+    const MetroPinUmaResultCallback& callback);
+
+// Function to un-pin a site-specific tile (bookmark) from the start screen.
+typedef void (*MetroUnPinFromStartScreen)(
+    const string16& title_id,
+    const MetroPinUmaResultCallback& callback);
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_METRO_H_
diff --git a/base/win/object_watcher.cc b/base/win/object_watcher.cc
new file mode 100644
index 0000000..5ebe185
--- /dev/null
+++ b/base/win/object_watcher.cc
@@ -0,0 +1,115 @@
+// Copyright (c) 2012 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/win/object_watcher.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+
+namespace base {
+namespace win {
+
+//-----------------------------------------------------------------------------
+
+ObjectWatcher::ObjectWatcher()
+    : object_(NULL),
+      wait_object_(NULL),
+      origin_loop_(NULL),
+      weak_factory_(this) {
+}
+
+ObjectWatcher::~ObjectWatcher() {
+  StopWatching();
+}
+
+bool ObjectWatcher::StartWatching(HANDLE object, Delegate* delegate) {
+  CHECK(delegate);
+  if (wait_object_) {
+    NOTREACHED() << "Already watching an object";
+    return false;
+  }
+
+  // Since our job is to just notice when an object is signaled and report the
+  // result back to this thread, we can just run on a Windows wait thread.
+  DWORD wait_flags = WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE;
+
+  // DoneWaiting can be synchronously called from RegisterWaitForSingleObject,
+  // so set up all state now.
+  callback_ = base::Bind(&ObjectWatcher::Signal, weak_factory_.GetWeakPtr(),
+                         delegate);
+  object_ = object;
+  origin_loop_ = MessageLoop::current();
+
+  if (!RegisterWaitForSingleObject(&wait_object_, object, DoneWaiting,
+                                   this, INFINITE, wait_flags)) {
+    DPLOG(FATAL) << "RegisterWaitForSingleObject failed";
+    object_ = NULL;
+    wait_object_ = NULL;
+    return false;
+  }
+
+  // We need to know if the current message loop is going away so we can
+  // prevent the wait thread from trying to access a dead message loop.
+  MessageLoop::current()->AddDestructionObserver(this);
+  return true;
+}
+
+bool ObjectWatcher::StopWatching() {
+  if (!wait_object_)
+    return false;
+
+  // Make sure ObjectWatcher is used in a single-threaded fashion.
+  DCHECK_EQ(origin_loop_, MessageLoop::current());
+
+  // Blocking call to cancel the wait. Any callbacks already in progress will
+  // finish before we return from this call.
+  if (!UnregisterWaitEx(wait_object_, INVALID_HANDLE_VALUE)) {
+    DPLOG(FATAL) << "UnregisterWaitEx failed";
+    return false;
+  }
+
+  weak_factory_.InvalidateWeakPtrs();
+  object_ = NULL;
+  wait_object_ = NULL;
+
+  MessageLoop::current()->RemoveDestructionObserver(this);
+  return true;
+}
+
+bool ObjectWatcher::IsWatching() const {
+  return object_ != NULL;
+}
+
+HANDLE ObjectWatcher::GetWatchedObject() const {
+  return object_;
+}
+
+// static
+void CALLBACK ObjectWatcher::DoneWaiting(void* param, BOOLEAN timed_out) {
+  DCHECK(!timed_out);
+
+  // The destructor blocks on any callbacks that are in flight, so we know that
+  // that is always a pointer to a valid ObjectWater.
+  ObjectWatcher* that = static_cast<ObjectWatcher*>(param);
+  that->origin_loop_->task_runner()->PostTask(FROM_HERE, that->callback_);
+  that->callback_.Reset();
+}
+
+void ObjectWatcher::Signal(Delegate* delegate) {
+  // Signaling the delegate may result in our destruction or a nested call to
+  // StartWatching(). As a result, we save any state we need and clear previous
+  // watcher state before signaling the delegate.
+  HANDLE object = object_;
+  StopWatching();
+  delegate->OnObjectSignaled(object);
+}
+
+void ObjectWatcher::WillDestroyCurrentMessageLoop() {
+  // Need to shutdown the watch so that we don't try to access the MessageLoop
+  // after this point.
+  StopWatching();
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/object_watcher.h b/base/win/object_watcher.h
new file mode 100644
index 0000000..d68d935
--- /dev/null
+++ b/base/win/object_watcher.h
@@ -0,0 +1,106 @@
+// Copyright (c) 2011 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_WIN_OBJECT_WATCHER_H_
+#define BASE_WIN_OBJECT_WATCHER_H_
+
+#include <windows.h>
+
+#include "base/base_export.h"
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_loop.h"
+
+namespace base {
+namespace win {
+
+// A class that provides a means to asynchronously wait for a Windows object to
+// become signaled.  It is an abstraction around RegisterWaitForSingleObject
+// that provides a notification callback, OnObjectSignaled, that runs back on
+// the origin thread (i.e., the thread that called StartWatching).
+//
+// This class acts like a smart pointer such that when it goes out-of-scope,
+// UnregisterWaitEx is automatically called, and any in-flight notification is
+// suppressed.
+//
+// Typical usage:
+//
+//   class MyClass : public base::ObjectWatcher::Delegate {
+//    public:
+//     void DoStuffWhenSignaled(HANDLE object) {
+//       watcher_.StartWatching(object, this);
+//     }
+//     virtual void OnObjectSignaled(HANDLE object) {
+//       // OK, time to do stuff!
+//     }
+//    private:
+//     base::ObjectWatcher watcher_;
+//   };
+//
+// In the above example, MyClass wants to "do stuff" when object becomes
+// signaled.  ObjectWatcher makes this task easy.  When MyClass goes out of
+// scope, the watcher_ will be destroyed, and there is no need to worry about
+// OnObjectSignaled being called on a deleted MyClass pointer.  Easy!
+// If the object is already signaled before being watched, OnObjectSignaled is
+// still called after (but not necessarily immediately after) watch is started.
+//
+class BASE_EXPORT ObjectWatcher : public MessageLoop::DestructionObserver {
+ public:
+  class BASE_EXPORT Delegate {
+   public:
+    virtual ~Delegate() {}
+    // Called from the MessageLoop when a signaled object is detected.  To
+    // continue watching the object, StartWatching must be called again.
+    virtual void OnObjectSignaled(HANDLE object) = 0;
+  };
+
+  ObjectWatcher();
+  ~ObjectWatcher() override;
+
+  // When the object is signaled, the given delegate is notified on the thread
+  // where StartWatching is called.  The ObjectWatcher is not responsible for
+  // deleting the delegate.
+  //
+  // Returns true if the watch was started.  Otherwise, false is returned.
+  //
+  bool StartWatching(HANDLE object, Delegate* delegate);
+
+  // Stops watching.  Does nothing if the watch has already completed.  If the
+  // watch is still active, then it is canceled, and the associated delegate is
+  // not notified.
+  //
+  // Returns true if the watch was canceled.  Otherwise, false is returned.
+  //
+  bool StopWatching();
+
+  // Returns true if currently watching an object.
+  bool IsWatching() const;
+
+  // Returns the handle of the object being watched.
+  HANDLE GetWatchedObject() const;
+
+ private:
+  // Called on a background thread when done waiting.
+  static void CALLBACK DoneWaiting(void* param, BOOLEAN timed_out);
+
+  void Signal(Delegate* delegate);
+
+  // MessageLoop::DestructionObserver implementation:
+  void WillDestroyCurrentMessageLoop() override;
+
+  // Internal state.
+  Closure callback_;
+  HANDLE object_;             // The object being watched
+  HANDLE wait_object_;        // Returned by RegisterWaitForSingleObject
+  MessageLoop* origin_loop_;  // Used to get back to the origin thread
+
+  WeakPtrFactory<ObjectWatcher> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(ObjectWatcher);
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_OBJECT_WATCHER_H_
diff --git a/base/win/object_watcher_unittest.cc b/base/win/object_watcher_unittest.cc
new file mode 100644
index 0000000..b30ca41
--- /dev/null
+++ b/base/win/object_watcher_unittest.cc
@@ -0,0 +1,174 @@
+// Copyright (c) 2011 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/win/object_watcher.h"
+
+#include <process.h>
+
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+class QuitDelegate : public ObjectWatcher::Delegate {
+ public:
+  void OnObjectSignaled(HANDLE object) override {
+    MessageLoop::current()->QuitWhenIdle();
+  }
+};
+
+class DecrementCountDelegate : public ObjectWatcher::Delegate {
+ public:
+  explicit DecrementCountDelegate(int* counter) : counter_(counter) {
+  }
+  void OnObjectSignaled(HANDLE object) override { --(*counter_); }
+
+ private:
+  int* counter_;
+};
+
+void RunTest_BasicSignal(MessageLoop::Type message_loop_type) {
+  MessageLoop message_loop(message_loop_type);
+
+  ObjectWatcher watcher;
+  EXPECT_FALSE(watcher.IsWatching());
+
+  // A manual-reset event that is not yet signaled.
+  HANDLE event = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+  QuitDelegate delegate;
+  bool ok = watcher.StartWatching(event, &delegate);
+  EXPECT_TRUE(ok);
+  EXPECT_TRUE(watcher.IsWatching());
+  EXPECT_EQ(event, watcher.GetWatchedObject());
+
+  SetEvent(event);
+
+  MessageLoop::current()->Run();
+
+  EXPECT_FALSE(watcher.IsWatching());
+  CloseHandle(event);
+}
+
+void RunTest_BasicCancel(MessageLoop::Type message_loop_type) {
+  MessageLoop message_loop(message_loop_type);
+
+  ObjectWatcher watcher;
+
+  // A manual-reset event that is not yet signaled.
+  HANDLE event = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+  QuitDelegate delegate;
+  bool ok = watcher.StartWatching(event, &delegate);
+  EXPECT_TRUE(ok);
+
+  watcher.StopWatching();
+
+  CloseHandle(event);
+}
+
+void RunTest_CancelAfterSet(MessageLoop::Type message_loop_type) {
+  MessageLoop message_loop(message_loop_type);
+
+  ObjectWatcher watcher;
+
+  int counter = 1;
+  DecrementCountDelegate delegate(&counter);
+
+  // A manual-reset event that is not yet signaled.
+  HANDLE event = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+  bool ok = watcher.StartWatching(event, &delegate);
+  EXPECT_TRUE(ok);
+
+  SetEvent(event);
+
+  // Let the background thread do its business
+  Sleep(30);
+
+  watcher.StopWatching();
+
+  RunLoop().RunUntilIdle();
+
+  // Our delegate should not have fired.
+  EXPECT_EQ(1, counter);
+
+  CloseHandle(event);
+}
+
+void RunTest_SignalBeforeWatch(MessageLoop::Type message_loop_type) {
+  MessageLoop message_loop(message_loop_type);
+
+  ObjectWatcher watcher;
+
+  // A manual-reset event that is signaled before we begin watching.
+  HANDLE event = CreateEvent(NULL, TRUE, TRUE, NULL);
+
+  QuitDelegate delegate;
+  bool ok = watcher.StartWatching(event, &delegate);
+  EXPECT_TRUE(ok);
+
+  MessageLoop::current()->Run();
+
+  EXPECT_FALSE(watcher.IsWatching());
+  CloseHandle(event);
+}
+
+void RunTest_OutlivesMessageLoop(MessageLoop::Type message_loop_type) {
+  // Simulate a MessageLoop that dies before an ObjectWatcher.  This ordinarily
+  // doesn't happen when people use the Thread class, but it can happen when
+  // people use the Singleton pattern or atexit.
+  HANDLE event = CreateEvent(NULL, TRUE, FALSE, NULL);  // not signaled
+  {
+    ObjectWatcher watcher;
+    {
+      MessageLoop message_loop(message_loop_type);
+
+      QuitDelegate delegate;
+      watcher.StartWatching(event, &delegate);
+    }
+  }
+  CloseHandle(event);
+}
+
+}  // namespace
+
+//-----------------------------------------------------------------------------
+
+TEST(ObjectWatcherTest, BasicSignal) {
+  RunTest_BasicSignal(MessageLoop::TYPE_DEFAULT);
+  RunTest_BasicSignal(MessageLoop::TYPE_IO);
+  RunTest_BasicSignal(MessageLoop::TYPE_UI);
+}
+
+TEST(ObjectWatcherTest, BasicCancel) {
+  RunTest_BasicCancel(MessageLoop::TYPE_DEFAULT);
+  RunTest_BasicCancel(MessageLoop::TYPE_IO);
+  RunTest_BasicCancel(MessageLoop::TYPE_UI);
+}
+
+TEST(ObjectWatcherTest, CancelAfterSet) {
+  RunTest_CancelAfterSet(MessageLoop::TYPE_DEFAULT);
+  RunTest_CancelAfterSet(MessageLoop::TYPE_IO);
+  RunTest_CancelAfterSet(MessageLoop::TYPE_UI);
+}
+
+TEST(ObjectWatcherTest, SignalBeforeWatch) {
+  RunTest_SignalBeforeWatch(MessageLoop::TYPE_DEFAULT);
+  RunTest_SignalBeforeWatch(MessageLoop::TYPE_IO);
+  RunTest_SignalBeforeWatch(MessageLoop::TYPE_UI);
+}
+
+TEST(ObjectWatcherTest, OutlivesMessageLoop) {
+  RunTest_OutlivesMessageLoop(MessageLoop::TYPE_DEFAULT);
+  RunTest_OutlivesMessageLoop(MessageLoop::TYPE_IO);
+  RunTest_OutlivesMessageLoop(MessageLoop::TYPE_UI);
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/pe_image.cc b/base/win/pe_image.cc
new file mode 100644
index 0000000..692b7b6
--- /dev/null
+++ b/base/win/pe_image.cc
@@ -0,0 +1,602 @@
+// Copyright (c) 2010 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 implements PEImage, a generic class to manipulate PE files.
+// This file was adapted from GreenBorder's Code.
+
+#include "base/win/pe_image.h"
+
+namespace base {
+namespace win {
+
+// TODO(jschuh): crbug.com/167707 Make sure this code works on 64-bit.
+
+// Structure to perform imports enumerations.
+struct EnumAllImportsStorage {
+  PEImage::EnumImportsFunction callback;
+  PVOID cookie;
+};
+
+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
+  //   if s1 > s2, return positive
+  // Exception if inputs are invalid.
+  int StrCmpByByte(LPCSTR s1, LPCSTR s2) {
+    while (*s1 != '\0' && *s1 == *s2) {
+      ++s1;
+      ++s2;
+    }
+
+    return (*reinterpret_cast<const unsigned char*>(s1) -
+            *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.
+bool ProcessImportChunk(const PEImage &image, LPCSTR module,
+                        PIMAGE_THUNK_DATA name_table,
+                        PIMAGE_THUNK_DATA iat, PVOID cookie) {
+  EnumAllImportsStorage &storage = *reinterpret_cast<EnumAllImportsStorage*>(
+                                       cookie);
+
+  return image.EnumOneImportChunk(storage.callback, module, name_table, iat,
+                                  storage.cookie);
+}
+
+// Callback used to enumerate delay imports. See EnumDelayImportChunksFunction.
+bool ProcessDelayImportChunk(const PEImage &image,
+                             PImgDelayDescr delay_descriptor,
+                             LPCSTR module, PIMAGE_THUNK_DATA name_table,
+                             PIMAGE_THUNK_DATA iat, PIMAGE_THUNK_DATA bound_iat,
+                             PIMAGE_THUNK_DATA unload_iat, PVOID cookie) {
+  EnumAllImportsStorage &storage = *reinterpret_cast<EnumAllImportsStorage*>(
+                                       cookie);
+
+  return image.EnumOneDelayImportChunk(storage.callback, delay_descriptor,
+                                       module, name_table, iat, bound_iat,
+                                       unload_iat, storage.cookie);
+}
+
+void PEImage::set_module(HMODULE module) {
+  module_ = module;
+}
+
+PIMAGE_DOS_HEADER PEImage::GetDosHeader() const {
+  return reinterpret_cast<PIMAGE_DOS_HEADER>(module_);
+}
+
+PIMAGE_NT_HEADERS PEImage::GetNTHeaders() const {
+  PIMAGE_DOS_HEADER dos_header = GetDosHeader();
+
+  return reinterpret_cast<PIMAGE_NT_HEADERS>(
+      reinterpret_cast<char*>(dos_header) + dos_header->e_lfanew);
+}
+
+PIMAGE_SECTION_HEADER PEImage::GetSectionHeader(UINT section) const {
+  PIMAGE_NT_HEADERS nt_headers = GetNTHeaders();
+  PIMAGE_SECTION_HEADER first_section = IMAGE_FIRST_SECTION(nt_headers);
+
+  if (section < nt_headers->FileHeader.NumberOfSections)
+    return first_section + section;
+  else
+    return NULL;
+}
+
+WORD PEImage::GetNumSections() const {
+  return GetNTHeaders()->FileHeader.NumberOfSections;
+}
+
+DWORD PEImage::GetImageDirectoryEntrySize(UINT directory) const {
+  PIMAGE_NT_HEADERS nt_headers = GetNTHeaders();
+
+  return nt_headers->OptionalHeader.DataDirectory[directory].Size;
+}
+
+PVOID PEImage::GetImageDirectoryEntryAddr(UINT directory) const {
+  PIMAGE_NT_HEADERS nt_headers = GetNTHeaders();
+
+  return RVAToAddr(
+      nt_headers->OptionalHeader.DataDirectory[directory].VirtualAddress);
+}
+
+PIMAGE_SECTION_HEADER PEImage::GetImageSectionFromAddr(PVOID address) const {
+  PBYTE target = reinterpret_cast<PBYTE>(address);
+  PIMAGE_SECTION_HEADER section;
+
+  for (UINT i = 0; NULL != (section = GetSectionHeader(i)); i++) {
+    // Don't use the virtual RVAToAddr.
+    PBYTE start = reinterpret_cast<PBYTE>(
+                      PEImage::RVAToAddr(section->VirtualAddress));
+
+    DWORD size = section->Misc.VirtualSize;
+
+    if ((start <= target) && (start + size > target))
+      return section;
+  }
+
+  return NULL;
+}
+
+PIMAGE_SECTION_HEADER PEImage::GetImageSectionHeaderByName(
+    LPCSTR section_name) const {
+  if (NULL == section_name)
+    return NULL;
+
+  PIMAGE_SECTION_HEADER ret = NULL;
+  int num_sections = GetNumSections();
+
+  for (int i = 0; i < num_sections; i++) {
+    PIMAGE_SECTION_HEADER section = GetSectionHeader(i);
+    if (0 == _strnicmp(reinterpret_cast<LPCSTR>(section->Name), section_name,
+                       sizeof(section->Name))) {
+      ret = section;
+      break;
+    }
+  }
+
+  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();
+
+  if (NULL == exports)
+    return NULL;
+
+  WORD ordinal = 0;
+  if (!GetProcOrdinal(name, &ordinal))
+    return NULL;
+
+  PDWORD functions = reinterpret_cast<PDWORD>(
+                         RVAToAddr(exports->AddressOfFunctions));
+
+  return functions + ordinal - exports->Base;
+}
+
+FARPROC PEImage::GetProcAddress(LPCSTR function_name) const {
+  PDWORD export_entry = GetExportEntry(function_name);
+  if (NULL == export_entry)
+    return NULL;
+
+  PBYTE function = reinterpret_cast<PBYTE>(RVAToAddr(*export_entry));
+
+  PBYTE exports = reinterpret_cast<PBYTE>(
+      GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_EXPORT));
+  DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_EXPORT);
+
+  // Check for forwarded exports as a special case.
+  if (exports <= function && exports + size > function)
+#pragma warning(push)
+#pragma warning(disable: 4312)
+    // This cast generates a warning because it is 32 bit specific.
+    return reinterpret_cast<FARPROC>(0xFFFFFFFF);
+#pragma warning(pop)
+
+  return reinterpret_cast<FARPROC>(function);
+}
+
+bool PEImage::GetProcOrdinal(LPCSTR function_name, WORD *ordinal) const {
+  if (NULL == ordinal)
+    return false;
+
+  PIMAGE_EXPORT_DIRECTORY exports = GetExportDirectory();
+
+  if (NULL == exports)
+    return false;
+
+  if (IsOrdinal(function_name)) {
+    *ordinal = ToOrdinal(function_name);
+  } else {
+    PDWORD names = reinterpret_cast<PDWORD>(RVAToAddr(exports->AddressOfNames));
+    PDWORD lower = names;
+    PDWORD upper = names + exports->NumberOfNames;
+    int cmp = -1;
+
+    // Binary Search for the name.
+    while (lower != upper) {
+      PDWORD middle = lower + (upper - lower) / 2;
+      LPCSTR name = reinterpret_cast<LPCSTR>(RVAToAddr(*middle));
+
+      // This may be called by sandbox before MSVCRT dll loads, so can't use
+      // CRT function here.
+      cmp = StrCmpByByte(function_name, name);
+
+      if (cmp == 0) {
+        lower = middle;
+        break;
+      }
+
+      if (cmp > 0)
+        lower = middle + 1;
+      else
+        upper = middle;
+    }
+
+    if (cmp != 0)
+      return false;
+
+
+    PWORD ordinals = reinterpret_cast<PWORD>(
+                         RVAToAddr(exports->AddressOfNameOrdinals));
+
+    *ordinal = ordinals[lower - names] + static_cast<WORD>(exports->Base);
+  }
+
+  return true;
+}
+
+bool PEImage::EnumSections(EnumSectionsFunction callback, PVOID cookie) const {
+  PIMAGE_NT_HEADERS nt_headers = GetNTHeaders();
+  UINT num_sections = nt_headers->FileHeader.NumberOfSections;
+  PIMAGE_SECTION_HEADER section = GetSectionHeader(0);
+
+  for (UINT i = 0; i < num_sections; i++, section++) {
+    PVOID section_start = RVAToAddr(section->VirtualAddress);
+    DWORD size = section->Misc.VirtualSize;
+
+    if (!callback(*this, section, section_start, size, cookie))
+      return false;
+  }
+
+  return true;
+}
+
+bool PEImage::EnumExports(EnumExportsFunction callback, PVOID cookie) const {
+  PVOID directory = GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_EXPORT);
+  DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_EXPORT);
+
+  // Check if there are any exports at all.
+  if (NULL == directory || 0 == size)
+    return true;
+
+  PIMAGE_EXPORT_DIRECTORY exports = reinterpret_cast<PIMAGE_EXPORT_DIRECTORY>(
+                                        directory);
+  UINT ordinal_base = exports->Base;
+  UINT num_funcs = exports->NumberOfFunctions;
+  UINT num_names = exports->NumberOfNames;
+  PDWORD functions  = reinterpret_cast<PDWORD>(RVAToAddr(
+                          exports->AddressOfFunctions));
+  PDWORD names = reinterpret_cast<PDWORD>(RVAToAddr(exports->AddressOfNames));
+  PWORD ordinals = reinterpret_cast<PWORD>(RVAToAddr(
+                       exports->AddressOfNameOrdinals));
+
+  for (UINT count = 0; count < num_funcs; count++) {
+    PVOID func = RVAToAddr(functions[count]);
+    if (NULL == func)
+      continue;
+
+    // Check for a name.
+    LPCSTR name = NULL;
+    UINT hint;
+    for (hint = 0; hint < num_names; hint++) {
+      if (ordinals[hint] == count) {
+        name = reinterpret_cast<LPCSTR>(RVAToAddr(names[hint]));
+        break;
+      }
+    }
+
+    if (name == NULL)
+      hint = 0;
+
+    // Check for forwarded exports.
+    LPCSTR forward = NULL;
+    if (reinterpret_cast<char*>(func) >= reinterpret_cast<char*>(directory) &&
+        reinterpret_cast<char*>(func) <= reinterpret_cast<char*>(directory) +
+            size) {
+      forward = reinterpret_cast<LPCSTR>(func);
+      func = 0;
+    }
+
+    if (!callback(*this, ordinal_base + count, hint, name, func, forward,
+                  cookie))
+      return false;
+  }
+
+  return true;
+}
+
+bool PEImage::EnumRelocs(EnumRelocsFunction callback, PVOID cookie) const {
+  PVOID directory = GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_BASERELOC);
+  DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_BASERELOC);
+  PIMAGE_BASE_RELOCATION base = reinterpret_cast<PIMAGE_BASE_RELOCATION>(
+      directory);
+
+  if (!directory)
+    return true;
+
+  while (size >= sizeof(IMAGE_BASE_RELOCATION) && base->SizeOfBlock &&
+         size >= base->SizeOfBlock) {
+    PWORD reloc = reinterpret_cast<PWORD>(base + 1);
+    UINT num_relocs = (base->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) /
+        sizeof(WORD);
+
+    for (UINT i = 0; i < num_relocs; i++, reloc++) {
+      WORD type = *reloc >> 12;
+      PVOID address = RVAToAddr(base->VirtualAddress + (*reloc & 0x0FFF));
+
+      if (!callback(*this, type, address, cookie))
+        return false;
+    }
+
+    size -= base->SizeOfBlock;
+    base = reinterpret_cast<PIMAGE_BASE_RELOCATION>(
+               reinterpret_cast<char*>(base) + base->SizeOfBlock);
+  }
+
+  return true;
+}
+
+bool PEImage::EnumImportChunks(EnumImportChunksFunction callback,
+                               PVOID cookie) const {
+  DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_IMPORT);
+  PIMAGE_IMPORT_DESCRIPTOR import = GetFirstImportChunk();
+
+  if (import == NULL || size < sizeof(IMAGE_IMPORT_DESCRIPTOR))
+    return true;
+
+  for (; import->FirstThunk; import++) {
+    LPCSTR module_name = reinterpret_cast<LPCSTR>(RVAToAddr(import->Name));
+    PIMAGE_THUNK_DATA name_table = reinterpret_cast<PIMAGE_THUNK_DATA>(
+                                       RVAToAddr(import->OriginalFirstThunk));
+    PIMAGE_THUNK_DATA iat = reinterpret_cast<PIMAGE_THUNK_DATA>(
+                                RVAToAddr(import->FirstThunk));
+
+    if (!callback(*this, module_name, name_table, iat, cookie))
+      return false;
+  }
+
+  return true;
+}
+
+bool PEImage::EnumOneImportChunk(EnumImportsFunction callback,
+                                 LPCSTR module_name,
+                                 PIMAGE_THUNK_DATA name_table,
+                                 PIMAGE_THUNK_DATA iat, PVOID cookie) const {
+  if (NULL == name_table)
+    return false;
+
+  for (; name_table && name_table->u1.Ordinal; name_table++, iat++) {
+    LPCSTR name = NULL;
+    WORD ordinal = 0;
+    WORD hint = 0;
+
+    if (IMAGE_SNAP_BY_ORDINAL(name_table->u1.Ordinal)) {
+      ordinal = static_cast<WORD>(IMAGE_ORDINAL32(name_table->u1.Ordinal));
+    } else {
+      PIMAGE_IMPORT_BY_NAME import = reinterpret_cast<PIMAGE_IMPORT_BY_NAME>(
+          RVAToAddr(name_table->u1.ForwarderString));
+
+      hint = import->Hint;
+      name = reinterpret_cast<LPCSTR>(&import->Name);
+    }
+
+    if (!callback(*this, module_name, ordinal, name, hint, iat, cookie))
+      return false;
+  }
+
+  return true;
+}
+
+bool PEImage::EnumAllImports(EnumImportsFunction callback, PVOID cookie) const {
+  EnumAllImportsStorage temp = { callback, cookie };
+  return EnumImportChunks(ProcessImportChunk, &temp);
+}
+
+bool PEImage::EnumDelayImportChunks(EnumDelayImportChunksFunction callback,
+                                    PVOID cookie) const {
+  PVOID directory = GetImageDirectoryEntryAddr(
+                        IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT);
+  DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT);
+  PImgDelayDescr delay_descriptor = reinterpret_cast<PImgDelayDescr>(directory);
+
+  if (directory == NULL || size == 0)
+    return true;
+
+  for (; delay_descriptor->rvaHmod; delay_descriptor++) {
+    PIMAGE_THUNK_DATA name_table;
+    PIMAGE_THUNK_DATA iat;
+    PIMAGE_THUNK_DATA bound_iat;    // address of the optional bound IAT
+    PIMAGE_THUNK_DATA unload_iat;   // address of optional copy of original IAT
+    LPCSTR module_name;
+
+    // check if VC7-style imports, using RVAs instead of
+    // VC6-style addresses.
+    bool rvas = (delay_descriptor->grAttrs & dlattrRva) != 0;
+
+    if (rvas) {
+      module_name = reinterpret_cast<LPCSTR>(
+                        RVAToAddr(delay_descriptor->rvaDLLName));
+      name_table = reinterpret_cast<PIMAGE_THUNK_DATA>(
+                       RVAToAddr(delay_descriptor->rvaINT));
+      iat = reinterpret_cast<PIMAGE_THUNK_DATA>(
+                RVAToAddr(delay_descriptor->rvaIAT));
+      bound_iat = reinterpret_cast<PIMAGE_THUNK_DATA>(
+                      RVAToAddr(delay_descriptor->rvaBoundIAT));
+      unload_iat = reinterpret_cast<PIMAGE_THUNK_DATA>(
+                       RVAToAddr(delay_descriptor->rvaUnloadIAT));
+    } else {
+#pragma warning(push)
+#pragma warning(disable: 4312)
+      // These casts generate warnings because they are 32 bit specific.
+      module_name = reinterpret_cast<LPCSTR>(delay_descriptor->rvaDLLName);
+      name_table = reinterpret_cast<PIMAGE_THUNK_DATA>(
+                       delay_descriptor->rvaINT);
+      iat = reinterpret_cast<PIMAGE_THUNK_DATA>(delay_descriptor->rvaIAT);
+      bound_iat = reinterpret_cast<PIMAGE_THUNK_DATA>(
+                      delay_descriptor->rvaBoundIAT);
+      unload_iat = reinterpret_cast<PIMAGE_THUNK_DATA>(
+                       delay_descriptor->rvaUnloadIAT);
+#pragma warning(pop)
+    }
+
+    if (!callback(*this, delay_descriptor, module_name, name_table, iat,
+                  bound_iat, unload_iat, cookie))
+      return false;
+  }
+
+  return true;
+}
+
+bool PEImage::EnumOneDelayImportChunk(EnumImportsFunction callback,
+                                      PImgDelayDescr delay_descriptor,
+                                      LPCSTR module_name,
+                                      PIMAGE_THUNK_DATA name_table,
+                                      PIMAGE_THUNK_DATA iat,
+                                      PIMAGE_THUNK_DATA bound_iat,
+                                      PIMAGE_THUNK_DATA unload_iat,
+                                      PVOID cookie) const {
+  UNREFERENCED_PARAMETER(bound_iat);
+  UNREFERENCED_PARAMETER(unload_iat);
+
+  for (; name_table->u1.Ordinal; name_table++, iat++) {
+    LPCSTR name = NULL;
+    WORD ordinal = 0;
+    WORD hint = 0;
+
+    if (IMAGE_SNAP_BY_ORDINAL(name_table->u1.Ordinal)) {
+      ordinal = static_cast<WORD>(IMAGE_ORDINAL32(name_table->u1.Ordinal));
+    } else {
+      PIMAGE_IMPORT_BY_NAME import;
+      bool rvas = (delay_descriptor->grAttrs & dlattrRva) != 0;
+
+      if (rvas) {
+        import = reinterpret_cast<PIMAGE_IMPORT_BY_NAME>(
+                     RVAToAddr(name_table->u1.ForwarderString));
+      } else {
+#pragma warning(push)
+#pragma warning(disable: 4312)
+        // This cast generates a warning because it is 32 bit specific.
+        import = reinterpret_cast<PIMAGE_IMPORT_BY_NAME>(
+                     name_table->u1.ForwarderString);
+#pragma warning(pop)
+      }
+
+      hint = import->Hint;
+      name = reinterpret_cast<LPCSTR>(&import->Name);
+    }
+
+    if (!callback(*this, module_name, ordinal, name, hint, iat, cookie))
+      return false;
+  }
+
+  return true;
+}
+
+bool PEImage::EnumAllDelayImports(EnumImportsFunction callback,
+                                  PVOID cookie) const {
+  EnumAllImportsStorage temp = { callback, cookie };
+  return EnumDelayImportChunks(ProcessDelayImportChunk, &temp);
+}
+
+bool PEImage::VerifyMagic() const {
+  PIMAGE_DOS_HEADER dos_header = GetDosHeader();
+
+  if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)
+    return false;
+
+  PIMAGE_NT_HEADERS nt_headers = GetNTHeaders();
+
+  if (nt_headers->Signature != IMAGE_NT_SIGNATURE)
+    return false;
+
+  if (nt_headers->FileHeader.SizeOfOptionalHeader !=
+      sizeof(IMAGE_OPTIONAL_HEADER))
+    return false;
+
+  if (nt_headers->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)
+    return false;
+
+  return true;
+}
+
+bool PEImage::ImageRVAToOnDiskOffset(DWORD rva, DWORD *on_disk_offset) const {
+  LPVOID address = RVAToAddr(rva);
+  return ImageAddrToOnDiskOffset(address, on_disk_offset);
+}
+
+bool PEImage::ImageAddrToOnDiskOffset(LPVOID address,
+                                      DWORD *on_disk_offset) const {
+  if (NULL == address)
+    return false;
+
+  // Get the section that this address belongs to.
+  PIMAGE_SECTION_HEADER section_header = GetImageSectionFromAddr(address);
+  if (NULL == section_header)
+    return false;
+
+  // Don't follow the virtual RVAToAddr, use the one on the base.
+  DWORD offset_within_section =
+      static_cast<DWORD>(reinterpret_cast<uintptr_t>(address)) -
+      static_cast<DWORD>(reinterpret_cast<uintptr_t>(
+          PEImage::RVAToAddr(section_header->VirtualAddress)));
+
+  *on_disk_offset = section_header->PointerToRawData + offset_within_section;
+  return true;
+}
+
+PVOID PEImage::RVAToAddr(DWORD rva) const {
+  if (rva == 0)
+    return NULL;
+
+  return reinterpret_cast<char*>(module_) + rva;
+}
+
+PVOID PEImageAsData::RVAToAddr(DWORD rva) const {
+  if (rva == 0)
+    return NULL;
+
+  PVOID in_memory = PEImage::RVAToAddr(rva);
+  DWORD disk_offset;
+
+  if (!ImageAddrToOnDiskOffset(in_memory, &disk_offset))
+    return NULL;
+
+  return PEImage::RVAToAddr(disk_offset);
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/pe_image.h b/base/win/pe_image.h
new file mode 100644
index 0000000..343d286
--- /dev/null
+++ b/base/win/pe_image.h
@@ -0,0 +1,269 @@
+// Copyright (c) 2010 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 was adapted from GreenBorder's Code.
+// To understand what this class is about (for other than well known functions
+// as GetProcAddress), a good starting point is "An In-Depth Look into the
+// Win32 Portable Executable File Format" by Matt Pietrek:
+// http://msdn.microsoft.com/msdnmag/issues/02/02/PE/default.aspx
+
+#ifndef BASE_WIN_PE_IMAGE_H_
+#define BASE_WIN_PE_IMAGE_H_
+
+#include <windows.h>
+
+#if defined(_WIN32_WINNT_WIN8)
+// The Windows 8 SDK defines FACILITY_VISUALCPP in winerror.h.
+#undef FACILITY_VISUALCPP
+#endif
+#include <DelayIMP.h>
+
+namespace base {
+namespace win {
+
+// This class is a wrapper for the Portable Executable File Format (PE).
+// Its main purpose is to provide an easy way to work with imports and exports
+// from a file, mapped in memory as image.
+class PEImage {
+ public:
+  // Callback to enumerate sections.
+  // cookie is the value passed to the enumerate method.
+  // Returns true to continue the enumeration.
+  typedef bool (*EnumSectionsFunction)(const PEImage &image,
+                                       PIMAGE_SECTION_HEADER header,
+                                       PVOID section_start, DWORD section_size,
+                                       PVOID cookie);
+
+  // Callback to enumerate exports.
+  // function is the actual address of the symbol. If forward is not null, it
+  // contains the dll and symbol to forward this export to. cookie is the value
+  // passed to the enumerate method.
+  // Returns true to continue the enumeration.
+  typedef bool (*EnumExportsFunction)(const PEImage &image, DWORD ordinal,
+                                      DWORD hint, LPCSTR name, PVOID function,
+                                      LPCSTR forward, PVOID cookie);
+
+  // Callback to enumerate import blocks.
+  // name_table and iat point to the imports name table and address table for
+  // this block. cookie is the value passed to the enumerate method.
+  // Returns true to continue the enumeration.
+  typedef bool (*EnumImportChunksFunction)(const PEImage &image, LPCSTR module,
+                                           PIMAGE_THUNK_DATA name_table,
+                                           PIMAGE_THUNK_DATA iat, PVOID cookie);
+
+  // Callback to enumerate imports.
+  // module is the dll that exports this symbol. cookie is the value passed to
+  // the enumerate method.
+  // Returns true to continue the enumeration.
+  typedef bool (*EnumImportsFunction)(const PEImage &image, LPCSTR module,
+                                      DWORD ordinal, LPCSTR name, DWORD hint,
+                                      PIMAGE_THUNK_DATA iat, PVOID cookie);
+
+  // Callback to enumerate dalayed import blocks.
+  // module is the dll that exports this block of symbols. cookie is the value
+  // passed to the enumerate method.
+  // Returns true to continue the enumeration.
+  typedef bool (*EnumDelayImportChunksFunction)(const PEImage &image,
+                                                PImgDelayDescr delay_descriptor,
+                                                LPCSTR module,
+                                                PIMAGE_THUNK_DATA name_table,
+                                                PIMAGE_THUNK_DATA iat,
+                                                PIMAGE_THUNK_DATA bound_iat,
+                                                PIMAGE_THUNK_DATA unload_iat,
+                                                PVOID cookie);
+
+  // Callback to enumerate relocations.
+  // cookie is the value passed to the enumerate method.
+  // Returns true to continue the enumeration.
+  typedef bool (*EnumRelocsFunction)(const PEImage &image, WORD type,
+                                     PVOID address, PVOID cookie);
+
+  explicit PEImage(HMODULE module) : module_(module) {}
+  explicit PEImage(const void* module) {
+    module_ = reinterpret_cast<HMODULE>(const_cast<void*>(module));
+  }
+
+  virtual ~PEImage() {}
+
+  // Gets the HMODULE for this object.
+  HMODULE module() const;
+
+  // Sets this object's HMODULE.
+  void set_module(HMODULE module);
+
+  // Checks if this symbol is actually an ordinal.
+  static bool IsOrdinal(LPCSTR name);
+
+  // Converts a named symbol to the corresponding ordinal.
+  static WORD ToOrdinal(LPCSTR name);
+
+  // Returns the DOS_HEADER for this PE.
+  PIMAGE_DOS_HEADER GetDosHeader() const;
+
+  // Returns the NT_HEADER for this PE.
+  PIMAGE_NT_HEADERS GetNTHeaders() const;
+
+  // Returns number of sections of this PE.
+  WORD GetNumSections() const;
+
+  // Returns the header for a given section.
+  // returns NULL if there is no such section.
+  PIMAGE_SECTION_HEADER GetSectionHeader(UINT section) const;
+
+  // Returns the size of a given directory entry.
+  DWORD GetImageDirectoryEntrySize(UINT directory) const;
+
+  // Returns the address of a given directory entry.
+  PVOID GetImageDirectoryEntryAddr(UINT directory) const;
+
+  // Returns the section header for a given address.
+  // Use: s = image.GetImageSectionFromAddr(a);
+  // Post: 's' is the section header of the section that contains 'a'
+  //       or NULL if there is no such section.
+  PIMAGE_SECTION_HEADER GetImageSectionFromAddr(PVOID address) const;
+
+  // Returns the section header for a given section.
+  PIMAGE_SECTION_HEADER GetImageSectionHeaderByName(LPCSTR section_name) const;
+
+  // Returns the first block of imports.
+  PIMAGE_IMPORT_DESCRIPTOR GetFirstImportChunk() const;
+
+  // 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
+  // Post: 'e' is a pointer to the export directory entry
+  //       that contains 'f's export RVA, or NULL if 'f'
+  //       is not exported from this image
+  PDWORD GetExportEntry(LPCSTR name) const;
+
+  // Returns the address for a given exported symbol.
+  // Use: p = image.GetProcAddress(f);
+  // Pre: 'f' is either a zero terminated string or ordinal.
+  // Post: if 'f' is a non-forwarded export from image, 'p' is
+  //       the exported function. If 'f' is a forwarded export
+  //       then p is the special value 0xFFFFFFFF. In this case
+  //       RVAToAddr(*GetExportEntry) can be used to resolve
+  //       the string that describes the forward.
+  FARPROC GetProcAddress(LPCSTR function_name) const;
+
+  // Retrieves the ordinal for a given exported symbol.
+  // Returns true if the symbol was found.
+  bool GetProcOrdinal(LPCSTR function_name, WORD *ordinal) const;
+
+  // Enumerates PE sections.
+  // cookie is a generic cookie to pass to the callback.
+  // Returns true on success.
+  bool EnumSections(EnumSectionsFunction callback, PVOID cookie) const;
+
+  // Enumerates PE exports.
+  // cookie is a generic cookie to pass to the callback.
+  // Returns true on success.
+  bool EnumExports(EnumExportsFunction callback, PVOID cookie) const;
+
+  // Enumerates PE imports.
+  // cookie is a generic cookie to pass to the callback.
+  // Returns true on success.
+  bool EnumAllImports(EnumImportsFunction callback, PVOID cookie) const;
+
+  // Enumerates PE import blocks.
+  // cookie is a generic cookie to pass to the callback.
+  // Returns true on success.
+  bool EnumImportChunks(EnumImportChunksFunction callback, PVOID cookie) const;
+
+  // Enumerates the imports from a single PE import block.
+  // cookie is a generic cookie to pass to the callback.
+  // Returns true on success.
+  bool EnumOneImportChunk(EnumImportsFunction callback, LPCSTR module_name,
+                          PIMAGE_THUNK_DATA name_table, PIMAGE_THUNK_DATA iat,
+                          PVOID cookie) const;
+
+
+  // Enumerates PE delay imports.
+  // cookie is a generic cookie to pass to the callback.
+  // Returns true on success.
+  bool EnumAllDelayImports(EnumImportsFunction callback, PVOID cookie) const;
+
+  // Enumerates PE delay import blocks.
+  // cookie is a generic cookie to pass to the callback.
+  // Returns true on success.
+  bool EnumDelayImportChunks(EnumDelayImportChunksFunction callback,
+                             PVOID cookie) const;
+
+  // Enumerates imports from a single PE delay import block.
+  // cookie is a generic cookie to pass to the callback.
+  // Returns true on success.
+  bool EnumOneDelayImportChunk(EnumImportsFunction callback,
+                               PImgDelayDescr delay_descriptor,
+                               LPCSTR module_name,
+                               PIMAGE_THUNK_DATA name_table,
+                               PIMAGE_THUNK_DATA iat,
+                               PIMAGE_THUNK_DATA bound_iat,
+                               PIMAGE_THUNK_DATA unload_iat,
+                               PVOID cookie) const;
+
+  // Enumerates PE relocation entries.
+  // cookie is a generic cookie to pass to the callback.
+  // Returns true on success.
+  bool EnumRelocs(EnumRelocsFunction callback, PVOID cookie) const;
+
+  // Verifies the magic values on the PE file.
+  // Returns true if all values are correct.
+  bool VerifyMagic() const;
+
+  // Converts an rva value to the appropriate address.
+  virtual PVOID RVAToAddr(DWORD rva) const;
+
+  // Converts an rva value to an offset on disk.
+  // Returns true on success.
+  bool ImageRVAToOnDiskOffset(DWORD rva, DWORD *on_disk_offset) const;
+
+  // Converts an address to an offset on disk.
+  // Returns true on success.
+  bool ImageAddrToOnDiskOffset(LPVOID address, DWORD *on_disk_offset) const;
+
+ private:
+  HMODULE module_;
+};
+
+// This class is an extension to the PEImage class that allows working with PE
+// files mapped as data instead of as image file.
+class PEImageAsData : public PEImage {
+ public:
+  explicit PEImageAsData(HMODULE hModule) : PEImage(hModule) {}
+
+  PVOID RVAToAddr(DWORD rva) const override;
+};
+
+inline bool PEImage::IsOrdinal(LPCSTR name) {
+  return reinterpret_cast<uintptr_t>(name) <= 0xFFFF;
+}
+
+inline WORD PEImage::ToOrdinal(LPCSTR name) {
+  return static_cast<WORD>(reinterpret_cast<intptr_t>(name));
+}
+
+inline HMODULE PEImage::module() const {
+  return module_;
+}
+
+inline PIMAGE_IMPORT_DESCRIPTOR PEImage::GetFirstImportChunk() const {
+  return reinterpret_cast<PIMAGE_IMPORT_DESCRIPTOR>(
+             GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_IMPORT));
+}
+
+inline PIMAGE_EXPORT_DIRECTORY PEImage::GetExportDirectory() const {
+  return reinterpret_cast<PIMAGE_EXPORT_DIRECTORY>(
+             GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_EXPORT));
+}
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_PE_IMAGE_H_
diff --git a/base/win/pe_image_test.cc b/base/win/pe_image_test.cc
new file mode 100644
index 0000000..e374598
--- /dev/null
+++ b/base/win/pe_image_test.cc
@@ -0,0 +1,31 @@
+// 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 <windows.h>
+
+#include <cfgmgr32.h>
+#include <shellapi.h>
+
+extern "C" {
+
+__declspec(dllexport) void ExportFunc1() {
+  // Call into user32.dll.
+  HWND dummy = GetDesktopWindow();
+  SetWindowTextA(dummy, "dummy");
+}
+
+__declspec(dllexport) void ExportFunc2() {
+  // Call into cfgmgr32.dll.
+  CM_MapCrToWin32Err(CR_SUCCESS, ERROR_SUCCESS);
+
+  // Call into shell32.dll.
+  SHFILEOPSTRUCT file_operation = {0};
+  SHFileOperation(&file_operation);
+
+  // Call into kernel32.dll.
+  HANDLE h = CreateEvent(NULL, FALSE, FALSE, NULL);
+  CloseHandle(h);
+}
+
+}  // extern "C"
diff --git a/base/win/pe_image_unittest.cc b/base/win/pe_image_unittest.cc
new file mode 100644
index 0000000..28b65a4
--- /dev/null
+++ b/base/win/pe_image_unittest.cc
@@ -0,0 +1,195 @@
+// Copyright (c) 2012 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 contains unit tests for PEImage.
+#include <algorithm>
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "base/win/pe_image.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+// Just counts the number of invocations.
+bool ImportsCallback(const PEImage& image,
+                     LPCSTR module,
+                     DWORD ordinal,
+                     LPCSTR name,
+                     DWORD hint,
+                     PIMAGE_THUNK_DATA iat,
+                     PVOID cookie) {
+  int* count = reinterpret_cast<int*>(cookie);
+  (*count)++;
+  return true;
+}
+
+// Just counts the number of invocations.
+bool SectionsCallback(const PEImage& image,
+                      PIMAGE_SECTION_HEADER header,
+                      PVOID section_start,
+                      DWORD section_size,
+                      PVOID cookie) {
+  int* count = reinterpret_cast<int*>(cookie);
+  (*count)++;
+  return true;
+}
+
+// Just counts the number of invocations.
+bool RelocsCallback(const PEImage& image,
+                    WORD type,
+                    PVOID address,
+                    PVOID cookie) {
+  int* count = reinterpret_cast<int*>(cookie);
+  (*count)++;
+  return true;
+}
+
+// Just counts the number of invocations.
+bool ImportChunksCallback(const PEImage& image,
+                          LPCSTR module,
+                          PIMAGE_THUNK_DATA name_table,
+                          PIMAGE_THUNK_DATA iat,
+                          PVOID cookie) {
+  int* count = reinterpret_cast<int*>(cookie);
+  (*count)++;
+  return true;
+}
+
+// Just counts the number of invocations.
+bool DelayImportChunksCallback(const PEImage& image,
+                               PImgDelayDescr delay_descriptor,
+                               LPCSTR module,
+                               PIMAGE_THUNK_DATA name_table,
+                               PIMAGE_THUNK_DATA iat,
+                               PIMAGE_THUNK_DATA bound_iat,
+                               PIMAGE_THUNK_DATA unload_iat,
+                               PVOID cookie) {
+  int* count = reinterpret_cast<int*>(cookie);
+  (*count)++;
+  return true;
+}
+
+// Just counts the number of invocations.
+bool ExportsCallback(const PEImage& image,
+                     DWORD ordinal,
+                     DWORD hint,
+                     LPCSTR name,
+                     PVOID function,
+                     LPCSTR forward,
+                     PVOID cookie) {
+  int* count = reinterpret_cast<int*>(cookie);
+  (*count)++;
+  return true;
+}
+
+}  // namespace
+
+// Tests that we are able to enumerate stuff from a PE file, and that
+// the actual number of items found matches an expected value.
+TEST(PEImageTest, EnumeratesPE) {
+  base::FilePath pe_image_test_path;
+  ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &pe_image_test_path));
+  pe_image_test_path = pe_image_test_path.Append(FILE_PATH_LITERAL("pe_image"));
+
+#if defined(ARCH_CPU_64_BITS)
+  pe_image_test_path =
+      pe_image_test_path.Append(FILE_PATH_LITERAL("pe_image_test_64.dll"));
+  const int sections = 6;
+  const int imports_dlls = 2;
+  const int delay_dlls = 2;
+  const int exports = 2;
+  const int imports = 69;
+  const int delay_imports = 2;
+  const int relocs = 632;
+#else
+  pe_image_test_path =
+      pe_image_test_path.Append(FILE_PATH_LITERAL("pe_image_test_32.dll"));
+  const int sections = 5;
+  const int imports_dlls = 2;
+  const int delay_dlls = 2;
+  const int exports = 2;
+  const int imports = 66;
+  const int delay_imports = 2;
+  const int relocs = 1586;
+#endif
+
+  HMODULE module = LoadLibrary(pe_image_test_path.value().c_str());
+  ASSERT_TRUE(NULL != module);
+
+  PEImage pe(module);
+  int count = 0;
+  EXPECT_TRUE(pe.VerifyMagic());
+
+  pe.EnumSections(SectionsCallback, &count);
+  EXPECT_EQ(sections, count);
+
+  count = 0;
+  pe.EnumImportChunks(ImportChunksCallback, &count);
+  EXPECT_EQ(imports_dlls, count);
+
+  count = 0;
+  pe.EnumDelayImportChunks(DelayImportChunksCallback, &count);
+  EXPECT_EQ(delay_dlls, count);
+
+  count = 0;
+  pe.EnumExports(ExportsCallback, &count);
+  EXPECT_EQ(exports, count);
+
+  count = 0;
+  pe.EnumAllImports(ImportsCallback, &count);
+  EXPECT_EQ(imports, count);
+
+  count = 0;
+  pe.EnumAllDelayImports(ImportsCallback, &count);
+  EXPECT_EQ(delay_imports, count);
+
+  count = 0;
+  pe.EnumRelocs(RelocsCallback, &count);
+  EXPECT_EQ(relocs, count);
+
+  FreeLibrary(module);
+}
+
+// Tests that we can locate an specific exported symbol, by name and by ordinal.
+TEST(PEImageTest, RetrievesExports) {
+  HMODULE module = LoadLibrary(L"advapi32.dll");
+  ASSERT_TRUE(NULL != module);
+
+  PEImage pe(module);
+  WORD ordinal;
+
+  EXPECT_TRUE(pe.GetProcOrdinal("RegEnumKeyExW", &ordinal));
+
+  FARPROC address1 = pe.GetProcAddress("RegEnumKeyExW");
+  FARPROC address2 = pe.GetProcAddress(reinterpret_cast<char*>(ordinal));
+  EXPECT_TRUE(address1 != NULL);
+  EXPECT_TRUE(address2 != NULL);
+  EXPECT_TRUE(address1 == address2);
+
+  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
diff --git a/base/win/registry.cc b/base/win/registry.cc
new file mode 100644
index 0000000..47afcbf
--- /dev/null
+++ b/base/win/registry.cc
@@ -0,0 +1,680 @@
+// Copyright (c) 2012 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/win/registry.h"
+
+#include <shlwapi.h>
+#include <algorithm>
+
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/win/windows_version.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+// RegEnumValue() reports the number of characters from the name that were
+// written to the buffer, not how many there are. This constant is the maximum
+// name size, such that a buffer with this size should read any name.
+const DWORD MAX_REGISTRY_NAME_SIZE = 16384;
+
+// Registry values are read as BYTE* but can have wchar_t* data whose last
+// wchar_t is truncated. This function converts the reported |byte_size| to
+// a size in wchar_t that can store a truncated wchar_t if necessary.
+inline DWORD to_wchar_size(DWORD byte_size) {
+  return (byte_size + sizeof(wchar_t) - 1) / sizeof(wchar_t);
+}
+
+// Mask to pull WOW64 access flags out of REGSAM access.
+const REGSAM kWow64AccessMask = KEY_WOW64_32KEY | KEY_WOW64_64KEY;
+
+}  // namespace
+
+// Watches for modifications to a key.
+class RegKey::Watcher : public ObjectWatcher::Delegate {
+ public:
+  explicit Watcher(RegKey* owner) : owner_(owner) {}
+  ~Watcher() override {}
+
+  bool StartWatching(HKEY key, const ChangeCallback& callback);
+
+  // Implementation of ObjectWatcher::Delegate.
+  void OnObjectSignaled(HANDLE object) override {
+    DCHECK(watch_event_.IsValid() && watch_event_.Get() == object);
+    ChangeCallback callback = callback_;
+    callback_.Reset();
+    callback.Run();
+  }
+
+ private:
+  RegKey* owner_;
+  ScopedHandle watch_event_;
+  ObjectWatcher object_watcher_;
+  ChangeCallback callback_;
+  DISALLOW_COPY_AND_ASSIGN(Watcher);
+};
+
+bool RegKey::Watcher::StartWatching(HKEY key, const ChangeCallback& callback) {
+  DCHECK(key);
+  DCHECK(callback_.is_null());
+
+  if (!watch_event_.IsValid())
+    watch_event_.Set(CreateEvent(NULL, TRUE, FALSE, NULL));
+
+  if (!watch_event_.IsValid())
+    return false;
+
+  DWORD filter = REG_NOTIFY_CHANGE_NAME |
+                 REG_NOTIFY_CHANGE_ATTRIBUTES |
+                 REG_NOTIFY_CHANGE_LAST_SET |
+                 REG_NOTIFY_CHANGE_SECURITY;
+
+  // Watch the registry key for a change of value.
+  LONG result = RegNotifyChangeKeyValue(key, TRUE, filter, watch_event_.Get(),
+                                        TRUE);
+  if (result != ERROR_SUCCESS) {
+    watch_event_.Close();
+    return false;
+  }
+
+  callback_ = callback;
+  return object_watcher_.StartWatching(watch_event_.Get(), this);
+}
+
+// RegKey ----------------------------------------------------------------------
+
+RegKey::RegKey() : key_(NULL), wow64access_(0) {
+}
+
+RegKey::RegKey(HKEY key) : key_(key), wow64access_(0) {
+}
+
+RegKey::RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access)
+    : key_(NULL),
+      wow64access_(0) {
+  if (rootkey) {
+    if (access & (KEY_SET_VALUE | KEY_CREATE_SUB_KEY | KEY_CREATE_LINK))
+      Create(rootkey, subkey, access);
+    else
+      Open(rootkey, subkey, access);
+  } else {
+    DCHECK(!subkey);
+    wow64access_ = access & kWow64AccessMask;
+  }
+}
+
+RegKey::~RegKey() {
+  Close();
+}
+
+LONG RegKey::Create(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
+  DWORD disposition_value;
+  return CreateWithDisposition(rootkey, subkey, &disposition_value, access);
+}
+
+LONG RegKey::CreateWithDisposition(HKEY rootkey, const wchar_t* subkey,
+                                   DWORD* disposition, REGSAM access) {
+  DCHECK(rootkey && subkey && access && disposition);
+  HKEY subhkey = NULL;
+  LONG result = RegCreateKeyEx(rootkey, subkey, 0, NULL,
+                               REG_OPTION_NON_VOLATILE, access, NULL, &subhkey,
+                               disposition);
+  if (result == ERROR_SUCCESS) {
+    Close();
+    key_ = subhkey;
+    wow64access_ = access & kWow64AccessMask;
+  }
+
+  return result;
+}
+
+LONG RegKey::CreateKey(const wchar_t* name, REGSAM access) {
+  DCHECK(name && access);
+  // After the application has accessed an alternate registry view using one of
+  // the [KEY_WOW64_32KEY / KEY_WOW64_64KEY] flags, all subsequent operations
+  // (create, delete, or open) on child registry keys must explicitly use the
+  // same flag. Otherwise, there can be unexpected behavior.
+  // http://msdn.microsoft.com/en-us/library/windows/desktop/aa384129.aspx.
+  if ((access & kWow64AccessMask) != wow64access_) {
+    NOTREACHED();
+    return ERROR_INVALID_PARAMETER;
+  }
+  HKEY subkey = NULL;
+  LONG result = RegCreateKeyEx(key_, name, 0, NULL, REG_OPTION_NON_VOLATILE,
+                               access, NULL, &subkey, NULL);
+  if (result == ERROR_SUCCESS) {
+    Close();
+    key_ = subkey;
+    wow64access_ = access & kWow64AccessMask;
+  }
+
+  return result;
+}
+
+LONG RegKey::Open(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
+  DCHECK(rootkey && subkey && access);
+  HKEY subhkey = NULL;
+
+  LONG result = RegOpenKeyEx(rootkey, subkey, 0, access, &subhkey);
+  if (result == ERROR_SUCCESS) {
+    Close();
+    key_ = subhkey;
+    wow64access_ = access & kWow64AccessMask;
+  }
+
+  return result;
+}
+
+LONG RegKey::OpenKey(const wchar_t* relative_key_name, REGSAM access) {
+  DCHECK(relative_key_name && access);
+  // After the application has accessed an alternate registry view using one of
+  // the [KEY_WOW64_32KEY / KEY_WOW64_64KEY] flags, all subsequent operations
+  // (create, delete, or open) on child registry keys must explicitly use the
+  // same flag. Otherwise, there can be unexpected behavior.
+  // http://msdn.microsoft.com/en-us/library/windows/desktop/aa384129.aspx.
+  if ((access & kWow64AccessMask) != wow64access_) {
+    NOTREACHED();
+    return ERROR_INVALID_PARAMETER;
+  }
+  HKEY subkey = NULL;
+  LONG result = RegOpenKeyEx(key_, relative_key_name, 0, access, &subkey);
+
+  // We have to close the current opened key before replacing it with the new
+  // one.
+  if (result == ERROR_SUCCESS) {
+    Close();
+    key_ = subkey;
+    wow64access_ = access & kWow64AccessMask;
+  }
+  return result;
+}
+
+void RegKey::Close() {
+  if (key_) {
+    ::RegCloseKey(key_);
+    key_ = NULL;
+    wow64access_ = 0;
+  }
+}
+
+// TODO(wfh): Remove this and other unsafe methods. See http://crbug.com/375400
+void RegKey::Set(HKEY key) {
+  if (key_ != key) {
+    Close();
+    key_ = key;
+  }
+}
+
+HKEY RegKey::Take() {
+  DCHECK_EQ(wow64access_, 0u);
+  HKEY key = key_;
+  key_ = NULL;
+  return key;
+}
+
+bool RegKey::HasValue(const wchar_t* name) const {
+  return RegQueryValueEx(key_, name, 0, NULL, NULL, NULL) == ERROR_SUCCESS;
+}
+
+DWORD RegKey::GetValueCount() const {
+  DWORD count = 0;
+  LONG result = RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL, &count,
+                                NULL, NULL, NULL, NULL);
+  return (result == ERROR_SUCCESS) ? count : 0;
+}
+
+LONG RegKey::GetValueNameAt(int index, std::wstring* name) const {
+  wchar_t buf[256];
+  DWORD bufsize = arraysize(buf);
+  LONG r = ::RegEnumValue(key_, index, buf, &bufsize, NULL, NULL, NULL, NULL);
+  if (r == ERROR_SUCCESS)
+    *name = buf;
+
+  return r;
+}
+
+LONG RegKey::DeleteKey(const wchar_t* name) {
+  DCHECK(key_);
+  DCHECK(name);
+  HKEY subkey = NULL;
+
+  // Verify the key exists before attempting delete to replicate previous
+  // behavior.
+  LONG result =
+      RegOpenKeyEx(key_, name, 0, READ_CONTROL | wow64access_, &subkey);
+  if (result != ERROR_SUCCESS)
+    return result;
+  RegCloseKey(subkey);
+
+  return RegDelRecurse(key_, std::wstring(name), wow64access_);
+}
+
+LONG RegKey::DeleteEmptyKey(const wchar_t* name) {
+  DCHECK(key_);
+  DCHECK(name);
+
+  HKEY target_key = NULL;
+  LONG result = RegOpenKeyEx(key_, name, 0, KEY_READ | wow64access_,
+                             &target_key);
+
+  if (result != ERROR_SUCCESS)
+    return result;
+
+  DWORD count = 0;
+  result = RegQueryInfoKey(target_key, NULL, 0, NULL, NULL, NULL, NULL, &count,
+                           NULL, NULL, NULL, NULL);
+
+  RegCloseKey(target_key);
+
+  if (result != ERROR_SUCCESS)
+    return result;
+
+  if (count == 0)
+    return RegDeleteKeyExWrapper(key_, name, wow64access_, 0);
+
+  return ERROR_DIR_NOT_EMPTY;
+}
+
+LONG RegKey::DeleteValue(const wchar_t* value_name) {
+  DCHECK(key_);
+  LONG result = RegDeleteValue(key_, value_name);
+  return result;
+}
+
+LONG RegKey::ReadValueDW(const wchar_t* name, DWORD* out_value) const {
+  DCHECK(out_value);
+  DWORD type = REG_DWORD;
+  DWORD size = sizeof(DWORD);
+  DWORD local_value = 0;
+  LONG result = ReadValue(name, &local_value, &size, &type);
+  if (result == ERROR_SUCCESS) {
+    if ((type == REG_DWORD || type == REG_BINARY) && size == sizeof(DWORD))
+      *out_value = local_value;
+    else
+      result = ERROR_CANTREAD;
+  }
+
+  return result;
+}
+
+LONG RegKey::ReadInt64(const wchar_t* name, int64* out_value) const {
+  DCHECK(out_value);
+  DWORD type = REG_QWORD;
+  int64 local_value = 0;
+  DWORD size = sizeof(local_value);
+  LONG result = ReadValue(name, &local_value, &size, &type);
+  if (result == ERROR_SUCCESS) {
+    if ((type == REG_QWORD || type == REG_BINARY) &&
+        size == sizeof(local_value))
+      *out_value = local_value;
+    else
+      result = ERROR_CANTREAD;
+  }
+
+  return result;
+}
+
+LONG RegKey::ReadValue(const wchar_t* name, std::wstring* out_value) const {
+  DCHECK(out_value);
+  const size_t kMaxStringLength = 1024;  // This is after expansion.
+  // Use the one of the other forms of ReadValue if 1024 is too small for you.
+  wchar_t raw_value[kMaxStringLength];
+  DWORD type = REG_SZ, size = sizeof(raw_value);
+  LONG result = ReadValue(name, raw_value, &size, &type);
+  if (result == ERROR_SUCCESS) {
+    if (type == REG_SZ) {
+      *out_value = raw_value;
+    } else if (type == REG_EXPAND_SZ) {
+      wchar_t expanded[kMaxStringLength];
+      size = ExpandEnvironmentStrings(raw_value, expanded, kMaxStringLength);
+      // Success: returns the number of wchar_t's copied
+      // Fail: buffer too small, returns the size required
+      // Fail: other, returns 0
+      if (size == 0 || size > kMaxStringLength) {
+        result = ERROR_MORE_DATA;
+      } else {
+        *out_value = expanded;
+      }
+    } else {
+      // Not a string. Oops.
+      result = ERROR_CANTREAD;
+    }
+  }
+
+  return result;
+}
+
+LONG RegKey::ReadValue(const wchar_t* name,
+                       void* data,
+                       DWORD* dsize,
+                       DWORD* dtype) const {
+  LONG result = RegQueryValueEx(key_, name, 0, dtype,
+                                reinterpret_cast<LPBYTE>(data), dsize);
+  return result;
+}
+
+LONG RegKey::ReadValues(const wchar_t* name,
+                        std::vector<std::wstring>* values) {
+  values->clear();
+
+  DWORD type = REG_MULTI_SZ;
+  DWORD size = 0;
+  LONG result = ReadValue(name, NULL, &size, &type);
+  if (FAILED(result) || size == 0)
+    return result;
+
+  if (type != REG_MULTI_SZ)
+    return ERROR_CANTREAD;
+
+  std::vector<wchar_t> buffer(size / sizeof(wchar_t));
+  result = ReadValue(name, &buffer[0], &size, NULL);
+  if (FAILED(result) || size == 0)
+    return result;
+
+  // Parse the double-null-terminated list of strings.
+  // Note: This code is paranoid to not read outside of |buf|, in the case where
+  // it may not be properly terminated.
+  const wchar_t* entry = &buffer[0];
+  const wchar_t* buffer_end = entry + (size / sizeof(wchar_t));
+  while (entry < buffer_end && entry[0] != '\0') {
+    const wchar_t* entry_end = std::find(entry, buffer_end, L'\0');
+    values->push_back(std::wstring(entry, entry_end));
+    entry = entry_end + 1;
+  }
+  return 0;
+}
+
+LONG RegKey::WriteValue(const wchar_t* name, DWORD in_value) {
+  return WriteValue(
+      name, &in_value, static_cast<DWORD>(sizeof(in_value)), REG_DWORD);
+}
+
+LONG RegKey::WriteValue(const wchar_t * name, const wchar_t* in_value) {
+  return WriteValue(name, in_value,
+      static_cast<DWORD>(sizeof(*in_value) * (wcslen(in_value) + 1)), REG_SZ);
+}
+
+LONG RegKey::WriteValue(const wchar_t* name,
+                        const void* data,
+                        DWORD dsize,
+                        DWORD dtype) {
+  DCHECK(data || !dsize);
+
+  LONG result = RegSetValueEx(key_, name, 0, dtype,
+      reinterpret_cast<LPBYTE>(const_cast<void*>(data)), dsize);
+  return result;
+}
+
+bool RegKey::StartWatching(const ChangeCallback& callback) {
+  if (!key_watcher_)
+    key_watcher_.reset(new Watcher(this));
+
+  if (!key_watcher_.get()->StartWatching(key_, callback))
+    return false;
+
+  return true;
+}
+
+// static
+LONG RegKey::RegDeleteKeyExWrapper(HKEY hKey,
+                                   const wchar_t* lpSubKey,
+                                   REGSAM samDesired,
+                                   DWORD Reserved) {
+  typedef LSTATUS(WINAPI* RegDeleteKeyExPtr)(HKEY, LPCWSTR, REGSAM, DWORD);
+
+  RegDeleteKeyExPtr reg_delete_key_ex_func =
+      reinterpret_cast<RegDeleteKeyExPtr>(
+          GetProcAddress(GetModuleHandleA("advapi32.dll"), "RegDeleteKeyExW"));
+
+  if (reg_delete_key_ex_func)
+    return reg_delete_key_ex_func(hKey, lpSubKey, samDesired, Reserved);
+
+  // Windows XP does not support RegDeleteKeyEx, so fallback to RegDeleteKey.
+  return RegDeleteKey(hKey, lpSubKey);
+}
+
+// static
+LONG RegKey::RegDelRecurse(HKEY root_key,
+                           const std::wstring& name,
+                           REGSAM access) {
+  // First, see if the key can be deleted without having to recurse.
+  LONG result = RegDeleteKeyExWrapper(root_key, name.c_str(), access, 0);
+  if (result == ERROR_SUCCESS)
+    return result;
+
+  HKEY target_key = NULL;
+  result = RegOpenKeyEx(
+      root_key, name.c_str(), 0, KEY_ENUMERATE_SUB_KEYS | access, &target_key);
+
+  if (result == ERROR_FILE_NOT_FOUND)
+    return ERROR_SUCCESS;
+  if (result != ERROR_SUCCESS)
+    return result;
+
+  std::wstring subkey_name(name);
+
+  // Check for an ending slash and add one if it is missing.
+  if (!name.empty() && subkey_name[name.length() - 1] != L'\\')
+    subkey_name += L"\\";
+
+  // Enumerate the keys
+  result = ERROR_SUCCESS;
+  const DWORD kMaxKeyNameLength = MAX_PATH;
+  const size_t base_key_length = subkey_name.length();
+  std::wstring key_name;
+  while (result == ERROR_SUCCESS) {
+    DWORD key_size = kMaxKeyNameLength;
+    result = RegEnumKeyEx(target_key,
+                          0,
+                          WriteInto(&key_name, kMaxKeyNameLength),
+                          &key_size,
+                          NULL,
+                          NULL,
+                          NULL,
+                          NULL);
+
+    if (result != ERROR_SUCCESS)
+      break;
+
+    key_name.resize(key_size);
+    subkey_name.resize(base_key_length);
+    subkey_name += key_name;
+
+    if (RegDelRecurse(root_key, subkey_name, access) != ERROR_SUCCESS)
+      break;
+  }
+
+  RegCloseKey(target_key);
+
+  // Try again to delete the key.
+  result = RegDeleteKeyExWrapper(root_key, name.c_str(), access, 0);
+
+  return result;
+}
+
+// RegistryValueIterator ------------------------------------------------------
+
+RegistryValueIterator::RegistryValueIterator(HKEY root_key,
+                                             const wchar_t* folder_key,
+                                             REGSAM wow64access)
+    : name_(MAX_PATH, L'\0'),
+      value_(MAX_PATH, L'\0') {
+  Initialize(root_key, folder_key, wow64access);
+}
+
+RegistryValueIterator::RegistryValueIterator(HKEY root_key,
+                                             const wchar_t* folder_key)
+    : name_(MAX_PATH, L'\0'),
+      value_(MAX_PATH, L'\0') {
+  Initialize(root_key, folder_key, 0);
+}
+
+void RegistryValueIterator::Initialize(HKEY root_key,
+                                       const wchar_t* folder_key,
+                                       REGSAM wow64access) {
+  DCHECK_EQ(wow64access & ~kWow64AccessMask, static_cast<REGSAM>(0));
+  LONG result =
+      RegOpenKeyEx(root_key, folder_key, 0, KEY_READ | wow64access, &key_);
+  if (result != ERROR_SUCCESS) {
+    key_ = NULL;
+  } else {
+    DWORD count = 0;
+    result = ::RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL, &count,
+                               NULL, NULL, NULL, NULL);
+
+    if (result != ERROR_SUCCESS) {
+      ::RegCloseKey(key_);
+      key_ = NULL;
+    } else {
+      index_ = count - 1;
+    }
+  }
+
+  Read();
+}
+
+RegistryValueIterator::~RegistryValueIterator() {
+  if (key_)
+    ::RegCloseKey(key_);
+}
+
+DWORD RegistryValueIterator::ValueCount() const {
+  DWORD count = 0;
+  LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, NULL, NULL, NULL,
+                                  &count, NULL, NULL, NULL, NULL);
+  if (result != ERROR_SUCCESS)
+    return 0;
+
+  return count;
+}
+
+bool RegistryValueIterator::Valid() const {
+  return key_ != NULL && index_ >= 0;
+}
+
+void RegistryValueIterator::operator++() {
+  --index_;
+  Read();
+}
+
+bool RegistryValueIterator::Read() {
+  if (Valid()) {
+    DWORD capacity = static_cast<DWORD>(name_.capacity());
+    DWORD name_size = capacity;
+    // |value_size_| is in bytes. Reserve the last character for a NUL.
+    value_size_ = static_cast<DWORD>((value_.size() - 1) * sizeof(wchar_t));
+    LONG result = ::RegEnumValue(
+        key_, index_, WriteInto(&name_, name_size), &name_size, NULL, &type_,
+        reinterpret_cast<BYTE*>(vector_as_array(&value_)), &value_size_);
+
+    if (result == ERROR_MORE_DATA) {
+      // Registry key names are limited to 255 characters and fit within
+      // MAX_PATH (which is 260) but registry value names can use up to 16,383
+      // characters and the value itself is not limited
+      // (from http://msdn.microsoft.com/en-us/library/windows/desktop/
+      // ms724872(v=vs.85).aspx).
+      // Resize the buffers and retry if their size caused the failure.
+      DWORD value_size_in_wchars = to_wchar_size(value_size_);
+      if (value_size_in_wchars + 1 > value_.size())
+        value_.resize(value_size_in_wchars + 1, L'\0');
+      value_size_ = static_cast<DWORD>((value_.size() - 1) * sizeof(wchar_t));
+      name_size = name_size == capacity ? MAX_REGISTRY_NAME_SIZE : capacity;
+      result = ::RegEnumValue(
+          key_, index_, WriteInto(&name_, name_size), &name_size, NULL, &type_,
+          reinterpret_cast<BYTE*>(vector_as_array(&value_)), &value_size_);
+    }
+
+    if (result == ERROR_SUCCESS) {
+      DCHECK_LT(to_wchar_size(value_size_), value_.size());
+      value_[to_wchar_size(value_size_)] = L'\0';
+      return true;
+    }
+  }
+
+  name_[0] = L'\0';
+  value_[0] = L'\0';
+  value_size_ = 0;
+  return false;
+}
+
+// RegistryKeyIterator --------------------------------------------------------
+
+RegistryKeyIterator::RegistryKeyIterator(HKEY root_key,
+                                         const wchar_t* folder_key) {
+  Initialize(root_key, folder_key, 0);
+}
+
+RegistryKeyIterator::RegistryKeyIterator(HKEY root_key,
+                                         const wchar_t* folder_key,
+                                         REGSAM wow64access) {
+  Initialize(root_key, folder_key, wow64access);
+}
+
+RegistryKeyIterator::~RegistryKeyIterator() {
+  if (key_)
+    ::RegCloseKey(key_);
+}
+
+DWORD RegistryKeyIterator::SubkeyCount() const {
+  DWORD count = 0;
+  LONG result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL,
+                                  NULL, NULL, NULL, NULL, NULL);
+  if (result != ERROR_SUCCESS)
+    return 0;
+
+  return count;
+}
+
+bool RegistryKeyIterator::Valid() const {
+  return key_ != NULL && index_ >= 0;
+}
+
+void RegistryKeyIterator::operator++() {
+  --index_;
+  Read();
+}
+
+bool RegistryKeyIterator::Read() {
+  if (Valid()) {
+    DWORD ncount = arraysize(name_);
+    FILETIME written;
+    LONG r = ::RegEnumKeyEx(key_, index_, name_, &ncount, NULL, NULL,
+                            NULL, &written);
+    if (ERROR_SUCCESS == r)
+      return true;
+  }
+
+  name_[0] = '\0';
+  return false;
+}
+
+void RegistryKeyIterator::Initialize(HKEY root_key,
+                                     const wchar_t* folder_key,
+                                     REGSAM wow64access) {
+  DCHECK_EQ(wow64access & ~kWow64AccessMask, static_cast<REGSAM>(0));
+  LONG result =
+      RegOpenKeyEx(root_key, folder_key, 0, KEY_READ | wow64access, &key_);
+  if (result != ERROR_SUCCESS) {
+    key_ = NULL;
+  } else {
+    DWORD count = 0;
+    result = ::RegQueryInfoKey(key_, NULL, 0, NULL, &count, NULL, NULL, NULL,
+                               NULL, NULL, NULL, NULL);
+
+    if (result != ERROR_SUCCESS) {
+      ::RegCloseKey(key_);
+      key_ = NULL;
+    } else {
+      index_ = count - 1;
+    }
+  }
+
+  Read();
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/registry.h b/base/win/registry.h
new file mode 100644
index 0000000..c3e015b
--- /dev/null
+++ b/base/win/registry.h
@@ -0,0 +1,259 @@
+// Copyright (c) 2012 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_WIN_REGISTRY_H_
+#define BASE_WIN_REGISTRY_H_
+
+#include <windows.h>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/stl_util.h"
+#include "base/win/object_watcher.h"
+#include "base/win/scoped_handle.h"
+
+namespace base {
+namespace win {
+
+// Utility class to read, write and manipulate the Windows Registry.
+// Registry vocabulary primer: a "key" is like a folder, in which there
+// are "values", which are <name, data> pairs, with an associated data type.
+//
+// Note:
+// ReadValue family of functions guarantee that the return arguments
+// are not touched in case of failure.
+class BASE_EXPORT RegKey {
+ public:
+  // Called from the MessageLoop when the key changes.
+  typedef base::Callback<void()> ChangeCallback;
+
+  RegKey();
+  explicit RegKey(HKEY key);
+  RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access);
+  ~RegKey();
+
+  LONG Create(HKEY rootkey, const wchar_t* subkey, REGSAM access);
+
+  LONG CreateWithDisposition(HKEY rootkey, const wchar_t* subkey,
+                             DWORD* disposition, REGSAM access);
+
+  // Creates a subkey or open it if it already exists.
+  LONG CreateKey(const wchar_t* name, REGSAM access);
+
+  // Opens an existing reg key.
+  LONG Open(HKEY rootkey, const wchar_t* subkey, REGSAM access);
+
+  // Opens an existing reg key, given the relative key name.
+  LONG OpenKey(const wchar_t* relative_key_name, REGSAM access);
+
+  // Closes this reg key.
+  void Close();
+
+  // Replaces the handle of the registry key and takes ownership of the handle.
+  void Set(HKEY key);
+
+  // Transfers ownership away from this object.
+  HKEY Take();
+
+  // Returns false if this key does not have the specified value, or if an error
+  // occurrs while attempting to access it.
+  bool HasValue(const wchar_t* value_name) const;
+
+  // Returns the number of values for this key, or 0 if the number cannot be
+  // determined.
+  DWORD GetValueCount() const;
+
+  // Determine the nth value's name.
+  LONG GetValueNameAt(int index, std::wstring* name) const;
+
+  // True while the key is valid.
+  bool Valid() const { return key_ != NULL; }
+
+  // Kill a key and everything that live below it; please be careful when using
+  // it.
+  LONG DeleteKey(const wchar_t* name);
+
+  // Deletes an empty subkey.  If the subkey has subkeys or values then this
+  // will fail.
+  LONG DeleteEmptyKey(const wchar_t* name);
+
+  // Deletes a single value within the key.
+  LONG DeleteValue(const wchar_t* name);
+
+  // Getters:
+
+  // Returns an int32 value. If |name| is NULL or empty, returns the default
+  // value, if any.
+  LONG ReadValueDW(const wchar_t* name, DWORD* out_value) const;
+
+  // Returns an int64 value. If |name| is NULL or empty, returns the default
+  // value, if any.
+  LONG ReadInt64(const wchar_t* name, int64* out_value) const;
+
+  // Returns a string value. If |name| is NULL or empty, returns the default
+  // value, if any.
+  LONG ReadValue(const wchar_t* name, std::wstring* out_value) const;
+
+  // Reads a REG_MULTI_SZ registry field into a vector of strings. Clears
+  // |values| initially and adds further strings to the list. Returns
+  // ERROR_CANTREAD if type is not REG_MULTI_SZ.
+  LONG ReadValues(const wchar_t* name, std::vector<std::wstring>* values);
+
+  // Returns raw data. If |name| is NULL or empty, returns the default
+  // value, if any.
+  LONG ReadValue(const wchar_t* name,
+                 void* data,
+                 DWORD* dsize,
+                 DWORD* dtype) const;
+
+  // Setters:
+
+  // Sets an int32 value.
+  LONG WriteValue(const wchar_t* name, DWORD in_value);
+
+  // Sets a string value.
+  LONG WriteValue(const wchar_t* name, const wchar_t* in_value);
+
+  // Sets raw data, including type.
+  LONG WriteValue(const wchar_t* name,
+                  const void* data,
+                  DWORD dsize,
+                  DWORD dtype);
+
+  // Starts watching the key to see if any of its values have changed.
+  // The key must have been opened with the KEY_NOTIFY access privilege.
+  // Returns true on success.
+  // To stop watching, delete this RegKey object. To continue watching the
+  // object after the callback is invoked, call StartWatching again.
+  bool StartWatching(const ChangeCallback& callback);
+
+  HKEY Handle() const { return key_; }
+
+ private:
+  class Watcher;
+
+  // Calls RegDeleteKeyEx on supported platforms, alternatively falls back to
+  // RegDeleteKey.
+  static LONG RegDeleteKeyExWrapper(HKEY hKey,
+                                    const wchar_t* lpSubKey,
+                                    REGSAM samDesired,
+                                    DWORD Reserved);
+
+  // Recursively deletes a key and all of its subkeys.
+  static LONG RegDelRecurse(HKEY root_key,
+                            const std::wstring& name,
+                            REGSAM access);
+
+  HKEY key_;  // The registry key being iterated.
+  REGSAM wow64access_;
+  scoped_ptr<Watcher> key_watcher_;
+
+  DISALLOW_COPY_AND_ASSIGN(RegKey);
+};
+
+// Iterates the entries found in a particular folder on the registry.
+class BASE_EXPORT RegistryValueIterator {
+ public:
+  // Construct a Registry Value Iterator with default WOW64 access.
+  RegistryValueIterator(HKEY root_key, const wchar_t* folder_key);
+
+  // Construct a Registry Key Iterator with specific WOW64 access, one of
+  // KEY_WOW64_32KEY or KEY_WOW64_64KEY, or 0.
+  // Note: |wow64access| should be the same access used to open |root_key|
+  // previously, or a predefined key (e.g. HKEY_LOCAL_MACHINE).
+  // See http://msdn.microsoft.com/en-us/library/windows/desktop/aa384129.aspx.
+  RegistryValueIterator(HKEY root_key,
+                        const wchar_t* folder_key,
+                        REGSAM wow64access);
+
+  ~RegistryValueIterator();
+
+  DWORD ValueCount() const;
+
+  // True while the iterator is valid.
+  bool Valid() const;
+
+  // Advances to the next registry entry.
+  void operator++();
+
+  const wchar_t* Name() const { return name_.c_str(); }
+  const wchar_t* Value() const { return vector_as_array(&value_); }
+  // ValueSize() is in bytes.
+  DWORD ValueSize() const { return value_size_; }
+  DWORD Type() const { return type_; }
+
+  int Index() const { return index_; }
+
+ private:
+  // Read in the current values.
+  bool Read();
+
+  void Initialize(HKEY root_key, const wchar_t* folder_key, REGSAM wow64access);
+
+  // The registry key being iterated.
+  HKEY key_;
+
+  // Current index of the iteration.
+  int index_;
+
+  // Current values.
+  std::wstring name_;
+  std::vector<wchar_t> value_;
+  DWORD value_size_;
+  DWORD type_;
+
+  DISALLOW_COPY_AND_ASSIGN(RegistryValueIterator);
+};
+
+class BASE_EXPORT RegistryKeyIterator {
+ public:
+  // Construct a Registry Key Iterator with default WOW64 access.
+  RegistryKeyIterator(HKEY root_key, const wchar_t* folder_key);
+
+  // Construct a Registry Value Iterator with specific WOW64 access, one of
+  // KEY_WOW64_32KEY or KEY_WOW64_64KEY, or 0.
+  // Note: |wow64access| should be the same access used to open |root_key|
+  // previously, or a predefined key (e.g. HKEY_LOCAL_MACHINE).
+  // See http://msdn.microsoft.com/en-us/library/windows/desktop/aa384129.aspx.
+  RegistryKeyIterator(HKEY root_key,
+                      const wchar_t* folder_key,
+                      REGSAM wow64access);
+
+  ~RegistryKeyIterator();
+
+  DWORD SubkeyCount() const;
+
+  // True while the iterator is valid.
+  bool Valid() const;
+
+  // Advances to the next entry in the folder.
+  void operator++();
+
+  const wchar_t* Name() const { return name_; }
+
+  int Index() const { return index_; }
+
+ private:
+  // Read in the current values.
+  bool Read();
+
+  void Initialize(HKEY root_key, const wchar_t* folder_key, REGSAM wow64access);
+
+  // The registry key being iterated.
+  HKEY key_;
+
+  // Current index of the iteration.
+  int index_;
+
+  wchar_t name_[MAX_PATH];
+
+  DISALLOW_COPY_AND_ASSIGN(RegistryKeyIterator);
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_REGISTRY_H_
diff --git a/base/win/registry_unittest.cc b/base/win/registry_unittest.cc
new file mode 100644
index 0000000..2257663
--- /dev/null
+++ b/base/win/registry_unittest.cc
@@ -0,0 +1,420 @@
+// Copyright (c) 2011 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/win/registry.h"
+
+#include <cstring>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/compiler_specific.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/stl_util.h"
+#include "base/win/windows_version.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+class RegistryTest : public testing::Test {
+ protected:
+#if defined(_WIN64)
+  static const REGSAM kNativeViewMask = KEY_WOW64_64KEY;
+  static const REGSAM kRedirectedViewMask = KEY_WOW64_32KEY;
+#else
+  static const REGSAM kNativeViewMask = KEY_WOW64_32KEY;
+  static const REGSAM kRedirectedViewMask = KEY_WOW64_64KEY;
+#endif  //  _WIN64
+
+  RegistryTest() {}
+  void SetUp() override {
+    // Create a temporary key.
+    RegKey key(HKEY_CURRENT_USER, L"", KEY_ALL_ACCESS);
+    key.DeleteKey(kRootKey);
+    ASSERT_NE(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, kRootKey, KEY_READ));
+    ASSERT_EQ(ERROR_SUCCESS, key.Create(HKEY_CURRENT_USER, kRootKey, KEY_READ));
+    foo_software_key_ = L"Software\\";
+    foo_software_key_ += kRootKey;
+    foo_software_key_ += L"\\Foo";
+  }
+
+  void TearDown() override {
+    // Clean up the temporary key.
+    RegKey key(HKEY_CURRENT_USER, L"", KEY_SET_VALUE);
+    ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(kRootKey));
+    ASSERT_NE(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, kRootKey, KEY_READ));
+  }
+
+  static bool IsRedirectorPresent() {
+#if defined(_WIN64)
+    return true;
+#else
+    return OSInfo::GetInstance()->wow64_status() == OSInfo::WOW64_ENABLED;
+#endif
+  }
+
+  const wchar_t* const kRootKey = L"Base_Registry_Unittest";
+  std::wstring foo_software_key_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(RegistryTest);
+};
+
+// static
+const REGSAM RegistryTest::kNativeViewMask;
+const REGSAM RegistryTest::kRedirectedViewMask;
+
+TEST_F(RegistryTest, ValueTest) {
+  RegKey key;
+
+  std::wstring foo_key(kRootKey);
+  foo_key += L"\\Foo";
+  ASSERT_EQ(ERROR_SUCCESS, key.Create(HKEY_CURRENT_USER, foo_key.c_str(),
+                                      KEY_READ));
+
+  {
+    ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, foo_key.c_str(),
+                                      KEY_READ | KEY_SET_VALUE));
+    ASSERT_TRUE(key.Valid());
+
+    const wchar_t kStringValueName[] = L"StringValue";
+    const wchar_t kDWORDValueName[] = L"DWORDValue";
+    const wchar_t kInt64ValueName[] = L"Int64Value";
+    const wchar_t kStringData[] = L"string data";
+    const DWORD kDWORDData = 0xdeadbabe;
+    const int64 kInt64Data = 0xdeadbabedeadbabeLL;
+
+    // Test value creation
+    ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(kStringValueName, kStringData));
+    ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(kDWORDValueName, kDWORDData));
+    ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(kInt64ValueName, &kInt64Data,
+                                            sizeof(kInt64Data), REG_QWORD));
+    EXPECT_EQ(3U, key.GetValueCount());
+    EXPECT_TRUE(key.HasValue(kStringValueName));
+    EXPECT_TRUE(key.HasValue(kDWORDValueName));
+    EXPECT_TRUE(key.HasValue(kInt64ValueName));
+
+    // Test Read
+    std::wstring string_value;
+    DWORD dword_value = 0;
+    int64 int64_value = 0;
+    ASSERT_EQ(ERROR_SUCCESS, key.ReadValue(kStringValueName, &string_value));
+    ASSERT_EQ(ERROR_SUCCESS, key.ReadValueDW(kDWORDValueName, &dword_value));
+    ASSERT_EQ(ERROR_SUCCESS, key.ReadInt64(kInt64ValueName, &int64_value));
+    EXPECT_STREQ(kStringData, string_value.c_str());
+    EXPECT_EQ(kDWORDData, dword_value);
+    EXPECT_EQ(kInt64Data, int64_value);
+
+    // Make sure out args are not touched if ReadValue fails
+    const wchar_t* kNonExistent = L"NonExistent";
+    ASSERT_NE(ERROR_SUCCESS, key.ReadValue(kNonExistent, &string_value));
+    ASSERT_NE(ERROR_SUCCESS, key.ReadValueDW(kNonExistent, &dword_value));
+    ASSERT_NE(ERROR_SUCCESS, key.ReadInt64(kNonExistent, &int64_value));
+    EXPECT_STREQ(kStringData, string_value.c_str());
+    EXPECT_EQ(kDWORDData, dword_value);
+    EXPECT_EQ(kInt64Data, int64_value);
+
+    // Test delete
+    ASSERT_EQ(ERROR_SUCCESS, key.DeleteValue(kStringValueName));
+    ASSERT_EQ(ERROR_SUCCESS, key.DeleteValue(kDWORDValueName));
+    ASSERT_EQ(ERROR_SUCCESS, key.DeleteValue(kInt64ValueName));
+    EXPECT_EQ(0U, key.GetValueCount());
+    EXPECT_FALSE(key.HasValue(kStringValueName));
+    EXPECT_FALSE(key.HasValue(kDWORDValueName));
+    EXPECT_FALSE(key.HasValue(kInt64ValueName));
+  }
+}
+
+TEST_F(RegistryTest, BigValueIteratorTest) {
+  RegKey key;
+  std::wstring foo_key(kRootKey);
+  foo_key += L"\\Foo";
+  ASSERT_EQ(ERROR_SUCCESS, key.Create(HKEY_CURRENT_USER, foo_key.c_str(),
+                                      KEY_READ));
+  ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, foo_key.c_str(),
+                                    KEY_READ | KEY_SET_VALUE));
+  ASSERT_TRUE(key.Valid());
+
+  // Create a test value that is larger than MAX_PATH.
+  std::wstring data(MAX_PATH * 2, L'a');
+
+  ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(data.c_str(), data.c_str()));
+
+  RegistryValueIterator iterator(HKEY_CURRENT_USER, foo_key.c_str());
+  ASSERT_TRUE(iterator.Valid());
+  EXPECT_STREQ(data.c_str(), iterator.Name());
+  EXPECT_STREQ(data.c_str(), iterator.Value());
+  // ValueSize() is in bytes, including NUL.
+  EXPECT_EQ((MAX_PATH * 2 + 1) * sizeof(wchar_t), iterator.ValueSize());
+  ++iterator;
+  EXPECT_FALSE(iterator.Valid());
+}
+
+TEST_F(RegistryTest, TruncatedCharTest) {
+  RegKey key;
+  std::wstring foo_key(kRootKey);
+  foo_key += L"\\Foo";
+  ASSERT_EQ(ERROR_SUCCESS, key.Create(HKEY_CURRENT_USER, foo_key.c_str(),
+                                      KEY_READ));
+  ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, foo_key.c_str(),
+                                    KEY_READ | KEY_SET_VALUE));
+  ASSERT_TRUE(key.Valid());
+
+  const wchar_t kName[] = L"name";
+  // kData size is not a multiple of sizeof(wchar_t).
+  const uint8 kData[] = { 1, 2, 3, 4, 5 };
+  EXPECT_EQ(5, arraysize(kData));
+  ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(kName, kData,
+                                          arraysize(kData), REG_BINARY));
+
+  RegistryValueIterator iterator(HKEY_CURRENT_USER, foo_key.c_str());
+  ASSERT_TRUE(iterator.Valid());
+  EXPECT_STREQ(kName, iterator.Name());
+  // ValueSize() is in bytes.
+  ASSERT_EQ(arraysize(kData), iterator.ValueSize());
+  // Value() is NUL terminated.
+  int end = (iterator.ValueSize() + sizeof(wchar_t) - 1) / sizeof(wchar_t);
+  EXPECT_NE(L'\0', iterator.Value()[end-1]);
+  EXPECT_EQ(L'\0', iterator.Value()[end]);
+  EXPECT_EQ(0, std::memcmp(kData, iterator.Value(), arraysize(kData)));
+  ++iterator;
+  EXPECT_FALSE(iterator.Valid());
+}
+
+TEST_F(RegistryTest, RecursiveDelete) {
+  RegKey key;
+  // Create kRootKey->Foo
+  //                  \->Bar (TestValue)
+  //                     \->Foo (TestValue)
+  //                        \->Bar
+  //                           \->Foo
+  //                  \->Moo
+  //                  \->Foo
+  // and delete kRootKey->Foo
+  std::wstring foo_key(kRootKey);
+  foo_key += L"\\Foo";
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.Create(HKEY_CURRENT_USER, foo_key.c_str(), KEY_WRITE));
+  ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Bar", KEY_WRITE));
+  ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(L"TestValue", L"TestData"));
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.Create(HKEY_CURRENT_USER, foo_key.c_str(), KEY_WRITE));
+  ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Moo", KEY_WRITE));
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.Create(HKEY_CURRENT_USER, foo_key.c_str(), KEY_WRITE));
+  ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Foo", KEY_WRITE));
+  foo_key += L"\\Bar";
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_WRITE));
+  foo_key += L"\\Foo";
+  ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Foo", KEY_WRITE));
+  ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(L"TestValue", L"TestData"));
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_READ));
+
+  ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, kRootKey, KEY_WRITE));
+  ASSERT_NE(ERROR_SUCCESS, key.DeleteKey(L"Bar"));
+  ASSERT_NE(ERROR_SUCCESS, key.DeleteEmptyKey(L"Foo"));
+  ASSERT_NE(ERROR_SUCCESS, key.DeleteEmptyKey(L"Foo\\Bar\\Foo"));
+  ASSERT_NE(ERROR_SUCCESS, key.DeleteEmptyKey(L"Foo\\Bar"));
+  ASSERT_EQ(ERROR_SUCCESS, key.DeleteEmptyKey(L"Foo\\Foo"));
+
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_WRITE));
+  ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Bar", KEY_WRITE));
+  ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"Foo", KEY_WRITE));
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_WRITE));
+  ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(L""));
+  ASSERT_NE(ERROR_SUCCESS,
+            key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_READ));
+
+  ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, kRootKey, KEY_WRITE));
+  ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(L"Foo"));
+  ASSERT_NE(ERROR_SUCCESS, key.DeleteKey(L"Foo"));
+  ASSERT_NE(ERROR_SUCCESS,
+            key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_READ));
+}
+
+// This test requires running as an Administrator as it tests redirected
+// registry writes to HKLM\Software
+// http://msdn.microsoft.com/en-us/library/windows/desktop/aa384253.aspx
+// TODO(wfh): flaky test on Vista.  See http://crbug.com/377917
+TEST_F(RegistryTest, DISABLED_Wow64RedirectedFromNative) {
+  if (!IsRedirectorPresent())
+    return;
+
+  RegKey key;
+
+  // Test redirected key access from non-redirected.
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.Create(HKEY_LOCAL_MACHINE,
+                       foo_software_key_.c_str(),
+                       KEY_WRITE | kRedirectedViewMask));
+  ASSERT_NE(ERROR_SUCCESS,
+            key.Open(HKEY_LOCAL_MACHINE, foo_software_key_.c_str(), KEY_READ));
+  ASSERT_NE(ERROR_SUCCESS,
+            key.Open(HKEY_LOCAL_MACHINE,
+                     foo_software_key_.c_str(),
+                     KEY_READ | kNativeViewMask));
+
+  // Open the non-redirected view of the parent and try to delete the test key.
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.Open(HKEY_LOCAL_MACHINE, L"Software", KEY_SET_VALUE));
+  ASSERT_NE(ERROR_SUCCESS, key.DeleteKey(kRootKey));
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.Open(HKEY_LOCAL_MACHINE,
+                     L"Software",
+                     KEY_SET_VALUE | kNativeViewMask));
+  ASSERT_NE(ERROR_SUCCESS, key.DeleteKey(kRootKey));
+
+  // Open the redirected view and delete the key created above.
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.Open(HKEY_LOCAL_MACHINE,
+                     L"Software",
+                     KEY_SET_VALUE | kRedirectedViewMask));
+  ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(kRootKey));
+}
+
+// Test for the issue found in http://crbug.com/384587 where OpenKey would call
+// Close() and reset wow64_access_ flag to 0 and cause a NOTREACHED to hit on a
+// subsequent OpenKey call.
+TEST_F(RegistryTest, SameWowFlags) {
+  RegKey key;
+
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.Open(HKEY_LOCAL_MACHINE,
+                     L"Software",
+                     KEY_READ | KEY_WOW64_64KEY));
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.OpenKey(L"Microsoft",
+                        KEY_READ | KEY_WOW64_64KEY));
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.OpenKey(L"Windows",
+                        KEY_READ | KEY_WOW64_64KEY));
+}
+
+// TODO(wfh): flaky test on Vista.  See http://crbug.com/377917
+TEST_F(RegistryTest, DISABLED_Wow64NativeFromRedirected) {
+  if (!IsRedirectorPresent())
+    return;
+  RegKey key;
+
+  // Test non-redirected key access from redirected.
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.Create(HKEY_LOCAL_MACHINE,
+                       foo_software_key_.c_str(),
+                       KEY_WRITE | kNativeViewMask));
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.Open(HKEY_LOCAL_MACHINE, foo_software_key_.c_str(), KEY_READ));
+  ASSERT_NE(ERROR_SUCCESS,
+            key.Open(HKEY_LOCAL_MACHINE,
+                     foo_software_key_.c_str(),
+                     KEY_READ | kRedirectedViewMask));
+
+  // Open the redirected view of the parent and try to delete the test key
+  // from the non-redirected view.
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.Open(HKEY_LOCAL_MACHINE,
+                     L"Software",
+                     KEY_SET_VALUE | kRedirectedViewMask));
+  ASSERT_NE(ERROR_SUCCESS, key.DeleteKey(kRootKey));
+
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.Open(HKEY_LOCAL_MACHINE,
+                     L"Software",
+                     KEY_SET_VALUE | kNativeViewMask));
+  ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(kRootKey));
+}
+
+TEST_F(RegistryTest, OpenSubKey) {
+  RegKey key;
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.Open(HKEY_CURRENT_USER,
+                     kRootKey,
+                     KEY_READ | KEY_CREATE_SUB_KEY));
+
+  ASSERT_NE(ERROR_SUCCESS, key.OpenKey(L"foo", KEY_READ));
+  ASSERT_EQ(ERROR_SUCCESS, key.CreateKey(L"foo", KEY_READ));
+  ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, kRootKey, KEY_READ));
+  ASSERT_EQ(ERROR_SUCCESS, key.OpenKey(L"foo", KEY_READ));
+
+  std::wstring foo_key(kRootKey);
+  foo_key += L"\\Foo";
+  ASSERT_EQ(ERROR_SUCCESS,
+            key.Open(HKEY_CURRENT_USER, foo_key.c_str(), KEY_READ));
+
+  ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, kRootKey, KEY_WRITE));
+  ASSERT_EQ(ERROR_SUCCESS, key.DeleteKey(L"foo"));
+}
+
+class TestChangeDelegate {
+ public:
+   TestChangeDelegate() : called_(false) {}
+   ~TestChangeDelegate() {}
+
+   void OnKeyChanged() {
+     MessageLoop::current()->QuitWhenIdle();
+     called_ = true;
+   }
+
+   bool WasCalled() {
+     bool was_called = called_;
+     called_ = false;
+     return was_called;
+   }
+
+ private:
+  bool called_;
+};
+
+TEST_F(RegistryTest, ChangeCallback) {
+  RegKey key;
+  TestChangeDelegate delegate;
+  MessageLoop message_loop;
+
+  std::wstring foo_key(kRootKey);
+  foo_key += L"\\Foo";
+  ASSERT_EQ(ERROR_SUCCESS, key.Create(HKEY_CURRENT_USER, foo_key.c_str(),
+                                      KEY_READ));
+
+  ASSERT_TRUE(key.StartWatching(Bind(&TestChangeDelegate::OnKeyChanged,
+                                     Unretained(&delegate))));
+  EXPECT_FALSE(delegate.WasCalled());
+
+  // Make some change.
+  RegKey key2;
+  ASSERT_EQ(ERROR_SUCCESS, key2.Open(HKEY_CURRENT_USER, foo_key.c_str(),
+                                      KEY_READ | KEY_SET_VALUE));
+  ASSERT_TRUE(key2.Valid());
+  EXPECT_EQ(ERROR_SUCCESS, key2.WriteValue(L"name", L"data"));
+
+  // Allow delivery of the notification.
+  EXPECT_FALSE(delegate.WasCalled());
+  base::RunLoop().Run();
+
+  ASSERT_TRUE(delegate.WasCalled());
+  EXPECT_FALSE(delegate.WasCalled());
+
+  ASSERT_TRUE(key.StartWatching(Bind(&TestChangeDelegate::OnKeyChanged,
+                                     Unretained(&delegate))));
+
+  // Change something else.
+  EXPECT_EQ(ERROR_SUCCESS, key2.WriteValue(L"name2", L"data2"));
+  base::RunLoop().Run();
+  ASSERT_TRUE(delegate.WasCalled());
+
+  ASSERT_TRUE(key.StartWatching(Bind(&TestChangeDelegate::OnKeyChanged,
+                                     Unretained(&delegate))));
+  base::RunLoop().RunUntilIdle();
+  EXPECT_FALSE(delegate.WasCalled());
+}
+
+}  // namespace
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/resource_util.cc b/base/win/resource_util.cc
new file mode 100644
index 0000000..0c10078
--- /dev/null
+++ b/base/win/resource_util.cc
@@ -0,0 +1,51 @@
+// Copyright (c) 2006-2008 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/logging.h"
+#include "base/win/resource_util.h"
+
+namespace base {
+namespace win {
+
+bool GetResourceFromModule(HMODULE module,
+                           int resource_id,
+                           LPCTSTR resource_type,
+                           void** data,
+                           size_t* length) {
+  if (!module)
+    return false;
+
+  if (!IS_INTRESOURCE(resource_id)) {
+    NOTREACHED();
+    return false;
+  }
+
+  HRSRC hres_info = FindResource(module, MAKEINTRESOURCE(resource_id),
+                                 resource_type);
+  if (NULL == hres_info)
+    return false;
+
+  DWORD data_size = SizeofResource(module, hres_info);
+  HGLOBAL hres = LoadResource(module, hres_info);
+  if (!hres)
+    return false;
+
+  void* resource = LockResource(hres);
+  if (!resource)
+    return false;
+
+  *data = resource;
+  *length = static_cast<size_t>(data_size);
+  return true;
+}
+
+bool GetDataResourceFromModule(HMODULE module,
+                               int resource_id,
+                               void** data,
+                               size_t* length) {
+  return GetResourceFromModule(module, resource_id, L"BINDATA", data, length);
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/resource_util.h b/base/win/resource_util.h
new file mode 100644
index 0000000..8a8baa0
--- /dev/null
+++ b/base/win/resource_util.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2011 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 contains utility functions for accessing resources in external
+// files (DLLs) or embedded in the executable itself.
+
+#ifndef BASE_WIN_RESOURCE_UTIL_H_
+#define BASE_WIN_RESOURCE_UTIL_H_
+
+#include <windows.h>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace win {
+
+// Function for getting a data resource of the specified |resource_type| from
+// a dll.  Some resources are optional, especially in unit tests, so this
+// returns false but doesn't raise an error if the resource can't be loaded.
+bool BASE_EXPORT GetResourceFromModule(HMODULE module,
+                                       int resource_id,
+                                       LPCTSTR resource_type,
+                                       void** data,
+                                       size_t* length);
+
+// Function for getting a data resource (BINDATA) from a dll.  Some
+// resources are optional, especially in unit tests, so this returns false
+// but doesn't raise an error if the resource can't be loaded.
+bool BASE_EXPORT GetDataResourceFromModule(HMODULE module,
+                                           int resource_id,
+                                           void** data,
+                                           size_t* length);
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_RESOURCE_UTIL_H_
diff --git a/base/win/scoped_bstr.cc b/base/win/scoped_bstr.cc
new file mode 100644
index 0000000..63ade0c
--- /dev/null
+++ b/base/win/scoped_bstr.cc
@@ -0,0 +1,71 @@
+// Copyright (c) 2010 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/win/scoped_bstr.h"
+
+#include "base/logging.h"
+
+namespace base {
+namespace win {
+
+ScopedBstr::ScopedBstr(const char16* non_bstr)
+    : bstr_(SysAllocString(non_bstr)) {
+}
+
+ScopedBstr::~ScopedBstr() {
+  COMPILE_ASSERT(sizeof(ScopedBstr) == sizeof(BSTR), ScopedBstrSize);
+  SysFreeString(bstr_);
+}
+
+void ScopedBstr::Reset(BSTR bstr) {
+  if (bstr != bstr_) {
+    // if |bstr_| is NULL, SysFreeString does nothing.
+    SysFreeString(bstr_);
+    bstr_ = bstr;
+  }
+}
+
+BSTR ScopedBstr::Release() {
+  BSTR bstr = bstr_;
+  bstr_ = NULL;
+  return bstr;
+}
+
+void ScopedBstr::Swap(ScopedBstr& bstr2) {
+  BSTR tmp = bstr_;
+  bstr_ = bstr2.bstr_;
+  bstr2.bstr_ = tmp;
+}
+
+BSTR* ScopedBstr::Receive() {
+  DCHECK(!bstr_) << "BSTR leak.";
+  return &bstr_;
+}
+
+BSTR ScopedBstr::Allocate(const char16* str) {
+  Reset(SysAllocString(str));
+  return bstr_;
+}
+
+BSTR ScopedBstr::AllocateBytes(size_t bytes) {
+  Reset(SysAllocStringByteLen(NULL, static_cast<UINT>(bytes)));
+  return bstr_;
+}
+
+void ScopedBstr::SetByteLen(size_t bytes) {
+  DCHECK(bstr_ != NULL) << "attempting to modify a NULL bstr";
+  uint32* data = reinterpret_cast<uint32*>(bstr_);
+  data[-1] = static_cast<uint32>(bytes);
+}
+
+size_t ScopedBstr::Length() const {
+  return SysStringLen(bstr_);
+}
+
+size_t ScopedBstr::ByteLength() const {
+  return SysStringByteLen(bstr_);
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/scoped_bstr.h b/base/win/scoped_bstr.h
new file mode 100644
index 0000000..7c9f5df
--- /dev/null
+++ b/base/win/scoped_bstr.h
@@ -0,0 +1,97 @@
+// Copyright (c) 2011 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_WIN_SCOPED_BSTR_H_
+#define BASE_WIN_SCOPED_BSTR_H_
+
+#include <windows.h>
+#include <oleauto.h>
+
+#include "base/base_export.h"
+#include "base/logging.h"
+#include "base/strings/string16.h"
+
+namespace base {
+namespace win {
+
+// Manages a BSTR string pointer.
+// The class interface is based on scoped_ptr.
+class BASE_EXPORT ScopedBstr {
+ public:
+  ScopedBstr() : bstr_(NULL) {
+  }
+
+  // Constructor to create a new BSTR.
+  //
+  // NOTE: Do not pass a BSTR to this constructor expecting ownership to
+  // be transferred - even though it compiles! ;-)
+  explicit ScopedBstr(const char16* non_bstr);
+  ~ScopedBstr();
+
+  // Give ScopedBstr ownership over an already allocated BSTR or NULL.
+  // If you need to allocate a new BSTR instance, use |allocate| instead.
+  void Reset(BSTR bstr = NULL);
+
+  // Releases ownership of the BSTR to the caller.
+  BSTR Release();
+
+  // Creates a new BSTR from a 16-bit C-style string.
+  //
+  // If you already have a BSTR and want to transfer ownership to the
+  // ScopedBstr instance, call |reset| instead.
+  //
+  // Returns a pointer to the new BSTR, or NULL if allocation failed.
+  BSTR Allocate(const char16* str);
+
+  // Allocates a new BSTR with the specified number of bytes.
+  // Returns a pointer to the new BSTR, or NULL if allocation failed.
+  BSTR AllocateBytes(size_t bytes);
+
+  // Sets the allocated length field of the already-allocated BSTR to be
+  // |bytes|.  This is useful when the BSTR was preallocated with e.g.
+  // SysAllocStringLen or SysAllocStringByteLen (call |AllocateBytes|) and then
+  // not all the bytes are being used.
+  //
+  // Note that if you want to set the length to a specific number of
+  // characters, you need to multiply by sizeof(wchar_t).  Oddly, there's no
+  // public API to set the length, so we do this ourselves by hand.
+  //
+  // NOTE: The actual allocated size of the BSTR MUST be >= bytes.  That
+  // responsibility is with the caller.
+  void SetByteLen(size_t bytes);
+
+  // Swap values of two ScopedBstr's.
+  void Swap(ScopedBstr& bstr2);
+
+  // Retrieves the pointer address.
+  // Used to receive BSTRs as out arguments (and take ownership).
+  // The function DCHECKs on the current value being NULL.
+  // Usage: GetBstr(bstr.Receive());
+  BSTR* Receive();
+
+  // Returns number of chars in the BSTR.
+  size_t Length() const;
+
+  // Returns the number of bytes allocated for the BSTR.
+  size_t ByteLength() const;
+
+  operator BSTR() const {
+    return bstr_;
+  }
+
+ protected:
+  BSTR bstr_;
+
+ private:
+  // Forbid comparison of ScopedBstr types.  You should never have the same
+  // BSTR owned by two different scoped_ptrs.
+  bool operator==(const ScopedBstr& bstr2) const;
+  bool operator!=(const ScopedBstr& bstr2) const;
+  DISALLOW_COPY_AND_ASSIGN(ScopedBstr);
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_SCOPED_BSTR_H_
diff --git a/base/win/scoped_bstr_unittest.cc b/base/win/scoped_bstr_unittest.cc
new file mode 100644
index 0000000..5f6f7df
--- /dev/null
+++ b/base/win/scoped_bstr_unittest.cc
@@ -0,0 +1,77 @@
+// Copyright (c) 2010 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/win/scoped_bstr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+static const wchar_t kTestString1[] = L"123";
+static const wchar_t kTestString2[] = L"456789";
+size_t test1_len = arraysize(kTestString1) - 1;
+size_t test2_len = arraysize(kTestString2) - 1;
+
+void DumbBstrTests() {
+  ScopedBstr b;
+  EXPECT_TRUE(b == NULL);
+  EXPECT_EQ(0, b.Length());
+  EXPECT_EQ(0, b.ByteLength());
+  b.Reset(NULL);
+  EXPECT_TRUE(b == NULL);
+  EXPECT_TRUE(b.Release() == NULL);
+  ScopedBstr b2;
+  b.Swap(b2);
+  EXPECT_TRUE(b2 == NULL);
+}
+
+void GiveMeABstr(BSTR* ret) {
+  *ret = SysAllocString(kTestString1);
+}
+
+void BasicBstrTests() {
+  ScopedBstr b1(kTestString1);
+  EXPECT_EQ(test1_len, b1.Length());
+  EXPECT_EQ(test1_len * sizeof(kTestString1[0]), b1.ByteLength());
+
+  ScopedBstr b2;
+  b1.Swap(b2);
+  EXPECT_EQ(test1_len, b2.Length());
+  EXPECT_EQ(0, b1.Length());
+  EXPECT_EQ(0, lstrcmp(b2, kTestString1));
+  BSTR tmp = b2.Release();
+  EXPECT_TRUE(tmp != NULL);
+  EXPECT_EQ(0, lstrcmp(tmp, kTestString1));
+  EXPECT_TRUE(b2 == NULL);
+  SysFreeString(tmp);
+
+  GiveMeABstr(b2.Receive());
+  EXPECT_TRUE(b2 != NULL);
+  b2.Reset();
+  EXPECT_TRUE(b2.AllocateBytes(100) != NULL);
+  EXPECT_EQ(100, b2.ByteLength());
+  EXPECT_EQ(100 / sizeof(kTestString1[0]), b2.Length());
+  lstrcpy(static_cast<BSTR>(b2), kTestString1);
+  EXPECT_EQ(test1_len, lstrlen(b2));
+  EXPECT_EQ(100 / sizeof(kTestString1[0]), b2.Length());
+  b2.SetByteLen(lstrlen(b2) * sizeof(kTestString2[0]));
+  EXPECT_EQ(b2.Length(), lstrlen(b2));
+
+  EXPECT_TRUE(b1.Allocate(kTestString2) != NULL);
+  EXPECT_EQ(test2_len, b1.Length());
+  b1.SetByteLen((test2_len - 1) * sizeof(kTestString2[0]));
+  EXPECT_EQ(test2_len - 1, b1.Length());
+}
+
+}  // namespace
+
+TEST(ScopedBstrTest, ScopedBstr) {
+  DumbBstrTests();
+  BasicBstrTests();
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/scoped_co_mem.h b/base/win/scoped_co_mem.h
new file mode 100644
index 0000000..fc85114
--- /dev/null
+++ b/base/win/scoped_co_mem.h
@@ -0,0 +1,68 @@
+// Copyright (c) 2011 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_WIN_SCOPED_CO_MEM_H_
+#define BASE_WIN_SCOPED_CO_MEM_H_
+
+#include <objbase.h>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+namespace base {
+namespace win {
+
+// Simple scoped memory releaser class for COM allocated memory.
+// Example:
+//   base::win::ScopedCoMem<ITEMIDLIST> file_item;
+//   SHGetSomeInfo(&file_item, ...);
+//   ...
+//   return;  <-- memory released
+template<typename T>
+class ScopedCoMem {
+ public:
+  ScopedCoMem() : mem_ptr_(NULL) {}
+  ~ScopedCoMem() {
+    Reset(NULL);
+  }
+
+  T** operator&() {  // NOLINT
+    DCHECK(mem_ptr_ == NULL);  // To catch memory leaks.
+    return &mem_ptr_;
+  }
+
+  operator T*() {
+    return mem_ptr_;
+  }
+
+  T* operator->() {
+    DCHECK(mem_ptr_ != NULL);
+    return mem_ptr_;
+  }
+
+  const T* operator->() const {
+    DCHECK(mem_ptr_ != NULL);
+    return mem_ptr_;
+  }
+
+  void Reset(T* ptr) {
+    if (mem_ptr_)
+      CoTaskMemFree(mem_ptr_);
+    mem_ptr_ = ptr;
+  }
+
+  T* get() const {
+    return mem_ptr_;
+  }
+
+ private:
+  T* mem_ptr_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedCoMem);
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_SCOPED_CO_MEM_H_
diff --git a/base/win/scoped_com_initializer.h b/base/win/scoped_com_initializer.h
new file mode 100644
index 0000000..92228ba
--- /dev/null
+++ b/base/win/scoped_com_initializer.h
@@ -0,0 +1,79 @@
+// Copyright (c) 2012 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_WIN_SCOPED_COM_INITIALIZER_H_
+#define BASE_WIN_SCOPED_COM_INITIALIZER_H_
+
+#include <objbase.h>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "build/build_config.h"
+
+namespace base {
+namespace win {
+
+// Initializes COM in the constructor (STA or MTA), and uninitializes COM in the
+// destructor.
+//
+// WARNING: This should only be used once per thread, ideally scoped to a
+// similar lifetime as the thread itself.  You should not be using this in
+// random utility functions that make COM calls -- instead ensure these
+// functions are running on a COM-supporting thread!
+class ScopedCOMInitializer {
+ public:
+  // Enum value provided to initialize the thread as an MTA instead of STA.
+  enum SelectMTA { kMTA };
+
+  // Constructor for STA initialization.
+  ScopedCOMInitializer() {
+    Initialize(COINIT_APARTMENTTHREADED);
+  }
+
+  // Constructor for MTA initialization.
+  explicit ScopedCOMInitializer(SelectMTA mta) {
+    Initialize(COINIT_MULTITHREADED);
+  }
+
+  ~ScopedCOMInitializer() {
+#ifndef NDEBUG
+    // Using the windows API directly to avoid dependency on platform_thread.
+    DCHECK_EQ(GetCurrentThreadId(), thread_id_);
+#endif
+    if (succeeded())
+      CoUninitialize();
+  }
+
+  bool succeeded() const { return SUCCEEDED(hr_); }
+
+ private:
+  void Initialize(COINIT init) {
+#ifndef NDEBUG
+    thread_id_ = GetCurrentThreadId();
+#endif
+    hr_ = CoInitializeEx(NULL, init);
+#ifndef NDEBUG
+    if (hr_ == S_FALSE)
+      LOG(ERROR) << "Multiple CoInitialize() calls for thread " << thread_id_;
+    else
+      DCHECK_NE(RPC_E_CHANGED_MODE, hr_) << "Invalid COM thread model change";
+#endif
+  }
+
+  HRESULT hr_;
+#ifndef NDEBUG
+  // In debug builds we use this variable to catch a potential bug where a
+  // ScopedCOMInitializer instance is deleted on a different thread than it
+  // was initially created on.  If that ever happens it can have bad
+  // consequences and the cause can be tricky to track down.
+  DWORD thread_id_;
+#endif
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedCOMInitializer);
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_SCOPED_COM_INITIALIZER_H_
diff --git a/base/win/scoped_comptr.h b/base/win/scoped_comptr.h
new file mode 100644
index 0000000..373c0c3
--- /dev/null
+++ b/base/win/scoped_comptr.h
@@ -0,0 +1,167 @@
+// Copyright (c) 2011 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_WIN_SCOPED_COMPTR_H_
+#define BASE_WIN_SCOPED_COMPTR_H_
+
+#include <unknwn.h>
+
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+
+namespace base {
+namespace win {
+
+// A fairly minimalistic smart class for COM interface pointers.
+// Uses scoped_refptr for the basic smart pointer functionality
+// and adds a few IUnknown specific services.
+template <class Interface, const IID* interface_id = &__uuidof(Interface)>
+class ScopedComPtr : public scoped_refptr<Interface> {
+ public:
+  // Utility template to prevent users of ScopedComPtr from calling AddRef
+  // and/or Release() without going through the ScopedComPtr class.
+  class BlockIUnknownMethods : public Interface {
+   private:
+    STDMETHOD(QueryInterface)(REFIID iid, void** object) = 0;
+    STDMETHOD_(ULONG, AddRef)() = 0;
+    STDMETHOD_(ULONG, Release)() = 0;
+  };
+
+  typedef scoped_refptr<Interface> ParentClass;
+
+  ScopedComPtr() {
+  }
+
+  explicit ScopedComPtr(Interface* p) : ParentClass(p) {
+  }
+
+  ScopedComPtr(const ScopedComPtr<Interface, interface_id>& p)
+      : ParentClass(p) {
+  }
+
+  ~ScopedComPtr() {
+    // We don't want the smart pointer class to be bigger than the pointer
+    // it wraps.
+    COMPILE_ASSERT(sizeof(ScopedComPtr<Interface, interface_id>) ==
+                   sizeof(Interface*), ScopedComPtrSize);
+  }
+
+  // Explicit Release() of the held object.  Useful for reuse of the
+  // ScopedComPtr instance.
+  // Note that this function equates to IUnknown::Release and should not
+  // be confused with e.g. scoped_ptr::release().
+  void Release() {
+    if (ptr_ != NULL) {
+      ptr_->Release();
+      ptr_ = NULL;
+    }
+  }
+
+  // Sets the internal pointer to NULL and returns the held object without
+  // releasing the reference.
+  Interface* Detach() {
+    Interface* p = ptr_;
+    ptr_ = NULL;
+    return p;
+  }
+
+  // Accepts an interface pointer that has already been addref-ed.
+  void Attach(Interface* p) {
+    DCHECK(!ptr_);
+    ptr_ = p;
+  }
+
+  // Retrieves the pointer address.
+  // Used to receive object pointers as out arguments (and take ownership).
+  // The function DCHECKs on the current value being NULL.
+  // Usage: Foo(p.Receive());
+  Interface** Receive() {
+    DCHECK(!ptr_) << "Object leak. Pointer must be NULL";
+    return &ptr_;
+  }
+
+  // A convenience for whenever a void pointer is needed as an out argument.
+  void** ReceiveVoid() {
+    return reinterpret_cast<void**>(Receive());
+  }
+
+  template <class Query>
+  HRESULT QueryInterface(Query** p) {
+    DCHECK(p != NULL);
+    DCHECK(ptr_ != NULL);
+    // IUnknown already has a template version of QueryInterface
+    // so the iid parameter is implicit here. The only thing this
+    // function adds are the DCHECKs.
+    return ptr_->QueryInterface(p);
+  }
+
+  // QI for times when the IID is not associated with the type.
+  HRESULT QueryInterface(const IID& iid, void** obj) {
+    DCHECK(obj != NULL);
+    DCHECK(ptr_ != NULL);
+    return ptr_->QueryInterface(iid, obj);
+  }
+
+  // Queries |other| for the interface this object wraps and returns the
+  // error code from the other->QueryInterface operation.
+  HRESULT QueryFrom(IUnknown* object) {
+    DCHECK(object != NULL);
+    return object->QueryInterface(Receive());
+  }
+
+  // Convenience wrapper around CoCreateInstance
+  HRESULT CreateInstance(const CLSID& clsid, IUnknown* outer = NULL,
+                         DWORD context = CLSCTX_ALL) {
+    DCHECK(!ptr_);
+    HRESULT hr = ::CoCreateInstance(clsid, outer, context, *interface_id,
+                                    reinterpret_cast<void**>(&ptr_));
+    return hr;
+  }
+
+  // Checks if the identity of |other| and this object is the same.
+  bool IsSameObject(IUnknown* other) {
+    if (!other && !ptr_)
+      return true;
+
+    if (!other || !ptr_)
+      return false;
+
+    ScopedComPtr<IUnknown> my_identity;
+    QueryInterface(my_identity.Receive());
+
+    ScopedComPtr<IUnknown> other_identity;
+    other->QueryInterface(other_identity.Receive());
+
+    return my_identity == other_identity;
+  }
+
+  // Provides direct access to the interface.
+  // Here we use a well known trick to make sure we block access to
+  // IUnknown methods so that something bad like this doesn't happen:
+  //    ScopedComPtr<IUnknown> p(Foo());
+  //    p->Release();
+  //    ... later the destructor runs, which will Release() again.
+  // and to get the benefit of the DCHECKs we add to QueryInterface.
+  // There's still a way to call these methods if you absolutely must
+  // by statically casting the ScopedComPtr instance to the wrapped interface
+  // and then making the call... but generally that shouldn't be necessary.
+  BlockIUnknownMethods* operator->() const {
+    DCHECK(ptr_ != NULL);
+    return reinterpret_cast<BlockIUnknownMethods*>(ptr_);
+  }
+
+  // Pull in operator=() from the parent class.
+  using scoped_refptr<Interface>::operator=;
+
+  // static methods
+
+  static const IID& iid() {
+    return *interface_id;
+  }
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_SCOPED_COMPTR_H_
diff --git a/base/win/scoped_comptr_unittest.cc b/base/win/scoped_comptr_unittest.cc
new file mode 100644
index 0000000..d38752d
--- /dev/null
+++ b/base/win/scoped_comptr_unittest.cc
@@ -0,0 +1,111 @@
+// Copyright (c) 2011 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/win/scoped_comptr.h"
+
+#include <shlobj.h>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/win/scoped_com_initializer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+struct Dummy {
+  Dummy() : adds(0), releases(0) { }
+  void AddRef() { ++adds; }
+  void Release() { ++releases; }
+
+  int adds;
+  int releases;
+};
+
+extern const IID dummy_iid;
+const IID dummy_iid = { 0x12345678u, 0x1234u, 0x5678u, 01, 23, 45, 67, 89,
+                        01, 23, 45 };
+
+}  // namespace
+
+TEST(ScopedComPtrTest, ScopedComPtr) {
+  EXPECT_EQ(memcmp(&ScopedComPtr<IUnknown>::iid(), &IID_IUnknown, sizeof(IID)),
+            0);
+
+  base::win::ScopedCOMInitializer com_initializer;
+  EXPECT_TRUE(com_initializer.succeeded());
+
+  ScopedComPtr<IUnknown> unk;
+  EXPECT_TRUE(SUCCEEDED(unk.CreateInstance(CLSID_ShellLink)));
+  ScopedComPtr<IUnknown> unk2;
+  unk2.Attach(unk.Detach());
+  EXPECT_TRUE(unk.get() == NULL);
+  EXPECT_TRUE(unk2.get() != NULL);
+
+  ScopedComPtr<IMalloc> mem_alloc;
+  EXPECT_TRUE(SUCCEEDED(CoGetMalloc(1, mem_alloc.Receive())));
+
+  ScopedComPtr<IUnknown> qi_test;
+  EXPECT_HRESULT_SUCCEEDED(mem_alloc.QueryInterface(IID_IUnknown,
+      reinterpret_cast<void**>(qi_test.Receive())));
+  EXPECT_TRUE(qi_test.get() != NULL);
+  qi_test.Release();
+
+  // test ScopedComPtr& constructor
+  ScopedComPtr<IMalloc> copy1(mem_alloc);
+  EXPECT_TRUE(copy1.IsSameObject(mem_alloc.get()));
+  EXPECT_FALSE(copy1.IsSameObject(unk2.get()));  // unk2 is valid but different
+  EXPECT_FALSE(copy1.IsSameObject(unk.get()));  // unk is NULL
+
+  IMalloc* naked_copy = copy1.Detach();
+  copy1 = naked_copy;  // Test the =(T*) operator.
+  naked_copy->Release();
+
+  copy1.Release();
+  EXPECT_FALSE(copy1.IsSameObject(unk2.get()));  // unk2 is valid, copy1 is not
+
+  // test Interface* constructor
+  ScopedComPtr<IMalloc> copy2(static_cast<IMalloc*>(mem_alloc.get()));
+  EXPECT_TRUE(copy2.IsSameObject(mem_alloc.get()));
+
+  EXPECT_TRUE(SUCCEEDED(unk.QueryFrom(mem_alloc.get())));
+  EXPECT_TRUE(unk.get() != NULL);
+  unk.Release();
+  EXPECT_TRUE(unk.get() == NULL);
+  EXPECT_TRUE(unk.IsSameObject(copy1.get()));  // both are NULL
+}
+
+TEST(ScopedComPtrTest, ScopedComPtrVector) {
+  // Verify we don't get error C2558.
+  typedef ScopedComPtr<Dummy, &dummy_iid> Ptr;
+  std::vector<Ptr> bleh;
+
+  scoped_ptr<Dummy> p(new Dummy);
+  {
+    Ptr p2(p.get());
+    EXPECT_EQ(p->adds, 1);
+    EXPECT_EQ(p->releases, 0);
+    Ptr p3 = p2;
+    EXPECT_EQ(p->adds, 2);
+    EXPECT_EQ(p->releases, 0);
+    p3 = p2;
+    EXPECT_EQ(p->adds, 3);
+    EXPECT_EQ(p->releases, 1);
+    // To avoid hitting a reallocation.
+    bleh.reserve(1);
+    bleh.push_back(p2);
+    EXPECT_EQ(p->adds, 4);
+    EXPECT_EQ(p->releases, 1);
+    EXPECT_EQ(bleh[0].get(), p.get());
+    bleh.pop_back();
+    EXPECT_EQ(p->adds, 4);
+    EXPECT_EQ(p->releases, 2);
+  }
+  EXPECT_EQ(p->adds, 4);
+  EXPECT_EQ(p->releases, 4);
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/scoped_gdi_object.h b/base/win/scoped_gdi_object.h
new file mode 100644
index 0000000..57b013e
--- /dev/null
+++ b/base/win/scoped_gdi_object.h
@@ -0,0 +1,77 @@
+// Copyright (c) 2010 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_WIN_SCOPED_GDI_OBJECT_H_
+#define BASE_WIN_SCOPED_GDI_OBJECT_H_
+
+#include <windows.h>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+namespace base {
+namespace win {
+
+// Like ScopedHandle but for GDI objects.
+template<class T>
+class ScopedGDIObject {
+ public:
+  ScopedGDIObject() : object_(NULL) {}
+  explicit ScopedGDIObject(T object) : object_(object) {}
+
+  ~ScopedGDIObject() {
+    Close();
+  }
+
+  T Get() {
+    return object_;
+  }
+
+  void Set(T object) {
+    if (object_ && object != object_)
+      Close();
+    object_ = object;
+  }
+
+  ScopedGDIObject& operator=(T object) {
+    Set(object);
+    return *this;
+  }
+
+  T release() {
+    T object = object_;
+    object_ = NULL;
+    return object;
+  }
+
+  operator T() { return object_; }
+
+ private:
+  void Close() {
+    if (object_)
+      DeleteObject(object_);
+  }
+
+  T object_;
+  DISALLOW_COPY_AND_ASSIGN(ScopedGDIObject);
+};
+
+// An explicit specialization for HICON because we have to call DestroyIcon()
+// instead of DeleteObject() for HICON.
+template<>
+void inline ScopedGDIObject<HICON>::Close() {
+  if (object_)
+    DestroyIcon(object_);
+}
+
+// Typedefs for some common use cases.
+typedef ScopedGDIObject<HBITMAP> ScopedBitmap;
+typedef ScopedGDIObject<HRGN> ScopedRegion;
+typedef ScopedGDIObject<HFONT> ScopedHFONT;
+typedef ScopedGDIObject<HICON> ScopedHICON;
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_SCOPED_GDI_OBJECT_H_
diff --git a/base/win/scoped_handle.cc b/base/win/scoped_handle.cc
new file mode 100644
index 0000000..ce944e4
--- /dev/null
+++ b/base/win/scoped_handle.cc
@@ -0,0 +1,257 @@
+// Copyright (c) 2012 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/win/scoped_handle.h"
+
+#include <unordered_map>
+
+#include "base/debug/alias.h"
+#include "base/hash.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/synchronization/lock_impl.h"
+
+extern "C" {
+__declspec(dllexport) void* GetHandleVerifier();
+typedef void* (*GetHandleVerifierFn)();
+}
+
+namespace {
+
+struct HandleHash {
+  size_t operator()(const HANDLE& handle) const {
+    char buffer[sizeof(handle)];
+    memcpy(buffer, &handle, sizeof(handle));
+    return base::Hash(buffer, sizeof(buffer));
+  }
+};
+
+struct Info {
+  const void* owner;
+  const void* pc1;
+  const void* pc2;
+  DWORD thread_id;
+};
+typedef std::unordered_map<HANDLE, Info, HandleHash> HandleMap;
+
+// g_lock protects the handle map and setting g_active_verifier.
+typedef base::internal::LockImpl NativeLock;
+base::LazyInstance<NativeLock>::Leaky g_lock = LAZY_INSTANCE_INITIALIZER;
+
+bool CloseHandleWrapper(HANDLE handle) {
+  if (!::CloseHandle(handle))
+    CHECK(false);
+  return true;
+}
+
+// Simple automatic locking using a native critical section so it supports
+// recursive locking.
+class AutoNativeLock {
+ public:
+  explicit AutoNativeLock(NativeLock& lock) : lock_(lock) {
+    lock_.Lock();
+  }
+
+  ~AutoNativeLock() {
+    lock_.Unlock();
+  }
+
+ private:
+  NativeLock& lock_;
+  DISALLOW_COPY_AND_ASSIGN(AutoNativeLock);
+};
+
+// Implements the actual object that is verifying handles for this process.
+// The active instance is shared across the module boundary but there is no
+// way to delete this object from the wrong side of it (or any side, actually).
+class ActiveVerifier {
+ public:
+  explicit ActiveVerifier(bool enabled)
+      : enabled_(enabled), closing_(false), lock_(g_lock.Pointer()) {
+  }
+
+  // Retrieves the current verifier.
+  static ActiveVerifier* Get();
+
+  // The methods required by HandleTraits. They are virtual because we need to
+  // forward the call execution to another module, instead of letting the
+  // compiler call the version that is linked in the current module.
+  virtual bool CloseHandle(HANDLE handle);
+  virtual void StartTracking(HANDLE handle, const void* owner,
+                             const void* pc1, const void* pc2);
+  virtual void StopTracking(HANDLE handle, const void* owner,
+                            const void* pc1, const void* pc2);
+  virtual void Disable();
+  virtual void OnHandleBeingClosed(HANDLE handle);
+
+ private:
+  ~ActiveVerifier();  // Not implemented.
+
+  static void InstallVerifier();
+
+  bool enabled_;
+  bool closing_;
+  NativeLock* lock_;
+  HandleMap map_;
+  DISALLOW_COPY_AND_ASSIGN(ActiveVerifier);
+};
+ActiveVerifier* g_active_verifier = NULL;
+
+// static
+ActiveVerifier* ActiveVerifier::Get() {
+  if (!g_active_verifier)
+    ActiveVerifier::InstallVerifier();
+
+  return g_active_verifier;
+}
+
+// static
+void ActiveVerifier::InstallVerifier() {
+#if defined(COMPONENT_BUILD)
+  AutoNativeLock lock(g_lock.Get());
+  g_active_verifier = new ActiveVerifier(true);
+#else
+  // If you are reading this, wondering why your process seems deadlocked, take
+  // a look at your DllMain code and remove things that should not be done
+  // there, like doing whatever gave you that nice windows handle you are trying
+  // to store in a ScopedHandle.
+  HMODULE main_module = ::GetModuleHandle(NULL);
+  GetHandleVerifierFn get_handle_verifier =
+      reinterpret_cast<GetHandleVerifierFn>(::GetProcAddress(
+          main_module, "GetHandleVerifier"));
+
+  if (!get_handle_verifier) {
+    g_active_verifier = new ActiveVerifier(false);
+    return;
+  }
+
+  ActiveVerifier* verifier =
+      reinterpret_cast<ActiveVerifier*>(get_handle_verifier());
+
+  // This lock only protects against races in this module, which is fine.
+  AutoNativeLock lock(g_lock.Get());
+  g_active_verifier = verifier ? verifier : new ActiveVerifier(true);
+#endif
+}
+
+bool ActiveVerifier::CloseHandle(HANDLE handle) {
+  if (!enabled_)
+    return CloseHandleWrapper(handle);
+
+  AutoNativeLock lock(*lock_);
+  closing_ = true;
+  CloseHandleWrapper(handle);
+  closing_ = false;
+
+  return true;
+}
+
+void ActiveVerifier::StartTracking(HANDLE handle, const void* owner,
+                                   const void* pc1, const void* pc2) {
+  if (!enabled_)
+    return;
+
+  // Idea here is to make our handles non-closable until we close it ourselves.
+  // Handles provided could be totally fabricated especially through our
+  // unittest, we are ignoring that for now by not checking return value.
+  ::SetHandleInformation(handle, HANDLE_FLAG_PROTECT_FROM_CLOSE,
+                         HANDLE_FLAG_PROTECT_FROM_CLOSE);
+
+  // Grab the thread id before the lock.
+  DWORD thread_id = GetCurrentThreadId();
+
+  AutoNativeLock lock(*lock_);
+
+  Info handle_info = { owner, pc1, pc2, thread_id };
+  std::pair<HANDLE, Info> item(handle, handle_info);
+  std::pair<HandleMap::iterator, bool> result = map_.insert(item);
+  if (!result.second) {
+    Info other = result.first->second;
+    base::debug::Alias(&other);
+    CHECK(false);
+  }
+}
+
+void ActiveVerifier::StopTracking(HANDLE handle, const void* owner,
+                                  const void* pc1, const void* pc2) {
+  if (!enabled_)
+    return;
+
+  // We expect handle to be protected till this point.
+  DWORD flags = 0;
+  if (::GetHandleInformation(handle, &flags)) {
+    CHECK_NE(0U, (flags & HANDLE_FLAG_PROTECT_FROM_CLOSE));
+
+    // Unprotect handle so that it could be closed.
+    ::SetHandleInformation(handle, HANDLE_FLAG_PROTECT_FROM_CLOSE, 0);
+  }
+
+  AutoNativeLock lock(*lock_);
+  HandleMap::iterator i = map_.find(handle);
+  if (i == map_.end())
+    CHECK(false);
+
+  Info other = i->second;
+  if (other.owner != owner) {
+    base::debug::Alias(&other);
+    CHECK(false);
+  }
+
+  map_.erase(i);
+}
+
+void ActiveVerifier::Disable() {
+  enabled_ = false;
+}
+
+void ActiveVerifier::OnHandleBeingClosed(HANDLE handle) {
+  AutoNativeLock lock(*lock_);
+  if (closing_)
+    return;
+
+  HandleMap::iterator i = map_.find(handle);
+  if (i == map_.end())
+    return;
+
+  Info other = i->second;
+  base::debug::Alias(&other);
+  CHECK(false);
+}
+
+}  // namespace
+
+void* GetHandleVerifier() {
+  return g_active_verifier;
+}
+
+namespace base {
+namespace win {
+
+// Static.
+bool HandleTraits::CloseHandle(HANDLE handle) {
+  return ActiveVerifier::Get()->CloseHandle(handle);
+}
+
+// Static.
+void VerifierTraits::StartTracking(HANDLE handle, const void* owner,
+                                   const void* pc1, const void* pc2) {
+  return ActiveVerifier::Get()->StartTracking(handle, owner, pc1, pc2);
+}
+
+// Static.
+void VerifierTraits::StopTracking(HANDLE handle, const void* owner,
+                                  const void* pc1, const void* pc2) {
+  return ActiveVerifier::Get()->StopTracking(handle, owner, pc1, pc2);
+}
+
+void DisableHandleVerifier() {
+  return ActiveVerifier::Get()->Disable();
+}
+
+void OnHandleBeingClosed(HANDLE handle) {
+  return ActiveVerifier::Get()->OnHandleBeingClosed(handle);
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/scoped_handle.h b/base/win/scoped_handle.h
new file mode 100644
index 0000000..97fd7a5
--- /dev/null
+++ b/base/win/scoped_handle.h
@@ -0,0 +1,177 @@
+// Copyright (c) 2012 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_WIN_SCOPED_HANDLE_H_
+#define BASE_WIN_SCOPED_HANDLE_H_
+
+#include <windows.h>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/move.h"
+
+// TODO(rvargas): remove this with the rest of the verifier.
+#if defined(COMPILER_MSVC)
+#include <intrin.h>
+#define BASE_WIN_GET_CALLER _ReturnAddress()
+#elif defined(COMPILER_GCC)
+#define BASE_WIN_GET_CALLER __builtin_extract_return_addr(\\
+    __builtin_return_address(0))
+#endif
+
+namespace base {
+namespace win {
+
+// Generic wrapper for raw handles that takes care of closing handles
+// automatically. The class interface follows the style of
+// the ScopedFILE class with one addition:
+//   - IsValid() method can tolerate multiple invalid handle values such as NULL
+//     and INVALID_HANDLE_VALUE (-1) for Win32 handles.
+template <class Traits, class Verifier>
+class GenericScopedHandle {
+  MOVE_ONLY_TYPE_FOR_CPP_03(GenericScopedHandle, RValue)
+
+ public:
+  typedef typename Traits::Handle Handle;
+
+  GenericScopedHandle() : handle_(Traits::NullHandle()) {}
+
+  explicit GenericScopedHandle(Handle handle) : handle_(Traits::NullHandle()) {
+    Set(handle);
+  }
+
+  // Move constructor for C++03 move emulation of this type.
+  GenericScopedHandle(RValue other) : handle_(Traits::NullHandle()) {
+    Set(other.object->Take());
+  }
+
+  ~GenericScopedHandle() {
+    Close();
+  }
+
+  bool IsValid() const {
+    return Traits::IsHandleValid(handle_);
+  }
+
+  // Move operator= for C++03 move emulation of this type.
+  GenericScopedHandle& operator=(RValue other) {
+    if (this != other.object) {
+      Set(other.object->Take());
+    }
+    return *this;
+  }
+
+  void Set(Handle handle) {
+    if (handle_ != handle) {
+      Close();
+
+      if (Traits::IsHandleValid(handle)) {
+        handle_ = handle;
+        Verifier::StartTracking(handle, this, BASE_WIN_GET_CALLER,
+                                tracked_objects::GetProgramCounter());
+      }
+    }
+  }
+
+  Handle Get() const {
+    return handle_;
+  }
+
+  // Transfers ownership away from this object.
+  Handle Take() {
+    Handle temp = handle_;
+    handle_ = Traits::NullHandle();
+    if (Traits::IsHandleValid(temp)) {
+      Verifier::StopTracking(temp, this, BASE_WIN_GET_CALLER,
+                             tracked_objects::GetProgramCounter());
+    }
+    return temp;
+  }
+
+  // Explicitly closes the owned handle.
+  void Close() {
+    if (Traits::IsHandleValid(handle_)) {
+      Verifier::StopTracking(handle_, this, BASE_WIN_GET_CALLER,
+                             tracked_objects::GetProgramCounter());
+
+      Traits::CloseHandle(handle_);
+      handle_ = Traits::NullHandle();
+    }
+  }
+
+ private:
+  Handle handle_;
+};
+
+#undef BASE_WIN_GET_CALLER
+
+// The traits class for Win32 handles that can be closed via CloseHandle() API.
+class HandleTraits {
+ public:
+  typedef HANDLE Handle;
+
+  // Closes the handle.
+  static bool BASE_EXPORT CloseHandle(HANDLE handle);
+
+  // Returns true if the handle value is valid.
+  static bool IsHandleValid(HANDLE handle) {
+    return handle != NULL && handle != INVALID_HANDLE_VALUE;
+  }
+
+  // Returns NULL handle value.
+  static HANDLE NullHandle() {
+    return NULL;
+  }
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(HandleTraits);
+};
+
+// Do-nothing verifier.
+class DummyVerifierTraits {
+ public:
+  typedef HANDLE Handle;
+
+  static void StartTracking(HANDLE handle, const void* owner,
+                            const void* pc1, const void* pc2) {}
+  static void StopTracking(HANDLE handle, const void* owner,
+                           const void* pc1, const void* pc2) {}
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(DummyVerifierTraits);
+};
+
+// Performs actual run-time tracking.
+class BASE_EXPORT VerifierTraits {
+ public:
+  typedef HANDLE Handle;
+
+  static void StartTracking(HANDLE handle, const void* owner,
+                            const void* pc1, const void* pc2);
+  static void StopTracking(HANDLE handle, const void* owner,
+                           const void* pc1, const void* pc2);
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(VerifierTraits);
+};
+
+typedef GenericScopedHandle<HandleTraits, VerifierTraits> ScopedHandle;
+
+// This function may be called by the embedder to disable the use of
+// VerifierTraits at runtime. It has no effect if DummyVerifierTraits is used
+// for ScopedHandle.
+void BASE_EXPORT DisableHandleVerifier();
+
+// This should be called whenever the OS is closing a handle, if extended
+// verification of improper handle closing is desired. If |handle| is being
+// tracked by the handle verifier and ScopedHandle is not the one closing it,
+// a CHECK is generated.
+void BASE_EXPORT OnHandleBeingClosed(HANDLE handle);
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_SCOPED_HANDLE_H_
diff --git a/base/win/scoped_hdc.h b/base/win/scoped_hdc.h
new file mode 100644
index 0000000..2452067
--- /dev/null
+++ b/base/win/scoped_hdc.h
@@ -0,0 +1,76 @@
+// Copyright (c) 2012 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_WIN_SCOPED_HDC_H_
+#define BASE_WIN_SCOPED_HDC_H_
+
+#include <windows.h>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/win/scoped_handle.h"
+
+namespace base {
+namespace win {
+
+// Like ScopedHandle but for HDC.  Only use this on HDCs returned from
+// GetDC.
+class ScopedGetDC {
+ public:
+  explicit ScopedGetDC(HWND hwnd)
+      : hwnd_(hwnd),
+        hdc_(GetDC(hwnd)) {
+    if (hwnd_) {
+      DCHECK(IsWindow(hwnd_));
+      DCHECK(hdc_);
+    } else {
+      // If GetDC(NULL) returns NULL, something really bad has happened, like
+      // GDI handle exhaustion.  In this case Chrome is going to behave badly no
+      // matter what, so we may as well just force a crash now.
+      CHECK(hdc_);
+    }
+  }
+
+  ~ScopedGetDC() {
+    if (hdc_)
+      ReleaseDC(hwnd_, hdc_);
+  }
+
+  operator HDC() { return hdc_; }
+
+ private:
+  HWND hwnd_;
+  HDC hdc_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedGetDC);
+};
+
+// Like ScopedHandle but for HDC.  Only use this on HDCs returned from
+// CreateCompatibleDC, CreateDC and CreateIC.
+class CreateDCTraits {
+ public:
+  typedef HDC Handle;
+
+  static bool CloseHandle(HDC handle) {
+    return ::DeleteDC(handle) != FALSE;
+  }
+
+  static bool IsHandleValid(HDC handle) {
+    return handle != NULL;
+  }
+
+  static HDC NullHandle() {
+    return NULL;
+  }
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(CreateDCTraits);
+};
+
+typedef GenericScopedHandle<CreateDCTraits, DummyVerifierTraits> ScopedCreateDC;
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_SCOPED_HDC_H_
diff --git a/base/win/scoped_hglobal.h b/base/win/scoped_hglobal.h
new file mode 100644
index 0000000..185ccbd
--- /dev/null
+++ b/base/win/scoped_hglobal.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2010 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_WIN_SCOPED_HGLOBAL_H_
+#define BASE_WIN_SCOPED_HGLOBAL_H_
+
+#include <windows.h>
+
+#include "base/basictypes.h"
+
+namespace base {
+namespace win {
+
+// Like ScopedHandle except for HGLOBAL.
+template<class T>
+class ScopedHGlobal {
+ public:
+  explicit ScopedHGlobal(HGLOBAL glob) : glob_(glob) {
+    data_ = static_cast<T>(GlobalLock(glob_));
+  }
+  ~ScopedHGlobal() {
+    GlobalUnlock(glob_);
+  }
+
+  T get() { return data_; }
+
+  size_t Size() const { return GlobalSize(glob_); }
+
+  T operator->() const {
+    assert(data_ != 0);
+    return data_;
+  }
+
+  T release() {
+    T data = data_;
+    data_ = NULL;
+    return data;
+  }
+
+ private:
+  HGLOBAL glob_;
+
+  T data_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedHGlobal);
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_SCOPED_HGLOBAL_H_
diff --git a/base/win/scoped_process_information.cc b/base/win/scoped_process_information.cc
new file mode 100644
index 0000000..634a538
--- /dev/null
+++ b/base/win/scoped_process_information.cc
@@ -0,0 +1,147 @@
+// Copyright (c) 2012 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/win/scoped_process_information.h"
+
+#include "base/logging.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/windows_version.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+// Duplicates source into target, returning true upon success. |target| is
+// guaranteed to be untouched in case of failure. Succeeds with no side-effects
+// if source is NULL.
+bool CheckAndDuplicateHandle(HANDLE source, ScopedHandle* target) {
+  if (!source)
+    return true;
+
+  HANDLE temp = NULL;
+
+  // TODO(shrikant): Remove following code as soon as we gather some
+  // information regarding AppContainer related DuplicateHandle failures that
+  // only seem to happen on certain machine and only random launches (normally
+  // renderer launches seem to succeed even on those machines.)
+  if (base::win::GetVersion() == base::win::VERSION_WIN8 ||
+      base::win::GetVersion() == base::win::VERSION_WIN8_1) {
+    typedef LONG (WINAPI *NtDuplicateObject)(
+        IN HANDLE SourceProcess,
+        IN HANDLE SourceHandle,
+        IN HANDLE TargetProcess,
+        OUT PHANDLE TargetHandle,
+        IN ACCESS_MASK DesiredAccess,
+        IN ULONG Attributes,
+        IN ULONG Options);
+
+    typedef ULONG (WINAPI *RtlNtStatusToDosError)(IN LONG Status);
+
+    NtDuplicateObject nt_duplicate_object =
+        reinterpret_cast<NtDuplicateObject>(::GetProcAddress(
+            GetModuleHandle(L"ntdll.dll"), "NtDuplicateObject"));
+    if (nt_duplicate_object != NULL) {
+      LONG status = nt_duplicate_object(::GetCurrentProcess(), source,
+                                        ::GetCurrentProcess(), &temp,
+                                        0, FALSE, DUPLICATE_SAME_ACCESS);
+      if (status < 0) {
+        DPLOG(ERROR) << "Failed to duplicate a handle.";
+        RtlNtStatusToDosError ntstatus_to_doserror =
+            reinterpret_cast<RtlNtStatusToDosError>(::GetProcAddress(
+                GetModuleHandle(L"ntdll.dll"), "RtlNtStatusToDosError"));
+        if (ntstatus_to_doserror != NULL) {
+          ::SetLastError(ntstatus_to_doserror(status));
+        }
+        return false;
+      }
+    }
+  } else {
+    if (!::DuplicateHandle(::GetCurrentProcess(), source,
+                           ::GetCurrentProcess(), &temp, 0, FALSE,
+                           DUPLICATE_SAME_ACCESS)) {
+      DPLOG(ERROR) << "Failed to duplicate a handle.";
+      return false;
+    }
+  }
+  target->Set(temp);
+  return true;
+}
+
+}  // namespace
+
+ScopedProcessInformation::ScopedProcessInformation()
+    : process_id_(0), thread_id_(0) {
+}
+
+ScopedProcessInformation::ScopedProcessInformation(
+    const PROCESS_INFORMATION& process_info) : process_id_(0), thread_id_(0) {
+  Set(process_info);
+}
+
+ScopedProcessInformation::~ScopedProcessInformation() {
+  Close();
+}
+
+bool ScopedProcessInformation::IsValid() const {
+  return process_id_ || process_handle_.Get() ||
+         thread_id_ || thread_handle_.Get();
+}
+
+void ScopedProcessInformation::Close() {
+  process_handle_.Close();
+  thread_handle_.Close();
+  process_id_ = 0;
+  thread_id_ = 0;
+}
+
+void ScopedProcessInformation::Set(const PROCESS_INFORMATION& process_info) {
+  if (IsValid())
+    Close();
+
+  process_handle_.Set(process_info.hProcess);
+  thread_handle_.Set(process_info.hThread);
+  process_id_ = process_info.dwProcessId;
+  thread_id_ = process_info.dwThreadId;
+}
+
+bool ScopedProcessInformation::DuplicateFrom(
+    const ScopedProcessInformation& other) {
+  DCHECK(!IsValid()) << "target ScopedProcessInformation must be NULL";
+  DCHECK(other.IsValid()) << "source ScopedProcessInformation must be valid";
+
+  if (CheckAndDuplicateHandle(other.process_handle(), &process_handle_) &&
+      CheckAndDuplicateHandle(other.thread_handle(), &thread_handle_)) {
+    process_id_ = other.process_id();
+    thread_id_ = other.thread_id();
+    return true;
+  }
+
+  return false;
+}
+
+PROCESS_INFORMATION ScopedProcessInformation::Take() {
+  PROCESS_INFORMATION process_information = {};
+  process_information.hProcess = process_handle_.Take();
+  process_information.hThread = thread_handle_.Take();
+  process_information.dwProcessId = process_id();
+  process_information.dwThreadId = thread_id();
+  process_id_ = 0;
+  thread_id_ = 0;
+
+  return process_information;
+}
+
+HANDLE ScopedProcessInformation::TakeProcessHandle() {
+  process_id_ = 0;
+  return process_handle_.Take();
+}
+
+HANDLE ScopedProcessInformation::TakeThreadHandle() {
+  thread_id_ = 0;
+  return thread_handle_.Take();
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/scoped_process_information.h b/base/win/scoped_process_information.h
new file mode 100644
index 0000000..2e24054
--- /dev/null
+++ b/base/win/scoped_process_information.h
@@ -0,0 +1,83 @@
+// Copyright (c) 2012 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_WIN_SCOPED_PROCESS_INFORMATION_H_
+#define BASE_WIN_SCOPED_PROCESS_INFORMATION_H_
+
+#include <windows.h>
+
+#include "base/basictypes.h"
+#include "base/base_export.h"
+#include "base/win/scoped_handle.h"
+
+namespace base {
+namespace win {
+
+// Manages the closing of process and thread handles from PROCESS_INFORMATION
+// structures. Allows clients to take ownership of either handle independently.
+class BASE_EXPORT ScopedProcessInformation {
+ public:
+  ScopedProcessInformation();
+  explicit ScopedProcessInformation(const PROCESS_INFORMATION& process_info);
+  ~ScopedProcessInformation();
+
+  // Returns true iff this instance is holding a thread and/or process handle.
+  bool IsValid() const;
+
+  // Closes the held thread and process handles, if any.
+  void Close();
+
+  // Populates this instance with the provided |process_info|.
+  void Set(const PROCESS_INFORMATION& process_info);
+
+  // Populates this instance with duplicate handles and the thread/process IDs
+  // from |other|. Returns false in case of failure, in which case this instance
+  // will be completely unpopulated.
+  bool DuplicateFrom(const ScopedProcessInformation& other);
+
+  // Transfers ownership of the held PROCESS_INFORMATION, if any, away from this
+  // instance.
+  PROCESS_INFORMATION Take();
+
+  // Transfers ownership of the held process handle, if any, away from this
+  // instance. Note that the related process_id will also be cleared.
+  HANDLE TakeProcessHandle();
+
+  // Transfers ownership of the held thread handle, if any, away from this
+  // instance. Note that the related thread_id will also be cleared.
+  HANDLE TakeThreadHandle();
+
+  // Returns the held process handle, if any, while retaining ownership.
+  HANDLE process_handle() const {
+    return process_handle_.Get();
+  }
+
+  // Returns the held thread handle, if any, while retaining ownership.
+  HANDLE thread_handle() const {
+    return thread_handle_.Get();
+  }
+
+  // Returns the held process id, if any.
+  DWORD process_id() const {
+    return process_id_;
+  }
+
+  // Returns the held thread id, if any.
+  DWORD thread_id() const {
+    return thread_id_;
+  }
+
+ private:
+  ScopedHandle process_handle_;
+  ScopedHandle thread_handle_;
+  DWORD process_id_;
+  DWORD thread_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedProcessInformation);
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_SCOPED_PROCESS_INFORMATION_H_
diff --git a/base/win/scoped_process_information_unittest.cc b/base/win/scoped_process_information_unittest.cc
new file mode 100644
index 0000000..614504d
--- /dev/null
+++ b/base/win/scoped_process_information_unittest.cc
@@ -0,0 +1,166 @@
+// Copyright (c) 2012 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 <windows.h>
+
+#include <string>
+
+#include "base/command_line.h"
+#include "base/process/kill.h"
+#include "base/process/process.h"
+#include "base/test/multiprocess_test.h"
+#include "base/win/scoped_process_information.h"
+#include "testing/multiprocess_func_list.h"
+
+namespace {
+
+const DWORD kProcessId = 4321;
+const DWORD kThreadId = 1234;
+const HANDLE kProcessHandle = reinterpret_cast<HANDLE>(7651);
+const HANDLE kThreadHandle = reinterpret_cast<HANDLE>(1567);
+
+void MockCreateProcess(base::win::ScopedProcessInformation* process_info) {
+  PROCESS_INFORMATION process_information = {};
+  process_information.dwProcessId = kProcessId;
+  process_information.dwThreadId = kThreadId;
+  process_information.hProcess = kProcessHandle;
+  process_information.hThread = kThreadHandle;
+  process_info->Set(process_information);
+}
+
+}  // namespace
+
+class ScopedProcessInformationTest : public base::MultiProcessTest {
+ protected:
+  void DoCreateProcess(const std::string& main_id,
+                       PROCESS_INFORMATION* process_handle);
+};
+
+MULTIPROCESS_TEST_MAIN(ReturnSeven) {
+  return 7;
+}
+
+MULTIPROCESS_TEST_MAIN(ReturnNine) {
+  return 9;
+}
+
+void ScopedProcessInformationTest::DoCreateProcess(
+    const std::string& main_id, PROCESS_INFORMATION* process_handle) {
+  std::wstring cmd_line = MakeCmdLine(main_id).GetCommandLineString();
+  STARTUPINFO startup_info = {};
+  startup_info.cb = sizeof(startup_info);
+
+  EXPECT_TRUE(::CreateProcess(NULL, &cmd_line[0],
+                              NULL, NULL, false, 0, NULL, NULL,
+                              &startup_info, process_handle));
+}
+
+TEST_F(ScopedProcessInformationTest, InitiallyInvalid) {
+  base::win::ScopedProcessInformation process_info;
+  ASSERT_FALSE(process_info.IsValid());
+}
+
+TEST_F(ScopedProcessInformationTest, Receive) {
+  base::win::ScopedProcessInformation process_info;
+  MockCreateProcess(&process_info);
+
+  EXPECT_TRUE(process_info.IsValid());
+  EXPECT_EQ(kProcessId, process_info.process_id());
+  EXPECT_EQ(kThreadId, process_info.thread_id());
+  EXPECT_EQ(kProcessHandle, process_info.process_handle());
+  EXPECT_EQ(kThreadHandle, process_info.thread_handle());
+  process_info.Take();
+}
+
+TEST_F(ScopedProcessInformationTest, TakeProcess) {
+  base::win::ScopedProcessInformation process_info;
+  MockCreateProcess(&process_info);
+
+  HANDLE process = process_info.TakeProcessHandle();
+  EXPECT_EQ(kProcessHandle, process);
+  EXPECT_EQ(NULL, process_info.process_handle());
+  EXPECT_EQ(0, process_info.process_id());
+  EXPECT_TRUE(process_info.IsValid());
+  process_info.Take();
+}
+
+TEST_F(ScopedProcessInformationTest, TakeThread) {
+  base::win::ScopedProcessInformation process_info;
+  MockCreateProcess(&process_info);
+
+  HANDLE thread = process_info.TakeThreadHandle();
+  EXPECT_EQ(kThreadHandle, thread);
+  EXPECT_EQ(NULL, process_info.thread_handle());
+  EXPECT_EQ(0, process_info.thread_id());
+  EXPECT_TRUE(process_info.IsValid());
+  process_info.Take();
+}
+
+TEST_F(ScopedProcessInformationTest, TakeBoth) {
+  base::win::ScopedProcessInformation process_info;
+  MockCreateProcess(&process_info);
+
+  process_info.TakeProcessHandle();
+  process_info.TakeThreadHandle();
+  EXPECT_FALSE(process_info.IsValid());
+  process_info.Take();
+}
+
+TEST_F(ScopedProcessInformationTest, TakeWholeStruct) {
+  base::win::ScopedProcessInformation process_info;
+  MockCreateProcess(&process_info);
+
+  PROCESS_INFORMATION to_discard = process_info.Take();
+  EXPECT_EQ(kProcessId, to_discard.dwProcessId);
+  EXPECT_EQ(kThreadId, to_discard.dwThreadId);
+  EXPECT_EQ(kProcessHandle, to_discard.hProcess);
+  EXPECT_EQ(kThreadHandle, to_discard.hThread);
+  EXPECT_FALSE(process_info.IsValid());
+}
+
+TEST_F(ScopedProcessInformationTest, Duplicate) {
+  PROCESS_INFORMATION temp_process_information;
+  DoCreateProcess("ReturnSeven", &temp_process_information);
+  base::win::ScopedProcessInformation process_info;
+  process_info.Set(temp_process_information);
+
+  base::win::ScopedProcessInformation duplicate;
+  duplicate.DuplicateFrom(process_info);
+
+  ASSERT_TRUE(process_info.IsValid());
+  ASSERT_NE(0u, process_info.process_id());
+  ASSERT_EQ(duplicate.process_id(), process_info.process_id());
+  ASSERT_NE(0u, process_info.thread_id());
+  ASSERT_EQ(duplicate.thread_id(), process_info.thread_id());
+
+  // Validate that we have separate handles that are good.
+  int exit_code = 0;
+  base::Process process(process_info.TakeProcessHandle());
+  ASSERT_TRUE(process.WaitForExit(&exit_code));
+  ASSERT_EQ(7, exit_code);
+
+  exit_code = 0;
+  base::Process dup_process(duplicate.TakeProcessHandle());
+  ASSERT_TRUE(dup_process.WaitForExit(&exit_code));
+  ASSERT_EQ(7, exit_code);
+
+  ASSERT_TRUE(::CloseHandle(process_info.TakeThreadHandle()));
+  ASSERT_TRUE(::CloseHandle(duplicate.TakeThreadHandle()));
+}
+
+TEST_F(ScopedProcessInformationTest, Set) {
+  base::win::ScopedProcessInformation base_process_info;
+  MockCreateProcess(&base_process_info);
+
+  PROCESS_INFORMATION base_struct = base_process_info.Take();
+
+  base::win::ScopedProcessInformation process_info;
+  process_info.Set(base_struct);
+
+  EXPECT_EQ(kProcessId, process_info.process_id());
+  EXPECT_EQ(kThreadId, process_info.thread_id());
+  EXPECT_EQ(kProcessHandle, process_info.process_handle());
+  EXPECT_EQ(kThreadHandle, process_info.thread_handle());
+  base_struct = process_info.Take();
+}
diff --git a/base/win/scoped_propvariant.h b/base/win/scoped_propvariant.h
new file mode 100644
index 0000000..62cc6a6
--- /dev/null
+++ b/base/win/scoped_propvariant.h
@@ -0,0 +1,58 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_WIN_SCOPED_PROPVARIANT_H_
+#define BASE_WIN_SCOPED_PROPVARIANT_H_
+
+#include <propidl.h>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+namespace base {
+namespace win {
+
+// A PROPVARIANT that is automatically initialized and cleared upon respective
+// construction and destruction of this class.
+class ScopedPropVariant {
+ public:
+  ScopedPropVariant() {
+    PropVariantInit(&pv_);
+  }
+
+  ~ScopedPropVariant() {
+    Reset();
+  }
+
+  // Returns a pointer to the underlying PROPVARIANT for use as an out param in
+  // a function call.
+  PROPVARIANT* Receive() {
+    DCHECK_EQ(pv_.vt, VT_EMPTY);
+    return &pv_;
+  }
+
+  // Clears the instance to prepare it for re-use (e.g., via Receive).
+  void Reset() {
+    if (pv_.vt != VT_EMPTY) {
+      HRESULT result = PropVariantClear(&pv_);
+      DCHECK_EQ(result, S_OK);
+    }
+  }
+
+  const PROPVARIANT& get() const { return pv_; }
+  const PROPVARIANT* ptr() const { return &pv_; }
+
+ private:
+  PROPVARIANT pv_;
+
+  // Comparison operators for ScopedPropVariant are not supported at this point.
+  bool operator==(const ScopedPropVariant&) const;
+  bool operator!=(const ScopedPropVariant&) const;
+  DISALLOW_COPY_AND_ASSIGN(ScopedPropVariant);
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_SCOPED_PROPVARIANT_H_
diff --git a/base/win/scoped_select_object.h b/base/win/scoped_select_object.h
new file mode 100644
index 0000000..347de79
--- /dev/null
+++ b/base/win/scoped_select_object.h
@@ -0,0 +1,43 @@
+// Copyright (c) 2011 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_WIN_SCOPED_SELECT_OBJECT_H_
+#define BASE_WIN_SCOPED_SELECT_OBJECT_H_
+
+#include <windows.h>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+namespace base {
+namespace win {
+
+// Helper class for deselecting object from DC.
+class ScopedSelectObject {
+ public:
+  ScopedSelectObject(HDC hdc, HGDIOBJ object)
+      : hdc_(hdc),
+        oldobj_(SelectObject(hdc, object)) {
+    DCHECK(hdc_);
+    DCHECK(object);
+    DCHECK(oldobj_ != NULL && oldobj_ != HGDI_ERROR);
+  }
+
+  ~ScopedSelectObject() {
+    HGDIOBJ object = SelectObject(hdc_, oldobj_);
+    DCHECK((GetObjectType(oldobj_) != OBJ_REGION && object != NULL) ||
+           (GetObjectType(oldobj_) == OBJ_REGION && object != HGDI_ERROR));
+  }
+
+ private:
+  HDC hdc_;
+  HGDIOBJ oldobj_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedSelectObject);
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_SCOPED_SELECT_OBJECT_H_
diff --git a/base/win/scoped_variant.cc b/base/win/scoped_variant.cc
new file mode 100644
index 0000000..f57ab93
--- /dev/null
+++ b/base/win/scoped_variant.cc
@@ -0,0 +1,276 @@
+// Copyright (c) 2010 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/win/scoped_variant.h"
+#include "base/logging.h"
+
+namespace base {
+namespace win {
+
+// Global, const instance of an empty variant.
+const VARIANT ScopedVariant::kEmptyVariant = { VT_EMPTY };
+
+ScopedVariant::~ScopedVariant() {
+  COMPILE_ASSERT(sizeof(ScopedVariant) == sizeof(VARIANT), ScopedVariantSize);
+  ::VariantClear(&var_);
+}
+
+ScopedVariant::ScopedVariant(const wchar_t* str) {
+  var_.vt = VT_EMPTY;
+  Set(str);
+}
+
+ScopedVariant::ScopedVariant(const wchar_t* str, UINT length) {
+  var_.vt = VT_BSTR;
+  var_.bstrVal = ::SysAllocStringLen(str, length);
+}
+
+ScopedVariant::ScopedVariant(int value, VARTYPE vt) {
+  var_.vt = vt;
+  var_.lVal = value;
+}
+
+ScopedVariant::ScopedVariant(double value, VARTYPE vt) {
+  DCHECK(vt == VT_R8 || vt == VT_DATE);
+  var_.vt = vt;
+  var_.dblVal = value;
+}
+
+ScopedVariant::ScopedVariant(IDispatch* dispatch) {
+  var_.vt = VT_EMPTY;
+  Set(dispatch);
+}
+
+ScopedVariant::ScopedVariant(IUnknown* unknown) {
+  var_.vt = VT_EMPTY;
+  Set(unknown);
+}
+
+ScopedVariant::ScopedVariant(SAFEARRAY* safearray) {
+  var_.vt = VT_EMPTY;
+  Set(safearray);
+}
+
+ScopedVariant::ScopedVariant(const VARIANT& var) {
+  var_.vt = VT_EMPTY;
+  Set(var);
+}
+
+void ScopedVariant::Reset(const VARIANT& var) {
+  if (&var != &var_) {
+    ::VariantClear(&var_);
+    var_ = var;
+  }
+}
+
+VARIANT ScopedVariant::Release() {
+  VARIANT var = var_;
+  var_.vt = VT_EMPTY;
+  return var;
+}
+
+void ScopedVariant::Swap(ScopedVariant& var) {
+  VARIANT tmp = var_;
+  var_ = var.var_;
+  var.var_ = tmp;
+}
+
+VARIANT* ScopedVariant::Receive() {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "variant leak. type: " << var_.vt;
+  return &var_;
+}
+
+VARIANT ScopedVariant::Copy() const {
+  VARIANT ret = { VT_EMPTY };
+  ::VariantCopy(&ret, &var_);
+  return ret;
+}
+
+int ScopedVariant::Compare(const VARIANT& var, bool ignore_case) const {
+  ULONG flags = ignore_case ? NORM_IGNORECASE : 0;
+  HRESULT hr = ::VarCmp(const_cast<VARIANT*>(&var_), const_cast<VARIANT*>(&var),
+                        LOCALE_USER_DEFAULT, flags);
+  int ret = 0;
+
+  switch (hr) {
+    case VARCMP_LT:
+      ret = -1;
+      break;
+
+    case VARCMP_GT:
+    case VARCMP_NULL:
+      ret = 1;
+      break;
+
+    default:
+      // Equal.
+      break;
+  }
+
+  return ret;
+}
+
+void ScopedVariant::Set(const wchar_t* str) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_BSTR;
+  var_.bstrVal = ::SysAllocString(str);
+}
+
+void ScopedVariant::Set(int8 i8) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_I1;
+  var_.cVal = i8;
+}
+
+void ScopedVariant::Set(uint8 ui8) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_UI1;
+  var_.bVal = ui8;
+}
+
+void ScopedVariant::Set(int16 i16) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_I2;
+  var_.iVal = i16;
+}
+
+void ScopedVariant::Set(uint16 ui16) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_UI2;
+  var_.uiVal = ui16;
+}
+
+void ScopedVariant::Set(int32 i32) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_I4;
+  var_.lVal = i32;
+}
+
+void ScopedVariant::Set(uint32 ui32) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_UI4;
+  var_.ulVal = ui32;
+}
+
+void ScopedVariant::Set(int64 i64) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_I8;
+  var_.llVal = i64;
+}
+
+void ScopedVariant::Set(uint64 ui64) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_UI8;
+  var_.ullVal = ui64;
+}
+
+void ScopedVariant::Set(float r32) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_R4;
+  var_.fltVal = r32;
+}
+
+void ScopedVariant::Set(double r64) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_R8;
+  var_.dblVal = r64;
+}
+
+void ScopedVariant::SetDate(DATE date) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_DATE;
+  var_.date = date;
+}
+
+void ScopedVariant::Set(IDispatch* disp) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_DISPATCH;
+  var_.pdispVal = disp;
+  if (disp)
+    disp->AddRef();
+}
+
+void ScopedVariant::Set(bool b) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_BOOL;
+  var_.boolVal = b ? VARIANT_TRUE : VARIANT_FALSE;
+}
+
+void ScopedVariant::Set(IUnknown* unk) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  var_.vt = VT_UNKNOWN;
+  var_.punkVal = unk;
+  if (unk)
+    unk->AddRef();
+}
+
+void ScopedVariant::Set(SAFEARRAY* array) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  if (SUCCEEDED(::SafeArrayGetVartype(array, &var_.vt))) {
+    var_.vt |= VT_ARRAY;
+    var_.parray = array;
+  } else {
+    DCHECK(!array) << "Unable to determine safearray vartype";
+    var_.vt = VT_EMPTY;
+  }
+}
+
+void ScopedVariant::Set(const VARIANT& var) {
+  DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
+  if (FAILED(::VariantCopy(&var_, &var))) {
+    DLOG(ERROR) << "VariantCopy failed";
+    var_.vt = VT_EMPTY;
+  }
+}
+
+ScopedVariant& ScopedVariant::operator=(const VARIANT& var) {
+  if (&var != &var_) {
+    VariantClear(&var_);
+    Set(var);
+  }
+  return *this;
+}
+
+bool ScopedVariant::IsLeakableVarType(VARTYPE vt) {
+  bool leakable = false;
+  switch (vt & VT_TYPEMASK) {
+    case VT_BSTR:
+    case VT_DISPATCH:
+    // we treat VT_VARIANT as leakable to err on the safe side.
+    case VT_VARIANT:
+    case VT_UNKNOWN:
+    case VT_SAFEARRAY:
+
+    // very rarely used stuff (if ever):
+    case VT_VOID:
+    case VT_PTR:
+    case VT_CARRAY:
+    case VT_USERDEFINED:
+    case VT_LPSTR:
+    case VT_LPWSTR:
+    case VT_RECORD:
+    case VT_INT_PTR:
+    case VT_UINT_PTR:
+    case VT_FILETIME:
+    case VT_BLOB:
+    case VT_STREAM:
+    case VT_STORAGE:
+    case VT_STREAMED_OBJECT:
+    case VT_STORED_OBJECT:
+    case VT_BLOB_OBJECT:
+    case VT_VERSIONED_STREAM:
+    case VT_BSTR_BLOB:
+      leakable = true;
+      break;
+  }
+
+  if (!leakable && (vt & VT_ARRAY) != 0) {
+    leakable = true;
+  }
+
+  return leakable;
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/scoped_variant.h b/base/win/scoped_variant.h
new file mode 100644
index 0000000..322fcf7
--- /dev/null
+++ b/base/win/scoped_variant.h
@@ -0,0 +1,164 @@
+// Copyright (c) 2011 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_WIN_SCOPED_VARIANT_H_
+#define BASE_WIN_SCOPED_VARIANT_H_
+
+#include <windows.h>
+#include <oleauto.h>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace win {
+
+// Scoped VARIANT class for automatically freeing a COM VARIANT at the
+// end of a scope.  Additionally provides a few functions to make the
+// encapsulated VARIANT easier to use.
+// Instead of inheriting from VARIANT, we take the containment approach
+// in order to have more control over the usage of the variant and guard
+// against memory leaks.
+class BASE_EXPORT ScopedVariant {
+ public:
+  // Declaration of a global variant variable that's always VT_EMPTY
+  static const VARIANT kEmptyVariant;
+
+  // Default constructor.
+  ScopedVariant() {
+    // This is equivalent to what VariantInit does, but less code.
+    var_.vt = VT_EMPTY;
+  }
+
+  // Constructor to create a new VT_BSTR VARIANT.
+  // NOTE: Do not pass a BSTR to this constructor expecting ownership to
+  // be transferred
+  explicit ScopedVariant(const wchar_t* str);
+
+  // Creates a new VT_BSTR variant of a specified length.
+  ScopedVariant(const wchar_t* str, UINT length);
+
+  // Creates a new integral type variant and assigns the value to
+  // VARIANT.lVal (32 bit sized field).
+  explicit ScopedVariant(int value, VARTYPE vt = VT_I4);
+
+  // Creates a new double-precision type variant.  |vt| must be either VT_R8
+  // or VT_DATE.
+  explicit ScopedVariant(double value, VARTYPE vt = VT_R8);
+
+  // VT_DISPATCH
+  explicit ScopedVariant(IDispatch* dispatch);
+
+  // VT_UNKNOWN
+  explicit ScopedVariant(IUnknown* unknown);
+
+  // SAFEARRAY
+  explicit ScopedVariant(SAFEARRAY* safearray);
+
+  // Copies the variant.
+  explicit ScopedVariant(const VARIANT& var);
+
+  ~ScopedVariant();
+
+  inline VARTYPE type() const {
+    return var_.vt;
+  }
+
+  // Give ScopedVariant ownership over an already allocated VARIANT.
+  void Reset(const VARIANT& var = kEmptyVariant);
+
+  // Releases ownership of the VARIANT to the caller.
+  VARIANT Release();
+
+  // Swap two ScopedVariant's.
+  void Swap(ScopedVariant& var);
+
+  // Returns a copy of the variant.
+  VARIANT Copy() const;
+
+  // The return value is 0 if the variants are equal, 1 if this object is
+  // greater than |var|, -1 if it is smaller.
+  int Compare(const VARIANT& var, bool ignore_case = false) const;
+
+  // Retrieves the pointer address.
+  // Used to receive a VARIANT as an out argument (and take ownership).
+  // The function DCHECKs on the current value being empty/null.
+  // Usage: GetVariant(var.receive());
+  VARIANT* Receive();
+
+  void Set(const wchar_t* str);
+
+  // Setters for simple types.
+  void Set(int8 i8);
+  void Set(uint8 ui8);
+  void Set(int16 i16);
+  void Set(uint16 ui16);
+  void Set(int32 i32);
+  void Set(uint32 ui32);
+  void Set(int64 i64);
+  void Set(uint64 ui64);
+  void Set(float r32);
+  void Set(double r64);
+  void Set(bool b);
+
+  // Creates a copy of |var| and assigns as this instance's value.
+  // Note that this is different from the Reset() method that's used to
+  // free the current value and assume ownership.
+  void Set(const VARIANT& var);
+
+  // COM object setters
+  void Set(IDispatch* disp);
+  void Set(IUnknown* unk);
+
+  // SAFEARRAY support
+  void Set(SAFEARRAY* array);
+
+  // Special setter for DATE since DATE is a double and we already have
+  // a setter for double.
+  void SetDate(DATE date);
+
+  // Allows const access to the contained variant without DCHECKs etc.
+  // This support is necessary for the V_XYZ (e.g. V_BSTR) set of macros to
+  // work properly but still doesn't allow modifications since we want control
+  // over that.
+  const VARIANT* ptr() const { return &var_; }
+
+  // Like other scoped classes (e.g scoped_refptr, ScopedComPtr, ScopedBstr)
+  // we support the assignment operator for the type we wrap.
+  ScopedVariant& operator=(const VARIANT& var);
+
+  // A hack to pass a pointer to the variant where the accepting
+  // function treats the variant as an input-only, read-only value
+  // but the function prototype requires a non const variant pointer.
+  // There's no DCHECK or anything here.  Callers must know what they're doing.
+  VARIANT* AsInput() const {
+    // The nature of this function is const, so we declare
+    // it as such and cast away the constness here.
+    return const_cast<VARIANT*>(&var_);
+  }
+
+  // Allows the ScopedVariant instance to be passed to functions either by value
+  // or by const reference.
+  operator const VARIANT&() const {
+    return var_;
+  }
+
+  // Used as a debug check to see if we're leaking anything.
+  static bool IsLeakableVarType(VARTYPE vt);
+
+ protected:
+  VARIANT var_;
+
+ private:
+  // Comparison operators for ScopedVariant are not supported at this point.
+  // Use the Compare method instead.
+  bool operator==(const ScopedVariant& var) const;
+  bool operator!=(const ScopedVariant& var) const;
+  DISALLOW_COPY_AND_ASSIGN(ScopedVariant);
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_SCOPED_VARIANT_H_
diff --git a/base/win/scoped_variant_unittest.cc b/base/win/scoped_variant_unittest.cc
new file mode 100644
index 0000000..d530d5b
--- /dev/null
+++ b/base/win/scoped_variant_unittest.cc
@@ -0,0 +1,261 @@
+// Copyright (c) 2011 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/win/scoped_variant.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+static const wchar_t kTestString1[] = L"Used to create BSTRs";
+static const wchar_t kTestString2[] = L"Also used to create BSTRs";
+
+void GiveMeAVariant(VARIANT* ret) {
+  EXPECT_TRUE(ret != NULL);
+  ret->vt = VT_BSTR;
+  V_BSTR(ret) = ::SysAllocString(kTestString1);
+}
+
+// A dummy IDispatch implementation (if you can call it that).
+// The class does nothing intelligent really.  Only increments a counter
+// when AddRef is called and decrements it when Release is called.
+class FakeComObject : public IDispatch {
+ public:
+  FakeComObject() : ref_(0) {
+  }
+
+  STDMETHOD_(DWORD, AddRef)() override {
+    ref_++;
+    return ref_;
+  }
+
+  STDMETHOD_(DWORD, Release)() override {
+    ref_--;
+    return ref_;
+  }
+
+  STDMETHOD(QueryInterface)(REFIID, void**) override { return E_NOTIMPL; }
+
+  STDMETHOD(GetTypeInfoCount)(UINT*) override { return E_NOTIMPL; }
+
+  STDMETHOD(GetTypeInfo)(UINT, LCID, ITypeInfo**) override { return E_NOTIMPL; }
+
+  STDMETHOD(GetIDsOfNames)(REFIID, LPOLESTR*, UINT, LCID, DISPID*) override {
+    return E_NOTIMPL;
+  }
+
+  STDMETHOD(Invoke)(DISPID,
+                    REFIID,
+                    LCID,
+                    WORD,
+                    DISPPARAMS*,
+                    VARIANT*,
+                    EXCEPINFO*,
+                    UINT*) override {
+    return E_NOTIMPL;
+  }
+
+  // A way to check the internal reference count of the class.
+  int ref_count() const {
+    return ref_;
+  }
+
+ protected:
+  int ref_;
+};
+
+}  // namespace
+
+TEST(ScopedVariantTest, ScopedVariant) {
+  ScopedVariant var;
+  EXPECT_TRUE(var.type() == VT_EMPTY);
+  // V_BSTR(var.ptr()) = NULL;  <- NOTE: Assignment like that is not supported.
+
+  ScopedVariant var_bstr(L"VT_BSTR");
+  EXPECT_EQ(VT_BSTR, V_VT(var_bstr.ptr()));
+  EXPECT_TRUE(V_BSTR(var_bstr.ptr()) != NULL);  // can't use EXPECT_NE for BSTR
+  var_bstr.Reset();
+  EXPECT_NE(VT_BSTR, V_VT(var_bstr.ptr()));
+  var_bstr.Set(kTestString2);
+  EXPECT_EQ(VT_BSTR, V_VT(var_bstr.ptr()));
+
+  VARIANT tmp = var_bstr.Release();
+  EXPECT_EQ(VT_EMPTY, V_VT(var_bstr.ptr()));
+  EXPECT_EQ(VT_BSTR, V_VT(&tmp));
+  EXPECT_EQ(0, lstrcmp(V_BSTR(&tmp), kTestString2));
+
+  var.Reset(tmp);
+  EXPECT_EQ(VT_BSTR, V_VT(var.ptr()));
+  EXPECT_EQ(0, lstrcmpW(V_BSTR(var.ptr()), kTestString2));
+
+  var_bstr.Swap(var);
+  EXPECT_EQ(VT_EMPTY, V_VT(var.ptr()));
+  EXPECT_EQ(VT_BSTR, V_VT(var_bstr.ptr()));
+  EXPECT_EQ(0, lstrcmpW(V_BSTR(var_bstr.ptr()), kTestString2));
+  var_bstr.Reset();
+
+  // Test the Compare and Copy routines.
+  GiveMeAVariant(var_bstr.Receive());
+  ScopedVariant var_bstr2(V_BSTR(var_bstr.ptr()));
+  EXPECT_EQ(0, var_bstr.Compare(var_bstr2));
+  var_bstr2.Reset();
+  EXPECT_NE(0, var_bstr.Compare(var_bstr2));
+  var_bstr2.Reset(var_bstr.Copy());
+  EXPECT_EQ(0, var_bstr.Compare(var_bstr2));
+  var_bstr2.Reset();
+  var_bstr2.Set(V_BSTR(var_bstr.ptr()));
+  EXPECT_EQ(0, var_bstr.Compare(var_bstr2));
+  var_bstr2.Reset();
+  var_bstr.Reset();
+
+  // Test for the SetDate setter.
+  SYSTEMTIME sys_time;
+  ::GetSystemTime(&sys_time);
+  DATE date;
+  ::SystemTimeToVariantTime(&sys_time, &date);
+  var.Reset();
+  var.SetDate(date);
+  EXPECT_EQ(VT_DATE, var.type());
+  EXPECT_EQ(date, V_DATE(var.ptr()));
+
+  // Simple setter tests.  These do not require resetting the variant
+  // after each test since the variant type is not "leakable" (i.e. doesn't
+  // need to be freed explicitly).
+
+  // We need static cast here since char defaults to int (!?).
+  var.Set(static_cast<int8>('v'));
+  EXPECT_EQ(VT_I1, var.type());
+  EXPECT_EQ('v', V_I1(var.ptr()));
+
+  var.Set(static_cast<short>(123));
+  EXPECT_EQ(VT_I2, var.type());
+  EXPECT_EQ(123, V_I2(var.ptr()));
+
+  var.Set(static_cast<int32>(123));
+  EXPECT_EQ(VT_I4, var.type());
+  EXPECT_EQ(123, V_I4(var.ptr()));
+
+  var.Set(static_cast<int64>(123));
+  EXPECT_EQ(VT_I8, var.type());
+  EXPECT_EQ(123, V_I8(var.ptr()));
+
+  var.Set(static_cast<uint8>(123));
+  EXPECT_EQ(VT_UI1, var.type());
+  EXPECT_EQ(123, V_UI1(var.ptr()));
+
+  var.Set(static_cast<unsigned short>(123));
+  EXPECT_EQ(VT_UI2, var.type());
+  EXPECT_EQ(123, V_UI2(var.ptr()));
+
+  var.Set(static_cast<uint32>(123));
+  EXPECT_EQ(VT_UI4, var.type());
+  EXPECT_EQ(123, V_UI4(var.ptr()));
+
+  var.Set(static_cast<uint64>(123));
+  EXPECT_EQ(VT_UI8, var.type());
+  EXPECT_EQ(123, V_UI8(var.ptr()));
+
+  var.Set(123.123f);
+  EXPECT_EQ(VT_R4, var.type());
+  EXPECT_EQ(123.123f, V_R4(var.ptr()));
+
+  var.Set(static_cast<double>(123.123));
+  EXPECT_EQ(VT_R8, var.type());
+  EXPECT_EQ(123.123, V_R8(var.ptr()));
+
+  var.Set(true);
+  EXPECT_EQ(VT_BOOL, var.type());
+  EXPECT_EQ(VARIANT_TRUE, V_BOOL(var.ptr()));
+  var.Set(false);
+  EXPECT_EQ(VT_BOOL, var.type());
+  EXPECT_EQ(VARIANT_FALSE, V_BOOL(var.ptr()));
+
+  // Com interface tests
+
+  var.Set(static_cast<IDispatch*>(NULL));
+  EXPECT_EQ(VT_DISPATCH, var.type());
+  EXPECT_EQ(NULL, V_DISPATCH(var.ptr()));
+  var.Reset();
+
+  var.Set(static_cast<IUnknown*>(NULL));
+  EXPECT_EQ(VT_UNKNOWN, var.type());
+  EXPECT_EQ(NULL, V_UNKNOWN(var.ptr()));
+  var.Reset();
+
+  FakeComObject faker;
+  EXPECT_EQ(0, faker.ref_count());
+  var.Set(static_cast<IDispatch*>(&faker));
+  EXPECT_EQ(VT_DISPATCH, var.type());
+  EXPECT_EQ(&faker, V_DISPATCH(var.ptr()));
+  EXPECT_EQ(1, faker.ref_count());
+  var.Reset();
+  EXPECT_EQ(0, faker.ref_count());
+
+  var.Set(static_cast<IUnknown*>(&faker));
+  EXPECT_EQ(VT_UNKNOWN, var.type());
+  EXPECT_EQ(&faker, V_UNKNOWN(var.ptr()));
+  EXPECT_EQ(1, faker.ref_count());
+  var.Reset();
+  EXPECT_EQ(0, faker.ref_count());
+
+  {
+    ScopedVariant disp_var(&faker);
+    EXPECT_EQ(VT_DISPATCH, disp_var.type());
+    EXPECT_EQ(&faker, V_DISPATCH(disp_var.ptr()));
+    EXPECT_EQ(1, faker.ref_count());
+  }
+  EXPECT_EQ(0, faker.ref_count());
+
+  {
+    ScopedVariant ref1(&faker);
+    EXPECT_EQ(1, faker.ref_count());
+    ScopedVariant ref2(static_cast<const VARIANT&>(ref1));
+    EXPECT_EQ(2, faker.ref_count());
+    ScopedVariant ref3;
+    ref3 = static_cast<const VARIANT&>(ref2);
+    EXPECT_EQ(3, faker.ref_count());
+  }
+  EXPECT_EQ(0, faker.ref_count());
+
+  {
+    ScopedVariant unk_var(static_cast<IUnknown*>(&faker));
+    EXPECT_EQ(VT_UNKNOWN, unk_var.type());
+    EXPECT_EQ(&faker, V_UNKNOWN(unk_var.ptr()));
+    EXPECT_EQ(1, faker.ref_count());
+  }
+  EXPECT_EQ(0, faker.ref_count());
+
+  VARIANT raw;
+  raw.vt = VT_UNKNOWN;
+  raw.punkVal = &faker;
+  EXPECT_EQ(0, faker.ref_count());
+  var.Set(raw);
+  EXPECT_EQ(1, faker.ref_count());
+  var.Reset();
+  EXPECT_EQ(0, faker.ref_count());
+
+  {
+    ScopedVariant number(123);
+    EXPECT_EQ(VT_I4, number.type());
+    EXPECT_EQ(123, V_I4(number.ptr()));
+  }
+
+  // SAFEARRAY tests
+  var.Set(static_cast<SAFEARRAY*>(NULL));
+  EXPECT_EQ(VT_EMPTY, var.type());
+
+  SAFEARRAY* sa = ::SafeArrayCreateVector(VT_UI1, 0, 100);
+  ASSERT_TRUE(sa != NULL);
+
+  var.Set(sa);
+  EXPECT_TRUE(ScopedVariant::IsLeakableVarType(var.type()));
+  EXPECT_EQ(VT_ARRAY | VT_UI1, var.type());
+  EXPECT_EQ(sa, V_ARRAY(var.ptr()));
+  // The array is destroyed in the destructor of var.
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/shortcut.cc b/base/win/shortcut.cc
new file mode 100644
index 0000000..f8b2182
--- /dev/null
+++ b/base/win/shortcut.cc
@@ -0,0 +1,342 @@
+// Copyright (c) 2012 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/win/shortcut.h"
+
+#include <shellapi.h>
+#include <shlobj.h>
+#include <propkey.h>
+
+#include "base/files/file_util.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/win/scoped_comptr.h"
+#include "base/win/scoped_propvariant.h"
+#include "base/win/win_util.h"
+#include "base/win/windows_version.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+// Initializes |i_shell_link| and |i_persist_file| (releasing them first if they
+// are already initialized).
+// If |shortcut| is not NULL, loads |shortcut| into |i_persist_file|.
+// If any of the above steps fail, both |i_shell_link| and |i_persist_file| will
+// be released.
+void InitializeShortcutInterfaces(
+    const wchar_t* shortcut,
+    ScopedComPtr<IShellLink>* i_shell_link,
+    ScopedComPtr<IPersistFile>* i_persist_file) {
+  i_shell_link->Release();
+  i_persist_file->Release();
+  if (FAILED(i_shell_link->CreateInstance(CLSID_ShellLink, NULL,
+                                          CLSCTX_INPROC_SERVER)) ||
+      FAILED(i_persist_file->QueryFrom(i_shell_link->get())) ||
+      (shortcut && FAILED((*i_persist_file)->Load(shortcut, STGM_READWRITE)))) {
+    i_shell_link->Release();
+    i_persist_file->Release();
+  }
+}
+
+}  // namespace
+
+ShortcutProperties::ShortcutProperties()
+    : icon_index(-1), dual_mode(false), options(0U) {
+}
+
+ShortcutProperties::~ShortcutProperties() {
+}
+
+bool CreateOrUpdateShortcutLink(const FilePath& shortcut_path,
+                                const ShortcutProperties& properties,
+                                ShortcutOperation operation) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  // A target is required unless |operation| is SHORTCUT_UPDATE_EXISTING.
+  if (operation != SHORTCUT_UPDATE_EXISTING &&
+      !(properties.options & ShortcutProperties::PROPERTIES_TARGET)) {
+    NOTREACHED();
+    return false;
+  }
+
+  bool shortcut_existed = PathExists(shortcut_path);
+
+  // Interfaces to the old shortcut when replacing an existing shortcut.
+  ScopedComPtr<IShellLink> old_i_shell_link;
+  ScopedComPtr<IPersistFile> old_i_persist_file;
+
+  // Interfaces to the shortcut being created/updated.
+  ScopedComPtr<IShellLink> i_shell_link;
+  ScopedComPtr<IPersistFile> i_persist_file;
+  switch (operation) {
+    case SHORTCUT_CREATE_ALWAYS:
+      InitializeShortcutInterfaces(NULL, &i_shell_link, &i_persist_file);
+      break;
+    case SHORTCUT_UPDATE_EXISTING:
+      InitializeShortcutInterfaces(shortcut_path.value().c_str(), &i_shell_link,
+                                   &i_persist_file);
+      break;
+    case SHORTCUT_REPLACE_EXISTING:
+      InitializeShortcutInterfaces(shortcut_path.value().c_str(),
+                                   &old_i_shell_link, &old_i_persist_file);
+      // Confirm |shortcut_path| exists and is a shortcut by verifying
+      // |old_i_persist_file| was successfully initialized in the call above. If
+      // so, initialize the interfaces to begin writing a new shortcut (to
+      // overwrite the current one if successful).
+      if (old_i_persist_file.get())
+        InitializeShortcutInterfaces(NULL, &i_shell_link, &i_persist_file);
+      break;
+    default:
+      NOTREACHED();
+  }
+
+  // Return false immediately upon failure to initialize shortcut interfaces.
+  if (!i_persist_file.get())
+    return false;
+
+  if ((properties.options & ShortcutProperties::PROPERTIES_TARGET) &&
+      FAILED(i_shell_link->SetPath(properties.target.value().c_str()))) {
+    return false;
+  }
+
+  if ((properties.options & ShortcutProperties::PROPERTIES_WORKING_DIR) &&
+      FAILED(i_shell_link->SetWorkingDirectory(
+          properties.working_dir.value().c_str()))) {
+    return false;
+  }
+
+  if (properties.options & ShortcutProperties::PROPERTIES_ARGUMENTS) {
+    if (FAILED(i_shell_link->SetArguments(properties.arguments.c_str())))
+      return false;
+  } else if (old_i_persist_file.get()) {
+    wchar_t current_arguments[MAX_PATH] = {0};
+    if (SUCCEEDED(old_i_shell_link->GetArguments(current_arguments,
+                                                 MAX_PATH))) {
+      i_shell_link->SetArguments(current_arguments);
+    }
+  }
+
+  if ((properties.options & ShortcutProperties::PROPERTIES_DESCRIPTION) &&
+      FAILED(i_shell_link->SetDescription(properties.description.c_str()))) {
+    return false;
+  }
+
+  if ((properties.options & ShortcutProperties::PROPERTIES_ICON) &&
+      FAILED(i_shell_link->SetIconLocation(properties.icon.value().c_str(),
+                                           properties.icon_index))) {
+    return false;
+  }
+
+  bool has_app_id =
+      (properties.options & ShortcutProperties::PROPERTIES_APP_ID) != 0;
+  bool has_dual_mode =
+      (properties.options & ShortcutProperties::PROPERTIES_DUAL_MODE) != 0;
+  if ((has_app_id || has_dual_mode) &&
+      GetVersion() >= VERSION_WIN7) {
+    ScopedComPtr<IPropertyStore> property_store;
+    if (FAILED(property_store.QueryFrom(i_shell_link.get())) ||
+        !property_store.get())
+      return false;
+
+    if (has_app_id &&
+        !SetAppIdForPropertyStore(property_store.get(),
+                                  properties.app_id.c_str())) {
+      return false;
+    }
+    if (has_dual_mode &&
+        !SetBooleanValueForPropertyStore(property_store.get(),
+                                         PKEY_AppUserModel_IsDualMode,
+                                         properties.dual_mode)) {
+      return false;
+    }
+  }
+
+  // Release the interfaces to the old shortcut to make sure it doesn't prevent
+  // overwriting it if needed.
+  old_i_persist_file.Release();
+  old_i_shell_link.Release();
+
+  HRESULT result = i_persist_file->Save(shortcut_path.value().c_str(), TRUE);
+
+  // Release the interfaces in case the SHChangeNotify call below depends on
+  // the operations above being fully completed.
+  i_persist_file.Release();
+  i_shell_link.Release();
+
+  // If we successfully created/updated the icon, notify the shell that we have
+  // done so.
+  const bool succeeded = SUCCEEDED(result);
+  if (succeeded) {
+    if (shortcut_existed) {
+      // TODO(gab): SHCNE_UPDATEITEM might be sufficient here; further testing
+      // required.
+      SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
+    } else {
+      SHChangeNotify(SHCNE_CREATE, SHCNF_PATH, shortcut_path.value().c_str(),
+                     NULL);
+    }
+  }
+
+  return succeeded;
+}
+
+bool ResolveShortcutProperties(const FilePath& shortcut_path,
+                               uint32 options,
+                               ShortcutProperties* properties) {
+  DCHECK(options && properties);
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  if (options & ~ShortcutProperties::PROPERTIES_ALL)
+    NOTREACHED() << "Unhandled property is used.";
+
+  ScopedComPtr<IShellLink> i_shell_link;
+
+  // Get pointer to the IShellLink interface.
+  if (FAILED(i_shell_link.CreateInstance(CLSID_ShellLink, NULL,
+                                         CLSCTX_INPROC_SERVER))) {
+    return false;
+  }
+
+  ScopedComPtr<IPersistFile> persist;
+  // Query IShellLink for the IPersistFile interface.
+  if (FAILED(persist.QueryFrom(i_shell_link.get())))
+    return false;
+
+  // Load the shell link.
+  if (FAILED(persist->Load(shortcut_path.value().c_str(), STGM_READ)))
+    return false;
+
+  // Reset |properties|.
+  properties->options = 0;
+
+  wchar_t temp[MAX_PATH];
+  if (options & ShortcutProperties::PROPERTIES_TARGET) {
+    if (FAILED(i_shell_link->GetPath(temp, MAX_PATH, NULL, SLGP_UNCPRIORITY)))
+      return false;
+    properties->set_target(FilePath(temp));
+  }
+
+  if (options & ShortcutProperties::PROPERTIES_WORKING_DIR) {
+    if (FAILED(i_shell_link->GetWorkingDirectory(temp, MAX_PATH)))
+      return false;
+    properties->set_working_dir(FilePath(temp));
+  }
+
+  if (options & ShortcutProperties::PROPERTIES_ARGUMENTS) {
+    if (FAILED(i_shell_link->GetArguments(temp, MAX_PATH)))
+      return false;
+    properties->set_arguments(temp);
+  }
+
+  if (options & ShortcutProperties::PROPERTIES_DESCRIPTION) {
+    // Note: description length constrained by MAX_PATH.
+    if (FAILED(i_shell_link->GetDescription(temp, MAX_PATH)))
+      return false;
+    properties->set_description(temp);
+  }
+
+  if (options & ShortcutProperties::PROPERTIES_ICON) {
+    int temp_index;
+    if (FAILED(i_shell_link->GetIconLocation(temp, MAX_PATH, &temp_index)))
+      return false;
+    properties->set_icon(FilePath(temp), temp_index);
+  }
+
+  // Windows 7+ options, avoiding unnecessary work.
+  if ((options & ShortcutProperties::PROPERTIES_WIN7) &&
+      GetVersion() >= VERSION_WIN7) {
+    ScopedComPtr<IPropertyStore> property_store;
+    if (FAILED(property_store.QueryFrom(i_shell_link.get())))
+      return false;
+
+    if (options & ShortcutProperties::PROPERTIES_APP_ID) {
+      ScopedPropVariant pv_app_id;
+      if (property_store->GetValue(PKEY_AppUserModel_ID,
+                                   pv_app_id.Receive()) != S_OK) {
+        return false;
+      }
+      switch (pv_app_id.get().vt) {
+        case VT_EMPTY:
+          properties->set_app_id(L"");
+          break;
+        case VT_LPWSTR:
+          properties->set_app_id(pv_app_id.get().pwszVal);
+          break;
+        default:
+          NOTREACHED() << "Unexpected variant type: " << pv_app_id.get().vt;
+          return false;
+      }
+    }
+
+    if (options & ShortcutProperties::PROPERTIES_DUAL_MODE) {
+      ScopedPropVariant pv_dual_mode;
+      if (property_store->GetValue(PKEY_AppUserModel_IsDualMode,
+                                   pv_dual_mode.Receive()) != S_OK) {
+        return false;
+      }
+      switch (pv_dual_mode.get().vt) {
+        case VT_EMPTY:
+          properties->set_dual_mode(false);
+          break;
+        case VT_BOOL:
+          properties->set_dual_mode(pv_dual_mode.get().boolVal == VARIANT_TRUE);
+          break;
+        default:
+          NOTREACHED() << "Unexpected variant type: " << pv_dual_mode.get().vt;
+          return false;
+      }
+    }
+  }
+
+  return true;
+}
+
+bool ResolveShortcut(const FilePath& shortcut_path,
+                     FilePath* target_path,
+                     string16* args) {
+  uint32 options = 0;
+  if (target_path)
+    options |= ShortcutProperties::PROPERTIES_TARGET;
+  if (args)
+    options |= ShortcutProperties::PROPERTIES_ARGUMENTS;
+  DCHECK(options);
+
+  ShortcutProperties properties;
+  if (!ResolveShortcutProperties(shortcut_path, options, &properties))
+    return false;
+
+  if (target_path)
+    *target_path = properties.target;
+  if (args)
+    *args = properties.arguments;
+  return true;
+}
+
+bool TaskbarPinShortcutLink(const wchar_t* shortcut) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  // "Pin to taskbar" is only supported after Win7.
+  if (GetVersion() < VERSION_WIN7)
+    return false;
+
+  intptr_t result = reinterpret_cast<intptr_t>(
+      ShellExecute(NULL, L"taskbarpin", shortcut, NULL, NULL, 0));
+  return result > 32;
+}
+
+bool TaskbarUnpinShortcutLink(const wchar_t* shortcut) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
+  // "Unpin from taskbar" is only supported after Win7.
+  if (GetVersion() < VERSION_WIN7)
+    return false;
+
+  intptr_t result = reinterpret_cast<intptr_t>(
+      ShellExecute(NULL, L"taskbarunpin", shortcut, NULL, NULL, 0));
+  return result > 32;
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/shortcut.h b/base/win/shortcut.h
new file mode 100644
index 0000000..6f7d10c
--- /dev/null
+++ b/base/win/shortcut.h
@@ -0,0 +1,168 @@
+// Copyright (c) 2012 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_WIN_SHORTCUT_H_
+#define BASE_WIN_SHORTCUT_H_
+
+#include <windows.h>
+
+#include "base/base_export.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/strings/string16.h"
+
+namespace base {
+namespace win {
+
+enum ShortcutOperation {
+  // Create a new shortcut (overwriting if necessary).
+  SHORTCUT_CREATE_ALWAYS = 0,
+  // Overwrite an existing shortcut (fails if the shortcut doesn't exist).
+  // If the arguments are not specified on the new shortcut, keep the old
+  // shortcut's arguments.
+  SHORTCUT_REPLACE_EXISTING,
+  // Update specified properties only on an existing shortcut.
+  SHORTCUT_UPDATE_EXISTING,
+};
+
+// Properties for shortcuts. Properties set will be applied to the shortcut on
+// creation/update, others will be ignored.
+// Callers are encouraged to use the setters provided which take care of
+// setting |options| as desired.
+struct BASE_EXPORT ShortcutProperties {
+  enum IndividualProperties {
+    PROPERTIES_TARGET = 1U << 0,
+    PROPERTIES_WORKING_DIR = 1U << 1,
+    PROPERTIES_ARGUMENTS = 1U << 2,
+    PROPERTIES_DESCRIPTION = 1U << 3,
+    PROPERTIES_ICON = 1U << 4,
+    PROPERTIES_APP_ID = 1U << 5,
+    PROPERTIES_DUAL_MODE = 1U << 6,
+    // Be sure to update the values below when adding a new property.
+    PROPERTIES_BASIC = PROPERTIES_TARGET |
+        PROPERTIES_WORKING_DIR |
+        PROPERTIES_ARGUMENTS |
+        PROPERTIES_DESCRIPTION |
+        PROPERTIES_ICON,
+    PROPERTIES_WIN7 = PROPERTIES_APP_ID | PROPERTIES_DUAL_MODE,
+    PROPERTIES_ALL = PROPERTIES_BASIC | PROPERTIES_WIN7
+  };
+
+  ShortcutProperties();
+  ~ShortcutProperties();
+
+  void set_target(const FilePath& target_in) {
+    target = target_in;
+    options |= PROPERTIES_TARGET;
+  }
+
+  void set_working_dir(const FilePath& working_dir_in) {
+    working_dir = working_dir_in;
+    options |= PROPERTIES_WORKING_DIR;
+  }
+
+  void set_arguments(const string16& arguments_in) {
+    // Size restriction as per MSDN at http://goo.gl/TJ7q5.
+    DCHECK(arguments_in.size() < MAX_PATH);
+    arguments = arguments_in;
+    options |= PROPERTIES_ARGUMENTS;
+  }
+
+  void set_description(const string16& description_in) {
+    // Size restriction as per MSDN at http://goo.gl/OdNQq.
+    DCHECK(description_in.size() < MAX_PATH);
+    description = description_in;
+    options |= PROPERTIES_DESCRIPTION;
+  }
+
+  void set_icon(const FilePath& icon_in, int icon_index_in) {
+    icon = icon_in;
+    icon_index = icon_index_in;
+    options |= PROPERTIES_ICON;
+  }
+
+  void set_app_id(const string16& app_id_in) {
+    app_id = app_id_in;
+    options |= PROPERTIES_APP_ID;
+  }
+
+  void set_dual_mode(bool dual_mode_in) {
+    dual_mode = dual_mode_in;
+    options |= PROPERTIES_DUAL_MODE;
+  }
+
+  // The target to launch from this shortcut. This is mandatory when creating
+  // a shortcut.
+  FilePath target;
+  // The name of the working directory when launching the shortcut.
+  FilePath working_dir;
+  // The arguments to be applied to |target| when launching from this shortcut.
+  // The length of this string must be less than MAX_PATH.
+  string16 arguments;
+  // The localized description of the shortcut.
+  // The length of this string must be less than MAX_PATH.
+  string16 description;
+  // The path to the icon (can be a dll or exe, in which case |icon_index| is
+  // the resource id).
+  FilePath icon;
+  int icon_index;
+  // The app model id for the shortcut (Win7+).
+  string16 app_id;
+  // Whether this is a dual mode shortcut (Win8+).
+  bool dual_mode;
+  // Bitfield made of IndividualProperties. Properties set in |options| will be
+  // set on the shortcut, others will be ignored.
+  uint32 options;
+};
+
+// This method creates (or updates) a shortcut link at |shortcut_path| using the
+// information given through |properties|.
+// Ensure you have initialized COM before calling into this function.
+// |operation|: a choice from the ShortcutOperation enum.
+// If |operation| is SHORTCUT_REPLACE_EXISTING or SHORTCUT_UPDATE_EXISTING and
+// |shortcut_path| does not exist, this method is a no-op and returns false.
+BASE_EXPORT bool CreateOrUpdateShortcutLink(
+    const FilePath& shortcut_path,
+    const ShortcutProperties& properties,
+    ShortcutOperation operation);
+
+// Resolves Windows shortcut (.LNK file).
+// This methods tries to resolve selected properties of a shortcut .LNK file.
+// The path of the shortcut to resolve is in |shortcut_path|. |options| is a bit
+// field composed of ShortcutProperties::IndividualProperties, to specify which
+// properties to read. It should be non-0. The resulting data are read into
+// |properties|, which must not be NULL. Note: PROPERTIES_TARGET will retrieve
+// the target path as stored in the shortcut but won't attempt to resolve that
+// path so it may not be valid. The function returns true if all requested
+// properties are successfully read. Otherwise some reads have failed and
+// intermediate values written to |properties| should be ignored.
+BASE_EXPORT bool ResolveShortcutProperties(const FilePath& shortcut_path,
+                                           uint32 options,
+                                           ShortcutProperties* properties);
+
+// Resolves Windows shortcut (.LNK file).
+// This is a wrapper to ResolveShortcutProperties() to handle the common use
+// case of resolving target and arguments. |target_path| and |args| are
+// optional output variables that are ignored if NULL (but at least one must be
+// non-NULL). The function returns true if all requested fields are found
+// successfully. Callers can safely use the same variable for both
+// |shortcut_path| and |target_path|.
+BASE_EXPORT bool ResolveShortcut(const FilePath& shortcut_path,
+                                 FilePath* target_path,
+                                 string16* args);
+
+// Pins a shortcut to the Windows 7 taskbar. The shortcut file must already
+// exist and be a shortcut that points to an executable. The app id of the
+// shortcut is used to group windows and must be set correctly.
+BASE_EXPORT bool TaskbarPinShortcutLink(const wchar_t* shortcut);
+
+// Unpins a shortcut from the Windows 7 taskbar. The shortcut must exist and
+// already be pinned to the taskbar. The app id of the shortcut is used as the
+// identifier for the taskbar item to remove and must be set correctly.
+BASE_EXPORT bool TaskbarUnpinShortcutLink(const wchar_t* shortcut);
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_SHORTCUT_H_
diff --git a/base/win/shortcut_unittest.cc b/base/win/shortcut_unittest.cc
new file mode 100644
index 0000000..794be23
--- /dev/null
+++ b/base/win/shortcut_unittest.cc
@@ -0,0 +1,322 @@
+// Copyright (c) 2012 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/win/shortcut.h"
+
+#include <string>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/test/test_file_util.h"
+#include "base/test/test_shortcut_win.h"
+#include "base/win/scoped_com_initializer.h"
+#include "base/win/windows_version.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+static const char kFileContents[] = "This is a target.";
+static const char kFileContents2[] = "This is another target.";
+
+class ShortcutTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+    ASSERT_TRUE(temp_dir_2_.CreateUniqueTempDir());
+
+    link_file_ = temp_dir_.path().Append(L"My Link.lnk");
+
+    // Shortcut 1's properties
+    {
+      const FilePath target_file(temp_dir_.path().Append(L"Target 1.txt"));
+      WriteFile(target_file, kFileContents, arraysize(kFileContents));
+
+      link_properties_.set_target(target_file);
+      link_properties_.set_working_dir(temp_dir_.path());
+      link_properties_.set_arguments(L"--magic --awesome");
+      link_properties_.set_description(L"Chrome is awesome.");
+      link_properties_.set_icon(link_properties_.target, 4);
+      link_properties_.set_app_id(L"Chrome");
+      link_properties_.set_dual_mode(false);
+    }
+
+    // Shortcut 2's properties (all different from properties of shortcut 1).
+    {
+      const FilePath target_file_2(temp_dir_.path().Append(L"Target 2.txt"));
+      WriteFile(target_file_2, kFileContents2, arraysize(kFileContents2));
+
+      FilePath icon_path_2;
+      CreateTemporaryFileInDir(temp_dir_.path(), &icon_path_2);
+
+      link_properties_2_.set_target(target_file_2);
+      link_properties_2_.set_working_dir(temp_dir_2_.path());
+      link_properties_2_.set_arguments(L"--super --crazy");
+      link_properties_2_.set_description(L"The best in the west.");
+      link_properties_2_.set_icon(icon_path_2, 0);
+      link_properties_2_.set_app_id(L"Chrome.UserLevelCrazySuffix");
+      link_properties_2_.set_dual_mode(true);
+    }
+  }
+
+  ScopedCOMInitializer com_initializer_;
+  ScopedTempDir temp_dir_;
+  ScopedTempDir temp_dir_2_;
+
+  // The link file to be created/updated in the shortcut tests below.
+  FilePath link_file_;
+
+  // Properties for the created shortcut.
+  ShortcutProperties link_properties_;
+
+  // Properties for the updated shortcut.
+  ShortcutProperties link_properties_2_;
+};
+
+}  // namespace
+
+TEST_F(ShortcutTest, CreateAndResolveShortcutProperties) {
+  uint32 valid_properties = ShortcutProperties::PROPERTIES_BASIC;
+  if (GetVersion() >= VERSION_WIN7)
+    valid_properties |= ShortcutProperties::PROPERTIES_WIN7;
+
+  // Test all properties.
+  FilePath file_1(temp_dir_.path().Append(L"Link1.lnk"));
+  ASSERT_TRUE(CreateOrUpdateShortcutLink(
+      file_1, link_properties_, SHORTCUT_CREATE_ALWAYS));
+
+  ShortcutProperties properties_read_1;
+  ASSERT_TRUE(ResolveShortcutProperties(
+      file_1, ShortcutProperties::PROPERTIES_ALL, &properties_read_1));
+  EXPECT_EQ(valid_properties, properties_read_1.options);
+  ValidatePathsAreEqual(link_properties_.target, properties_read_1.target);
+  ValidatePathsAreEqual(link_properties_.working_dir,
+                        properties_read_1.working_dir);
+  EXPECT_EQ(link_properties_.arguments, properties_read_1.arguments);
+  EXPECT_EQ(link_properties_.description, properties_read_1.description);
+  ValidatePathsAreEqual(link_properties_.icon, properties_read_1.icon);
+  EXPECT_EQ(link_properties_.icon_index, properties_read_1.icon_index);
+  if (GetVersion() >= VERSION_WIN7) {
+    EXPECT_EQ(link_properties_.app_id, properties_read_1.app_id);
+    EXPECT_EQ(link_properties_.dual_mode, properties_read_1.dual_mode);
+  }
+
+  // Test simple shortcut with no special properties set.
+  FilePath file_2(temp_dir_.path().Append(L"Link2.lnk"));
+  ShortcutProperties only_target_properties;
+  only_target_properties.set_target(link_properties_.target);
+  ASSERT_TRUE(CreateOrUpdateShortcutLink(
+      file_2, only_target_properties, SHORTCUT_CREATE_ALWAYS));
+
+  ShortcutProperties properties_read_2;
+  ASSERT_TRUE(ResolveShortcutProperties(
+      file_2, ShortcutProperties::PROPERTIES_ALL, &properties_read_2));
+  EXPECT_EQ(valid_properties, properties_read_2.options);
+  ValidatePathsAreEqual(only_target_properties.target,
+                        properties_read_2.target);
+  ValidatePathsAreEqual(FilePath(), properties_read_2.working_dir);
+  EXPECT_EQ(L"", properties_read_2.arguments);
+  EXPECT_EQ(L"", properties_read_2.description);
+  ValidatePathsAreEqual(FilePath(), properties_read_2.icon);
+  EXPECT_EQ(0, properties_read_2.icon_index);
+  if (GetVersion() >= VERSION_WIN7) {
+    EXPECT_EQ(L"", properties_read_2.app_id);
+    EXPECT_FALSE(properties_read_2.dual_mode);
+  }
+}
+
+TEST_F(ShortcutTest, CreateAndResolveShortcut) {
+  ShortcutProperties only_target_properties;
+  only_target_properties.set_target(link_properties_.target);
+
+  ASSERT_TRUE(CreateOrUpdateShortcutLink(
+      link_file_, only_target_properties, SHORTCUT_CREATE_ALWAYS));
+
+  FilePath resolved_name;
+  EXPECT_TRUE(ResolveShortcut(link_file_, &resolved_name, NULL));
+
+  char read_contents[arraysize(kFileContents)];
+  base::ReadFile(resolved_name, read_contents, arraysize(read_contents));
+  EXPECT_STREQ(kFileContents, read_contents);
+}
+
+TEST_F(ShortcutTest, ResolveShortcutWithArgs) {
+  ASSERT_TRUE(CreateOrUpdateShortcutLink(
+      link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS));
+
+  FilePath resolved_name;
+  string16 args;
+  EXPECT_TRUE(ResolveShortcut(link_file_, &resolved_name, &args));
+
+  char read_contents[arraysize(kFileContents)];
+  base::ReadFile(resolved_name, read_contents, arraysize(read_contents));
+  EXPECT_STREQ(kFileContents, read_contents);
+  EXPECT_EQ(link_properties_.arguments, args);
+}
+
+TEST_F(ShortcutTest, CreateShortcutWithOnlySomeProperties) {
+  ShortcutProperties target_and_args_properties;
+  target_and_args_properties.set_target(link_properties_.target);
+  target_and_args_properties.set_arguments(link_properties_.arguments);
+
+  ASSERT_TRUE(CreateOrUpdateShortcutLink(
+      link_file_, target_and_args_properties,
+      SHORTCUT_CREATE_ALWAYS));
+
+  ValidateShortcut(link_file_, target_and_args_properties);
+}
+
+TEST_F(ShortcutTest, CreateShortcutVerifyProperties) {
+  ASSERT_TRUE(CreateOrUpdateShortcutLink(
+      link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS));
+
+  ValidateShortcut(link_file_, link_properties_);
+}
+
+TEST_F(ShortcutTest, UpdateShortcutVerifyProperties) {
+  ASSERT_TRUE(CreateOrUpdateShortcutLink(
+      link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS));
+
+  ASSERT_TRUE(CreateOrUpdateShortcutLink(
+      link_file_, link_properties_2_, SHORTCUT_UPDATE_EXISTING));
+
+  ValidateShortcut(link_file_, link_properties_2_);
+}
+
+TEST_F(ShortcutTest, UpdateShortcutUpdateOnlyTargetAndResolve) {
+  ASSERT_TRUE(CreateOrUpdateShortcutLink(
+      link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS));
+
+  ShortcutProperties update_only_target_properties;
+  update_only_target_properties.set_target(link_properties_2_.target);
+
+  ASSERT_TRUE(CreateOrUpdateShortcutLink(
+      link_file_, update_only_target_properties,
+      SHORTCUT_UPDATE_EXISTING));
+
+  ShortcutProperties expected_properties = link_properties_;
+  expected_properties.set_target(link_properties_2_.target);
+  ValidateShortcut(link_file_, expected_properties);
+
+  FilePath resolved_name;
+  EXPECT_TRUE(ResolveShortcut(link_file_, &resolved_name, NULL));
+
+  char read_contents[arraysize(kFileContents2)];
+  base::ReadFile(resolved_name, read_contents, arraysize(read_contents));
+  EXPECT_STREQ(kFileContents2, read_contents);
+}
+
+TEST_F(ShortcutTest, UpdateShortcutMakeDualMode) {
+  ASSERT_TRUE(CreateOrUpdateShortcutLink(
+      link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS));
+
+  ShortcutProperties make_dual_mode_properties;
+  make_dual_mode_properties.set_dual_mode(true);
+
+  ASSERT_TRUE(CreateOrUpdateShortcutLink(
+      link_file_, make_dual_mode_properties,
+      SHORTCUT_UPDATE_EXISTING));
+
+  ShortcutProperties expected_properties = link_properties_;
+  expected_properties.set_dual_mode(true);
+  ValidateShortcut(link_file_, expected_properties);
+}
+
+TEST_F(ShortcutTest, UpdateShortcutRemoveDualMode) {
+  ASSERT_TRUE(CreateOrUpdateShortcutLink(
+      link_file_, link_properties_2_, SHORTCUT_CREATE_ALWAYS));
+
+  ShortcutProperties remove_dual_mode_properties;
+  remove_dual_mode_properties.set_dual_mode(false);
+
+  ASSERT_TRUE(CreateOrUpdateShortcutLink(
+      link_file_, remove_dual_mode_properties,
+      SHORTCUT_UPDATE_EXISTING));
+
+  ShortcutProperties expected_properties = link_properties_2_;
+  expected_properties.set_dual_mode(false);
+  ValidateShortcut(link_file_, expected_properties);
+}
+
+TEST_F(ShortcutTest, UpdateShortcutClearArguments) {
+  ASSERT_TRUE(CreateOrUpdateShortcutLink(
+      link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS));
+
+  ShortcutProperties clear_arguments_properties;
+  clear_arguments_properties.set_arguments(string16());
+
+  ASSERT_TRUE(CreateOrUpdateShortcutLink(
+      link_file_, clear_arguments_properties,
+      SHORTCUT_UPDATE_EXISTING));
+
+  ShortcutProperties expected_properties = link_properties_;
+  expected_properties.set_arguments(string16());
+  ValidateShortcut(link_file_, expected_properties);
+}
+
+TEST_F(ShortcutTest, FailUpdateShortcutThatDoesNotExist) {
+  ASSERT_FALSE(CreateOrUpdateShortcutLink(
+      link_file_, link_properties_, SHORTCUT_UPDATE_EXISTING));
+  ASSERT_FALSE(PathExists(link_file_));
+}
+
+TEST_F(ShortcutTest, ReplaceShortcutAllProperties) {
+  ASSERT_TRUE(CreateOrUpdateShortcutLink(
+      link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS));
+
+  ASSERT_TRUE(CreateOrUpdateShortcutLink(
+      link_file_, link_properties_2_, SHORTCUT_REPLACE_EXISTING));
+
+  ValidateShortcut(link_file_, link_properties_2_);
+}
+
+TEST_F(ShortcutTest, ReplaceShortcutSomeProperties) {
+  ASSERT_TRUE(CreateOrUpdateShortcutLink(
+      link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS));
+
+  ShortcutProperties new_properties;
+  new_properties.set_target(link_properties_2_.target);
+  new_properties.set_arguments(link_properties_2_.arguments);
+  new_properties.set_description(link_properties_2_.description);
+  ASSERT_TRUE(CreateOrUpdateShortcutLink(
+      link_file_, new_properties, SHORTCUT_REPLACE_EXISTING));
+
+  // Expect only properties in |new_properties| to be set, all other properties
+  // should have been overwritten.
+  ShortcutProperties expected_properties(new_properties);
+  expected_properties.set_working_dir(FilePath());
+  expected_properties.set_icon(FilePath(), 0);
+  expected_properties.set_app_id(string16());
+  expected_properties.set_dual_mode(false);
+  ValidateShortcut(link_file_, expected_properties);
+}
+
+TEST_F(ShortcutTest, FailReplaceShortcutThatDoesNotExist) {
+  ASSERT_FALSE(CreateOrUpdateShortcutLink(
+      link_file_, link_properties_, SHORTCUT_REPLACE_EXISTING));
+  ASSERT_FALSE(PathExists(link_file_));
+}
+
+// Test that the old arguments remain on the replaced shortcut when not
+// otherwise specified.
+TEST_F(ShortcutTest, ReplaceShortcutKeepOldArguments) {
+  ASSERT_TRUE(CreateOrUpdateShortcutLink(
+      link_file_, link_properties_, SHORTCUT_CREATE_ALWAYS));
+
+  // Do not explicitly set the arguments.
+  link_properties_2_.options &=
+      ~ShortcutProperties::PROPERTIES_ARGUMENTS;
+  ASSERT_TRUE(CreateOrUpdateShortcutLink(
+      link_file_, link_properties_2_, SHORTCUT_REPLACE_EXISTING));
+
+  ShortcutProperties expected_properties(link_properties_2_);
+  expected_properties.set_arguments(link_properties_.arguments);
+  ValidateShortcut(link_file_, expected_properties);
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/startup_information.cc b/base/win/startup_information.cc
new file mode 100644
index 0000000..aff52eb
--- /dev/null
+++ b/base/win/startup_information.cc
@@ -0,0 +1,109 @@
+// Copyright (c) 2012 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/win/startup_information.h"
+
+#include "base/logging.h"
+#include "base/win/windows_version.h"
+
+namespace {
+
+typedef BOOL (WINAPI *InitializeProcThreadAttributeListFunction)(
+    LPPROC_THREAD_ATTRIBUTE_LIST attribute_list,
+    DWORD attribute_count,
+    DWORD flags,
+    PSIZE_T size);
+static InitializeProcThreadAttributeListFunction
+    initialize_proc_thread_attribute_list;
+
+typedef BOOL (WINAPI *UpdateProcThreadAttributeFunction)(
+    LPPROC_THREAD_ATTRIBUTE_LIST attribute_list,
+    DWORD flags,
+    DWORD_PTR attribute,
+    PVOID value,
+    SIZE_T size,
+    PVOID previous_value,
+    PSIZE_T return_size);
+static UpdateProcThreadAttributeFunction update_proc_thread_attribute_list;
+
+typedef VOID (WINAPI *DeleteProcThreadAttributeListFunction)(
+    LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList);
+static DeleteProcThreadAttributeListFunction delete_proc_thread_attribute_list;
+
+}  // namespace
+
+namespace base {
+namespace win {
+
+StartupInformation::StartupInformation() {
+  memset(&startup_info_, 0, sizeof(startup_info_));
+
+  // Pre Windows Vista doesn't support STARTUPINFOEX.
+  if (base::win::GetVersion() < base::win::VERSION_VISTA) {
+    startup_info_.StartupInfo.cb = sizeof(STARTUPINFO);
+    return;
+  }
+
+  startup_info_.StartupInfo.cb = sizeof(startup_info_);
+
+  // Load the attribute API functions.
+  if (!initialize_proc_thread_attribute_list ||
+      !update_proc_thread_attribute_list ||
+      !delete_proc_thread_attribute_list) {
+    HMODULE module = ::GetModuleHandleW(L"kernel32.dll");
+    initialize_proc_thread_attribute_list =
+        reinterpret_cast<InitializeProcThreadAttributeListFunction>(
+            ::GetProcAddress(module, "InitializeProcThreadAttributeList"));
+    update_proc_thread_attribute_list =
+        reinterpret_cast<UpdateProcThreadAttributeFunction>(
+            ::GetProcAddress(module, "UpdateProcThreadAttribute"));
+    delete_proc_thread_attribute_list =
+        reinterpret_cast<DeleteProcThreadAttributeListFunction>(
+            ::GetProcAddress(module, "DeleteProcThreadAttributeList"));
+  }
+}
+
+StartupInformation::~StartupInformation() {
+  if (startup_info_.lpAttributeList) {
+    delete_proc_thread_attribute_list(startup_info_.lpAttributeList);
+    delete [] reinterpret_cast<BYTE*>(startup_info_.lpAttributeList);
+  }
+}
+
+bool StartupInformation::InitializeProcThreadAttributeList(
+    DWORD attribute_count) {
+  if (startup_info_.StartupInfo.cb != sizeof(startup_info_) ||
+      startup_info_.lpAttributeList)
+    return false;
+
+  SIZE_T size = 0;
+  initialize_proc_thread_attribute_list(NULL, attribute_count, 0, &size);
+  if (size == 0)
+    return false;
+
+  startup_info_.lpAttributeList =
+      reinterpret_cast<LPPROC_THREAD_ATTRIBUTE_LIST>(new BYTE[size]);
+  if (!initialize_proc_thread_attribute_list(startup_info_.lpAttributeList,
+                                           attribute_count, 0, &size)) {
+    delete [] reinterpret_cast<BYTE*>(startup_info_.lpAttributeList);
+    startup_info_.lpAttributeList = NULL;
+    return false;
+  }
+
+  return true;
+}
+
+bool StartupInformation::UpdateProcThreadAttribute(
+    DWORD_PTR attribute,
+    void* value,
+    size_t size) {
+  if (!startup_info_.lpAttributeList)
+    return false;
+  return !!update_proc_thread_attribute_list(startup_info_.lpAttributeList, 0,
+                                       attribute, value, size, NULL, NULL);
+}
+
+}  // namespace win
+}  // namespace base
+
diff --git a/base/win/startup_information.h b/base/win/startup_information.h
new file mode 100644
index 0000000..3f18ee5
--- /dev/null
+++ b/base/win/startup_information.h
@@ -0,0 +1,50 @@
+// Copyright (c) 2012 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_WIN_STARTUP_INFORMATION_H_
+#define BASE_WIN_STARTUP_INFORMATION_H_
+
+#include <windows.h>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace win {
+
+// Manages the lifetime of additional attributes in STARTUPINFOEX.
+class BASE_EXPORT StartupInformation {
+ public:
+  StartupInformation();
+
+  ~StartupInformation();
+
+  // Initialize the attribute list for the specified number of entries.
+  bool InitializeProcThreadAttributeList(DWORD attribute_count);
+
+  // Sets one entry in the initialized attribute list.
+  // |value| needs to live at least as long as the StartupInformation object
+  // this is called on.
+  bool UpdateProcThreadAttribute(DWORD_PTR attribute,
+                                 void* value,
+                                 size_t size);
+
+  LPSTARTUPINFOW startup_info() { return &startup_info_.StartupInfo; }
+  const LPSTARTUPINFOW startup_info() const {
+    return const_cast<const LPSTARTUPINFOW>(&startup_info_.StartupInfo);
+  }
+
+  bool has_extended_startup_info() const {
+    return !!startup_info_.lpAttributeList;
+  }
+
+ private:
+  STARTUPINFOEXW startup_info_;
+  DISALLOW_COPY_AND_ASSIGN(StartupInformation);
+};
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_STARTUP_INFORMATION_H_
diff --git a/base/win/startup_information_unittest.cc b/base/win/startup_information_unittest.cc
new file mode 100644
index 0000000..36c6e84
--- /dev/null
+++ b/base/win/startup_information_unittest.cc
@@ -0,0 +1,78 @@
+// Copyright (c) 2012 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 <windows.h>
+
+#include <string>
+
+#include "base/command_line.h"
+#include "base/test/multiprocess_test.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/scoped_process_information.h"
+#include "base/win/startup_information.h"
+#include "base/win/windows_version.h"
+#include "testing/multiprocess_func_list.h"
+
+const wchar_t kSectionName[] = L"EventTestSection";
+const size_t kSectionSize = 4096;
+
+MULTIPROCESS_TEST_MAIN(FireInheritedEvents) {
+  HANDLE section = ::OpenFileMappingW(PAGE_READWRITE, false, kSectionName);
+  HANDLE* events = reinterpret_cast<HANDLE*>(::MapViewOfFile(section,
+      PAGE_READWRITE, 0, 0, kSectionSize));
+  // This event should not be valid because it wasn't explicitly inherited.
+  if (::SetEvent(events[1]))
+    return -1;
+  // This event should be valid because it was explicitly inherited.
+  if (!::SetEvent(events[0]))
+    return -1;
+
+  return 0;
+}
+
+class StartupInformationTest : public base::MultiProcessTest {};
+
+// Verify that only the explicitly specified event is inherited.
+TEST_F(StartupInformationTest, InheritStdOut) {
+  if (base::win::GetVersion() < base::win::VERSION_VISTA)
+    return;
+
+  base::win::StartupInformation startup_info;
+
+  HANDLE section = ::CreateFileMappingW(INVALID_HANDLE_VALUE, NULL,
+                                        PAGE_READWRITE, 0, kSectionSize,
+                                        kSectionName);
+  ASSERT_TRUE(section);
+
+  HANDLE* events = reinterpret_cast<HANDLE*>(::MapViewOfFile(section,
+      FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, kSectionSize));
+
+  // Make two inheritable events.
+  SECURITY_ATTRIBUTES security_attributes = { sizeof(security_attributes),
+                                              NULL, true };
+  events[0] = ::CreateEvent(&security_attributes, false, false, NULL);
+  ASSERT_TRUE(events[0]);
+  events[1] = ::CreateEvent(&security_attributes, false, false, NULL);
+  ASSERT_TRUE(events[1]);
+
+  ASSERT_TRUE(startup_info.InitializeProcThreadAttributeList(1));
+  ASSERT_TRUE(startup_info.UpdateProcThreadAttribute(
+      PROC_THREAD_ATTRIBUTE_HANDLE_LIST, &events[0],
+      sizeof(events[0])));
+
+  std::wstring cmd_line =
+      MakeCmdLine("FireInheritedEvents").GetCommandLineString();
+
+  PROCESS_INFORMATION temp_process_info = {};
+  ASSERT_TRUE(::CreateProcess(NULL, &cmd_line[0],
+                              NULL, NULL, true, EXTENDED_STARTUPINFO_PRESENT,
+                              NULL, NULL, startup_info.startup_info(),
+                              &temp_process_info)) << ::GetLastError();
+  base::win::ScopedProcessInformation process_info(temp_process_info);
+
+  // Only the first event should be signalled
+  EXPECT_EQ(WAIT_OBJECT_0, ::WaitForMultipleObjects(2, events, false,
+                                                    4000));
+}
+
diff --git a/base/win/win_util.cc b/base/win/win_util.cc
new file mode 100644
index 0000000..cf93444
--- /dev/null
+++ b/base/win/win_util.cc
@@ -0,0 +1,494 @@
+// Copyright (c) 2012 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/win/win_util.h"
+
+#include <aclapi.h>
+#include <cfgmgr32.h>
+#include <lm.h>
+#include <powrprof.h>
+#include <shellapi.h>
+#include <shlobj.h>
+#include <shobjidl.h>  // Must be before propkey.
+#include <initguid.h>
+#include <propkey.h>
+#include <propvarutil.h>
+#include <sddl.h>
+#include <setupapi.h>
+#include <signal.h>
+#include <stdlib.h>
+
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/threading/thread_restrictions.h"
+#include "base/win/metro.h"
+#include "base/win/registry.h"
+#include "base/win/scoped_co_mem.h"
+#include "base/win/scoped_handle.h"
+#include "base/win/scoped_propvariant.h"
+#include "base/win/windows_version.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+// Sets the value of |property_key| to |property_value| in |property_store|.
+bool SetPropVariantValueForPropertyStore(
+    IPropertyStore* property_store,
+    const PROPERTYKEY& property_key,
+    const ScopedPropVariant& property_value) {
+  DCHECK(property_store);
+
+  HRESULT result = property_store->SetValue(property_key, property_value.get());
+  if (result == S_OK)
+    result = property_store->Commit();
+  return SUCCEEDED(result);
+}
+
+void __cdecl ForceCrashOnSigAbort(int) {
+  *((int*)0) = 0x1337;
+}
+
+const wchar_t kWindows8OSKRegPath[] =
+    L"Software\\Classes\\CLSID\\{054AAE20-4BEA-4347-8A35-64A533254A9D}"
+    L"\\LocalServer32";
+
+// Returns true if a physical keyboard is detected on Windows 8 and up.
+// Uses the Setup APIs to enumerate the attached keyboards and returns true
+// if the keyboard count is 1 or more.. While this will work in most cases
+// it won't work if there are devices which expose keyboard interfaces which
+// are attached to the machine.
+bool IsKeyboardPresentOnSlate() {
+  // This function is only supported for Windows 8 and up.
+  DCHECK(GetVersion() >= VERSION_WIN8);
+
+  // This function should be only invoked for machines with touch screens.
+  if ((GetSystemMetrics(SM_DIGITIZER) & NID_INTEGRATED_TOUCH)
+        != NID_INTEGRATED_TOUCH) {
+    return true;
+  }
+
+  // If the device is docked, the user is treating the device as a PC.
+  if (GetSystemMetrics(SM_SYSTEMDOCKED) != 0)
+    return true;
+
+  // To determine whether a keyboard is present on the device, we do the
+  // following:-
+  // 1. Check whether the device supports auto rotation. If it does then
+  //    it possibly supports flipping from laptop to slate mode. If it
+  //    does not support auto rotation, then we assume it is a desktop
+  //    or a normal laptop and assume that there is a keyboard.
+
+  // 2. If the device supports auto rotation, then we get its platform role
+  //    and check the system metric SM_CONVERTIBLESLATEMODE to see if it is
+  //    being used in slate mode. If yes then we return false here to ensure
+  //    that the OSK is displayed.
+
+  // 3. If step 1 and 2 fail then we check attached keyboards and return true
+  //    if we find ACPI\* or HID\VID* keyboards.
+
+  typedef BOOL (WINAPI* GetAutoRotationState)(PAR_STATE state);
+
+  GetAutoRotationState get_rotation_state =
+      reinterpret_cast<GetAutoRotationState>(::GetProcAddress(
+          GetModuleHandle(L"user32.dll"), "GetAutoRotationState"));
+
+  if (get_rotation_state) {
+    AR_STATE auto_rotation_state = AR_ENABLED;
+    get_rotation_state(&auto_rotation_state);
+    if ((auto_rotation_state & AR_NOSENSOR) ||
+        (auto_rotation_state & AR_NOT_SUPPORTED)) {
+      // If there is no auto rotation sensor or rotation is not supported in
+      // the current configuration, then we can assume that this is a desktop
+      // or a traditional laptop.
+      return true;
+    }
+  }
+
+  // Check if the device is being used as a laptop or a tablet. This can be
+  // checked by first checking the role of the device and then the
+  // corresponding system metric (SM_CONVERTIBLESLATEMODE). If it is being used
+  // as a tablet then we want the OSK to show up.
+  POWER_PLATFORM_ROLE role = PowerDeterminePlatformRole();
+
+  if (((role == PlatformRoleMobile) || (role == PlatformRoleSlate)) &&
+       (GetSystemMetrics(SM_CONVERTIBLESLATEMODE) == 0))
+    return false;
+
+  const GUID KEYBOARD_CLASS_GUID =
+      { 0x4D36E96B, 0xE325,  0x11CE,
+          { 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18 } };
+
+  // Query for all the keyboard devices.
+  HDEVINFO device_info =
+      SetupDiGetClassDevs(&KEYBOARD_CLASS_GUID, NULL, NULL, DIGCF_PRESENT);
+  if (device_info == INVALID_HANDLE_VALUE)
+    return false;
+
+  // Enumerate all keyboards and look for ACPI\PNP and HID\VID devices. If
+  // the count is more than 1 we assume that a keyboard is present. This is
+  // under the assumption that there will always be one keyboard device.
+  int keyboard_count = 0;
+  for (DWORD i = 0;; ++i) {
+    SP_DEVINFO_DATA device_info_data = { 0 };
+    device_info_data.cbSize = sizeof(device_info_data);
+    if (!SetupDiEnumDeviceInfo(device_info, i, &device_info_data))
+      break;
+
+    // Get the device ID.
+    wchar_t device_id[MAX_DEVICE_ID_LEN];
+    CONFIGRET status = CM_Get_Device_ID(device_info_data.DevInst,
+                                        device_id,
+                                        MAX_DEVICE_ID_LEN,
+                                        0);
+    if (status == CR_SUCCESS) {
+      // To reduce the scope of the hack we only look for ACPI and HID\\VID
+      // prefixes in the keyboard device ids.
+      if (StartsWith(device_id, L"ACPI", false) ||
+          StartsWith(device_id, L"HID\\VID", false)) {
+        keyboard_count++;
+      }
+    }
+  }
+  // The heuristic we are using is to check the count of keyboards and return
+  // true if the API's report one or more keyboards. Please note that this
+  // will break for non keyboard devices which expose a keyboard PDO.
+  return keyboard_count >= 1;
+}
+
+}  // namespace
+
+static bool g_crash_on_process_detach = false;
+
+void GetNonClientMetrics(NONCLIENTMETRICS_XP* metrics) {
+  DCHECK(metrics);
+  metrics->cbSize = sizeof(*metrics);
+  const bool success = !!SystemParametersInfo(
+      SPI_GETNONCLIENTMETRICS,
+      metrics->cbSize,
+      reinterpret_cast<NONCLIENTMETRICS*>(metrics),
+      0);
+  DCHECK(success);
+}
+
+bool GetUserSidString(std::wstring* user_sid) {
+  // Get the current token.
+  HANDLE token = NULL;
+  if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &token))
+    return false;
+  ScopedHandle token_scoped(token);
+
+  DWORD size = sizeof(TOKEN_USER) + SECURITY_MAX_SID_SIZE;
+  scoped_ptr<BYTE[]> user_bytes(new BYTE[size]);
+  TOKEN_USER* user = reinterpret_cast<TOKEN_USER*>(user_bytes.get());
+
+  if (!::GetTokenInformation(token, TokenUser, user, size, &size))
+    return false;
+
+  if (!user->User.Sid)
+    return false;
+
+  // Convert the data to a string.
+  wchar_t* sid_string;
+  if (!::ConvertSidToStringSid(user->User.Sid, &sid_string))
+    return false;
+
+  *user_sid = sid_string;
+
+  ::LocalFree(sid_string);
+
+  return true;
+}
+
+bool IsShiftPressed() {
+  return (::GetKeyState(VK_SHIFT) & 0x8000) == 0x8000;
+}
+
+bool IsCtrlPressed() {
+  return (::GetKeyState(VK_CONTROL) & 0x8000) == 0x8000;
+}
+
+bool IsAltPressed() {
+  return (::GetKeyState(VK_MENU) & 0x8000) == 0x8000;
+}
+
+bool IsAltGrPressed() {
+  return (::GetKeyState(VK_MENU) & 0x8000) == 0x8000 &&
+      (::GetKeyState(VK_CONTROL) & 0x8000) == 0x8000;
+}
+
+bool UserAccountControlIsEnabled() {
+  // This can be slow if Windows ends up going to disk.  Should watch this key
+  // for changes and only read it once, preferably on the file thread.
+  //   http://code.google.com/p/chromium/issues/detail?id=61644
+  ThreadRestrictions::ScopedAllowIO allow_io;
+
+  RegKey key(HKEY_LOCAL_MACHINE,
+             L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System",
+             KEY_READ);
+  DWORD uac_enabled;
+  if (key.ReadValueDW(L"EnableLUA", &uac_enabled) != ERROR_SUCCESS)
+    return true;
+  // Users can set the EnableLUA value to something arbitrary, like 2, which
+  // Vista will treat as UAC enabled, so we make sure it is not set to 0.
+  return (uac_enabled != 0);
+}
+
+bool SetBooleanValueForPropertyStore(IPropertyStore* property_store,
+                                     const PROPERTYKEY& property_key,
+                                     bool property_bool_value) {
+  ScopedPropVariant property_value;
+  if (FAILED(InitPropVariantFromBoolean(property_bool_value,
+                                        property_value.Receive()))) {
+    return false;
+  }
+
+  return SetPropVariantValueForPropertyStore(property_store,
+                                             property_key,
+                                             property_value);
+}
+
+bool SetStringValueForPropertyStore(IPropertyStore* property_store,
+                                    const PROPERTYKEY& property_key,
+                                    const wchar_t* property_string_value) {
+  ScopedPropVariant property_value;
+  if (FAILED(InitPropVariantFromString(property_string_value,
+                                       property_value.Receive()))) {
+    return false;
+  }
+
+  return SetPropVariantValueForPropertyStore(property_store,
+                                             property_key,
+                                             property_value);
+}
+
+bool SetAppIdForPropertyStore(IPropertyStore* property_store,
+                              const wchar_t* app_id) {
+  // App id should be less than 64 chars and contain no space. And recommended
+  // format is CompanyName.ProductName[.SubProduct.ProductNumber].
+  // See http://msdn.microsoft.com/en-us/library/dd378459%28VS.85%29.aspx
+  DCHECK(lstrlen(app_id) < 64 && wcschr(app_id, L' ') == NULL);
+
+  return SetStringValueForPropertyStore(property_store,
+                                        PKEY_AppUserModel_ID,
+                                        app_id);
+}
+
+static const char16 kAutoRunKeyPath[] =
+    L"Software\\Microsoft\\Windows\\CurrentVersion\\Run";
+
+bool AddCommandToAutoRun(HKEY root_key, const string16& name,
+                         const string16& command) {
+  RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_SET_VALUE);
+  return (autorun_key.WriteValue(name.c_str(), command.c_str()) ==
+      ERROR_SUCCESS);
+}
+
+bool RemoveCommandFromAutoRun(HKEY root_key, const string16& name) {
+  RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_SET_VALUE);
+  return (autorun_key.DeleteValue(name.c_str()) == ERROR_SUCCESS);
+}
+
+bool ReadCommandFromAutoRun(HKEY root_key,
+                            const string16& name,
+                            string16* command) {
+  RegKey autorun_key(root_key, kAutoRunKeyPath, KEY_QUERY_VALUE);
+  return (autorun_key.ReadValue(name.c_str(), command) == ERROR_SUCCESS);
+}
+
+void SetShouldCrashOnProcessDetach(bool crash) {
+  g_crash_on_process_detach = crash;
+}
+
+bool ShouldCrashOnProcessDetach() {
+  return g_crash_on_process_detach;
+}
+
+void SetAbortBehaviorForCrashReporting() {
+  // Prevent CRT's abort code from prompting a dialog or trying to "report" it.
+  // Disabling the _CALL_REPORTFAULT behavior is important since otherwise it
+  // has the sideffect of clearing our exception filter, which means we
+  // don't get any crash.
+  _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
+
+  // Set a SIGABRT handler for good measure. We will crash even if the default
+  // is left in place, however this allows us to crash earlier. And it also
+  // lets us crash in response to code which might directly call raise(SIGABRT)
+  signal(SIGABRT, ForceCrashOnSigAbort);
+}
+
+bool IsTabletDevice() {
+  if (GetSystemMetrics(SM_MAXIMUMTOUCHES) == 0)
+    return false;
+
+  Version version = GetVersion();
+  if (version == VERSION_XP)
+    return (GetSystemMetrics(SM_TABLETPC) != 0);
+
+  // If the device is docked, the user is treating the device as a PC.
+  if (GetSystemMetrics(SM_SYSTEMDOCKED) != 0)
+    return false;
+
+  // PlatformRoleSlate was only added in Windows 8, but prior to Win8 it is
+  // still possible to check for a mobile power profile.
+  POWER_PLATFORM_ROLE role = PowerDeterminePlatformRole();
+  bool mobile_power_profile = (role == PlatformRoleMobile);
+  bool slate_power_profile = false;
+  if (version >= VERSION_WIN8)
+    slate_power_profile = (role == PlatformRoleSlate);
+
+  if (mobile_power_profile || slate_power_profile)
+    return (GetSystemMetrics(SM_CONVERTIBLESLATEMODE) == 0);
+
+  return false;
+}
+
+bool DisplayVirtualKeyboard() {
+  if (GetVersion() < VERSION_WIN8)
+    return false;
+
+  if (IsKeyboardPresentOnSlate())
+    return false;
+
+  static LazyInstance<string16>::Leaky osk_path = LAZY_INSTANCE_INITIALIZER;
+
+  if (osk_path.Get().empty()) {
+    // We need to launch TabTip.exe from the location specified under the
+    // LocalServer32 key for the {{054AAE20-4BEA-4347-8A35-64A533254A9D}}
+    // CLSID.
+    // TabTip.exe is typically found at
+    // c:\program files\common files\microsoft shared\ink on English Windows.
+    // We don't want to launch TabTip.exe from
+    // c:\program files (x86)\common files\microsoft shared\ink. This path is
+    // normally found on 64 bit Windows.
+    RegKey key(HKEY_LOCAL_MACHINE, kWindows8OSKRegPath,
+               KEY_READ | KEY_WOW64_64KEY);
+    DWORD osk_path_length = 1024;
+    if (key.ReadValue(NULL,
+                      WriteInto(&osk_path.Get(), osk_path_length),
+                      &osk_path_length,
+                      NULL) != ERROR_SUCCESS) {
+      DLOG(WARNING) << "Failed to read on screen keyboard path from registry";
+      return false;
+    }
+    size_t common_program_files_offset =
+        osk_path.Get().find(L"%CommonProgramFiles%");
+    // Typically the path to TabTip.exe read from the registry will start with
+    // %CommonProgramFiles% which needs to be replaced with the corrsponding
+    // expanded string.
+    // If the path does not begin with %CommonProgramFiles% we use it as is.
+    if (common_program_files_offset != string16::npos) {
+      // Preserve the beginning quote in the path.
+      osk_path.Get().erase(common_program_files_offset,
+                           wcslen(L"%CommonProgramFiles%"));
+      // The path read from the registry contains the %CommonProgramFiles%
+      // environment variable prefix. On 64 bit Windows the SHGetKnownFolderPath
+      // function returns the common program files path with the X86 suffix for
+      // the FOLDERID_ProgramFilesCommon value.
+      // To get the correct path to TabTip.exe we first read the environment
+      // variable CommonProgramW6432 which points to the desired common
+      // files path. Failing that we fallback to the SHGetKnownFolderPath API.
+
+      // We then replace the %CommonProgramFiles% value with the actual common
+      // files path found in the process.
+      string16 common_program_files_path;
+      scoped_ptr<wchar_t[]> common_program_files_wow6432;
+      DWORD buffer_size =
+          GetEnvironmentVariable(L"CommonProgramW6432", NULL, 0);
+      if (buffer_size) {
+        common_program_files_wow6432.reset(new wchar_t[buffer_size]);
+        GetEnvironmentVariable(L"CommonProgramW6432",
+                               common_program_files_wow6432.get(),
+                               buffer_size);
+        common_program_files_path = common_program_files_wow6432.get();
+        DCHECK(!common_program_files_path.empty());
+      } else {
+        ScopedCoMem<wchar_t> common_program_files;
+        if (FAILED(SHGetKnownFolderPath(FOLDERID_ProgramFilesCommon, 0, NULL,
+                                        &common_program_files))) {
+          return false;
+        }
+        common_program_files_path = common_program_files;
+      }
+
+      osk_path.Get().insert(1, common_program_files_path);
+    }
+  }
+
+  HINSTANCE ret = ::ShellExecuteW(NULL,
+                                  L"",
+                                  osk_path.Get().c_str(),
+                                  NULL,
+                                  NULL,
+                                  SW_SHOW);
+  return reinterpret_cast<intptr_t>(ret) > 32;
+}
+
+bool DismissVirtualKeyboard() {
+  if (GetVersion() < VERSION_WIN8)
+    return false;
+
+  // We dismiss the virtual keyboard by generating the ESC keystroke
+  // programmatically.
+  const wchar_t kOSKClassName[] = L"IPTip_Main_Window";
+  HWND osk = ::FindWindow(kOSKClassName, NULL);
+  if (::IsWindow(osk) && ::IsWindowEnabled(osk)) {
+    PostMessage(osk, WM_SYSCOMMAND, SC_CLOSE, 0);
+    return true;
+  }
+  return false;
+}
+
+typedef HWND (*MetroRootWindow) ();
+
+enum DomainEnrollementState {UNKNOWN = -1, NOT_ENROLLED, ENROLLED};
+static volatile long int g_domain_state = UNKNOWN;
+
+bool IsEnrolledToDomain() {
+  // Doesn't make any sense to retry inside a user session because joining a
+  // domain will only kick in on a restart.
+  if (g_domain_state == UNKNOWN) {
+    LPWSTR domain;
+    NETSETUP_JOIN_STATUS join_status;
+    if(::NetGetJoinInformation(NULL, &domain, &join_status) != NERR_Success)
+      return false;
+    ::NetApiBufferFree(domain);
+    ::InterlockedCompareExchange(&g_domain_state,
+                                 join_status == ::NetSetupDomainName ?
+                                     ENROLLED : NOT_ENROLLED,
+                                 UNKNOWN);
+  }
+
+  return g_domain_state == ENROLLED;
+}
+
+void SetDomainStateForTesting(bool state) {
+  g_domain_state = state ? ENROLLED : NOT_ENROLLED;
+}
+
+bool MaybeHasSHA256Support() {
+  const OSInfo* os_info = OSInfo::GetInstance();
+
+  if (os_info->version() == VERSION_PRE_XP)
+    return false;  // Too old to have it and this OS is not supported anyway.
+
+  if (os_info->version() == VERSION_XP)
+    return os_info->service_pack().major >= 3;  // Windows XP SP3 has it.
+
+  // Assume it is missing in this case, although it may not be. This category
+  // includes Windows XP x64, and Windows Server, where a hotfix could be
+  // deployed.
+  if (os_info->version() == VERSION_SERVER_2003)
+    return false;
+
+  DCHECK(os_info->version() >= VERSION_VISTA);
+  return true;  // New enough to have SHA-256 support.
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/win_util.h b/base/win/win_util.h
new file mode 100644
index 0000000..8513f62
--- /dev/null
+++ b/base/win/win_util.h
@@ -0,0 +1,167 @@
+// Copyright (c) 2012 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.
+
+// =============================================================================
+// PLEASE READ
+//
+// In general, you should not be adding stuff to this file.
+//
+// - If your thing is only used in one place, just put it in a reasonable
+//   location in or near that one place. It's nice you want people to be able
+//   to re-use your function, but realistically, if it hasn't been necessary
+//   before after so many years of development, it's probably not going to be
+//   used in other places in the future unless you know of them now.
+//
+// - If your thing is used by multiple callers and is UI-related, it should
+//   probably be in app/win/ instead. Try to put it in the most specific file
+//   possible (avoiding the *_util files when practical).
+//
+// =============================================================================
+
+#ifndef BASE_WIN_WIN_UTIL_H_
+#define BASE_WIN_WIN_UTIL_H_
+
+#include <windows.h>
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/strings/string16.h"
+
+struct IPropertyStore;
+struct _tagpropertykey;
+typedef _tagpropertykey PROPERTYKEY;
+
+// This is the same as NONCLIENTMETRICS except that the
+// unused member |iPaddedBorderWidth| has been removed.
+struct NONCLIENTMETRICS_XP {
+    UINT    cbSize;
+    int     iBorderWidth;
+    int     iScrollWidth;
+    int     iScrollHeight;
+    int     iCaptionWidth;
+    int     iCaptionHeight;
+    LOGFONTW lfCaptionFont;
+    int     iSmCaptionWidth;
+    int     iSmCaptionHeight;
+    LOGFONTW lfSmCaptionFont;
+    int     iMenuWidth;
+    int     iMenuHeight;
+    LOGFONTW lfMenuFont;
+    LOGFONTW lfStatusFont;
+    LOGFONTW lfMessageFont;
+};
+
+namespace base {
+namespace win {
+
+BASE_EXPORT void GetNonClientMetrics(NONCLIENTMETRICS_XP* metrics);
+
+// Returns the string representing the current user sid.
+BASE_EXPORT bool GetUserSidString(std::wstring* user_sid);
+
+// Returns true if the shift key is currently pressed.
+BASE_EXPORT bool IsShiftPressed();
+
+// Returns true if the ctrl key is currently pressed.
+BASE_EXPORT bool IsCtrlPressed();
+
+// Returns true if the alt key is currently pressed.
+BASE_EXPORT bool IsAltPressed();
+
+// Returns true if the altgr key is currently pressed.
+// Windows does not have specific key code and modifier bit and Alt+Ctrl key is
+// used as AltGr key in Windows.
+BASE_EXPORT bool IsAltGrPressed();
+
+// Returns false if user account control (UAC) has been disabled with the
+// EnableLUA registry flag. Returns true if user account control is enabled.
+// NOTE: The EnableLUA registry flag, which is ignored on Windows XP
+// machines, might still exist and be set to 0 (UAC disabled), in which case
+// this function will return false. You should therefore check this flag only
+// if the OS is Vista or later.
+BASE_EXPORT bool UserAccountControlIsEnabled();
+
+// Sets the boolean value for a given key in given IPropertyStore.
+BASE_EXPORT bool SetBooleanValueForPropertyStore(
+    IPropertyStore* property_store,
+    const PROPERTYKEY& property_key,
+    bool property_bool_value);
+
+// Sets the string value for a given key in given IPropertyStore.
+BASE_EXPORT bool SetStringValueForPropertyStore(
+    IPropertyStore* property_store,
+    const PROPERTYKEY& property_key,
+    const wchar_t* property_string_value);
+
+// Sets the application id in given IPropertyStore. The function is intended
+// for tagging application/chromium shortcut, browser window and jump list for
+// Win7.
+BASE_EXPORT bool SetAppIdForPropertyStore(IPropertyStore* property_store,
+                                          const wchar_t* app_id);
+
+// Adds the specified |command| using the specified |name| to the AutoRun key.
+// |root_key| could be HKCU or HKLM or the root of any user hive.
+BASE_EXPORT bool AddCommandToAutoRun(HKEY root_key, const string16& name,
+                                     const string16& command);
+// Removes the command specified by |name| from the AutoRun key. |root_key|
+// could be HKCU or HKLM or the root of any user hive.
+BASE_EXPORT bool RemoveCommandFromAutoRun(HKEY root_key, const string16& name);
+
+// Reads the command specified by |name| from the AutoRun key. |root_key|
+// could be HKCU or HKLM or the root of any user hive. Used for unit-tests.
+BASE_EXPORT bool ReadCommandFromAutoRun(HKEY root_key,
+                                        const string16& name,
+                                        string16* command);
+
+// Sets whether to crash the process during exit. This is inspected by DLLMain
+// and used to intercept unexpected terminations of the process (via calls to
+// exit(), abort(), _exit(), ExitProcess()) and convert them into crashes.
+// Note that not all mechanisms for terminating the process are covered by
+// this. In particular, TerminateProcess() is not caught.
+BASE_EXPORT void SetShouldCrashOnProcessDetach(bool crash);
+BASE_EXPORT bool ShouldCrashOnProcessDetach();
+
+// Adjusts the abort behavior so that crash reports can be generated when the
+// process is aborted.
+BASE_EXPORT void SetAbortBehaviorForCrashReporting();
+
+// A tablet is a device that is touch enabled and also is being used
+// "like a tablet".  This is used primarily for metrics in order to gain some
+// insight into how users use Chrome.
+BASE_EXPORT bool IsTabletDevice();
+
+// Get the size of a struct up to and including the specified member.
+// This is necessary to set compatible struct sizes for different versions
+// of certain Windows APIs (e.g. SystemParametersInfo).
+#define SIZEOF_STRUCT_WITH_SPECIFIED_LAST_MEMBER(struct_name, member) \
+    offsetof(struct_name, member) + \
+    (sizeof static_cast<struct_name*>(NULL)->member)
+
+// Displays the on screen keyboard on Windows 8 and above. Returns true on
+// success.
+BASE_EXPORT bool DisplayVirtualKeyboard();
+
+// Dismisses the on screen keyboard if it is being displayed on Windows 8 and.
+// above. Returns true on success.
+BASE_EXPORT bool DismissVirtualKeyboard();
+
+// Returns true if the machine is enrolled to a domain.
+BASE_EXPORT bool IsEnrolledToDomain();
+
+// Used by tests to mock any wanted state. Call with |state| set to true to
+// simulate being in a domain and false otherwise.
+BASE_EXPORT void SetDomainStateForTesting(bool state);
+
+// Returns true if the current operating system has support for SHA-256
+// certificates. As its name indicates, this function provides a best-effort
+// answer, which is solely based on comparing version numbers. The function
+// may be re-implemented in the future to return a reliable value, based on
+// run-time detection of this capability.
+BASE_EXPORT bool MaybeHasSHA256Support();
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_WIN_UTIL_H_
diff --git a/base/win/win_util_unittest.cc b/base/win/win_util_unittest.cc
new file mode 100644
index 0000000..24141cd
--- /dev/null
+++ b/base/win/win_util_unittest.cc
@@ -0,0 +1,58 @@
+// Copyright (c) 2010 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 <windows.h>
+
+#include "base/basictypes.h"
+#include "base/strings/string_util.h"
+#include "base/win/win_util.h"
+#include "base/win/windows_version.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace win {
+
+namespace {
+
+// Saves the current thread's locale ID when initialized, and restores it when
+// the instance is going out of scope.
+class ThreadLocaleSaver {
+ public:
+  ThreadLocaleSaver() : original_locale_id_(GetThreadLocale()) {}
+  ~ThreadLocaleSaver() { SetThreadLocale(original_locale_id_); }
+
+ private:
+  LCID original_locale_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(ThreadLocaleSaver);
+};
+
+}  // namespace
+
+// The test is somewhat silly, because the Vista bots some have UAC enabled
+// and some have it disabled. At least we check that it does not crash.
+TEST(BaseWinUtilTest, TestIsUACEnabled) {
+  if (GetVersion() >= base::win::VERSION_VISTA) {
+    UserAccountControlIsEnabled();
+  } else {
+    EXPECT_TRUE(UserAccountControlIsEnabled());
+  }
+}
+
+TEST(BaseWinUtilTest, TestGetUserSidString) {
+  std::wstring user_sid;
+  EXPECT_TRUE(GetUserSidString(&user_sid));
+  EXPECT_TRUE(!user_sid.empty());
+}
+
+TEST(BaseWinUtilTest, TestGetNonClientMetrics) {
+  NONCLIENTMETRICS_XP metrics = {0};
+  GetNonClientMetrics(&metrics);
+  EXPECT_GT(metrics.cbSize, 0u);
+  EXPECT_GT(metrics.iScrollWidth, 0);
+  EXPECT_GT(metrics.iScrollHeight, 0);
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/windows_version.cc b/base/win/windows_version.cc
new file mode 100644
index 0000000..fc2def3
--- /dev/null
+++ b/base/win/windows_version.cc
@@ -0,0 +1,178 @@
+// Copyright (c) 2012 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/win/windows_version.h"
+
+#include <windows.h>
+
+#include "base/logging.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/win/registry.h"
+
+namespace {
+typedef BOOL (WINAPI *GetProductInfoPtr)(DWORD, DWORD, DWORD, DWORD, PDWORD);
+}
+
+namespace base {
+namespace win {
+
+// static
+OSInfo* OSInfo::GetInstance() {
+  // Note: we don't use the Singleton class because it depends on AtExitManager,
+  // and it's convenient for other modules to use this classs without it. This
+  // pattern is copied from gurl.cc.
+  static OSInfo* info;
+  if (!info) {
+    OSInfo* new_info = new OSInfo();
+    if (InterlockedCompareExchangePointer(
+        reinterpret_cast<PVOID*>(&info), new_info, NULL)) {
+      delete new_info;
+    }
+  }
+  return info;
+}
+
+OSInfo::OSInfo()
+    : version_(VERSION_PRE_XP),
+      architecture_(OTHER_ARCHITECTURE),
+      wow64_status_(GetWOW64StatusForProcess(GetCurrentProcess())) {
+  OSVERSIONINFOEX version_info = { sizeof version_info };
+  ::GetVersionEx(reinterpret_cast<OSVERSIONINFO*>(&version_info));
+  version_number_.major = version_info.dwMajorVersion;
+  version_number_.minor = version_info.dwMinorVersion;
+  version_number_.build = version_info.dwBuildNumber;
+  if ((version_number_.major == 5) && (version_number_.minor > 0)) {
+    // Treat XP Pro x64, Home Server, and Server 2003 R2 as Server 2003.
+    version_ = (version_number_.minor == 1) ? VERSION_XP : VERSION_SERVER_2003;
+  } else if (version_number_.major == 6) {
+    switch (version_number_.minor) {
+      case 0:
+        // Treat Windows Server 2008 the same as Windows Vista.
+        version_ = VERSION_VISTA;
+        break;
+      case 1:
+        // Treat Windows Server 2008 R2 the same as Windows 7.
+        version_ = VERSION_WIN7;
+        break;
+      case 2:
+        // Treat Windows Server 2012 the same as Windows 8.
+        version_ = VERSION_WIN8;
+        break;
+      default:
+        DCHECK_EQ(version_number_.minor, 3);
+        version_ = VERSION_WIN8_1;
+        break;
+    }
+  } else if (version_number_.major == 10) {
+    version_ = VERSION_WIN10;
+  } else if (version_number_.major > 6) {
+    NOTREACHED();
+    version_ = VERSION_WIN_LAST;
+  }
+  service_pack_.major = version_info.wServicePackMajor;
+  service_pack_.minor = version_info.wServicePackMinor;
+
+  SYSTEM_INFO system_info = { 0 };
+  ::GetNativeSystemInfo(&system_info);
+  switch (system_info.wProcessorArchitecture) {
+    case PROCESSOR_ARCHITECTURE_INTEL: architecture_ = X86_ARCHITECTURE; break;
+    case PROCESSOR_ARCHITECTURE_AMD64: architecture_ = X64_ARCHITECTURE; break;
+    case PROCESSOR_ARCHITECTURE_IA64:  architecture_ = IA64_ARCHITECTURE; break;
+  }
+  processors_ = system_info.dwNumberOfProcessors;
+  allocation_granularity_ = system_info.dwAllocationGranularity;
+
+  GetProductInfoPtr get_product_info;
+  DWORD os_type;
+
+  if (version_info.dwMajorVersion == 6 || version_info.dwMajorVersion == 10) {
+    // Only present on Vista+.
+    get_product_info = reinterpret_cast<GetProductInfoPtr>(
+        ::GetProcAddress(::GetModuleHandle(L"kernel32.dll"), "GetProductInfo"));
+
+    get_product_info(version_info.dwMajorVersion, version_info.dwMinorVersion,
+                     0, 0, &os_type);
+    switch (os_type) {
+      case PRODUCT_CLUSTER_SERVER:
+      case PRODUCT_DATACENTER_SERVER:
+      case PRODUCT_DATACENTER_SERVER_CORE:
+      case PRODUCT_ENTERPRISE_SERVER:
+      case PRODUCT_ENTERPRISE_SERVER_CORE:
+      case PRODUCT_ENTERPRISE_SERVER_IA64:
+      case PRODUCT_SMALLBUSINESS_SERVER:
+      case PRODUCT_SMALLBUSINESS_SERVER_PREMIUM:
+      case PRODUCT_STANDARD_SERVER:
+      case PRODUCT_STANDARD_SERVER_CORE:
+      case PRODUCT_WEB_SERVER:
+        version_type_ = SUITE_SERVER;
+        break;
+      case PRODUCT_PROFESSIONAL:
+      case PRODUCT_ULTIMATE:
+      case PRODUCT_ENTERPRISE:
+      case PRODUCT_BUSINESS:
+        version_type_ = SUITE_PROFESSIONAL;
+        break;
+      case PRODUCT_HOME_BASIC:
+      case PRODUCT_HOME_PREMIUM:
+      case PRODUCT_STARTER:
+      default:
+        version_type_ = SUITE_HOME;
+        break;
+    }
+  } else if (version_info.dwMajorVersion == 5 &&
+             version_info.dwMinorVersion == 2) {
+    if (version_info.wProductType == VER_NT_WORKSTATION &&
+        system_info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) {
+      version_type_ = SUITE_PROFESSIONAL;
+    } else if (version_info.wSuiteMask & VER_SUITE_WH_SERVER ) {
+      version_type_ = SUITE_HOME;
+    } else {
+      version_type_ = SUITE_SERVER;
+    }
+  } else if (version_info.dwMajorVersion == 5 &&
+             version_info.dwMinorVersion == 1) {
+    if(version_info.wSuiteMask & VER_SUITE_PERSONAL)
+      version_type_ = SUITE_HOME;
+    else
+      version_type_ = SUITE_PROFESSIONAL;
+  } else {
+    // Windows is pre XP so we don't care but pick a safe default.
+    version_type_ = SUITE_HOME;
+  }
+}
+
+OSInfo::~OSInfo() {
+}
+
+std::string OSInfo::processor_model_name() {
+  if (processor_model_name_.empty()) {
+    const wchar_t kProcessorNameString[] =
+        L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0";
+    base::win::RegKey key(HKEY_LOCAL_MACHINE, kProcessorNameString, KEY_READ);
+    string16 value;
+    key.ReadValue(L"ProcessorNameString", &value);
+    processor_model_name_ = UTF16ToUTF8(value);
+  }
+  return processor_model_name_;
+}
+
+// static
+OSInfo::WOW64Status OSInfo::GetWOW64StatusForProcess(HANDLE process_handle) {
+  typedef BOOL (WINAPI* IsWow64ProcessFunc)(HANDLE, PBOOL);
+  IsWow64ProcessFunc is_wow64_process = reinterpret_cast<IsWow64ProcessFunc>(
+      GetProcAddress(GetModuleHandle(L"kernel32.dll"), "IsWow64Process"));
+  if (!is_wow64_process)
+    return WOW64_DISABLED;
+  BOOL is_wow64 = FALSE;
+  if (!(*is_wow64_process)(process_handle, &is_wow64))
+    return WOW64_UNKNOWN;
+  return is_wow64 ? WOW64_ENABLED : WOW64_DISABLED;
+}
+
+Version GetVersion() {
+  return OSInfo::GetInstance()->version();
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/windows_version.h b/base/win/windows_version.h
new file mode 100644
index 0000000..a52e64e
--- /dev/null
+++ b/base/win/windows_version.h
@@ -0,0 +1,124 @@
+// Copyright (c) 2012 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_WIN_WINDOWS_VERSION_H_
+#define BASE_WIN_WINDOWS_VERSION_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+typedef void* HANDLE;
+
+namespace base {
+namespace win {
+
+// The running version of Windows.  This is declared outside OSInfo for
+// syntactic sugar reasons; see the declaration of GetVersion() below.
+// NOTE: Keep these in order so callers can do things like
+// "if (base::win::GetVersion() >= base::win::VERSION_VISTA) ...".
+enum Version {
+  VERSION_PRE_XP = 0,  // Not supported.
+  VERSION_XP,
+  VERSION_SERVER_2003, // Also includes XP Pro x64 and Server 2003 R2.
+  VERSION_VISTA,       // Also includes Windows Server 2008.
+  VERSION_WIN7,        // Also includes Windows Server 2008 R2.
+  VERSION_WIN8,        // Also includes Windows Server 2012.
+  VERSION_WIN8_1,      // Also includes Windows Server 2012 R2.
+  VERSION_WIN10,       // Also includes Windows 10 Server.
+  VERSION_WIN_LAST,    // Indicates error condition.
+};
+
+// A rough bucketing of the available types of versions of Windows. This is used
+// to distinguish enterprise enabled versions from home versions and potentially
+// server versions.
+enum VersionType {
+  SUITE_HOME,
+  SUITE_PROFESSIONAL,
+  SUITE_SERVER,
+  SUITE_LAST,
+};
+
+// A singleton that can be used to query various pieces of information about the
+// OS and process state. Note that this doesn't use the base Singleton class, so
+// it can be used without an AtExitManager.
+class BASE_EXPORT OSInfo {
+ public:
+  struct VersionNumber {
+    int major;
+    int minor;
+    int build;
+  };
+
+  struct ServicePack {
+    int major;
+    int minor;
+  };
+
+  // The processor architecture this copy of Windows natively uses.  For
+  // example, given an x64-capable processor, we have three possibilities:
+  //   32-bit Chrome running on 32-bit Windows:           X86_ARCHITECTURE
+  //   32-bit Chrome running on 64-bit Windows via WOW64: X64_ARCHITECTURE
+  //   64-bit Chrome running on 64-bit Windows:           X64_ARCHITECTURE
+  enum WindowsArchitecture {
+    X86_ARCHITECTURE,
+    X64_ARCHITECTURE,
+    IA64_ARCHITECTURE,
+    OTHER_ARCHITECTURE,
+  };
+
+  // Whether a process is running under WOW64 (the wrapper that allows 32-bit
+  // processes to run on 64-bit versions of Windows).  This will return
+  // WOW64_DISABLED for both "32-bit Chrome on 32-bit Windows" and "64-bit
+  // Chrome on 64-bit Windows".  WOW64_UNKNOWN means "an error occurred", e.g.
+  // the process does not have sufficient access rights to determine this.
+  enum WOW64Status {
+    WOW64_DISABLED,
+    WOW64_ENABLED,
+    WOW64_UNKNOWN,
+  };
+
+  static OSInfo* GetInstance();
+
+  Version version() const { return version_; }
+  // The next two functions return arrays of values, [major, minor(, build)].
+  VersionNumber version_number() const { return version_number_; }
+  VersionType version_type() const { return version_type_; }
+  ServicePack service_pack() const { return service_pack_; }
+  WindowsArchitecture architecture() const { return architecture_; }
+  int processors() const { return processors_; }
+  size_t allocation_granularity() const { return allocation_granularity_; }
+  WOW64Status wow64_status() const { return wow64_status_; }
+  std::string processor_model_name();
+
+  // Like wow64_status(), but for the supplied handle instead of the current
+  // process.  This doesn't touch member state, so you can bypass the singleton.
+  static WOW64Status GetWOW64StatusForProcess(HANDLE process_handle);
+
+ private:
+  OSInfo();
+  ~OSInfo();
+
+  Version version_;
+  VersionNumber version_number_;
+  VersionType version_type_;
+  ServicePack service_pack_;
+  WindowsArchitecture architecture_;
+  int processors_;
+  size_t allocation_granularity_;
+  WOW64Status wow64_status_;
+  std::string processor_model_name_;
+
+  DISALLOW_COPY_AND_ASSIGN(OSInfo);
+};
+
+// Because this is by far the most commonly-requested value from the above
+// singleton, we add a global-scope accessor here as syntactic sugar.
+BASE_EXPORT Version GetVersion();
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_WINDOWS_VERSION_H_
diff --git a/base/win/wrapped_window_proc.cc b/base/win/wrapped_window_proc.cc
new file mode 100644
index 0000000..61b79ed
--- /dev/null
+++ b/base/win/wrapped_window_proc.cc
@@ -0,0 +1,63 @@
+// Copyright (c) 2012 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/win/wrapped_window_proc.h"
+
+#include "base/atomicops.h"
+#include "base/logging.h"
+#include "base/process/memory.h"
+
+namespace {
+
+base::win::WinProcExceptionFilter s_exception_filter = NULL;
+
+}  // namespace.
+
+namespace base {
+namespace win {
+
+WinProcExceptionFilter SetWinProcExceptionFilter(
+    WinProcExceptionFilter filter) {
+  subtle::AtomicWord rv = subtle::NoBarrier_AtomicExchange(
+      reinterpret_cast<subtle::AtomicWord*>(&s_exception_filter),
+      reinterpret_cast<subtle::AtomicWord>(filter));
+  return reinterpret_cast<WinProcExceptionFilter>(rv);
+}
+
+int CallExceptionFilter(EXCEPTION_POINTERS* info) {
+  return s_exception_filter ? s_exception_filter(info) :
+                              EXCEPTION_CONTINUE_SEARCH;
+}
+
+BASE_EXPORT void InitializeWindowClass(
+    const char16* class_name,
+    WNDPROC window_proc,
+    UINT style,
+    int class_extra,
+    int window_extra,
+    HCURSOR cursor,
+    HBRUSH background,
+    const char16* menu_name,
+    HICON large_icon,
+    HICON small_icon,
+    WNDCLASSEX* class_out) {
+  class_out->cbSize = sizeof(WNDCLASSEX);
+  class_out->style = style;
+  class_out->lpfnWndProc = window_proc;
+  class_out->cbClsExtra = class_extra;
+  class_out->cbWndExtra = window_extra;
+  class_out->hInstance = base::GetModuleFromAddress(window_proc);
+  class_out->hIcon = large_icon;
+  class_out->hCursor = cursor;
+  class_out->hbrBackground = background;
+  class_out->lpszMenuName = menu_name;
+  class_out->lpszClassName = class_name;
+  class_out->hIconSm = small_icon;
+
+  // Check if |window_proc| is valid.
+  DCHECK(class_out->hInstance != NULL);
+}
+
+}  // namespace win
+}  // namespace base
diff --git a/base/win/wrapped_window_proc.h b/base/win/wrapped_window_proc.h
new file mode 100644
index 0000000..d464a9c
--- /dev/null
+++ b/base/win/wrapped_window_proc.h
@@ -0,0 +1,85 @@
+// Copyright (c) 2012 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.
+
+// Provides a way to handle exceptions that happen while a WindowProc is
+// running. The behavior of exceptions generated inside a WindowProc is OS
+// dependent, but it is possible that the OS just ignores the exception and
+// continues execution, which leads to unpredictable behavior for Chrome.
+
+#ifndef BASE_WIN_WRAPPED_WINDOW_PROC_H_
+#define BASE_WIN_WRAPPED_WINDOW_PROC_H_
+
+#include <windows.h>
+
+#include "base/base_export.h"
+#include "base/strings/string16.h"
+
+namespace base {
+namespace win {
+
+// An exception filter for a WindowProc. The return value determines how the
+// exception should be handled, following standard SEH rules. However, the
+// expected behavior for this function is to not return, instead of returning
+// EXCEPTION_EXECUTE_HANDLER or similar, given that in general we are not
+// prepared to handle exceptions.
+typedef int (__cdecl *WinProcExceptionFilter)(EXCEPTION_POINTERS* info);
+
+// Sets the filter to deal with exceptions inside a WindowProc. Returns the old
+// exception filter, if any.
+// This function should be called before any window is created.
+BASE_EXPORT WinProcExceptionFilter SetWinProcExceptionFilter(
+    WinProcExceptionFilter filter);
+
+// Calls the registered exception filter.
+BASE_EXPORT int CallExceptionFilter(EXCEPTION_POINTERS* info);
+
+// Initializes the WNDCLASSEX structure |*class_out| to be passed to
+// RegisterClassEx() making sure that it is associated with the module
+// containing the window procedure.
+BASE_EXPORT void InitializeWindowClass(
+    const char16* class_name,
+    WNDPROC window_proc,
+    UINT style,
+    int class_extra,
+    int window_extra,
+    HCURSOR cursor,
+    HBRUSH background,
+    const char16* menu_name,
+    HICON large_icon,
+    HICON small_icon,
+    WNDCLASSEX* class_out);
+
+// Wrapper that supplies a standard exception frame for the provided WindowProc.
+// The normal usage is something like this:
+//
+// LRESULT CALLBACK MyWinProc(HWND hwnd, UINT message,
+//                            WPARAM wparam, LPARAM lparam) {
+//   // Do Something.
+// }
+//
+// ...
+//
+//   WNDCLASSEX wc = {0};
+//   wc.lpfnWndProc = WrappedWindowProc<MyWinProc>;
+//   wc.lpszClassName = class_name;
+//   ...
+//   RegisterClassEx(&wc);
+//
+//   CreateWindowW(class_name, window_name, ...
+//
+template <WNDPROC proc>
+LRESULT CALLBACK WrappedWindowProc(HWND hwnd, UINT message,
+                                   WPARAM wparam, LPARAM lparam) {
+  LRESULT rv = 0;
+  __try {
+    rv = proc(hwnd, message, wparam, lparam);
+  } __except(CallExceptionFilter(GetExceptionInformation())) {
+  }
+  return rv;
+}
+
+}  // namespace win
+}  // namespace base
+
+#endif  // BASE_WIN_WRAPPED_WINDOW_PROC_H_
diff --git a/base/win/wrapped_window_proc_unittest.cc b/base/win/wrapped_window_proc_unittest.cc
new file mode 100644
index 0000000..161c913
--- /dev/null
+++ b/base/win/wrapped_window_proc_unittest.cc
@@ -0,0 +1,79 @@
+// Copyright (c) 2011 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/message_loop/message_loop.h"
+#include "base/win/wrapped_window_proc.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+DWORD kExceptionCode = 12345;
+WPARAM kCrashMsg = 98765;
+
+// A trivial WindowProc that generates an exception.
+LRESULT CALLBACK TestWindowProc(HWND hwnd, UINT message,
+                                WPARAM wparam, LPARAM lparam) {
+  if (message == kCrashMsg)
+    RaiseException(kExceptionCode, 0, 0, NULL);
+  return DefWindowProc(hwnd, message, wparam, lparam);
+}
+
+// This class implements an exception filter that can be queried about a past
+// exception.
+class TestWrappedExceptionFiter {
+ public:
+  TestWrappedExceptionFiter() : called_(false) {
+    EXPECT_FALSE(s_filter_);
+    s_filter_ = this;
+  }
+
+  ~TestWrappedExceptionFiter() {
+    EXPECT_EQ(s_filter_, this);
+    s_filter_ = NULL;
+  }
+
+  bool called() {
+    return called_;
+  }
+
+  // The actual exception filter just records the exception.
+  static int Filter(EXCEPTION_POINTERS* info) {
+    EXPECT_FALSE(s_filter_->called_);
+    if (info->ExceptionRecord->ExceptionCode == kExceptionCode)
+      s_filter_->called_ = true;
+    return EXCEPTION_EXECUTE_HANDLER;
+  }
+
+ private:
+  bool called_;
+  static TestWrappedExceptionFiter* s_filter_;
+};
+TestWrappedExceptionFiter* TestWrappedExceptionFiter::s_filter_ = NULL;
+
+}  // namespace.
+
+TEST(WrappedWindowProc, CatchesExceptions) {
+  HINSTANCE hinst = GetModuleHandle(NULL);
+  std::wstring class_name(L"TestClass");
+
+  WNDCLASS wc = {0};
+  wc.lpfnWndProc = base::win::WrappedWindowProc<TestWindowProc>;
+  wc.hInstance = hinst;
+  wc.lpszClassName = class_name.c_str();
+  RegisterClass(&wc);
+
+  HWND window = CreateWindow(class_name.c_str(), 0, 0, 0, 0, 0, 0, HWND_MESSAGE,
+                             0, hinst, 0);
+  ASSERT_TRUE(window);
+
+  // Before generating the exception we make sure that the filter will see it.
+  TestWrappedExceptionFiter wrapper;
+  base::win::WinProcExceptionFilter old_filter =
+      base::win::SetWinProcExceptionFilter(TestWrappedExceptionFiter::Filter);
+
+  SendMessage(window, kCrashMsg, 0, 0);
+  EXPECT_TRUE(wrapper.called());
+
+  base::win::SetWinProcExceptionFilter(old_filter);
+}